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
tkTable.tcl
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: tkTable.c
===================================================================
--- tkTable.c (nonexistent)
+++ tkTable.c (revision 1765)
@@ -0,0 +1,4898 @@
+/*
+ * tkTable.c --
+ *
+ * This module implements table widgets for the Tk
+ * toolkit. An table displays a 2D array of strings
+ * and allows the strings to be edited.
+ *
+ * Based on Tk3 table widget written by Roland King
+ *
+ * Updates 1996 by:
+ * Jeffrey Hobbs jeff.hobbs@acm.org
+ * John Ellson ellson@lucent.com
+ * Peter Bruecker peter@bj-ig.de
+ * Tom Moore tmoore@spatial.ca
+ * Sebastian Wangnick wangnick@orthogon.de
+ *
+ * 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 "tkTable.h"
+#ifdef DEBUG
+#include "../../dprint.h"
+#endif
+
+INLINE static void TableFlushCache _ANSI_ARGS_((Table *tablePtr));
+static int TableClear _ANSI_ARGS_((register Table *tablePtr, int mode,
+ char *first, char *last));
+INLINE static void TableGetGc _ANSI_ARGS_((Display *display, Drawable d,
+ TableTag *tagPtr, GC *tagGc));
+static void TableRedrawHighlight _ANSI_ARGS_((Table *tablePtr));
+static void TableDisplay _ANSI_ARGS_((ClientData clientdata));
+static void TableFlashEvent _ANSI_ARGS_((ClientData clientdata));
+static void TableAddFlash _ANSI_ARGS_((Table *tablePtr, int row, int col));
+static void TableSetActiveIndex _ANSI_ARGS_((register Table *tablePtr));
+static void TableGetActiveBuf _ANSI_ARGS_((register Table *tablePtr));
+static char * TableVarProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, char *name, char *index,
+ int flags));
+static void TableGeometryRequest _ANSI_ARGS_((Table *tablePtr));
+static void TableAdjustActive _ANSI_ARGS_((register Table *tablePtr));
+static void TableAdjustParams _ANSI_ARGS_((register Table *tablePtr));
+static void TableCursorEvent _ANSI_ARGS_((ClientData clientData));
+static void TableConfigCursor _ANSI_ARGS_((register Table *tablePtr));
+static int TableFetchSelection _ANSI_ARGS_((ClientData clientData,
+ int offset, char *buffer, int maxBytes));
+static void TableLostSelection _ANSI_ARGS_((ClientData clientData));
+static Tk_RestrictAction TableRestrictProc _ANSI_ARGS_((ClientData arg,
+ XEvent *eventPtr));
+static int TableValidateChange _ANSI_ARGS_((Table *tablePtr, int r,
+ int c, char *old, char *new, int index));
+static void TableDeleteChars _ANSI_ARGS_((register Table *tablePtr,
+ int index, int count));
+static void TableInsertChars _ANSI_ARGS_((register Table *tablePtr,
+ int index, char *string));
+static int TableWidgetCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+static void TableDestroy _ANSI_ARGS_((ClientData clientdata));
+static void TableEventProc _ANSI_ARGS_((ClientData clientData,
+ XEvent *eventPtr));
+static int TableConfigure _ANSI_ARGS_((Tcl_Interp *interp,
+ Table *tablePtr, int argc, char **argv,
+ int flags, int forceUpdate));
+static void TableCmdDeletedProc _ANSI_ARGS_((ClientData clientData));
+static int TableCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+
+/*
+ * The list of command values for all the widget commands
+ * We could use enum for many of these #defines, but it adds
+ * just that much more code size...
+ */
+#define CMD_ACTIVATE 1 /* activate command a la listbox */
+#define CMD_BBOX 3 /* bounding box of cell */
+#define CMD_BORDER 5 /* border movement function */
+#define CMD_CGET 7 /* basic cget widget command */
+#define CMD_CLEAR 8 /* clear state command */
+#define CMD_CONFIGURE 9 /* general configure command */
+#define CMD_CURSELECTION 11 /* get current selected cell(s) */
+#define CMD_CURVALUE 13 /* get current selection buffer */
+#define CMD_DELETE 15 /* delete text in the selection */
+#define CMD_FLUSH 17 /* flush the table cache */
+#define CMD_GET 19 /* get mode a la listbox */
+#define CMD_HEIGHT 21 /* (re)set row heights */
+#define CMD_ICURSOR 23 /* set the insertion cursor */
+#define CMD_INDEX 25 /* get an index */
+#define CMD_INSERT 27 /* insert text at any position */
+#define CMD_REREAD 31 /* reread the current selection */
+#define CMD_SCAN 33 /* scan command a la listbox */
+#define CMD_SEE 35 /* see command a la listbox */
+#define CMD_SELECTION 37 /* selection command a la listbox */
+#define CMD_SET 39 /* set command, to set multiple items */
+#define CMD_TAG 41 /* tag command menu */
+#define CMD_VALIDATE 43 /* validate contents of active cell */
+#define CMD_VERSION 45 /* hidden command to return version */
+#define CMD_WIDTH 47 /* (re)set column widths */
+#define CMD_WINDOW 49 /* manage embedded windows */
+#define CMD_XVIEW 51 /* change x view of widget (for scrollbars) */
+#define CMD_YVIEW 53 /* change y view of widget (for scrollbars) */
+
+/* The list of commands for the command parser */
+
+static Cmd_Struct main_cmds[] = {
+ {"activate", CMD_ACTIVATE},
+ {"bbox", CMD_BBOX},
+ {"border", CMD_BORDER},
+ {"cget", CMD_CGET},
+ {"clear", CMD_CLEAR},
+ {"configure", CMD_CONFIGURE},
+ {"curselection", CMD_CURSELECTION},
+ {"curvalue", CMD_CURVALUE},
+ {"delete", CMD_DELETE},
+ {"flush", CMD_FLUSH},
+ {"get", CMD_GET},
+ {"height", CMD_HEIGHT},
+ {"icursor", CMD_ICURSOR},
+ {"index", CMD_INDEX},
+ {"insert", CMD_INSERT},
+ {"reread", CMD_REREAD},
+ {"scan", CMD_SCAN},
+ {"see", CMD_SEE},
+ {"selection", CMD_SELECTION},
+ {"set", CMD_SET},
+ {"tag", CMD_TAG},
+ {"validate", CMD_VALIDATE},
+ {"version", CMD_VERSION},
+ {"window", CMD_WINDOW},
+ {"width", CMD_WIDTH},
+ {"xview", CMD_XVIEW},
+ {"yview", CMD_YVIEW},
+ {"", 0}
+};
+
+/* selection subcommands */
+#define SEL_ANCHOR 1 /* set selection anchor */
+#define SEL_CLEAR 2 /* clear list from selection */
+#define SEL_INCLUDES 3 /* query items inclusion in selection */
+#define SEL_SET 4 /* include items in selection */
+
+static Cmd_Struct sel_cmds[]= {
+ {"anchor", SEL_ANCHOR},
+ {"clear", SEL_CLEAR},
+ {"includes", SEL_INCLUDES},
+ {"set", SEL_SET},
+ {"", 0 }
+};
+
+/* -selecttype selection type options */
+/* These alter how the selection set/clear commands behave */
+#define SEL_ROW (1<<0)
+#define SEL_COL (1<<1)
+#define SEL_BOTH (1<<2)
+#define SEL_CELL (1<<3)
+#define SEL_NONE (1<<4)
+
+static Cmd_Struct sel_vals[]= {
+ {"row", SEL_ROW},
+ {"col", SEL_COL},
+ {"both", SEL_BOTH},
+ {"cell", SEL_CELL},
+ {"", 0 }
+};
+
+/* clear subcommands */
+#define CLEAR_TAGS (1<<0)
+#define CLEAR_SIZES (1<<1)
+#define CLEAR_CACHE (1<<2)
+static Cmd_Struct clear_cmds[] = {
+ {"tags", CLEAR_TAGS},
+ {"sizes", CLEAR_SIZES},
+ {"cache", CLEAR_CACHE},
+ {"all", CLEAR_TAGS | CLEAR_SIZES | CLEAR_CACHE},
+ {"", 0}
+};
+
+/* -resizeborders options */
+static Cmd_Struct resize_vals[]= {
+ {"row", SEL_ROW}, /* allow rows to be dragged */
+ {"col", SEL_COL}, /* allow cols to be dragged */
+ {"both", SEL_ROW|SEL_COL}, /* allow either to be dragged */
+ {"none", SEL_NONE}, /* allow nothing to be dragged */
+ {"", 0 }
+};
+
+/* insert/delete subcommands */
+#define MOD_ACTIVE 1
+#define MOD_COLS 2
+#define MOD_ROWS 3
+static Cmd_Struct mod_cmds[] = {
+ {"active", MOD_ACTIVE},
+ {"cols", MOD_COLS},
+ {"rows", MOD_ROWS},
+ {"", 0}
+};
+
+/* border subcommands */
+#define BD_MARK 1
+#define BD_DRAGTO 2
+static Cmd_Struct bd_cmds[] = {
+ {"mark", BD_MARK},
+ {"dragto", BD_DRAGTO},
+ {"", 0}
+};
+
+/* drawmode values */
+/* The display redraws with a pixmap using TK function calls */
+#define DRAW_MODE_SLOW (1<<0)
+/* The redisplay is direct to the screen, but TK function calls are still
+ * used to give correct 3-d border appearance and thus remain compatible
+ * with other TK apps */
+#define DRAW_MODE_TK_COMPAT (1<<1)
+/* the redisplay goes straight to the screen and the 3d borders are rendered
+ * with a single pixel wide line only. It cheats and uses the internal
+ * border structure to do the borders */
+#define DRAW_MODE_FAST (1<<2)
+#define DRAW_MODE_SINGLE (1<<3)
+
+static Cmd_Struct drawmode_vals[] = {
+ {"fast", DRAW_MODE_FAST},
+ {"compatible", DRAW_MODE_TK_COMPAT},
+ {"slow", DRAW_MODE_SLOW},
+ {"single", DRAW_MODE_SINGLE},
+ {"", 0}
+};
+
+/* stretchmode values */
+#define STRETCH_MODE_NONE (1<<0) /* No additional pixels will be
+ added to rows or cols */
+#define STRETCH_MODE_UNSET (1<<1) /* All default rows or columns will
+ be stretched to fill the screen */
+#define STRETCH_MODE_ALL (1<<2) /* All rows/columns will be padded
+ to fill the window */
+#define STRETCH_MODE_LAST (1<<3) /* Stretch last elememt to fill
+ window */
+#define STRETCH_MODE_FILL (1<<4) /* More ROWS in Window */
+
+static Cmd_Struct stretch_vals[] = {
+ {"none", STRETCH_MODE_NONE},
+ {"unset", STRETCH_MODE_UNSET},
+ {"all", STRETCH_MODE_ALL},
+ {"last", STRETCH_MODE_LAST},
+ {"fill", STRETCH_MODE_FILL},
+ {"", 0}
+};
+
+static Cmd_Struct state_vals[]= {
+ {"normal", STATE_NORMAL},
+ {"disabled", STATE_DISABLED},
+ {"", 0 }
+};
+
+/* The widget configuration table */
+static Tk_CustomOption drawOpt = { Cmd_OptionSet, Cmd_OptionGet,
+ (ClientData)(&drawmode_vals) };
+static Tk_CustomOption resizeTypeOpt = { Cmd_OptionSet, Cmd_OptionGet,
+ (ClientData)(&resize_vals) };
+static Tk_CustomOption stretchOpt = { Cmd_OptionSet, Cmd_OptionGet,
+ (ClientData)(&stretch_vals) };
+static Tk_CustomOption selTypeOpt = { Cmd_OptionSet, Cmd_OptionGet,
+ (ClientData)(&sel_vals) };
+static Tk_CustomOption stateTypeOpt = { Cmd_OptionSet, Cmd_OptionGet,
+ (ClientData)(&state_vals) };
+
+static Tk_ConfigSpec TableConfig[] = {
+ {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", "center",
+ Tk_Offset(Table, defaultTag.anchor), 0 },
+ {TK_CONFIG_BOOLEAN, "-autoclear", "autoClear", "AutoClear", "0",
+ Tk_Offset(Table, autoClear), 0 },
+ {TK_CONFIG_BORDER, "-background", "background", "Background", NORMAL_BG,
+ Tk_Offset(Table, defaultTag.bg), 0 },
+ {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, (char *) NULL, 0, 0},
+ {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *) NULL, 0, 0},
+ {TK_CONFIG_CURSOR, "-bordercursor", "borderCursor", "Cursor", "crosshair",
+ Tk_Offset(Table, bdcursor), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", "1",
+ Tk_Offset(Table, borderWidth), 0 },
+ {TK_CONFIG_STRING, "-browsecommand", "browseCommand", "BrowseCommand", "",
+ Tk_Offset(Table, browseCmd), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_SYNONYM, "-browsecmd", "browseCommand", (char *) NULL,
+ (char *) NULL, 0, TK_CONFIG_NULL_OK},
+ {TK_CONFIG_BOOLEAN, "-cache", "cache", "Cache", "0",
+ Tk_Offset(Table, caching), 0},
+ {TK_CONFIG_INT, "-colorigin", "colOrigin", "Origin", "0",
+ Tk_Offset(Table, colOffset), 0 },
+ {TK_CONFIG_INT, "-cols", "cols", "Cols", "10",
+ Tk_Offset(Table, cols), 0 },
+ {TK_CONFIG_STRING, "-colseparator", "colSeparator", "Separator", NULL,
+ Tk_Offset(Table, colSep), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_CUSTOM, "-colstretchmode", "colStretch", "StretchMode", "none",
+ Tk_Offset (Table, colStretch), 0 , &stretchOpt },
+ {TK_CONFIG_STRING, "-coltagcommand", "colTagCommand", "TagCommand", NULL,
+ Tk_Offset(Table, colTagCmd), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_INT, "-colwidth", "colWidth", "ColWidth", "10",
+ Tk_Offset(Table, defColWidth), 0 },
+ {TK_CONFIG_STRING, "-command", "command", "Command", "",
+ Tk_Offset(Table, command), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", "xterm",
+ Tk_Offset(Table, cursor), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_CUSTOM, "-drawmode", "drawMode", "DrawMode", "compatible",
+ Tk_Offset(Table, drawMode), 0, &drawOpt },
+ {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection",
+ "ExportSelection", "1", Tk_Offset(Table, exportSelection), 0},
+ {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, (char *) NULL, 0, 0},
+ {TK_CONFIG_BOOLEAN, "-flashmode", "flashMode", "FlashMode", "0",
+ Tk_Offset(Table, flashMode), 0 },
+ {TK_CONFIG_INT, "-flashtime", "flashTime", "FlashTime", "2",
+ Tk_Offset(Table, flashTime), 0 },
+ {TK_CONFIG_FONT, "-font", "font", "Font", DEF_TABLE_FONT,
+ Tk_Offset(Table, defaultTag.tkfont), 0 },
+ {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground", "black",
+ Tk_Offset(Table, defaultTag.fg), 0 },
+ {TK_CONFIG_INT, "-height", "height", "Height", "0",
+ Tk_Offset(Table, maxReqRows), 0 },
+ {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
+ "HighlightBackground", NORMAL_BG, Tk_Offset(Table, highlightBgColorPtr), 0},
+ {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
+ HIGHLIGHT, Tk_Offset(Table, highlightColorPtr), 0 },
+ {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
+ "HighlightThickness", "2", Tk_Offset(Table, highlightWidth), 0 },
+ {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
+ "Black", Tk_Offset(Table, insertBg), 0 },
+ {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
+ "0", Tk_Offset(Table, insertBorderWidth), TK_CONFIG_COLOR_ONLY},
+ {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
+ "0", Tk_Offset(Table, insertBorderWidth), TK_CONFIG_MONO_ONLY},
+ {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime", "300",
+ Tk_Offset(Table, insertOffTime), 0},
+ {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime", "600",
+ Tk_Offset(Table, insertOnTime), 0},
+ {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", "2",
+ Tk_Offset(Table, insertWidth), 0},
+ {TK_CONFIG_BOOLEAN, "-invertselected", "invertSelected", "InvertSelected",
+ "0", Tk_Offset(Table, invertSelected), 0},
+ {TK_CONFIG_PIXELS, "-maxheight", "maxHeight", "MaxHeight", "600",
+ Tk_Offset(Table, maxReqHeight), 0 },
+ {TK_CONFIG_PIXELS, "-maxwidth", "maxWidth", "MaxWidth", "800",
+ Tk_Offset(Table, maxReqWidth), 0 },
+ {TK_CONFIG_BOOLEAN, "-multiline", "multiline", "Multiline", "1",
+ Tk_Offset(Table, defaultTag.multiline), 0 },
+ {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", "2", Tk_Offset(Table, padX), 0},
+ {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", "1", Tk_Offset(Table, padY), 0},
+ {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", "sunken",
+ Tk_Offset(Table, defaultTag.relief), 0 },
+ {TK_CONFIG_CUSTOM, "-resizeborders", "resizeBorders", "ResizeBorders",
+ "both", Tk_Offset(Table, resize), 0, &resizeTypeOpt },
+ {TK_CONFIG_PIXELS, "-rowheight", "rowHeight", "RowHeight", "1",
+ Tk_Offset(Table, defRowHeight), 0 },
+ {TK_CONFIG_INT, "-roworigin", "rowOrigin", "Origin", "0",
+ Tk_Offset(Table, rowOffset), 0 },
+ {TK_CONFIG_INT, "-rows", "rows", "Rows", "10", Tk_Offset(Table, rows), 0 },
+ {TK_CONFIG_STRING, "-rowseparator", "rowSeparator", "Separator", NULL,
+ Tk_Offset(Table, rowSep), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_CUSTOM, "-rowstretchmode", "rowStretch", "StretchMode", "none",
+ Tk_Offset(Table, rowStretch), 0 , &stretchOpt },
+ {TK_CONFIG_STRING, "-rowtagcommand", "rowTagCommand", "TagCommand", NULL,
+ Tk_Offset(Table, rowTagCmd), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_SYNONYM, "-selcmd", "selectionCommand", (char *) NULL,
+ (char *) NULL, 0, TK_CONFIG_NULL_OK},
+ {TK_CONFIG_STRING, "-selectioncommand", "selectionCommand",
+ "SelectionCommand", NULL, Tk_Offset(Table, selCmd), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_STRING, "-selectmode", "selectMode", "SelectMode", "browse",
+ Tk_Offset(Table, selectMode), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_BOOLEAN, "-selecttitles", "selectTitles", "SelectTitles", "0",
+ Tk_Offset(Table, selectTitles), 0 },
+ {TK_CONFIG_CUSTOM, "-selecttype", "selectType", "SelectType", "cell",
+ Tk_Offset(Table, selectType), 0, &selTypeOpt },
+ {TK_CONFIG_CUSTOM, "-state", "state", "State", "normal",
+ Tk_Offset(Table, state), 0, &stateTypeOpt},
+ {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", (char *) NULL,
+ Tk_Offset(Table, takeFocus), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_INT, "-titlecols", "titleCols", "TitleCols", "0",
+ Tk_Offset(Table, titleCols), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_INT, "-titlerows", "titleRows", "TitleRows", "0",
+ Tk_Offset(Table, titleRows), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_BOOLEAN, "-usecommand", "useCommand", "UseCommand", "1",
+ Tk_Offset(Table, useCmd), 0},
+ {TK_CONFIG_STRING, "-variable", "variable", "Variable", (char *) NULL,
+ Tk_Offset(Table, arrayVar), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_BOOLEAN, "-validate", "validate", "Validate", "0",
+ Tk_Offset(Table, validate), 0 },
+ {TK_CONFIG_STRING, "-validatecommand", "validateCommand", "ValidateCommand",
+ "", Tk_Offset(Table, valCmd), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_SYNONYM, "-vcmd", "validateCommand", (char *) NULL,
+ (char *) NULL, 0, TK_CONFIG_NULL_OK},
+ {TK_CONFIG_INT, "-width", "width", "Width", "0",
+ Tk_Offset(Table, maxReqCols), 0 },
+ {TK_CONFIG_BOOLEAN, "-wrap", "wrap", "Wrap", "0",
+ Tk_Offset(Table, defaultTag.wrap), 0 },
+ {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
+ NULL, Tk_Offset(Table, xScrollCmd), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
+ NULL, Tk_Offset(Table, yScrollCmd), TK_CONFIG_NULL_OK },
+ {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, 0 }
+};
+
+/*
+ * This specifies the configure options that will cause an update to
+ * occur, so we should have a quick lookup table for them.
+ * Keep this in sync with the above values.
+ */
+static Cmd_Struct update_config[] = {
+ {"-anchor", 1}, {"-background", 1},
+ {"-bg", 1}, {"-bd", 1},
+ {"-borderwidth", 1}, {"-cache", 1},
+ {"-command", 1}, {"-colorigin", 1},
+ {"-cols", 1}, {"-colstretchmode", 1},
+ {"-coltagcommand", 1}, {"-drawmode", 1},
+ {"-fg", 1}, {"-font", 1},
+ {"-foreground", 1},
+ {"-height", 1}, {"-highlightbackground", 1},
+ {"-highlightcolor", 1}, {"-highlightthickness", 1},
+ {"-insertbackground", 1}, {"-insertborderwidth", 1},
+ {"-insertwidth", 1}, {"-invertselected", 1},
+ {"-maxheight", 1}, {"-maxwidth", 1},
+ {"-multiline", 1},
+ {"-padx", 1}, {"-pady", 1},
+ {"-relief", 1}, {"-roworigin", 1},
+ {"-rows", 1}, {"-rowstretchmode", 1},
+ {"-rowtagcommand", 1}, {"-state", 1},
+ {"-titlecols", 1}, {"-titlerows", 1},
+ {"-usecommand", 1}, {"-variable", 1},
+ {"-width", 1}, {"-wrap", 1},
+ {"-xscrollcommand", 1}, {"-yscrollcommand", 1},
+ {"", 0},
+};
+
+/*
+ * END HEADER INFORMATION
+ */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableFlushCache --
+ * Flushes the internal cache of the table.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+INLINE static void
+TableFlushCache(register Table *tablePtr)
+{
+ /* Just get rid of it and reinit it */
+ Tcl_DeleteHashTable(tablePtr->cache);
+ ckfree((char *) (tablePtr->cache));
+ tablePtr->cache = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->cache, TCL_STRING_KEYS);
+}
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableRefresh --
+ * Refreshes an area of the table based on the mode.
+ * row,col in real coords (0-based)
+ *
+ * Results:
+ * Will cause redraw for visible cells
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+TableRefresh(register Table *tablePtr, int row, int col, int mode)
+{
+ int x, y, w, h;
+
+ if (mode & CELL) {
+ if (TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0)) {
+ TableInvalidate(tablePtr, x, y, w, h, mode);
+ }
+ } else if (mode & ROW) {
+ /* get the position of the leftmost cell in the row */
+ if ((mode & INV_FILL) && row < tablePtr->topRow) {
+ /* Invalidate whole table */
+ TableInvalidateAll(tablePtr, mode);
+ } else if (TableCellVCoords(tablePtr, row, tablePtr->leftCol,
+ &x, &y, &w, &h, 0)) {
+ /* Invalidate from this row, maybe to end */
+ TableInvalidate(tablePtr, 0, y, Tk_Width(tablePtr->tkwin),
+ (mode&INV_FILL)?Tk_Height(tablePtr->tkwin):h, mode);
+ }
+ } else if (mode & COL) {
+ /* get the position of the topmost cell on the column */
+ if ((mode & INV_FILL) && col < tablePtr->leftCol) {
+ /* Invalidate whole table */
+ TableInvalidateAll(tablePtr, mode);
+ } else if (TableCellVCoords(tablePtr, tablePtr->topRow, col,
+ &x, &y, &w, &h, 0)) {
+ /* Invalidate from this column, maybe to end */
+ TableInvalidate(tablePtr, x, 0,
+ (mode&INV_FILL)?Tk_Width(tablePtr->tkwin):w,
+ Tk_Height(tablePtr->tkwin), mode);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableClear --
+ * Clears state information about the table.
+ *
+ * Results:
+ * Cached info can be lost. Returns valid Tcl result.
+ *
+ * Side effects:
+ * Can cause redraw.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+TableClear(register Table *tablePtr, int mode, char *first, char *last)
+{
+ int redraw = 0;
+
+ if (mode == 0) return TCL_ERROR;
+
+ if (first == NULL) {
+ if (mode & CLEAR_TAGS) {
+ Tcl_DeleteHashTable(tablePtr->rowStyles);
+ Tcl_DeleteHashTable(tablePtr->colStyles);
+ Tcl_DeleteHashTable(tablePtr->cellStyles);
+ Tcl_DeleteHashTable(tablePtr->flashCells);
+ Tcl_DeleteHashTable(tablePtr->selCells);
+
+ /* style hash tables */
+ Tcl_InitHashTable(tablePtr->rowStyles, TCL_ONE_WORD_KEYS);
+ Tcl_InitHashTable(tablePtr->colStyles, TCL_ONE_WORD_KEYS);
+ Tcl_InitHashTable(tablePtr->cellStyles, TCL_STRING_KEYS);
+
+ /* special style hash tables */
+ Tcl_InitHashTable(tablePtr->flashCells, TCL_STRING_KEYS);
+ Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS);
+ }
+
+ if (mode & CLEAR_SIZES) {
+ Tcl_DeleteHashTable(tablePtr->colWidths);
+ Tcl_DeleteHashTable(tablePtr->rowHeights);
+
+ /* style hash tables */
+ Tcl_InitHashTable(tablePtr->colWidths, TCL_ONE_WORD_KEYS);
+ Tcl_InitHashTable(tablePtr->rowHeights, TCL_ONE_WORD_KEYS);
+ }
+
+ if (mode & CLEAR_CACHE) {
+ TableFlushCache(tablePtr);
+ /* If we were caching and we have no other data source,
+ * invalidate all the cells */
+ if (tablePtr->dataSource == DATA_CACHE) {
+ TableGetActiveBuf(tablePtr);
+ }
+ }
+ redraw = 1;
+ } else {
+ int row, col, r1, r2, c1, c2;
+ Tcl_HashEntry *entryPtr;
+ char buf[INDEX_BUFSIZE];
+
+ if (TableGetIndex(tablePtr, first, &row, &col) == TCL_ERROR ||
+ (last != NULL && TableGetIndex(tablePtr, last, &r2, &c2)==TCL_ERROR)) {
+ return TCL_ERROR;
+ }
+ if (last == NULL) {
+ r1 = r2 = row;
+ c1 = c2 = col;
+ } else {
+ r1 = MIN(row,r2); r2 = MAX(row,r2);
+ c1 = MIN(col,c2); c2 = MAX(col,c2);
+ }
+ for (row = r1; row <= r2; row++) {
+ /* Note that *Styles entries are user based (no offset)
+ * while size entries are 0-based (real) */
+ if ((mode & CLEAR_TAGS) &&
+ (entryPtr = Tcl_FindHashEntry(tablePtr->rowStyles, (char *) row))) {
+ Tcl_DeleteHashEntry(entryPtr);
+ redraw = 1;
+ }
+
+ if ((mode & CLEAR_SIZES) &&
+ (entryPtr = Tcl_FindHashEntry(tablePtr->rowHeights,
+ (char *) row-tablePtr->rowOffset))) {
+ Tcl_DeleteHashEntry(entryPtr);
+ redraw = 1;
+ }
+
+ for (col = c1; col <= c2; col++) {
+ TableMakeArrayIndex(row, col, buf);
+
+ if (mode & CLEAR_TAGS) {
+ if ((row == r1) && (entryPtr = Tcl_FindHashEntry(tablePtr->colStyles,
+ (char *) col))) {
+ Tcl_DeleteHashEntry(entryPtr);
+ redraw = 1;
+ }
+ if ((entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf))) {
+ Tcl_DeleteHashEntry(entryPtr);
+ redraw = 1;
+ }
+ if ((entryPtr = Tcl_FindHashEntry(tablePtr->flashCells, buf))) {
+ Tcl_DeleteHashEntry(entryPtr);
+ redraw = 1;
+ }
+ if ((entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf))) {
+ Tcl_DeleteHashEntry(entryPtr);
+ redraw = 1;
+ }
+ }
+
+ if ((mode & CLEAR_SIZES) && row == r1 &&
+ (entryPtr = Tcl_FindHashEntry(tablePtr->colWidths, (char *)
+ col-tablePtr->colOffset))) {
+ Tcl_DeleteHashEntry(entryPtr);
+ redraw = 1;
+ }
+
+ if ((mode & CLEAR_CACHE) &&
+ (entryPtr = Tcl_FindHashEntry(tablePtr->cache, buf))) {
+ Tcl_DeleteHashEntry(entryPtr);
+ /* if the cache is our data source,
+ * we need to invalidate the cells changed */
+ if ((tablePtr->dataSource == DATA_CACHE) &&
+ (row-tablePtr->rowOffset == tablePtr->activeRow &&
+ col-tablePtr->colOffset == tablePtr->activeCol))
+ TableGetActiveBuf(tablePtr);
+ redraw = 1;
+ }
+ }
+ }
+ }
+ /* This could be more sensitive about what it updates,
+ * but that can actually be a lot more costly in some cases */
+ if (redraw) {
+ if (mode & CLEAR_SIZES) {
+ TableAdjustParams(tablePtr);
+ /* rerequest geometry */
+ TableGeometryRequest(tablePtr);
+ }
+ TableInvalidateAll(tablePtr, 0);
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableGetGc --
+ * Gets a GC corresponding to the tag structure passed.
+ *
+ * Results:
+ * Returns usable GC.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+INLINE static void
+TableGetGc(Display *display, Drawable d, TableTag *tagPtr, GC *tagGc)
+{
+ XGCValues gcValues;
+ gcValues.foreground = Tk_3DBorderColor(tagPtr->fg)->pixel;
+ gcValues.background = Tk_3DBorderColor(tagPtr->bg)->pixel;
+ gcValues.font = Tk_FontId(tagPtr->tkfont);
+ if (*tagGc == NULL) {
+ gcValues.graphics_exposures = False;
+ *tagGc = XCreateGC(display, d,
+ GCForeground|GCBackground|GCFont|GCGraphicsExposures,
+ &gcValues);
+ } else {
+ XChangeGC(display, *tagGc, GCForeground|GCBackground|GCFont, &gcValues);
+ }
+}
+
+#define TableFreeGc XFreeGC
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableRedrawHighlight --
+ * Redraws just the highlight for the window
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+INLINE static void
+TableRedrawHighlight(Table *tablePtr)
+{
+ if ((tablePtr->flags & REDRAW_BORDER) && tablePtr->highlightWidth > 0) {
+ GC gc = Tk_GCForColor((tablePtr->flags & HAS_FOCUS)
+ ?(tablePtr->highlightColorPtr)
+ :(tablePtr->highlightBgColorPtr),
+ Tk_WindowId(tablePtr->tkwin));
+ Tk_DrawFocusHighlight(tablePtr->tkwin, gc, tablePtr->highlightWidth,
+ Tk_WindowId(tablePtr->tkwin));
+ }
+ tablePtr->flags &= ~REDRAW_BORDER;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TableUndisplay --
+ * This procedure removes the contents of a table window
+ * that have been moved offscreen.
+ *
+ * Results:
+ * Embedded windows can be unmapped.
+ *
+ * Side effects:
+ * Information disappears from the screen.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+TableUndisplay(register Table *tablePtr)
+{
+ register int *seen = tablePtr->seen;
+ int row, col;
+
+ TableGetLastCell(tablePtr, &row, &col);
+ if (seen[0] != -1) {
+ if (seen[0] < tablePtr->topRow) {
+ /* Remove now hidden rows */
+ EmbWinUnmap(tablePtr, seen[0], tablePtr->topRow-1, 0, seen[3]);
+ }
+ if (seen[1] < tablePtr->leftCol) {
+ /* Remove now hidden cols */
+ EmbWinUnmap(tablePtr, 0, seen[2], seen[1], tablePtr->leftCol-1);
+ }
+ if (seen[2] > row) {
+ /* Remove now off-screen rows */
+ EmbWinUnmap(tablePtr, row+1, seen[2], 0, seen[3]);
+ }
+ if (seen[3] > col) {
+ /* Remove now off-screen cols */
+ EmbWinUnmap(tablePtr, 0, seen[2], col+1, seen[3]);
+ }
+ }
+ seen[0] = tablePtr->topRow;
+ seen[1] = tablePtr->leftCol;
+ seen[2] = row;
+ seen[3] = col;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TableDisplay --
+ * This procedure redraws the contents of a table window.
+ * The conditional code in this function is due to these factors:
+ * o Lack of XSetClipRectangles on Windows
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Information appears on the screen.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+TableDisplay(ClientData clientdata)
+{
+ register Table *tablePtr = (Table *) clientdata;
+ Tk_Window tkwin = tablePtr->tkwin;
+ Display *display = tablePtr->display;
+ Drawable window;
+#ifdef _WIN32
+ Drawable clipWind;
+#else
+ XRectangle clipRect;
+#endif
+ int rowFrom, rowTo, colFrom, colTo,
+ invalidX, invalidY, invalidWidth, invalidHeight,
+ x, y, width, height, itemX, itemY, itemW, itemH,
+ row, col, urow, ucol, cx, cy, cw, ch, bd,
+ numBytes, new, boundW, boundH, maxW, maxH,
+ originX, originY, activeCell, clipRectSet, shouldInvert;
+ GC tagGc = NULL, topGc, bottomGc;
+ char *string = NULL;
+ char buf[INDEX_BUFSIZE];
+ TableTag *tagPtr = NULL, *titlePtr, *selPtr, *activePtr, *flashPtr,
+ *rowPtr, *colPtr;
+ Tcl_HashEntry *entryPtr;
+ static XPoint rect[3] = { {0, 0}, {0, 0}, {0, 0} };
+ Tcl_HashTable *colTagsCache = NULL;
+ Tk_TextLayout textLayout = NULL;
+ TableEmbWindow *ewPtr;
+
+ if ((tablePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
+ return;
+ }
+ tablePtr->flags &= ~REDRAW_PENDING;
+
+ bd = tablePtr->borderWidth;
+ boundW = Tk_Width(tkwin)-tablePtr->highlightWidth;
+ boundH = Tk_Height(tkwin)-tablePtr->highlightWidth;
+
+ /* Constrain drawable to not include highlight borders */
+ invalidX = MAX(tablePtr->highlightWidth, tablePtr->invalidX);
+ invalidY = MAX(tablePtr->highlightWidth, tablePtr->invalidY);
+ invalidWidth = MIN(tablePtr->invalidWidth, MAX(1, boundW-invalidX));
+ invalidHeight = MIN(tablePtr->invalidHeight, MAX(1, boundH-invalidY));
+
+ /*
+ * if we are using the slow drawing mode with a pixmap
+ * create the pixmap and adjust x && y for offset in pixmap
+ */
+ if (tablePtr->drawMode == DRAW_MODE_SLOW) {
+ window = Tk_GetPixmap(display, Tk_WindowId(tkwin),
+ invalidWidth, invalidHeight, Tk_Depth(tkwin));
+ } else {
+ window = Tk_WindowId(tkwin);
+ }
+#ifdef _WIN32
+ clipWind = Tk_GetPixmap(display, window,
+ invalidWidth, invalidHeight, Tk_Depth(tkwin));
+#endif
+
+ /* set up the permanent tag styles */
+ entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, "title");
+ titlePtr = (TableTag *) Tcl_GetHashValue(entryPtr);
+ entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, "sel");
+ selPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
+ entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, "active");
+ activePtr= (TableTag *) Tcl_GetHashValue(entryPtr);
+ entryPtr = Tcl_FindHashEntry(tablePtr->tagTable, "flash");
+ flashPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
+
+ /* find out the cells represented by the invalid region */
+ TableWhatCell(tablePtr, invalidX, invalidY, &rowFrom, &colFrom);
+ TableWhatCell(tablePtr, invalidX+invalidWidth-1,
+ invalidY+invalidHeight-1, &rowTo, &colTo);
+
+#ifdef DEBUG
+ tcl_dprintf(tablePtr->interp, "display %d,%d => %d,%d",
+ rowFrom+tablePtr->rowOffset, colFrom+tablePtr->colOffset,
+ rowTo+tablePtr->rowOffset, colTo+tablePtr->colOffset);
+#endif
+
+ /*
+ * Initialize colTagsCache hash table to cache column tag names.
+ */
+ colTagsCache = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(colTagsCache, TCL_ONE_WORD_KEYS);
+
+ /* Cycle through the cells and display them */
+ for (row = rowFrom; row <= rowTo; row++) {
+ /*
+ * are we in the 'dead zone' between the
+ * title rows and the first displayed row
+ */
+ if (row < tablePtr->topRow && row >= tablePtr->titleRows) {
+ row = tablePtr->topRow;
+ }
+
+ /* Cache the row in user terms */
+ urow = row+tablePtr->rowOffset;
+
+ /* Get the row tag once for all iterations of col */
+ rowPtr = FindRowColTag(tablePtr, urow, ROW);
+
+ for (col = colFrom; col <= colTo; col++) {
+ activeCell = 0;
+ /*
+ * are we in the 'dead zone' between the
+ * title cols and the first displayed col
+ */
+ if (col < tablePtr->leftCol && col >= tablePtr->titleCols) {
+ col = tablePtr->leftCol;
+ }
+
+ /* Cache the col in user terms */
+ ucol = col+tablePtr->colOffset;
+
+ /* put the use cell ref into a buffer for the hash lookups */
+ TableMakeArrayIndex(urow, ucol, buf);
+
+ /* get the coordinates for the cell */
+ TableCellCoords(tablePtr, row, col, &x, &y, &width, &height);
+
+ /* Constrain drawn size to the visual boundaries */
+ if (width > boundW-x) {
+ width = boundW-x;
+ }
+ if (height > boundH-y) {
+ height = boundH-y;
+ }
+
+ /* Create the tag here */
+ tagPtr = TableNewTag();
+ /* First, merge in the default tag */
+ TableMergeTag(tagPtr, &(tablePtr->defaultTag));
+
+ if ((entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf)) != NULL) {
+ ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
+
+ if (ewPtr->tkwin != NULL) {
+ /* Display embedded window instead of text */
+
+ /* if active, make it disabled to avoid unnecessary editing */
+ if ((tablePtr->flags & HAS_ACTIVE)
+ && row == tablePtr->activeRow && col == tablePtr->activeCol) {
+ tablePtr->flags |= ACTIVE_DISABLED;
+ }
+
+ EmbWinDisplay(tablePtr, window, ewPtr, tagPtr,
+ x, y, width, height);
+
+ if (tablePtr->drawMode == DRAW_MODE_SLOW) {
+ /* Correctly adjust x && y with the offset */
+ x -= invalidX;
+ y -= invalidY;
+ }
+ Tk_Fill3DRectangle(tkwin, window, tagPtr->bg,
+ x, y, width, height, bd, TK_RELIEF_FLAT);
+
+ goto ImageUsed;
+ }
+ }
+
+ if (tablePtr->drawMode == DRAW_MODE_SLOW) {
+ /* Correctly adjust x && y with the offset */
+ x -= invalidX;
+ y -= invalidY;
+ }
+
+ shouldInvert = 0;
+ /*
+ * get the combined tag structure for the cell
+ * first clear out a new tag structure that we will build in
+ * then add tags as we realize they belong.
+ * Tags with the highest priority are added first
+ */
+
+ /*
+ * Merge colPtr if it exists
+ * let's see if we have the value cached already
+ * if not, run the findColTag routine and cache the value
+ */
+ entryPtr = Tcl_CreateHashEntry(colTagsCache, (char *)ucol, &new);
+ if (new) {
+ colPtr = FindRowColTag(tablePtr, ucol, COL);
+ Tcl_SetHashValue(entryPtr, colPtr);
+ } else {
+ colPtr = (TableTag *) Tcl_GetHashValue(entryPtr);
+ }
+ if (colPtr != (TableTag *) NULL)
+ TableMergeTag(tagPtr, colPtr);
+ /* Merge rowPtr if it exists */
+ if (rowPtr != (TableTag *) NULL)
+ TableMergeTag(tagPtr, rowPtr);
+ /* Am I in the titles */
+ if (row < tablePtr->topRow || col < tablePtr->leftCol)
+ TableMergeTag(tagPtr, titlePtr);
+ /* Does this have a cell tag */
+ if ((entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf)) != NULL)
+ TableMergeTag(tagPtr, (TableTag *) Tcl_GetHashValue(entryPtr));
+ /* is this cell selected? */
+ if (Tcl_FindHashEntry(tablePtr->selCells, buf) != NULL) {
+ if (tablePtr->invertSelected && !activeCell) {
+ shouldInvert = 1;
+ } else {
+ TableMergeTag(tagPtr, selPtr);
+ }
+ }
+ /* is this cell active? */
+ if ((tablePtr->flags & HAS_ACTIVE) && tablePtr->state == STATE_NORMAL
+ && row == tablePtr->activeRow && col == tablePtr->activeCol) {
+ if (tagPtr->state == STATE_DISABLED) {
+ tablePtr->flags |= ACTIVE_DISABLED;
+ } else {
+ TableMergeTag(tagPtr, activePtr);
+ activeCell = 1;
+ tablePtr->flags &= ~ACTIVE_DISABLED;
+ }
+ }
+ /* if flash mode is on, is this cell flashing */
+ if (tablePtr->flashMode &&
+ Tcl_FindHashEntry(tablePtr->flashCells, buf) != NULL)
+ TableMergeTag(tagPtr, flashPtr);
+
+ if (shouldInvert) TableInvertTag(tagPtr);
+
+ /*
+ * first fill in a blank rectangle. This is left as a Tk call instead
+ * of a direct X call for Tk compatibilty. The TK_RELIEF_FLAT ensures
+ * that only XFillRectangle is called anyway so the speed is the same
+ */
+ Tk_Fill3DRectangle(tkwin, window, tagPtr->bg,
+ x, y, width, height, bd, TK_RELIEF_FLAT);
+
+ /*
+ * If an image is in the tag, draw it
+ */
+ if (tagPtr->image != NULL) {
+ Tk_SizeOfImage(tagPtr->image, &itemW, &itemH);
+ /* Handle anchoring of image in cell space */
+ switch (tagPtr->anchor) {
+ case TK_ANCHOR_NW:
+ case TK_ANCHOR_W:
+ case TK_ANCHOR_SW: /* western position */
+ originX = itemX = 0;
+ break;
+ case TK_ANCHOR_N:
+ case TK_ANCHOR_S:
+ case TK_ANCHOR_CENTER: /* centered position */
+ itemX = MAX(0, (itemW-width)/2-bd);
+ originX = MAX(0, (width-itemW)/2);
+ break;
+ default: /* eastern position */
+ itemX = MAX(0, itemW-width-2*bd);
+ originX = MAX(0, width-itemW);
+ }
+ switch (tagPtr->anchor) {
+ case TK_ANCHOR_N:
+ case TK_ANCHOR_NE:
+ case TK_ANCHOR_NW: /* northern position */
+ originY = itemY = 0;
+ break;
+ case TK_ANCHOR_W:
+ case TK_ANCHOR_E:
+ case TK_ANCHOR_CENTER: /* centered position */
+ itemY = MAX(0, (itemH-height)/2-bd);
+ originY = MAX(0, (height-itemH)/2);
+ break;
+ default: /* southern position */
+ itemY = MAX(0, itemH-height-2*bd);
+ originY = MAX(0, height-itemH);
+ }
+ Tk_RedrawImage(tagPtr->image, itemX, itemY,
+ MIN(itemW, width-originX-2*bd),
+ MIN(itemH, height-originY-2*bd), window,
+ x+originX+bd, y+originY+bd);
+ /* Jump to avoid display of the text value */
+ if (tagPtr->showtext == 0)
+ goto ImageUsed;
+ }
+
+ /* get the GC for this particular blend of tags
+ * this creates the GC if it never existed, otherwise it
+ * modifies the one we have */
+ TableGetGc(display, window, tagPtr, &tagGc);
+
+ /* if this is the active cell, use the buffer */
+ if (activeCell) {
+ string = tablePtr->activeBuf;
+ } else {
+ /* Is there a value in the cell? If so, draw it */
+ string = TableGetCellValue(tablePtr, urow, ucol);
+ }
+
+ numBytes = strlen(string);
+ /* If there is a string, show it */
+ if (activeCell || numBytes) {
+ /* get the dimensions of the string */
+ textLayout = Tk_ComputeTextLayout(tagPtr->tkfont, string, numBytes,
+ (tagPtr->wrap>0) ? width : 0,
+ tagPtr->justify,
+ (tagPtr->multiline>0) ? 0 :
+ TK_IGNORE_NEWLINES,
+ &itemW, &itemH);
+
+ /*
+ * Set the origin coordinates of the string to draw using the anchor.
+ * origin represents the (x,y) coordinate of the lower left corner of
+ * the text box, relative to the internal (inside the border) window
+ */
+
+ /* set the X origin first */
+ switch (tagPtr->anchor) {
+ case TK_ANCHOR_NW:
+ case TK_ANCHOR_W:
+ case TK_ANCHOR_SW: /* western position */
+ originX = tablePtr->padX;
+ break;
+ case TK_ANCHOR_N:
+ case TK_ANCHOR_S:
+ case TK_ANCHOR_CENTER: /* centered position */
+ originX = (width-itemW)/2 - bd;
+ break;
+ default: /* eastern position */
+ originX = width-itemW-2*bd-tablePtr->padX;
+ }
+
+ /* then set the Y origin */
+ switch (tagPtr->anchor) {
+ case TK_ANCHOR_N:
+ case TK_ANCHOR_NE:
+ case TK_ANCHOR_NW: /* northern position */
+ originY = tablePtr->padY;
+ break;
+ case TK_ANCHOR_W:
+ case TK_ANCHOR_E:
+ case TK_ANCHOR_CENTER: /* centered position */
+ originY = (height-itemH)/2 - bd;
+ break;
+ default: /* southern position */
+ originY = height-itemH-2*bd-tablePtr->padY;
+ }
+
+ /*
+ * if this is the selected cell and we are editing
+ * ensure that the cursor will be displayed
+ */
+ if (activeCell) {
+#if (TK_MINOR_VERSION > 0)
+ int insertByte;
+
+ insertByte = Tcl_UtfAtIndex(string, tablePtr->icursor) - string;
+ Tk_CharBbox(textLayout, MIN(numBytes, insertByte),
+ &cx, &cy, &cw, &ch);
+#else
+ Tk_CharBbox(textLayout, MIN(numBytes, tablePtr->icursor),
+ &cx, &cy, &cw, &ch);
+#endif
+ /* we have to fudge with maxW because of odd width
+ * determination for newlines at the end of a line */
+ maxW = width-bd-tablePtr->padX-tablePtr->insertWidth
+ -(cx+MIN(tablePtr->charWidth, cw));
+ maxH = height-bd-tablePtr->padY-(cy+ch);
+ if (originX < tablePtr->padX+bd-cx) {
+ /* cursor off cell to the left */
+ /* use western positioning to cet cursor at left edge
+ * with slight variation to show some text */
+ originX = tablePtr->padX+bd-cx
+ +MIN(cx, width-2*bd-tablePtr->padX-tablePtr->insertWidth);
+ } else if (originX > maxW) {
+ /* cursor off cell to the right */
+ /* use eastern positioning to cet cursor at right edge */
+ originX = maxW;
+ }
+ if (originY < tablePtr->padY+bd-cy) {
+ /* cursor before top of cell */
+ /* use northern positioning to cet cursor at top edge */
+ originY = tablePtr->padY+bd-cy;
+ } else if (originY > maxH) {
+ /* cursor beyond bottom of cell */
+ /* use southern positioning to cet cursor at bottom edge */
+ originY = maxH;
+ }
+ tablePtr->activeLayout = textLayout;
+ tablePtr->activeX = originX;
+ tablePtr->activeY = originY;
+ }
+ /*
+ * use a clip rectangle only if necessary as it means
+ * updating the GC in the server which slows everything down.
+ * The bd offsets allow us to fudge a little more since the
+ * borders are drawn after drawing the string.
+ */
+ if ((clipRectSet = ((originX < bd) || (originY < bd)
+ || (originX+itemW > width-bd)
+ || (originY+itemH > height-bd)))) {
+#ifdef _WIN32
+ /* We always draw in the upper-left corner of the clipWind */
+ Tk_Fill3DRectangle(tkwin, clipWind, tagPtr->bg, 0, 0,
+ width, height, bd, TK_RELIEF_FLAT);
+ Tk_DrawTextLayout(display, clipWind, tagGc, textLayout,
+ originX+bd, originY+bd, 0, -1);
+ XCopyArea(display, clipWind, window, tagGc, 0, 0,
+ width, height, x, y);
+#else
+ /* set the clipping rectangle */
+ clipRect.x = x;
+ clipRect.y = y;
+ clipRect.width = width;
+ clipRect.height = height;
+ XSetClipRectangles(display, tagGc, 0, 0, &clipRect, 1, Unsorted);
+#endif
+ }
+
+#ifdef _WIN32 /* no cliprect on windows */
+ if (!clipRectSet)
+#endif
+ Tk_DrawTextLayout(display, window, tagGc, textLayout,
+ x+originX+bd, y+originY+bd, 0, -1);
+
+#ifndef _WIN32 /* no cliprect on windows */
+ /* reset the clip mask */
+ if (clipRectSet) {
+ XSetClipMask(display, tagGc, None);
+ }
+#endif
+
+ /* if this is the active cell draw the cursor if it's on.
+ * this ignores clip rectangles. */
+ if (activeCell && (tablePtr->flags & CURSOR_ON) &&
+ (originY+bd+cy < height) &&
+ (originX+cx+bd-(tablePtr->insertWidth/2) >= 0)) {
+ /* make sure it will fit in the box */
+ maxW = MAX(0, originY+bd+cy);
+ maxH = MIN(ch, height-maxW);
+ Tk_Fill3DRectangle(tkwin, window, tablePtr->insertBg,
+ x+originX+cx+bd-(tablePtr->insertWidth/2),
+ y+maxW, tablePtr->insertWidth,
+ maxH, 0, TK_RELIEF_FLAT);
+ }
+ }
+
+ ImageUsed:
+ /* Draw the 3d border on the pixmap correctly offset */
+ if (tablePtr->borderWidth) {
+ switch (tablePtr->drawMode) {
+ case DRAW_MODE_SLOW:
+ case DRAW_MODE_TK_COMPAT:
+ Tk_Draw3DRectangle(tkwin, window, tagPtr->bg,
+ x, y, width, height, bd, tagPtr->relief);
+ break;
+ case DRAW_MODE_FAST:
+ /*
+ ** choose the GCs to get the best approximation
+ ** to the desired drawing style
+ */
+ switch(tagPtr->relief) {
+ case TK_RELIEF_FLAT:
+ topGc = bottomGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_FLAT_GC);
+ break;
+ case TK_RELIEF_RAISED:
+ case TK_RELIEF_RIDGE:
+ topGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_LIGHT_GC);
+ bottomGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_DARK_GC);
+ break;
+ default: /* TK_RELIEF_SUNKEN TK_RELIEF_GROOVE */
+ bottomGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_LIGHT_GC);
+ topGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_DARK_GC);
+ break;
+ }
+
+ /* draw a line with single pixel width */
+ rect[0].x = x + width - 1;
+ rect[0].y = y;
+ rect[1].y = height - 1;
+ rect[2].x = -width + 1;
+ XDrawLines(display, window, bottomGc, rect, 3, CoordModePrevious);
+ rect[0].x = x;
+ rect[0].y = y + height - 1;
+ rect[1].y = -height + 1;
+ rect[2].x = width - 1;
+ XDrawLines(display, window, topGc, rect, 3, CoordModePrevious);
+ break;
+ case DRAW_MODE_SINGLE:
+ topGc = Tk_3DBorderGC(tkwin, tagPtr->bg, TK_3D_DARK_GC);
+ /* draw a line with single pixel width */
+ rect[0].x = x;
+ rect[0].y = y + height - 1;
+ rect[1].y = -height + 1;
+ rect[2].x = width - 1;
+ XDrawLines(display, window, topGc, rect, 3, CoordModePrevious);
+ break;
+ }
+ }
+
+ /* delete the tag structure */
+ ckfree((char *) (tagPtr));
+ if (textLayout && !activeCell) {
+ Tk_FreeTextLayout(textLayout);
+ textLayout = NULL;
+ }
+ }
+ }
+#ifdef _WIN32
+ Tk_FreePixmap(display, clipWind);
+#endif
+
+ /* Take care of removing embedded windows that are no longer in view */
+ TableUndisplay(tablePtr);
+
+ /* copy over and delete the pixmap if we are in slow mode */
+ if (tablePtr->drawMode == DRAW_MODE_SLOW) {
+ /* Get a default valued GC */
+ TableGetGc(display, window, &(tablePtr->defaultTag), &tagGc);
+ XCopyArea(display, window, Tk_WindowId(tkwin), tagGc, 0, 0,
+ invalidWidth, invalidHeight, invalidX, invalidY);
+ Tk_FreePixmap(display, window);
+ window = Tk_WindowId(tkwin);
+ }
+
+ /*
+ * if we have got to the end of the table,
+ * clear the area after the last row/col
+ */
+ TableCellCoords(tablePtr, tablePtr->rows-1, tablePtr->cols-1,
+ &x, &y, &width, &height);
+
+ /* This should occur before moving pixmap, but this simplifies things
+ *
+ * Could use Tk_Fill3DRectangle instead of XFillRectangle
+ * for best compatibility, and XClearArea could be used on Unix
+ * for best speed, so this is the compromise w/o #ifdef's
+ */
+ if (x+width < invalidX+invalidWidth) {
+ XFillRectangle(display, window,
+ Tk_3DBorderGC(tkwin, tablePtr->defaultTag.bg,
+ TK_3D_FLAT_GC), x+width, invalidY,
+ invalidX+invalidWidth-x-width, invalidHeight);
+ }
+
+ if (y+height < invalidY+invalidHeight) {
+ XFillRectangle(display, window,
+ Tk_3DBorderGC(tkwin, tablePtr->defaultTag.bg,
+ TK_3D_FLAT_GC), invalidX, y+height,
+ invalidWidth, invalidY+invalidHeight-y-height);
+ }
+
+ if (tagGc != NULL) {
+ TableFreeGc(display, tagGc);
+ }
+ TableRedrawHighlight(tablePtr);
+ /*
+ * Free the hash table used to cache evaluations.
+ */
+ Tcl_DeleteHashTable(colTagsCache);
+ ckfree((char *) (colTagsCache));
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableInvalidate --
+ * Invalidates a rectangle and adds it to the total invalid rectangle
+ * waiting to be redrawn. If the INV_FORCE flag bit is set,
+ * it does an update instantly else waits until Tk is idle.
+ *
+ * Results:
+ * Will schedule table (re)display.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+void
+TableInvalidate(Table * tablePtr, int x, int y,
+ int width, int height, int flags)
+{
+ register int hl = tablePtr->highlightWidth;
+ register Tk_Window tkwin = tablePtr->tkwin;
+
+ /* make sure that the window hasn't been destroyed already */
+ /* avoid allocating 0 sized pixmaps which would be fatal */
+ /* and check if rectangle is even on the screen */
+ if ((tkwin == NULL) || (width <= 0) || (height <= 0)
+ || (x > Tk_Width(tkwin)) || (y > Tk_Height(tkwin))) return;
+
+ /* If not even mapped, wait for the remap to redraw all */
+ if (!Tk_IsMapped(tkwin)) {
+ tablePtr->flags |= REDRAW_ON_MAP;
+ return;
+ }
+
+ /* if no pending updates then replace the rectangle,
+ * otherwise find the bounding rectangle */
+ if ((flags & INV_HIGHLIGHT) &&
+ (x < hl || y < hl || x+width >= Tk_Width(tkwin)-hl ||
+ y+height >= Tk_Height(tkwin)-hl)) {
+ tablePtr->flags |= REDRAW_BORDER;
+ }
+
+ if (tablePtr->flags & REDRAW_PENDING) {
+ tablePtr->invalidWidth = MAX(tablePtr->invalidX+tablePtr->invalidWidth,
+ x + width);
+ tablePtr->invalidHeight = MAX(tablePtr->invalidY+tablePtr->invalidHeight,
+ y + height);
+ if (tablePtr->invalidX > x) tablePtr->invalidX = x;
+ if (tablePtr->invalidY > y) tablePtr->invalidY = y;
+ tablePtr->invalidWidth -= tablePtr->invalidX;
+ tablePtr->invalidHeight -= tablePtr->invalidY;
+ /* are we forcing this update out */
+ if (flags & INV_FORCE) {
+ Tcl_CancelIdleCall(TableDisplay, (ClientData) tablePtr);
+ TableDisplay((ClientData) tablePtr);
+ }
+ } else {
+ tablePtr->invalidX = x;
+ tablePtr->invalidY = y;
+ tablePtr->invalidWidth = width;
+ tablePtr->invalidHeight = height;
+ if (flags & INV_FORCE) {
+ TableDisplay((ClientData) tablePtr);
+ } else {
+ tablePtr->flags |= REDRAW_PENDING;
+ Tcl_DoWhenIdle(TableDisplay, (ClientData) tablePtr);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableFlashEvent --
+ * Called when the flash timer goes off.
+ *
+ * Results:
+ * Decrements all the entries in the hash table and invalidates
+ * any cells that expire, deleting them from the table. If the
+ * table is now empty, stops the timer, else reenables it.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableFlashEvent(ClientData clientdata)
+{
+ Table *tablePtr = (Table *) clientdata;
+ Tcl_HashEntry *entryPtr;
+ Tcl_HashSearch search;
+ int entries, count, row, col;
+
+ entries = 0;
+ for (entryPtr = Tcl_FirstHashEntry(tablePtr->flashCells, &search);
+ entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
+ count = (int) Tcl_GetHashValue(entryPtr);
+ if (--count <= 0) {
+ /* get the cell address and invalidate that region only */
+ TableParseArrayIndex(&row, &col,
+ Tcl_GetHashKey(tablePtr->flashCells, entryPtr));
+
+ /* delete the entry from the table */
+ Tcl_DeleteHashEntry(entryPtr);
+
+ TableRefresh(tablePtr, row-tablePtr->rowOffset,
+ col-tablePtr->colOffset, CELL|INV_FORCE);
+ } else {
+ Tcl_SetHashValue(entryPtr, (ClientData) count);
+ entries++;
+ }
+ }
+
+ /* do I need to restart the timer */
+ if (entries && tablePtr->flashMode)
+ tablePtr->flashTimer = Tcl_CreateTimerHandler(250, TableFlashEvent,
+ (ClientData) tablePtr);
+ else
+ tablePtr->flashTimer = 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableAddFlash --
+ * Adds a flash on cell row,col (real coords) with the default timeout
+ * if flashing is enabled and flashtime > 0.
+ *
+ * Results:
+ * Cell will flash.
+ *
+ * Side effects:
+ * Will start flash timer if it didn't exist.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableAddFlash(Table *tablePtr, int row, int col)
+{
+ char buf[INDEX_BUFSIZE];
+ int dummy;
+ Tcl_HashEntry *entryPtr;
+
+ if (!tablePtr->flashMode || tablePtr->flashTime < 1)
+ return;
+
+ /* create the array index in user coords */
+ TableMakeArrayIndex(row+tablePtr->rowOffset, col+tablePtr->colOffset, buf);
+
+ /* add the flash to the hash table */
+ entryPtr = Tcl_CreateHashEntry(tablePtr->flashCells, buf, &dummy);
+ Tcl_SetHashValue(entryPtr, tablePtr->flashTime);
+
+ /* now set the timer if it's not already going and invalidate the area */
+ if (tablePtr->flashTimer == NULL)
+ tablePtr->flashTimer = Tcl_CreateTimerHandler(250, TableFlashEvent,
+ (ClientData) tablePtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableSetActiveIndex --
+ * Sets the "active" index of the associated array to the current
+ * value of the active buffer.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Traces on the array can cause side effects.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableSetActiveIndex(register Table *tablePtr)
+{
+ if (tablePtr->arrayVar) {
+ tablePtr->flags |= SET_ACTIVE;
+ Tcl_SetVar2(tablePtr->interp, tablePtr->arrayVar, "active",
+ tablePtr->activeBuf, TCL_GLOBAL_ONLY);
+ tablePtr->flags &= ~SET_ACTIVE;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableGetActiveBuf --
+ * Get the current selection into the buffer and mark it as unedited.
+ * Set the position to the end of the string.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * tablePtr->activeBuf will change.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableGetActiveBuf(register Table *tablePtr)
+{
+ char *data = "";
+
+ if (tablePtr->flags & HAS_ACTIVE)
+ data = TableGetCellValue(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
+ tablePtr->activeCol+tablePtr->colOffset);
+
+ if (strcmp(tablePtr->activeBuf, data) == 0) {
+ /* this forced SetActiveIndex is necessary if we change array vars and
+ * they happen to have these cells equal, we won't properly set the
+ * active index for the new array var unless we do this here */
+ TableSetActiveIndex(tablePtr);
+ return;
+ }
+ /* is the buffer long enough */
+ tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, strlen(data)+1);
+ strcpy(tablePtr->activeBuf, data);
+ TableGetIcursor(tablePtr, "end", (int *)0);
+ tablePtr->flags &= ~TEXT_CHANGED;
+ TableSetActiveIndex(tablePtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableVarProc --
+ * This is the trace procedure associated with the Tcl array. No
+ * validation will occur here because this only triggers when the
+ * array value is directly set, and we can't maintain the old value.
+ *
+ * Results:
+ * Invalidates changed cell.
+ *
+ * Side effects:
+ * Creates/Updates entry in the cache if we are caching.
+ *
+ *----------------------------------------------------------------------
+ */
+static char *
+TableVarProc(clientData, interp, name, index, flags)
+ ClientData clientData; /* Information about table. */
+ Tcl_Interp *interp; /* Interpreter containing variable. */
+ char *name; /* Not used. */
+ char *index; /* Not used. */
+ int flags; /* Information about what happened. */
+{
+ Table *tablePtr = (Table *) clientData;
+ int dummy, row, col, update = 1;
+
+ /* This is redundant, as the name should always == arrayVar */
+ name = tablePtr->arrayVar;
+
+ /* is this the whole var being destroyed or just one cell being deleted */
+ if ((flags & TCL_TRACE_UNSETS) && index == NULL) {
+ /* if this isn't the interpreter being destroyed reinstate the trace */
+ if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
+ Tcl_SetVar2(interp, name, TEST_KEY, "", TCL_GLOBAL_ONLY);
+ Tcl_UnsetVar2(interp, name, TEST_KEY, TCL_GLOBAL_ONLY);
+ Tcl_ResetResult(interp);
+
+ /* set a trace on the variable */
+ Tcl_TraceVar(interp, name,
+ TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY,
+ (Tcl_VarTraceProc *)TableVarProc, (ClientData) tablePtr);
+
+ /* only do the following if arrayVar is our data source */
+ if (tablePtr->dataSource & DATA_ARRAY) {
+ /* clear the selection buffer */
+ TableGetActiveBuf(tablePtr);
+ /* flush any cache */
+ TableFlushCache(tablePtr);
+ /* and invalidate the table */
+ TableInvalidateAll(tablePtr, 0);
+ }
+ }
+ return (char *) NULL;
+ }
+ /* only continue if arrayVar is our data source */
+ if (!(tablePtr->dataSource & DATA_ARRAY)) {
+ return (char *) NULL;
+ }
+ /* get the cell address and invalidate that region only.
+ * Make sure that it is a valid cell address. */
+ if (strcmp("active", index) == 0) {
+ if (tablePtr->flags & SET_ACTIVE) {
+ /* If we are already setting the active cell, the update
+ * will occur in other code */
+ update = 0;
+ } else {
+ /* modified TableGetActiveBuf */
+ char *data = "";
+
+ row = tablePtr->activeRow;
+ col = tablePtr->activeCol;
+ if (tablePtr->flags & HAS_ACTIVE)
+ data = Tcl_GetVar2(interp, name, index, TCL_GLOBAL_ONLY);
+ if (!data) data = "";
+
+ if (strcmp(tablePtr->activeBuf, data) == 0) {
+ return (char *) NULL;
+ }
+ tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf,
+ strlen(data)+1);
+ strcpy(tablePtr->activeBuf, data);
+ /* set cursor to the last char */
+ TableGetIcursor(tablePtr, "end", (int *)0);
+ tablePtr->flags |= TEXT_CHANGED;
+ }
+ } else if (TableParseArrayIndex(&row, &col, index) == 2) {
+ char buf[INDEX_BUFSIZE];
+ /* Make sure it won't trigger on array(2,3extrastuff) */
+ TableMakeArrayIndex(row, col, buf);
+ if (strcmp(buf, index)) {
+ return (char *) NULL;
+ }
+ if (tablePtr->caching) {
+ Tcl_HashEntry *entryPtr;
+ char *val, *data = NULL;
+
+ data = Tcl_GetVar2(interp, name, index, TCL_GLOBAL_ONLY);
+ if (!data) data = "";
+ val = (char *)ckalloc(strlen(data)+1);
+ strcpy(val, data);
+ entryPtr = Tcl_CreateHashEntry(tablePtr->cache, buf, &dummy);
+ Tcl_SetHashValue(entryPtr, val);
+ }
+ /* convert index to real coords */
+ row -= tablePtr->rowOffset;
+ col -= tablePtr->colOffset;
+ /* did the active cell just update */
+ if (row == tablePtr->activeRow && col == tablePtr->activeCol)
+ TableGetActiveBuf(tablePtr);
+ /* Flash the cell */
+ TableAddFlash(tablePtr, row, col);
+ } else {
+ return (char *) NULL;
+ }
+
+ if (update) TableRefresh(tablePtr, row, col, CELL);
+
+ return (char *) NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableGeometryRequest --
+ * This procedure is invoked to request a new geometry from Tk.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Geometry information is updated and a new requested size is
+ * registered for the widget. Internal border info is also set.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableGeometryRequest(tablePtr)
+ register Table *tablePtr;
+{
+ int x, y;
+
+ /* Do the geometry request
+ * If -width #cols was not specified or it is greater than the real
+ * number of cols, use maxWidth as a lower bound, with the other lower
+ * bound being the upper bound of the window's user-set width and the
+ * value of -maxwidth set by the programmer
+ * Vice versa for rows/height
+ */
+ x = MIN((tablePtr->maxReqCols==0 || tablePtr->maxReqCols > tablePtr->cols) ?
+ tablePtr->maxWidth : tablePtr->colStarts[tablePtr->maxReqCols],
+ tablePtr->maxReqWidth) + 2*tablePtr->highlightWidth;
+ y = MIN((tablePtr->maxReqRows==0 || tablePtr->maxReqRows > tablePtr->rows) ?
+ tablePtr->maxHeight : tablePtr->rowStarts[tablePtr->maxReqRows],
+ tablePtr->maxReqHeight) + 2*tablePtr->highlightWidth;
+ Tk_GeometryRequest(tablePtr->tkwin, x, y);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableAdjustActive --
+ * This procedure is called by AdjustParams and CMD_ACTIVATE to
+ * move the active cell.
+ *
+ * Results:
+ * Old and new active cell indices will be invalidated.
+ *
+ * Side effects:
+ * If the old active cell index was edited, it will be saved.
+ * The active buffer will be updated.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableAdjustActive(tablePtr)
+ register Table *tablePtr; /* Widget record for table */
+{
+ if (tablePtr->flags & HAS_ACTIVE) {
+ /* make sure the active cell has a reasonable real index */
+ tablePtr->activeRow = MAX(0, MIN(tablePtr->activeRow, tablePtr->rows-1));
+ tablePtr->activeCol = MAX(0, MIN(tablePtr->activeCol, tablePtr->cols-1));
+ }
+
+ /*
+ * now check the new value of active cell against the original,
+ * If it changed, invalidate the area, else leave it alone
+ */
+ if (tablePtr->oldActRow != tablePtr->activeRow ||
+ tablePtr->oldActCol != tablePtr->activeCol) {
+ int x, y, width, height;
+ /* put the value back in the cell */
+ if (tablePtr->oldActRow >= 0 && tablePtr->oldActCol >= 0) {
+ /*
+ * Set the value of the old active cell to the active buffer
+ * SetCellValue will check if the value actually changed
+ */
+ if (tablePtr->flags & TEXT_CHANGED) {
+ /* WARNING an outside trace will be triggered here and if it
+ * calls something that causes TableAdjustParams to be called
+ * again, we are in data consistency trouble */
+ /* HACK - turn TEXT_CHANGED off now to possibly avoid the
+ * above data inconsistency problem. */
+ tablePtr->flags &= ~TEXT_CHANGED;
+ TableSetCellValue(tablePtr, tablePtr->oldActRow+tablePtr->rowOffset,
+ tablePtr->oldActCol+tablePtr->colOffset,
+ tablePtr->activeBuf);
+ }
+ /* invalidate the old active cell */
+ TableCellCoords(tablePtr, tablePtr->oldActRow, tablePtr->oldActCol,
+ &x, &y, &width, &height);
+ TableInvalidate(tablePtr, x, y, width, height, 0);
+ }
+
+ /* get the new value of the active cell into buffer */
+ TableGetActiveBuf(tablePtr);
+
+ /* invalidate the new active cell */
+ TableCellCoords(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
+ &x, &y, &width, &height);
+ TableInvalidate(tablePtr, x, y, width, height, 0);
+ /* set the old active row/col for the next time this function is called */
+ tablePtr->oldActRow = tablePtr->activeRow;
+ tablePtr->oldActCol = tablePtr->activeCol;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableAdjustParams --
+ * Calculate the row and column starts. Adjusts the topleft corner
+ * variable to keep it within the screen range, out of the titles
+ * and keep the screen full make sure the selected cell is in the
+ * visible area checks to see if the top left cell has changed at
+ * all and invalidates the table if it has.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Number of rows can change if -rowstretchmode == fill.
+ * topRow && leftCol can change to fit display.
+ * activeRow/Col can change to ensure it is a valid cell.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableAdjustParams(register Table *tablePtr)
+{
+ int topRow, leftCol, row, col, total, i, value, x, y, width, height;
+ int w, h, bd, hl, recalc = 0;
+ int diff, unpreset, lastUnpreset, pad, lastPad, numPixels;
+ int defColWidth, defRowHeight;
+ Tcl_HashEntry *entryPtr;
+
+ /* cache the borderwidth (doubled) for many upcoming calculations */
+ bd = 2*tablePtr->borderWidth;
+ hl = tablePtr->highlightWidth;
+ w = Tk_Width(tablePtr->tkwin)-2*hl;
+ h = Tk_Height(tablePtr->tkwin)-2*hl;
+
+ /* account for whether defColWidth is in chars (>=0) or pixels (<0) */
+ /* bd is added in here for convenience */
+ if (tablePtr->defColWidth > 0)
+ defColWidth = tablePtr->charWidth * tablePtr->defColWidth + bd;
+ else
+ defColWidth = -(tablePtr->defColWidth) + bd;
+ if (tablePtr->defRowHeight > 0)
+ defRowHeight = tablePtr->charHeight * tablePtr->defRowHeight + bd;
+ else
+ defRowHeight = -(tablePtr->defRowHeight) + bd;
+
+ /* Set up the arrays to hold the col pixels and starts */
+ if (tablePtr->colPixels) ckfree((char *) tablePtr->colPixels);
+ tablePtr->colPixels = (int *) ckalloc(tablePtr->cols * sizeof(int));
+ if (tablePtr->colStarts) ckfree((char *) tablePtr->colStarts);
+ tablePtr->colStarts = (int *) ckalloc((tablePtr->cols+1) * sizeof(int));
+
+ /* get all the preset columns and set their widths */
+ lastUnpreset = 0;
+ numPixels = 0;
+ unpreset = 0;
+ for (i = 0; i < tablePtr->cols; i++) {
+ if ((entryPtr = Tcl_FindHashEntry(tablePtr->colWidths,
+ (char *) i)) == NULL) {
+ tablePtr->colPixels[i] = -1;
+ unpreset++;
+ lastUnpreset = i;
+ } else {
+ value = (int) Tcl_GetHashValue(entryPtr);
+ if (value <= 0) {
+ tablePtr->colPixels[i] = -value + bd;
+ } else {
+ tablePtr->colPixels[i] = value * tablePtr->charWidth + bd;
+ }
+ numPixels += tablePtr->colPixels[i];
+ }
+ }
+
+ /* work out how much to pad each col depending on the mode */
+ diff = w-numPixels-(unpreset*defColWidth);
+ total = 0;
+ /* now do the padding and calculate the column starts */
+ /* diff lower than 0 means we can't see the entire set of columns,
+ * thus no special stretching will occur & we optimize the calculation */
+ if (diff <= 0) {
+ for (i = 0; i < tablePtr->cols; i++) {
+ if (tablePtr->colPixels[i] == -1)
+ tablePtr->colPixels[i] = defColWidth;
+ tablePtr->colStarts[i] = total;
+ total += tablePtr->colPixels[i];
+ }
+ } else {
+ switch(tablePtr->colStretch) {
+ case STRETCH_MODE_NONE:
+ pad = 0;
+ lastPad = 0;
+ break;
+ case STRETCH_MODE_UNSET:
+ if (unpreset == 0) {
+ pad = 0;
+ lastPad = 0;
+ } else {
+ pad = diff / unpreset;
+ lastPad = diff - pad * (unpreset - 1);
+ }
+ break;
+ case STRETCH_MODE_LAST:
+ pad = 0;
+ lastPad = diff;
+ lastUnpreset = tablePtr->cols - 1;
+ break;
+ default: /* STRETCH_MODE_ALL, but also FILL for cols */
+ pad = diff / tablePtr->cols;
+ /* force it to be applied to the last column too */
+ lastUnpreset = tablePtr->cols - 1;
+ lastPad = diff - pad * lastUnpreset;
+ }
+
+ for (i = 0; i < tablePtr->cols; i++) {
+ if (tablePtr->colPixels[i] == -1) {
+ tablePtr->colPixels[i] = defColWidth
+ + ((i==lastUnpreset)?lastPad:pad);
+ } else if (tablePtr->colStretch == STRETCH_MODE_ALL) {
+ tablePtr->colPixels[i] += (i==lastUnpreset)?lastPad:pad;
+ }
+ tablePtr->colStarts[i] = total;
+ total += tablePtr->colPixels[i];
+ }
+ }
+ tablePtr->colStarts[i] = tablePtr->maxWidth = total;
+
+ /*
+ * The 'do' loop is only necessary for rows because of FILL mode
+ */
+ do {
+ /* Set up the arrays to hold the row pixels and starts */
+ /* FIX - this can be moved outside 'do' if you check >row size */
+ if (tablePtr->rowPixels) ckfree((char *) tablePtr->rowPixels);
+ tablePtr->rowPixels = (int *) ckalloc(tablePtr->rows * sizeof(int));
+
+ /* get all the preset rows and set their heights */
+ lastUnpreset = 0;
+ numPixels = 0;
+ unpreset = 0;
+ for (i = 0; i < tablePtr->rows; i++) {
+ if ((entryPtr = Tcl_FindHashEntry(tablePtr->rowHeights,
+ (char *) i)) == NULL) {
+ tablePtr->rowPixels[i] = -1;
+ unpreset++;
+ lastUnpreset = i;
+ } else {
+ value = (int) Tcl_GetHashValue(entryPtr);
+ if (value <= 0) {
+ tablePtr->rowPixels[i] = -value + bd;
+ } else {
+ tablePtr->rowPixels[i] = value * tablePtr->charHeight + bd;
+ }
+ numPixels += tablePtr->rowPixels[i];
+ }
+ }
+
+ /* work out how much to pad each row depending on the mode */
+ diff = h-numPixels-(unpreset*defRowHeight);
+ switch(tablePtr->rowStretch) {
+ case STRETCH_MODE_NONE:
+ pad = 0;
+ lastPad = 0;
+ break;
+ case STRETCH_MODE_UNSET:
+ if (unpreset == 0) {
+ pad = 0;
+ lastPad = 0;
+ } else {
+ pad = MAX(0,diff) / unpreset;
+ lastPad = MAX(0,diff) - pad * (unpreset - 1);
+ }
+ break;
+ case STRETCH_MODE_LAST:
+ pad = 0;
+ lastPad = MAX(0,diff);
+ /* force it to be applied to the last column too */
+ lastUnpreset = tablePtr->rows - 1;
+ break;
+ case STRETCH_MODE_FILL:
+ pad = 0;
+ lastPad = diff;
+ if (diff && !recalc) {
+ tablePtr->rows += (diff/defRowHeight);
+ if (diff < 0 && tablePtr->rows < 0)
+ tablePtr->rows = 0;
+ lastUnpreset = tablePtr->rows - 1;
+ recalc = 1;
+ continue;
+ } else {
+ lastUnpreset = tablePtr->rows - 1;
+ recalc = 0;
+ }
+ break;
+ default: /* STRETCH_MODE_ALL */
+ pad = MAX(0,diff) / tablePtr->rows;
+ /* force it to be applied to the last column too */
+ lastUnpreset = tablePtr->rows - 1;
+ lastPad = MAX(0,diff) - pad * lastUnpreset;
+ }
+ } while (recalc);
+
+ if (tablePtr->rowStarts) ckfree((char *) tablePtr->rowStarts);
+ tablePtr->rowStarts = (int *) ckalloc((tablePtr->rows+1)*sizeof(int));
+ /* now do the padding and calculate the row starts */
+ total = 0;
+ for (i = 0; i < tablePtr->rows; i++) {
+ if (tablePtr->rowPixels[i] == -1) {
+ tablePtr->rowPixels[i] = defRowHeight
+ + ((i==lastUnpreset)?lastPad:pad);
+ } else if (tablePtr->rowStretch == STRETCH_MODE_ALL) {
+ tablePtr->rowPixels[i] += (i==lastUnpreset)?lastPad:pad;
+ }
+ /* calculate the start of each row */
+ tablePtr->rowStarts[i] = total;
+ total += tablePtr->rowPixels[i];
+ }
+ tablePtr->rowStarts[i] = tablePtr->maxHeight = total;
+
+ /* make sure the top row and col have reasonable real indices */
+ tablePtr->topRow = topRow =
+ MAX(tablePtr->titleRows, MIN(tablePtr->topRow, tablePtr->rows-1));
+ tablePtr->leftCol = leftCol =
+ MAX(tablePtr->titleCols, MIN(tablePtr->leftCol, tablePtr->cols-1));
+
+ /* If we dont have the info, dont bother to fix up the other parameters */
+ if (Tk_WindowId(tablePtr->tkwin) == None) {
+ tablePtr->oldTopRow = tablePtr->oldLeftCol = -1;
+ return;
+ }
+
+ w += hl;
+ h += hl;
+ /*
+ * If we use this value of topRow, will we fill the window?
+ * if not, decrease it until we will, or until it gets to titleRows
+ * make sure we don't cut off the bottom row
+ */
+ for (; topRow > tablePtr->titleRows; topRow--)
+ if ((tablePtr->maxHeight-(tablePtr->rowStarts[topRow-1] -
+ tablePtr->rowStarts[tablePtr->titleRows])) > h)
+ break;
+ /*
+ * If we use this value of topCol, will we fill the window?
+ * if not, decrease it until we will, or until it gets to titleCols
+ * make sure we don't cut off the left column
+ */
+ for (; leftCol > tablePtr->titleCols; leftCol--)
+ if ((tablePtr->maxWidth-(tablePtr->colStarts[leftCol-1] -
+ tablePtr->colStarts[tablePtr->titleCols])) > w)
+ break;
+
+ tablePtr->topRow = topRow;
+ tablePtr->leftCol = leftCol;
+
+ /* Now work out where the bottom right for scrollbar update
+ * and testing for one last stretch */
+ TableGetLastCell(tablePtr, &row, &col);
+ TableCellVCoords(tablePtr, row, col, &x, &y, &width, &height, 0);
+
+ /*
+ * Do we have scrollbars, if so, calculate and call the TCL functions In
+ * order to get the scrollbar to be completely full when the whole screen
+ * is shown and there are titles, we have to arrange for the scrollbar
+ * range to be 0 -> rows-titleRows etc. This leads to the position
+ * setting methods, toprow and leftcol, being relative to the titles, not
+ * absolute row and column numbers.
+ */
+ if (tablePtr->yScrollCmd != NULL || tablePtr->xScrollCmd != NULL) {
+ Tcl_Interp *interp = tablePtr->interp;
+ char buf[INDEX_BUFSIZE];
+ double first, last;
+
+ /*
+ * We must hold onto the interpreter because the data referred to at
+ * tablePtr might be freed as a result of the call to Tcl_VarEval.
+ */
+ Tcl_Preserve((ClientData) interp);
+
+ /* Do we have a Y-scrollbar and rows to scroll? */
+ if (tablePtr->yScrollCmd != NULL) {
+ if (row < tablePtr->titleRows) {
+ first = 0;
+ last = 1;
+ } else {
+ diff = tablePtr->rowStarts[tablePtr->titleRows];
+ last = (double) (tablePtr->rowStarts[tablePtr->rows]-diff);
+ first = (tablePtr->rowStarts[topRow]-diff) / last;
+ last = (height+tablePtr->rowStarts[row]-diff) / last;
+ }
+ sprintf(buf, " %g %g", first, last);
+ if (Tcl_VarEval(interp, tablePtr->yScrollCmd,
+ buf, (char *) NULL) != TCL_OK) {
+ Tcl_AddErrorInfo(interp,
+ "\n (vertical scrolling command executed by table)");
+ Tcl_BackgroundError(interp);
+ }
+ }
+ /* Do we have a X-scrollbar and cols to scroll? */
+ if (tablePtr->xScrollCmd != NULL) {
+ if (col < tablePtr->titleCols) {
+ first = 0;
+ last = 1;
+ } else {
+ diff = tablePtr->colStarts[tablePtr->titleCols];
+ last = (double) (tablePtr->colStarts[tablePtr->cols]-diff);
+ first = (tablePtr->colStarts[leftCol]-diff) / last;
+ last = (width+tablePtr->colStarts[col]-diff) / last;
+ }
+ sprintf(buf, " %g %g", first, last);
+ if (Tcl_VarEval(interp, tablePtr->xScrollCmd,
+ buf, (char *) NULL) != TCL_OK) {
+ Tcl_AddErrorInfo(interp,
+ "\n (horizontal scrolling command executed by table)");
+ Tcl_BackgroundError(interp);
+ }
+ }
+
+ Tcl_Release((ClientData) interp);
+ }
+
+ /* Adjust the last row/col to fill empty space if it is visible */
+ /* do this after setting the scrollbars to not upset its calculations */
+ if (row == tablePtr->rows-1 && tablePtr->rowStretch != STRETCH_MODE_NONE) {
+ diff = h-(y+height);
+ if (diff > 0) {
+ tablePtr->rowPixels[tablePtr->rows-1] += diff;
+ tablePtr->rowStarts[tablePtr->rows] += diff;
+ }
+ }
+ if (col == tablePtr->cols-1 && tablePtr->colStretch != STRETCH_MODE_NONE) {
+ diff = w-(x+width);
+ if (diff > 0) {
+ tablePtr->colPixels[tablePtr->cols-1] += diff;
+ tablePtr->colStarts[tablePtr->cols] += diff;
+ }
+ }
+
+ TableAdjustActive(tablePtr);
+
+ /*
+ * now check the new value of topleft cell against the originals,
+ * If they changed, invalidate the area, else leave it alone
+ */
+ if (tablePtr->topRow != tablePtr->oldTopRow ||
+ tablePtr->leftCol != tablePtr->oldLeftCol) {
+ /* set the old top row/col for the next time this function is called */
+ tablePtr->oldTopRow = tablePtr->topRow;
+ tablePtr->oldLeftCol = tablePtr->leftCol;
+ /* only the upper corner title cells wouldn't change */
+ TableInvalidateAll(tablePtr, 0);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableCursorEvent --
+ * Toggle the cursor status. Equivalent to EntryBlinkProc.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The cursor will be switched off/on.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableCursorEvent(ClientData clientData)
+{
+ register Table *tablePtr = (Table *) clientData;
+
+ if (!(tablePtr->flags & HAS_FOCUS) || (tablePtr->insertOffTime == 0)) {
+ return;
+ }
+
+ if (tablePtr->cursorTimer != NULL)
+ Tcl_DeleteTimerHandler(tablePtr->cursorTimer);
+
+ tablePtr->cursorTimer =
+ Tcl_CreateTimerHandler((tablePtr->flags & CURSOR_ON) ?
+ tablePtr->insertOffTime : tablePtr->insertOnTime,
+ TableCursorEvent, (ClientData) tablePtr);
+ /* Toggle the cursor */
+ tablePtr->flags ^= CURSOR_ON;
+
+ /* invalidate the cell */
+ TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
+ CELL|INV_FORCE);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableConfigCursor --
+ * Configures the timer depending on the state of the table.
+ * Equivalent to EntryFocusProc.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The cursor will be switched off/on.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableConfigCursor(register Table *tablePtr)
+{
+ /* to get a cursor, we have to have focus and allow edits */
+ if ((tablePtr->flags & HAS_FOCUS) && !(tablePtr->flags & ACTIVE_DISABLED) &&
+ (tablePtr->state == STATE_NORMAL)) {
+ /* turn the cursor on */
+ if (!(tablePtr->flags & CURSOR_ON)) {
+ tablePtr->flags |= CURSOR_ON;
+ }
+
+ /* set up the first timer */
+ if (tablePtr->insertOffTime != 0) {
+ /* make sure nothing existed */
+ Tcl_DeleteTimerHandler(tablePtr->cursorTimer);
+ tablePtr->cursorTimer = Tcl_CreateTimerHandler(tablePtr->insertOnTime,
+ TableCursorEvent,
+ (ClientData) tablePtr);
+ }
+
+ } else {
+ /* turn the cursor off */
+ if ((tablePtr->flags & CURSOR_ON)) {
+ tablePtr->flags &= ~CURSOR_ON;
+ }
+
+ /* and disable the timer */
+ if (tablePtr->cursorTimer != NULL)
+ Tcl_DeleteTimerHandler(tablePtr->cursorTimer);
+ tablePtr->cursorTimer = NULL;
+ }
+
+ /* Invalidate the selection window to show or hide the cursor */
+ TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
+ CELL|INV_FORCE);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableFetchSelection --
+ * This procedure is called back by Tk when the selection is
+ * requested by someone. It returns part or all of the selection
+ * in a buffer provided by the caller.
+ *
+ * Results:
+ * The return value is the number of non-NULL bytes stored
+ * at buffer. Buffer is filled (or partially filled) with a
+ * NULL-terminated string containing part or all of the selection,
+ * as given by offset and maxBytes.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+TableFetchSelection(clientData, offset, buffer, maxBytes)
+ ClientData clientData; /* Information about table widget. */
+ int offset; /* Offset within selection of first
+ * character to be returned. */
+ char *buffer; /* Location in which to place
+ * selection. */
+ int maxBytes; /* Maximum number of bytes to place
+ * at buffer, not including terminating
+ * NULL character. */
+{
+ register Table *tablePtr = (Table *) clientData;
+ Tcl_Interp *interp = tablePtr->interp;
+ char *value, *data, *rowsep = tablePtr->rowSep, *colsep = tablePtr->colSep;
+ Tcl_DString selection;
+ Tcl_HashEntry *entryPtr;
+ Tcl_HashSearch search;
+ int length, count, lastrow=0, needcs=0, r, c, listArgc, rslen=0, cslen=0;
+ int numcols, numrows;
+ char **listArgv;
+
+ /* if we are not exporting the selection || we have no data source, return */
+ if (!tablePtr->exportSelection ||
+ (tablePtr->dataSource == DATA_NONE)) {
+ return -1;
+ }
+
+ /* First get a sorted list of the selected elements */
+ Tcl_DStringInit(&selection);
+ for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search);
+ entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
+ Tcl_DStringAppendElement(&selection,
+ Tcl_GetHashKey(tablePtr->selCells, entryPtr));
+ }
+ value = TableCellSort(tablePtr, Tcl_DStringValue(&selection));
+ Tcl_DStringFree(&selection);
+
+ if (value == NULL ||
+ Tcl_SplitList(interp, value, &listArgc, &listArgv) != TCL_OK) {
+ return -1;
+ }
+ ckfree(value);
+
+ Tcl_DStringInit(&selection);
+ rslen = (rowsep?(strlen(rowsep)):0);
+ cslen = (colsep?(strlen(colsep)):0);
+ numrows = numcols = 0;
+ for (count = 0; count < listArgc; count++) {
+ TableParseArrayIndex(&r, &c, listArgv[count]);
+ if (count) {
+ if (lastrow != r) {
+ lastrow = r;
+ needcs = 0;
+ if (rslen) {
+ Tcl_DStringAppend(&selection, rowsep, rslen);
+ } else {
+ Tcl_DStringEndSublist(&selection);
+ Tcl_DStringStartSublist(&selection);
+ }
+ ++numrows;
+ } else {
+ if (++needcs > numcols)
+ numcols = needcs;
+ }
+ } else {
+ lastrow = r;
+ needcs = 0;
+ if (!rslen)
+ Tcl_DStringStartSublist(&selection);
+ }
+ data = TableGetCellValue(tablePtr, r, c);
+ if (cslen) {
+ if (needcs)
+ Tcl_DStringAppend(&selection, colsep, cslen);
+ Tcl_DStringAppend(&selection, data, -1);
+ } else {
+ Tcl_DStringAppendElement(&selection, data);
+ }
+ }
+ if (!rslen && count)
+ Tcl_DStringEndSublist(&selection);
+ ckfree((char *) listArgv);
+
+ if (tablePtr->selCmd != NULL) {
+ Tcl_DString script;
+ Tcl_DStringInit(&script);
+ ExpandPercents(tablePtr, tablePtr->selCmd, numrows+1, numcols+1,
+ Tcl_DStringValue(&selection), (char *) NULL,
+ listArgc, &script, CMD_ACTIVATE);
+ if (Tcl_GlobalEval(interp, Tcl_DStringValue(&script)) == TCL_ERROR) {
+ Tcl_AddErrorInfo(interp,
+ "\n (error in table selection command)");
+ Tcl_BackgroundError(interp);
+ Tcl_DStringFree(&script);
+ Tcl_DStringFree(&selection);
+ return -1;
+ } else {
+ Tcl_DStringGetResult(interp, &selection);
+ }
+ Tcl_DStringFree(&script);
+ }
+
+ length = Tcl_DStringLength(&selection);
+
+ if (length == 0)
+ return -1;
+
+ /* Copy the requested portion of the selection to the buffer. */
+ count = length - offset;
+ if (count <= 0) {
+ count = 0;
+ } else {
+ if (count > maxBytes) {
+ count = maxBytes;
+ }
+ memcpy((VOID *) buffer, (VOID *) (Tcl_DStringValue(&selection) + offset),
+ (size_t) count);
+ }
+ buffer[count] = '\0';
+ Tcl_DStringFree(&selection);
+ return count;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableLostSelection --
+ * This procedure is called back by Tk when the selection is
+ * grabbed away from a table widget.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The existing selection is unhighlighted, and the window is
+ * marked as not containing a selection.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableLostSelection(clientData)
+ ClientData clientData; /* Information about table widget. */
+{
+ register Table *tablePtr = (Table *) clientData;
+
+ if (tablePtr->exportSelection) {
+ Tcl_HashEntry *entryPtr;
+ Tcl_HashSearch search;
+ int row, col;
+
+ /* Same as SEL CLEAR ALL */
+ for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search);
+ entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
+ TableParseArrayIndex(&row, &col,
+ Tcl_GetHashKey(tablePtr->selCells,entryPtr));
+ Tcl_DeleteHashEntry(entryPtr);
+ TableRefresh(tablePtr, row-tablePtr->rowOffset,
+ col-tablePtr->colOffset, CELL);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableRestrictProc --
+ * A Tk_RestrictProc used by TableValidateChange to eliminate any
+ * extra key input events in the event queue that
+ * have a serial number no less than a given value.
+ *
+ * Results:
+ * Returns either TK_DISCARD_EVENT or TK_DEFER_EVENT.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+static Tk_RestrictAction
+TableRestrictProc(serial, eventPtr)
+ ClientData serial;
+ XEvent *eventPtr;
+{
+ if ((eventPtr->type == KeyRelease || eventPtr->type == KeyPress) &&
+ ((eventPtr->xany.serial-(unsigned int)serial) > 0)) {
+ return TK_DEFER_EVENT;
+ } else {
+ return TK_PROCESS_EVENT;
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TableValidateChange --
+ * This procedure is invoked when any character is added or
+ * removed from the table widget, or a set has triggered validation.
+ *
+ * Results:
+ * TCL_OK if the validatecommand accepts the new string,
+ * TCL_BREAK if the validatecommand rejects the new string,
+ * TCL_ERROR if any problems occured with validatecommand.
+ *
+ * Side effects:
+ * The insertion/deletion may be aborted, and the
+ * validatecommand might turn itself off (if an error
+ * or loop condition arises).
+ *
+ *--------------------------------------------------------------
+ */
+static int
+TableValidateChange(tablePtr, r, c, old, new, index)
+ register Table *tablePtr; /* Table that needs validation. */
+ int r, c; /* row,col index of cell in user coords */
+ char *old; /* current value of cell */
+ char *new; /* potential new value of cell */
+ int index; /* index of insert/delete, -1 otherwise */
+{
+ register Tcl_Interp *interp = tablePtr->interp;
+ int code, bool;
+ Tk_RestrictProc *restrict;
+ ClientData cdata;
+ Tcl_DString script;
+
+ if (tablePtr->valCmd == NULL || tablePtr->validate == 0) {
+ return TCL_OK;
+ }
+
+ /* Magic code to make this bit of code synchronous in the face of
+ * possible new key events */
+ XSync(tablePtr->display, False);
+ restrict = Tk_RestrictEvents(TableRestrictProc, (ClientData)
+ NextRequest(tablePtr->display), &cdata);
+
+ /*
+ * If we're already validating, then we're hitting a loop condition
+ * Return and set validate to 0 to disallow further validations
+ * and prevent current validation from finishing
+ */
+ if (tablePtr->flags & VALIDATING) {
+ tablePtr->validate = 0;
+ return TCL_OK;
+ }
+ tablePtr->flags |= VALIDATING;
+
+ /* Now form command string and run through the -validatecommand */
+ Tcl_DStringInit(&script);
+ ExpandPercents(tablePtr, tablePtr->valCmd, r, c, old, new, index, &script,
+ CMD_VALIDATE);
+ code = Tcl_GlobalEval(tablePtr->interp, Tcl_DStringValue(&script));
+ Tcl_DStringFree(&script);
+
+ if (code != TCL_OK && code != TCL_RETURN) {
+ Tcl_AddErrorInfo(interp, "\n\t(in validation command executed by table)");
+ Tk_BackgroundError(interp);
+ code = TCL_ERROR;
+ } else if (Tcl_GetBoolean(interp, Tcl_GetStringResult(interp),
+ &bool) != TCL_OK) {
+ Tcl_AddErrorInfo(interp, "\n\tboolean not returned by validation command");
+ Tk_BackgroundError(interp);
+ code = TCL_ERROR;
+ } else {
+ if (bool)
+ code = TCL_OK;
+ else
+ code = TCL_BREAK;
+ }
+ Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
+
+ /*
+ * If ->validate has become VALIDATE_NONE during the validation,
+ * it means that a loop condition almost occured. Do not allow
+ * this validation result to finish.
+ */
+ if (tablePtr->validate == 0) {
+ code = TCL_ERROR;
+ }
+
+ /* If validate will return ERROR, then disallow further validations */
+ if (code == TCL_ERROR) {
+ tablePtr->validate = 0;
+ }
+
+ Tk_RestrictEvents(restrict, cdata, &cdata);
+ tablePtr->flags &= ~VALIDATING;
+
+ return code;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ExpandPercents --
+ * Given a command and an event, produce a new command
+ * by replacing % constructs in the original command
+ * with information from the X event.
+ *
+ * Results:
+ * The new expanded command is appended to the dynamic string
+ * given by dsPtr.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+void
+ExpandPercents(tablePtr, before, r, c, old, new, index, dsPtr, cmdType)
+ Table *tablePtr; /* Table that needs validation. */
+ char *before; /* Command containing percent
+ * expressions to be replaced. */
+ int r, c; /* row,col index of cell */
+ char *old; /* current value of cell */
+ char *new; /* potential new value of cell */
+ int index; /* index of insert/delete */
+ Tcl_DString *dsPtr; /* Dynamic string in which to append
+ * new command. */
+ int cmdType; /* type of command to make %-subs for */
+{
+ int spaceNeeded, cvtFlags; /* Used to substitute string as proper Tcl
+ * list element. */
+ int number, length;
+ char *string;
+ char buf[INDEX_BUFSIZE];
+
+ /* This returns the static value of the string as set in the array */
+ if (old == NULL && cmdType == CMD_VALIDATE) {
+ old = TableGetCellValue(tablePtr, r, c);
+ }
+
+ while (1) {
+ /*
+ * Find everything up to the next % character and append it
+ * to the result string.
+ */
+ for (string = before; (*string != 0) && (*string != '%'); string++) {
+ /* Empty loop body. */
+ }
+ if (string != before) {
+ Tcl_DStringAppend(dsPtr, before, string-before);
+ before = string;
+ }
+ if (*before == 0) break;
+
+ /* There's a percent sequence here. Process it. */
+ number = 0;
+ string = "??";
+ /* cmdType independent substitutions */
+ switch (before[1]) {
+ case 'c':
+ number = c;
+ goto doNumber;
+ case 'C': /* index of cell */
+ TableMakeArrayIndex(r, c, buf);
+ string = buf;
+ goto doString;
+ case 'r':
+ number = r;
+ goto doNumber;
+ case 'i': /* index of cursor OR |number| of cells selected */
+ number = index;
+ goto doNumber;
+ case 's': /* Current cell value */
+ string = old;
+ goto doString;
+ case 'S': /* Potential new value of cell */
+ string = (new?new:old);
+ goto doString;
+ case 'W': /* widget name */
+ string = Tk_PathName(tablePtr->tkwin);
+ goto doString;
+ default:
+ buf[0] = before[1];
+ buf[1] = '\0';
+ string = buf;
+ goto doString;
+ }
+
+ doNumber:
+ sprintf(buf, "%d", number);
+ string = buf;
+
+ doString:
+ spaceNeeded = Tcl_ScanElement(string, &cvtFlags);
+ length = Tcl_DStringLength(dsPtr);
+ Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
+ spaceNeeded = Tcl_ConvertElement(string, Tcl_DStringValue(dsPtr) + length,
+ cvtFlags | TCL_DONT_USE_BRACES);
+ Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
+ before += 2;
+ }
+ Tcl_DStringAppend(dsPtr, "", 1);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableDeleteChars --
+ * Remove one or more characters from an table widget.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Memory gets freed, the table gets modified and (eventually)
+ * redisplayed.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableDeleteChars(tablePtr, index, count)
+ register Table *tablePtr; /* Table widget to modify. */
+ int index; /* Index of first character to delete. */
+ int count; /* How many characters to delete. */
+{
+ int x, y, width, height;
+#if (TK_MINOR_VERSION > 0)
+ int byteIndex, byteCount, newByteCount, numBytes, numChars;
+ char *new, *string;
+
+ string = tablePtr->activeBuf;
+ numBytes = strlen(string);
+ numChars = Tcl_NumUtfChars(string, numBytes);
+ if ((index + count) > numChars) {
+ count = numChars - index;
+ }
+ if (count <= 0) {
+ return;
+ }
+
+ byteIndex = Tcl_UtfAtIndex(string, index) - string;
+ byteCount = Tcl_UtfAtIndex(string + byteIndex, count) - (string + byteIndex);
+
+ newByteCount = numBytes + 1 - byteCount;
+ new = (char *) ckalloc((unsigned) newByteCount);
+ memcpy(new, string, (size_t) byteIndex);
+ strcpy(new + byteIndex, string + byteIndex + byteCount);
+#else
+ int oldlen;
+ char *new;
+
+ /* this gets the length of the string, as well as ensuring that
+ * the cursor isn't beyond the end char */
+ TableGetIcursor(tablePtr, "end", &oldlen);
+
+ if ((index+count) > oldlen)
+ count = oldlen-index;
+ if (count <= 0)
+ return;
+
+ new = (char *) ckalloc((unsigned)(oldlen-count+1));
+ strncpy(new, tablePtr->activeBuf, (size_t) index);
+ strcpy(new+index, tablePtr->activeBuf+index+count);
+ /* make sure this string is null terminated */
+ new[oldlen-count] = '\0';
+#endif
+ /* This prevents deletes on BREAK or validation error. */
+ if (tablePtr->validate &&
+ TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
+ tablePtr->activeCol+tablePtr->colOffset,
+ tablePtr->activeBuf, new, index) != TCL_OK) {
+ ckfree(new);
+ return;
+ }
+
+ ckfree(tablePtr->activeBuf);
+ tablePtr->activeBuf = new;
+
+ /* mark the text as changed */
+ tablePtr->flags |= TEXT_CHANGED;
+
+ if (tablePtr->icursor >= index) {
+ if (tablePtr->icursor >= (index+count)) {
+ tablePtr->icursor -= count;
+ } else {
+ tablePtr->icursor = index;
+ }
+ }
+
+ TableSetActiveIndex(tablePtr);
+
+ TableCellCoords(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
+ &x, &y, &width, &height);
+ TableInvalidate(tablePtr, x, y, width, height, INV_FORCE);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableInsertChars --
+ * Add new characters to the active cell of a table widget.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * New information gets added to tablePtr; it will be redisplayed
+ * soon, but not necessarily immediately.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableInsertChars(tablePtr, index, value)
+ register Table *tablePtr; /* Table that is to get the new elements. */
+ int index; /* Add the new elements before this element. */
+ char *value; /* New characters to add (NULL-terminated
+ * string). */
+{
+#if (TK_MINOR_VERSION > 0)
+ int x, y, width, height, oldlen;
+ int byteIndex, byteCount;
+ char *new, *string;
+
+ string = tablePtr->activeBuf;
+ byteIndex = Tcl_UtfAtIndex(string, index) - string;
+ byteCount = strlen(value);
+ if (byteCount == 0) {
+ return;
+ }
+
+ /* Is this an autoclear and this is the first update */
+ /* Note that this clears without validating */
+ if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) {
+ /* set the buffer to be empty */
+ tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1);
+ tablePtr->activeBuf[0] = '\0';
+ /* the insert position now has to be 0 */
+ index = 0;
+ }
+
+ oldlen = strlen(string);
+ new = (char *) ckalloc((unsigned)(oldlen + byteCount + 1));
+ memcpy(new, string, (size_t) byteIndex);
+ strcpy(new + byteIndex, value);
+ strcpy(new + byteIndex + byteCount, string + byteIndex);
+
+ /* validate potential new active buffer */
+ /* This prevents inserts on either BREAK or validation error. */
+ if (tablePtr->validate &&
+ TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
+ tablePtr->activeCol+tablePtr->colOffset,
+ tablePtr->activeBuf, new, byteIndex) != TCL_OK) {
+ ckfree(new);
+ return;
+ }
+
+ /*
+ * The following construction is used because inserting improperly
+ * formed UTF-8 sequences between other improperly formed UTF-8
+ * sequences could result in actually forming valid UTF-8 sequences;
+ * the number of characters added may not be Tcl_NumUtfChars(string, -1),
+ * because of context. The actual number of characters added is how
+ * many characters were are in the string now minus the number that
+ * used to be there.
+ */
+
+ if (tablePtr->icursor >= index) {
+ tablePtr->icursor += Tcl_NumUtfChars(new, oldlen+byteCount)
+ - Tcl_NumUtfChars(tablePtr->activeBuf, oldlen);
+ }
+
+ ckfree(string);
+ tablePtr->activeBuf = new;
+
+#else
+ int x, y, width, height, oldlen, newlen;
+ char *new;
+
+ newlen = strlen(value);
+ if (newlen == 0) return;
+
+ /* Is this an autoclear and this is the first update */
+ /* Note that this clears without validating */
+ if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) {
+ /* set the buffer to be empty */
+ tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1);
+ tablePtr->activeBuf[0] = '\0';
+ /* the insert position now has to be 0 */
+ index = 0;
+ }
+ oldlen = strlen(tablePtr->activeBuf);
+ /* get the buffer to at least the right length */
+ new = (char *) ckalloc((unsigned)(oldlen+newlen+1));
+ strncpy(new, tablePtr->activeBuf, (size_t) index);
+ strcpy(new+index, value);
+ strcpy(new+index+newlen, (tablePtr->activeBuf)+index);
+ /* make sure this string is null terminated */
+ new[oldlen+newlen] = '\0';
+
+ /* validate potential new active buffer */
+ /* This prevents inserts on either BREAK or validation error. */
+ if (tablePtr->validate &&
+ TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
+ tablePtr->activeCol+tablePtr->colOffset,
+ tablePtr->activeBuf, new, index) != TCL_OK) {
+ ckfree(new);
+ return;
+ }
+ ckfree(tablePtr->activeBuf);
+ tablePtr->activeBuf = new;
+
+ if (tablePtr->icursor >= index) {
+ tablePtr->icursor += newlen;
+ }
+#endif
+
+ /* mark the text as changed */
+ tablePtr->flags |= TEXT_CHANGED;
+
+ TableSetActiveIndex(tablePtr);
+
+ TableCellCoords(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
+ &x, &y, &width, &height);
+ TableInvalidate(tablePtr, x, y, width, height, INV_FORCE);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableModifyRCaux --
+ * Helper function that does the core work of moving rows/cols
+ * and associated tags.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Moves cell data and possibly tag data
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableModifyRCaux(tablePtr, type, which, movetag, tagTblPtr, dimTblPtr,
+ offset, from, to, lo, hi, check)
+ Table *tablePtr; /* Information about text widget. */
+ int type; /* insert (CMD_INSERT) | delete (CMD_DELETE) */
+ int which; /* rows (MOD_ROWS) or cols (MOD_COLS) */
+ int movetag; /* whether tags are supposed to be moved */
+ Tcl_HashTable *tagTblPtr, *dimTblPtr; /* Pointers to the row/col tags
+ * and width/height tags */
+ int offset; /* appropriate offset */
+ int from, to; /* the from and to row/col */
+ int lo, hi; /* the lo and hi col/row */
+ int check; /* the boundary check for shifting items */
+{
+ int j, dummy;
+ char buf[INDEX_BUFSIZE], buf1[INDEX_BUFSIZE];
+ Tcl_HashEntry *entryPtr, *newPtr;
+
+ /* move row/col style && width/height here */
+ if (movetag) {
+ if ((entryPtr=Tcl_FindHashEntry(tagTblPtr, (char *)from)) != NULL) {
+ Tcl_DeleteHashEntry(entryPtr);
+ }
+ if ((entryPtr=Tcl_FindHashEntry(dimTblPtr, (char *)from-offset)) != NULL) {
+ Tcl_DeleteHashEntry(entryPtr);
+ }
+ if (!check) {
+ if ((entryPtr=Tcl_FindHashEntry(tagTblPtr, (char *)to)) != NULL) {
+ newPtr = Tcl_CreateHashEntry(tagTblPtr, (char *)from, &dummy);
+ Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
+ Tcl_DeleteHashEntry(entryPtr);
+ }
+ if ((entryPtr=Tcl_FindHashEntry(dimTblPtr, (char *)to-offset)) != NULL) {
+ newPtr = Tcl_CreateHashEntry(dimTblPtr, (char *)from-offset, &dummy);
+ Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
+ Tcl_DeleteHashEntry(entryPtr);
+ }
+ }
+ }
+ for (j = lo; j <= hi; j++) {
+ if (which == MOD_COLS) {
+ TableMakeArrayIndex(j, from, buf);
+ TableMakeArrayIndex(j, to, buf1);
+ TableSetCellValue(tablePtr, j, from, check ? "" :
+ TableGetCellValue(tablePtr, j, to));
+ } else {
+ TableMakeArrayIndex(from, j, buf);
+ TableMakeArrayIndex(to, j, buf1);
+ TableSetCellValue(tablePtr, from, j, check ? "" :
+ TableGetCellValue(tablePtr, to, j));
+ }
+ /* move cell style here */
+ if (movetag) {
+ if ((entryPtr=Tcl_FindHashEntry(tablePtr->cellStyles,buf)) != NULL) {
+ Tcl_DeleteHashEntry(entryPtr);
+ }
+ if (!check &&
+ (entryPtr=Tcl_FindHashEntry(tablePtr->cellStyles,buf1))!=NULL) {
+ newPtr = Tcl_CreateHashEntry(tablePtr->cellStyles, buf, &dummy);
+ Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
+ Tcl_DeleteHashEntry(entryPtr);
+ }
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableModifyRC --
+ * Modify rows/cols of the table (insert or delete)
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Modifies associated row/col data
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+TableModifyRC(tablePtr, interp, type, which, argc, argv)
+ Table *tablePtr; /* Information about text widget. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int type; /* insert (CMD_INSERT) | delete (CMD_DELETE) */
+ int which; /* rows (MOD_ROWS) or cols (MOD_COLS) */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int i, first, lo, hi, idx, c, argsLeft, x, y, offset;
+ int maxrow, maxcol, maxkey, minkey, movetitle, movetag, movedim;
+ size_t length;
+ char *arg;
+ Tcl_HashTable *tagTblPtr, *dimTblPtr;
+ Tcl_HashSearch search;
+ int *dimPtr;
+
+ movetitle = 1;
+ movetag = 1;
+ movedim = 1;
+ maxcol = tablePtr->cols-1+tablePtr->colOffset;
+ maxrow = tablePtr->rows-1+tablePtr->rowOffset;
+ for (i = 3; i < argc; i++) {
+ arg = argv[i];
+ if (arg[0] != '-') {
+ break;
+ }
+ length = strlen(arg);
+ if (length < 2) {
+ badSwitch:
+ Tcl_AppendResult(interp, "bad switch \"", arg,
+ "\": must be -cols, -keeptitles, -holddimensions, ",
+ "-holdtags, -rows, or --",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ c = arg[1];
+ if ((c == 'h') && (length > 5) &&
+ (strncmp(argv[i], "-holddimensions", length) == 0)) {
+ movedim = 0;
+ } else if ((c == 'h') && (length > 5) &&
+ (strncmp(argv[i], "-holdtags", length) == 0)) {
+ movetag = 0;
+ } else if ((c == 'k') && (strncmp(argv[i], "-keeptitles", length) == 0)) {
+ movetitle = 0;
+ } else if ((c == 'c') && (strncmp(argv[i], "-cols", length) == 0)) {
+ if (i >= (argc-1)) {
+ Tcl_SetResult(interp, "no value given for \"-cols\" option",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[++i], &maxcol) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ maxcol = MAX(maxcol, tablePtr->titleCols+tablePtr->colOffset);
+ } else if ((c == 'r') && (strncmp(argv[i], "-rows", length) == 0)) {
+ if (i >= (argc-1)) {
+ Tcl_SetResult(interp, "no value given for \"-rows\" option",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[++i], &maxrow) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ maxrow = MAX(maxrow, tablePtr->titleRows+tablePtr->rowOffset);
+ } else if ((c == '-') && (strncmp(argv[i], "--", length) == 0)) {
+ i++;
+ break;
+ } else {
+ goto badSwitch;
+ }
+ }
+ argsLeft = argc - i;
+ if (argsLeft != 1 && argsLeft != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ (type == CMD_DELETE) ? " delete" : " insert",
+ (which == MOD_COLS) ? " cols" : " rows",
+ " ?switches? index ?count?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ c = 1;
+ if (strcmp(argv[i], "end") == 0) {
+ /* allow "end" to be specified as an index */
+ idx = (which == MOD_COLS) ? maxcol : maxrow;
+ } else if (Tcl_GetInt(interp, argv[i], &idx) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (argsLeft == 2 && Tcl_GetInt(interp, argv[++i], &c) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (tablePtr->state == STATE_DISABLED || c == 0)
+ return TCL_OK;
+
+ if (which == MOD_COLS) {
+ maxkey = maxcol;
+ minkey = tablePtr->colOffset+tablePtr->titleCols;
+ lo = tablePtr->rowOffset+(movetitle?0:tablePtr->titleRows);
+ hi = maxrow;
+ offset = tablePtr->colOffset;
+ tagTblPtr = tablePtr->colStyles;
+ dimTblPtr = tablePtr->colWidths;
+ dimPtr = &(tablePtr->cols);
+ } else {
+ maxkey = maxrow;
+ minkey = tablePtr->rowOffset+tablePtr->titleRows;
+ lo = tablePtr->colOffset+(movetitle?0:tablePtr->titleCols);
+ hi = maxcol;
+ offset = tablePtr->rowOffset;
+ tagTblPtr = tablePtr->rowStyles;
+ dimTblPtr = tablePtr->rowHeights;
+ dimPtr = &(tablePtr->rows);
+ }
+
+ if (type == CMD_DELETE) {
+ /* Handle row/col deletion */
+ first = MAX(MIN(idx,idx+c), minkey);
+ /* (index = i && count = 1) == (index = i && count = -1) */
+ if (c < 0) {
+ /* if the count is negative, make sure that the col count will delete
+ * no greater than the original index */
+ c = idx-first;
+ first++;
+ }
+ if (movedim) {
+ *dimPtr -= c;
+ }
+ for (i = first; i <= maxkey; i++) {
+ TableModifyRCaux(tablePtr, type, which, movetag, tagTblPtr,
+ dimTblPtr, offset, i, i+c, lo, hi, ((i+c)>maxkey));
+ }
+ } else {
+ /* Handle row/col insertion */
+ first = MAX(MIN(idx, maxkey), minkey);
+ /* +count means insert after index, -count means insert before index */
+ if (c < 0) {
+ c = -c;
+ } else {
+ first++;
+ }
+ if (movedim) {
+ maxkey += c;
+ *dimPtr += c;
+ }
+ for (i = maxkey; i >= first; i--) {
+ /* move row/col style && width/height here */
+ TableModifyRCaux(tablePtr, type, which, movetag, tagTblPtr,
+ dimTblPtr, offset, i, i-c, lo, hi, ((i-c)selCells, &search) != NULL) {
+ /* clear selection - forceful, but effective */
+ Tcl_DeleteHashTable(tablePtr->selCells);
+ ckfree((char *) (tablePtr->selCells));
+ tablePtr->selCells = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS);
+ }
+
+ TableAdjustParams(tablePtr);
+ if (which == MOD_COLS) {
+ TableCellCoords(tablePtr, 0, first, &x, &y, &offset, &offset);
+ TableInvalidate(tablePtr, x, y,
+ Tk_Width(tablePtr->tkwin)-x,
+ Tk_Height(tablePtr->tkwin), 0);
+ } else {
+ TableCellCoords(tablePtr, first, 0, &x, &y, &offset, &offset);
+ TableInvalidate(tablePtr, x, y,
+ Tk_Width(tablePtr->tkwin),
+ Tk_Height(tablePtr->tkwin)-y, 0);
+ }
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TableWidgetCmd --
+ * This procedure is invoked to process the Tcl command
+ * that corresponds to a widget managed by this module.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *--------------------------------------------------------------
+ */
+static int
+TableWidgetCmd(clientData, interp, argc, argv)
+ ClientData clientData; /* Information about listbox widget. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ Tcl_HashEntry *entryPtr;
+ Tcl_HashSearch search;
+ Tcl_HashTable *hashTablePtr;
+ int result, retval, sub_retval, row, col, x, y;
+ int i, width, height, dummy, key, value, posn, offset;
+ char buf1[INDEX_BUFSIZE], buf2[INDEX_BUFSIZE];
+
+ Table *tablePtr = (Table *) clientData;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " option ?arg arg ...?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ Tcl_Preserve(clientData);
+
+ result = TCL_OK;
+ /* parse the first parameter */
+ retval = Cmd_Parse(interp, main_cmds, argv[1]);
+
+ /* Switch on the parameter value */
+ switch (retval) {
+ case 0:
+ /* error, the return string is already set up */
+ result = TCL_ERROR;
+ break;
+
+ case CMD_ACTIVATE:
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " activate index\"", (char *)NULL);
+ result = TCL_ERROR;
+ } else if (TableGetIndex(tablePtr, argv[2], &row, &col) == TCL_ERROR) {
+ result = TCL_ERROR;
+ } else {
+ /* convert to valid active index in real coords */
+ row -= tablePtr->rowOffset;
+ col -= tablePtr->colOffset;
+ /* we do this regardless, to avoid cell commit problems */
+ if ((tablePtr->flags & HAS_ACTIVE) &&
+ (tablePtr->flags & TEXT_CHANGED)) {
+ tablePtr->flags &= ~TEXT_CHANGED;
+ TableSetCellValue(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
+ tablePtr->activeCol+tablePtr->colOffset,
+ tablePtr->activeBuf);
+ }
+ if (row != tablePtr->activeRow || col != tablePtr->activeCol) {
+ if (tablePtr->flags & HAS_ACTIVE) {
+ TableMakeArrayIndex(tablePtr->activeRow+tablePtr->rowOffset,
+ tablePtr->activeCol+tablePtr->colOffset, buf1);
+ } else {
+ buf1[0] = '\0';
+ }
+ tablePtr->flags |= HAS_ACTIVE;
+ tablePtr->flags &= ~ACTIVE_DISABLED;
+ tablePtr->activeRow = row;
+ tablePtr->activeCol = col;
+ if (tablePtr->activeLayout) {
+ Tk_FreeTextLayout(tablePtr->activeLayout);
+ tablePtr->activeLayout = NULL;
+ }
+ TableAdjustActive(tablePtr);
+ TableConfigCursor(tablePtr);
+ if (!(tablePtr->flags & BROWSE_CMD) && tablePtr->browseCmd != NULL) {
+ Tcl_DString script;
+ tablePtr->flags |= BROWSE_CMD;
+ row = tablePtr->activeRow+tablePtr->rowOffset;
+ col = tablePtr->activeCol+tablePtr->colOffset;
+ TableMakeArrayIndex(row, col, buf2);
+ Tcl_DStringInit(&script);
+ ExpandPercents(tablePtr, tablePtr->browseCmd, row, col, buf1, buf2,
+ tablePtr->icursor, &script, CMD_ACTIVATE);
+ result = Tcl_GlobalEval(interp, Tcl_DStringValue(&script));
+ if (result == TCL_OK || result == TCL_RETURN)
+ Tcl_ResetResult(interp);
+ Tcl_DStringFree(&script);
+ tablePtr->flags &= ~BROWSE_CMD;
+ }
+ } else if ((tablePtr->activeLayout != NULL) &&
+ !(tablePtr->flags & ACTIVE_DISABLED) && argv[2][0] == '@' &&
+ TableCellVCoords(tablePtr, row, col, &x, &y,
+ &dummy, &dummy, 0)) {
+ /* we are clicking into the same cell */
+ /* If it was activated with @x,y indexing, find the closest char */
+ char *p;
+
+ /* no error checking because GetIndex did it for us */
+ p = argv[2]+1;
+ x = strtol(p, &p, 0) - x - tablePtr->activeX;
+ y = strtol(++p, &p, 0) - y - tablePtr->activeY;
+
+ tablePtr->icursor = Tk_PointToChar(tablePtr->activeLayout, x, y);
+ TableConfigCursor(tablePtr);
+ }
+ tablePtr->flags |= HAS_ACTIVE;
+ }
+ break; /* ACTIVATE */
+
+ case CMD_BBOX: {
+ /* bounding box of cell(s) */
+ if (argc < 3 || argc > 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " bbox first ?last?\"", (char *) NULL);
+ result = TCL_ERROR;
+ } else if (TableGetIndex(tablePtr, argv[2], &row, &col) == TCL_ERROR) {
+ result = TCL_ERROR;
+ } else if (argc == 3) {
+ row -= tablePtr->rowOffset; col -= tablePtr->colOffset;
+ if (TableCellVCoords(tablePtr, row, col, &x, &y, &width, &height, 0)) {
+ sprintf(buf1, "%d %d %d %d", x, y, width, height);
+ Tcl_SetResult(interp, buf1, TCL_VOLATILE);
+ }
+ } else if (TableGetIndex(tablePtr, argv[3], &x, &y) == TCL_ERROR) {
+ result = TCL_ERROR;
+ } else {
+ int r1, c1, r2, c2, minX = 99999, minY = 99999, maxX = 0, maxY = 0;
+ row -= tablePtr->rowOffset; col -= tablePtr->colOffset;
+ x -= tablePtr->rowOffset; y -= tablePtr->colOffset;
+ r1 = MIN(row,x); r2 = MAX(row,x);
+ c1 = MIN(col,y); c2 = MAX(col,y);
+ key = 0;
+ for (row = r1; row <= r2; row++) {
+ for (col = c1; col <= c2; col++) {
+ if (TableCellVCoords(tablePtr, row, col, &x, &y,
+ &width, &height, 0)) {
+ /* Get max bounding box */
+ if (x < minX) minX = x;
+ if (y < minY) minY = y;
+ if (x+width > maxX) maxX = x+width;
+ if (y+height > maxY) maxY = y+height;
+ key++;
+ }
+ /* FIX - This could break on else for speed */
+ }
+ }
+ if (key) {
+ sprintf(buf1, "%d %d %d %d", minX, minY, maxX-minX, maxY-minY);
+ Tcl_SetResult(interp, buf1, TCL_VOLATILE);
+ }
+ }
+ }
+ break; /* BBOX */
+
+ case CMD_BORDER:
+ if (argc > 6) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " border mark|dragto x y ?r|c?\"", (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ sub_retval = Cmd_Parse(interp, bd_cmds, argv[2]);
+ if (sub_retval == 0 || Tcl_GetInt(interp, argv[3], &x) != TCL_OK ||
+ Tcl_GetInt(interp, argv[4], &y) != TCL_OK) {
+ result = TCL_ERROR;
+ break;
+ }
+ switch (sub_retval) {
+ case BD_MARK:
+ /* Use x && y to determine if we are over a border */
+ value = TableAtBorder(tablePtr, x, y, &row, &col);
+ /* Cache the row && col for use in DRAGTO */
+ tablePtr->scanMarkRow = row;
+ tablePtr->scanMarkCol = col;
+ if (!value) break;
+ TableCellCoords(tablePtr, row, col, &x, &y, &dummy, &dummy);
+ tablePtr->scanMarkX = x;
+ tablePtr->scanMarkY = y;
+ if (argc == 5 || argv[5][0] == 'r') {
+ if (row < 0)
+ buf1[0] = '\0';
+ else
+ sprintf(buf1, "%d", row+tablePtr->rowOffset);
+ Tcl_AppendElement(interp, buf1);
+ }
+ if (argc == 5 || argv[5][0] == 'c') {
+ if (col < 0)
+ buf1[0] = '\0';
+ else
+ sprintf(buf1, "%d", col+tablePtr->colOffset);
+ Tcl_AppendElement(interp, buf1);
+ }
+ break; /* BORDER MARK */
+ case BD_DRAGTO:
+ /* check to see if we want to resize any borders */
+ if (tablePtr->resize == SEL_NONE) break;
+ row = tablePtr->scanMarkRow;
+ col = tablePtr->scanMarkCol;
+ TableCellCoords(tablePtr, row, col, &width, &height, &dummy, &dummy);
+ key = 0;
+ if (row >= 0 && (tablePtr->resize & SEL_ROW)) {
+ /* row border was active, move it */
+ /* FIX should this be 1 or 2 bds off? */
+ value = y-height-tablePtr->borderWidth;
+ if (value < -1) value = -1;
+ if (value != tablePtr->scanMarkY) {
+ entryPtr = Tcl_CreateHashEntry(tablePtr->rowHeights,
+ (char *) row, &dummy);
+ /* -value means rowHeight will be interp'd as pixels, not lines */
+ Tcl_SetHashValue(entryPtr, (ClientData) MIN(0,-value));
+ tablePtr->scanMarkY = value;
+ key++;
+ }
+ }
+ if (col >= 0 && (tablePtr->resize & SEL_COL)) {
+ /* col border was active, move it */
+ value = x-width-tablePtr->borderWidth;
+ if (value < -1) value = -1;
+ if (value != tablePtr->scanMarkX) {
+ entryPtr = Tcl_CreateHashEntry(tablePtr->colWidths,
+ (char *) col, &dummy);
+ /* -value means colWidth will be interp'd as pixels, not chars */
+ Tcl_SetHashValue(entryPtr, (ClientData) MIN(0,-value));
+ tablePtr->scanMarkX = value;
+ key++;
+ }
+ }
+ /* Only if something changed do we want to update */
+ if (key) {
+ TableAdjustParams(tablePtr);
+ /* Only rerequest geometry if the basis is the #rows &| #cols */
+ if (tablePtr->maxReqCols || tablePtr->maxReqRows)
+ TableGeometryRequest(tablePtr);
+ TableInvalidateAll(tablePtr, 0);
+ }
+ break; /* BORDER DRAGTO */
+ }
+ break; /* BORDER */
+
+ case CMD_CGET:
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " cget option\"", (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ result = Tk_ConfigureValue(interp, tablePtr->tkwin, TableConfig,
+ (char *) tablePtr, argv[2], 0);
+ break; /* CGET */
+
+ case CMD_CLEAR:
+ if (argc < 3 || argc > 5) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " clear option ?first? ?last?\"", (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+
+ sub_retval = Cmd_Parse(interp, clear_cmds, argv[2]);
+ result = TableClear(tablePtr, sub_retval,
+ (argc>3)?argv[3]:NULL, (argc>4)?argv[4]:NULL);
+ break; /* CLEAR */
+
+ case CMD_CONFIGURE:
+ switch (argc) {
+ case 2:
+ result = Tk_ConfigureInfo(interp, tablePtr->tkwin, TableConfig,
+ (char *) tablePtr, (char *) NULL, 0);
+ break;
+ case 3:
+ result = Tk_ConfigureInfo(interp, tablePtr->tkwin, TableConfig,
+ (char *) tablePtr, argv[2], 0);
+ break;
+ default:
+ result = TableConfigure(interp, tablePtr, argc - 2, argv + 2,
+ TK_CONFIG_ARGV_ONLY, 0);
+ }
+ break; /* CONFIGURE */
+
+ case CMD_CURVALUE:
+ /* Get current active cell buffer */
+ if (argc > 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " curvalue ??\"", (char *)NULL);
+ result = TCL_ERROR;
+ } else if (tablePtr->flags & HAS_ACTIVE) {
+ if (argc == 3 && strcmp(argv[2], tablePtr->activeBuf)) {
+ key = TCL_OK;
+ /* validate potential new active buffer contents
+ * only accept if validation returns acceptance. */
+ if (tablePtr->validate &&
+ TableValidateChange(tablePtr,
+ tablePtr->activeRow+tablePtr->rowOffset,
+ tablePtr->activeCol+tablePtr->colOffset,
+ tablePtr->activeBuf,
+ argv[2], tablePtr->icursor) != TCL_OK) {
+ break;
+ }
+ tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf,
+ strlen(argv[2])+1);
+ strcpy(tablePtr->activeBuf, argv[2]);
+ /* mark the text as changed */
+ tablePtr->flags |= TEXT_CHANGED;
+ TableSetActiveIndex(tablePtr);
+ /* check for possible adjustment of icursor */
+ TableGetIcursor(tablePtr, "insert", (int *)0);
+ TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
+ CELL|INV_FORCE);
+ if (key == TCL_ERROR) {
+ result = TCL_ERROR;
+ break;
+ }
+ }
+ Tcl_AppendResult(interp, tablePtr->activeBuf, (char *)NULL);
+ }
+ break; /* CURVALUE */
+
+ case CMD_CURSELECTION:
+ if ((argc != 2 && argc != 4) ||
+ (argc == 4 && (argv[2][0] == '\0' ||
+ strncmp(argv[2], "set", strlen(argv[2]))))) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " curselection ?set ?\"", (char *)NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ /* make sure there is a data source to accept set */
+ if (argc == 4 && (tablePtr->state == STATE_DISABLED ||
+ (tablePtr->dataSource == DATA_NONE)))
+ break;
+ for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search);
+ entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
+ if (argc == 2) {
+ Tcl_AppendElement(interp,
+ Tcl_GetHashKey(tablePtr->selCells, entryPtr));
+ } else {
+ TableParseArrayIndex(&row, &col,
+ Tcl_GetHashKey(tablePtr->selCells, entryPtr));
+ TableSetCellValue(tablePtr, row, col, argv[3]);
+ row -= tablePtr->rowOffset;
+ col -= tablePtr->colOffset;
+ if (row == tablePtr->activeRow && col == tablePtr->activeCol) {
+ TableGetActiveBuf(tablePtr);
+ }
+ TableCellCoords(tablePtr, row, col, &x, &y, &width, &height);
+ TableInvalidate(tablePtr, x, y, width, height, 0);
+ }
+ }
+ if (argc == 2) {
+ Tcl_SetResult(interp,
+ TableCellSort(tablePtr, Tcl_GetStringResult(interp)),
+ TCL_DYNAMIC);
+ }
+ break; /* CURSELECTION */
+
+ case CMD_DELETE:
+ if (argc < 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " delete option ?switches? arg ?arg?\"",
+ (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ sub_retval = Cmd_Parse (interp, mod_cmds, argv[2]);
+ switch (sub_retval) {
+ case 0:
+ result = TCL_ERROR;
+ break;
+ case MOD_ACTIVE:
+ if (argc > 5) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " delete active first ?last?\"", (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ if (TableGetIcursor(tablePtr, argv[3], &posn) == TCL_ERROR) {
+ result = TCL_ERROR;
+ break;
+ }
+ if (argc == 4) {
+ value = posn+1;
+ } else if (TableGetIcursor(tablePtr, argv[4], &value) == TCL_ERROR) {
+ result = TCL_ERROR;
+ break;
+ }
+ if (value >= posn && (tablePtr->flags & HAS_ACTIVE) &&
+ !(tablePtr->flags & ACTIVE_DISABLED) &&
+ tablePtr->state == STATE_NORMAL)
+ TableDeleteChars(tablePtr, posn, value-posn);
+ break; /* DELETE ACTIVE */
+ case MOD_COLS:
+ case MOD_ROWS:
+ result = TableModifyRC(tablePtr, interp, CMD_DELETE, sub_retval,
+ argc, argv);
+ break; /* DELETE ROWS */
+ }
+ break; /* DELETE */
+
+ case CMD_GET: {
+ int r1, c1, r2, c2;
+
+ if (argc < 3 || argc > 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " get first ?last?\"", (char *)NULL);
+ result = TCL_ERROR;
+ } else if (TableGetIndex(tablePtr, argv[2], &row, &col) == TCL_ERROR) {
+ result = TCL_ERROR;
+ } else if (argc == 3) {
+ Tcl_SetResult(interp, TableGetCellValue(tablePtr, row, col), TCL_STATIC);
+ } else if (TableGetIndex(tablePtr, argv[3], &r2, &c2) == TCL_ERROR) {
+ result = TCL_ERROR;
+ } else {
+ r1 = MIN(row,r2); r2 = MAX(row,r2);
+ c1 = MIN(col,c2); c2 = MAX(col,c2);
+ for ( row = r1; row <= r2; row++ ) {
+ for ( col = c1; col <= c2; col++ ) {
+ Tcl_AppendElement(interp, TableGetCellValue(tablePtr, row, col));
+ }
+ }
+ }
+ }
+ break; /* GET */
+
+ case CMD_FLUSH: /* FIX - DEPRECATED */
+ if (argc > 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " flush ?first? ?last?\"", (char *) NULL);
+ result = TCL_ERROR;
+ } else {
+ result = TableClear(tablePtr, CLEAR_CACHE,
+ (argc>2)?argv[2]:NULL, (argc>3)?argv[3]:NULL);
+ }
+ break; /* FLUSH */
+
+ case CMD_HEIGHT:
+ case CMD_WIDTH:
+ /* changes the width/height of certain selected columns */
+ if (argc != 3 && (argc & 1)) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ (retval == CMD_WIDTH) ?
+ " width ?col? ?width col width ...?\"" :
+ " height ?row? ?height row height ...?\"",
+ (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ if (retval == CMD_WIDTH) {
+ hashTablePtr = tablePtr->colWidths;
+ offset = tablePtr->colOffset;
+ } else {
+ hashTablePtr = tablePtr->rowHeights;
+ offset = tablePtr->rowOffset;
+ }
+
+ if (argc == 2) {
+ /* print out all the preset column widths or row heights */
+ entryPtr = Tcl_FirstHashEntry(hashTablePtr, &search);
+ while (entryPtr != NULL) {
+ posn = ((int) Tcl_GetHashKey(hashTablePtr, entryPtr)) + offset;
+ value = (int) Tcl_GetHashValue(entryPtr);
+ sprintf(buf1, "%d %d", posn, value);
+ Tcl_AppendElement(interp, buf1);
+ entryPtr = Tcl_NextHashEntry(&search);
+ }
+ } else if (argc == 3) {
+ /* get the width/height of a particular row/col */
+ if (Tcl_GetInt(interp, argv[2], &posn) != TCL_OK) {
+ result = TCL_ERROR;
+ break;
+ }
+ /* no range check is done, why bother? */
+ posn -= offset;
+ entryPtr = Tcl_FindHashEntry(hashTablePtr, (char *) posn);
+ if (entryPtr != NULL) {
+ sprintf(buf1, "%d", (int) Tcl_GetHashValue(entryPtr));
+ Tcl_SetResult(interp, buf1, TCL_VOLATILE);
+ } else {
+ sprintf(buf1, "%d", (retval == CMD_WIDTH) ?
+ tablePtr->defColWidth : tablePtr->defRowHeight);
+ Tcl_SetResult(interp, buf1, TCL_VOLATILE);
+ }
+ } else {
+ for (i=2; iflags & HAS_ACTIVE) ||
+ (tablePtr->flags & ACTIVE_DISABLED) ||
+ tablePtr->state == STATE_DISABLED)
+ break;
+ switch (argc) {
+ case 2:
+ sprintf(buf1, "%d", tablePtr->icursor);
+ Tcl_SetResult(interp, buf1, TCL_VOLATILE);
+ break;
+ case 3:
+ if (TableGetIcursor(tablePtr, argv[2], (int *)0) != TCL_OK) {
+ result = TCL_ERROR;
+ break;
+ }
+ TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL);
+ break;
+ default:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " icursor arg\"", (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ break; /* ICURSOR */
+
+ case CMD_INDEX:
+ if (argc < 3 || argc > 4 ||
+ TableGetIndex(tablePtr, argv[2], &row, &col) == TCL_ERROR ||
+ (argc == 4 && (strcmp(argv[3], "row") && strcmp(argv[3], "col")))) {
+ if (!strlen(Tcl_GetStringResult(interp))) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " index index ?row|col?\"", (char *)NULL);
+ }
+ result = TCL_ERROR;
+ break;
+ }
+ if (argc == 3) {
+ TableMakeArrayIndex(row, col, buf1);
+ } else if (argv[3][0] == 'r') { /* INDEX row */
+ sprintf(buf1, "%d", row);
+ } else { /* INDEX col */
+ sprintf(buf1, "%d", col);
+ }
+ Tcl_SetResult(interp, buf1, TCL_VOLATILE);
+ break; /* INDEX */
+
+ case CMD_INSERT:
+ /* are edits enabled */
+ if (argc < 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " insert option ?switches? arg ?arg?\"", (char *)NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ sub_retval = Cmd_Parse(interp, mod_cmds, argv[2]);
+ switch (sub_retval) {
+ case 0:
+ result = TCL_ERROR;
+ break;
+ case MOD_ACTIVE:
+ if (argc != 5) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " insert active index string\"", (char *)NULL);
+ result = TCL_ERROR;
+ } else if (TableGetIcursor(tablePtr, argv[3], &posn) != TCL_OK) {
+ result = TCL_ERROR;
+ } else if ((tablePtr->flags & HAS_ACTIVE) &&
+ !(tablePtr->flags & ACTIVE_DISABLED) &&
+ tablePtr->state == STATE_NORMAL) {
+ TableInsertChars(tablePtr, posn, argv[4]);
+ }
+ break; /* INSERT ACTIVE */
+ case MOD_COLS:
+ case MOD_ROWS:
+ result = TableModifyRC(tablePtr, interp, CMD_INSERT, sub_retval,
+ argc, argv);
+ break;
+ }
+ break; /* INSERT */
+
+ case CMD_REREAD:
+ /* this rereads the selection from the array */
+ if (!(tablePtr->flags & HAS_ACTIVE) ||
+ (tablePtr->flags & ACTIVE_DISABLED) ||
+ tablePtr->state == STATE_DISABLED)
+ break;
+ TableGetActiveBuf(tablePtr);
+ TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol,
+ CELL|INV_FORCE);
+ break; /* REREAD */
+
+ case CMD_SCAN:
+ if (argc != 5) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " scan mark|dragto x y\"", (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ } else if (Tcl_GetInt(interp, argv[3], &x) == TCL_ERROR ||
+ Tcl_GetInt(interp, argv[4], &y) == TCL_ERROR) {
+ result = TCL_ERROR;
+ break;
+ }
+ if ((argv[2][0] == 'm')
+ && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) {
+ TableWhatCell(tablePtr, x, y, &row, &col);
+ tablePtr->scanMarkRow = row-tablePtr->topRow;
+ tablePtr->scanMarkCol = col-tablePtr->leftCol;
+ tablePtr->scanMarkX = x;
+ tablePtr->scanMarkY = y;
+ } else if ((argv[2][0] == 'd')
+ && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) {
+ int oldTop = tablePtr->topRow, oldLeft = tablePtr->leftCol;
+ y += (5*(y-tablePtr->scanMarkY));
+ x += (5*(x-tablePtr->scanMarkX));
+
+ TableWhatCell(tablePtr, x, y, &row, &col);
+
+ /* maintain appropriate real index */
+ tablePtr->topRow = MAX(MIN(row-tablePtr->scanMarkRow,
+ tablePtr->rows-1), tablePtr->titleRows);
+ tablePtr->leftCol = MAX(MIN(col-tablePtr->scanMarkCol,
+ tablePtr->cols-1), tablePtr->titleCols);
+
+ /* Adjust the table if new top left */
+ if (oldTop != tablePtr->topRow || oldLeft != tablePtr->leftCol)
+ TableAdjustParams(tablePtr);
+ } else {
+ Tcl_AppendResult(interp, "bad scan option \"", argv[2],
+ "\": must be mark or dragto", (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ break; /* SCAN */
+
+ case CMD_SEE:
+ if (argc!=3 || TableGetIndex(tablePtr,argv[2],&row,&col)==TCL_ERROR) {
+ if (!strlen(Tcl_GetStringResult(interp))) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " see index\"", (char *)NULL);
+ }
+ result = TCL_ERROR;
+ break;
+ }
+ /* Adjust from user to master coords */
+ row -= tablePtr->rowOffset;
+ col -= tablePtr->colOffset;
+ if (!TableCellVCoords(tablePtr, row, col, &x, &x, &x, &x, 1)) {
+ tablePtr->topRow = row-1;
+ tablePtr->leftCol = col-1;
+ TableAdjustParams(tablePtr);
+ }
+ break; /* SEE */
+
+ case CMD_SELECTION:
+ if (argc<3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " selection option args\"", (char *)NULL);
+ result=TCL_ERROR;
+ break;
+ }
+ retval = Cmd_Parse(interp, sel_cmds, argv[2]);
+ switch(retval) {
+ case 0: /* failed to parse the argument, error */
+ return TCL_ERROR;
+ case SEL_ANCHOR:
+ if (argc != 4 || TableGetIndex(tablePtr,argv[3],&row,&col) != TCL_OK) {
+ if (!strlen(Tcl_GetStringResult(interp)))
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " selection anchor index\"", (char *)NULL);
+ result=TCL_ERROR;
+ break;
+ }
+ tablePtr->flags |= HAS_ANCHOR;
+ /* maintain appropriate real index */
+ if (tablePtr->selectTitles) {
+ tablePtr->anchorRow = MIN(MAX(0,row-tablePtr->rowOffset),
+ tablePtr->rows-1);
+ tablePtr->anchorCol = MIN(MAX(0,col-tablePtr->colOffset),
+ tablePtr->cols-1);
+ } else {
+ tablePtr->anchorRow = MIN(MAX(tablePtr->titleRows,
+ row-tablePtr->rowOffset),
+ tablePtr->rows-1);
+ tablePtr->anchorCol = MIN(MAX(tablePtr->titleCols,
+ col-tablePtr->colOffset),
+ tablePtr->cols-1);
+ }
+ break;
+ case SEL_CLEAR:
+ if ( argc != 4 && argc != 5 ) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " selection clear all| ??\"",
+ (char *)NULL);
+ result=TCL_ERROR;
+ break;
+ }
+ if (strcmp(argv[3],"all") == 0) {
+ for(entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search);
+ entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
+ TableParseArrayIndex(&row, &col,
+ Tcl_GetHashKey(tablePtr->selCells,entryPtr));
+ Tcl_DeleteHashEntry(entryPtr);
+ TableCellCoords(tablePtr, row-tablePtr->rowOffset,
+ col-tablePtr->colOffset, &x, &y, &width, &height);
+ TableInvalidate(tablePtr, x, y, width, height, 0);
+ }
+ } else {
+ int clo=0,chi=0,r1,c1,r2,c2;
+ if (TableGetIndex(tablePtr,argv[3],&row,&col) == TCL_ERROR ||
+ (argc==5 && TableGetIndex(tablePtr,argv[4],&r2,&c2)==TCL_ERROR)) {
+ result = TCL_ERROR;
+ break;
+ }
+ key = 0;
+ if (argc == 4) {
+ r1 = r2 = row;
+ c1 = c2 = col;
+ } else {
+ r1 = MIN(row,r2); r2 = MAX(row,r2);
+ c1 = MIN(col,c2); c2 = MAX(col,c2);
+ }
+ switch (tablePtr->selectType) {
+ case SEL_BOTH:
+ clo = c1; chi = c2;
+ c1 = tablePtr->colOffset;
+ c2 = tablePtr->cols-1+c1;
+ key = 1;
+ goto CLEAR_CELLS;
+ CLEAR_BOTH:
+ key = 0;
+ c1 = clo; c2 = chi;
+ case SEL_COL:
+ r1 = tablePtr->rowOffset;
+ r2 = tablePtr->rows-1+r1;
+ break;
+ case SEL_ROW:
+ c1 = tablePtr->colOffset;
+ c2 = tablePtr->cols-1+c1;
+ break;
+ }
+ /* row/col are in user index coords */
+ CLEAR_CELLS:
+ for ( row = r1; row <= r2; row++ ) {
+ for ( col = c1; col <= c2; col++ ) {
+ TableMakeArrayIndex(row, col, buf1);
+ if ((entryPtr=Tcl_FindHashEntry(tablePtr->selCells, buf1))!=NULL) {
+ Tcl_DeleteHashEntry(entryPtr);
+ TableCellCoords(tablePtr, row-tablePtr->rowOffset,
+ col-tablePtr->colOffset,&x,&y,&width,&height);
+ TableInvalidate(tablePtr, x, y, width, height, 0);
+ }
+ }
+ }
+ if (key) goto CLEAR_BOTH;
+ }
+ break; /* SELECTION CLEAR */
+ case SEL_INCLUDES:
+ if (argc != 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " selection includes index\"", (char *)NULL);
+ result = TCL_ERROR;
+ } else if (TableGetIndex(tablePtr, argv[3], &row, &col) == TCL_ERROR) {
+ result = TCL_ERROR;
+ } else {
+ TableMakeArrayIndex(row, col, buf1);
+ if (Tcl_FindHashEntry(tablePtr->selCells, buf1)) {
+ Tcl_SetResult(interp, "1", TCL_STATIC);
+ } else {
+ Tcl_SetResult(interp, "0", TCL_STATIC);
+ }
+ }
+ break; /* SELECTION INCLUDES */
+ case SEL_SET: {
+ int clo=0, chi=0, r1, c1, r2, c2, titleRows, titleCols;
+ if (argc < 4 || argc > 5) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " selection set first ?last?\"", (char *)NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ if (TableGetIndex(tablePtr,argv[3],&row,&col) == TCL_ERROR ||
+ (argc==5 && TableGetIndex(tablePtr,argv[4],&r2,&c2)==TCL_ERROR)) {
+ result = TCL_ERROR;
+ break;
+ }
+ key = 0;
+ if (tablePtr->selectTitles) {
+ titleRows = 0;
+ titleCols = 0;
+ } else {
+ titleRows = tablePtr->titleRows;
+ titleCols = tablePtr->titleCols;
+ }
+ /* maintain appropriate user index */
+ row = MIN(MAX(titleRows+tablePtr->rowOffset, row),
+ tablePtr->rows-1+tablePtr->rowOffset);
+ col = MIN(MAX(titleCols+tablePtr->colOffset, col),
+ tablePtr->cols-1+tablePtr->colOffset);
+ if (argc == 4) {
+ r1 = r2 = row;
+ c1 = c2 = col;
+ } else {
+ r2 = MIN(MAX(titleRows+tablePtr->rowOffset, r2),
+ tablePtr->rows-1+tablePtr->rowOffset);
+ c2 = MIN(MAX(titleCols+tablePtr->colOffset, c2),
+ tablePtr->cols-1+tablePtr->colOffset);
+ r1 = MIN(row,r2); r2 = MAX(row,r2);
+ c1 = MIN(col,c2); c2 = MAX(col,c2);
+ }
+ switch (tablePtr->selectType) {
+ case SEL_BOTH:
+ clo = c1; chi = c2;
+ c1 = titleCols+tablePtr->colOffset;
+ c2 = tablePtr->cols-1+tablePtr->colOffset;
+ key = 1;
+ goto SET_CELLS;
+ SET_BOTH:
+ key = 0;
+ c1 = clo; c2 = chi;
+ case SEL_COL:
+ r1 = titleRows+tablePtr->rowOffset;
+ r2 = tablePtr->rows-1+tablePtr->rowOffset;
+ break;
+ case SEL_ROW:
+ c1 = titleCols+tablePtr->colOffset;
+ c2 = tablePtr->cols-1+tablePtr->colOffset;
+ break;
+ }
+ SET_CELLS:
+ entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search);
+ for ( row = r1; row <= r2; row++ ) {
+ for ( col = c1; col <= c2; col++ ) {
+ TableMakeArrayIndex(row, col, buf1);
+ if (Tcl_FindHashEntry(tablePtr->selCells, buf1) == NULL) {
+ Tcl_CreateHashEntry(tablePtr->selCells, buf1, &dummy);
+ TableCellCoords(tablePtr, row-tablePtr->rowOffset,
+ col-tablePtr->colOffset, &x, &y, &width, &height);
+ TableInvalidate(tablePtr, x, y, width, height, 0);
+ }
+ }
+ }
+ if (key) goto SET_BOTH;
+
+ /* Adjust the table for top left, selection on screen etc */
+ TableAdjustParams(tablePtr);
+
+ /* If the table was previously empty and we want to export the
+ * selection, we should grab it now */
+ if (entryPtr==NULL && tablePtr->exportSelection) {
+ Tk_OwnSelection(tablePtr->tkwin, XA_PRIMARY, TableLostSelection,
+ (ClientData) tablePtr);
+ }
+ }
+ break; /* SELECTION SET */
+ }
+ break; /* SELECTION */
+
+ case CMD_SET:
+ /* sets any number of tags/indices to a given value */
+ if (argc < 3 || (argc > 3 && (argc & 1))) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " set index ?value? ?index value ...?\"",
+ (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ /* make sure there is a data source to accept set */
+ if (tablePtr->dataSource == DATA_NONE)
+ break;
+ if (argc == 3) {
+ if (TableGetIndex(tablePtr, argv[2], &row, &col) != TCL_OK) {
+ result = TCL_ERROR;
+ break;
+ }
+ Tcl_SetResult(interp, TableGetCellValue(tablePtr, row, col),
+ TCL_STATIC);
+ } else if (tablePtr->state == STATE_NORMAL) {
+ for (i=2; irowOffset;
+ col -= tablePtr->colOffset;
+ if (row == tablePtr->activeRow && col == tablePtr->activeCol) {
+ TableGetActiveBuf(tablePtr);
+ }
+ TableCellCoords(tablePtr, row, col, &x, &y, &width, &height);
+ TableInvalidate(tablePtr, x, y, width, height, 0);
+ }
+ }
+ break;
+
+ case CMD_TAG:
+ /* a veritable plethora of tag commands */
+ /* do we have another argument */
+ if (argc < 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " tag option ?arg arg ...?\"", (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ /* all the rest is now done in a separate function */
+ result = TableTagCmd(tablePtr, interp, argc, argv);
+ break; /* TAG */
+
+ case CMD_VALIDATE:
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " validate index\"", (char *) NULL);
+ result = TCL_ERROR;
+ } else if (TableGetIndex(tablePtr, argv[2], &row, &col) == TCL_ERROR) {
+ result = TCL_ERROR;
+ } else {
+ value = tablePtr->validate;
+ tablePtr->validate = 1;
+ key = TableValidateChange(tablePtr, row, col, (char *) NULL,
+ (char *) NULL, -1);
+ tablePtr->validate = value;
+ sprintf(buf1, "%d", (key == TCL_OK) ? 1 : 0);
+ Tcl_SetResult(interp, buf1, TCL_VOLATILE);
+ }
+ break;
+
+ case CMD_VERSION:
+ if (argc != 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " version\"", (char *) NULL);
+ result = TCL_ERROR;
+ } else {
+ Tcl_SetResult(interp, TBL_VERSION, TCL_VOLATILE);
+ }
+ break;
+
+ case CMD_WINDOW:
+ /* a veritable plethora of window commands */
+ /* do we have another argument */
+ if (argc < 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " window option ?arg arg ...?\"", (char *) NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ /* all the rest is now done in a separate function */
+ result = TableWindowCmd(tablePtr, interp, argc, argv);
+ break;
+
+ case CMD_XVIEW:
+ case CMD_YVIEW:
+ if (argc == 2) {
+ int diff;
+ double first, last;
+ TableGetLastCell(tablePtr, &row, &col);
+ TableCellVCoords(tablePtr, row, col, &x, &y, &width, &height, 0);
+ if (retval == CMD_YVIEW) {
+ if (row < tablePtr->titleRows) {
+ first = 0;
+ last = 1;
+ } else {
+ diff = tablePtr->rowStarts[tablePtr->titleRows];
+ last = (double) (tablePtr->rowStarts[tablePtr->rows]-diff);
+ first = (tablePtr->rowStarts[tablePtr->topRow]-diff) / last;
+ last = (height+tablePtr->rowStarts[row]-diff) / last;
+ }
+ } else {
+ if (col < tablePtr->titleCols) {
+ first = 0;
+ last = 1;
+ } else {
+ diff = tablePtr->colStarts[tablePtr->titleCols];
+ last = (double) (tablePtr->colStarts[tablePtr->cols]-diff);
+ first = (tablePtr->colStarts[tablePtr->leftCol]-diff) / last;
+ last = (width+tablePtr->colStarts[col]-diff) / last;
+ }
+ }
+ sprintf(buf1, "%g %g", first, last);
+ Tcl_SetResult(interp, buf1, TCL_VOLATILE);
+ } else {
+ /* cache old topleft to see if it changes */
+ int oldTop = tablePtr->topRow, oldLeft = tablePtr->leftCol;
+ if (argc == 3) {
+ if (Tcl_GetInt(interp, argv[2], &value) != TCL_OK) {
+ result = TCL_ERROR;
+ break;
+ }
+ if (retval == CMD_YVIEW) {
+ tablePtr->topRow = value + tablePtr->titleRows;
+ } else {
+ tablePtr->leftCol = value + tablePtr->titleCols;
+ }
+ } else {
+ double frac;
+ sub_retval = Tk_GetScrollInfo(interp, argc, argv, &frac, &value);
+ switch (sub_retval) {
+ case TK_SCROLL_ERROR:
+ result = TCL_ERROR;
+ break;
+ case TK_SCROLL_MOVETO:
+ if (frac < 0) frac = 0;
+ if (retval == CMD_YVIEW) {
+ tablePtr->topRow = (int)(frac*tablePtr->rows)+tablePtr->titleRows;
+ } else {
+ tablePtr->leftCol = (int)(frac*tablePtr->cols)+tablePtr->titleCols;
+ }
+ break;
+ case TK_SCROLL_PAGES:
+ TableGetLastCell(tablePtr, &row, &col);
+ if (retval == CMD_YVIEW) {
+ tablePtr->topRow += value * (row-tablePtr->topRow+1);
+ } else {
+ tablePtr->leftCol += value * (col-tablePtr->leftCol+1);
+ }
+ break;
+ case TK_SCROLL_UNITS:
+ if (retval == CMD_YVIEW) {
+ tablePtr->topRow += value;
+ } else {
+ tablePtr->leftCol += value;
+ }
+ break;
+ }
+ }
+ /* maintain appropriate real index */
+ tablePtr->topRow = MAX(tablePtr->titleRows,
+ MIN(tablePtr->topRow, tablePtr->rows-1));
+ tablePtr->leftCol = MAX(tablePtr->titleCols,
+ MIN(tablePtr->leftCol, tablePtr->cols-1));
+ /* Do the table adjustment if topRow || leftCol changed */
+ if (oldTop != tablePtr->topRow || oldLeft != tablePtr->leftCol)
+ TableAdjustParams(tablePtr);
+ }
+ break; /* XVIEW/YVIEW */
+ }
+ Tcl_Release(clientData);
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableDestroy --
+ * This procedure is invoked by Tcl_EventuallyFree
+ * to clean up the internal structure of a table at a safe time
+ * (when no-one is using it anymore).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Everything associated with the table is freed up (hopefully).
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableDestroy(ClientData clientdata)
+{
+ register Table *tablePtr = (Table *) clientdata;
+ Tcl_HashEntry *entryPtr;
+ Tcl_HashSearch search;
+
+ /* These may be repetitive from DestroyNotify, but it doesn't hurt */
+ /* cancel any pending update or timer */
+ if (tablePtr->flags & REDRAW_PENDING) {
+ Tcl_CancelIdleCall(TableDisplay, (ClientData) tablePtr);
+ tablePtr->flags &= ~REDRAW_PENDING;
+ }
+ Tcl_DeleteTimerHandler(tablePtr->cursorTimer);
+ Tcl_DeleteTimerHandler(tablePtr->flashTimer);
+
+ /* delete the variable trace */
+ if (tablePtr->arrayVar != NULL) {
+ Tcl_UntraceVar(tablePtr->interp, tablePtr->arrayVar,
+ TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY,
+ (Tcl_VarTraceProc *)TableVarProc, (ClientData) tablePtr);
+ }
+
+ /* delete cached activeLayout */
+ if (tablePtr->activeLayout != NULL) {
+ Tk_FreeTextLayout(tablePtr->activeLayout);
+ tablePtr->activeLayout = NULL;
+ }
+ /* free the arrays with row/column pixel sizes */
+ if (tablePtr->colPixels) ckfree((char *) tablePtr->colPixels);
+ if (tablePtr->rowPixels) ckfree((char *) tablePtr->rowPixels);
+ if (tablePtr->colStarts) ckfree((char *) tablePtr->colStarts);
+ if (tablePtr->rowStarts) ckfree((char *) tablePtr->rowStarts);
+
+ /* free the selection buffer */
+ if (tablePtr->activeBuf != NULL) ckfree(tablePtr->activeBuf);
+
+ /* delete the cache, row, column and cell style hash tables */
+ Tcl_DeleteHashTable(tablePtr->cache);
+ ckfree((char *) (tablePtr->cache));
+ Tcl_DeleteHashTable(tablePtr->rowStyles);
+ ckfree((char *) (tablePtr->rowStyles));
+ Tcl_DeleteHashTable(tablePtr->colStyles);
+ ckfree((char *) (tablePtr->colStyles));
+ Tcl_DeleteHashTable(tablePtr->cellStyles);
+ ckfree((char *) (tablePtr->cellStyles));
+ Tcl_DeleteHashTable(tablePtr->flashCells);
+ ckfree((char *) (tablePtr->flashCells));
+ Tcl_DeleteHashTable(tablePtr->selCells);
+ ckfree((char *) (tablePtr->selCells));
+ Tcl_DeleteHashTable(tablePtr->colWidths);
+ ckfree((char *) (tablePtr->colWidths));
+ Tcl_DeleteHashTable(tablePtr->rowHeights);
+ ckfree((char *) (tablePtr->rowHeights));
+
+ /* Now free up all the tag information */
+ for (entryPtr = Tcl_FirstHashEntry(tablePtr->tagTable, &search);
+ entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
+ TableCleanupTag(tablePtr, (TableTag *) Tcl_GetHashValue(entryPtr));
+ ckfree((char *) Tcl_GetHashValue(entryPtr));
+ }
+ /* free up the stuff in the default tag */
+ TableCleanupTag(tablePtr, &(tablePtr->defaultTag));
+ /* And delete the actual hash table */
+ Tcl_DeleteHashTable(tablePtr->tagTable);
+ ckfree((char *) (tablePtr->tagTable));
+
+ /* Now free up all the embedded window info */
+ for (entryPtr = Tcl_FirstHashEntry(tablePtr->winTable, &search);
+ entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
+ EmbWinDelete(tablePtr, (TableEmbWindow *) Tcl_GetHashValue(entryPtr));
+ }
+ /* And delete the actual hash table */
+ Tcl_DeleteHashTable(tablePtr->winTable);
+ ckfree((char *) (tablePtr->winTable));
+
+ /* free the configuration options in the widget */
+ Tk_FreeOptions(TableConfig, (char *) tablePtr, tablePtr->display, 0);
+
+ /* and free the widget memory at last! */
+ ckfree((char *) (tablePtr));
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TableEventProc --
+ * This procedure is invoked by the Tk dispatcher for various
+ * events on tables.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * When the window gets deleted, internal structures get
+ * cleaned up. When it gets exposed, it is redisplayed.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+TableEventProc(clientData, eventPtr)
+ ClientData clientData; /* Information about window. */
+ XEvent *eventPtr; /* Information about event. */
+{
+ Table *tablePtr = (Table *) clientData;
+ int row, col;
+
+ switch (eventPtr->type) {
+
+ case MotionNotify:
+ if (!(tablePtr->resize & SEL_NONE) && (tablePtr->bdcursor != None) &&
+ TableAtBorder(tablePtr, eventPtr->xmotion.x, eventPtr->xmotion.y,
+ &row, &col) &&
+ ((row>=0 && (tablePtr->resize & SEL_ROW)) ||
+ (col>=0 && (tablePtr->resize & SEL_COL)))) {
+ /* The bordercursor is defined and we meet the criteria for being
+ * over a border. Set the cursor to border if not already so */
+ if (!(tablePtr->flags & OVER_BORDER)) {
+ tablePtr->flags |= OVER_BORDER;
+ Tk_DefineCursor(tablePtr->tkwin, tablePtr->bdcursor);
+ }
+ } else if (tablePtr->flags & OVER_BORDER) {
+ tablePtr->flags &= ~OVER_BORDER;
+ if (tablePtr->cursor != None) {
+ Tk_DefineCursor(tablePtr->tkwin, tablePtr->cursor);
+ } else {
+ Tk_UndefineCursor(tablePtr->tkwin);
+ }
+ }
+ break;
+
+ case Expose:
+ TableInvalidate(tablePtr, eventPtr->xexpose.x, eventPtr->xexpose.y,
+ eventPtr->xexpose.width, eventPtr->xexpose.height,
+ INV_HIGHLIGHT);
+ break;
+
+ case DestroyNotify:
+ /* remove the command from the interpreter */
+ if (tablePtr->tkwin != NULL) {
+ tablePtr->tkwin = NULL;
+ Tcl_DeleteCommandFromToken(tablePtr->interp, tablePtr->widgetCmd);
+ }
+
+ /* cancel any pending update or timer */
+ if (tablePtr->flags & REDRAW_PENDING) {
+ Tcl_CancelIdleCall(TableDisplay, (ClientData) tablePtr);
+ tablePtr->flags &= ~REDRAW_PENDING;
+ }
+ Tcl_DeleteTimerHandler(tablePtr->cursorTimer);
+ Tcl_DeleteTimerHandler(tablePtr->flashTimer);
+
+ Tcl_EventuallyFree((ClientData) tablePtr, (Tcl_FreeProc *) TableDestroy);
+ break;
+
+ case MapNotify: /* redraw table when remapped if it changed */
+ if (tablePtr->flags & REDRAW_ON_MAP) {
+ tablePtr->flags &= ~REDRAW_ON_MAP;
+ Tcl_Preserve((ClientData) tablePtr);
+ TableAdjustParams(tablePtr);
+ TableInvalidateAll(tablePtr, INV_FORCE|INV_HIGHLIGHT);
+ Tcl_Release((ClientData) tablePtr);
+ }
+ break;
+
+ case ConfigureNotify:
+ Tcl_Preserve((ClientData) tablePtr);
+ TableAdjustParams(tablePtr);
+ TableInvalidateAll(tablePtr, INV_FORCE|INV_HIGHLIGHT);
+ Tcl_Release((ClientData) tablePtr);
+ break;
+
+ case FocusIn:
+ case FocusOut:
+ if (eventPtr->xfocus.detail != NotifyInferior) {
+ tablePtr->flags |= REDRAW_BORDER;
+ if (eventPtr->type == FocusOut) {
+ tablePtr->flags &= ~HAS_FOCUS;
+ } else {
+ tablePtr->flags |= HAS_FOCUS;
+ }
+ TableRedrawHighlight(tablePtr);
+ /* cancel the timer */
+ TableConfigCursor(tablePtr);
+ }
+ break;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableConfigure --
+ * This procedure is called to process an argv/argc list, plus
+ * the Tk option database, in order to configure (or reconfigure)
+ * a table widget.
+ *
+ * Results:
+ * The return value is a standard Tcl result. If TCL_ERROR is
+ * returned, then interp result contains an error message.
+ *
+ * Side effects:
+ * Configuration information, such as colors, border width, etc.
+ * get set for tablePtr; old resources get freed, if there were any.
+ * Certain values might be constrained.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+TableConfigure(interp, tablePtr, argc, argv, flags, forceUpdate)
+ Tcl_Interp *interp; /* Used for error reporting. */
+ register Table *tablePtr; /* Information about widget; may or may
+ * not already have values for some fields. */
+ int argc; /* Number of valid entries in argv. */
+ char **argv; /* Arguments. */
+ int flags; /* Flags to pass to Tk_ConfigureWidget. */
+ int forceUpdate; /* Whether to force an update - required
+ * for initial configuration */
+{
+ Tcl_HashSearch search;
+ int oldUse, oldCaching, oldExport, result = TCL_OK;
+ char *oldVar;
+ Tcl_DString error;
+ Tk_FontMetrics fm;
+
+ oldExport = tablePtr->exportSelection;
+ oldCaching = tablePtr->caching;
+ oldUse = tablePtr->useCmd;
+ oldVar = tablePtr->arrayVar;
+
+ /* Do the configuration */
+ if (Tk_ConfigureWidget(interp, tablePtr->tkwin, TableConfig, argc, argv,
+ (char *) tablePtr, flags) != TCL_OK)
+ return TCL_ERROR;
+
+ Tcl_DStringInit(&error);
+
+ /* Any time we configure, reevaluate what our data source is */
+ tablePtr->dataSource = DATA_NONE;
+ if (tablePtr->caching) {
+ tablePtr->dataSource |= DATA_CACHE;
+ }
+ if (tablePtr->command && tablePtr->useCmd) {
+ tablePtr->dataSource |= DATA_COMMAND;
+ } else if (tablePtr->arrayVar) {
+ tablePtr->dataSource |= DATA_ARRAY;
+ }
+
+ /* Check to see if the array variable was changed */
+ if (strcmp((tablePtr->arrayVar?tablePtr->arrayVar:""),(oldVar?oldVar:""))) {
+ /* only do the following if arrayVar is our data source */
+ if (tablePtr->dataSource & DATA_ARRAY) {
+ /* ensure that the cache will flush later so it gets the new values */
+ oldCaching = !(tablePtr->caching);
+ }
+ /* remove the trace on the old array variable if there was one */
+ if (oldVar != NULL)
+ Tcl_UntraceVar(interp, oldVar,
+ TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY,
+ (Tcl_VarTraceProc *)TableVarProc, (ClientData)tablePtr);
+ /* Check whether variable is an array and trace it if it is */
+ if (tablePtr->arrayVar != NULL) {
+ /* does the variable exist as an array? */
+ if (Tcl_SetVar2(interp, tablePtr->arrayVar, TEST_KEY, "",
+ TCL_GLOBAL_ONLY) == NULL) {
+ Tcl_DStringAppend(&error, "invalid variable value \"", -1);
+ Tcl_DStringAppend(&error, tablePtr->arrayVar, -1);
+ Tcl_DStringAppend(&error, "\": could not be made an array", -1);
+ ckfree(tablePtr->arrayVar);
+ tablePtr->arrayVar = NULL;
+ tablePtr->dataSource &= ~DATA_ARRAY;
+ result = TCL_ERROR;
+ } else {
+ Tcl_UnsetVar2(interp, tablePtr->arrayVar, TEST_KEY, TCL_GLOBAL_ONLY);
+ /* remove the effect of the evaluation */
+ /* set a trace on the variable */
+ Tcl_TraceVar(interp, tablePtr->arrayVar,
+ TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY,
+ (Tcl_VarTraceProc *)TableVarProc, (ClientData) tablePtr);
+
+ /* only do the following if arrayVar is our data source */
+ if (tablePtr->dataSource & DATA_ARRAY) {
+ /* get the current value of the selection */
+ TableGetActiveBuf(tablePtr);
+ }
+ }
+ }
+ }
+ if ((tablePtr->command && tablePtr->useCmd && !oldUse) ||
+ (tablePtr->arrayVar && !(tablePtr->useCmd) && oldUse)) {
+ /* our effective data source changed, so flush and
+ * retrieve new active buffer */
+ TableFlushCache(tablePtr);
+ TableGetActiveBuf(tablePtr);
+ forceUpdate = 1;
+ } else if (oldCaching != tablePtr->caching) {
+ /* caching changed, so just clear the cache for safety */
+ TableFlushCache(tablePtr);
+ forceUpdate = 1;
+ }
+
+ /* set up the default column width and row height */
+ Tk_GetFontMetrics(tablePtr->defaultTag.tkfont, &fm);
+ tablePtr->charWidth = Tk_TextWidth(tablePtr->defaultTag.tkfont, "0", 1);
+ tablePtr->charHeight = fm.linespace + 2;
+
+ if (tablePtr->insertWidth <= 0) {
+ tablePtr->insertWidth = 2;
+ }
+ if (tablePtr->insertBorderWidth > tablePtr->insertWidth/2) {
+ tablePtr->insertBorderWidth = tablePtr->insertWidth/2;
+ }
+ tablePtr->highlightWidth = MAX(0,tablePtr->highlightWidth);
+ /* the border must be >= 0 */
+ tablePtr->borderWidth = MAX(0,tablePtr->borderWidth);
+ /* when drawing fast or single, the border must be <= 1 */
+ if (tablePtr->drawMode & (DRAW_MODE_SINGLE|DRAW_MODE_FAST)) {
+ tablePtr->borderWidth = MIN(1,tablePtr->borderWidth);
+ }
+
+ /* Ensure that certain values are within proper constraints */
+ tablePtr->rows = MAX(1,tablePtr->rows);
+ tablePtr->cols = MAX(1,tablePtr->cols);
+ tablePtr->titleRows = MIN(MAX(0,tablePtr->titleRows),tablePtr->rows);
+ tablePtr->titleCols = MIN(MAX(0,tablePtr->titleCols),tablePtr->cols);
+ tablePtr->padX = MAX(0,tablePtr->padX);
+ tablePtr->padY = MAX(0,tablePtr->padY);
+ tablePtr->maxReqCols = MAX(0,tablePtr->maxReqCols);
+ tablePtr->maxReqRows = MAX(0,tablePtr->maxReqRows);
+
+ /*
+ * Claim the selection if we've suddenly started exporting it and
+ * there is a selection to export.
+ */
+ if (tablePtr->exportSelection && !oldExport &&
+ (Tcl_FirstHashEntry(tablePtr->selCells, &search) != NULL)) {
+ Tk_OwnSelection(tablePtr->tkwin, XA_PRIMARY, TableLostSelection,
+ (ClientData) tablePtr);
+ }
+
+ /* only do the full reconfigure if absolutely necessary */
+ if (!forceUpdate) {
+ int i;
+ for (i = 0; i < argc-1; i += 2) {
+ if (Cmd_GetValue(update_config, argv[i])) {
+ forceUpdate = 1;
+ break;
+ }
+ }
+ }
+ if (forceUpdate) {
+ /*
+ * Calculate the row and column starts
+ * Adjust the top left corner of the internal display
+ */
+ TableAdjustParams(tablePtr);
+ /* reset the cursor */
+ TableConfigCursor(tablePtr);
+ /* set up the background colour in the window */
+ Tk_SetBackgroundFromBorder(tablePtr->tkwin, tablePtr->defaultTag.bg);
+ /* set the geometry and border */
+ TableGeometryRequest(tablePtr);
+ Tk_SetInternalBorder(tablePtr->tkwin, tablePtr->highlightWidth);
+ /* invalidate the whole table */
+ TableInvalidateAll(tablePtr, INV_HIGHLIGHT);
+ }
+ /* FIX this is goofy because the result could be munged by other
+ * functions. Needs to be improved */
+ Tcl_ResetResult(interp);
+ if (result == TCL_ERROR) {
+ Tcl_AddErrorInfo(interp, "\t(configuring table widget)");
+ Tcl_DStringResult(interp, &error);
+ }
+ Tcl_DStringFree(&error);
+ return result;
+}
+
+#ifndef CLASSPATCH
+/*
+ * As long as we wait for the Function in general
+ *
+ * This parses the "-class" option for the table.
+ */
+static void
+Tk_ClassOption(Tk_Window tkwin, char *defaultclass, int *argcp, char ***argvp)
+{
+ char *classname = (((*argcp)<3) || (strcmp((*argvp)[2],"-class"))) ?
+ defaultclass : ((*argcp)-=2,(*argcp)+=2,(*argvp)[1]);
+ Tk_SetClass(tkwin,classname);
+}
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TableCmdDeletedProc --
+ *
+ * This procedure is invoked when a widget command is deleted. If
+ * the widget isn't already in the process of being destroyed,
+ * this command destroys it.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The widget is destroyed.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+TableCmdDeletedProc(ClientData clientData)
+{
+ Table *tablePtr = (Table *) clientData;
+ Tk_Window tkwin;
+
+ /*
+ * This procedure could be invoked either because the window was
+ * destroyed and the command was then deleted (in which case tkwin
+ * is NULL) or because the command was deleted, and then this procedure
+ * destroys the widget.
+ */
+
+ /* This is needed to avoid bug where the DLL is unloaded before
+ * the table is properly destroyed */
+ Tcl_DeleteExitHandler((Tcl_ExitProc *) TableCmdDeletedProc,
+ (ClientData) tablePtr);
+ if (tablePtr->tkwin != NULL) {
+ tkwin = tablePtr->tkwin;
+ tablePtr->tkwin = NULL;
+ Tk_DestroyWindow(tkwin);
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TableCmd --
+ * This procedure is invoked to process the "table" Tcl
+ * command. See the user documentation for details on what
+ * it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *--------------------------------------------------------------
+ */
+static int
+TableCmd(clientData, interp, argc, argv)
+ ClientData clientData; /* Main window associated with
+ * interpreter. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ register Table *tablePtr;
+ Tk_Window tkwin = (Tk_Window) clientData;
+ Tk_Window new;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " pathname ?options?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
+ if (new == NULL) {
+ return TCL_ERROR;
+ }
+
+ tablePtr = (Table *) ckalloc(sizeof(Table));
+ tablePtr->tkwin = new;
+ tablePtr->display = Tk_Display(new);
+ tablePtr->interp = interp;
+
+ tablePtr->topRow = 0;
+ tablePtr->leftCol = 0;
+ tablePtr->anchorRow = -1;
+ tablePtr->anchorCol = -1;
+ tablePtr->activeRow = -1;
+ tablePtr->activeCol = -1;
+ tablePtr->oldTopRow = -1;
+ tablePtr->oldLeftCol = -1;
+ tablePtr->oldActRow = -1;
+ tablePtr->oldActCol = -1;
+ tablePtr->seen[0] = -1;
+ tablePtr->icursor = 0;
+ tablePtr->flags = 0;
+
+ tablePtr->colPixels = (int *) 0;
+ tablePtr->rowPixels = (int *) 0;
+ tablePtr->colStarts = (int *) 0;
+ tablePtr->rowStarts = (int *) 0;
+ tablePtr->cursorTimer = (Tcl_TimerToken)0;
+ tablePtr->flashTimer = (Tcl_TimerToken)0;
+ tablePtr->dataSource = DATA_NONE;
+ tablePtr->activeBuf = ckalloc(1);
+ *(tablePtr->activeBuf) = '\0';
+ tablePtr->activeLayout = NULL;
+
+ /* misc tables */
+ tablePtr->tagTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->tagTable, TCL_STRING_KEYS);
+ tablePtr->winTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->winTable, TCL_STRING_KEYS);
+
+ /* internal value cache */
+ tablePtr->cache = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->cache, TCL_STRING_KEYS);
+
+ /* style hash tables */
+ tablePtr->colWidths = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->colWidths, TCL_ONE_WORD_KEYS);
+ tablePtr->rowHeights = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->rowHeights, TCL_ONE_WORD_KEYS);
+
+ /* style hash tables */
+ tablePtr->rowStyles = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->rowStyles, TCL_ONE_WORD_KEYS);
+ tablePtr->colStyles = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->colStyles, TCL_ONE_WORD_KEYS);
+ tablePtr->cellStyles = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->cellStyles, TCL_STRING_KEYS);
+
+ /* special style hash tables */
+ tablePtr->flashCells = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->flashCells, TCL_STRING_KEYS);
+ tablePtr->selCells = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS);
+
+ tablePtr->rows = 0;
+ tablePtr->cols = 0;
+ tablePtr->selectMode = NULL;
+ tablePtr->selectTitles = 0;
+ tablePtr->defRowHeight = 0;
+ tablePtr->defColWidth = 0;
+ tablePtr->arrayVar = NULL;
+ tablePtr->borderWidth = 0;
+ tablePtr->defaultTag.anchor = TK_ANCHOR_CENTER;
+ tablePtr->defaultTag.bg = NULL;
+ tablePtr->defaultTag.fg = NULL;
+ tablePtr->defaultTag.tkfont = NULL;
+ tablePtr->defaultTag.image = NULL;
+ tablePtr->defaultTag.imageStr = NULL;
+ tablePtr->defaultTag.justify = TK_JUSTIFY_LEFT;
+ tablePtr->defaultTag.multiline = 1;
+ tablePtr->defaultTag.relief = TK_RELIEF_FLAT;
+ tablePtr->defaultTag.showtext = 0;
+ tablePtr->defaultTag.state = STATE_UNKNOWN;
+ tablePtr->defaultTag.wrap = 0;
+ tablePtr->yScrollCmd = NULL;
+ tablePtr->xScrollCmd = NULL;
+ tablePtr->insertBg = NULL;
+ tablePtr->cursor = None;
+ tablePtr->bdcursor = None;
+ tablePtr->titleRows = 0;
+ tablePtr->titleCols = 0;
+ tablePtr->drawMode = DRAW_MODE_TK_COMPAT;
+ tablePtr->colStretch = STRETCH_MODE_NONE;
+ tablePtr->rowStretch = STRETCH_MODE_NONE;
+ tablePtr->maxWidth = 0;
+ tablePtr->maxHeight = 0;
+ tablePtr->charWidth = 0;
+ tablePtr->charHeight = 0;
+ tablePtr->colOffset = 0;
+ tablePtr->rowOffset = 0;
+ tablePtr->flashTime = 2;
+ tablePtr->rowTagCmd = NULL;
+ tablePtr->colTagCmd = NULL;
+ tablePtr->highlightWidth = 0;
+ tablePtr->highlightBgColorPtr = NULL;
+ tablePtr->highlightColorPtr = NULL;
+ tablePtr->takeFocus = NULL;
+ tablePtr->state = STATE_NORMAL;
+ tablePtr->insertWidth = 0;
+ tablePtr->insertBorderWidth = 0;
+ tablePtr->insertOnTime = 0;
+ tablePtr->insertOffTime = 0;
+ tablePtr->invertSelected = 0;
+ tablePtr->autoClear = 0;
+ tablePtr->flashMode = 0;
+ tablePtr->exportSelection = 1;
+ tablePtr->rowSep = NULL;
+ tablePtr->colSep = NULL;
+ tablePtr->browseCmd = NULL;
+ tablePtr->command = NULL;
+ tablePtr->selCmd = NULL;
+ tablePtr->valCmd = NULL;
+ tablePtr->validate = 0;
+ tablePtr->useCmd = 1;
+ tablePtr->caching = 0;
+ tablePtr->padX = 0;
+ tablePtr->padY = 0;
+ tablePtr->maxReqCols = 0;
+ tablePtr->maxReqRows = 0;
+ tablePtr->maxReqWidth = 800;
+ tablePtr->maxReqHeight = 600;
+
+ /* selection handlers needed here */
+
+ Tk_ClassOption(new, "Table", &argc, &argv);
+ Tk_CreateEventHandler(tablePtr->tkwin,
+ PointerMotionMask|ExposureMask|StructureNotifyMask|FocusChangeMask|VisibilityChangeMask,
+ TableEventProc, (ClientData) tablePtr);
+ Tk_CreateSelHandler(tablePtr->tkwin, XA_PRIMARY, XA_STRING,
+ TableFetchSelection, (ClientData) tablePtr, XA_STRING);
+
+ tablePtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(tablePtr->tkwin),
+ TableWidgetCmd, (ClientData) tablePtr,
+ (Tcl_CmdDeleteProc *) TableCmdDeletedProc);
+ if (TableConfigure(interp, tablePtr, argc - 2, argv + 2, 0, 1) != TCL_OK) {
+ Tk_DestroyWindow(new);
+ return TCL_ERROR;
+ }
+ TableInitTags(tablePtr);
+ /* This is needed to avoid bug where the DLL is unloaded before
+ * the table is properly destroyed */
+ Tcl_CreateExitHandler((Tcl_ExitProc *) TableCmdDeletedProc,
+ (ClientData) tablePtr);
+ Tcl_SetResult(interp, Tk_PathName(tablePtr->tkwin), TCL_STATIC);
+ return TCL_OK;
+}
+
+/* Function to call on loading the Table module */
+
+EXPORT(int,Tktable_Init)(interp)
+ Tcl_Interp *interp;
+{
+ static char init_script[] =
+ "if {[catch {source \"" TCL_RUNTIME "\"}]} {\n"
+#include "tkTabletcl.h"
+ "}\n";
+ if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL ||
+ Tcl_PkgRequire(interp, "Tk", TK_VERSION, 0) == NULL ||
+ Tcl_PkgProvide(interp, "Tktable", TBL_VERSION) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ Tcl_CreateCommand(interp, TBL_COMMAND, TableCmd,
+ (ClientData) Tk_MainWindow(interp),
+ (Tcl_CmdDeleteProc *) NULL);
+
+ return Tcl_Eval(interp, init_script);
+}
+
+EXPORT(int,Tktable_SafeInit)(interp)
+ Tcl_Interp *interp;
+{
+ return Tktable_Init(interp);
+}
+
+#ifdef _WIN32
+/*
+ *----------------------------------------------------------------------
+ *
+ * DllEntryPoint --
+ *
+ * This wrapper function is used by Windows to invoke the
+ * initialization code for the DLL. If we are compiling
+ * with Visual C++, this routine will be renamed to DllMain.
+ * routine.
+ *
+ * Results:
+ * Returns TRUE;
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+BOOL APIENTRY
+DllEntryPoint(hInst, reason, reserved)
+ HINSTANCE hInst; /* Library instance handle. */
+ DWORD reason; /* Reason this function is being called. */
+ LPVOID reserved; /* Not used. */
+{
+ return TRUE;
+}
+#endif
tkTable.c
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: tclmain.c
===================================================================
--- tclmain.c (nonexistent)
+++ tclmain.c (revision 1765)
@@ -0,0 +1,100 @@
+/* tclmain.c - a simple main() for IDE programs that use Tk.
+ Copyright (C) 1997, 1998 Cygnus Solutions.
+ Written by Tom Tromey . */
+
+#include
+
+#include
+#include
+
+#include
+
+#ifdef HAVE_STDLIB_H
+#include
+#endif
+
+#ifdef _WIN32
+#include
+#include
+#endif
+
+#include "guitcl.h"
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* This is like Tk_Main, except that the resulting program doesn't try
+ to act like a script interpreter. It never reads commands from
+ stdin. */
+void
+ide_main (int argc, char *argv[], Tcl_AppInitProc *appInitProc)
+{
+ Tcl_Interp *interp;
+ char *args;
+ char buf[20];
+
+ Tcl_FindExecutable (argv[0]);
+ interp = Tcl_CreateInterp ();
+
+#ifdef TCL_MEM_DEBUG
+ Tcl_InitMemory (interp);
+#endif
+
+ args = Tcl_Merge (argc - 1, argv + 1);
+ Tcl_SetVar (interp, "argv", args, TCL_GLOBAL_ONLY);
+ Tcl_Free (args);
+
+ sprintf (buf, "%d", argc-1);
+ Tcl_SetVar (interp, "argc", buf, TCL_GLOBAL_ONLY);
+ Tcl_SetVar (interp, "argv0", argv[0], TCL_GLOBAL_ONLY);
+
+ /* We set this to "1" so that the console window will work. */
+ Tcl_SetVar (interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
+
+#if IDE_ENABLED
+ Tcl_SetVar (interp, "IDE_ENABLED", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar (interp, "IDE_ENABLED", "0", TCL_GLOBAL_ONLY);
+#endif
+
+ if ((*appInitProc) (interp) != TCL_OK)
+ {
+ Tcl_Channel err_channel;
+ char *msg;
+
+ /* Guarantee that errorInfo is set properly. */
+ Tcl_AddErrorInfo (interp, "");
+ msg = Tcl_GetVar (interp, "errorInfo", TCL_GLOBAL_ONLY);
+
+ /* On Windows, we are probably running as a windows app, and
+ stderr is the bit bucket, so we call a win32 function to
+ display the error. */
+
+#ifdef _WIN32
+ MessageBox (NULL, msg, NULL, MB_OK | MB_ICONERROR | MB_TASKMODAL);
+#else
+ err_channel = Tcl_GetStdChannel (TCL_STDERR);
+ if (err_channel)
+ {
+
+ Tcl_Write (err_channel, msg, -1);
+ Tcl_Write (err_channel, "\n", 1);
+ }
+#endif
+
+ Tcl_DeleteInterp (interp);
+ Tcl_Exit (EXIT_FAILURE);
+ }
+
+ Tcl_ResetResult (interp);
+
+ /* Now just go until the user decides to shut down. */
+ Tk_MainLoop ();
+ Tcl_DeleteInterp (interp);
+ Tcl_Exit (EXIT_SUCCESS);
+}
tclmain.c
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: subcommand.c
===================================================================
--- subcommand.c (nonexistent)
+++ subcommand.c (revision 1765)
@@ -0,0 +1,126 @@
+/* subcommand.c - Automate handling of subcommands in Tcl.
+ Copyright (C) 1997 Cygnus Solutions.
+ Written by Tom Tromey . */
+
+#include
+
+#include
+
+#include "subcommand.h"
+
+/* A pointer to this structure is the clientdata for
+ subcommand_implementation. */
+
+struct subcommand_clientdata
+{
+ const struct ide_subcommand_table *commands;
+ ClientData subdata;
+ Tcl_CmdDeleteProc *delete;
+};
+
+/* This is called when one of our commands is deleted. */
+static void
+subcommand_deleted (ClientData cd)
+{
+ struct subcommand_clientdata *data = (struct subcommand_clientdata *) cd;
+
+ if (data->delete)
+ (*data->delete) (data->subdata);
+ Tcl_Free ((char *) data);
+}
+
+/* This function implements any Tcl command registered as having
+ subcommands. The ClientData here must be a pointer to the command
+ table. */
+static int
+subcommand_implementation (ClientData cd, Tcl_Interp *interp,
+ int argc, char *argv[])
+{
+ struct subcommand_clientdata *data = (struct subcommand_clientdata *) cd;
+ const struct ide_subcommand_table *commands = data->commands;
+ int i;
+
+ if (argc < 2)
+ {
+ Tcl_AppendResult (interp, "wrong # args: must be \"",
+ argv[0], " key ?arg ...?\"", (char *) NULL);
+ return (TCL_ERROR);
+ }
+
+ for (i = 0; commands[i].method != NULL; ++i)
+ {
+ if (! strcmp (argv[1], commands[i].method))
+ {
+ if (argc < commands[i].min_args)
+ {
+ char buf[20];
+ Tcl_AppendResult (interp, "wrong # args: got ", (char *) NULL);
+ sprintf (buf, "%d", argc);
+ Tcl_AppendResult (interp, buf, " but expected at least ",
+ (char *) NULL);
+ sprintf (buf, "%d", commands[i].min_args);
+ Tcl_AppendResult (interp, buf, (char *) NULL);
+ return (TCL_ERROR);
+ }
+
+ if (commands[i].max_args > 0 && argc > commands[i].max_args)
+ {
+ char buf[20];
+ Tcl_AppendResult (interp, "wrong # args: got ", (char *) NULL);
+ sprintf (buf, "%d", argc);
+ Tcl_AppendResult (interp, buf, " but expected at most ",
+ (char *) NULL);
+ sprintf (buf, "%d", commands[i].max_args);
+ Tcl_AppendResult (interp, buf, (char *) NULL);
+ return (TCL_ERROR);
+ }
+
+ return (commands[i].func (data->subdata, interp, argc, argv));
+ }
+ }
+
+ Tcl_AppendResult (interp, "unrecognized key \"", argv[1],
+ "\"; must be one of ", (char *) NULL);
+ for (i = 0; commands[i].method != NULL; ++i)
+ Tcl_AppendResult (interp, "\"", commands[i].method,
+ (commands[i + 1].method == NULL) ? "\"" : "\", ",
+ (char *) NULL);
+ return (TCL_ERROR);
+}
+
+/* Define a command with subcommands. */
+int
+ide_create_command_with_subcommands (Tcl_Interp *interp, char *name,
+ const struct ide_subcommand_table *table,
+ ClientData subdata,
+ Tcl_CmdDeleteProc *delete)
+{
+ int i;
+ struct subcommand_clientdata *data;
+
+ /* Sanity check. */
+ for (i = 0; table[i].method != NULL; ++i)
+ {
+ if ((table[i].min_args > table[i].max_args && table[i].max_args != -1)
+ || table[i].min_args < 2
+ || table[i].max_args < -1)
+ {
+ Tcl_AppendResult (interp, "subcommand \"", table[i].method,
+ "\" of command \"", name,
+ "\" has bad argument count",
+ (char *) NULL);
+ return (TCL_ERROR);
+ }
+ }
+
+ data = (struct subcommand_clientdata *) Tcl_Alloc (sizeof *data);
+ data->commands = table;
+ data->subdata = subdata;
+ data->delete = delete;
+
+ if (Tcl_CreateCommand (interp, name, subcommand_implementation,
+ (ClientData) data, subcommand_deleted) == NULL)
+ return (TCL_ERROR);
+
+ return (TCL_OK);
+}
subcommand.c
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: tkCanvLayout.h
===================================================================
--- tkCanvLayout.h (nonexistent)
+++ tkCanvLayout.h (revision 1765)
@@ -0,0 +1,117 @@
+#ifndef LAYOUT_H
+#define LAYOUT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+Unlike the original code, we assume that the set of nodes
+known to this layout graph is always kept 1-1 with the set
+of dual nodes. Similarly with respect to edges.
+This implies that every time a dual is created/deleted,
+that the corresponding create/delete methods must be
+called in the layout graph class.
+Additionally, we assume the existence of two ``update''
+methods that propagate the correct location and size info
+between the layout graph nodes and their duals.
+*/
+
+struct Layout_Graph; /* hidden */
+
+/* ptr to user's node info */
+typedef void* pItem;
+
+/*
+As inputs, we need the following:
+
+For nodes: bbox that just surrounds the node.
+For edges: width and height of the text (if any)
+ associated with the edge.
+
+As outputs, we provide the following:
+
+For nodes: new absolute position of the northwest corner
+ of the bbox for the node.
+For edges: (x,y) coordinates of the endpoints of the edge.
+
+To avoid proliferation of types,
+we define a single struct (ItemGeom)
+that is used to carry all the input and output info.
+
+Item type Direction ItemGeom Fields Used
+--------- --------- --------------------
+Node In x1,y1,x2,y2
+ Out x1,y1
+Edge In width,height
+ Out x1,y1,x2,y2
+
+*/
+
+/* All values are in pixels */
+struct ItemGeom {
+ double x1,y1;
+ double x2,y2;
+ double width,height;
+};
+typedef struct ItemGeom ItemGeom;
+
+struct LayoutConfig {
+ pItem rootnode;
+ int graphorder;
+ int nodespaceH;
+ int nodespaceV;
+ int xoffset;
+ int yoffset;
+ int computenodesize;
+ int elementsperline;
+ int hideedges;
+ int keeprandompositions;
+ int maxx;
+ int maxy;
+ int gridlock;
+};
+typedef struct LayoutConfig LayoutConfig;
+
+extern LayoutConfig GetLayoutConfig _ANSI_ARGS_((struct Layout_Graph*));
+extern void SetLayoutConfig _ANSI_ARGS_((struct Layout_Graph*, LayoutConfig));
+
+extern int LayoutISI _ANSI_ARGS_((struct Layout_Graph*));
+extern int LayoutTree _ANSI_ARGS_((struct Layout_Graph*));
+extern int LayoutMatrix _ANSI_ARGS_((struct Layout_Graph*));
+extern int LayoutRandom _ANSI_ARGS_((struct Layout_Graph*));
+
+#if DEBUGGING
+extern void LayoutDebugging _ANSI_ARGS_((struct Layout_Graph*, struct Node *currentnode, char *string, int type));
+#endif
+
+extern struct Layout_Graph* LayoutCreateGraph _ANSI_ARGS_(());
+extern void LayoutFreeGraph _ANSI_ARGS_((struct Layout_Graph*));
+extern void LayoutClearGraph _ANSI_ARGS_((struct Layout_Graph*));
+
+extern int LayoutCreateNode _ANSI_ARGS_((struct Layout_Graph*,
+ pItem nodeid,
+ pItem from, pItem to));
+extern int LayoutDeleteNode _ANSI_ARGS_((struct Layout_Graph*, pItem nodeid));
+extern int LayoutCreateEdge _ANSI_ARGS_((struct Layout_Graph*,
+ pItem edgeid,
+ pItem from, pItem to));
+extern int LayoutDeleteEdge _ANSI_ARGS_((struct Layout_Graph*, pItem edgeid));
+
+extern int LayoutGetIthNode _ANSI_ARGS_((struct Layout_Graph*, long, pItem*));
+
+extern int LayoutGetIthEdge _ANSI_ARGS_((struct Layout_Graph*, long, pItem*));
+
+extern int LayoutGetNodeBBox _ANSI_ARGS_((struct Layout_Graph*, pItem, ItemGeom*));
+extern int LayoutSetNodeBBox _ANSI_ARGS_((struct Layout_Graph*, pItem, ItemGeom));
+
+extern int LayoutGetEdgeEndPoints _ANSI_ARGS_((struct Layout_Graph*, pItem, ItemGeom*));
+extern int LayoutSetEdgeDim _ANSI_ARGS_((struct Layout_Graph*, pItem, ItemGeom));
+
+extern char* LayoutGetError _ANSI_ARGS_((struct Layout_Graph*));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*LAYOUT_H*/
tkCanvLayout.h
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: tkTable.h
===================================================================
--- tkTable.h (nonexistent)
+++ tkTable.h (revision 1765)
@@ -0,0 +1,418 @@
+/*
+ * tkTable.h --
+ *
+ * This is the header file for the module that implements
+ * table widgets for the Tk toolkit.
+ *
+ * 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 _TKTABLE_H_
+#define _TKTABLE_H_
+
+#include
+#include
+#include
+#include
+
+#include "tkTableCmd.h"
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include
+# undef WIN32_LEAN_AND_MEAN
+
+/*
+ * VC++ has an alternate entry point called DllMain, so we need to rename
+ * our entry point.
+ */
+
+# if defined(_MSC_VER)
+# define EXPORT(a,b) __declspec(dllexport) a b
+# define DllEntryPoint DllMain
+# else
+# if defined(__BORLANDC__)
+# define EXPORT(a,b) a _export b
+# else
+# define EXPORT(a,b) a b
+# endif
+# endif
+
+/* Necessary to get XSync call defined */
+# include
+
+#else /* ! WIN32 */
+# define EXPORT(a,b) a b
+#endif /* WIN32 */
+
+#ifdef INLINE
+#undef INLINE
+#endif
+#ifdef __GNUC__
+# define INLINE inline
+#else
+# if defined(_MSC_VER)
+# define INLINE __inline
+# else
+# define INLINE
+# endif
+#endif
+
+#ifndef NORMAL_BG
+# ifdef _WIN32
+# define NORMAL_BG "SystemButtonFace"
+# define ACTIVE_BG NORMAL_BG
+# define SELECT_BG "SystemHighlight"
+# define DISABLED "SystemDisabledText"
+# define HIGHLIGHT "SystemWindowFrame"
+# define DEF_TABLE_FONT "{MS Sans Serif} 8"
+# else
+# define NORMAL_BG "#d9d9d9"
+# define ACTIVE_BG "#fcfcfc"
+# define SELECT_BG "#c3c3c3"
+# define DISABLED "#a3a3a3"
+# define HIGHLIGHT "Black"
+# define DEF_TABLE_FONT "Helvetica -12"
+# endif
+#endif
+
+#define MAX(A,B) (((A)>(B))?(A):(B))
+#define MIN(A,B) (((A)>(B))?(B):(A))
+#define ARSIZE(A) (sizeof(A)/sizeof(*A))
+#define INDEX_BUFSIZE 64 /* max size of buffer for indices */
+#define TEST_KEY "#TEST KEY#" /* index for testing array existence */
+
+/*
+ * Assigned bits of "flags" fields of Table structures, and what those
+ * bits mean:
+ *
+ * REDRAW_PENDING: Non-zero means a DoWhenIdle handler has
+ * already been queued to redisplay the table.
+ * REDRAW_BORDER: Non-zero means 3-D border must be redrawn
+ * around window during redisplay. Normally
+ * only text portion needs to be redrawn.
+ * CURSOR_ON: Non-zero means insert cursor is displayed at
+ * present. 0 means it isn't displayed.
+ * TEXT_CHANGED: Non-zero means the active cell text is being edited.
+ * HAS_FOCUS: Non-zero means this window has the input focus.
+ * HAS_ACTIVE: Non-zero means the active cell is set.
+ * HAS_ANCHOR: Non-zero means the anchor cell is set.
+ * BROWSE_CMD: Non-zero means we're evaluating the -browsecommand.
+ * VALIDATING: Non-zero means we are in a valCmd
+ * SET_ACTIVE: About to set the active array element internally
+ * ACTIVE_DISABLED: Non-zero means the active cell is -state disabled
+ * OVER_BORDER: Non-zero means we are over a table cell border
+ * REDRAW_ON_MAP: Forces a redraw on the unmap
+ *
+ * FIX - consider adding UPDATE_SCROLLBAR a la entry
+ */
+#define REDRAW_PENDING (1L<<0)
+#define CURSOR_ON (1L<<1)
+#define HAS_FOCUS (1L<<2)
+#define TEXT_CHANGED (1L<<3)
+#define HAS_ACTIVE (1L<<4)
+#define HAS_ANCHOR (1L<<5)
+#define BROWSE_CMD (1L<<6)
+#define REDRAW_BORDER (1L<<7)
+#define VALIDATING (1L<<8)
+#define SET_ACTIVE (1L<<9)
+#define ACTIVE_DISABLED (1L<<10)
+#define OVER_BORDER (1L<<11)
+#define REDRAW_ON_MAP (1L<<12)
+
+/* Flags for TableInvalidate && TableRedraw */
+#define ROW (1L<<0)
+#define COL (1L<<1)
+#define CELL (ROW|COL)
+#define INV_FILL (1L<<3) /* use for Redraw when the affected
+ * row/col will affect neighbors */
+#define INV_FORCE (1L<<4)
+#define INV_HIGHLIGHT (1L<<5)
+
+/*
+ * Definitions for tablePtr->dataSource, by bit
+ */
+#define DATA_NONE 0
+#define DATA_CACHE (1<<1)
+#define DATA_ARRAY (1<<2)
+#define DATA_COMMAND (1<<3)
+
+typedef enum {
+ STATE_UNUSED, STATE_UNKNOWN, STATE_HIDDEN,
+ STATE_NORMAL, STATE_DISABLED, STATE_ACTIVE,
+ STATE_LAST
+} TableState;
+
+/* The tag structure */
+typedef struct {
+ Tk_3DBorder bg; /* background color */
+ Tk_3DBorder fg; /* foreground color */
+ int relief; /* relief type */
+ Tk_Font tkfont; /* Information about text font, or NULL. */
+ Tk_Anchor anchor; /* default anchor point */
+ char * imageStr; /* name of image */
+ Tk_Image image; /* actual pointer to image, if any */
+ TableState state; /* state of the cell */
+ Tk_Justify justify; /* justification of text in the cell */
+ int multiline; /* wrapping style of multiline text */
+ int wrap; /* wrapping style of multiline text */
+ int showtext; /* whether to display text over image */
+} TableTag;
+
+/* The widget structure for the table Widget */
+
+typedef struct {
+ /* basic information about the window and the interpreter */
+ Tk_Window tkwin;
+ Display *display;
+ Tcl_Interp *interp;
+ Tcl_Command widgetCmd; /* Token for entry's widget command. */
+ /* Configurable Options */
+ int autoClear;
+ char *selectMode; /* single, browse, multiple, or extended */
+ int selectType; /* row, col, both, or cell */
+ int selectTitles; /* whether to do automatic title selection */
+ int rows, cols; /* number of rows and columns */
+ int defRowHeight; /* default row height in chars (positive)
+ * or pixels (negative) */
+ int defColWidth; /* default column width in chars (positive)
+ * or pixels (negative) */
+ int maxReqCols; /* the requested # cols to display */
+ int maxReqRows; /* the requested # rows to display */
+ int maxReqWidth; /* the maximum requested width in pixels */
+ int maxReqHeight; /* the maximum requested height in pixels */
+ char *arrayVar; /* name of traced array variable */
+ char *rowSep; /* separator string to place between
+ * rows when getting selection */
+ char *colSep; /* separator string to place between
+ * cols when getting selection */
+ int borderWidth; /* internal borderwidth */
+ TableTag defaultTag; /* the default tag colors/fonts etc */
+ char *yScrollCmd; /* the y-scroll command */
+ char *xScrollCmd; /* the x-scroll command */
+ char *browseCmd; /* the command that is called when the
+ * active cell changes */
+ int caching; /* whether to cache values of table */
+ char *command; /* A command to eval when get/set occurs
+ * for table values */
+ int useCmd; /* Signals whether to use command or the
+ * array variable, will be 0 if command errs */
+ char *selCmd; /* the command that is called to when a
+ * [selection get] call occurs for a table */
+ char *valCmd; /* Command prefix to use when invoking
+ * validate command. NULL means don't
+ * invoke commands. Malloc'ed. */
+ int validate; /* Non-zero means try to validate */
+ Tk_3DBorder insertBg; /* the cursor color */
+ Tk_Cursor cursor; /* the regular mouse pointer */
+ Tk_Cursor bdcursor; /* the mouse pointer when over borders */
+ int exportSelection; /* Non-zero means tie internal table
+ * to X selection. */
+ TableState state; /* Normal or disabled. Table is read-only
+ * when disabled. */
+ int insertWidth; /* Total width of insert cursor. */
+ int insertBorderWidth; /* Width of 3-D border around insert cursor. */
+ int insertOnTime; /* Number of milliseconds cursor should spend
+ * in "on" state for each blink. */
+ int insertOffTime; /* Number of milliseconds cursor should spend
+ * in "off" state for each blink. */
+ int invertSelected; /* Whether to draw selected cells swapping
+ foreground and background */
+ int colStretch; /* The way to stretch columns if the window
+ is too large */
+ int rowStretch; /* The way to stretch rows if the window is
+ too large */
+ int colOffset; /* X index of leftmost col in the display */
+ int rowOffset; /* Y index of topmost row in the display */
+ int drawMode; /* The mode to use when redrawing */
+ int flashMode; /* Specifies whether flashing is enabled */
+ int flashTime; /* The number of ms to flash a cell for */
+ int resize; /* -resizeborders option for interactive
+ * resizing of borders */
+ char *rowTagCmd, *colTagCmd; /* script to eval for getting row/tag cmd */
+ int highlightWidth; /* Width in pixels of highlight to draw
+ * around widget when it has the focus.
+ * <= 0 means don't draw a highlight. */
+ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight
+ * area when highlight is off. */
+ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
+ char *takeFocus; /* Used only in Tcl to check if this
+ * widget will accept focus */
+ int padX, padY; /* Extra space around text (pixels to leave
+ * on each side). Ignored for bitmaps and
+ * images. */
+
+ /* Cached Information */
+ int titleRows, titleCols; /* the number of rows|cols to use as a title */
+ /* these are kept in real coords */
+ int topRow, leftCol; /* The topleft cell to display excluding the
+ * fixed title rows. This is just the
+ * config request. The actual cell used may
+ * be different to keep the screen full */
+ int anchorRow, anchorCol; /* the row,col of the anchor cell */
+ int activeRow, activeCol; /* the row,col of the active cell */
+ int oldTopRow, oldLeftCol; /* cached by TableAdjustParams */
+ int oldActRow, oldActCol; /* cached by TableAdjustParams */
+ int icursor; /* The index of the insertion cursor in the
+ active cell */
+ int flags; /* An or'ed combination of flags concerning
+ redraw/cursor etc. */
+ int dataSource; /* where our data comes from:
+ * DATA_{NONE,CACHE,ARRAY,COMMAND} */
+ int maxWidth, maxHeight; /* max width|height required in pixels */
+ int charWidth, charHeight; /* size of a character in the default font */
+ int *colPixels; /* Array of the pixel width of each column */
+ int *rowPixels; /* Array of the pixel height of each row */
+ int *colStarts, *rowStarts; /* Array of start pixels for rows|columns */
+ int scanMarkX, scanMarkY; /* Used by "scan" and "border" to mark */
+ int scanMarkRow, scanMarkCol; /* necessary information for dragto */
+ /* values in these are kept in user coords */
+ Tcl_HashTable *cache; /* value cache */
+ /* colWidths and rowHeights are indexed from 0, so always adjust numbers
+ by the appropriate *Offset factor */
+ Tcl_HashTable *colWidths; /* hash table of non default column widths */
+ Tcl_HashTable *rowHeights; /* hash table of non default row heights */
+ Tcl_HashTable *tagTable; /* table for style tags */
+ Tcl_HashTable *winTable; /* table for embedded windows */
+ Tcl_HashTable *rowStyles; /* table for row styles */
+ Tcl_HashTable *colStyles; /* table for col styles */
+ Tcl_HashTable *cellStyles; /* table for cell styles */
+ Tcl_HashTable *flashCells; /* table of flashing cells */
+ Tcl_HashTable *selCells; /* table of selected cells */
+ Tcl_TimerToken cursorTimer; /* timer token for the cursor blinking */
+ Tcl_TimerToken flashTimer; /* timer token for the cell flashing */
+ char *activeBuf; /* buffer where the selection is kept
+ for editing the active cell */
+ Tk_TextLayout activeLayout; /* cache of active layout */
+ int activeX, activeY; /* cache offset of active layout in cell */
+ /* The invalid rectangle if there is an update pending */
+ int invalidX, invalidY, invalidWidth, invalidHeight;
+ int seen[4]; /* see TableUndisplay */
+} Table;
+
+/*
+ * HEADERS FOR EMBEDDED WINDOWS
+ */
+
+/*
+ * A structure of the following type holds information for each window
+ * embedded in a table widget.
+ */
+
+typedef struct TableEmbWindow {
+ Table *tablePtr; /* Information about the overall table
+ * widget. */
+ Tk_Window tkwin; /* Window for this segment. NULL
+ * means that the window hasn't
+ * been created yet. */
+ Tcl_HashEntry *hPtr; /* entry into winTable */
+ Tk_3DBorder bg; /* background color */
+ char *create; /* Script to create window on-demand.
+ * NULL means no such script.
+ * Malloc-ed. */
+ int relief; /* relief type */
+ int sticky; /* How to align window in space */
+ int padX, padY; /* Padding to leave around each side
+ * of window, in pixels. */
+ int displayed; /* Non-zero means that the window
+ * has been displayed on the screen
+ * recently. */
+} TableEmbWindow;
+
+extern void EmbWinDisplay _ANSI_ARGS_((Table *tablePtr, Drawable window,
+ TableEmbWindow *ewPtr,
+ TableTag *tagPtr, int x, int y,
+ int width, int height));
+extern void EmbWinUnmap _ANSI_ARGS_((register Table *tablePtr,
+ int rlo, int rhi,
+ int clo, int chi));
+extern void EmbWinDelete _ANSI_ARGS_((register Table *tablePtr,
+ TableEmbWindow *ewPtr));
+extern int TableWindowCmd _ANSI_ARGS_((Table *tablePtr,
+ Tcl_Interp *interp,
+ int argc, char *argv[]));
+
+/*
+ * HEADERS IN TKTABLETAG
+ */
+
+extern TableTag *TableNewTag _ANSI_ARGS_((void));
+extern void TableMergeTag _ANSI_ARGS_((TableTag *baseTag,
+ TableTag *addTag));
+extern void TableInvertTag _ANSI_ARGS_((TableTag *baseTag));
+extern void TableInitTags _ANSI_ARGS_((Table *tablePtr));
+extern TableTag *FindRowColTag _ANSI_ARGS_((Table *tablePtr,
+ int cell, int type));
+extern void TableCleanupTag _ANSI_ARGS_((Table *tablePtr,
+ TableTag *tagPtr));
+extern int TableTagCmd _ANSI_ARGS_((Table *tablePtr, Tcl_Interp *interp,
+ int argc, char *argv[]));
+
+/*
+ * HEADERS IN TKTABLECELL
+ */
+
+extern void TableCellCoords _ANSI_ARGS_((Table *tablePtr, int row,
+ int col, int *rx, int *ry,
+ int *rw, int *rh));
+extern int TableCellVCoords _ANSI_ARGS_((Table *tablePtr, int row,
+ int col, int *rx, int *ry,
+ int *rw, int *rh, int full));
+extern void TableWhatCell _ANSI_ARGS_((register Table *tablePtr,
+ int x, int y, int *row, int *col));
+extern int TableAtBorder _ANSI_ARGS_((Table *tablePtr, int x, int y,
+ int *row, int *col));
+extern char * TableGetCellValue _ANSI_ARGS_((Table *tablePtr, int r, int c));
+extern int TableSetCellValue _ANSI_ARGS_((Table *tablePtr, int r, int c,
+ char *value));
+extern char * TableCellSort _ANSI_ARGS_((Table *tablePtr, char *str));
+extern int TableGetIcursor _ANSI_ARGS_((Table *tablePtr, char *arg,
+ int *posn));
+extern int TableGetIndex _ANSI_ARGS_((register Table *tablePtr, char *str,
+ int *row_p, int *col_p));
+
+/*
+ * HEADERS IN TKTABLE
+ */
+
+EXTERN EXPORT(int,Example_Init) _ANSI_ARGS_((Tcl_Interp *interp));
+
+extern void ExpandPercents _ANSI_ARGS_((Table *tablePtr, char *before,
+ int r, int c, char *old, char *new, int index,
+ Tcl_DString *dsPtr, int cmdType));
+extern void TableInvalidate _ANSI_ARGS_((Table *tablePtr, int x, int y,
+ int width, int height,
+ int force));
+extern void TableRefresh _ANSI_ARGS_((register Table *tablePtr,
+ int arg1, int arg2, int mode));
+
+#define TableInvalidateAll(tablePtr, flags) \
+ TableInvalidate((tablePtr), 0, 0, Tk_Width((tablePtr)->tkwin),\
+ Tk_Height((tablePtr)->tkwin), (flags))
+
+ /*
+ * Turn row/col into an index into the table
+ */
+#define TableMakeArrayIndex(r, c, i) sprintf((i), "%d,%d", (r), (c))
+
+ /*
+ * Turn array index back into row/col
+ * return the number of args parsed (should be two)
+ */
+#define TableParseArrayIndex(r, c, i) sscanf((i), "%d,%d", (r), (c))
+
+ /*
+ * Macro for finding the last cell of the table
+ */
+#define TableGetLastCell(tablePtr, rowPtr, colPtr) \
+ TableWhatCell((tablePtr),\
+ Tk_Width((tablePtr)->tkwin)-(tablePtr)->highlightWidth,\
+ Tk_Height((tablePtr)->tkwin)-(tablePtr)->highlightWidth,\
+ (rowPtr), (colPtr))
+
+#endif /* _TKTABLE_H_ */
+
tkTable.h
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: xpmlib.c
===================================================================
--- xpmlib.c (nonexistent)
+++ xpmlib.c (revision 1765)
@@ -0,0 +1,1592 @@
+/**
+ * tixImgXpm.c --
+ *
+ * This file implements images of type "pixmap" for Tix.
+ * ______________________________________________________________________
+ *
+ * Copyright statement for tixImgXpm.c
+ * Copyright 1996, Expert Interface Technologies
+ *
+ * The following terms apply only to this file and no other parts of the
+ * Tix library.
+ *
+ * Permission is hereby granted, without written agreement and
+ * without license or royalty fees, to use, copy, modify, and
+ * distribute this file, for any purpose, provided that existing
+ * copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions.
+ *
+ * DISCLAIMER OF ALL WARRANTIES
+ *
+ * IN NO EVENT SHALL THE AUTHOR OF THIS SOFTWARE 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 AUTHOR OF THIS SOFTWARE HAS
+ * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE AUTHOR OF THIS SOFTWARE 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 AUTHOR OF THIS SOFTWARE HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+ * MODIFICATIONS.
+ * ___________________________________________________________________
+ *
+ * This file is adapted from the Tk 4.0 source file tkImgBmap.c
+ * Original tkImgBmap.c copyright information:
+ *
+ * Copyright (c) 1994 The Regents of the University of California.
+ * Copyright (c) 1994-1995 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms.tcltk" for information on usage
+ * and redistribution of the original tkImgBmap.c file, and for a
+ * DISCLAIMER OF ALL WARRANTIES from the authors of tkImgBmap.c.
+ */
+#include "tkInt.h"
+#include "tkPort.h"
+
+#include "guitcl.h"
+
+/* constants used only in this file */
+
+#define XPM_MONO 1
+#define XPM_GRAY_4 2
+#define XPM_GRAY 3
+#define XPM_COLOR 4
+#define XPM_SYMBOLIC 5
+#define XPM_UNKNOWN 6
+
+/*
+ * The following data structure represents the master for a pixmap
+ * image:
+ */
+
+typedef struct PixmapMaster {
+ Tk_ImageMaster tkMaster; /* Tk's token for image master. NULL means
+ * the image is being deleted. */
+ Tcl_Interp *interp; /* Interpreter for application that is
+ * using image. */
+ Tcl_Command imageCmd; /* Token for image command (used to delete
+ * it when the image goes away). NULL means
+ * the image command has already been
+ * deleted. */
+ char *fileString; /* Value of -file option (malloc'ed).
+ * valid only if the -file option is specified
+ */
+ char *dataString; /* Value of -data option (malloc'ed).
+ * valid only if the -data option is specified
+ */
+ /* First in list of all instances associated
+ * with this master. */
+ Tk_Uid id; /* ID's for XPM data already compiled
+ * into the tixwish binary */
+ int size[2]; /* width and height */
+ int ncolors; /* number of colors */
+ int cpp; /* characters per pixel */
+ char ** data; /* The data that defines this pixmap
+ * image (array of strings). It is
+ * converted into an X Pixmap when this
+ * image is instanciated
+ */
+ int isDataAlloced; /* False iff the data is got from
+ * the -id switch */
+ struct PixmapInstance *instancePtr;
+} PixmapMaster;
+
+/* Make this more portable */
+
+typedef struct ColorStruct {
+ char c; /* This is used if CPP is one */
+ char * cstring; /* This is used if CPP is bigger than one */
+ XColor * colorPtr;
+} ColorStruct;
+
+/*
+ * The following data structure represents all of the instances of an
+ * image that lie within a particular window:
+ *
+ * %% ToDo
+ * Currently one instance is created for each window that uses this pixmap.
+ * This is usually OK because pixmaps are usually not shared or only shared by
+ * a small number of windows. To improve resource allocation, we can
+ * create an instance for each (Display x Visual x Depth) combo. This will
+ * usually reduce the number of instances to one.
+ */
+typedef struct PixmapInstance {
+ int refCount; /* Number of instances that share this
+ * data structure. */
+ PixmapMaster *masterPtr; /* Pointer to master for image. */
+ Tk_Window tkwin; /* Window in which the instances will be
+ * displayed. */
+ Pixmap pixmap; /* The pixmap to display. */
+ Pixmap mask; /* Mask: only display pixmap pixels where
+ * there are 1's here. */
+ GC gc; /* Graphics context for displaying pixmap.
+ * None means there was an error while
+ * setting up the instance, so it cannot
+ * be displayed. */
+ struct PixmapInstance *nextPtr;
+ /* Next in list of all instance structures
+ * associated with masterPtr (NULL means
+ * end of list).
+ */
+ ColorStruct * colors;
+} PixmapInstance;
+
+/*
+ * The type record for pixmap images:
+ */
+
+static int ImgXpmCreate _ANSI_ARGS_((Tcl_Interp *interp,
+ char *name, int argc, Tcl_Obj *CONST objv[],
+ Tk_ImageType *typePtr, Tk_ImageMaster master,
+ ClientData *clientDataPtr));
+static ClientData ImgXpmGet _ANSI_ARGS_((Tk_Window tkwin,
+ ClientData clientData));
+static void ImgXpmDisplay _ANSI_ARGS_((ClientData clientData,
+ Display *display, Drawable drawable,
+ int imageX, int imageY, int width, int height,
+ int drawableX, int drawableY));
+static void ImgXpmFree _ANSI_ARGS_((ClientData clientData,
+ Display *display));
+static void ImgXpmDelete _ANSI_ARGS_((ClientData clientData));
+
+static Tk_ImageType tixPixmapImageType = {
+ "pixmap", /* name */
+ ImgXpmCreate, /* createProc */
+ ImgXpmGet, /* getProc */
+ ImgXpmDisplay, /* displayProc */
+ ImgXpmFree, /* freeProc */
+ ImgXpmDelete, /* deleteProc */
+ (Tk_ImageType *) NULL /* nextPtr */
+};
+
+/*
+ * Information used for parsing configuration specs:
+ */
+
+static Tk_ConfigSpec configSpecs[] = {
+ {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(PixmapMaster, dataString), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(PixmapMaster, fileString), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_UID, "-id", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(PixmapMaster, id), TK_CONFIG_NULL_OK},
+ {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, 0}
+};
+
+/*
+ * Prototypes for procedures used only locally in this file:
+ */
+static int ImgXpmCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int argc, char **argv));
+static void ImgXpmCmdDeletedProc _ANSI_ARGS_((
+ ClientData clientData));
+static void ImgXpmConfigureInstance _ANSI_ARGS_((
+ PixmapInstance *instancePtr));
+static int ImgXpmConfigureMaster _ANSI_ARGS_((
+ PixmapMaster *masterPtr, int argc, char **argv,
+ int flags));
+static int ImgXpmGetData _ANSI_ARGS_((Tcl_Interp *interp,
+ PixmapMaster *masterPtr));
+static char ** ImgXpmGetDataFromFile _ANSI_ARGS_((Tcl_Interp * interp,
+ char * string, int * numLines_return));
+static char ** ImgXpmGetDataFromId _ANSI_ARGS_((Tcl_Interp * interp,
+ char * id));
+static char ** ImgXpmGetDataFromString _ANSI_ARGS_((Tcl_Interp*interp,
+ char * string, int * numLines_return));
+static void ImgXpmGetPixmapFromData _ANSI_ARGS_((
+ Tcl_Interp * interp,
+ PixmapMaster *masterPtr,
+ PixmapInstance *instancePtr));
+
+/* Local data, used only in this file */
+static Tcl_HashTable xpmTable;
+static int xpmTableInited = 0;
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ImgXpmCreate --
+ *
+ * This procedure is called by the Tk image code to create "pixmap"
+ * images.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * The data structure for a new image is allocated.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+ImgXpmCreate(interp, name, argc, objv, typePtr, master, clientDataPtr)
+ Tcl_Interp *interp; /* Interpreter for application containing
+ * image. */
+ char *name; /* Name to use for image. */
+ int argc; /* Number of arguments. */
+ Tcl_Obj *CONST objv[]; /* Argument strings for options (doesn't
+ * include image name or type). */
+ Tk_ImageType *typePtr; /* Pointer to our type record (not used). */
+ Tk_ImageMaster master; /* Token for image, to be used by us in
+ * later callbacks. */
+ ClientData *clientDataPtr; /* Store manager's token for image here;
+ * it will be returned in later callbacks. */
+{
+ PixmapMaster *masterPtr;
+ char **argv;
+ int i;
+
+ masterPtr = (PixmapMaster *) ckalloc(sizeof(PixmapMaster));
+ masterPtr->tkMaster = master;
+ masterPtr->interp = interp;
+ masterPtr->imageCmd = Tcl_CreateCommand(interp, name, ImgXpmCmd,
+ (ClientData) masterPtr, ImgXpmCmdDeletedProc);
+
+ masterPtr->fileString = NULL;
+ masterPtr->dataString = NULL;
+ masterPtr->id = NULL;
+ masterPtr->data = NULL;
+ masterPtr->isDataAlloced = 0;
+ masterPtr->instancePtr = NULL;
+
+ argv = (char **) ckalloc (argc * sizeof (char *));
+ for (i = 0; i < argc; i++) {
+ argv[i] = Tcl_GetStringFromObj(objv[i], (int *) NULL);
+ }
+
+ if (ImgXpmConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) {
+ ImgXpmDelete((ClientData) masterPtr);
+ ckfree ((char *) argv);
+ return TCL_ERROR;
+ }
+ ckfree ((char *) argv);
+ *clientDataPtr = (ClientData) masterPtr;
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ImgXpmConfigureMaster --
+ *
+ * This procedure is called when a pixmap image is created or
+ * reconfigured. It process configuration options and resets
+ * any instances of the image.
+ *
+ * Results:
+ * A standard Tcl return value. If TCL_ERROR is returned then
+ * an error message is left in masterPtr->interp->result.
+ *
+ * Side effects:
+ * Existing instances of the image will be redisplayed to match
+ * the new configuration options.
+ *
+ * If any error occurs, the state of *masterPtr is restored to
+ * previous state.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+ImgXpmConfigureMaster(masterPtr, argc, argv, flags)
+ PixmapMaster *masterPtr; /* Pointer to data structure describing
+ * overall pixmap image to (reconfigure). */
+ int argc; /* Number of entries in argv. */
+ char **argv; /* Pairs of configuration options for image. */
+ int flags; /* Flags to pass to Tk_ConfigureWidget,
+ * such as TK_CONFIG_ARGV_ONLY. */
+{
+ PixmapInstance *instancePtr;
+ char * oldData, * oldFile;
+ Tk_Uid oldId;
+
+ oldData = masterPtr->dataString;
+ oldFile = masterPtr->fileString;
+ oldId = masterPtr->id;
+
+ if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp),
+ configSpecs, argc, argv, (char *) masterPtr, flags)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ if (masterPtr->id != NULL ||
+ masterPtr->dataString != NULL ||
+ masterPtr->fileString != NULL) {
+ if (ImgXpmGetData(masterPtr->interp, masterPtr) != TCL_OK) {
+ goto error;
+ }
+ } else {
+ Tcl_AppendResult(masterPtr->interp,
+ "must specify one of -data, -file or -id", NULL);
+ goto error;
+ }
+
+ /*
+ * Cycle through all of the instances of this image, regenerating
+ * the information for each instance. Then force the image to be
+ * redisplayed everywhere that it is used.
+ */
+ for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
+ instancePtr = instancePtr->nextPtr) {
+ ImgXpmConfigureInstance(instancePtr);
+ }
+
+ if (masterPtr->data) {
+ Tk_ImageChanged(masterPtr->tkMaster, 0, 0,
+ masterPtr->size[0], masterPtr->size[1],
+ masterPtr->size[0], masterPtr->size[1]);
+ } else {
+ Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, 0, 0);
+ }
+
+ done:
+ return TCL_OK;
+
+ error:
+ /* Restore it to the original (possible valid) mode */
+ masterPtr->dataString = oldData;
+ masterPtr->fileString = oldFile;
+ masterPtr->id = oldId;
+ return TCL_ERROR;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ImgXpmGetData --
+ *
+ * Given a file name or ASCII string, this procedure parses the
+ * file or string contents to produce binary data for a pixmap.
+ *
+ * Results:
+ * If the pixmap description was parsed successfully then the data
+ * is read into an array of strings. This array will later be used
+ * to create X Pixmaps for each instance.
+ *
+ * Side effects:
+ * The masterPtr->data array is allocated when successful. Contents of
+ * *masterPtr is changed only when successful.
+ *----------------------------------------------------------------------
+ */
+static int
+ImgXpmGetData(interp, masterPtr)
+ Tcl_Interp *interp; /* For reporting errors. */
+ PixmapMaster *masterPtr;
+{
+ char ** data = NULL;
+ int isAllocated = 0; /* do we need to free "data"? */
+ int listArgc;
+ char ** listArgv = NULL;
+ int numLines;
+ int size[2];
+ int cpp;
+ int ncolors;
+
+ if (masterPtr->id != NULL) {
+ data = ImgXpmGetDataFromId(interp, masterPtr->id);
+ isAllocated = 0;
+ }
+ else if (masterPtr->fileString != NULL) {
+ data = ImgXpmGetDataFromFile(interp, masterPtr->fileString, &numLines);
+ isAllocated = 1;
+ }
+ else if (masterPtr->dataString != NULL) {
+ data = ImgXpmGetDataFromString(interp,masterPtr->dataString,&numLines);
+ isAllocated = 1;
+ }
+ else {
+ /* Should have been enforced by ImgXpmConfigureMaster() */
+ panic("ImgXpmGetData(): -data, -file and -id are all NULL");
+ }
+
+ if (data == NULL) {
+ return TCL_ERROR;
+ }
+
+ /* Parse the first line of the data and get info about this pixmap */
+ if (Tcl_SplitList(interp, data[0], &listArgc, &listArgv) != TCL_OK) {
+ goto error;
+ }
+
+ if (listArgc < 4) {
+ Tcl_AppendResult(interp, "File format error", NULL);
+ goto error;
+ }
+
+ if (Tcl_GetInt(interp, listArgv[0], &size[0]) != TCL_OK) {
+ goto error;
+ }
+ if (Tcl_GetInt(interp, listArgv[1], &size[1]) != TCL_OK) {
+ goto error;
+ }
+ if (Tcl_GetInt(interp, listArgv[2], &ncolors) != TCL_OK) {
+ goto error;
+ }
+ if (Tcl_GetInt(interp, listArgv[3], &cpp) != TCL_OK) {
+ goto error;
+ }
+
+ if (isAllocated) {
+ if (numLines != size[1] + ncolors + 1) {
+ /* the number of lines read from the file/data
+ * is not the same as specified in the data
+ */
+ goto error;
+ }
+ }
+
+ done:
+ if (masterPtr->isDataAlloced && masterPtr->data) {
+ ckfree((char*)masterPtr->data);
+ }
+ masterPtr->isDataAlloced = isAllocated;
+ masterPtr->data = data;
+ masterPtr->size[0] = size[0];
+ masterPtr->size[1] = size[1];
+ masterPtr->cpp = cpp;
+ masterPtr->ncolors = ncolors;
+
+#if 1 /* Zsolt Koppany 17-sep-96 */
+ if (listArgv) {
+ ckfree((char*)listArgv);
+ }
+#endif /* 1 */
+ return TCL_OK;
+
+ error:
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "File format error", NULL);
+
+ if (isAllocated && data) {
+ ckfree((char*)data);
+ }
+ if (listArgv) {
+ ckfree((char*)listArgv);
+ }
+
+ return TCL_ERROR;
+}
+
+static char ** ImgXpmGetDataFromId(interp, id)
+ Tcl_Interp * interp;
+ char * id;
+{
+ Tcl_HashEntry * hashPtr;
+
+ if (xpmTableInited == 0) {
+ hashPtr = NULL;
+ } else {
+ hashPtr = Tcl_FindHashEntry(&xpmTable, id);
+ }
+
+ if (hashPtr == NULL) {
+ Tcl_AppendResult(interp, "unknown pixmap ID \"", id,
+ "\"", NULL);
+ return (char**)NULL;
+ } else {
+ return (char**)Tcl_GetHashValue(hashPtr);
+ }
+}
+
+static char ** ImgXpmGetDataFromString(interp, string, numLines_return)
+ Tcl_Interp * interp;
+ char * string;
+ int * numLines_return;
+{
+ int quoted;
+ char * p, * list;
+ int numLines;
+ char ** data = NULL;
+
+ /* skip the leading blanks (leading blanks are not defined in the
+ * the XPM definition, but skipping them shouldn't hurt. Also, the ability
+ * to skip the leading blanks is good for using in-line XPM data in TCL
+ * scripts
+ */
+ while (isspace(*string)) {
+ ++ string;
+ }
+
+ /* parse the header */
+ if (strncmp("/* XPM", string, 6) != 0) {
+ goto error;
+ }
+
+ /* strip the comments */
+ for (quoted = 0, p=string; *p;) {
+ if (!quoted) {
+ if (*p == '"') {
+ quoted = 1;
+ ++ p;
+ continue;
+ }
+
+ if (*p == '/' && *(p+1) == '*') {
+ *p++ = ' ';
+ *p++ = ' ';
+ while (1) {
+ if (*p == 0) {
+ break;
+ }
+ if (*p == '*' && *(p+1) == '/') {
+ *p++ = ' ';
+ *p++ = ' ';
+ break;
+ }
+ *p++ = ' ';
+ }
+ continue;
+ }
+ ++ p;
+ } else {
+ if (*p == '"') {
+ quoted = 0;
+ }
+ ++ p;
+ }
+ }
+
+ /* Search for the opening brace */
+ for (p=string; *p;) {
+ if (*p != '{') {
+ ++ p;
+ } else {
+ ++p;
+ break;
+ }
+ }
+
+ /* Change the buffer in to a proper TCL list */
+ quoted = 0;
+ list = p;
+
+ while (*p) {
+ if (!quoted) {
+ if (*p == '"') {
+ quoted = 1;
+ ++ p;
+ continue;
+ }
+
+ if (isspace(*p)) {
+ *p = ' ';
+ }
+ else if (*p == ',') {
+ *p = ' ';
+ }
+ else if (*p == '}') {
+ *p = 0;
+ break;
+ }
+ ++p;
+ }
+ else {
+ if (*p == '"') {
+ quoted = 0;
+ }
+ ++ p;
+ }
+ }
+
+ /* The following code depends on the fact that Tcl_SplitList
+ * strips away double quoates inside a list: ie:
+ * if string == "\"1\" \"2\"" then
+ * list[0] = "1"
+ * list[1] = "2"
+ * and NOT
+ *
+ * list[0] = "\"1\""
+ * list[1] = "\"2\""
+ */
+ if (Tcl_SplitList(interp, list, &numLines, &data) != TCL_OK) {
+ goto error;
+ } else {
+ if (numLines == 0) {
+ /* error: empty data? */
+ if (data != NULL) {
+ ckfree((char*)data);
+ goto error;
+ }
+ }
+ * numLines_return = numLines;
+ return data;
+ }
+
+ error:
+ Tcl_AppendResult(interp, "File format error", NULL);
+ return (char**) NULL;
+}
+
+static char ** ImgXpmGetDataFromFile(interp, fileName, numLines_return)
+ Tcl_Interp * interp;
+ char * fileName;
+ int * numLines_return;
+{
+ int fileId, size;
+ char ** data;
+ struct stat statBuf;
+ char *cmdBuffer = NULL;
+ Tcl_DString buffer; /* initialized by Tcl_TildeSubst */
+
+#if 1
+ fileId = -1; /* Zsolt Koppany 23-mar-96 */
+#endif
+
+ fileName = Tcl_TildeSubst(interp, fileName, &buffer);
+ if (fileName == NULL) {
+ goto error;
+ }
+
+ fileId = open(fileName, O_RDONLY, 0);
+ if (fileId < 0) {
+ Tcl_AppendResult(interp, "couldn't read file \"", fileName,
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ if (fstat(fileId, &statBuf) == -1) {
+ Tcl_AppendResult(interp, "couldn't stat file \"", fileName,
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ close(fileId);
+ goto error;
+ }
+ cmdBuffer = (char *) ckalloc((unsigned) statBuf.st_size+1);
+ size = read(fileId, cmdBuffer, (size_t) statBuf.st_size);
+ if (size < 0) {
+ Tcl_AppendResult(interp, "error in reading file \"", fileName,
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ close(fileId);
+ goto error;
+ }
+ if (close(fileId) != 0) {
+ Tcl_AppendResult(interp, "error closing file \"", fileName,
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
+ goto error;
+ }
+ cmdBuffer[size] = 0;
+
+ done:
+ data = ImgXpmGetDataFromString(interp, cmdBuffer, numLines_return);
+#if 1 /* Zsolt Koppany 23-mar-96 */
+ if (fileId != -1)
+ close(fileId);
+#endif
+
+ ckfree(cmdBuffer);
+ Tcl_DStringFree(&buffer);
+ return data;
+
+ error:
+#if 1 /* Zsolt Koppany 23-mar-96 */
+ if (fileId != -1)
+ close(fileId);
+#endif
+ if (cmdBuffer != NULL) {
+ ckfree(cmdBuffer);
+ }
+ Tcl_DStringFree(&buffer);
+ return (char**)NULL;
+}
+
+
+static char * GetType(colorDefn, type_ret)
+ char * colorDefn;
+ int * type_ret;
+{
+ char * p = colorDefn;
+
+ /* skip white spaces */
+ while (*p && isspace(*p)) {
+ p ++;
+ }
+
+ /* parse the type */
+ if (p[0] != '\0' && p[0] == 'm' &&
+ p[1] != '\0' && isspace(p[1])) {
+ *type_ret = XPM_MONO;
+ p += 2;
+ }
+ else if (p[0] != '\0' && p[0] == 'g' &&
+ p[1] != '\0' && p[1] == '4' &&
+ p[2] != '\0' && isspace(p[2])) {
+ *type_ret = XPM_GRAY_4;
+ p += 3;
+ }
+ else if (p[0] != '\0' && p[0] == 'g' &&
+ p[1] != '\0' && isspace(p[1])) {
+ *type_ret = XPM_GRAY;
+ p += 2;
+ }
+ else if (p[0] != '\0' && p[0] == 'c' &&
+ p[1] != '\0' && isspace(p[1])) {
+ *type_ret = XPM_COLOR;
+ p += 2;
+ }
+ else if (p[0] != '\0' && p[0] == 's' &&
+ p[1] != '\0' && isspace(p[1])) {
+ *type_ret = XPM_SYMBOLIC;
+ p += 2;
+ }
+ else {
+ *type_ret = XPM_UNKNOWN;
+ return NULL;
+ }
+
+ return p;
+}
+
+/* colorName is guaranteed to be big enough */
+static char * GetColor(colorDefn, colorName, type_ret)
+ char * colorDefn;
+ char * colorName; /* if found, name is copied to this array */
+ int * type_ret;
+{
+ int type;
+ char * p;
+
+ if (!colorDefn) {
+ return NULL;
+ }
+
+ if ((colorDefn = GetType(colorDefn, &type)) == NULL) {
+ /* unknown type */
+ return NULL;
+ }
+ else {
+ *type_ret = type;
+ }
+
+ /* skip white spaces */
+ while (*colorDefn && isspace(*colorDefn)) {
+ colorDefn ++;
+ }
+
+ p = colorName;
+
+ while (1) {
+ int dummy;
+
+ while (*colorDefn && !isspace(*colorDefn)) {
+ *p++ = *colorDefn++;
+ }
+
+ if (!*colorDefn) {
+ break;
+ }
+
+ if (GetType(colorDefn, &dummy) == NULL) {
+ /* the next string should also be considered as a part of a color
+ * name */
+
+ while (*colorDefn && isspace(*colorDefn)) {
+ *p++ = *colorDefn++;
+ }
+ } else {
+ break;
+ }
+ if (!*colorDefn) {
+ break;
+ }
+ }
+
+ /* Mark the end of the colorName */
+ *p = '\0';
+
+ return colorDefn;
+}
+
+/*----------------------------------------------------------------------
+ * ImgXpmGetPixmapFromData --
+ *
+ * Creates a pixmap for an image instance.
+ *----------------------------------------------------------------------
+ */
+static void ImgXpmGetPixmapFromData(interp, masterPtr, instancePtr)
+ Tcl_Interp * interp;
+ PixmapMaster *masterPtr;
+ PixmapInstance *instancePtr;
+{
+ XImage * image = NULL, * mask = NULL;
+ int pad, bitmap_pad, depth, i, j, k, lOffset, isTransp = 0, isMono, bpl;
+ ColorStruct * colors;
+ GC gc;
+ Display *display = Tk_Display(instancePtr->tkwin);
+
+ depth = Tk_Depth(instancePtr->tkwin);
+ if (depth > 16) {
+ pad = 32;
+ }
+ else if (depth > 8) {
+ pad = 16;
+ }
+ else {
+ pad = 8;
+ }
+
+ switch ((Tk_Visual(instancePtr->tkwin))->class) {
+ case StaticGray:
+ case GrayScale:
+ isMono = 1;
+ break;
+ default:
+ isMono = 0;
+ }
+
+ /*
+ * Create the XImage structures to store the temporary image
+ */
+#ifdef _WIN32
+ /* On Windows, we always create the bitmap using 24 bits, because
+ that lets us just store the RGB value, and not worry about
+ building a color palette. */
+ image = XCreateImage(display,
+ Tk_Visual(instancePtr->tkwin),
+ 24, ZPixmap, 0, 0,
+ masterPtr->size[0], masterPtr->size[1], pad, 0);
+#else
+ image = XCreateImage(display,
+ Tk_Visual(instancePtr->tkwin),
+ depth, ZPixmap, 0, 0,
+ masterPtr->size[0], masterPtr->size[1], pad, 0);
+#endif
+ image->data =
+ (char *)ckalloc(image->bytes_per_line * masterPtr->size[1]);
+#ifdef _WIN32
+ /* On Windows, we don't use a clip pixmap, so it's important to
+ clear the data. */
+ memset (image->data, 0, image->bytes_per_line * masterPtr->size[1]);
+#endif
+
+/* If the width of the mask is half or less than the size of
+ the padding used, then the pixmap mask might be drawn twice as
+ high as it should. Adding one to the width seems to fix this problem.
+ [irox: 10/14/98 ] */
+#define LONGBITS (sizeof(long) * 8)
+ bitmap_pad = (pad + LONGBITS - 1) / LONGBITS * LONGBITS;
+
+ if (masterPtr->size[0]<=(bitmap_pad/2)) {
+ mask = XCreateImage(display,
+ Tk_Visual(instancePtr->tkwin),
+ 1, ZPixmap, 0, 0,
+ masterPtr->size[0]+1, masterPtr->size[1], pad, 0);
+ } else {
+ mask = XCreateImage(display,
+ Tk_Visual(instancePtr->tkwin),
+ 1, ZPixmap, 0, 0,
+ masterPtr->size[0], masterPtr->size[1], pad, 0);
+ }
+
+ mask->data =
+ (char *)ckalloc(mask->bytes_per_line * masterPtr->size[1]);
+#ifdef _WIN32
+ /* On Windows, we don't use a clip pixmap, so it's important to
+ clear the data. */
+ memset (mask->data, 0, mask->bytes_per_line * masterPtr->size[1]);
+#endif
+
+ /*
+ * Parse the colors
+ */
+ lOffset = 1;
+ colors = (ColorStruct*)ckalloc(sizeof(ColorStruct)*masterPtr->ncolors);
+
+ /* Initialize the color structures */
+ for (i=0; incolors; i++) {
+ colors[i].colorPtr = NULL;
+ if (masterPtr->cpp == 1) {
+ colors[i].c = 0;
+ } else {
+ colors[i].cstring = (char*)ckalloc(masterPtr->cpp);
+ colors[i].cstring[0] = 0;
+ }
+ }
+
+ for (i=0; incolors; i++) {
+ char * colorDefn; /* the color definition line */
+ char * colorName; /* temp place to hold the color name
+ * defined for one type of visual */
+ char * useName; /* the color name used for this
+ * color. If there are many names
+ * defined, choose the name that is
+ * "best" for the target visual
+ */
+ int found;
+
+ colorDefn = masterPtr->data[i+lOffset]+masterPtr->cpp;
+ colorName = (char*)ckalloc(strlen(colorDefn));
+ useName = (char*)ckalloc(strlen(colorDefn));
+ found = 0;
+
+ while (colorDefn && *colorDefn) {
+ int type;
+
+ if ((colorDefn=GetColor(colorDefn, colorName, &type)) == NULL) {
+ break;
+ }
+ if (colorName[0] == '\0') {
+ continue;
+ }
+
+ switch (type) {
+ case XPM_MONO:
+ if (isMono && depth == 1) {
+ strcpy(useName, colorName);
+ found = 1; goto gotcolor;
+ }
+ break;
+ case XPM_GRAY_4:
+ if (isMono && depth == 4) {
+ strcpy(useName, colorName);
+ found = 1; goto gotcolor;
+ }
+ break;
+ case XPM_GRAY:
+ if (isMono && depth > 4) {
+ strcpy(useName, colorName);
+ found = 1; goto gotcolor;
+ }
+ break;
+ case XPM_COLOR:
+ if (!isMono) {
+ strcpy(useName, colorName);
+ found = 1; goto gotcolor;
+ }
+ break;
+ }
+ if (type != XPM_SYMBOLIC && type != XPM_UNKNOWN) {
+ if (!found) { /* use this color as default */
+ strcpy(useName, colorName);
+ found = 1;
+ }
+ }
+ }
+
+ gotcolor:
+ if (masterPtr->cpp == 1) {
+ colors[i].c = masterPtr->data[i+lOffset][0];
+ } else {
+ strncpy(colors[i].cstring, masterPtr->data[i+lOffset],
+ (size_t)masterPtr->cpp);
+ }
+
+ if (found) {
+ if (strncasecmp(useName, "none",4) != 0) {
+ colors[i].colorPtr = Tk_GetColor(interp,
+ instancePtr->tkwin, Tk_GetUid(useName));
+ if (colors[i].colorPtr == NULL) {
+ colors[i].colorPtr = Tk_GetColor(interp,
+ instancePtr->tkwin, Tk_GetUid("black"));
+ }
+ }
+ } else {
+ colors[i].colorPtr = Tk_GetColor(interp,
+ instancePtr->tkwin, Tk_GetUid("black"));
+ }
+
+ ckfree(colorName);
+ ckfree(useName);
+ }
+
+ lOffset += masterPtr->ncolors;
+
+ /*
+ * Parse the main body of the image
+ */
+ for (i=0; isize[1]; i++) {
+ char * p = masterPtr->data[i+lOffset];
+
+ for (j=0; jsize[0]; j++) {
+ if (masterPtr->cpp == 1) {
+ for (k=0; kncolors; k++) {
+ if (*p == colors[k].c) {
+ if (colors[k].colorPtr != NULL) {
+ XPutPixel(image, j, i, colors[k].colorPtr->pixel);
+ XPutPixel(mask, j, i, 1);
+ } else {
+ XPutPixel(mask, j, i, 0);
+ isTransp = 1;
+ }
+ break;
+ }
+ }
+ if (*p) {
+ p++;
+ }
+ } else {
+ for (k=0; kncolors; k++) {
+ if (strncmp(p, colors[k].cstring,
+ (size_t)masterPtr->cpp) == 0) {
+ if (colors[k].colorPtr != NULL) {
+ XPutPixel(image, j, i, colors[k].colorPtr->pixel);
+ XPutPixel(mask, j, i, 1);
+ } else {
+ XPutPixel(mask, j, i, 0);
+ isTransp = 1;
+ }
+ break;
+ }
+ }
+ for (k=0; *p && kcpp; k++) {
+ p++;
+ }
+ }
+ }
+ }
+
+ /*
+ * Create the pixmap(s) from the XImage structure. The mask is created
+ * only if needed (i.e., there is at least one transparent pixel)
+ */
+ instancePtr->colors = colors;
+
+ /* main image */
+ instancePtr->pixmap = Tk_GetPixmap(display,
+ Tk_WindowId(instancePtr->tkwin),
+ masterPtr->size[0], masterPtr->size[1], depth);
+
+ gc = Tk_GetGC(instancePtr->tkwin, 0, NULL);
+
+ TkPutImage(NULL, 0, display, instancePtr->pixmap,
+ gc, image, 0, 0, 0, 0, masterPtr->size[0], masterPtr->size[1]);
+
+ Tk_FreeGC(display, gc);
+
+ /* mask, if necessary */
+ if (isTransp) {
+ instancePtr->mask = Tk_GetPixmap(display,
+ Tk_WindowId(instancePtr->tkwin),
+ masterPtr->size[0], masterPtr->size[1], 1);
+ gc = XCreateGC(display, instancePtr->mask, 0, NULL);
+
+ TkPutImage(NULL, 0, display, instancePtr->mask,
+ gc, mask, 0, 0, 0, 0, masterPtr->size[0], masterPtr->size[1]);
+ XFreeGC(display, gc);
+ } else {
+ instancePtr->mask = None;
+ }
+
+ /* Done */
+ if (image) {
+ ckfree((char*)image->data);
+ image->data = NULL;
+#ifndef _WIN32
+ XDestroyImage(image);
+#else
+ ckfree((char *)image);
+#endif
+ }
+ if (mask) {
+ ckfree((char*)mask->data);
+ mask->data = NULL;
+#ifndef _WIN32
+ XDestroyImage(mask);
+#else
+ ckfree((char *)mask);
+#endif
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ImgXpmConfigureInstance --
+ *
+ * This procedure is called to create displaying information for
+ * a pixmap image instance based on the configuration information
+ * in the master. It is invoked both when new instances are
+ * created and when the master is reconfigured.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Generates errors via Tk_BackgroundError if there are problems
+ * in setting up the instance.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+ImgXpmConfigureInstance(instancePtr)
+ PixmapInstance *instancePtr; /* Instance to reconfigure. */
+{
+ PixmapMaster *masterPtr = instancePtr->masterPtr;
+ XGCValues gcValues;
+ GC gc;
+ unsigned int gcMask;
+
+ if (instancePtr->pixmap != None) {
+ Tk_FreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->pixmap);
+ }
+ if (instancePtr->mask != None) {
+ Tk_FreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->mask);
+ }
+
+ if (instancePtr->colors != NULL) {
+ int i;
+ for (i=0; incolors; i++) {
+ if (instancePtr->colors[i].colorPtr != NULL) {
+ Tk_FreeColor(instancePtr->colors[i].colorPtr);
+ }
+ if (masterPtr->cpp != 1) {
+ ckfree(instancePtr->colors[i].cstring);
+ }
+ }
+ ckfree((char*)instancePtr->colors);
+ }
+
+ if (Tk_WindowId(instancePtr->tkwin) == None) {
+ Tk_MakeWindowExist(instancePtr->tkwin);
+ }
+
+ /* Assumption: masterPtr->data is always non NULL (enfored by
+ * ImgXpmConfigureMaster()). Also, the data must be in a valid
+ * format (partially enforced by ImgXpmConfigureMaster(), see comments
+ * inside that function).
+ */
+ ImgXpmGetPixmapFromData(masterPtr->interp, masterPtr, instancePtr);
+
+ /* Allocate a GC for drawing this instance (mask is not used if there
+ * is no transparent pixels inside the image).*/
+ if (instancePtr->mask != None) {
+ gcMask = GCGraphicsExposures|GCClipMask;
+ } else {
+ gcMask = GCGraphicsExposures;
+ }
+
+#ifdef _WIN32
+ if (instancePtr->mask != None) {
+ /* See ImgXpmDisplay. If we have a mask, we set the GC
+ function to merge the source onto the destination. In
+ ImgXpmDisplay we use the mask to clear the destination
+ first. */
+ gcMask |= GCFunction;
+ gcValues.function = GXor;
+ }
+#endif
+
+ gcValues.graphics_exposures = False;
+ gcValues.clip_mask = instancePtr->mask;
+
+ gc = Tk_GetGC(instancePtr->tkwin, gcMask, &gcValues);
+
+ if (instancePtr->gc != None) {
+ Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
+ }
+ instancePtr->gc = gc;
+ return;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ImgXpmCmd --
+ *
+ * This procedure is invoked to process the Tcl command
+ * that corresponds to an image managed by this module.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+ImgXpmCmd(clientData, interp, argc, argv)
+ ClientData clientData; /* Information about button widget. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ PixmapMaster *masterPtr = (PixmapMaster *) clientData;
+ int c, code;
+ size_t length;
+
+ if (argc < 2) {
+ sprintf(interp->result,
+ "wrong # args: should be \"%.50s option ?arg arg ...?\"",
+ argv[0]);
+ return TCL_ERROR;
+ }
+ c = argv[1][0];
+ length = strlen(argv[1]);
+ if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
+ && (length >= 2)) {
+ if (argc != 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " cget option\"",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
+ (char *) masterPtr, argv[2], 0);
+ } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
+ && (length >= 2)) {
+ if (argc == 2) {
+ code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
+ configSpecs, (char *) masterPtr, (char *) NULL, 0);
+ } else if (argc == 3) {
+ code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
+ configSpecs, (char *) masterPtr, argv[2], 0);
+ } else {
+ code = ImgXpmConfigureMaster(masterPtr, argc-2, argv+2,
+ TK_CONFIG_ARGV_ONLY);
+ }
+ return code;
+ }
+
+ error:
+
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": must be cget or configure", (char *) NULL);
+ return TCL_ERROR;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ImgXpmGet --
+ *
+ * This procedure is called for each use of a pixmap image in a
+ * widget.
+ *
+ * Results:
+ * The return value is a token for the instance, which is passed
+ * back to us in calls to ImgXpmDisplay and ImgXpmFre.
+ *
+ * Side effects:
+ * A data structure is set up for the instance (or, an existing
+ * instance is re-used for the new one).
+ *
+ *----------------------------------------------------------------------
+ */
+
+static ClientData
+ImgXpmGet(tkwin, masterData)
+ Tk_Window tkwin; /* Window in which the instance will be
+ * used. */
+ ClientData masterData; /* Pointer to our master structure for the
+ * image. */
+{
+ PixmapMaster *masterPtr = (PixmapMaster *) masterData;
+ PixmapInstance *instancePtr;
+
+ /*
+ * See if there is already an instance for this window. If so
+ * then just re-use it.
+ */
+
+ for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
+ instancePtr = instancePtr->nextPtr) {
+ if (instancePtr->tkwin == tkwin) {
+ instancePtr->refCount++;
+ return (ClientData) instancePtr;
+ }
+ }
+
+ /*
+ * The image isn't already in use in this window. Make a new
+ * instance of the image.
+ */
+ instancePtr = (PixmapInstance *) ckalloc(sizeof(PixmapInstance));
+ instancePtr->refCount = 1;
+ instancePtr->masterPtr = masterPtr;
+ instancePtr->tkwin = tkwin;
+ instancePtr->pixmap = None;
+ instancePtr->mask = None;
+ instancePtr->gc = None;
+ instancePtr->nextPtr = masterPtr->instancePtr;
+ instancePtr->colors = NULL;
+ masterPtr->instancePtr = instancePtr;
+ ImgXpmConfigureInstance(instancePtr);
+
+ /*
+ * If this is the first instance, must set the size of the image.
+ */
+ if (instancePtr->nextPtr == NULL) {
+ if (masterPtr->data) {
+ Tk_ImageChanged(masterPtr->tkMaster, 0, 0,
+ masterPtr->size[0], masterPtr->size[1],
+ masterPtr->size[0], masterPtr->size[1]);
+ } else {
+ Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, 0, 0);
+ }
+ }
+
+ return (ClientData) instancePtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ImgXpmDisplay --
+ *
+ * This procedure is invoked to draw a pixmap image.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * A portion of the image gets rendered in a pixmap or window.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+ImgXpmDisplay(clientData, display, drawable, imageX, imageY, width,
+ height, drawableX, drawableY)
+ ClientData clientData; /* Pointer to PixmapInstance structure for
+ * for instance to be displayed. */
+ Display *display; /* Display on which to draw image. */
+ Drawable drawable; /* Pixmap or window in which to draw image. */
+ int imageX, imageY; /* Upper-left corner of region within image
+ * to draw. */
+ int width, height; /* Dimensions of region within image to draw.*/
+ int drawableX, drawableY; /* Coordinates within drawable that
+ * correspond to imageX and imageY. */
+{
+ PixmapInstance *instancePtr = (PixmapInstance *) clientData;
+
+ /*
+ * If there's no graphics context, it means that an error occurred
+ * while creating the image instance so it can't be displayed.
+ */
+
+ if (instancePtr->gc == None) {
+ return;
+ }
+
+ /*
+ * We always use masking: modify the mask origin within
+ * the graphics context to line up with the image's origin.
+ * Then draw the image and reset the clip origin, if there's
+ * a mask.
+ */
+
+#ifdef _WIN32
+ /* The Tk 7.6 XCopyArea implementation on Windows does not support
+ a pixmap as a clip region, so we use the mask to first clear
+ out everything in the destination that we want to paint. */
+ if (instancePtr->mask != None) {
+ XGCValues gcValues;
+ GC gc;
+
+ gcValues.function = GXandInverted;
+ gcValues.graphics_exposures = False;
+ gc = Tk_GetGC(instancePtr->tkwin, GCFunction|GCGraphicsExposures,
+ &gcValues);
+ XCopyArea(display, instancePtr->mask, drawable, gc, imageX,
+ imageY, (unsigned) width, (unsigned) height, drawableX,
+ drawableY);
+ Tk_FreeGC(display, gc);
+ }
+#endif
+
+ XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
+ drawableY - imageY);
+ XCopyArea(display, instancePtr->pixmap, drawable, instancePtr->gc,
+ imageX, imageY, (unsigned) width, (unsigned) height,
+ drawableX, drawableY);
+ XSetClipOrigin(display, instancePtr->gc, 0, 0);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ImgXpmFree --
+ *
+ * This procedure is called when a widget ceases to use a
+ * particular instance of an image.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Internal data structures get cleaned up.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+ImgXpmFree(clientData, display)
+ ClientData clientData; /* Pointer to PixmapInstance structure for
+ * for instance to be displayed. */
+ Display *display; /* Display containing window that used image.*/
+{
+ PixmapInstance *instancePtr = (PixmapInstance *) clientData;
+ PixmapInstance *prevPtr;
+
+ instancePtr->refCount--;
+ if (instancePtr->refCount > 0) {
+ return;
+ }
+
+ /*
+ * There are no more uses of the image within this widget. Free
+ * the instance structure.
+ */
+ if (instancePtr->pixmap != None) {
+ Tk_FreePixmap(display, instancePtr->pixmap);
+ }
+ if (instancePtr->mask != None) {
+ Tk_FreePixmap(display, instancePtr->mask);
+ }
+ if (instancePtr->gc != None) {
+ Tk_FreeGC(display, instancePtr->gc);
+ }
+ if (instancePtr->colors != NULL) {
+ int i;
+ for (i=0; imasterPtr->ncolors; i++) {
+ if (instancePtr->colors[i].colorPtr != NULL) {
+ Tk_FreeColor(instancePtr->colors[i].colorPtr);
+ }
+ if (instancePtr->masterPtr->cpp != 1) {
+ ckfree(instancePtr->colors[i].cstring);
+ }
+ }
+ ckfree((char*)instancePtr->colors);
+ }
+
+ if (instancePtr->masterPtr->instancePtr == instancePtr) {
+ instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
+ } else {
+ for (prevPtr = instancePtr->masterPtr->instancePtr;
+ prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
+ /* Empty loop body */
+ }
+ prevPtr->nextPtr = instancePtr->nextPtr;
+ }
+ ckfree((char *) instancePtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ImgXpmDelete --
+ *
+ * This procedure is called by the image code to delete the
+ * master structure for an image.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Resources associated with the image get freed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+ImgXpmDelete(masterData)
+ ClientData masterData; /* Pointer to PixmapMaster structure for
+ * image. Must not have any more instances. */
+{
+ PixmapMaster *masterPtr = (PixmapMaster *) masterData;
+
+ if (masterPtr->instancePtr != NULL) {
+ panic("tried to delete pixmap image when instances still exist");
+ }
+ masterPtr->tkMaster = NULL;
+ if (masterPtr->imageCmd != NULL) {
+ Tcl_DeleteCommand(masterPtr->interp,
+ Tcl_GetCommandName(masterPtr->interp, masterPtr->imageCmd));
+ }
+ if (masterPtr->isDataAlloced && masterPtr->data != NULL) {
+ ckfree((char*)masterPtr->data);
+ }
+ Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
+ ckfree((char *) masterPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ImgXpmCmdDeletedProc --
+ *
+ * This procedure is invoked when the image command for an image
+ * is deleted. It deletes the image.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The image is deleted.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+ImgXpmCmdDeletedProc(clientData)
+ ClientData clientData; /* Pointer to PixmapMaster structure for
+ * image. */
+{
+ PixmapMaster *masterPtr = (PixmapMaster *) clientData;
+
+ masterPtr->imageCmd = NULL;
+ if (masterPtr->tkMaster != NULL) {
+ Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
+ }
+}
+
+
+
+#if 0
+
+/* We currently don't need this code for the IDE.
+ If we ever do, uncomment it and change its name so that it starts
+ with the "ide_" prefix. */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tix_DefinePixmap
+ *
+ * Define an XPM data structure with an unique name, so that you can
+ * later refer to this pixmap using the -id switch in [image create
+ * pixmap].
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The data is stored in a HashTable.
+ *----------------------------------------------------------------------
+ */
+int
+Tix_DefinePixmap(interp, name, data)
+ Tcl_Interp * interp;
+ Tk_Uid name; /* Name to use for bitmap. Must not already
+ * be defined as a bitmap. */
+ char **data;
+{
+ int new;
+ Tcl_HashEntry *hshPtr;
+
+ if (!xpmTableInited) {
+ xpmTableInited = 1;
+ Tcl_InitHashTable(&xpmTable, TCL_ONE_WORD_KEYS);
+ }
+
+ hshPtr = Tcl_CreateHashEntry(&xpmTable, name, &new);
+ if (!new) {
+ Tcl_AppendResult(interp, "pixmap \"", name,
+ "\" is already defined", (char *) NULL);
+ return TCL_ERROR;
+ }
+ Tcl_SetHashValue(hshPtr, (char*)data);
+ return TCL_OK;
+}
+
+#endif
+
+void
+ide_create_xpm_image_type ()
+{
+ Tk_CreateImageType(&tixPixmapImageType);
+}
xpmlib.c
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: tclhelp.c
===================================================================
--- tclhelp.c (nonexistent)
+++ tclhelp.c (revision 1765)
@@ -0,0 +1,618 @@
+/* tclhelp.c -- TCL interface to help.
+ Copyright (C) 1997 Cygnus Solutions.
+ Written by Ian Lance Taylor . */
+
+#include "config.h"
+
+#include
+#include
+
+#ifdef HAVE_STDLIB_H
+#include
+#endif
+
+#include
+#ifndef errno
+extern int errno;
+#endif
+
+#ifdef HAVE_STRING_H
+#include
+#else
+#ifdef HAVE_STRINGS_H
+#include
+#else
+extern char *strerror ();
+#endif
+#endif
+
+#ifdef _WIN32
+/* We avoid warnings by including this before tcl.h. */
+#include
+#include
+#endif
+
+#include
+#include
+
+#include "guitcl.h"
+#include "subcommand.h"
+
+/* This file defines one TCL command with subcommands. This command
+ may be used to bring up a help window.
+
+ ide_help initialize ...
+ Initialize the help system.
+
+ On Windows, this takes two arguments: the name of the help
+ file, and the name of the header file which may be used to map
+ help topics to numbers. This header files is created by the
+ help system.
+
+ The Unix help system has not yet been implemented.
+
+ ide_help topic TOPIC
+ Brings up a help window for the particular topic. The topic is
+ a string.
+
+ ide_help toc
+ Brings up a help window for the main table of contents.
+
+ ide_help display_file FILENAME TOPIC_ID
+ The "display_file" subcommand was added as a hack to get the Foundry Tour to
+ launch. The help system can't handle more than one help file and should
+ be rewritten */
+
+#ifdef _WIN32
+
+/* Windows implementation. This uses WinHelp. */
+
+/* We use an instance of this structure as the client data for the
+ ide_help command. */
+
+struct help_command_data
+{
+ /* The name of the help file. */
+ char *filename;
+ /* The name of the help header file which we use to map topic
+ strings to numbers. */
+ char *header_filename;
+ /* A hash table mapping help topic strings to numbers. */
+ Tcl_HashTable topic_hash;
+ /* Nonzero if the hash table has been initialized. */
+ int hash_initialized;
+ /* The window we are passing to WinHelp. */
+ HWND window;
+};
+
+/* This function is called as an exit handler. */
+
+static void
+help_command_atexit (ClientData cd)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+
+ /* Tell Windows we don't need any more help. */
+ if (hdata->window != NULL)
+ WinHelp (hdata->window, hdata->filename, HELP_QUIT, 0);
+}
+
+/* This function is called if the ide_help command is deleted. */
+
+static void
+help_command_deleted (ClientData cd)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+
+ /* Run the exit handler now, rather than when we exit. */
+ help_command_atexit (cd);
+ Tcl_DeleteExitHandler (help_command_atexit, cd);
+
+ if (hdata->filename != NULL)
+ free (hdata->filename);
+ if (hdata->header_filename != NULL)
+ free (hdata->header_filename);
+ if (hdata->hash_initialized)
+ Tcl_DeleteHashTable (&hdata->topic_hash);
+ Tcl_Free ((char *) hdata);
+}
+
+/* Initialize the help system: choose a window, and set up the topic
+ hash table. We don't set up the topic hash table when the command
+ is created, because there's no point wasting time on it at program
+ startup time if the help system is not going to be used. */
+
+static int
+help_initialize (Tcl_Interp *interp, struct help_command_data *hdata)
+{
+ if (hdata->filename == NULL || hdata->header_filename == NULL)
+ {
+ Tcl_SetResult (interp, "help system has not been initialized",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+
+ if (hdata->window == NULL)
+ {
+ HWND window, parent;
+
+ /* We don't really care what window we use, although it should
+ probably be one that will last until the application exits. */
+ window = GetActiveWindow ();
+ if (window == NULL)
+ window = GetFocus ();
+ if (window == NULL)
+ {
+ Tcl_SetResult (interp, "can't find window to use for help",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+
+ while ((parent = GetParent (window)) != NULL)
+ window = parent;
+
+ hdata->window = window;
+
+ Tcl_CreateExitHandler (help_command_atexit, (ClientData) hdata);
+ }
+
+ if (! hdata->hash_initialized)
+ {
+ FILE *e;
+ char buf[200];
+
+ e = fopen (hdata->header_filename, "r");
+ if (e == NULL)
+ {
+ Tcl_AppendResult (interp, "can't open help file \"",
+ hdata->header_filename, "\": ",
+ strerror (errno), (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ Tcl_InitHashTable (&hdata->topic_hash, TCL_STRING_KEYS);
+ hdata->hash_initialized = 1;
+
+ /* We expect the format of the header file to be tightly
+ constrained: the lines of interest will look like
+ #define TOPIC_STRING TOPIC_NUMBER
+ We ignore all other lines. We assume that topic strings have
+ a limited length, since they are created by humans, so for
+ simplicity we use fgets with a fixed size buffer. The error
+ checking is minimal, but that's OK, because this file is part
+ of the application; it is not created by the user. */
+
+ while (fgets (buf, sizeof buf, e) != NULL)
+ {
+ char *s, *topic;
+ int number;
+ Tcl_HashEntry *he;
+ int new;
+
+ if (strncmp (buf, "#define", 7) != 0)
+ continue;
+
+ s = buf + 7;
+ while (isspace ((unsigned char) *s))
+ ++s;
+ topic = s;
+ while (! isspace ((unsigned char) *s))
+ ++s;
+ *s = '\0';
+
+ number = atoi (s + 1);
+ if (number == 0)
+ continue;
+
+ he = Tcl_CreateHashEntry (&hdata->topic_hash, topic, &new);
+ Tcl_SetHashValue (he, (ClientData) number);
+ }
+
+ fclose (e);
+ }
+
+ return TCL_OK;
+}
+
+/* Implement the ide_help initialize command. We don't actually look
+ at the files now; we only do that if the user requests help. */
+
+static int
+help_initialize_command (ClientData cd, Tcl_Interp *interp, int argc,
+ char **argv)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+
+ hdata->filename = strdup (argv[2]);
+ hdata->header_filename = strdup (argv[3]);
+ return TCL_OK;
+}
+
+#define INIT_MINARGS (4)
+#define INIT_MAXARGS (4)
+
+/* Implement the ide_help topic command. */
+
+static int
+help_topic_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+ Tcl_HashEntry *he;
+
+ if (help_initialize (interp, hdata) != TCL_OK)
+ return TCL_ERROR;
+
+ he = Tcl_FindHashEntry (&hdata->topic_hash, argv[2]);
+ if (he == NULL)
+ {
+ Tcl_AppendResult (interp, "unknown help topic \"", argv[2], "\"",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ if (! WinHelp (hdata->window, hdata->filename, HELP_CONTEXT,
+ (DWORD) Tcl_GetHashValue (he)))
+ {
+ char buf[200];
+
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), 0,
+ buf, 200, NULL);
+ Tcl_AppendResult (interp, "WinHelp failed: ", buf, (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ return TCL_OK;
+}
+
+/* Implement the ide_help toc command. */
+
+static int
+help_toc_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+
+ if (help_initialize (interp, hdata) != TCL_OK)
+ return TCL_ERROR;
+
+ if (! WinHelp (hdata->window, hdata->filename, HELP_FINDER, 0))
+ {
+ char buf[200];
+
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), 0,
+ buf, 200, NULL);
+ Tcl_AppendResult (interp, "WinHelp failed: ", buf, (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ return TCL_OK;
+}
+
+/* Implement the ide_help display_file command. */
+/* This is a hack to display an external help file, */
+/* by 'external' I mean not part of Foundry Help. */
+/* This was added specifically to display the Foundry */
+/* Tour help file and should be made less hacky in the future */
+/* The "display_file" subcommand was added as a hack to get the Foundry Tour to */
+/* launch. The help system can't handle more than one help file and should */
+/* be rewritten */
+
+static int
+help_display_file_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+ FILE *e;
+ DWORD topic_id = 0; /* default topic id is 0 which brings up the find dialog */
+
+ /* We call Help initialize just to make sure the window handle is setup */
+ /* We don't care about the finding the main help file and checking the */
+ /* hash table but we do it anyway because this is a hack. */
+ if (help_initialize (interp, hdata) != TCL_OK)
+ return TCL_ERROR;
+
+ /* We should check to see if the help file we want exists since function */
+ /* 'help_initialize' checked the wrong file (it checked the main help file) */
+ e = fopen (argv[2], "r");
+ if (e == NULL)
+ {
+ Tcl_AppendResult (interp, "can't open help file \"",
+ argv[2], "\": ",
+ strerror (errno), (char *) NULL);
+ return TCL_ERROR;
+ }
+ fclose (e);
+ if (argc > 3)
+ {
+ if ( Tcl_GetInt (interp, argv[3], &topic_id) != TCL_OK )
+ return TCL_ERROR;
+ }
+
+ if (! WinHelp (hdata->window, argv[2], HELP_CONTEXT, topic_id))
+ {
+ char buf[200];
+
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), 0,
+ buf, 200, NULL);
+ Tcl_AppendResult (interp, "WinHelp failed: ", buf, (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ return TCL_OK;
+}
+
+/* Initialize the help command structure. */
+
+struct help_command_data *
+hdata_initialize ()
+{
+ struct help_command_data *hdata;
+
+ hdata = (struct help_command_data *) Tcl_Alloc (sizeof *hdata);
+
+ hdata->filename = NULL;
+ hdata->header_filename = NULL;
+ hdata->hash_initialized = 0;
+ hdata->window = NULL;
+
+ return hdata;
+}
+
+#else /* ! _WIN32 */
+
+/* The Unix help implementation. */
+
+/* We use an instance of this structure as the client data for the
+ ide_help command. */
+
+struct help_command_data
+{
+ /* path to webhelp.csh file */
+ char *filename;
+ /* path to foundry.hh file */
+ char *header_filename;
+ /* path to help directory */
+ char *help_dir;
+ /* A hash table mapping help topic strings to numbers. */
+ Tcl_HashTable topic_hash;
+ /* Nonzero if the hash table has been initialized. */
+ int hash_initialized;
+ /* pointer to large block of memory used for hashing */
+ char *memory_block;
+ };
+
+/* This function is called if the ide_help command is deleted. */
+
+static void
+help_command_deleted (ClientData cd)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+
+ if (hdata->filename != NULL)
+ free (hdata->filename);
+ if (hdata->header_filename != NULL)
+ free (hdata->header_filename);
+ if (hdata->hash_initialized)
+ Tcl_DeleteHashTable (&hdata->topic_hash);
+ if (hdata->memory_block != NULL)
+ free (hdata->memory_block);
+ Tcl_Free ((char *) hdata);
+}
+
+/* Implement the ide_help initialize command. */
+
+static int
+help_initialize_command (ClientData cd, Tcl_Interp *interp, int argc,
+ char **argv)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+
+ hdata->filename = strdup (argv[2]);
+ hdata->header_filename = strdup (argv[3]);
+ hdata->help_dir = strdup (argv[4]);
+ return TCL_OK;
+}
+
+static int
+help_initialize (Tcl_Interp *interp, struct help_command_data *hdata)
+{
+
+ if (hdata->filename == NULL || hdata->header_filename == NULL)
+ {
+ Tcl_SetResult (interp, "help system has not been initialized",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+
+ if (! hdata->hash_initialized)
+ {
+ FILE *e;
+ char buf[200], *block_start;
+
+ block_start = hdata->memory_block = malloc(6000);
+
+ e = fopen (hdata->header_filename, "r");
+ if (e == NULL)
+ {
+ Tcl_AppendResult (interp, "can't open help file \"",
+ hdata->header_filename, "\": ",
+ strerror (errno), (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ Tcl_InitHashTable (&hdata->topic_hash, TCL_STRING_KEYS);
+ hdata->hash_initialized = 1;
+
+ /* We expect the format of the header file to be tightly
+ constrained: the lines of interest will look like
+ #define TOPIC_STRING TOPIC_FILENAME
+ We ignore all other lines. We assume that topic strings have
+ a limited length, since they are created by humans, so for
+ simplicity we use fgets with a fixed size buffer. The error
+ checking is minimal, but that's OK, because this file is part
+ of the application; it is not created by the user. */
+
+ while (fgets (buf, sizeof buf, e) != NULL)
+ {
+ char *s, *topic, *strng;
+ Tcl_HashEntry *he;
+ int new;
+
+ if (strncmp (buf, "#define", 7) != 0)
+ continue;
+
+ s = buf + 7;
+ while (isspace ((unsigned char) *s))
+ ++s;
+ topic = s;
+ while (! isspace ((unsigned char) *s))
+ ++s;
+ *s = '\0';
+
+ ++s;
+ while (isspace ((unsigned char) *s))
+ ++s;
+ strng = s;
+ while (! isspace ((unsigned char) *s))
+ ++s;
+ *s = '\0';
+ strcpy (block_start, strng);
+
+ he = Tcl_CreateHashEntry (&hdata->topic_hash, topic, &new);
+ Tcl_SetHashValue (he, (ClientData) block_start);
+ block_start += strlen(strng) + 2;
+
+ }
+ fclose (e);
+
+ }
+
+ return TCL_OK;
+
+}
+
+#define INIT_MINARGS 2
+#define INIT_MAXARGS 5
+
+/* Implement the ide_help topic command. */
+
+static int
+help_topic_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+ Tcl_HashEntry *he;
+ char htmlFile[250], htmlFile2[250];
+
+ if (help_initialize (interp, hdata) != TCL_OK)
+ return TCL_ERROR;
+
+ he = Tcl_FindHashEntry (&hdata->topic_hash, argv[2]);
+ if (he == NULL)
+ {
+ Tcl_AppendResult (interp, "unknown help topic \"", argv[2], "\"",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ else
+ {
+
+ strcpy (htmlFile, hdata->help_dir);
+ strcat (htmlFile, "/");
+ strcat (htmlFile, Tcl_GetHashValue (he));
+
+ ShowHelp (htmlFile, hdata->filename);
+ return TCL_OK;
+ }
+}
+
+/* Implement the ide_help toc command. */
+
+static int
+help_toc_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+ char htmlFile[250];
+
+ strcpy (htmlFile, hdata->help_dir);
+ strcat (htmlFile, "/start.htm");
+
+ if (! ShowHelp (htmlFile, hdata->filename))
+ { Tcl_SetResult (interp, "Help not available", TCL_STATIC);
+ return TCL_ERROR;
+ }
+}
+
+/* Implement the ide_help display command. */
+
+static int
+help_display_file_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
+{
+ struct help_command_data *hdata = (struct help_command_data *) cd;
+
+ if (! ShowHelp (argv[2], hdata->filename))
+ { Tcl_SetResult (interp, "Help not available", TCL_STATIC);
+ return TCL_ERROR;
+ }
+}
+
+/* Initialize the help command structure. */
+
+struct help_command_data *
+hdata_initialize ()
+{
+ struct help_command_data *hdata;
+
+ hdata = (struct help_command_data *) Tcl_Alloc (sizeof *hdata);
+
+ hdata->filename = NULL;
+ hdata->help_dir = NULL;
+ hdata->header_filename = NULL;
+ hdata->hash_initialized = 0;
+ hdata->memory_block = NULL;
+
+ return hdata;
+}
+
+int
+ShowHelp(const char* html_filename, const char* shellFile)
+{
+ int pidProcess = fork();
+ if (pidProcess == 0)
+ {
+ /* new child process */
+ execl("/bin/csh", "/bin/csh", shellFile, html_filename, 0);
+ /* execl only returns if error occurred */
+ _exit(-1);
+ }
+ /* fork failed, error number is why */
+ else if (pidProcess == (-1))
+ { return 0; }
+}
+
+#endif /* ! _WIN32 */
+
+/* The subcommand table. */
+/* The "display_file" subcommand was added as a hack to get the Foundry Tour to */
+/* launch. The help system can't handle more than one help file and should */
+/* be rewritten */
+static const struct ide_subcommand_table help_commands[] =
+{
+ { "initialize", help_initialize_command, INIT_MINARGS, INIT_MAXARGS },
+ { "topic", help_topic_command, 3, 3 },
+ { "toc", help_toc_command, 2, 2 },
+ { "display_file", help_display_file_command, 3, 4 },
+ { NULL, NULL, 0, 0 }
+};
+
+/* This function creates the ide_help TCL command. */
+
+int
+ide_create_help_command (Tcl_Interp *interp)
+{
+ struct help_command_data *hdata;
+
+ hdata = hdata_initialize ();
+
+ return ide_create_command_with_subcommands (interp, "ide_help",
+ help_commands,
+ (ClientData) hdata,
+ help_command_deleted);
+}
tclhelp.c
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: tkGraphCanvas.c
===================================================================
--- tkGraphCanvas.c (nonexistent)
+++ tkGraphCanvas.c (revision 1765)
@@ -0,0 +1,899 @@
+#include "default.h"
+#include "tkInt.h"
+#include "tkPort.h"
+#include "tkCanvas.h"
+#include "tkCanvLayout.h"
+
+extern Tk_ItemType tkEdgeType;
+
+static Tk_Uid allUid = NULL;
+
+typedef struct Layout_Graph Layout_Graph;
+
+static
+char* layableitems[] = {
+ "bitmap",
+ "edge",
+ "oval",
+ "polygon",
+ "rectangle",
+ "text",
+ "window",
+ (char*)0
+};
+
+/* Define a config set for graph command */
+static Tk_ConfigSpec graphspecs[] = {
+ {TK_CONFIG_BOOLEAN, "-computenodesize", (char*)NULL, (char*)NULL,
+ "0", Tk_Offset(LayoutConfig,computenodesize), 0, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_INT, "-gridlock", (char*)NULL, (char*)NULL,
+ "0", Tk_Offset(LayoutConfig,gridlock), 0, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_INT, "-elementsperline", (char*)NULL, (char*)NULL,
+ "0", Tk_Offset(LayoutConfig,elementsperline), 0, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_BOOLEAN, "-hideedges", (char*)NULL, (char*)NULL,
+ "0", Tk_Offset(LayoutConfig,hideedges), 0, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_BOOLEAN, "-keeprandompositions", (char*)NULL, (char*)NULL,
+ "0", Tk_Offset(LayoutConfig,keeprandompositions), 0, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_PIXELS, "-nodespaceh", (char*)NULL, (char*)NULL,
+ "5", Tk_Offset(LayoutConfig,nodespaceH), 0, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_PIXELS, "-nodespacev", (char*)NULL, (char*)NULL,
+ "5", Tk_Offset(LayoutConfig,nodespaceV), 0, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_PIXELS, "-maxx", (char*)NULL, (char*)NULL,
+ (char*)NULL, Tk_Offset(LayoutConfig,maxx),
+ TK_CONFIG_DONT_SET_DEFAULT, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_PIXELS, "-maxy", (char*)NULL, (char*)NULL,
+ (char*)NULL, Tk_Offset(LayoutConfig,maxy),
+ TK_CONFIG_DONT_SET_DEFAULT, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_INT, "-order", (char*)NULL, (char*)NULL,
+ "0", Tk_Offset(LayoutConfig,graphorder), 0, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_PIXELS, "-xoffset", (char*)NULL, (char*)NULL,
+ "4", Tk_Offset(LayoutConfig,xoffset), 0, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_PIXELS, "-yoffset", (char*)NULL, (char*)NULL,
+ "4", Tk_Offset(LayoutConfig,yoffset), 0, (Tk_CustomOption*)NULL},
+ {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, 0}
+};
+
+/*
+ * See tkCanvas.h for key data structures used to implement canvases.
+ */
+
+/*
+ * The structure defined below is used to keep track of a tag search
+ * in progress. Only the "prevPtr" field should be accessed by anyone
+ * other than StartTagSearch and NextItem.
+ */
+
+typedef struct TagSearch {
+ TkCanvas *canvasPtr; /* Canvas widget being searched. */
+ Tk_Uid tag; /* Tag to search for. 0 means return
+ * all items. */
+ Tk_Item *prevPtr; /* Item just before last one found (or NULL
+ * if last one found was first in the item
+ * list of canvasPtr). */
+ Tk_Item *currentPtr; /* Pointer to last item returned. */
+ int searchOver; /* Non-zero means NextItem should always
+ * return NULL. */
+} TagSearch;
+
+static Tk_Item * NextItem _ANSI_ARGS_((TagSearch *searchPtr));
+static Tk_Item * StartTagSearch _ANSI_ARGS_((TkCanvas *canvasPtr,
+ char *tag, TagSearch *searchPtr));
+static Tcl_HashTable * graph_table _ANSI_ARGS_((Tcl_Interp *interp));
+
+int MY_graphOrder (struct Layout_Graph* This);
+void * MY_EdgeParent (struct Layout_Graph* This, int i, int num);
+void * MY_EdgeFromNode (struct Layout_Graph* This, int i);
+
+
+static
+int
+getnodebbox(interp,canvasPtr, iPtr, bbox)
+ Tcl_Interp* interp;
+ TkCanvas* canvasPtr;
+ Tk_Item* iPtr;
+ ItemGeom* bbox;
+{
+ bbox->x1 = iPtr->x1;
+ bbox->y1 = iPtr->y1;
+ bbox->x2 = iPtr->x2;
+ bbox->y2 = iPtr->y2;
+ return TCL_OK;
+}
+
+static
+int
+getedgedim(canvasPtr, e, dim)
+ TkCanvas* canvasPtr;
+ Tk_Item* e;
+ ItemGeom* dim;
+{
+ int argc2;
+ char **argv2;
+
+ /* Read the text height of this edge. */
+ Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
+ e->typePtr->configSpecs,
+ (char *) e, "-textheight", 0);
+ if(Tcl_SplitList(canvasPtr->interp, canvasPtr->interp->result,
+ &argc2, &argv2) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ dim->height = atol(argv2[4]);
+ ckfree((char *) argv2);
+ /* Read the text width of this edge. */
+ Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
+ e->typePtr->configSpecs,
+ (char *) e, "-textwidth", 0);
+ if(Tcl_SplitList(canvasPtr->interp, canvasPtr->interp->result,
+ &argc2, &argv2) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ dim->width = atol(argv2[4]);
+ ckfree((char *) argv2);
+ Tcl_ResetResult(canvasPtr->interp);
+ return TCL_OK;
+}
+
+static
+int
+setnodegeom(interp,canvasPtr,iPtr,geom)
+ Tcl_Interp* interp;
+ TkCanvas* canvasPtr;
+ Tk_Item* iPtr;
+ ItemGeom geom;
+{
+ double deltax, deltay;
+
+ if(iPtr->typePtr->translateProc == NULL) {
+ Tcl_AppendResult(interp,"item has no translation proc",(char*)0);
+ return TCL_ERROR;
+ }
+
+ /* get the delta x,y of the item */
+ deltax = geom.x1 - iPtr->x1;
+ deltay = geom.y1 - iPtr->y1;
+
+ Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, iPtr->x1, iPtr->y1, iPtr->x2, iPtr->y2);
+ (void)(*iPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr, iPtr, deltax, deltay);
+ Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, iPtr->x1, iPtr->y1, iPtr->x2, iPtr->y2);
+ return TCL_OK;
+}
+
+static Layout_Graph *
+GetGraphLayoutII(TkCanvas *canvasPtr, Tcl_Interp *interp);
+static
+int
+setedgegeom(interp,canvasPtr,iPtr,geom,i)
+ Tcl_Interp* interp;
+ TkCanvas* canvasPtr;
+ Tk_Item* iPtr;
+ ItemGeom geom;
+ int i;
+{
+ /* register char* nm;
+ register int c; */
+ int argc = 4;
+ char x1[TCL_DOUBLE_SPACE];
+ char y1[TCL_DOUBLE_SPACE];
+ char x2[TCL_DOUBLE_SPACE];
+ char y2[TCL_DOUBLE_SPACE];
+ char x3[TCL_DOUBLE_SPACE];
+ char y3[TCL_DOUBLE_SPACE];
+ char x4[TCL_DOUBLE_SPACE];
+ char y4[TCL_DOUBLE_SPACE];
+ char* argv[8];
+ Layout_Graph *graph=GetGraphLayoutII(canvasPtr, interp);
+
+ LayoutConfig cnf = GetLayoutConfig (/*canvasPtr->*/graph);
+ double xd = geom.x1 - geom.x2 /*- 10.0*/ , xdiff;
+
+ if (xd < 0.0) xd = geom.x2 - geom.x1 /*- 10.0*/;
+
+ if(iPtr->typePtr->coordProc == NULL) {
+ Tcl_AppendResult(interp,"could not set edge item coordinates",(char*)0);
+ return TCL_ERROR;
+ }
+ argv[0] = x1;
+ argv[1] = y1;
+ argv[2] = x2;
+ argv[3] = y2;
+ argv[4] = x3;
+ argv[5] = y3;
+ argv[6] = x4;
+ argv[7] = y4;
+
+ sprintf(x1,"%g",geom.x1);
+ sprintf(y1,"%g",geom.y1);
+ sprintf(x2,"%g",geom.x2);
+ sprintf(y2,"%g",geom.y2);
+
+ if (cnf.gridlock!=0)
+ {
+ /* changing lines, only when right to left */
+ if (! MY_graphOrder (/*canvasPtr->*/graph))
+ {
+ xdiff = (double) cnf.nodespaceH - xd;
+ if (xdiff < 0.0) xdiff = xd - (double) cnf.nodespaceH;
+
+ if (xdiff < 2.0 &&
+ MY_EdgeParent(/*canvasPtr->*/graph, i, 0) ==
+ MY_EdgeFromNode (/*canvasPtr->*/graph, i))
+ {
+ sprintf (x4, "%g", geom.x2);
+ sprintf (y4, "%g", geom.y2);
+
+ sprintf (x2, "%g", geom.x1 + (geom.x2 - geom.x1) / 2);
+ sprintf (y2, "%g", geom.y1);
+ sprintf (x3, "%g", geom.x1 + (geom.x2 - geom.x1) / 2);
+ sprintf (y3, "%g", geom.y2);
+ argc = 8;
+ }
+ }
+ }
+ Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, iPtr->x1, iPtr->y1, iPtr->x2, iPtr->y2);
+ (void)(*iPtr->typePtr->coordProc)(interp, (Tk_Canvas) canvasPtr, iPtr,
+ /* argc-3, argv+3); 08nov95 wmt */
+ argc, argv);
+ Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, iPtr->x1, iPtr->y1, iPtr->x2, iPtr->y2);
+ return TCL_OK;
+}
+
+static
+int
+GetEdgeNodes(interp,canvasPtr,i,fp,tp)
+ Tcl_Interp* interp;
+ TkCanvas* canvasPtr;
+ Tk_Item* i;
+ char** fp;
+ char** tp;
+{
+ int argc;
+ char** argv;
+ char * buf;
+
+ /* Read the from node id of this edge. */
+ Tk_ConfigureInfo(interp, canvasPtr->tkwin,
+ i->typePtr->configSpecs,
+ (char *) i, "-from", 0);
+ if(Tcl_SplitList(interp, interp->result,
+ &argc, &argv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ /* This should actuall be a call like Tcl_Strdup() */
+ buf = (char*)ckalloc (strlen(argv[4])+1);
+ strcpy (buf, argv[4]);
+ *fp = buf;
+ ckfree((char*)argv);
+ /* Read the to node id of this edge. */
+ Tk_ConfigureInfo(interp, canvasPtr->tkwin,
+ i->typePtr->configSpecs,
+ (char *) i, "-to", 0);
+ if(Tcl_SplitList(interp, interp->result,
+ &argc, &argv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ buf = (char*)ckalloc (strlen(argv[4])+1);
+ strcpy (buf, argv[4]);
+ *tp = buf;
+ ckfree((char*)argv);
+ Tcl_ResetResult(interp);
+ return TCL_OK;
+}
+
+
+int
+createcanvasgraph(interp,canvCmd,graph)
+ Tcl_Interp* interp;
+ Tcl_CmdInfo *canvCmd;
+ Layout_Graph **graph;
+{
+ LayoutConfig cfg;
+ int argc1; char* argv1[3];
+
+ *graph = LayoutCreateGraph();
+ if(!*graph) {
+ Tcl_AppendResult(interp,"cannot create graph for canvas",(char*)0);
+ return TCL_ERROR;
+ }
+ cfg = GetLayoutConfig(*graph);
+ /* Establish max x and max y based on canvas height/width */
+ argv1[0] = "";
+ argv1[1] = "cget";
+ argv1[2] = "-width";
+ argc1 = 3;
+ if ((canvCmd->proc)(canvCmd->clientData, interp, argc1, argv1)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ cfg.maxx = atol(Tcl_GetStringResult(interp));
+
+ argv1[2] = "-height";
+ if ((canvCmd->proc) (canvCmd->clientData, interp, argc1, argv1)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ cfg.maxy = atol(Tcl_GetStringResult(interp));
+ Tcl_ResetResult(interp);
+ SetLayoutConfig(*graph,cfg);
+ return TCL_OK;
+}
+
+static Tcl_HashTable *
+graph_table (Tcl_Interp *interp)
+{
+ return (Tcl_HashTable *) Tcl_GetAssocData (interp, "canvasgraph", NULL);
+}
+
+/*
+ *-------------------------------------------------------------
+ *
+ * GetGraphLayout --
+ * Gets graph info for canvas. Adds a new entry if needed.
+ *
+ * Results:
+ * Standard Tcl Error
+ *-------------------------------------------------------------
+ */
+
+static Layout_Graph *
+GetGraphLayout(canvCmd, interp)
+ Tcl_CmdInfo *canvCmd;
+ Tcl_Interp *interp;
+{
+ Tcl_HashEntry *entry;
+
+ entry = Tcl_FindHashEntry(graph_table(interp), (char *)canvCmd->clientData);
+ if (entry)
+ return (Layout_Graph *)Tcl_GetHashValue(entry);
+
+ return NULL;
+}
+
+static Layout_Graph *
+GetGraphLayoutII(canvasPtr, interp)
+ TkCanvas *canvasPtr;
+ Tcl_Interp *interp;
+{
+ Tcl_HashEntry *entry;
+ entry = Tcl_FindHashEntry(graph_table(interp), (char *)canvasPtr);
+ if (entry)
+ return (Layout_Graph *)Tcl_GetHashValue(entry);
+
+ return NULL;
+}
+
+static int
+GetCreatedGraphLayout(interp, canvCmd, graph)
+ Tcl_Interp *interp;
+ Tcl_CmdInfo *canvCmd;
+ Layout_Graph **graph;
+{
+ *graph = GetGraphLayout(canvCmd, interp);
+ if (*graph == NULL) {
+ Tcl_HashEntry *newitem;
+ int new;
+
+ /* No item, let's make one and add it to the table. */
+ if (createcanvasgraph(interp, canvCmd, graph) != TCL_OK)
+ return TCL_ERROR;
+ newitem = Tcl_CreateHashEntry(graph_table(interp),
+ (char *)(canvCmd->clientData), &new);
+ Tcl_SetHashValue(newitem, (ClientData) *graph);
+ }
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * GraphCanvasCmd --
+ * This procedure is invoked to process the new "graph"
+ * command. This command takes a canvas and uses it to layout
+ * the canvas items with a pretty graph structure.
+ *
+ * Results:
+ * Standard Tcl result.
+ *
+ *--------------------------------------------------------------
+ */
+
+int
+GraphCanvasCmd(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ int argc;
+ char **argv;
+{
+ Tcl_CmdInfo canvCmd;
+ size_t length;
+ int c, i;
+ Layout_Graph *graph;
+ TkCanvas *canvasPtr;
+
+ if (argc < 3) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " canvas option ?arg arg ...?\"",
+ (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;
+ }
+ canvasPtr = (TkCanvas *)(canvCmd.clientData);
+
+ c = argv[2][0];
+ length = strlen(argv[2]);
+ if ((c == 'a') && (strncmp(argv[2], "add", length) == 0)) {
+ char* newargv[4];
+ if (argc < 4) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ", argv[1], " add tagOrId ?tagOrId ...?\"",
+ (char *) NULL);
+ goto error;
+ }
+
+ if (GetCreatedGraphLayout(interp, &canvCmd, &graph) != TCL_OK)
+ goto error;
+
+ for (i = 3; i < argc; i++) {
+ Tk_Item *itemPtr;
+ TagSearch search;
+ /* Loop through all the items */
+ for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);
+ itemPtr != NULL; itemPtr = NextItem(&search)) {
+ char* nm = itemPtr->typePtr->name;
+ /* create a new edge or node */
+ if(strcmp(nm,"edge") == 0) {
+ char* fname;
+ char* tname;
+ Tk_Item* f;
+ Tk_Item* t;
+ /* find the from and to node pItems */
+ if(GetEdgeNodes(interp,canvasPtr,itemPtr,&fname,&tname) != TCL_OK)
+ goto error;
+ /* find the from and to node pItems */
+ f = StartTagSearch(canvasPtr, fname, &search);
+ t = StartTagSearch(canvasPtr, tname, &search);
+ ckfree(fname); ckfree(tname);
+ if(LayoutCreateEdge(graph,
+ (pItem)itemPtr,
+ (pItem)f, (pItem)t) != TCL_OK) {
+ char* msg = LayoutGetError(graph);
+ if(!msg)
+ msg = "could not record edge in graph";
+ Tcl_AppendResult(interp,msg,(char*)0);
+ goto error;
+ }
+ } else { /* not an edge; assume a node */
+ /* verify that we can handle this */
+ char** p;
+ for(p=layableitems;*p;p++) {
+ if(strcmp(*p,nm)==0) break;
+ }
+ if(!*p) {
+ Tcl_AppendResult(interp,"cannot yet handle ",nm,(char*)0);
+ goto error;
+ }
+ if(LayoutCreateNode(graph,
+ (pItem)itemPtr,NULL,NULL) !=TCL_OK) {
+ char* msg = LayoutGetError(graph);
+ if(!msg)
+ msg = "could not record node in graph";
+ Tcl_AppendResult(interp,msg,(char*)0);
+ goto error;
+ }
+ }
+ }
+ }
+
+ } else if ((c == 'c') && (strncmp(argv[2], "configure", length) == 0)) {
+ register int ok;
+ LayoutConfig cfg;
+ if (GetCreatedGraphLayout(interp, &canvCmd, &graph) != TCL_OK)
+ goto error;
+ cfg = GetLayoutConfig(graph);
+
+ if(argc == 3) {
+ /* get all options */
+ ok = Tk_ConfigureInfo(interp,
+ Tk_CanvasTkwin(*(Tk_Canvas *)canvasPtr),
+ graphspecs,(char*)&cfg, (char*)NULL, 0);
+ } else if(argc == 4) {
+ /* get one option */
+ ok = Tk_ConfigureInfo(interp,
+ Tk_CanvasTkwin(*(Tk_Canvas *)canvasPtr),
+ graphspecs,(char*)&cfg, argv[3], 0);
+ } else { /* setting one or more options */
+ ok = Tk_ConfigureWidget(interp,
+ Tk_CanvasTkwin(*(Tk_Canvas *)canvasPtr),
+ graphspecs, argc-3, argv+3,
+ (char*)&cfg, TK_CONFIG_ARGV_ONLY);
+ if(ok == TCL_OK) {
+ SetLayoutConfig(graph,cfg);
+ }
+ }
+ if(ok != TCL_OK) goto error;
+ } else if ((c == 'c') && (strncmp(argv[2], "clear", length) == 0)) {
+ /* clear graph; ignore if no graph */
+ Layout_Graph *graph = GetGraphLayout(&canvCmd, interp);
+ if (graph)
+ LayoutClearGraph(graph);
+ } else if ((c == 'd') && (strncmp(argv[2], "destroy", length) == 0)) {
+ /* destroy any graph info connected to the canvas,
+ but without destroying the canvas
+ */
+ Layout_Graph *graph = GetGraphLayout(&canvCmd, interp);
+ if (graph) {
+ Tcl_HashEntry *entry;
+ entry = Tcl_FindHashEntry(graph_table(interp),
+ (char *)(canvCmd.clientData));
+
+ LayoutFreeGraph(graph);
+ /* Remove hash table entry */
+ Tcl_DeleteHashEntry(entry);
+ }
+ } else if ((c == 'e') && (strncmp(argv[2], "edges", length) == 0)) {
+ Tk_Item* ip;
+ Layout_Graph *graph = GetGraphLayout(&canvCmd, interp);
+ /* return list of edges associated with graph, if any */
+ if(!graph) goto done;
+ for(i=0;LayoutGetIthEdge(graph,i,(pItem*)&ip)==TCL_OK;i++) {
+ char convertbuffer[20];
+ sprintf(convertbuffer, "%d", ip->id);
+ Tcl_AppendElement(interp,convertbuffer);
+ }
+ } else if ((c == 'l') && (strncmp(argv[2], "layout", length) == 0)) {
+ char* which;
+ Tk_Item* ip;
+ Layout_Graph *graph = GetGraphLayout(&canvCmd, interp);
+
+ if(!graph) goto done;
+
+ /* get the geometries of the items attached to the graph */
+ for(i=0;LayoutGetIthNode(graph,i,(pItem*)&ip)==TCL_OK;i++) {
+ ItemGeom geom;
+ if(getnodebbox(interp,canvasPtr,ip,&geom) != TCL_OK
+ || LayoutSetNodeBBox(graph,ip,geom) != TCL_OK) {
+ Tcl_AppendResult(interp, "could not get node location", (char *) NULL);
+ goto error;
+ }
+ }
+ for(i=0;LayoutGetIthEdge(graph,i,(pItem*)&ip)==TCL_OK;i++) {
+ ItemGeom geom;
+ if(getedgedim(canvasPtr,ip,&geom) != TCL_OK
+ || LayoutSetEdgeDim(graph,ip,geom) != TCL_OK) {
+ Tcl_AppendResult(interp, "could not get edge location", (char *) NULL);
+ goto error;
+ }
+ }
+
+ if(argc > 3) which = argv[3]; else which = "isi";
+ if(strcmp(which,"tree")==0) {
+ if(LayoutTree(graph) == TCL_ERROR) {
+ Tcl_AppendResult(interp, "layout failed",(char *) NULL);
+ goto error;
+ }
+ } else if(strcmp(which,"isi")==0) {
+ if(LayoutISI(graph) == TCL_ERROR) {
+ Tcl_AppendResult(interp, "layout failed",(char *) NULL);
+ goto error;
+ }
+ } else if(strcmp(which,"matrix")==0) {
+ if(LayoutMatrix(graph) == TCL_ERROR) {
+ Tcl_AppendResult(interp, "layout failed",(char *) NULL);
+ goto error;
+ }
+ } else if(strcmp(which,"random")==0) {
+ if(LayoutRandom(graph) == TCL_ERROR) {
+ Tcl_AppendResult(interp, "layout failed",(char *) NULL);
+ goto error;
+ }
+ } else {
+ Tcl_AppendResult(interp, "unknown layout algorithm", which, (char *) NULL);
+ goto error;
+ }
+ /* move the various items into place after layout */
+ for(i=0;LayoutGetIthNode(graph,i,(pItem*)&ip)==TCL_OK;i++) {
+ ItemGeom geom;
+ if(LayoutGetNodeBBox(graph,ip,&geom) != TCL_OK
+ || setnodegeom(interp,canvasPtr,ip,geom) != TCL_OK) {
+ Tcl_AppendResult(interp, "could not set node location", (char *) NULL);
+ goto error;
+ }
+ }
+ for(i=0;LayoutGetIthEdge(graph,i,(pItem*)&ip)==TCL_OK;i++) {
+ ItemGeom geom;
+ if(LayoutGetEdgeEndPoints(graph,ip,&geom) != TCL_OK
+ || setedgegeom(interp,canvasPtr,ip,geom,i) != TCL_OK) {
+ Tcl_AppendResult(interp, "could not set edge location", (char *) NULL);
+ goto error;
+ }
+ }
+ } else if ((c == 'n') && (strncmp(argv[2], "nodes", length) == 0)) {
+ Tk_Item* ip;
+ Layout_Graph *graph = GetGraphLayout(&canvCmd, interp);
+
+ /* return list of nodes associated with graph */
+ if(!graph) goto done;
+ for(i=0;LayoutGetIthNode(graph,i,(pItem*)&ip)==TCL_OK;i++) {
+ char convertbuffer[20];
+ sprintf(convertbuffer, "%d", ip->id);
+ Tcl_AppendElement(interp,convertbuffer);
+ }
+ } else if ((c == 'r') && (strncmp(argv[2], "remove", length) == 0)) {
+ char* nm;
+ Tk_Item *itemPtr;
+ TagSearch search;
+ Layout_Graph *graph = GetGraphLayout(&canvCmd, interp);
+
+ if(!graph) goto done;
+ for (i = 3; i < argc; i++) {
+ for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);
+ itemPtr != NULL; itemPtr = NextItem(&search)) {
+ nm = itemPtr->typePtr->name;
+ /* delete a new edge or node */
+ if(strcmp(nm,"edge") == 0) {
+ (void)LayoutDeleteEdge(graph,itemPtr);
+ } else { /* not an edge; assume a node */
+ (void)LayoutDeleteNode(graph,itemPtr);
+ }
+ }
+ }
+ } else {
+ Tcl_AppendResult(interp, "bad option \"", argv[2],
+ "\": must be add, configure, clear, ",
+ "destroy, edges, layout, nodes, remove",
+ (char *) NULL);
+ goto error;
+ }
+ done:
+ return TCL_OK;
+ error:
+ return TCL_ERROR;
+}
+
+/* If graph is deleted, make it go away */
+static void
+delete_graph_command(ClientData clientData, Tcl_Interp *interp)
+{
+ Tcl_DeleteHashTable((Tcl_HashTable *) clientData);
+
+ ckfree ((char*) clientData);
+}
+
+/*
+ *-------------------------------------------------------------
+ * GraphLayoutInit()
+ * Adds appropriate commands to Tcl interpreter, and
+ * inits necessary tables.
+ *-------------------------------------------------------------
+ */
+int
+create_graph_command(Tcl_Interp *interp)
+{
+ Tcl_HashTable *graphTable= (Tcl_HashTable*)ckalloc (sizeof (Tcl_HashTable));
+
+ Tcl_InitHashTable(graphTable, TCL_ONE_WORD_KEYS);
+
+ /*
+ * Create an associated data that stores the
+ * hash table
+ */
+ Tcl_SetAssocData (interp, "canvasgraph",
+ delete_graph_command,
+ (void*) graphTable);
+
+ allUid = Tk_GetUid("all");
+
+ if (Tcl_CreateCommand(interp, "graph", GraphCanvasCmd,
+ NULL, NULL /*delete_graph_command*/ ) == NULL)
+ return TCL_ERROR;
+
+ Tk_CreateItemType(&tkEdgeType);
+
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * StartTagSearch --
+ *
+ * This procedure is called to initiate an enumeration of
+ * all items in a given canvas that contain a given tag.
+ *
+ * Results:
+ * The return value is a pointer to the first item in
+ * canvasPtr that matches tag, or NULL if there is no
+ * such item. The information at *searchPtr is initialized
+ * such that successive calls to NextItem will return
+ * successive items that match tag.
+ *
+ * Side effects:
+ * SearchPtr is linked into a list of searches in progress
+ * on canvasPtr, so that elements can safely be deleted
+ * while the search is in progress. EndTagSearch must be
+ * called at the end of the search to unlink searchPtr from
+ * this list.
+ *
+ *--------------------------------------------------------------
+ */
+
+static Tk_Item *
+StartTagSearch(canvasPtr, tag, searchPtr)
+ TkCanvas *canvasPtr; /* Canvas whose items are to be
+ * searched. */
+ char *tag; /* String giving tag value. */
+ TagSearch *searchPtr; /* Record describing tag search;
+ * will be initialized here. */
+{
+ int id;
+ Tk_Item *itemPtr, *prevPtr;
+ Tk_Uid *tagPtr;
+ Tk_Uid uid;
+ int count;
+
+ /*
+ * Initialize the search.
+ */
+
+ searchPtr->canvasPtr = canvasPtr;
+ searchPtr->searchOver = 0;
+
+ /*
+ * Find the first matching item in one of several ways. If the tag
+ * is a number then it selects the single item with the matching
+ * identifier. In this case see if the item being requested is the
+ * hot item, in which case the search can be skipped.
+ */
+
+ if (isdigit(UCHAR(*tag))) {
+ char *end;
+
+ id = strtoul(tag, &end, 0);
+ if (*end == 0) {
+ itemPtr = canvasPtr->hotPtr;
+ prevPtr = canvasPtr->hotPrevPtr;
+ if ((itemPtr == NULL) || (itemPtr->id != id) || (prevPtr == NULL)
+ || (prevPtr->nextPtr != itemPtr)) {
+ for (prevPtr = NULL, itemPtr = canvasPtr->firstItemPtr;
+ itemPtr != NULL;
+ prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
+ if (itemPtr->id == id) {
+ break;
+ }
+ }
+ }
+ searchPtr->prevPtr = prevPtr;
+ searchPtr->searchOver = 1;
+ canvasPtr->hotPtr = itemPtr;
+ canvasPtr->hotPrevPtr = prevPtr;
+ return itemPtr;
+ }
+ }
+
+ searchPtr->tag = uid = Tk_GetUid(tag);
+ if (uid == allUid) {
+
+ /*
+ * All items match.
+ */
+
+ searchPtr->tag = NULL;
+ searchPtr->prevPtr = NULL;
+ searchPtr->currentPtr = canvasPtr->firstItemPtr;
+ return canvasPtr->firstItemPtr;
+ }
+
+ /*
+ * None of the above. Search for an item with a matching tag.
+ */
+
+ for (prevPtr = NULL, itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
+ prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
+ for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
+ count > 0; tagPtr++, count--) {
+ if (*tagPtr == uid) {
+ searchPtr->prevPtr = prevPtr;
+ searchPtr->currentPtr = itemPtr;
+ return itemPtr;
+ }
+ }
+ }
+ searchPtr->prevPtr = prevPtr;
+ searchPtr->searchOver = 1;
+ return NULL;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * NextItem --
+ *
+ * This procedure returns successive items that match a given
+ * tag; it should be called only after StartTagSearch has been
+ * used to begin a search.
+ *
+ * Results:
+ * The return value is a pointer to the next item that matches
+ * the tag specified to StartTagSearch, or NULL if no such
+ * item exists. *SearchPtr is updated so that the next call
+ * to this procedure will return the next item.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+static Tk_Item *
+NextItem(searchPtr)
+ TagSearch *searchPtr; /* Record describing search in
+ * progress. */
+{
+ Tk_Item *itemPtr, *prevPtr;
+ int count;
+ Tk_Uid uid;
+ Tk_Uid *tagPtr;
+
+ /*
+ * Find next item in list (this may not actually be a suitable
+ * one to return), and return if there are no items left.
+ */
+
+ prevPtr = searchPtr->prevPtr;
+ if (prevPtr == NULL) {
+ itemPtr = searchPtr->canvasPtr->firstItemPtr;
+ } else {
+ itemPtr = prevPtr->nextPtr;
+ }
+ if ((itemPtr == NULL) || (searchPtr->searchOver)) {
+ searchPtr->searchOver = 1;
+ return NULL;
+ }
+ if (itemPtr != searchPtr->currentPtr) {
+ /*
+ * The structure of the list has changed. Probably the
+ * previously-returned item was removed from the list.
+ * In this case, don't advance prevPtr; just return
+ * its new successor (i.e. do nothing here).
+ */
+ } else {
+ prevPtr = itemPtr;
+ itemPtr = prevPtr->nextPtr;
+ }
+
+ /*
+ * Handle special case of "all" search by returning next item.
+ */
+
+ uid = searchPtr->tag;
+ if (uid == NULL) {
+ searchPtr->prevPtr = prevPtr;
+ searchPtr->currentPtr = itemPtr;
+ return itemPtr;
+ }
+
+ /*
+ * Look for an item with a particular tag.
+ */
+
+ for ( ; itemPtr != NULL; prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
+ for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
+ count > 0; tagPtr++, count--) {
+ if (*tagPtr == uid) {
+ searchPtr->prevPtr = prevPtr;
+ searchPtr->currentPtr = itemPtr;
+ return itemPtr;
+ }
+ }
+ }
+ searchPtr->prevPtr = prevPtr;
+ searchPtr->searchOver = 1;
+ return NULL;
+}
tkGraphCanvas.c
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: tclwingrab.c
===================================================================
--- tclwingrab.c (nonexistent)
+++ tclwingrab.c (revision 1765)
@@ -0,0 +1,64 @@
+/* tclwingrab.c -- Tcl routines to enable and disable windows on Windows.
+ Copyright (C) 1997 Cygnus Solutions.
+ Written by Ian Lance Taylor .
+
+ This file contains routines to enable and disable windows on
+ Windows. This is used to support grabs on Windows in Tk 8.0.
+
+ The routines in this file are expected to be invoked from
+ ide_grab_support, which is defined in libide/library/wingrab.tcl.
+ They are not expected to be invoked directly, so they are not
+ really documented. */
+
+#ifdef _WIN32
+
+#include
+
+#include
+#include
+
+#include "guitcl.h"
+
+/* FIXME: We need to dig into the Tk window implementation internals
+ to convert a Tk window to an HWND. */
+
+#include
+
+/* Enable or disable a window. If the clientdata argument is NULL, we
+ disable the window. Otherwise we enable the window. This is just
+ a quick hack; if we ever need to do something else, we can use a
+ more serious method to distinguish the commands. */
+
+static int
+wingrab_command (ClientData cd, Tcl_Interp *interp, int objc,
+ Tcl_Obj *const *objv)
+{
+ long l;
+ HWND hwnd;
+
+ /* Note that here we understand the return value of wm frame. */
+
+ if (Tcl_GetLongFromObj (interp, objv[1], &l) != TCL_OK)
+ return TCL_ERROR;
+
+ hwnd = (HWND) l;
+ EnableWindow (hwnd, cd != NULL);
+
+ return TCL_OK;
+}
+
+/* Create the ide_grab_support_disable and ide_grab_support_enable
+ commands. */
+
+int
+ide_create_win_grab_command (Tcl_Interp *interp)
+{
+ if (Tcl_CreateObjCommand (interp, "ide_grab_support_disable",
+ wingrab_command, NULL, NULL) == NULL
+ || Tcl_CreateObjCommand (interp, "ide_grab_support_enable",
+ wingrab_command, (ClientData) 1, NULL) == NULL)
+ return TCL_ERROR;
+ return TCL_OK;
+}
+
+#endif /* _WIN32 */
tclwingrab.c
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: subcommand.h
===================================================================
--- subcommand.h (nonexistent)
+++ subcommand.h (revision 1765)
@@ -0,0 +1,31 @@
+/* subcommand.h - Handle commands with subcommands.
+ Copyright (C) 1997 Cygnus Solutions.
+ Written by Tom Tromey . */
+
+#ifndef SUBCOMMAND_H
+#define SUBCOMMAND_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ide_subcommand_table
+{
+ const char *method; /* Method name. If NULL, then this is
+ the last entry in the table. */
+ Tcl_CmdProc *func; /* The implementation. */
+ int min_args; /* Minimum number of args. */
+ int max_args; /* Maximum number of args. -1 means
+ no maximum. */
+};
+
+/* Define a command with subcommands. */
+int ide_create_command_with_subcommands
+ (Tcl_Interp *interp, char *name, const struct ide_subcommand_table *table,
+ ClientData, Tcl_CmdDeleteProc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SUBCOMMAND_H */
subcommand.h
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: tkTabletcl.h
===================================================================
--- tkTabletcl.h (nonexistent)
+++ tkTabletcl.h (revision 1765)
@@ -0,0 +1,366 @@
+"proc tkTableClipboardKeysyms {copy cut paste} {\n"
+" bind Table <$copy> {tk_tableCopy %W}\n"
+" bind Table <$cut> {tk_tableCut %W}\n"
+" bind Table <$paste> {tk_tablePaste %W}\n"
+"}\n"
+"bind Table <3> {\n"
+" ## You might want to check for row returned if you want to\n"
+" ## restrict the resizing of certain rows\n"
+" %W border mark %x %y\n"
+"}\n"
+"bind Table { %W border dragto %x %y }\n"
+"bind Table <1> {\n"
+" if {[winfo exists %W]} {\n"
+" tkTableBeginSelect %W [%W index @%x,%y]\n"
+" focus %W\n"
+" }\n"
+"}\n"
+"bind Table {\n"
+" array set tkPriv {x %x y %y}\n"
+" tkTableMotion %W [%W index @%x,%y]\n"
+"}\n"
+"bind Table {\n"
+" # empty\n"
+"}\n"
+"bind Table {\n"
+" if {[winfo exists %W]} {\n"
+" tkCancelRepeat\n"
+" %W activate @%x,%y\n"
+" }\n"
+"}\n"
+"bind Table {tkTableBeginExtend %W [%W index @%x,%y]}\n"
+"bind Table {tkTableBeginToggle %W [%W index @%x,%y]}\n"
+"bind Table {tkCancelRepeat}\n"
+"bind Table {\n"
+" array set tkPriv {x %x y %y}\n"
+" tkTableAutoScan %W\n"
+"}\n"
+"bind Table <2> {\n"
+" %W scan mark %x %y\n"
+" array set tkPriv {x %x y %y}\n"
+" set tkPriv(mouseMoved) 0\n"
+"}\n"
+"bind Table {\n"
+" if {(%x != $tkPriv(x)) || (%y != $tkPriv(y))} { set tkPriv(mouseMoved) 1 }\n"
+" if $tkPriv(mouseMoved) { %W scan dragto %x %y }\n"
+"}\n"
+"bind Table {\n"
+" if {!$tkPriv(mouseMoved)} { tk_tablePaste %W [%W index @%x,%y] }\n"
+"}\n"
+"if {[string comp {} [info command event]]} {\n"
+" tkTableClipboardKeysyms \n"
+"} else {\n"
+" tkTableClipboardKeysyms Control-c Control-x Control-v\n"
+"}\n"
+"bind Table {\n"
+" # empty to allow Tk focus movement\n"
+"}\n"
+"bind Table {\n"
+" catch {%W activate active}\n"
+"}\n"
+"bind Table {tkTableExtendSelect %W -1 0}\n"
+"bind Table {tkTableExtendSelect %W 1 0}\n"
+"bind Table {tkTableExtendSelect %W 0 -1}\n"
+"bind Table {tkTableExtendSelect %W 0 1}\n"
+"bind Table {%W yview scroll -1 pages; %W activate @0,0}\n"
+"bind Table {%W yview scroll 1 pages; %W activate @0,0}\n"
+"bind Table {%W xview scroll -1 pages}\n"
+"bind Table {%W xview scroll 1 pages}\n"
+"bind Table {%W see origin}\n"
+"bind Table {%W see end}\n"
+"bind Table {\n"
+" %W selection clear all\n"
+" %W activate origin\n"
+" %W selection set active\n"
+" %W see active\n"
+"}\n"
+"bind Table {\n"
+" %W selection clear all\n"
+" %W activate end\n"
+" %W selection set active\n"
+" %W see active\n"
+"}\n"
+"bind Table {tkTableDataExtend %W origin}\n"
+"bind Table {tkTableDataExtend %W end}\n"
+"bind Table
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