OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/trunk/insight/libgui/src
    from Rev 578 to Rev 1765
    Reverse comparison

Rev 578 → Rev 1765

/Makefile.in
0,0 → 1,441
# Makefile.in generated automatically by automake 1.4 from Makefile.am
 
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
 
 
 
SHELL = @SHELL@
 
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
 
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
 
DESTDIR =
 
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
 
top_builddir = ..
 
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
 
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
 
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
host_triplet = @host@
BFDHDIR = @BFDHDIR@
BFDLIB = @BFDLIB@
CC = @CC@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEJAGNUHDIR = @DEJAGNUHDIR@
DEJAGNULIB = @DEJAGNULIB@
DEVOHDIR = @DEVOHDIR@
ENDIAN = @ENDIAN@
EXEEXT = @EXEEXT@
GUILIB = @GUILIB@
HAVE_DEVO_SIM = @HAVE_DEVO_SIM@
IDEHDIR = @IDEHDIR@
IDELIB = @IDELIB@
IDETCLLIB = @IDETCLLIB@
ILUHDIR = @ILUHDIR@
ILULIB = @ILULIB@
ILUTOP = @ILUTOP@
INTLHDIR = @INTLHDIR@
INTLLIB = @INTLLIB@
ITCLHDIR = @ITCLHDIR@
ITCLLIB = @ITCLLIB@
ITCLMKIDX = @ITCLMKIDX@
ITCLSH = @ITCLSH@
ITCL_BUILD_LIB_SPEC = @ITCL_BUILD_LIB_SPEC@
ITCL_DIR = @ITCL_DIR@
ITCL_LIB_FILE = @ITCL_LIB_FILE@
ITCL_LIB_FULL_PATH = @ITCL_LIB_FULL_PATH@
ITCL_SH = @ITCL_SH@
ITK_BUILD_LIB_SPEC = @ITK_BUILD_LIB_SPEC@
ITK_LIB_FILE = @ITK_LIB_FILE@
ITK_LIB_FULL_PATH = @ITK_LIB_FULL_PATH@
LIBERTY = @LIBERTY@
LIBGCC = @LIBGCC@
LIBGUIHDIR = @LIBGUIHDIR@
LIBGUILIB = @LIBGUILIB@
LIBGUI_LIBRARY_DIR = @LIBGUI_LIBRARY_DIR@
LIBIBERTY = @LIBIBERTY@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
OBJEXT = @OBJEXT@
OPCODESLIB = @OPCODESLIB@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
RPATH_ENVVAR = @RPATH_ENVVAR@
RUNTESTDIR = @RUNTESTDIR@
SIMHDIR = @SIMHDIR@
SIMLIB = @SIMLIB@
TCLCONFIG = @TCLCONFIG@
TCLHDIR = @TCLHDIR@
TCL_BIN_DIR = @TCL_BIN_DIR@
TCL_BUILD_LIB_SPEC = @TCL_BUILD_LIB_SPEC@
TCL_CFLAGS = @TCL_CFLAGS@
TCL_DEFS = @TCL_DEFS@
TCL_LD_FLAGS = @TCL_LD_FLAGS@
TCL_LD_SEARCH_FLAGS = @TCL_LD_SEARCH_FLAGS@
TCL_LIBRARY = @TCL_LIBRARY@
TCL_LIBS = @TCL_LIBS@
TCL_LIB_FILE = @TCL_LIB_FILE@
TCL_LIB_FULL_PATH = @TCL_LIB_FULL_PATH@
TCL_LIB_SPEC = @TCL_LIB_SPEC@
TCL_RANLIB = @TCL_RANLIB@
TCL_SHLIB_CFLAGS = @TCL_SHLIB_CFLAGS@
TCL_SHLIB_LD = @TCL_SHLIB_LD@
TIXHDIR = @TIXHDIR@
TIX_BUILD_LIB_SPEC = @TIX_BUILD_LIB_SPEC@
TIX_LIB_FULL_PATH = @TIX_LIB_FULL_PATH@
TKCONFIG = @TKCONFIG@
TKHDIR = @TKHDIR@
TK_BUILD_INCLUDES = @TK_BUILD_INCLUDES@
TK_BUILD_LIB_SPEC = @TK_BUILD_LIB_SPEC@
TK_DEFS = @TK_DEFS@
TK_LIBS = @TK_LIBS@
TK_LIB_FILE = @TK_LIB_FILE@
TK_LIB_FULL_PATH = @TK_LIB_FULL_PATH@
TK_LIB_SPEC = @TK_LIB_SPEC@
TK_VERSION = @TK_VERSION@
TK_XINCLUDES = @TK_XINCLUDES@
TK_XLIBSW = @TK_XLIBSW@
VERSION = @VERSION@
ac_cv_c_itclsh = @ac_cv_c_itclsh@
 
AUTOMAKE_OPTIONS = cygnus
 
noinst_LIBRARIES = libgui.a
 
@INSTALL_LIBGUI_TRUE@include_HEADERS = @INSTALL_LIBGUI_TRUE@\
@INSTALL_LIBGUI_TRUE@ guitcl.h subcommand.h
 
TBL_VERSION = 2.1
 
# tkTable version info
 
# This sets the name that tkTable will define for itself when loaded
# If you change this, then the demos won't work, but it might be necessary
# for those with another built-in "table" command
TBL_COMMAND = table
 
LIBGUI_CFLAGS = @LIBGUI_CFLAGS@
 
INCLUDES = $(LIBGUI_CFLAGS) $(TCLHDIR) \
$(TKHDIR) \
$(TK_XINCLUDES) $(TCL_DEFS) $(TK_DEFS) \
$(TKHDIR)/../unix $(TKHDIR)/../win \
-DTBL_VERSION=\"$(TBL_VERSION)\"\
-DTBL_COMMAND=\"$(TBL_COMMAND)\"\
-DTCL_RUNTIME=\"tkTable.tcl\"
 
 
libgui_a_SOURCES = guitcl.h paths.c subcommand.c subcommand.h \
xpmlib.c tclmain.c tkGraphCanvas.c \
tkCanvEdge.c tkCanvLayout.c tkCanvLayout.h tclhelp.c tclgetdir.c \
tclwinprint.c tclsizebox.c tclshellexe.c tclmapi.c tclwinfont.c \
tclwingrab.c tclwinmode.c tclwinpath.c tclmsgbox.c tclcursor.c \
tkTable.c tkTableCmd.c tkTableCell.c tkTableTag.c tkTableWin.c \
tkWinPrintText.c tkWinPrintCanvas.c tkWarpPointer.c
 
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
LIBRARIES = $(noinst_LIBRARIES)
 
 
DEFS = @DEFS@ -I. -I$(srcdir) -I..
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
libgui_a_LIBADD =
libgui_a_OBJECTS = paths.$(OBJEXT) subcommand.$(OBJEXT) \
xpmlib.$(OBJEXT) tclmain.$(OBJEXT) tkGraphCanvas.$(OBJEXT) \
tkCanvEdge.$(OBJEXT) tkCanvLayout.$(OBJEXT) tclhelp.$(OBJEXT) \
tclgetdir.$(OBJEXT) tclwinprint.$(OBJEXT) tclsizebox.$(OBJEXT) \
tclshellexe.$(OBJEXT) tclmapi.$(OBJEXT) tclwinfont.$(OBJEXT) \
tclwingrab.$(OBJEXT) tclwinmode.$(OBJEXT) tclwinpath.$(OBJEXT) \
tclmsgbox.$(OBJEXT) tclcursor.$(OBJEXT) tkTable.$(OBJEXT) \
tkTableCmd.$(OBJEXT) tkTableCell.$(OBJEXT) tkTableTag.$(OBJEXT) \
tkTableWin.$(OBJEXT) tkWinPrintText.$(OBJEXT) \
tkWinPrintCanvas.$(OBJEXT) tkWarpPointer.$(OBJEXT)
AR = ar
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
HEADERS = $(include_HEADERS)
 
DIST_COMMON = Makefile.am Makefile.in
 
 
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
TAR = tar
GZIP_ENV = --best
SOURCES = $(libgui_a_SOURCES)
OBJECTS = $(libgui_a_OBJECTS)
 
all: all-redirect
.SUFFIXES:
.SUFFIXES: .S .c .o .obj .s
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) $(srcdir)/tkTable_version.in
cd $(top_srcdir) && $(AUTOMAKE) --cygnus src/Makefile
 
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
 
 
mostlyclean-noinstLIBRARIES:
 
clean-noinstLIBRARIES:
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
 
distclean-noinstLIBRARIES:
 
maintainer-clean-noinstLIBRARIES:
 
.c.o:
$(COMPILE) -c $<
 
# FIXME: We should only use cygpath when building on Windows,
# and only if it is available.
.c.obj:
$(COMPILE) -c `cygpath -w $<`
 
.s.o:
$(COMPILE) -c $<
 
.S.o:
$(COMPILE) -c $<
 
mostlyclean-compile:
-rm -f *.o core *.core
-rm -f *.$(OBJEXT)
 
clean-compile:
 
distclean-compile:
-rm -f *.tab.c
 
maintainer-clean-compile:
 
libgui.a: $(libgui_a_OBJECTS) $(libgui_a_DEPENDENCIES)
-rm -f libgui.a
$(AR) cru libgui.a $(libgui_a_OBJECTS) $(libgui_a_LIBADD)
$(RANLIB) libgui.a
 
install-includeHEADERS: $(include_HEADERS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(includedir)
@list='$(include_HEADERS)'; for p in $$list; do \
if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p"; \
$(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p; \
done
 
uninstall-includeHEADERS:
@$(NORMAL_UNINSTALL)
list='$(include_HEADERS)'; for p in $$list; do \
rm -f $(DESTDIR)$(includedir)/$$p; \
done
 
tags: TAGS
 
ID: $(HEADERS) $(SOURCES) $(LISP)
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
here=`pwd` && cd $(srcdir) \
&& mkid -f$$here/ID $$unique $(LISP)
 
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
 
mostlyclean-tags:
 
clean-tags:
 
distclean-tags:
-rm -f TAGS ID
 
maintainer-clean-tags:
 
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
 
subdir = src
 
distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
if test -f $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
cp -pr $$d/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
info-am:
info: info-am
dvi-am:
dvi: dvi-am
check-am:
check: check-am
installcheck-am:
installcheck: installcheck-am
install-info-am:
install-info: install-info-am
install-exec-am: install-exec-local
install-exec: install-exec-am
 
install-data-am: install-includeHEADERS
install-data: install-data-am
 
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-am
uninstall-am: uninstall-includeHEADERS
uninstall: uninstall-am
all-am: Makefile $(LIBRARIES) $(HEADERS)
all-redirect: all-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
installdirs:
$(mkinstalldirs) $(DESTDIR)$(includedir)
 
 
mostlyclean-generic:
 
clean-generic:
 
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
 
maintainer-clean-generic:
mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
 
mostlyclean: mostlyclean-am
 
clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
mostlyclean-am
 
clean: clean-am
 
distclean-am: distclean-noinstLIBRARIES distclean-compile \
distclean-tags distclean-generic clean-am
 
distclean: distclean-am
 
maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
maintainer-clean-compile maintainer-clean-tags \
maintainer-clean-generic distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
 
maintainer-clean: maintainer-clean-am
 
.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile uninstall-includeHEADERS \
install-includeHEADERS tags mostlyclean-tags distclean-tags clean-tags \
maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \
installcheck-am installcheck install-info-am install-info \
install-exec-local install-exec-am install-exec install-data-am \
install-data install-am install uninstall-am uninstall all-redirect \
all-am all installdirs mostlyclean-generic distclean-generic \
clean-generic maintainer-clean-generic clean mostlyclean distclean \
maintainer-clean
 
 
tkTabletcl.h: $(srcdir)/tkTable.tcl
sed -e '/^$\#/d' -e '/^$$/d' -e 's/\"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' <$(srcdir)/tkTable.tcl >tkTabletcl.h || rm tkTabletcl.h
 
# Defining lib_LIBRARIES conditionally doesn't do the right thing.
install-exec-local:
@INSTALL_LIBGUI_TRUE@ @$(NORMAL_INSTALL)
@INSTALL_LIBGUI_TRUE@ $(mkinstalldirs) $(libdir)
@INSTALL_LIBGUI_TRUE@ $(INSTALL_DATA) libgui.a $(libdir)/libgui.a
@INSTALL_LIBGUI_TRUE@ @$(POST_INSTALL)
@INSTALL_LIBGUI_TRUE@ $(RANLIB) $(libdir)/libgui.a
 
paths.$(OBJEXT): paths.c guitcl.h
subcommand.$(OBJEXT): subcommand.c subcommand.h
tkCanvEdge.$(OBJEXT): tkCanvEdge.c ../config.h
tkCanvLayout.$(OBJEXT): tkCanvLayout.c ../config.h tkCanvLayout.h
tkGraphCanvas.$(OBJEXT): tkGraphCanvas.c tkCanvLayout.h
xpmlib.$(OBJEXT): xpmlib.c guitcl.h
assertions.$(OBJEXT): assertions.c ../config.h assertions.h
tclcursor.$(OBJEXT): tclcursor.c ../config.h guitcl.h subcommand.h
tclhelp.$(OBJEXT): tclhelp.c ../config.h guitcl.h subcommand.h
tclgetdir.$(OBJEXT): tclgetdir.c guitcl.h
tclmain.$(OBJEXT): tclmain.c guitcl.h
tclwinprint.$(OBJEXT): tclwinprint.c guitcl.h subcommand.h
tclsizebox.$(OBJEXT): tclsizebox.c guitcl.h
tclshellexe.$(OBJEXT): tclshellexe.c guitcl.h
tclmapi.$(OBJEXT): tclmapi.c guitcl.h subcommand.h
tclwinfont.$(OBJEXT): tclwinfont.c guitcl.h
tclwingrab.$(OBJEXT): tclwingrab.c guitcl.h
tclwinpath.$(OBJEXT): tclwinpath.c guitcl.h subcommand.h
tclwinmode.$(OBJEXT): tclwinmode.c guitcl.h
tkTable.$(OBJEXT): tkTable.c tkTable.h tkTableCmd.h tkTabletcl.h
tkTableCell.$(OBJEXT): tkTableCell.c tkTable.h tkTableCmd.h
tkTableTag.$(OBJEXT): tkTableTag.c tkTable.h tkTableCmd.h
tkTableWin.$(OBJEXT):tkTableWin.c tkTable.h tkTableCmd.h
tkTableCmd.$(OBJEXT): tkTableCmd.c tkTableCmd.h
tkTabletcl.h: tkTable.tcl
 
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
Makefile.in Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkTableWin.c =================================================================== --- tkTableWin.c (nonexistent) +++ tkTableWin.c (revision 1765) @@ -0,0 +1,856 @@ +/* + * tkTableWin.c -- + * + * This module implements embedded windows for table widgets. + * Much of this code is adapted from tkGrid.c and tkTextWind.c. + * + * Copyright (c) 1998 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include "tkTable.h" + +static int StickyParseProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, char *value, + char *widgRec, int offset)); +static char * StickyPrintProc _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin, char *widgRec, int offset, + Tcl_FreeProc **freeProcPtr)); + +static void EmbWinLostSlaveProc _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin)); +static void EmbWinRequestProc _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin)); + +static void EmbWinCleanup _ANSI_ARGS_((Table *tablePtr, + TableEmbWindow *ewPtr)); +static int EmbWinConfigure _ANSI_ARGS_((Table *tablePtr, + TableEmbWindow *ewPtr, + int argc, char **argv)); +static void EmbWinStructureProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); +static void EmbWinUnmapNow _ANSI_ARGS_((Tk_Window ewTkwin, + Tk_Window tkwin)); + +static Tk_GeomMgr tableGeomType = { + "table", /* name */ + EmbWinRequestProc, /* requestProc */ + EmbWinLostSlaveProc, /* lostSlaveProc */ +}; + +/* windows subcommands */ +#define WIN_CGET 1 /* get config item of embedded window */ +#define WIN_CONFIGURE 2 /* configure an embedded window */ +#define WIN_DELETE 3 /* delete an embedded window */ +#define WIN_MOVE 4 /* moves a window index */ +#define WIN_NAMES 5 /* print the embedded window names */ +static Cmd_Struct win_cmds[] = { + {"configure", WIN_CONFIGURE}, + {"cget", WIN_CGET}, + {"delete", WIN_DELETE}, + {"move", WIN_MOVE}, + {"names", WIN_NAMES}, + {"", 0} +}; + +/* Flag values for "sticky"ness The 16 combinations subsume the packer's + * notion of anchor and fill. + * + * STICK_NORTH This window sticks to the top of its cavity. + * STICK_EAST This window sticks to the right edge of its cavity. + * STICK_SOUTH This window sticks to the bottom of its cavity. + * STICK_WEST This window sticks to the left edge of its cavity. + */ + +#define STICK_NORTH (1<<0) +#define STICK_EAST (1<<1) +#define STICK_SOUTH (1<<2) +#define STICK_WEST (1<<3) + +/* + * The default specification for configuring embedded windows + * Done like this to make the command line parsing easy + */ + +static Tk_CustomOption stickyOption = {StickyParseProc, StickyPrintProc, + (ClientData) NULL}; + +static Tk_ConfigSpec winConfigSpecs[] = { + {TK_CONFIG_BORDER, "-background", "background", "Background", NULL, + Tk_Offset(TableEmbWindow, bg), + TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, + {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, + (char *) NULL, 0, 0 }, + {TK_CONFIG_STRING, "-create", (char *) NULL, (char *) NULL, (char *) NULL, + Tk_Offset(TableEmbWindow, create), + TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, + {TK_CONFIG_PIXELS, "-padx", (char *) NULL, (char *) NULL, (char *) NULL, + Tk_Offset(TableEmbWindow, padX), TK_CONFIG_DONT_SET_DEFAULT }, + {TK_CONFIG_PIXELS, "-pady", (char *) NULL, (char *) NULL, (char *) NULL, + Tk_Offset(TableEmbWindow, padY), TK_CONFIG_DONT_SET_DEFAULT }, + {TK_CONFIG_CUSTOM, "-sticky", (char *) NULL, (char *) NULL, (char *) NULL, + Tk_Offset(TableEmbWindow, sticky), TK_CONFIG_DONT_SET_DEFAULT, + &stickyOption}, + {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", NULL, + Tk_Offset(TableEmbWindow, relief), 0 }, + {TK_CONFIG_WINDOW, "-window", (char *) NULL, (char *) NULL, (char *) NULL, + Tk_Offset(TableEmbWindow, tkwin), + TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0 } +}; + +/* + *---------------------------------------------------------------------- + * + * StickyPrintProc -- + * Converts the internal boolean combination of "sticky" bits onto + * a TCL string element containing zero or more of n, s, e, or w. + * + * Results: + * A string is placed into the "result" pointer. + * + * Side effects: + * none. + * + *---------------------------------------------------------------------- + */ +static char * +StickyPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Ignored. */ + Tk_Window tkwin; /* Window for text widget. */ + char *widgRec; /* Pointer to TkTextEmbWindow + * structure. */ + int offset; /* Ignored. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + int flags = ((TableEmbWindow *) widgRec)->sticky; + int count = 0; + char *result = (char *) ckalloc(5*sizeof(char)); + + if (flags&STICK_NORTH) result[count++] = 'n'; + if (flags&STICK_EAST) result[count++] = 'e'; + if (flags&STICK_SOUTH) result[count++] = 's'; + if (flags&STICK_WEST) result[count++] = 'w'; + + *freeProcPtr = TCL_DYNAMIC; + result[count] = '\0'; + return result; +} + +/* + *---------------------------------------------------------------------- + * + * StringParseProc -- + * Converts an ascii string representing a widgets stickyness + * into the boolean result. + * + * Results: + * The boolean combination of the "sticky" bits is retuned. If an + * error occurs, such as an invalid character, -1 is returned instead. + * + * Side effects: + * none + * + *---------------------------------------------------------------------- + */ +static int +StickyParseProc(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* Not used.*/ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window for text widget. */ + char *value; /* Value of option. */ + char *widgRec; /* Pointer to TkTextEmbWindow + * structure. */ + int offset; /* Offset into item (ignored). */ +{ + register TableEmbWindow *ewPtr = (TableEmbWindow *) widgRec; + int sticky = 0; + char c; + + while ((c = *value++) != '\0') { + switch (c) { + case 'n': case 'N': sticky |= STICK_NORTH; break; + case 'e': case 'E': sticky |= STICK_EAST; break; + case 's': case 'S': sticky |= STICK_SOUTH; break; + case 'w': case 'W': sticky |= STICK_WEST; break; + case ' ': case ',': case '\t': case '\r': case '\n': break; + default: + Tcl_AppendResult(interp, "bad sticky value \"", --value, + "\": must contain n, s, e or w", + (char *) NULL); + return TCL_ERROR; + } + } + ewPtr->sticky = sticky; + return TCL_OK; +} + +/* + * ckallocs space for a new embedded window structure and clears the structure + * returns the pointer to the new structure + */ +static TableEmbWindow * +TableNewEmbWindow(Table *tablePtr) +{ + TableEmbWindow *ewPtr = (TableEmbWindow *) ckalloc(sizeof(TableEmbWindow)); + ewPtr->tablePtr = tablePtr; + ewPtr->tkwin = NULL; + ewPtr->hPtr = NULL; + ewPtr->bg = NULL; + ewPtr->create = NULL; + ewPtr->relief = -1; + ewPtr->sticky = 0; + ewPtr->padX = 0; + ewPtr->padY = 0; + ewPtr->displayed = 0; + return ewPtr; +} + +/* + *---------------------------------------------------------------------- + * + * EmbWinCleanup -- + * Releases resources used by an embedded window before it is freed up. + * + * Results: + * Window will no longer be valid. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static void +EmbWinCleanup(Table *tablePtr, TableEmbWindow *ewPtr) +{ + /* free the options in the widget */ + Tk_FreeOptions(winConfigSpecs, (char *) ewPtr, tablePtr->display, 0); +} + +/* + *-------------------------------------------------------------- + * + * EmbWinDisplay -- + * + * This procedure is invoked by TableDisplay for + * mapping windows into cells. + * + * Results: + * Displays or moves window on table screen. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +void +EmbWinDisplay(Table *tablePtr, Drawable window, TableEmbWindow *ewPtr, + TableTag *tagPtr, int x, int y, int width, int height) +{ + Tk_Window tkwin = tablePtr->tkwin; + Tk_Window ewTkwin = ewPtr->tkwin; + int diffx=0; /* Cavity width - slave width. */ + int diffy=0; /* Cavity hight - slave height. */ + int sticky = ewPtr->sticky; + + + if (ewPtr->bg) + tagPtr->bg = ewPtr->bg; + if (ewPtr->relief != -1) + tagPtr->relief = ewPtr->relief; + + x += ewPtr->padX/2; + width -= ewPtr->padX; + y += ewPtr->padY/2; + height -= ewPtr->padY; + + if (width > Tk_ReqWidth(ewPtr->tkwin)) { + diffx = width - Tk_ReqWidth(ewPtr->tkwin); + width = Tk_ReqWidth(ewPtr->tkwin); + } + if (height > Tk_ReqHeight(ewPtr->tkwin)) { + diffy = height - Tk_ReqHeight(ewPtr->tkwin); + height = Tk_ReqHeight(ewPtr->tkwin); + } + if (sticky&STICK_EAST && sticky&STICK_WEST) { + width += diffx; + } + if (sticky&STICK_NORTH && sticky&STICK_SOUTH) { + height += diffy; + } + if (!(sticky&STICK_WEST)) { + x += (sticky&STICK_EAST) ? diffx : diffx/2; + } + if (!(sticky&STICK_NORTH)) { + y += (sticky&STICK_SOUTH) ? diffy : diffy/2; + } + + /* If we fall below a specific minimum width/height requirement, + * we just unmap the window */ + if (width < 4 || height < 4) { + if (ewPtr->displayed) { + EmbWinUnmapNow(ewTkwin, tkwin); + } + return; + } + + if (tkwin == Tk_Parent(ewTkwin)) { + if ((x != Tk_X(ewTkwin)) || (y != Tk_Y(ewTkwin)) + || (width != Tk_Width(ewTkwin)) || (height != Tk_Height(ewTkwin))) { + Tk_MoveResizeWindow(ewTkwin, x, y, width, height); + } + Tk_MapWindow(ewTkwin); + } else { + Tk_MaintainGeometry(ewTkwin, tkwin, x, y, width, height); + } + ewPtr->displayed = 1; +} + +/* + *-------------------------------------------------------------- + * + * EmbWinUnmapNow -- + * Handles unmapping the window depending on parent. + * tkwin should be tablePtr->tkwin. + * ewTkwin should be ewPtr->tkwin. + * + * Results: + * Removes the window. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +static void +EmbWinUnmapNow(Tk_Window ewTkwin, Tk_Window tkwin) +{ + if (tkwin != Tk_Parent(ewTkwin)) { + Tk_UnmaintainGeometry(ewTkwin, tkwin); + } else { + Tk_UnmapWindow(ewTkwin); + } +} + +/* + *-------------------------------------------------------------- + * + * EmbWinUnmap -- + * This procedure is invoked by TableAdjustParams for + * unmapping windows managed moved offscreen. + * rlo, ... should be in real coords. + * + * Results: + * None. + * + * Side effects: + * Unmaps embedded windows. + * + *-------------------------------------------------------------- + */ +void +EmbWinUnmap(Table *tablePtr, int rlo, int rhi, int clo, int chi) +{ + register TableEmbWindow *ewPtr; + Tcl_HashEntry *entryPtr; + int row, col; + char buf[INDEX_BUFSIZE]; + + /* we need to deal with things user coords */ + rlo += tablePtr->rowOffset; + rhi += tablePtr->rowOffset; + clo += tablePtr->colOffset; + chi += tablePtr->colOffset; + for (row = rlo; row <= rhi; row++) { + for (col = clo; col <= chi; col++) { + TableMakeArrayIndex(row, col, buf); + if ((entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf)) != NULL) { + ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); + if (ewPtr->displayed) { + ewPtr->displayed = 0; + if (ewPtr->tkwin != NULL && tablePtr->tkwin != NULL) { + EmbWinUnmapNow(ewPtr->tkwin, tablePtr->tkwin); + } + } + } + } + } +} + +/* + *-------------------------------------------------------------- + * + * EmbWinRequestProc -- + * This procedure is invoked by Tk_GeometryRequest for + * windows managed by the Table. + * + * Results: + * None. + * + * Side effects: + * Arranges for tkwin, and all its managed siblings, to + * be re-arranged at the next idle point. + * + *-------------------------------------------------------------- + */ +static void +EmbWinRequestProc(clientData, tkwin) + ClientData clientData; /* Table's information about + * window that got new preferred + * geometry. */ + Tk_Window tkwin; /* Other Tk-related information + * about the window. */ +{ + register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData; + + /* resize depends on the sticky */ + if (ewPtr->displayed && ewPtr->hPtr != NULL) { + Table *tablePtr = ewPtr->tablePtr; + int row, col, x, y, width, height; + + TableParseArrayIndex(&row, &col, + Tcl_GetHashKey(tablePtr->winTable, ewPtr->hPtr)); + if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, &x, &y, &width, &height, 0)) { + TableInvalidate(tablePtr, x, y, width, height, 0); + } + } +} + +static void +EmbWinRemove(TableEmbWindow *ewPtr) +{ + Table *tablePtr = ewPtr->tablePtr; + + ewPtr->tkwin = NULL; + ewPtr->displayed = 0; + if (tablePtr->tkwin != NULL) { + int row, col, x, y, width, height; + + TableParseArrayIndex(&row, &col, + Tcl_GetHashKey(tablePtr->winTable, ewPtr->hPtr)); + if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, &x, &y, &width, &height, 0)) + TableInvalidate(tablePtr, x, y, width, height, 1); + } +} + +/* + *-------------------------------------------------------------- + * + * EmbWinLostSlaveProc -- + * This procedure is invoked by Tk whenever some other geometry + * claims control over a slave that used to be managed by us. + * + * Results: + * None. + * + * Side effects: + * Forgets all table-related information about the slave. + * + *-------------------------------------------------------------- + */ + +static void +EmbWinLostSlaveProc(clientData, tkwin) + ClientData clientData; /* Table structure for slave window that + * was stolen away. */ + Tk_Window tkwin; /* Tk's handle for the slave window. */ +{ + register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData; + + Tk_DeleteEventHandler(ewPtr->tkwin, StructureNotifyMask, + EmbWinStructureProc, (ClientData) ewPtr); +#if 0 + Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr); +#endif + EmbWinUnmapNow(tkwin, ewPtr->tablePtr->tkwin); + EmbWinRemove(ewPtr); +} + +/* + *-------------------------------------------------------------- + * + * EmbWinStructureProc -- + * This procedure is invoked by the Tk event loop whenever + * StructureNotify events occur for a window that's embedded + * in a table widget. This procedure's only purpose is to + * clean up when windows are deleted. + * + * Results: + * None. + * + * Side effects: + * The window is disassociated from the window segment, and + * the portion of the table is redisplayed. + * + *-------------------------------------------------------------- + */ +static void +EmbWinStructureProc(clientData, eventPtr) + ClientData clientData; /* Pointer to record describing window item. */ + XEvent *eventPtr; /* Describes what just happened. */ +{ + register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData; + + if (eventPtr->type != DestroyNotify) { + return; + } + + EmbWinRemove(ewPtr); +} + +/* + *-------------------------------------------------------------- + * + * EmbWinDelete -- + * This procedure is invoked by ... whenever + * an embedded window is being deleted. + * + * Results: + * None. + * + * Side effects: + * The embedded window is deleted, if it exists, and any resources + * associated with it are released. + * + *-------------------------------------------------------------- + */ +void +EmbWinDelete(register Table *tablePtr, TableEmbWindow *ewPtr) +{ + Tcl_HashEntry *entryPtr; + + if (ewPtr->tkwin != NULL) { + int row, col, x, y, width, height; + entryPtr = ewPtr->hPtr; + + /* + * Delete the event handler for the window before destroying + * the window, so that EmbWinStructureProc doesn't get called + * (we'll already do everything that it would have done, and + * it will just get confused). + */ + + Tk_DeleteEventHandler(ewPtr->tkwin, StructureNotifyMask, + EmbWinStructureProc, (ClientData) ewPtr); + Tk_DestroyWindow(ewPtr->tkwin); + + if (tablePtr->tkwin != NULL && entryPtr != NULL) { + TableParseArrayIndex(&row, &col, + Tcl_GetHashKey(tablePtr->winTable, entryPtr)); + Tcl_DeleteHashEntry(entryPtr); + + if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, + &x, &y, &width, &height, 0)) + TableInvalidate(tablePtr, x, y, width, height, 0); + } + } +#if 0 + Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr); +#endif + EmbWinCleanup(tablePtr, ewPtr); + ckfree((char *) ewPtr); +} + +/* + *-------------------------------------------------------------- + * + * EmbWinConfigure -- + * This procedure is called to handle configuration options + * for an embedded window, using an argc/argv list. + * + * Results: + * The return value is a standard Tcl result. If TCL_ERROR is + * returned, then the interp's result contains an error message.. + * + * Side effects: + * Configuration information for the embedded window changes, + * such as alignment, stretching, or name of the embedded + * window. + * + *-------------------------------------------------------------- + */ +static int +EmbWinConfigure(tablePtr, ewPtr, argc, argv) + Table *tablePtr; /* Information about table widget that + * contains embedded window. */ + TableEmbWindow *ewPtr; /* Embedded window to be configured. */ + int argc; /* Number of strings in argv. */ + char **argv; /* Array of strings describing configuration + * options. */ +{ + Tk_Window oldWindow; + + oldWindow = ewPtr->tkwin; + if (Tk_ConfigureWidget(tablePtr->interp, tablePtr->tkwin, winConfigSpecs, + argc, argv, (char *) ewPtr, TK_CONFIG_ARGV_ONLY) + != TCL_OK) { + return TCL_ERROR; + } + if (oldWindow != ewPtr->tkwin) { + ewPtr->displayed = 0; + if (oldWindow != NULL) { + Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, + EmbWinStructureProc, (ClientData) ewPtr); + Tk_ManageGeometry(oldWindow, (Tk_GeomMgr *) NULL, + (ClientData) NULL); + EmbWinUnmapNow(oldWindow, tablePtr->tkwin); + } + if (ewPtr->tkwin != NULL) { + Tk_Window ancestor, parent; + + /* + * Make sure that the table is either the parent of the + * embedded window or a descendant of that parent. Also, + * don't allow a top-level window to be managed inside + * a table. + */ + + parent = Tk_Parent(ewPtr->tkwin); + for (ancestor = tablePtr->tkwin; ; + ancestor = Tk_Parent(ancestor)) { + if (ancestor == parent) { + break; + } + if (Tk_IsTopLevel(ancestor)) { + badMaster: + Tcl_AppendResult(tablePtr->interp, "can't embed ", + Tk_PathName(ewPtr->tkwin), " in ", + Tk_PathName(tablePtr->tkwin), (char *) NULL); + ewPtr->tkwin = NULL; + return TCL_ERROR; + } + } + if (Tk_IsTopLevel(ewPtr->tkwin) || (ewPtr->tkwin == tablePtr->tkwin)) { + goto badMaster; + } + + /* + * Take over geometry management for the window, plus create + * an event handler to find out when it is deleted. + */ + + Tk_ManageGeometry(ewPtr->tkwin, &tableGeomType, (ClientData) ewPtr); + Tk_CreateEventHandler(ewPtr->tkwin, StructureNotifyMask, + EmbWinStructureProc, (ClientData) ewPtr); + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TableWindowCmd -- + * This procedure is invoked to process the window method + * that corresponds to a widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +TableWindowCmd(Table * tablePtr, register Tcl_Interp *interp, + int argc, char *argv[]) +{ + int result = TCL_OK, retval; + int row, col, x, y, width, height, i, new; + TableEmbWindow *ewPtr; + Tcl_HashEntry *entryPtr; + Tcl_HashSearch search; + char buf[INDEX_BUFSIZE], *keybuf; + + /* parse the next argument */ + retval = Cmd_Parse(interp, win_cmds, argv[2]); + switch (retval) { + /* failed to parse the argument, error */ + case 0: + return TCL_ERROR; + + case WIN_CGET: + if (argc != 5) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " window cget index option\"", (char *) NULL); + return TCL_ERROR; + } + if ((entryPtr=Tcl_FindHashEntry(tablePtr->winTable, argv[3])) == NULL) { + Tcl_AppendResult(interp, "no window at index \"", argv[3], + "\"", (char *) NULL); + return TCL_ERROR; + } else { + ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); + result = Tk_ConfigureValue(interp, tablePtr->tkwin, winConfigSpecs, + (char *) ewPtr, argv[4], 0); + } + return result; /* CGET */ + + case WIN_CONFIGURE: + if (argc < 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " window configure index ?arg arg ...?\"", + (char *) NULL); + return TCL_ERROR; + } + if (TableGetIndex(tablePtr, argv[3], &row, &col) == TCL_ERROR) { + return TCL_ERROR; + } + TableMakeArrayIndex(row, col, buf); + entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, buf, &new); + if (new) { + /* create the structure */ + ewPtr = TableNewEmbWindow(tablePtr); + + /* insert it into the table */ + Tcl_SetHashValue(entryPtr, (ClientData) ewPtr); + ewPtr->hPtr = entryPtr; + + /* configure the window structure */ + result = EmbWinConfigure(tablePtr, ewPtr, argc-4, argv+4); + if (result == TCL_ERROR) { + /* release the structure */ + EmbWinCleanup(tablePtr, ewPtr); + ckfree((char *) ewPtr); + + /* and free the hash table entry */ + Tcl_DeleteHashEntry(entryPtr); + return TCL_ERROR; + } + + /* if a window was specified, make sure it exists */ + } else { + /* pointer wasn't null, do a reconfig if we have enough arguments */ + /* get the window pointer from the table */ + ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); + + /* 5 args means that there are values to replace */ + if (argc > 5) { + /* and do a reconfigure */ + result = EmbWinConfigure(tablePtr, ewPtr, argc-4, argv+4); + if (result == TCL_ERROR) + return TCL_ERROR; + } + } + + /* + * If there were less than 6 args, we need + * to do a printout of the config, even for new windows + */ + if (argc < 6) { + result = Tk_ConfigureInfo(interp, tablePtr->tkwin, winConfigSpecs, + (char *) ewPtr, (argc == 5)?argv[4]:0, 0); + } else { + /* Otherwise we reconfigured so invalidate the table for a redraw */ + if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, + &x, &y, &width, &height, 0)) { + TableInvalidate(tablePtr, x, y, width, height, 1); + } + } + return result; /* CONFIGURE */ + + case WIN_DELETE: + if (argc < 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " window delete index ?index ...?\"", (char *) NULL); + return TCL_ERROR; + } + for (i = 3; i < argc; i++) { + if ((entryPtr = Tcl_FindHashEntry(tablePtr->winTable, argv[i]))!=NULL) { + /* get the window pointer */ + ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); + + EmbWinDelete(tablePtr, ewPtr); + } + } + /* clear up anything that might have been placed in the result string */ + Tcl_SetResult(interp, "", TCL_STATIC); + return result; + + case WIN_MOVE: + if (argc != 5) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " window move oldIndex newIndex\"", (char *) NULL); + return TCL_ERROR; + } + if (TableGetIndex(tablePtr, argv[3], &x, &y) == TCL_ERROR || + TableGetIndex(tablePtr, argv[4], &row, &col) == TCL_ERROR) { + return TCL_ERROR; + } + TableMakeArrayIndex(x, y, buf); + if ((entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf)) == NULL) { + Tcl_AppendResult(interp, "no window at index \"", argv[3], + "\"", (char *) NULL); + return TCL_ERROR; + } + /* avoid moving it to the same location */ + if (x == row && y == col) { + return TCL_OK; + } + /* get the window pointer */ + ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); + /* and free the old hash table entry */ + Tcl_DeleteHashEntry(entryPtr); + + TableMakeArrayIndex(row, col, buf); + entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, buf, &new); + if (!new) { + /* window already there - just delete it */ + TableEmbWindow *ewPtrDel; + + ewPtrDel = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); + /* This prevents the deletion of it's own entry, since we need it */ + ewPtrDel->hPtr = NULL; + EmbWinDelete(tablePtr, ewPtrDel); + } + /* set the new entry's value */ + Tcl_SetHashValue(entryPtr, (ClientData) ewPtr); + ewPtr->hPtr = entryPtr; + + /* Invalidate old cell */ + if (TableCellVCoords(tablePtr, x-tablePtr->rowOffset, + y-tablePtr->colOffset, + &x, &y, &width, &height, 0)) { + TableInvalidate(tablePtr, x, y, width, height, 0); + } + /* Invalidate new cell */ + if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, + &x, &y, &width, &height, 0)) { + TableInvalidate(tablePtr, x, y, width, height, 0); + } + break; + + case WIN_NAMES: + /* just print out the image names */ + if (argc != 3 && argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " window names ?pattern?\"", (char *) NULL); + return TCL_ERROR; + } + entryPtr = Tcl_FirstHashEntry(tablePtr->winTable, &search); + while (entryPtr != NULL) { + keybuf = Tcl_GetHashKey(tablePtr->winTable, entryPtr); + if (argc == 3 || Tcl_StringMatch(keybuf, argv[3])) + Tcl_AppendElement(interp, keybuf); + entryPtr = Tcl_NextHashEntry(&search); + } + Tcl_SetResult(interp, + TableCellSort(tablePtr, Tcl_GetStringResult(interp)), + TCL_DYNAMIC); + break; + } + return TCL_OK; +}
tkTableWin.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tclwinmode.c =================================================================== --- tclwinmode.c (nonexistent) +++ tclwinmode.c (revision 1765) @@ -0,0 +1,89 @@ +/* tclwinmode.c - Tcl access to SetErrorMode function. + Copyright (C) 1998 Cygnus Solutions. + Written by Tom Tromey . */ + +#include +#include "guitcl.h" + +#ifdef __CYGWIN32__ + +#include + +struct pair +{ + const char *name; + UINT value; +}; + +static struct pair values[] = +{ + { "failcriticalerrors", SEM_FAILCRITICALERRORS }, + { "noalignmentfaultexcept", SEM_NOALIGNMENTFAULTEXCEPT }, + { "nogpfaulterrorbox", SEM_NOGPFAULTERRORBOX }, + { "noopenfileerrorbox", SEM_NOOPENFILEERRORBOX }, + { NULL, 0 } +}; + +#endif + +static int +seterrormode_command (ClientData cd, Tcl_Interp *interp, + int argc, char *argv[]) +{ +#ifdef __CYGWIN32__ + int len, i; + char **list; + UINT val = 0; + + if (argc != 2) + { + Tcl_AppendResult (interp, "wrong # args: should be \"", + argv[0], " modelist\"", (char *) NULL); + return TCL_ERROR; + } + + if (Tcl_SplitList (interp, argv[1], &len, &list) != TCL_OK) + return TCL_ERROR; + + for (i = 0; i < len; ++i) + { + int j, found = 0; + for (j = 0; values[j].name; ++j) + { + if (! strcmp (values[j].name, list[i])) + { + found = 1; + val |= values[j].value; + break; + } + } + if (! found) + { + Tcl_AppendResult (interp, "unrecognized key \"", list[i], + "\"", (char *) NULL); + Tcl_Free ((char *) list); + return TCL_ERROR; + } + } + Tcl_Free ((char *) list); + + val = SetErrorMode (val); + + for (i = 0; values[i].name; ++i) + { + if (val & values[i].value) + Tcl_AppendElement (interp, values[i].name); + } +#endif /* __CYGWIN32__ */ + + return TCL_OK; +} + +int +ide_create_set_error_mode_command (Tcl_Interp *interp) +{ + if (Tcl_CreateCommand (interp, "ide_set_error_mode", + seterrormode_command, NULL, NULL) == NULL) + return TCL_ERROR; + return TCL_OK; +}
tclwinmode.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkCanvEdge.c =================================================================== --- tkCanvEdge.c (nonexistent) +++ tkCanvEdge.c (revision 1765) @@ -0,0 +1,2095 @@ +/* + * tkCanvEdge.c -- + * + * This file implements edge items for canvas widgets. + * + * Copyright (c) 1993 by Sven Delmas + * All rights reserved. + * See the file COPYRIGHT for the copyright notes. + * + * + * This source is based upon the file tkCanvLine.c from: + * + * John Ousterhout + * + * Copyright (c) 1992-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. + */ + +/* 05may96 wmt: converted to tk4.1 */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include "tkInt.h" +#include "tkCanvas.h" +/* #include "tkConfig.h" 05nov95 wmt */ +#include "tkPort.h" + +#ifdef _MSC_VER +#define F_OK 0 +#endif + +/* + * The structure below defines the record for each edge item. + */ +typedef struct EdgeItem { + Tk_Item header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + Tk_Canvas canvas; /* Canvas containing item. Needed for + * parsing arrow shapes. a register variable */ + int numPoints; /* Number of points in edge (always >= 2). */ + double *coordPtr; /* Pointer to malloc-ed array containing + * x- and y-coords of all points in edge. + * X-coords are even-valued indices, y-coords + * are corresponding odd-valued indices. If + * the edge has arrowheads then the first + * and last points have been adjusted to refer + * to the necks of the arrowheads rather than + * their tips. The actual endpoints are + * stored in the *firstArrowPtr and + * *lastArrowPtr, if they exist. */ + + char *label; /* Label to display. */ + char *menu1; /* Standard menu for item, usually + * activated with button-3. */ + char *menu2; /* Alternative menu for item, usually + * activated with meta-button-3. */ + char *menu3; /* Alternative menu for item, usually + * activated with control-button-3. */ + char *name; /* Name for item. */ + char *state; /* State of item, this value is used + * to represent the selection status + * (normal, selected). */ + char *graphName; /* Name of the Graph. */ + char *from; /* From icon id. */ + char *to; /* To icon id. */ + Tk_Font tkfont; /* Font for drawing text. */ + Tk_TextLayout textLayout; /* Cached text layout information. */ + Tk_Justify justify; /* Justification to use for text within + * window. */ + + int width; /* Width of edge. */ + int textHeight; /* Height of text label in points. */ + int textWidth; /* Width of text label in points. */ + XColor *fgColor; /* Foreground color for edge. */ + XColor *bgColor; /* Background color to use for icon. */ + Pixmap fillStipple; /* Stipple bitmap for filling edge. */ + int capStyle; /* Cap style for edge. */ + int joinStyle; /* Join style for edge. */ + + GC invertedGc; /* Graphics context to use for drawing + * the edge label on screen. */ + GC gc; /* Graphics context for filling edge. */ + Tk_Uid arrow; /* Indicates whether or not to draw arrowheads: + * "none", "first", "last", or "both". */ + float arrowShapeA; /* Distance from tip of arrowhead to center. */ + float arrowShapeB; /* Distance from tip of arrowhead to trailing + * point, measured along shaft. */ + float arrowShapeC; /* Distance of trailing points from outside + * edge of shaft. */ + double *firstArrowPtr; /* Points to array of PTS_IN_ARROW points + * describing polygon for arrowhead at first + * point in edge. First point of arrowhead + * is tip. Malloc'ed. NULL means no arrowhead + * at first point. */ + double *lastArrowPtr; /* Points to polygon for arrowhead at last + * point in edge (PTS_IN_ARROW points, first + * of which is tip). Malloc'ed. NULL means + * no arrowhead at last point. */ + int smooth; /* Non-zero means draw edge smoothed (i.e. + * with Bezier splines). */ + int splineSteps; /* Number of steps in each spline segment. */ +} EdgeItem; + +/* + * Number of points in an arrowHead: + */ +#define PTS_IN_ARROW 6 + +/* + * Prototypes for procedures defined in this file: + */ +static int ArrowheadPostscript _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, EdgeItem *edgePtr, + double *arrowPtr)); +static void ComputeEdgeBbox _ANSI_ARGS_((Tk_Canvas canvas, + EdgeItem *edgePtr)); +static int ConfigureEdge _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int argc, + char **argv, int flags)); +static int ConfigureArrows _ANSI_ARGS_((Tk_Canvas canvas, + EdgeItem *edgePtr)); +static int CreateEdge _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, struct Tk_Item *itemPtr, + int argc, char **argv)); +static void DeleteEdge _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, Display *display)); +static void DisplayEdge _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, Display *display, Drawable dst, + int x, int y, int width, int height)); +static int EdgeCoords _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, + int argc, char **argv)); +static int EdgeToArea _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, double *rectPtr)); +static double EdgeToPoint _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, double *coordPtr)); +static int EdgeToPostscript _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); +static int ParseArrowShape _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, char *value, + char *recordPtr, int offset)); +static char * PrintArrowShape _ANSI_ARGS_((ClientData clientData, + Tk_Window tkwin, char *recordPtr, int offset, + Tcl_FreeProc **freeProcPtr)); +static void ScaleEdge _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, double originX, double originY, + double scaleX, double scaleY)); +static void TranslateEdge _ANSI_ARGS_((Tk_Canvas canvas, + Tk_Item *itemPtr, double deltaX, double deltaY)); + +/* + * Information used for parsing configuration specs. If you change any + * of the default strings, be sure to change the corresponding default + * values in CreateEdge. + */ +static Tk_CustomOption arrowShapeOption = +{ ParseArrowShape, PrintArrowShape, (ClientData) NULL}; + +static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, + Tk_CanvasTagsPrintProc, (ClientData) NULL}; + +static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_UID, "-arrow", (char *) NULL, (char *) NULL, + "none", Tk_Offset(EdgeItem, arrow), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-arrowshape", (char *) NULL, (char *) NULL, + "8 10 3", Tk_Offset(EdgeItem, arrowShapeA), + TK_CONFIG_DONT_SET_DEFAULT, &arrowShapeOption}, + {TK_CONFIG_COLOR, "-background", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(EdgeItem, bgColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CAP_STYLE, "-capstyle", (char *) NULL, (char *) NULL, + "butt", Tk_Offset(EdgeItem, capStyle), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL, + "black", Tk_Offset(EdgeItem, fgColor), TK_CONFIG_NULL_OK}, + {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, + "Helvetica 12 bold", Tk_Offset(EdgeItem, tkfont), 0}, + {TK_CONFIG_STRING, "-from", (char *) NULL, (char *) NULL, + "", Tk_Offset(EdgeItem, from), 0}, + {TK_CONFIG_STRING, "-graphname", (char *) NULL, (char *) NULL, + "", Tk_Offset(EdgeItem, graphName), 0}, + {TK_CONFIG_JOIN_STYLE, "-joinstyle", (char *) NULL, (char *) NULL, + "round", Tk_Offset(EdgeItem, joinStyle), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_STRING, "-label", (char *) NULL, (char *) NULL, + "", Tk_Offset(EdgeItem, label), 0}, + {TK_CONFIG_STRING, "-menu1", (char *) NULL, (char *) NULL, + "", Tk_Offset(EdgeItem, menu1), 0}, + {TK_CONFIG_STRING, "-menu2", (char *) NULL, (char *) NULL, + "", Tk_Offset(EdgeItem, menu2), 0}, + {TK_CONFIG_STRING, "-menu3", (char *) NULL, (char *) NULL, + "", Tk_Offset(EdgeItem, menu3), 0}, + {TK_CONFIG_STRING, "-name", (char *) NULL, (char *) NULL, + "", Tk_Offset(EdgeItem, name), 0}, + {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL, + "0", Tk_Offset(EdgeItem, smooth), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL, + "12", Tk_Offset(EdgeItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_STRING, "-state", (char *) NULL, (char *) NULL, + "", Tk_Offset(EdgeItem, state), 0}, + {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(EdgeItem, fillStipple), TK_CONFIG_NULL_OK}, + {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, + (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, + {TK_CONFIG_PIXELS, "-textheight", (char *) NULL, (char *) NULL, + "0", Tk_Offset(EdgeItem, textHeight), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_PIXELS, "-textwidth", (char *) NULL, (char *) NULL, + "0", Tk_Offset(EdgeItem, textWidth), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_STRING, "-to", (char *) NULL, (char *) NULL, + "", Tk_Offset(EdgeItem, to), 0}, + {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, + "1", Tk_Offset(EdgeItem, width), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", + "left", Tk_Offset(EdgeItem, justify), 0}, + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0} +}; + +/* + * The structures below defines the edge item type by means + * of procedures that can be invoked by generic item code. + */ +Tk_ItemType tkEdgeType = { + "edge", /* name */ + sizeof(EdgeItem), /* itemSize */ + CreateEdge, /* createProc */ + configSpecs, /* configSpecs */ + ConfigureEdge, /* configureProc */ + EdgeCoords, /* coordProc */ + DeleteEdge, /* deleteProc */ + DisplayEdge, /* displayProc */ + 0, /* alwaysRedraw */ + EdgeToPoint, /* pointProc */ + EdgeToArea, /* areaProc */ + EdgeToPostscript, /* postscriptProc */ + ScaleEdge, /* scaleProc */ + TranslateEdge, /* 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 */ +}; + +/* + * The Tk_Uid's below refer to uids for the various arrow types: + */ +static Tk_Uid noneUid = NULL; +static Tk_Uid firstUid = NULL; +static Tk_Uid lastUid = NULL; +static Tk_Uid bothUid = NULL; + +/* + * The definition below determines how large are static arrays + * used to hold spline points (splines larger than this have to + * have their arrays malloc-ed). + */ +#define MAX_STATIC_POINTS 200 + +/* + *-------------------------------------------------------------- + * + * CreateEdge -- + * + * This procedure is invoked to create a new edge 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 edge item is created. + * + *-------------------------------------------------------------- + */ + +static int +CreateEdge(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 edge. */ +{ + EdgeItem *edgePtr = (EdgeItem *) itemPtr; + int i; + + if (argc < 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tk_PathName(Tk_CanvasTkwin(canvas)), "\" create ", + itemPtr->typePtr->name, + " x1 y1 x2 y2 ?x3 y3 ...? ?options?", + (char *) NULL); + return TCL_ERROR; + } + + /* + * Carry out initialization that is needed to set defaults and to + * allow proper cleanup after errors during the the remainder of + * this procedure. + */ + edgePtr->bgColor = None; + edgePtr->canvas = canvas; + edgePtr->capStyle = CapButt; + edgePtr->coordPtr = NULL; + edgePtr->fgColor = None; + edgePtr->fillStipple = None; + edgePtr->tkfont = NULL; + edgePtr->from = NULL; + edgePtr->graphName = NULL; + edgePtr->joinStyle = JoinRound; + edgePtr->label = NULL; + edgePtr->menu1 = NULL; + edgePtr->menu2 = NULL; + edgePtr->menu3 = NULL; + edgePtr->name = NULL; + edgePtr->numPoints = 0; + edgePtr->smooth = 0; + edgePtr->splineSteps = 12; + edgePtr->state = NULL; + edgePtr->textWidth = 0; + edgePtr->to = NULL; + edgePtr->width = 1; + edgePtr->textLayout = NULL; + edgePtr->justify = TK_JUSTIFY_LEFT; + + edgePtr->invertedGc = None; + edgePtr->gc = None; + if (noneUid == NULL) { + noneUid = Tk_GetUid("none"); + firstUid = Tk_GetUid("first"); + lastUid = Tk_GetUid("last"); + bothUid = Tk_GetUid("both"); + } + edgePtr->arrow = noneUid; + edgePtr->arrowShapeA = 8.0; + edgePtr->arrowShapeB = 10.0; + edgePtr->arrowShapeC = 3.0; + edgePtr->firstArrowPtr = NULL; + edgePtr->lastArrowPtr = NULL; + + /* + * Count the number of points and then parse them into a point + * array. Leading arguments are assumed to be points if they + * start with a digit or a minus sign followed by a digit. + */ + + for (i = 4; i < (argc-1); i+=2) { + if ((!isdigit(UCHAR(argv[i][0]))) && + ((argv[i][0] != '-') || (!isdigit(UCHAR(argv[i][1]))))) { + break; + } + } + if (EdgeCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) { + goto error; + } + if (ConfigureEdge(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { + return TCL_OK; + } + + error: + DeleteEdge(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * EdgeCoords -- + * + * This procedure is invoked to process the "coords" widget + * command on edges. 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 +EdgeCoords(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, ... */ +{ + EdgeItem *edgePtr = (EdgeItem *) itemPtr; + char buffer[TCL_DOUBLE_SPACE]; + int i, numPoints; + + if (argc == 0) { + double *coordPtr; + int numCoords; + + numCoords = 2*edgePtr->numPoints; + if (edgePtr->firstArrowPtr != NULL) { + coordPtr = edgePtr->firstArrowPtr; + } else { + coordPtr = edgePtr->coordPtr; + } + for (i = 0; i < numCoords; i++, coordPtr++) { + if (i == 2) { + coordPtr = edgePtr->coordPtr+2; + } + if ((edgePtr->lastArrowPtr != NULL) && (i == (numCoords-2))) { + coordPtr = edgePtr->lastArrowPtr; + } + Tcl_PrintDouble(interp, *coordPtr, buffer); + Tcl_AppendElement(interp, buffer); + } + } else if (argc < 4) { + Tcl_AppendResult(interp, + "too few coordinates for edge: must have at least 4", + (char *) NULL); + return TCL_ERROR; + } else if (argc & 1) { + Tcl_AppendResult(interp, + "odd number of coordinates specified for edge", + (char *) NULL); + return TCL_ERROR; + } else { + numPoints = argc/2; + if (edgePtr->numPoints != numPoints) { + if (edgePtr->coordPtr != NULL) { + ckfree((char *) edgePtr->coordPtr); + } + edgePtr->coordPtr = (double *) ckalloc((unsigned) + (sizeof(double) * argc)); + edgePtr->numPoints = numPoints; + } + for (i = argc-1; i >= 0; i--) { + if (Tk_CanvasGetCoord(interp, canvas, argv[i], &edgePtr->coordPtr[i]) + != TCL_OK) { + return TCL_ERROR; + } + } + + /* + * Update arrowheads by throwing away any existing arrow-head + * information and calling ConfigureArrows to recompute it. + */ + + if (edgePtr->firstArrowPtr != NULL) { + ckfree((char *) edgePtr->firstArrowPtr); + edgePtr->firstArrowPtr = NULL; + } + if (edgePtr->lastArrowPtr != NULL) { + ckfree((char *) edgePtr->lastArrowPtr); + edgePtr->lastArrowPtr = NULL; + } + if (edgePtr->arrow != noneUid) { + ConfigureArrows(canvas, edgePtr); + } + ComputeEdgeBbox(canvas, edgePtr); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ConfigureEdge -- + * + * This procedure is invoked to configure various aspects + * of a edge 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, such as colors and stipple + * patterns, may be set for itemPtr. + * + *-------------------------------------------------------------- + */ + +static int +ConfigureEdge(interp, canvas, itemPtr, argc, argv, flags) + Tcl_Interp *interp; /* Used for error reporting. */ + Tk_Canvas canvas; /* Canvas containing itemPtr. */ + Tk_Item *itemPtr; /* Edge 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. */ +{ + EdgeItem *edgePtr = (EdgeItem *) itemPtr; + XGCValues gcValues; + GC newGC; + unsigned long mask; + char *value, *fullName, **list; + int counter, listCounter = 0; + Tcl_DString varName, fileName, buffer; + Tk_Window tkwin; + Tk_3DBorder bgBorder; + + tkwin = Tk_CanvasTkwin(canvas); + bgBorder = ((TkCanvas *) canvas)->bgBorder; + + if (Tk_ConfigureWidget(interp, tkwin, + configSpecs, argc, argv, + (char *) edgePtr, flags) != TCL_OK) { + return TCL_ERROR; + } + + /* + * A few of the options require additional processing, such as + * graphics contexts. + */ + + /* the normal gc */ + if (edgePtr->fgColor == NULL) { + newGC = None; + } else { + mask = GCBackground|GCForeground|GCJoinStyle|GCLineWidth; + if (edgePtr->bgColor != NULL) { + gcValues.background = edgePtr->bgColor->pixel; + } else { + gcValues.background = Tk_3DBorderColor(bgBorder)->pixel; + } + gcValues.foreground = edgePtr->fgColor->pixel; + gcValues.join_style = edgePtr->joinStyle; + if (edgePtr->width < 0) { + edgePtr->width = 1; + } + gcValues.line_width = edgePtr->width; + if (edgePtr->fillStipple != None) { + gcValues.stipple = edgePtr->fillStipple; + gcValues.fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } + if (edgePtr->arrow == noneUid) { + gcValues.cap_style = edgePtr->capStyle; + mask |= GCCapStyle; + } + if (edgePtr->tkfont != NULL) { + gcValues.font = Tk_FontId(edgePtr->tkfont); + mask |= GCFont; + } + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } + if (edgePtr->gc != None) { + Tk_FreeGC(((TkCanvas *) canvas)->display, edgePtr->gc); + } + edgePtr->gc = newGC; + + /* the inverted gc */ + if (edgePtr->fgColor == NULL) { + newGC = None; + } else { + mask = GCForeground | GCBackground; + gcValues.background = edgePtr->fgColor->pixel; + if (edgePtr->bgColor != NULL) { + gcValues.foreground = edgePtr->bgColor->pixel; + } else { + gcValues.foreground = Tk_3DBorderColor(bgBorder)->pixel; + } + if (edgePtr->tkfont != NULL) { + gcValues.font = Tk_FontId(edgePtr->tkfont); + mask |= GCFont; + } + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } + if (edgePtr->invertedGc != None) { + Tk_FreeGC(((TkCanvas *) canvas)->display, edgePtr->invertedGc); + } + edgePtr->invertedGc = newGC; + + /* + * Keep spline parameters within reasonable limits. + */ + if (edgePtr->splineSteps < 1) { + edgePtr->splineSteps = 1; + } else if (edgePtr->splineSteps > 100) { + edgePtr->splineSteps = 100; + } + + /* + * Setup arrowheads, if needed. If arrowheads are turned off, + * restore the edge's endpoints (they were shortened when the + * arrowheads were added). + */ + if ((edgePtr->firstArrowPtr != NULL) && (edgePtr->arrow != firstUid) + && (edgePtr->arrow != bothUid)) { + edgePtr->coordPtr[0] = edgePtr->firstArrowPtr[0]; + edgePtr->coordPtr[1] = edgePtr->firstArrowPtr[1]; + ckfree((char *) edgePtr->firstArrowPtr); + edgePtr->firstArrowPtr = NULL; + } + if ((edgePtr->lastArrowPtr != NULL) && (edgePtr->arrow != lastUid) + && (edgePtr->arrow != bothUid)) { + int index; + + index = 2*(edgePtr->numPoints-1); + edgePtr->coordPtr[index] = edgePtr->lastArrowPtr[0]; + edgePtr->coordPtr[index+1] = edgePtr->lastArrowPtr[1]; + ckfree((char *) edgePtr->lastArrowPtr); + edgePtr->lastArrowPtr = NULL; + } + if (edgePtr->arrow != noneUid) { + if ((edgePtr->arrow != firstUid) && (edgePtr->arrow != lastUid) + && (edgePtr->arrow != bothUid)) { + Tcl_AppendResult(interp, "bad arrow spec \"", + edgePtr->arrow, + "\": must be none, first, last, or both", + (char *) NULL); + edgePtr->arrow = noneUid; + return TCL_ERROR; + } + ConfigureArrows(canvas, edgePtr); + } + + /* Calculate the text width & height in points. */ + Tk_FreeTextLayout(edgePtr->textLayout); + edgePtr->textLayout = Tk_ComputeTextLayout(edgePtr->tkfont, + edgePtr->label, + strlen (edgePtr->label), + edgePtr->width, + edgePtr->justify, + 0, &edgePtr->textWidth, &edgePtr->textHeight); + + /* do we have a menu ? */ + if (edgePtr->menu1 != NULL && strlen(edgePtr->menu1) > (size_t) 0 && + edgePtr->menu1[0] != '.') { + /* do we have to load the new menu definition ? */ + (void) Tcl_VarEval(interp, "info commands .emenu-", + edgePtr->menu1, (char *) NULL); + if (strlen(interp->result) == 0) { + /* the following code retrieves the path list for the menus. This */ + /* is done because I don't want to attatch the pathname list to */ + /* each icon. */ + Tcl_DStringInit(&varName); + Tcl_DStringAppend(&varName, "ip_priv(", -1); + Tcl_DStringAppend(&varName, Tk_PathName(tkwin), -1); + Tcl_DStringAppend(&varName, ",edgemenupath)", -1); + if ((value = Tcl_GetVar(interp, varName.string, + TCL_GLOBAL_ONLY)) != NULL) { + if (Tcl_SplitList(interp, value, &listCounter, + &list) == TCL_OK) { + /* walk through list of pathnames. */ + for (counter = 0; counter < listCounter; counter++) { + /* create the filename to load. */ + Tcl_DStringInit(&fileName); + Tcl_DStringAppend(&fileName, list[counter], -1); + Tcl_DStringAppend(&fileName, "/", -1); + Tcl_DStringAppend(&fileName, edgePtr->menu1, -1); + Tcl_DStringAppend(&fileName, ".emenu", -1); + Tcl_DStringInit(&buffer); + fullName = Tcl_TildeSubst(interp, + fileName.string, &buffer); + if (access(fullName, F_OK) != -1) { + /* load new menu. */ + Tcl_VarEval(interp, "source ", fullName, + (char *) NULL); + } + Tcl_DStringFree(&fileName); + Tcl_DStringFree(&buffer); + } + ckfree((char *) list); + } + } + Tcl_DStringFree(&varName); + } + } + + /* do we have a menu ? */ + if (edgePtr->menu2 != NULL && strlen(edgePtr->menu2) > (size_t) 0 && + edgePtr->menu2[0] != '.') { + /* do we have to load the new menu definition ? */ + (void) Tcl_VarEval(interp, "info commands .emenu-", + edgePtr->menu2, (char *) NULL); + if (strlen(interp->result) == 0) { + /* the following code retrieves the path list for the menus. This */ + /* is done because I don't want to attatch the pathname list to */ + /* each icon. */ + Tcl_DStringInit(&varName); + Tcl_DStringAppend(&varName, "ip_priv(", -1); + Tcl_DStringAppend(&varName, Tk_PathName(tkwin), -1); + Tcl_DStringAppend(&varName, ",edgemenupath)", -1); + if ((value = Tcl_GetVar(interp, varName.string, + TCL_GLOBAL_ONLY)) != NULL) { + if (Tcl_SplitList(interp, value, &listCounter, + &list) == TCL_OK) { + /* walk through list of pathnames. */ + for (counter = 0; counter < listCounter; counter++) { + /* create the filename to load. */ + Tcl_DStringInit(&fileName); + Tcl_DStringAppend(&fileName, list[counter], -1); + Tcl_DStringAppend(&fileName, "/", -1); + Tcl_DStringAppend(&fileName, edgePtr->menu2, -1); + Tcl_DStringAppend(&fileName, ".emenu", -1); + Tcl_DStringInit(&buffer); + fullName = Tcl_TildeSubst(interp, + fileName.string, &buffer); + if (access(fullName, F_OK) != -1) { + /* load new menu. */ + Tcl_VarEval(interp, "source ", fullName, + (char *) NULL); + } + Tcl_DStringFree(&fileName); + Tcl_DStringFree(&buffer); + } + ckfree((char *) list); + } + } + Tcl_DStringFree(&varName); + } + } + + /* do we have a menu ? */ + if (edgePtr->menu3 != NULL && strlen(edgePtr->menu3) > (size_t) 0 && + edgePtr->menu3[0] != '.') { + /* do we have to load the new menu definition ? */ + (void) Tcl_VarEval(interp, "info commands .emenu-", + edgePtr->menu3, (char *) NULL); + if (strlen(interp->result) == 0) { + /* the following code retrieves the path list for the menus. This */ + /* is done because I don't want to attatch the pathname list to */ + /* each icon. */ + Tcl_DStringInit(&varName); + Tcl_DStringAppend(&varName, "ip_priv(", -1); + Tcl_DStringAppend(&varName, Tk_PathName(tkwin), -1); + Tcl_DStringAppend(&varName, ",edgemenupath)", -1); + if ((value = Tcl_GetVar(interp, varName.string, + TCL_GLOBAL_ONLY)) != NULL) { + if (Tcl_SplitList(interp, value, &listCounter, + &list) == TCL_OK) { + /* walk through list of pathnames. */ + for (counter = 0; counter < listCounter; counter++) { + /* create the filename to load. */ + Tcl_DStringInit(&fileName); + Tcl_DStringAppend(&fileName, list[counter], -1); + Tcl_DStringAppend(&fileName, "/", -1); + Tcl_DStringAppend(&fileName, edgePtr->menu3, -1); + Tcl_DStringAppend(&fileName, ".emenu", -1); + Tcl_DStringInit(&buffer); + fullName = Tcl_TildeSubst(interp, + fileName.string, &buffer); + if (access(fullName, F_OK) != -1) { + /* load new menu. */ + Tcl_VarEval(interp, "source ", fullName, + (char *) NULL); + } + Tcl_DStringFree(&fileName); + Tcl_DStringFree(&buffer); + } + ckfree((char *) list); + } + } + Tcl_DStringFree(&varName); + } + } + + /* + * Recompute bounding box for edge. + */ + + ComputeEdgeBbox(canvas, edgePtr); + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * DeleteEdge -- + * + * This procedure is called to clean up the data structure + * associated with a edge item. + * + * Results: + * None. + * + * Side effects: + * Resources associated with itemPtr are released. + * + *-------------------------------------------------------------- + */ + +static void +DeleteEdge(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. */ +{ + EdgeItem *edgePtr = (EdgeItem *) itemPtr; + + if (edgePtr->bgColor != NULL) { + Tk_FreeColor(edgePtr->bgColor); + } + if (edgePtr->coordPtr != NULL) { + ckfree((char *) edgePtr->coordPtr); + } + if (edgePtr->fgColor != NULL) { + Tk_FreeColor(edgePtr->fgColor); + } + if (edgePtr->fillStipple != None) { + Tk_FreeBitmap(display, edgePtr->fillStipple); + } + if (edgePtr->tkfont != NULL) { + Tk_FreeFont(edgePtr->tkfont); + } + if (edgePtr->from != NULL) { + ckfree(edgePtr->from); + } + if (edgePtr->graphName != NULL) { + ckfree(edgePtr->graphName); + } + if (edgePtr->label != NULL) { + ckfree(edgePtr->label); + } + if (edgePtr->menu1 != NULL) { + ckfree(edgePtr->menu1); + } + if (edgePtr->menu2 != NULL) { + ckfree(edgePtr->menu2); + } + if (edgePtr->menu3 != NULL) { + ckfree(edgePtr->menu3); + } + if (edgePtr->name != NULL) { + ckfree(edgePtr->name); + } + if (edgePtr->state != NULL) { + ckfree(edgePtr->state); + } + if (edgePtr->to != NULL) { + ckfree(edgePtr->to); + } + + if (edgePtr->invertedGc != None) { + Tk_FreeGC(display, edgePtr->invertedGc); + } + if (edgePtr->gc != None) { + Tk_FreeGC(display, edgePtr->gc); + } + if (edgePtr->firstArrowPtr != NULL) { + ckfree((char *) edgePtr->firstArrowPtr); + } + if (edgePtr->lastArrowPtr != NULL) { + ckfree((char *) edgePtr->lastArrowPtr); + } + if (edgePtr->textLayout != NULL) { + ckfree((char *) edgePtr->textLayout); + } +} + +/* + *-------------------------------------------------------------- + * + * ComputeEdgeBbox -- + * + * This procedure is invoked to compute the bounding box of + * all the pixels that may be drawn as part of a edge. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header + * for itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +ComputeEdgeBbox(canvas, edgePtr) + Tk_Canvas canvas; /* Canvas that contains item. */ + EdgeItem *edgePtr; /* Item whose bbos is to be + * recomputed. */ +{ + double *coordPtr; + int i, lineWidth, lineHeight; + + coordPtr = edgePtr->coordPtr; + edgePtr->header.x1 = edgePtr->header.x2 = *coordPtr; + edgePtr->header.y1 = edgePtr->header.y2 = coordPtr[1]; + + /* + * Compute the bounding box of all the points in the edge, + * then expand in all directions by the edge's width to take + * care of butting or rounded corners and projecting or + * rounded caps. This expansion is an overestimate (worst-case + * is square root of two over two) but it's simple. Don't do + * anything special for curves. This causes an additional + * overestimate in the bounding box, but is faster. + */ + + for (i = 1, coordPtr = edgePtr->coordPtr+2; i < edgePtr->numPoints; + i++, coordPtr += 2) { + TkIncludePoint((Tk_Item *) edgePtr, coordPtr); + } + edgePtr->header.x1 -= edgePtr->width; + edgePtr->header.x2 += edgePtr->width; + edgePtr->header.y1 -= edgePtr->width; + edgePtr->header.y2 += edgePtr->width; + + /* + * For mitered edges, make a second pass through all the points. + * Compute the locations of the two miter vertex points and add + * those into the bounding box. + */ + + if (edgePtr->joinStyle == JoinMiter) { + for (i = edgePtr->numPoints, coordPtr = edgePtr->coordPtr; i >= 3; + i--, coordPtr += 2) { + double miter[4]; + int j; + + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + (double) edgePtr->width, miter, miter+2)) { + for (j = 0; j < 4; j += 2) { + TkIncludePoint((Tk_Item *) edgePtr, miter+j); + } + } + } + } + + /* + * Add in the sizes of arrowheads, if any. + */ + + if (edgePtr->arrow != noneUid) { + if (edgePtr->arrow != lastUid) { + for (i = 0, coordPtr = edgePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint((Tk_Item *) edgePtr, coordPtr); + } + } + if (edgePtr->arrow != firstUid) { + for (i = 0, coordPtr = edgePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkIncludePoint((Tk_Item *) edgePtr, coordPtr); + } + } + } + + /* + * Add one more pixel of fudge factor just to be safe (e.g. + * X may round differently than we do). + */ + + edgePtr->header.x1 -= 1; + edgePtr->header.x2 += 1; + edgePtr->header.y1 -= 1; + edgePtr->header.y2 += 1; + + /* maybe we have a label that is wider than the line */ + if (edgePtr->tkfont != NULL && edgePtr->label != NULL) { + Tk_FreeTextLayout(edgePtr->textLayout); + edgePtr->textLayout = Tk_ComputeTextLayout(edgePtr->tkfont, + edgePtr->label, + strlen (edgePtr->label), + edgePtr->width, + edgePtr->justify, + 0, &lineWidth, &lineHeight); + lineWidth = strlen(edgePtr->label); + if (lineWidth > (edgePtr->header.x2 - edgePtr->header.x2)) { + edgePtr->header.x1 -= + (lineWidth - (edgePtr->header.x2 - edgePtr->header.x2)) / 2; + edgePtr->header.x2 += + (lineWidth - (edgePtr->header.x2 - edgePtr->header.x2)) / 2; + } + if (lineHeight > + (edgePtr->header.y2 - edgePtr->header.y2)) { + edgePtr->header.y1 -= + (lineHeight - (edgePtr->header.y2 - edgePtr->header.y2)) + / 2; + edgePtr->header.y2 += + (lineHeight - (edgePtr->header.y2 - edgePtr->header.y2)) / 2; + } + } +} + +/* + *-------------------------------------------------------------- + * + * DisplayEdge -- + * + * This procedure is invoked to draw a edge item in a given + * drawable. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation + * information in canvas. + * + *-------------------------------------------------------------- + */ + +static void +DisplayEdge(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). */ +{ + EdgeItem *edgePtr = (EdgeItem *) itemPtr; + XPoint staticPoints[MAX_STATIC_POINTS]; + XPoint *pointPtr; + XPoint *pPtr; + register double *coordPtr; + int i, numPoints, lineHeight; + int centerX, centerY, lineWidth; + short drawableX, drawableY; + + if (edgePtr->gc == None) { + return; + } + + /* + * Build up an array of points in screen coordinates. Use a + * static array unless the edge has an enormous number of points; + * in this case, dynamically allocate an array. For smoothed edges, + * generate the curve points on each redisplay. + */ + + if ((edgePtr->smooth) && (edgePtr->numPoints > 2)) { + numPoints = 1 + edgePtr->numPoints*edgePtr->splineSteps; + } else { + numPoints = edgePtr->numPoints; + } + + if (numPoints <= MAX_STATIC_POINTS) { + pointPtr = staticPoints; + } else { + pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint))); + } + + if (edgePtr->smooth) { + numPoints = TkMakeBezierCurve(canvas, edgePtr->coordPtr, + edgePtr->numPoints, + edgePtr->splineSteps, pointPtr, + (double *) NULL); + } else { + for (i = 0, coordPtr = edgePtr->coordPtr, pPtr = pointPtr; + i < edgePtr->numPoints; i += 1, coordPtr += 2, pPtr++) { + Tk_CanvasDrawableCoords(canvas, coordPtr[0], coordPtr[1], + &pPtr->x, &pPtr->y); + } + } + + /* + * Display edge, the free up edge storage if it was dynamically + * allocated. If we're stippling, then modify the stipple offset + * in the GC. Be sure to reset the offset when done, since the + * GC is supposed to be read-only. + */ + + if (edgePtr->fillStipple != None) { + XSetTSOrigin(display, edgePtr->gc, + -((TkCanvas *) canvas)->drawableXOrigin, + -((TkCanvas *) canvas)->drawableYOrigin); + } + XDrawLines(display, drawable, edgePtr->gc, + pointPtr, numPoints, CoordModeOrigin); + if (pointPtr[numPoints-1].x > pointPtr[numPoints-2].x) { + centerX = ((pointPtr[numPoints-1].x - pointPtr[numPoints-2].x) / 2) + + pointPtr[numPoints-2].x; + } else { + centerX = ((pointPtr[numPoints-2].x - pointPtr[numPoints-1].x) / 2) + + pointPtr[numPoints-1].x; + } + if (pointPtr[numPoints-1].y > pointPtr[numPoints-2].y) { + centerY = ((pointPtr[numPoints-1].y - pointPtr[numPoints-2].y) / 2) + + pointPtr[numPoints-2].y; + } else { + centerY = ((pointPtr[numPoints-2].y - pointPtr[numPoints-1].y) / 2) + + pointPtr[numPoints-1].y; + } + if (pointPtr != staticPoints) { + ckfree((char *) pointPtr); + } + + /* + * Display arrowheads, if they are wanted. + */ + + if (edgePtr->arrow != noneUid) { + if (edgePtr->arrow != lastUid) { + TkFillPolygon(canvas, edgePtr->firstArrowPtr, PTS_IN_ARROW, + display, drawable, edgePtr->gc, NULL); + } + if (edgePtr->arrow != firstUid) { + TkFillPolygon(canvas, edgePtr->lastArrowPtr, PTS_IN_ARROW, + display, drawable, edgePtr->gc, NULL); + } + } + if (edgePtr->fillStipple != None) { + XSetTSOrigin(display, edgePtr->gc, 0, 0); + } + + /* display the label */ + if (edgePtr->label != NULL && (size_t) strlen(edgePtr->label) > 0) { + Tk_FreeTextLayout(edgePtr->textLayout); + edgePtr->textLayout = Tk_ComputeTextLayout(edgePtr->tkfont, + edgePtr->label, + strlen (edgePtr->label), + edgePtr->width, + edgePtr->justify, + 0, &lineWidth, &lineHeight); + lineWidth = strlen(edgePtr->label); + if (strcmp(edgePtr->state, "selected") == 0) { + XFillRectangle(display, drawable, + edgePtr->gc, + centerX - (lineWidth / 2) - 1, + centerY - (lineHeight / 2) - 1, + lineWidth + 2, lineHeight + 2); + Tk_CanvasDrawableCoords(canvas, + (double) (edgePtr->header.x1 + x), + (double) (edgePtr->header.y1 + y), + &drawableX, &drawableY); + Tk_DrawTextLayout(display, drawable, edgePtr->gc, + edgePtr->textLayout, + drawableX, drawableY, + 0, -1); + } else { + XFillRectangle(display, drawable, + edgePtr->invertedGc, + centerX - (lineWidth / 2) - 1, + centerY - (lineHeight / 2) - 1, + lineWidth + 2, lineHeight + 2); + Tk_CanvasDrawableCoords(canvas, + (double) (edgePtr->header.x1 + x), + (double) (edgePtr->header.y1 + y), + &drawableX, &drawableY); + Tk_DrawTextLayout(display, drawable, edgePtr->gc, + edgePtr->textLayout, + drawableX, drawableY, + 0, -1); + } + } +} + +/* + *-------------------------------------------------------------- + * + * EdgeToPoint -- + * + * Computes the distance from a given point to a given + * edge, in canvas units. + * + * Results: + * The return value is 0 if the point whose x and y coordinates + * are pointPtr[0] and pointPtr[1] is inside the edge. If the + * point isn't inside the edge then the return value is the + * distance from the point to the edge. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static double +EdgeToPoint(canvas, itemPtr, pointPtr) + Tk_Canvas canvas; /* Canvas containing item. */ + Tk_Item *itemPtr; /* Item to check against point. */ + double *pointPtr; /* Pointer to x and y coordinates. */ +{ + EdgeItem *edgePtr = (EdgeItem *) itemPtr; + register double *coordPtr, *edgePoints; + double staticSpace[2*MAX_STATIC_POINTS]; + double poly[10]; + double bestDist, dist; + int numPoints, count; + int changedMiterToBevel; /* Non-zero means that a mitered corner + * had to be treated as beveled after all + * because the angle was < 11 degrees. */ + + bestDist = 1.0e40; + + /* + * Handle smoothed edges by generating an expanded set of points + * against which to do the check. + */ + + if ((edgePtr->smooth) && (edgePtr->numPoints > 2)) { + numPoints = 1 + edgePtr->numPoints*edgePtr->splineSteps; + if (numPoints <= MAX_STATIC_POINTS) { + edgePoints = staticSpace; + } else { + edgePoints = (double *) ckalloc((unsigned) + (2*numPoints*sizeof(double))); + } + numPoints = TkMakeBezierCurve(canvas, edgePtr->coordPtr, + edgePtr->numPoints, + edgePtr->splineSteps, (XPoint *) NULL, + edgePoints); + } else { + numPoints = edgePtr->numPoints; + edgePoints = edgePtr->coordPtr; + } + + /* + * The overall idea is to iterate through all of the edges of + * the edge, computing a polygon for each edge and testing the + * point against that polygon. In addition, there are additional + * tests to deal with rounded joints and caps. + */ + + changedMiterToBevel = 0; + for (count = numPoints, coordPtr = edgePoints; count >= 2; + count--, coordPtr += 2) { + + /* + * If rounding is done around the first point then compute + * the distance between the point and the point. + */ + + if (((edgePtr->capStyle == CapRound) && (count == numPoints)) + || ((edgePtr->joinStyle == JoinRound) + && (count != numPoints))) { + dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) + - edgePtr->width/2.0; + if (dist <= 0.0) { + bestDist = 0.0; + goto done; + } else if (dist < bestDist) { + bestDist = dist; + } + } + + /* + * Compute the polygonal shape corresponding to this edge, + * consisting of two points for the first point of the edge + * and two points for the last point of the edge. + */ + + if (count == numPoints) { + TkGetButtPoints(coordPtr+2, coordPtr, (double) edgePtr->width, + edgePtr->capStyle == CapProjecting, poly, poly+2); + } else if ((edgePtr->joinStyle == JoinMiter) && !changedMiterToBevel) { + poly[0] = poly[6]; + poly[1] = poly[7]; + poly[2] = poly[4]; + poly[3] = poly[5]; + } else { + TkGetButtPoints(coordPtr+2, coordPtr, (double) edgePtr->width, 0, + poly, poly+2); + + /* + * If this edge uses beveled joints, then check the distance + * to a polygon comprising the last two points of the previous + * polygon and the first two from this polygon; this checks + * the wedges that fill the mitered joint. + */ + + if ((edgePtr->joinStyle == JoinBevel) || changedMiterToBevel) { + poly[8] = poly[0]; + poly[9] = poly[1]; + dist = TkPolygonToPoint(poly, 5, pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto done; + } else if (dist < bestDist) { + bestDist = dist; + } + changedMiterToBevel = 0; + } + } + if (count == 2) { + TkGetButtPoints(coordPtr, coordPtr+2, (double) edgePtr->width, + edgePtr->capStyle == CapProjecting, poly+4, poly+6); + } else if (edgePtr->joinStyle == JoinMiter) { + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + (double) edgePtr->width, poly+4, poly+6) == 0) { + changedMiterToBevel = 1; + TkGetButtPoints(coordPtr, coordPtr+2, (double) edgePtr->width, + 0, poly+4, poly+6); + } + } else { + TkGetButtPoints(coordPtr, coordPtr+2, (double) edgePtr->width, 0, + poly+4, poly+6); + } + poly[8] = poly[0]; + poly[9] = poly[1]; + dist = TkPolygonToPoint(poly, 5, pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto done; + } else if (dist < bestDist) { + bestDist = dist; + } + } + + /* + * If caps are rounded, check the distance to the cap around the + * final end point of the edge. + */ + + if (edgePtr->capStyle == CapRound) { + dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) + - edgePtr->width/2.0; + if (dist <= 0.0) { + bestDist = 0.0; + goto done; + } else if (dist < bestDist) { + bestDist = dist; + } + } + + /* + * If there are arrowheads, check the distance to the arrowheads. + */ + + if (edgePtr->arrow != noneUid) { + if (edgePtr->arrow != lastUid) { + dist = TkPolygonToPoint(edgePtr->firstArrowPtr, PTS_IN_ARROW, + pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto done; + } else if (dist < bestDist) { + bestDist = dist; + } + } + if (edgePtr->arrow != firstUid) { + dist = TkPolygonToPoint(edgePtr->lastArrowPtr, PTS_IN_ARROW, + pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto done; + } else if (dist < bestDist) { + bestDist = dist; + } + } + } + + done: + if ((edgePoints != staticSpace) && (edgePoints != edgePtr->coordPtr)) { + ckfree((char *) edgePoints); + } + return bestDist; +} + +/* + *-------------------------------------------------------------- + * + * EdgeToArea -- + * + * This procedure is called to determine whether an item + * lies entirely inside, entirely outside, or overlapping + * a given rectangular area. + * + * Results: + * -1 is returned if the item is entirely outside the + * area, 0 if it overlaps, and 1 if it is entirely + * inside the given area. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +EdgeToArea(canvas, itemPtr, rectPtr) + Tk_Canvas canvas; /* Canvas containing item. */ + Tk_Item *itemPtr; /* Item to check against edge. */ + double *rectPtr; +{ + EdgeItem *edgePtr = (EdgeItem *) itemPtr; + register double *coordPtr; + double staticSpace[2*MAX_STATIC_POINTS]; + double *edgePoints, poly[10]; + double radius; + int numPoints, count; + int changedMiterToBevel; /* Non-zero means that a mitered corner + * had to be treated as beveled after all + * because the angle was < 11 degrees. */ + int inside; /* Tentative guess about what to return, + * based on all points seen so far: one + * means everything seen so far was + * inside the area; -1 means everything + * was outside the area. 0 means overlap + * has been found. */ + + radius = edgePtr->width/2.0; + inside = -1; + + /* + * Handle smoothed edges by generating an expanded set of points + * against which to do the check. + */ + + if ((edgePtr->smooth) && (edgePtr->numPoints > 2)) { + numPoints = 1 + edgePtr->numPoints*edgePtr->splineSteps; + if (numPoints <= MAX_STATIC_POINTS) { + edgePoints = staticSpace; + } else { + edgePoints = (double *) ckalloc((unsigned) + (2*numPoints*sizeof(double))); + } + numPoints = TkMakeBezierCurve(canvas, edgePtr->coordPtr, + edgePtr->numPoints, + edgePtr->splineSteps, (XPoint *) NULL, + edgePoints); + } else { + numPoints = edgePtr->numPoints; + edgePoints = edgePtr->coordPtr; + } + + coordPtr = edgePoints; + if ((coordPtr[0] >= rectPtr[0]) && (coordPtr[0] <= rectPtr[2]) + && (coordPtr[1] >= rectPtr[1]) && (coordPtr[1] <= rectPtr[3])) { + inside = 1; + } + + /* + * Iterate through all of the edges of the edge, computing a polygon + * for each edge and testing the area against that polygon. In + * addition, there are additional tests to deal with rounded joints + * and caps. + */ + + changedMiterToBevel = 0; + for (count = numPoints; count >= 2; count--, coordPtr += 2) { + + /* + * If rounding is done around the first point of the edge + * then test a circular region around the point with the + * area. + */ + + if (((edgePtr->capStyle == CapRound) && (count == numPoints)) + || ((edgePtr->joinStyle == JoinRound) + && (count != numPoints))) { + poly[0] = coordPtr[0] - radius; + poly[1] = coordPtr[1] - radius; + poly[2] = coordPtr[0] + radius; + poly[3] = coordPtr[1] + radius; + if (TkOvalToArea(poly, rectPtr) != inside) { + inside = 0; + goto done; + } + } + + /* + * Compute the polygonal shape corresponding to this edge, + * consisting of two points for the first point of the edge + * and two points for the last point of the edge. + */ + + if (count == numPoints) { + TkGetButtPoints(coordPtr+2, coordPtr, (double) edgePtr->width, + edgePtr->capStyle == CapProjecting, poly, poly+2); + } else if ((edgePtr->joinStyle == JoinMiter) && !changedMiterToBevel) { + poly[0] = poly[6]; + poly[1] = poly[7]; + poly[2] = poly[4]; + poly[3] = poly[5]; + } else { + TkGetButtPoints(coordPtr+2, coordPtr, (double) edgePtr->width, 0, + poly, poly+2); + + /* + * If the last joint was beveled, then also check a + * polygon comprising the last two points of the previous + * polygon and the first two from this polygon; this checks + * the wedges that fill the beveled joint. + */ + + if ((edgePtr->joinStyle == JoinBevel) || changedMiterToBevel) { + poly[8] = poly[0]; + poly[9] = poly[1]; + if (TkPolygonToArea(poly, 5, rectPtr) != inside) { + inside = 0; + goto done; + } + changedMiterToBevel = 0; + } + } + if (count == 2) { + TkGetButtPoints(coordPtr, coordPtr+2, (double) edgePtr->width, + edgePtr->capStyle == CapProjecting, poly+4, poly+6); + } else if (edgePtr->joinStyle == JoinMiter) { + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + (double) edgePtr->width, poly+4, poly+6) == 0) { + changedMiterToBevel = 1; + TkGetButtPoints(coordPtr, coordPtr+2, (double) edgePtr->width, + 0, poly+4, poly+6); + } + } else { + TkGetButtPoints(coordPtr, coordPtr+2, (double) edgePtr->width, 0, + poly+4, poly+6); + } + poly[8] = poly[0]; + poly[9] = poly[1]; + if (TkPolygonToArea(poly, 5, rectPtr) != inside) { + inside = 0; + goto done; + } + } + + /* + * If caps are rounded, check the cap around the final point + * of the edge. + */ + + if (edgePtr->capStyle == CapRound) { + poly[0] = coordPtr[0] - radius; + poly[1] = coordPtr[1] - radius; + poly[2] = coordPtr[0] + radius; + poly[3] = coordPtr[1] + radius; + if (TkOvalToArea(poly, rectPtr) != inside) { + inside = 0; + goto done; + } + } + + /* + * Check arrowheads, if any. + */ + + if (edgePtr->arrow != noneUid) { + if (edgePtr->arrow != lastUid) { + if (TkPolygonToArea(edgePtr->firstArrowPtr, PTS_IN_ARROW, + rectPtr) != inside) { + inside = 0; + goto done; + } + } + if (edgePtr->arrow != firstUid) { + if (TkPolygonToArea(edgePtr->lastArrowPtr, PTS_IN_ARROW, + rectPtr) != inside) { + inside = 0; + goto done; + } + } + } + + done: + if ((edgePoints != staticSpace) && (edgePoints != edgePtr->coordPtr)) { + ckfree((char *) edgePoints); + } + return inside; +} + +/* + *-------------------------------------------------------------- + * + * ScaleEdge -- + * + * This procedure is invoked to rescale a edge item. + * + * Results: + * None. + * + * Side effects: + * The edge 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 +ScaleEdge(canvas, itemPtr, originX, originY, scaleX, scaleY) + Tk_Canvas canvas; /* Canvas containing edge. */ + Tk_Item *itemPtr; /* Edge 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. */ +{ + EdgeItem *edgePtr = (EdgeItem *) itemPtr; + double *coordPtr; + int i; + + for (i = 0, coordPtr = edgePtr->coordPtr; i < edgePtr->numPoints; + i++, coordPtr += 2) { + coordPtr[0] = originX + scaleX*(*coordPtr - originX); + coordPtr[1] = originY + scaleY*(coordPtr[1] - originY); + } + if (edgePtr->firstArrowPtr != NULL) { + for (i = 0, coordPtr = edgePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + coordPtr[0] = originX + scaleX*(coordPtr[0] - originX); + coordPtr[1] = originY + scaleY*(coordPtr[1] - originY); + } + } + if (edgePtr->lastArrowPtr != NULL) { + for (i = 0, coordPtr = edgePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + coordPtr[0] = originX + scaleX*(coordPtr[0] - originX); + coordPtr[1] = originY + scaleY*(coordPtr[1] - originY); + } + } + ComputeEdgeBbox(canvas, edgePtr); +} + +/* + *-------------------------------------------------------------- + * + * TranslateEdge -- + * + * This procedure is called to move a edge by a given amount. + * + * Results: + * None. + * + * Side effects: + * The position of the edge is offset by (xDelta, yDelta), and + * the bounding box is updated in the generic part of the item + * structure. + * + *-------------------------------------------------------------- + */ + +static void +TranslateEdge(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. */ +{ + EdgeItem *edgePtr = (EdgeItem *) itemPtr; + double *coordPtr; + int i; + + for (i = 0, coordPtr = edgePtr->coordPtr; i < edgePtr->numPoints; + i++, coordPtr += 2) { + coordPtr[0] += deltaX; + coordPtr[1] += deltaY; + } + if (edgePtr->firstArrowPtr != NULL) { + for (i = 0, coordPtr = edgePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + coordPtr[0] += deltaX; + coordPtr[1] += deltaY; + } + } + if (edgePtr->lastArrowPtr != NULL) { + for (i = 0, coordPtr = edgePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + coordPtr[0] += deltaX; + coordPtr[1] += deltaY; + } + } + ComputeEdgeBbox(canvas, edgePtr); +} + +/* + *-------------------------------------------------------------- + * + * ParseArrowShape -- + * + * This procedure is called back during option parsing to + * parse arrow shape information. + * + * Results: + * The return value is a standard Tcl result: TCL_OK means + * that the arrow shape information was parsed ok, and + * TCL_ERROR means it couldn't be parsed. + * + * Side effects: + * Arrow information in recordPtr is updated. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +ParseArrowShape(clientData, interp, tkwin, value, recordPtr, offset) + ClientData clientData; /* Not used. */ + Tcl_Interp *interp; /* Used for error reporting. */ + Tk_Window tkwin; /* Not used. */ + char *value; /* Textual specification of arrow shape. */ + char *recordPtr; /* Pointer to item record in which to + * store arrow information. */ + int offset; /* Offset of shape information in widget + * record. */ +{ + EdgeItem *edgePtr = (EdgeItem *) recordPtr; + double a, b, c; + int argc; + char **argv = NULL; + + if (offset != Tk_Offset(EdgeItem, arrowShapeA)) { + panic("ParseArrowShape received bogus offset"); + } + + if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) { + syntaxError: + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "bad arrow shape \"", value, + "\": must be list with three numbers", (char *) NULL); + if (argv != NULL) { + ckfree((char *) argv); + } + return TCL_ERROR; + } + if (argc != 3) { + goto syntaxError; + } + if ((Tk_CanvasGetCoord(interp, edgePtr->canvas, argv[0], &a) != TCL_OK) + || (Tk_CanvasGetCoord(interp, edgePtr->canvas, argv[1], &b) != TCL_OK) + || (Tk_CanvasGetCoord(interp, edgePtr->canvas, argv[2], &c) != TCL_OK)) { + goto syntaxError; + } + edgePtr->arrowShapeA = a; + edgePtr->arrowShapeB = b; + edgePtr->arrowShapeC = c; + ckfree((char *) argv); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * PrintArrowShape -- + * + * This procedure is a callback invoked by the configuration + * code to return a printable value describing an arrow shape. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static char * +PrintArrowShape(clientData, tkwin, recordPtr, offset, freeProcPtr) + ClientData clientData; /* Not used. */ + Tk_Window tkwin; /* Window associated with edgePtr's widget. */ + char *recordPtr; /* Pointer to item record containing current + * shape information. */ + int offset; /* Offset of arrow information in record. */ + Tcl_FreeProc **freeProcPtr;/* Store address of procedure to call to + * free string here. */ +{ + EdgeItem *edgePtr = (EdgeItem *) recordPtr; + char *buffer; + + buffer = ckalloc(120); + sprintf(buffer, "%.5g %.5g %.5g", edgePtr->arrowShapeA, + edgePtr->arrowShapeB, edgePtr->arrowShapeC); + *freeProcPtr = (Tcl_FreeProc *) free; + return buffer; +} + +/* + *-------------------------------------------------------------- + * + * ConfigureArrows -- + * + * If arrowheads have been requested for a edge, this + * procedure makes arrangements for the arrowheads. + * + * Results: + * A standard Tcl return value. If an error occurs, then + * an error message is left in interp->result. + * + * Side effects: + * Information in edgePtr is set up for one or two arrowheads. + * the firstArrowPtr and lastArrowPtr polygons are allocated + * and initialized, if need be, and the end points of the edge + * are adjusted so that a thick edge doesn't stick out past + * the arrowheads. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +ConfigureArrows(canvas, edgePtr) + Tk_Canvas canvas; /* Canvas in which arrows will be + * displayed (interp and tkwin + * fields are needed). */ + EdgeItem *edgePtr; /* Item to configure for arrows. */ +{ + double *poly, *coordPtr; + double dx, dy, length, sinTheta, cosTheta, temp, shapeC; + double fracHeight; /* Edge width as fraction of + * arrowhead width. */ + double backup; /* Distance to backup end points + * so the edge ends in the middle + * of the arrowhead. */ + double vertX, vertY; /* Position of arrowhead vertex. */ + + /* + * If there's an arrowhead on the first point of the edge, compute + * its polygon and adjust the first point of the edge so that the + * edge doesn't stick out past the leading edge of the arrowhead. + */ + + shapeC = edgePtr->arrowShapeC + edgePtr->width/2.0; + fracHeight = (edgePtr->width/2.0)/shapeC; + backup = fracHeight*edgePtr->arrowShapeB + + edgePtr->arrowShapeA*(1.0 - fracHeight)/2.0; + if (edgePtr->arrow != lastUid) { + poly = edgePtr->firstArrowPtr; + if (poly == NULL) { + poly = (double *) ckalloc((unsigned) + (2*PTS_IN_ARROW*sizeof(double))); + poly[0] = poly[10] = edgePtr->coordPtr[0]; + poly[1] = poly[11] = edgePtr->coordPtr[1]; + edgePtr->firstArrowPtr = poly; + } + dx = poly[0] - edgePtr->coordPtr[2]; + dy = poly[1] - edgePtr->coordPtr[3]; + length = hypot(dx, dy); + if (length == 0) { + sinTheta = cosTheta = 0.0; + } else { + sinTheta = dy/length; + cosTheta = dx/length; + } + vertX = poly[0] - edgePtr->arrowShapeA*cosTheta; + vertY = poly[1] - edgePtr->arrowShapeA*sinTheta; + temp = shapeC*sinTheta; + poly[2] = poly[0] - edgePtr->arrowShapeB*cosTheta + temp; + poly[8] = poly[2] - 2*temp; + temp = shapeC*cosTheta; + poly[3] = poly[1] - edgePtr->arrowShapeB*sinTheta - temp; + poly[9] = poly[3] + 2*temp; + poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight); + poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight); + poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight); + poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight); + + /* + * Polygon done. Now move the first point towards the second so + * that the corners at the end of the edge are inside the + * arrowhead. + */ + + edgePtr->coordPtr[0] = poly[0] - backup*cosTheta; + edgePtr->coordPtr[1] = poly[1] - backup*sinTheta; + } + + /* + * Similar arrowhead calculation for the last point of the edge. + */ + + if (edgePtr->arrow != firstUid) { + coordPtr = edgePtr->coordPtr + 2*(edgePtr->numPoints-2); + poly = edgePtr->lastArrowPtr; + if (poly == NULL) { + poly = (double *) ckalloc((unsigned) + (2*PTS_IN_ARROW*sizeof(double))); + poly[0] = poly[10] = coordPtr[2]; + poly[1] = poly[11] = coordPtr[3]; + edgePtr->lastArrowPtr = poly; + } + dx = poly[0] - coordPtr[0]; + dy = poly[1] - coordPtr[1]; + length = hypot(dx, dy); + if (length == 0) { + sinTheta = cosTheta = 0.0; + } else { + sinTheta = dy/length; + cosTheta = dx/length; + } + vertX = poly[0] - edgePtr->arrowShapeA*cosTheta; + vertY = poly[1] - edgePtr->arrowShapeA*sinTheta; + temp = shapeC*sinTheta; + poly[2] = poly[0] - edgePtr->arrowShapeB*cosTheta + temp; + poly[8] = poly[2] - 2*temp; + temp = shapeC*cosTheta; + poly[3] = poly[1] - edgePtr->arrowShapeB*sinTheta - temp; + poly[9] = poly[3] + 2*temp; + poly[4] = poly[2]*fracHeight + vertX*(1.0-fracHeight); + poly[5] = poly[3]*fracHeight + vertY*(1.0-fracHeight); + poly[6] = poly[8]*fracHeight + vertX*(1.0-fracHeight); + poly[7] = poly[9]*fracHeight + vertY*(1.0-fracHeight); + coordPtr[2] = poly[0] - backup*cosTheta; + coordPtr[3] = poly[1] - backup*sinTheta; + } + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * EdgeToPostscript -- + * + * This procedure is called to generate Postscript for + * edge 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 +EdgeToPostscript(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. */ +{ + register EdgeItem *edgePtr = (EdgeItem *) itemPtr; + char buffer[200]; + char *style; + + if (edgePtr->fgColor == NULL) { + return TCL_OK; + } + + /* + * Generate a path for the edge's center-edge (do this differently + * for straight edges and smoothed edges). + */ + + if (!edgePtr->smooth) { + Tk_CanvasPsPath(interp, canvas, edgePtr->coordPtr, edgePtr->numPoints); + } else { + if (edgePtr->fillStipple == None) { + TkMakeBezierPostscript(interp, canvas, edgePtr->coordPtr, edgePtr->numPoints); + } else { + /* + * Special hack: Postscript printers don't appear to be able + * to turn a path drawn with "curveto"s into a clipping path + * without exceeding resource limits, so TkMakeBezierPostscript + * won't work for stippled curves. Instead, generate all of + * the intermediate points here and output them into the + * Postscript file with "edgeto"s instead. + */ + + double staticPoints[2*MAX_STATIC_POINTS]; + double *pointPtr; + int numPoints; + + numPoints = 1 + edgePtr->numPoints*edgePtr->splineSteps; + pointPtr = staticPoints; + if (numPoints > MAX_STATIC_POINTS) { + pointPtr = (double *) ckalloc((unsigned) + (numPoints * 2 * sizeof(double))); + } + numPoints = TkMakeBezierCurve(canvas, edgePtr->coordPtr, + edgePtr->numPoints, + edgePtr->splineSteps, (XPoint *) NULL, + pointPtr); + Tk_CanvasPsPath(interp, canvas, pointPtr, numPoints); + if (pointPtr != staticPoints) { + ckfree((char *) pointPtr); + } + } + } + + /* + * Set other edge-drawing parameters and stroke out the edge. + */ + + sprintf(buffer, "%d setlinewidth\n", edgePtr->width); + Tcl_AppendResult(interp, buffer, (char *) NULL); + style = "0 setlinecap\n"; + if (edgePtr->capStyle == CapRound) { + style = "1 setlinecap\n"; + } else if (edgePtr->capStyle == CapProjecting) { + style = "2 setlinecap\n"; + } + Tcl_AppendResult(interp, style, (char *) NULL); + style = "0 setlinejoin\n"; + if (edgePtr->joinStyle == JoinRound) { + style = "1 setlinejoin\n"; + } else if (edgePtr->joinStyle == JoinBevel) { + style = "2 setlinejoin\n"; + } + Tcl_AppendResult(interp, style, (char *) NULL); + if (Tk_CanvasPsColor(interp, canvas, edgePtr->fgColor) != TCL_OK) { + return TCL_ERROR; + }; + if (edgePtr->fillStipple != None) { + if (Tk_CanvasPsStipple(interp, canvas, edgePtr->fillStipple) + != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "stroke\n", (char *) NULL); + } + + /* + * Output polygons for the arrowheads, if there are any. + */ + + if (edgePtr->firstArrowPtr != NULL) { + if (ArrowheadPostscript(interp, canvas, edgePtr, edgePtr->firstArrowPtr) != + TCL_OK) { + return TCL_ERROR; + } + } + if (edgePtr->lastArrowPtr != NULL) { + if (ArrowheadPostscript(interp, canvas, edgePtr, edgePtr->lastArrowPtr) != + TCL_OK) { + return TCL_ERROR; + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ArrowheadPostscript -- + * + * This procedure is called to generate Postscript for + * an arrowhead for a edge item. + * + * 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 + * arrowhead is appended to the result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +ArrowheadPostscript(interp, canvas, edgePtr, arrowPtr) + Tcl_Interp *interp; /* Leave Postscript or error message + * here. */ + Tk_Canvas canvas; /* Information about overall canvas. */ + EdgeItem *edgePtr; /* Edge item for which Postscript is + * being generated. */ + double *arrowPtr; /* Pointer to first of five points + * describing arrowhead polygon. */ +{ + Tk_CanvasPsPath(interp, canvas, arrowPtr, PTS_IN_ARROW); + if (edgePtr->fillStipple != None) { + if (Tk_CanvasPsStipple(interp, canvas, edgePtr->fillStipple) + != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "fill\n", (char *) NULL); + } + return TCL_OK; +}
tkCanvEdge.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tclshellexe.c =================================================================== --- tclshellexe.c (nonexistent) +++ tclshellexe.c (revision 1765) @@ -0,0 +1,76 @@ +/* tclshellexe.c - Interface to Windows ShellExecute function. + Copyright (C) 1997 Cygnus Solutions. + Written by Tom Tromey ; + Code mostly taken from S-N. */ + +#ifdef _WIN32 + +#include + +#include + +#include +#include + +#include "guitcl.h" + +static int +shell_execute_command (ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + char *operation; + char *file; + char *param; + char *dir; + int ret; + + if (argc < 3 || argc > 5) + { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " operation file ?parameters? ?directory?\"", NULL); + + return TCL_ERROR; + } + operation = argv[1]; /* Mandatory */ + if (!*operation) + operation = NULL; + + file = argv[2]; /* Mandatory */ + + if (argc > 3) + { + param = argv[3]; + if (!*param) + param = NULL; + } + else + param = NULL; + + if (argc > 4) + { + dir = argv[4]; + if (!*dir) + dir = NULL; + } + else + dir = NULL; + + ret = (int)ShellExecute(NULL, operation, file, param, dir, SW_SHOWNORMAL); + if (ret <= 32) + { + Tcl_AppendResult(interp, strerror(ret), NULL); + return TCL_ERROR; + } + return TCL_OK; +} + +int +ide_create_shell_execute_command (Tcl_Interp *interp) +{ + if (Tcl_CreateCommand (interp, "ide_shell_execute", shell_execute_command, + NULL, NULL) == NULL) + return TCL_ERROR; + return TCL_OK; +} + +#endif /* _WIN32 */
tclshellexe.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tclwinprint.c =================================================================== --- tclwinprint.c (nonexistent) +++ tclwinprint.c (revision 1765) @@ -0,0 +1,935 @@ +/* tclwinprint.c -- Tcl routines for printing on Windows. + Copyright (C) 1997 Cygnus Solutions. + Written by Ian Lance Taylor . + + This file contains routines to support printing on Windows from + Tcl. */ + +#ifdef _WIN32 + +#include + +#include +#include + +#include "subcommand.h" +#include "guitcl.h" + +#include + +#undef PRINT_BUFSIZE +#define PRINT_BUFSIZE 10240 + +/* FIXME: We need to dig into the Tk window implementation internals + to convert a Tk Window to an HWND. */ + +#include + +/* This implementation is minimal. It's just enough to print a text + file. Additional features can be added as necessary. + + One interesting idea that would fit into the Windows printing + scheme would be to have printing generate a limited canvas widget, + and permit Tk scripts to use canvas commands to draw items on the + page. + + This file defines a Tcl command with subcommands. + + ide_winprint page_setup OPTIONS + Invoke the Windows Page Setup dialog. This will record + information internally that will be used for later printing. + + Supported options: + -parent WINDOW + Set the parent window of the dialog box. The dialog + box is modal with respect to this window. The default + is the main window. + + ide_winprint print_text QUERYPROC TEXTPROC OPTIONS + Print text. This will start formatting the print job. The + user will still be able to interact with Tk. Typically, a + dialog box would be put up with a cancel button to permit the + user to cancel the print job by calling ide_winprint abort. + + The QUERYPROC argument is a Tcl procedure which tells the print + job what to do next. This is invoked alternately with the text + procedure until the print job is finished. QUERYPROC is called + first. This should return one of the following strings: + continue + Just invoke the text procedure and continue + printing. + done + The print job is finished. + newpage + Skip to a new page and continue printing. + + The TEXTPROC argument is a Tcl procedure which returns a single + line of text to print. This procedure will be invoked + alternately with the query procedure until the query procedure + indicates that the print job is complete. Page breaks are + handled automatically. + + Supported options: + -dialog BOOLEAN + Whether to display the Windows Print dialog. The + default is true. If false, this will use the default + printer. + -parent WINDOW + Set the parent window of the dialog box. The dialog + box is modal with respect to this window. The default + is the main window. + -name STRING + Set the name of the document. The default name is the + empty string. + -pageproc PAGEPROC + PAGEPROC is executed at the start of each new page. It + will be called with one argument, which is the page + number. It will be called before either QUERYPROC or + TEXTPROC is called on this page. If QUERYPROC never + returns newpage, then PAGEPROC will always be invoked + after a call to TEXTPROC. PAGEPROC should return one + of the following strings: + continue + Keep going. + done + Stop printing. + -postscript + Use PostScript output. + -initproc INITPROC + INITPROC is called at the start of the print job. + + ide_winprint abort + Abort a print job in process. If there is no current print + job, this does nothing. + + */ + +/* An instance of this structure is the client data for the + ide_winprint command. */ + +struct winprint_data +{ + /* Information from the Page Setup dialog. */ + PAGESETUPDLG *page_setup; + /* This is set non-zero if the print job is aborted. */ + int aborted; +}; + +/* Delete the ide_winprint command. */ + +static void +winprint_command_deleted (ClientData cd) +{ + struct winprint_data *wd = (struct winprint_data *) cd; + + if (wd->page_setup != NULL) + { + /* FIXME: I don't know if we are supposed to free the hDevMode + and hDevNames fields. */ + Tcl_Free ((char *) wd->page_setup); + } + + Tcl_Free ((char *) wd); +} + +/* Implement ide_winprint page_setup. */ + +static int +winprint_page_setup_command (ClientData cd, Tcl_Interp *interp, int argc, + char **argv) +{ + struct winprint_data *wd = (struct winprint_data *) cd; + Tk_Window parent; + int i, mode, ret; + PAGESETUPDLG psd; + + parent = Tk_MainWindow (interp); + + for (i = 2; i < argc; i += 2) + { + if (i + 1 >= argc) + { + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + "value for \"", argv[i], "\" missing", + (char *) NULL); + return TCL_ERROR; + } + + if (strcmp (argv[i], "-parent") == 0) + { + parent = Tk_NameToWindow (interp, argv[i + 1], + Tk_MainWindow (interp)); + if (parent == NULL) + return TCL_ERROR; + } + else + { + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + "unknown option \"", argv[i], "\"", + (char *) NULL); + return TCL_ERROR; + } + } + + if (wd->page_setup != NULL) + psd = *wd->page_setup; + else + { + memset (&psd, 0, sizeof (PAGESETUPDLG)); + psd.lStructSize = sizeof (PAGESETUPDLG); + psd.Flags = PSD_DEFAULTMINMARGINS; + } + + if (Tk_WindowId (parent) == None) + Tk_MakeWindowExist (parent); + psd.hwndOwner = Tk_GetHWND (Tk_WindowId (parent)); + + mode = Tcl_SetServiceMode (TCL_SERVICE_ALL); + + ret = PageSetupDlg (&psd); + + (void) Tcl_SetServiceMode (mode); + + if (! ret) + { + DWORD code; + + code = CommDlgExtendedError (); + if (code == 0) + { + /* The user pressed cancel. */ + return TCL_OK; + } + else + { + char buf[20]; + + sprintf (buf, "0x%lx", (unsigned long) code); + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + "Windows common dialog error ", buf, + (char *) NULL); + return TCL_ERROR; + } + } + + if (wd->page_setup == NULL) + wd->page_setup = (PAGESETUPDLG *) Tcl_Alloc (sizeof (PAGESETUPDLG)); + + *wd->page_setup = psd; + + return TCL_OK; +} + +/* The abort function needs a static variable (ewww). */ + +static struct winprint_data *abort_wd; + +/* This is the abort function we pass to the Windows print routine. */ + +static BOOL CALLBACK +abort_function (HDC hdc, int code) +{ + while (Tcl_DoOneEvent (TCL_DONT_WAIT)) + ; + return ! abort_wd->aborted; +} + +/* Handle an error in a Windows system call. */ + +static void +windows_error (Tcl_Interp *interp, const char *fn) +{ + char buf[20]; + + sprintf (buf, "%lu", (unsigned long) GetLastError ()); + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + "Windows error in ", fn, ": ", buf, (char *) NULL); +} + +/* This structure holds the options for the ide_winprint print_text + command. */ + +struct print_text_options +{ + /* Whether to use the print dialog. */ + int dialog; + /* The parent window. */ + char *parent; + /* The document name. */ + char *name; + /* The page procedure. */ + char *pageproc; + /* The init procedure. This is called once before printing. */ + char *initproc; + /* Print using PostScript? */ + int postscript; +}; + +/* Handle options for the ide_winprint print_text command. */ + +static int +winprint_print_text_options (struct winprint_data *wd, Tcl_Interp *interp, + int argc, char **argv, + struct print_text_options *pto) +{ + int i; + + pto->dialog = 1; + pto->parent = NULL; + pto->name = ""; + pto->pageproc = NULL; + pto->postscript = 0; + pto->initproc = NULL; + + for (i = 4; i < argc; i += 2) + { + if (i + 1 >= argc) + { + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + "value for \"", argv[i], "\" missing", + (char *) NULL); + return TCL_ERROR; + } + + if (strcmp (argv[i], "-dialog") == 0) + { + if (Tcl_GetBoolean (interp, argv[i + 1], &pto->dialog) != TCL_OK) + return TCL_ERROR; + } + else if (strcmp (argv[i], "-parent") == 0) + pto->parent = argv[i + 1]; + else if (strcmp (argv[i], "-name") == 0) + pto->name = argv[i + 1]; + else if (strcmp (argv[i], "-pageproc") == 0) + pto->pageproc = argv[i + 1]; + else if (strcmp (argv[i], "-initproc") == 0) + pto->initproc = argv[i + 1]; + else if (strcmp (argv[i], "-postscript") == 0) + pto->postscript = 1; + else + { + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + "unknown option \"", argv[i], "\"", + (char *) NULL); + return TCL_ERROR; + } + } + + return TCL_OK; +} + +/* Invoke the print dialog for the ide_winprint print_text command. + We always call PrintDlg, even if the -dialog false option was used, + because it returns the device context we use for printing. */ + +static int +winprint_print_text_dialog (struct winprint_data *wd, Tcl_Interp *interp, + const struct print_text_options *pto, + PRINTDLG *pd, int *cancelled) +{ + int mode, ret; + + *cancelled = 0; + + memset (pd, 0, sizeof (PRINTDLG)); + pd->lStructSize = sizeof (PRINTDLG); + + if (! pto->dialog) + pd->Flags = PD_RETURNDEFAULT | PD_RETURNDC; + else + { + Tk_Window parent; + + if (pto->parent == NULL) + parent = Tk_MainWindow (interp); + else + { + parent = Tk_NameToWindow (interp, pto->parent, + Tk_MainWindow (interp)); + if (parent == NULL) + return TCL_ERROR; + } + if (Tk_WindowId (parent) == None) + Tk_MakeWindowExist (parent); + pd->hwndOwner = Tk_GetHWND (Tk_WindowId (parent)); + + if (wd->page_setup != NULL) + { + pd->hDevMode = wd->page_setup->hDevMode; + pd->hDevNames = wd->page_setup->hDevNames; + } + + pd->Flags = PD_NOSELECTION | PD_RETURNDC | PD_USEDEVMODECOPIES; + + pd->nCopies = 1; + pd->nFromPage = 1; + pd->nToPage = 1; + pd->nMinPage = 1; + pd->nMaxPage = 0xffff; + } + + mode = Tcl_SetServiceMode (TCL_SERVICE_ALL); + + ret = PrintDlg (pd); + + (void) Tcl_SetServiceMode (mode); + + if (! ret) + { + DWORD code; + + code = CommDlgExtendedError (); + + /* For some errors, the print dialog will already have reported + an error. We treat those as though the user pressed cancel. + Unfortunately, I do not know just which errors those are. */ + + if (code == 0 || code == PDERR_NODEFAULTPRN) + { + *cancelled = 1; + return TCL_OK; + } + else + { + char buf[20]; + + sprintf (buf, "0x%lx", (unsigned long) code); + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + "Windows common dialog error ", buf, + (char *) NULL); + return TCL_ERROR; + } + } + + return TCL_OK; +} + +/* Get the margins in device units. */ + +static void +winprint_get_margins (struct winprint_data *wd, const PRINTDLG *pd, + int *top_ptr, int *left_ptr, int *bottom_ptr) +{ + int topmargin, leftmargin, bottommargin; + int logx, logy; + + if (wd->page_setup == NULL) + { + /* Use 1 inch margins. */ + topmargin = 1000; + leftmargin = 1000; + bottommargin = 1000; + } + else + { + topmargin = wd->page_setup->rtMargin.top; + leftmargin = wd->page_setup->rtMargin.left; + bottommargin = wd->page_setup->rtMargin.bottom; + if ((wd->page_setup->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) != 0) + { + topmargin = (topmargin * 1000) / 2540; + leftmargin = (leftmargin * 1000) / 2540; + bottommargin = (bottommargin * 1000) / 2540; + } + } + + logx = GetDeviceCaps (pd->hDC, LOGPIXELSX); + logy = GetDeviceCaps (pd->hDC, LOGPIXELSY); + + topmargin = (topmargin * logy) / 1000; + leftmargin = (leftmargin * logx) / 1000; + bottommargin = (bottommargin * logy) / 1000; + + *top_ptr = topmargin; + *left_ptr = leftmargin; + *bottom_ptr = GetDeviceCaps (pd->hDC, VERTRES) - bottommargin; +} + +/* Prepare to start printing. */ + +static int +winprint_start (struct winprint_data *wd, Tcl_Interp *interp, PRINTDLG *pd, + const struct print_text_options *pto, int *cancelled) +{ + DOCINFO di; + + *cancelled = 0; + + wd->aborted = 0; + + /* We have no way to pass information to the abort function, so we + need to use a global variable. */ + abort_wd = wd; + if (! SetAbortProc (pd->hDC, abort_function)) + { + windows_error (interp, "SetAbortFunc"); + return TCL_ERROR; + } + + di.cbSize = sizeof (DOCINFO); + di.lpszDocName = pto->name; + di.lpszOutput = NULL; + di.lpszDatatype = NULL; + di.fwType = 0; + + if (StartDoc (pd->hDC, &di) <= 0) + { + if (GetLastError () == ERROR_CANCELLED) + *cancelled = 1; + else + { + windows_error (interp, "StartDoc"); + return TCL_ERROR; + } + } + + return TCL_OK; +} + +/* Finish printing. */ + +static int +winprint_finish (struct winprint_data *wd, Tcl_Interp *interp, + PRINTDLG *pd, int error) +{ + int ret; + + ret = TCL_OK; + + if (error || wd->aborted) + AbortDoc (pd->hDC); + else + { + if (EndDoc (pd->hDC) <= 0) + { + windows_error (interp, "EndDoc"); + ret = TCL_ERROR; + } + } + + DeleteDC (pd->hDC); + + return ret; +} + +/* Values the ide_winprint print_text query or page procedure can + return. */ + +enum winprint_query { Q_CONTINUE, Q_NEWPAGE, Q_DONE }; + +/* Invoke the query or page procedure for ide_winprint print_text. */ + +static int +winprint_print_text_invoke (Tcl_Interp *interp, char *proc, const char *name, + enum winprint_query *result) +{ + char *q; + + if (Tcl_Eval (interp, proc) == TCL_ERROR) + return TCL_ERROR; + + q = Tcl_GetStringFromObj (Tcl_GetObjResult (interp), (int *) NULL); + if (strcmp (q, "continue") == 0) + *result = Q_CONTINUE; + else if (strcmp (q, "newpage") == 0) + *result = Q_NEWPAGE; + else if (strcmp (q, "done") == 0) + *result = Q_DONE; + else + { + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + "bad return from ", name, " procedure: \"", + q, "\"", (char *) NULL); + return TCL_ERROR; + } + + return TCL_OK; +} + +/* Implement ide_winprint print_text. */ +static int +winprint_print_command (ClientData cd, Tcl_Interp *interp, int argc, + char **argv) +{ + struct winprint_data *wd = (struct winprint_data *) cd; + char *queryproc; + char *textproc; + struct print_text_options pto; + PRINTDLG pd; + int cancelled; + int top, bottom, left; + TEXTMETRIC tm; + POINT pt; + int lineheight; + int pageno; + int error=0, done, needquery; + struct { + short len; /* Defined to be 16 bits.... */ + char buffer[PRINT_BUFSIZE+1]; + } indata; + + queryproc = argv[2]; + textproc = argv[3]; + + if (winprint_print_text_options (wd, interp, argc, argv, &pto) != TCL_OK) + return TCL_ERROR; + + if (winprint_print_text_dialog (wd, interp, &pto, &pd, &cancelled) != TCL_OK) + return TCL_ERROR; + if (cancelled) + return TCL_OK; + + if (pto.postscript) + { + int eps_printing = 33; + int result; + short bresult = 1; /* EPS printing download suppressed */ + result = Escape (pd.hDC, eps_printing, sizeof (BOOL), (LPCSTR)&bresult, NULL); + if ( result < 0 ) + { + /* The EPSPRINTING escape failed! */ + Tcl_AppendElement(interp, + "ide_winprint: EPSPRINTING escape implemented but failed"); + DeleteDC (pd.hDC); + return TCL_ERROR; + } + } + else + { + winprint_get_margins(wd, &pd, &top, &left, &bottom); + } + + if (winprint_start (wd, interp, &pd, &pto, &cancelled) != TCL_OK) + { + DeleteDC (pd.hDC); + return TCL_ERROR; + } + if (cancelled) + { + DeleteDC (pd.hDC); + return TCL_OK; + } + + /* init and start init-procedure if available */ + if (pto.initproc != NULL) + { + Tcl_DString initStr; + char buf[64]; + Tcl_DStringInit (&initStr); + Tcl_DStringAppend (&initStr, pto.initproc, -1); + + /* Here we must pass the customer selection from the PrintDialog + * as parameters for the init command, */ + /* From page */ + Tcl_DStringAppendElement (&initStr, "-frompage"); + sprintf (buf, "%i", pd.nFromPage); + Tcl_DStringAppendElement (&initStr, buf); + /* To Page */ + Tcl_DStringAppendElement (&initStr, "-topage"); + sprintf (buf, "%i", pd.nToPage); + Tcl_DStringAppendElement (&initStr, buf); + /* # Copies */ + Tcl_DStringAppendElement (&initStr, "-copies"); + sprintf (buf, "%i", pd.nCopies); + Tcl_DStringAppendElement (&initStr, buf); + /* Print Selection? */ + Tcl_DStringAppendElement (&initStr, "-selection"); + Tcl_DStringAppendElement (&initStr, (pd.Flags&PD_SELECTION) ? "1" : "0"); + + /* Execute tcl/command */ + if (Tcl_Eval (interp, Tcl_DStringValue(&initStr)) != TCL_OK) + { + Tcl_DStringFree (&initStr); + return TCL_ERROR; + } + Tcl_DStringFree (&initStr); + } + + if (pto.postscript) + { + Tcl_DString pageStr; + int status, retval, len, i; + char *l, msgbuf[128]; + enum winprint_query q = 0; + + /* Note: NT 4.0 seems to leave the default CTM quite tiny! */ + strcpy (indata.buffer, "\r\nsave\r\ninitmatrix\r\n"); + indata.len = strlen(indata.buffer); + Escape(pd.hDC, PASSTHROUGH, 0, (LPCSTR)&indata, NULL); + + /* Init command for page-procedure */ + if (pto.pageproc != NULL) + { + Tcl_DStringInit (&pageStr); + Tcl_DStringAppend (&pageStr, pto.pageproc, -1); + Tcl_DStringAppendElement (&pageStr, "-1"); + } + + /* Start printing */ + while (1) + { + /* Run page-procedure to update the display */ + status = winprint_print_text_invoke (interp, Tcl_DStringValue(&pageStr), "page", &q); + if (status != TCL_OK || q == Q_DONE) + { + error = 1; + break; + } + + /* query next characters to send to printer */ + if (winprint_print_text_invoke (interp, queryproc, "query", &q) != TCL_OK) + { + error = 1; + break; + } + if (q != Q_CONTINUE) + { + done = 1; + break; + } + if (Tcl_Eval (interp, textproc) == TCL_ERROR) + { + error = 1; + break; + } + l = Tcl_GetStringFromObj (Tcl_GetObjResult (interp), &len); + for (i=0; iaborted) + break; + + /* Start a new page. */ + if (pto.pageproc != NULL) + { + Tcl_DString ds; + char buf[20]; + enum winprint_query q; + int status; + + Tcl_DStringInit (&ds); + Tcl_DStringAppend (&ds, pto.pageproc, -1); + sprintf (buf, "%d", pageno); + Tcl_DStringAppendElement (&ds, buf); + + status = winprint_print_text_invoke (interp, Tcl_DStringValue (&ds), + "page", &q); + + Tcl_DStringFree (&ds); + + if (status != TCL_OK) + { + error = 1; + break; + } + + if (q == Q_DONE) + { + done = 1; + break; + } + } + + if (needquery) + { + enum winprint_query q; + + if (winprint_print_text_invoke (interp, queryproc, "query", &q) + != TCL_OK) + { + error = 1; + break; + } + + if (q == Q_DONE) + { + done = 1; + break; + } + + /* Ignore Q_NEWPAGE, since we're about to start a new page + anyhow. */ + + needquery = 0; + } + + if (StartPage (pd.hDC) <= 0) + { + windows_error (interp, "StartPage"); + error = 1; + break; + } + + y = top; + + /* Print a page. */ + + while (1) + { + char *l; + int len; + enum winprint_query q; + + if (Tcl_Eval (interp, textproc) == TCL_ERROR) + { + error = 1; + break; + } + + l = Tcl_GetStringFromObj (Tcl_GetObjResult (interp), &len); + + TextOut (pd.hDC, left, y, l, len); + y += lineheight; + + if (y >= bottom) + { + needquery = 1; + break; + } + + if (winprint_print_text_invoke (interp, queryproc, "query", &q) + != TCL_OK) + { + error = 1; + break; + } + + if (q == Q_DONE) + { + done = 1; + break; + } + else if (q == Q_NEWPAGE) + break; + } + + if (error) + break; + + if (EndPage (pd.hDC) <= 0) + { + /* It's OK for EndPage to return an error if the print job + was cancelled. */ + if (! wd->aborted) + { + windows_error (interp, "EndPage"); + error = 1; + } + break; + } + + if (done) + break; + + ++pageno; + } + } + + if (winprint_finish (wd, interp, &pd, error) != TCL_OK) + error = 1; + + if (error) + return TCL_ERROR; + + Tcl_ResetResult (interp); + return TCL_OK; +} + +/* Implement ide_winprint abort. */ + +static int +winprint_abort_command (ClientData cd, Tcl_Interp *interp, int argc, + char **argv) +{ + struct winprint_data *wd = (struct winprint_data *) cd; + + wd->aborted = 1; + return TCL_OK; +} + +/* The subcommand table. */ + +static const struct ide_subcommand_table winprint_commands[] = +{ + { "page_setup", winprint_page_setup_command, 2, -1 }, + { "print_text", winprint_print_command, 4, -1 }, + { "print", winprint_print_command, 6, -1 }, + { "abort", winprint_abort_command, 2, 2 }, + { NULL, NULL, 0, 0 } +}; + +/* This function creates the ide_winprint Tcl command. */ + +int +ide_create_winprint_command (Tcl_Interp *interp) +{ + struct winprint_data *wd; + + wd = (struct winprint_data *) Tcl_Alloc (sizeof *wd); + wd->page_setup = NULL; + wd->aborted = 0; + + return ide_create_command_with_subcommands (interp, "ide_winprint", + winprint_commands, + (ClientData) wd, + winprint_command_deleted); +} + +#endif /* _WIN32 */ + + + + + +
tclwinprint.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: paths.c =================================================================== --- paths.c (nonexistent) +++ paths.c (revision 1765) @@ -0,0 +1,299 @@ +/* paths.c - Find IDE and application Tcl libraries. + Copyright (C) 1997 Cygnus Solutions. + Written by Tom Tromey . */ + +#include +#include + +#include "guitcl.h" + + + +/* This Tcl code sets up all the path information we care about. + + We first look for the gui library. This can be set by the + CYGNUS_GUI_LIBRARY environment variable. Otherwise, it is named + gui, and is found in $prefix/share/cygnus, where $prefix is + determined by looking at the directory where the running executable + is installed. + + We then look for the ide library. This can be set by the + CYGNUS_IDE_LIBRARY environment variable. Otherwise, it is named + ide, and is also found in $prefix/share/cygnus. + + It is OK if only one of these libraries exist. If neither exists, + we report an error. + + We also set the following elements in the global Paths array. + + prefix -- as in the configure argument + exec_prefix -- ditto + bindir -- ditto + libexecdir -- ditto + guidir -- the gui directory (not set if it does not exist) + idedir -- the ide directory (not set if it does not exist) + appdir -- see below + bitmapdir -- see below + + Paths(appdir) is set based on the ide_initialize_paths APPNAME + parameter. If a directory $prefix/share/cygnus/APPNAME exists, we + set Paths(appdir) to it. More precisely, we set Paths(appdir) if + an APPNAME directory exists which is a sibling directory of the gui + or ide directory. For convenience of some tools, we also check for + $prefix/share/APPNAME, or, more precisely, we check whether APPNAME + is a sibling directory of the parent of the gui or ide directory. + + Paths(bitmapdir) is set if gui or ide have a sibling directory + named bitmaps. */ + +#ifndef _MSC_VER +static char init_script[] = "\ +proc initialize_paths {} {\n\ + global ide_application_name auto_path env Paths\n\ + global tcl_library\n\ + rename initialize_paths {}\n\ + # First find the GUI library.\n\ + set guidirs {}\n\ + set prefdirs {}\n\ + if [info exists env(CYGNUS_GUI_LIBRARY)] {\n\ + lappend guidirs $env(CYGNUS_GUI_LIBRARY)\n\ + }\n\ + set here [pwd]\n\ + set exec_name [info nameofexecutable]\n\ + if {[string compare [file type $exec_name] \"link\"] == 0} {\n\ + set exec_name [file readlink $exec_name]\n\ + if {[string compare [file pathtype $exec_name] \"relative\"] == 0} {\n\ + set exec_name [file join [pwd] $exec_name]\n\ + }\n\ + }\n\ + cd [file dirname $exec_name]\n\ + # Handle build with --exec-prefix and build without.\n\ + set d [file join [file dirname [pwd]] usr share]\n\ + lappend prefdirs $d\n\ + lappend guidirs [file join $d cygnus gui]\n\ + set d [file join [file dirname [pwd]] share]\n\ + lappend prefdirs $d\n\ + lappend guidirs [file join $d cygnus gui]\n\ + set d [file join [file dirname [file dirname [pwd]]] share]\n\ + lappend prefdirs $d\n\ + lappend guidirs [file join $d cygnus gui]\n\ + set Paths(bindir) [pwd]\n\ + # Base `prefix' on where the `share' dir is found\n\ + foreach sd $prefdirs {\n\ + if [file isdirectory $sd] {\n\ + set Paths(prefix) [file dirname $sd]\n\ + break\n\ + }\n\ + }\n\ + if {[file isdirectory [file join [file dirname [pwd]] libexec]]} {\n\ + set Paths(libexecdir) [file join [file dirname [pwd]] libexec]\n\ + } else {\n\ + set Paths(libexecdir) $Paths(bindir)\n\ + }\n\ + set Paths(exec_prefix) [file dirname [pwd]]\n\ + cd $here\n\ + # Try to handle running from the build tree:\n\ + lappend guidirs [file join [file dirname [file dirname $tcl_library]] libgui library]\n\ + foreach sd $guidirs {\n\ + if {[file exists [file join $sd tclIndex]]} {\n\ + lappend auto_path $sd\n\ + set Paths(guidir) $sd\n\ + break\n\ + }\n\ + }\n\ + # Now find the IDE library, if it exists.\n\ + set idedirs {}\n\ + if [info exists env(CYGNUS_IDE_LIBRARY)] {\n\ + lappend idedirs $env(CYGNUS_IDE_LIBRARY)\n\ + }\n\ + foreach d $prefdirs {\n\ + lappend idedirs [file join $d cygnus ide]\n\ + }\n\ + # Try to handle running from the build tree:\n\ + lappend idedirs [file join [file dirname [file dirname $tcl_library]] libide library]\n\ + foreach sd $idedirs {\n\ + if {[file exists [file join $sd tclIndex]]} {\n\ + lappend auto_path $sd\n\ + set Paths(idedir) $sd\n\ + break\n\ + }\n\ + }\n\ + # Now set the bitmap directory:\n\ + foreach v [list guidir idedir] {\n\ + if {[info exists Paths($v)]} {\n\ + set d [file dirname $Paths($v)]\n\ + if {[file isdirectory [file join $d bitmaps]]} {\n\ + set Paths(bitmapdir) [file join $d bitmaps]\n\ + }\n\ + }\n\ + }\n\ + \n\ + # We do things in a somewhat roundabout way here. This lets us\n\ + # run from the source directory, if we're willing to be a little messy\n\ + # in our test scripts. FIXME: find a cleaner way.\n\ + # This routine is really meant to find the libgui & libide library directories.\n\ + #\n\ + # The client may not want it trying to find the application library\n\ + # Signal that by setting ide_application_name to empty string\n\ + if {$ide_application_name != \"\"} {\n\ + foreach v [list guidir idedir] {\n\ + if {[info exists Paths($v)]} {\n\ + set d [file dirname $Paths($v)]\n\ + if {[file isdirectory [file join $d $ide_application_name]]} {\n\ + lappend auto_path [file join $d $ide_application_name]\n\ + set Paths(appdir) [file join $d $ide_application_name]\n\ + }\n\ + }\n\ + }\n\ + if {! [info exists Paths(appdir)]} {\n\ + foreach v [list guidir idedir] {\n\ + if {[info exists Paths($v)]} {\n\ + set d [file dirname [file dirname $Paths($v)]]\n\ + if {[file isdirectory [file join $d $ide_application_name]]} {\n\ + lappend auto_path [file join $d $ide_application_name]\n\ + set Paths(appdir) [file join $d $ide_application_name]\n\ + }\n\ + }\n\ + }\n\ + }\n\ + }\n\ + if {[info exists Paths(guidir)] || [info exists Paths(idedir)]} {\n\ + return\n\ + }\n\ + # FIXME: must run this message through gettext.\n\ + # Can only do this once gettext is in C and not just a stub.\n\ + set msg \"Can't find the GUI Tcl library in the following directories:\n\"\n\ + append msg \" $guidirs $idedirs\n\"\n\ + error $msg\n\ +}\n\ +initialize_paths"; +#else +static char init_script[] = "\ +proc initialize_paths {} {\n\ + global ide_application_name auto_path env Paths\n\ + global tcl_library\n\ + rename initialize_paths {}\n\ + set guidirs {}\n\ + set here [pwd]\n\ + cd [file dirname [info nameofexecutable]]\n\ + set d [file join [file dirname [pwd]] share]\n\ + lappend guidirs [file join $d cygnus gui]\n\ + set d [file join [file dirname [file dirname [pwd]]] share]\n\ + lappend guidirs [file join $d cygnus gui]\n\ + lappend guidirs [file join [file dirname [file dirname $tcl_library]] libgui library]\n\ + foreach sd $guidirs {\n\ + if {[file exists [file join $sd tclIndex]]} {\n\ + lappend auto_path $sd\n\ + set Paths(guidir) $sd\n\ + break\n\ + }\n\ + }\n\ + foreach v [list guidir] {\n\ + if {[info exists Paths($v)]} {\n\ + set d [file dirname $Paths($v)]\n\ + if {[file isdirectory [file join $d bitmaps]]} {\n\ + set Paths(bitmapdir) [file join $d bitmaps]\n\ + }\n\ + }\n\ + }\n\ + \n\ + if {$ide_application_name != \"\"} {\n\ + foreach v [list guidir ] {\n\ + if {[info exists Paths($v)]} {\n\ + set d [file dirname $Paths($v)]\n\ + if {[file isdirectory [file join $d $ide_application_name]]} {\n\ + lappend auto_path [file join $d $ide_application_name]\n\ + set Paths(appdir) [file join $d $ide_application_name]\n\ + }\n\ + }\n\ + }\n\ + if {! [info exists Paths(appdir)]} {\n\ + foreach v [list guidir] {\n\ + if {[info exists Paths($v)]} {\n\ + set d [file dirname [file dirname $Paths($v)]]\n\ + if {[file isdirectory [file join $d $ide_application_name]]} {\n\ + lappend auto_path [file join $d $ide_application_name]\n\ + set Paths(appdir) [file join $d $ide_application_name]\n\ + }\n\ + }\n\ + }\n\ + }\n\ + }\n\ + if {[info exists Paths(guidir)]} {\n\ + return\n\ + }\n\ + set msg \"Can't find the GUI Tcl library in the following directories:\n\"\n\ + append msg \" $guidirs\n\"\n\ + error $msg\n\ +}\n\ +initialize_paths"; +#endif + +/* Initialize the global Paths variable. */ +int +ide_initialize_paths (Tcl_Interp *interp, char *appname) +{ + if (Tcl_SetVar (interp, "ide_application_name", appname, + TCL_GLOBAL_ONLY) == NULL) + return (TCL_ERROR); + return (Tcl_GlobalEval (interp, init_script)); +} + +#ifdef TCLPRO_DEBUGGER +static char run_app_script[] = "\ +proc initialize_find_app_script {} {\n\ + global Paths env ide_application_name\n\ + rename initialize_find_app_script {}\n\ + if {[info exists env(TCLPRO_DEBUG_DIR)]} {\n\ + source [file join $env(TCLPRO_DEBUG_DIR) prodebug.tcl]\n\ + debugger_init\n\ + }\n\ + # Look in idedir for the sake of test apps like idetrace.\n\ + foreach v [list appdir idedir] {\n\ + if {[info exists Paths($v)]} {\n\ + set file [file join $Paths($v) ${ide_application_name}.tcl]\n\ + if {[file exists $file]} {\n\ + if {[info exists env(TCLPRO_DEBUG_DIR)]} {\n\ + # Right now, only one process can be debugged at a time.\n\ + # Unset the debug dir, so we won't try to debug any\n\ + # child processes...\n\ + unset env(TCLPRO_DEBUG_DIR)\n\ + uplevel #0 debugger_eval [list source $file]\n\ + } else {\n\ + uplevel #0 [list source $file]\n\ + }\n\ + return\n\ + }\n\ + }\n\ + }\n\ + # FIXME: must run message through gettext.\n\ + error \"Can't find ${ide_application_name}.tcl\"\n\ +}\n\ +initialize_find_app_script"; +#else +static char run_app_script[] = "\ +proc initialize_find_app_script {} {\n\ + global Paths ide_application_name\n\ + rename initialize_find_app_script {}\n\ + # Look in idedir for the sake of test apps like idetrace.\n\ + foreach v [list appdir idedir] {\n\ + if {[info exists Paths($v)]} {\n\ + set file [file join $Paths($v) ${ide_application_name}.tcl]\n\ + if {[file exists $file]} {\n\ + uplevel #0 [list source $file]\n\ + return\n\ + }\n\ + }\n\ + }\n\ + # FIXME: must run message through gettext.\n\ + error \"Can't find ${ide_application_name}.tcl\"\n\ +}\n\ +initialize_find_app_script"; +#endif + +/* Run the application-specific init script. */ +int +ide_run_app_script (Tcl_Interp *interp) +{ + return (Tcl_GlobalEval (interp, run_app_script)); +}
paths.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkTable_version.in =================================================================== --- tkTable_version.in (nonexistent) +++ tkTable_version.in (revision 1765) @@ -0,0 +1 @@ +TBL_VERSION = 2.1
tkTable_version.in Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tclcursor.c =================================================================== --- tclcursor.c (nonexistent) +++ tclcursor.c (revision 1765) @@ -0,0 +1,77 @@ +/* tclcursor.c - Tcl function to compute the size of a cursor. + Copyright (C) 1997 Cygnus Solutions. + Written by Tom Tromey . */ + +/* Interestingly, there is no way to get the size of a cursor in X. + We would have to change Tk to keep track of this information if we + cared about it. Luckily, we only care for Windows. */ + +/* This makes a Tcl command with two subcommands: + + ide_cursor size - Return size of cursor as list {WIDTH HEIGHT} + + ide_cursor position - Return position of cursor as list {X Y} + + */ + +#ifdef _WIN32 + +#include + +#include +#include + +#include "guitcl.h" +#include "subcommand.h" + +static int +get_cursor_size (ClientData cd, Tcl_Interp *interp, int argc, char *argv[]) +{ + char buf[30]; + + sprintf (buf, "%d", GetSystemMetrics (SM_CXCURSOR)); + Tcl_AppendElement (interp, buf); + sprintf (buf, "%d", GetSystemMetrics (SM_CYCURSOR)); + Tcl_AppendElement (interp, buf); + + return TCL_OK; +} + +static int +get_cursor_position (ClientData cd, Tcl_Interp *interp, int argc, char *argv[]) +{ + POINT where; + char buf[30]; + + if (! GetCursorPos (&where)) + { + Tcl_AppendResult (interp, argv[0], ": couldn't get cursor position", + (char *) NULL); + return TCL_ERROR; + } + + sprintf (buf, "%ld", where.x); + Tcl_AppendElement (interp, buf); + sprintf (buf, "%ld", where.y); + Tcl_AppendElement (interp, buf); + + return TCL_OK; +} + +static const struct ide_subcommand_table cursor_commands[] = +{ + { "size", get_cursor_size, 2, 2 }, + { "position", get_cursor_position, 2, 2 }, + { NULL, NULL, 0, 0 } +}; + +int +ide_create_cursor_command (Tcl_Interp *interp) +{ + return ide_create_command_with_subcommands (interp, "ide_cursor", + cursor_commands, + (ClientData) NULL, + NULL); +} + +#endif /* _WIN32 */
tclcursor.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkCanvLayout.c =================================================================== --- tkCanvLayout.c (nonexistent) +++ tkCanvLayout.c (revision 1765) @@ -0,0 +1,2680 @@ +/* + * Copyright (c) 1993 by Sven Delmas + * All rights reserved. + * See the file COPYRIGHT for the copyright notes. + * + */ + +/* renamed from layout.c to tkCanvLayout.c by Will Taylor 09nov95 */ +/* converted to Tk4.1 by Will Taylor 05may96 */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include +#include +#include +#include "tkCanvLayout.h" + +#if defined (__MSVC__) && ! defined (HAVE_RAND) +#define HAVE_RAND +#endif + +/* + * Functions to compute random numbers. These don't have to be + * particular good random number generators. + */ +#ifdef HAVE_RANDOM +#define RANDOM random () +#define SRANDOM srandom +#else /* HAVE_RANDOM */ +#ifdef HAVE_DRAND48 +#define MY_RAND_MAX 65536 +#define RANDOM ((long) (drand48 () * MY_RAND_MAX)) +#define SRANDOM srand48 +#else /* HAVE_DRAND48 */ +#ifdef HAVE_RAND +#define RANDOM rand () +#define SRANDOM srand +#else +#warning no random number generator specified, default: random, srandom +#define HAVE_RANDOM +#define RANDOM random () +#define SRANDOM srandom +#endif /* HAVE_RAND */ +#endif /* HAVE_DRAND48 */ +#endif /* HAVE_RANDOM */ + +#define LAYOUT_OK TCL_OK +#define LAYOUT_ERROR TCL_ERROR + +/* + * This value is added to the line length in pixels, so the distance + * between two nodes can be calculated correctly. + */ +#define LINE_INCREMENT 10 + +/* + * Turn on/off debugging. + */ +#define DEBUGGING 1 +#define DEBUG_LAYOUT 0 +#define DEBUG_PLACE 0 +#define TESTING 0 + +/* + * the datastructures used for layouting. + */ + +/* + * these datas/variables are used by the tree layouter. + */ + +struct TreeData { + double tmpX; /* A temporary x position. */ + double tmpY; /* A temporary y position. */ +}; +typedef struct TreeData TreeData; + +#define TREE_TMP_X_POS(node) (node)->treeData.tmpX +#define SET_TREE_TMP_X_POS(node,pos) (node)->treeData.tmpX = (pos) +#define TREE_TMP_Y_POS(node) (node)->treeData.tmpY +#define SET_TREE_TMP_Y_POS(node,pos) (node)->treeData.tmpY = (pos) + +#if DEBUGGING +#define DEBUG_PRINT_TREE_NODE_POS(node, s) TkCanvLayoutDebugging(node, s, 1) +#else +#define DEBUG_PRINT_TREE_NODE_POS(node, s) +#endif + + +/* + * A topologically ordered node. stored in the global array toplist + * (0 to toplistnum). + */ +struct Topology { + struct Nodes *nodePtr; +}; +typedef struct Topology Topology; + +/* +Define edge information +*/ + +struct Edge { + pItem edgeid; /* edge identifier */ + ItemGeom info; + struct Nodes* fromNode; /* A pointer to the ``from'' node struct. */ + struct Nodes* toNode; /* A pointer to the ``to'' node struct. */ + int ignore; /* Ignore this edge. */ + int visited; /* This edge was visited. */ +}; +typedef struct Edge Edge; + +/* + * A graph node. stored in a global array named nodes + * (0 to nodenum). + */ +struct Nodes { + pItem itemPtr; /* Pointer to the Node dual. */ + ItemGeom info; /* bounding box of the dual */ + int ignore; /* Ignore this node. */ + int visited; /* This node was already */ + /* visited/layouted. */ + double x; /* The calculated x position. */ + double y; /* The calculated y position. */ + int parentNum; /* The number of parent nodes. */ + Edge** parent; /* The array of parent nodes. */ + int succNum; /* The number of successor nodes. */ + Edge** succ; /* The array of successor nodes. */ + struct TreeData treeData; /* temporary tree layout nodes */ +#if 0 + char *data; /* Special data attached to */ + /* this node. The contents */ + /* depend from the layouting */ + /* algorithms. */ +#endif +}; +typedef struct Nodes Nodes; +typedef struct Nodes Node; + +/* + * Defines that hide internal functionality. + */ + +/* + * Get and set the edge ignore flag. Edges which are ignored will not + * be traversed. The first parameter is the edge, and the second + * parameter (if you call the setting) is the new value of the + * ignore flag. + */ +#define IGNORE_EDGE(edge) (edge)->ignore +#define SET_IGNORE_EDGE(edge,mode) (edge)->ignore=mode + +/* + * Get and set the edge visited flag. This flag is usually set to true + * when the edge was visited. The first parameter is the edge, and the + * second parameter (if you call the setting) is the new value of the + * visited flag. + */ +#define VISITED_EDGE(edge) (edge)->visited +#define SET_VISITED_EDGE(edge,mode) (edge)->visited=mode + +/* + * Get and set the node ignore flag. Nodes which are ignored will not + * be traversed, and they are not placed/layouted. The first parameter + * is the node, and the second parameter (if you call the setting) is + * the new value of the ignore flag. + */ +#define IGNORE_NODE(node) (node)->ignore +#define SET_IGNORE_NODE(node,mode) (node)->ignore=mode +#define RESET_IGNORE_NODE(i) for (i = 0; i < THIS(nodeNum); i++) nodes[i]->ignore=0; + +/* + * Get and set the node visited flag. This flag is usually set to true + * when the node was visited. Currently this flag is mainly used for the + * topological sorting. The first parameter is the node, and the + * second parameter (if you call the setting) is the new value of the + * visited flag. + */ +#define VISITED_NODE(node) (node)->visited +#define SET_VISITED_NODE(node,mode) (node)->visited=mode +#define RESET_VISITED_NODE(i) for (i = 0; i < THIS(nodeNum); i++) THIS(nodes)[i]->visited=0; + +/* + * Get and set the number of parent nodes. The first parameter is the + * node, and the second parameter (if you call the setting) is the new + * number of parents. + */ +#define PARENT_NUM(node) (node)->parentNum +#define SET_PARENT_NUM(node,num) (node)->parentNum=num + +/* + * Get and set the number of successor nodes. The first parameter is + * the node, and the second parameter (if you call the setting) is the + * new number of successors. + */ +#define SUCC_NUM(node) (node)->succNum +#define SET_SUCC_NUM(node,num) (node)->succNum=num + +/* + * Get and set the node item. This item is the corresponding dual + * item for this node. The first parameter is the node, and the second + * parameter (if you call the setting) is the new dual item pointer. + */ +#define NODE_ITEM(node) (node)->itemPtr +#define SET_NODE_ITEM(node,item) (node)->itemPtr=item + +/* Get and set the node x1,x2,y1, and y2 positions. */ +#define NODE_X1_POS(node) (node)->info.x1 +#define NODE_Y1_POS(node) (node)->info.y1 +#define NODE_X2_POS(node) (node)->info.x2 +#define NODE_Y2_POS(node) (node)->info.y2 + +#define SET_NODE_X1_POS(node,v) (node)->info.x1 = (v) +#define SET_NODE_Y1_POS(node,v) (node)->info.y1 = (v) +#define SET_NODE_X2_POS(node,v) (node)->info.x2 = (v) +#define SET_NODE_Y2_POS(node,v) (node)->info.y2 = (v) + +/* Get, by calculation, the node's width and height */ +#define CALC_NODE_HEIGHT(n) (NODE_Y2_POS(n) - NODE_Y1_POS(n)) +#define CALC_NODE_WIDTH(n) (NODE_X2_POS(n) - NODE_X1_POS(n)) + +/* Get/Set the node dual geom */ +#define NODE_GEOM(node) (node)->info +#define SET_NODE_GEOM(node,inf) (node)->info = (inf) + +/* + * Get and set the node x position. This is the value for the final + * placing of the node. The first parameter is the node, and the + * second parameter (if you call the setting) is the new x position. + */ +#define NODE_X_POS(node) (node)->x +#define SET_NODE_X_POS(node,pos) (node)->x=pos + +/* + * Get and set the node y position. This is the value for the final + * placing of the node. The first parameter is the node, and the + * second parameter (if you call the setting) is the new y position. + */ +#define NODE_Y_POS(node) (node)->y +#define SET_NODE_Y_POS(node,pos) (node)->y=pos + +/* + * Get and set the nodes width. The parameter specifies the node + * whose width and height will be returned. + */ +#define NODE_WIDTH(node) (node)->info.width +#define SET_NODE_WIDTH(node,size) (node)->info.width=size + +/* + * Get and set the nodes height. The parameter specifies the node + * whose width and height will be returned. + */ +#define NODE_HEIGHT(node) (node)->info.height +#define SET_NODE_HEIGHT(node,size) (node)->info.height=size + +#define EDGE_ITEM(edge) (edge)->edgeid +#define SET_EDGE_ITEM(edge,item) (edge)->edgeid=item + +/* + * Return the parent/successor edge/node for the specified node. The + * second parameter is a integer counter that is used as index for the + * parent/successor array. Usually this index is generated by a + * FOR_ALL_* macro. + */ +#define PARENT_EDGE(node, i) (node)->parent[i] +#define PARENT_NODE(node, i) (node)->parent[i]->fromNode +#define PARENT_ID(node, i) (node)->parent[i]->edgeid +#define SUCC_EDGE(node, i) (node)->succ[i] +#define SUCC_NODE(node, i) (node)->succ[i]->toNode +#define SUCC_ID(node, i) (node)->succ[i]->edgeid +#define DUMMY_NODE(node) ((node)->itemPtr == (pItem) NULL) + +/* Get and set the edge x1,x2,y1, and y2 positions. */ +#define EDGE_X1_POS(edge) (edge)->info.x1 +#define EDGE_X2_POS(edge) (edge)->info.x2 +#define EDGE_Y1_POS(edge) (edge)->info.y1 +#define EDGE_Y2_POS(edge) (edge)->info.y2 + +/* Get/Set the edge dual geom */ +#define EDGE_GEOM(edge) (edge)->info +#define SET_EDGE_GEOM(edge,inf) (edge)->info = inf + +/* + * Return the node specified by the integer counter passed to this + * macro. The nodes in the array are topologically ordered (beginning + * with the index 0. The index is usually created by the macro + * FOR_ALL_TOP_NODES. + */ +#define TOP_NODE(i) THIS(topList)[i]->nodePtr + +/* + * Walk through all nodes that are currently defined. The only + * parameter is the integer counter that is used to index the array. + */ +#define FOR_ALL_NODES(i) for (i = 0; i < THIS(nodeNum); i++) + +/* + * Walk through all edges that are currently defined. The only + * parameter is the integer counter that is used to index the array. + */ +#define FOR_ALL_EDGES(i) for (i = 0; i < THIS(edgeNum); i++) + +/* + * Walk through all parents/successors of the specified node. The + * second parameter is the integer counter that is used to index the + * array. + */ +#define FOR_ALL_PARENTS(node, i) for (i = 0; i < (node)->parentNum; i++) +#define FOR_ALL_SUCCS(node, i) for (i = 0; i < (node)->succNum; i++) + +/* + * Walk through all nodes in topological order. The only parameter is + * the integer counter that is used to index the array. This call + * requires a call of the topological order function, before it can be + * used. + */ +#define FOR_ALL_TOP_NODES(i) for (i = 0; i < THIS(topListNum); i++) + +/* + * DEBUGGING MACROS. + */ +#if DEBUGGING +#define DEBUG_PRINT_NODE_POS(GRAPH, NODE, S) LayoutDebugging(GRAPH, NODE, S, 0) +#define DEBUG_PRINT_STRING(S1, S2) fprintf(stderr, "%s %s<\n", S2, S1); +#else +#define DEBUG_PRINT_NODE_POS(GRAPH, NODE, S) +#define DEBUG_PRINT_STRING(S1, S2) +#endif + + +#define THIS(x) This->x + +struct Layout_Graph { + /* Start with user settable configuration items */ + long iconSpaceV; /* The vertical space between icons. */ + long iconSpaceH; /*The horizontal space between icons.*/ + int graphOrder; /* Ordering... 0 = LR, 1 = TD. */ + Node *rootNode; /* The root node. */ + long xOffset; /* The x offset for the placing. */ + long yOffset; /* The y offset for the placing. */ + + /* + * These datas/variables are used by the random layouter. + */ + int keepRandomPositions; /* Don't change the position of */ + /* already placed icons when */ + /* layouting with the random */ + /* placer. */ + long maxX, maxY; /* Maximal X and Y coordinates */ + /* for the random placer. */ + /* + * Misc. variables used for layouting. + */ + + int nodeNum; /* The number of graph nodes. */ + Node** nodes; /* The list of graph nodes. */ + int edgeNum; /* The number of graph edges. */ + Edge** edges; /* The list of graph edges. */ + int topListNum; /* The current node number. */ + Topology **topList; /* The sorted nodes. */ + int computeiconsize; /* Use the biggest icon size. */ + int elementsPerLine; /* How many elements per line. */ + int hideEdges; /* make edges zero length (Matrix)*/ + int edgeHeight; /* The standard height of an edge. */ + int edgeOrder; /* Set the edges to the layout order.*/ + int edgeWidth; /* The standard width of an edge. */ + int iconHeight, iconWidth; /* The standard icon size. */ + double posX1, posY1, posX2, posY2; /* Coordinates */ + double maxXPosition; /* Maximal X and Y coordinates */ + double maxYPosition; /* for the random placer. */ + int layoutTypesNum; /* The number of layout types. */ + char **layoutTypes; /* The types of items that will + be layouted. */ + int gridlock; /* avoid using diagnal lines */ + char* errmsg; + +#ifdef ignore + char* graphName + char *idlist; /* The list of ids to layout. */ + char *sortcommand; /* The Tcl procedure called for */ + long rootId; + char convertBuffer[100]; /* Convert numbers to strings.*/ +#endif +}; + +typedef struct Layout_Graph Layout_Graph; + +static int deleteedge _ANSI_ARGS_((Layout_Graph*,Edge*,int)); +static int deletenode _ANSI_ARGS_((Layout_Graph*,Node*,int)); +static void compress_succ _ANSI_ARGS_((Layout_Graph*,Node*)); +static void compress_parent _ANSI_ARGS_((Layout_Graph*,Node*)); + +static void LayoutISISetX _ANSI_ARGS_((Layout_Graph*, Node*)); +static void LayoutISISetY _ANSI_ARGS_((Layout_Graph*, Node*/*, int type*/)); +static void LayoutTreeSetX _ANSI_ARGS_((Layout_Graph*, Node*)); +static void LayoutTreeSetY _ANSI_ARGS_((Layout_Graph*, Node*)); +static int LayoutBuildGraph _ANSI_ARGS_((Layout_Graph*)); +static Node* LayoutGraphRoot _ANSI_ARGS_((Layout_Graph*)); +static void LayoutGraphSortTopological _ANSI_ARGS_((Layout_Graph*, Node*)); +static int LayoutGraphPlaceNodes _ANSI_ARGS_((Layout_Graph*)); +static int LayoutGraphPlaceEdges _ANSI_ARGS_((Layout_Graph*)); +static int LayoutEdgeWidth _ANSI_ARGS_((Layout_Graph*)); +static int LayoutEdge _ANSI_ARGS_((Layout_Graph*, Edge*, Node*, Node*)); + +#if(defined(__cplusplus) || defined(c_plusplus)) +#define AC1(t1,a1) (t1 a1) +#define AC2(t1,a1,t2,a2) (t1 a1, t2 a2) +#define AC3(t1,a1,t2,a2,t3,a3) (t1 a1, t2 a2, t3 a3) +#define AC4(t1,a1,t2,a2,t3,a3,t4,a4) (t1 a1, t2 a2, t3 a3, t4 a4) +#define AC5(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) +#else +#define AC1(t1,a1) (a1) t1 a1; +#define AC2(t1,a1,t2,a2) (a1,a2) t1 a1; t2 a2; +#define AC3(t1,a1,t2,a2,t3,a3) (a1,a2,a3) t1 a1; t2 a2; t3 a3; +#define AC4(t1,a1,t2,a2,t3,a3,t4,a4) (a1,a2,a3,a4) t1 a1; t2 a2; t3 a3; t4 a4; +#define AC5(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5) (a1,a2,a3,a4,a5) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5; +#endif + +static +void +MY_LayoutISISetY _ANSI_ARGS_((Layout_Graph*, Node*, double)); + + + +/* + *-------------------------------------------------------------- + * + * LayoutDebugging -- + * + * This procedure is invoked to print debugging informations. + * + * Results: + * None + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +#if DEBUGGING +void +LayoutDebugging( + Layout_Graph* This, + Node *currentNode, /* This is the current node. */ + char *string, + int type) +{ + double tmpX, tmpY; + + if(THIS(graphOrder)) { + /* Place nodes top down. */ + tmpX = THIS(xOffset) - NODE_HEIGHT(THIS(rootNode)); + tmpY = THIS(yOffset) - NODE_WIDTH(THIS(rootNode)); + } else { + /* Place nodes left to right. */ + tmpX = THIS(xOffset) - NODE_WIDTH(THIS(rootNode)); + tmpY = THIS(yOffset) - NODE_HEIGHT(THIS(rootNode)); + } + + if(!DUMMY_NODE(currentNode)) { + fprintf(stderr, "%-6s Node %-3ld: x=%-g y=%-g x=%-g y=%-g\n", + /* string, CANVAS_ITEM_ID(NODE_ITEM(currentNode)), 08nov95 wmt */ + string, 0L, + NODE_X_POS(currentNode) + tmpX, + NODE_Y_POS(currentNode) + tmpY, + NODE_X_POS(currentNode), + NODE_Y_POS(currentNode)); + } else { + fprintf(stderr, "%-6s Node dummy: x=%-g y=%-g x=%-g y=%-g\n", + string, NODE_X_POS(currentNode) + tmpX, + NODE_Y_POS(currentNode) + tmpY, + NODE_X_POS(currentNode), + NODE_Y_POS(currentNode)); + } + switch (type) { + case 1: + fprintf(stderr, + " x=%-g y=%-g x=%-g y=%-g\n", + TREE_TMP_X_POS(currentNode) + tmpX, + TREE_TMP_Y_POS(currentNode) + tmpY, + TREE_TMP_X_POS(currentNode), + TREE_TMP_Y_POS(currentNode)); + break; + default: + break; + } +} +#endif + +/* + *-------------------------------------------------------------- + * + * LayoutISISetX -- + * + * This procedure is invoked to calculate the x ISI position. + * + * Results: + * None + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define min(a,b) ((a) > (b) ? (b) : (a)) +#endif +static +void +LayoutISISetX AC2(Layout_Graph*,This, Node*,currentNode) /* This is the current node. */ +{ + int counter, visitedAllChilds = 1; + + if(IGNORE_NODE(currentNode)) { + return; + } + if(VISITED_NODE(currentNode)) { + return; + } + + FOR_ALL_SUCCS(currentNode, counter) { + /* Are there un layouted children ? */ + if(IGNORE_EDGE(SUCC_EDGE(currentNode, counter))) { + continue; + } + if(IGNORE_NODE(SUCC_NODE(currentNode, counter))) { + continue; + } + if(!VISITED_NODE(SUCC_NODE(currentNode, counter))) { + visitedAllChilds = 0; + } + } + +/* SET_VISITED_NODE(currentNode, 1);*/ + if(!visitedAllChilds) { + FOR_ALL_SUCCS(currentNode, counter) { + /* Layout the children of this node. */ + if(IGNORE_EDGE(SUCC_EDGE(currentNode, counter))) { + continue; + } + if(IGNORE_NODE(SUCC_NODE(currentNode, counter))) { + continue; + } + if(!VISITED_NODE(SUCC_NODE(currentNode, counter))) { + LayoutISISetX(This,SUCC_NODE(currentNode, counter)); + } + } + if(SUCC_NUM(currentNode) == 1) { + SET_NODE_X_POS(currentNode, + NODE_X_POS(SUCC_NODE(currentNode, 0))); + } + else + { + + /* Khamis 8:30 23 Oct 1996 */ + int i, pingo = 0; + double x1 = 0.0, x2 = 0.0; + FOR_ALL_SUCCS (currentNode, i) + { + if(IGNORE_NODE(SUCC_NODE(currentNode, i))) + continue; + /* + if(! VISITED_NODE(SUCC_NODE(currentNode, i))) + continue; + */ + if (PARENT_NODE(SUCC_NODE(currentNode, i), 0) != + currentNode) + continue; + if (! pingo) + { + x1 = NODE_X_POS(SUCC_NODE(currentNode, i)); + pingo = 1; + } + x1 = min (x1, NODE_X_POS(SUCC_NODE(currentNode, i))); + x2 = max (x2, NODE_X_POS(SUCC_NODE(currentNode, i))); + } + if (! pingo) + { + x1 = x2 = NODE_X_POS (SUCC_NODE(currentNode, 0)); + } + +#if 1 /* Khamis 8:30 23 Oct 1996 */ + SET_NODE_X_POS(currentNode, x1 + (x2 - x1) / 2.0); +#else /* original */ + SET_NODE_X_POS(currentNode, + NODE_X_POS(SUCC_NODE(currentNode, 0)) + + ((NODE_X_POS(SUCC_NODE(currentNode, + SUCC_NUM(currentNode)-1)) - + NODE_X_POS(SUCC_NODE(currentNode, 0))) / 2)); +#endif + } + } + else + { + /* Set the x position of the current node. */ + if(THIS(graphOrder)) { + /* Place nodes top down. */ + SET_NODE_X_POS(currentNode, THIS(maxXPosition)); + THIS(maxXPosition) = NODE_X_POS(currentNode) + THIS(iconSpaceH) + + THIS(edgeWidth) + NODE_WIDTH(currentNode); + } else { + /* Place nodes left to right. */ + SET_NODE_X_POS(currentNode, THIS(maxXPosition)); + THIS(maxXPosition) = NODE_X_POS(currentNode) + THIS(iconSpaceV) + + THIS(edgeHeight) + NODE_HEIGHT(currentNode); + } + } + SET_VISITED_NODE(currentNode, 1); +} + +/* + *-------------------------------------------------------------- + * + * LayoutISISetY -- + * + * This procedure is invoked to calculate the y ISI position. + * + * Results: + * None + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static +void +LayoutISISetY AC2(Layout_Graph*,This, Node*,currentNode) /* This is the current node. */ +{ + int counter; + double tmpMaxY; + + /* Was this node already layouted ? */ + if(IGNORE_NODE(currentNode)) { + return; + } + if(VISITED_NODE(currentNode)) { + return; + } + + SET_VISITED_NODE(currentNode, 1); + + if(PARENT_NUM(currentNode) != 0) { + FOR_ALL_PARENTS(currentNode, counter) { + /* Are there un layouted parents ? */ + if(IGNORE_EDGE(PARENT_EDGE(currentNode, counter))) { + /*continue;*/ + break; + } + if(IGNORE_NODE(PARENT_NODE(currentNode, counter))) { + /*continue;*/ + break; + } + if(!VISITED_NODE(PARENT_NODE(currentNode, counter))) { + LayoutISISetY(This,PARENT_NODE(currentNode, counter)); + } + break; + } + tmpMaxY = 0; + FOR_ALL_PARENTS(currentNode, counter) { + if(THIS(graphOrder)) { + if(NODE_Y_POS(PARENT_NODE(currentNode, counter)) + + NODE_HEIGHT(PARENT_NODE(currentNode, counter)) > tmpMaxY) { + tmpMaxY = NODE_Y_POS(PARENT_NODE(currentNode, counter)) + + NODE_HEIGHT(PARENT_NODE(currentNode, counter)); + } + } else { + if(NODE_Y_POS(PARENT_NODE(currentNode, counter)) + + NODE_WIDTH + (PARENT_NODE(currentNode, counter)) > tmpMaxY) { + tmpMaxY = NODE_Y_POS(PARENT_NODE(currentNode, counter)) + + NODE_WIDTH(PARENT_NODE(currentNode, counter)); + } + } + break; + } + if(THIS(graphOrder)) { + /* Place nodes top down. */ + SET_NODE_Y_POS(currentNode, tmpMaxY + THIS(edgeHeight) + THIS(iconSpaceV)); + } else { + /* Place nodes left to right. */ + SET_NODE_Y_POS(currentNode, tmpMaxY + THIS(edgeWidth) + THIS(iconSpaceH)); + } + } else { + if(THIS(graphOrder)) { + /* Place nodes top down. */ + SET_NODE_Y_POS(currentNode, 0); + } else { + /* Place nodes left to right. */ + SET_NODE_Y_POS(currentNode, 0); + } + } + + /*SET_VISITED_NODE(currentNode, 1);*/ +} + +/*********************************************************/ +static +void +MY_LayoutISISetY AC3(Layout_Graph*,This, Node*,currentNode, double, y) +{ + int counter; + double tmpMaxY; + + /* Was this node already layouted ? */ + if(IGNORE_NODE(currentNode)) { + return; + } + if(VISITED_NODE(currentNode)) { + return; + } + + SET_VISITED_NODE(currentNode, 1); + + SET_NODE_Y_POS(currentNode, y); + + FOR_ALL_SUCCS (currentNode, counter) { + /* Are there un layouted parents ? */ + if(IGNORE_EDGE(PARENT_EDGE(currentNode, counter))) { + /*continue;*/ + break; + } + if(IGNORE_NODE(PARENT_NODE(currentNode, counter))) { + /*continue;*/ + break; + } + + if (PARENT_NODE(SUCC_NODE(currentNode, counter), 0) != + currentNode) + continue; + + if(THIS(graphOrder)) { + tmpMaxY = NODE_Y_POS (currentNode) + NODE_HEIGHT (currentNode); + /*+ THIS(edgeHeight) + THIS(iconSpaceV); */ + } else { + tmpMaxY = NODE_Y_POS(currentNode) + + NODE_WIDTH(currentNode) + + THIS(edgeWidth) + THIS(iconSpaceH); + } + + MY_LayoutISISetY(This, PARENT_NODE(currentNode, counter), + tmpMaxY); + } +} +/*********************************************************/ + + + +/* + *-------------------------------------------------------------- + * + * LayoutTreeSetX -- + * + * This procedure is invoked to calculate the x tree position. + * The procedure is called for all icons in the topological + * order. + * + * Results: + * None + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +static +void +LayoutTreeSetX AC2(Layout_Graph*,This, Node*,currentNode) /* This is the current node */ +{ + int counter; + + /* Was this node already layouted ? */ + if(TREE_TMP_X_POS(currentNode) != -1 || IGNORE_NODE(currentNode)) { + return; + } + if(DUMMY_NODE(currentNode)) { + return; + } + + SET_VISITED_NODE(currentNode, 1); + if(PARENT_NUM(currentNode) > 0 && + VISITED_NODE(PARENT_NODE(currentNode, 0))) { + /* There are parents, and the parent was already visited. This */ + /* means that this node is the first child we layout at this */ + /* level. That means it occurs at the same level as the parent. */ + SET_VISITED_NODE(PARENT_NODE(currentNode, 0), 0); + SET_TREE_TMP_X_POS(currentNode, + TREE_TMP_X_POS(PARENT_NODE(currentNode, 0))); + } else { + /* Append the icon to the current maximal x position. It is not */ + /* the first child of the parent. */ + SET_TREE_TMP_X_POS(currentNode, THIS(maxXPosition)); + } + + /* Set the x position of the current node. If the order is top down, */ + /* we use the maximum edge width. */ + if(THIS(graphOrder)) { + /* Place nodes top down. */ + SET_NODE_X_POS(currentNode, TREE_TMP_X_POS(currentNode)); + /* Do we have a new maximal x position ? */ + if(NODE_X_POS(currentNode) + THIS(iconSpaceH) + THIS(edgeWidth) + + NODE_WIDTH(currentNode) > THIS(maxXPosition)) { + THIS(maxXPosition) = NODE_X_POS(currentNode) + THIS(iconSpaceH) + + THIS(edgeWidth) + NODE_WIDTH(currentNode); + } + } else { + /* Place nodes left to right. */ + SET_NODE_X_POS(currentNode, TREE_TMP_X_POS(currentNode)); + /* Do we have a new maximal x position ? */ + if((NODE_X_POS(currentNode) + THIS(iconSpaceV) + THIS(edgeHeight) + + NODE_HEIGHT(currentNode)) > THIS(maxXPosition)) { + THIS(maxXPosition) = NODE_X_POS(currentNode) + THIS(iconSpaceV) + + THIS(edgeHeight) + NODE_HEIGHT(currentNode); + } + } + + /* Walk through all successors. */ + FOR_ALL_SUCCS(currentNode, counter) { + /* Layout the children of this node. */ + if(IGNORE_NODE(SUCC_EDGE(currentNode, counter))) { + continue; + } + LayoutTreeSetX(This,SUCC_NODE(currentNode, counter)); + } +} + +/* + *-------------------------------------------------------------- + * + * LayoutTreeSetY -- + * + * This procedure is invoked to calculate the y tree position. + * + * Results: + * None + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +static +void +LayoutTreeSetY AC2(Layout_Graph*,This, Node*,currentNode) /* This is the current node. */ +{ + int counter; + double tmpMaxY; + + if(IGNORE_NODE(currentNode)) { + return; + } + if(DUMMY_NODE(currentNode)) { + return; + } + if(VISITED_NODE(currentNode)) { + return; + } + + SET_VISITED_NODE(currentNode, 1); + tmpMaxY = 0; + /* Walk through all parents. */ + FOR_ALL_PARENTS(currentNode, counter) { + /* Find the parent of this node that has the greatest Y. This way */ + /* the graph is always growing to the Y direction. */ + if(IGNORE_NODE(PARENT_EDGE(currentNode, counter)) || + IGNORE_NODE(PARENT_NODE(currentNode, counter))) { + continue; + } + if(THIS(graphOrder)) { + /* Place nodes top down. */ + if(TREE_TMP_Y_POS(PARENT_NODE(currentNode, counter)) + + NODE_HEIGHT(PARENT_NODE(currentNode, counter)) + + THIS(edgeHeight) + THIS(iconSpaceV) > tmpMaxY) { + tmpMaxY = TREE_TMP_Y_POS(PARENT_NODE(currentNode, counter)) + + NODE_HEIGHT(PARENT_NODE(currentNode, counter)) + THIS(edgeHeight) + + THIS(iconSpaceV); + } + } else { + if(TREE_TMP_Y_POS(PARENT_NODE(currentNode, counter)) + + NODE_WIDTH(PARENT_NODE(currentNode, counter)) + + THIS(edgeWidth) + THIS(iconSpaceH) > tmpMaxY) { + tmpMaxY = TREE_TMP_Y_POS(PARENT_NODE(currentNode, counter)) + + NODE_WIDTH(PARENT_NODE(currentNode, counter)) + THIS(edgeWidth) + + THIS(iconSpaceH); + } + } + } + + /* Set the y position of the current node. */ + if(THIS(graphOrder)) { + /* Place nodes top down. */ + SET_NODE_Y_POS(currentNode, tmpMaxY); + /* Keep the maximal y position, this way we can later calculate the */ + /* correct Y position for children of this widget. */ + SET_TREE_TMP_Y_POS(currentNode, NODE_Y_POS(currentNode)); + } else { + /* Place nodes left to right. */ + SET_NODE_Y_POS(currentNode, tmpMaxY); + /* Keep the maximal y position, this way we can later calculate the */ + /* correct Y position for children of this widget. */ + SET_TREE_TMP_Y_POS(currentNode, NODE_Y_POS(currentNode)); + } +} + +/* + *-------------------------------------------------------------- + * + * createnode -- + * + * This procedure is invoked to create a new node. Optionally the + * procedure can be used to create dummy nodes. In that case the + * fromNode and toNode parameters are specified. + * + * Results: + * None + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +int +LayoutCreateNode AC4(Layout_Graph*,This,pItem,itemPtr, pItem,fromNode, pItem, toNode) +{ + int counter1 = 0, counter2 = 0, counter3 = 0, counter4 = 0, found = 0; + Node *tmpNode; + Edge *tmpEdge; + ItemGeom bbox; + + /* see if this item was already added */ + FOR_ALL_NODES(counter1) { + if(NODE_ITEM(THIS(nodes)[counter1]) == itemPtr) { + THIS(errmsg) = "attempt to insert duplicate graph node"; + return LAYOUT_ERROR; + } + } + THIS(nodeNum)++; + if(THIS(nodes) == NULL) { + THIS(nodes) = (Node **) ckalloc(THIS(nodeNum) * sizeof(Node *)); + } else { + THIS(nodes) = (Node **) ckrealloc((char *) THIS(nodes), + THIS(nodeNum) * sizeof(Node *)); + } + tmpNode = (Node *) ckalloc(sizeof(Node)); + SET_NODE_ITEM(tmpNode, itemPtr); + SET_IGNORE_NODE(tmpNode, 0); + SET_VISITED_NODE(tmpNode, 0); + SET_NODE_X_POS(tmpNode, 0); + SET_NODE_Y_POS(tmpNode, 0); + SET_TREE_TMP_X_POS(tmpNode, -1); + SET_TREE_TMP_Y_POS(tmpNode, -1); + bbox.x1 = bbox.y1 = bbox.x2 = bbox.y2 = bbox.width = bbox.height = 0; + SET_NODE_GEOM(tmpNode,bbox); + SET_PARENT_NUM(tmpNode, 0); + tmpNode->parent = (Edge**) NULL; + SET_SUCC_NUM(tmpNode, 0); + tmpNode->succ = (Edge**) NULL; + THIS(nodes)[THIS(nodeNum)-1] = tmpNode; + +#if 0 + /* create the specific data slot. */ + if(createdatanode != NULL) { + (*createdatanode)(THIS(nodes)[THIS(nodeNum)-1]); + } +#endif + + /* insert the dummy node. */ + if(fromNode != (Node*) NULL && toNode != (Node*) NULL) { + FOR_ALL_NODES(counter1) { + if(THIS(nodes)[counter1] == fromNode) { + FOR_ALL_SUCCS(THIS(nodes)[counter1], counter2) { + if(SUCC_NODE(THIS(nodes)[counter1], counter2) == toNode) { + found++; + break; + } + } + break; + } + } + FOR_ALL_NODES(counter3) { + if(THIS(nodes)[counter3] == toNode) { + FOR_ALL_PARENTS(THIS(nodes)[counter3], counter4) { + if(PARENT_NODE(THIS(nodes)[counter3], counter4) == fromNode) { + found++; + break; + } + } + break; + } + } + if(found == 2) { + DEBUG_PRINT_NODE_POS(This, THIS(nodes)[counter1], "dummy insert from"); + DEBUG_PRINT_NODE_POS(This, THIS(nodes)[counter3], "dummy insert to"); + SET_PARENT_NUM(tmpNode, 1); + SET_SUCC_NUM(tmpNode, 1); + SET_NODE_X_POS(tmpNode, 10); + SET_NODE_Y_POS(tmpNode, 10); + THIS(nodes)[THIS(nodeNum)-1]->parent = (Edge**) + ckalloc(THIS(nodes)[THIS(nodeNum)-1]->parentNum * sizeof(Edge*)); + tmpEdge = (Edge* ) ckalloc(sizeof(Edge)); + SET_IGNORE_EDGE(tmpEdge, 0); + SET_VISITED_EDGE(tmpEdge, 0); + tmpEdge->fromNode = THIS(nodes)[counter1]; + tmpEdge->toNode = THIS(nodes)[counter3]; + THIS(nodes)[THIS(nodeNum)-1]->parent[0] = tmpEdge; + THIS(nodes)[THIS(nodeNum)-1]->succ = (Edge**) + ckalloc(THIS(nodes)[THIS(nodeNum)-1]->succNum * sizeof(Edge* )); + THIS(nodes)[THIS(nodeNum)-1]->succ[0] = tmpEdge; + THIS(nodes)[counter3]->parent[counter4]->toNode = tmpNode; + THIS(nodes)[counter1]->succ[counter2]->fromNode = tmpNode; + } + } + return LAYOUT_OK; +} + +int +LayoutDeleteNode AC2(Layout_Graph*,This, pItem,nodeid) +{ + register int i; + + /* find the matching node*/ + FOR_ALL_NODES(i) { + if(NODE_ITEM(THIS(nodes)[i]) == nodeid) { + return deletenode(This,THIS(nodes)[i],i); + } + } + THIS(errmsg) = "node delete: no such node"; + return LAYOUT_ERROR; +} + +static +int +deletenode AC3(Layout_Graph*,This, Node*,thisnode, int,index) +{ + register int i; + /* remove all attached edges */ + FOR_ALL_EDGES(i) { + register Edge* e = THIS(edges)[i]; + if(e->toNode == thisnode + || e->fromNode == thisnode) { + deleteedge(This,e,i); + } + } + + /* clean up node */ + if(thisnode->parent) ckfree((char*)thisnode->parent); + if(thisnode->succ) ckfree((char*)thisnode->succ); + + /* free and clear node */ + THIS(nodeNum)--; + if(THIS(nodeNum) > 0) { + THIS(nodes)[index] = THIS(nodes)[THIS(nodeNum)]; + } + ckfree((char*)thisnode); + return LAYOUT_OK; +} + + +int +LayoutCreateEdge AC4(Layout_Graph*,This, pItem,edgeid, pItem,fromid, pItem,toid) +{ + register int i; + register Node* n; + Node* fromnode = NULL; + Node* tonode = NULL; + Edge* tmpEdge; + + /* see if this item was already added */ + FOR_ALL_EDGES(i) { + if(EDGE_ITEM(THIS(edges)[i]) == edgeid) { + THIS(errmsg) = "attempt to insert duplicate graph edge"; + return LAYOUT_ERROR; + } + } + /* locate the actual from and to nodes */ + FOR_ALL_NODES(i) { + n = THIS(nodes)[i]; + if(NODE_ITEM(n) == fromid) { + fromnode = n; + } else if(NODE_ITEM(n) == toid) { + tonode = n; + } + } + if(!fromnode || !tonode) { + THIS(errmsg) = "edge was missing from or to node"; + return LAYOUT_ERROR; + } + + /* create Edge */ + tmpEdge = (Edge* ) ckalloc(sizeof(Edge)); + if(!tmpEdge) { + THIS(errmsg) = "malloc failure"; + return LAYOUT_ERROR; + } + SET_IGNORE_EDGE(tmpEdge, 0); + SET_VISITED_EDGE(tmpEdge, 0); + tmpEdge->edgeid = edgeid; + tmpEdge->fromNode = fromnode; + tmpEdge->toNode = tonode; + + THIS(edgeNum)++; + if(THIS(edges) == NULL) { + THIS(edges) = (Edge* *) ckalloc(THIS(edgeNum) * sizeof(Edge* )); + } else { + THIS(edges) = (Edge* *) ckrealloc((char *) THIS(edges), + THIS(edgeNum) * sizeof(Edge* )); + } + THIS(edges)[THIS(edgeNum)-1] = tmpEdge; + + /* insert the succ and parent edge structs */ + tonode->parentNum++; + if(tonode->parent == NULL) { + tonode->parent = (Edge**) + ckalloc(tonode->parentNum * sizeof(Edge*)); + } else { + tonode->parent = (Edge**) + ckrealloc((char *) tonode->parent, + tonode->parentNum * sizeof(Edge*)); + } + tonode->parent[tonode->parentNum - 1] = tmpEdge; + + fromnode->succNum++; + if(fromnode->succ == NULL) { + fromnode->succ = (Edge**) + ckalloc(fromnode->succNum * sizeof(Edge*)); + } else { + fromnode->succ = (Edge**) + ckrealloc((char *) fromnode->succ, + fromnode->succNum * sizeof(Edge*)); + } + fromnode->succ[fromnode->succNum-1] = tmpEdge; + + return LAYOUT_OK; +} + +static +void +compress_succ AC2(Layout_Graph*,This, Node*,n) +{ + register Edge** p; + register Edge** q; + + for(p=n->succ,q=p+(n->succNum);p < q;p++) { + if(*p != NULL) continue; + /* found a null entry earlier than where q is pointing */ + /* move q down to look for a non-null entry */ + do { --q; } while(q > p && *q == NULL); + if(q <= p) break; /* p points to last non-null entry */ + *p = *q; + } + n->succNum = p - n->succ; +} + +static +void +compress_parent AC2(Layout_Graph*,This, Node*,n) +{ + register Edge** p; + register Edge** q; + + for(p=n->parent,q=p+(n->parentNum);p < q;p++) { + if(*p != NULL) continue; + /* found a null entry earlier than where q is pointing */ + /* move q down to look for a non-null entry */ + do { --q; } while(q > p && *q == NULL); + if(q <= p) break; /* p points to last non-null entry */ + *p = *q; + } + n->parentNum = p - n->parent; +} + +static +int +deleteedge AC3(Layout_Graph*,This, Edge*,e, int,index) +{ + register int i; + register int j; + register int found; + + /* remove all references to this Edge */ + FOR_ALL_NODES(i) { + register Node* n = THIS(nodes)[i]; + found = 0; + FOR_ALL_SUCCS(n,j) { + if(SUCC_EDGE(n,j) == e) { + SUCC_EDGE(n,j) = NULL; + found = 1; + } + } + if(found) {compress_succ(This,n);} + found = 0; + FOR_ALL_PARENTS(n,j) { + if(PARENT_EDGE(n,j) == e) { + PARENT_EDGE(n,j) = NULL; + found = 1; + } + } + if(found) {compress_parent(This,n);} + } + /* free and clear Edge*/ + THIS(edgeNum)--; + if(THIS(edgeNum) > 0) { + THIS(edges)[index] = THIS(edges)[THIS(edgeNum)]; + } + ckfree((char*)e); + return LAYOUT_OK; +} + +int +LayoutDeleteEdge AC2(Layout_Graph*,This, pItem,eid) +{ + register int i; + + /* find matching edge object */ + FOR_ALL_EDGES(i) { + register Edge* e = THIS(edges)[i]; + if(e->edgeid == eid) { + return deleteedge(This,e,i); + } + } + THIS(errmsg) = "edge delete: no such edge"; + return LAYOUT_ERROR; +} + + +/* + *-------------------------------------------------------------- + * + * LayoutBuildGraph -- + * + * This procedure is invoked to create the internal + * graph structure used for layouting. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +static +int +LayoutBuildGraph AC1(Layout_Graph*,This) +{ + register int counter; + + /* Walk through all nodes to compute various things */ + FOR_ALL_NODES(counter) { + register Node* n = THIS(nodes)[counter]; + /* Find the greatest icon dimensions. */ + if(NODE_WIDTH(n) > THIS(iconWidth)) { + THIS(iconWidth) = (int)NODE_WIDTH(n); + } + if(NODE_HEIGHT(n) > THIS(iconHeight)) { + THIS(iconHeight) = (int)NODE_HEIGHT(n); + } + } + + return LAYOUT_OK; +} + +/* + *-------------------------------------------------------------- + * + * LayoutClearGraph -- + * + *-------------------------------------------------------------- + */ + +void +LayoutClearGraph AC1(Layout_Graph*,This) +{ + register int counter; + register Node* n; + + /* Free allocated memory. */ + FOR_ALL_EDGES(counter) { + ckfree((char *) THIS(edges)[counter]); + } + THIS(edgeNum) = 0; + FOR_ALL_NODES(counter) { + n = THIS(nodes)[counter]; + if (n->parent != NULL) + ckfree((char*)n->parent); + if (n->succ != NULL) + ckfree((char*)n->succ); + if (n != NULL) + ckfree((char *)n); + } + THIS(nodeNum) = 0; + FOR_ALL_TOP_NODES(counter) { + ckfree((char *) THIS(topList)[counter]); + } + THIS(topListNum) = 0; + if (THIS(topList) != NULL) + { + ckfree ((char *) (THIS(topList))); + THIS(topList) = NULL; + } + if (THIS(nodes) != NULL) + { + ckfree ((char *) (THIS(nodes))); + THIS(nodes) = NULL; + } + THIS(rootNode) = NULL; +} + + +/* + *-------------------------------------------------------------- + * + * LayoutFreeGraph -- + * + * This procedure is invoked to free the graph structures + * used for layouting. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +void +LayoutFreeGraph AC1(Layout_Graph*,This) +{ + LayoutClearGraph(This); + + /* now cleanup the Layout Graph structure */ + if (THIS(edges) != NULL) + { + ckfree((char *) THIS(edges)); + THIS(edges) = NULL; + } + if (THIS(nodes) != NULL) + { + ckfree((char *) THIS(nodes)); + THIS(nodes) = NULL; + } + if (THIS(topList) != NULL) + { + ckfree((char *) THIS(topList)); + THIS(topList) = NULL; + } + + /* free graph layout structure */ + ckfree ((char *) This); +} + +/* + *-------------------------------------------------------------- + * + * LayoutGraphRoot -- + * + * This procedure is invoked to find the root of a graph. + * + * Results: + * The root node. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +static +Node* +LayoutGraphRoot AC1(Layout_Graph*,This) +{ + int optimalRootNum = -10000, minParentNum = -1, maxSuccNum = -1, + counter, counter1, counter2, counter3, lidx; + Node *tmprootNode, *node; + + /* Khamis 27-mar-97 + * reorder nodes, so that nodes with not empty subtree displayed + * first + */ + lidx = 0; + FOR_ALL_NODES(counter) + { + if (counter == 0 || IGNORE_NODE(THIS(nodes)[counter])) + continue; + + if (SUCC_NUM(THIS(nodes)[counter]) > SUCC_NUM(THIS(nodes)[lidx])) + { + node = THIS(nodes)[counter]; + THIS(nodes)[counter] = THIS(nodes)[lidx]; + THIS(nodes)[lidx] = node; + + /* search for next node with no subtree */ + while (SUCC_NUM(THIS(nodes)[lidx]) > 0 && lidx < counter) + { + lidx ++; + } + } + } + + tmprootNode = THIS(rootNode); + + /* Find a root node. This node has no parents. In case we do not */ + /* have such a node... find the node with the smallest number of */ + /* parents. */ + +#if 0 /* Zsolt Koppany */ + tmprootNode = THIS(nodes)[0]; + return tmprootNode; +#endif + if(!tmprootNode) { + /* We try to find the node with the most children and the least */ + /* parents. This node will become root. */ + FOR_ALL_NODES(counter) { + if(IGNORE_NODE(THIS(nodes)[counter])) { + continue; + } + if((SUCC_NUM(THIS(nodes)[counter]) > 0 && + optimalRootNum <= (SUCC_NUM(THIS(nodes)[counter]) - + PARENT_NUM(THIS(nodes)[counter])) && + (minParentNum > PARENT_NUM(THIS(nodes)[counter]) || + (minParentNum == PARENT_NUM(THIS(nodes)[counter]) && + maxSuccNum < SUCC_NUM(THIS(nodes)[counter])))) || + optimalRootNum == -10000 || + + /* khamis: 17-mars-97, root with no parents have more priority */ + PARENT_NUM(THIS(nodes)[counter]) < PARENT_NUM(tmprootNode)) { + tmprootNode = THIS(nodes)[counter]; + + minParentNum = PARENT_NUM(THIS(nodes)[counter]); + maxSuccNum = SUCC_NUM(THIS(nodes)[counter]); + if(SUCC_NUM(THIS(nodes)[counter]) > 0) { + optimalRootNum = + (SUCC_NUM(THIS(nodes)[counter]) - PARENT_NUM(THIS(nodes)[counter])); + } + } + } + } + + /* No nodes... so abort the search. */ + if(tmprootNode == NULL) { + return NULL; + } + + /* There is no node with no parents. So use the node with the */ + /* smallest number of parents, and ignore the edges leading to this */ + /* node. */ + if(PARENT_NUM(tmprootNode) != 0) { + for (counter1 = 0; counter1 < PARENT_NUM(tmprootNode); counter1++) { + SET_IGNORE_NODE(PARENT_EDGE(tmprootNode, counter1), 1); + FOR_ALL_NODES(counter2) { + /* Ignore dummy nodes. */ + if(DUMMY_NODE(THIS(nodes)[counter2])) { + continue; + } + if(NODE_ITEM(THIS(nodes)[counter2]) == + NODE_ITEM(PARENT_NODE(tmprootNode, counter1))) { + FOR_ALL_SUCCS(THIS(nodes)[counter2], counter3) { + if(NODE_ITEM(SUCC_NODE(THIS(nodes)[counter2], counter3)) == + NODE_ITEM(tmprootNode)) { + SET_IGNORE_NODE(SUCC_EDGE(THIS(nodes)[counter2], counter3), 1); + } + } + } + } + } + } + return tmprootNode; +} + +/* + *-------------------------------------------------------------- + * + * LayoutGraphSortTopological -- + * + * This procedure is invoked to sort a graph topological. + * + * Results: + * None + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +static +void +LayoutGraphSortTopological AC2(Layout_Graph*,This, Node*,currentNode) /* This is the current node. */ +{ + int counter; + Topology *tmpTopology; + + if(VISITED_NODE(currentNode) || IGNORE_NODE(currentNode)) { + return; + } + + /* Append the current node to the list of topologically sorted */ + /* nodes. */ + THIS(topListNum)++; + if(THIS(topList) == NULL) { + THIS(topList) = (Topology **) ckalloc(THIS(topListNum) * sizeof(Topology *)); + } else { + THIS(topList) = (Topology **) ckrealloc((char *) THIS(topList), + THIS(topListNum) * sizeof(Topology *)); + } + tmpTopology = (Topology *) ckalloc(sizeof(Topology)); + tmpTopology->nodePtr = currentNode; + THIS(topList)[THIS(topListNum)-1] = tmpTopology; + + SET_VISITED_NODE(currentNode, 1); + /* Walk through all successors. */ + FOR_ALL_SUCCS(currentNode, counter) { + if(IGNORE_EDGE(SUCC_EDGE(currentNode, counter))) { + continue; + } + if(IGNORE_NODE(SUCC_NODE(currentNode, counter))) { + continue; + } + if(VISITED_NODE(SUCC_NODE(currentNode, counter))) { + SET_IGNORE_EDGE(SUCC_EDGE(currentNode, counter), 1); + continue; + } + LayoutGraphSortTopological(This,SUCC_NODE(currentNode, counter)); + } +} + +/* + *-------------------------------------------------------------- + * + * LayoutGraphPlaceNodes -- + * + * This procedure is invoked to actually place the graph nodes. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +static +int +LayoutGraphPlaceNodes AC1(Layout_Graph*,This) +{ + int counter; + double tmpX, tmpY; + + SRANDOM(getpid() + time((time_t *) NULL)); + + FOR_ALL_NODES(counter) { + register Node* n = THIS(nodes)[counter]; + if(IGNORE_NODE(n)) { + continue; + } + if(NODE_X_POS(n) != -1 && + NODE_Y_POS(n) != -1) { + if(THIS(graphOrder)) { + /* Place nodes top down. */ + tmpX = NODE_X_POS(n); + tmpY = NODE_Y_POS(n); + } else { + /* Place nodes left to right. */ + tmpX = NODE_Y_POS(n); + tmpY = NODE_X_POS(n); + } + } else { + /* are we allowed to place the icon ? */ + if(THIS(keepRandomPositions) && + NODE_X_POS(n) > 0 && + NODE_Y_POS(n) > 0) { + continue; + } + tmpX = (long) (RANDOM % THIS(maxX)) - NODE_WIDTH(n); + tmpY = (long) (RANDOM % THIS(maxY)) - NODE_HEIGHT(n); + } + if(tmpX < 0) { + tmpX = 0; + } + if(tmpY < 0) { + tmpY = 0; + } + if(!DUMMY_NODE(n)) { + ItemGeom g; + g = NODE_GEOM(n); + /* recalc Item Geom based on our layout */ + g.x1 = tmpX+THIS(xOffset); + g.y1 = tmpY+THIS(yOffset); + g.x2 = g.x1 + g.width; + g.y2 = g.y1 + g.height; + SET_NODE_GEOM(n,g); + } + } + return LAYOUT_OK; +} + +/* + *-------------------------------------------------------------- + * + * LayoutGraphPlaceEdges -- + * + * This procedure is invoked to relayout all edges. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +static +int +LayoutGraphPlaceEdges AC1(Layout_Graph*,This) +{ + register int i; + + /* scan through all edges */ + FOR_ALL_EDGES(i) { + /* layout edges. */ + LayoutEdge(This,THIS(edges)[i], NULL, NULL); + } + return LAYOUT_OK; +} + +/* + *-------------------------------------------------------------- + * + * LayoutEdgeWidth -- + * + * This procedure is invoked to find the widest edge. Widest + * means the edge with the maximal x expansion. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +static +int +LayoutEdgeWidth AC1(Layout_Graph*,This) +{ +#if 1 /* Khamis, 19:00 20 Okt 1996 */ + THIS(edgeHeight) = 0; + THIS(edgeWidth) = 0; +#else + register int i; + if(THIS(edgeWidth) == 0) { + /* Walk through all edges. */ + FOR_ALL_EDGES(i) { + if(THIS(edges)[i]->info.height + LINE_INCREMENT > THIS(edgeHeight)) { + THIS(edgeHeight) = THIS(edges)[i]->info.height + LINE_INCREMENT; + } + if(THIS(edges)[i]->info.width + LINE_INCREMENT > THIS(edgeWidth)) { + THIS(edgeWidth) = THIS(edges)[i]->info.width + LINE_INCREMENT; + } + } + } + +#endif + + return LAYOUT_OK; +} + +/* + *-------------------------------------------------------------- + * + * LayoutEdge -- + * + * This procedure is invoked to adjust the edge to the new + * locations of the connected nodes. This algorithm only works + * for simple edges. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +static +int +LayoutEdge AC4(Layout_Graph*,This, + Edge*,e, /* Current edge. */ + Node*,fromNode, /* Source node. */ + Node*,toNode) /* Target node. */ +{ + int result = LAYOUT_OK; +#if 0 + Node *currentNode; +#endif + ItemGeom geom; + + if(fromNode == (Node*) NULL && toNode == (Node*) NULL) + { + fromNode = e->fromNode; + toNode = e->toNode; + } +#if 0 + else + { + /* Place one specific edge... */ + /* WARNING !!! this code is old and not adapted to the new Edge*/ + /* placing. The code is not tested. This stuff will be used to */ + /* display multi point edges.... */ + fromPtr = NODE_ITEM(fromNode); + while (DUMMY_NODE(toNode) && SUCC_NUM(toNode) > 0) { + toNode = SUCC_NODE(toNode, 0); + } + toPtr = NODE_ITEM(toNode); + if(itemPtr == (pItem ) NULL) { + /* Match the numeric id value to a concrete item pointer. */ + FOR_ALL_CANVAS_ITEMS(canvasPtr, itemPtr) { + if(strcmp(CANVAS_ITEM_TYPE(itemPtr), "edge") == 0) { + /* Get "from" id */ + Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin, + itemPtr->typePtr->configSpecs, + (char *) itemPtr, "-from", 0); + if(Tcl_SplitList(canvasPtr->interp, + canvasPtr->interp->result, + &argc2, &argv2) != LAYOUT_OK) { + return LAYOUT_ERROR; + } + fromId = atol(argv2[4]); + ckfree((char *) argv2); + + /* Get "to" id */ + Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin, + itemPtr->typePtr->configSpecs, + (char *) itemPtr, "-to", 0); + if(Tcl_SplitList(canvasPtr->interp, + canvasPtr->interp->result, + &argc2, &argv2) != LAYOUT_OK) { + return LAYOUT_ERROR; + } + toId = atol(argv2[4]); + ckfree((char *) argv2); + + if(fromId == CANVAS_ITEM_ID(fromPtr) && + toId == CANVAS_ITEM_ID(toPtr)) { + curPtr = itemPtr; + FOR_ALL_SUCCS(fromNode, counter1) { + Tcl_DStringInit(&positionString); + if(fromPtr->x1 > fromPtr->x2) { + THIS(posX1) = fromPtr->x1 + ((fromPtr->x2 - fromPtr->x1) / 2); + } else { + THIS(posX1) = fromPtr->x2 + ((fromPtr->x1 - fromPtr->x2) / 2); + } + if(fromPtr->y1 > fromPtr->y2) { + THIS(posY1) = fromPtr->y1 + ((fromPtr->y2 - fromPtr->y1) / 2); + } else { + THIS(posY1) = fromPtr->y2 + ((fromPtr->y1 - fromPtr->y2) / 2); + } + if(toPtr->x1 > toPtr->x2) { + THIS(posX2) = toPtr->x1 + ((toPtr->x2 - toPtr->x1) / 2); + } else { + THIS(posX2) = toPtr->x2 + ((toPtr->x1 - toPtr->x2) / 2); + } + if(toPtr->y1 > toPtr->y2) { + THIS(posY2) = toPtr->y1 + ((toPtr->y2 - toPtr->y1) / 2); + } else { + THIS(posY2) = toPtr->y2 + ((toPtr->y1 - toPtr->y2) / 2); + } + + if(fromPtr->y2 <= toPtr->y1) { + sprintf(convertBuffer, "%d %d ", THIS(posX1), fromPtr->y2); + } else { + if(fromPtr->y1 >= toPtr->y2) { + sprintf(convertBuffer, "%d %d ", THIS(posX1), fromPtr->y1); + } else { + if(fromPtr->x2 < toPtr->x1) { + sprintf(convertBuffer, "%d %d ", fromPtr->x2, THIS(posY1)); + } else { + sprintf(convertBuffer, "%d %d ", fromPtr->x1, THIS(posY1)); + } + } + } + + Tcl_DStringAppend(&positionString, convertBuffer, -1); + currentNode = SUCC_NODE(fromNode, counter1); + while (DUMMY_NODE(currentNode) && SUCC_NUM(currentNode) > 0) { + currentNode = SUCC_NODE(currentNode, 0); + sprintf(convertBuffer, "%g %g ", /*300.0, 300.0*/ + NODE_X_POS(currentNode), NODE_Y_POS(currentNode)); + Tcl_DStringAppend(&positionString, convertBuffer, -1); + } + if(NODE_ITEM(currentNode) != toPtr) { + Tcl_DStringFree(&positionString); + continue; + } + if(fromPtr->y2 <= toPtr->y1) { + sprintf(convertBuffer, "%d %d ", THIS(posX2), toPtr->y1); + } else { + if(fromPtr->y1 >= toPtr->y2) { + sprintf(convertBuffer, "%d %d ", THIS(posX2), toPtr->y2); + } else { + if(fromPtr->x2 < toPtr->x1) { + sprintf(convertBuffer, "%d %d ", toPtr->x1, THIS(posY2)); + } else { + sprintf(convertBuffer, "%d %d ", toPtr->x2, THIS(posY2)); + } + } + } + Tcl_DStringAppend(&positionString, convertBuffer, -1); + + /* Set new coordinates */ + if(Tcl_SplitList(canvasPtr->interp, positionString.string, + &argc2, &argv2) != LAYOUT_OK) { + return LAYOUT_ERROR; + } + Tcl_ResetResult(canvasPtr->interp); + result = (*curPtr->typePtr->coordProc) + (canvasPtr, curPtr, argc2, argv2); + ckfree((char *) argv2); + Tcl_DStringFree(&positionString); + } + return result; + } + } + } + } + } +#endif /* #if 0 */ + + /* Is this a regular edge ? */ + if(fromNode != NULL && toNode != NULL) { + /* calculate the various node anchors. */ + /* calc center of the from node */ + if(fromNode->info.x1 > fromNode->info.x2) { + THIS(posX1) = fromNode->info.x1 + ((fromNode->info.x2 - fromNode->info.x1) / 2); + } else { + THIS(posX1) = fromNode->info.x2 + ((fromNode->info.x1 - fromNode->info.x2) / 2); + } + if(fromNode->info.y1 > fromNode->info.y2) { + THIS(posY1) = fromNode->info.y1 + ((fromNode->info.y2 - fromNode->info.y1) / 2); + } else { + THIS(posY1) = fromNode->info.y2 + ((fromNode->info.y1 - fromNode->info.y2) / 2); + } + /* calc center of the to node */ + if(toNode->info.x1 > toNode->info.x2) { + THIS(posX2) = toNode->info.x1 + ((toNode->info.x2 - toNode->info.x1) / 2); + } else { + THIS(posX2) = toNode->info.x2 + ((toNode->info.x1 - toNode->info.x2) / 2); + } + if(toNode->info.y1 > toNode->info.y2) { + THIS(posY2) = toNode->info.y1 + ((toNode->info.y2 - toNode->info.y1) / 2); + } else { + THIS(posY2) = toNode->info.y2 + ((toNode->info.y1 - toNode->info.y2) / 2); + } + + if(THIS(edgeOrder)) { + /* Place the edges according to the graph order... only along + * the generale layout direction. */ + if(THIS(graphOrder)) { + /* Place nodes top down. */ + if(fromNode->info.y2 <= toNode->info.y1) { + geom.x1 = THIS(posX1); + geom.y1 = fromNode->info.y2; + geom.x2 = THIS(posX2); + geom.y2 = toNode->info.y1; + } else { + geom.x1 = THIS(posX1); + geom.y1 = fromNode->info.y1; + geom.x2 = THIS(posX2); + geom.y2 = toNode->info.y2; + } + } else { + /* Place nodes left to right. */ + if(fromNode->info.x2 < toNode->info.x1) { + geom.x1 = fromNode->info.x2; + geom.y1 = THIS(posY1); + geom.x2 = toNode->info.x1; + geom.y2 = THIS(posY2); + } else { + geom.x1 = fromNode->info.x1; + geom.y1 = THIS(posY1); + geom.x2 = toNode->info.x2; + geom.y2 = THIS(posY2); + } + } + } else { + /* Place the edges so that they use the shortest distance. */ + if(fromNode->info.y2 <= toNode->info.y1) { + /* from is above to */ + if(fromNode->info.x2 <= toNode->info.x1) { + /* from is left from to */ + if(THIS(graphOrder)) { + /* Place nodes top down. */ + geom.x1 = THIS(posX1); + geom.y1 = fromNode->info.y2; + geom.x2 = THIS(posX2); + geom.y2 = toNode->info.y1; + } else { + geom.x1 = fromNode->info.x2; + geom.y1 = THIS(posY1); + geom.x2 = toNode->info.x1; + geom.y2 = THIS(posY2); + } + } else { + if(fromNode->info.x1 >= toNode->info.x2) { + /* from is right from to */ + if(THIS(graphOrder)) { + /* Place nodes top down. */ + geom.x1 = THIS(posX1); + geom.y1 = fromNode->info.y2; + geom.x2 = THIS(posX2); + geom.y2 = toNode->info.y1; + } else { + geom.x1 = fromNode->info.x1; + geom.y1 = THIS(posY1); + geom.x2 = toNode->info.x2; + geom.y2 = THIS(posY2); + } + } else { + /* from is at same level as to */ + geom.x1 = THIS(posX1); + geom.y1 = fromNode->info.y2; + geom.x2 = THIS(posX2); + geom.y2 = toNode->info.y1; + } + } + } else { + if(fromNode->info.y1 >= toNode->info.y2) { + /* from is below to */ + if(fromNode->info.x2 <= toNode->info.x1) { + /* from is left from to */ + if(THIS(graphOrder)) { + /* Place nodes top down. */ + geom.x1 = THIS(posX1); + geom.y1 = fromNode->info.y1; + geom.x2 = THIS(posX2); + geom.y2 = toNode->info.y2; + } else { + geom.x1 = fromNode->info.x2; + geom.y1 = THIS(posY1); + geom.x2 = toNode->info.x1; + geom.y2 = THIS(posY2); + } + } else { + if(fromNode->info.x1 >= toNode->info.x2) { + /* from is right from to */ + if(THIS(graphOrder)) { + /* Place nodes top down. */ + geom.x1 = THIS(posX1); + geom.y1 = fromNode->info.y1; + geom.x2 = THIS(posX2); + geom.y2 = toNode->info.y2; + } else { + geom.x1 = fromNode->info.x1; + geom.y1 = THIS(posY1); + geom.x2 = toNode->info.x2; + geom.y2 = THIS(posY2); + } + } else { + /* from is at same level as to */ + geom.x1 = THIS(posX1); + geom.y1 = fromNode->info.y1; + geom.x2 = THIS(posX2); + geom.y2 = toNode->info.y2; + } + } + } else { + /* from is at same level as to */ + if(fromNode->info.x2 <= toNode->info.x1) { + /* from is left from to */ + geom.x1 = fromNode->info.x2; + geom.y1 = THIS(posY1); + geom.x2 = toNode->info.x1; + geom.y2 = THIS(posY2); + } else { + if(fromNode->info.x1 > toNode->info.x2) { + /* from is right from to */ + geom.x1 = fromNode->info.x1; + geom.y1 = THIS(posY1); + geom.x2 = toNode->info.x2; + geom.y2 = THIS(posY2); + } else { + if(fromNode->info.x1 <= toNode->info.x1) { + /* from is partially left from to */ + geom.x1 = fromNode->info.x2; + geom.y1 = THIS(posY1); + geom.x2 = toNode->info.x1; + geom.y2 = THIS(posY2); + } else { + /* from is partially right from to */ + geom.x1 = fromNode->info.x1; + geom.y1 = THIS(posY1); + geom.x2 = toNode->info.x2; + geom.y2 = THIS(posY2); + } + } + } + } + } + } + } + + /* Set new coordinates on Edge*/ + SET_EDGE_GEOM(e,geom); + + return result; +} + +/* + *-------------------------------------------------------------- + * + * LayoutISI -- + * + * This procedure is invoked to place icons with ISI. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +int +LayoutISI AC1(Layout_Graph*,This) +{ + int counter, result = LAYOUT_OK; + + THIS(maxXPosition) = 0; + THIS(maxYPosition) = 0; + if(THIS(topList)) { + /* free layout specific data slots. */ + for (counter = 0; counter < THIS(topListNum); counter++) { + ckfree((char *) THIS(topList)[counter]); + } + ckfree((char*)THIS(topList)); + THIS(topList) = NULL; + } + THIS(topListNum) = 0; + THIS(topList) = (Topology **) NULL; + + /* find the widest/highest edge. */ + LayoutEdgeWidth(This); + + /* build the internal graph structure. */ + if(LayoutBuildGraph(This) != LAYOUT_OK) { + return LAYOUT_ERROR; + } + + /* find root of the graph. */ + if((THIS(rootNode) = LayoutGraphRoot(This)) == NULL) { + THIS(errmsg) = "no root node"; + return LAYOUT_ERROR; + } + + /* sort the graph topological. */ + LayoutGraphSortTopological(This,THIS(rootNode)); + FOR_ALL_NODES(counter) { + if(PARENT_NUM(THIS(nodes)[counter]) == 0) { + LayoutGraphSortTopological(This,THIS(nodes)[counter]); + } + } + + /* Calculate the x position values. */ + RESET_VISITED_NODE(counter); + FOR_ALL_NODES(counter) { + if(PARENT_NUM(THIS(nodes)[counter]) == 0) { + LayoutISISetX(This,THIS(nodes)[counter]); + } + } + +#if 0 + RESET_VISITED_NODE(counter); + FOR_ALL_NODES(counter) { + if(PARENT_NUM(THIS(nodes)[counter]) == 0) { + MY_LayoutISISetY(This,THIS(nodes)[counter], 0); + } + } +#else + RESET_VISITED_NODE(counter); + FOR_ALL_NODES(counter) { + if(SUCC_NUM(THIS(nodes)[counter]) == 0) { + LayoutISISetY(This,THIS(nodes)[counter]); + } + } +#endif + +#if 1 + if (! THIS(graphOrder)) { + while (1) { + int found; + found = 0; + FOR_ALL_NODES(counter) { + if(PARENT_NUM (THIS(nodes)[counter]) > 0 && + NODE_Y_POS (THIS(nodes)[counter]) < + NODE_Y_POS (PARENT_NODE(THIS(nodes)[counter], 0)) + + NODE_WIDTH (PARENT_NODE(THIS(nodes)[counter], 0)) + + THIS(edgeWidth) + THIS(iconSpaceH)) { + SET_NODE_Y_POS(THIS(nodes)[counter], + + NODE_Y_POS (PARENT_NODE(THIS(nodes)[counter], 0)) + + NODE_WIDTH (PARENT_NODE(THIS(nodes)[counter], 0)) + + THIS(edgeWidth) + THIS(iconSpaceH)); + found = 1; + } + + if (SUCC_NUM (THIS(nodes)[counter]) == 1 && + PARENT_NODE (SUCC_NODE (THIS(nodes)[counter], 0), 0) == THIS(nodes)[counter]) { + SET_NODE_X_POS(SUCC_NODE (THIS(nodes)[counter], 0), + NODE_X_POS(THIS(nodes)[counter])); + } + } + if (! found) + break; + } + } +#endif + + /* Place the graph items. */ + if(LayoutGraphPlaceNodes(This) != LAYOUT_OK) { + result = LAYOUT_ERROR; + } else if(LayoutGraphPlaceEdges(This) != LAYOUT_OK) { + result = LAYOUT_ERROR; + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * LayoutMatrix -- + * + * This procedure is invoked to place icons as matrix. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +int +LayoutMatrix AC1(Layout_Graph*,This) +{ + int result = LAYOUT_OK, greatestX = 10, + greatestY = 10, greatestHeight = 0, columnCounter = 0, + tmpIconWidth = 0, offset = 0, counter; + ItemGeom geom; + + /* Scan through all canvas items. */ + FOR_ALL_NODES(counter) { + register Node* n = THIS(nodes)[counter]; + /* Find the greatest icon dimensions. */ + if(THIS(computeiconsize)) { + if(NODE_WIDTH(n) > THIS(iconWidth)) { + THIS(iconWidth) = (int)NODE_WIDTH(n); + } + if(NODE_HEIGHT(n) > THIS(iconHeight)) { + THIS(iconHeight) = (int)NODE_HEIGHT(n); + } + } + } + + /* Walk through the list of NODES */ + FOR_ALL_NODES(counter) { + register Node* n = THIS(nodes)[counter]; + geom = NODE_GEOM(n); + if(THIS(iconWidth) == 0) { + tmpIconWidth = (int)NODE_WIDTH(n); + offset = (int) ((NODE_WIDTH(n) / 2.0) - (NODE_WIDTH(n) / 2.0)); + } else { + tmpIconWidth = THIS(iconWidth); + offset = (int) ((THIS(iconWidth) / 2.0) - (NODE_WIDTH(n) / 2.0)); + } + /* Is this the highest icon so far ? */ + if(NODE_HEIGHT(n) > greatestHeight) { + greatestHeight = (int) NODE_HEIGHT(n); + } + + /* Place icon on the current line. */ + if(greatestX + tmpIconWidth < THIS(maxX) && + (THIS(elementsPerLine) == 0 || + columnCounter < THIS(elementsPerLine))) { + geom.x1 = offset + greatestX + THIS(xOffset); + geom.y1 = greatestY + THIS(yOffset); + geom.x2 = geom.x1 + geom.width; + geom.y2 = geom.y1 + geom.height; + greatestX += (tmpIconWidth + THIS(iconSpaceH)); + columnCounter++; + SET_NODE_GEOM(n,geom); + } else { + /* Place icon on the next line. */ + if(THIS(iconHeight) > 0) { + greatestY += (THIS(iconHeight) + THIS(iconSpaceV)); + } else { + greatestY += (greatestHeight + THIS(iconSpaceV)); + } + geom.x1 = 10 + offset + greatestX + THIS(xOffset); + geom.y1 = greatestY + THIS(yOffset); + geom.x2 = geom.x1 + geom.width; + geom.y2 = geom.y1 + geom.height; + greatestHeight = (int) geom.height; + greatestX = 10 + (tmpIconWidth + THIS(iconSpaceH)); + columnCounter = 1; + SET_NODE_GEOM(n,geom); + } + } + + if(THIS(hideEdges)) { + /* make all edges zero length, and place at maxX,MaxY + to get them out of the way + */ + FOR_ALL_EDGES(counter) { + geom.x2 = (geom.x1 = THIS(maxX)); + geom.y2 = (geom.y1 = THIS(maxY)); + geom.width = (geom.height = 0); + SET_EDGE_GEOM(THIS(edges)[counter],geom); + } + } else if(LayoutGraphPlaceEdges(This) != LAYOUT_OK) { + result = LAYOUT_ERROR; + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * LayoutRandom -- + * + * This procedure is invoked to place icons randomly. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +int +LayoutRandom AC1(Layout_Graph*,This) +{ + int result = LAYOUT_OK; + int counter; + + SRANDOM(getpid() + time((time_t *) NULL)); + /* walk through all nodes */ + FOR_ALL_NODES(counter) { + register Node* itemptr = THIS(nodes)[counter]; + long tmpx, tmpy; + ItemGeom geom; + + /* randomly place icons. */ + /* are we allowed to place the icon ? */ + if(THIS(keepRandomPositions) && + NODE_X_POS(itemptr) > 0 && + NODE_Y_POS(itemptr) > 0) { + continue; + } + tmpx = (long) (RANDOM % THIS(maxX)) - (long) NODE_WIDTH(itemptr); + tmpy = (long) (RANDOM % THIS(maxY)) - (long) NODE_HEIGHT(itemptr); + if(tmpx <= 0) { + tmpx = 1; + } + if(tmpy <= 0) { + tmpy = 1; + } + geom = NODE_GEOM(itemptr); + geom.x1 = tmpx + THIS(xOffset); + geom.y1 = tmpy + THIS(yOffset); + geom.x2 = geom.x1 + NODE_WIDTH(itemptr); + geom.y2 = geom.y1 + NODE_HEIGHT(itemptr); + SET_NODE_GEOM(itemptr,geom); + } + + if(LayoutGraphPlaceEdges(This) != LAYOUT_OK) { + result = LAYOUT_ERROR; + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * LayoutTree -- + * + * this procedure is invoked to place icons as tree. + * + * results: + * a standard tcl result. + * + * side effects: + * see the user documentation. + * + * 09nov95 wmt: add handling of -hideedges + *-------------------------------------------------------------- + */ + +int +LayoutTree AC1(Layout_Graph*,This) +{ + int result = LAYOUT_OK, counter; + ItemGeom geom; + + THIS(maxXPosition) = 0; + THIS(maxYPosition) = 0; + if(THIS(topList)) { + /* free layout specific data slots. */ + for (counter = 0; counter < THIS(topListNum); counter++) { + ckfree((char *) THIS(topList)[counter]); + } + ckfree((char*)THIS(topList)); + } + THIS(topListNum) = 0; + THIS(topList) = (Topology **) NULL; + + /* find the widest/highest edge. */ + LayoutEdgeWidth(This); + + /* build the internal graph structure. */ + if(LayoutBuildGraph(This) != LAYOUT_OK) { + return LAYOUT_ERROR; + } + + /* find root of the graph. */ + if((THIS(rootNode) = LayoutGraphRoot(This)) == NULL) { + THIS(errmsg) = "no root node"; + return LAYOUT_ERROR; + } + + /* sort the graph topological. */ + LayoutGraphSortTopological(This,THIS(rootNode)); + FOR_ALL_NODES(counter) { + if(PARENT_NUM(THIS(nodes)[counter]) == 0) { + LayoutGraphSortTopological(This,THIS(nodes)[counter]); + } + } + + /* calculate the position values. */ + RESET_VISITED_NODE(counter); + LayoutTreeSetX(This,THIS(rootNode)); + FOR_ALL_NODES(counter) { + if(PARENT_NUM(THIS(nodes)[counter]) == 0) { + LayoutTreeSetX(This,THIS(nodes)[counter]); + } + } + RESET_VISITED_NODE(counter); + FOR_ALL_TOP_NODES(counter) { + LayoutTreeSetY(This,TOP_NODE(counter)); + } + + /* place the graph items. */ + if(LayoutGraphPlaceNodes(This) != LAYOUT_OK) { + result = LAYOUT_ERROR; + } + if(THIS(hideEdges)) { + /* make all edges zero length, and place at maxX,MaxY + to get them out of the way + */ + FOR_ALL_EDGES(counter) { + geom.x2 = (geom.x1 = THIS(maxX)); + geom.y2 = (geom.y1 = THIS(maxY)); + geom.width = (geom.height = 0); + SET_EDGE_GEOM(THIS(edges)[counter],geom); + } + } else if(LayoutGraphPlaceEdges(This) != LAYOUT_OK) { + result = LAYOUT_ERROR; + } + return result; +} + +Layout_Graph* +LayoutCreateGraph() +{ + register Layout_Graph* This; + + This = (Layout_Graph*)ckalloc(sizeof(Layout_Graph)); + if(!This) return This; +#if 1 /* multiX */ + memset((char *)This,0,sizeof(Layout_Graph)); +#endif + /* Initialize global data. */ + THIS(graphOrder) = 0; + THIS(iconSpaceH) = 5; + THIS(iconSpaceV) = 5; + THIS(xOffset) = 4; + THIS(yOffset) = 4; + THIS(maxX) = 0; + THIS(maxY) = 0; + THIS(rootNode) = NULL; + + THIS(keepRandomPositions) = 0; + THIS(nodeNum) = 0; + THIS(nodes) = NULL; + THIS(edgeNum) = 0; + THIS(edges) = NULL; + THIS(topListNum) = 0; + THIS(topList) = NULL; + THIS(computeiconsize) = 0; + THIS(elementsPerLine) = 0; + THIS(hideEdges) = 0; + THIS(edgeHeight) = 2; + THIS(edgeOrder) = 0; + THIS(edgeWidth) = 0; + THIS(iconWidth) = 0; + THIS(iconHeight) = 0; + THIS(posX1) = 0; + THIS(posY1) = 0; + THIS(posX2) = 0; + THIS(posY2) = 0; + THIS(gridlock) = 0; +#if 0 + THIS(idlist) = NULL; +#endif + THIS(maxXPosition) = 0.0; + THIS(maxYPosition) = 0.0; +#if 1 + THIS(layoutTypesNum) = 0; +#else + THIS(layoutTypesNum) = 1; + THIS(layoutTypes) = (char **) ckalloc(2); + THIS(layoutTypes) = (char **) ckalloc(10); + *THIS(layoutTypes) = '\0'; + *(1+THIS(layoutTypes))) = '\0'; + *THIS(layoutTypes) = (char *) ckalloc(10); + strcpy(*THIS(layoutTypes), "icon"); +#endif + THIS(errmsg) = (char*)NULL; + return This; +} + +LayoutConfig +GetLayoutConfig(This) + struct Layout_Graph* This; +{ + LayoutConfig c; + c.rootnode = THIS(rootNode)?NODE_ITEM(THIS(rootNode)):NULL; + c.graphorder = THIS(graphOrder); + c.nodespaceH = (long)THIS(iconSpaceH); + c.nodespaceV = (long)THIS(iconSpaceV); + c.xoffset = THIS(xOffset); + c.yoffset = THIS(yOffset); + c.computenodesize = THIS(computeiconsize); + c.elementsperline = THIS(elementsPerLine); + c.hideedges = THIS(hideEdges); + c.keeprandompositions = THIS(keepRandomPositions); + c.maxx = THIS(maxX); + c.maxy = THIS(maxY); + c.gridlock = THIS(gridlock); + return c; +} + +void +SetLayoutConfig(This,c) + struct Layout_Graph* This; + LayoutConfig c; +{ + register int i; + THIS(graphOrder) = c.graphorder; + THIS(iconSpaceH) = c.nodespaceH; + THIS(iconSpaceV) = c.nodespaceV; + THIS(xOffset) = c.xoffset; + THIS(yOffset) = c.yoffset; + THIS(computeiconsize) = c.computenodesize; + THIS(elementsPerLine) = c.elementsperline; + THIS(hideEdges) = c.hideedges; + THIS(keepRandomPositions) = c.keeprandompositions; + THIS(maxX) = c.maxx; + THIS(maxY) = c.maxy; + THIS(gridlock) = c.gridlock; + + /* rootNode needs special work */ + if(c.rootnode) { + FOR_ALL_NODES(i) { + if(NODE_ITEM(THIS(nodes)[i]) == c.rootnode) { + THIS(rootNode) = THIS(nodes)[i]; + } + } + } +} + +int +LayoutGetIthNode(This,index,idp) + struct Layout_Graph* This; + long index; + pItem* idp; +{ + if(index < 0 || index >= THIS(nodeNum)) return LAYOUT_ERROR; + *idp = NODE_ITEM(THIS(nodes)[index]); + return LAYOUT_OK; +} + +int +LayoutGetNodeBBox(This,id,geomp) + struct Layout_Graph* This; + pItem id; + ItemGeom* geomp; +{ + register Node* ip = NULL; + register int i; + + /* find matching node */ + FOR_ALL_NODES(i) { + if(NODE_ITEM(THIS(nodes)[i]) == id) { + ip = THIS(nodes)[i]; + break; /* Khamis 11-oct-96 */ + } + } + if(!ip) return LAYOUT_ERROR; + *geomp = NODE_GEOM(ip); + return LAYOUT_OK; +} + +int +LayoutSetNodeBBox(This,id,geom) + struct Layout_Graph* This; + pItem id; + ItemGeom geom; +{ + register Node* ip = NULL; + register int i; + + /* find matching node */ + FOR_ALL_NODES(i) { + if(NODE_ITEM(THIS(nodes)[i]) == id) { + ip = THIS(nodes)[i]; + break; /* Khamis 11-oct-96 */ + } + } + if(!ip) return LAYOUT_ERROR; + if(!DUMMY_NODE(ip)) { + SET_NODE_GEOM(ip,geom); + SET_NODE_HEIGHT(ip, CALC_NODE_HEIGHT(ip)); + SET_NODE_WIDTH(ip, CALC_NODE_WIDTH(ip)); + } else { + SET_NODE_HEIGHT(ip, 1); + SET_NODE_WIDTH(ip, 1); + } + return LAYOUT_OK; +} + +int +LayoutGetIthEdge(This,index,idp) + struct Layout_Graph* This; + long index; + pItem* idp; +{ + if(index < 0 || index >= THIS(edgeNum)) return LAYOUT_ERROR; + *idp = EDGE_ITEM(THIS(edges)[index]); + return LAYOUT_OK; +} + +int +LayoutGetEdgeEndPoints(This,id,geomp) + struct Layout_Graph* This; + pItem id; + ItemGeom* geomp; +{ + register Edge* ip = NULL; + register int i; + + /* find matching edge */ + FOR_ALL_EDGES(i) { + if(EDGE_ITEM(THIS(edges)[i]) == id) { + ip = THIS(edges)[i]; + break; /* Khamis 11-oct-96 */ + } + } + if(!ip) return LAYOUT_ERROR; + *geomp = EDGE_GEOM(ip); + return LAYOUT_OK; +} + +int +LayoutSetEdgeDim(This,id,geom) + struct Layout_Graph* This; + pItem id; + ItemGeom geom; +{ + register Edge* ip = NULL; + register int i; + + /* find matching edge */ + FOR_ALL_EDGES(i) { + if(EDGE_ITEM(THIS(edges)[i]) == id) { + ip = THIS(edges)[i]; + break; /* Khamis 11-oct-96 */ + } + } + if(!ip) return LAYOUT_ERROR; + SET_EDGE_GEOM(ip,geom); + return LAYOUT_OK; +} + +char* +LayoutGetError(This) + struct Layout_Graph* This; +{ + register char* msg = THIS(errmsg); + THIS(errmsg) = (char*)0; + return msg; +} + + +/* KHAMIS */ + +void * MY_EdgeFromNode (This, i) + struct Layout_Graph* This; + int i; +{ + return THIS(edges)[i]->fromNode; +} + +void * MY_EdgeToNode (This, i) + struct Layout_Graph* This; + int i; +{ + return THIS(edges)[i]->toNode; +} + +int MY_EdgeParentNum (This, i) + struct Layout_Graph* This; + int i; +{ + return THIS(edges)[i]->toNode->parentNum; +} + +void * MY_EdgeParent (This, i, num) + struct Layout_Graph* This; + int i; + int num; +{ + return THIS(edges)[i]->toNode->parent[num]->fromNode; +} + +int MY_EdgeSuccNum (This, i) + struct Layout_Graph* This; + int i; +{ + return THIS(edges)[i]->fromNode->succNum; +} + +void * MY_EdgeSucc (This, i, num) + struct Layout_Graph* This; + int i; +{ + return THIS(edges)[i]->fromNode->succ[num]->toNode; +} + +int MY_graphOrder (This) + struct Layout_Graph* This; +{ + return THIS(graphOrder); +} + +/* KHAMIS END */ +
tkCanvLayout.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkTable.tcl =================================================================== --- tkTable.tcl (nonexistent) +++ tkTable.tcl (revision 1765) @@ -0,0 +1,560 @@ +# table.tcl -- +# +# version 1.8, jeff.hobbs@acm.org +# This file defines the default bindings for Tk table widgets +# and provides procedures that help in implementing those bindings. +# + +#-------------------------------------------------------------------------- +# tkPriv elements used in this file: +# +# afterId - Token returned by "after" for autoscanning. +# tablePrev - The last element to be selected or deselected +# during a selection operation. +#-------------------------------------------------------------------------- + +# tkTableClipboardKeysyms -- +# This procedure is invoked to identify the keys that correspond to +# the "copy", "cut", and "paste" functions for the clipboard. +# +# Arguments: +# copy - Name of the key (keysym name plus modifiers, if any, +# such as "Meta-y") used for the copy operation. +# cut - Name of the key used for the cut operation. +# paste - Name of the key used for the paste operation. + +proc tkTableClipboardKeysyms {copy cut paste} { + bind Table <$copy> {tk_tableCopy %W} + bind Table <$cut> {tk_tableCut %W} + bind Table <$paste> {tk_tablePaste %W} +} + +## Interactive row resizing, affected by -resizeborders option +## +bind Table <3> { + ## You might want to check for row returned if you want to + ## restrict the resizing of certain rows + %W border mark %x %y +} +bind Table { %W border dragto %x %y } + +## Button events + +bind Table <1> { + if {[winfo exists %W]} { + tkTableBeginSelect %W [%W index @%x,%y] + focus %W + } +} +bind Table { + array set tkPriv {x %x y %y} + tkTableMotion %W [%W index @%x,%y] +} +bind Table { + # empty +} +bind Table { + if {[winfo exists %W]} { + tkCancelRepeat + %W activate @%x,%y + } +} + +bind Table {tkTableBeginExtend %W [%W index @%x,%y]} +bind Table {tkTableBeginToggle %W [%W index @%x,%y]} +bind Table {tkCancelRepeat} +bind Table { + array set tkPriv {x %x y %y} + tkTableAutoScan %W +} +bind Table <2> { + %W scan mark %x %y + array set tkPriv {x %x y %y} + set tkPriv(mouseMoved) 0 +} +bind Table { + if {(%x != $tkPriv(x)) || (%y != $tkPriv(y))} { set tkPriv(mouseMoved) 1 } + if $tkPriv(mouseMoved) { %W scan dragto %x %y } +} +bind Table { + if {!$tkPriv(mouseMoved)} { tk_tablePaste %W [%W index @%x,%y] } +} + +## Key events + +if {[string comp {} [info command event]]} { + tkTableClipboardKeysyms +} else { + tkTableClipboardKeysyms Control-c Control-x Control-v +} + +bind Table { + # empty to allow Tk focus movement +} +# This forces a cell commit if an active cell exists +# Remove this if you don't want cell commit to occur +# on every FocusOut +bind Table { + catch {%W activate active} +} +bind Table {tkTableExtendSelect %W -1 0} +bind Table {tkTableExtendSelect %W 1 0} +bind Table {tkTableExtendSelect %W 0 -1} +bind Table {tkTableExtendSelect %W 0 1} +bind Table {%W yview scroll -1 pages; %W activate @0,0} +bind Table {%W yview scroll 1 pages; %W activate @0,0} +bind Table {%W xview scroll -1 pages} +bind Table {%W xview scroll 1 pages} +bind Table {%W see origin} +bind Table {%W see end} +bind Table { + %W selection clear all + %W activate origin + %W selection set active + %W see active +} +bind Table { + %W selection clear all + %W activate end + %W selection set active + %W see active +} +bind Table {tkTableDataExtend %W origin} +bind Table {tkTableDataExtend %W end} +bind Table {tkTableBeginSelect %W [%W index active]}\n" +"bind Table {tkTableBeginExtend %W [%W index active]}\n" +"bind Table {tkTableSelectAll %W}\n" +"bind Table {\n" +" if {[string match browse [%W cget -selectmode]]} {%W selection clear all}\n" +"}\n" +"bind Table {tkTableMoveCell %W -1 0}\n" +"bind Table {tkTableMoveCell %W 1 0}\n" +"bind Table {tkTableMoveCell %W 0 -1}\n" +"bind Table {tkTableMoveCell %W 0 1}\n" +"bind Table {\n" +" if {[string compare {} %A]} { %W insert active insert %A }\n" +"}\n" +"bind Table {\n" +" set tkPriv(junk) [%W icursor]\n" +" if {[string compare {} $tkPriv(junk)] && $tkPriv(junk)} {\n" +" %W delete active [expr {$tkPriv(junk)-1}]\n" +" }\n" +"}\n" +"bind Table {%W delete active insert}\n" +"bind Table {%W reread}\n" +"bind Table {\n" +" %W insert active insert \"\n\"\n" +"}\n" +"bind Table {%W icursor [expr {[%W icursor]-1}]}\n" +"bind Table {%W icursor [expr {[%W icursor]+1}]}\n" +"bind Table {%W icursor end}\n" +"bind Table {%W icursor 0}\n" +"bind Table {%W delete active insert end}\n" +"bind Table {tkTableChangeWidth %W active 1}\n" +"bind Table {tkTableChangeWidth %W active -1}\n" +"proc tkTableBeginSelect {w el} {\n" +" global tkPriv\n" +" if {[scan $el %d,%d r c] != 2} return\n" +" switch [$w cget -selectmode] {\n" +" multiple {\n" +" if {[$w tag includes title $el]} {\n" +" ## in the title area\n" +" if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {\n" +" ## We're in a column header\n" +" if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {\n" +" ## We're in the topleft title area\n" +" set inc topleft\n" +" set el2 end\n" +" } else {\n" +" set inc [$w index topleft row],$c\n" +" set el2 [$w index end row],$c\n" +" }\n" +" } else {\n" +" ## We're in a row header\n" +" set inc $r,[$w index topleft col]\n" +" set el2 $r,[$w index end col]\n" +" }\n" +" } else {\n" +" set inc $el\n" +" set el2 $el\n" +" }\n" +" if [$w selection includes $inc] {\n" +" $w selection clear $el $el2\n" +" } else {\n" +" $w selection set $el $el2\n" +" }\n" +" }\n" +" extended {\n" +" $w selection clear all\n" +" if {[$w tag includes title $el]} {\n" +" if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {\n" +" ## We're in a column header\n" +" if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {\n" +" $w selection set origin end\n" +" } else {\n" +" $w selection set $el [$w index end row],$c\n" +" }\n" +" } else {\n" +" ## We're in a row header\n" +" $w selection set $el $r,[$w index end col]\n" +" }\n" +" } else {\n" +" $w selection set $el\n" +" }\n" +" $w selection anchor $el\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" default {\n" +" if {![$w tag includes title $el]} {\n" +" $w selection clear all\n" +" $w selection set $el\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" $w selection anchor $el\n" +" }\n" +" }\n" +"}\n" +"proc tkTableMotion {w el} {\n" +" global tkPriv\n" +" if {![info exists tkPriv(tablePrev)]} {\n" +" set tkPriv(tablePrev) $el\n" +" return\n" +" }\n" +" if {[string match $tkPriv(tablePrev) $el]} return\n" +" switch [$w cget -selectmode] {\n" +" browse {\n" +" $w selection clear all\n" +" $w selection set $el\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" extended {\n" +" scan $tkPriv(tablePrev) %d,%d r c\n" +" scan $el %d,%d elr elc\n" +" if {[$w tag includes title $el]} {\n" +" if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {\n" +" ## We're in a column header\n" +" if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {\n" +" ## We're in the topleft title area\n" +" $w selection clear anchor end\n" +" } else {\n" +" $w selection clear anchor [$w index end row],$c\n" +" }\n" +" $w selection set anchor [$w index end row],$elc\n" +" } else {\n" +" ## We're in a row header\n" +" $w selection clear anchor $r,[$w index end col]\n" +" $w selection set anchor $elr,[$w index end col]\n" +" }\n" +" } else {\n" +" $w selection clear anchor $tkPriv(tablePrev)\n" +" $w selection set anchor $el\n" +" }\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" }\n" +"}\n" +"proc tkTableBeginExtend {w el} {\n" +" if {[string match extended [$w cget -selectmode]] &&\n" +" [$w selection includes anchor]} {\n" +" tkTableMotion $w $el\n" +" }\n" +"}\n" +"proc tkTableBeginToggle {w el} {\n" +" global tkPriv\n" +" if {[string match extended [$w cget -selectmode]]} {\n" +" set tkPriv(tablePrev) $el\n" +" $w selection anchor $el\n" +" if [$w selection includes $el] {\n" +" $w selection clear $el\n" +" } else {\n" +" $w selection set $el\n" +" }\n" +" }\n" +"}\n" +"proc tkTableAutoScan {w} {\n" +" global tkPriv\n" +" if {![winfo exists $w]} return\n" +" set x $tkPriv(x)\n" +" set y $tkPriv(y)\n" +" if {$y >= [winfo height $w]} {\n" +" $w yview scroll 1 units\n" +" } elseif {$y < 0} {\n" +" $w yview scroll -1 units\n" +" } elseif {$x >= [winfo width $w]} {\n" +" $w xview scroll 1 units\n" +" } elseif {$x < 0} {\n" +" $w xview scroll -1 units\n" +" } else {\n" +" return\n" +" }\n" +" tkTableMotion $w [$w index @$x,$y]\n" +" set tkPriv(afterId) [after 50 tkTableAutoScan $w]\n" +"}\n" +"proc tkTableMoveCell {w x y} {\n" +" global tkPriv\n" +" if {[catch {$w index active row} r]} return\n" +" set c [$w index active col]\n" +" $w activate [incr r $x],[incr c $y]\n" +" $w see active\n" +" switch [$w cget -selectmode] {\n" +" browse {\n" +" $w selection clear all\n" +" $w selection set active\n" +" }\n" +" extended {\n" +" $w selection clear all\n" +" $w selection set active\n" +" $w selection anchor active\n" +" set tkPriv(tablePrev) [$w index active]\n" +" }\n" +" }\n" +"}\n" +"proc tkTableExtendSelect {w x y} {\n" +" if {[string compare extended [$w cget -selectmode]] ||\n" +" [catch {$w index active row} r]} return\n" +" set c [$w index active col]\n" +" $w activate [incr r $x],[incr c $y]\n" +" $w see active\n" +" tkTableMotion $w [$w index active]\n" +"}\n" +"proc tkTableDataExtend {w el} {\n" +" set mode [$w cget -selectmode]\n" +" if {[string match extended $mode]} {\n" +" $w activate $el\n" +" $w see $el\n" +" if [$w selection includes anchor] {tkTableMotion $w $el}\n" +" } elseif {[string match multiple $mode]} {\n" +" $w activate $el\n" +" $w see $el\n" +" }\n" +"}\n" +"proc tkTableSelectAll {w} {\n" +" if {[regexp {^(single|browse)$} [$w cget -selectmode]]} {\n" +" $w selection clear all\n" +" $w selection set active\n" +" tkTableHandleType $w [$w index active]\n" +" } else {\n" +" $w selection set origin end\n" +" }\n" +"}\n" +"proc tkTableChangeWidth {w i a} {\n" +" set tmp [$w index $i col]\n" +" if {[set width [$w width $tmp]] >= 0} {\n" +" $w width $tmp [incr width $a]\n" +" } else {\n" +" $w width $tmp [incr width -$a]\n" +" }\n" +"}\n" +"proc tk_tableCopy w {\n" +" if {[selection own -displayof $w] == \"$w\"} {\n" +" clipboard clear -displayof $w\n" +" catch {clipboard append -displayof $w [selection get -displayof $w]}\n" +" }\n" +"}\n" +"proc tk_tableCut w {\n" +" if {[selection own -displayof $w] == \"$w\"} {\n" +" clipboard clear -displayof $w\n" +" catch {\n" +" clipboard append -displayof $w [selection get -displayof $w]\n" +" $w cursel set {}\n" +" $w selection clear all\n" +" }\n" +" }\n" +"}\n" +"proc tk_tablePaste {w {cell {}}} {\n" +" if {[string compare {} $cell]} {\n" +" if {[catch {selection get -displayof $w} data]} return\n" +" } else {\n" +" if {[catch {selection get -displayof $w -selection CLIPBOARD} data]} {\n" +" return\n" +" }\n" +" set cell active\n" +" }\n" +" tk_tablePasteHandler $w [$w index $cell] $data\n" +" if {[$w cget -state] == \"normal\"} {focus $w}\n" +"}\n" +"proc tk_tablePasteHandler {w cell data} {\n" +" set rows [expr {[$w cget -rows]-[$w cget -roworigin]}]\n" +" set cols [expr {[$w cget -cols]-[$w cget -colorigin]}]\n" +" set r [$w index $cell row]\n" +" set c [$w index $cell col]\n" +" set rsep [$w cget -rowseparator]\n" +" set csep [$w cget -colseparator]\n" +" ## Assume separate rows are split by row separator if specified\n" +" ## If you were to want multi-character row separators, you would need:\n" +" # regsub -all $rsep $data data\n" +" # set data [join $data ]\n" +" if {[string comp {} $rsep]} { set data [split $data $rsep] }\n" +" set row $r\n" +" foreach line $data {\n" +" if {$row > $rows} break\n" +" set col $c\n" +" ## Assume separate cols are split by col separator if specified\n" +" ## Unless a -separator was specified\n" +" if {[string comp {} $csep]} { set line [split $line $csep] }\n" +" ## If you were to want multi-character col separators, you would need:\n" +" # regsub -all $csep $line line\n" +" # set line [join $line ]\n" +" foreach item $line {\n" +" if {$col > $cols} break\n" +" $w set $row,$col $item\n" +" incr col\n" +" }\n" +" incr row\n" +" }\n" +"}\n"
tkTabletcl.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tclmsgbox.c =================================================================== --- tclmsgbox.c (nonexistent) +++ tclmsgbox.c (revision 1765) @@ -0,0 +1,462 @@ +/* tclmsgbox.c -- Tcl code to handle a Windows MessageBox in the background. + Copyright (C) 1998 Cygnus Solutions. + Written by Ian Lance Taylor . */ + +#ifdef _WIN32 + +#include +#include + +#include + +/* FIXME: We use some internal Tcl and Tk Windows stuff. */ +#include + +EXTERN HINSTANCE TclWinGetTclInstance (void); + +#include "guitcl.h" + +/* This file defines a single Tcl command. + + ide_messageBox CODE [ARGUMENTS] + + This is just like tk_messageBox, except that it does not return + a value. Instead, when the user clicks on a button closing the + message box, this invokes CODE, appending the selected value. + + On Windows, this runs the MessageBox function in another + thread. This permits a program which handles IDE requests from + other programs to not return from the request until the + MessageBox completes. This is not possible without using + another thread, since the MessageBox function call will be + running its own event loop, and will be higher on the stack + than the IDE request. + + On Unix tk_messageBox runs in the regular Tk event loop, so + another thread is not required. + + */ + +static LRESULT CALLBACK msgbox_wndproc (HWND, UINT, WPARAM, LPARAM); +static int msgbox_eventproc (Tcl_Event *, int); + +/* The hidden message box window. */ + +static HWND hidden_hwnd; + +/* The message number we use to indicate that the MessageBox call has + completed. */ + +#define MSGBOX_MESSAGE (WM_USER + 1) + +/* We pass a pointer to this structure to the thread function. It + passes it back to the hidden window procedure. */ + +struct msgbox_data +{ + /* Tcl interpreter. */ + Tcl_Interp *interp; + /* Tcl code to execute when MessageBox completes. */ + char *code; + /* Hidden window handle. */ + HWND hidden_hwnd; + /* MessageBox arguments. */ + HWND hwnd; + char *message; + char *title; + int flags; + /* Result of MessageBox call. */ + int result; +}; + +/* This is the structure we pass to Tcl_QueueEvent. */ + +struct msgbox_event +{ + /* The base structure for all events. */ + Tcl_Event header; + /* The message box data for this event. */ + struct msgbox_data *md; +}; + +/* Initialize a hidden window to handle messages from the message box + thread. */ + +static int +msgbox_init () +{ + WNDCLASS class; + + if (hidden_hwnd != NULL) + return TCL_OK; + + class.style = 0; + class.cbClsExtra = 0; + class.cbWndExtra = 0; + class.hInstance = TclWinGetTclInstance(); + class.hbrBackground = NULL; + class.lpszMenuName = NULL; + class.lpszClassName = "ide_messagebox"; + class.lpfnWndProc = msgbox_wndproc; + class.hIcon = NULL; + class.hCursor = NULL; + + if (! RegisterClass (&class)) + return TCL_ERROR; + + hidden_hwnd = CreateWindow ("ide_messagebox", "ide_messagebox", WS_TILED, + 0, 0, 0, 0, NULL, NULL, class.hInstance, NULL); + if (hidden_hwnd == NULL) + return TCL_ERROR; + + return TCL_OK; +} + +/* This is called as an exit handler. */ + +static void +msgbox_exit (ClientData cd) +{ + if (hidden_hwnd != NULL) + { + UnregisterClass ("ide_messagebox", TclWinGetTclInstance ()); + DestroyWindow (hidden_hwnd); + hidden_hwnd = NULL; + + /* FIXME: Ideally we would kill off any remaining threads and + somehow free up the associated data. */ + } +} + +/* This is the thread function which actually invokes the MessageBox + function. This function runs in a separate thread. */ + +static DWORD WINAPI +msgbox_thread (LPVOID arg) +{ + struct msgbox_data *md = (struct msgbox_data *) arg; + + md->result = MessageBox (md->hwnd, md->message, md->title, + md->flags | MB_SETFOREGROUND); + PostMessage (md->hidden_hwnd, MSGBOX_MESSAGE, 0, (LPARAM) arg); + return 0; +} + +/* This function handles Windows events for the hidden window. When + the MessageBox function call completes in the thread, this function + will be called with MSGBOX_MESSAGE. */ + +static LRESULT CALLBACK +msgbox_wndproc (HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + struct msgbox_event *me; + + if (message != MSGBOX_MESSAGE) + return DefWindowProc (hwnd, message, wparam, lparam); + + /* Queue up a Tcl event. */ + me = (struct msgbox_event *) Tcl_Alloc (sizeof *me); + me->header.proc = msgbox_eventproc; + me->md = (struct msgbox_data *) lparam; + Tcl_QueueEvent ((Tcl_Event *) me, TCL_QUEUE_TAIL); + + return 0; +} + +/* This function handles Tcl events. It is invoked when a MessageBox + has completed. */ + +static int +msgbox_eventproc (Tcl_Event *event, int flags) +{ + struct msgbox_event *me = (struct msgbox_event *) event; + char *resstr; + Tcl_DString ds; + int ret; + + /* Only execute the Tcl code if we are waiting for window events. */ + if ((flags & TCL_WINDOW_EVENTS) == 0) + return 0; + + /* This switch is copied from Tk_MessageBoxCmd in Tk. */ + switch (me->md->result) + { + case IDABORT: resstr = "abort"; break; + case IDCANCEL: resstr = "cancel"; break; + case IDIGNORE: resstr = "ignore"; break; + case IDNO: resstr = "no"; break; + case IDOK: resstr = "ok"; break; + case IDRETRY: resstr = "retry"; break; + case IDYES: resstr = "yes"; break; + default: resstr = ""; + } + + Tcl_DStringInit (&ds); + Tcl_DStringAppend (&ds, me->md->code, -1); + Tcl_DStringAppendElement (&ds, resstr); + + /* FIXME: What if the interpreter has been deleted? */ + ret = Tcl_GlobalEval (me->md->interp, Tcl_DStringValue (&ds)); + + Tcl_DStringFree (&ds); + + /* We are now done with the msgbox_data structure, so we can free + the fields and the structure itself. */ + Tcl_Free (me->md->code); + Tcl_Free (me->md->message); + Tcl_Free (me->md->title); + Tcl_Free ((char *) me->md); + + if (ret != TCL_OK) + Tcl_BackgroundError (me->md->interp); + + return 1; +} + +/* This is a direct steal from tkWinDialog.c, for the use of msgbox. + I kept the same formatting as well, to make it easier to merge + changes. */ + +typedef struct MsgTypeInfo { + char * name; + int type; + int numButtons; + char * btnNames[3]; +} MsgTypeInfo; + +#define NUM_TYPES 6 + +static MsgTypeInfo +msgTypeInfo[NUM_TYPES] = { + {"abortretryignore", MB_ABORTRETRYIGNORE, 3, {"abort", "retry", "ignore"}}, + {"ok", MB_OK, 1, {"ok" }}, + {"okcancel", MB_OKCANCEL, 2, {"ok", "cancel" }}, + {"retrycancel", MB_RETRYCANCEL, 2, {"retry", "cancel" }}, + {"yesno", MB_YESNO, 2, {"yes", "no" }}, + {"yesnocancel", MB_YESNOCANCEL, 3, {"yes", "no", "cancel"}} +}; + +/* This is mostly a direct steal from Tk_MessageBoxCmd in Tk. I kept + the same formatting as well, to make it easier to merge changes. */ + +static int +msgbox_internal (ClientData clientData, Tcl_Interp *interp, int argc, + char **argv, char *code) +{ + int flags; + Tk_Window parent = NULL; + HWND hWnd; + char *message = ""; + char *title = ""; + int icon = MB_ICONINFORMATION; + int type = MB_OK; + int modal = MB_SYSTEMMODAL; + int i, j; + char *defaultBtn = NULL; + int defaultBtnIdx = -1; + + for (i=1; iinterp = interp; + md->code = Tcl_Alloc (strlen (code) + 1); + strcpy (md->code, code); + md->hidden_hwnd = hidden_hwnd; + md->hwnd = hWnd; + md->message = Tcl_Alloc (strlen (message) + 1); + strcpy (md->message, message); + md->title = Tcl_Alloc (strlen (title) + 1); + strcpy (md->title, title); + md->flags = flags | modal; + + /* Start the thread. This will call MessageBox, and then start + the ball rolling to execute the specified code. */ + thread = CreateThread (NULL, 0, msgbox_thread, (LPVOID) md, 0, &tid); + CloseHandle (thread); + } + + return TCL_OK; + + arg_missing: + Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing", + NULL); + return TCL_ERROR; +} + +/* This is the ide_messageBox function. */ + +static int +msgbox (ClientData cd, Tcl_Interp *interp, int argc, char **argv) +{ + if (argc < 2) + { + char buf[10]; + + sprintf (buf, "%d", argc); + Tcl_AppendResult (interp, "wrong # args: got ", buf, + " but expected at least 2", (char *) NULL); + return TCL_ERROR; + } + + /* Note that we don't bother to pass the correct value for argv[0] + to msgbox_internal, since it doesn't look at it anyhow. Note + that we will pass a NULL clientdata argument. */ + return msgbox_internal (cd, interp, argc - 1, argv + 1, argv[1]); +} + +/* Create the Tcl command. */ + +int +ide_create_messagebox_command (Tcl_Interp *interp) +{ + Tcl_CreateExitHandler (msgbox_exit, NULL); + if (Tcl_CreateCommand (interp, "ide_messageBox", msgbox, NULL, NULL) == NULL) + return TCL_ERROR; + return TCL_OK; +} + +#endif /* _WIN32 */
tclmsgbox.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkWinPrintCanvas.c =================================================================== --- tkWinPrintCanvas.c (nonexistent) +++ tkWinPrintCanvas.c (revision 1765) @@ -0,0 +1,193 @@ + +#ifdef _WIN32 + +#include + +#include "tkWinInt.h" +#include "tkCanvas.h" + +#include +#include + + + +/* + *-------------------------------------------------------------- + * + * PrintCanvasCmd -- + * When invoked with the correct args this will bring up a + * standard Windows print dialog box and then print the + * contence of the canvas. + * + * Results: + * Standard Tcl result. + * + *-------------------------------------------------------------- + */ + + +int +PrintCanvasCmd(clientData, interp, argc, argv) + ClientData clientData; + Tcl_Interp *interp; + int argc; + char **argv; +{ + PRINTDLG pd; + Tcl_CmdInfo canvCmd; + TkCanvas *canvasPtr; + TkWinDrawable *PrinterDrawable; + Tk_Window tkwin;/* = canvasPtr->tkwin;*/ + Tk_Item *itemPtr; + Pixmap pixmap; + HDC hDCpixmap; + TkWinDCState pixmapState; + DEVMODE dm; + float Ptr_pixX,Ptr_pixY,Ptr_mmX,Ptr_mmY; + float canv_pixX,canv_pixY,canv_mmX,canv_mmY; + + int widget_X_size = 0; + int widget_Y_size = 0; + int page_Y_size, page_X_size; + int tiles_wide,tiles_high; + int tile_y, tile_x; + int screenX1, screenX2, screenY1, screenY2, width, height; + DOCINFO *lpdi = malloc(sizeof(DOCINFO)); + + if (argc < 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " canvas \"", + (char *) NULL); + return TCL_ERROR; + } + + /* The second arg is the canvas widget */ + if (!Tcl_GetCommandInfo(interp, argv[1], &canvCmd)) { + Tcl_AppendResult(interp, "couldn't get canvas information for \"", + argv[1], "\"", (char *) NULL); + return TCL_ERROR; + } + + memset(&dm,0,sizeof(DEVMODE)); + dm.dmSize = sizeof(DEVMODE); + dm.dmScale = 500; + + memset(lpdi,0,sizeof(DOCINFO)); + lpdi->cbSize=sizeof(DOCINFO); + lpdi->lpszDocName=malloc(255); + sprintf((char*)lpdi->lpszDocName,"SN - Printing\0"); + lpdi->lpszOutput=NULL; + + canvasPtr = (TkCanvas *)(canvCmd.clientData); + tkwin = canvasPtr->tkwin; + memset(&pd,0,sizeof( PRINTDLG )); + pd.lStructSize = sizeof( PRINTDLG ); + pd.hwndOwner = NULL; + pd.hDevMode = NULL; + pd.hDevNames = NULL; + /* pd.hDC = */ + pd.Flags = PD_RETURNDC; + + /* Get printer details. */ + if (!PrintDlg(&pd)) { + goto done; + } + + PrinterDrawable = (TkWinDrawable *) ckalloc(sizeof(TkWinDrawable)); + PrinterDrawable->type = TWD_WINDC; + PrinterDrawable->winDC.hdc = pd.hDC; + + Ptr_pixX=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,HORZRES); + Ptr_pixY=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,VERTRES); + Ptr_mmX=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,HORZSIZE); + Ptr_mmY=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,VERTSIZE); + + screenX1=0; screenY1=0; + screenX2=canvasPtr->width; screenY2=canvasPtr->height; + canvasPtr->drawableXOrigin = screenX1 - 30; + canvasPtr->drawableYOrigin = screenY1 - 30; + pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), + (screenX2 + 30 - canvasPtr->drawableXOrigin), + (screenY2 + 30 - canvasPtr->drawableYOrigin), + Tk_Depth(tkwin)); + width = screenX2 - screenX1; + height = screenY2 - screenY1; + + hDCpixmap = TkWinGetDrawableDC(Tk_Display(tkwin), pixmap, &pixmapState); + canv_pixX=(float)GetDeviceCaps(hDCpixmap,HORZRES); + canv_pixY=(float)GetDeviceCaps(hDCpixmap,VERTRES); + canv_mmX=(float)GetDeviceCaps(hDCpixmap,HORZSIZE); + canv_mmY=(float)GetDeviceCaps(hDCpixmap,VERTSIZE); + + + SetMapMode(PrinterDrawable->winDC.hdc,MM_ISOTROPIC); + SetWindowExtEx(PrinterDrawable->winDC.hdc,(int)((float)canv_pixX),(int)((float)canv_pixY),NULL); + SetViewportExtEx(PrinterDrawable->winDC.hdc,(int)((float)Ptr_pixX), + (int)((float)Ptr_pixY), + NULL); + + /* max X and Y for canvas */ + for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; + itemPtr = itemPtr->nextPtr) { + if (itemPtr->x1 > widget_X_size) { + widget_X_size = itemPtr->x1; + } + if (itemPtr->y1 > widget_Y_size) { + widget_Y_size = itemPtr->y1; + } + } + + /* Calculate the number of tiles high */ + page_Y_size = GetDeviceCaps(hDCpixmap,LOGPIXELSY)*(Ptr_mmY/22); + page_X_size = GetDeviceCaps(hDCpixmap,LOGPIXELSX)*(Ptr_mmX/22); + + tiles_high = ( widget_Y_size / page_Y_size ); /* start at zero */ + tiles_wide = ( widget_X_size / page_X_size ); /* start at zero */ + + StartDoc(pd.hDC,lpdi); + + for (tile_x = 0; tile_x <= tiles_wide;tile_x++) { + for (tile_y = 0; tile_y <= tiles_high;tile_y++) { + SetViewportOrgEx(pd.hDC,-(tile_x*Ptr_pixX),-(tile_y*Ptr_pixY),NULL); + StartPage(pd.hDC); + + for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; + itemPtr = itemPtr->nextPtr) { + (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr, + canvasPtr->display, (unsigned long) PrinterDrawable/*pixmap*/, screenX1, screenY1, width, + height); + } + + EndPage(pd.hDC); + } + } + EndDoc(pd.hDC); + +done: + return TCL_OK; + error: + return TCL_ERROR; +} + + + +static void +ide_delete_print_canvas_command(ClientData clientData) +{ + /* destructor code here.*/ +} + +int +ide_create_printcanvas_command (Tcl_Interp *interp) +{ + + /* initialization code here */ + + if (Tcl_CreateCommand(interp, "ide_print_canvas", PrintCanvasCmd, + NULL, ide_delete_print_canvas_command) == NULL) + return TCL_ERROR; + + return TCL_OK; +} + +#endif /* _WIN32 */
tkWinPrintCanvas.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkWarpPointer.c =================================================================== --- tkWarpPointer.c (nonexistent) +++ tkWarpPointer.c (revision 1765) @@ -0,0 +1,78 @@ + +/* ----------------------------------------------------------------------------- +* NAME: +* WarpPointer +* +* SYNOPSIS: int WarpPointer (clientData, interp, objc, objv) +* Implements tcl function: +* warp_pointer win x y +* +* DESC: +* Forces the pointer to a specific location. There is probably +* no good reason to use this except in the testsuite! +* +* ARGS: +* win (objv[1]) - tk window name that coordinates are relative to. +* Use "." for absolute coordinates +* +* x (obvj[2]) - X coordinate +* y (objv[3]) - Y coordinate +* RETURNS: +* +* +* NOTES: +* +* +* ---------------------------------------------------------------------------*/ +#include "tk.h" +#ifdef _WIN32 +#include +#include +#endif + +int +WarpPointer (clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +{ + Tk_Window tkwin; + int x, y; + char *str; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "widgetId x y"); + return TCL_ERROR; + } + + if ((Tcl_GetIntFromObj (interp, objv[2], &x) == TCL_ERROR) || + (Tcl_GetIntFromObj (interp, objv[3], &y) == TCL_ERROR)) + return TCL_ERROR; + + tkwin = Tk_NameToWindow(interp, Tcl_GetStringFromObj(objv[1], NULL), \ + Tk_MainWindow (interp)); + if (tkwin == NULL) + return TCL_ERROR; + + { +#ifdef _WIN32 + int wx, wy; + Tk_GetRootCoords (tkwin, &wx, &wy); + SetCursorPos (wx + x, wy + y); +#else + Window win = Tk_WindowId(tkwin); + XWarpPointer(Tk_Display(tkwin), None, win, 0, 0, 0, 0, x, y); +#endif + } + + return TCL_OK; +} + +int +cyg_create_warp_pointer_command (Tcl_Interp *interp) +{ + if (!Tcl_CreateObjCommand (interp, "warp_pointer", WarpPointer, NULL, NULL)) + return TCL_ERROR; + return TCL_OK; +}
tkWarpPointer.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkTableCmd.c =================================================================== --- tkTableCmd.c (nonexistent) +++ tkTableCmd.c (revision 1765) @@ -0,0 +1,158 @@ +/* + * tkTableCmd.c -- + * + * This module implements command structure lookups. + * + * Copyright (c) 1997,1998 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include "tkTableCmd.h" + +/* + * Functions for handling custom options that use Cmd_Structs + */ + +int +Cmd_OptionSet(ClientData clientData, Tcl_Interp *interp, + Tk_Window unused, char *value, char *widgRec, int offset) +{ + Cmd_Struct *p = (Cmd_Struct *)clientData; + int mode = Cmd_GetValue(p,value); + if (!mode) { + Cmd_GetError(interp,p,value); + return TCL_ERROR; + } + *((int*)(widgRec+offset)) = mode; + return TCL_OK; +} + +char * +Cmd_OptionGet(ClientData clientData, Tk_Window unused, + char *widgRec, int offset, Tcl_FreeProc **freeProcPtr) +{ + Cmd_Struct *p = (Cmd_Struct *)clientData; + int mode = *((int*)(widgRec+offset)); + return Cmd_GetName(p,mode); +} + +/* + * Options for bits in an int + * This will set/clear one bit in an int, the specific bit + * being passed in clientData + */ +int +Cmd_BitSet(ClientData clientData, Tcl_Interp *interp, + Tk_Window unused, char *value, char *widgRec, int offset) +{ + int mode; + if (Tcl_GetBoolean(interp, value, &mode) != TCL_OK) { + return TCL_ERROR; + } + if (mode) { + *((int*)(widgRec+offset)) |= (int)clientData; + } else { + *((int*)(widgRec+offset)) &= ~((int)clientData); + } + return TCL_OK; +} + +char * +Cmd_BitGet(ClientData clientData, Tk_Window unused, + char *widgRec, int offset, Tcl_FreeProc **freeProcPtr) +{ + return (*((int*)(widgRec+offset)) & (int) clientData)?"1":"0"; +} + +/* + * simple Cmd_Struct lookup functions + */ + +char * +Cmd_GetName(const Cmd_Struct *cmds, int val) +{ + for(;cmds->name && cmds->name[0];cmds++) { + if (cmds->value==val) return cmds->name; + } + return NULL; +} + +int +Cmd_GetValue(const Cmd_Struct *cmds, const char *arg) +{ + int len=strlen(arg); + for(;cmds->name && cmds->name[0];cmds++) { + if (!strncmp(cmds->name,arg,len)) return cmds->value; + } + return 0; +} + +void +Cmd_GetError(Tcl_Interp *interp, const Cmd_Struct *cmds, const char *arg) +{ + int i; + Tcl_AppendResult(interp, "bad option \"", arg, "\" must be ", (char *) 0); + for(i=0;cmds->name && cmds->name[0];cmds++,i++) { + Tcl_AppendResult(interp, (i?", ":""), cmds->name, (char *) 0); + } +} + +/* + * Parses a command string passed in an arg comparing it with all the + * command strings in the command array. If it finds a string which is a + * unique identifier of one of the commands, returns the index . If none of + * the commands match, or the abbreviation is not unique, then it sets up + * the message accordingly and returns 0 + */ + +int +Cmd_Parse (Tcl_Interp *interp, Cmd_Struct *cmds, const char *arg) +{ + int len = (int)strlen(arg); + Cmd_Struct *matched = (Cmd_Struct *) 0; + int err = 0; + Cmd_Struct *next = cmds; + while (*(next->name)) { + if (strncmp (next->name, arg, len) == 0) { + /* have we already matched this one if so make up an error message */ + if (matched) { + if (!err) { + Tcl_AppendResult(interp, "ambiguous option \"", arg, + "\" could be ", matched->name, (char *) 0); + matched = next; + err = 1; + } + Tcl_AppendResult(interp, ", ", next->name, (char *) 0); + } else { + matched = next; + /* return on an exact match */ + if (len == (int)strlen(next->name)) + return matched->value; + } + } + next++; + } + /* did we get multiple possibilities */ + if (err) return 0; + /* did we match any at all */ + if (matched) { + return matched->value; + } else { + Tcl_AppendResult(interp, "bad option \"", arg, "\" must be ", + (char *) NULL); + next = cmds; + while (1) { + Tcl_AppendResult(interp, next->name, (char *) NULL); + /* the end of them all ? */ + if (!*((++next)->name)) return 0; + /* or the last one at least */ + if (*((next + 1)->name)) + Tcl_AppendResult(interp, ", ", (char *) NULL); + else + Tcl_AppendResult(interp, " or ", (char *) NULL); + } + } +}
tkTableCmd.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tclwinpath.c =================================================================== --- tclwinpath.c (nonexistent) +++ tclwinpath.c (revision 1765) @@ -0,0 +1,181 @@ +/* tclwinpath.c -- Tcl routines to convert paths under cygwin32. + Copyright (C) 1997 Cygnus Solutions. + Written by Ian Lance Taylor . + + This file contains Tcl interface routines to do path translation + when using cygwin32. */ + +#ifdef __CYGWIN32__ + +#include + +#include + +#include "guitcl.h" +#include "subcommand.h" + +/* The path conversion routines are not declared anywhere that I know + of. */ + +extern void cygwin32_conv_to_win32_path (const char *, char *); +extern void cygwin32_conv_to_full_win32_path (const char *, char *); +extern void cygwin32_conv_to_posix_path (const char *, char *); +extern void cygwin32_conv_to_full_posix_path (const char *, char *); +extern int cygwin32_posix_path_list_p (const char *); +extern int cygwin32_win32_to_posix_path_list_buf_size (const char *); +extern int cygwin32_posix_to_win32_path_list_buf_size (const char *); +extern void cygwin32_win32_to_posix_path_list (char *, char *); +extern void cygwin32_posix_to_win32_path_list (char *, char *); +extern void cygwin32_split_path (const char *, char *, char *); + +/* This file declares a Tcl command with subcommands. + + Each of the following subcommands returns a string based on the + PATH argument. If PATH is already in the desired form, these + commands just return it unchanged. + + ide_cygwin_path to_win32 PATH + Return PATH converted to a win32 pathname. + + ide_cygwin_path to_full_win32 PATH + Return PATH converted to an absolute win32 pathname. + + ide_cygwin_path to_posix PATH + Return PATH converted to a POSIX pathname. + + ide_cygwin_path to_full_posix PATH + Return PATH converted to an absolute POSIX pathname. + + The following subcommand returns a boolean value. + + ide_cygwin_path posix_path_list_p PATHLIST + Return whether PATHLIST is a POSIX style path list. + + The following subcommands return strings. + + ide_cygwin_path posix_to_win32_path_list PATHLIST + Return PATHLIST converted from POSIX style to win32 style. + + ide_cygwin_path win32_to_posix_path_list PATHLIST + Return PATHLIST converted from win32 style to POSIX style. + + */ + +/* Handle ide_cygwin_path to_win32. */ + +static int +path_to_win32 (ClientData cd, Tcl_Interp *interp, int argc, char **argv) +{ + char buf[MAX_PATH]; + + cygwin32_conv_to_win32_path (argv[2], buf); + Tcl_SetResult (interp, buf, TCL_VOLATILE); + return TCL_OK; +} + +/* Handle ide_cygwin_path to_full_win32. */ + +static int +path_to_full_win32 (ClientData cd, Tcl_Interp *interp, int argc, char **argv) +{ + char buf[MAX_PATH]; + + cygwin32_conv_to_full_win32_path (argv[2], buf); + Tcl_SetResult (interp, buf, TCL_VOLATILE); + return TCL_OK; +} + +/* Handle ide_cygwin_path to_posix. */ + +static int +path_to_posix (ClientData cd, Tcl_Interp *interp, int argc, char **argv) +{ + char buf[MAX_PATH]; + + cygwin32_conv_to_posix_path (argv[2], buf); + Tcl_SetResult (interp, buf, TCL_VOLATILE); + return TCL_OK; +} + +/* Handle ide_cygwin_path to_full_posix. */ + +static int +path_to_full_posix (ClientData cd, Tcl_Interp *interp, int argc, char **argv) +{ + char buf[MAX_PATH]; + + cygwin32_conv_to_full_posix_path (argv[2], buf); + Tcl_SetResult (interp, buf, TCL_VOLATILE); + return TCL_OK; +} + +/* Handle ide_cygwin_path posix_path_list_p. */ + +static int +path_posix_path_list_p (ClientData cd, Tcl_Interp *interp, int argc, + char **argv) +{ + int ret; + + ret = cygwin32_posix_path_list_p (argv[2]); + Tcl_ResetResult (interp); + Tcl_SetBooleanObj (Tcl_GetObjResult (interp), ret); + return TCL_OK; +} + +/* Handle ide_cygwin_path posix_to_win32_path_list. */ + +static int +path_posix_to_win32_path_list (ClientData cd, Tcl_Interp *interp, int argc, + char **argv) +{ + int size; + char *buf; + + size = cygwin32_posix_to_win32_path_list_buf_size (argv[2]); + buf = Tcl_Alloc (size); + cygwin32_posix_to_win32_path_list (argv[2], buf); + Tcl_SetResult (interp, buf, TCL_DYNAMIC); + return TCL_OK; +} + +/* Handle ide_cygwin_path win32_to_posix_path_list. */ + +static int +path_win32_to_posix_path_list (ClientData cd, Tcl_Interp *interp, int argc, + char **argv) +{ + int size; + char *buf; + + size = cygwin32_win32_to_posix_path_list_buf_size (argv[2]); + buf = Tcl_Alloc (size); + cygwin32_win32_to_posix_path_list (argv[2], buf); + Tcl_SetResult (interp, buf, TCL_DYNAMIC); + return TCL_OK; +} + +/* The subcommand table. */ + +static const struct ide_subcommand_table path_commands[] = +{ + { "to_win32", path_to_win32, 3, 3 }, + { "to_full_win32", path_to_full_win32, 3, 3 }, + { "to_posix", path_to_posix, 3, 3 }, + { "to_full_posix", path_to_full_posix, 3, 3 }, + { "posix_path_list_p", path_posix_path_list_p, 3, 3 }, + { "posix_to_win32_path_list", path_posix_to_win32_path_list, 3, 3 }, + { "win32_to_posix_path_list", path_win32_to_posix_path_list, 3, 3 }, + { NULL, NULL, 0, 0} +}; + +/* Create the ide_cygwin_path command. */ + +int +ide_create_cygwin_path_command (Tcl_Interp *interp) +{ + return ide_create_command_with_subcommands (interp, "ide_cygwin_path", + path_commands, NULL, NULL); +} + +#endif /* __CYGWIN32__ */
tclwinpath.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkWinPrintText.c =================================================================== --- tkWinPrintText.c (nonexistent) +++ tkWinPrintText.c (revision 1765) @@ -0,0 +1,533 @@ + +#ifdef _WIN32 + +#include + +#include "tkInt.h" +#include "tkWinInt.h" +#include "tkPort.h" +#include "tkText.h" + +#define MAXINT 32000000 + +#define HAS_3D_BORDER 1 +#define NEW_LAYOUT 2 +#define TOP_LINE 4 +#define BOTTOM_LINE 8 + + +#define DINFO_OUT_OF_DATE 1 +#define REDRAW_PENDING 2 +#define REDRAW_BORDERS 4 +#define REPICK_NEEDED 8 + + + +/* + * The following structure describes one line of the display, which may + * be either part or all of one line of the text. + */ + +typedef struct DLine { + TkTextIndex index; /* Identifies first character in text + * that is displayed on this line. */ + int count; /* Number of characters accounted for by this + * display line, including a trailing space + * or newline that isn't actually displayed. */ + int y; /* Y-position at which line is supposed to + * be drawn (topmost pixel of rectangular + * area occupied by line). */ + int oldY; /* Y-position at which line currently + * appears on display. -1 means line isn't + * currently visible on display and must be + * redrawn. This is used to move lines by + * scrolling rather than re-drawing. */ + int height; /* Height of line, in pixels. */ + int baseline; /* Offset of text baseline from y, in + * pixels. */ + int spaceAbove; /* How much extra space was added to the + * top of the line because of spacing + * options. This is included in height + * and baseline. */ + int spaceBelow; /* How much extra space was added to the + * bottom of the line because of spacing + * options. This is included in height. */ + int length; /* Total length of line, in pixels. */ + TkTextDispChunk *chunkPtr; /* Pointer to first chunk in list of all + * of those that are displayed on this + * line of the screen. */ + struct DLine *nextPtr; /* Next in list of all display lines for + * this window. The list is sorted in + * order from top to bottom. Note: the + * next DLine doesn't always correspond + * to the next line of text: (a) can have + * multiple DLines for one text line, and + * (b) can have gaps where DLine's have been + * deleted because they're out of date. */ + int flags; /* Various flag bits: see below for values. */ +} DLine; + + +typedef struct TextDInfo { + Tcl_HashTable styleTable; /* Hash table that maps from StyleValues + * to TextStyles for this widget. */ + DLine *dLinePtr; /* First in list of all display lines for + * this widget, in order from top to bottom. */ + GC copyGC; /* Graphics context for copying from off- + * screen pixmaps onto screen. */ + GC scrollGC; /* Graphics context for copying from one place + * in the window to another (scrolling): + * differs from copyGC in that we need to get + * GraphicsExpose events. */ + int x; /* First x-coordinate that may be used for + * actually displaying line information. + * Leaves space for border, etc. */ + int y; /* First y-coordinate that may be used for + * actually displaying line information. + * Leaves space for border, etc. */ + int maxX; /* First x-coordinate to right of available + * space for displaying lines. */ + int maxY; /* First y-coordinate below available + * space for displaying lines. */ + int topOfEof; /* Top-most pixel (lowest y-value) that has + * been drawn in the appropriate fashion for + * the portion of the window after the last + * line of the text. This field is used to + * figure out when to redraw part or all of + * the eof field. */ + + /* + * Information used for scrolling: + */ + + int newCharOffset; /* Desired x scroll position, measured as the + * number of average-size characters off-screen + * to the left for a line with no left + * margin. */ + int curPixelOffset; /* Actual x scroll position, measured as the + * number of pixels off-screen to the left. */ + int maxLength; /* Length in pixels of longest line that's + * visible in window (length may exceed window + * size). If there's no wrapping, this will + * be zero. */ + double xScrollFirst, xScrollLast; + /* Most recent values reported to horizontal + * scrollbar; used to eliminate unnecessary + * reports. */ + double yScrollFirst, yScrollLast; + /* Most recent values reported to vertical + * scrollbar; used to eliminate unnecessary + * reports. */ + + /* + * The following information is used to implement scanning: + */ + + int scanMarkChar; /* Character that was at the left edge of + * the window when the scan started. */ + int scanMarkX; /* X-position of mouse at time scan started. */ + int scanTotalScroll; /* Total scrolling (in screen lines) that has + * occurred since scanMarkY was set. */ + int scanMarkY; /* Y-position of mouse at time scan started. */ + + /* + * Miscellaneous information: + */ + + int dLinesInvalidated; /* This value is set to 1 whenever something + * happens that invalidates information in + * DLine structures; if a redisplay + * is in progress, it will see this and + * abort the redisplay. This is needed + * because, for example, an embedded window + * could change its size when it is first + * displayed, invalidating the DLine that + * is currently being displayed. If redisplay + * continues, it will use freed memory and + * could dump core. */ + int flags; /* Various flag values: see below for + * definitions. */ +} TextDInfo; + +/* + * The following structure describes how to display a range of characters. + * The information is generated by scanning all of the tags associated + * with the characters and combining that with default information for + * the overall widget. These structures form the hash keys for + * dInfoPtr->styleTable. + */ + +typedef struct StyleValues { + Tk_3DBorder border; /* Used for drawing background under text. + * NULL means use widget background. */ + int borderWidth; /* Width of 3-D border for background. */ + int relief; /* 3-D relief for background. */ + Pixmap bgStipple; /* Stipple bitmap for background. None + * means draw solid. */ + XColor *fgColor; /* Foreground color for text. */ + Tk_Font tkfont; /* Font for displaying text. */ + Pixmap fgStipple; /* Stipple bitmap for text and other + * foreground stuff. None means draw + * solid.*/ + int justify; /* Justification style for text. */ + int lMargin1; /* Left margin, in pixels, for first display + * line of each text line. */ + int lMargin2; /* Left margin, in pixels, for second and + * later display lines of each text line. */ + int offset; /* Offset in pixels of baseline, relative to + * baseline of line. */ + int overstrike; /* Non-zero means draw overstrike through + * text. */ + int rMargin; /* Right margin, in pixels. */ + int spacing1; /* Spacing above first dline in text line. */ + int spacing2; /* Spacing between lines of dline. */ + int spacing3; /* Spacing below last dline in text line. */ + TkTextTabArray *tabArrayPtr;/* Locations and types of tab stops (may + * be NULL). */ + int underline; /* Non-zero means draw underline underneath + * text. */ + Tk_Uid wrapMode; /* How to handle wrap-around for this tag. + * One of tkTextCharUid, tkTextNoneUid, + * or tkTextWordUid. */ +} StyleValues; + +/* + * The following structure extends the StyleValues structure above with + * graphics contexts used to actually draw the characters. The entries + * in dInfoPtr->styleTable point to structures of this type. + */ + +typedef struct TextStyle { + int refCount; /* Number of times this structure is + * referenced in Chunks. */ + GC bgGC; /* Graphics context for background. None + * means use widget background. */ + GC fgGC; /* Graphics context for foreground. */ + StyleValues *sValuePtr; /* Raw information from which GCs were + * derived. */ + Tcl_HashEntry *hPtr; /* Pointer to entry in styleTable. Used + * to delete entry. */ +} TextStyle; + + + + +void DisplayDLineToDrawable(TkText *textPtr, DLine *dlPtr, DLine *prevPtr, TkWinDrawable *drawable); + +/* + *-------------------------------------------------------------- + * + * PrintTextCmd -- + * When invoked with the correct args this will bring up a + * standard Windows print dialog box and then print the + * contence of the text wiget. + * + * Results: + * Standard Tcl result. + * + *-------------------------------------------------------------- + */ + +static int +PrintTextCmd(clientData, interp, argc, argv) + ClientData clientData; + Tcl_Interp *interp; + int argc; + char **argv; +{ + PRINTDLG pd; + Tcl_CmdInfo textCmd; + TkText *textPtr; + TextDInfo *dInfoPtr; + DLine *dlPtr; + TkWinDrawable *PrinterDrawable; + Tk_Window tkwin; + Tk_Item *itemPtr; + int maxHeight; + DLine *prevPtr; + Pixmap pixmap; + int bottomY = 0; /* Initialization needed only to stop + * compiler warnings. */ + DOCINFO *lpdi = malloc(sizeof(DOCINFO)); + TkTextIndex first, last; + int numLines; + HDC hDCpixmap; + TkWinDCState pixmapState; + DEVMODE dm; + float Ptr_pixX,Ptr_pixY,Ptr_mmX,Ptr_mmY; + float canv_pixX,canv_pixY,canv_mmX,canv_mmY; + int page_Y_size,tiles_high,tile_y; + int screenX1, screenX2, screenY1, screenY2, width, height; + + int saved_x; + int saved_y; + int saved_w; + int saved_h; + int saved_maxX; + int saved_maxY; + int saved_eof; + + + if (argc < 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " text \"", + (char *) NULL); + return TCL_ERROR; + } + + /* + * The second arg is the canvas widget. + */ + if (!Tcl_GetCommandInfo(interp, argv[1], &textCmd)) { + Tcl_AppendResult(interp, "couldn't get text information for \"", + argv[1], "\"", (char *) NULL); + return TCL_ERROR; + } + + memset(&dm,0,sizeof(DEVMODE)); + dm.dmSize = sizeof(DEVMODE); + dm.dmScale = 500; + + memset(lpdi,0,sizeof(DOCINFO)); + lpdi->cbSize=sizeof(DOCINFO); + lpdi->lpszDocName=malloc(255); + sprintf((char*)lpdi->lpszDocName,"SN - Printing\0"); + lpdi->lpszOutput=NULL; + + textPtr = (TkText *)(textCmd.clientData); + + tkwin = textPtr->tkwin; + dInfoPtr = textPtr->dInfoPtr; + dlPtr=dInfoPtr->dLinePtr; + memset(&pd,0,sizeof( PRINTDLG )); + pd.lStructSize = sizeof( PRINTDLG ); + pd.hwndOwner = NULL; + pd.hDevMode = NULL; + pd.hDevNames = NULL; + pd.Flags = PD_RETURNDC|PD_NOSELECTION; + + /* + * Get printer details. + */ + if (!PrintDlg(&pd)) { + goto done; + } + + PrinterDrawable = (TkWinDrawable *) ckalloc(sizeof(TkWinDrawable)); + PrinterDrawable->type = TWD_WINDC; + PrinterDrawable->winDC.hdc = pd.hDC; + + Ptr_pixX=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,HORZRES); + Ptr_pixY=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,VERTRES); + Ptr_mmX=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,HORZSIZE); + Ptr_mmY=(float)GetDeviceCaps(PrinterDrawable->winDC.hdc,VERTSIZE); + + screenX1=0; screenY1=0; + screenX2=dInfoPtr->maxX; screenY2=dInfoPtr->maxY; + pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), + (screenX2 + 30), + (screenY2 + 30), + Tk_Depth(tkwin)); + width = screenX2 - screenX1; + height = screenY2 - screenY1; + + hDCpixmap = TkWinGetDrawableDC(Tk_Display(tkwin), pixmap, &pixmapState); + canv_pixX=(float)GetDeviceCaps(hDCpixmap,HORZRES); + canv_pixY=(float)GetDeviceCaps(hDCpixmap,VERTRES); + canv_mmX=(float)GetDeviceCaps(hDCpixmap,HORZSIZE); + canv_mmY=(float)GetDeviceCaps(hDCpixmap,VERTSIZE); + + /* + * Save text widget data. + */ + dInfoPtr = textPtr->dInfoPtr; + saved_x = dInfoPtr->x; + saved_y = dInfoPtr->y; + saved_w = Tk_Width(textPtr->tkwin); + saved_h = Tk_Height(textPtr->tkwin); + saved_maxX = dInfoPtr->maxX; + saved_maxY = dInfoPtr->maxY; + saved_eof = dInfoPtr->topOfEof; + dInfoPtr->maxX = MAXINT; + Tk_Width(textPtr->tkwin) = MAXINT; + + dInfoPtr->maxY = MAXINT; + Tk_Height(textPtr->tkwin) = MAXINT; + + /* Make the text widget big enough for all the + text to be seen. */ + + numLines = TkBTreeNumLines(textPtr->tree); +#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + TkTextMakeByteIndex(textPtr->tree, 0, 0, &first); + TkTextMakeByteIndex(textPtr->tree, numLines, 100, &last); +#else + TkTextMakeIndex(textPtr->tree, 0, 0, &first); + TkTextMakeIndex(textPtr->tree, numLines, 100, &last); +#endif + TkTextChanged(textPtr, &first, &last); + + /* + * Set the display info flag to out-of-date. + */ + + textPtr->dInfoPtr->flags|=DINFO_OUT_OF_DATE; + + /* + *TkTextXviewCmd will call UpdateDisplayInfo. + */ + + TkTextXviewCmd(textPtr, interp, 2, NULL); + dInfoPtr = textPtr->dInfoPtr; + + SetMapMode(PrinterDrawable->winDC.hdc,MM_ISOTROPIC); + SetWindowExtEx(PrinterDrawable->winDC.hdc,(int)((float)canv_pixX),(int)((float)canv_pixY),NULL); + SetViewportExtEx(PrinterDrawable->winDC.hdc,(int)((float)Ptr_pixX), + (int)((float)Ptr_pixY), + NULL); + + /* + * Get max Y for text widget. + */ + maxHeight = -1; + for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; + dlPtr = dlPtr->nextPtr) { + maxHeight = dlPtr->y + dlPtr->height; + } + + /* + * Calculate the number of tiles high. + */ + page_Y_size = GetDeviceCaps(hDCpixmap,LOGPIXELSY)*(Ptr_mmY/22); + + tiles_high = ( maxHeight / page_Y_size ); /* start at page zero */ + + StartDoc(pd.hDC,lpdi); + for (tile_y = 0; tile_y <= tiles_high;tile_y++) { + SetViewportOrgEx(pd.hDC,0,-(tile_y*Ptr_pixY),NULL); + + StartPage(pd.hDC); + + if (maxHeight > 0) { + for (prevPtr = NULL, dlPtr = textPtr->dInfoPtr->dLinePtr; + (dlPtr != NULL) && (dlPtr->y < dInfoPtr->maxY); + prevPtr = dlPtr, dlPtr = dlPtr->nextPtr) { + DisplayDLineToDrawable(textPtr, dlPtr, prevPtr, PrinterDrawable); + + } + } + + + EndPage(pd.hDC); + } + EndDoc(pd.hDC); + + /* + * Restore text widget data. + */ + + dInfoPtr->x = saved_x; + dInfoPtr->y = saved_y; + Tk_Width(textPtr->tkwin) = saved_w; + Tk_Height(textPtr->tkwin) = saved_h; + dInfoPtr->maxY = saved_maxY; + dInfoPtr->maxX = saved_maxX; + dInfoPtr->topOfEof = saved_eof; + /* + * Pitch the info again. + */ + TkTextChanged(textPtr, &first, &last); + + /* + * Display info not valid anymore. + */ + + textPtr->dInfoPtr->flags|=DINFO_OUT_OF_DATE; + +done: + return TCL_OK; + error: + return TCL_ERROR; +} + + + +static void +ide_delete_print_text_command(ClientData clientData) +{ + /* destructor code here.*/ +} + +int +ide_create_print_text_command (Tcl_Interp *interp) +{ + + if (Tcl_CreateCommand(interp, "ide_print_text", + PrintTextCmd, + NULL, NULL) == NULL) + return TCL_ERROR; + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * DisplayDLineToDrawable -- + * + * This procedure is invoked to draw a single line to a HDC + * + *---------------------------------------------------------------------- + */ + +static void +DisplayDLineToDrawable(textPtr, dlPtr, prevPtr, drawable) + TkText *textPtr; /* Text widget in which to draw line. */ + register DLine *dlPtr; /* Information about line to draw. */ + DLine *prevPtr; /* Line just before one to draw, or NULL + * if dlPtr is the top line. */ + TkWinDrawable *drawable; /* drawable to use for displaying. + * Caller must make sure it's large enough + * to hold line. */ +{ + register TkTextDispChunk *chunkPtr; + TextDInfo *dInfoPtr = textPtr->dInfoPtr; + Display *display; + int height, x; + + /* + * First, clear the area of the line to the background color for the + * text widget. + */ + + display = Tk_Display(textPtr->tkwin); + + for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL); + chunkPtr = chunkPtr->nextPtr) { + if (chunkPtr->displayProc == TkTextInsertDisplayProc) { + /* + * Already displayed the insertion cursor above. Don't + * do it again here. + */ + + continue; + } else { + x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curPixelOffset; + if ((x + chunkPtr->width <= 0) || (x >= dInfoPtr->maxX)) { + (*chunkPtr->displayProc)(chunkPtr, -chunkPtr->width, + dlPtr->y, + dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, + dlPtr->baseline - dlPtr->spaceAbove, display, (unsigned long)drawable, + dlPtr->y + dlPtr->spaceAbove); + } else { + (*chunkPtr->displayProc)(chunkPtr, x, dlPtr->y, + dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, + dlPtr->baseline - dlPtr->spaceAbove, display, (unsigned long)drawable, + dlPtr->y + dlPtr->spaceAbove); + } + } + } + +} + +#endif /* _WIN */
tkWinPrintText.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkTableCmd.h =================================================================== --- tkTableCmd.h (nonexistent) +++ tkTableCmd.h (revision 1765) @@ -0,0 +1,52 @@ +/* + * tkTableCmd.h -- + * + * This is the header file for the module that implements + * command structure lookups. + * + * Copyright (c) 1997,1998 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#ifndef _CMD_H_ +#define _CMD_H_ + +#include +#include +#include + +/* structure for use in parsing table commands/values */ +typedef struct { + char *name; /* name of the command/value */ + int value; /* >0 because 0 represents an error */ +} Cmd_Struct; + +extern char * Cmd_GetName _ANSI_ARGS_((const Cmd_Struct *cmds, int val)); +extern int Cmd_GetValue _ANSI_ARGS_((const Cmd_Struct *cmds, + const char *arg)); +extern void Cmd_GetError _ANSI_ARGS_((Tcl_Interp *interp, + const Cmd_Struct *cmds, + const char *arg)); +extern int Cmd_Parse _ANSI_ARGS_((Tcl_Interp *interp, Cmd_Struct *cmds, + const char *arg)); +extern int Cmd_OptionSet _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, + Tk_Window unused, char *value, + char *widgRec, int offset)); +extern char * Cmd_OptionGet _ANSI_ARGS_((ClientData clientData, + Tk_Window unused, char *widgRec, + int offset, + Tcl_FreeProc **freeProcPtr)); +extern int Cmd_BitSet _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, + Tk_Window unused, char *value, + char *widgRec, int offset)); +extern char * Cmd_BitGet _ANSI_ARGS_((ClientData clientData, + Tk_Window unused, char *widgRec, + int offset, + Tcl_FreeProc **freeProcPtr)); + +#endif /* _CMD_H_ */
tkTableCmd.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tclgetdir.c =================================================================== --- tclgetdir.c (nonexistent) +++ tclgetdir.c (revision 1765) @@ -0,0 +1,269 @@ +/* tclgetdir.c -- TCL code to browse for a directory. + Copyright (C) 1997, 1998 Cygnus Solutions. + Written by Ian Lance Taylor . */ + +#ifdef _WIN32 +#include +#ifndef _GNU_H_WINDOWS_H /* if not using old Cygwin Win32 headers */ +#include +#endif +#endif + +#include +#include + +#include "guitcl.h" + +/* This file defines one TCL command. + + ide_get_directory + Allows the user to select a directory. Returns the selected + directory as a string. */ + +#ifdef _WIN32 + +#include +/* a call back to set the initial selected directory */ + +/* defines currently missing from Cygwin32 */ +#ifndef BFFM_INITIALIZED + + +LPITEMIDLIST WINAPI SHBrowseForFolderA(LPBROWSEINFO lpbi); + +/* message from browser */ +#define BFFM_INITIALIZED 1 +#define BFFM_SELCHANGED 2 + +/* messages to browser */ +#define BFFM_SETSTATUSTEXTA (WM_USER + 100) +#define BFFM_ENABLEOK (WM_USER + 101) +#define BFFM_SETSELECTIONA (WM_USER + 102) +#define BFFM_SETSELECTIONW (WM_USER + 103) +#define BFFM_SETSTATUSTEXTW (WM_USER + 104) + +#ifdef UNICODE +#define SHBrowseForFolder SHBrowseForFolderW +#define BFFM_SETSTATUSTEXT BFFM_SETSTATUSTEXTW +#define BFFM_SETSELECTION BFFM_SETSELECTIONW +#else +#define SHBrowseForFolder SHBrowseForFolderA +#define BFFM_SETSTATUSTEXT BFFM_SETSTATUSTEXTA +#define BFFM_SETSELECTION BFFM_SETSELECTIONA +#endif + +#endif /* ! BFFM_INITIALIZED */ + +/* FIXME: We need to dig into the Tk window implementation internals. */ + +int CALLBACK MyBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + if (uMsg==BFFM_INITIALIZED) + { + SendMessage(hwnd,BFFM_SETSELECTION,(WPARAM)TRUE,(LPARAM)lpData); + } + return 0; +} + +/* Implement the Windows version of the ide_get_directory command. */ +static int +get_directory_command (ClientData cd, Tcl_Interp *interp, int argc, + char **argv) +{ + BROWSEINFO bi; + char buf[MAX_PATH + 1]; + Tk_Window parent; + int i, oldMode; + LPITEMIDLIST idlist; + char *p; + int atts; + Tcl_DString tempBuffPtr; +#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_DString titleDString; + Tcl_DString initialDirDString; + Tcl_DString resultDString; + + Tcl_DStringInit(&titleDString); + Tcl_DStringInit(&initialDirDString); +#endif + + Tcl_DStringInit(&tempBuffPtr); + + bi.hwndOwner = NULL; + bi.pidlRoot = NULL; + bi.pszDisplayName = buf; + bi.lpszTitle = NULL; + bi.ulFlags = 0; + bi.lpfn = NULL; + bi.lParam = 0; + bi.iImage = 0; + + parent = Tk_MainWindow (interp); + + for (i = 1; i < argc; i += 2) + { + int v; + int len; + + v = i + 1; + len = strlen (argv[i]); + + if (strncmp (argv[i], "-parent", len) == 0) + { + if (v == argc) + goto arg_missing; + + parent = Tk_NameToWindow (interp, argv[v], + Tk_MainWindow (interp)); + if (parent == NULL) + return TCL_ERROR; + } + else if (strncmp (argv[i], "-title", len) == 0) + { + + if (v == argc) + goto arg_missing; + +#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_UtfToExternalDString(NULL, argv[v], -1, &titleDString); + bi.lpszTitle = Tcl_DStringValue(&titleDString); +#else + bi.lpszTitle = argv[v]; +#endif + } + else if (strncmp (argv[i], "-initialdir", len) == 0) + { + if (v == argc) + goto arg_missing; + + /* bi.lParam will be passed to the callback function.(save the need for globals)*/ + bi.lParam = (LPARAM) Tcl_TranslateFileName(interp, argv[v], &tempBuffPtr); +#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_UtfToExternalDString(NULL, (char *) bi.lParam, -1, &initialDirDString); + bi.lParam = (LPARAM) Tcl_DStringValue(&initialDirDString); +#endif + bi.lpfn = MyBrowseCallbackProc; + } + else + { + Tcl_AppendResult (interp, "unknown option \"", argv[i], + "\", must be -parent or -title", (char *) NULL); + return TCL_ERROR; + } + } + + if (Tk_WindowId (parent) == None) + Tk_MakeWindowExist (parent); + + bi.hwndOwner = Tk_GetHWND (Tk_WindowId (parent)); + + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + idlist = SHBrowseForFolder (&bi); + Tcl_SetServiceMode(oldMode); + + if (idlist == NULL) + { + /* User pressed the cancel button. */ + return TCL_OK; + } + + if (! SHGetPathFromIDList (idlist, buf)) + { + Tcl_SetResult (interp, "could not get path for directory", TCL_STATIC); + return TCL_ERROR; + } + + /* Ensure the directory exists. */ + atts = GetFileAttributesA (buf); + if (atts == -1 || ! (atts & FILE_ATTRIBUTE_DIRECTORY)) + { + Tcl_AppendResult (interp, "path \"", buf, "\" is not a directory", + (char *) NULL); + /* FIXME: free IDLIST. */ + return TCL_ERROR; + } + + /* FIXME: We are supposed to free IDLIST using the shell task + allocator, but cygwin32 doesn't define the required interfaces + yet. */ + + + + /* Normalize the path for Tcl. */ +#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_ExternalToUtfDString(NULL, buf, -1, &resultDString); + p = Tcl_DStringValue(&resultDString); +#else + p = buf; +#endif + for (; *p != '\0'; ++p) + if (*p == '\\') + *p = '/'; + + Tcl_ResetResult(interp); +#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_SetResult(interp, Tcl_DStringValue(&resultDString), TCL_VOLATILE); + Tcl_DStringFree(&resultDString); + Tcl_DStringFree(&titleDString); + Tcl_DStringFree(&initialDirDString); +#else + Tcl_SetResult(interp, buf, TCL_VOLATILE); +#endif + Tcl_DStringFree(&tempBuffPtr); + + return TCL_OK; + + arg_missing: + Tcl_AppendResult(interp, "value for \"", argv[argc - 1], "\" missing", + NULL); + return TCL_ERROR; +} + + +#else /* ! _WIN32 */ + +/* Use our modified file dialog, and hope the user picks a directory. */ + +static int +get_directory_command (ClientData cd, Tcl_Interp *interp, int argc, + char **argv) +{ + char **new_args; + char *merge; + int result, i; + + /* We can't directly run Tk_GetOpenFile, because it wants some + ClientData that we're best off not knowing. So instead we + re-eval. This is a lot less efficient, but it doesn't really + matter. */ + + new_args = (char **) Tcl_Alloc ((argc + 2) * sizeof (char *)); + + new_args[0] = "tk_getOpenFile"; + new_args[1] = "-choosedir"; + new_args[2] = "1"; + + for (i = 1; i < argc; ++i) + new_args[2 + i] = argv[i]; + + merge = Tcl_Merge (argc + 2, new_args); + result = Tcl_GlobalEval (interp, merge); + + Tcl_Free (merge); + Tcl_Free ((char *) new_args); + + return result; +} + +#endif /* ! _WIN32 */ + +/* This function creates the ide_get_directory TCL command. */ + +int +ide_create_get_directory_command (Tcl_Interp *interp) +{ + if (Tcl_CreateCommand (interp, "ide_get_directory", get_directory_command, + NULL, NULL) == NULL) + return TCL_ERROR; + return TCL_OK; +}
tclgetdir.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkTableTag.c =================================================================== --- tkTableTag.c (nonexistent) +++ tkTableTag.c (revision 1765) @@ -0,0 +1,756 @@ +/* + * tkTableTag.c -- + * + * This module implements tags for table widgets. + * + * Copyright (c) 1998 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include "tkTable.h" + +static void CreateTagEntry _ANSI_ARGS_((Table *tablePtr, char *name, + int argc, char **argv)); +static void TableImageProc _ANSI_ARGS_((ClientData clientData, int x, + int y, int width, int height, + int imageWidth, int imageHeight)); + +/* tag subcommands */ +#define TAG_CELLTAG 1 /* tag a cell */ +#define TAG_CGET 2 /* get a config value */ +#define TAG_COLTAG 3 /* tag a column */ +#define TAG_CONFIGURE 4 /* config/create a new tag */ +#define TAG_DELETE 5 /* delete a tag */ +#define TAG_EXISTS 6 /* does a tag exist? */ +#define TAG_NAMES 7 /* print the tag names */ +#define TAG_ROWTAG 8 /* tag a row */ +#define TAG_INCLUDES 9 /* does an index have a particular tag */ + +static Cmd_Struct tag_cmds[] = { + {"celltag", TAG_CELLTAG}, + {"coltag", TAG_COLTAG}, + {"configure", TAG_CONFIGURE}, + {"cget", TAG_CGET}, + {"delete", TAG_DELETE}, + {"exists", TAG_EXISTS}, + {"names", TAG_NAMES}, + {"rowtag", TAG_ROWTAG}, + {"includes", TAG_INCLUDES}, + {"", 0} +}; + +static Cmd_Struct tagState_vals[]= { + {"unknown", STATE_UNKNOWN}, + {"normal", STATE_NORMAL}, + {"disabled", STATE_DISABLED}, + {"", 0 } +}; + +static Tk_CustomOption tagStateOpt = { Cmd_OptionSet, Cmd_OptionGet, + (ClientData)(&tagState_vals) }; + +/* + * The default specification for configuring tags + * Done like this to make the command line parsing easy + */ + +static Tk_ConfigSpec tagConfig[] = { + {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", "center", + Tk_Offset(TableTag, anchor), TK_CONFIG_DONT_SET_DEFAULT }, + {TK_CONFIG_BORDER, "-background", "background", "Background", NULL, + Tk_Offset(TableTag, bg), + TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, + {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, + (char *) NULL, 0, 0 }, + {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", NULL, + Tk_Offset(TableTag, fg), + TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, + {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, + (char *) NULL, 0, 0 }, + {TK_CONFIG_FONT, "-font", "font", "Font", NULL, + Tk_Offset(TableTag, tkfont), + TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, + {TK_CONFIG_STRING, "-image", "image", "Image", NULL, + Tk_Offset(TableTag, imageStr), + TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, + {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify", "left", + Tk_Offset(TableTag, justify), TK_CONFIG_DONT_SET_DEFAULT }, + {TK_CONFIG_INT, "-multiline", "multiline", "Multiline", "1", + Tk_Offset(TableTag, multiline), TK_CONFIG_DONT_SET_DEFAULT }, + {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", "flat", + Tk_Offset(TableTag, relief), + TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK }, + {TK_CONFIG_INT, "-showtext", "showText", "ShowText", "0", + Tk_Offset(TableTag, showtext), TK_CONFIG_DONT_SET_DEFAULT }, + {TK_CONFIG_CUSTOM, "-state", "state", "State", "unknown", + Tk_Offset(TableTag, state), TK_CONFIG_DONT_SET_DEFAULT, &tagStateOpt }, + {TK_CONFIG_INT, "-wrap", "wrap", "Wrap", "0", + Tk_Offset(TableTag, wrap), TK_CONFIG_DONT_SET_DEFAULT }, + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0 } +}; + +/* + *---------------------------------------------------------------------- + * + * TableImageProc -- + * Called when an image associated with a tag is changed. + * + * Results: + * None. + * + * Side effects: + * Invalidates the whole table. + * FIX - should only invalidate affected cells. + * + *---------------------------------------------------------------------- + */ +static void +TableImageProc(ClientData clientData, int x, int y, int width, int height, + int imageWidth, int imageHeight) +{ + TableInvalidateAll((Table *)clientData, 0); +} + +/* + *---------------------------------------------------------------------- + * + * TableNewTag -- + * ckallocs space for a new tag structure and inits the structure. + * + * Results: + * Returns a pointer to the new structure. Must be freed later. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +TableTag * +TableNewTag(void) +{ + TableTag *tagPtr = (TableTag *) ckalloc(sizeof(TableTag)); + tagPtr->anchor = (Tk_Anchor)-1; + tagPtr->bg = NULL; + tagPtr->fg = NULL; + tagPtr->tkfont = NULL; + tagPtr->image = NULL; + tagPtr->imageStr = NULL; + tagPtr->justify = (Tk_Justify)-1; + tagPtr->multiline = -1; + tagPtr->relief = -1; + tagPtr->showtext = -1; + tagPtr->state = STATE_UNKNOWN; + tagPtr->wrap = -1; + return tagPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TableMergeTag -- + * This routine merges two tags by adding any fields from the addTag + * that are set to the baseTag. + * + * Results: + * baseTag will inherit all set characteristics of addTag + * (addTag thus has the priority). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void +TableMergeTag(TableTag *baseTag, TableTag *addTag) +{ + if (addTag->anchor != (Tk_Anchor)-1) baseTag->anchor = addTag->anchor; + if (addTag->bg != NULL) baseTag->bg = addTag->bg; + if (addTag->fg != NULL) baseTag->fg = addTag->fg; + if (addTag->tkfont != NULL) baseTag->tkfont = addTag->tkfont; + if (addTag->imageStr != NULL) { + baseTag->imageStr = addTag->imageStr; + baseTag->image = addTag->image; + } + if (addTag->multiline >= 0) baseTag->multiline = addTag->multiline; + if (addTag->relief != -1) baseTag->relief = addTag->relief; + if (addTag->showtext >= 0) baseTag->showtext = addTag->showtext; + if (addTag->state != STATE_UNKNOWN) baseTag->state = addTag->state; + if (addTag->justify != (Tk_Justify)-1) baseTag->justify = addTag->justify; + if (addTag->wrap >= 0) baseTag->wrap = addTag->wrap; +} + +/* + *---------------------------------------------------------------------- + * + * TableInvertTag -- + * This routine swaps background and foreground for the selected tag. + * + * Results: + * Inverts fg and bg of tag. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void +TableInvertTag(TableTag *baseTag) +{ + Tk_3DBorder tmpBg; + + tmpBg = baseTag->fg; + baseTag->fg = baseTag->bg; + baseTag->bg = tmpBg; +} + +/* + *---------------------------------------------------------------------- + * + * CreateTagEntry -- + * Takes a name and optional args and create a tag entry in the + * table's tag table. + * + * Results: + * A new tag entry will be created. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static void +CreateTagEntry(Table *tablePtr, char *name, int argc, char **argv) +{ + Tcl_HashEntry *entryPtr; + TableTag *tagPtr = TableNewTag(); + int dummy; + Tk_ConfigureWidget(tablePtr->interp, tablePtr->tkwin, tagConfig, + argc, argv, (char *)tagPtr, TK_CONFIG_ARGV_ONLY); + entryPtr = Tcl_CreateHashEntry(tablePtr->tagTable, name, &dummy); + Tcl_SetHashValue(entryPtr, (ClientData) tagPtr); +} + +/* + *---------------------------------------------------------------------- + * + * TableInitTags -- + * Creates the static table tags. + * + * Results: + * active, sel, title and flash are created as tags. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void +TableInitTags(Table *tablePtr) +{ + static char *activeArgs[] = {"-bg", ACTIVE_BG, "-relief", "flat" }; + static char *selArgs[] = {"-bg", SELECT_BG, "-relief", "sunken" }; + static char *titleArgs[] = {"-bg", DISABLED, "-relief", "flat", + "-fg", "white", "-state", "disabled" }; + static char *flashArgs[] = {"-bg", "red" }; + CreateTagEntry(tablePtr, "active", ARSIZE(activeArgs), activeArgs); + CreateTagEntry(tablePtr, "sel", ARSIZE(selArgs), selArgs); + CreateTagEntry(tablePtr, "title", ARSIZE(titleArgs), titleArgs); + CreateTagEntry(tablePtr, "flash", ARSIZE(flashArgs), flashArgs); +} + +/* + *---------------------------------------------------------------------- + * + * FindRowColTag -- + * Finds a row/col tag based on the row/col styles and tagCommand. + * + * Results: + * Returns tag associated with row/col cell, if any. + * + * Side effects: + * Possible side effects from eval of tagCommand. + * + *---------------------------------------------------------------------- + */ +TableTag * +FindRowColTag(Table *tablePtr, int cell, int mode) +{ + Tcl_HashTable *hash; + Tcl_HashEntry *entryPtr; + + hash = (mode == ROW) ? tablePtr->rowStyles : tablePtr->colStyles; + if ((entryPtr = Tcl_FindHashEntry(hash, (char *)cell)) == NULL) { + char *cmd = (mode == ROW) ? tablePtr->rowTagCmd : tablePtr->colTagCmd; + if (cmd) { + register Tcl_Interp *interp = tablePtr->interp; + char buf[INDEX_BUFSIZE]; + /* Since it does not exist, eval command with row/col appended */ + sprintf(buf, " %d", cell); + Tcl_Preserve((ClientData) interp); + if (Tcl_VarEval(interp, cmd, buf, (char *)NULL) == TCL_OK) { + char *name = Tcl_GetStringResult(interp); + if (name && *name) { + /* If a result was returned, check to see if it is a known tag */ + entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, name); + } + } + Tcl_Release((ClientData) interp); + Tcl_ResetResult(interp); + } + } + return (TableTag *) (entryPtr ? Tcl_GetHashValue(entryPtr) : NULL); +} + +/* + *---------------------------------------------------------------------- + * + * TableCleanupTag -- + * Releases the resources used by a tag before it is freed up. + * + * Results: + * None. + * + * Side effects: + * The tag is no longer valid. + * + *---------------------------------------------------------------------- + */ +void +TableCleanupTag(Table *tablePtr, TableTag *tagPtr) +{ + if (tagPtr->image) + Tk_FreeImage(tagPtr->image); + /* free the options in the widget */ + Tk_FreeOptions(tagConfig, (char *) tagPtr, tablePtr->display, 0); +} + +/* + *-------------------------------------------------------------- + * + * TableTagCmd -- + * This procedure is invoked to process the tag method + * that corresponds to a widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +TableTagCmd(Table * tablePtr, register Tcl_Interp *interp, + int argc, char *argv[]) +{ + int result = TCL_OK, retval, i, newEntry, value; + int row, col; + TableTag *tagPtr; + Tcl_HashEntry *entryPtr, *scanPtr, *newEntryPtr, *oldEntryPtr; + Tcl_HashTable *hashTblPtr; + Tcl_HashSearch search; + Tk_Image image; + char buf[INDEX_BUFSIZE], *keybuf, *yes = "1", *no = "0"; + + /* parse the next argument */ + retval = Cmd_Parse(interp, tag_cmds, argv[2]); + switch (retval) { + /* failed to parse the argument, error */ + case 0: + return TCL_ERROR; + + case TAG_CELLTAG: + /* tag a (group of) cell(s) */ + if (argc < 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " tag cell tag ?arg arg ...?\"", (char *) NULL); + return TCL_ERROR; + } + /* are we deleting */ + if (!(*argv[3])) + tagPtr = NULL; + else { + /* check to see if the tag actually exists */ + if ((entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, argv[3]))==NULL) { + /* Unknown tag, just return empty string */ + Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); + return TCL_OK; + } + /* get the pointer to the tag structure */ + tagPtr = (TableTag *) Tcl_GetHashValue (entryPtr); + } + + /* No more args -> display only */ + if (argc == 4) { + /* Added special handling for tags: active, flash, sel, title */ + + if ((tablePtr->flags & HAS_ACTIVE) && strcmp(argv[3], "active") == 0) { + TableMakeArrayIndex(tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, buf); + Tcl_AppendElement(interp, buf); + } else if (tablePtr->flashMode && strcmp(argv[3], "flash") == 0) { + for (scanPtr = Tcl_FirstHashEntry(tablePtr->flashCells, &search); + scanPtr != NULL; scanPtr = Tcl_NextHashEntry(&search)) { + Tcl_AppendElement(interp, + Tcl_GetHashKey(tablePtr->flashCells, scanPtr)); + } + } else if (strcmp(argv[3], "sel") == 0) { + for (scanPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); + scanPtr != NULL; scanPtr = Tcl_NextHashEntry(&search)) { + Tcl_AppendElement(interp, + Tcl_GetHashKey(tablePtr->selCells, scanPtr)); + } + } else if (strcmp(argv[3], "title") == 0 && + (tablePtr->titleRows || tablePtr->titleCols)) { + for (row = tablePtr->rowOffset; + row < tablePtr->rowOffset+tablePtr->rows; row++) { + for (col = tablePtr->colOffset; + col < tablePtr->colOffset+tablePtr->titleCols; col++) { + TableMakeArrayIndex(row, col, buf); + Tcl_AppendElement(interp, buf); + } + } + for (row = tablePtr->rowOffset; + row < tablePtr->rowOffset+tablePtr->titleRows; row++) { + for (col = tablePtr->colOffset+tablePtr->titleCols; + col < tablePtr->colOffset+tablePtr->cols; col++) { + TableMakeArrayIndex(row, col, buf); + Tcl_AppendElement(interp, buf); + } + } + } else { + for (scanPtr = Tcl_FirstHashEntry(tablePtr->cellStyles, &search); + scanPtr != NULL; scanPtr = Tcl_NextHashEntry(&search)) { + /* is this the tag pointer for this cell */ + if ((TableTag *) Tcl_GetHashValue(scanPtr) == tagPtr) { + Tcl_AppendElement(interp, + Tcl_GetHashKey(tablePtr->cellStyles, scanPtr)); + } + } + } + return TCL_OK; + } + /* Now loop through the arguments and fill in the hash table */ + for (i = 4; i < argc; i++) { + /* can I parse this argument */ + if (TableGetIndex(tablePtr, argv[i], &row, &col) != TCL_OK) { + return TCL_ERROR; + } + /* get the hash key ready */ + TableMakeArrayIndex(row, col, buf); + + /* is this a deletion */ + if (tagPtr == NULL) { + oldEntryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf); + if (oldEntryPtr != NULL) + Tcl_DeleteHashEntry(oldEntryPtr); + } else { + /* add a key to the hash table */ + newEntryPtr = Tcl_CreateHashEntry(tablePtr->cellStyles, buf, + &newEntry); + + /* and set it to point to the Tag structure */ + Tcl_SetHashValue (newEntryPtr, (ClientData) tagPtr); + } + /* now invalidate the area */ + TableRefresh(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, CELL); + } + return TCL_OK; + + case TAG_COLTAG: + case TAG_ROWTAG: + /* tag a row or a column */ + if (argc < 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " tag ", (retval == TAG_ROWTAG) ? "row" : + "col", " tag ?arg arg ..?\"", (char *) NULL); + return TCL_ERROR; + } + /* if the tag is null, we are deleting */ + if (!(*argv[3])) + tagPtr = NULL; + else { /* check to see if the tag actually exists */ + if ((entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, argv[3]))==NULL) { + /* Unknown tag, just return empty string */ + Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); + return TCL_OK; + } + /* get the pointer to the tag structure */ + tagPtr = (TableTag *) Tcl_GetHashValue (entryPtr); + } + + /* and choose the correct hash table */ + hashTblPtr = (retval == TAG_ROWTAG) ? + tablePtr->rowStyles : tablePtr->colStyles; + + /* No more args -> display only */ + if (argc == 4) { + for (scanPtr = Tcl_FirstHashEntry(hashTblPtr, &search); + scanPtr != NULL; scanPtr = Tcl_NextHashEntry(&search)) { + /* is this the tag pointer on this row */ + if ((TableTag *) Tcl_GetHashValue (scanPtr) == tagPtr) { + sprintf(buf, "%d", (int) Tcl_GetHashKey (hashTblPtr, scanPtr)); + Tcl_AppendElement(interp, buf); + } + } + return TCL_OK; + } + /* Now loop through the arguments and fill in the hash table */ + for (i = 4; i < argc; i++) { + /* can I parse this argument */ + if (Tcl_GetInt(interp, argv[i], &value) != TCL_OK) { + return TCL_ERROR; + } + /* deleting or adding */ + if (tagPtr == NULL) { + oldEntryPtr = Tcl_FindHashEntry(hashTblPtr, (char *) value); + if (oldEntryPtr != NULL) + Tcl_DeleteHashEntry(oldEntryPtr); + } else { + /* add a key to the hash table */ + newEntryPtr = Tcl_CreateHashEntry(hashTblPtr, (char *) value, + &newEntry); + + /* and set it to point to the Tag structure */ + Tcl_SetHashValue (newEntryPtr, (ClientData) tagPtr); + } + /* and invalidate the row or column affected */ + if (retval == TAG_ROWTAG) { + TableRefresh(tablePtr, value-tablePtr->rowOffset, 0, ROW); + } else { + TableRefresh(tablePtr, 0, value-tablePtr->colOffset, COL); + } + } + return TCL_OK; /* COLTAG && ROWTAG */ + + case TAG_CGET: + if (argc != 5) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " tag cget tagName option\"", (char *) NULL); + return TCL_ERROR; + } + if ((entryPtr=Tcl_FindHashEntry(tablePtr->tagTable, argv[3])) == NULL) { + Tcl_AppendResult(interp, "invalid tag name \"", argv[3], + "\"", (char *) NULL); + return TCL_ERROR; + } else { + tagPtr = (TableTag *) Tcl_GetHashValue (entryPtr); + result = Tk_ConfigureValue(interp, tablePtr->tkwin, tagConfig, + (char *) tagPtr, argv[4], 0); + } + return result; /* CGET */ + + case TAG_CONFIGURE: + if (argc < 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " tag configure tagName ?arg arg ...?\"", + (char *) NULL); + return TCL_ERROR; + } + /* first see if this is a reconfiguration */ + entryPtr = Tcl_CreateHashEntry(tablePtr->tagTable, argv[3], &newEntry); + if (newEntry) { + /* create the structure */ + tagPtr = TableNewTag(); + + /* insert it into the table */ + Tcl_SetHashValue(entryPtr, (ClientData) tagPtr); + + /* configure the tag structure */ + result = Tk_ConfigureWidget(interp, tablePtr->tkwin, tagConfig, + argc - 4, argv + 4, (char *) tagPtr, 0); + if (result == TCL_ERROR) + return TCL_ERROR; + } else { + /* pointer wasn't null, do a reconfig if we have enough arguments */ + /* get the tag pointer from the table */ + tagPtr = (TableTag *) Tcl_GetHashValue(entryPtr); + + /* 5 args means that there are values to replace */ + if (argc > 5) { + /* and do a reconfigure */ + result = Tk_ConfigureWidget(interp, tablePtr->tkwin, + tagConfig, argc - 4, argv + 4, + (char *) tagPtr, TK_CONFIG_ARGV_ONLY); + if (result == TCL_ERROR) + return TCL_ERROR; + } + } + + /* handle change of image name */ + if (tagPtr->imageStr) { + image = Tk_GetImage(interp, tablePtr->tkwin, tagPtr->imageStr, + TableImageProc, (ClientData)tablePtr); + if (image == NULL) + result = TCL_ERROR; + } else { + image = NULL; + } + if (tagPtr->image) { + Tk_FreeImage(tagPtr->image); + } + tagPtr->image = image; + + /* + * If there were less than 6 args, we need + * to do a printout of the config, even for new tags + */ + if (argc < 6) { + result = Tk_ConfigureInfo(interp, tablePtr->tkwin, tagConfig, + (char *) tagPtr, (argc == 5)?argv[4]:0, 0); + } else { + /* Otherwise we reconfigured so invalidate the table for a redraw */ + TableInvalidateAll(tablePtr, 0); + } + return result; + + case TAG_DELETE: + /* delete a tag */ + if (argc < 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " tag delete tagName ?tagName ...?\"", (char *) NULL); + return TCL_ERROR; + } + /* run through the remaining arguments */ + for (i = 3; i < argc; i++) { + /* cannot delete the title tag */ + if (strcmp(argv[i], "title") == 0 || strcmp (argv[i], "sel") == 0 || + strcmp(argv[i], "flash") == 0 || strcmp (argv[i], "active") == 0) { + Tcl_AppendResult(interp, "cannot delete ", argv[i], + " tag", (char *) NULL); + return TCL_ERROR; + } + if ((entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, argv[i]))!=NULL) { + /* get the tag pointer */ + tagPtr = (TableTag *) Tcl_GetHashValue(entryPtr); + + /* delete all references to this tag in rows */ + scanPtr = Tcl_FirstHashEntry(tablePtr->rowStyles, &search); + for (; scanPtr != NULL; scanPtr = Tcl_NextHashEntry(&search)) + if ((TableTag *)Tcl_GetHashValue(scanPtr) == tagPtr) + Tcl_DeleteHashEntry(scanPtr); + + /* delete all references to this tag in cols */ + scanPtr = Tcl_FirstHashEntry(tablePtr->colStyles, &search); + for (; scanPtr != NULL; scanPtr = Tcl_NextHashEntry(&search)) + if ((TableTag *)Tcl_GetHashValue(scanPtr) == tagPtr) + Tcl_DeleteHashEntry(scanPtr); + + /* delete all references to this tag in cells */ + scanPtr = Tcl_FirstHashEntry(tablePtr->cellStyles, &search); + for (; scanPtr != NULL; scanPtr = Tcl_NextHashEntry(&search)) + if ((TableTag *)Tcl_GetHashValue(scanPtr) == tagPtr) + Tcl_DeleteHashEntry(scanPtr); + + /* release the structure */ + TableCleanupTag(tablePtr, tagPtr); + ckfree((char *) tagPtr); + + /* and free the hash table entry */ + Tcl_DeleteHashEntry(entryPtr); + } + } + /* since we deleted a tag, redraw the screen */ + TableInvalidateAll(tablePtr, 0); + return result; + + case TAG_EXISTS: + if (argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " tag exists tagName\"", (char *) NULL); + return TCL_ERROR; + } + if (Tcl_FindHashEntry(tablePtr->tagTable, argv[3]) != NULL) { + Tcl_SetResult(interp, yes, TCL_VOLATILE); + } else { + Tcl_SetResult(interp, no, TCL_VOLATILE); + } + return TCL_OK; + + case TAG_INCLUDES: + /* does a tag contain a index ? */ + if (argc != 5) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " tag includes tag index\"", (char *) NULL); + return TCL_ERROR; + } + /* check to see if the tag actually exists */ + if ((entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, argv[3])) == NULL) { + /* Unknown tag, just return no */ + Tcl_SetResult(interp, no, TCL_VOLATILE); + return TCL_OK; + } + /* parse index */ + if (TableGetIndex (tablePtr, argv[4], &row, &col) != TCL_OK) { + return TCL_ERROR; + } + /* create hash key */ + TableMakeArrayIndex(row, col, buf); + + if (strcmp(argv[3], "active") == 0) { + if (tablePtr->activeRow+tablePtr->rowOffset == row && + tablePtr->activeCol+tablePtr->colOffset == col) + Tcl_SetResult(interp, yes, TCL_VOLATILE); + else + Tcl_SetResult(interp, no, TCL_VOLATILE); + return TCL_OK; + } else if (strcmp(argv[3], "flash") == 0) { + if (tablePtr->flashMode && Tcl_FindHashEntry(tablePtr->flashCells, buf)) + Tcl_SetResult(interp, yes, TCL_VOLATILE); + else + Tcl_SetResult(interp, no, TCL_VOLATILE); + return TCL_OK; + } else if (strcmp(argv[3], "sel") == 0) { + if (Tcl_FindHashEntry(tablePtr->selCells, buf)) + Tcl_SetResult(interp, yes, TCL_VOLATILE); + else + Tcl_SetResult(interp, no, TCL_VOLATILE); + return TCL_OK; + } else if (strcmp(argv[3], "title") == 0) { + if (row < tablePtr->titleRows+tablePtr->rowOffset || + col < tablePtr->titleCols+tablePtr->colOffset) + Tcl_SetResult(interp, yes, TCL_VOLATILE); + else + Tcl_SetResult(interp, no, TCL_VOLATILE); + return TCL_OK; + } + + /* get the pointer to the tag structure */ + tagPtr = (TableTag *) Tcl_GetHashValue(entryPtr); + scanPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf); + /* look to see if there is a cell, row, or col tag for this cell */ + if ((scanPtr && ((TableTag *) Tcl_GetHashValue(scanPtr) == tagPtr)) || + (tagPtr == FindRowColTag(tablePtr, row, ROW)) || + (tagPtr == FindRowColTag(tablePtr, col, COL))) { + /* yes there is - return true */ + Tcl_SetResult(interp, yes, TCL_VOLATILE); + return TCL_OK; + } + Tcl_SetResult(interp, no, TCL_VOLATILE); + return TCL_OK; + + case TAG_NAMES: + /* just print out the tag names */ + if (argc != 3 && argc != 4) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " tag names ?pattern?\"", (char *) NULL); + return TCL_ERROR; + } + entryPtr = Tcl_FirstHashEntry(tablePtr->tagTable, &search); + while (entryPtr != NULL) { + keybuf = Tcl_GetHashKey(tablePtr->tagTable, entryPtr); + if (argc == 3 || Tcl_StringMatch(keybuf, argv[3])) + Tcl_AppendElement(interp, keybuf); + entryPtr = Tcl_NextHashEntry(&search); + } + return TCL_OK; + } + return TCL_OK; +} +
tkTableTag.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tkTableCell.c =================================================================== --- tkTableCell.c (nonexistent) +++ tkTableCell.c (revision 1765) @@ -0,0 +1,563 @@ +/* + * tkTableCell.c -- + * + * This module implements cell oriented functions for table + * widgets. + * + * Copyright (c) 1998 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include "tkTable.h" + +static int TableSortCompareProc _ANSI_ARGS_((CONST VOID *first, + CONST VOID *second)); + +/* + *---------------------------------------------------------------------- + * + * TableCellCoords -- + * Takes a row,col pair in real coords and finds it position + * on the virtual screen. + * + * Results: + * The virtual x, y, width, and height of the cell + * are placed in the pointers. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void +TableCellCoords(Table *tablePtr, int row, int col, + int *x, int *y, int *width, int *height) +{ + if (tablePtr->rows <= 0 || tablePtr->cols <= 0) { + *width = *height = *x = *y = 0; + return; + } + /* real coords required, always should be passed acceptable values, + * but this is a possible seg fault otherwise */ + row = MIN(tablePtr->rows-1, MAX(0, row)); + col = MIN(tablePtr->cols-1, MAX(0, col)); + *width = tablePtr->colPixels[col]; + *height = tablePtr->rowPixels[row]; + *x = tablePtr->highlightWidth + tablePtr->colStarts[col] - + ((col < tablePtr->titleCols) ? 0 : tablePtr->colStarts[tablePtr->leftCol] + - tablePtr->colStarts[tablePtr->titleCols]); + *y = tablePtr->highlightWidth + tablePtr->rowStarts[row] - + ((row < tablePtr->titleRows) ? 0 : tablePtr->rowStarts[tablePtr->topRow] + - tablePtr->rowStarts[tablePtr->titleRows]); +} + +/* + *---------------------------------------------------------------------- + * + * TableCellVCoords -- + * Takes a row,col pair in real coords and finds it position + * on the actual screen. The full arg specifies whether + * only 100% visible cells should be considered visible. + * + * Results: + * The x, y, width, and height of the cell are placed in the pointers, + * depending upon visibility of the cell. + * Returns 0 for hidden and 1 for visible cells. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +int +TableCellVCoords(Table *tablePtr, int row, int col, + int *rx, int *ry, int *rw, int *rh, int full) +{ + if (tablePtr->tkwin == NULL) return 0; + + if ((row < tablePtr->topRow && row >= tablePtr->titleRows) || + (col < tablePtr->leftCol && col >= tablePtr->titleCols)) { + /* hiding in "dead" space between title areas and visible cells */ + *rx = 0; *ry = 0; *rw = 0; *rh = 0; + return 0; + } else { + int x, y, w, h, w0, h0, hl = tablePtr->highlightWidth; + /* Necessary to use separate vars in case dummies are passed in */ + TableCellCoords(tablePtr, row, col, &x, &y, &w, &h); + *rx = x; *ry = y; + if (full) { + w0 = w; h0 = h; + } else { + /* if we don't care about seeing the whole thing, then + * make sure we at least see a pixel worth */ + w0 = h0 = 1; + } + /* Is the cell visible? */ + if (x(Tk_Width(tablePtr->tkwin)-hl) + || (y+h0)>(Tk_Height(tablePtr->tkwin)-hl)) { + /* definitely off the screen */ + *rw = *rh = 0; + return 0; + } else { + if (full) { + *rw = w; *rh = h; + } else { + *rw = MIN(w, Tk_Width(tablePtr->tkwin)-hl-x); + *rh = MIN(h, Tk_Height(tablePtr->tkwin)-hl-y); + } + return 1; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TableWhatCell -- + * Takes a x,y screen coordinate and determines what cell contains. + * that point. This will return cells that are beyond the right/bottom + * edge of the viewable screen. + * + * Results: + * The row,col of the cell are placed in the pointers. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void +TableWhatCell(register Table *tablePtr, int x, int y, int *row, int *col) +{ + int i; + x = MAX(0, x); y = MAX(0, y); + /* Adjust for table's global highlightthickness border */ + x -= tablePtr->highlightWidth; + y -= tablePtr->highlightWidth; + /* Adjust the x coord if not in the column titles to change display coords + * into internal coords */ + x += (x < tablePtr->colStarts[tablePtr->titleCols]) ? 0 : + tablePtr->colStarts[tablePtr->leftCol] - + tablePtr->colStarts[tablePtr->titleCols]; + y += (y < tablePtr->rowStarts[tablePtr->titleRows]) ? 0 : + tablePtr->rowStarts[tablePtr->topRow] - + tablePtr->rowStarts[tablePtr->titleRows]; + x = MIN(x, tablePtr->maxWidth-1); + y = MIN(y, tablePtr->maxHeight-1); + for (i = 1; x >= tablePtr->colStarts[i]; i++); + *col = i - 1; + for (i = 1; y >= tablePtr->rowStarts[i]; i++); + *row = i - 1; +} + +/* + *---------------------------------------------------------------------- + * + * TableAtBorder -- + * Takes a x,y screen coordinate and determines if that point is + * over a border. + * + * Results: + * The left/top row,col corresponding to that point are placed in + * the pointers. The number of borders (+1 for row, +1 for col) + * hit is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +int +TableAtBorder(Table * tablePtr, int x, int y, int *row, int *col) +{ + int i, borders = 2, bd = tablePtr->borderWidth; + int dbd = 2*bd; + x = MAX(0, x); y = MAX(0, y); + x -= tablePtr->highlightWidth; y -= tablePtr->highlightWidth; + /* Adjust the x coord if not in the column titles to change display coords + * into internal coords */ + x += (x < tablePtr->colStarts[tablePtr->titleCols]) ? 0 : + tablePtr->colStarts[tablePtr->leftCol] - + tablePtr->colStarts[tablePtr->titleCols]; + y += (y < tablePtr->rowStarts[tablePtr->titleRows]) ? 0 : + tablePtr->rowStarts[tablePtr->topRow] - + tablePtr->rowStarts[tablePtr->titleRows]; + x = MIN(x, tablePtr->maxWidth - 1); + y = MIN(y, tablePtr->maxHeight - 1); + for (i = 1; i <= tablePtr->cols && x+dbd >= tablePtr->colStarts[i]; i++); + if (x > tablePtr->colStarts[--i]+bd) { + borders--; + *col = -1; + } else { + *col = (--i < tablePtr->leftCol && i >= tablePtr->titleCols) ? + tablePtr->titleCols-1 : i; + } + for (i = 1; i <= tablePtr->rows && y+dbd >= tablePtr->rowStarts[i]; i++); + if (y > tablePtr->rowStarts[--i]+bd) { + borders--; + *row = -1; + } else { + *row = (--i < tablePtr->topRow && i >= tablePtr->titleRows) ? + tablePtr->titleRows-1 : i; + } + return borders; +} + +/* + *---------------------------------------------------------------------- + * + * TableGetCellValue -- + * Takes a row,col pair in user coords and returns the value for + * that cell. This varies depending on what data source the + * user has selected. + * + * Results: + * The value of the cell is returned. The return value is VOLATILE + * (do not free). + * + * Side effects: + * The value will be cached if caching is turned on. + * + *---------------------------------------------------------------------- + */ +char * +TableGetCellValue(Table *tablePtr, int r, int c) +{ + register Tcl_Interp *interp = tablePtr->interp; + char *result = NULL; + char buf[INDEX_BUFSIZE]; + Tcl_HashEntry *entryPtr = NULL; + int new = 1; + + TableMakeArrayIndex(r, c, buf); + + if (tablePtr->caching) { + /* if we are caching, let's see if we have the value cached */ + entryPtr = Tcl_CreateHashEntry(tablePtr->cache, buf, &new); + if (!new) { + result = (char *) Tcl_GetHashValue(entryPtr); + return result?result:""; + } + } + if (tablePtr->command && tablePtr->useCmd) { + Tcl_DString script; + Tcl_DStringInit(&script); + ExpandPercents(tablePtr, tablePtr->command, r, c, "", (char *)NULL, + 0, &script, 0); + if (Tcl_GlobalEval(interp, Tcl_DStringValue(&script)) == TCL_ERROR) { + tablePtr->useCmd = 0; + tablePtr->dataSource &= ~DATA_COMMAND; + if (tablePtr->arrayVar) + tablePtr->dataSource |= DATA_ARRAY; + Tcl_AddErrorInfo(interp, "\n\t(in command executed by table)"); + Tcl_AddErrorInfo(interp, Tcl_DStringValue(&script)); + Tk_BackgroundError(interp); + TableInvalidateAll(tablePtr, 0); + } else { + result = Tcl_GetStringResult(interp); + } + Tcl_FreeResult(interp); + Tcl_DStringFree(&script); + } else if (tablePtr->arrayVar) { + result = Tcl_GetVar2(interp, tablePtr->arrayVar, buf, TCL_GLOBAL_ONLY); + } + if (result == NULL) + result = ""; + if (tablePtr->caching && entryPtr != NULL) { + /* if we are caching, make sure we cache the returned value */ + /* entryPtr will have been set from above, but check to make sure + * someone didn't change caching during -command evaluation */ + char *val; + val = (char *)ckalloc(strlen(result)+1); + strcpy(val, result); + Tcl_SetHashValue(entryPtr, val); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TableSetCellValue -- + * Takes a row,col pair in user coords and saves the given value for + * that cell. This varies depending on what data source the + * user has selected. + * + * Results: + * Returns TCL_ERROR or TCL_OK, depending on whether an error + * occured during set (ie: during evaluation of -command). + * + * Side effects: + * If the value is NULL (empty string), it will be unset from + * an array rather than set to the empty string. + * + *---------------------------------------------------------------------- + */ +int +TableSetCellValue(Table *tablePtr, int r, int c, char *value) +{ + register Tcl_Interp *interp = tablePtr->interp; + char buf[INDEX_BUFSIZE]; + int code = TCL_OK; + + TableMakeArrayIndex(r, c, buf); + + if (tablePtr->state == STATE_DISABLED) + return code; + if (tablePtr->command && tablePtr->useCmd) { + Tcl_DString script; + + Tcl_DStringInit(&script); + ExpandPercents(tablePtr, tablePtr->command, r, c, value, (char *)NULL, + 1, &script, 0); + if (Tcl_GlobalEval(interp, Tcl_DStringValue(&script)) == TCL_ERROR) { + /* An error resulted. Prevent further triggering of the command + * and set up the error message. */ + tablePtr->useCmd = 0; + tablePtr->dataSource &= ~DATA_COMMAND; + if (tablePtr->arrayVar) + tablePtr->dataSource |= DATA_ARRAY; + Tcl_AddErrorInfo(interp, "\n\t(in command executed by table)"); + Tk_BackgroundError(interp); + code = TCL_ERROR; + } + Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); + Tcl_DStringFree(&script); + } else if (tablePtr->arrayVar) { + if (value == NULL || *value == '\0') { + Tcl_UnsetVar2(interp, tablePtr->arrayVar, buf, TCL_GLOBAL_ONLY); + } else if (Tcl_SetVar2(interp, tablePtr->arrayVar, buf, value, + TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { + code = TCL_ERROR; + } + } + if (tablePtr->caching && code == TCL_OK) { + Tcl_HashEntry *entryPtr; + int new; + char *val; + + val = (char *)ckalloc(strlen(value)+1); + strcpy(val, value); + entryPtr = Tcl_CreateHashEntry(tablePtr->cache, buf, &new); + Tcl_SetHashValue(entryPtr, val); + } + return code; +} + +/* + *---------------------------------------------------------------------- + * + * TableSortCompareProc -- + * This procedure is invoked by qsort to determine the proper + * ordering between two elements. + * + * Results: + * < 0 means first is "smaller" than "second", > 0 means "first" + * is larger than "second", and 0 means they should be treated + * as equal. + * + * Side effects: + * None, unless a user-defined comparison command does something + * weird. + * + *---------------------------------------------------------------------- + */ +static int +TableSortCompareProc(first, second) + CONST VOID *first, *second; /* Elements to be compared. */ +{ + int r1, c1, r2, c2; + char *firstString = *((char **) first); + char *secondString = *((char **) second); + + /* This doesn't account for badly formed indices */ + sscanf(firstString, "%d,%d", &r1, &c1); + sscanf(secondString, "%d,%d", &r2, &c2); + if (r1 > r2) + return 1; + else if (r1 < r2) + return -1; + else if (c1 > c2) + return 1; + else if (c1 < c2) + return -1; + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * TableCellSort -- + * Sort a list of table cell elements (of form row,col) + * + * Results: + * Returns the sorted list of elements. Because Tcl_Merge allocs + * the space for result, it must later be ckfree'd by caller. + * + * Side effects: + * Behaviour undefined for ill-formed input list of elements. + * + *---------------------------------------------------------------------- + */ +char * +TableCellSort(Table *tablePtr, char *str) +{ + int listArgc; + char **listArgv; + char *result; + + if (Tcl_SplitList(tablePtr->interp, str, &listArgc, &listArgv) != TCL_OK) + return str; + qsort((VOID *) listArgv, (size_t) listArgc, sizeof (char *), + TableSortCompareProc); + result = Tcl_Merge(listArgc, listArgv); + ckfree((char *) listArgv); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TableGetIcursor -- + * Parses the argument as an index into the active cell string. + * Recognises 'end', 'insert' or an integer. Constrains it to the + * size of the buffer. This acts like a "SetIcursor" when *posn is NULL. + * + * Results: + * If (posn != NULL), then it gets the cursor position. + * + * Side effects: + * Can move cursor position. + * + *---------------------------------------------------------------------- + */ +int +TableGetIcursor(Table *tablePtr, char *arg, int *posn) +{ + int tmp, len; +#if (TK_MINOR_VERSION > 0) + len = Tcl_NumUtfChars(tablePtr->activeBuf, strlen(tablePtr->activeBuf)); +#else + len = strlen(tablePtr->activeBuf); +#endif + /* ensure icursor didn't get out of sync */ + if (tablePtr->icursor > len) tablePtr->icursor = len; + /* is this end */ + if (strcmp(arg, "end") == 0) { + tmp = len; + } else if (strcmp(arg, "insert") == 0) { + tmp = tablePtr->icursor; + } else { + if (Tcl_GetInt(tablePtr->interp, arg, &tmp) != TCL_OK) { + return TCL_ERROR; + } + tmp = MIN(MAX(0, tmp), len); + } + if (posn) + *posn = tmp; + else + tablePtr->icursor = tmp; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TableGetIndex -- + * Parse an index into a table and return either its value + * or an error. + * + * Results: + * A standard Tcl result. If all went well, then *row,*col is + * filled in with the index corresponding to string. If an + * error occurs then an error message is left in interp result. + * The index returned is in user coords. + * + * Side effects: + * Sets row,col index to an appropriately constrained user index. + * + *-------------------------------------------------------------- + */ +int +TableGetIndex(tablePtr, str, row_p, col_p) + register Table *tablePtr; /* Table for which the index is being + * specified. */ + char *str; /* Symbolic specification of cell in table. */ + int *row_p; /* Where to store converted row. */ + int *col_p; /* Where to store converted col. */ +{ + int r, c, len = strlen(str); + + /* + * Note that all of these values will be adjusted by row/ColOffset + */ + if (str[0] == '@') { /* @x,y coordinate */ + int x, y; + char *p, *end; + + p = str+1; + x = strtol(p, &end, 0); + if ((end == p) || (*end != ',')) + goto IndexError; + p = end+1; + y = strtol(p, &end, 0); + if ((end == p) || (*end != '\0')) + goto IndexError; + TableWhatCell(tablePtr, x, y, &r, &c); + r += tablePtr->rowOffset; + c += tablePtr->colOffset; + } else if (sscanf(str, "%d,%d", &r,&c) == 2) { + char buf[INDEX_BUFSIZE]; + TableMakeArrayIndex(r, c, buf); + /* Make sure it won't work for "2,3extrastuff" */ + if (strcmp(buf, str)) + goto IndexError; + /* ensure appropriate user index */ + r = MIN(MAX(tablePtr->rowOffset,r),tablePtr->rows-1+tablePtr->rowOffset); + c = MIN(MAX(tablePtr->colOffset,c),tablePtr->cols-1+tablePtr->colOffset); + } else if (len > 1 && strncmp(str, "active", len) == 0 ) { /* active */ + if (tablePtr->flags & HAS_ACTIVE) { + r = tablePtr->activeRow+tablePtr->rowOffset; + c = tablePtr->activeCol+tablePtr->colOffset; + } else { + Tcl_AppendResult(tablePtr->interp, "no \"active\" cell in table", NULL); + return TCL_ERROR; + } + } else if (len > 1 && strncmp(str, "anchor", len) == 0) { /* anchor */ + if (tablePtr->flags & HAS_ANCHOR) { + r = tablePtr->anchorRow+tablePtr->rowOffset; + c = tablePtr->anchorCol+tablePtr->colOffset; + } else { + Tcl_AppendResult(tablePtr->interp, "no \"anchor\" cell in table", NULL); + return TCL_ERROR; + } + } else if (strncmp(str, "end", len) == 0) { /* end */ + r = tablePtr->rows-1+tablePtr->rowOffset; + c = tablePtr->cols-1+tablePtr->colOffset; + } else if (strncmp(str, "origin", len) == 0) { /* origin */ + r = tablePtr->titleRows+tablePtr->rowOffset; + c = tablePtr->titleCols+tablePtr->colOffset; + } else if (strncmp(str, "topleft", len) == 0) { /* topleft */ + r = tablePtr->topRow+tablePtr->rowOffset; + c = tablePtr->leftCol+tablePtr->colOffset; + } else if (strncmp(str, "bottomright", len) == 0) { /* bottomright */ + TableGetLastCell(tablePtr, &r, &c); + r += tablePtr->rowOffset; + c += tablePtr->colOffset; + } else { + IndexError: + Tcl_AppendResult(tablePtr->interp, "bad table index \"", + str, "\"", (char *)NULL); + return TCL_ERROR; + } + + /* Note: values are expected to be properly constrained + * as a user index by this point */ + if (row_p) *row_p = r; + if (col_p) *col_p = c; + return TCL_OK; +} +
tkTableCell.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tclsizebox.c =================================================================== --- tclsizebox.c (nonexistent) +++ tclsizebox.c (revision 1765) @@ -0,0 +1,236 @@ +/* tclsizebox.c -- Tcl code to create a sizebox on Windows. + Copyright (C) 1997, 1998 Cygnus Solutions. + Written by Ian Lance Taylor . */ + +#ifdef _WIN32 + +#include + +#include +#include + +#include "guitcl.h" + +/* We need to make some Tk internal calls. The only alternative is to + actually move this code into Tk. */ + +#include + +/* These should really be defined in the cygwin32 header files. */ + +#ifndef GetStockPen +#define GetStockPen(p) ((HPEN) GetStockObject (p)) +#define GetStockBrush(b) ((HBRUSH) GetStockObject (b)) +#define SelectPen(dc, p) (SelectObject (dc, (HGDIOBJ) p)) +#define SelectBrush(dc, b) (SelectObject (dc, (HGDIOBJ) b)) +#define DeleteBrush(b) (DeleteObject ((HGDIOBJ) b)) +#endif + +/* This file defines the Tcl command sizebox. + + sizebox PATHNAME [OPTIONS] + + Creates a sizebox named PATHNAME. This accepts the standard window + options. This should be attached to the lower right corner of a + window in order to work as expected. */ + +/* We use + +/* We use an instance of the structure as the Windows user data for + the window. */ + +struct sizebox_userdata +{ + /* The real window procedure. */ + WNDPROC wndproc; + /* The Tk window. */ + Tk_Window tkwin; +}; + +/* The window procedure we use for a sizebox. The default sizebox + handling doesn't seem to erase the background if the sizebox is not + exactly the correct size, so we handle that here. */ + +static LRESULT CALLBACK +sizebox_wndproc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + struct sizebox_userdata *su; + + su = (struct sizebox_userdata *) GetWindowLong (hwnd, GWL_USERDATA); + + switch (msg) + { + case WM_ERASEBKGND: + /* The default sizebox handling doesn't seem to erase the + background if the sizebox is not exactly the correct size, so + we handle that here. */ + if (Tk_Height (su->tkwin) != GetSystemMetrics (SM_CYHSCROLL) + || Tk_Width (su->tkwin) != GetSystemMetrics (SM_CXVSCROLL)) + { + HDC hdc = (HDC) wparam; + RECT r; + HPEN hpen; + HBRUSH hbrush; + + GetClientRect (hwnd, &r); + hpen = SelectPen (hdc, GetStockPen (NULL_PEN)); + hbrush = SelectBrush (hdc, GetSysColorBrush (COLOR_3DFACE)); + Rectangle (hdc, r.left, r.top, r.right + 1, r.bottom + 1); + hbrush = SelectBrush (hdc, hbrush); + DeleteBrush (hbrush); + SelectPen (hdc, hpen); + return 1; + } + break; + + /* We need to handle cursor handling here. We also use Tk + cursor handling via a call to Tk_DefineCursor, but we can't + rely on it, because it will only take effect if Tk sees a + MOUSEMOVE event which won't happen if the mouse moves + directly from outside any Tk window to the sizebox. */ + case WM_SETCURSOR: + SetCursor (LoadCursor (NULL, IDC_SIZENWSE)); + return 1; + } + + return CallWindowProc (su->wndproc, hwnd, msg, wparam, lparam); +} + +/* This is called by the Tk dispatcher for various events. */ + +static void +sizebox_event_proc (ClientData cd, XEvent *event_ptr) +{ + HWND hwnd = (HWND) cd; + struct sizebox_userdata *su; + + if (! hwnd) + return; + + if (event_ptr->type == DestroyNotify) + { + su = (struct sizebox_userdata *) GetWindowLong (hwnd, GWL_USERDATA); + SetWindowLong (hwnd, GWL_USERDATA, 0); + SetWindowLong (hwnd, GWL_WNDPROC, (LONG) su->wndproc); + Tcl_Free ((char *) su); + DestroyWindow (hwnd); + } +} + +/* Create a sizebox window. */ + +static Window +sizebox_create (Tk_Window tkwin, Window parent, ClientData cd) +{ + POINT pt; + Tk_Window parwin; + HWND parhwnd; + HWND hwnd; + struct sizebox_userdata *su; + Window result; + + /* We need to tell Windows that the parent of the sizebox is the + toplevel which holds it. Otherwise the sizebox will try to + resize the child window, which doesn't make much sense. */ + + pt.x = Tk_X (tkwin); + pt.y = Tk_Y (tkwin); + ClientToScreen (TkWinGetHWND (parent), &pt); + + parwin = (Tk_Window) TkWinGetWinPtr (parent); + while (! Tk_IsTopLevel (parwin)) + parwin = Tk_Parent (parwin); + parhwnd = TkWinGetWrapperWindow (parwin); + + ScreenToClient (parhwnd, &pt); + + hwnd = CreateWindow ("SCROLLBAR", NULL, + WS_CHILD | WS_VISIBLE | SBS_SIZEGRIP, + pt.x, pt.y, Tk_Width (tkwin), Tk_Height (tkwin), + parhwnd, NULL, Tk_GetHINSTANCE (), NULL); + + su = (struct sizebox_userdata *) Tcl_Alloc (sizeof *su); + su->tkwin = tkwin; + su->wndproc = (WNDPROC) GetWindowLong (hwnd, GWL_WNDPROC); + SetWindowLong (hwnd, GWL_USERDATA, (LONG) su); + SetWindowLong (hwnd, GWL_WNDPROC, (LONG) sizebox_wndproc); + + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + + result = Tk_AttachHWND (tkwin, hwnd); + + Tk_CreateEventHandler (tkwin, StructureNotifyMask, sizebox_event_proc, + hwnd); + + return result; +} + +/* The class procedure table for a sizebox widget. This is an + internal Tk structure. */ + +static TkClassProcs sizebox_procs = +{ + sizebox_create, /* createProc */ + NULL, /* geometryProc */ + NULL /* modalProc */ +}; + +/* The implementation of the sizebox command. */ + +static int +sizebox_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv) +{ + Tk_Window tkmain; + Tk_Window new; + Tk_Cursor cursor; + + if (argc < 2) + { + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj(Tcl_GetObjResult (interp), + "wrong # args: should be \"", + argv[0], " pathname ?options?\"", (char *) NULL); + return TCL_ERROR; + } + + tkmain = Tk_MainWindow (interp); + if (tkmain == NULL) + return TCL_ERROR; + + new = Tk_CreateWindowFromPath (interp, tkmain, argv[1], (char *) NULL); + if (new == NULL) + return TCL_ERROR; + + Tk_SetClass (new, "Sizebox"); + + /* This is a Tk internal function. */ + TkSetClassProcs (new, &sizebox_procs, NULL); + + /* FIXME: We should handle options here, but we currently don't have + any. */ + + Tk_GeometryRequest (new, GetSystemMetrics (SM_CXVSCROLL), + GetSystemMetrics (SM_CYHSCROLL)); + + cursor = Tk_GetCursor (interp, new, Tk_GetUid ("size_nw_se")); + if (cursor == None) + return TCL_ERROR; + Tk_DefineCursor (new, cursor); + + Tcl_SetResult (interp, Tk_PathName (new), TCL_STATIC); + return TCL_OK; +} + +/* Create the sizebox command. */ + +int +ide_create_sizebox_command (Tcl_Interp *interp) +{ + if (Tcl_CreateCommand (interp, "ide_sizebox", sizebox_command, NULL, + NULL) == NULL) + return TCL_ERROR; + return TCL_OK; +} + +#endif /* _WIN32 */
tclsizebox.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tclwinfont.c =================================================================== --- tclwinfont.c (nonexistent) +++ tclwinfont.c (revision 1765) @@ -0,0 +1,331 @@ +/* tclwinfont.c -- Tcl routine to let the user choose a font on Windows. + Copyright (C) 1997 Cygnus Solutions. + Written by Ian Lance Taylor . + + This file provides a Tcl command which may be used to let the user + select a font on Windows. */ + +#ifdef _WIN32 + +#include + +#include +#include + +#include "guitcl.h" + +/* FIXME: We need to dig into the Tk window implementation internals + to convert a Tk Windows to an HWND. */ + +#include + +/* FIXME: We grovel around in the Tk internal font structures. */ + +#include +#include + +/* This file defines a single Tcl command. + + ide_win_choose_font OPTIONS + Choose a font on Windows. This opens a modal dialog box to + permit the user to choose a font. This returns a string naming + the new font, or the empty string if the user did not choose a + font. + + Supported options: + -default FONT + FONT is the name of a font to use to initialize the + default choice in the dialog box. + -parent WINDOW + Set the parent window of the dialog box. The dialog + box is modal with respect to this window. The default + is the main window. + + FIXME: The current implementation only supports choosing a screen + font. To permit choosing printer fonts, we would need to have a + device context for the printer. + + */ + +/* Implement the ide_win_choose_font procedure. */ + +static int +win_choose_font (ClientData cd, Tcl_Interp *interp, int argc, char **argv) +{ + char *deffont; + Tk_Window parent; + int i, oldMode; + CHOOSEFONT cf; + LOGFONT lf; + HDC hdc; + HFONT hfont; + char facebuf[LF_FACESIZE]; + TEXTMETRIC tm; + int pointsize; + char *s; + Tcl_DString resultStr; /* used to translate result in UTF8 in Tcl/Tk8.1 */ + deffont = NULL; + parent = Tk_MainWindow (interp); + + for (i = 1; i < argc; i += 2) + { + if (i + 1 >= argc) + { + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + "value for \"", argv[i], "\" missing", + (char *) NULL); + return TCL_ERROR; + } + + if (strcmp (argv[i], "-default") == 0) + deffont = argv[i + 1]; + else if (strcmp (argv[i], "-parent") == 0) + { + parent = Tk_NameToWindow (interp, argv[i + 1], + Tk_MainWindow (interp)); + if (parent == NULL) + return TCL_ERROR; + } + else + { + Tcl_ResetResult (interp); + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + "unknown option \"", argv[i], "\"", + (char *) NULL); + return TCL_ERROR; + } + } + + memset (&cf, 0, sizeof (CHOOSEFONT)); + cf.lStructSize = sizeof (CHOOSEFONT); + + if (Tk_WindowId (parent) == None) + Tk_MakeWindowExist (parent); + cf.hwndOwner = Tk_GetHWND (Tk_WindowId (parent)); + + cf.lpLogFont = &lf; + cf.Flags = CF_SCREENFONTS | CF_FORCEFONTEXIST; + + memset (&lf, 0, sizeof (LOGFONT)); + + if (deffont != NULL) + { + Tk_Font tkfont; + const TkFontAttributes *fa; + + tkfont = Tk_GetFont (interp, parent, deffont); + if (tkfont == NULL) + return TCL_ERROR; + + cf.Flags |= CF_INITTOLOGFONTSTRUCT; + + /* In order to initialize LOGFONT, we need to extract the real + font attributes from the Tk internal font information. */ + fa = &((TkFont *) tkfont)->fa; + + /* This code is taken from TkpGetFontFromAttributes. It + converts a TkFontAttributes structure into a LOGFONT + structure. */ +#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + lf.lfHeight = - fa->size; +#else + lf.lfHeight = - fa->pointsize; +#endif + if (lf.lfHeight < 0) + lf.lfHeight = MulDiv (lf.lfHeight, + 254 * WidthOfScreen (Tk_Screen (parent)), + 720 * WidthMMOfScreen (Tk_Screen (parent))); + lf.lfWeight = fa->weight == TK_FW_NORMAL ? FW_NORMAL : FW_BOLD; + lf.lfItalic = fa->slant; + lf.lfUnderline = fa->underline; + lf.lfStrikeOut = fa->overstrike; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + if (fa->family == NULL) + lf.lfFaceName[0] = '\0'; + else + strncpy (lf.lfFaceName, fa->family, sizeof (lf.lfFaceName)); + + Tk_FreeFont (tkfont); + } + + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + if (! ChooseFont (&cf)) + { + DWORD code; + + code = CommDlgExtendedError (); + if (code == 0) + { + /* The user pressed cancel. */ + Tcl_ResetResult (interp); + return TCL_OK; + } + else + { + char buf[200]; + + sprintf (buf, "Windows common dialog error 0x%lx", (unsigned long) code); + Tcl_ResetResult (interp); + #if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_ExternalToUtfDString(NULL, buf, -1, &resultStr); + #else + Tcl_InitDString(&resultStr); + Tcl_DStingAppend(&resultStr, buf, -1); + #endif + Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), + Tcl_DStringValue(&resultStr), + (char *) NULL); + Tcl_DStringFree(&resultStr); + return TCL_ERROR; + } + } + Tcl_SetServiceMode(oldMode); + /* We now have a LOGFONT structure. We store it into a device + context, and then extract enough information to build a Tk font + specification. With luck, when Tk interprets the font + specification it will wind up with the font that the user expects + to see. Some of this code is taken from AllocFont. */ + + hfont = CreateFontIndirect (&lf); + if (hfont == NULL) + { + /* This should be impossible. */ + #if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_ExternalToUtfDString(NULL, "CreateFontIndirect failed on chosen font", -1, &resultStr); + #else + Tcl_InitDString(&resultStr); + Tcl_DStingAppend(&resultStr, "CreateFontIndirect failed on chosen font", -1); + #endif + Tcl_SetResult (interp, Tcl_DStringValue(&resultStr), TCL_STATIC); + Tcl_DStringFree(&resultStr); + return TCL_ERROR; + } + + hdc = GetDC (cf.hwndOwner); + hfont = SelectObject (hdc, hfont); + GetTextFace (hdc, sizeof (facebuf), facebuf); + GetTextMetrics (hdc, &tm); + + Tcl_ResetResult (interp); + +#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_ExternalToUtfDString(NULL, facebuf, -1, &resultStr); +#else + Tcl_InitDString(&resultStr); + Tcl_DStingAppend(&resultStr,facebuf,-1); +#endif + + if (Tcl_ListObjAppendElement (interp, Tcl_GetObjResult (interp), + Tcl_NewStringObj (Tcl_DStringValue(&resultStr), -1)) != TCL_OK) { + Tcl_DStringFree(&resultStr); + return TCL_ERROR; + } + + Tcl_DStringFree(&resultStr); + + pointsize = MulDiv (tm.tmHeight - tm.tmInternalLeading, + 720 * WidthMMOfScreen (Tk_Screen (parent)), + 254 * WidthOfScreen (Tk_Screen (parent))); + + if (Tcl_ListObjAppendElement (interp, Tcl_GetObjResult (interp), + Tcl_NewIntObj (pointsize)) != TCL_OK) { + return TCL_ERROR; + } + + if (tm.tmWeight > FW_MEDIUM) + s = "bold"; + else + s = "normal"; + +#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_ExternalToUtfDString(NULL, s, -1, &resultStr); +#else + Tcl_InitDString(&resultStr); + Tcl_DStingAppend(&resultStr, s, -1); +#endif + + if (Tcl_ListObjAppendElement (interp, Tcl_GetObjResult (interp), + Tcl_NewStringObj (Tcl_DStringValue(&resultStr), -1)) != TCL_OK) { + Tcl_DStringFree(&resultStr); + return TCL_ERROR; + } + + Tcl_DStringFree(&resultStr); + + if (tm.tmItalic) + s = "italic"; + else + s = "roman"; + +#if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_ExternalToUtfDString(NULL, s, -1, &resultStr); +#else + Tcl_InitDString(&resultStr); + Tcl_DStingAppend(&resultStr, s, -1); +#endif + + if (Tcl_ListObjAppendElement (interp, Tcl_GetObjResult (interp), + Tcl_NewStringObj (Tcl_DStringValue(&resultStr), -1)) != TCL_OK) { + Tcl_DStringFree(&resultStr); + return TCL_ERROR; + } + Tcl_DStringFree(&resultStr); + + if (tm.tmUnderlined) + { + #if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_ExternalToUtfDString(NULL, "underline", -1, &resultStr); + #else + Tcl_InitDString(&resultStr); + Tcl_DStingAppend(&resultStr,"underline",-1); + #endif + if (Tcl_ListObjAppendElement (interp, Tcl_GetObjResult (interp), + Tcl_NewStringObj (Tcl_DStringValue(&resultStr), -1)) + != TCL_OK) { + Tcl_DStringFree(&resultStr); + return TCL_ERROR; + } + Tcl_DStringFree(&resultStr); + } + + if (tm.tmStruckOut) + { + #if (TCL_MAJOR_VERSION >= 8) && (TCL_MINOR_VERSION >= 1) + Tcl_ExternalToUtfDString(NULL, "overstrike", -1, &resultStr); + #else + Tcl_InitDString(&resultStr); + Tcl_DStingAppend(&resultStr, "overstrike", -1); + #endif + if (Tcl_ListObjAppendElement (interp, Tcl_GetObjResult (interp), + Tcl_NewStringObj (Tcl_DStringValue(&resultStr), -1)) + != TCL_OK) { + Tcl_DStringFree(&resultStr); + return TCL_ERROR; + } + Tcl_DStringFree(&resultStr); + } + + hfont = SelectObject (hdc, hfont); + ReleaseDC (cf.hwndOwner, hdc); + DeleteObject (hfont); + + return TCL_OK; +} + +/* Create the Tcl command. */ + +int +ide_create_win_choose_font_command (Tcl_Interp *interp) +{ + if (Tcl_CreateCommand (interp, "ide_win_choose_font", win_choose_font, + NULL, NULL) == NULL) + return TCL_ERROR; + return TCL_OK; +} + +#endif /* _WIN32 */
tclwinfont.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: Makefile.am =================================================================== --- Makefile.am (nonexistent) +++ Makefile.am (revision 1765) @@ -0,0 +1,84 @@ +## Process this file with automake to produce Makefile.in. + +AUTOMAKE_OPTIONS = cygnus + +noinst_LIBRARIES = libgui.a + +if INSTALL_LIBGUI + +include_HEADERS = \ + guitcl.h subcommand.h + +endif + +# tkTable version info +include $(srcdir)/tkTable_version.in + +# This sets the name that tkTable will define for itself when loaded +# If you change this, then the demos won't work, but it might be necessary +# for those with another built-in "table" command +TBL_COMMAND = table + +tkTabletcl.h: $(srcdir)/tkTable.tcl + sed -e '/^$\#/d' -e '/^$$/d' -e 's/\"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' <$(srcdir)/tkTable.tcl >tkTabletcl.h || rm tkTabletcl.h + + + +# Defining lib_LIBRARIES conditionally doesn't do the right thing. +install-exec-local: +if INSTALL_LIBGUI + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(libdir) + $(INSTALL_DATA) libgui.a $(libdir)/libgui.a + @$(POST_INSTALL) + $(RANLIB) $(libdir)/libgui.a +endif + +LIBGUI_CFLAGS=@LIBGUI_CFLAGS@ + +## Some of the files in this directory want to see Tk internals. +## Nasty. +INCLUDES = $(LIBGUI_CFLAGS) $(TCLHDIR) \ +$(TKHDIR) \ +$(TK_XINCLUDES) $(TCL_DEFS) $(TK_DEFS) \ +$(TKHDIR)/../unix $(TKHDIR)/../win \ +-DTBL_VERSION=\"$(TBL_VERSION)\"\ +-DTBL_COMMAND=\"$(TBL_COMMAND)\"\ +-DTCL_RUNTIME=\"tkTable.tcl\" + +libgui_a_SOURCES = guitcl.h paths.c subcommand.c subcommand.h \ +xpmlib.c tclmain.c tkGraphCanvas.c \ +tkCanvEdge.c tkCanvLayout.c tkCanvLayout.h tclhelp.c tclgetdir.c \ +tclwinprint.c tclsizebox.c tclshellexe.c tclmapi.c tclwinfont.c \ +tclwingrab.c tclwinmode.c tclwinpath.c tclmsgbox.c tclcursor.c \ +tkTable.c tkTableCmd.c tkTableCell.c tkTableTag.c tkTableWin.c \ +tkWinPrintText.c tkWinPrintCanvas.c tkWarpPointer.c + +## Dependencies + +paths.$(OBJEXT): paths.c guitcl.h +subcommand.$(OBJEXT): subcommand.c subcommand.h +tkCanvEdge.$(OBJEXT): tkCanvEdge.c ../config.h +tkCanvLayout.$(OBJEXT): tkCanvLayout.c ../config.h tkCanvLayout.h +tkGraphCanvas.$(OBJEXT): tkGraphCanvas.c tkCanvLayout.h +xpmlib.$(OBJEXT): xpmlib.c guitcl.h +assertions.$(OBJEXT): assertions.c ../config.h assertions.h +tclcursor.$(OBJEXT): tclcursor.c ../config.h guitcl.h subcommand.h +tclhelp.$(OBJEXT): tclhelp.c ../config.h guitcl.h subcommand.h +tclgetdir.$(OBJEXT): tclgetdir.c guitcl.h +tclmain.$(OBJEXT): tclmain.c guitcl.h +tclwinprint.$(OBJEXT): tclwinprint.c guitcl.h subcommand.h +tclsizebox.$(OBJEXT): tclsizebox.c guitcl.h +tclshellexe.$(OBJEXT): tclshellexe.c guitcl.h +tclmapi.$(OBJEXT): tclmapi.c guitcl.h subcommand.h +tclwinfont.$(OBJEXT): tclwinfont.c guitcl.h +tclwingrab.$(OBJEXT): tclwingrab.c guitcl.h +tclwinpath.$(OBJEXT): tclwinpath.c guitcl.h subcommand.h +tclwinmode.$(OBJEXT): tclwinmode.c guitcl.h +tkTable.$(OBJEXT): tkTable.c tkTable.h tkTableCmd.h tkTabletcl.h +tkTableCell.$(OBJEXT): tkTableCell.c tkTable.h tkTableCmd.h +tkTableTag.$(OBJEXT): tkTableTag.c tkTable.h tkTableCmd.h +tkTableWin.$(OBJEXT):tkTableWin.c tkTable.h tkTableCmd.h +tkTableCmd.$(OBJEXT): tkTableCmd.c tkTableCmd.h +tkTabletcl.h: tkTable.tcl +
Makefile.am Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tclmapi.c =================================================================== --- tclmapi.c (nonexistent) +++ tclmapi.c (revision 1765) @@ -0,0 +1,79 @@ +/* tclmapi.c - Tcl interface to MAPI. + Copyright (C) 1997 Cygnus Solutions + Written by Tom Tromey . */ + +#ifdef _WIN32 + +#include +#include + +#include +#include + +#include "guitcl.h" +#include "subcommand.h" + +/* Usage for the mapi command: + mapi simple-send TO-ADDRESS SUBJECT TEXT. + + This command has been deliberately kept very simple; it only does + what we need. However it can be extended by adding new subcommands + if necessary. */ + +static int +mapi_command (ClientData cd, Tcl_Interp *interp, int argc, char *argv[]) +{ + MapiMessage message; + MapiRecipDesc to; + ULONG result; + + message.ulReserved = 0; + message.lpszSubject = argv[3]; + message.lpszNoteText = argv[4]; + message.lpszMessageType = NULL; + message.lpszDateReceived = NULL; + message.lpszConversationID = NULL; + message.flFlags = 0; + message.lpOriginator = NULL; + message.nRecipCount = 1; + message.lpRecips = &to; + message.nFileCount = 0; + message.lpFiles = NULL; + + to.ulReserved = 0; + to.ulRecipClass = MAPI_TO; + to.lpszName = ""; + /* FIXME: smtp:address? */ + to.lpszAddress = argv[2]; + to.ulEIDSize = 0; + to.lpEntryID = NULL; + + result = MAPISendMail (0, 0, &message, MAPI_LOGON_UI, 0); + if (result != SUCCESS_SUCCESS) + { + /* We could decode the error here. */ + char buf[20]; + + sprintf (buf, "0x%lx", result); + Tcl_AppendResult (interp, argv[0], ": failed with status ", + buf, (char *) NULL); + return TCL_ERROR; + } + + return TCL_OK; +} + +static const struct ide_subcommand_table mapi_table[] = +{ + { "simple-send", mapi_command, 5, 5 }, + { NULL, NULL, 0, 0 } +}; + +int +ide_create_mapi_command (Tcl_Interp *interp) +{ + return ide_create_command_with_subcommands (interp, "ide_mapi", + mapi_table, NULL, NULL); +} + +#endif /* _WIN32 */
tclmapi.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: guitcl.h =================================================================== --- guitcl.h (nonexistent) +++ guitcl.h (revision 1765) @@ -0,0 +1,107 @@ +/* guitcl.h - Interface to Tcl layer of GUI support code. + Copyright (C) 1997, 1998 Cygnus Solutions. + Written by Tom Tromey . */ + +#ifndef GUITCL_H +#define GUITCL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is like Tk_Main, but it doesn't assume that the program wants + to act like an interactive interpreter. */ +extern void +ide_main (int ide_argc, char *ide_argv[], Tcl_AppInitProc *); + +/* Set up the XPM image reader. This requires Tk to be linked in. + However, it does not require Tk to be initialized before calling. */ +extern void +ide_create_xpm_image_type (void); + +/* This locates the libide and application-specific Tcl libraries. It + sets the global Tcl variable `ide_application_name' to IDE_APPNAME, + and initializes a global Paths array with useful path information. + The application-specific Tcl library is assumed to be in the + directory $datadir/IDE_APPNAME/. + Returns a standard Tcl result. */ +extern int +ide_initialize_paths (Tcl_Interp *, char *ide_appname); + +/* This tries to find the application-specific startup file. If it is + found, it is sourced. If not, an error results. The file is + assumed to be named $datadir/IDE_APPNAME/IDE_APPNAME.tcl, where + IDE_APPNAME is the name that was previously passed to + ide_initialize_paths. + Returns a standard Tcl result. */ +extern int +ide_run_app_script (Tcl_Interp *); + +/* This adds the new graph command for manipulating graphs to the + interpreter IDE_INTERP. + Returns a standard Tcl result. */ +extern int +create_graph_command (Tcl_Interp *ide_interp); + +/* This function creates the ide_help Tcl command. */ +int +ide_create_help_command (Tcl_Interp *); + +/* This function creates the ide_get_directory Tcl command. */ +int +ide_create_get_directory_command (Tcl_Interp *); + +/* This function creates the ide_winprint Tcl command. */ +int +ide_create_winprint_command (Tcl_Interp *); + +/* This function creates the ide_sizebox Tcl command. */ +int +ide_create_sizebox_command (Tcl_Interp *); + +/* This function creates the ide_shell_execute command. */ +int +ide_create_shell_execute_command (Tcl_Interp *); + +/* This function creates the `ide_mapi' command. */ +int +ide_create_mapi_command (Tcl_Interp *); + +/* This function creates the `ide_win_choose_font' command. */ +int +ide_create_win_choose_font_command (Tcl_Interp *); + +/* This function creates internal commands used by ide_grab_support on + Windows. */ +int +ide_create_win_grab_command (Tcl_Interp *); + +/* This function creates the `ide_cygwin_path' command. */ +int +ide_create_cygwin_path_command (Tcl_Interp *); + +/* This function creates the ide_cursor command on Windows. */ +int +ide_create_cursor_command (Tcl_Interp *); + +/* This function creates the ide_set_error_mode command. On Windows, + this translates into a call to SetErrorMode. On Unix, this command + is a no-op. */ +int +ide_create_set_error_mode_command (Tcl_Interp *); + +/* This function creates the ide_messageBox command. */ +int +ide_create_messagebox_command (Tcl_Interp *); + +/* This function creates the "warp_pointer" command. Warp_pointer + forces the pointer to a specific location. There is probably no + good reason to use this except in the testsuite! */ +int +cyg_create_warp_pointer_command (Tcl_Interp *interp); + +#ifdef __cplusplus +} +#endif + +#endif /* GUITCL_H */
guitcl.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.