diff --git a/pd/src/makefile.in b/pd/src/makefile.in index 7af86d0576f1f47a312ad6e38b20cf5b576459e1..8b3229ca0fab9c41685b5b13c046e9fd27ab5ae0 100644 --- a/pd/src/makefile.in +++ b/pd/src/makefile.in @@ -107,7 +107,7 @@ endif .PHONY: pd gui externs all all: pd $(BIN_DIR)/pd-watchdog gui $(BIN_DIR)/pdsend \ - $(BIN_DIR)/pdreceive externs + $(BIN_DIR)/pdreceive externs tkpath bin: pd $(BIN_DIR)/pd-watchdog gui $(BIN_DIR)/pdsend \ $(BIN_DIR)/pdreceive @@ -189,6 +189,11 @@ externs: make -C ../extra/pd~ @EXTERNTARGET@ make -C ../extra/stdout @EXTERNTARGET@ +tkpath: + cd ../tkpath && aclocal && autoconf && ./configure --prefix=$(prefix) + make -C ../tkpath + cd ../src + BINARYMODE=@binarymode@ ABOUT_FILE=$(DESTDIR)$(pddocdir)/1.manual/1.introduction.txt @@ -199,6 +204,8 @@ install: all install -m644 pd.tk $(DESTDIR)$(libpdbindir)/pd.tk install -m644 pkgIndex.tcl $(DESTDIR)$(libpdbindir)/pkgIndex.tcl install -m644 helpbrowser.tcl $(DESTDIR)$(libpdbindir)/helpbrowser.tcl + install -m644 ../tkpath/library/tkpath.tcl $(DESTDIR)$(libpdbindir)/tkpath.tcl + install -m644 ../tkpath/libtkpath*so $(DESTDIR)$(libpdbindir)/ install -d $(DESTDIR)$(bindir) install $(BINARYMODE) $(PDEXEC) $(DESTDIR)$(bindir)/@PDEXEC@ # kludge to allow pd~ to work by default in pd-l2ork @@ -258,6 +265,7 @@ distclean: clean autom4te.cache/output.* autom4te.cache/traces.* autom4te.cache/requests -rmdir autom4te.cache -rm -rf autom4te-*.cache + cd ../tkpath && make distclean tags: $(SRC) $(GSRC); ctags *.[ch] @@ -297,12 +305,3 @@ etags_Linux: etags_MINGW: find /usr/local/include/ -type f -name \*.h -exec etags -a '{}' \; - - - - - - - - - diff --git a/pd/src/pkgIndex.tcl b/pd/src/pkgIndex.tcl index 13d4f4f77fe695cc8590aa0d2258bcb4b55e0f07..8f3a611b53b44a270b7d5464b01e0feb53a8ede4 100644 --- a/pd/src/pkgIndex.tcl +++ b/pd/src/pkgIndex.tcl @@ -1,3 +1,20 @@ -# Tcl package index file, version 1.1 +# pkgIndex.tcl. Generated from pkgIndex.tcl.in by configure. +# package ifneeded helpbrowser 0.1 [list source [file join $dir helpbrowser.tcl]] + +namespace eval ::tkpath { + proc load_package {dir} { + load [file join $dir libtkpath0.3.2.so] + # Allow optional redirect of library components. + # Only necessary for testing, but could be used elsewhere. + if {[info exists ::env(TKPATH_LIBRARY)]} { + set dir $::env(TKPATH_LIBRARY) + } + source $dir/tkpath.tcl + };# load_package +} + +package ifneeded tkpath 0.3.2 [list ::tkpath::load_package $dir] + +#*EOF* diff --git a/pd/tkpath/ChangeLog b/pd/tkpath/ChangeLog new file mode 100755 index 0000000000000000000000000000000000000000..bacbbebfa7cf65ca15dc7b1c000c92b2017e977a --- /dev/null +++ b/pd/tkpath/ChangeLog @@ -0,0 +1,71 @@ +2012-07-04 George Petasis <petasis@iit.demokritos.gr> + + * generic/tkpUtil.c: Fix in the tkStateKeyObjType definistion, in + order to compile with Tk 8.6. + * tclconfig/install-sh: + * tclconfig/tcl.m4: + * configure, configure.in: Updated to TEA 3.9. + * generic/*.c: Various fixes for mingw32/mingw64. + +2011-10-28 Peter Spjuth <peter.spjuth@gmail.com> + + * win/makefile.vc + * generic/path.c: + * configure, configure.in: Bumped revision to 0.3.2 + +2011-10-28 Peter Spjuth <peter.spjuth@gmail.com> + + * generic/tkCanvPath.c (PathCoords): + Fixed memory leak when using coords command with path item. + +2010-03-15 Peter Spjuth <peter.spjuth@gmail.com> + + * generic/tkIntPath.h: Updated PATH_DEPIXELIZE to avoid an offset + error with negative coordinates. + * demos/arcs.tcl: Added an arc where the offset error was visible. + +2010-03-15 Peter Spjuth <peter.spjuth@gmail.com> + + * unix/tkUnixCairoPath.c (TkPathInit): Get correct size of Drawable. + This fixes an intermittent strange clipping bug. + +2010-03-10 George Petasis <petasis@iit.demokritos.gr> + + * generic/tkpCanvPoly.c: fixes in DeletePolygon() to avoid double + releases of polyPtr->coordPtr & polyPtr->fillGC by + Tk_FreeConfigOptions(). + + * generic/tkpCanvUtil.c: fixes in Tk_PathDeleteOutline(), to set the + default empty values in the various Tk_PathOutline members, to stop + double releases done by Tk_FreeConfigOptions() (i.e. by + DeletePolygon() in tkpCanvPoly.c). + + * generic/tkpCanvas.c: fix in DestroyCanvas(), so as + TkPathCanvasItemIteratorPrev() accepts a pointer that has not been + just freed. + + * generic/tkpUtil.c: added a CONST before tkStateKeyObjType, to get + the code to compile with Tk 8.6. + + * win/tkWinGDIPlusPath.cpp: changed the file from Mac OS X format to + windows, as the MS C++ 10.0 compiler stopped with an error. + + * win/makefile.vc: I updated the windows makefile, to compile tkpath + with VC++ 10.0 compiler. May need further tweaking to work with + earlier versions. + +2009-04-01 Jeff Hobbs <jeffh@ActiveState.com> + + * Makefile.in (VPATH): add macosx subdir to VPATH + +2009-03-31 Jeff Hobbs <jeffh@ActiveState.com> + + * Makefile.in, tclconfig/config.m4: updated to TEA 3.7 and improved + * configure, configure.in: Makefile for Windows build + + * win/tkWinGDIPlusPath.cpp: clarify TkPathContext_ typedef + + * pkgIndex.tcl.in: use a more flexible pkgIndex.tcl.in starter + + * generic/tkPathStyle.c (Tk_PathDashOptionSetProc): initialize newPtr + diff --git a/pd/tkpath/README.txt b/pd/tkpath/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..485a6855113b09f74c348c6227ace983d280224e --- /dev/null +++ b/pd/tkpath/README.txt @@ -0,0 +1,54 @@ + + README for tkpath + _________________ + +This package implements path drawing modelled after its SVG counterpart, +see http://www.w3.org/TR/SVG11/. See the doc directory for more info. + +There are three backends used for drawing. They are all platform specific +except for the Tk drawing which uses only the API found in Tk. This +backend is very limited and has some problems with multiple subpaths. +It is only to be used as a fallback when the cairo backend is missing. + +The backends: + + 1) CoreGraphics for MacOSX, built using ProjectBuilder + + 2) GDI+ for WinXP, built by VC++7 (.NET), runs also on older system + using the gdiplus.dll + + 3) cairo (http://cairographics.org), built using the automake system; + the configure.in and Makefile.in files are a hack, so please help + yourself (and me). It requires a cairo 1.0 installation since + incompatible API changes appeared before 1.0 (libcairo.so.2 ?). + +There used to be two additional backends, GDI and core Tk drawing, but +these have been dropped. + +I could think of another backend based on X11 that has more features than +the compatibility layer of Tk, since the fallback is only necessary on unix +systems anyway. Perhaps an OpenGL backend would also be useful, mainly on +unix systems without cairo support. + +There are two important Design Principles: + + 1) Follow the SVG graphics model. Make it more condensed without + giving up any features. For instance, tkpath keeps only a -matrix + option which comprises translate, scale etc. attributes + + 2) Keep the actual path drawing code separate and independent of any + canvas code. + +Open Issues: + +There are a number of design choices that I'd like to discuss. + + o How to provide coordinates for prect? As the standard Tk way (x1,y1,x2,y2), + using sizes (x,y,width,height), or using options (x,y,-width,-height)? + + o What shall the precedence of the -style option compared to the individual + options be? + +Copyright (c) 2005-2008 Mats Bengtsson + +BSD style license. diff --git a/pd/tkpath/TODO b/pd/tkpath/TODO new file mode 100644 index 0000000000000000000000000000000000000000..73699f26a2cd094c19ac8f0e3acb9026d79d5ab6 --- /dev/null +++ b/pd/tkpath/TODO @@ -0,0 +1,72 @@ + +TODO + BUGS and undecided for tkpath +------------------------------------ + + o The 'delete itemOrTag' may match items of any combination and therefore + deleteing a group may delete items already in the list which may crash. + + o Scaling rotated arcs. Much math! Simplified. + Test case: + pack [tkp::canvas .c -width 600 -height 400] + set p "M 100 100 a 100 25 60 1 0 50 -25" + set id [.c create path $p] + set id [.c create path $p -stroke red -matrix {{2 0} {0 1} {0 0}}] + set id [.c create path $p -stroke blue] + .c scale $id 0 0 2 1 + + o Optimize segmentation computations used for hittesting in the 'Point' + functions. + + o Perhaps an OpenGL renderer. + + o Perhaps lightweight items with no own style options but only a reference + to a styleName to save a lot of memory. See TreeCtrl. + + o I have paid no attention to if strokes are transformed or not. Sort out! + CG + cairo: strokes are scaled exactly. + + o Perhaps it would be useful to allow multiple objects on a single item + by supplying many coordinates for pline, prect, circle, and ellipse? + + o I would like to move the TkPathInit/TkPathFree to the canvas + Display function instead of having it in the items Display function. + This is currently not possible due to the X11 emulation code + used by the old items. This would save a lot of cpu, on aqua + in particular. + + o Try to get rid of the Tk_Uid. + + o Perhaps have the Tk_PathItem's x1, y1, ... as doubles. + That would make translations and scaling easier since we don't have + to bother about roundoffs. Separate flag for hidden? + + o What to do with the -state option for the new items? + + o Perhaps it would be useful to have the precedence order between + item options and style options configurable. + + o Maybe there should be a group item also for tkp::surface? + + o Would it be useful to be able to set the viewport and coordinate + system for the canvas, like SVG does? Note that this is possible + using the root items -matrix option. + + o gdi+ seems unable to produce antialiasing effects on a surface but + there seems to be no gdi+ specific way of drawing in memory bitmaps + but had to call CreateDIBSection() which is a Win32 GDI API. + + o All postscript is missing. + + o Need to sort out how the tags "all" and "root" (0) shall interact. + + o It could be useful to have a 'style reset' command that sets all options + to their defaults and clears the mask. + + o Write all test code. + + o Add clipping. Use an extra item option '-clipto idOrTags' where the joint + set of all idOrTags form the clipping region. It should be possible to use + items not on the display, and perhaps the -state option can be used to hide items. + + + diff --git a/pd/tkpath/configure.in b/pd/tkpath/configure.in new file mode 100644 index 0000000000000000000000000000000000000000..3081bf5af596cd554082523120e65da984f99290 --- /dev/null +++ b/pd/tkpath/configure.in @@ -0,0 +1,282 @@ +#!/bin/bash -norc +dnl This file is an input file used by the GNU "autoconf" program to +dnl generate the file "configure", which is run during Tcl installation +dnl to configure the system for the local environment. +# +# RCS: @(#) $Id: configure.in,v 1.19 2012/07/04 20:43:21 petasis Exp $ + +#----------------------------------------------------------------------- +# Sample configure.in for Tcl Extensions. The only places you should +# need to modify this file are marked by the string __CHANGE__ +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# Set your package name and version numbers here. +# +# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION +# set as provided. These will also be added as -D defs in your Makefile +# so you can encode the package version directly into the source files. +#----------------------------------------------------------------------- + +AC_INIT([tkpath], [0.3.2]) + +#-------------------------------------------------------------------- +# Call TEA_INIT as the first TEA_ macro to set up initial vars. +# This will define a ${TEA_PLATFORM} variable == "unix" or "windows" +# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. +#-------------------------------------------------------------------- + +TEA_INIT([3.9]) + +AC_CONFIG_AUX_DIR(tclconfig) + +#-------------------------------------------------------------------- +# Load the tclConfig.sh file +#-------------------------------------------------------------------- + +TEA_PATH_TCLCONFIG +TEA_LOAD_TCLCONFIG + +#-------------------------------------------------------------------- +# Load the tkConfig.sh file if necessary (Tk extension) +#-------------------------------------------------------------------- + +TEA_PATH_TKCONFIG +TEA_LOAD_TKCONFIG + +#----------------------------------------------------------------------- +# Handle the --prefix=... option by defaulting to what Tcl gave. +# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. +#----------------------------------------------------------------------- + +TEA_PREFIX + +#----------------------------------------------------------------------- +# Standard compiler checks. +# This sets up CC by using the CC env var, or looks for gcc otherwise. +# This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create +# the basic setup necessary to compile executables. +#----------------------------------------------------------------------- + +TEA_SETUP_COMPILER + +#-------------------------------------------------------------------- +# The code makes use of PTR2INT, ensure the correct definition is +# picked from Tcl/Tk internal headers... +#-------------------------------------------------------------------- +AS_IF([test "$do64bit" = "yes"], [ + tcl_ok=no +], [ + tcl_ok=yes +]) +AC_CHECK_TYPE([intptr_t], [ + AC_DEFINE([HAVE_INTPTR_T], 1, [Do we have the intptr_t type?])], [ + AC_CACHE_CHECK([for pointer-size signed integer type], tcl_cv_intptr_t, [ + for tcl_cv_intptr_t in "int" "long" "long long" none; do + if test "$tcl_cv_intptr_t" != none; then + AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT], + [[sizeof (void *) <= sizeof ($tcl_cv_intptr_t)]])], + [tcl_ok=yes], [tcl_ok=no]) + test "$tcl_ok" = yes && break; fi + done]) + if test "$tcl_cv_intptr_t" != none; then + AC_DEFINE_UNQUOTED([intptr_t], [$tcl_cv_intptr_t], [Signed integer + type wide enough to hold a pointer.]) + fi +]) +AC_CHECK_TYPE([uintptr_t], [ + AC_DEFINE([HAVE_UINTPTR_T], 1, [Do we have the uintptr_t type?])], [ + AC_CACHE_CHECK([for pointer-size unsigned integer type], tcl_cv_uintptr_t, [ + for tcl_cv_uintptr_t in "unsigned int" "unsigned long" "unsigned long long" \ + none; do + if test "$tcl_cv_uintptr_t" != none; then + AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT], + [[sizeof (void *) <= sizeof ($tcl_cv_uintptr_t)]])], + [tcl_ok=yes], [tcl_ok=no]) + test "$tcl_ok" = yes && break; fi + done]) + if test "$tcl_cv_uintptr_t" != none; then + AC_DEFINE_UNQUOTED([uintptr_t], [$tcl_cv_uintptr_t], [Unsigned integer + type wide enough to hold a pointer.]) + fi +]) + +#----------------------------------------------------------------------- +# Specify the C source files to compile in TEA_ADD_SOURCES, +# public headers that need to be installed in TEA_ADD_HEADERS, +# stub library C source files to compile in TEA_ADD_STUB_SOURCES, +# and runtime Tcl library files in TEA_ADD_TCL_SOURCES. +# This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS +# and PKG_TCL_SOURCES. +#----------------------------------------------------------------------- + +TEA_ADD_SOURCES([path.c \ + tkPath.c \ + tkpCanvas.c \ + tkpCanvArc.c \ + tkpCanvBmap.c \ + tkpCanvImg.c \ + tkpCanvLine.c \ + tkpCanvPoly.c \ + tkpCanvPs.c \ + tkpCanvText.c \ + tkpCanvUtil.c \ + tkpCanvWind.c \ + tkpRectOval.c \ + tkpTrig.c \ + tkpUtil.c \ + tkCanvPathUtil.c \ + tkCanvEllipse.c \ + tkCanvGroup.c \ + tkCanvPath.c \ + tkCanvPimage.c \ + tkCanvPline.c \ + tkCanvPpoly.c \ + tkCanvPrect.c \ + tkCanvPtext.c \ + tkCanvGradient.c \ + tkPathGradient.c \ + tkCanvStyle.c \ + tkPathStyle.c \ + tkPathSurface.c \ + tkPathUtil.c]) +TEA_ADD_HEADERS([]) +TEA_ADD_INCLUDES([-I. -I\"`${CYGPATH} ${srcdir}/generic`\"]) +TEA_ADD_LIBS([]) +TEA_ADD_CFLAGS([]) +TEA_ADD_STUB_SOURCES([]) +TEA_ADD_TCL_SOURCES([library/tkpath.tcl]) + +#-------------------------------------------------------------------- +# A few miscellaneous platform-specific items: +# +# Define a special symbol for Windows (BUILD_sample in this case) so +# that we create the export library with the dll. +# +# Windows creates a few extra files that need to be cleaned up. +# You can add more files to clean if your extension creates any extra +# files. +# +# TEA_ADD_* any platform specific compiler/build info here. +#-------------------------------------------------------------------- + +if test "${TEA_PLATFORM}" = "windows" ; then + AC_PROG_CXX + CC=$CXX + + AC_DEFINE(BUILD_tkpath, 1, [Build windows export dll]) + CLEANFILES="pkgIndex.tcl *.lib *.dll *.exp *.ilk *.pdb vc*.pch" + TEA_ADD_SOURCES([win/tkWinGDIPlusPath.cpp]) + TEA_ADD_LIBS([gdiplus.lib gdi32.lib]) + #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) + + ## Check if the compiler accepts -static-libstdc++ (i.e. mingw)... + AC_CACHE_CHECK([if the compiler understands -static-libstdc++], + tcl_cv_cc_staticlib, [ + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -static-libstdc++" + AC_TRY_COMPILE(,, tcl_cv_cc_staticlib=yes, tcl_cv_cc_staticlib=no) + CFLAGS=$hold_cflags]) + +else + CLEANFILES="pkgIndex.tcl" + if test "${TEA_WINDOWINGSYSTEM}" = "aqua" ; then + TEA_ADD_SOURCES([macosx/tkMacOSXPath.c]) + TEA_ADD_LIBS([-framework Carbon]) + TEA_ADD_LIBS([-framework CoreServices]) + else + TEA_ADD_SOURCES([unix/tkUnixCairoPath.c]) + TEA_ADD_INCLUDES([`freetype-config --cflags`]) + TEA_ADD_INCLUDES([-I/usr/include/cairo]) + TEA_ADD_LIBS([-lcairo]) + fi +fi +AC_SUBST(CLEANFILES) + +#-------------------------------------------------------------------- +# Choose which headers you need. Extension authors should try very +# hard to only rely on the Tcl public header files. Internal headers +# contain private data structures and are subject to change without +# notice. +# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG +#-------------------------------------------------------------------- + +TEA_PUBLIC_TCL_HEADERS +#TEA_PRIVATE_TCL_HEADERS + +#TEA_PUBLIC_TK_HEADERS +TEA_PRIVATE_TK_HEADERS +#TEA_PATH_X + +#-------------------------------------------------------------------- +# Check whether --enable-threads or --disable-threads was given. +# This auto-enables if Tcl was compiled threaded. +#-------------------------------------------------------------------- + +TEA_ENABLE_THREADS + +#-------------------------------------------------------------------- +# The statement below defines a collection of symbols related to +# building as a shared library instead of a static library. +#-------------------------------------------------------------------- + +TEA_ENABLE_SHARED + +#-------------------------------------------------------------------- +# This macro figures out what flags to use with the compiler/linker +# when building shared/static debug/optimized objects. This information +# can be taken from the tclConfig.sh file, but this figures it all out. +#-------------------------------------------------------------------- + +TEA_CONFIG_CFLAGS + +#-------------------------------------------------------------------- +# Set the default compiler switches based on the --enable-symbols option. +#-------------------------------------------------------------------- + +TEA_ENABLE_SYMBOLS + +#-------------------------------------------------------------------- +# Everyone should be linking against the Tcl stub library. If you +# can't for some reason, remove this definition. If you aren't using +# stubs, you also need to modify the SHLIB_LD_LIBS setting below to +# link against the non-stubbed Tcl library. Add Tk too if necessary. +#-------------------------------------------------------------------- + +AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) +AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) + +#-------------------------------------------------------------------- +# This macro generates a line to use when building a library. It +# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, +# and TEA_LOAD_TCLCONFIG macros above. +#-------------------------------------------------------------------- + +TEA_MAKE_LIB + +#-------------------------------------------------------------------- +# Determine the name of the tclsh and/or wish executables in the +# Tcl and Tk build directories or the location they were installed +# into. These paths are used to support running test cases only, +# the Makefile should not be making use of these paths to generate +# a pkgIndex.tcl file or anything else at extension build time. +#-------------------------------------------------------------------- + +TEA_PROG_TCLSH +TEA_PROG_WISH + +if test "${TEA_PLATFORM}" = "windows" ; then + ## If the compiler accepts -static-libstdc++, modify the compiler + ## and linker options... + if test $tcl_cv_cc_staticlib = yes; then + CFLAGS="$CFLAGS -static-libgcc -static-libstdc++" + SHLIB_LD="$SHLIB_LD -static-libgcc -static-libstdc++" + fi +fi + +#-------------------------------------------------------------------- +# Finally, substitute all of the various values into the Makefile. +# You may alternatively have a special pkgIndex.tcl.in or other files +# which require substituting th AC variables in. Include these here. +#-------------------------------------------------------------------- + +AC_OUTPUT([Makefile pkgIndex.tcl]) diff --git a/pd/tkpath/demos/all.tcl b/pd/tkpath/demos/all.tcl new file mode 100644 index 0000000000000000000000000000000000000000..80bf0538e9699007467a5dcf4a4f17067aa736bc --- /dev/null +++ b/pd/tkpath/demos/all.tcl @@ -0,0 +1 @@ + set dir [file dirname [info script]] set tail [file tail [info script]] foreach fileName [glob -nocomplain -directory $dir *.tcl] { if {[file tail $fileName] ne $tail} { source $fileName } } \ No newline at end of file diff --git a/pd/tkpath/demos/apple.tcl b/pd/tkpath/demos/apple.tcl new file mode 100644 index 0000000000000000000000000000000000000000..08456f919dcda40a0fa2aea28cb93d582352a411 --- /dev/null +++ b/pd/tkpath/demos/apple.tcl @@ -0,0 +1,25 @@ +package require tkpath 0.3.0 + +set t .c_apple +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + +set grad [$w gradient create linear -stops \ + {{0.0 "#00bb00"} {0.35 "#00bb00"} {0.35 "#ffff00"} {0.50 "#ffff00"} \ + {0.50 "#ff6600"} {0.65 "#ff6600"} {0.65 "#dd0000"} {0.8 "#dd0000"} \ + {0.8 "#3366cc"} {1.0 "#3366cc"}} \ + -lineartransition {0 0 0 1}] + +$w create path "M 0 0 C 20 0 40 -20 70 -20 S 130 30 130 60 \ + 110 200 60 200 20 180 0 180 \ + -10 200 -60 200 -130 90 -130 60 \ + -110 -20 -70 -20 -20 0 0 0 z \ + M 0 -10 Q -10 -60 50 -80 Q 50 -20 0 -10 z" \ + -fill $grad -stroke "" -tags apple + +$w move apple 200 120 + + + + diff --git a/pd/tkpath/demos/arcs.tcl b/pd/tkpath/demos/arcs.tcl new file mode 100644 index 0000000000000000000000000000000000000000..e1b7e6ec5bfbde8eb11fecf447006e6f4347a5f5 --- /dev/null +++ b/pd/tkpath/demos/arcs.tcl @@ -0,0 +1,74 @@ +package require tkpath 0.3.0 + +set t .c_arcs +destroy $t +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 500 -height 400 -bg white] + +$w create path "M 20 350 l 50 -25 \ + a 25 25 -30 0 1 50 -25 l 50 -25 \ + a 25 50 -30 0 1 50 -25 l 50 -25 \ + a 25 75 -30 0 1 50 -25 l 50 -25 \ + a 25 100 -30 0 1 50 -25 l 50 -25" -stroke red -strokewidth 2 + +$w create path "M 30 350 h 100 a 25 200 0 0 1 50 0 h 60" \ + -stroke blue -strokewidth 2 + +$w create path "M 100 100 a 25 25 -30 0 1 50 -25 z" -fill yellow -strokewidth 2 +$w create path "M 180 100 a 25 25 30 0 1 50 25 z" -fill yellow -strokewidth 2 + +set r 40 +set a 10 +set b 6 +set b2 [expr {2*$b}] +set r2 [expr {2*$r}] +set ra [expr {$r+$a}] +set a2 [expr {2*$r+$a}] + +proc tkp::circlepath {r} { + + return [list M -6 -$a l -$b -$b M -6 -$a l -$b $b] +} + +$w create path "M 0 0 A $r $r 0 1 1 0 $r2 A $r $r 0 1 1 0 0 Z" \ + -strokewidth 2 -tag acircle + +$w create path "M 0 -$a A $ra $ra 0 1 1 6 $a2" \ + -stroke red -tag acircle +$w create path "M 0 -$a v -$b v $b2" \ + -stroke red -tag acircle +$w create path "M 6 $a2 l $b -$b M 6 $a2 l $b $b" \ + -stroke red -tag acircle + +$w create path "M 0 $a2 A $ra $ra 0 1 1 -6 -$a" \ + -stroke red -tag acircle +$w create path "M 0 $a2 v -$b v $b2" \ + -stroke red -tag acircle +$w create path "M -6 -$a l -$b -$b M -6 -$a l -$b $b" \ + -stroke red -tag acircle + +$w create ptext -20 [expr {$a2+30}] \ + -text "M 0 0 A $r $r 0 1 1 0 $r2 A $r $r 0 1 1 0 0 Z" \ + -textanchor middle -tags acircle + +$w move acircle 400 220 + +# Make an elllipse around origo and put it in place using a transation matrix +namespace import ::tcl::mathop::* +proc ellipsepath {x y rx ry} { + list \ + M $x [- $y $ry] \ + a $rx $ry 0 1 1 0 [* 2 $ry] \ + a $rx $ry 0 1 1 0 [* -2 $ry] \ + Z +} +set Phi [expr {45 / 180.0 * 3.1415926535}] +set cosPhi [expr {cos($Phi)*4}] +set sinPhi [expr {sin($Phi)*4}] +set msinPhi [- $sinPhi] +set matrix \ + [list [list $cosPhi $msinPhi] [list $sinPhi $cosPhi] \ + [list 200 200]] +$w create path [ellipsepath 0 0 20 10] -stroke purple -matrix $matrix + diff --git a/pd/tkpath/demos/butterfly.tcl b/pd/tkpath/demos/butterfly.tcl new file mode 100644 index 0000000000000000000000000000000000000000..7a1c594a0d82133766b00f1d184e47b9f4b173f6 --- /dev/null +++ b/pd/tkpath/demos/butterfly.tcl @@ -0,0 +1,10 @@ +package require tkpath 0.3.0 + +set t .c_butterfly +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 420 -height 320 -bg white] + +$w create path {M 204.33 139.83 C 196.33 133.33 206.68 132.82 206.58 132.58 C 192.33 97.08 169.35 81.41 167.58 80.58 C 162.12 78.02 159.48 78.26 160.45 76.97 C 161.41 75.68 167.72 79.72 168.58 80.33 C 193.83 98.33 207.58 132.33 207.58 132.33 C 207.58 132.33 209.33 133.33 209.58 132.58 C 219.58 103.08 239.58 87.58 246.33 81.33 C 253.08 75.08 256.63 74.47 247.33 81.58 C 218.58 103.58 210.34 132.23 210.83 132.33 C 222.33 134.83 211.33 140.33 211.83 139.83 C 214.85 136.81 214.83 145.83 214.83 145.83 C 214.83 145.83 231.83 110.83 298.33 66.33 C 302.43 63.59 445.83 -14.67 395.83 80.83 C 393.24 85.79 375.83 105.83 375.83 105.83 C 375.83 105.83 377.33 114.33 371.33 121.33 C 370.3 122.53 367.83 134.33 361.83 140.83 C 360.14 142.67 361.81 139.25 361.83 140.83 C 362.33 170.83 337.76 170.17 339.33 170.33 C 348.83 171.33 350.19 183.66 350.33 183.83 C 355.83 190.33 353.83 191.83 355.83 194.83 C 366.63 211.02 355.24 210.05 356.83 212.83 C 360.83 219.83 355.99 222.72 357.33 224.83 C 360.83 230.33 354.75 233.84 354.83 235.33 C 355.33 243.83 349.67 240.73 349.83 244.33 C 350.33 255.33 346.33 250.83 343.83 254.83 C 336.33 266.83 333.46 262.38 332.83 263.83 C 329.83 270.83 325.81 269.15 324.33 270.83 C 320.83 274.83 317.33 274.83 315.83 276.33 C 308.83 283.33 304.86 278.39 303.83 278.83 C 287.83 285.83 280.33 280.17 277.83 280.33 C 270.33 280.83 271.48 279.67 269.33 277.83 C 237.83 250.83 219.33 211.83 215.83 206.83 C 214.4 204.79 211.35 193.12 212.33 195.83 C 214.33 201.33 213.33 250.33 207.83 250.33 C 202.33 250.33 201.83 204.33 205.33 195.83 C 206.43 193.16 204.4 203.72 201.79 206.83 C 196.33 213.33 179.5 250.83 147.59 277.83 C 145.42 279.67 146.58 280.83 138.98 280.33 C 136.46 280.17 128.85 285.83 112.65 278.83 C 111.61 278.39 107.58 283.33 100.49 276.33 C 98.97 274.83 95.43 274.83 91.88 270.83 C 90.39 269.15 86.31 270.83 83.27 263.83 C 82.64 262.38 79.73 266.83 72.13 254.83 C 69.6 250.83 65.54 255.33 66.05 244.33 C 66.22 240.73 60.48 243.83 60.99 235.33 C 61.08 233.84 54.91 230.33 58.45 224.83 C 59.81 222.72 54.91 219.83 58.96 212.83 C 60.57 210.05 49.04 211.02 59.97 194.83 C 62 191.83 59.97 190.33 65.54 183.83 C 65.69 183.66 67.06 171.33 76.69 170.33 C 78.28 170.17 53.39 170.83 53.9 140.83 C 53.92 139.25 55.61 142.67 53.9 140.83 C 47.82 134.33 45.32 122.53 44.27 121.33 C 38.19 114.33 39.71 105.83 39.71 105.83 C 39.71 105.83 22.08 85.79 19.46 80.83 C -31.19 -14.67 114.07 63.59 118.22 66.33 C 185.58 110.83 202 145.83 202 145.83 C 202 145.83 202.36 143.28 203 141.83 C 203.64 140.39 204.56 140.02 204.33 139.83 z} -fill #f67f00 -strokewidth 1 -stroke {} +$w create path {M 203.62 139.62 C 195.62 133.12 205.96 132.6 205.87 132.37 C 191.62 96.87 168.64 81.2 166.87 80.37 C 161.41 77.81 158.77 78.05 159.73 76.76 C 160.69 75.47 167.01 79.51 167.87 80.12 C 193.12 98.12 206.87 132.12 206.87 132.12 C 206.87 132.12 208.62 133.12 208.87 132.37 C 218.87 102.87 238.87 87.37 245.62 81.12 C 252.37 74.87 255.92 74.26 246.62 81.37 C 217.87 103.37 209.63 132.01 210.12 132.12 C 221.62 134.62 210.62 140.12 211.12 139.62 C 214.14 136.6 214.12 145.62 214.12 145.62 C 214.12 145.62 231.12 110.62 297.62 66.12 C 301.71 63.38 445.12 -14.88 395.12 80.62 C 392.53 85.57 375.12 105.62 375.12 105.62 C 375.12 105.62 376.62 114.12 370.62 121.12 C 369.59 122.32 367.12 134.12 361.12 140.62 C 359.43 142.46 361.09 139.04 361.12 140.62 C 361.62 170.62 337.05 169.96 338.62 170.12 C 348.12 171.12 349.47 183.45 349.62 183.62 C 355.12 190.12 353.12 191.62 355.12 194.62 C 365.91 210.81 354.53 209.84 356.12 212.62 C 360.12 219.62 355.28 222.51 356.62 224.62 C 360.12 230.12 354.03 233.62 354.12 235.12 C 354.62 243.62 348.96 240.52 349.12 244.12 C 349.62 255.12 345.62 250.62 343.12 254.62 C 335.62 266.62 332.74 262.17 332.12 263.62 C 329.12 270.62 325.09 268.94 323.62 270.62 C 320.12 274.62 316.62 274.62 315.12 276.12 C 308.12 283.12 304.15 278.17 303.12 278.62 C 287.12 285.62 279.62 279.95 277.12 280.12 C 269.62 280.62 270.77 279.46 268.62 277.62 C 237.12 250.62 218.62 211.62 215.12 206.62 C 213.69 204.57 210.63 192.91 211.62 195.62 C 213.62 201.12 212.62 250.12 207.12 250.12 C 201.62 250.12 201.12 204.12 204.62 195.62 C 205.72 192.95 203.69 203.5 201.08 206.62 C 195.62 213.12 178.79 250.62 146.88 277.62 C 144.71 279.46 145.87 280.62 138.27 280.12 C 135.75 279.95 128.14 285.62 111.94 278.62 C 110.9 278.17 106.87 283.12 99.78 276.12 C 98.26 274.62 94.72 274.62 91.17 270.62 C 89.68 268.94 85.6 270.62 82.56 263.62 C 81.93 262.17 79.01 266.62 71.42 254.62 C 68.88 250.62 64.83 255.12 65.34 244.12 C 65.51 240.52 59.77 243.62 60.27 235.12 C 60.36 233.62 54.2 230.12 57.74 224.62 C 59.1 222.51 54.2 219.62 58.25 212.62 C 59.86 209.84 48.33 210.81 59.26 194.62 C 61.29 191.62 59.26 190.12 64.83 183.62 C 64.98 183.45 66.35 171.12 75.98 170.12 C 77.57 169.96 52.68 170.62 53.18 140.62 C 53.21 139.04 54.9 142.46 53.18 140.62 C 47.11 134.12 44.6 122.32 43.56 121.12 C 37.48 114.12 39 105.62 39 105.62 C 39 105.62 21.37 85.57 18.74 80.62 C -31.9 -14.88 113.36 63.38 117.51 66.12 C 184.87 110.62 201.29 145.62 201.29 145.62 C 201.29 145.62 201.65 143.07 202.29 141.62 C 202.93 140.18 203.85 139.81 203.62 139.62 z M 242.12 153.12 C 245.16 153.02 251.35 156.17 255.12 155.12 C 280.55 148.06 328.44 154.56 331.62 155.62 C 343.62 159.62 351.62 131.12 326.12 131.12 C 294.59 131.12 301.12 129.12 280.12 126.12 C 278.34 125.87 252.6 135.42 228.62 149.12 C 225.12 151.12 227.12 153.62 242.12 153.12 z M 223.12 148.12 C 225.66 148.4 238.12 139.62 277.12 124.12 C 279.49 123.18 279.62 118.12 300.62 108.62 C 301.99 108 300.12 104.62 314.62 92.62 C 321.79 86.69 297.12 87.62 291.62 88.62 C 286.12 89.62 272.62 100.62 272.62 100.62 C 272.62 100.62 287.8 88.55 282.62 90.12 C 271.12 93.62 241.12 126.62 231.12 140.62 C 221.12 154.62 247.62 116.62 254.12 110.62 C 260.62 104.62 204.62 146.12 223.12 148.12 z M 335.62 128.62 C 350.14 131.53 348.62 110.12 341.12 109.12 C 329.55 107.58 307.51 108.3 301.12 110.62 C 284.62 116.62 280.29 122.65 281.62 123.12 C 310.12 133.12 330.62 127.62 335.62 128.62 z M 335.12 106.62 C 341.04 107.36 351.12 109.62 351.62 101.62 C 351.87 97.6 365.62 104.62 368.62 105.12 C 371.1 105.53 358.12 100.33 353.62 97.12 C 350.12 94.62 349.51 91.76 349.12 91.62 C 317.12 80.12 303.62 107.12 303.62 107.12 C 303.62 107.12 331.12 106.12 335.12 106.62 z M 400.62 62.62 C 395.62 54.62 386.66 57.08 383.62 53.62 C 369.12 37.12 335.54 58.28 363.12 56.12 C 395.12 53.62 401.21 63.57 400.62 62.62 z M 376.62 66.62 C 390.13 66.62 396.12 72.62 395.12 71.62 C 388.12 64.62 382.12 66.12 380.62 64.12 C 371.7 52.23 345.12 64.62 347.12 67.62 C 349.12 70.62 373.12 66.62 376.62 66.62 z M 330.12 76.12 C 309.12 81.12 318.12 88.62 320.62 88.12 C 340.05 84.24 334.5 75.08 330.12 76.12 z M 340.62 52.12 C 331.12 53.12 330.48 70.43 335.12 67.12 C 342.12 62.12 350.12 51.12 340.62 52.12 z M 315.62 75.62 C 329.62 70.12 319.12 67.62 314.62 68.12 C 310.12 68.62 306.79 75.45 308.12 78.12 C 311.12 84.12 312.91 76.69 315.62 75.62 z M 359.62 121.12 C 364.12 118.62 358.62 112.62 354.62 115.12 C 350.62 117.62 355.12 123.62 359.62 121.12 z M 350.12 78.62 C 361.89 90.39 366.62 84.12 369.12 83.12 C 377.24 79.87 386.12 88.62 384.62 87.12 C 377.34 79.84 372.62 81.12 371.62 79.62 C 364.01 68.2 352.66 75.44 350.12 75.62 C 343.12 76.12 334.43 81.03 337.62 80.12 C 341.12 79.12 348.62 77.12 350.12 78.62 z M 383.62 44.12 C 390.62 39.12 381.4 37.85 379.62 38.12 C 373.12 39.12 376.62 49.12 383.62 44.12 z M 224.62 181.12 C 230.12 187.62 291.62 285.12 282.12 252.62 C 280.83 248.2 285.62 266.12 291.12 256.12 C 292.66 253.32 301.27 253.03 274.62 208.62 C 273.12 206.12 252.62 198.12 232.12 175.62 C 229.02 172.21 220.05 175.72 224.62 181.12 z M 280.12 215.62 C 284.62 222.62 295.81 246.07 296.62 249.62 C 299.12 260.62 306.12 248.12 307.62 248.62 C 320.78 253.01 311.12 241.12 310.12 238.12 C 300.95 210.62 279.62 213.12 279.62 213.12 C 279.62 213.12 275.62 208.62 280.12 215.62 z M 253.62 256.12 C 266.26 274.09 271.12 267.12 273.62 265.12 C 281.32 258.96 232.34 196.14 229.12 192.12 C 225.12 187.12 225.12 215.62 253.62 256.12 z M 300.12 219.12 C 306.62 224.12 313.86 245.19 317.62 244.62 C 327.62 243.12 321.62 234.62 324.12 236.12 C 326.62 237.62 331.62 234.95 330.12 232.12 C 317.62 208.62 298.12 216.12 298.12 216.12 C 298.12 216.12 293.62 214.12 300.12 219.12 z M 235.62 168.62 C 216.12 168.62 282.12 222.62 301.12 212.12 C 305.06 209.94 296.12 208.62 297.62 197.12 C 297.9 195.02 284.12 191.12 284.12 178.12 C 284.12 173.88 276.2 172.12 251.12 172.12 C 246.62 172.12 256.03 168.62 235.62 168.62 z M 307.62 213.62 C 325.89 215.65 330.23 229.8 332.62 228.12 C 361.12 208.12 309.89 199.96 300.62 201.12 C 296.62 201.62 303.12 213.12 307.62 213.62 z M 238.62 164.12 C 242.12 166.62 254.12 176.62 292.62 168.12 C 294.09 167.8 263.62 167.62 259.62 166.62 C 255.62 165.62 236.25 162.43 238.62 164.12 z M 305.12 198.62 C 342.62 207.62 332.72 201.36 334.12 200.62 C 342.62 196.12 333.33 195.23 334.62 193.62 C 338.83 188.36 327.62 185.12 304.12 182.62 C 298.56 182.03 287.54 179.27 287.12 180.12 C 283.62 187.12 300.33 197.47 305.12 198.62 z M 311.12 182.12 C 343.62 187.62 323.23 177.43 323.62 177.12 C 335.12 168.12 297.12 168.12 297.12 168.12 C 297.12 168.12 280.79 172 281.12 172.62 C 285.62 181.12 307.15 181.45 311.12 182.12 z M 249.62 253.62 C 249.62 253.62 220.62 207.12 226.62 188.12 C 227.83 184.31 213.62 165.62 220.12 197.12 C 220.22 197.61 218.89 190.43 216.62 187.12 C 214.35 183.81 211.18 184.9 213.12 194.62 C 218.01 219.05 249.62 253.62 249.62 253.62 z M 289.12 83.62 C 296.62 81.62 293.12 79.12 288.62 78.12 C 284.12 77.12 281.62 85.62 289.12 83.62 z M 187.4 149.12 C 163.12 135.42 137.04 125.87 135.23 126.12 C 113.96 129.12 120.58 131.12 88.64 131.12 C 62.81 131.12 70.91 159.62 83.07 155.62 C 86.29 154.56 134.8 148.06 160.56 155.12 C 164.37 156.17 170.65 153.02 173.73 153.12 C 188.92 153.62 190.95 151.12 187.4 149.12 z M 161.57 110.62 C 168.15 116.62 195 154.62 184.87 140.62 C 174.74 126.62 144.35 93.62 132.7 90.12 C 127.46 88.55 142.83 100.62 142.83 100.62 C 142.83 100.62 129.16 89.62 123.58 88.62 C 118.01 87.62 93.03 86.69 100.29 92.62 C 114.97 104.62 113.08 108 114.47 108.62 C 135.74 118.12 135.87 123.18 138.27 124.12 C 177.78 139.62 190.4 148.4 192.97 148.12 C 211.71 146.12 154.99 104.62 161.57 110.62 z M 133.71 123.12 C 135.07 122.65 130.68 116.62 113.96 110.62 C 107.49 108.3 85.16 107.58 73.44 109.12 C 65.85 110.12 64.31 131.53 79.01 128.62 C 84.08 127.62 104.84 133.12 133.71 123.12 z M 111.43 107.12 C 111.43 107.12 97.75 80.12 65.34 91.62 C 64.95 91.76 64.33 94.62 60.78 97.12 C 56.23 100.33 43.08 105.53 45.59 105.12 C 48.63 104.62 62.55 97.6 62.81 101.62 C 63.31 109.62 73.53 107.36 79.52 106.62 C 83.57 106.12 111.43 107.12 111.43 107.12 z M 51.16 56.12 C 79.09 58.28 45.08 37.12 30.39 53.62 C 27.31 57.08 18.24 54.62 13.17 62.62 C 12.57 63.57 18.74 53.62 51.16 56.12 z M 67.37 67.62 C 69.39 64.62 42.47 52.23 33.43 64.12 C 31.91 66.12 25.83 64.62 18.74 71.62 C 17.73 72.62 23.8 66.62 37.48 66.62 C 41.03 66.62 65.34 70.62 67.37 67.62 z M 84.59 76.12 C 105.86 81.12 96.74 88.62 94.21 88.12 C 74.53 84.24 80.15 75.08 84.59 76.12 z M 79.52 67.12 C 84.22 70.43 83.57 53.12 73.95 52.12 C 64.33 51.12 72.43 62.12 79.52 67.12 z M 106.87 78.12 C 108.22 75.45 104.84 68.62 100.29 68.12 C 95.73 67.62 85.09 70.12 99.27 75.62 C 102.02 76.69 103.83 84.12 106.87 78.12 z M 59.77 115.12 C 55.72 112.62 50.14 118.62 54.7 121.12 C 59.26 123.62 63.82 117.62 59.77 115.12 z M 76.99 80.12 C 80.22 81.03 71.42 76.12 64.33 75.62 C 61.75 75.44 50.26 68.2 42.55 79.62 C 41.53 81.12 36.75 79.84 29.38 87.12 C 27.86 88.62 36.85 79.87 45.08 83.12 C 47.61 84.12 52.41 90.39 64.33 78.62 C 65.85 77.12 73.44 79.12 76.99 80.12 z M 34.44 38.12 C 32.64 37.85 23.3 39.12 30.39 44.12 C 37.48 49.12 41.03 39.12 34.44 38.12 z M 183.86 175.62 C 163.09 198.12 142.32 206.12 140.8 208.62 C 113.81 253.03 122.53 253.32 124.09 256.12 C 129.66 266.12 134.52 248.2 133.21 252.62 C 123.58 285.12 185.88 187.62 191.45 181.12 C 196.08 175.72 187 172.21 183.86 175.62 z M 135.74 213.12 C 135.74 213.12 114.13 210.62 104.84 238.12 C 103.83 241.12 94.05 253.01 107.38 248.62 C 108.9 248.12 115.99 260.62 118.52 249.62 C 119.34 246.07 130.68 222.62 135.23 215.62 C 139.79 208.62 135.74 213.12 135.74 213.12 z M 186.89 192.12 C 183.64 196.14 134.02 258.96 141.82 265.12 C 144.35 267.12 149.27 274.09 162.08 256.12 C 190.95 215.62 190.95 187.12 186.89 192.12 z M 117 216.12 C 117 216.12 97.25 208.62 84.59 232.12 C 83.06 234.95 88.13 237.62 90.66 236.12 C 93.2 234.62 87.12 243.12 97.25 244.62 C 101.06 245.19 108.39 224.12 114.97 219.12 C 121.56 214.12 117 216.12 117 216.12 z M 164.61 172.12 C 139.2 172.12 131.18 173.88 131.18 178.12 C 131.18 191.12 117.23 195.02 117.51 197.12 C 119.03 208.62 109.97 209.94 113.96 212.12 C 133.21 222.62 200.06 168.62 180.31 168.62 C 159.64 168.62 169.17 172.12 164.61 172.12 z M 114.47 201.12 C 105.08 199.96 53.18 208.12 82.05 228.12 C 84.47 229.8 88.87 215.65 107.38 213.62 C 111.94 213.12 118.52 201.62 114.47 201.12 z M 156 166.62 C 151.95 167.62 121.09 167.8 122.57 168.12 C 161.57 176.62 173.73 166.62 177.27 164.12 C 179.67 162.43 160.05 165.62 156 166.62 z M 128.14 180.12 C 127.71 179.27 116.55 182.03 110.92 182.62 C 87.12 185.12 75.76 188.36 80.03 193.62 C 81.33 195.23 71.92 196.12 80.53 200.62 C 81.95 201.36 71.92 207.62 109.91 198.62 C 114.76 197.47 131.69 187.12 128.14 180.12 z M 134.22 172.62 C 134.56 172 118.01 168.12 118.01 168.12 C 118.01 168.12 79.52 168.12 91.17 177.12 C 91.57 177.43 70.91 187.62 103.83 182.12 C 107.86 181.45 129.66 181.12 134.22 172.62 z M 203.1 194.62 C 205.07 184.9 201.85 183.81 199.56 187.12 C 197.26 190.43 195.91 197.61 196.01 197.12 C 202.6 165.62 188.21 184.31 189.43 188.12 C 195.5 207.12 166.13 253.62 166.13 253.62 C 166.13 253.62 198.15 219.05 203.1 194.62 z M 126.62 78.12 C 122.06 79.12 118.52 81.62 126.12 83.62 C 133.71 85.62 131.18 77.12 126.62 78.12 z} -fill #000000 -strokewidth 1 -stroke {} +$w create path {M 363.73 85.73 C 359.27 86.29 355.23 86.73 354.23 81.23 C 353.23 75.73 355.73 73.73 363.23 75.73 C 370.73 77.73 375.73 84.23 363.73 85.73 z M 327.23 89.23 C 327.23 89.23 308.51 93.65 325.73 80.73 C 333.73 74.73 334.23 79.73 334.73 82.73 C 335.48 87.2 327.23 89.23 327.23 89.23 z M 384.23 48.73 C 375.88 47.06 376.23 42.23 385.23 40.23 C 386.7 39.91 389.23 49.73 384.23 48.73 z M 389.23 48.73 C 391.73 48.23 395.73 49.23 396.23 52.73 C 396.73 56.23 392.73 58.23 390.23 56.23 C 387.73 54.23 386.73 49.23 389.23 48.73 z M 383.23 59.73 C 385.73 58.73 393.23 60.23 392.73 63.23 C 392.23 66.23 386.23 66.73 383.73 65.23 C 381.23 63.73 380.73 60.73 383.23 59.73 z M 384.23 77.23 C 387.23 74.73 390.73 77.23 391.73 78.73 C 392.73 80.23 387.73 82.23 386.23 82.73 C 384.73 83.23 381.23 79.73 384.23 77.23 z M 395.73 40.23 C 395.73 40.23 399.73 40.23 398.73 41.73 C 397.73 43.23 394.73 43.23 394.73 43.23 z M 401.73 49.23 C 401.73 49.23 405.73 49.23 404.73 50.73 C 403.73 52.23 400.73 52.23 400.73 52.23 z M 369.23 97.23 C 369.23 97.23 374.23 99.23 373.23 100.73 C 372.23 102.23 370.73 104.73 367.23 101.23 C 363.73 97.73 369.23 97.23 369.23 97.23 z M 355.73 116.73 C 358.73 114.23 362.23 116.73 363.23 118.23 C 364.23 119.73 359.23 121.73 357.73 122.23 C 356.23 122.73 352.73 119.23 355.73 116.73 z M 357.73 106.73 C 360.73 104.23 363.23 107.73 364.23 109.23 C 365.23 110.73 361.23 111.73 359.73 112.23 C 358.23 112.73 354.73 109.23 357.73 106.73 z M 340.73 73.23 C 337.16 73.43 331.23 71.73 340.23 65.73 C 348.55 60.19 348.23 61.73 348.73 64.73 C 349.48 69.2 344.3 73.04 340.73 73.23 z M 310.23 82.23 C 310.23 82.23 306.73 79.23 313.73 73.23 C 321.33 66.73 320.23 69.23 320.73 72.23 C 321.48 76.7 310.23 82.23 310.23 82.23 z M 341.23 55.73 C 341.23 55.73 347.23 54.73 346.23 56.23 C 345.23 57.73 342.73 63.23 339.23 59.73 C 335.73 56.23 341.23 55.73 341.23 55.73 z M 374.73 86.23 C 376.11 86.23 377.23 87.36 377.23 88.73 C 377.23 90.11 376.11 91.23 374.73 91.23 C 373.36 91.23 372.23 90.11 372.23 88.73 C 372.23 87.36 373.36 86.23 374.73 86.23 z M 369.73 110.73 C 371.11 110.73 372.23 111.86 372.23 113.23 C 372.23 114.61 371.11 115.73 369.73 115.73 C 368.36 115.73 367.23 114.61 367.23 113.23 C 367.23 111.86 368.36 110.73 369.73 110.73 z M 365.73 120.73 C 367.11 120.73 368.23 121.86 368.23 123.23 C 368.23 124.61 367.11 125.73 365.73 125.73 C 364.36 125.73 363.23 124.61 363.23 123.23 C 363.23 121.86 364.36 120.73 365.73 120.73 z M 349.73 127.23 C 351.11 127.23 352.23 128.36 352.23 129.73 C 352.23 131.11 351.11 132.23 349.73 132.23 C 348.36 132.23 347.23 131.11 347.23 129.73 C 347.23 128.36 348.36 127.23 349.73 127.23 z M 358.23 128.73 C 359.61 128.73 362.23 130.86 362.23 132.23 C 362.23 133.61 359.61 133.73 358.23 133.73 C 356.86 133.73 355.73 132.61 355.73 131.23 C 355.73 129.86 356.86 128.73 358.23 128.73 z M 382.23 89.73 C 383.61 89.73 384.73 90.86 384.73 92.23 C 384.73 93.61 383.61 94.73 382.23 94.73 C 380.86 94.73 379.73 93.61 379.73 92.23 C 379.73 90.86 380.86 89.73 382.23 89.73 z M 395.73 66.23 C 397.11 66.23 398.23 67.36 398.23 68.73 C 398.23 70.11 397.11 71.23 395.73 71.23 C 394.36 71.23 393.23 70.11 393.23 68.73 C 393.23 67.36 394.36 66.23 395.73 66.23 z M 300.73 74.23 C 303.05 75.16 314.23 67.73 310.73 66.73 C 307.23 65.73 298.23 73.23 300.73 74.23 z M 319.73 61.23 C 322.23 61.73 329.73 58.73 326.23 57.73 C 322.73 56.73 317.09 60.71 319.73 61.23 z M 271.73 91.73 C 277.23 88.73 292.73 81.23 285.23 82.23 C 277.73 83.23 267.01 94.31 271.73 91.73 z M 364.23 42.23 C 366.73 42.73 374.23 39.73 370.73 38.73 C 367.23 37.73 361.59 41.71 364.23 42.23 z M 292.23 78.73 C 294.73 79.23 299.73 76.73 296.23 75.73 C 292.73 74.73 289.59 78.21 292.23 78.73 z M 355.23 141.23 C 356.61 141.23 357.73 142.86 357.73 144.23 C 357.73 145.61 357.11 145.73 355.73 145.73 C 354.36 145.73 353.23 144.61 353.23 143.23 C 353.23 141.86 353.86 141.23 355.23 141.23 z M 347.73 140.73 C 349.11 140.73 351.23 141.36 351.23 142.73 C 351.23 144.11 348.61 143.73 347.23 143.73 C 345.86 143.73 344.73 142.61 344.73 141.23 C 344.73 139.86 346.36 140.73 347.73 140.73 z M 349.73 155.23 C 351.11 155.23 353.73 157.36 353.73 158.73 C 353.73 160.11 351.11 160.23 349.73 160.23 C 348.36 160.23 347.23 159.11 347.23 157.73 C 347.23 156.36 348.36 155.23 349.73 155.23 z M 337.73 175.73 C 341.73 174.73 341.73 176.73 342.73 180.23 C 343.73 183.73 350.8 195.11 339.23 181.23 C 336.73 178.23 333.73 176.73 337.73 175.73 z M 349.73 187.73 C 351.11 187.73 352.23 188.86 352.23 190.23 C 352.23 191.61 351.11 192.73 349.73 192.73 C 348.36 192.73 347.23 191.61 347.23 190.23 C 347.23 188.86 348.36 187.73 349.73 187.73 z M 352.23 196.73 C 353.61 196.73 354.73 197.86 354.73 199.23 C 354.73 200.61 353.61 201.73 352.23 201.73 C 350.86 201.73 349.73 200.61 349.73 199.23 C 349.73 197.86 350.86 196.73 352.23 196.73 z M 352.4 205.73 C 353.77 205.73 355.73 208.86 355.73 210.23 C 355.73 211.61 354.61 212.73 353.23 212.73 C 351.86 212.73 349.07 211.11 349.07 209.73 C 349.07 208.36 351.02 205.73 352.4 205.73 z M 353.73 221.73 C 355.11 221.73 354.73 221.86 354.73 223.23 C 354.73 224.61 354.61 223.73 353.23 223.73 C 351.86 223.73 352.23 224.61 352.23 223.23 C 352.23 221.86 352.36 221.73 353.73 221.73 z M 340.23 188.73 C 341.61 188.73 341.23 188.86 341.23 190.23 C 341.23 191.61 341.11 190.73 339.73 190.73 C 338.36 190.73 338.73 191.61 338.73 190.23 C 338.73 188.86 338.86 188.73 340.23 188.73 z M 343.23 201.23 C 344.61 201.23 344.23 201.36 344.23 202.73 C 344.23 204.11 344.44 207.73 343.07 207.73 C 341.69 207.73 341.73 204.11 341.73 202.73 C 341.73 201.36 341.86 201.23 343.23 201.23 z M 346.73 215.23 C 348.11 215.23 347.73 215.36 347.73 216.73 C 347.73 218.11 347.61 217.23 346.23 217.23 C 344.86 217.23 345.23 218.11 345.23 216.73 C 345.23 215.36 345.36 215.23 346.73 215.23 z M 340.57 228.73 C 341.94 228.73 341.73 228.86 341.73 230.23 C 341.73 231.61 341.44 230.73 340.07 230.73 C 338.69 230.73 339.23 231.61 339.23 230.23 C 339.23 228.86 339.19 228.73 340.57 228.73 z M 349.4 232.07 C 350.77 232.07 352.07 234.02 352.07 235.4 C 352.07 236.77 349.11 239.23 347.73 239.23 C 346.36 239.23 346.73 240.11 346.73 238.73 C 346.73 237.36 348.02 232.07 349.4 232.07 z M 343.73 246.4 C 345.11 246.4 347.4 246.02 347.4 247.4 C 347.4 248.77 344.11 251.23 342.73 251.23 C 341.36 251.23 341.73 252.11 341.73 250.73 C 341.73 249.36 342.36 246.4 343.73 246.4 z M 335.23 239.23 C 336.61 239.23 336.23 239.36 336.23 240.73 C 336.23 242.11 336.11 241.23 334.73 241.23 C 333.36 241.23 333.73 242.11 333.73 240.73 C 333.73 239.36 333.86 239.23 335.23 239.23 z M 332.73 258.4 C 334.11 258.4 335.4 260.02 335.4 261.4 C 335.4 262.77 333.11 262.23 331.73 262.23 C 330.36 262.23 330.73 263.11 330.73 261.73 C 330.73 260.36 331.36 258.4 332.73 258.4 z M 324.4 263.73 C 325.77 263.73 325.07 265.36 325.07 266.73 C 325.07 268.11 320.11 271.23 318.73 271.23 C 317.36 271.23 317.73 272.11 317.73 270.73 C 317.73 269.36 323.02 263.73 324.4 263.73 z M 325.23 247.73 C 326.61 247.73 326.23 247.86 326.23 249.23 C 326.23 250.61 326.11 249.73 324.73 249.73 C 323.36 249.73 323.73 250.61 323.73 249.23 C 323.73 247.86 323.86 247.73 325.23 247.73 z M 313.23 256.23 C 314.61 256.23 319.07 258.02 319.07 259.4 C 319.07 260.77 313.44 263.07 312.07 263.07 C 310.69 263.07 309.73 260.77 309.73 259.4 C 309.73 258.02 311.86 256.23 313.23 256.23 z M 300.23 260.73 C 301.61 260.73 301.23 260.86 301.23 262.23 C 301.23 263.61 301.11 262.73 299.73 262.73 C 298.36 262.73 298.73 263.61 298.73 262.23 C 298.73 260.86 298.86 260.73 300.23 260.73 z M 308.23 272.73 C 309.61 272.73 309.23 272.86 309.23 274.23 C 309.23 275.61 309.11 274.73 307.73 274.73 C 306.36 274.73 306.73 275.61 306.73 274.23 C 306.73 272.86 306.86 272.73 308.23 272.73 z M 305.23 273.73 C 306.61 273.73 306.23 273.86 306.23 275.23 C 306.23 276.61 306.11 275.73 304.73 275.73 C 303.36 275.73 303.73 276.61 303.73 275.23 C 303.73 273.86 303.86 273.73 305.23 273.73 z M 293.73 274.07 C 294.65 274.07 295.73 275.48 295.73 276.4 C 295.73 277.32 295.65 276.73 294.73 276.73 C 293.82 276.73 291.4 277.98 291.4 277.07 C 291.4 276.15 292.82 274.07 293.73 274.07 z M 296.73 276.73 C 297.65 276.73 297.4 276.82 297.4 277.73 C 297.4 278.65 297.32 278.07 296.4 278.07 C 295.48 278.07 295.73 278.65 295.73 277.73 C 295.73 276.82 295.82 276.73 296.73 276.73 z M 291.4 263.73 C 292.32 263.73 293.73 267.15 293.73 268.07 C 293.73 268.98 290.65 268.73 289.73 268.73 C 288.82 268.73 287.4 265.98 287.4 265.07 C 287.4 264.15 290.48 263.73 291.4 263.73 z M 280.07 274.73 C 281.44 274.73 281.23 274.86 281.23 276.23 C 281.23 277.61 280.94 276.73 279.57 276.73 C 278.19 276.73 278.73 277.61 278.73 276.23 C 278.73 274.86 278.69 274.73 280.07 274.73 z M 277.07 267.73 C 278.44 267.73 276.4 271.02 276.4 272.4 C 276.4 273.77 271.94 274.23 270.57 274.23 C 269.19 274.23 271.73 272.44 271.73 271.07 C 271.73 269.69 275.69 267.73 277.07 267.73 z M 52.23 84.9 C 56.7 85.46 60.73 85.9 61.73 80.4 C 62.73 74.9 60.23 72.9 52.73 74.9 C 45.23 76.9 40.23 83.4 52.23 84.9 z M 88.73 88.4 C 88.73 88.4 107.45 92.81 90.23 79.9 C 82.23 73.9 81.73 78.9 81.23 81.9 C 80.49 86.37 88.73 88.4 88.73 88.4 z M 31.73 47.9 C 40.08 46.23 39.73 41.4 30.73 39.4 C 29.27 39.07 26.73 48.9 31.73 47.9 z M 26.73 47.9 C 24.23 47.4 20.23 48.4 19.73 51.9 C 19.23 55.4 23.23 57.4 25.73 55.4 C 28.23 53.4 29.23 48.4 26.73 47.9 z M 32.73 58.9 C 30.23 57.9 22.73 59.4 23.23 62.4 C 23.73 65.4 29.73 65.9 32.23 64.4 C 34.73 62.9 35.23 59.9 32.73 58.9 z M 31.73 76.4 C 28.73 73.9 25.23 76.4 24.23 77.9 C 23.23 79.4 28.23 81.4 29.73 81.9 C 31.23 82.4 34.73 78.9 31.73 76.4 z M 20.23 39.4 C 20.23 39.4 16.23 39.4 17.23 40.9 C 18.23 42.4 21.23 42.4 21.23 42.4 z M 14.23 48.4 C 14.23 48.4 10.23 48.4 11.23 49.9 C 12.23 51.4 15.23 51.4 15.23 51.4 z M 46.73 96.4 C 46.73 96.4 41.73 98.4 42.73 99.9 C 43.73 101.4 45.23 103.9 48.73 100.4 C 52.23 96.9 46.73 96.4 46.73 96.4 z M 60.23 115.9 C 57.23 113.4 53.73 115.9 52.73 117.4 C 51.73 118.9 56.73 120.9 58.23 121.4 C 59.73 121.9 63.23 118.4 60.23 115.9 z M 58.23 105.9 C 55.23 103.4 52.73 106.9 51.73 108.4 C 50.73 109.9 54.73 110.9 56.23 111.4 C 57.73 111.9 61.23 108.4 58.23 105.9 z M 75.23 72.4 C 78.8 72.6 84.73 70.9 75.73 64.9 C 67.41 59.35 67.73 60.9 67.23 63.9 C 66.49 68.37 71.66 72.2 75.23 72.4 z M 105.73 81.4 C 105.73 81.4 109.23 78.4 102.23 72.4 C 94.64 65.89 95.73 68.4 95.23 71.4 C 94.49 75.87 105.73 81.4 105.73 81.4 z M 74.73 54.9 C 74.73 54.9 68.73 53.9 69.73 55.4 C 70.73 56.9 73.23 62.4 76.73 58.9 C 80.23 55.4 74.73 54.9 74.73 54.9 z M 41.23 85.4 C 39.86 85.4 38.73 86.53 38.73 87.9 C 38.73 89.28 39.86 90.4 41.23 90.4 C 42.61 90.4 43.73 89.28 43.73 87.9 C 43.73 86.53 42.61 85.4 41.23 85.4 z M 46.23 109.9 C 44.86 109.9 43.73 111.03 43.73 112.4 C 43.73 113.78 44.86 114.9 46.23 114.9 C 47.61 114.9 48.73 113.78 48.73 112.4 C 48.73 111.03 47.61 109.9 46.23 109.9 z M 50.23 119.9 C 48.86 119.9 47.73 121.03 47.73 122.4 C 47.73 123.78 48.86 124.9 50.23 124.9 C 51.61 124.9 52.73 123.78 52.73 122.4 C 52.73 121.03 51.61 119.9 50.23 119.9 z M 66.23 126.4 C 64.86 126.4 63.73 127.53 63.73 128.9 C 63.73 130.28 64.86 131.4 66.23 131.4 C 67.61 131.4 68.73 130.28 68.73 128.9 C 68.73 127.53 67.61 126.4 66.23 126.4 z M 57.73 127.9 C 56.36 127.9 53.73 130.03 53.73 131.4 C 53.73 132.78 56.36 132.9 57.73 132.9 C 59.11 132.9 60.23 131.78 60.23 130.4 C 60.23 129.03 59.11 127.9 57.73 127.9 z M 33.73 88.9 C 32.36 88.9 31.23 90.03 31.23 91.4 C 31.23 92.78 32.36 93.9 33.73 93.9 C 35.11 93.9 36.23 92.78 36.23 91.4 C 36.23 90.03 35.11 88.9 33.73 88.9 z M 20.23 65.4 C 18.86 65.4 17.73 66.53 17.73 67.9 C 17.73 69.28 18.86 70.4 20.23 70.4 C 21.61 70.4 22.73 69.28 22.73 67.9 C 22.73 66.53 21.61 65.4 20.23 65.4 z M 115.23 73.4 C 112.91 74.33 101.73 66.9 105.23 65.9 C 108.73 64.9 117.73 72.4 115.23 73.4 z M 96.23 60.4 C 93.73 60.9 86.23 57.9 89.73 56.9 C 93.23 55.9 98.87 59.87 96.23 60.4 z M 144.23 90.9 C 138.73 87.9 123.23 80.4 130.73 81.4 C 138.23 82.4 148.96 93.48 144.23 90.9 z M 51.73 41.4 C 49.23 41.9 41.73 38.9 45.23 37.9 C 48.73 36.9 54.37 40.87 51.73 41.4 z M 123.73 77.9 C 121.23 78.4 116.23 75.9 119.73 74.9 C 123.23 73.9 126.37 77.37 123.73 77.9 z M 60.73 140.4 C 59.36 140.4 58.23 142.03 58.23 143.4 C 58.23 144.78 58.86 144.9 60.23 144.9 C 61.61 144.9 62.73 143.78 62.73 142.4 C 62.73 141.03 62.11 140.4 60.73 140.4 z M 68.23 139.9 C 66.86 139.9 64.73 140.53 64.73 141.9 C 64.73 143.28 67.36 142.9 68.73 142.9 C 70.11 142.9 71.23 141.78 71.23 140.4 C 71.23 139.03 69.61 139.9 68.23 139.9 z M 66.23 154.4 C 64.86 154.4 62.23 156.53 62.23 157.9 C 62.23 159.28 64.86 159.4 66.23 159.4 C 67.61 159.4 68.73 158.28 68.73 156.9 C 68.73 155.53 67.61 154.4 66.23 154.4 z M 78.23 174.9 C 74.23 173.9 74.23 175.9 73.23 179.4 C 72.23 182.9 65.17 194.28 76.73 180.4 C 79.23 177.4 82.23 175.9 78.23 174.9 z M 66.23 186.9 C 64.86 186.9 63.73 188.02 63.73 189.4 C 63.73 190.77 64.86 191.9 66.23 191.9 C 67.61 191.9 68.73 190.77 68.73 189.4 C 68.73 188.02 67.61 186.9 66.23 186.9 z M 63.73 195.9 C 62.36 195.9 61.23 197.02 61.23 198.4 C 61.23 199.77 62.36 200.9 63.73 200.9 C 65.11 200.9 66.23 199.77 66.23 198.4 C 66.23 197.02 65.11 195.9 63.73 195.9 z M 63.57 204.9 C 62.19 204.9 60.23 208.02 60.23 209.4 C 60.23 210.77 61.36 211.9 62.73 211.9 C 64.11 211.9 66.9 210.27 66.9 208.9 C 66.9 207.52 64.94 204.9 63.57 204.9 z M 62.23 220.9 C 60.86 220.9 61.23 221.02 61.23 222.4 C 61.23 223.77 61.36 222.9 62.73 222.9 C 64.11 222.9 63.73 223.77 63.73 222.4 C 63.73 221.02 63.61 220.9 62.23 220.9 z M 75.73 187.9 C 74.36 187.9 74.73 188.02 74.73 189.4 C 74.73 190.77 74.86 189.9 76.23 189.9 C 77.61 189.9 77.23 190.77 77.23 189.4 C 77.23 188.02 77.11 187.9 75.73 187.9 z M 72.73 200.4 C 71.36 200.4 71.73 200.52 71.73 201.9 C 71.73 203.27 71.53 206.9 72.9 206.9 C 74.28 206.9 74.23 203.27 74.23 201.9 C 74.23 200.52 74.11 200.4 72.73 200.4 z M 69.23 214.4 C 67.86 214.4 68.23 214.52 68.23 215.9 C 68.23 217.27 68.36 216.4 69.73 216.4 C 71.11 216.4 70.73 217.27 70.73 215.9 C 70.73 214.52 70.61 214.4 69.23 214.4 z M 75.4 227.9 C 74.03 227.9 74.23 228.02 74.23 229.4 C 74.23 230.77 74.53 229.9 75.9 229.9 C 77.28 229.9 76.73 230.77 76.73 229.4 C 76.73 228.02 76.78 227.9 75.4 227.9 z M 66.57 231.23 C 65.19 231.23 63.9 233.19 63.9 234.57 C 63.9 235.94 66.86 238.4 68.23 238.4 C 69.61 238.4 69.23 239.27 69.23 237.9 C 69.23 236.52 67.94 231.23 66.57 231.23 z M 72.23 245.57 C 70.86 245.57 68.57 245.19 68.57 246.57 C 68.57 247.94 71.86 250.4 73.23 250.4 C 74.61 250.4 74.23 251.27 74.23 249.9 C 74.23 248.52 73.61 245.57 72.23 245.57 z M 80.73 238.4 C 79.36 238.4 79.73 238.52 79.73 239.9 C 79.73 241.27 79.86 240.4 81.23 240.4 C 82.61 240.4 82.23 241.27 82.23 239.9 C 82.23 238.52 82.11 238.4 80.73 238.4 z M 83.23 257.57 C 81.86 257.57 80.57 259.19 80.57 260.57 C 80.57 261.94 82.86 261.4 84.23 261.4 C 85.61 261.4 85.23 262.27 85.23 260.9 C 85.23 259.52 84.61 257.57 83.23 257.57 z M 91.57 262.9 C 90.19 262.9 90.9 264.52 90.9 265.9 C 90.9 267.27 95.86 270.4 97.23 270.4 C 98.61 270.4 98.23 271.27 98.23 269.9 C 98.23 268.52 92.94 262.9 91.57 262.9 z M 90.73 246.9 C 89.36 246.9 89.73 247.02 89.73 248.4 C 89.73 249.77 89.86 248.9 91.23 248.9 C 92.61 248.9 92.23 249.77 92.23 248.4 C 92.23 247.02 92.11 246.9 90.73 246.9 z M 102.73 255.4 C 101.36 255.4 96.9 257.19 96.9 258.57 C 96.9 259.94 102.53 262.23 103.9 262.23 C 105.28 262.23 106.23 259.94 106.23 258.57 C 106.23 257.19 104.11 255.4 102.73 255.4 z M 115.73 259.9 C 114.36 259.9 114.73 260.02 114.73 261.4 C 114.73 262.77 114.86 261.9 116.23 261.9 C 117.61 261.9 117.23 262.77 117.23 261.4 C 117.23 260.02 117.11 259.9 115.73 259.9 z M 107.73 271.9 C 106.36 271.9 106.73 272.02 106.73 273.4 C 106.73 274.77 106.86 273.9 108.23 273.9 C 109.61 273.9 109.23 274.77 109.23 273.4 C 109.23 272.02 109.11 271.9 107.73 271.9 z M 110.73 272.9 C 109.36 272.9 109.73 273.02 109.73 274.4 C 109.73 275.77 109.86 274.9 111.23 274.9 C 112.61 274.9 112.23 275.77 112.23 274.4 C 112.23 273.02 112.11 272.9 110.73 272.9 z M 122.23 273.23 C 121.32 273.23 120.23 274.65 120.23 275.57 C 120.23 276.48 120.32 275.9 121.23 275.9 C 122.15 275.9 124.57 277.15 124.57 276.23 C 124.57 275.32 123.15 273.23 122.23 273.23 z M 119.23 275.9 C 118.32 275.9 118.57 275.98 118.57 276.9 C 118.57 277.82 118.65 277.23 119.57 277.23 C 120.48 277.23 120.23 277.82 120.23 276.9 C 120.23 275.98 120.15 275.9 119.23 275.9 z M 124.57 262.9 C 123.65 262.9 122.23 266.32 122.23 267.23 C 122.23 268.15 125.32 267.9 126.23 267.9 C 127.15 267.9 128.57 265.15 128.57 264.23 C 128.57 263.32 125.48 262.9 124.57 262.9 z M 135.9 273.9 C 134.53 273.9 134.73 274.02 134.73 275.4 C 134.73 276.77 135.03 275.9 136.4 275.9 C 137.78 275.9 137.23 276.77 137.23 275.4 C 137.23 274.02 137.28 273.9 135.9 273.9 z M 138.9 266.9 C 137.53 266.9 139.57 270.19 139.57 271.57 C 139.57 272.94 144.03 273.4 145.4 273.4 C 146.78 273.4 144.23 271.61 144.23 270.23 C 144.23 268.86 140.28 266.9 138.9 266.9 z M 211 134.8 C 209.63 134.8 209.83 134.93 209.83 136.3 C 209.83 137.68 210.13 136.8 211.5 136.8 C 212.88 136.8 212.33 137.68 212.33 136.3 C 212.33 134.93 212.38 134.8 211 134.8 z M 205.5 134.8 C 204.13 134.8 204.33 134.93 204.33 136.3 C 204.33 137.68 204.63 136.8 206 136.8 C 207.38 136.8 206.83 137.68 206.83 136.3 C 206.83 134.93 206.88 134.8 205.5 134.8 z M 211 143.8 C 209.63 143.8 209.83 143.93 209.83 145.3 C 209.83 146.68 210.13 145.8 211.5 145.8 C 212.88 145.8 212.33 146.68 212.33 145.3 C 212.33 143.93 212.38 143.8 211 143.8 z M 204.9 143.7 C 203.53 143.7 203.73 143.83 203.73 145.2 C 203.73 146.58 204.03 145.7 205.4 145.7 C 206.78 145.7 206.23 146.58 206.23 145.2 C 206.23 143.83 206.28 143.7 204.9 143.7 z M 213 154.3 C 211.63 154.3 212 155.43 212 156.8 C 212 158.18 212.42 161.3 213.8 161.3 C 215.17 161.3 214.33 157.18 214.33 155.8 C 214.33 154.43 214.38 154.3 213 154.3 z M 204 154.3 C 202.63 154.3 202.6 155.53 202.6 156.9 C 202.6 158.28 201.63 161.5 203 161.5 C 204.38 161.5 204.8 157.68 204.8 156.3 C 204.8 154.93 205.38 154.3 204 154.3 z} -fill #fff6e3 -strokewidth 1 -stroke {} diff --git a/pd/tkpath/demos/clock.tcl b/pd/tkpath/demos/clock.tcl new file mode 100644 index 0000000000000000000000000000000000000000..5d82f1f24c99d227542b7e762123fd88ce75da62 --- /dev/null +++ b/pd/tkpath/demos/clock.tcl @@ -0,0 +1,53 @@ +package require tkpath 0.3.0 + +set t .c_clock +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + + +namespace eval ::clock { + + variable w $::w + + set r1 160 + set r2 140 + set r3 120 + set r4 100 + + for {set i 1} {$i <= 12} {incr i} { + set phi [expr (30.0*$i - 90.0)*3.14159/180.0] + set sinPhi [expr sin($phi)] + set cosPhi [expr cos($phi)] + set pt1($i) [list [expr $r1*$cosPhi] [expr $r1*$sinPhi]] + set pt2($i) [list [expr $r2*$cosPhi] [expr $r2*$sinPhi]] + set pt3($i) [list [expr $r3*$cosPhi] [expr $r3*$sinPhi]] + } + + $w create path \ + "M $pt2(1) L $pt1(1) M $pt2(2) L $pt1(2) M $pt3(3) L $pt1(3) \ + M $pt2(4) L $pt1(4) M $pt2(5) L $pt1(5) M $pt3(6) L $pt1(6) \ + M $pt2(7) L $pt1(7) M $pt2(8) L $pt1(8) M $pt3(9) L $pt1(9) \ + M $pt2(10) L $pt1(10) M $pt2(11) L $pt1(11) M $pt3(12) L $pt1(12)" \ + -tags clock -strokewidth 4 -strokelinecap round + + $w create path "M 0 4 L $r4 4 $r4 10 $r2 0 $r4 -10 $r4 -4 0 -4 z" \ + -stroke "" -fill gray50 -tags pointer + + $w move clock 200 200 + $w move pointer 200 200 + + proc ticker {secs} { + variable w + if {[winfo exists $w]} { + after 1000 [list clock::ticker [expr [incr secs] % 60]] + set phi [expr $secs*2.0*3.14159/60.0] + set m [::tkp::transform rotate $phi 200 200] + $w itemconfig pointer -m $m + } + } + + ticker -15 +} + + diff --git a/pd/tkpath/demos/ellipse.tcl b/pd/tkpath/demos/ellipse.tcl new file mode 100644 index 0000000000000000000000000000000000000000..fa60b7554fe2b6d4ed260f2c8ad532356e1d53c8 --- /dev/null +++ b/pd/tkpath/demos/ellipse.tcl @@ -0,0 +1,22 @@ +package require tkpath 0.3.0 + +set t .c_ellipse +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + +$w create circle 60 60 -r 32 -stroke "#c8c8c8" -fill "#e6e6e6" +$w create circle 200 60 -r 32 -stroke "#a19de2" -fill "#d6d6ff" + +$w create circle 60 160 -r 40 -stroke "#9ac790" -fill "#cae2c5" +$w create circle 200 160 -r 40 -stroke "#e2a19d" -fill "#ffd6d6" + +$w create ellipse 200 280 -rx 20 -ry 60 -stroke "#999999" +$w create ellipse 100 260 -rx 60 -ry 20 -stroke "#666666" -strokewidth 3 -fill "#bdbdbd" + +set id [$w create ellipse 280 280 -rx 20 -ry 60] +$w bind $id <Button-1> [list puts "hit $id"] + +$w create circle 300 220 -r 8 -fill red -stroke "" +$w create circle 300 240 -r 8 -fill green -stroke "" +$w create circle 300 260 -r 8 -fill blue -stroke "" diff --git a/pd/tkpath/demos/fillrule.tcl b/pd/tkpath/demos/fillrule.tcl new file mode 100644 index 0000000000000000000000000000000000000000..cc98eb3bbcbd11ce6d5012197809fa8bfa2954cd --- /dev/null +++ b/pd/tkpath/demos/fillrule.tcl @@ -0,0 +1,33 @@ +package require tkpath 0.3.0 + +destroy ._fillrule +toplevel ._fillrule +set w ._fillrule.c +pack [tkp::canvas $w -bg white -width 300 -height 300] +$w create path "M 10 10 h 80 v 80 h -80 z m 20 20 h 40 v 40 h -40 z" \ + -fill green -fillrule nonzero + +set id [$w create path "M 10 10 h 80 v 80 h -80 z m 20 20 h 40 v 40 h -40 z" \ + -fill blue -fillrule evenodd] +$w move $id 100 0 + +proc ellipsepathCW {x y rx ry} { + return "M $x $y a $rx $ry 0 1 1 0 [expr {2*$ry}] a $rx $ry 0 1 1 0 [expr {-2*$ry}] Z" +} + +proc ellipsepathCCW {x y rx ry} { + return "M $x $y a $rx $ry 0 1 0 0 [expr {2*$ry}] a $rx $ry 0 1 0 0 [expr {-2*$ry}] Z" +} + +set r1 40 +set r2 20 +set circleCW "[ellipsepathCW 0 0 $r1 $r1] [ellipsepathCW 0 20 $r2 $r2]" +set id [$w create path $circleCW -fill green -fillrule nonzero] +$w move $id 50 120 + +set circleCCW "[ellipsepathCW 0 0 $r1 $r1] [ellipsepathCCW 0 20 $r2 $r2]" +set id [$w create path $circleCCW -fill blue -fillrule evenodd] +$w move $id 150 120 + +$w create text 50 240 -text "nonzero" +$w create text 150 240 -text "evenodd" diff --git a/pd/tkpath/demos/gradients.tcl b/pd/tkpath/demos/gradients.tcl new file mode 100644 index 0000000000000000000000000000000000000000..37eec07a1a68efb0b122bf2b20144b35b8e3f349 --- /dev/null +++ b/pd/tkpath/demos/gradients.tcl @@ -0,0 +1 @@ +package require tkpath 0.3.0 set t .c_gradients toplevel $t set w $t.c pack [tkp::canvas $w -bg white -width 480 -height 400] set rainbow [::tkp::gradientstopsstyle rainbow] set g1 [$w gradient create linear -stops {{0 lightblue} {1 blue}}] $w create prect 10 10 210 60 -fill $g1 $w create text 220 20 -anchor w -text "-stops {{0 lightblue} {1 blue}}" set g2 [$w gradient create linear -stops {{0 "#f60"} {1 "#ff6"}} \ -lineartransition {50 0 160 0} -units userspace] $w create prect 10 70 210 120 -fill $g2 $w create text 220 80 -anchor w -text "-stops {{0 #f60} {1 #ff6}}" $w create text 220 100 -anchor w -text "-lineartransition {50 0 160 0} -units userspace" set g5 [$w gradient create linear -stops {{0 lightgreen} {1 green}}] $w create prect 10 130 210 180 -fill $g5 $w create text 220 140 -anchor w -text "-stops {{0 lightgreen} {1 green}}" set g3 [$w gradient create linear -stops {{0 "#f60"} {1 "#ff6"}} \ -lineartransition {0 0 0 1}] $w create path "M 40 200 q 60 -200 120 0 z" -fill $g3 set g4 [$w gradient create linear -stops $rainbow] $w create prect 10 210 210 260 -fill $g4 $w create text 220 220 -anchor w -text "rainbow" set g6 [$w gradient create radial -stops {{0 white} {1 black}}] $w create circle 60 330 -r 50 -fill $g6 set g7 [$w gradient create radial -stops {{0 white} {1 black}} \ -radialtransition {0.6 0.4 0.5 0.7 0.3}] $w create circle 200 330 -r 50 -fill $g7 -stroke "" set g8 [$w gradient create radial -stops {{0 white} {1 black}} \ -radialtransition {0.6 0.4 0.8 0.7 0.3}] $w create circle 340 330 -r 50 -fill $g8 -stroke "" proc GradientsOnButton {w} { set id [$w find withtag current] if {$id ne ""} { set type [$w type $id] switch -- $type { prect - path - circle - ellipse { set stroke [$w itemcget $id -stroke] set fill [$w itemcget $id -fill] puts "Hit a $type with stroke $stroke and fill $fill" } } } } $w bind all <Button-1> [list GradientsOnButton $w] \ No newline at end of file diff --git a/pd/tkpath/demos/group.tcl b/pd/tkpath/demos/group.tcl new file mode 100644 index 0000000000000000000000000000000000000000..436269980230c29f892b4a28a3484c96680d6f7a --- /dev/null +++ b/pd/tkpath/demos/group.tcl @@ -0,0 +1,38 @@ +package require tkpath 0.3.0 + +set t .c_group +destroy $t +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + +array set stroke [list 1 "#c8c8c8" 2 "#a19de2" 3 "#9ac790" 4 "#e2a19d"] +array set fill [list 1 "#e6e6e6" 2 "#d6d6ff" 3 "#cae2c5" 4 "#ffd6d6"] + +$w create prect 10 10 390 390 -rx 20 -strokewidth 4 -stroke gray70 -tags g0 + +foreach i {1 2 3 4} { + set s($i) [$w style create -strokewidth 3 -stroke $stroke($i)] + set f($i) [$w style create -strokewidth 3 -stroke $stroke($i) -fill $fill($i)] + + $w create group -tags g$i + $w create prect 10 10 180 180 -rx 10 -parent g$i -style $s($i) + + set id [$w create path "M 0 0 l 30 40 h -60 z" -parent g$i -style $f($i)] + $w move $id 60 40 + + set id [$w create path "M -20 0 h 40 l -40 80 h 40 z" -parent g$i -style $f($i)] + $w move $id 140 40 + + set id [$w create ellipse 0 0 -rx 30 -ry 20 -parent g$i -style $f($i)] + $w move $id 60 140 +} + +$w move g1 10 10 +$w move g2 200 10 +$w move g3 10 200 +$w move g4 200 200 + +unset -nocomplain s f stroke fill + + diff --git a/pd/tkpath/demos/hittest.tcl b/pd/tkpath/demos/hittest.tcl new file mode 100644 index 0000000000000000000000000000000000000000..79c1c2df518e034d1b046bd9096df6638ae3439c --- /dev/null +++ b/pd/tkpath/demos/hittest.tcl @@ -0,0 +1,28 @@ +package require tkpath 0.3.0 + +set t .c_hittest +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + +set id [$w create path "M 20 20 L 120 20 v 30 h -20 z"] +$w bind $id <Button-1> [list puts "hit $id"] + +set id [$w create path "M 10 80 h 100 v 100 z" -fill red] +$w bind $id <Button-1> [list puts "hit $id (red triangle)"] + +set id [$w create path "M 20 200 Q 50 120 100 200 T 150 200 200 200"] +$w bind $id <Button-1> [list puts "hit $id (quad bezier)"] + +set id [$w create path "M 10 250 h 80 v 80 h -80 z m 20 20 h 40 v 40 h -40 z" \ + -fill green -fillrule nonzero] +$w bind $id <Button-1> [list puts "hit $id (green with nonzero rule)"] + +set id [$w create path "M 110 250 h 80 v 80 h -80 z m 20 20 h 40 v 40 h -40 z" \ + -fill blue -fillrule evenodd] +$w bind $id <Button-1> [list puts "hit $id (blue with evenodd rule)"] + +set id [$w create path "M 220 50 v 100" -strokewidth 36 -strokelinecap round] +$w bind $id <Button-1> [list puts "hit $id (fat line with rounded caps)"] + + diff --git a/pd/tkpath/demos/image.tcl b/pd/tkpath/demos/image.tcl new file mode 100644 index 0000000000000000000000000000000000000000..77673723600535147ec300978f129eca5cfd6ad0 --- /dev/null +++ b/pd/tkpath/demos/image.tcl @@ -0,0 +1,28 @@ +package require tkpath 0.3.0 + +set t .c_image +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + +set dir [file dirname [info script]] +set imageFile [file join $dir trees.gif] +set name [image create photo -file $imageFile] +set x 20 +set y 20 +$w create pimage $x $y -image $name + +$w create prect $x $y \ + [expr $x+[image width $name]] [expr $y+[image height $name]] + +set m [::tkp::transform rotate 0.5] +lset m {2 0} 220 +lset m {2 1} -120 +$w create pimage 100 100 -image $name -matrix $m + +set m [::tkp::transform scale 2 0.8] +$w create pimage 10 300 -image $name -matrix $m + + + + diff --git a/pd/tkpath/demos/inherit.tcl b/pd/tkpath/demos/inherit.tcl new file mode 100644 index 0000000000000000000000000000000000000000..dcd9e26b2d0c8e9e26207260da652e09adc62ee0 --- /dev/null +++ b/pd/tkpath/demos/inherit.tcl @@ -0,0 +1,41 @@ +# +# This file demonstrates the inheritance mechanisms. Note that items inherit +# style options set in their parents, but the items own style option +# takes precedence. +# +package require tkpath 0.3.0 + +set t .c_inherit +destroy $t +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + +array set stroke [list 1 "#c8c8c8" 2 "#a19de2" 3 "#9ac790" 4 "#e2a19d"] +array set fill [list 1 "#e6e6e6" 2 "#d6d6ff" 3 "#cae2c5" 4 "#ffd6d6"] + +$w create prect 10 10 390 390 -rx 20 -strokewidth 4 -stroke gray70 -tags g0 + +foreach i {1 2 3 4} { + + $w create group -tags g$i -strokewidth 3 -stroke $stroke($i) -fill $fill($i) + $w create prect 10 10 180 180 -rx 10 -parent g$i -fill "" + + set id [$w create path "M 0 0 l 30 40 h -60 z" -parent g$i] + $w move $id 60 40 + + set id [$w create path "M -20 0 h 40 l -40 80 h 40 z" -parent g$i] + $w move $id 140 40 + + set id [$w create ellipse 0 0 -rx 30 -ry 20 -parent g$i -strokewidth 6] + $w move $id 60 140 +} + +$w move g1 10 10 +$w move g2 200 10 +$w move g3 10 200 +$w move g4 200 200 + +unset -nocomplain stroke fill + + diff --git a/pd/tkpath/demos/isexy.tcl b/pd/tkpath/demos/isexy.tcl new file mode 100644 index 0000000000000000000000000000000000000000..136bd43e3b25ef919ec465d80e5b6b4943d1cdf7 --- /dev/null +++ b/pd/tkpath/demos/isexy.tcl @@ -0,0 +1,177 @@ +package require tkpath 0.3.0 + +set transparent 1 + +set t .c_isexy1 +destroy $t +toplevel $t +set w $t.c +if {$transparent && $tcl_version >= 8.5 && [tk windowingsystem] eq "aqua"} { + wm attributes $t -transparent 1 + tkp::canvas $w -width 400 -height 400 -bg systemTransparent -highlightthickness 0 +} else { + tkp::canvas $w -width 400 -height 400 -highlightthickness 0 +} +pack $w -fill both -expand 1 + +set ::tkp::antialias 1 + +set height 24 +set width 120 +set radius 12 + +array set light { + gray "#e6e6e6" + blue "#d6d6ff" + green "#cae2c5" + red "#ffd6d6" +} + +proc drawcolumn {w tag {op 1.0}} { + global height width radius light + + array set font [font actual systemSystemFont] + set family $font(-family) + set fsize $font(-size) + + set g1 [$w gradient create linear \ + -stops [list [list 0.0 gray90 $op] [list 1.0 gray60 $op]] \ + -lineartransition {0 0 0 1}] + + set ybase [expr {$height - ($height - $fsize)/2 - 1}] + + set id1 [$w create prect 0 0 $width $height -rx $radius \ + -fill $g1 -stroke gray50 -tags $tag -strokeopacity $op] + set id2 [$w create ptext 20 $ybase -fontfamily $family -fontsize $fsize \ + -text "Vikings" -tags $tag -fill white -fillopacity $op] + set id3 [$w create ptext 20 $ybase -fontfamily $family -fontsize $fsize \ + -text "Vikings" -tags $tag -fillopacity $op] + + $w move $id2 0 1 + + set y 0 + foreach col {gray blue green red} text {Tor Freja Fro Oden} { + incr y [expr {$height + 8}] + set id1 [$w create prect 0 0 $width $height -rx $radius \ + -fill $light($col) -stroke "" -tags $tag -fillopacity $op] + set id2 [$w create ptext 20 $ybase -fill gray30 -text $text -tags $tag \ + -fillopacity $op -fontfamily $family -fontsize $fsize] + $w move $id1 0 $y + $w move $id2 0 $y + } +} + +proc drawbar {w tag} { + + set g1 [$w gradient create linear \ + -stops {{0.0 "#c3c3c3"} {1.0 "#969696"}} \ + -lineartransition {0 0 0 1}] + $w create prect 0 0 2000 40 -fill $g1 -stroke "" -tags $tag + $w create pline 0 40 2000 40 -stroke "#404040" +} + +proc drawbutton {win grad1 grad2 tag {type plain}} { + + set w 26 + set h 21 + set r 4 + set a [expr {$w-2*$r}] + set b [expr {$h-2*$r}] + set c [expr {$w-$r}] + + switch -- $type { + plain { + set p "M $r 0 h $a q $r 0 $r $r v $b q 0 $r -$r $r h -$a q -$r 0 -$r -$r v -$b q 0 -$r $r -$r Z" + } + left { + set p "M $r 0 h $c v $h h -$c q -$r 0 -$r -$r v -$b q 0 -$r $r -$r Z" + } + center { + set p "M 0 0 h $w v $h h -$w z" + } + right { + set p "M 0 0 h $c q $r 0 $r $r v $b q 0 $r -$r $r h -$c z" + } + } + set id1 [$win create path $p -stroke "#c2c2c2" -tags $tag -fill ""] + set id2 [$win create path $p -stroke "#454545" -tags $tag -fill $grad1] + $win move $id1 0 1 + + $win bind $id2 <ButtonPress-1> [list $win itemconfig $id2 -fill $grad2] + $win bind $id2 <ButtonRelease-1> [list $win itemconfig $id2 -fill $grad1] +} + +proc drawhammer {w tag} { + set path "M 0 -3 H 2 L 5 -2 V 0 H 1 V 8 H -1 V 0 H -5 V -2 L -2 -3 z" + return [$w create path $path -stroke "" -fill gray50 -tags $tag] +} + +drawcolumn $w c1 +$w move c1 10 60 +drawcolumn $w c2 0.6 +$w move c2 [expr {$width + 2*10}] 60 + +drawhammer $w hammer +$w move hammer 80 102 +$w itemconfig hammer -matrix [::tkp::transform rotate -0.7 80 102] + +drawbar $w bar + +set g1 [$w gradient create linear \ + -stops {{0.0 "#ffffff"} {0.5 "#d1d1d1"} {1.0 "#a9a9a9"}} \ + -lineartransition {0 0 0 1}] +set g2 [$w gradient create linear \ + -stops {{0.0 "#222222"} {0.1 "#4b4b4b"} {0.9 "#616161"} {1.0 "#454545"}} \ + -lineartransition {0 0 0 1}] + +drawbutton $w $g1 $g2 b1 +set l 12 +set path "M 0 0 h $l M 0 3 h $l M 0 6 h $l M 0 9 h $l" +set id [$w create path $path -stroke "#0f0f0f" -tags b1] +$w move $id 8 6 +set id [$w create path $path -stroke white -strokeopacity 0.5 -tags b1] +$w move $id 8 7 +$w move b1 20 10 + +drawbutton $w $g1 $g2 b2 left +set path "M 0 0 l 9 4 v -9 z" +set id [$w create path $path -fill white -stroke "" -tags {b2 b2-a}] +set id [$w create path $path -fill black -stroke "" -tags {b2 b2-a} -fillopacity 0.7] +$w move b2-a 8 10 +$w move b2 60 10 + +drawbutton $w $g1 $g2 b3 right +set path "M 0 0 l -9 4 v -9 z" +set id [$w create path $path -fill white -stroke "" -tags {b3 b3-a}] +set id [$w create path $path -fill black -stroke "" -tags {b3 b3-a} -fillopacity 0.78] +$w move b3-a 17 10 +$w move b3 [expr {60+26}] 10 + +proc drawletter {w c tag} { + array set font [font actual systemSystemFont] + set family $font(-family) + set fsize $font(-size) + + $w create ptext 10 17 -fontfamily $family -fontsize $fsize -tags $tag \ + -text $c -fill white + $w create ptext 10 16 -fontfamily $family -fontsize $fsize -tags $tag \ + -text $c -fillopacity 0.8 +} + +drawbutton $w $g1 $g2 b4 left +drawbutton $w $g1 $g2 b5 center +drawbutton $w $g1 $g2 b6 center +drawbutton $w $g1 $g2 b7 right +drawletter $w M b4c +drawletter $w A b5c +drawletter $w T b6c +drawletter $w S b7c +$w move b4 [expr {130+0*26}] 10 +$w move b5 [expr {130+1*26}] 10 +$w move b6 [expr {130+2*26}] 10 +$w move b7 [expr {130+3*26}] 10 +$w move b4c [expr {130+0*26}] 10 +$w move b5c [expr {130+1*26}] 10 +$w move b6c [expr {130+2*26}] 10 +$w move b7c [expr {130+3*26}] 10 + diff --git a/pd/tkpath/demos/lines.tcl b/pd/tkpath/demos/lines.tcl new file mode 100644 index 0000000000000000000000000000000000000000..b32596c7a089539f01213beab76cb0904a5ae729 --- /dev/null +++ b/pd/tkpath/demos/lines.tcl @@ -0,0 +1,38 @@ +package require tkpath 0.3.0 + +set t .c_lines +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + +$w create pline 20 20 180 20 +$w create pline 200 20 260 20 -stroke blue + +$w create pline 20 30 180 30 -stroke green +$w create pline 200 30 260 30 -stroke red + +$w create pline 20 40 260 40 -stroke "#999999" +$w create pline 40 50 120 80 -stroke "#666666" -strokewidth 3 + +$w create pline 150 60 170 60 -stroke red -strokewidth 4 +$w create pline 150 70 170 70 -stroke green -strokewidth 4 +$w create pline 150 80 170 80 -stroke blue -strokewidth 4 + +$w create polyline 20 200 30 200 30 180 50 180 50 200 \ + 70 200 70 160 90 160 90 200 110 200 110 120 130 120 \ + 130 200 + +$w create polyline 150 200 200 120 150 120 200 200 -stroke gray50 -strokewidth 4 +$w create polyline 220 200 270 120 220 120 270 200 -stroke gray50 -strokewidth 4 \ + -fill gray80 + +$w create ppolygon 75 237 89 280 134 280 98 307 111 350 75 325 38 350 \ + 51 307 15 280 60 280 -stroke "#9ac790" -strokewidth 4 -fill "#cae2c5" + +$w create ppolygon 240 250 283 275 283 325 240 350 196 325 196 275 \ + -stroke "#a19de2" -strokewidth 6 -fill "#d6d6ff" + +$w create text 300 20 -anchor w -text "pline" +$w create text 300 150 -anchor w -text "polyline" +$w create text 300 300 -anchor w -text "ppolygon" + diff --git a/pd/tkpath/demos/opacity.tcl b/pd/tkpath/demos/opacity.tcl new file mode 100644 index 0000000000000000000000000000000000000000..9a300f96c594a37ef918a8d9f8aaaa3b5ac57e05 --- /dev/null +++ b/pd/tkpath/demos/opacity.tcl @@ -0,0 +1,62 @@ +package require tkpath 0.3.0 + +set t .c_opacity +destroy $t +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + + +namespace eval ::opacity { + + variable w $::w + + set r 60 + set d [expr 2*$r] + set opacity 0.50 + variable rc 100 + + foreach col {red green blue} { + $w create circle 0 $r -r $r \ + -stroke "" -fill $col -fillopacity $opacity -tags $col + } + + $w move root 200 [expr 200-$r] + + variable time 0 + variable speed 0.06 + + proc step {} { + variable w + variable rc + variable time + variable speed + + if {![winfo exists $w]} { + return + } + set phi [expr $time*$speed] + + set tx [expr $rc*cos([expr $phi*11./17.])] + set ty [expr $rc*sin($phi)] + set m [list {1 0} {0 1} [list $tx $ty]] + $w itemconfig red -matrix $m + + set tx [expr $rc*cos($phi)] + set ty [expr $rc*sin([expr $phi*3./7.])] + set m [list {1 0} {0 1} [list $tx $ty]] + $w itemconfig green -matrix $m + + set tx [expr $rc*cos([expr $phi*23./29. + 1.0])] + set ty [expr $rc*sin([expr $phi + 1.0])] + set m [list {1 0} {0 1} [list $tx $ty]] + $w itemconfig blue -matrix $m + + incr time + after 40 opacity::step + } + + step +} + + diff --git a/pd/tkpath/demos/paths.txt b/pd/tkpath/demos/paths.txt new file mode 100755 index 0000000000000000000000000000000000000000..3034e2dd3bf6a3d0170eddcea293e622d8bcb6fe --- /dev/null +++ b/pd/tkpath/demos/paths.txt @@ -0,0 +1,171 @@ +# 21111730 +M 11.398207664489746 5.6979951858520508 A 0.15625 0.15625 0 1 1 11.398207664489746 6.0104951858520508 A 0.15625 0.15625 0 1 1 11.398207664489746 5.6979951858520508 M 4.90625 6.1293802261352539 A 0.15625 0.15625 0 1 1 4.90625 6.4418802261352539 A 0.15625 0.15625 0 1 1 4.90625 6.1293802261352539 M 4.90625 5.0668802261352539 A 0.15625 0.15625 0 1 1 4.90625 5.3793802261352539 A 0.15625 0.15625 0 1 1 4.90625 5.0668802261352539 M 1.6330419778823853 6.1293802261352539 A 0.15625 0.15625 0 1 1 1.6330419778823853 6.4418802261352539 A 0.15625 0.15625 0 1 1 1.6330419778823853 6.1293802261352539 M 1.0392919778823853 5.6979951858520508 A 0.15625 0.15625 0 1 1 1.0392919778823853 6.0104951858520508 A 0.15625 0.15625 0 1 1 1.0392919778823853 5.6979951858520508 M 1.3020050525665283 5.9607081413269043 A 0.15625 0.15625 0 1 1 1.3020050525665283 6.2732081413269043 A 0.15625 0.15625 0 1 1 1.3020050525665283 5.9607081413269043 M 2.9607079029083252 5.6979951858520508 A 0.15625 0.15625 0 1 1 2.9607079029083252 6.0104951858520508 A 0.15625 0.15625 0 1 1 2.9607079029083252 5.6979951858520508 M 2.0 5.0 A 0.15625 0.15625 0 1 1 2.0 5.3125 A 0.15625 0.15625 0 1 1 2.0 5.0 M 2.3669579029083252 6.1293802261352539 A 0.15625 0.15625 0 1 1 2.3669579029083252 6.4418802261352539 A 0.15625 0.15625 0 1 1 2.3669579029083252 6.1293802261352539 M 2.0 6.1875 A 0.15625 0.15625 0 1 1 2.0 6.5 A 0.15625 0.15625 0 1 1 2.0 6.1875 M 2.6979949474334717 5.9607081413269043 A 0.15625 0.15625 0 1 1 2.6979949474334717 6.2732081413269043 A 0.15625 0.15625 0 1 1 2.6979949474334717 5.9607081413269043 M 7.53125 5.0668802261352539 A 0.15625 0.15625 0 1 1 7.53125 5.3793802261352539 A 0.15625 0.15625 0 1 1 7.53125 5.0668802261352539 M 7.53125 6.1293802261352539 A 0.15625 0.15625 0 1 1 7.53125 6.4418802261352539 A 0.15625 0.15625 0 1 1 7.53125 6.1293802261352539 M 9.7395048141479492 5.9607081413269043 A 0.15625 0.15625 0 1 1 9.7395048141479492 6.2732081413269043 A 0.15625 0.15625 0 1 1 9.7395048141479492 5.9607081413269043 M 9.4767923355102539 5.6979951858520508 A 0.15625 0.15625 0 1 1 9.4767923355102539 6.0104951858520508 A 0.15625 0.15625 0 1 1 9.4767923355102539 5.6979951858520508 M 10.4375 5.0 A 0.15625 0.15625 0 1 1 10.4375 5.3125 A 0.15625 0.15625 0 1 1 10.4375 5.0 M 10.4375 6.1875 A 0.15625 0.15625 0 1 1 10.4375 6.5 A 0.15625 0.15625 0 1 1 10.4375 6.1875 M 10.070542335510254 6.1293802261352539 A 0.15625 0.15625 0 1 1 10.070542335510254 6.4418802261352539 A 0.15625 0.15625 0 1 1 10.070542335510254 6.1293802261352539 M 10.804457664489746 6.1293802261352539 A 0.15625 0.15625 0 1 1 10.804457664489746 6.4418802261352539 A 0.15625 0.15625 0 1 1 10.804457664489746 6.1293802261352539 M 11.135495185852051 5.9607081413269043 A 0.15625 0.15625 0 1 1 11.135495185852051 6.2732081413269043 A 0.15625 0.15625 0 1 1 11.135495185852051 5.9607081413269043 M 0.5 4.5 L 0.5 7.0 L 11.9375 7.0 L 11.9375 4.5 L 0.5 4.5 +tkpath::transform scale 50.0 -50.0 +.c move all 2 -10 + +# ------------------------------ + +# 23058030 +M 22.0 -26.0 L 22.0 -24.0 L 27.167299270629883 -24.0 A 36.249994896250975 36.249994896250975 0 0 1 32.000011444091797 -17.03118896484375 L 32.0 0.0 L 7.75 0.0 A 7.7500000000000009 7.7500000000000009 0 0 0 9.2417820951595786e-008 -7.75 L -5.8125 -7.625 L -14.8125 -26.0 L 22.0 -26.0 M 25.5 -27.125 L 25.5 -30.125 L -20.375 -30.125 L -20.375 -3.0 L -30.75 -3.0 L -30.75 0.375 L -5.75 0.375 L -5.75 0.0 A 5.75 5.75 0 0 1 5.75 0.0 L 5.75 0.375 L 8.0 4.0 L 37.5 4.0 A 3.5 3.5 0 0 0 41.0 0.5 L 41.0 -17.625 L 38.0 -27.125 L 25.5 -27.125 +tkpath::transform scale 10.38961038961039 -10.38961038961039 +.c move all 33 -7 + +# ------------------------------ + +# 3l56172 +M 2.1679000854492187 -6.630000114440918 L 1.4961999654769897 -7.7430000305175781 A 0.12500014389113079 0.12500014389113079 0 0 0 1.3246122598648071 -7.7854208946228027 L 0.052400000393390656 -7.0176000595092773 A 0.12500000932909691 0.12500000932909691 0 0 0 -0.0070782001130282879 -6.8946499824523926 L 0.85189998149871826 -0.21809999644756317 A 0.24999999999999975 0.24999999999999975 0 0 0 1.0999000072479248 -2.3883618607140056e-016 L 1.4500000476837158 0.0 A 0.25 0.25 0 0 0 1.7000000476837158 -0.25 L 1.7000000476837158 -4.5 A 0.25 0.25 0 0 1 1.9500000476837158 -4.75 L 8.5699996948242187 -4.75 A 0.25 0.25 0 0 1 8.8199996948242187 -4.5 L 8.8199996948242187 -0.25 A 0.24999999999999975 0.24999999999999975 0 0 0 9.0699996948242187 -2.3883618607140056e-016 L 9.380000114440918 0.0 A 0.25 0.25 0 0 0 9.630000114440918 -0.25 L 9.630000114440918 -4.8720998764038086 A 0.50000033409458167 0.50000033409458167 0 0 0 9.2541513442993164 -5.3564414978027344 A 2.4400000498260157 2.4400000498260157 0 0 1 7.4411635398864746 -7.3993253707885742 L 5.6999998092651367 -10.280099868774414 A 0.12499967404394985 0.12499967404394985 0 0 0 5.5284123420715332 -10.322420120239258 L 4.20989990234375 -9.5267000198364258 A 0.125000082295601 0.125000082295601 0 0 0 4.1674790382385254 -9.3551120758056641 L 4.8392000198364258 -8.2420997619628906 A 0.25000000272211764 0.25000000272211764 0 0 1 4.7542757987976074 -7.8988585472106934 L 2.511199951171875 -6.545100212097168 A 0.25000000272211764 0.25000000272211764 0 0 1 2.1679587364196777 -6.6300244331359863 +tkpath::transform scale 37.5 -37.5 +.c move all 3 -3 + +# ------------------------------ + +# 4200001p +M 0.0 -2.875 L 0.0 0.0 L 0.0 2.875 L 7.9611001014709473 2.4993999004364014 A 0.49995743833108469 0.49995743833108469 0 0 0 8.308563232421875 1.6649335622787476 L 8.0155000686645508 1.3401999473571777 A 1.9999691405765694 1.9999691405765694 0 0 1 7.5177445411682129 0.26559340953826904 L 4.625 0.26559999585151672 A 0.26560020446777444 0.26560020446777444 0 0 1 4.3593997955322266 -2.3219490330461667e-008 A 0.26559999585151672 0.26559999585151672 0 0 1 4.625 -0.26559999585151672 L 7.5177001953125 -0.26559999585151672 A 2.0000139721622912 2.0000139721622912 0 0 1 8.0154666900634766 -1.3402301073074341 L 8.3086004257202148 -1.6648999452590942 A 0.49994016366221161 0.49994016366221161 0 0 0 7.9610943794250488 -2.4992830753326416 L 0.0 -2.875 +tkpath::transform scale 57.142857142857146 -57.142857142857146 +.c move all 3 -5 + +# ------------------------------ + +# 4200002s +M 11.249899864196777 3.0936994552612305 A 4.2188005447387695 4.2188005447387695 0 1 1 11.249899864196777 11.53130054473877 A 4.2188005447387695 4.2188005447387695 0 1 1 11.249899864196777 3.0936994552612305 M 20.879400253295898 11.802800178527832 A 10.624974407951097 10.624974407951097 0 0 1 13.999879837036133 17.575428009033203 A 1.6249761009967187 1.6249761009967187 0 1 1 13.158819198608398 14.436267852783203 A 7.3750245431124659 7.3750245431124659 0 0 0 17.933942794799805 4.1956815719604492 A 1.6249741531421891 1.6249741531421891 0 0 1 18.719882965087891 2.0361611843109131 A 1.6249734187086999 1.6249734187086999 0 0 1 20.879438400268555 2.8221826553344727 A 10.624974044059929 10.624974044059929 0 0 1 20.879400253295898 11.802800178527832 M 23.8125 8.25 L 23.8125 0.0 L 7.4998998641967773 0.0 A 7.5000000000000151 7.5000000000000151 0 0 0 -0.00010013580322265625 7.4999995231628418 L -9.9999997473787516e-005 46.625 L 0.25 46.625 L 0.25 48.625 L 11.439499855041504 48.625 A 0.49999999698775355 0.49999999698775355 0 0 0 11.918793678283691 48.267398834228516 L 23.8125 8.25 +tkpath::transform scale 11.111111111111111 -11.111111111111111 +.c move all 3 -51 + +# ------------------------------ + +# 4300007p +M -10.0 -1.2812995910644531 A 1.2812995910644531 1.2812995910644531 0 1 1 -10.0 1.2812995910644531 A 1.2812995910644531 1.2812995910644531 0 1 1 -10.0 -1.2812995910644531 M -8.0 0.0 A 2.0 2.0 0 0 0 -10.0 -2.0 A 2.0000002250291069 2.0000002250291069 0 0 0 -11.826537132263184 -0.81471651792526245 L -13.718099594116211 3.4261000156402588 A 3.2499741522794272 3.2499741522794272 0 0 0 -13.468227386474609 6.5314521789550781 L -13.362199783325195 6.6932997703552246 A 11.15630897810888 11.15630897810888 0 0 0 -6.7810039520263672 11.390213966369629 L -6.105100154876709 11.562100410461426 A 22.296898345112911 22.296898345112911 0 0 0 -0.94220173358917236 12.247514724731445 L 0.17649999260902405 12.264200210571289 A 13.296881796912059 13.296881796912059 0 0 0 2.8221900463104248 12.038548469543457 L 4.4130001068115234 11.740699768066406 A 8.7812942402398004 8.7812942402398004 0 0 0 10.863511085510254 -0.36060208082199097 L 10.780699729919434 -0.55320000648498535 A 9.0313299476671993 9.0313299476671993 0 0 0 7.7040948867797852 -4.3545904159545898 A 8.7500343070636344 8.7500343070636344 0 0 1 -6.0768270492553711 1.8766350746154785 A 1.5000362396240281 1.5000362396240281 0 0 1 -8.0000362396240234 0.43749988079071045 L -8.0 0.0 +tkpath::transform scale 26.666666666666668 -26.666666666666668 +.c move all 16 -15 + +# ------------------------------ + +# 50110b +M 10.906499862670898 -16.237600326538086 L 8.8359003067016602 -19.82390022277832 L 0.0 -14.722399711608887 A 20.999999841779239 20.999999841779239 0 0 0 8.5000247955322266 4.2638948798412457e-005 L 11.03339958190918 -1.4625999927520752 L 19.436800003051758 -1.4625999927520752 L 20.880199432373047 -1.4625999927520752 L 22.32349967956543 -1.4625999927520752 L 30.726999282836914 -1.4625999927520752 L 33.260299682617187 0.0 A 21.000000847595341 21.000000847595341 0 0 0 41.760368347167969 -14.722381591796875 L 32.924400329589844 -19.82390022277832 L 30.853799819946289 -16.237600326538086 A 10.0 10.0 0 0 1 20.880199432373047 -6.9626007080078125 A 9.9999997792904178 9.9999997792904178 0 0 1 10.906521797180176 -16.237514495849609 +tkpath::transform scale 17.021276595744681 -17.021276595744681 +.c move all 3 -3 + +# ------------------------------ + +# 60701156 +M 22.5 32.5 L 27.5 32.5 A 1.0 1.0 0 1 1 27.5 34.5 L 22.5 34.5 A 1.0 1.0 0 0 1 21.5 33.5 A 1.0 1.0 0 0 1 22.5 32.5 M -27.5 32.5 L -22.5 32.5 A 1.0 1.0 0 0 1 -21.5 33.5 A 1.0 1.0 0 0 1 -22.5 34.5 L -27.5 34.5 A 1.0 1.0 0 0 1 -27.5 32.5 M 45.0 0.375 A 2.125 2.125 0 1 1 45.0 4.625 A 2.125 2.125 0 1 1 45.0 0.375 M 6.75 34.875 A 2.125 2.125 0 1 1 6.75 39.125 A 2.125 2.125 0 1 1 6.75 34.875 M -6.75 34.875 A 2.125 2.125 0 1 1 -6.75 39.125 A 2.125 2.125 0 1 1 -6.75 34.875 M -45.0 0.375 A 2.125 2.125 0 1 1 -45.0 4.625 A 2.125 2.125 0 1 1 -45.0 0.375 M 16.25 20.5 L 0.0 20.5 L -16.25 20.5 A 4.7499995203968046 4.7499995203968046 0 0 1 -19.456502914428711 19.254402160644531 L -40.5 0.0 L -45.0 0.0 A 2.5000000000000115 2.5000000000000115 0 0 0 -47.5 2.4999997615814209 L -47.5 7.1511001586914062 A 3.9999984827847435 3.9999984827847435 0 0 0 -47.155220031738281 8.7757091522216797 L -37.841800689697266 29.730899810791016 A 3.999978085321795 3.999978085321795 0 0 0 -36.877262115478516 31.066057205200195 L -27.64430046081543 39.459800720214844 A 4.0000343322753906 4.0000343322753906 0 0 0 -24.95359992980957 40.500034332275391 L 0.0 40.5 L 24.95359992980957 40.5 A 3.9999997683939843 3.9999997683939843 0 0 0 27.644275665283203 39.459774017333984 L 36.877201080322266 31.066200256347656 A 4.0000345034849305 4.0000345034849305 0 0 0 37.841770172119141 29.730985641479492 L 47.155200958251953 8.7756996154785156 A 3.9999771118164063 3.9999771118164063 0 0 0 47.499977111816406 7.1511001586914062 L 47.5 2.5 A 2.5 2.5 0 0 0 45.0 1.7780915628762273e-016 L 40.5 0.0 L 19.456499099731445 19.254400253295898 A 4.7499275218276624 4.7499275218276624 0 0 1 16.249998092651367 20.499927520751953 +tkpath::transform scale 8.0 -8.0 +.c move all 50 -43 + +# ------------------------------ + +# 61700538 +M -5.2453668786256458e-007 12.0 A 12.000000022207344 12.000000022207344 0 0 1 -2.0672976970672607 11.820587158203125 L -2.3868999481201172 13.013099670410156 A 1.0625047814906097 1.0625047814906097 0 0 1 -4.4395246505737305 12.463192939758301 L -4.1199002265930176 11.270600318908691 A 11.99999984645736 11.99999984645736 0 0 1 -10.23020076751709 6.2723989486694336 A 0.50006191017629587 0.50006191017629587 0 0 1 -10.157546997070312 5.6574530601501465 L -5.7929000854492187 1.2928999662399292 A 0.99999046325683594 0.99999046325683594 0 0 0 -5.5000095367431641 0.58579999208450317 L -5.5 0.3125 L -7.6875 0.3125 A 0.31250000000000122 0.31250000000000122 0 0 1 -8.0 -2.7319618567389625e-008 A 0.3125 0.3125 0 0 1 -7.6875 -0.3125 L -5.5 -0.3125 L -5.5 -0.58579999208450317 A 1.0000000250326495 1.0000000250326495 0 0 0 -5.7928929328918457 -1.2929065227508545 L -10.157500267028809 -5.6574997901916504 A 0.49992491264386568 0.49992491264386568 0 0 1 -10.230038642883301 -6.272301197052002 A 12.000000219629753 12.000000219629753 0 0 1 -4.1198945045471191 -11.270602226257324 L -4.4394998550415039 -12.463199615478516 A 1.0624790907949369 1.0624790907949369 0 0 1 -2.3869247436523437 -13.013092994689941 L -2.0673000812530518 -11.820599555969238 A 12.000013351440431 12.000013351440431 0 0 1 1.4309873108686588e-007 -12.00001335144043 A 12.00000018650144 12.00000018650144 0 0 1 2.0672986507415771 -11.820587158203125 L 2.3868999481201172 -13.013099670410156 A 1.0624790907949369 1.0624790907949369 0 1 1 4.4394750595092773 -12.463207244873047 L 4.1199002265930176 -11.270600318908691 A 12.000000160995265 12.000000160995265 0 0 1 10.230201721191406 -6.2723979949951172 A 0.50002852982497781 0.50002852982497781 0 0 1 10.157623291015625 -5.6573762893676758 L 5.7929000854492187 -1.2928999662399292 A 0.99991989135742365 0.99991989135742365 0 0 0 5.4999799728393555 -0.58580005168914795 L 5.5 -0.3125 L 7.6875 -0.3125 A 0.3125 0.3125 0 0 1 8.0 0.0 A 0.3125 0.3125 0 0 1 7.6875 0.3125 L 5.5 0.3125 L 5.5 0.58579999208450317 A 0.9999998564451914 0.9999998564451914 0 0 0 5.7928934097290039 1.2929067611694336 L 10.157500267028809 5.6574997901916504 A 0.49992491264386568 0.49992491264386568 0 0 1 10.230038642883301 6.272301197052002 A 12.000000229025959 12.000000229025959 0 0 1 4.1198997497558594 11.270600318908691 L 4.4394998550415039 12.463199615478516 A 1.0624790907949369 1.0624790907949369 0 0 1 2.3869247436523437 13.013092994689941 L 2.0673000812530518 11.820599555969238 A 12.000013351440442 12.000013351440442 0 0 1 -5.2453725629675318e-007 12.00001335144043 M 0.35640421509742737 -20.49690055847168 A 20.499998092651367 20.499998092651367 0 1 0 20.499998092651367 0.0 A 20.49999999034064 20.49999999034064 0 0 0 3.9129061698913574 -20.123100280761719 A 3.9999755772748098 3.9999755772748098 0 0 1 0.35641822218894958 -20.496929168701172 +tkpath::transform scale 13.043478260869565 -13.043478260869565 +.c move all 23 -23 + +# ------------------------------ + +# 71442 +M 4.7767237214280112e-016 -10.0625 A 0.12500000000000022 0.12500000000000022 0 0 0 0.1249999925494194 -9.9375 L 0.65729302167892456 -9.9375 A 0.12499996342062933 0.12499996342062933 0 0 0 0.78201490640640259 -10.054166793823242 A 0.34375 0.34375 0 0 1 1.46875 -10.03125 L 1.46875 -9.71875 A 0.34375002040378955 0.34375002040378955 0 0 1 0.78201472759246826 -9.6958332061767578 A 0.125 0.125 0 0 0 0.65729302167892456 -9.8125 L 0.125 -9.8125 A 0.12499999999999953 0.12499999999999953 0 0 0 4.7767237214280112e-016 -9.6875 L 0.0 -6.5625 A 0.12500000000000022 0.12500000000000022 0 0 0 0.1249999925494194 -6.4375 L 0.65729302167892456 -6.4375 A 0.12499996342062933 0.12499996342062933 0 0 0 0.78201490640640259 -6.5541667938232422 A 0.34375 0.34375 0 0 1 1.46875 -6.53125 L 1.46875 -6.21875 A 0.34375002040378955 0.34375002040378955 0 0 1 0.78201472759246826 -6.1958332061767578 A 0.125 0.125 0 0 0 0.65729302167892456 -6.3125 L 0.0 -6.3125 L 0.0 -1.3125 A 0.12500000000000022 0.12500000000000022 0 0 0 0.1249999925494194 -1.1875 L 0.69538402557373047 -1.1875 A 0.12500000513978182 0.12500000513978182 0 0 0 0.80994844436645508 -1.2625000476837158 A 0.34374998334767354 0.34374998334767354 0 1 1 0.8099479079246521 -0.98750007152557373 A 0.125 0.125 0 0 0 0.69538402557373047 -1.0625 L 0.125 -1.0625 A 0.12499999999999953 0.12499999999999953 0 0 0 4.7767237214280112e-016 -0.9375 L 0.0 -0.125 A 0.12500000000000008 0.12500000000000008 0 0 0 0.1249999925494194 -1.1941809303570028e-016 L 16.875 0.0 A 2.0 2.0 0 0 0 18.875 -2.0 L 18.875 -4.65625 A 0.125 0.125 0 0 0 18.75 -4.78125 L 17.3125 -4.78125 A 0.125 0.125 0 0 0 17.1875 -4.65625 L 17.1875 -4.651249885559082 A 0.11999988555908203 0.11999988555908203 0 0 1 17.067499160766602 -4.53125 L 16.807500839233398 -4.53125 A 0.12000083923339844 0.12000083923339844 0 0 1 16.6875 -4.651249885559082 L 16.6875 -4.65625 A 0.125 0.125 0 0 0 16.5625 -4.78125 L 14.990566253662109 -4.78125 A 0.12499980510968539 0.12499980510968539 0 0 0 14.900641441345215 -4.7430744171142578 L 14.099358558654785 -3.9131760597229004 A 0.125 0.125 0 0 1 14.009433746337891 -3.875 L 11.871734619140625 -3.875 A 0.12499990705711025 0.12499990705711025 0 0 1 11.774990081787109 -3.9208452701568604 L 10.725009918212891 -5.2041549682617187 A 0.125 0.125 0 0 0 10.628265380859375 -5.25 L 4.4952621459960938 -5.25 A 0.37500022991594584 0.37500022991594584 0 0 1 4.1254048347473145 -5.5631070137023926 L 4.0 -6.3125 L 4.0 -12.375 A 0.125 0.125 0 0 0 3.875 -12.5 L 0.125 -12.5 A 0.12499999999999953 0.12499999999999953 0 0 0 4.7767237214280112e-016 -12.375 L 0.0 -10.0625 +tkpath::transform scale 33.333333333333336 -33.333333333333336 +.c move all 3 -3 + +# ------------------------------ + +# acad1 +M 22.196474075317383 12.625 A 0.375 0.375 0 0 1 22.196474075317383 11.875 L 23.446474075317383 11.875 A 0.375 0.375 0 1 1 23.446474075317383 12.625 L 22.196474075317383 12.625 M 24.527111053466797 8.2343997955322266 A 0.26560020446777344 0.26560020446777344 0 1 1 24.527111053466797 8.7656002044677734 A 0.26560020446777344 0.26560020446777344 0 1 1 24.527111053466797 8.2343997955322266 M 21.633974075317383 9.5 L 20.383974075317383 9.5 A 0.375 0.375 0 0 1 20.383974075317383 8.75 L 21.633974075317383 8.75 A 0.375 0.375 0 1 1 21.633974075317383 9.5 M 26.027111053466797 10.984399795532227 A 0.26560020446777344 0.26560020446777344 0 1 1 26.027111053466797 11.515600204467773 A 0.26560020446777344 0.26560020446777344 0 1 1 26.027111053466797 10.984399795532227 M 14.508975028991699 12.625 A 0.375 0.375 0 0 1 14.508975028991699 11.875 L 15.758975028991699 11.875 A 0.375 0.375 0 1 1 15.758975028991699 12.625 L 14.508975028991699 12.625 M 15.508975028991699 6.6875 L 14.258975028991699 6.6875 A 0.375 0.375 0 0 1 14.258975028991699 5.9375 L 15.508975028991699 5.9375 A 0.375 0.375 0 1 1 15.508975028991699 6.6875 M 12.696475028991699 9.5 A 0.375 0.375 0 0 1 12.696475028991699 8.75 L 13.946475028991699 8.75 A 0.375 0.375 0 1 1 13.946475028991699 9.5 L 12.696475028991699 9.5 M 11.758975028991699 6.6875 L 10.508975028991699 6.6875 A 0.375 0.375 0 0 1 10.508975028991699 5.9375 L 11.758975028991699 5.9375 A 0.375 0.375 0 1 1 11.758975028991699 6.6875 M 11.116024971008301 3.875 A 0.375 0.375 0 0 1 11.116024971008301 3.125 L 12.366024971008301 3.125 A 0.375 0.375 0 1 1 12.366024971008301 3.875 L 11.116024971008301 3.875 M 10.633975028991699 0.875 L 9.3839750289916992 0.875 A 0.375 0.375 0 0 1 9.3839750289916992 0.125 L 10.633975028991699 0.125 A 0.375 0.375 0 1 1 10.633975028991699 0.875 M 4.1160249710083008 3.875 A 0.375 0.375 0 0 1 4.1160249710083008 3.125 L 5.3660249710083008 3.125 A 0.375 0.375 0 1 1 5.3660249710083008 3.875 L 4.1160249710083008 3.875 M 2.3839750289916992 0.875 A 0.375 0.375 0 0 1 2.3839750289916992 0.125 L 3.6339750289916992 0.125 A 0.375 0.375 0 1 1 3.6339750289916992 0.875 L 2.3839750289916992 0.875 M 27.15516471862793 13.25 A 0.49999939964946288 0.49999939964946288 0 0 0 27.588176727294922 12.5 L 25.206607818603516 8.375 A 0.5 0.5 0 0 0 24.773595809936523 8.125 L 18.02729606628418 8.125 A 0.49999939964946288 0.49999939964946288 0 0 1 17.594284057617188 7.875 L 12.903311729431152 -0.25 A 0.5 0.5 0 0 0 12.470298767089844 -0.5 L 0.0 -0.5 A 0.50000000018507684 0.50000000018507684 0 0 0 -0.43301275372505188 0.24999991059303284 L 1.8763879537582397 4.25 A 0.5 0.5 0 0 0 2.3094010353088379 4.5 L 7.9752960205078125 4.5 A 0.50000022555554469 0.50000022555554469 0 0 1 8.4083089828491211 4.75 L 13.17144775390625 13.0 A 0.5 0.5 0 0 0 13.604460716247559 13.25 L 27.15516471862793 13.25 +tkpath::transform scale 24.242424242424242 -24.242424242424242 +.c move all 3 -16 + +# ------------------------------ + +# inn-002 +M 0.88012826442718506 2.029172420501709 L 1.6674723625183105 2.187000036239624 L 1.7890000343322754 2.187000036239624 L 3.0250000953674316 2.187000036239624 L 3.1465277671813965 2.187000036239624 L 3.1465277671813965 2.2569999694824219 A 0.15000009536743164 0.15000009536743164 0 0 0 3.2965278625488281 2.4070000648498535 A 0.14999990212045899 0.14999990212045899 0 0 0 3.3713626861572266 2.3869988918304443 L 3.4967317581176758 2.3148293495178223 L 3.4667978286743164 2.2628297805786133 L 3.4932522773742676 2.3087852001190186 L 3.5274279117584229 2.3681530952453613 L 3.5559494495391846 2.3517343997955322 L 3.5313193798065186 2.365912914276123 L 3.4877960681915283 2.3909673690795898 L 3.3809020519256592 2.4525017738342285 L 3.3841443061828613 2.4581341743469238 L 3.3482699394226074 2.5200886726379395 L 3.4198613166809082 2.5201795101165771 L 3.3839867115020752 2.5821340084075928 L 3.4555783271789551 2.5822250843048096 L 3.4197037220001221 2.6441795825958252 L 3.4912950992584229 2.6442704200744629 L 3.4554204940795898 2.7062249183654785 L 3.5270118713378906 2.7063159942626953 L 3.4911375045776367 2.7682704925537109 L 3.5627288818359375 2.7683613300323486 L 3.5268542766571045 2.8303158283233643 L 3.5984458923339844 2.8304069042205811 L 3.5625710487365723 2.8923614025115967 L 3.6341626644134521 2.8924522399902344 L 3.5982880592346191 2.95440673828125 L 3.6698794364929199 2.9544978141784668 L 3.634005069732666 3.0164520740509033 L 3.7055964469909668 3.0165431499481201 L 3.6697218418121338 3.0784976482391357 L 3.7413132190704346 3.0785887241363525 L 3.7054386138916016 3.1405429840087891 L 3.7770299911499023 3.1406340599060059 L 3.7411556243896484 3.2025885581970215 L 3.8127470016479492 3.2026796340942383 L 3.7768726348876953 3.2646338939666748 L 3.8484640121459961 3.2647249698638916 L 3.8125894069671631 3.3266794681549072 L 3.8841807842254639 3.3267703056335449 L 3.8483061790466309 3.3887248039245605 L 3.9198975563049316 3.3888158798217773 L 3.8840231895446777 3.450770378112793 L 3.9556145668029785 3.4508612155914307 L 3.9197402000427246 3.5128157138824463 L 3.9913315773010254 3.5129067897796631 L 3.9554569721221924 3.5748612880706787 L 4.0270481109619141 3.5749521255493164 L 4.1339426040649414 3.5134179592132568 L 4.2020959854125977 3.4741849899291992 L 4.4053158760070801 3.0212526321411133 L 3.9044251441955566 2.1511321067810059 L 3.8702495098114014 2.0917642116546631 L 3.8636407852172852 2.0802836418151855 L 3.8437950611114502 2.0458087921142578 L 3.8853945732116699 2.0218615531921387 L 3.905240535736084 2.0563364028930664 L 3.9118492603302002 2.0678169727325439 L 3.9460248947143555 2.1271848678588867 L 4.4295759201049805 2.9671833515167236 L 4.4932575225830078 2.8252513408660889 L 4.0552239418029785 2.0643236637115479 L 4.0210485458374023 2.0049557685852051 L 4.014439582824707 1.9934751987457275 L 3.9945938587188721 1.9590003490447998 L 4.0471282005310059 1.9287586212158203 L 4.5033836364746094 0.26847946643829346 A 0.032000064849853516 0.032000064849853516 0 0 0 4.5045280456542969 0.25999999046325684 A 0.03200000524520874 0.03200000524520874 0 0 0 4.4725279808044434 0.2279999852180481 L 4.1255278587341309 0.22800000011920929 A 0.22800000011920929 0.22800000011920929 0 0 1 4.1255278587341309 -0.22800000011920929 L 4.4725275039672852 -0.22800000011920929 A 0.032000064849853516 0.032000064849853516 0 0 0 4.5045280456542969 -0.25999999046325684 A 0.032000030011009498 0.032000030011009498 0 0 0 4.5033841133117676 -0.26847943663597107 L 4.0517692565917969 -1.911870002746582 A 0.24999993497043824 0.24999993497043824 0 0 0 3.9354307651519775 -2.0622892379760742 L 3.3713626861572266 -2.3869991302490234 A 0.15000009536743164 0.15000009536743164 0 0 0 3.2965278625488281 -2.4070000648498535 A 0.1500000961194696 0.1500000961194696 0 0 0 3.1465277671813965 -2.2569849491119385 L 3.1465277671813965 -2.187000036239624 L 3.0250000953674316 -2.187000036239624 L 1.7890000343322754 -2.187000036239624 L 1.6674723625183105 -2.187000036239624 L 1.6674723625183105 -2.2569849491119385 A 0.15000009536743164 0.15000009536743164 0 0 0 1.5174722671508789 -2.4070000648498535 A 0.14999990212045899 0.14999990212045899 0 0 0 1.4426374435424805 -2.3869988918304443 L 0.87856924533843994 -2.0622892379760742 A 0.24999997917316732 0.24999997917316732 0 0 0 0.76223063468933105 -1.911870002746582 L 0.31061625480651855 -0.26847946643829346 A 0.03200000524520874 0.03200000524520874 0 0 0 0.30947220325469971 -0.25999999046325684 A 0.03200000524520874 0.03200000524520874 0 0 0 0.34147220849990845 -0.2279999852180481 L 0.68847227096557617 -0.22800000011920929 A 0.22800000011920929 0.22800000011920929 0 1 1 0.6884722113609314 0.22800000011920929 L 0.34147238731384277 0.22800000011920929 A 0.03200000524520874 0.03200000524520874 0 0 0 0.30947220325469971 0.25999999046325684 A 0.03200000127402465 0.03200000127402465 0 0 0 0.31061610579490662 0.26847943663597107 L 0.76497209072113037 1.9218457937240601 A 0.14999990024184198 0.14999990024184198 0 0 0 0.88012820482254028 2.029172420501709 +tkpath::transform scale 54.545454545454547 -54.545454545454547 +.c move all 2 -6 + +# ------------------------------ + +# swent25 +M 5.5 -14.031300067901611 A 1.5313000679016113 1.5313000679016113 0 1 1 5.5 -10.968699932098389 A 1.5313000679016113 1.5313000679016113 0 1 1 5.5 -14.031300067901611 M 15.625 -17.9375 A 5.4375 5.4375 0 1 1 15.625 -7.0625 A 5.4375 5.4375 0 1 1 15.625 -17.9375 M 20.675899505615234 -5.1195998191833496 L 21.72760009765625 -4.0679001808166504 A 12.499999751603607 12.499999751603607 0 0 0 24.707427978515625 -15.188623428344727 L 23.27079963684082 -14.80370044708252 A 0.56249986180852851 0.56249986180852851 0 0 1 22.9796142578125 -15.89033317565918 L 24.416299819946289 -16.275299072265625 A 12.500000316711663 12.500000316711663 0 0 0 16.275300979614258 -24.416254043579102 L 15.890299797058105 -22.97960090637207 A 0.56249986180852851 0.56249986180852851 0 0 1 14.803667068481445 -23.270786285400391 L 15.188599586486816 -24.707399368286133 A 12.499999551493749 12.499999551493749 0 0 0 4.0678696632385254 -21.727630615234375 L 5.1195998191833496 -20.675899505615234 A 0.56249959524661886 0.56249959524661886 0 1 1 4.3240523338317871 -19.880453109741211 L 3.27239990234375 -20.932100296020508 A 12.500000044043663 12.500000044043663 0 0 0 0.29257193207740784 -9.811375617980957 L 1.729200005531311 -10.19629955291748 A 0.56249980010116396 0.56249980010116396 0 0 1 2.0203857421875 -9.1096668243408203 L 0.58370000123977661 -8.7246999740600586 A 12.500000085500224 12.500000085500224 0 0 0 8.7246999740600586 -0.58374589681625366 L 9.1097002029418945 -2.0204000473022461 A 0.56249980010116396 0.56249980010116396 0 1 1 10.196332931518555 -1.7292141914367676 L 9.8114004135131836 -0.29260000586509705 A 12.49999946652858 12.49999946652858 0 0 0 20.93212890625 -3.2723681926727295 L 19.880399703979492 -4.3241000175476074 A 0.56249959524661886 0.56249959524661886 0 0 1 20.675947189331055 -5.1195473670959473 +tkpath::transform scale 20.689655172413794 -20.689655172413794 +.c move all 2 -2 + +# ------------------------------ + +# 3812-001a +M 6.9576940536499023 14.852907180786133 A 2.032688990880771 2.032688990880771 0 0 1 6.8966689109802246 14.992527961730957 A 36.788067211411565 36.788067211411565 0 0 1 6.8816580772399902 14.777599334716797 A 0.26831729315193981 0.26831729315193981 0 0 0 6.8182668685913086 14.599067687988281 A 0.27536862701577847 0.27536862701577847 0 0 0 6.6497197151184082 14.502318382263184 A 0.51140992824604325 0.51140992824604325 0 0 0 6.4829564094543457 14.496724128723145 A 2.787801220116072 2.787801220116072 0 0 0 6.6352558135986328 14.367502212524414 A 0.38170282775879122 0.38170282775879122 0 0 1 6.8106346130371094 14.276609420776367 A 0.32613939449961249 0.32613939449961249 0 0 1 6.6923904418945313 14.237912178039551 A 0.70656303794125619 0.70656303794125619 0 0 1 6.5804076194763184 14.158535003662109 A 0.72776927356579091 0.72776927356579091 0 0 0 6.4552278518676758 14.068667411804199 A 0.31379718309275972 0.31379718309275972 0 0 0 6.3516011238098145 14.039505004882813 A 1.3692358710666535 1.3692358710666535 0 0 1 6.7463517189025879 13.959247589111328 A 1.5313966855373489 1.5313966855373489 0 0 0 6.9303956031799316 13.929219245910645 A 0.45359223633226542 0.45359223633226542 0 0 0 7.1614670753479004 13.802163124084473 A 0.4420517000149411 0.4420517000149411 0 0 0 7.2736830711364746 13.54228687286377 A 0.9093708102732051 0.9093708102732051 0 0 0 7.2587127685546875 13.262838363647461 A 1.1683846281976593 1.1683846281976593 0 0 0 7.2328343391418457 13.159546852111816 A 0.7053763768500958 0.7053763768500958 0 0 1 7.5241179466247559 12.897701263427734 A 5.6923784908839457 5.6923784908839457 0 0 0 7.7016921043395996 13.152002334594727 A 4.0573299858235234 4.0573299858235234 0 0 0 6.9576945304870605 14.8529052734375 M 5.8506488800048828 13.532208442687988 A 0.74981455494037186 0.74981455494037186 0 0 0 5.8821687698364258 13.187268257141113 A 0.61903004352400903 0.61903004352400903 0 0 0 5.6214756965637207 12.785055160522461 A 1.4384657987108482 1.4384657987108482 0 0 0 5.0089058876037598 12.564282417297363 A 1.377220885070864 1.377220885070864 0 0 1 4.8532271385192871 11.947909355163574 A 3.9604951009308329 3.9604951009308329 0 0 0 4.9917254447937012 11.349333763122559 A 0.55379201856563964 0.55379201856563964 0 0 1 5.1944174766540527 11.628030776977539 A 0.76941155916083992 0.76941155916083992 0 0 0 5.0906448364257812 11.886250495910645 A 0.41648466811071472 0.41648466811071472 0 0 0 5.2717723846435547 12.323159217834473 A 2.6635672358745444 2.6635672358745444 0 0 0 5.519075870513916 12.471870422363281 A 3.9054258651015741 3.9054258651015741 0 0 1 5.5250716209411621 12.475295066833496 A 1.4576598574137647 1.4576598574137647 0 0 1 5.6528472900390625 12.55561637878418 A 0.65686074739109024 0.65686074739109024 0 0 1 5.6225476264953613 12.698685646057129 A 0.65237323569943029 0.65237323569943029 0 0 1 5.7085189819335938 12.596511840820313 A 0.55888119642814738 0.55888119642814738 0 0 1 5.8428888320922852 12.754881858825684 A 0.59573022302013079 0.59573022302013079 0 0 1 5.8492217063903809 12.48737907409668 A 5.1990783151426454 5.1990783151426454 0 0 1 6.3339447975158691 12.251306533813477 A 1.0050689568499784 1.0050689568499784 0 0 0 6.5279903411865234 12.131686210632324 A 0.54856273629778607 0.54856273629778607 0 0 0 6.7049107551574707 11.879550933837891 A 0.59743451756335431 0.59743451756335431 0 0 0 6.7180881500244141 11.560447692871094 A 1.2357220463010088 1.2357220463010088 0 0 0 6.5310831069946289 11.119160652160645 A 0.96926050479451897 0.96926050479451897 0 0 1 6.9019994735717773 10.575871467590332 A 3.8798882566553066 3.8798882566553066 0 0 0 7.2042403221130371 12.282570838928223 A 0.056723197749454599 0.056723197749454599 0 0 1 7.1285696029663086 12.355759620666504 A 1.1669449271272578 1.1669449271272578 0 0 0 6.9996514320373535 12.273387908935547 A 0.70450044479008878 0.70450044479008878 0 0 0 6.6879663467407227 12.182380676269531 A 0.41693726339910814 0.41693726339910814 0 0 0 6.51934814453125 12.218269348144531 A 0.43483995194132091 0.43483995194132091 0 0 0 6.422177791595459 12.281587600708008 A 0.76304933710393852 0.76304933710393852 0 0 0 6.2683701515197754 12.486014366149902 L 6.1702346801757813 12.663297653198242 A 1.2350744005282095 1.2350744005282095 0 0 1 6.0594987869262695 12.827616691589355 A 0.56964713091349406 0.56964713091349406 0 0 1 5.9121427536010742 12.953261375427246 A 0.5259782501029836 0.5259782501029836 0 0 1 6.0330491065979004 12.939273834228516 A 0.66576599133068359 0.66576599133068359 0 0 1 6.1055660247802734 12.943890571594238 A 1.2350743408103149 1.2350743408103149 0 0 1 6.2987937927246094 12.98778247833252 A 3.4948657566865382 3.4948657566865382 0 0 0 6.617487907409668 13.082778930664063 A 0.39899034593850163 0.39899034593850163 0 0 0 6.5314235687255859 13.134840965270996 A 0.39678760410428265 0.39678760410428265 0 0 0 6.4170475006103516 13.284322738647461 A 0.76256467094122993 0.76256467094122993 0 0 0 6.3633155822753906 13.534442901611328 A 34.655360310805804 34.655360310805804 0 0 0 6.3510723114013672 13.707261085510254 A 0.93035717052043065 0.93035717052043065 0 0 1 6.3320140838623047 13.865982055664063 A 0.70773230333812021 0.70773230333812021 0 0 1 6.2796950340270996 14.034726142883301 A 0.40871473582910961 0.40871473582910961 0 0 0 6.0551466941833496 14.225984573364258 A 0.41379239189346567 0.41379239189346567 0 0 1 5.8624067306518555 14.18466854095459 A 1.6544109580048154 1.6544109580048154 0 0 0 5.6730446815490723 14.124160766601562 A 2.8044274038358621 2.8044274038358621 0 0 1 5.7758417129516602 13.775436401367188 A 2.3873453417241204 2.3873453417241204 0 0 0 5.8506488800048828 13.532208442687988 M 7.7964987754821777 13.752200126647949 A 0.10704963063829841 0.10704963063829841 0 0 1 7.7068452835083008 13.659345626831055 A 3.2962219714050165 3.2962219714050165 0 0 1 7.9098916053771973 13.397394180297852 A 3.2510256645676554 3.2510256645676554 0 0 1 8.1500892639160156 13.713069915771484 A 1.9608529662023104 1.9608529662023104 0 0 1 8.1208724975585937 13.826691627502441 A 0.25627510277893928 0.25627510277893928 0 0 0 7.9690036773681641 13.749981880187988 A 0.52498956285921716 0.52498956285921716 0 0 0 7.7964992523193359 13.752200126647949 M 8.1447515487670898 13.151946067810059 A 4.0510187118284353 4.0510187118284353 0 0 0 8.6119747161865234 12.359066963195801 A 1.2406463776561438 1.2406463776561438 0 0 1 8.8149900436401367 12.794990539550781 A 1.2823663144354225 1.2823663144354225 0 0 0 8.5988225936889648 13.203782081604004 A 0.57503107920037499 0.57503107920037499 0 0 0 8.5873594284057617 13.538050651550293 A 0.54696797163103039 0.54696797163103039 0 0 0 8.7437553405761719 13.794264793395996 A 1.1465230826390092 1.1465230826390092 0 0 0 8.9404020309448242 13.937527656555176 A 14.654286979263809 14.654286979263809 0 0 0 9.1468029022216797 14.055200576782227 A 1.2051432432882441 1.2051432432882441 0 0 1 9.5026140213012695 14.321812629699707 A 0.63787827202546876 0.63787827202546876 0 0 1 9.0638933181762695 14.347716331481934 A 1.0640007001424256 1.0640007001424256 0 0 1 8.6871976852416992 14.127266883850098 A 3.9931946967182954 3.9931946967182954 0 0 0 8.1447525024414062 13.151947021484375 M 9.727630615234375 13.647651672363281 A 0.87693224275068682 0.87693224275068682 0 0 0 9.7807140350341797 13.282944679260254 A 0.54100401568822643 0.54100401568822643 0 0 0 9.5699195861816406 12.91209602355957 A 1.2167097499416399 1.2167097499416399 0 0 0 8.9962053298950195 12.689079284667969 A 1.3851541253584845 1.3851541253584845 0 0 1 8.7671699523925781 11.947909355163574 A 3.976923639487095 3.976923639487095 0 0 0 8.9056692123413086 11.349333763122559 A 0.52740867100556665 0.52740867100556665 0 0 1 9.0748424530029297 11.546893119812012 A 0.81710747860420652 0.81710747860420652 0 0 0 8.9263105392456055 11.888853073120117 A 0.39838168446350075 0.39838168446350075 0 0 0 9.0199308395385742 12.222663879394531 A 0.72814012283569074 0.72814012283569074 0 0 0 9.2409934997558594 12.387665748596191 A 2.0237606332912805 2.0237606332912805 0 0 1 9.5609474182128906 12.590375900268555 A 0.57493436244953144 0.57493436244953144 0 0 1 9.6820468902587891 12.736868858337402 A 0.70664756151211783 0.70664756151211783 0 0 1 9.7212553024291992 12.350665092468262 A 4.6192385305378707 4.6192385305378707 0 0 0 9.8149528503417969 12.055394172668457 A 0.43882611094634161 0.43882611094634161 0 0 0 9.7697610855102539 11.701882362365723 A 0.54007993271830668 0.54007993271830668 0 0 0 9.495631217956543 11.494656562805176 A 1.1683107738983289 1.1683107738983289 0 0 0 9.2433395385742187 11.427013397216797 A 0.45779047370372117 0.45779047370372117 0 0 1 8.9445524215698242 10.965888023376465 A 0.51127789496974096 0.51127789496974096 0 0 1 9.0971145629882812 11.062028884887695 A 0.49394886472272942 0.49394886472272942 0 0 0 9.1645908355712891 11.23062801361084 A 0.23369495240943691 0.23369495240943691 0 0 0 9.3499088287353516 11.347012519836426 A 0.35410062429816236 0.35410062429816236 0 0 0 9.486933708190918 11.325981140136719 A 9.5192548964767489 9.5192548964767489 0 0 0 9.6111288070678711 11.284396171569824 A 0.57248949004229288 0.57248949004229288 0 0 1 9.7224521636962891 11.257674217224121 A 0.29559291348889982 0.29559291348889982 0 0 1 9.8292570114135742 11.261699676513672 A 0.41066065538960334 0.41066065538960334 0 0 1 9.6810684204101562 11.100037574768066 A 2.4153521880800257 2.4153521880800257 0 0 0 9.5894203186035156 10.946331024169922 A 0.25508654201970854 0.25508654201970854 0 0 0 9.4516992568969727 10.841532707214355 A 0.23727590776463292 0.23727590776463292 0 0 0 9.3258934020996094 10.840473175048828 A 0.5309745488445089 0.5309745488445089 0 0 0 9.1161861419677734 10.950915336608887 A 0.38210737428366137 0.38210737428366137 0 0 1 8.9499597549438477 10.772501945495605 A 3.9564227771806846 3.9564227771806846 0 0 0 8.7935581207275391 9.6569681167602539 A 0.94172741753853395 0.94172741753853395 0 0 1 9.0905961990356445 9.9533195495605469 A 0.74392480577472719 0.74392480577472719 0 0 1 9.1833105087280273 10.35277271270752 A 1.1060704661443028 1.1060704661443028 0 0 1 9.0914735794067383 10.748799324035645 A 0.61357519978731023 0.61357519978731023 0 0 0 9.285243034362793 10.715694427490234 A 0.42228935577233218 0.42228935577233218 0 0 0 9.4885053634643555 10.556425094604492 A 0.45307900945209351 0.45307900945209351 0 0 0 9.5578861236572266 10.185111045837402 A 0.48471969550323107 0.48471969550323107 0 0 0 9.3884382247924805 9.9183187484741211 A 0.92274667767574448 0.92274667767574448 0 0 0 9.0779314041137695 9.7420787811279297 A 0.82113364184761406 0.82113364184761406 0 0 1 9.3274755477905273 9.7984628677368164 A 0.78889783886112697 0.78889783886112697 0 0 0 9.4981508255004883 9.8553228378295898 A 0.32122053425289276 0.32122053425289276 0 0 0 9.6605319976806641 9.8524456024169922 A 0.224335418952438 0.224335418952438 0 0 0 9.7870903015136719 9.7497100830078125 A 0.4478710694703309 0.4478710694703309 0 0 0 9.8462228775024414 9.5814657211303711 A 1.2571250421665725 1.2571250421665725 0 0 0 9.8435821533203125 9.1871509552001953 A 0.53287771944859186 0.53287771944859186 0 0 1 9.5682392120361328 9.5036087036132812 A 1.3070264486466605 1.3070264486466605 0 0 1 9.6538639068603516 9.0802011489868164 A 20.877143590248064 20.877143590248064 0 0 0 9.727452278137207 8.860748291015625 A 0.87693224275068682 0.87693224275068682 0 0 0 9.7805356979370117 8.4960422515869141 A 0.54100401568822643 0.54100401568822643 0 0 0 9.5697412490844727 8.1251926422119141 A 1.2167097499416399 1.2167097499416399 0 0 0 8.9960269927978516 7.9021768569946289 A 1.3851541177817099 1.3851541177817099 0 0 1 8.7669925689697266 7.1610064506530762 A 3.9769238095704398 3.9769238095704398 0 0 0 8.905491828918457 6.5624303817749023 A 0.52740781603958919 0.52740781603958919 0 0 1 9.0746650695800781 6.7599906921386719 A 0.81710730823883537 0.81710730823883537 0 0 0 8.9261322021484375 7.1019496917724609 A 0.3983820001748809 0.3983820001748809 0 0 0 9.0197525024414062 7.4357614517211914 A 0.72814013672483047 0.72814013672483047 0 0 0 9.2408151626586914 7.6007628440856934 A 2.0237606332912805 2.0237606332912805 0 0 1 9.5607700347900391 7.8034734725952148 A 0.57493436244953144 0.57493436244953144 0 0 1 9.6818695068359375 7.9499654769897461 A 0.70664773812460024 0.70664773812460024 0 0 1 9.7210779190063477 7.5637617111206055 A 4.6192383450974566 4.6192383450974566 0 0 0 9.8147754669189453 7.2684907913208008 A 0.43882611094634161 0.43882611094634161 0 0 0 9.7695827484130859 6.9149794578552246 A 0.54007993271830668 0.54007993271830668 0 0 0 9.4954538345336914 6.7077541351318359 A 1.1683115302991802 1.1683115302991802 0 0 0 9.2431621551513672 6.6401095390319824 A 0.46280926036283832 0.46280926036283832 0 0 1 9.0169057846069336 6.4593758583068848 A 0.41532329281150754 0.41532329281150754 0 0 1 8.9443750381469727 6.1789851188659668 A 0.51127748095303893 0.51127748095303893 0 0 1 9.0969362258911133 6.2751264572143555 A 0.49394860918642508 0.49394860918642508 0 0 0 9.1644134521484375 6.4437246322631836 A 0.23369495240943691 0.23369495240943691 0 0 0 9.3497314453125 6.5601096153259277 A 0.35410095070226827 0.35410095070226827 0 0 0 9.4867563247680664 6.5390777587890625 A 9.5192550148496906 9.5192550148496906 0 0 0 9.6109504699707031 6.4974932670593262 A 0.57248901757058612 0.57248901757058612 0 0 1 9.7222747802734375 6.4707722663879395 A 0.29559291348889982 0.29559291348889982 0 0 1 9.8290786743164062 6.4747967720031738 A 0.41066043873792679 0.41066043873792679 0 0 1 9.6808900833129883 6.313133716583252 A 2.4153527829089905 2.4153527829089905 0 0 0 9.5892419815063477 6.1594281196594238 A 0.25508654201970854 0.25508654201970854 0 0 0 9.4515209197998047 6.0546293258666992 A 0.23727569202269516 0.23727569202269516 0 0 0 9.3257160186767578 6.0535707473754883 A 0.53097444701218033 0.53097444701218033 0 0 0 9.1160087585449219 6.1640129089355469 A 0.38210689902740547 0.38210689902740547 0 0 1 8.9497823715209961 5.9855990409851074 A 3.9564228966138169 3.9564228966138169 0 0 0 8.7933807373046875 4.8700652122497559 A 0.52907013729812913 0.52907013729812913 0 0 1 9.0875320434570312 5.1549229621887207 A 2.1382119367162296 2.1382119367162296 0 0 1 9.1926670074462891 5.566521167755127 A 0.69725508362184063 0.69725508362184063 0 0 0 9.3492774963378906 5.850867748260498 A 0.23401931895229308 0.23401931895229308 0 0 0 9.5197772979736328 5.9394388198852539 A 0.27105640534167147 0.27105640534167147 0 0 0 9.6865482330322266 5.8881072998046875 A 0.48507921191478587 0.48507921191478587 0 0 0 9.8799371719360352 5.5773768424987793 A 0.48507922842809043 0.48507922842809043 0 0 0 10.073325157165527 5.8881072998046875 A 0.27105661135631681 0.27105661135631681 0 0 0 10.240096092224121 5.9394388198852539 A 0.23401963954775135 0.23401963954775135 0 0 0 10.410595893859863 5.8508682250976563 A 0.69725520732280544 0.69725520732280544 0 0 0 10.567206382751465 5.5665206909179687 A 2.1382114344811294 2.1382114344811294 0 0 1 10.672341346740723 5.1549224853515625 A 0.52907020749892819 0.52907020749892819 0 0 1 10.966493606567383 4.8700637817382812 A 3.956422872854457 3.956422872854457 0 0 0 10.810091018676758 5.9855990409851074 A 0.38210695438543552 0.38210695438543552 0 0 1 10.643864631652832 6.1640129089355469 A 0.53097421393839972 0.53097421393839972 0 0 0 10.434157371520996 6.0535702705383301 A 0.23727572367955174 0.23727572367955174 0 0 0 10.308351516723633 6.0546298027038574 A 0.25508653615813193 0.25508653615813193 0 0 0 10.170632362365723 6.1594266891479492 A 2.4153523717481908 2.4153523717481908 0 0 0 10.078984260559082 6.313133716583252 A 0.41065981587621236 0.41065981587621236 0 0 1 9.9307947158813477 6.4747962951660156 A 0.29559283346620535 0.29559283346620535 0 0 1 10.037598609924316 6.4707722663879395 A 0.57248910422683186 0.57248910422683186 0 0 1 10.148921966552734 6.4974932670593262 A 9.5192539125265689 9.5192539125265689 0 0 0 10.273116111755371 6.5390772819519043 A 0.35410090803787075 0.35410090803787075 0 0 0 10.410141944885254 6.5601096153259277 A 0.23369525196910046 0.23369525196910046 0 0 0 10.595459938049316 6.4437251091003418 A 0.49394852849419923 0.49394852849419923 0 0 0 10.662936210632324 6.2751259803771973 A 0.51127776982407891 0.51127776982407891 0 0 1 10.815499305725098 6.1789851188659668 A 0.41532325837259465 0.41532325837259465 0 0 1 10.74296760559082 6.459376335144043 A 0.46280989153895408 0.46280989153895408 0 0 1 10.516712188720703 6.6401095390319824 A 1.1683112820627981 1.1683112820627981 0 0 0 10.264420509338379 6.7077536582946777 A 0.54008003917320924 0.54008003917320924 0 0 0 9.990290641784668 6.9149789810180664 A 0.43882624507429946 0.43882624507429946 0 0 0 9.9450979232788086 7.2684907913208008 A 4.6192384297226639 4.6192384297226639 0 0 0 10.038796424865723 7.5637617111206055 A 0.70664761244348018 0.70664761244348018 0 0 1 10.078004837036133 7.9499654769897461 A 0.57493429840429955 0.57493429840429955 0 0 1 10.199103355407715 7.8034734725952148 A 2.0237602651005706 2.0237602651005706 0 0 1 10.519057273864746 7.6007628440856934 A 0.72814014759716461 0.72814014759716461 0 0 0 10.740120887756348 7.4357614517211914 A 0.39838180286674818 0.39838180286674818 0 0 0 10.833741188049316 7.1019496917724609 A 0.81710735187117689 0.81710735187117689 0 0 0 10.685209274291992 6.7599906921386719 A 0.52740821033680052 0.52740821033680052 0 0 1 10.854381561279297 6.5624299049377441 A 3.9769229585447179 3.9769229585447179 0 0 0 10.992880821228027 7.1610069274902344 A 1.385154075109732 1.385154075109732 0 0 1 10.763846397399902 7.9021768569946289 A 1.2167097969386742 1.2167097969386742 0 0 0 10.190132141113281 8.1251926422119141 A 0.54100389814488126 0.54100389814488126 0 0 0 9.9793376922607422 8.4960412979125977 A 0.87693216664228979 0.87693216664228979 0 0 0 10.032421112060547 8.860748291015625 A 20.877144464507673 20.877144464507673 0 0 0 10.106008529663086 9.0801973342895508 A 1.3070264547844079 1.3070264547844079 0 0 1 10.191728591918945 9.5036602020263672 A 0.53287796085617145 0.53287796085617145 0 0 1 9.9162912368774414 9.1871509552001953 A 1.2571246499087032 1.2571246499087032 0 0 0 9.9136495590209961 9.5814657211303711 A 0.44787171618693927 0.44787171618693927 0 0 0 9.9727821350097656 9.7497100830078125 A 0.224335639862214 0.224335639862214 0 0 0 10.099342346191406 9.8524456024169922 A 0.32122072195578755 0.32122072195578755 0 0 0 10.261722564697266 9.8553237915039062 A 0.78889781592828567 0.78889781592828567 0 0 0 10.432397842407227 9.7984628677368164 A 0.82113355012266231 0.82113355012266231 0 0 1 10.681942939758301 9.7420797348022461 A 0.92274667722629322 0.92274667722629322 0 0 0 10.371435165405273 9.9183187484741211 A 0.48471987725589777 0.48471987725589777 0 0 0 10.201988220214844 10.185111045837402 A 0.45307913778388903 0.45307913778388903 0 0 0 10.271368026733398 10.556424140930176 A 0.42228963442858364 0.42228963442858364 0 0 0 10.474629402160645 10.715694427490234 A 0.61357530987381059 0.61357530987381059 0 0 0 10.668399810791016 10.748800277709961 A 1.1060705657037775 1.1060705657037775 0 0 1 10.576563835144043 10.352771759033203 A 0.74392484567917183 0.74392484567917183 0 0 1 10.669277191162109 9.9533205032348633 A 0.94172691536118402 0.94172691536118402 0 0 1 10.966316223144531 9.6569662094116211 A 3.9564228745449515 3.9564228745449515 0 0 0 10.80991268157959 10.772501945495605 A 0.38210698885652422 0.38210698885652422 0 0 1 10.64368724822998 10.950916290283203 A 0.53097375308611638 0.53097375308611638 0 0 0 10.433979988098145 10.840473175048828 A 0.23727598424582746 0.23727598424582746 0 0 0 10.308174133300781 10.841532707214355 A 0.25508653615813193 0.25508653615813193 0 0 0 10.170454025268555 10.946330070495605 A 2.4153523717481908 2.4153523717481908 0 0 0 10.078805923461914 11.10003662109375 A 0.41066022024294069 0.41066022024294069 0 0 1 9.9306163787841797 11.261699676513672 A 0.29559283346620535 0.29559283346620535 0 0 1 10.037420272827148 11.257675170898438 A 0.57248955444205096 0.57248955444205096 0 0 1 10.148744583129883 11.284395217895508 A 9.5192541823658434 9.5192541823658434 0 0 0 10.27293872833252 11.325980186462402 A 0.35410047431267599 0.35410047431267599 0 0 0 10.409964561462402 11.347012519836426 A 0.23369525196910046 0.23369525196910046 0 0 0 10.595282554626465 11.23062801361084 A 0.49394871405133789 0.49394871405133789 0 0 0 10.662758827209473 11.062029838562012 A 0.51127732789817693 0.51127732789817693 0 0 1 10.81532096862793 10.965888023376465 A 0.45779008347790501 0.45779008347790501 0 0 1 10.516533851623535 11.42701244354248 A 1.1683108381839773 1.1683108381839773 0 0 0 10.264243125915527 11.494657516479492 A 0.54008003917320924 0.54008003917320924 0 0 0 9.9901123046875 11.701881408691406 A 0.43882624507429946 0.43882624507429946 0 0 0 9.944920539855957 12.055394172668457 A 4.6192382703365515 4.6192382703365515 0 0 0 10.038618087768555 12.350664138793945 A 0.70664778042930154 0.70664778042930154 0 0 1 10.077826499938965 12.736868858337402 A 0.57493429840429955 0.57493429840429955 0 0 1 10.198925971984863 12.590376853942871 A 2.023760674301804 2.023760674301804 0 0 1 10.518879890441895 12.387665748596191 A 0.72814021011413688 0.72814021011413688 0 0 0 10.73994255065918 12.222663879394531 A 0.39838171902771324 0.39838171902771324 0 0 0 10.833562850952148 11.888853073120117 A 0.8171076366100577 0.8171076366100577 0 0 0 10.685030937194824 11.546894073486328 A 0.52740821033680052 0.52740821033680052 0 0 1 10.854204177856445 11.349332809448242 A 3.9769229585447179 3.9769229585447179 0 0 0 10.992702484130859 11.947909355163574 A 1.385154075109732 1.385154075109732 0 0 1 10.763669013977051 12.689079284667969 A 1.2167097969386742 1.2167097969386742 0 0 0 10.189953804016113 12.912095069885254 A 0.54100389814488126 0.54100389814488126 0 0 0 9.9791593551635742 13.282944679260254 A 0.87693216664228979 0.87693216664228979 0 0 0 10.032242774963379 13.647650718688965 A 20.877144464507673 20.877144464507673 0 0 0 10.105831146240234 13.867100715637207 A 1.3070264547844079 1.3070264547844079 0 0 1 10.191550254821777 14.290563583374023 A 0.53287796085617145 0.53287796085617145 0 0 1 9.9161138534545898 13.974054336547852 A 0.6936713747957487 0.6936713747957487 0 0 1 9.8820276260375977 13.82731819152832 L 9.8778457641601562 13.82731819152832 A 0.69367143657038333 0.69367143657038333 0 0 1 9.8437595367431641 13.974053382873535 A 0.53287771944859186 0.53287771944859186 0 0 1 9.5684165954589844 14.290512084960938 A 1.3070264486466605 1.3070264486466605 0 0 1 9.6540422439575195 13.867104530334473 A 20.877143664793483 20.877143664793483 0 0 0 9.727630615234375 13.647651672363281 M 12.05817985534668 13.152002334594727 A 5.6923785459290022 5.6923785459290022 0 0 0 12.235755920410156 12.897702217102051 A 0.70537563589083185 0.70537563589083185 0 0 1 12.527039527893066 13.159546852111816 A 1.1683841412390163 1.1683841412390163 0 0 0 12.501161575317383 13.262837409973145 A 0.90937112568361567 0.90937112568361567 0 0 0 12.486189842224121 13.54228687286377 A 0.44205214620625538 0.44205214620625538 0 0 0 12.598516464233398 13.802285194396973 A 0.45359210264867289 0.45359210264867289 0 0 0 12.829477310180664 13.929219245910645 A 1.5313968639959197 1.5313968639959197 0 0 0 13.013521194458008 13.959247589111328 A 1.3692360011948952 1.3692360011948952 0 0 1 13.408272743225098 14.039505958557129 A 0.31379731941635547 0.31379731941635547 0 0 0 13.304646492004395 14.068667411804199 A 0.72776921200796818 0.72776921200796818 0 0 0 13.179466247558594 14.158535003662109 A 0.70656314743644222 0.70656314743644222 0 0 1 13.067482948303223 14.237912178039551 A 0.32613861859730486 0.32613861859730486 0 0 1 12.949239730834961 14.276608467102051 A 0.3817028060923307 0.3817028060923307 0 0 1 13.124617576599121 14.36750316619873 A 2.7878009287158747 2.7878009287158747 0 0 0 13.276917457580566 14.496724128723145 A 0.51140986946259392 0.51140986946259392 0 0 0 13.110154151916504 14.502318382263184 A 0.27536830323417372 0.27536830323417372 0 0 0 12.941606521606445 14.599067687988281 A 0.26831757675822954 0.26831757675822954 0 0 0 12.878212928771973 14.777609825134277 A 36.788065606827352 36.788065606827352 0 0 1 12.863204956054688 14.992527961730957 A 2.032688607037842 2.032688607037842 0 0 1 12.802179336547852 14.852906227111816 A 4.0573295969519663 4.0573295969519663 0 0 0 12.058181762695313 13.152003288269043 M 12.053028106689453 13.659345626831055 A 0.10704938446613389 0.10704938446613389 0 0 1 11.963374137878418 13.752200126647949 A 0.52498957065850571 0.52498957065850571 0 0 0 11.790870666503906 13.749981880187988 A 0.25627600444947096 0.25627600444947096 0 0 0 11.63900089263916 13.826690673828125 A 1.9608524953114292 1.9608524953114292 0 0 1 11.609785079956055 13.713068008422852 A 3.251026466007485 3.251026466007485 0 0 1 11.849983215332031 13.397393226623535 A 3.2962224975684817 3.2962224975684817 0 0 1 12.053028106689453 13.659345626831055 M 11.072675704956055 14.127266883850098 A 1.064000619826571 1.064000619826571 0 0 1 10.695979118347168 14.34771728515625 A 0.63789843282217162 0.63789843282217162 0 0 1 10.255148887634277 14.320932388305664 A 1.2062183652901242 1.2062183652901242 0 0 1 10.613069534301758 14.055200576782227 A 14.654286019374117 14.654286019374117 0 0 0 10.819470405578613 13.937528610229492 A 1.1465232677965678 1.1465232677965678 0 0 0 11.016119003295898 13.794265747070313 A 0.54696790173467635 0.54696790173467635 0 0 0 11.172513961791992 13.538049697875977 A 0.57503119442711403 0.57503119442711403 0 0 0 11.161050796508789 13.20378303527832 A 1.2823666178279944 1.2823666178279944 0 0 0 10.944883346557617 12.794990539550781 A 1.2406463765118039 1.2406463765118039 0 0 1 11.14789867401123 12.359066009521484 A 4.0510188999922718 4.0510188999922718 0 0 0 11.615120887756348 13.151946067810059 A 3.993195364003097 3.993195364003097 0 0 0 11.072675704956055 14.127265930175781 M 13.984031677246094 13.77543830871582 A 2.8044271454420251 2.8044271454420251 0 0 1 14.086828231811523 14.124162673950195 A 1.6544105654603383 1.6544105654603383 0 0 0 13.897467613220215 14.18466854095459 A 0.41379231950729578 0.41379231950729578 0 0 1 13.704727172851563 14.225983619689941 A 0.40871435759197045 0.40871435759197045 0 0 0 13.480177879333496 14.034726142883301 A 0.70773288477541985 0.70773288477541985 0 0 1 13.427859306335449 13.865983009338379 A 0.93035763754300094 0.93035763754300094 0 0 1 13.408803939819336 13.707273483276367 A 34.655360995318631 34.655360995318631 0 0 0 13.396556854248047 13.534456253051758 A 0.76256409411250459 0.76256409411250459 0 0 0 13.342825889587402 13.284322738647461 A 0.39678784719964616 0.39678784719964616 0 0 0 13.228450775146484 13.134840965270996 A 0.398989699046783 0.398989699046783 0 0 0 13.142385482788086 13.082778930664063 A 3.494864949262602 3.494864949262602 0 0 0 13.461080551147461 12.987783432006836 A 1.2350736999256009 1.2350736999256009 0 0 1 13.654308319091797 12.943890571594238 A 0.66576597241771196 0.66576597241771196 0 0 1 13.726824760437012 12.939272880554199 A 0.52597822925787741 0.52597822925787741 0 0 1 13.84773063659668 12.953261375427246 A 0.56964753278682234 0.56964753278682234 0 0 1 13.700374603271484 12.827616691589355 A 1.2350747985935857 1.2350747985935857 0 0 1 13.589638710021973 12.663296699523926 L 13.491503715515137 12.486014366149902 A 0.76304969705452863 0.76304969705452863 0 0 0 13.337696075439453 12.281587600708008 A 0.43483989145020752 0.43483989145020752 0 0 0 13.24052619934082 12.218269348144531 A 0.4169373239310481 0.4169373239310481 0 0 0 13.071907043457031 12.182380676269531 A 0.70450041386470585 0.70450041386470585 0 0 0 12.760222434997559 12.27338695526123 A 1.1669450209912251 1.1669450209912251 0 0 0 12.631304740905762 12.355759620666504 A 0.056723629426792405 0.056723629426792405 0 0 1 12.555633544921875 12.282570838928223 A 3.8798880383513858 3.8798880383513858 0 0 0 12.857873916625977 10.575872421264648 A 0.9692604724751992 0.9692604724751992 0 0 1 13.228790283203125 11.119160652160645 A 1.2357223083060567 1.2357223083060567 0 0 0 13.04178524017334 11.560447692871094 A 0.59743418533885928 0.59743418533885928 0 0 0 13.054962158203125 11.879550933837891 A 0.54856198607068041 0.54856198607068041 0 0 0 13.23188304901123 12.131686210632324 A 1.0050693292678667 1.0050693292678667 0 0 0 13.425930023193359 12.251307487487793 A 5.1990785162582753 5.1990785162582753 0 0 1 13.910654067993164 12.487380027770996 A 0.59573000630965944 0.59573000630965944 0 0 1 13.916983604431152 12.754881858825684 A 0.55888118397079134 0.55888118397079134 0 0 1 14.05135440826416 12.596511840820313 A 0.65237358730424633 0.65237358730424633 0 0 1 14.137326240539551 12.698685646057129 A 0.65686085365819458 0.65686085365819458 0 0 1 14.107027053833008 12.55561637878418 A 1.4576598024491836 1.4576598024491836 0 0 1 14.234807014465332 12.475301742553711 A 3.9054249661933356 3.9054249661933356 0 0 1 14.240797996520996 12.471870422363281 A 2.6635672465935745 2.6635672465935745 0 0 0 14.488101005554199 12.323159217834473 A 0.41648461022410072 0.41648461022410072 0 0 0 14.669228553771973 11.886250495910645 A 0.76941127575826918 0.76941127575826918 0 0 0 14.565456390380859 11.628031730651855 A 0.5537921748741339 0.5537921748741339 0 0 1 14.768148422241211 11.349332809448242 A 3.9604953131044125 3.9604953131044125 0 0 0 14.906646728515625 11.947909355163574 A 1.3772210993416969 1.3772210993416969 0 0 1 14.750967979431152 12.564281463623047 A 1.4384667138271108 1.4384667138271108 0 0 0 14.138398170471191 12.785055160522461 A 0.61902998342956261 0.61902998342956261 0 0 0 13.877704620361328 13.187268257141113 A 0.74981457249614125 0.74981457249614125 0 0 0 13.909224510192871 13.532208442687988 A 2.387346493852271 2.387346493852271 0 0 0 13.984031677246094 13.775436401367188 M 12.05817985534668 3.5781965255737305 A 5.6923783738288973 5.6923783738288973 0 0 0 12.235755920410156 3.3238964080810547 A 0.70537581486080736 0.70537581486080736 0 0 1 12.527039527893066 3.5857415199279785 A 1.1683842359246783 1.1683842359246783 0 0 0 12.501161575317383 3.6890316009521484 A 0.90937117374426957 0.90937117374426957 0 0 0 12.486189842224121 3.9684808254241943 A 0.44205214620625538 0.44205214620625538 0 0 0 12.598516464233398 4.2284793853759766 A 0.45359210264867289 0.45359210264867289 0 0 0 12.829477310180664 4.3554134368896484 A 1.5313962428749581 1.5313962428749581 0 0 0 13.013521194458008 4.3854413032531738 A 1.3692354301710672 1.3692354301710672 0 0 1 13.408272743225098 4.465700626373291 A 0.31379649544893051 0.31379649544893051 0 0 0 13.304646492004395 4.4948620796203613 A 0.72776928842224786 0.72776928842224786 0 0 0 13.179466247558594 4.5847287178039551 A 0.70656356140108345 0.70656356140108345 0 0 1 13.067482948303223 4.6641063690185547 A 0.3261388551940067 0.3261388551940067 0 0 1 12.949239730834961 4.7028031349182129 A 0.38170286745238702 0.38170286745238702 0 0 1 13.124617576599121 4.793696403503418 A 2.7878007415092223 2.7878007415092223 0 0 0 13.276917457580566 4.9229183197021484 A 0.51140977595952242 0.51140977595952242 0 0 0 13.110154151916504 4.9285130500793457 A 0.27536830323417372 0.27536830323417372 0 0 0 12.941606521606445 5.0252618789672852 A 0.26831757675822954 0.26831757675822954 0 0 0 12.878212928771973 5.2038044929504395 A 36.788066022171641 36.788066022171641 0 0 1 12.863204956054688 5.4187221527099609 A 2.0326885917792681 2.0326885917792681 0 0 1 12.802179336547852 5.2791013717651367 A 4.0573297399391173 4.0573297399391173 0 0 0 12.058181762695313 3.5781972408294678 M 13.342825889587402 3.7105166912078857 A 0.39678766154406991 0.39678766154406991 0 0 0 13.228450775146484 3.5610353946685791 A 0.39899030378594741 0.39899030378594741 0 0 0 13.142385482788086 3.5089731216430664 A 3.4948652265525526 3.4948652265525526 0 0 0 13.461080551147461 3.4139771461486816 A 1.235074235962929 1.235074235962929 0 0 1 13.654308319091797 3.3700852394104004 A 0.6657657340087707 0.6657657340087707 0 0 1 13.726824760437012 3.3654677867889404 A 0.52597822925787741 0.52597822925787741 0 0 1 13.84773063659668 3.3794553279876709 A 0.56964756212105661 0.56964756212105661 0 0 1 13.700374603271484 3.2538111209869385 A 1.2350747861891467 1.2350747861891467 0 0 1 13.589638710021973 3.0894913673400879 L 13.491503715515137 2.9122085571289062 A 0.76304952380411006 0.76304952380411006 0 0 0 13.337696075439453 2.7077817916870117 A 0.43483989145020752 0.43483989145020752 0 0 0 13.24052619934082 2.6444635391235352 A 0.41693684429788408 0.41693684429788408 0 0 0 13.071907043457031 2.6085755825042725 A 0.70450015010622424 0.70450015010622424 0 0 0 12.760222434997559 2.6995816230773926 A 1.1669445812287864 1.1669445812287864 0 0 0 12.631304740905762 2.7819540500640869 A 0.056723539481674676 0.056723539481674676 0 0 1 12.555633544921875 2.7087655067443848 A 3.8798880919633105 3.8798880919633105 0 0 0 12.857873916625977 1.0020663738250732 A 0.96926044265737965 0.96926044265737965 0 0 1 13.228790283203125 1.5453553199768066 A 1.2357222596154656 1.2357222596154656 0 0 0 13.04178524017334 1.9866418838500977 A 0.59743425849012222 0.59743425849012222 0 0 0 13.054962158203125 2.3057448863983154 A 0.54856276777585267 0.54856276777585267 0 0 0 13.23188304901123 2.5578811168670654 A 1.0050693557731705 1.0050693557731705 0 0 0 13.425930023193359 2.6775021553039551 A 5.199078459870023 5.199078459870023 0 0 1 13.910654067993164 2.9135744571685791 A 0.59572991024825384 0.59572991024825384 0 0 1 13.916983604431152 3.1810753345489502 A 0.55888095476861377 0.55888095476861377 0 0 1 14.05135440826416 3.0227060317993164 A 0.65237397395684493 0.65237397395684493 0 0 1 14.137326240539551 3.1248800754547119 A 0.65686089990842234 0.65686089990842234 0 0 1 14.107027053833008 2.9818108081817627 A 1.4576602807871479 1.4576602807871479 0 0 1 14.234807014465332 2.9014966487884521 A 3.9054256396800646 3.9054256396800646 0 0 1 14.240797996520996 2.8980643749237061 A 2.6635671140630617 2.6635671140630617 0 0 0 14.488101005554199 2.7493536472320557 A 0.41648456032785786 0.41648456032785786 0 0 0 14.669228553771973 2.3124454021453857 A 0.76941127575826918 0.76941127575826918 0 0 0 14.565456390380859 2.0542259216308594 A 0.55379256140259703 0.55379256140259703 0 0 1 14.768148422241211 1.7755274772644043 A 3.9604953489045434 3.9604953489045434 0 0 0 14.906646728515625 2.3741028308868408 A 1.3772208790214986 1.3772208790214986 0 0 1 14.750967979431152 2.990476131439209 A 1.4384661958073761 1.4384661958073761 0 0 0 14.138398170471191 3.2112493515014648 A 0.61903002553614361 0.61903002553614361 0 0 0 13.877704620361328 3.6134624481201172 A 0.74981457249614125 0.74981457249614125 0 0 0 13.909224510192871 3.9584026336669922 A 2.387346083180224 2.387346083180224 0 0 0 13.984031677246094 4.2016305923461914 A 2.8044272503373038 2.8044272503373038 0 0 1 14.086828231811523 4.5503559112548828 A 1.6544106087595321 1.6544106087595321 0 0 0 13.897467613220215 4.610863208770752 A 0.41379276816710536 0.41379276816710536 0 0 1 13.704727172851563 4.6521787643432617 A 0.40871512245705111 0.40871512245705111 0 0 0 13.480177879333496 4.4609198570251465 A 0.70773211227501642 0.70773211227501642 0 0 1 13.427859306335449 4.2921772003173828 A 0.93035763754300094 0.93035763754300094 0 0 1 13.408803939819336 4.1334676742553711 A 34.655360471910157 34.655360471910157 0 0 0 13.396556854248047 3.9606499671936035 A 0.76256409411250459 0.76256409411250459 0 0 0 13.342825889587402 3.7105171680450439 M 6.9576940536499023 5.2791013717651367 A 2.0326887686326653 2.0326887686326653 0 0 1 6.8966689109802246 5.4187221527099609 A 36.788066813594746 36.788066813594746 0 0 1 6.8816580772399902 5.2037935256958008 A 0.26831760107239849 0.26831760107239849 0 0 0 6.8182668685913086 5.0252618789672852 A 0.27536800394063637 0.27536800394063637 0 0 0 6.6497197151184082 4.9285130500793457 A 0.51140974233162417 0.51140974233162417 0 0 0 6.4829564094543457 4.9229183197021484 A 2.7878010439607679 2.7878010439607679 0 0 0 6.6352558135986328 4.793696403503418 A 0.3817027253618579 0.3817027253618579 0 0 1 6.8106346130371094 4.7028031349182129 A 0.32613930490804283 0.32613930490804283 0 0 1 6.6923904418945313 4.6641058921813965 A 0.70656339833619042 0.70656339833619042 0 0 1 6.5804076194763184 4.5847291946411133 A 0.72776898165128368 0.72776898165128368 0 0 0 6.4552278518676758 4.4948620796203613 A 0.31379670873108062 0.31379670873108062 0 0 0 6.3516011238098145 4.4657001495361328 A 1.3692358710666535 1.3692358710666535 0 0 1 6.7463517189025879 4.385441780090332 A 1.5313964530042801 1.5313964530042801 0 0 0 6.9303956031799316 4.3554134368896484 A 0.45359206982635181 0.45359206982635181 0 0 0 7.1614670753479004 4.2283573150634766 A 0.4420517000149411 0.4420517000149411 0 0 0 7.2736830711364746 3.9684808254241943 A 0.9093708102732051 0.9093708102732051 0 0 0 7.2587127685546875 3.6890325546264648 A 1.168384742873146 1.168384742873146 0 0 0 7.2328343391418457 3.5857415199279785 A 0.70537596126634328 0.70537596126634328 0 0 1 7.5241179466247559 3.3238961696624756 A 5.6923782458363217 5.6923782458363217 0 0 0 7.7016921043395996 3.5781958103179932 A 4.0573298136714309 4.0573298136714309 0 0 0 6.9576945304870605 5.2790999412536621 M 5.8821687698364258 3.6134629249572754 A 0.61902984650566406 0.61902984650566406 0 0 0 5.6214756965637207 3.2112495899200439 A 1.4384663841522729 1.4384663841522729 0 0 0 5.0089058876037598 2.990476131439209 A 1.3772208816144347 1.3772208816144347 0 0 1 4.8532271385192871 2.3741040229797363 A 3.9604953478572464 3.9604953478572464 0 0 0 4.9917254447937012 1.7755274772644043 A 0.55379216512418983 0.55379216512418983 0 0 1 5.1944174766540527 2.0542254447937012 A 0.76941151172961897 0.76941151172961897 0 0 0 5.0906448364257812 2.3124449253082275 A 0.41648486832485704 0.41648486832485704 0 0 0 5.2717723846435547 2.7493536472320557 A 2.6635671329860489 2.6635671329860489 0 0 0 5.519075870513916 2.8980643749237061 A 3.9054257058081507 3.9054257058081507 0 0 1 5.5250716209411621 2.9014894962310791 A 1.4576599495258977 1.4576599495258977 0 0 1 5.6528472900390625 2.9818112850189209 A 0.65686067233740952 0.65686067233740952 0 0 1 5.6225476264953613 3.1248798370361328 A 0.65237356722526418 0.65237356722526418 0 0 1 5.7085189819335938 3.0227057933807373 A 0.5588812529681445 0.5588812529681445 0 0 1 5.8428888320922852 3.1810755729675293 A 0.59573022302013079 0.59573022302013079 0 0 1 5.8492217063903809 2.9135727882385254 A 5.199078580717388 5.199078580717388 0 0 1 6.3339447975158691 2.6775016784667969 A 1.0050695326763948 1.0050695326763948 0 0 0 6.5279903411865234 2.5578811168670654 A 0.5485622081266639 0.5485622081266639 0 0 0 6.7049107551574707 2.3057451248168945 A 0.59743451756335431 0.59743451756335431 0 0 0 6.7180881500244141 1.9866416454315186 A 1.2357222470481593 1.2357222470481593 0 0 0 6.5310831069946289 1.5453552007675171 A 0.96926021488375569 0.96926021488375569 0 0 1 6.9019994735717773 1.0020661354064941 A 3.8798881636927249 3.8798881636927249 0 0 0 7.2042403221130371 2.7087647914886475 A 0.056723197749454599 0.056723197749454599 0 0 1 7.1285696029663086 2.781954288482666 A 1.1669446141320206 1.1669446141320206 0 0 0 6.9996514320373535 2.6995818614959717 A 0.70450020668820557 0.70450020668820557 0 0 0 6.6879663467407227 2.6085755825042725 A 0.41693692502284968 0.41693692502284968 0 0 0 6.51934814453125 2.6444633007049561 A 0.43484008261091567 0.43484008261091567 0 0 0 6.422177791595459 2.7077817916870117 A 0.76304954204970021 0.76304954204970021 0 0 0 6.2683701515197754 2.9122085571289062 L 6.1702346801757813 3.089491605758667 A 1.2350743250936642 1.2350743250936642 0 0 1 6.0594987869262695 3.2538111209869385 A 0.56964705465161891 0.56964705465161891 0 0 1 5.9121427536010742 3.3794553279876709 A 0.5259782501029836 0.5259782501029836 0 0 1 6.0330491065979004 3.3654677867889404 A 0.66576575457539877 0.66576575457539877 0 0 1 6.1055660247802734 3.3700854778289795 A 1.2350743408103149 1.2350743408103149 0 0 1 6.2987937927246094 3.4139771461486816 A 3.4948655472219046 3.4948655472219046 0 0 0 6.617487907409668 3.5089731216430664 A 0.39899009495177357 0.39899009495177357 0 0 0 6.5314235687255859 3.5610353946685791 A 0.39678779577826762 0.39678779577826762 0 0 0 6.4170475006103516 3.7105166912078857 A 0.76256469147215122 0.76256469147215122 0 0 0 6.3633155822753906 3.960637092590332 A 34.655359888111406 34.655359888111406 0 0 0 6.3510723114013672 4.1334552764892578 A 0.93035707321704675 0.93035707321704675 0 0 1 6.3320140838623047 4.2921772003173828 A 0.70773230333812021 0.70773230333812021 0 0 1 6.2796950340270996 4.4609198570251465 A 0.4087151551768971 0.4087151551768971 0 0 0 6.0551466941833496 4.6521787643432617 A 0.41379280813320363 0.41379280813320363 0 0 1 5.8624067306518555 4.610863208770752 A 1.6544108733481928 1.6544108733481928 0 0 0 5.6730446815490723 4.5503549575805664 A 2.8044272396468557 2.8044272396468557 0 0 1 5.7758417129516602 4.2016301155090332 A 2.3873456309414989 2.3873456309414989 0 0 0 5.8506488800048828 3.9584028720855713 A 0.74981452120921777 0.74981452120921777 0 0 0 5.8821687698364258 3.6134629249572754 M 8.1447515487670898 3.5781407356262207 A 4.0510187113159928 4.0510187113159928 0 0 0 8.6119747161865234 2.7852611541748047 A 1.2406463207963612 1.2406463207963612 0 0 1 8.8149900436401367 3.2211852073669434 A 1.2823662428115628 1.2823662428115628 0 0 0 8.5988225936889648 3.6299769878387451 A 0.57503114067894001 0.57503114067894001 0 0 0 8.5873594284057617 3.9642446041107178 A 0.54696797163103039 0.54696797163103039 0 0 0 8.7437553405761719 4.2204594612121582 A 1.1465234798824271 1.1465234798824271 0 0 0 8.9404020309448242 4.3637223243713379 A 14.654287451679041 14.654287451679041 0 0 0 9.1468029022216797 4.4813947677612305 A 1.2051432432882441 1.2051432432882441 0 0 1 9.5026140213012695 4.7480068206787109 A 0.63787872857914485 0.63787872857914485 0 0 1 9.0638933181762695 4.7739105224609375 A 1.0640003467463164 1.0640003467463164 0 0 1 8.6871976852416992 4.5534605979919434 A 3.9931949844458123 3.9931949844458123 0 0 0 8.1447525024414062 3.5781416893005371 M 9.7805356979370117 3.7091391086578369 A 0.54100363570726318 0.54100363570726318 0 0 0 9.5697412490844727 3.3382899761199951 A 1.2167097499416399 1.2167097499416399 0 0 0 8.9960269927978516 3.1152739524841309 A 1.3851541215700767 1.3851541215700767 0 0 1 8.7669925689697266 2.3741037845611572 A 3.9769234806617577 3.9769234806617577 0 0 0 8.905491828918457 1.7755275964736938 A 0.5274078688553423 0.5274078688553423 0 0 1 9.0746650695800781 1.9730879068374634 A 0.81710735083007713 0.81710735083007713 0 0 0 8.9261322021484375 2.315047025680542 A 0.39838184231915075 0.39838184231915075 0 0 0 9.0197525024414062 2.6488585472106934 A 0.72814013672483047 0.72814013672483047 0 0 0 9.2408151626586914 2.8138599395751953 A 2.0237604268990195 2.0237604268990195 0 0 1 9.5607700347900391 3.0165705680847168 A 0.57493400411984963 0.57493400411984963 0 0 1 9.6818695068359375 3.1630630493164062 A 0.70664764981832429 0.70664764981832429 0 0 1 9.7210779190063477 2.7768592834472656 A 4.6192382806451748 4.6192382806451748 0 0 0 9.8147754669189453 2.4815878868103027 A 0.43882623460792486 0.43882623460792486 0 0 0 9.7695827484130859 2.1280760765075684 A 0.54007993271830668 0.54007993271830668 0 0 0 9.4954538345336914 1.9208512306213379 A 1.1683112699702047 1.1683112699702047 0 0 0 9.2431621551513672 1.853206992149353 A 0.45779047370372117 0.45779047370372117 0 0 1 8.9443740844726563 1.3920822143554687 A 0.51127800934284229 0.51127800934284229 0 0 1 9.0969362258911133 1.4882234334945679 A 0.49394854530240029 0.49394854530240029 0 0 0 9.1644134521484375 1.6568219661712646 A 0.23369519018400267 0.23369519018400267 0 0 0 9.3497314453125 1.7732068300247192 A 0.35410072668298143 0.35410072668298143 0 0 0 9.4867563247680664 1.7521748542785645 A 9.5192547892939281 9.5192547892939281 0 0 0 9.6109504699707031 1.710590124130249 A 0.57248913568851212 0.57248913568851212 0 0 1 9.7222747802734375 1.6838692426681519 A 0.29559291348889982 0.29559291348889982 0 0 1 9.8290786743164062 1.6878937482833862 A 0.41066043873792679 0.41066043873792679 0 0 1 9.6808900833129883 1.526231050491333 A 2.4153526647273877 2.4153526647273877 0 0 0 9.5892419815063477 1.3725252151489258 A 0.25508642829032963 0.25508642829032963 0 0 0 9.4515209197998047 1.2677267789840698 A 0.23727580722829744 0.23727580722829744 0 0 0 9.3257160186767578 1.2666676044464111 A 0.53097427759146365 0.53097427759146365 0 0 0 9.1160087585449219 1.3771100044250488 A 0.38210689902740547 0.38210689902740547 0 0 1 8.9497823715209961 1.1986961364746094 A 3.9604954105902221 3.9604954105902221 0 0 0 8.9438056945800781 0.96675193309783936 L 10.816068649291992 0.96675008535385132 A 3.9604948819226298 3.9604948819226298 0 0 0 10.810091018676758 1.1986953020095825 A 0.38210705923025806 0.38210705923025806 0 0 1 10.643864631652832 1.3771101236343384 A 0.53097408429452952 0.53097408429452952 0 0 0 10.434157371520996 1.2666676044464111 A 0.23727572367955174 0.23727572367955174 0 0 0 10.308351516723633 1.2677267789840698 A 0.25508653615813193 0.25508653615813193 0 0 0 10.170632362365723 1.3725240230560303 A 2.4153524646042914 2.4153524646042914 0 0 0 10.078984260559082 1.5262309312820435 A 0.4106600180595571 0.4106600180595571 0 0 1 9.9307947158813477 1.6878936290740967 A 0.29559283346620535 0.29559283346620535 0 0 1 10.037598609924316 1.6838692426681519 A 0.57248910422683186 0.57248910422683186 0 0 1 10.148921966552734 1.7105903625488281 A 9.5192552421924841 9.5192552421924841 0 0 0 10.273116111755371 1.7521740198135376 A 0.35410078894776231 0.35410078894776231 0 0 0 10.410141944885254 1.7732068300247192 A 0.23369519245039785 0.23369519245039785 0 0 0 10.595459938049316 1.6568219661712646 A 0.49394850529968143 0.49394850529968143 0 0 0 10.662936210632324 1.4882233142852783 A 0.51127790705274156 0.51127790705274156 0 0 1 10.815499305725098 1.3920822143554687 A 0.45779030726107039 0.45779030726107039 0 0 1 10.516712188720703 1.8532068729400635 A 1.1683111865822449 1.1683111865822449 0 0 0 10.264420509338379 1.9208512306213379 A 0.54008003917320924 0.54008003917320924 0 0 0 9.990290641784668 2.1280760765075684 A 0.43882617666944246 0.43882617666944246 0 0 0 9.9450979232788086 2.4815876483917236 A 4.6192383898761316 4.6192383898761316 0 0 0 10.038796424865723 2.7768585681915283 A 0.70664761244348018 0.70664761244348018 0 0 1 10.078004837036133 3.1630628108978271 A 0.57493429840429955 0.57493429840429955 0 0 1 10.199103355407715 3.0165705680847168 A 2.0237604697008469 2.0237604697008469 0 0 1 10.519057273864746 2.8138601779937744 A 0.72813998700546545 0.72813998700546545 0 0 0 10.740120887756348 2.6488585472106934 A 0.39838180286674818 0.39838180286674818 0 0 0 10.833741188049316 2.3150472640991211 A 0.81710735187117689 0.81710735187117689 0 0 0 10.685209274291992 1.9730880260467529 A 0.52740821033680052 0.52740821033680052 0 0 1 10.854381561279297 1.7755274772644043 A 3.9769230300718541 3.9769230300718541 0 0 0 10.992880821228027 2.3741037845611572 A 1.385154075109732 1.385154075109732 0 0 1 10.763846397399902 3.11527419090271 A 1.2167098172336015 1.2167098172336015 0 0 0 10.190132141113281 3.3382894992828369 A 0.54100384502745058 0.54100384502745058 0 0 0 9.9793376922607422 3.7091386318206787 A 0.87693216664228979 0.87693216664228979 0 0 0 10.032421112060547 4.073845386505127 A 20.877142108706462 20.877142108706462 0 0 0 10.106008529663086 4.2932949066162109 A 1.3070264547844079 1.3070264547844079 0 0 1 10.191728591918945 4.7167572975158691 A 0.56528821993922085 0.56528821993922085 0 0 1 9.8820266723632812 4.2535128593444824 L 9.8778457641601562 4.2535128593444824 A 0.56528802668965861 0.56528802668965861 0 0 1 9.5682392120361328 4.7167057991027832 A 1.3070264486466605 1.3070264486466605 0 0 1 9.6538639068603516 4.2932987213134766 A 20.877143086404814 20.877143086404814 0 0 0 9.727452278137207 4.0738458633422852 A 0.87693222674621296 0.87693222674621296 0 0 0 9.7805356979370117 3.7091388702392578 M 11.072675704956055 4.5534605979919434 A 1.064000619826571 1.064000619826571 0 0 1 10.695979118347168 4.7739109992980957 A 0.63789799630145394 0.63789799630145394 0 0 1 10.255148887634277 4.7471261024475098 A 1.2062183884505191 1.2062183884505191 0 0 1 10.613069534301758 4.4813952445983887 A 14.654286573177275 14.654286573177275 0 0 0 10.819470405578613 4.3637228012084961 A 1.1465230676633875 1.1465230676633875 0 0 0 11.016119003295898 4.2204594612121582 A 0.54696802895437291 0.54696802895437291 0 0 0 11.172513961791992 3.9642448425292969 A 0.57503111731212264 0.57503111731212264 0 0 0 11.161050796508789 3.6299772262573242 A 1.2823664702014874 1.2823664702014874 0 0 0 10.944883346557617 3.2211849689483643 A 1.2406465171443093 1.2406465171443093 0 0 1 11.14789867401123 2.7852609157562256 A 4.0510184976498307 4.0510184976498307 0 0 0 11.615120887756348 3.5781402587890625 A 3.9931948164878435 3.9931948164878435 0 0 0 11.072675704956055 4.5534605979919434 M 6.5542736053466797 1.1329443454742432 A 0.96202164341359087 0.96202164341359087 0 0 1 6.4686708450317383 0.96674996614456177 L 6.6931123733520508 0.96675008535385132 A 2.0326852734634469 2.0326852734634469 0 0 1 6.5542731285095215 1.1329444646835327 M 5.9661703109741211 1.1448348760604858 A 3.4116146586705001 3.4116146586705001 0 0 1 6.4925589561462402 1.1849268674850464 A 1.7732938697110574 1.7732938697110574 0 0 1 6.1516385078430176 1.4669536352157593 A 1.0622386054334785 1.0622386054334785 0 0 0 5.808772087097168 1.5902141332626343 A 1.7376845425330059 1.7376845425330059 0 0 1 5.7024345397949219 1.4138782024383545 A 0.36037689715811216 0.36037689715811216 0 0 0 5.6114010810852051 1.304845929145813 A 0.21670328936977085 0.21670328936977085 0 0 0 5.4351816177368164 1.2620906829833984 A 0.52156549300883748 0.52156549300883748 0 0 0 5.202242374420166 1.3771101236343384 A 0.37410945273306112 0.37410945273306112 0 0 1 5.0360164642333984 1.1986961364746094 A 3.295898776263579 3.295898776263579 0 0 0 5.0300393104553223 0.96675080060958862 L 5.281548023223877 0.96675008535385132 A 0.53686511988422791 0.53686511988422791 0 0 0 5.6525740623474121 1.1442794799804687 A 2.0256772748529834 2.0256772748529834 0 0 0 5.9661707878112793 1.1448346376419067 M 4.692436695098877 1.9657130241394043 L 4.692436695098877 0.96675008535385132 L 4.7792496681213379 0.96675008535385132 A 3.1647806105764289 3.1647806105764289 0 0 1 4.692436695098877 1.9657131433486938 M 5.3732714653015137 1.8675237894058228 A 0.47468428433327708 0.47468428433327708 0 0 1 5.0264406204223633 1.46031653881073 A 3.9604949985545574 3.9604949985545574 0 0 0 5.0306086540222168 1.3920822143554687 A 0.51634880886946766 0.51634880886946766 0 0 1 5.1831703186035156 1.4882233142852783 A 0.48127194799431983 0.48127194799431983 0 0 0 5.2488880157470703 1.6541109085083008 A 0.24489979303607617 0.24489979303607617 0 0 0 5.3853945732116699 1.7643637657165527 A 0.28347269894718313 0.28347269894718313 0 0 0 5.542119026184082 1.7610547542572021 A 1.8093866256771556 1.8093866256771556 0 0 0 5.6516242027282715 1.7258572578430176 A 0.61227881037250531 0.61227881037250531 0 0 0 5.6006293296813965 1.7972464561462402 A 0.80252775940607579 0.80252775940607579 0 0 0 5.5689153671264648 1.8537275791168213 A 0.69920461009139645 0.69920461009139645 0 0 0 5.5449709892272949 1.9004660844802856 A 1.0983379482641877 1.0983379482641877 0 0 0 5.3732714653015137 1.8675236701965332 M 4.6924371719360352 2.8340084552764893 A 1.5750156045527177 1.5750156045527177 0 0 1 4.8595333099365234 3.0653300285339355 A 1.7237387767990988 1.7237387767990988 0 0 0 4.6924371719360352 3.3095672130584717 L 4.692436695098877 2.8340079784393311 M 11.402124404907227 2.2932093143463135 A 0.58584089901987701 0.58584089901987701 0 0 0 11.716293334960938 2.4283797740936279 A 2.3971708719605074 2.3971708719605074 0 0 0 12.079375267028809 2.4341573715209961 A 3.3291637812302577 3.3291637812302577 0 0 1 12.29078483581543 2.432750940322876 A 0.61166656839138633 0.61166656839138633 0 0 1 12.109477043151855 2.5204994678497314 A 0.59927613737804175 0.59927613737804175 0 0 0 11.899999618530273 2.5012998580932617 A 0.29596881021077104 0.29596881021077104 0 0 0 11.769671440124512 2.5432922840118408 A 0.23203673265944877 0.23203673265944877 0 0 0 11.666668891906738 2.697350025177002 A 0.8538224185831309 0.8538224185831309 0 0 0 11.652617454528809 2.8351030349731445 A 0.71884047322651723 0.71884047322651723 0 0 1 11.625530242919922 3.0379071235656738 A 3.2962227068974825 3.2962227068974825 0 0 1 11.05519962310791 1.2075074911117554 A 0.51334649678282895 0.51334649678282895 0 0 1 11.210971832275391 1.4293495416641235 A 1.3368626970440718 1.3368626970440718 0 0 0 11.215561866760254 1.9579989910125732 A 0.60412137580959269 0.60412137580959269 0 0 0 11.402124404907227 2.2932090759277344 M 11.08558464050293 0.96675008535385132 L 11.338702201843262 0.96675008535385132 A 0.59932725012440557 0.59932725012440557 0 0 1 11.335972785949707 1.2525743246078491 A 0.56584462310676575 0.56584462310676575 0 0 1 11.443924903869629 1.1285834312438965 A 1.1941932772263795 1.1941932772263795 0 0 1 11.710570335388184 0.96675002574920654 L 11.896651268005371 0.96675008535385132 A 0.40175974456275254 0.40175974456275254 0 0 0 11.915377616882324 1.1339828968048096 A 0.24345152878008897 0.24345152878008897 0 0 0 12.019766807556152 1.2606018781661987 A 0.67649261940572469 0.67649261940572469 0 0 0 11.818281173706055 1.2290645837783813 A 1.0651430689712298 1.0651430689712298 0 0 0 11.62716007232666 1.2432695627212524 A 1.405556835037912 1.405556835037912 0 0 0 11.309347152709961 1.3343850374221802 A 0.69243745358098574 0.69243745358098574 0 0 1 11.08558464050293 0.96674990653991699 M 7.3709444999694824 1.6737812757492065 A 6.9899221181451434 6.9899221181451434 0 0 0 7.2567315101623535 2.15043044090271 A 4.3324701493437505 4.3324701493437505 0 0 1 7.1294898986816406 1.564794659614563 A 2.349588968241799 2.349588968241799 0 0 1 7.1190605163574219 0.96674966812133789 L 7.3055639266967773 0.96675008535385132 A 4.3890679462262492 4.3890679462262492 0 0 0 7.2896361351013184 1.1565424203872681 A 0.67150166414209222 0.67150166414209222 0 0 1 7.2743077278137207 1.292087197303772 A 0.72008503519516864 0.72008503519516864 0 0 1 7.2187070846557617 1.4463584423065186 A 0.16741793416736689 0.16741793416736689 0 0 1 7.2966089248657227 1.3698341846466064 A 0.66941766435053163 0.66941766435053163 0 0 1 7.4220213890075684 1.3352556228637695 A 2.2203508708685096 2.2203508708685096 0 0 1 7.54132080078125 1.3176378011703491 A 0.85566085323903085 0.85566085323903085 0 0 0 7.6599416732788086 1.2949619293212891 A 0.59774050058816741 0.59774050058816741 0 0 0 7.3709440231323242 1.6737817525863647 M 8.7046728134155273 1.2075086832046509 A 3.2962222817613869 3.2962222817613869 0 0 1 8.134343147277832 3.0379073619842529 A 0.71884049967860852 0.71884049967860852 0 0 1 8.1072568893432617 2.8351032733917236 A 0.85382254448059869 0.85382254448059869 0 0 0 8.0932044982910156 2.6973502635955811 A 0.23203674774751698 0.23203674774751698 0 0 0 7.990201473236084 2.5432922840118408 A 0.29596862558063775 0.29596862558063775 0 0 0 7.8598732948303223 2.5012998580932617 A 0.59927607686494189 0.59927607686494189 0 0 0 7.6503968238830566 2.5204997062683105 A 0.61166690283416103 0.61166690283416103 0 0 1 7.469088077545166 2.4327507019042969 A 3.3291637723866745 3.3291637723866745 0 0 1 7.6804990768432617 2.4341573715209961 A 2.3971709380822297 2.3971709380822297 0 0 0 8.0435800552368164 2.428380012512207 A 0.58584074322524393 0.58584074322524393 0 0 0 8.3577489852905273 2.2932093143463135 A 0.60412191958372952 0.60412191958372952 0 0 0 8.5443115234375 1.9579992294311523 A 1.3368626673357373 1.3368626673357373 0 0 0 8.5489015579223633 1.4293495416641235 A 0.5133461512100852 0.5133461512100852 0 0 1 8.7046737670898437 1.2075085639953613 M 8.6742887496948242 0.96675002574920654 A 0.69243742988709067 0.69243742988709067 0 0 1 8.450526237487793 1.3343850374221802 A 1.4055563907381226 1.4055563907381226 0 0 0 8.1327142715454102 1.2432698011398315 A 1.0651431091443622 1.0651431091443622 0 0 0 7.9415936470031738 1.2290645837783813 A 0.67649257382117334 0.67649257382117334 0 0 0 7.7401018142700195 1.2606037855148315 A 0.24345111188353399 0.24345111188353399 0 0 0 7.8444957733154297 1.1339828968048096 A 0.40175972076643923 0.40175972076643923 0 0 0 7.8632221221923828 0.96675008535385132 L 8.0493030548095703 0.96675008535385132 A 1.1941930643451006 1.1941930643451006 0 0 1 8.315948486328125 1.1285836696624756 A 0.56584448407889176 0.56584448407889176 0 0 1 8.4239015579223633 1.2525743246078491 A 0.59932724278955019 0.59932724278955019 0 0 1 8.4211711883544922 0.96674990653991699 L 8.6742887496948242 0.96675008535385132 M 7.9089345932006836 3.3323273658752441 A 3.1748659678124214 3.1748659678124214 0 0 1 7.3830418586730957 2.4930038452148437 A 0.45874428479429563 0.45874428479429563 0 0 1 7.6093320846557617 2.5929620265960693 A 0.49173407435393951 0.49173407435393951 0 0 0 7.5900373458862305 2.7787587642669678 A 0.26256388160486294 0.26256388160486294 0 0 0 7.628899097442627 2.901280403137207 A 0.24943850529571401 0.24943850529571401 0 0 0 7.7926554679870605 3.0075924396514893 A 1.8139889174294788 1.8139889174294788 0 0 0 7.9409494400024414 3.0310423374176025 A 0.55151940476725136 0.55151940476725136 0 0 1 8.1095676422119141 3.0738320350646973 A 3.2962221487710432 3.2962221487710432 0 0 1 7.9089350700378418 3.3323278427124023 M 7.214935302734375 2.9371557235717773 A 0.20527229483548698 0.20527229483548698 0 0 1 7.2743616104125977 2.8726034164428711 A 2.8921097098393846 2.8921097098393846 0 0 0 7.4241414070129395 3.1594488620758057 A 0.58536583113064156 0.58536583113064156 0 0 1 7.0941348075866699 3.4821703433990479 A 0.98371507668937208 0.98371507668937208 0 0 0 6.9390230178833008 3.4606368541717529 A 0.49091829746282573 0.49091829746282573 0 0 0 7.1053609848022461 3.279076099395752 A 0.99613933960839773 0.99613933960839773 0 0 0 7.2149357795715332 2.9371554851531982 M 12.099931716918945 1.2949618101119995 A 0.85566084504121998 0.85566084504121998 0 0 0 12.218552589416504 1.31763756275177 A 2.2203509989916652 2.2203509989916652 0 0 1 12.33785343170166 1.3352558612823486 A 0.66941752910666086 0.66941752910666086 0 0 1 12.463264465332031 1.3698341846466064 A 0.16741847720116487 0.16741847720116487 0 0 1 12.541166305541992 1.4463584423065186 A 0.72008495443007636 0.72008495443007636 0 0 1 12.485565185546875 1.2920870780944824 A 0.67150163392488438 0.67150163392488438 0 0 1 12.47023868560791 1.1565423011779785 A 4.3890679945943312 4.3890679945943312 0 0 0 12.454309463500977 0.96675044298171997 L 12.640812873840332 0.96675008535385132 A 2.349588916949974 2.349588916949974 0 0 1 12.630382537841797 1.5647950172424316 A 4.332469564362027 4.332469564362027 0 0 1 12.503142356872559 2.1504325866699219 A 6.9899226067052957 6.9899226067052957 0 0 0 12.388930320739746 1.6737830638885498 A 0.59773998674621587 0.59773998674621587 0 0 0 12.099932670593262 1.2949620485305786 M 15.06744384765625 1.9657126665115356 A 3.1647805525174393 3.1647805525174393 0 0 1 14.980623245239258 0.96675044298171997 L 15.067437171936035 0.96675008535385132 L 15.06744384765625 1.9657130241394043 M 13.608234405517578 1.4669533967971802 A 1.773293549031149 1.773293549031149 0 0 1 13.267313003540039 1.1849265098571777 A 3.4116146881421932 3.4116146881421932 0 0 1 13.793704032897949 1.1448348760604858 A 2.0256772826379912 2.0256772826379912 0 0 0 14.107298851013184 1.1442794799804687 A 0.53686504885259734 0.53686504885259734 0 0 0 14.478324890136719 0.96675002574920654 L 14.72983455657959 0.96675008535385132 A 3.2958984238532958 3.2958984238532958 0 0 0 14.723855972290039 1.1986955404281616 A 0.37410895309314401 0.37410895309314401 0 0 1 14.557631492614746 1.3771102428436279 A 0.52156545821629985 0.52156545821629985 0 0 0 14.324691772460937 1.262090802192688 A 0.21670326396767833 0.21670326396767833 0 0 0 14.148472785949707 1.3048458099365234 A 0.36037627788594112 0.36037627788594112 0 0 0 14.057438850402832 1.4138782024383545 A 1.7376841938825525 1.7376841938825525 0 0 1 13.951101303100586 1.5902143716812134 A 1.0622385369383616 1.0622385369383616 0 0 0 13.608235359191895 1.4669536352157593 M 13.205599784851074 1.1329442262649536 A 2.0326855415034726 2.0326855415034726 0 0 1 13.066761016845703 0.96674978733062744 L 13.29121208190918 0.96675008535385132 A 0.96202194194389934 0.96202194194389934 0 0 1 13.205599784851074 1.1329445838928223 M 12.150541305541992 2.5929620265960693 A 0.45874418367530467 0.45874418367530467 0 0 1 12.3768310546875 2.493004322052002 A 3.1748661182590734 3.1748661182590734 0 0 1 11.85093879699707 3.3323278427124023 A 3.2962220181394817 3.2962220181394817 0 0 1 11.650306701660156 3.07383131980896 A 0.55151933884774373 0.55151933884774373 0 0 1 11.818924903869629 3.0310423374176025 A 1.8139887959240757 1.8139887959240757 0 0 0 11.967218399047852 3.0075924396514893 A 0.24943834235285559 0.24943834235285559 0 0 0 12.130973815917969 2.901280403137207 A 0.26256387526040759 0.26256387526040759 0 0 0 12.169836044311523 2.7787590026855469 A 0.49173404514148616 0.49173404514148616 0 0 0 12.150543212890625 2.5929605960845947 M 12.48554515838623 2.8726034164428711 A 0.20527191017892868 0.20527191017892868 0 0 1 12.544971466064453 2.9371557235717773 A 0.99613946816950394 0.99613946816950394 0 0 0 12.654545783996582 3.279076099395752 A 0.49091826997167892 0.49091826997167892 0 0 0 12.820882797241211 3.4606366157531738 A 0.98371522175414916 0.98371522175414916 0 0 0 12.665771484375 3.4821701049804687 A 0.58536610968366476 0.58536610968366476 0 0 1 12.33576488494873 3.1594488620758057 A 2.8921091277183963 2.8921091277183963 0 0 0 12.48554515838623 2.872603178024292 M 14.374478340148926 1.7643637657165527 A 0.24489939138869368 0.24489939138869368 0 0 0 14.510985374450684 1.6541110277175903 A 0.48127171394716933 0.48127171394716933 0 0 0 14.576703071594238 1.4882233142852783 A 0.51634916916025553 0.51634916916025553 0 0 1 14.729264259338379 1.3920820951461792 A 3.9604957691617941 3.9604957691617941 0 0 0 14.733433723449707 1.460315465927124 A 0.47468430109565013 0.47468430109565013 0 0 1 14.386601448059082 1.8675237894058228 A 1.0983378099846473 1.0983378099846473 0 0 0 14.214902877807617 1.9004659652709961 A 0.69920472121685595 0.69920472121685595 0 0 0 14.190958023071289 1.8537279367446899 A 0.8025285415139094 0.8025285415139094 0 0 0 14.159244537353516 1.7972466945648193 A 0.61227892933069006 0.61227892933069006 0 0 0 14.108248710632324 1.7258573770523071 A 1.8093866935876648 1.8093866935876648 0 0 0 14.217753410339355 1.7610547542572021 A 0.28347274674566852 0.28347274674566852 0 0 0 14.374478340148926 1.7643637657165527 M 15.067437171936035 2.8340079784393311 L 15.067437171936035 3.3095674514770508 A 1.7237387423311847 1.7237387423311847 0 0 0 14.90034008026123 3.0653300285339355 A 1.5750156637310557 1.5750156637310557 0 0 1 15.067438125610352 2.8340075016021729 M 6.4925594329833984 10.758732795715332 A 1.7732944335750651 1.7732944335750651 0 0 1 6.1516385078430176 11.040759086608887 A 1.0622380587463944 1.0622380587463944 0 0 0 5.808772087097168 11.164020538330078 A 1.7376845835970316 1.7376845835970316 0 0 1 5.7024345397949219 10.98768424987793 A 0.36037717596901064 0.36037717596901064 0 0 0 5.6114010810852051 10.87865161895752 A 0.21670340635100477 0.21670340635100477 0 0 0 5.4351816177368164 10.835896492004395 A 0.5215656845088017 0.5215656845088017 0 0 0 5.202242374420166 10.950915336608887 A 0.37410896839468855 0.37410896839468855 0 0 1 5.0360164642333984 10.772501945495605 A 3.864262366129616 3.864262366129616 0 0 0 4.9013676643371582 9.734501838684082 A 0.64312401730293844 0.64312401730293844 0 0 1 5.1099338531494141 9.8335351943969727 A 1.1442962311836598 1.1442962311836598 0 0 0 5.1760659217834473 10.372074127197266 A 0.54358674086618097 0.54358674086618097 0 0 0 5.6525740623474121 10.718085289001465 A 2.0256769309523177 2.0256769309523177 0 0 0 5.9661707878112793 10.718640327453613 A 3.4116150510996182 3.4116150510996182 0 0 1 6.4925589561462402 10.758732795715332 M 6.5909953117370605 10.294003486633301 A 2.0748369897536594 2.0748369897536594 0 0 1 6.8254337310791016 10.336627960205078 A 1.8687783728155221 1.8687783728155221 0 0 1 6.5542736053466797 10.70674991607666 A 0.96202166581702897 0.96202166581702897 0 0 1 6.4564547538757324 10.508131980895996 A 3.464581080443569 3.464581080443569 0 0 1 6.3724784851074219 10.207461357116699 A 0.26619938780279995 0.26619938780279995 0 0 0 6.4707627296447754 10.26451587677002 A 0.6338784195759285 0.6338784195759285 0 0 0 6.5909943580627441 10.294002532958984 M 6.4829559326171875 9.7098217010498047 A 2.787801220116072 2.787801220116072 0 0 0 6.6352558135986328 9.5805997848510742 A 0.38170282775879122 0.38170282775879122 0 0 1 6.8106346130371094 9.4897060394287109 A 0.32613939449961249 0.32613939449961249 0 0 1 6.6923904418945313 9.4510097503662109 A 0.70656303794125619 0.70656303794125619 0 0 1 6.5804076194763184 9.3716316223144531 A 0.72776927356579091 0.72776927356579091 0 0 0 6.4552278518676758 9.2817649841308594 A 0.29034118070161757 0.29034118070161757 0 0 0 6.3875770568847656 9.2585763931274414 A 3.2999640042846492 3.2999640042846492 0 0 0 6.7549276351928711 9.2574453353881836 A 0.67532235527591378 0.67532235527591378 0 0 0 6.9577465057373047 9.2077178955078125 A 0.52374385211750774 0.52374385211750774 0 0 0 7.1804637908935547 9.0292949676513672 A 0.69043650390930889 0.69043650390930889 0 0 0 7.2914867401123047 8.759063720703125 A 1.2161340023153915 1.2161340023153915 0 0 0 7.3143963813781738 8.4740056991577148 A 1.5840411846795552 1.5840411846795552 0 0 0 7.3025846481323242 8.3273563385009766 A 0.41292533831786371 0.41292533831786371 0 0 1 7.4842829704284668 8.047459602355957 A 5.001294465455584 5.001294465455584 0 0 0 7.7016925811767578 8.3650979995727539 A 4.0573299858235234 4.0573299858235234 0 0 0 6.9576945304870605 10.06600284576416 A 2.032688990880771 2.032688990880771 0 0 1 6.8966689109802246 10.205625534057617 A 36.7880664157789 36.7880664157789 0 0 1 6.8816580772399902 9.9906959533691406 A 0.26831729315193981 0.26831729315193981 0 0 0 6.8182668685913086 9.8121652603149414 A 0.27536862701577847 0.27536862701577847 0 0 0 6.6497197151184082 9.7154159545898437 A 0.51140992824604325 0.51140992824604325 0 0 0 6.4829564094543457 9.7098217010498047 M 6.5279903411865234 7.3447837829589844 A 0.54856228477165303 0.54856228477165303 0 0 0 6.7049107551574707 7.0926480293273926 A 0.59743451756335431 0.59743451756335431 0 0 0 6.7180881500244141 6.7735447883605957 A 1.2357223139638918 1.2357223139638918 0 0 0 6.5310831069946289 6.3322582244873047 A 0.96926039745043535 0.96926039745043535 0 0 1 6.9019994735717773 5.7889690399169922 A 3.9279671558470839 3.9279671558470839 0 0 0 7.2081108093261719 7.511049747467041 A 0.056723197749454599 0.056723197749454599 0 0 1 7.1285696029663086 7.5688567161560059 A 1.1666825734805202 1.1666825734805202 0 0 0 6.9998617172241211 7.4865984916687012 A 0.70401703806129667 0.70401703806129667 0 0 0 6.6879668235778809 7.3954777717590332 A 0.41688578230639406 0.41688578230639406 0 0 0 6.5192608833312988 7.4314064979553223 A 0.4357030362993064 0.4357030362993064 0 0 0 6.421877384185791 7.4949302673339844 A 0.76356941861995242 0.76356941861995242 0 0 0 6.2683696746826172 7.6991114616394043 L 6.1702933311462402 7.8762884140014648 A 1.2389301577597043 1.2389301577597043 0 0 1 6.0595622062683105 8.0406379699707031 A 0.56969330500902438 0.56969330500902438 0 0 1 5.9121427536010742 8.1663579940795898 A 0.52845880569815651 0.52845880569815651 0 0 1 6.0322251319885254 8.1524238586425781 A 0.61573605068395454 0.61573605068395454 0 0 1 6.1054372787475586 8.1568136215209961 A 1.1476191441306376 1.1476191441306376 0 0 1 6.289769172668457 8.1981525421142578 A 0.56477611206062805 0.56477611206062805 0 0 0 6.1784863471984863 8.3414487838745117 A 1.1947101171087178 1.1947101171087178 0 0 0 6.0877351760864258 8.5808305740356445 A 6.6246031963530241 6.6246031963530241 0 0 1 5.9866743087768555 9.0164155960083008 A 0.80653075398738694 0.80653075398738694 0 0 1 5.8003215789794922 9.3591785430908203 A 0.69519752263871304 0.69519752263871304 0 0 1 6.0118222236633301 9.280364990234375 A 1.2436349877124659 1.2436349877124659 0 0 1 6.2553200721740723 9.2573041915893555 A 0.32695794610571161 0.32695794610571161 0 0 0 6.128150463104248 9.3434696197509766 A 0.53376078819213724 0.53376078819213724 0 0 0 6.0551505088806152 9.4390869140625 A 0.34248239105436284 0.34248239105436284 0 0 1 5.9193058013916016 9.4192771911621094 A 1.896215422268684 1.896215422268684 0 0 0 5.6730446815490723 9.3372573852539062 A 1.8851188325074844 1.8851188325074844 0 0 1 5.7118091583251953 9.1843700408935547 A 12.102788413946163 12.102788413946163 0 0 0 5.8615427017211914 8.714451789855957 A 0.77291166900909936 0.77291166900909936 0 0 0 5.8821687698364258 8.4003658294677734 A 0.61902938095659765 0.61902938095659765 0 0 0 5.6214761734008789 7.9981522560119629 A 1.3901215305450521 1.3901215305450521 0 0 0 5.1240634918212891 7.7965235710144043 A 1.6031741933527488 1.6031741933527488 0 0 0 5.0089058876037598 7.777379035949707 A 1.4834470947401759 1.4834470947401759 0 0 1 4.8758978843688965 7.3971080780029297 A 1.4678459702983859 1.4678459702983859 0 0 1 4.8533411026000977 7.1606450080871582 A 3.9604951476730288 3.9604951476730288 0 0 0 4.9917254447937012 6.5624303817749023 A 0.55379216512418983 0.55379216512418983 0 0 1 5.1944174766540527 6.8411283493041992 A 0.76941146429846885 0.76941146429846885 0 0 0 5.0906448364257812 7.0993480682373047 A 0.4164850685390396 0.4164850685390396 0 0 0 5.2717723846435547 7.5362563133239746 A 2.6635669373143491 2.6635669373143491 0 0 0 5.519075870513916 7.684967041015625 A 3.9054259127260775 3.9054259127260775 0 0 1 5.5250716209411621 7.6883926391601562 A 1.4576602174193971 1.4576602174193971 0 0 1 5.6528472900390625 7.7687139511108398 A 0.65686074739109024 0.65686074739109024 0 0 1 5.6225476264953613 7.9117827415466309 A 0.65237357843024946 0.65237357843024946 0 0 1 5.7085189819335938 7.8096089363098145 A 0.5588812529681445 0.5588812529681445 0 0 1 5.8428888320922852 7.9679784774780273 A 0.59573022302013079 0.59573022302013079 0 0 1 5.8492217063903809 7.7004756927490234 A 5.1990781417701148 5.1990781417701148 0 0 1 6.3339447975158691 7.4644045829772949 A 1.0050696264048093 1.0050696264048093 0 0 0 6.5279903411865234 7.3447842597961426 M 6.5542736053466797 5.9198470115661621 A 0.96202137669659671 0.96202137669659671 0 0 1 6.4564547538757324 5.7212285995483398 A 3.4645819021419082 3.4645819021419082 0 0 1 6.3724784851074219 5.4205589294433594 A 0.26619938780279995 0.26619938780279995 0 0 0 6.4707627296447754 5.4776134490966797 A 0.63387855250777525 0.63387855250777525 0 0 0 6.5909943580627441 5.5070996284484863 A 2.07483704151274 2.07483704151274 0 0 1 6.8254337310791016 5.5497250556945801 A 1.8687784133264165 1.8687784133264165 0 0 1 6.5542736053466797 5.9198474884033203 M 6.4925594329833984 5.9718294143676758 A 1.7732938466554176 1.7732938466554176 0 0 1 6.1516385078430176 6.2538566589355469 A 1.0622387090353678 1.0622387090353678 0 0 0 5.808772087097168 6.3771166801452637 A 1.7376844250451027 1.7376844250451027 0 0 1 5.7024345397949219 6.2007808685302734 A 0.36037680422117696 0.36037680422117696 0 0 0 5.6114010810852051 6.0917487144470215 A 0.21670340635100477 0.21670340635100477 0 0 0 5.4351816177368164 6.0489935874938965 A 0.52156558338536907 0.52156558338536907 0 0 0 5.202242374420166 6.1640129089355469 A 0.3741092591356911 0.3741092591356911 0 0 1 5.0360164642333984 5.9855985641479492 A 3.8642621360242435 3.8642621360242435 0 0 0 4.9013676643371582 4.9475994110107422 A 0.64312406428296176 0.64312406428296176 0 0 1 5.1099338531494141 5.0466318130493164 A 1.1442960625149627 1.1442960625149627 0 0 0 5.1760659217834473 5.5851702690124512 A 0.54358676738308997 0.54358676738308997 0 0 0 5.6525740623474121 5.9311823844909668 A 2.0256771686878574 2.0256771686878574 0 0 0 5.9661707878112793 5.9317374229431152 A 3.4116145408622338 3.4116145408622338 0 0 1 6.4925589561462402 5.9718294143676758 M 5.3732714653015137 6.6544265747070312 A 0.47468428433327708 0.47468428433327708 0 0 1 5.0264406204223633 6.2472190856933594 A 3.9604949985545574 3.9604949985545574 0 0 0 5.0306086540222168 6.1789851188659668 A 0.51634884093347821 0.51634884093347821 0 0 1 5.1831703186035156 6.2751259803771973 A 0.48127188430481904 0.48127188430481904 0 0 0 5.2488880157470703 6.4410138130187988 A 0.24489967961902975 0.24489967961902975 0 0 0 5.3853945732116699 6.5512666702270508 A 0.28347255745937605 0.28347255745937605 0 0 0 5.542119026184082 6.5479574203491211 A 1.809386654515134 1.809386654515134 0 0 0 5.6516242027282715 6.5127601623535156 A 0.61227862950258494 0.61227862950258494 0 0 0 5.6006293296813965 6.5841493606567383 A 0.8025279677756938 0.8025279677756938 0 0 0 5.5689153671264648 6.6406307220458984 A 0.69920464857734543 0.69920464857734543 0 0 0 5.5449709892272949 6.6873693466186523 A 1.0983376067010477 1.0983376067010477 0 0 0 5.3732714653015137 6.6544270515441895 M 4.692436695098877 6.7652020454406738 L 4.692436695098877 6.1000785827636719 A 0.5451479353072981 0.5451479353072981 0 0 1 4.7893600463867187 5.9944114685058594 A 3.3042862778864297 3.3042862778864297 0 0 1 4.692436695098877 6.7652020454406738 M 6.1887578964233398 4.934654712677002 A 0.23841587038599535 0.23841587038599535 0 0 0 6.3351173400878906 4.9795374870300293 A 0.67549969093626394 0.67549969093626394 0 0 0 6.2946586608886719 5.1249175071716309 A 0.61783308429773143 0.61783308429773143 0 0 0 6.1887578964233398 4.9346551895141602 M 5.3435201644897461 4.7966775894165039 A 0.32507404653760275 0.32507404653760275 0 0 1 5.1925678253173828 4.8343305587768555 A 0.30573158849962079 0.30573158849962079 0 0 1 5.0450143814086914 4.7849149703979492 A 1.6262430309260043 1.6262430309260043 0 0 1 4.7910375595092773 4.6002488136291504 A 1.9484225017041013 1.9484225017041013 0 0 1 5.3426599502563477 4.5647149085998535 A 1.0433747940151117 1.0433747940151117 0 0 1 5.5669803619384766 4.7411689758300781 A 0.54887019588336872 0.54887019588336872 0 0 0 5.3435201644897461 4.7966771125793457 M 5.1232867240905762 4.4558501243591309 A 1.2902523297602353 1.2902523297602353 0 0 0 5.0180668830871582 4.4557895660400391 A 1.3946353033935242 1.3946353033935242 0 0 0 4.9163179397583008 4.4634723663330078 A 0.6657399767401746 0.6657399767401746 0 0 1 4.823056697845459 4.4681816101074219 A 0.11306257688105872 0.11306257688105872 0 0 1 4.719151496887207 4.4193077087402344 A 3.9604954814120004 3.9604954814120004 0 0 0 4.692436695098877 4.3580398559570312 L 4.692436695098877 4.148646354675293 A 0.82690088686504248 0.82690088686504248 0 0 0 4.8530588150024414 4.2930340766906738 A 2.7345284445758109 2.7345284445758109 0 0 0 5.1232872009277344 4.4558477401733398 M 5.661674976348877 4.6167125701904297 A 2.12785406427321 2.12785406427321 0 0 1 6.0237627029418945 4.7463951110839844 A 0.6228623255121446 0.6228623255121446 0 0 0 6.0777630805969238 4.8274312019348145 A 0.56156472834872251 0.56156472834872251 0 0 0 5.8746547698974609 4.7422771453857422 A 0.79932925215639627 0.79932925215639627 0 0 0 5.6538724899291992 4.7308268547058105 A 0.76356839670086596 0.76356839670086596 0 0 1 5.6616740226745605 4.6167120933532715 M 4.692436695098877 5.9298601150512695 L 4.692436695098877 5.1776518821716309 A 3.3109846286708806 3.3109846286708806 0 0 1 4.7737751007080078 5.6504526138305664 A 0.65195133500315028 0.65195133500315028 0 0 1 4.692436695098877 5.9298596382141113 M 4.692436695098877 8.096470832824707 L 4.692436695098877 7.62091064453125 A 1.5750160983904138 1.5750160983904138 0 0 1 4.8595333099365234 7.8522329330444336 A 1.7237390747702577 1.7237390747702577 0 0 0 4.6924371719360352 8.0964698791503906 M 4.692436695098877 9.9645547866821289 A 3.3449507567954115 3.3449507567954115 0 0 1 4.692436695098877 11.539519309997559 L 4.692436695098877 9.9645547866821289 M 5.3732714653015137 11.441329956054688 A 0.47468428433327708 0.47468428433327708 0 0 1 5.0264406204223633 11.034122467041016 A 3.9604950235220899 3.9604950235220899 0 0 0 5.0306086540222168 10.965888023376465 A 0.51634848810793621 0.51634848810793621 0 0 1 5.1831703186035156 11.062028884887695 A 0.48127213906294875 0.48127213906294875 0 0 0 5.2488880157470703 11.227916717529297 A 0.24489998645857489 0.24489998645857489 0 0 0 5.3853945732116699 11.338169097900391 A 0.28347284043572174 0.28347284043572174 0 0 0 5.542119026184082 11.334860801696777 A 1.8093864959486532 1.8093864959486532 0 0 0 5.6516242027282715 11.299662590026855 A 0.61227881037250531 0.61227881037250531 0 0 0 5.6006293296813965 11.371052742004395 A 0.80252775128592901 0.80252775128592901 0 0 0 5.5689153671264648 11.427533149719238 A 0.69920455976025087 0.69920455976025087 0 0 0 5.5449709892272949 11.474271774291992 A 1.0983384467045567 1.0983384467045567 0 0 0 5.3732714653015137 11.441329002380371 M 5.3435201644897461 9.5835800170898437 A 0.32507356970232382 0.32507356970232382 0 0 1 5.1925678253173828 9.6212329864501953 A 0.30573158849962079 0.30573158849962079 0 0 1 5.0450143814086914 9.5718173980712891 A 1.6262428525296095 1.6262428525296095 0 0 1 4.7910375595092773 9.3871517181396484 A 1.9484225017041013 1.9484225017041013 0 0 1 5.3426599502563477 9.3516178131103516 A 1.0433745125128424 1.0433745125128424 0 0 1 5.5669803619384766 9.5280723571777344 A 0.54886956749289273 0.54886956749289273 0 0 0 5.3435201644897461 9.5835800170898437 M 4.692436695098877 9.1449441909790039 L 4.692436695098877 8.9355497360229492 A 0.82690054400180546 0.82690054400180546 0 0 0 4.8530588150024414 9.0799369812011719 A 2.7345283666134241 2.7345283666134241 0 0 0 5.1232872009277344 9.2427501678466797 A 1.2902525597983419 1.2902525597983419 0 0 0 5.0180668830871582 9.2426919937133789 A 1.3946353033935242 1.3946353033935242 0 0 0 4.9163179397583008 9.2503747940063477 A 0.6657399767401746 0.6657399767401746 0 0 1 4.823056697845459 9.2550840377807617 A 0.11306270218302987 0.11306270218302987 0 0 1 4.719151496887207 9.2062101364135742 A 3.9604952918179963 3.9604952918179963 0 0 0 4.692436695098877 9.1449432373046875 M 5.661674976348877 9.4036149978637695 A 2.12785406427321 2.12785406427321 0 0 1 6.0237627029418945 9.5332975387573242 A 0.6228623255121446 0.6228623255121446 0 0 0 6.0777630805969238 9.6143341064453125 A 0.56156519571641383 0.56156519571641383 0 0 0 5.8746547698974609 9.529179573059082 A 0.79932906687821637 0.79932906687821637 0 0 0 5.6538724899291992 9.5177297592163086 A 0.763568328633486 0.763568328633486 0 0 1 5.6616740226745605 9.4036149978637695 M 6.1887578964233398 9.7215576171875 A 0.23841587038599535 0.23841587038599535 0 0 0 6.3351173400878906 9.7664403915405273 A 0.67549961520497082 0.67549961520497082 0 0 0 6.2946586608886719 9.9118194580078125 A 0.61783308429773143 0.61783308429773143 0 0 0 6.1887578964233398 9.7215576171875 M 4.6924371719360352 12.407814025878906 A 1.5750159466668752 1.5750159466668752 0 0 1 4.8595333099365234 12.63913631439209 A 1.7237390747702577 1.7237390747702577 0 0 0 4.6924371719360352 12.883373260498047 L 4.692436695098877 12.407814025878906 M 12.05817985534668 8.3650989532470703 A 5.0012935465107686 5.0012935465107686 0 0 0 12.275589942932129 8.0474586486816406 A 0.41292610496268506 0.41292610496268506 0 0 1 12.457289695739746 8.3273563385009766 A 1.5840415392400218 1.5840415392400218 0 0 0 12.445477485656738 8.4740056991577148 A 1.2161340319413845 1.2161340319413845 0 0 0 12.468386650085449 8.759063720703125 A 0.69043704023018126 0.69043704023018126 0 0 0 12.579408645629883 9.0292940139770508 A 0.52374393462830671 0.52374393462830671 0 0 0 12.802125930786133 9.2077178955078125 A 0.67532244673346109 0.67532244673346109 0 0 0 13.004944801330566 9.2574453353881836 A 3.2999640486003994 3.2999640486003994 0 0 0 13.372296333312988 9.2585763931274414 A 0.29034097125454122 0.29034097125454122 0 0 0 13.304646492004395 9.2817649841308594 A 0.72776921200796818 0.72776921200796818 0 0 0 13.179466247558594 9.3716325759887695 A 0.70656314743644222 0.70656314743644222 0 0 1 13.067482948303223 9.4510087966918945 A 0.32613861859730486 0.32613861859730486 0 0 1 12.949239730834961 9.4897060394287109 A 0.3817028060923307 0.3817028060923307 0 0 1 13.124617576599121 9.5805997848510742 A 2.7878015192694341 2.7878015192694341 0 0 0 13.276917457580566 9.7098217010498047 A 0.51140986946259392 0.51140986946259392 0 0 0 13.110154151916504 9.7154159545898437 A 0.27536830323417372 0.27536830323417372 0 0 0 12.941606521606445 9.8121652603149414 A 0.26831757675822954 0.26831757675822954 0 0 0 12.878212928771973 9.9907073974609375 A 36.788066437516811 36.788066437516811 0 0 1 12.863204956054688 10.205624580383301 A 2.032688607037842 2.032688607037842 0 0 1 12.802179336547852 10.066003799438477 A 4.0573295969519663 4.0573295969519663 0 0 0 12.058181762695313 8.3651008605957031 M 13.773199081420898 9.0164146423339844 A 6.6246039918087849 6.6246039918087849 0 0 1 13.672139167785645 8.5808305740356445 A 1.1947096797064443 1.1947096797064443 0 0 0 13.581386566162109 8.3414497375488281 A 0.56477618596985546 0.56477618596985546 0 0 0 13.470104217529297 8.1981525421142578 A 1.1476198074164983 1.1476198074164983 0 0 1 13.654437065124512 8.1568136215209961 A 0.61573603463320636 0.61573603463320636 0 0 1 13.727648735046387 8.1524238586425781 A 0.52845877751861747 0.52845877751861747 0 0 1 13.84773063659668 8.1663579940795898 A 0.56969351999717188 0.56969351999717188 0 0 1 13.700310707092285 8.0406379699707031 A 1.2389306684418586 1.2389306684418586 0 0 1 13.589582443237305 7.8762936592102051 L 13.491503715515137 7.6991114616394043 A 0.76356898743972168 0.76356898743972168 0 0 0 13.337855339050293 7.4948081970214844 A 0.43570287723587869 0.43570287723587869 0 0 0 13.240612030029297 7.4314064979553223 A 0.41688581305633615 0.41688581305633615 0 0 0 13.071907997131348 7.3954782485961914 A 0.70401694864471998 0.70401694864471998 0 0 0 12.760011672973633 7.4865984916687012 A 1.1666823019756605 1.1666823019756605 0 0 0 12.631303787231445 7.5688562393188477 A 0.056723165671602425 0.056723165671602425 0 0 1 12.551762580871582 7.5110507011413574 A 3.9279674719184277 3.9279674719184277 0 0 0 12.857873916625977 5.7889704704284668 A 0.9692604724751992 0.9692604724751992 0 0 1 13.228790283203125 6.3322582244873047 A 1.2357222109249186 1.2357222109249186 0 0 0 13.04178524017334 6.7735447883605957 A 0.59743433164147131 0.59743433164147131 0 0 0 13.054962158203125 7.0926480293273926 A 0.5485625815463282 0.5485625815463282 0 0 0 13.23188304901123 7.3447837829589844 A 1.0050693822796046 1.0050693822796046 0 0 0 13.425930023193359 7.4644050598144531 A 5.199078580174306 5.199078580174306 0 0 1 13.910654067993164 7.700477123260498 A 0.59572991024825384 0.59572991024825384 0 0 1 13.916983604431152 7.9679784774780273 A 0.55888058408327101 0.55888058408327101 0 0 1 14.05135440826416 7.8096084594726563 A 0.65237358730424633 0.65237358730424633 0 0 1 14.137326240539551 7.9117832183837891 A 0.65686085365819458 0.65686085365819458 0 0 1 14.107027053833008 7.7687134742736816 A 1.4576600726324391 1.4576600726324391 0 0 1 14.234807014465332 7.6883993148803711 A 3.9054253721094079 3.9054253721094079 0 0 1 14.240797996520996 7.6849675178527832 A 2.6635676152280801 2.6635676152280801 0 0 0 14.488101005554199 7.5362567901611328 A 0.41648451043174545 0.41648451043174545 0 0 0 14.669228553771973 7.0993480682373047 A 0.76941127575826918 0.76941127575826918 0 0 0 14.565456390380859 6.8411293029785156 A 0.55379256140259703 0.55379256140259703 0 0 1 14.768148422241211 6.5624303817749023 A 3.9604954634462377 3.9604954634462377 0 0 0 14.906533241271973 7.16064453125 A 1.4678459935873478 1.4678459935873478 0 0 1 14.883975028991699 7.3971080780029297 A 1.4834466130496053 1.4834466130496053 0 0 1 14.750967025756836 7.7773795127868652 A 1.603174349126852 1.603174349126852 0 0 0 14.635810852050781 7.7965230941772461 A 1.3901218900334771 1.3901218900334771 0 0 0 14.138398170471191 7.9981517791748047 A 0.61902998342956261 0.61902998342956261 0 0 0 13.877704620361328 8.400364875793457 A 0.77291169468025545 0.77291169468025545 0 0 0 13.898330688476562 8.7144508361816406 A 12.102790228629743 12.102790228629743 0 0 0 14.048064231872559 9.1843709945678711 A 1.88511911108182 1.88511911108182 0 0 1 14.08682918548584 9.3372583389282227 A 1.896214559835472 1.896214559835472 0 0 0 13.840568542480469 9.419276237487793 A 0.34248242268648738 0.34248242268648738 0 0 1 13.704723358154297 9.4390869140625 A 0.53376170084956553 0.53376170084956553 0 0 0 13.631723403930664 9.343470573425293 A 0.32695770024446608 0.32695770024446608 0 0 0 13.50455379486084 9.2573041915893555 A 1.2436349185511077 1.2436349185511077 0 0 1 13.748051643371582 9.280364990234375 A 0.6951974876919863 0.6951974876919863 0 0 1 13.959550857543945 9.3591775894165039 A 0.80653111354243912 0.80653111354243912 0 0 1 13.773199081420898 9.0164155960083008 M 7.6687374114990234 8.9261989593505859 A 3.251026466007485 3.251026466007485 0 0 1 7.908935546875 8.6105241775512695 A 3.2962221979884503 3.2962221979884503 0 0 1 8.1119804382324219 8.8724765777587891 A 0.10704938446613389 0.10704938446613389 0 0 1 8.0223264694213867 8.9653310775756836 A 0.52498957065850571 0.52498957065850571 0 0 0 7.849822998046875 8.9631128311157227 A 0.25627566037084759 0.25627566037084759 0 0 0 7.6979537010192871 9.0398225784301758 A 1.9608529604713336 1.9608529604713336 0 0 1 7.6687369346618652 8.9261989593505859 M 8.1447515487670898 8.3650436401367187 A 4.0510187597789979 4.0510187597789979 0 0 0 8.6119747161865234 7.5721640586853027 A 1.2406463776561438 1.2406463776561438 0 0 1 8.8149900436401367 8.0080881118774414 A 1.2823663144354225 1.2823663144354225 0 0 0 8.5988225936889648 8.4168796539306641 A 0.57503107920037499 0.57503107920037499 0 0 0 8.5873594284057617 8.7511482238769531 A 0.54696797163103039 0.54696797163103039 0 0 0 8.7437553405761719 9.0073623657226562 A 1.1465230826390092 1.1465230826390092 0 0 0 8.9404020309448242 9.1506252288818359 A 14.654286264673535 14.654286264673535 0 0 0 9.1468029022216797 9.2682971954345703 A 1.2051432432882441 1.2051432432882441 0 0 1 9.5026140213012695 9.5349092483520508 A 0.63787772164741596 0.63787772164741596 0 0 1 9.0638933181762695 9.5608139038085938 A 1.0640007001424256 1.0640007001424256 0 0 1 8.6871976852416992 9.3403635025024414 A 3.9931946967182954 3.9931946967182954 0 0 0 8.1447525024414062 8.3650445938110352 M 11.072675704956055 9.3403635025024414 A 1.064000619826571 1.064000619826571 0 0 1 10.695979118347168 9.5608139038085938 A 0.63789843282217162 0.63789843282217162 0 0 1 10.255148887634277 9.5340299606323242 A 1.2062183421334987 1.2062183421334987 0 0 1 10.613069534301758 9.2682971954345703 A 14.654286870826338 14.654286870826338 0 0 0 10.819470405578613 9.1506252288818359 A 1.1465232677965678 1.1465232677965678 0 0 0 11.016119003295898 9.0073633193969727 A 0.54696790173467635 0.54696790173467635 0 0 0 11.172513961791992 8.7511472702026367 A 0.57503119442711403 0.57503119442711403 0 0 0 11.161050796508789 8.4168806076049805 A 1.2823666178279944 1.2823666178279944 0 0 0 10.944883346557617 8.0080881118774414 A 1.2406466577768447 1.2406466577768447 0 0 1 11.14789867401123 7.5721640586853027 A 4.0510191871724892 4.0510191871724892 0 0 0 11.615120887756348 8.3650436401367187 A 3.993195364003097 3.993195364003097 0 0 0 11.072675704956055 9.3403635025024414 M 11.647893905639648 8.8724765777587891 A 3.296222333117909 3.296222333117909 0 0 1 11.850939750671387 8.6105251312255859 A 3.2510256597724934 3.2510256597724934 0 0 1 12.091136932373047 8.9262008666992187 A 1.9608529662023104 1.9608529662023104 0 0 1 12.061920166015625 9.0398225784301758 A 0.25627516428624791 0.25627516428624791 0 0 0 11.910051345825195 8.9631137847900391 A 0.52498956285921716 0.52498956285921716 0 0 0 11.737545967102051 8.9653310775756836 A 0.10704963063829841 0.10704963063829841 0 0 1 11.647892951965332 8.8724765777587891 M 11.250778198242188 6.7115364074707031 A 3.9149144725772276 3.9149144725772276 0 0 1 11.19777774810791 6.9373340606689453 A 2.8073202762868026 2.8073202762868026 0 0 1 11.058847427368164 6.1692876815795898 A 0.52438291017087468 0.52438291017087468 0 0 1 11.212691307067871 6.1210088729858398 A 6.0595475167558863 6.0595475167558863 0 0 1 11.345952987670898 6.1016082763671875 A 0.60042602872630491 0.60042602872630491 0 0 0 11.442379951477051 6.0825858116149902 A 0.31043093737325778 0.31043093737325778 0 0 0 11.485533714294434 6.0678491592407227 A 0.24835961115427779 0.24835961115427779 0 0 0 11.595284461975098 5.9838681221008301 A 0.29395813306378454 0.29395813306378454 0 0 0 11.649641036987305 5.8041186332702637 A 0.64068312726423904 0.64068312726423904 0 0 0 11.60844898223877 5.5744190216064453 A 2.5323555957892649 2.5323555957892649 0 0 1 11.650474548339844 5.5245089530944824 A 0.59167135608775745 0.59167135608775745 0 0 0 11.853487968444824 5.6832399368286133 A 14.246318850092466 14.246318850092466 0 0 0 12.065937042236328 5.7919216156005859 A 1.2449540705951139 1.2449540705951139 0 0 1 12.232629776000977 5.8955574035644531 A 0.54880578796416235 0.54880578796416235 0 0 1 12.364949226379395 6.0394773483276367 A 0.53479220857265519 0.53479220857265519 0 0 1 12.346828460693359 5.8806672096252441 A 1.0792752651821584 1.0792752651821584 0 0 1 12.385617256164551 5.6518387794494629 A 45.459482669489844 45.459482669489844 0 0 0 12.440646171569824 5.456822395324707 A 0.96341747881174822 0.96341747881174822 0 0 0 12.475471496582031 5.2713766098022461 A 0.40360564921283321 0.40360564921283321 0 0 0 12.362766265869141 4.9524149894714355 A 2.5321546363621712 2.5321546363621712 0 0 1 12.466596603393555 4.899378776550293 A 3.1751808775855985 3.1751808775855985 0 0 1 12.630135536193848 5.65045166015625 A 0.66865708032609894 0.66865708032609894 0 0 1 12.391573905944824 6.1212878227233887 A 1.3489879307817079 1.3489879307817079 0 0 0 12.027557373046875 6.0230188369750977 A 0.90261888466847229 0.90261888466847229 0 0 0 11.835853576660156 6.0172610282897949 A 0.57176668877825854 0.57176668877825854 0 0 0 11.517806053161621 6.1350774765014648 A 0.60882327201567021 0.60882327201567021 0 0 0 11.327905654907227 6.4133753776550293 A 2.4064430631785005 2.4064430631785005 0 0 0 11.250778198242188 6.7115359306335449 M 11.117523193359375 5.5993003845214844 A 0.32791260176388171 0.32791260176388171 0 0 0 11.065628051757812 5.6821784973144531 A 3.2402759964857228 3.2402759964857228 0 0 1 11.451355934143066 4.4014325141906738 A 1.3168764071836123 1.3168764071836123 0 0 1 11.568138122558594 4.504300594329834 A 0.49449497531813214 0.49449497531813214 0 0 1 11.505107879638672 4.7847237586975098 A 0.42535454424699665 0.42535454424699665 0 0 1 11.73277759552002 4.7032408714294434 A 1.316892772450805 1.316892772450805 0 0 1 11.77742862701416 4.774259090423584 A 0.95814501751230252 0.95814501751230252 0 0 0 11.611708641052246 5.0574359893798828 A 0.47216014682473156 0.47216014682473156 0 0 0 11.569117546081543 5.2281136512756348 A 0.40059011367437092 0.40059011367437092 0 0 0 11.610852241516113 5.4631423950195313 A 0.12581545705244265 0.12581545705244265 0 0 1 11.480119705200195 5.5068702697753906 A 0.33863456707213879 0.33863456707213879 0 0 0 11.309605598449707 5.5022649765014648 A 0.32520289538542563 0.32520289538542563 0 0 0 11.117524147033691 5.5993003845214844 M 7.2745151519775391 6.7449021339416504 A 0.60412128776401253 0.60412128776401253 0 0 0 7.4610767364501953 7.0801119804382324 A 0.58584089901987701 0.58584089901987701 0 0 0 7.7752456665039062 7.2152829170227051 A 2.3971705795048801 2.3971705795048801 0 0 0 8.1383275985717773 7.2210597991943359 A 3.3291639238194803 3.3291639238194803 0 0 1 8.3497371673583984 7.2196536064147949 A 0.61166668278066227 0.61166668278066227 0 0 1 8.1684293746948242 7.3074021339416504 A 0.59927598080658218 0.59927598080658218 0 0 0 7.9589519500732422 7.2882027626037598 A 0.29596860634939187 0.29596860634939187 0 0 0 7.8286242485046387 7.3301949501037598 A 0.23203660562750292 0.23203660562750292 0 0 0 7.725621223449707 7.4842529296875 A 0.85382294902369393 0.85382294902369393 0 0 0 7.7115693092346191 7.6220059394836426 A 0.71884053337102549 0.71884053337102549 0 0 1 7.6844825744628906 7.8248095512390137 A 3.2962222275783182 3.2962222275783182 0 0 1 7.1141533851623535 5.994410514831543 A 0.51334654236411881 0.51334654236411881 0 0 1 7.2699241638183594 6.216252326965332 A 1.3368626232900835 1.3368626232900835 0 0 0 7.2745141983032227 6.7449016571044922 M 8.7010250091552734 6.169288158416748 A 2.8073197594057664 2.8073197594057664 0 0 1 8.5620946884155273 6.9373354911804199 A 3.9149148045811044 3.9149148045811044 0 0 1 8.5090951919555664 6.7115359306335449 A 2.4064432740740531 2.4064432740740531 0 0 0 8.4319677352905273 6.4133763313293457 A 0.60882285637997557 0.60882285637997557 0 0 0 8.2420673370361328 6.135077953338623 A 0.57176667232750245 0.57176667232750245 0 0 0 7.9240202903747559 6.0172605514526367 A 0.90261888382396283 0.90261888382396283 0 0 0 7.7323174476623535 6.0230188369750977 A 1.3489882770275907 1.3489882770275907 0 0 0 7.3682994842529297 6.1212878227233887 A 0.66865701198736816 0.66865701198736816 0 0 1 7.1297378540039062 5.6504507064819336 A 3.175181692114915 3.175181692114915 0 0 1 7.2932777404785156 4.8993792533874512 A 2.5321547781869502 2.5321547781869502 0 0 1 7.3971080780029297 4.9524154663085938 A 0.40360603914092807 0.40360603914092807 0 0 0 7.2844018936157227 5.2713761329650879 A 0.96341772331694031 0.96341772331694031 0 0 0 7.3192296028137207 5.4568219184875488 A 45.459484683823625 45.459484683823625 0 0 0 7.3742537498474121 5.6518368721008301 A 1.0792747735608956 1.0792747735608956 0 0 1 7.4130454063415527 5.8806672096252441 A 0.5347921966332374 0.5347921966332374 0 0 1 7.3949246406555176 6.0394768714904785 A 0.54880638669956838 0.54880638669956838 0 0 1 7.5272445678710938 5.8955574035644531 A 1.244954079023683 1.244954079023683 0 0 1 7.6939353942871094 5.7919225692749023 A 14.246318741178086 14.246318741178086 0 0 0 7.9063835144042969 5.6832408905029297 A 0.59167138697491262 0.59167138697491262 0 0 0 8.1093997955322266 5.5245089530944824 A 2.532355933436631 2.532355933436631 0 0 1 8.1514253616333008 5.5744199752807617 A 0.64068307654725098 0.64068307654725098 0 0 0 8.1102313995361328 5.8041186332702637 A 0.29395815041161771 0.29395815041161771 0 0 0 8.1645889282226562 5.9838681221008301 A 0.24835955264454976 0.24835955264454976 0 0 0 8.2743396759033203 6.0678496360778809 A 0.31043099536277646 0.31043099536277646 0 0 0 8.3174934387207031 6.0825858116149902 A 0.60042565216167842 0.60042565216167842 0 0 0 8.4139223098754883 6.1016077995300293 A 6.0595469213889261 6.0595469213889261 0 0 1 8.5471830368041992 6.121009349822998 A 0.52438237883273708 0.52438237883273708 0 0 1 8.7010259628295898 6.169288158416748 M 8.3085174560546875 4.4014334678649902 A 3.2402764686598178 3.2402764686598178 0 0 1 8.6942453384399414 5.6821794509887695 A 0.32791253348921406 0.32791253348921406 0 0 0 8.6423501968383789 5.5993003845214844 A 0.32520258775150618 0.32520258775150618 0 0 0 8.4502687454223633 5.5022644996643066 A 0.33863450141343882 0.33863450141343882 0 0 0 8.2797536849975586 5.5068707466125488 A 0.12581582411588368 0.12581582411588368 0 0 1 8.1490201950073242 5.4631423950195313 A 0.40058997555107945 0.40058997555107945 0 0 0 8.1907558441162109 5.2281136512756348 A 0.47216019870324116 0.47216019870324116 0 0 0 8.1481647491455078 5.0574355125427246 A 0.95814532327406876 0.95814532327406876 0 0 0 7.9824457168579102 4.7742586135864258 A 1.3168925366452564 1.3168925366452564 0 0 1 8.0270967483520508 4.7032403945922852 A 0.42535450076742198 0.42535450076742198 0 0 1 8.254765510559082 4.784724235534668 A 0.49449504407441836 0.49449504407441836 0 0 1 8.1917352676391602 4.504300594329834 A 1.3168770583969331 1.3168770583969331 0 0 1 8.3085174560546875 4.4014320373535156 M 7.7299075126647949 4.5950717926025391 A 0.22817316006447616 0.22817316006447616 0 0 0 7.8109478950500488 4.6568822860717773 A 0.41252664908980996 0.41252664908980996 0 0 0 7.9344229698181152 4.6901297569274902 A 1.9610778761597727 1.9610778761597727 0 0 1 7.8970675468444824 4.7520227432250977 A 1.0843247180621407 1.0843247180621407 0 0 0 7.6804227828979492 4.7938508987426758 A 0.79306827573241545 0.79306827573241545 0 0 0 7.4893074035644531 4.8783597946166992 A 6.191420287566606 6.191420287566606 0 0 1 7.3543715476989746 4.7359447479248047 A 3.3471617142475223 3.3471617142475223 0 0 1 7.6502475738525391 4.1694231033325195 A 1.1940905066162759 1.1940905066162759 0 0 1 7.6990580558776855 4.2483606338500977 A 0.53451921462833152 0.53451921462833152 0 0 0 7.6730985641479492 4.396176815032959 A 0.37087117214129711 0.37087117214129711 0 0 0 7.684241771697998 4.5060439109802246 A 0.23581537787965573 0.23581537787965573 0 0 0 7.7299075126647949 4.5950717926025391 M 7.9098916053771973 3.8236238956451416 A 3.2510256693664537 3.2510256693664537 0 0 1 8.1500892639160156 4.1392979621887207 A 1.9608530267328856 1.9608530267328856 0 0 1 8.1208724975585937 4.2529196739196777 A 0.25627563713979795 0.25627563713979795 0 0 0 7.9690036773681641 4.1762099266052246 A 0.52498956285921716 0.52498956285921716 0 0 0 7.7964992523193359 4.1784281730651855 A 0.10704968808936267 0.10704968808936267 0 0 1 7.7068452835083008 4.0855741500854492 A 3.2962227481671267 3.2962227481671267 0 0 1 7.9098916053771973 3.823622465133667 M 8.4357833862304687 7.2799072265625 A 3.1748659786841329 3.1748659786841329 0 0 1 7.9098906517028809 8.1192302703857422 A 3.2962226609070182 3.2962226609070182 0 0 1 7.7092585563659668 7.8607344627380371 A 0.55151974800933456 0.55151974800933456 0 0 1 7.8778767585754395 7.8179445266723633 A 1.8139885621743783 1.8139885621743783 0 0 0 8.0261707305908203 7.7944951057434082 A 0.2494386087833983 0.2494386087833983 0 0 0 8.1899271011352539 7.6881833076477051 A 0.26256388952463433 0.26256388952463433 0 0 0 8.2287883758544922 7.5656619071960449 A 0.49173411436005382 0.49173411436005382 0 0 0 8.2094955444335938 7.3798632621765137 A 0.45874428380740728 0.45874428380740728 0 0 1 8.4357843399047852 7.2799072265625 M 7.0742340087890625 8.1162786483764648 A 0.93633442260628674 0.93633442260628674 0 0 0 7.2149357795715332 7.7240581512451172 A 0.20625914123298342 0.20625914123298342 0 0 1 7.2743616104125977 7.6595058441162109 A 3.9604951904713457 3.9604951904713457 0 0 0 7.348701000213623 7.8090415000915527 A 0.36760926724132759 0.36760926724132759 0 0 1 7.1892375946044922 8.1584196090698242 A 1.5990989079854789 1.5990989079854789 0 0 0 7.0742344856262207 8.1162786483764648 M 12.645720481872559 5.9944114685058594 A 3.296222557724763 3.296222557724763 0 0 1 12.075389862060547 7.8248100280761719 A 0.71884049728792709 0.71884049728792709 0 0 1 12.048304557800293 7.6220059394836426 A 0.85382239855407438 0.85382239855407438 0 0 0 12.034252166748047 7.4842534065246582 A 0.23203669080273179 0.23203669080273179 0 0 0 11.931248664855957 7.330195426940918 A 0.2959686628642681 0.2959686628642681 0 0 0 11.800920486450195 7.2882022857666016 A 0.59927605441212783 0.59927605441212783 0 0 0 11.59144401550293 7.3074021339416504 A 0.61166674085722272 0.61166674085722272 0 0 1 11.410135269165039 7.2196536064147949 A 3.3291639005628051 3.3291639005628051 0 0 1 11.621546745300293 7.2210602760314941 A 2.3971706367629251 2.3971706367629251 0 0 0 11.984627723693848 7.2152824401855469 A 0.58584114231266249 0.58584114231266249 0 0 0 12.298796653747559 7.0801124572753906 A 0.6041221255087974 0.6041221255087974 0 0 0 12.485358238220215 6.7449021339416504 A 1.3368627124468135 1.3368627124468135 0 0 0 12.489949226379395 6.216252326965332 A 0.51334624304174603 0.51334624304174603 0 0 1 12.645721435546875 5.9944109916687012 M 13.608234405517578 6.2538561820983887 A 1.7732937621027725 1.7732937621027725 0 0 1 13.267313003540039 5.9718294143676758 A 3.4116145716612847 3.4116145716612847 0 0 1 13.793704032897949 5.9317374229431152 A 2.0256771477178801 2.0256771477178801 0 0 0 14.107298851013184 5.9311823844909668 A 0.54358659562559242 0.54358659562559242 0 0 0 14.583806991577148 5.5851707458496094 A 1.1442961198669541 1.1442961198669541 0 0 0 14.64993953704834 5.0466318130493164 A 0.64312408180786274 0.64312408180786274 0 0 1 14.85850715637207 4.9475975036621094 A 3.8642626530050088 3.8642626530050088 0 0 0 14.723855972290039 5.9855985641479492 A 0.37410916359460411 0.37410916359460411 0 0 1 14.557631492614746 6.1640129089355469 A 0.52156499155455427 0.52156499155455427 0 0 0 14.324691772460937 6.0489935874938965 A 0.21670335742917948 0.21670335742917948 0 0 0 14.148472785949707 6.0917487144470215 A 0.36037650536694371 0.36037650536694371 0 0 0 14.057438850402832 6.2007808685302734 A 1.7376845074378184 1.7376845074378184 0 0 1 13.951101303100586 6.3771171569824219 A 1.0622388892425447 1.0622388892425447 0 0 0 13.608235359191895 6.2538561820983887 M 14.733432769775391 6.2472195625305176 A 0.47468441608790074 0.47468441608790074 0 0 1 14.386601448059082 6.6544265747070312 A 1.0983392288062181 1.0983392288062181 0 0 0 14.213031768798828 6.6878843307495117 A 0.69824262121304348 0.69824262121304348 0 0 0 14.190958023071289 6.6406307220458984 A 0.80252835335377559 0.80252835335377559 0 0 0 14.159244537353516 6.5841493606567383 A 0.61227842320414938 0.61227842320414938 0 0 0 14.108248710632324 6.5127601623535156 A 1.8093869828908422 1.8093869828908422 0 0 0 14.217753410339355 6.5479578971862793 A 0.28347276056776743 0.28347276056776743 0 0 0 14.374478340148926 6.5512661933898926 A 0.24489939138869368 0.24489939138869368 0 0 0 14.510985374450684 6.4410138130187988 A 0.48127171394716933 0.48127171394716933 0 0 0 14.576703071594238 6.2751259803771973 A 0.51634891981626396 0.51634891981626396 0 0 1 14.729264259338379 6.1789851188659668 A 3.9604958106404813 3.9604958106404813 0 0 0 14.733433723449707 6.247218132019043 M 15.067437171936035 6.7652010917663574 A 3.3042863633179169 3.3042863633179169 0 0 1 14.970514297485352 5.9944114685058594 A 0.54514815031226715 0.54514815031226715 0 0 1 15.067436218261719 6.1000781059265137 L 15.067437171936035 6.7652020454406738 M 13.465214729309082 5.1249179840087891 A 0.67549960208696636 0.67549960208696636 0 0 0 13.42475700378418 4.9795379638671875 A 0.23841593631996286 0.23841593631996286 0 0 0 13.571115493774414 4.934654712677002 A 0.61783382055311686 0.61783382055311686 0 0 0 13.465214729309082 5.1249175071716309 M 12.109626770019531 4.1694245338439941 A 3.3471614361712905 3.3471614361712905 0 0 1 12.405501365661621 4.7359457015991211 A 6.1914196474242518 6.1914196474242518 0 0 1 12.270565986633301 4.8783602714538574 A 0.79306872509938842 0.79306872509938842 0 0 0 12.079451560974121 4.7938508987426758 A 1.0843245939966906 1.0843245939966906 0 0 0 11.86280632019043 4.7520227432250977 A 1.961078412150157 1.961078412150157 0 0 1 11.82544994354248 4.6901297569274902 A 0.41252639201450969 0.41252639201450969 0 0 0 11.948925971984863 4.6568818092346191 A 0.22817278568006738 0.22817278568006738 0 0 0 12.029966354370117 4.5950717926025391 A 0.23581545891648686 0.23581545891648686 0 0 0 12.075631141662598 4.5060439109802246 A 0.37087108808067104 0.37087108808067104 0 0 0 12.086774826049805 4.396176815032959 A 0.5345192182293842 0.5345192182293842 0 0 0 12.060815811157227 4.2483606338500977 A 1.1940910269976406 1.1940910269976406 0 0 1 12.109626770019531 4.1694235801696777 M 11.79086971282959 4.1762099266052246 A 0.25627570223357699 0.25627570223357699 0 0 0 11.63900089263916 4.2529196739196777 A 1.9608530061099041 1.9608530061099041 0 0 1 11.609785079956055 4.1392960548400879 A 3.2510257001980474 3.2510257001980474 0 0 1 11.849983215332031 3.8236219882965088 A 3.2962221884948253 3.2962221884948253 0 0 1 12.053028106689453 4.0855746269226074 A 0.10704938446613389 0.10704938446613389 0 0 1 11.963374137878418 4.1784281730651855 A 0.52498957065850571 0.52498957065850571 0 0 0 11.790870666503906 4.1762099266052246 M 13.387394905090332 5.4205594062805176 A 3.4645814150949872 3.4645814150949872 0 0 1 13.30341911315918 5.7212285995483398 A 0.96202139263119002 0.96202139263119002 0 0 1 13.205599784851074 5.9198470115661621 A 1.8687784033120283 1.8687784033120283 0 0 1 12.934439659118652 5.5497245788574219 A 2.0748370957788249 2.0748370957788249 0 0 1 13.168878555297852 5.5070996284484863 A 0.6338786570511844 0.6338786570511844 0 0 0 13.28911018371582 5.4776134490966797 A 0.26619937952610567 0.26619937952610567 0 0 0 13.387394905090332 5.4205598831176758 M 14.417214393615723 4.5647149085998535 A 1.948422459191351 1.948422459191351 0 0 1 14.968835830688477 4.6002488136291504 A 1.6262428878785764 1.6262428878785764 0 0 1 14.714859008789063 4.784914493560791 A 0.30573145701094118 0.30573145701094118 0 0 1 14.567305564880371 4.8343305587768555 A 0.32507402083274256 0.32507402083274256 0 0 1 14.416353225708008 4.7966775894165039 A 0.54887012393841006 0.54887012393841006 0 0 0 14.192893028259277 4.7411689758300781 A 1.0433751105127447 1.0433751105127447 0 0 1 14.417214393615723 4.5647149085998535 M 14.936816215515137 4.4681816101074219 A 0.66574000764433328 0.66574000764433328 0 0 1 14.84355640411377 4.4634723663330078 A 1.3946353016901396 1.3946353016901396 0 0 0 14.741806983947754 4.4557895660400391 A 1.2902523481206813 1.2902523481206813 0 0 0 14.636587142944336 4.4558501243591309 A 2.7345284763391962 2.7345284763391962 0 0 0 14.906813621520996 4.293034553527832 A 0.82690097021820252 0.82690097021820252 0 0 0 15.067436218261719 4.148646354675293 L 15.067437171936035 4.3580408096313477 A 3.9604947896919112 3.9604947896919112 0 0 0 15.040722846984863 4.4193062782287598 A 0.11306227057771716 0.11306227057771716 0 0 1 14.936817169189453 4.4681816101074219 M 13.885219573974609 4.7422771453857422 A 0.56156493108816863 0.56156493108816863 0 0 0 13.682110786437988 4.8274312019348145 A 0.62286231034154438 0.62286231034154438 0 0 0 13.736110687255859 4.7463951110839844 A 2.1278539750979326 2.1278539750979326 0 0 1 14.098199844360352 4.6167120933532715 A 0.76356792294645093 0.76356792294645093 0 0 1 14.106000900268555 4.7308268547058105 A 0.79932929756617455 0.79932929756617455 0 0 0 13.885218620300293 4.7422776222229004 M 15.067436218261719 5.9298596382141113 A 0.65195132248672483 0.65195132248672483 0 0 1 14.986098289489746 5.6504507064819336 A 3.3109841787380447 3.3109841787380447 0 0 1 15.067436218261719 5.1776518821716309 L 15.067437171936035 5.9298601150512695 M 11.849982261657715 8.1192302703857422 A 3.1748659500564353 3.1748659500564353 0 0 1 11.324089050292969 7.2799067497253418 A 0.45874440389960919 0.45874440389960919 0 0 1 11.550379753112793 7.3798651695251465 A 0.49173403262148296 0.49173403262148296 0 0 0 11.531085014343262 7.5656614303588867 A 0.26256397827143463 0.26256397827143463 0 0 0 11.569947242736816 7.6881833076477051 A 0.24943818804869941 0.24943818804869941 0 0 0 11.73370361328125 7.7944951057434082 A 1.8139885707524614 1.8139885707524614 0 0 0 11.881997108459473 7.8179450035095215 A 0.55151959348011126 0.55151959348011126 0 0 1 12.050614356994629 7.8607344627380371 A 3.2962228478560789 3.2962228478560789 0 0 1 11.849982261657715 8.1192312240600586 M 12.485511779785156 7.6595058441162109 A 0.20625947245214937 0.20625947245214937 0 0 1 12.544938087463379 7.7240581512451172 A 0.93633380673662725 0.93633380673662725 0 0 0 12.685639381408691 8.1162786483764648 A 1.5990992457485507 1.5990992457485507 0 0 0 12.570635795593262 8.1584186553955078 A 0.36760872753307933 0.36760872753307933 0 0 1 12.411172866821289 7.8090419769287109 A 3.9604955936556614 3.9604955936556614 0 0 0 12.485512733459473 7.6595058441162109 M 15.067437171936035 7.62091064453125 L 15.067437171936035 8.096470832824707 A 1.7237383064000853 1.7237383064000853 0 0 0 14.90034008026123 7.8522324562072754 A 1.5750155071878322 1.5750155071878322 0 0 1 15.067438125610352 7.6209101676940918 M 11.402124404907227 11.86701488494873 A 0.58584126818762527 0.58584126818762527 0 0 0 11.716293334960938 12.002184867858887 A 2.3971705795048801 2.3971705795048801 0 0 0 12.079375267028809 12.007963180541992 A 3.329163447132562 3.329163447132562 0 0 1 12.29078483581543 12.006556510925293 A 0.61166630455243831 0.61166630455243831 0 0 1 12.109477043151855 12.094305038452148 A 0.59927621296823441 0.59927621296823441 0 0 0 11.899999618530273 12.075105667114258 A 0.29596811183713867 0.29596811183713867 0 0 0 11.769671440124512 12.117097854614258 A 0.23203677500390521 0.23203677500390521 0 0 0 11.666668891906738 12.27115535736084 A 0.85382240393814601 0.85382240393814601 0 0 0 11.652617454528809 12.408908843994141 A 0.71884047322651723 0.71884047322651723 0 0 1 11.625530242919922 12.611712455749512 A 3.2962227077286901 3.2962227077286901 0 0 1 11.05519962310791 10.781312942504883 A 0.51334657741493483 0.51334657741493483 0 0 1 11.210971832275391 11.003154754638672 A 1.3368626232900835 1.3368626232900835 0 0 0 11.215561866760254 11.531805038452148 A 0.60412128776401253 0.60412128776401253 0 0 0 11.402124404907227 11.86701488494873 M 11.315303802490234 10.438742637634277 A 1.0792753642635622 1.0792753642635622 0 0 1 11.354093551635742 10.667570114135742 A 0.53479232088424822 0.53479232088424822 0 0 1 11.335971832275391 10.826380729675293 A 0.54880619094148753 0.54880619094148753 0 0 1 11.468292236328125 10.682459831237793 A 1.2449532611054803 1.2449532611054803 0 0 1 11.634983062744141 10.578825950622559 A 14.246319301581584 14.246319301581584 0 0 0 11.847431182861328 10.47014331817627 A 0.59167115010187021 0.59167115010187021 0 0 0 12.050447463989258 10.31141185760498 A 2.5327264826886018 2.5327264826886018 0 0 1 12.076850891113281 10.342464447021484 A 0.57260696129402033 0.57260696129402033 0 0 0 12.027342796325684 10.592774391174316 A 0.28976521617440198 0.28976521617440198 0 0 0 12.103578567504883 10.772713661193848 A 0.3071386538859468 0.3071386538859468 0 0 0 12.21800422668457 10.847936630249023 A 0.36394878921134599 0.36394878921134599 0 0 0 12.260574340820313 10.861318588256836 A 0.39969250380299309 0.39969250380299309 0 0 0 12.355043411254883 10.872941017150879 A 1.1461938374248757 1.1461938374248757 0 0 1 12.494224548339844 10.868719100952148 A 0.26174380788304946 0.26174380788304946 0 0 1 12.642073631286621 10.956191062927246 A 2.8073202122732281 2.8073202122732281 0 0 1 12.503142356872559 11.724238395690918 A 3.9149138700917883 3.9149138700917883 0 0 1 12.450142860412598 11.498438835144043 A 2.4064431253619709 2.4064431253619709 0 0 0 12.373015403747559 11.200279235839844 A 0.6088225522482148 0.6088225522482148 0 0 0 12.183115005493164 10.921980857849121 A 0.5717661961761723 0.5717661961761723 0 0 0 11.865068435668945 10.804163932800293 A 0.9026192730539746 0.9026192730539746 0 0 0 11.673364639282227 10.809921264648438 A 1.3489884007359518 1.3489884007359518 0 0 0 11.309347152709961 10.908190727233887 A 0.66865704212405241 0.66865704212405241 0 0 1 11.070785522460938 10.43735408782959 A 3.1751809066089645 3.1751809066089645 0 0 1 11.234325408935547 9.6862812042236328 A 2.5321550628689873 2.5321550628689873 0 0 1 11.338155746459961 9.73931884765625 A 0.403605652707894 0.403605652707894 0 0 0 11.225449562072754 10.058279037475586 A 0.9634175136869183 0.9634175136869183 0 0 0 11.260275840759277 10.24372386932373 A 45.459487478697412 45.459487478697412 0 0 0 11.315300941467285 10.438739776611328 M 8.7046728134155273 10.781313896179199 A 3.2962224158181588 3.2962224158181588 0 0 1 8.134343147277832 12.611712455749512 A 0.71884049728792709 0.71884049728792709 0 0 1 8.1072568893432617 12.408908843994141 A 0.85382297002084051 0.85382297002084051 0 0 0 8.0932044982910156 12.27115535736084 A 0.23203694838651681 0.23203694838651681 0 0 0 7.990201473236084 12.117097854614258 A 0.29596811292035291 0.29596811292035291 0 0 0 7.8598732948303223 12.075105667114258 A 0.59927622550653303 0.59927622550653303 0 0 0 7.6503968238830566 12.094305992126465 A 0.61166656207850156 0.61166656207850156 0 0 1 7.469088077545166 12.006555557250977 A 3.3291634423885124 3.3291634423885124 0 0 1 7.6804990768432617 12.007963180541992 A 2.3971705930866212 2.3971705930866212 0 0 0 8.0435800552368164 12.002185821533203 A 0.58584052610309034 0.58584052610309034 0 0 0 8.3577489852905273 11.86701488494873 A 0.60412191958372952 0.60412191958372952 0 0 0 8.5443115234375 11.531805038452148 A 1.336862622224702 1.336862622224702 0 0 0 8.5489015579223633 11.003155708312988 A 0.51334587571517021 0.51334587571517021 0 0 1 8.7046737670898437 10.781313896179199 M 7.3097310066223145 11.498438835144043 A 3.9149145354835468 3.9149145354835468 0 0 1 7.2567305564880371 11.724237442016602 A 2.8073197245255792 2.8073197245255792 0 0 1 7.1178011894226074 10.95619010925293 A 0.26174357644234247 0.26174357644234247 0 0 1 7.2656488418579102 10.868719100952148 A 1.1461938256213968 1.1461938256213968 0 0 1 7.4048304557800293 10.872941017150879 A 0.39969250527210376 0.39969250527210376 0 0 0 7.4992990493774414 10.861318588256836 A 0.36394866851170637 0.36394866851170637 0 0 0 7.5418686866760254 10.847936630249023 A 0.3071383429379333 0.3071383429379333 0 0 0 7.6562948226928711 10.772713661193848 A 0.28976584019282892 0.28976584019282892 0 0 0 7.7325310707092285 10.592774391174316 A 0.57260694188211925 0.57260694188211925 0 0 0 7.6830229759216309 10.342463493347168 A 2.5327269678438018 2.5327269678438018 0 0 1 7.7094268798828125 10.31141185760498 A 0.59167115123648828 0.59167115123648828 0 0 0 7.9124417304992676 10.47014331817627 A 14.246319510988215 14.246319510988215 0 0 0 8.1248893737792969 10.578824996948242 A 1.2449539298278927 1.2449539298278927 0 0 1 8.2915821075439453 10.682460784912109 A 0.54880597646788676 0.54880597646788676 0 0 1 8.4239015579223633 10.826380729675293 A 0.53479222592162967 0.53479222592162967 0 0 1 8.4057807922363281 10.667570114135742 A 1.0792752651821584 1.0792752651821584 0 0 1 8.4445695877075195 10.438741683959961 A 45.459486768093953 45.459486768093953 0 0 0 8.4995965957641602 10.243725776672363 A 0.96341791212741368 0.96341791212741368 0 0 0 8.534423828125 10.058279037475586 A 0.40360564921283321 0.40360564921283321 0 0 0 8.4217195510864258 9.7393178939819336 A 2.5321543452624242 2.5321543452624242 0 0 1 8.5255489349365234 9.6862821578979492 A 3.1751813080521014 3.1751813080521014 0 0 1 8.6890878677368164 10.43735408782959 A 0.66865708032609894 0.66865708032609894 0 0 1 8.450526237487793 10.908190727233887 A 1.3489885801547801 1.3489885801547801 0 0 0 8.0865097045898438 10.809921264648438 A 0.90261925090868955 0.90261925090868955 0 0 0 7.894805908203125 10.804162979125977 A 0.57176631088298036 0.57176631088298036 0 0 0 7.576758861541748 10.921980857849121 A 0.60882297343473102 0.60882297343473102 0 0 0 7.3868584632873535 11.200278282165527 A 2.4064432827967059 2.4064432827967059 0 0 0 7.3097305297851563 11.498438835144043 M 7.6280703544616699 10.015016555786133 A 0.40059011367437092 0.40059011367437092 0 0 0 7.6698055267333984 10.250044822692871 A 0.068326011462106456 0.068326011462106456 0 0 1 7.5608563423156738 10.264206886291504 A 0.23550299596826796 0.23550299596826796 0 0 0 7.3550472259521484 10.250560760498047 A 0.41401592064573056 0.41401592064573056 0 0 0 7.176476001739502 10.386202812194824 A 0.47716421425558231 0.47716421425558231 0 0 0 7.1209192276000977 10.514121055603027 A 3.2435539603165968 3.2435539603165968 0 0 1 7.5103087425231934 9.1883354187011719 A 1.3168767429602806 1.3168767429602806 0 0 1 7.6270909309387207 9.291203498840332 A 0.49449521057865192 0.49449521057865192 0 0 1 7.5640602111816406 9.5716266632080078 A 0.42535412102008102 0.42535412102008102 0 0 1 7.7917299270629883 9.4901437759399414 A 1.3168926411780819 1.3168926411780819 0 0 1 7.8363804817199707 9.561161994934082 A 0.95814513057264339 0.95814513057264339 0 0 0 7.670661449432373 9.8443384170532227 A 0.4721606228829201 0.4721606228829201 0 0 0 7.6280694007873535 10.015016555786133 M 8.1345834732055664 9.2929468154907227 A 0.37087106503345751 0.37087106503345751 0 0 0 8.1457271575927734 9.183079719543457 A 0.5345192182293842 0.5345192182293842 0 0 0 8.1197681427001953 9.0352640151977539 A 1.1940904862454051 1.1940904862454051 0 0 1 8.1685791015625 8.9563264846801758 A 3.347161794935225 3.347161794935225 0 0 1 8.4644546508789062 9.5228481292724609 A 6.1914195223972035 6.1914195223972035 0 0 1 8.3295183181762695 9.6652631759643555 A 0.7930682673911289 0.7930682673911289 0 0 0 8.1384038925170898 9.580754280090332 A 1.0843243402518845 1.0843243402518845 0 0 0 7.9217586517333984 9.5389251708984375 A 1.9610782361975556 1.9610782361975556 0 0 1 7.8844022750854492 9.4770326614379883 A 0.41252702151716658 0.41252702151716658 0 0 0 8.007878303527832 9.4437856674194336 A 0.22817296752639141 0.22817296752639141 0 0 0 8.0889186859130859 9.3819751739501953 A 0.23581530640479176 0.23581530640479176 0 0 0 8.1345834732055664 9.2929468154907227 M 7.9089345932006836 12.906132698059082 A 3.1748663886746975 3.1748663886746975 0 0 1 7.3830418586730957 12.06680965423584 A 0.45874379761521 0.45874379761521 0 0 1 7.6093320846557617 12.166768074035645 A 0.49173407435393951 0.49173407435393951 0 0 0 7.5900373458862305 12.352564811706543 A 0.26256388160486294 0.26256388160486294 0 0 0 7.628899097442627 12.475085258483887 A 0.24943890496178386 0.24943890496178386 0 0 0 7.7926554679870605 12.581398010253906 A 1.8139891542612592 1.8139891542612592 0 0 0 7.9409494400024414 12.604848861694336 A 0.5515196539603876 0.5515196539603876 0 0 1 8.1095676422119141 12.647637367248535 A 3.2962227411874734 3.2962227411874734 0 0 1 7.9089350700378418 12.906133651733398 M 7.214935302734375 12.510961532592773 A 0.20527268530768131 0.20527268530768131 0 0 1 7.2743616104125977 12.446409225463867 A 2.8921095878341228 2.8921095878341228 0 0 0 7.4241414070129395 12.733254432678223 A 0.5853656087578466 0.5853656087578466 0 0 1 7.0941348075866699 13.055975914001465 A 0.98371548130557418 0.98371548130557418 0 0 0 6.9390230178833008 13.034441947937012 A 0.49091840928391578 0.49091840928391578 0 0 0 7.1053609848022461 12.852882385253906 A 0.99613937025957666 0.99613937025957666 0 0 0 7.2149357795715332 12.510961532592773 M 15.067436218261719 11.552104949951172 A 3.3449483237640094 3.3449483237640094 0 0 1 15.067436218261719 9.9771404266357422 L 15.067437171936035 11.552104949951172 M 14.733432769775391 11.034122467041016 A 0.47468441608790074 0.47468441608790074 0 0 1 14.386601448059082 11.441329956054688 A 1.0983401476794081 1.0983401476794081 0 0 0 14.213031768798828 11.474786758422852 A 0.69824288475025353 0.69824288475025353 0 0 0 14.190958023071289 11.427534103393555 A 0.80252772948147644 0.80252772948147644 0 0 0 14.159244537353516 11.371052742004395 A 0.61227842320414938 0.61227842320414938 0 0 0 14.108248710632324 11.299663543701172 A 1.8093862554137925 1.8093862554137925 0 0 0 14.217753410339355 11.334859848022461 A 0.28347297720984699 0.28347297720984699 0 0 0 14.374478340148926 11.338170051574707 A 0.24489939138869368 0.24489939138869368 0 0 0 14.510985374450684 11.227916717529297 A 0.48127265032636851 0.48127265032636851 0 0 0 14.576703071594238 11.062028884887695 A 0.51634875609187736 0.51634875609187736 0 0 1 14.729264259338379 10.965887069702148 A 3.9604957442746245 3.9604957442746245 0 0 0 14.733433723449707 11.034121513366699 M 13.267315864562988 10.758732795715332 A 3.4116150403163776 3.4116150403163776 0 0 1 13.793704032897949 10.718640327453613 A 2.025676910047665 2.025676910047665 0 0 0 14.107298851013184 10.718085289001465 A 0.54358676820188101 0.54358676820188101 0 0 0 14.583806991577148 10.372074127197266 A 1.1442961198669541 1.1442961198669541 0 0 0 14.64993953704834 9.8335351943969727 A 0.64312432958599108 0.64312432958599108 0 0 1 14.85850715637207 9.7344999313354492 A 3.8642626562715474 3.8642626562715474 0 0 0 14.723855972290039 10.772500991821289 A 0.37410874259171745 0.37410874259171745 0 0 1 14.557631492614746 10.950915336608887 A 0.52156572891497532 0.52156572891497532 0 0 0 14.324691772460937 10.835896492004395 A 0.21670335742917948 0.21670335742917948 0 0 0 14.148472785949707 10.87865161895752 A 0.36037666108228916 0.36037666108228916 0 0 0 14.057438850402832 10.98768424987793 A 1.7376845074378184 1.7376845074378184 0 0 1 13.951101303100586 11.164020538330078 A 1.0622380916264205 1.0622380916264205 0 0 0 13.608235359191895 11.040760040283203 A 1.7732938036628205 1.7732938036628205 0 0 1 13.267313003540039 10.758731842041016 M 12.249565124511719 9.1883363723754883 A 3.2435542625410818 3.2435542625410818 0 0 1 12.638954162597656 10.514122009277344 A 0.47716447649224686 0.47716447649224686 0 0 0 12.58339786529541 10.386203765869141 A 0.41401548147173362 0.41401548147173362 0 0 0 12.404826164245605 10.250560760498047 A 0.23550296058097181 0.23550296058097181 0 0 0 12.199017524719238 10.26420783996582 A 0.068326613499095412 0.068326613499095412 0 0 1 12.090067863464355 10.250044822692871 A 0.40058991525268955 0.40058991525268955 0 0 0 12.131803512573242 10.015016555786133 A 0.47216019870324116 0.47216019870324116 0 0 0 12.089212417602539 9.8443384170532227 A 0.95814509734919673 0.95814509734919673 0 0 0 11.923492431640625 9.5611610412597656 A 1.3168920212103361 1.3168920212103361 0 0 1 11.968143463134766 9.490142822265625 A 0.42535393743902622 0.42535393743902622 0 0 1 12.195813179016113 9.5716266632080078 A 0.49449500892540521 0.49449500892540521 0 0 1 12.132782936096191 9.291203498840332 A 1.316876424898668 1.316876424898668 0 0 1 12.249565124511719 9.1883354187011719 M 11.295418739318848 9.5228471755981445 A 3.3471616951961658 3.3471616951961658 0 0 1 11.591294288635254 8.9563255310058594 A 1.1940905005189721 1.1940905005189721 0 0 1 11.640105247497559 9.0352640151977539 A 0.53451919889927524 0.53451919889927524 0 0 0 11.61414623260498 9.183079719543457 A 0.37087118303051625 0.37087118303051625 0 0 0 11.625289916992188 9.2929468154907227 A 0.23581457521188523 0.23581457521188523 0 0 0 11.670955657958984 9.3819742202758789 A 0.22817300264094964 0.22817300264094964 0 0 0 11.751995086669922 9.4437847137451172 A 0.41252707205833172 0.41252707205833172 0 0 0 11.875471115112305 9.4770336151123047 A 1.9610780675901722 1.9610780675901722 0 0 1 11.838114738464355 9.5389261245727539 A 1.0843243990590457 1.0843243990590457 0 0 0 11.62147045135498 9.5807533264160156 A 0.79306877295997835 0.79306877295997835 0 0 0 11.430355072021484 9.6652631759643555 A 6.1914205188943319 6.1914205188943319 0 0 1 11.295417785644531 9.5228471755981445 M 13.465214729309082 9.9118204116821289 A 0.67549942373415262 0.67549942373415262 0 0 0 13.42475700378418 9.7664403915405273 A 0.23841593631996286 0.23841593631996286 0 0 0 13.571115493774414 9.7215576171875 A 0.61783351084200011 0.61783351084200011 0 0 0 13.465214729309082 9.9118204116821289 M 13.303418159484863 10.508131980895996 A 0.96202193550918602 0.96202193550918602 0 0 1 13.205599784851074 10.706750869750977 A 1.8687781708576441 1.8687781708576441 0 0 1 12.934439659118652 10.336627006530762 A 2.0748370882648772 2.0748370882648772 0 0 1 13.168878555297852 10.294002532958984 A 0.63387839045862371 0.63387839045862371 0 0 0 13.28911018371582 10.26451587677002 A 0.26619937952610567 0.26619937952610567 0 0 0 13.387394905090332 10.207462310791016 A 3.4645820234655194 3.4645820234655194 0 0 1 13.30341911315918 10.508131980895996 M 14.968835830688477 9.3871517181396484 A 1.6262428280205419 1.6262428280205419 0 0 1 14.714859008789063 9.5718173980712891 A 0.30573145701094118 0.30573145701094118 0 0 1 14.567305564880371 9.6212329864501953 A 0.3250735992290304 0.3250735992290304 0 0 1 14.416353225708008 9.5835800170898437 A 0.54886958602762925 0.54886958602762925 0 0 0 14.192893028259277 9.5280723571777344 A 1.043375040536356 1.043375040536356 0 0 1 14.417214393615723 9.3516178131103516 A 1.948422459191351 1.948422459191351 0 0 1 14.968835830688477 9.3871517181396484 M 14.906814575195312 9.0799369812011719 A 0.8269007104262035 0.8269007104262035 0 0 0 15.067436218261719 8.9355497360229492 L 15.067437171936035 9.1449441909790039 A 3.9604953920143369 3.9604953920143369 0 0 0 15.040722846984863 9.2062091827392578 A 0.11306265683405703 0.11306265683405703 0 0 1 14.936817169189453 9.2550849914550781 A 0.66574000764433328 0.66574000764433328 0 0 1 14.84355640411377 9.2503747940063477 A 1.3946353016901396 1.3946353016901396 0 0 0 14.741806983947754 9.2426919937133789 A 1.2902525879542925 1.2902525879542925 0 0 0 14.636587142944336 9.2427520751953125 A 2.7345282795606827 2.7345282795606827 0 0 0 14.906813621520996 9.0799369812011719 M 13.885219573974609 9.529179573059082 A 0.56156479211006727 0.56156479211006727 0 0 0 13.682110786437988 9.6143331527709961 A 0.62286231034154438 0.62286231034154438 0 0 0 13.736110687255859 9.5332975387573242 A 2.127854181010028 2.127854181010028 0 0 1 14.098199844360352 9.4036149978637695 A 0.76356791974935823 0.76356791974935823 0 0 1 14.106000900268555 9.5177297592163086 A 0.79932904326896526 0.79932904326896526 0 0 0 13.885218620300293 9.529179573059082 M 12.48554515838623 12.446409225463867 A 0.2052721507000598 0.2052721507000598 0 0 1 12.544971466064453 12.510961532592773 A 0.99613946816950394 0.99613946816950394 0 0 0 12.654545783996582 12.852882385253906 A 0.49091826997167892 0.49091826997167892 0 0 0 12.820882797241211 13.034442901611328 A 0.98371537389116837 0.98371537389116837 0 0 0 12.665771484375 13.055975914001465 A 0.58536601875489813 0.58536601875489813 0 0 1 12.33576488494873 12.733254432678223 A 2.8921091604089662 2.8921091604089662 0 0 0 12.48554515838623 12.446408271789551 M 12.169836044311523 12.352564811706543 A 0.49173411436005382 0.49173411436005382 0 0 0 12.150543212890625 12.166766166687012 A 0.45874381183325758 0.45874381183325758 0 0 1 12.3768310546875 12.066810607910156 A 3.1748658051503345 3.1748658051503345 0 0 1 11.85093879699707 12.906133651733398 A 3.2962218430276589 3.2962218430276589 0 0 1 11.650306701660156 12.647636413574219 A 0.55151957629823911 0.55151957629823911 0 0 1 11.818924903869629 12.60484790802002 A 1.8139890296737744 1.8139890296737744 0 0 0 11.967218399047852 12.581398963928223 A 0.24943886684434574 0.24943886684434574 0 0 0 12.130973815917969 12.475085258483887 A 0.26256388952463433 0.26256388952463433 0 0 0 12.169836044311523 12.352563858032227 M 14.900341033935547 12.639135360717773 A 1.5750164464474807 1.5750164464474807 0 0 1 15.067438125610352 12.407814025878906 L 15.067437171936035 12.883373260498047 A 1.7237387423311847 1.7237387423311847 0 0 0 14.90034008026123 12.639135360717773 M 13.984031677246094 23.3492431640625 A 2.8044273552326597 2.8044273552326597 0 0 1 14.086828231811523 23.697967529296875 A 1.6544117125613285 1.6544117125613285 0 0 0 13.897467613220215 23.758474349975586 A 0.41379231950729578 0.41379231950729578 0 0 1 13.704727172851563 23.799789428710938 A 0.40871557257632535 0.40871557257632535 0 0 0 13.480177879333496 23.608530044555664 A 0.70773211227501642 0.70773211227501642 0 0 1 13.427859306335449 23.439786911010742 A 0.93035766946621257 0.93035766946621257 0 0 1 13.408803939819336 23.28108024597168 A 34.655360995318631 34.655360995318631 0 0 0 13.396556854248047 23.108261108398438 A 0.76256409411250459 0.76256409411250459 0 0 0 13.342825889587402 22.858127593994141 A 0.39678724886377503 0.39678724886377503 0 0 0 13.228450775146484 22.708646774291992 A 0.39899085949113861 0.39899085949113861 0 0 0 13.142385482788086 22.656583786010742 A 3.4948646460622919 3.4948646460622919 0 0 0 13.461080551147461 22.561588287353516 A 1.2350746438577633 1.2350746438577633 0 0 1 13.654308319091797 22.517696380615234 A 0.66576597241771196 0.66576597241771196 0 0 1 13.726824760437012 22.513078689575195 A 0.52597817485106746 0.52597817485106746 0 0 1 13.84773063659668 22.527067184448242 A 0.56964814274132425 0.56964814274132425 0 0 1 13.700374603271484 22.401422500610352 A 1.2350742811878714 1.2350742811878714 0 0 1 13.589638710021973 22.237104415893555 L 13.491503715515137 22.059820175170898 A 0.76304838672257291 0.76304838672257291 0 0 0 13.337696075439453 21.85539436340332 A 0.43484075275364326 0.43484075275364326 0 0 0 13.24052619934082 21.792074203491211 A 0.4169373239310481 0.4169373239310481 0 0 0 13.071907043457031 21.756185531616211 A 0.70449947174172445 0.70449947174172445 0 0 0 12.760222434997559 21.847192764282227 A 1.1669455415365182 1.1669455415365182 0 0 0 12.631304740905762 21.9295654296875 A 0.056723269651478461 0.056723269651478461 0 0 1 12.555633544921875 21.856376647949219 A 3.8798880860064155 3.8798880860064155 0 0 0 12.857873916625977 20.149677276611328 A 0.9692604724751992 0.9692604724751992 0 0 1 13.228790283203125 20.692966461181641 A 1.2357223083060567 1.2357223083060567 0 0 0 13.04178524017334 21.134252548217773 A 0.59743477055137584 0.59743477055137584 0 0 0 13.054962158203125 21.453357696533203 A 0.5485625815463282 0.5485625815463282 0 0 0 13.23188304901123 21.705493927001953 A 1.0050693292678667 1.0050693292678667 0 0 0 13.425930023193359 21.825115203857422 A 5.1990786441050751 5.1990786441050751 0 0 1 13.910654067993164 22.061185836791992 A 0.59572981418721427 0.59572981418721427 0 0 1 13.916983604431152 22.32868766784668 A 0.55888132545411751 0.55888132545411751 0 0 1 14.05135440826416 22.170316696166992 A 0.65237355646535522 0.65237355646535522 0 0 1 14.137326240539551 22.272491455078125 A 0.6568610386611633 0.6568610386611633 0 0 1 14.107027053833008 22.129423141479492 A 1.4576599532097074 1.4576599532097074 0 0 1 14.234807014465332 22.049108505249023 A 3.905424018924704 3.905424018924704 0 0 1 14.240797996520996 22.045675277709961 A 2.663566659390443 2.663566659390443 0 0 0 14.488101005554199 21.896965026855469 A 0.41648461022410072 0.41648461022410072 0 0 0 14.669228553771973 21.460056304931641 A 0.76941127575826918 0.76941127575826918 0 0 0 14.565456390380859 21.201837539672852 A 0.55379238947221876 0.55379238947221876 0 0 1 14.768148422241211 20.923139572143555 A 3.9604950267034811 3.9604950267034811 0 0 0 14.906646728515625 21.52171516418457 A 1.3772206587014302 1.3772206587014302 0 0 1 14.750967979431152 22.138086318969727 A 1.4384659131087609 1.4384659131087609 0 0 0 14.138398170471191 22.358861923217773 A 0.61902938160140475 0.61902938160140475 0 0 0 13.877704620361328 22.761074066162109 A 0.74981457249614125 0.74981457249614125 0 0 0 13.909224510192871 23.106014251708984 A 2.3873453603342538 2.3873453603342538 0 0 0 13.984031677246094 23.349241256713867 M 12.05817985534668 22.725809097290039 A 5.6923776816881615 5.6923776816881615 0 0 0 12.235755920410156 22.471508026123047 A 0.70537513154526843 0.70537513154526843 0 0 1 12.527039527893066 22.733352661132813 A 1.1683850759225474 1.1683850759225474 0 0 0 12.501161575317383 22.836643218994141 A 0.90937112568361567 0.90937112568361567 0 0 0 12.486189842224121 23.116092681884766 A 0.44205278495683897 0.44205278495683897 0 0 0 12.598516464233398 23.376091003417969 A 0.45359210264867289 0.45359210264867289 0 0 0 12.829477310180664 23.503025054931641 A 1.5313951473469181 1.5313951473469181 0 0 0 13.013521194458008 23.533052444458008 A 1.3692360810007553 1.3692360810007553 0 0 1 13.408272743225098 23.613311767578125 A 0.31379728330145362 0.31379728330145362 0 0 0 13.304646492004395 23.642475128173828 A 0.72776872978214058 0.72776872978214058 0 0 0 13.179466247558594 23.732339859008789 A 0.70656255542414936 0.70656255542414936 0 0 1 13.067482948303223 23.811716079711914 A 0.32613861859730486 0.32613861859730486 0 0 1 12.949239730834961 23.850414276123047 A 0.38170409203997868 0.38170409203997868 0 0 1 13.124617576599121 23.941308975219727 A 2.7878017507562207 2.7878017507562207 0 0 0 13.276917457580566 24.070529937744141 A 0.51140986946259392 0.51140986946259392 0 0 0 13.110154151916504 24.07612419128418 A 0.27536890959181459 0.27536890959181459 0 0 0 12.941606521606445 24.172872543334961 A 0.26831759550791351 0.26831759550791351 0 0 0 12.878212928771973 24.351417541503906 A 36.788067268209808 36.788067268209808 0 0 1 12.863204956054688 24.566333770751953 A 2.0326889254437326 2.0326889254437326 0 0 1 12.802179336547852 24.426713943481445 A 4.0573301689006218 4.0573301689006218 0 0 0 12.058181762695313 22.725809097290039 M 12.109626770019531 23.317035675048828 A 3.3471612700802122 3.3471612700802122 0 0 1 12.405501365661621 23.883556365966797 A 6.191420080744118 6.191420080744118 0 0 1 12.270565986633301 24.025972366333008 A 0.7930682673911289 0.7930682673911289 0 0 0 12.079451560974121 23.941461563110352 A 1.0843244248326545 1.0843244248326545 0 0 0 11.86280632019043 23.899633407592773 A 1.9610784582897467 1.9610784582897467 0 0 1 11.82544994354248 23.837739944458008 A 0.41252566461540202 0.41252566461540202 0 0 0 11.948925971984863 23.804492950439453 A 0.22817272700178604 0.22817272700178604 0 0 0 12.029966354370117 23.742683410644531 A 0.23581490533049726 0.23581490533049726 0 0 0 12.075631141662598 23.653656005859375 A 0.37087106503345751 0.37087106503345751 0 0 0 12.086774826049805 23.543788909912109 A 0.53451951341820836 0.53451951341820836 0 0 0 12.060815811157227 23.395973205566406 A 1.1940894530032173 1.1940894530032173 0 0 1 12.109626770019531 23.317035675048828 M 14.906814575195312 23.440647125244141 A 0.82690153996200466 0.82690153996200466 0 0 0 15.067436218261719 23.296258926391602 L 15.067437171936035 23.505651473999023 A 3.9604953920143369 3.9604953920143369 0 0 0 15.040722846984863 23.566917419433594 A 0.11306179579941213 0.11306179579941213 0 0 1 14.936817169189453 23.615793228149414 A 0.66574066788559372 0.66574066788559372 0 0 1 14.84355640411377 23.611082077026367 A 1.3946353016901396 1.3946353016901396 0 0 0 14.741806983947754 23.603401184082031 A 1.290252108312578 1.290252108312578 0 0 0 14.636587142944336 23.603462219238281 A 2.734529066674777 2.734529066674777 0 0 0 14.906813621520996 23.440645217895508 M 5.6730451583862305 23.697967529296875 A 2.8044274038358621 2.8044274038358621 0 0 1 5.7758417129516602 23.3492431640625 A 2.3873455728637922 2.3873455728637922 0 0 0 5.8506488800048828 23.106014251708984 A 0.74981455494037186 0.74981455494037186 0 0 0 5.8821687698364258 22.761074066162109 A 0.61902898691988251 0.61902898691988251 0 0 0 5.6214756965637207 22.358861923217773 A 1.4384659665580932 1.4384659665580932 0 0 0 5.0089058876037598 22.138088226318359 A 1.377220885070864 1.377220885070864 0 0 1 4.8532271385192871 21.52171516418457 A 3.9604948895712315 3.9604948895712315 0 0 0 4.9917254447937012 20.923139572143555 A 0.55379185792757668 0.55379185792757668 0 0 1 5.1944174766540527 21.201837539672852 A 0.76941145729709526 0.76941145729709526 0 0 0 5.0906448364257812 21.460056304931641 A 0.41648466811071472 0.41648466811071472 0 0 0 5.2717723846435547 21.896965026855469 A 2.6635668619908466 2.6635668619908466 0 0 0 5.519075870513916 22.045675277709961 A 3.9054253123523037 3.9054253123523037 0 0 1 5.5250716209411621 22.049100875854492 A 1.4576597973631229 1.4576597973631229 0 0 1 5.6528472900390625 22.129423141479492 A 0.65686059501270277 0.65686059501270277 0 0 1 5.6225476264953613 22.272491455078125 A 0.65237319088504098 0.65237319088504098 0 0 1 5.7085189819335938 22.170316696166992 A 0.55888172409761072 0.55888172409761072 0 0 1 5.8428888320922852 22.328685760498047 A 0.59573045913091471 0.59573045913091471 0 0 1 5.8492217063903809 22.061183929443359 A 5.1990783151426454 5.1990783151426454 0 0 1 6.3339447975158691 21.825113296508789 A 1.0050700013185219 1.0050700013185219 0 0 0 6.5279903411865234 21.705493927001953 A 0.54856273629778607 0.54856273629778607 0 0 0 6.7049107551574707 21.453357696533203 A 0.59743430079136839 0.59743430079136839 0 0 0 6.7180881500244141 21.134254455566406 A 1.2357216516742644 1.2357216516742644 0 0 0 6.5310831069946289 20.692966461181641 A 0.96926078399799831 0.96926078399799831 0 0 1 6.9019994735717773 20.149677276611328 A 3.8798878848050546 3.8798878848050546 0 0 0 7.2042403221130371 21.856374740600586 A 0.056723873965597214 0.056723873965597214 0 0 1 7.1285696029663086 21.9295654296875 A 1.1669449487773902 1.1669449487773902 0 0 0 6.9996514320373535 21.847192764282227 A 0.70449939410799456 0.70449939410799456 0 0 0 6.6879663467407227 21.756187438964844 A 0.41693726339910814 0.41693726339910814 0 0 0 6.51934814453125 21.792074203491211 A 0.43483995194132091 0.43483995194132091 0 0 0 6.422177791595459 21.855392456054688 A 0.76304973319073155 0.76304973319073155 0 0 0 6.2683701515197754 22.059820175170898 L 6.1702346801757813 22.237102508544922 A 1.2350737970620274 1.2350737970620274 0 0 1 6.0594987869262695 22.401422500610352 A 0.56964795121611533 0.56964795121611533 0 0 1 5.9121427536010742 22.527067184448242 A 0.52597825310824442 0.52597825310824442 0 0 1 6.0330491065979004 22.513078689575195 A 0.66576599133068359 0.66576599133068359 0 0 1 6.1055660247802734 22.517696380615234 A 1.2350743408103149 1.2350743408103149 0 0 1 6.2987937927246094 22.561588287353516 A 3.4948655857474975 3.4948655857474975 0 0 0 6.617487907409668 22.656585693359375 A 0.39898959867864653 0.39898959867864653 0 0 0 6.5314235687255859 22.708646774291992 A 0.39678749756995552 0.39678749756995552 0 0 0 6.4170475006103516 22.858127593994141 A 0.76256467094122993 0.76256467094122993 0 0 0 6.3633155822753906 23.108247756958008 A 34.655359335358852 34.655359335358852 0 0 0 6.3510723114013672 23.28106689453125 A 0.9303569759138971 0.9303569759138971 0 0 1 6.3320140838623047 23.439788818359375 A 0.70773147516963619 0.70773147516963619 0 0 1 6.2796950340270996 23.608530044555664 A 0.40871557452481067 0.40871557452481067 0 0 0 6.0551466941833496 23.799789428710938 A 0.41379239189346567 0.41379239189346567 0 0 1 5.8624067306518555 23.758474349975586 A 1.6544108733481928 1.6544108733481928 0 0 0 5.6730446815490723 23.697967529296875 M 5.1232867240905762 23.603462219238281 A 1.290252099747464 1.290252099747464 0 0 0 5.0180668830871582 23.603401184082031 A 1.3946353033935242 1.3946353033935242 0 0 0 4.9163179397583008 23.611083984375 A 0.66574066686440425 0.66574066686440425 0 0 1 4.823056697845459 23.615793228149414 A 0.11306191427471897 0.11306191427471897 0 0 1 4.719151496887207 23.566919326782227 A 3.9604950740840281 3.9604950740840281 0 0 0 4.692436695098877 23.505651473999023 L 4.692436695098877 23.296257019042969 A 0.82690110625229341 0.82690110625229341 0 0 0 4.8530588150024414 23.440647125244141 A 2.7345287885616312 2.7345287885616312 0 0 0 5.1232872009277344 23.603458404541016 M 10.19145679473877 23.864316940307617 A 0.53287796085617145 0.53287796085617145 0 0 1 9.9161138534545898 23.547859191894531 A 0.69367054156565 0.69367054156565 0 0 1 9.8820276260375977 23.401124954223633 L 9.8778457641601562 23.401124954223633 A 0.69367053655449762 0.69367053655449762 0 0 1 9.8437595367431641 23.547859191894531 A 0.53287771944859186 0.53287771944859186 0 0 1 9.5684165954589844 23.864316940307617 A 1.3070264486466605 1.3070264486466605 0 0 1 9.6540422439575195 23.440908432006836 A 20.87714381388432 20.87714381388432 0 0 0 9.727630615234375 23.221456527709961 A 0.8769321147167024 0.8769321147167024 0 0 0 9.7807140350341797 22.85675048828125 A 0.54100401568822643 0.54100401568822643 0 0 0 9.5699195861816406 22.48590087890625 A 1.216708583673908 1.216708583673908 0 0 0 8.9962053298950195 22.262886047363281 A 1.3851541102050995 1.3851541102050995 0 0 1 8.7671699523925781 21.52171516418457 A 3.9769236832603978 3.9769236832603978 0 0 0 8.9056692123413086 20.923137664794922 A 0.52740824848100631 0.52740824848100631 0 0 1 9.0748424530029297 21.120700836181641 A 0.81710747860420652 0.81710747860420652 0 0 0 8.9263105392456055 21.462657928466797 A 0.39838231588658152 0.39838231588658152 0 0 0 9.0199308395385742 21.796470642089844 A 0.72813929213921424 0.72813929213921424 0 0 0 9.2409934997558594 21.961471557617188 A 2.0237599502643455 2.0237599502643455 0 0 1 9.5609474182128906 22.164182662963867 A 0.57493457986964158 0.57493457986964158 0 0 1 9.6820468902587891 22.310674667358398 A 0.70664756151211783 0.70664756151211783 0 0 1 9.7212553024291992 21.924470901489258 A 4.6192385056749146 4.6192385056749146 0 0 0 9.8149528503417969 21.62919807434082 A 0.43882611094634161 0.43882611094634161 0 0 0 9.7697610855102539 21.275686264038086 A 0.54008053373595111 0.54008053373595111 0 0 0 9.495631217956543 21.068464279174805 A 1.1683107738983289 1.1683107738983289 0 0 0 9.2433395385742187 21.000818252563477 A 0.4577895877694399 0.4577895877694399 0 0 1 8.9445524215698242 20.539691925048828 A 0.51127706694178299 0.51127706694178299 0 0 1 9.0971145629882812 20.635835647583008 A 0.49394915882181106 0.49394915882181106 0 0 0 9.1645908355712891 20.804433822631836 A 0.23369597355791913 0.23369597355791913 0 0 0 9.3499088287353516 20.920818328857422 A 0.3541003810324333 0.3541003810324333 0 0 0 9.486933708190918 20.899785995483398 A 9.5192548964767489 9.5192548964767489 0 0 0 9.6111288070678711 20.85820198059082 A 0.57248979125491362 0.57248979125491362 0 0 1 9.7224521636962891 20.83148193359375 A 0.29559291348889982 0.29559291348889982 0 0 1 9.8292570114135742 20.835504531860352 A 0.41065978878553339 0.41065978878553339 0 0 1 9.6810684204101562 20.67384147644043 A 2.4153528971400409 2.4153528971400409 0 0 0 9.5894203186035156 20.520135879516602 A 0.25508654201970854 0.25508654201970854 0 0 0 9.4516992568969727 20.415338516235352 A 0.2372763979292031 0.2372763979292031 0 0 0 9.3258934020996094 20.414278030395508 A 0.53097475251938464 0.53097475251938464 0 0 0 9.1161861419677734 20.524721145629883 A 0.38210689902740547 0.38210689902740547 0 0 1 8.9499597549438477 20.346307754516602 A 3.9564230426929119 3.9564230426929119 0 0 0 8.7935581207275391 19.23077392578125 A 0.94172771647992837 0.94172771647992837 0 0 1 9.0905961990356445 19.527126312255859 A 0.74392480577472719 0.74392480577472719 0 0 1 9.1833105087280273 19.926576614379883 A 1.106070848640099 1.106070848640099 0 0 1 9.0914735794067383 20.322607040405273 A 0.61357519978731023 0.61357519978731023 0 0 0 9.285243034362793 20.289499282836914 A 0.42229068020926297 0.42229068020926297 0 0 0 9.4885053634643555 20.130231857299805 A 0.4530792410165802 0.4530792410165802 0 0 0 9.5578861236572266 19.758916854858398 A 0.48471954404575063 0.48471954404575063 0 0 0 9.3884382247924805 19.492124557495117 A 0.92274728047631738 0.92274728047631738 0 0 0 9.0779314041137695 19.315885543823242 A 0.82113398476760235 0.82113398476760235 0 0 1 9.3274755477905273 19.372268676757813 A 0.78889754278393842 0.78889754278393842 0 0 0 9.4981508255004883 19.429130554199219 A 0.32122053425289276 0.32122053425289276 0 0 0 9.6605319976806641 19.426250457763672 A 0.22433566255745355 0.22433566255745355 0 0 0 9.7870903015136719 19.323514938354492 A 0.44787120023867361 0.44787120023867361 0 0 0 9.8462228775024414 19.155271530151367 A 1.2571250421665725 1.2571250421665725 0 0 0 9.8435821533203125 18.760957717895508 A 0.53287771944859186 0.53287771944859186 0 0 1 9.5682392120361328 19.077413558959961 A 1.3070264486466605 1.3070264486466605 0 0 1 9.6538639068603516 18.654006958007813 A 20.877143515702652 20.877143515702652 0 0 0 9.727452278137207 18.434553146362305 A 0.8769321147167024 0.8769321147167024 0 0 0 9.7805356979370117 18.069847106933594 A 0.54100401568822643 0.54100401568822643 0 0 0 9.5697412490844727 17.698997497558594 A 1.216708583673908 1.216708583673908 0 0 0 8.9960269927978516 17.475982666015625 A 1.3851541102050995 1.3851541102050995 0 0 1 8.7669925689697266 16.734811782836914 A 3.9769233656090912 3.9769233656090912 0 0 0 8.905491828918457 16.136236190795898 A 0.52740824848100631 0.52740824848100631 0 0 1 9.0746650695800781 16.333797454833984 A 0.81710747860420652 0.81710747860420652 0 0 0 8.9261322021484375 16.675756454467773 A 0.39838231588658152 0.39838231588658152 0 0 0 9.0197525024414062 17.009567260742188 A 0.72813929213921424 0.72813929213921424 0 0 0 9.2408151626586914 17.174568176269531 A 2.0237599502643455 2.0237599502643455 0 0 1 9.5607700347900391 17.377279281616211 A 0.57493457986964158 0.57493457986964158 0 0 1 9.6818695068359375 17.523771286010742 A 0.70664756151211783 0.70664756151211783 0 0 1 9.7210779190063477 17.137567520141602 A 4.6192385305378707 4.6192385305378707 0 0 0 9.8147754669189453 16.842296600341797 A 0.43882611094634161 0.43882611094634161 0 0 0 9.7695827484130859 16.488784790039063 A 0.54008053373595111 0.54008053373595111 0 0 0 9.4954538345336914 16.281560897827148 A 1.1683107738983289 1.1683107738983289 0 0 0 9.2431621551513672 16.21391487121582 A 0.46280978187794919 0.46280978187794919 0 0 1 9.0169057846069336 16.033182144165039 A 0.41532324377397439 0.41532324377397439 0 0 1 8.9443750381469727 15.752791404724121 A 0.51127789496974096 0.51127789496974096 0 0 1 9.0969362258911133 15.848931312561035 A 0.49394886472272942 0.49394886472272942 0 0 0 9.1644134521484375 16.01753044128418 A 0.23369495240943691 0.23369495240943691 0 0 0 9.3497314453125 16.133914947509766 A 0.3541003810324333 0.3541003810324333 0 0 0 9.4867563247680664 16.112882614135742 A 9.5192542908603617 9.5192542908603617 0 0 0 9.6109504699707031 16.071298599243164 A 0.57248979125491362 0.57248979125491362 0 0 1 9.7222747802734375 16.044578552246094 A 0.29559291348889982 0.29559291348889982 0 0 1 9.8290786743164062 16.048603057861328 A 0.4106602391410899 0.4106602391410899 0 0 1 9.6808900833129883 15.886940002441406 A 2.4153521691593167 2.4153521691593167 0 0 0 9.5892419815063477 15.733234405517578 A 0.25508654201970854 0.25508654201970854 0 0 0 9.4515209197998047 15.628435134887695 A 0.23727590776463292 0.23727590776463292 0 0 0 9.3257160186767578 15.627375602722168 A 0.5309745488445089 0.5309745488445089 0 0 0 9.1160087585449219 15.737817764282227 A 0.38210737428366137 0.38210737428366137 0 0 1 8.9497823715209961 15.559404373168945 A 3.9564228966138169 3.9564228966138169 0 0 0 8.7933807373046875 14.44387149810791 A 0.52907013729812913 0.52907013729812913 0 0 1 9.0875320434570312 14.728728294372559 A 2.1382119367162296 2.1382119367162296 0 0 1 9.1926670074462891 15.140326499938965 A 0.69725437832114834 0.69725437832114834 0 0 0 9.3492774963378906 15.424674034118652 A 0.23401931895229308 0.23401931895229308 0 0 0 9.5197772979736328 15.51324462890625 A 0.27105640534167147 0.27105640534167147 0 0 0 9.6865482330322266 15.461913108825684 A 0.48507929252855275 0.48507929252855275 0 0 0 9.8799371719360352 15.151183128356934 A 0.48507922842809043 0.48507922842809043 0 0 0 10.073325157165527 15.461913108825684 A 0.27105661135631681 0.27105661135631681 0 0 0 10.240096092224121 15.51324462890625 A 0.23401963954775135 0.23401963954775135 0 0 0 10.410595893859863 15.424674034118652 A 0.69725441431264967 0.69725441431264967 0 0 0 10.567206382751465 15.140327453613281 A 2.1382123304719887 2.1382123304719887 0 0 1 10.672341346740723 14.728727340698242 A 0.52907065172171497 0.52907065172171497 0 0 1 10.966493606567383 14.443868637084961 A 3.9564228745449515 3.9564228745449515 0 0 0 10.810091018676758 15.559405326843262 A 0.38210698885652422 0.38210698885652422 0 0 1 10.643864631652832 15.737818717956543 A 0.53097467479071125 0.53097467479071125 0 0 0 10.434157371520996 15.627375602722168 A 0.23727598424582746 0.23727598424582746 0 0 0 10.308351516723633 15.628435134887695 A 0.25508653615813193 0.25508653615813193 0 0 0 10.170632362365723 15.733232498168945 A 2.4153528294692115 2.4153528294692115 0 0 0 10.078984260559082 15.886940002441406 A 0.4106607256590577 0.4106607256590577 0 0 1 9.9307947158813477 16.048603057861328 A 0.29559283346620535 0.29559283346620535 0 0 1 10.037598609924316 16.044578552246094 A 0.57248978434183617 0.57248978434183617 0 0 1 10.148921966552734 16.071298599243164 A 9.5192550723571241 9.5192550723571241 0 0 0 10.273116111755371 16.112882614135742 A 0.35410038904476215 0.35410038904476215 0 0 0 10.410141944885254 16.133914947509766 A 0.23369525196910046 0.23369525196910046 0 0 0 10.595459938049316 16.01753044128418 A 0.49394871405133789 0.49394871405133789 0 0 0 10.662936210632324 15.848932266235352 A 0.51127732789817693 0.51127732789817693 0 0 1 10.815499305725098 15.752790451049805 A 0.41532325837259465 0.41532325837259465 0 0 1 10.74296760559082 16.033182144165039 A 0.4628094445701143 0.4628094445701143 0 0 1 10.516712188720703 16.21391487121582 A 1.1683108381839773 1.1683108381839773 0 0 0 10.264420509338379 16.281558990478516 A 0.54008082641477662 0.54008082641477662 0 0 0 9.990290641784668 16.488784790039063 A 0.43882624507429946 0.43882624507429946 0 0 0 9.9450979232788086 16.842296600341797 A 4.6192378940703822 4.6192378940703822 0 0 0 10.038796424865723 17.137567520141602 A 0.70664778042930154 0.70664778042930154 0 0 1 10.078004837036133 17.523771286010742 A 0.57493482662222195 0.57493482662222195 0 0 1 10.199103355407715 17.377277374267578 A 2.0237597930567901 2.0237597930567901 0 0 1 10.519057273864746 17.174568176269531 A 0.72813944271484021 0.72813944271484021 0 0 0 10.740120887756348 17.009567260742188 A 0.39838188670633617 0.39838188670633617 0 0 0 10.833741188049316 16.675754547119141 A 0.8171076366100577 0.8171076366100577 0 0 0 10.685209274291992 16.333797454833984 A 0.52740743057909478 0.52740743057909478 0 0 1 10.854381561279297 16.136236190795898 A 3.9769238682900871 3.9769238682900871 0 0 0 10.992880821228027 16.734811782836914 A 1.385154075109732 1.385154075109732 0 0 1 10.763846397399902 17.475982666015625 A 1.2167109152062265 1.2167109152062265 0 0 0 10.190132141113281 17.698997497558594 A 0.54100379191043491 0.54100379191043491 0 0 0 9.9793376922607422 18.069847106933594 A 0.87693249924797234 0.87693249924797234 0 0 0 10.032421112060547 18.434553146362305 A 20.87714351701025 20.87714351701025 0 0 0 10.106008529663086 18.654003143310547 A 1.3070264547844079 1.3070264547844079 0 0 1 10.191728591918945 19.07746696472168 A 0.53287796085617145 0.53287796085617145 0 0 1 9.9162912368774414 18.760955810546875 A 1.2571246499087032 1.2571246499087032 0 0 0 9.9136495590209961 19.155271530151367 A 0.44787171618693927 0.44787171618693927 0 0 0 9.9727821350097656 19.323514938354492 A 0.2243353136047159 0.2243353136047159 0 0 0 10.099342346191406 19.426252365112305 A 0.32122072195578755 0.32122072195578755 0 0 0 10.261722564697266 19.429128646850586 A 0.78889757888945633 0.78889757888945633 0 0 0 10.432397842407227 19.372268676757813 A 0.82113392634625415 0.82113392634625415 0 0 1 10.681942939758301 19.315883636474609 A 0.92274615524724413 0.92274615524724413 0 0 0 10.371435165405273 19.492124557495117 A 0.48472009816280731 0.48472009816280731 0 0 0 10.201988220214844 19.758916854858398 A 0.45307858778090382 0.45307858778090382 0 0 0 10.271368026733398 20.130229949951172 A 0.42229085951587364 0.42229085951587364 0 0 0 10.474629402160645 20.289501190185547 A 0.61357530987381059 0.61357530987381059 0 0 0 10.668399810791016 20.322605133056641 A 1.1060706477718008 1.1060706477718008 0 0 1 10.576563835144043 19.926578521728516 A 0.74392484567917183 0.74392484567917183 0 0 1 10.669277191162109 19.527124404907227 A 0.94172742160250578 0.94172742160250578 0 0 1 10.966316223144531 19.230772018432617 A 3.9564228813075033 3.9564228813075033 0 0 0 10.80991268157959 20.346307754516602 A 0.38210653500622954 0.38210653500622954 0 0 1 10.64368724822998 20.524721145629883 A 0.53097486193113597 0.53097486193113597 0 0 0 10.433979988098145 20.414279937744141 A 0.23727638050602762 0.23727638050602762 0 0 0 10.308174133300781 20.415336608886719 A 0.25508653615813193 0.25508653615813193 0 0 0 10.170454025268555 20.520135879516602 A 2.4153528294692115 2.4153528294692115 0 0 0 10.078805923461914 20.67384147644043 A 0.4106607256590577 0.4106607256590577 0 0 1 9.9306163787841797 20.835504531860352 A 0.29559283346620535 0.29559283346620535 0 0 1 10.037420272827148 20.831480026245117 A 0.57248978434183617 0.57248978434183617 0 0 1 10.148744583129883 20.85820198059082 A 9.5192550723571241 9.5192550723571241 0 0 0 10.27293872833252 20.899785995483398 A 0.35410038904476215 0.35410038904476215 0 0 0 10.409964561462402 20.920818328857422 A 0.2336956021255748 0.2336956021255748 0 0 0 10.595282554626465 20.804431915283203 A 0.4939490928343046 0.4939490928343046 0 0 0 10.662758827209473 20.635833740234375 A 0.51127873741315133 0.51127873741315133 0 0 1 10.81532096862793 20.539693832397461 A 0.45779097861065521 0.45779097861065521 0 0 1 10.516533851623535 21.000818252563477 A 1.1683108381839773 1.1683108381839773 0 0 0 10.264243125915527 21.068462371826172 A 0.54008082641477662 0.54008082641477662 0 0 0 9.9901123046875 21.275688171386719 A 0.43882624507429946 0.43882624507429946 0 0 0 9.944920539855957 21.62919807434082 A 4.6192377477854256 4.6192377477854256 0 0 0 10.038618087768555 21.924468994140625 A 0.70664778042930154 0.70664778042930154 0 0 1 10.077826499938965 22.310674667358398 A 0.57493482662222195 0.57493482662222195 0 0 1 10.198925971984863 22.164180755615234 A 2.0237597930567901 2.0237597930567901 0 0 1 10.518879890441895 21.961471557617188 A 0.72813944271484021 0.72813944271484021 0 0 0 10.73994255065918 21.796470642089844 A 0.39838188670633617 0.39838188670633617 0 0 0 10.833562850952148 21.462657928466797 A 0.8171076366100577 0.8171076366100577 0 0 0 10.685030937194824 21.120698928833008 A 0.52740743057909478 0.52740743057909478 0 0 1 10.854204177856445 20.923139572143555 A 3.976923582181739 3.976923582181739 0 0 0 10.992702484130859 21.52171516418457 A 1.385154075109732 1.385154075109732 0 0 1 10.763669013977051 22.262886047363281 A 1.2167109152062265 1.2167109152062265 0 0 0 10.189953804016113 22.48590087890625 A 0.54100379191043491 0.54100379191043491 0 0 0 9.9791593551635742 22.85675048828125 A 0.87693249924797234 0.87693249924797234 0 0 0 10.032242774963379 23.221456527709961 A 20.877143607043006 20.877143607043006 0 0 0 10.105831146240234 23.44090461730957 A 1.3070264547844079 1.3070264547844079 0 0 1 10.191550254821777 23.864368438720703 M 6.9576940536499023 24.426713943481445 A 2.0326885012825366 2.0326885012825366 0 0 1 6.8966689109802246 24.566333770751953 A 36.78806644760413 36.78806644760413 0 0 1 6.8816580772399902 24.351406097412109 A 0.26831729315193981 0.26831729315193981 0 0 0 6.8182668685913086 24.172874450683594 A 0.2753684746530633 0.2753684746530633 0 0 0 6.6497197151184082 24.07612419128418 A 0.51140992824604325 0.51140992824604325 0 0 0 6.4829564094543457 24.070529937744141 A 2.7878014290144564 2.7878014290144564 0 0 0 6.6352558135986328 23.941307067871094 A 0.38170220352804768 0.38170220352804768 0 0 1 6.8106346130371094 23.850414276123047 A 0.32613856134335639 0.32613856134335639 0 0 1 6.6923904418945313 23.811717987060547 A 0.70656301469569915 0.70656301469569915 0 0 1 6.5804076194763184 23.732339859008789 A 0.72776819893626765 0.72776819893626765 0 0 0 6.4552278518676758 23.642473220825195 A 0.31379742572639446 0.31379742572639446 0 0 0 6.3516011238098145 23.613311767578125 A 1.3692360224764084 1.3692360224764084 0 0 1 6.7463517189025879 23.533052444458008 A 1.5313968610926456 1.5313968610926456 0 0 0 6.9303956031799316 23.503025054931641 A 0.45359223633226542 0.45359223633226542 0 0 0 7.1614670753479004 23.375968933105469 A 0.4420517000149411 0.4420517000149411 0 0 0 7.2736830711364746 23.116092681884766 A 0.90937100721351105 0.90937100721351105 0 0 0 7.2587127685546875 22.836643218994141 A 1.1683846301274614 1.1683846301274614 0 0 0 7.2328343391418457 22.733352661132813 A 0.70537489511275309 0.70537489511275309 0 0 1 7.5241179466247559 22.471508026123047 A 5.6923775968144845 5.6923775968144845 0 0 0 7.7016921043395996 22.725807189941406 A 4.0573298136714309 4.0573298136714309 0 0 0 6.9576945304870605 24.426712036132813 M 8.1447515487670898 22.725753784179688 A 4.0510193392872811 4.0510193392872811 0 0 0 8.6119747161865234 21.932872772216797 A 1.2406461420174812 1.2406461420174812 0 0 1 8.8149900436401367 22.368795394897461 A 1.2823663144354225 1.2823663144354225 0 0 0 8.5988225936889648 22.777587890625 A 0.57503107920037499 0.57503107920037499 0 0 0 8.5873594284057617 23.111856460571289 A 0.54696797163103039 0.54696797163103039 0 0 0 8.7437553405761719 23.368070602416992 A 1.1465245124361456 1.1465245124361456 0 0 0 8.9404020309448242 23.511333465576172 A 14.654286875227626 14.654286875227626 0 0 0 9.1468029022216797 23.629005432128906 A 1.2051425986827764 1.2051425986827764 0 0 1 9.5026140213012695 23.895618438720703 A 0.63787827202546876 0.63787827202546876 0 0 1 9.0638933181762695 23.92152214050293 A 1.0639998603007932 1.0639998603007932 0 0 1 8.6871976852416992 23.701070785522461 A 3.9931946967182954 3.9931946967182954 0 0 0 8.1447525024414062 22.725753784179688 M 7.354372501373291 23.883554458618164 A 3.3471616951961658 3.3471616951961658 0 0 1 7.6502475738525391 23.317033767700195 A 1.1940906544693597 1.1940906544693597 0 0 1 7.6990580558776855 23.395971298217773 A 0.53451926181804998 0.53451926181804998 0 0 0 7.6730985641479492 23.543788909912109 A 0.37087117214129711 0.37087117214129711 0 0 0 7.684241771697998 23.653656005859375 A 0.2358147067448858 0.2358147067448858 0 0 0 7.7299075126647949 23.742683410644531 A 0.2281722519990757 0.2281722519990757 0 0 0 7.8109478950500488 23.804494857788086 A 0.412525868285672 0.412525868285672 0 0 0 7.9344229698181152 23.837739944458008 A 1.9610784722817698 1.9610784722817698 0 0 1 7.8970675468444824 23.899633407592773 A 1.084324261498123 1.084324261498123 0 0 0 7.6804227828979492 23.941461563110352 A 0.79306827573241545 0.79306827573241545 0 0 0 7.4893074035644531 24.025970458984375 A 6.1914203068888547 6.1914203068888547 0 0 1 7.3543715476989746 23.883556365966797 M 8.3085174560546875 23.549043655395508 A 3.2402764283476237 3.2402764283476237 0 0 1 8.6942453384399414 24.829790115356445 A 0.32791315447169994 0.32791315447169994 0 0 0 8.6423501968383789 24.746912002563477 A 0.32520306053047587 0.32520306053047587 0 0 0 8.4502687454223633 24.649875640869141 A 0.33863522449303995 0.33863522449303995 0 0 0 8.2797536849975586 24.654481887817383 A 0.12581552866723444 0.12581552866723444 0 0 1 8.1490201950073242 24.610754013061523 A 0.40058979465758526 0.40058979465758526 0 0 0 8.1907558441162109 24.375726699829102 A 0.47215936643146234 0.47215936643146234 0 0 0 8.1481647491455078 24.205047607421875 A 0.95814495904303931 0.95814495904303931 0 0 0 7.9824457168579102 23.921871185302734 A 1.3168919859615911 1.3168919859615911 0 0 1 8.0270967483520508 23.850851058959961 A 0.42535414363053897 0.42535414363053897 0 0 1 8.254765510559082 23.932334899902344 A 0.49449493862875088 0.49449493862875088 0 0 1 8.1917352676391602 23.651912689208984 A 1.3168770835118107 1.3168770835118107 0 0 1 8.3085174560546875 23.549043655395508 M 11.072675704956055 23.701070785522461 A 1.0640009224551576 1.0640009224551576 0 0 1 10.695979118347168 23.92152214050293 A 0.63789794356994822 0.63789794356994822 0 0 1 10.255148887634277 23.894737243652344 A 1.2062184116146835 1.2062184116146835 0 0 1 10.613069534301758 23.629007339477539 A 14.654286870826338 14.654286870826338 0 0 0 10.819470405578613 23.511333465576172 A 1.1465230676633875 1.1465230676633875 0 0 0 11.016119003295898 23.368070602416992 A 0.5469681561744556 0.5469681561744556 0 0 0 11.172513961791992 23.111856460571289 A 0.57503088596767948 0.57503088596767948 0 0 0 11.161050796508789 22.777589797973633 A 1.2823666178279944 1.2823666178279944 0 0 0 10.944883346557617 22.368795394897461 A 1.2406463765118039 1.2406463765118039 0 0 1 11.14789867401123 21.932872772216797 A 4.0510187130350648 4.0510187130350648 0 0 0 11.615120887756348 22.725751876831055 A 3.9931957065279264 3.9931957065279264 0 0 0 11.072675704956055 23.701072692871094 M 11.065628051757812 24.829788208007813 A 3.2402759964857228 3.2402759964857228 0 0 1 11.451355934143066 23.549043655395508 A 1.3168771066563636 1.3168771066563636 0 0 1 11.568138122558594 23.651910781860352 A 0.49449521057865192 0.49449521057865192 0 0 1 11.505107879638672 23.932334899902344 A 0.42535401526867928 0.42535401526867928 0 0 1 11.73277759552002 23.850852966308594 A 1.3168923085982829 1.3168923085982829 0 0 1 11.77742862701416 23.921869277954102 A 0.95814557727645677 0.95814557727645677 0 0 0 11.611708641052246 24.205047607421875 A 0.47216014682473156 0.47216014682473156 0 0 0 11.569117546081543 24.375724792480469 A 0.40059011367437092 0.40059011367437092 0 0 0 11.610852241516113 24.610754013061523 A 0.12581499587497785 0.12581499587497785 0 0 1 11.480119705200195 24.654481887817383 A 0.33863528097064877 0.33863528097064877 0 0 0 11.309605598449707 24.649875640869141 A 0.32520289538542563 0.32520289538542563 0 0 0 11.117524147033691 24.746912002563477 A 0.32791298171064986 0.32791298171064986 0 0 0 11.065628051757812 24.829790115356445 M 6.5542736053466797 20.280555725097656 A 0.96202108757655025 0.96202108757655025 0 0 1 6.4564547538757324 20.081937789916992 A 3.4645811500039119 3.4645811500039119 0 0 1 6.3724784851074219 19.781267166137695 A 0.2661997123908012 0.2661997123908012 0 0 0 6.4707627296447754 19.838321685791016 A 0.63387780927605752 0.63387780927605752 0 0 0 6.5909943580627441 19.867807388305664 A 2.0748379684597085 2.0748379684597085 0 0 1 6.8254337310791016 19.910432815551758 A 1.8687791076275149 1.8687791076275149 0 0 1 6.5542736053466797 20.280557632446289 M 6.4925594329833984 20.332536697387695 A 1.7732943203935065 1.7732943203935065 0 0 1 6.1516385078430176 20.614564895629883 A 1.062239123442958 1.062239123442958 0 0 0 5.808772087097168 20.737825393676758 A 1.7376845835970316 1.7376845835970316 0 0 1 5.7024345397949219 20.561489105224609 A 0.36037657871897066 0.36037657871897066 0 0 0 5.6114010810852051 20.452457427978516 A 0.21670247050120131 0.21670247050120131 0 0 0 5.4351816177368164 20.409702301025391 A 0.52156496149527043 0.52156496149527043 0 0 0 5.202242374420166 20.524721145629883 A 0.37410858119752377 0.37410858119752377 0 0 1 5.0360164642333984 20.346307754516602 A 3.8642616562812546 3.8642616562812546 0 0 0 4.9013676643371582 19.308307647705078 A 0.64312479136867418 0.64312479136867418 0 0 1 5.1099338531494141 19.407341003417969 A 1.1442958938464394 1.1442958938464394 0 0 0 5.1760659217834473 19.945878982543945 A 0.54358676738308997 0.54358676738308997 0 0 0 5.6525740623474121 20.291891098022461 A 2.0256778818944774 2.0256778818944774 0 0 0 5.9661707878112793 20.292446136474609 A 3.4116150510996182 3.4116150510996182 0 0 1 6.4925589561462402 20.332538604736328 M 6.4829559326171875 19.283628463745117 A 2.7878014290144564 2.7878014290144564 0 0 0 6.6352558135986328 19.15440559387207 A 0.38170220352804768 0.38170220352804768 0 0 1 6.8106346130371094 19.063510894775391 A 0.32613856134335639 0.32613856134335639 0 0 1 6.6923904418945313 19.024814605712891 A 0.70656301469569915 0.70656301469569915 0 0 1 6.5804076194763184 18.945438385009766 A 0.72776819893626765 0.72776819893626765 0 0 0 6.4552278518676758 18.855569839477539 A 0.29034093256065552 0.29034093256065552 0 0 0 6.3875770568847656 18.832382202148437 A 3.2999635282706694 3.2999635282706694 0 0 0 6.7549276351928711 18.83125114440918 A 0.67532231633596651 0.67532231633596651 0 0 0 6.9577465057373047 18.781524658203125 A 0.52374385211750774 0.52374385211750774 0 0 0 7.1804637908935547 18.603099822998047 A 0.69043680574221211 0.69043680574221211 0 0 0 7.2914867401123047 18.332870483398437 A 1.2161340023153915 1.2161340023153915 0 0 0 7.3143963813781738 18.047811508178711 A 1.5840413053070488 1.5840413053070488 0 0 0 7.3025846481323242 17.901161193847656 A 0.41292533831786371 0.41292533831786371 0 0 1 7.4842829704284668 17.621265411376953 A 5.0012941811850888 5.0012941811850888 0 0 0 7.7016925811767578 17.93890380859375 A 4.0573298136714309 4.0573298136714309 0 0 0 6.9576945304870605 19.639808654785156 A 2.0326885012825366 2.0326885012825366 0 0 1 6.8966689109802246 19.779430389404297 A 36.78806644760413 36.78806644760413 0 0 1 6.8816580772399902 19.564502716064453 A 0.26831729315193981 0.26831729315193981 0 0 0 6.8182668685913086 19.385971069335938 A 0.2753684746530633 0.2753684746530633 0 0 0 6.6497197151184082 19.289220809936523 A 0.51140992824604325 0.51140992824604325 0 0 0 6.4829564094543457 19.283626556396484 M 6.4220185279846191 17.068614959716797 A 0.76356963738845096 0.76356963738845096 0 0 0 6.2683696746826172 17.272918701171875 L 6.1702933311462402 17.450094223022461 A 1.2389306819738271 1.2389306819738271 0 0 1 6.0595622062683105 17.614444732666016 A 0.56969304741295701 0.56969304741295701 0 0 1 5.9121427536010742 17.740163803100586 A 0.52845976321923893 0.52845976321923893 0 0 1 6.0322251319885254 17.726228713989258 A 0.61573603137567912 0.61573603137567912 0 0 1 6.1054372787475586 17.730617523193359 A 1.1476197990671584 1.1476197990671584 0 0 1 6.289769172668457 17.77195930480957 A 0.56477565570201449 0.56477565570201449 0 0 0 6.1784863471984863 17.915254592895508 A 1.1947103576857805 1.1947103576857805 0 0 0 6.0877351760864258 18.154636383056641 A 6.6246032333755691 6.6246032333755691 0 0 1 5.9866743087768555 18.590221405029297 A 0.80653139863302892 0.80653139863302892 0 0 1 5.8003215789794922 18.9329833984375 A 0.69519603623594928 0.69519603623594928 0 0 1 6.0118222236633301 18.854171752929688 A 1.2436340534625998 1.2436340534625998 0 0 1 6.2553200721740723 18.831111907958984 A 0.32695672629330724 0.32695672629330724 0 0 0 6.128150463104248 18.917276382446289 A 0.53376013776580011 0.53376013776580011 0 0 0 6.0551505088806152 19.012893676757813 A 0.34248239105436284 0.34248239105436284 0 0 1 5.9193058013916016 18.993082046508789 A 1.8962146745675217 1.8962146745675217 0 0 0 5.6730446815490723 18.911064147949219 A 1.8851188260711644 1.8851188260711644 0 0 1 5.7118091583251953 18.758176803588867 A 12.102788210499272 12.102788210499272 0 0 0 5.8615427017211914 18.288257598876953 A 0.77291153642361299 0.77291153642361299 0 0 0 5.8821687698364258 17.974170684814453 A 0.61902898691988251 0.61902898691988251 0 0 0 5.6214761734008789 17.571958541870117 A 1.3901224509792358 1.3901224509792358 0 0 0 5.1240634918212891 17.370328903198242 A 1.6031734000804418 1.6031734000804418 0 0 0 5.0089058876037598 17.351184844970703 A 1.4834471017188884 1.4834471017188884 0 0 1 4.8758978843688965 16.970914840698242 A 1.4678459770229555 1.4678459770229555 0 0 1 4.8533411026000977 16.734451293945313 A 3.9604951944152851 3.9604951944152851 0 0 0 4.9917254447937012 16.136236190795898 A 0.55379185792757668 0.55379185792757668 0 0 1 5.1944174766540527 16.414934158325195 A 0.76941145729709526 0.76941145729709526 0 0 0 5.0906448364257812 16.673154830932617 A 0.41648466811071472 0.41648466811071472 0 0 0 5.2717723846435547 17.110061645507813 A 2.6635666387590713 2.6635666387590713 0 0 0 5.519075870513916 17.258771896362305 A 3.9054253123523037 3.9054253123523037 0 0 1 5.5250716209411621 17.262199401855469 A 1.4576597973631229 1.4576597973631229 0 0 1 5.6528472900390625 17.342519760131836 A 0.65686059501270277 0.65686059501270277 0 0 1 5.6225476264953613 17.485588073730469 A 0.65237319088504098 0.65237319088504098 0 0 1 5.7085189819335938 17.383413314819336 A 0.55888172409761072 0.55888172409761072 0 0 1 5.8428888320922852 17.541784286499023 A 0.59573045913091471 0.59573045913091471 0 0 1 5.8492217063903809 17.274280548095703 A 5.1990783151426454 5.1990783151426454 0 0 1 6.3339447975158691 17.038209915161133 A 1.0050700013185219 1.0050700013185219 0 0 0 6.5279903411865234 16.918590545654297 A 0.54856273629778607 0.54856273629778607 0 0 0 6.7049107551574707 16.666454315185547 A 0.59743430079136839 0.59743430079136839 0 0 0 6.7180881500244141 16.34735107421875 A 1.2357225816269009 1.2357225816269009 0 0 0 6.5310831069946289 15.906064033508301 A 0.96926050479451897 0.96926050479451897 0 0 1 6.9019994735717773 15.362773895263672 A 3.9279673417314469 3.9279673417314469 0 0 0 7.2081108093261719 17.084856033325195 A 0.056723873965597214 0.056723873965597214 0 0 1 7.1285696029663086 17.142663955688477 A 1.1666821557434335 1.1666821557434335 0 0 0 6.9998617172241211 17.060405731201172 A 0.70401761221204429 0.70401761221204429 0 0 0 6.6879668235778809 16.969284057617188 A 0.41688573387916444 0.41688573387916444 0 0 0 6.5192608833312988 17.005212783813477 A 0.43570221506414741 0.43570221506414741 0 0 0 6.421877384185791 17.068737030029297 M 6.4925594329833984 15.545635223388672 A 1.7732944335750651 1.7732944335750651 0 0 1 6.1516385078430176 15.827661514282227 A 1.0622380587463944 1.0622380587463944 0 0 0 5.808772087097168 15.950922966003418 A 1.7376845835970316 1.7376845835970316 0 0 1 5.7024345397949219 15.77458667755127 A 0.36037717596901064 0.36037717596901064 0 0 0 5.6114010810852051 15.665554046630859 A 0.21670340635100477 0.21670340635100477 0 0 0 5.4351816177368164 15.622798919677734 A 0.52156496149527043 0.52156496149527043 0 0 0 5.202242374420166 15.737817764282227 A 0.37410896839468855 0.37410896839468855 0 0 1 5.0360164642333984 15.559405326843262 A 3.864262366129616 3.864262366129616 0 0 0 4.9013676643371582 14.521404266357422 A 0.64312401730293844 0.64312401730293844 0 0 1 5.1099338531494141 14.620438575744629 A 1.1442962311836598 1.1442962311836598 0 0 0 5.1760659217834473 15.158976554870605 A 0.54358674086618097 0.54358674086618097 0 0 0 5.6525740623474121 15.504987716674805 A 2.0256769309523177 2.0256769309523177 0 0 0 5.9661707878112793 15.505542755126953 A 3.4116150510996182 3.4116150510996182 0 0 1 6.4925589561462402 15.545635223388672 M 6.5909953117370605 15.080906867980957 A 2.0748379167015276 2.0748379167015276 0 0 1 6.8254337310791016 15.123531341552734 A 1.8687783728155221 1.8687783728155221 0 0 1 6.5542736053466797 15.493653297424316 A 0.96202166581702897 0.96202166581702897 0 0 1 6.4564547538757324 15.295034408569336 A 3.464581080443569 3.464581080443569 0 0 1 6.3724784851074219 14.994364738464355 A 0.26619938780279995 0.26619938780279995 0 0 0 6.4707627296447754 15.051419258117676 A 0.6338784195759285 0.6338784195759285 0 0 0 6.5909943580627441 15.080904960632324 M 4.8530588150024414 18.653741836547852 A 2.7345287885616312 2.7345287885616312 0 0 0 5.1232872009277344 18.816555023193359 A 1.290252099747464 1.290252099747464 0 0 0 5.0180668830871582 18.816497802734375 A 1.3946353033935242 1.3946353033935242 0 0 0 4.9163179397583008 18.824180603027344 A 0.66574066686440425 0.66574066686440425 0 0 1 4.823056697845459 18.828891754150391 A 0.11306191427471897 0.11306191427471897 0 0 1 4.719151496887207 18.78001594543457 A 3.9604950740840281 3.9604950740840281 0 0 0 4.692436695098877 18.71875 L 4.692436695098877 18.509355545043945 A 0.82690110625229341 0.82690110625229341 0 0 0 4.8530588150024414 18.653743743896484 M 4.692436695098877 15.637319564819336 A 0.47183072267594195 0.47183072267594195 0 0 1 4.7618775367736816 15.568217277526855 A 3.2217918428370078 3.2217918428370078 0 0 1 4.692436695098877 16.21864128112793 L 4.692436695098877 15.637319564819336 M 5.3732714653015137 16.228231430053711 A 0.47468381022215556 0.47468381022215556 0 0 1 5.0264406204223633 15.821024894714355 A 3.9604950235220899 3.9604950235220899 0 0 0 5.0306086540222168 15.752790451049805 A 0.51634848810793621 0.51634848810793621 0 0 1 5.1831703186035156 15.848932266235352 A 0.48127213906294875 0.48127213906294875 0 0 0 5.2488880157470703 16.014820098876953 A 0.24490013328724849 0.24490013328724849 0 0 0 5.3853945732116699 16.125072479248047 A 0.28347284043572174 0.28347284043572174 0 0 0 5.542119026184082 16.121763229370117 A 1.8093864994403366 1.8093864994403366 0 0 0 5.6516242027282715 16.086566925048828 A 0.61227876526439473 0.61227876526439473 0 0 0 5.6006293296813965 16.157953262329102 A 0.80252780002805801 0.80252780002805801 0 0 0 5.5689153671264648 16.214435577392578 A 0.69920481442047477 0.69920481442047477 0 0 0 5.5449709892272949 16.261175155639648 A 1.09833681899699 1.09833681899699 0 0 0 5.3732714653015137 16.228233337402344 M 4.692436695098877 14.871824264526367 A 3.383532736368148 3.383532736368148 0 0 1 4.7462925910949707 15.224257469177246 A 0.66545125706869934 0.66545125706869934 0 0 1 4.692436695098877 15.447536468505859 L 4.692436695098877 14.871824264526367 M 5.3435201644897461 14.370482444763184 A 0.32507356970232382 0.32507356970232382 0 0 1 5.1925678253173828 14.408135414123535 A 0.30573158849962079 0.30573158849962079 0 0 1 5.0450143814086914 14.358720779418945 A 1.6262428525296095 1.6262428525296095 0 0 1 4.7910375595092773 14.174055099487305 A 1.9484225017041013 1.9484225017041013 0 0 1 5.3426599502563477 14.138520240783691 A 1.0433745125128424 1.0433745125128424 0 0 1 5.5669803619384766 14.314975738525391 A 0.54886956749289273 0.54886956749289273 0 0 0 5.3435201644897461 14.3704833984375 M 4.692436695098877 13.931846618652344 L 4.692436695098877 13.722452163696289 A 0.82690054400180546 0.82690054400180546 0 0 0 4.8530588150024414 13.866839408874512 A 2.7345279446652353 2.7345279446652353 0 0 0 5.1232872009277344 14.029653549194336 A 1.2902525597983419 1.2902525597983419 0 0 0 5.0180668830871582 14.029595375061035 A 1.3946353033935242 1.3946353033935242 0 0 0 4.9163179397583008 14.037278175354004 A 0.6657399767401746 0.6657399767401746 0 0 1 4.823056697845459 14.041987419128418 A 0.11306270218302987 0.11306270218302987 0 0 1 4.719151496887207 13.993112564086914 A 3.9604952918179963 3.9604952918179963 0 0 0 4.692436695098877 13.931845664978027 M 5.6538715362548828 14.304632186889648 A 0.763568328633486 0.763568328633486 0 0 1 5.6616740226745605 14.190517425537109 A 2.12785406427321 2.12785406427321 0 0 1 6.0237627029418945 14.32020092010498 A 0.6228623255121446 0.6228623255121446 0 0 0 6.0777630805969238 14.401236534118652 A 0.56156519571641383 0.56156519571641383 0 0 0 5.8746547698974609 14.316082954406738 A 0.79932906687821637 0.79932906687821637 0 0 0 5.6538724899291992 14.304633140563965 M 6.3351173400878906 14.553342819213867 A 0.67549961520497082 0.67549961520497082 0 0 0 6.2946586608886719 14.698722839355469 A 0.61783308429773143 0.61783308429773143 0 0 0 6.1887578964233398 14.508460998535156 A 0.23841587038599535 0.23841587038599535 0 0 0 6.3351173400878906 14.553342819213867 M 4.6924371719360352 17.194717407226563 A 1.5750160449956254 1.5750160449956254 0 0 1 4.8595333099365234 17.42603874206543 A 1.7237390747702577 1.7237390747702577 0 0 0 4.6924371719360352 17.670276641845703 L 4.692436695098877 17.19471549987793 M 4.692436695098877 21.125909805297852 L 4.692436695098877 19.550947189331055 A 3.3449482151046319 3.3449482151046319 0 0 1 4.692436695098877 21.125909805297852 M 5.3435201644897461 19.157386779785156 A 0.32507452337288162 0.32507452337288162 0 0 1 5.1925678253173828 19.195039749145508 A 0.30573158849962079 0.30573158849962079 0 0 1 5.0450143814086914 19.145624160766602 A 1.6262435661152812 1.6262435661152812 0 0 1 4.7910375595092773 18.960958480834961 A 1.9484215509294898 1.9484215509294898 0 0 1 5.3426599502563477 18.925424575805664 A 1.0433745125128424 1.0433745125128424 0 0 1 5.5669803619384766 19.101877212524414 A 0.54886956749289273 0.54886956749289273 0 0 0 5.3435201644897461 19.157386779785156 M 5.661674976348877 18.977420806884766 A 2.1278551300580433 2.1278551300580433 0 0 1 6.0237627029418945 19.10710334777832 A 0.62286200436172479 0.62286200436172479 0 0 0 6.0777630805969238 19.188138961791992 A 0.5615648174897746 0.5615648174897746 0 0 0 5.8746547698974609 19.102985382080078 A 0.79932943744875617 0.79932943744875617 0 0 0 5.6538724899291992 19.091535568237305 A 0.763568328633486 0.763568328633486 0 0 1 5.6616740226745605 18.977420806884766 M 6.1887578964233398 19.295364379882812 A 0.23841591227041298 0.23841591227041298 0 0 0 6.3351173400878906 19.340246200561523 A 0.67549961520497082 0.67549961520497082 0 0 0 6.2946586608886719 19.485626220703125 A 0.61783345355636032 0.61783345355636032 0 0 0 6.1887578964233398 19.295364379882812 M 5.3732714653015137 21.015134811401367 A 0.47468391205281302 0.47468391205281302 0 0 1 5.0264406204223633 20.607929229736328 A 3.9604948237834323 3.9604948237834323 0 0 0 5.0306086540222168 20.539693832397461 A 0.51634835985883998 0.51634835985883998 0 0 1 5.1831703186035156 20.635835647583008 A 0.48127213906294875 0.48127213906294875 0 0 0 5.2488880157470703 20.801723480224609 A 0.24489907912168141 0.24489907912168141 0 0 0 5.3853945732116699 20.91197395324707 A 0.28347284043572174 0.28347284043572174 0 0 0 5.542119026184082 20.908666610717773 A 1.809387551030706 1.809387551030706 0 0 0 5.6516242027282715 20.873468399047852 A 0.61227876526439473 0.61227876526439473 0 0 0 5.6006293296813965 20.944856643676758 A 0.80252780002805801 0.80252780002805801 0 0 0 5.5689153671264648 21.001338958740234 A 0.69920430515489118 0.69920430515489118 0 0 0 5.5449709892272949 21.048078536987305 A 1.09833681899699 1.09833681899699 0 0 0 5.3732714653015137 21.01513671875 M 4.6924371719360352 21.981620788574219 A 1.5750160449956254 1.5750160449956254 0 0 1 4.8595333099365234 22.212942123413086 A 1.7237390747702577 1.7237390747702577 0 0 0 4.6924371719360352 22.457178115844727 L 4.692436695098877 21.981618881225586 M 12.05817985534668 17.938905715942383 A 5.0012938004963692 5.0012938004963692 0 0 0 12.275589942932129 17.621265411376953 A 0.41292516344301367 0.41292516344301367 0 0 1 12.457289695739746 17.901161193847656 A 1.5840415715741791 1.5840415715741791 0 0 0 12.445477485656738 18.047809600830078 A 1.2161342195783902 1.2161342195783902 0 0 0 12.468386650085449 18.332868576049805 A 0.69043704023018126 0.69043704023018126 0 0 0 12.579408645629883 18.60310173034668 A 0.52374393462830671 0.52374393462830671 0 0 0 12.802125930786133 18.781522750854492 A 0.67532220326076842 0.67532220326076842 0 0 0 13.004944801330566 18.83125114440918 A 3.2999635724229908 3.2999635724229908 0 0 0 13.372296333312988 18.832382202148437 A 0.29034092880908802 0.29034092880908802 0 0 0 13.304646492004395 18.855571746826172 A 0.72776872978214058 0.72776872978214058 0 0 0 13.179466247558594 18.945436477661133 A 0.70656255542414936 0.70656255542414936 0 0 1 13.067482948303223 19.024814605712891 A 0.32613861859730486 0.32613861859730486 0 0 1 12.949239730834961 19.063510894775391 A 0.38170409203997868 0.38170409203997868 0 0 1 13.124617576599121 19.15440559387207 A 2.7878017507562207 2.7878017507562207 0 0 0 13.276917457580566 19.283628463745117 A 0.51140986946259392 0.51140986946259392 0 0 0 13.110154151916504 19.289220809936523 A 0.27536890959181459 0.27536890959181459 0 0 0 12.941606521606445 19.385969161987305 A 0.26831759550791351 0.26831759550791351 0 0 0 12.878212928771973 19.56451416015625 A 36.788067268209808 36.788067268209808 0 0 1 12.863204956054688 19.779430389404297 A 2.0326889254437326 2.0326889254437326 0 0 1 12.802179336547852 19.639810562133789 A 4.0573301689006218 4.0573301689006218 0 0 0 12.058181762695313 17.938905715942383 M 14.048064231872559 18.758176803588867 A 1.885119306593688 1.885119306593688 0 0 1 14.08682918548584 18.911064147949219 A 1.8962137859599271 1.8962137859599271 0 0 0 13.840568542480469 18.993082046508789 A 0.34248242268648738 0.34248242268648738 0 0 1 13.704723358154297 19.01289176940918 A 0.53376040747520348 0.53376040747520348 0 0 0 13.631723403930664 18.917276382446289 A 0.32695803475493818 0.32695803475493818 0 0 0 13.50455379486084 18.831110000610352 A 1.2436340043444833 1.2436340043444833 0 0 1 13.748051643371582 18.854171752929688 A 0.69519606672879009 0.69519606672879009 0 0 1 13.959550857543945 18.9329833984375 A 0.806530669091714 0.806530669091714 0 0 1 13.773199081420898 18.590221405029297 A 6.6246033475957926 6.6246033475957926 0 0 1 13.672139167785645 18.154636383056641 A 1.1947092480454991 1.1947092480454991 0 0 0 13.581386566162109 17.915254592895508 A 0.56477543879552849 0.56477543879552849 0 0 0 13.470104217529297 17.771957397460938 A 1.1476200950514812 1.1476200950514812 0 0 1 13.654437065124512 17.730619430541992 A 0.61573603242348662 0.61573603242348662 0 0 1 13.727648735046387 17.726228713989258 A 0.52845986531756739 0.52845986531756739 0 0 1 13.84773063659668 17.740163803100586 A 0.56969242368572603 0.56969242368572603 0 0 1 13.700310707092285 17.614442825317383 A 1.2389294501323682 1.2389294501323682 0 0 1 13.589582443237305 17.450099945068359 L 13.491503715515137 17.272916793823242 A 0.76356895021514914 0.76356895021514914 0 0 0 13.337855339050293 17.068614959716797 A 0.43570285646057422 0.43570285646057422 0 0 0 13.240612030029297 17.005212783813477 A 0.41688581443840494 0.41688581443840494 0 0 0 13.071907997131348 16.969284057617188 A 0.70401747709327589 0.70401747709327589 0 0 0 12.760011672973633 17.060405731201172 A 1.1666818956551821 1.1666818956551821 0 0 0 12.631303787231445 17.142663955688477 A 0.056723064521527776 0.056723064521527776 0 0 1 12.551762580871582 17.084857940673828 A 3.9279674719184277 3.9279674719184277 0 0 0 12.857873916625977 15.362776756286621 A 0.9692604724751992 0.9692604724751992 0 0 1 13.228790283203125 15.906063079833984 A 1.2357223083060567 1.2357223083060567 0 0 0 13.04178524017334 16.34735107421875 A 0.59743477055137584 0.59743477055137584 0 0 0 13.054962158203125 16.666454315185547 A 0.5485625815463282 0.5485625815463282 0 0 0 13.23188304901123 16.918590545654297 A 1.0050693292678667 1.0050693292678667 0 0 0 13.425930023193359 17.038211822509766 A 5.1990786441050751 5.1990786441050751 0 0 1 13.910654067993164 17.274282455444336 A 0.59572981418721427 0.59572981418721427 0 0 1 13.916983604431152 17.541784286499023 A 0.55888132545411751 0.55888132545411751 0 0 1 14.05135440826416 17.383415222167969 A 0.65237355646535522 0.65237355646535522 0 0 1 14.137326240539551 17.485588073730469 A 0.6568610386611633 0.6568610386611633 0 0 1 14.107027053833008 17.342519760131836 A 1.4576599532097074 1.4576599532097074 0 0 1 14.234807014465332 17.262205123901367 A 3.905424018924704 3.905424018924704 0 0 1 14.240797996520996 17.258773803710937 A 2.6635678338187709 2.6635678338187709 0 0 0 14.488101005554199 17.110061645507813 A 0.41648461022410072 0.41648461022410072 0 0 0 14.669228553771973 16.673152923583984 A 0.76941127575826918 0.76941127575826918 0 0 0 14.565456390380859 16.414936065673828 A 0.55379238947221876 0.55379238947221876 0 0 1 14.768148422241211 16.136236190795898 A 3.960495320289096 3.960495320289096 0 0 0 14.906533241271973 16.73444938659668 A 1.4678459935873478 1.4678459935873478 0 0 1 14.883975028991699 16.970914840698242 A 1.4834472643219148 1.4834472643219148 0 0 1 14.750967025756836 17.351184844970703 A 1.6031734146815571 1.6031734146815571 0 0 0 14.635810852050781 17.370328903198242 A 1.3901221362883041 1.3901221362883041 0 0 0 14.138398170471191 17.571958541870117 A 0.61902938160140475 0.61902938160140475 0 0 0 13.877704620361328 17.974170684814453 A 0.77291143972607679 0.77291143972607679 0 0 0 13.898330688476562 18.28825569152832 A 12.102790382622825 12.102790382622825 0 0 0 14.048064231872559 18.758176803588867 M 15.067438125610352 18.71875 A 3.9604953920143369 3.9604953920143369 0 0 0 15.040722846984863 18.78001594543457 A 0.11306179579941213 0.11306179579941213 0 0 1 14.936817169189453 18.828889846801758 A 0.66574066788559372 0.66574066788559372 0 0 1 14.84355640411377 18.824180603027344 A 1.3946353016901396 1.3946353016901396 0 0 0 14.741806983947754 18.816497802734375 A 1.290252108312578 1.290252108312578 0 0 0 14.636587142944336 18.816558837890625 A 2.734529066674777 2.734529066674777 0 0 0 14.906813621520996 18.653741836547852 A 0.82690153996200466 0.82690153996200466 0 0 0 15.067436218261719 18.509355545043945 L 15.067437171936035 18.71875 M 8.1447515487670898 17.938850402832031 A 4.0510189515840498 4.0510189515840498 0 0 0 8.6119747161865234 17.145969390869141 A 1.2406461420174812 1.2406461420174812 0 0 1 8.8149900436401367 17.581892013549805 A 1.2823663144354225 1.2823663144354225 0 0 0 8.5988225936889648 17.990684509277344 A 0.57503107920037499 0.57503107920037499 0 0 0 8.5873594284057617 18.324953079223633 A 0.54696797163103039 0.54696797163103039 0 0 0 8.7437553405761719 18.581167221069336 A 1.1465245124361456 1.1465245124361456 0 0 0 8.9404020309448242 18.724431991577148 A 14.654287291372361 14.654287291372361 0 0 0 9.1468029022216797 18.842103958129883 A 1.2051425986827764 1.2051425986827764 0 0 1 9.5026140213012695 19.108715057373047 A 0.63787827202546876 0.63787827202546876 0 0 1 9.0638933181762695 19.134618759155273 A 1.0639998603007932 1.0639998603007932 0 0 1 8.6871976852416992 18.914167404174805 A 3.9931946967182954 3.9931946967182954 0 0 0 8.1447525024414062 17.938850402832031 M 8.1685800552368164 18.530134201049805 A 3.3471621536993927 3.3471621536993927 0 0 1 8.4644546508789062 19.096654891967773 A 6.191420080744118 6.191420080744118 0 0 1 8.3295183181762695 19.239068984985352 A 0.7930682673911289 0.7930682673911289 0 0 0 8.1384038925170898 19.154560089111328 A 1.0843243402518845 1.0843243402518845 0 0 0 7.9217586517333984 19.11273193359375 A 1.9610782822620181 1.9610782822620181 0 0 1 7.8844022750854492 19.050838470458984 A 0.41252585845713097 0.41252585845713097 0 0 0 8.007878303527832 19.01759147644043 A 0.22817236044616451 0.22817236044616451 0 0 0 8.0889186859130859 18.955780029296875 A 0.23581487546379432 0.23581487546379432 0 0 0 8.1345834732055664 18.866752624511719 A 0.37087106503345751 0.37087106503345751 0 0 0 8.1457271575927734 18.756885528564453 A 0.53451951341820836 0.53451951341820836 0 0 0 8.1197681427001953 18.60906982421875 A 1.1940894530032173 1.1940894530032173 0 0 1 8.1685791015625 18.530132293701172 M 11.072675704956055 18.914167404174805 A 1.0640009224551576 1.0640009224551576 0 0 1 10.695979118347168 19.134618759155273 A 0.63789794356994822 0.63789794356994822 0 0 1 10.255148887634277 19.107833862304688 A 1.2062184116146835 1.2062184116146835 0 0 1 10.613069534301758 18.842103958129883 A 14.654286318651488 14.654286318651488 0 0 0 10.819470405578613 18.724431991577148 A 1.1465230676633875 1.1465230676633875 0 0 0 11.016119003295898 18.581169128417969 A 0.5469681561744556 0.5469681561744556 0 0 0 11.172513961791992 18.324953079223633 A 0.57503088596767948 0.57503088596767948 0 0 0 11.161050796508789 17.990686416625977 A 1.2823666178279944 1.2823666178279944 0 0 0 10.944883346557617 17.581892013549805 A 1.2406463765118039 1.2406463765118039 0 0 1 11.14789867401123 17.145969390869141 A 4.0510187130350648 4.0510187130350648 0 0 0 11.615120887756348 17.938848495483398 A 3.9931957065279264 3.9931957065279264 0 0 0 11.072675704956055 18.914169311523438 M 11.295418739318848 19.096652984619141 A 3.3471619362349827 3.3471619362349827 0 0 1 11.591294288635254 18.530132293701172 A 1.1940894964454727 1.1940894964454727 0 0 1 11.640105247497559 18.609067916870117 A 0.53451926181804998 0.53451926181804998 0 0 0 11.61414623260498 18.756885528564453 A 0.37087118303051625 0.37087118303051625 0 0 0 11.625289916992188 18.866752624511719 A 0.23581518058358147 0.23581518058358147 0 0 0 11.670955657958984 18.955780029296875 A 0.22817244919590007 0.22817244919590007 0 0 0 11.751995086669922 19.01759147644043 A 0.41252571493543683 0.41252571493543683 0 0 0 11.875471115112305 19.050838470458984 A 1.9610781329960516 1.9610781329960516 0 0 1 11.838114738464355 19.11273193359375 A 1.0843243990590457 1.0843243990590457 0 0 0 11.62147045135498 19.154560089111328 A 0.79306877295997835 0.79306877295997835 0 0 0 11.430355072021484 19.239068984985352 A 6.1914208413316132 6.1914208413316132 0 0 1 11.295417785644531 19.096652984619141 M 11.212608337402344 15.694774627685547 A 3.2141349492236673 3.2141349492236673 0 0 1 11.348191261291504 15.675039291381836 A 0.78569753179576018 0.78569753179576018 0 0 0 11.442599296569824 15.65629768371582 A 0.34473957742265682 0.34473957742265682 0 0 0 11.485722541809082 15.641542434692383 A 0.25688880054395813 0.25688880054395813 0 0 0 11.595072746276855 15.557929992675781 A 0.29947793754797092 0.29947793754797092 0 0 0 11.649618148803711 15.379173278808594 A 0.6362289260862618 0.6362289260862618 0 0 0 11.60844898223877 15.148190498352051 A 2.5324559814086847 2.5324559814086847 0 0 1 11.650474548339844 15.09827995300293 A 0.38272230808106661 0.38272230808106661 0 0 0 11.712601661682129 15.163169860839844 A 0.79977972379229423 0.79977972379229423 0 0 0 11.853488922119141 15.257012367248535 A 14.246318828718605 14.246318828718605 0 0 0 12.065937042236328 15.365693092346191 A 1.2449540506785453 1.2449540506785453 0 0 1 12.232629776000977 15.469328880310059 A 0.54880637936449106 0.54880637936449106 0 0 1 12.364949226379395 15.613249778747559 A 0.53479222592162967 0.53479222592162967 0 0 1 12.346828460693359 15.454438209533691 A 1.0792752651821584 1.0792752651821584 0 0 1 12.385617256164551 15.225610733032227 A 45.459482308784224 45.459482308784224 0 0 0 12.440646171569824 15.030593872070313 A 0.96341838713815897 0.96341838713815897 0 0 0 12.475471496582031 14.845148086547852 A 0.40360564921283321 0.40360564921283321 0 0 0 12.362766265869141 14.526186943054199 A 2.5321543452624242 2.5321543452624242 0 0 1 12.466596603393555 14.473150253295898 A 3.1751808332779343 3.1751808332779343 0 0 1 12.630135536193848 15.224223136901855 A 0.66865708032609894 0.66865708032609894 0 0 1 12.391573905944824 15.695059776306152 A 1.3489885214327966 1.3489885214327966 0 0 0 12.027557373046875 15.596790313720703 A 0.90261921450738314 0.90261921450738314 0 0 0 11.835853576660156 15.591032981872559 A 0.57176631088298036 0.57176631088298036 0 0 0 11.517806053161621 15.70884895324707 A 0.60882297343473102 0.60882297343473102 0 0 0 11.327905654907227 15.987148284912109 A 2.4064428839138485 2.4064428839138485 0 0 0 11.250778198242188 16.285306930541992 A 3.9149145952448094 3.9149145952448094 0 0 1 11.19777774810791 16.511106491088867 A 2.8073202762868026 2.8073202762868026 0 0 1 11.058847427368164 15.743059158325195 A 0.5235475069044303 0.5235475069044303 0 0 1 11.213446617126465 15.694650650024414 M 11.117523193359375 15.17307186126709 A 0.32341730365004018 0.32341730365004018 0 0 0 11.065628051757812 15.255949974060059 A 3.2401642148063128 3.2401642148063128 0 0 1 11.451355934143066 13.975204467773438 A 1.3168764071836123 1.3168764071836123 0 0 1 11.568138122558594 14.078072547912598 A 0.49449521057865192 0.49449521057865192 0 0 1 11.505107879638672 14.358495712280273 A 0.42535406814331433 0.42535406814331433 0 0 1 11.73277759552002 14.277012825012207 A 1.3168922296187469 1.3168922296187469 0 0 1 11.77742862701416 14.348031044006348 A 0.95814501751230252 0.95814501751230252 0 0 0 11.611708641052246 14.631207466125488 A 0.47216014682473156 0.47216014682473156 0 0 0 11.569117546081543 14.801885604858398 A 0.40059011367437092 0.40059011367437092 0 0 0 11.610852241516113 15.036913871765137 A 0.12083552160191205 0.12083552160191205 0 0 1 11.49929141998291 15.082951545715332 A 0.39266835977442721 0.39266835977442721 0 0 0 11.304083824157715 15.077133178710938 A 0.31569691108848658 0.31569691108848658 0 0 0 11.117524147033691 15.17307186126709 M 8.7010250091552734 15.743060111999512 A 2.8073193065383126 2.8073193065383126 0 0 1 8.5620946884155273 16.511106491088867 A 3.9149148045811044 3.9149148045811044 0 0 1 8.5090951919555664 16.285306930541992 A 2.406443422786221 2.406443422786221 0 0 0 8.4319677352905273 15.987147331237793 A 0.608822121866889 0.608822121866889 0 0 0 8.2420673370361328 15.708850860595703 A 0.57176617061102764 0.57176617061102764 0 0 0 7.9240202903747559 15.591032028198242 A 0.90261920818168784 0.90261920818168784 0 0 0 7.7323174476623535 15.59679126739502 A 1.3489884007359518 1.3489884007359518 0 0 0 7.3682994842529297 15.695059776306152 A 0.66865704212405241 0.66865704212405241 0 0 1 7.1297378540039062 15.224223136901855 A 3.1751815350135972 3.1751815350135972 0 0 1 7.2932777404785156 14.473150253295898 A 2.532153862311203 2.532153862311203 0 0 1 7.3971080780029297 14.526186943054199 A 0.40360603914092807 0.40360603914092807 0 0 0 7.2844018936157227 14.845148086547852 A 0.96341785679832892 0.96341785679832892 0 0 0 7.3192296028137207 15.030592918395996 A 45.459484749079913 45.459484749079913 0 0 0 7.3742537498474121 15.225608825683594 A 1.0792747735608956 1.0792747735608956 0 0 1 7.4130454063415527 15.454439163208008 A 0.53479232088424822 0.53479232088424822 0 0 1 7.3949246406555176 15.613248825073242 A 0.54880629453226115 0.54880629453226115 0 0 1 7.5272445678710938 15.469328880310059 A 1.2449541081852038 1.2449541081852038 0 0 1 7.6939353942871094 15.365694046020508 A 14.24631924640253 14.24631924640253 0 0 0 7.9063835144042969 15.257012367248535 A 0.799779081055918 0.799779081055918 0 0 0 8.047271728515625 15.163169860839844 A 0.38272236114212577 0.38272236114212577 0 0 0 8.1093997955322266 15.098280906677246 A 2.5324570352242657 2.5324570352242657 0 0 1 8.1514244079589844 15.148190498352051 A 0.63622894858529677 0.63622894858529677 0 0 0 8.110255241394043 15.379172325134277 A 0.29947773789986959 0.29947773789986959 0 0 0 8.1648006439208984 15.557930946350098 A 0.25688894143854424 0.25688894143854424 0 0 0 8.2741508483886719 15.641542434692383 A 0.34473958810739896 0.34473958810739896 0 0 0 8.3172750473022461 15.656296730041504 A 0.78569755039027955 0.78569755039027955 0 0 0 8.4116830825805664 15.675040245056152 A 3.2141349379119126 3.2141349379119126 0 0 1 8.5472660064697266 15.694774627685547 A 0.52354762989046932 0.52354762989046932 0 0 1 8.7010250091552734 15.743060111999512 M 7.2745151519775391 16.318674087524414 A 0.60412128776401253 0.60412128776401253 0 0 0 7.4610767364501953 16.65388298034668 A 0.58584158253958296 0.58584158253958296 0 0 0 7.7752456665039062 16.789054870605469 A 2.3971715314686426 2.3971715314686426 0 0 0 8.1383275985717773 16.794832229614258 A 3.3291640175332189 3.3291640175332189 0 0 1 8.3497371673583984 16.793424606323242 A 0.61166721966579118 0.61166721966579118 0 0 1 8.1684293746948242 16.881174087524414 A 0.59927550569189703 0.59927550569189703 0 0 0 7.9589519500732422 16.861974716186523 A 0.29596927445871885 0.29596927445871885 0 0 0 7.8286242485046387 16.903966903686523 A 0.23203660562750292 0.23203660562750292 0 0 0 7.725621223449707 17.058025360107422 A 0.85382297831983633 0.85382297831983633 0 0 0 7.7115693092346191 17.195777893066406 A 0.71884027387531801 0.71884027387531801 0 0 1 7.6844825744628906 17.398582458496094 A 3.2962222309031239 3.2962222309031239 0 0 1 7.1141533851623535 15.568181991577148 A 0.51334670362730694 0.51334670362730694 0 0 1 7.2699241638183594 15.790023803710938 A 1.3368628199675892 1.3368628199675892 0 0 0 7.2745141983032227 16.318674087524414 M 8.3085174560546875 13.975205421447754 A 3.2401644878990168 3.2401644878990168 0 0 1 8.6942453384399414 15.255950927734375 A 0.32341731298634446 0.32341731298634446 0 0 0 8.6423501968383789 15.17307186126709 A 0.31569684424990396 0.31569684424990396 0 0 0 8.4557905197143555 15.077132225036621 A 0.39266853533814922 0.39266853533814922 0 0 0 8.2605819702148437 15.082951545715332 A 0.12083508491232769 0.12083508491232769 0 0 1 8.1490211486816406 15.036914825439453 A 0.40058991525268955 0.40058991525268955 0 0 0 8.1907558441162109 14.801885604858398 A 0.47216019870324116 0.47216019870324116 0 0 0 8.1481647491455078 14.631207466125488 A 0.95814532327406876 0.95814532327406876 0 0 0 7.9824457168579102 14.348030090332031 A 1.3168925190233081 1.3168925190233081 0 0 1 8.0270967483520508 14.277011871337891 A 0.42535393743902622 0.42535393743902622 0 0 1 8.254765510559082 14.358495712280273 A 0.49449500892540521 0.49449500892540521 0 0 1 8.1917352676391602 14.078072547912598 A 1.316876424898668 1.316876424898668 0 0 1 8.3085174560546875 13.975204467773438 M 7.6804227828979492 14.367622375488281 A 0.79306827573241545 0.79306827573241545 0 0 0 7.4893074035644531 14.452131271362305 A 6.1914200860429496 6.1914200860429496 0 0 1 7.3543715476989746 14.30971622467041 A 3.34716145415869 3.34716145415869 0 0 1 7.6502475738525391 13.743194580078125 A 1.1940903588046845 1.1940903588046845 0 0 1 7.6990580558776855 13.82213306427002 A 0.53451919889927524 0.53451919889927524 0 0 0 7.6730985641479492 13.969948768615723 A 0.37087117214129711 0.37087117214129711 0 0 0 7.684241771697998 14.079815864562988 A 0.23581531211238757 0.23581531211238757 0 0 0 7.7299075126647949 14.168843269348145 A 0.22817300264094964 0.22817300264094964 0 0 0 7.8109478950500488 14.230653762817383 A 0.41252717429975944 0.41252717429975944 0 0 0 7.9344229698181152 14.263901710510254 A 1.9610780030993724 1.9610780030993724 0 0 1 7.8970675468444824 14.325794219970703 A 1.084324261498123 1.084324261498123 0 0 0 7.6804227828979492 14.367622375488281 M 7.709259033203125 17.434505462646484 A 0.5515196192253996 0.5515196192253996 0 0 1 7.8778767585754395 17.391716003417969 A 1.8139887399102583 1.8139887399102583 0 0 0 8.0261707305908203 17.368267059326172 A 0.24943768046266379 0.24943768046266379 0 0 0 8.1899271011352539 17.261955261230469 A 0.26256341354166302 0.26256341354166302 0 0 0 8.2287883758544922 17.139434814453125 A 0.4917338374864183 0.4917338374864183 0 0 0 8.2094955444335938 16.953634262084961 A 0.45874367598015653 0.45874367598015653 0 0 1 8.4357843399047852 16.853679656982422 A 3.1748659786841329 3.1748659786841329 0 0 1 7.9098906517028809 17.693002700805664 A 3.2962224686186823 3.2962224686186823 0 0 1 7.7092585563659668 17.434505462646484 M 7.214935302734375 17.297863006591797 A 0.20625941532967831 0.20625941532967831 0 0 1 7.2743616104125977 17.233310699462891 A 3.9604949692483111 3.9604949692483111 0 0 0 7.348701000213623 17.382846832275391 A 0.36760820990866788 0.36760820990866788 0 0 1 7.1892375946044922 17.732223510742187 A 1.5990977473866843 1.5990977473866843 0 0 0 7.0742344856262207 17.690084457397461 A 0.93633436550427374 0.93633436550427374 0 0 0 7.2149357795715332 17.297863006591797 M 7.6979537010192871 18.613628387451172 A 1.96085307896335 1.96085307896335 0 0 1 7.6687369346618652 18.500005722045898 A 3.2510261672329213 3.2510261672329213 0 0 1 7.908935546875 18.184329986572266 A 3.2962217974093666 3.2962217974093666 0 0 1 8.1119804382324219 18.446283340454102 A 0.1070503265824239 0.1070503265824239 0 0 1 8.0223264694213867 18.53913688659668 A 0.52498957065850571 0.52498957065850571 0 0 0 7.849822998046875 18.536918640136719 A 0.25627603235792057 0.25627603235792057 0 0 0 7.6979537010192871 18.613628387451172 M 12.645720481872559 15.568182945251465 A 3.296222557724763 3.296222557724763 0 0 1 12.075389862060547 17.398582458496094 A 0.71884049728792709 0.71884049728792709 0 0 1 12.048304557800293 17.195777893066406 A 0.85382239855407438 0.85382239855407438 0 0 0 12.034252166748047 17.058025360107422 A 0.23203669080273179 0.23203669080273179 0 0 0 11.931248664855957 16.903966903686523 A 0.29596936195902812 0.29596936195902812 0 0 0 11.800920486450195 16.861972808837891 A 0.59927559457423496 0.59927559457423496 0 0 0 11.59144401550293 16.881174087524414 A 0.611667064812915 0.611667064812915 0 0 1 11.410135269165039 16.793424606323242 A 3.329164010068026 3.329164010068026 0 0 1 11.621546745300293 16.794832229614258 A 2.3971715864282399 2.3971715864282399 0 0 0 11.984627723693848 16.789054870605469 A 0.58584164687656148 0.58584164687656148 0 0 0 12.298796653747559 16.65388298034668 A 0.6041214508620637 0.6041214508620637 0 0 0 12.485358238220215 16.318674087524414 A 1.336862802669089 1.336862802669089 0 0 0 12.489949226379395 15.790024757385254 A 0.51334587571517021 0.51334587571517021 0 0 1 12.645721435546875 15.568182945251465 M 15.067437171936035 15.637319564819336 L 15.067437171936035 16.21864128112793 A 3.2217920599126808 3.2217920599126808 0 0 1 14.99799633026123 15.568216323852539 A 0.47183029053076847 0.47183029053076847 0 0 1 15.067437171936035 15.637319564819336 M 14.733432769775391 15.821024894714355 A 0.47468441608790074 0.47468441608790074 0 0 1 14.386601448059082 16.228231430053711 A 1.0983386160269992 1.0983386160269992 0 0 0 14.213031768798828 16.261690139770508 A 0.6982433203709324 0.6982433203709324 0 0 0 14.190958023071289 16.214437484741211 A 0.80252779389527285 0.80252779389527285 0 0 0 14.159244537353516 16.157955169677734 A 0.61227806633251503 0.61227806633251503 0 0 0 14.108248710632324 16.086565017700195 A 1.8093862680002413 1.8093862680002413 0 0 0 14.217753410339355 16.121763229370117 A 0.28347297720984699 0.28347297720984699 0 0 0 14.374478340148926 16.125072479248047 A 0.24489986938662953 0.24489986938662953 0 0 0 14.510985374450684 16.014820098876953 A 0.48127265032636851 0.48127265032636851 0 0 0 14.576703071594238 15.848932266235352 A 0.5163496393106265 0.5163496393106265 0 0 1 14.729264259338379 15.752790451049805 A 3.9604957442746245 3.9604957442746245 0 0 0 14.733433723449707 15.821023941040039 M 13.608234405517578 15.827661514282227 A 1.7732938036628205 1.7732938036628205 0 0 1 13.267313003540039 15.545634269714355 A 3.4116150403163776 3.4116150403163776 0 0 1 13.793704032897949 15.505542755126953 A 2.025676910047665 2.025676910047665 0 0 0 14.107298851013184 15.504987716674805 A 0.54358676820188101 0.54358676820188101 0 0 0 14.583806991577148 15.158976554870605 A 1.1442961198669541 1.1442961198669541 0 0 0 14.64993953704834 14.620437622070313 A 0.64312432958599108 0.64312432958599108 0 0 1 14.85850715637207 14.521403312683105 A 3.8642626562715474 3.8642626562715474 0 0 0 14.723855972290039 15.559403419494629 A 0.37410874259171745 0.37410874259171745 0 0 1 14.557631492614746 15.737818717956543 A 0.5215647955911149 0.5215647955911149 0 0 0 14.324691772460937 15.622798919677734 A 0.21670335742917948 0.21670335742917948 0 0 0 14.148472785949707 15.665554046630859 A 0.36037666108228916 0.36037666108228916 0 0 0 14.057438850402832 15.77458667755127 A 1.7376845074378184 1.7376845074378184 0 0 1 13.951101303100586 15.950922966003418 A 1.0622380916264205 1.0622380916264205 0 0 0 13.608235359191895 15.827662467956543 M 12.109626770019531 13.743196487426758 A 3.3471609113159495 3.3471609113159495 0 0 1 12.405501365661621 14.309717178344727 A 6.1914198558026721 6.1914198558026721 0 0 1 12.270565986633301 14.452132225036621 A 0.7930682673911289 0.7930682673911289 0 0 0 12.079451560974121 14.367622375488281 A 1.0843244248326545 1.0843244248326545 0 0 0 11.86280632019043 14.325794219970703 A 1.961078412150157 1.961078412150157 0 0 1 11.82544994354248 14.263900756835937 A 0.41252721536211617 0.41252721536211617 0 0 0 11.948925971984863 14.230653762817383 A 0.22817296752639141 0.22817296752639141 0 0 0 12.029966354370117 14.168844223022461 A 0.23581533625408452 0.23581533625408452 0 0 0 12.075631141662598 14.079815864562988 A 0.37087106503345751 0.37087106503345751 0 0 0 12.086774826049805 13.969948768615723 A 0.5345192182293842 0.5345192182293842 0 0 0 12.060815811157227 13.82213306427002 A 1.1940904862454051 1.1940904862454051 0 0 1 12.109626770019531 13.743195533752441 M 13.465214729309082 14.698723793029785 A 0.67549942373415262 0.67549942373415262 0 0 0 13.42475700378418 14.553343772888184 A 0.23841593631996286 0.23841593631996286 0 0 0 13.571115493774414 14.50846004486084 A 0.61783351084200011 0.61783351084200011 0 0 0 13.465214729309082 14.698723793029785 M 12.934440612792969 15.123531341552734 A 2.0748380348040891 2.0748380348040891 0 0 1 13.168878555297852 15.080905914306641 A 0.63387839045862371 0.63387839045862371 0 0 0 13.28911018371582 15.051418304443359 A 0.26619937952610567 0.26619937952610567 0 0 0 13.387394905090332 14.994365692138672 A 3.4645820234655194 3.4645820234655194 0 0 1 13.30341911315918 15.295035362243652 A 0.96202193550918602 0.96202193550918602 0 0 1 13.205599784851074 15.493653297424316 A 1.8687781708576441 1.8687781708576441 0 0 1 12.934439659118652 15.123530387878418 M 15.067437171936035 14.871824264526367 L 15.067437171936035 15.447536468505859 A 0.66545078206208907 0.66545078206208907 0 0 1 15.013581275939941 15.22425651550293 A 3.3835330555464758 3.3835330555464758 0 0 1 15.067436218261719 14.871823310852051 M 14.417214393615723 14.138520240783691 A 1.948422459191351 1.948422459191351 0 0 1 14.968835830688477 14.174054145812988 A 1.6262428280205419 1.6262428280205419 0 0 1 14.714859008789063 14.358720779418945 A 0.30573145701094118 0.30573145701094118 0 0 1 14.567305564880371 14.408136367797852 A 0.3250735992290304 0.3250735992290304 0 0 1 14.416353225708008 14.370482444763184 A 0.54886958602762925 0.54886958602762925 0 0 0 14.192893028259277 14.314975738525391 A 1.043375040536356 1.043375040536356 0 0 1 14.417214393615723 14.138521194458008 M 14.906814575195312 13.866839408874512 A 0.8269007104262035 0.8269007104262035 0 0 0 15.067436218261719 13.722452163696289 L 15.067437171936035 13.931846618652344 A 3.9604953920143369 3.9604953920143369 0 0 0 15.040722846984863 13.993111610412598 A 0.11306265683405703 0.11306265683405703 0 0 1 14.936817169189453 14.041987419128418 A 0.66574000764433328 0.66574000764433328 0 0 1 14.84355640411377 14.037278175354004 A 1.3946353016901396 1.3946353016901396 0 0 0 14.741806983947754 14.029595375061035 A 1.2902525879542925 1.2902525879542925 0 0 0 14.636587142944336 14.029655456542969 A 2.7345282795606827 2.7345282795606827 0 0 0 14.906813621520996 13.866840362548828 M 13.885219573974609 14.316082954406738 A 0.56156479211006727 0.56156479211006727 0 0 0 13.682110786437988 14.401236534118652 A 0.62286231034154438 0.62286231034154438 0 0 0 13.736110687255859 14.320199966430664 A 2.1278532577951252 2.1278532577951252 0 0 1 14.098199844360352 14.190518379211426 A 0.76356791974935823 0.76356791974935823 0 0 1 14.106000900268555 14.304632186889648 A 0.79932904326896526 0.79932904326896526 0 0 0 13.885218620300293 14.316082954406738 M 12.685640335083008 17.690084457397461 A 1.599098818452996 1.599098818452996 0 0 0 12.570635795593262 17.73222541809082 A 0.36760866977033713 0.36760866977033713 0 0 1 12.411172866821289 17.382846832275391 A 3.9604950952345264 3.9604950952345264 0 0 0 12.485512733459473 17.233312606811523 A 0.20625947245214937 0.20625947245214937 0 0 1 12.544938087463379 17.297863006591797 A 0.93633435339791371 0.93633435339791371 0 0 0 12.685639381408691 17.690084457397461 M 11.849982261657715 17.693002700805664 A 3.1748657049944051 3.1748657049944051 0 0 1 11.324089050292969 16.853677749633789 A 0.45874539978408008 0.45874539978408008 0 0 1 11.550379753112793 16.953636169433594 A 0.49173415782022917 0.49173415782022917 0 0 0 11.531085014343262 17.139432907104492 A 0.2625634761980668 0.2625634761980668 0 0 0 11.569947242736816 17.261955261230469 A 0.24943771838794726 0.24943771838794726 0 0 0 11.73370361328125 17.368267059326172 A 1.8139886736400084 1.8139886736400084 0 0 0 11.881997108459473 17.391716003417969 A 0.5515196539603876 0.5515196539603876 0 0 1 12.050614356994629 17.434505462646484 A 3.2962227504966095 3.2962227504966095 0 0 1 11.849982261657715 17.693002700805664 M 11.737546920776367 18.53913688659668 A 0.10704963063829841 0.10704963063829841 0 0 1 11.647892951965332 18.446281433105469 A 3.296222333117909 3.296222333117909 0 0 1 11.850939750671387 18.184331893920898 A 3.2510264621321627 3.2510264621321627 0 0 1 12.091136932373047 18.500005722045898 A 1.9608529662023104 1.9608529662023104 0 0 1 12.061920166015625 18.613628387451172 A 0.2562761099933627 0.2562761099933627 0 0 0 11.910051345825195 18.536918640136719 A 0.52498956285921716 0.52498956285921716 0 0 0 11.737545967102051 18.53913688659668 M 15.067437171936035 17.19471549987793 L 15.067437171936035 17.670276641845703 A 1.7237387423311847 1.7237387423311847 0 0 0 14.90034008026123 17.42603874206543 A 1.575016192818022 1.575016192818022 0 0 1 15.067438125610352 17.19471549987793 M 11.402124404907227 21.440820693969727 A 0.58584158253958296 0.58584158253958296 0 0 0 11.716293334960938 21.575992584228516 A 2.3971715314686426 2.3971715314686426 0 0 0 12.079375267028809 21.581769943237305 A 3.3291640175332189 3.3291640175332189 0 0 1 12.29078483581543 21.580362319946289 A 0.61166721966579118 0.61166721966579118 0 0 1 12.109477043151855 21.668111801147461 A 0.59927550569189703 0.59927550569189703 0 0 0 11.899999618530273 21.64891242980957 A 0.29596927445871885 0.29596927445871885 0 0 0 11.769671440124512 21.69090461730957 A 0.23203660562750292 0.23203660562750292 0 0 0 11.666668891906738 21.844961166381836 A 0.85382242346492565 0.85382242346492565 0 0 0 11.652617454528809 21.98271369934082 A 0.71884073272088755 0.71884073272088755 0 0 1 11.625530242919922 22.185518264770508 A 3.2962227077286901 3.2962227077286901 0 0 1 11.05519962310791 20.355119705200195 A 0.51334689994433891 0.51334689994433891 0 0 1 11.210971832275391 20.576959609985352 A 1.3368628199675892 1.3368628199675892 0 0 0 11.215561866760254 21.105609893798828 A 0.60412128776401253 0.60412128776401253 0 0 0 11.402124404907227 21.440820693969727 M 11.309347152709961 20.481996536254883 A 0.66865698185102262 0.66865698185102262 0 0 1 11.070785522460938 20.011157989501953 A 3.1751809066089645 3.1751809066089645 0 0 1 11.234325408935547 19.260087966918945 A 2.5321550628689873 2.5321550628689873 0 0 1 11.338155746459961 19.31312370300293 A 0.40360556435450579 0.40360556435450579 0 0 0 11.225449562072754 19.632083892822266 A 0.9634175136869183 0.9634175136869183 0 0 0 11.260275840759277 19.817529678344727 A 45.459483476999829 45.459483476999829 0 0 0 11.315300941467285 20.012546539306641 A 1.0792753642635622 1.0792753642635622 0 0 1 11.354093551635742 20.241376876831055 A 0.53479232088424822 0.53479232088424822 0 0 1 11.335971832275391 20.400186538696289 A 0.54880600660513468 0.54880600660513468 0 0 1 11.468292236328125 20.256265640258789 A 1.2449540498658143 1.2449540498658143 0 0 1 11.634983062744141 20.152631759643555 A 14.246319301581584 14.246319301581584 0 0 0 11.847431182861328 20.043949127197266 A 0.59167249236601061 0.59167249236601061 0 0 0 12.050447463989258 19.885217666625977 A 2.5327270457132709 2.5327270457132709 0 0 1 12.076850891113281 19.916269302368164 A 0.57260698935284493 0.57260698935284493 0 0 0 12.027342796325684 20.166582107543945 A 0.28976521617440198 0.28976521617440198 0 0 0 12.103578567504883 20.346519470214844 A 0.30713709416458196 0.30713709416458196 0 0 0 12.21800422668457 20.421741485595703 A 0.36394971481496502 0.36394971481496502 0 0 0 12.260574340820313 20.435125350952148 A 0.39969249213430064 0.39969249213430064 0 0 0 12.355043411254883 20.446746826171875 A 1.1461940697717659 1.1461940697717659 0 0 1 12.494224548339844 20.442523956298828 A 0.26174307982603179 0.26174307982603179 0 0 1 12.642073631286621 20.529996871948242 A 2.8073202122732281 2.8073202122732281 0 0 1 12.503142356872559 21.298044204711914 A 3.9149138700917883 3.9149138700917883 0 0 1 12.450142860412598 21.072244644165039 A 2.4064440314710436 2.4064440314710436 0 0 0 12.373015403747559 20.774084091186523 A 0.60882181773476129 0.60882181773476129 0 0 0 12.183115005493164 20.495786666870117 A 0.5717661961761723 0.5717661961761723 0 0 0 11.865068435668945 20.377969741821289 A 0.90261892046396197 0.90261892046396197 0 0 0 11.673364639282227 20.383726119995117 A 1.3489868942732932 1.3489868942732932 0 0 0 11.309347152709961 20.481996536254883 M 8.7046728134155273 20.355121612548828 A 3.2962222739118934 3.2962222739118934 0 0 1 8.134343147277832 22.185520172119141 A 0.71884049728792709 0.71884049728792709 0 0 1 8.1072568893432617 21.98271369934082 A 0.85382297002084051 0.85382297002084051 0 0 0 8.0932044982910156 21.844961166381836 A 0.23203694838651681 0.23203694838651681 0 0 0 7.990201473236084 21.690902709960937 A 0.29596936195902812 0.29596936195902812 0 0 0 7.8598732948303223 21.648910522460937 A 0.59927546838883394 0.59927546838883394 0 0 0 7.6503968238830566 21.668111801147461 A 0.61166734037785875 0.61166734037785875 0 0 1 7.469088077545166 21.580362319946289 A 3.3291640283813595 3.3291640283813595 0 0 1 7.6804990768432617 21.581769943237305 A 2.3971715427519533 2.3971715427519533 0 0 0 8.0435800552368164 21.575992584228516 A 0.58584133877037536 0.58584133877037536 0 0 0 8.3577489852905273 21.440820693969727 A 0.60412133254179834 0.60412133254179834 0 0 0 8.5443115234375 21.105611801147461 A 1.336862622224702 1.336862622224702 0 0 0 8.5489015579223633 20.576961517333984 A 0.51334587571517021 0.51334587571517021 0 0 1 8.7046737670898437 20.355119705200195 M 7.3097310066223145 21.072244644165039 A 3.9149145952448094 3.9149145952448094 0 0 1 7.2567305564880371 21.298042297363281 A 2.8073197245255792 2.8073197245255792 0 0 1 7.1178011894226074 20.529996871948242 A 0.26174245239329386 0.26174245239329386 0 0 1 7.2656488418579102 20.442525863647461 A 1.1461940812552671 1.1461940812552671 0 0 1 7.4048304557800293 20.446744918823242 A 0.39969251792721899 0.39969251792721899 0 0 0 7.4992990493774414 20.435125350952148 A 0.36394955905025389 0.36394955905025389 0 0 0 7.5418686866760254 20.421743392944336 A 0.30713828638810053 0.30713828638810053 0 0 0 7.6562948226928711 20.346519470214844 A 0.28976541826615393 0.28976541826615393 0 0 0 7.7325310707092285 20.166582107543945 A 0.5726073307164371 0.5726073307164371 0 0 0 7.6830229759216309 19.916269302368164 A 2.5327269678438018 2.5327269678438018 0 0 1 7.7094268798828125 19.885217666625977 A 0.59167242212341198 0.59167242212341198 0 0 0 7.9124417304992676 20.043949127197266 A 14.246318444301586 14.246318444301586 0 0 0 8.1248893737792969 20.152629852294922 A 1.2449541729286357 1.2449541729286357 0 0 1 8.2915821075439453 20.256267547607422 A 0.54880597646788676 0.54880597646788676 0 0 1 8.4239015579223633 20.400186538696289 A 0.53479219122410537 0.53479219122410537 0 0 1 8.4057807922363281 20.241376876831055 A 1.0792755247454595 1.0792755247454595 0 0 1 8.4445695877075195 20.012548446655273 A 45.459482308784224 45.459482308784224 0 0 0 8.4995965957641602 19.817531585693359 A 0.96341807890904918 0.96341807890904918 0 0 0 8.534423828125 19.632085800170898 A 0.40360564921283321 0.40360564921283321 0 0 0 8.4217195510864258 19.31312370300293 A 2.5321543452624242 2.5321543452624242 0 0 1 8.5255489349365234 19.260087966918945 A 3.1751812194369995 3.1751812194369995 0 0 1 8.6890878677368164 20.011161804199219 A 0.66865781213235709 0.66865781213235709 0 0 1 8.450526237487793 20.481996536254883 A 1.3489870396604429 1.3489870396604429 0 0 0 8.0865097045898438 20.383726119995117 A 0.90261895528432834 0.90261895528432834 0 0 0 7.894805908203125 20.377969741821289 A 0.57176631088298036 0.57176631088298036 0 0 0 7.576758861541748 20.495786666870117 A 0.60882252057038577 0.60882252057038577 0 0 0 7.3868584632873535 20.774084091186523 A 2.4064438205882657 2.4064438205882657 0 0 0 7.3097305297851563 21.072244644165039 M 7.6698050498962402 19.823850631713867 A 0.068326011462106456 0.068326011462106456 0 0 1 7.5608563423156738 19.8380126953125 A 0.23550299596826796 0.23550299596826796 0 0 0 7.3550472259521484 19.824365615844727 A 0.41401496534038668 0.41401496534038668 0 0 0 7.176476001739502 19.96000862121582 A 0.47716442668360021 0.47716442668360021 0 0 0 7.1209192276000977 20.087926864624023 A 3.2435535028326377 3.2435535028326377 0 0 1 7.5103087425231934 18.762142181396484 A 1.3168771066563636 1.3168771066563636 0 0 1 7.6270909309387207 18.865007400512695 A 0.49449521057865192 0.49449521057865192 0 0 1 7.5640602111816406 19.145431518554688 A 0.42535404170573032 0.42535404170573032 0 0 1 7.7917299270629883 19.063949584960938 A 1.3168923085982829 1.3168923085982829 0 0 1 7.8363804817199707 19.134965896606445 A 0.95814535669684453 0.95814535669684453 0 0 0 7.670661449432373 19.418144226074219 A 0.47216073186571705 0.47216073186571705 0 0 0 7.6280694007873535 19.588823318481445 A 0.40059011367437092 0.40059011367437092 0 0 0 7.6698055267333984 19.823850631713867 M 7.9089345932006836 22.479938507080078 A 3.1748660145748815 3.1748660145748815 0 0 1 7.3830418586730957 21.640615463256836 A 0.4587439274818868 0.4587439274818868 0 0 1 7.6093320846557617 21.740571975708008 A 0.49173415782022917 0.49173415782022917 0 0 0 7.5900373458862305 21.926370620727539 A 0.26256388160486294 0.26256388160486294 0 0 0 7.628899097442627 22.048891067504883 A 0.24943771838794726 0.24943771838794726 0 0 0 7.7926554679870605 22.155202865600586 A 1.8139885777894953 1.8139885777894953 0 0 0 7.9409494400024414 22.178653717041016 A 0.5515196539603876 0.5515196539603876 0 0 1 8.1095676422119141 22.221443176269531 A 3.2962226948308313 3.2962226948308313 0 0 1 7.9089350700378418 22.479940414428711 M 7.4241085052490234 22.307060241699219 A 0.58536667022298139 0.58536667022298139 0 0 1 7.0941019058227539 22.629781723022461 A 0.98371548130557418 0.98371548130557418 0 0 0 6.9389901161193848 22.608247756958008 A 0.49091754086105793 0.49091754086105793 0 0 0 7.1053280830383301 22.426687240600586 A 0.99613924765519768 0.99613924765519768 0 0 0 7.2149028778076172 22.084766387939453 A 0.20527190436365755 0.20527190436365755 0 0 1 7.2743287086486816 22.020214080810547 A 2.8921095878341228 2.8921095878341228 0 0 0 7.4241089820861816 22.307060241699219 M 7.9690036773681641 23.323822021484375 A 0.52498956285921716 0.52498956285921716 0 0 0 7.7964992523193359 23.326040267944336 A 0.10705010400199104 0.10705010400199104 0 0 1 7.7068452835083008 23.233184814453125 A 3.2962219714050165 3.2962219714050165 0 0 1 7.9098916053771973 22.971233367919922 A 3.2510263332054468 3.2510263332054468 0 0 1 8.1500892639160156 23.286909103393555 A 1.9608529662023104 1.9608529662023104 0 0 1 8.1208724975585937 23.400531768798828 A 0.2562761099933627 0.2562761099933627 0 0 0 7.9690036773681641 23.323820114135742 M 15.067436218261719 21.125909805297852 A 3.3449485482822872 3.3449485482822872 0 0 1 15.067436218261719 19.550945281982422 L 15.067437171936035 21.125909805297852 M 13.608234405517578 20.614564895629883 A 1.7732939283491131 1.7732939283491131 0 0 1 13.267313003540039 20.332536697387695 A 3.4116150403163776 3.4116150403163776 0 0 1 13.793704032897949 20.292446136474609 A 2.0256778607285262 2.0256778607285262 0 0 0 14.107298851013184 20.291891098022461 A 0.54358642304966742 0.54358642304966742 0 0 0 14.583806991577148 19.945878982543945 A 1.1442961198669541 1.1442961198669541 0 0 0 14.64993953704834 19.407341003417969 A 0.64312298330050854 0.64312298330050854 0 0 1 14.85850715637207 19.308305740356445 A 3.8642626562715474 3.8642626562715474 0 0 0 14.723855972290039 20.346305847167969 A 0.37410874259171745 0.37410874259171745 0 0 1 14.557631492614746 20.524721145629883 A 0.5215647955911149 0.5215647955911149 0 0 0 14.324691772460937 20.409702301025391 A 0.21670260973787783 0.21670260973787783 0 0 0 14.148472785949707 20.452457427978516 A 0.36037673284843363 0.36037673284843363 0 0 0 14.057438850402832 20.561489105224609 A 1.7376839674334603 1.7376839674334603 0 0 1 13.951101303100586 20.737825393676758 A 1.0622379718483219 1.0622379718483219 0 0 0 13.608235359191895 20.614564895629883 M 12.249565124511719 18.762142181396484 A 3.2435541271922492 3.2435541271922492 0 0 1 12.638954162597656 20.087928771972656 A 0.47716478265939521 0.47716478265939521 0 0 0 12.58339786529541 19.96000862121582 A 0.41401494383732551 0.41401494383732551 0 0 0 12.404826164245605 19.824365615844727 A 0.23550296058097181 0.23550296058097181 0 0 0 12.199017524719238 19.8380126953125 A 0.068326613499095412 0.068326613499095412 0 0 1 12.090067863464355 19.823850631713867 A 0.40058979465758526 0.40058979465758526 0 0 0 12.131803512573242 19.588823318481445 A 0.47215979947694281 0.47215979947694281 0 0 0 12.089212417602539 19.418146133422852 A 0.95814509734919673 0.95814509734919673 0 0 0 11.923492431640625 19.134967803955078 A 1.3168920212103361 1.3168920212103361 0 0 1 11.968143463134766 19.063947677612305 A 0.42535414363053897 0.42535414363053897 0 0 1 12.195813179016113 19.145431518554688 A 0.49449493862875088 0.49449493862875088 0 0 1 12.132782936096191 18.865009307861328 A 1.3168770835118107 1.3168770835118107 0 0 1 12.249565124511719 18.762140274047852 M 13.387394905090332 19.781269073486328 A 3.4645820104173555 3.4645820104173555 0 0 1 13.30341911315918 20.081937789916992 A 0.96202113413135226 0.96202113413135226 0 0 1 13.205599784851074 20.280555725097656 A 1.8687784622830717 1.8687784622830717 0 0 1 12.934439659118652 19.910434722900391 A 2.0748380348040891 2.0748380348040891 0 0 1 13.168878555297852 19.867807388305664 A 0.63387770752196049 0.63387770752196049 0 0 0 13.28911018371582 19.838321685791016 A 0.26619949907947021 0.26619949907947021 0 0 0 13.387394905090332 19.781269073486328 M 13.571115493774414 19.295364379882812 A 0.61783291857020228 0.61783291857020228 0 0 0 13.465214729309082 19.485626220703125 A 0.67549942373415262 0.67549942373415262 0 0 0 13.42475700378418 19.340246200561523 A 0.23841615253167306 0.23841615253167306 0 0 0 13.571115493774414 19.295364379882812 M 14.968835830688477 18.960958480834961 A 1.6262436498992972 1.6262436498992972 0 0 1 14.714859008789063 19.145624160766602 A 0.30573145701094118 0.30573145701094118 0 0 1 14.567305564880371 19.195039749145508 A 0.32507444243660744 0.32507444243660744 0 0 1 14.416353225708008 19.157386779785156 A 0.54886958602762925 0.54886958602762925 0 0 0 14.192893028259277 19.101879119873047 A 1.0433751804902183 1.0433751804902183 0 0 1 14.417214393615723 18.925422668457031 A 1.9484215258091424 1.9484215258091424 0 0 1 14.968835830688477 18.960958480834961 M 13.885219573974609 19.102985382080078 A 0.56156479211006727 0.56156479211006727 0 0 0 13.682110786437988 19.188138961791992 A 0.62286204086638675 0.62286204086638675 0 0 0 13.736110687255859 19.10710334777832 A 2.1278544201104594 2.1278544201104594 0 0 1 14.098199844360352 18.977420806884766 A 0.76356791974935823 0.76356791974935823 0 0 1 14.106000900268555 19.091535568237305 A 0.79932955188179255 0.79932955188179255 0 0 0 13.885218620300293 19.102987289428711 M 14.213031768798828 21.048591613769531 A 0.6982433203709324 0.6982433203709324 0 0 0 14.190958023071289 21.001338958740234 A 0.80252779389527285 0.80252779389527285 0 0 0 14.159244537353516 20.944858551025391 A 0.61227806633251503 0.61227806633251503 0 0 0 14.108248710632324 20.873468399047852 A 1.809386530829548 1.809386530829548 0 0 0 14.217753410339355 20.908666610717773 A 0.28347297720984699 0.28347297720984699 0 0 0 14.374478340148926 20.911975860595703 A 0.24489939138869368 0.24489939138869368 0 0 0 14.510985374450684 20.801721572875977 A 0.48127246952729724 0.48127246952729724 0 0 0 14.576703071594238 20.635835647583008 A 0.5163496393106265 0.5163496393106265 0 0 1 14.729264259338379 20.539693832397461 A 3.9604959433728801 3.9604959433728801 0 0 0 14.733433723449707 20.607927322387695 A 0.47468324473684703 0.47468324473684703 0 0 1 14.386601448059082 21.015134811401367 A 1.0983392283139344 1.0983392283139344 0 0 0 14.213031768798828 21.048591613769531 M 12.665771484375 22.629781723022461 A 0.58536638247046247 0.58536638247046247 0 0 1 12.33576488494873 22.307060241699219 A 2.8921097016754205 2.8921097016754205 0 0 0 12.48554515838623 22.02021598815918 A 0.20527166965862342 0.20527166965862342 0 0 1 12.544971466064453 22.084766387939453 A 0.99613862731339387 0.99613862731339387 0 0 0 12.654545783996582 22.426687240600586 A 0.4909177508256195 0.4909177508256195 0 0 0 12.820882797241211 22.608247756958008 A 0.98371537389116837 0.98371537389116837 0 0 0 12.665771484375 22.629781723022461 M 11.85093879699707 22.479940414428711 A 3.2962222358282669 3.2962222358282669 0 0 1 11.650306701660156 22.221443176269531 A 0.55151957629823911 0.55151957629823911 0 0 1 11.818924903869629 22.178653717041016 A 1.8139884784150391 1.8139884784150391 0 0 0 11.967218399047852 22.155202865600586 A 0.24943807592293987 0.24943807592293987 0 0 0 12.130973815917969 22.048891067504883 A 0.26256388952463433 0.26256388952463433 0 0 0 12.169836044311523 21.926370620727539 A 0.4917338374864183 0.4917338374864183 0 0 0 12.150543212890625 21.740571975708008 A 0.45874367598015653 0.45874367598015653 0 0 1 12.3768310546875 21.640615463256836 A 3.174865712100079 3.174865712100079 0 0 1 11.85093879699707 22.479938507080078 M 11.79086971282959 23.323820114135742 A 0.25627603235792057 0.25627603235792057 0 0 0 11.63900089263916 23.400529861450195 A 1.9608526138037057 1.9608526138037057 0 0 1 11.609785079956055 23.286909103393555 A 3.2510261672329213 3.2510261672329213 0 0 1 11.849983215332031 22.971233367919922 A 3.2962215513802442 3.2962215513802442 0 0 1 12.053028106689453 23.233184814453125 A 0.1070503265824239 0.1070503265824239 0 0 1 11.963374137878418 23.326040267944336 A 0.52498957065850571 0.52498957065850571 0 0 0 11.790870666503906 23.323822021484375 M 15.067437171936035 21.981618881225586 L 15.067437171936035 22.457178115844727 A 1.7237387423311847 1.7237387423311847 0 0 0 14.90034008026123 22.212940216064453 A 1.575016192818022 1.575016192818022 0 0 1 15.067438125610352 21.981618881225586 M 6.4925594329833984 25.119440078735352 A 2.0326883321992617 2.0326883321992617 0 0 1 6.2374811172485352 25.34174919128418 L 5.6983675956726074 25.34174919128418 A 0.3509063976634787 0.3509063976634787 0 0 0 5.6114010810852051 25.239358901977539 A 0.21670247050120131 0.21670247050120131 0 0 0 5.4351816177368164 25.196605682373047 A 0.52156496149527043 0.52156496149527043 0 0 0 5.202242374420166 25.311624526977539 A 0.37410858119752377 0.37410858119752377 0 0 1 5.0360164642333984 25.133211135864258 A 3.8642616562812546 3.8642616562812546 0 0 0 4.9013676643371582 24.095211029052734 A 0.64312479136867418 0.64312479136867418 0 0 1 5.1099338531494141 24.194244384765625 A 1.1442958938464394 1.1442958938464394 0 0 0 5.1760659217834473 24.732780456542969 A 0.54358676738308997 0.54358676738308997 0 0 0 5.6525740623474121 25.078794479370117 A 2.0256778818944774 2.0256778818944774 0 0 0 5.9661707878112793 25.079349517822266 A 3.4116150510996182 3.4116150510996182 0 0 1 6.4925589561462402 25.119440078735352 M 6.5542736053466797 25.06745719909668 A 0.96202108757655025 0.96202108757655025 0 0 1 6.4564547538757324 24.868839263916016 A 3.4645811500039119 3.4645811500039119 0 0 1 6.3724784851074219 24.568170547485352 A 0.2661997123908012 0.2661997123908012 0 0 0 6.4707627296447754 24.625223159790039 A 0.63387780927605752 0.63387780927605752 0 0 0 6.5909943580627441 24.65471076965332 A 2.0748379684597085 2.0748379684597085 0 0 1 6.8254337310791016 24.697336196899414 A 1.8687791076275149 1.8687791076275149 0 0 1 6.5542736053466797 25.067459106445313 M 4.692436695098877 25.077470779418945 L 4.692436695098877 24.325263977050781 A 3.3109846541359427 3.3109846541359427 0 0 1 4.7737751007080078 24.798063278198242 A 0.65195151944623519 0.65195151944623519 0 0 1 4.692436695098877 25.077472686767578 M 5.3435201644897461 23.944290161132812 A 0.32507452337288162 0.32507452337288162 0 0 1 5.1925678253173828 23.981943130493164 A 0.30573158849962079 0.30573158849962079 0 0 1 5.0450143814086914 23.932525634765625 A 1.6262435661152812 1.6262435661152812 0 0 1 4.7910375595092773 23.747859954833984 A 1.9484215509294898 1.9484215509294898 0 0 1 5.3426599502563477 23.71232795715332 A 1.0433745125128424 1.0433745125128424 0 0 1 5.5669803619384766 23.88878059387207 A 0.54886956749289273 0.54886956749289273 0 0 0 5.3435201644897461 23.94428825378418 M 6.1887578964233398 24.082267761230469 A 0.23841591227041298 0.23841591227041298 0 0 0 6.3351173400878906 24.12714958190918 A 0.67549961520497082 0.67549961520497082 0 0 0 6.2946586608886719 24.272529602050781 A 0.61783345355636032 0.61783345355636032 0 0 0 6.1887578964233398 24.082265853881836 M 5.661674976348877 23.764322280883789 A 2.1278551300580433 2.1278551300580433 0 0 1 6.0237627029418945 23.894004821777344 A 0.62286200436172479 0.62286200436172479 0 0 0 6.0777630805969238 23.975042343139648 A 0.5615648174897746 0.5615648174897746 0 0 0 5.8746547698974609 23.889888763427734 A 0.79932943744875617 0.79932943744875617 0 0 0 5.6538724899291992 23.878437042236328 A 0.763568328633486 0.763568328633486 0 0 1 5.6616740226745605 23.764324188232422 M 5.3853945732116699 25.698877334594727 A 0.28347284043572174 0.28347284043572174 0 0 0 5.542119026184082 25.695568084716797 A 1.809387551030706 1.809387551030706 0 0 0 5.6516242027282715 25.660371780395508 A 0.61227876526439473 0.61227876526439473 0 0 0 5.6006293296813965 25.731760025024414 A 0.80252780002805801 0.80252780002805801 0 0 0 5.5689153671264648 25.788242340087891 A 0.69824281677744693 0.69824281677744693 0 0 0 5.546842098236084 25.835494995117188 A 1.0983386238290185 1.0983386238290185 0 0 0 5.3732714653015137 25.802038192749023 A 0.47468391205281302 0.47468391205281302 0 0 1 5.0264406204223633 25.394830703735352 A 3.9604948237834323 3.9604948237834323 0 0 0 5.0306086540222168 25.326595306396484 A 0.51634835985883998 0.51634835985883998 0 0 1 5.1831703186035156 25.422737121582031 A 0.48127213906294875 0.48127213906294875 0 0 0 5.2488880157470703 25.588624954223633 A 0.24489907912168141 0.24489907912168141 0 0 0 5.3853945732116699 25.698877334594727 M 4.692436695098877 25.247690200805664 A 0.54514818148798694 0.54514818148798694 0 0 1 4.7893600463867187 25.142023086547852 A 3.3042862848842218 3.3042862848842218 0 0 1 4.7818641662597656 25.34174919128418 L 4.692436695098877 25.34174919128418 L 4.692436695098877 25.247690200805664 M 11.212693214416504 25.268619537353516 A 6.0595457142018354 6.0595457142018354 0 0 1 11.345952987670898 25.24921989440918 A 0.60042662322313189 0.60042662322313189 0 0 0 11.442379951477051 25.230197906494141 A 0.31042981643550965 0.31042981643550965 0 0 0 11.485533714294434 25.215459823608398 A 0.24836037853587084 0.24836037853587084 0 0 0 11.595284461975098 25.131479263305664 A 0.29395810307557585 0.29395810307557585 0 0 0 11.649641036987305 24.951730728149414 A 0.64068329550582626 0.64068329550582626 0 0 0 11.60844898223877 24.722030639648437 A 2.5323558535364312 2.5323558535364312 0 0 1 11.650474548339844 24.672119140625 A 0.59167262697500966 0.59167262697500966 0 0 0 11.853487968444824 24.830852508544922 A 14.24631887151229 14.24631887151229 0 0 0 12.065937042236328 24.939533233642578 A 1.2449545766743393 1.2449545766743393 0 0 1 12.232629776000977 25.043169021606445 A 0.54880637936449106 0.54880637936449106 0 0 1 12.364949226379395 25.187089920043945 A 0.53479219122410537 0.53479219122410537 0 0 1 12.346828460693359 25.028278350830078 A 1.0792755247454595 1.0792755247454595 0 0 1 12.385617256164551 24.79945182800293 A 45.459481657964872 45.459481657964872 0 0 0 12.440646171569824 24.604434967041016 A 0.96341760389838782 0.96341760389838782 0 0 0 12.475471496582031 24.418989181518555 A 0.40360564921283321 0.40360564921283321 0 0 0 12.362766265869141 24.100027084350586 A 2.5321543452624242 2.5321543452624242 0 0 1 12.466596603393555 24.046989440917969 A 3.1751816942111803 3.1751816942111803 0 0 1 12.630135536193848 24.798063278198242 A 0.66865781213235709 0.66865781213235709 0 0 1 12.391573905944824 25.268899917602539 A 1.3489870983836705 1.3489870983836705 0 0 0 12.027557373046875 25.170629501342773 A 0.90261891887847567 0.90261891887847567 0 0 0 11.835853576660156 25.164873123168945 A 0.57176631088298036 0.57176631088298036 0 0 0 11.517806053161621 25.282690048217773 A 0.46981259994298791 0.46981259994298791 0 0 0 11.454439163208008 25.34174919128418 L 11.060439109802246 25.34174919128418 A 3.2964004181866282 3.2964004181866282 0 0 1 11.058847427368164 25.316898345947266 A 0.52438182490463203 0.52438182490463203 0 0 1 11.212691307067871 25.268621444702148 M 8.7933797836303711 24.017675399780273 A 0.52907063918989827 0.52907063918989827 0 0 1 9.0875320434570312 24.302536010742188 A 2.1382120797783641 2.1382120797783641 0 0 1 9.1926670074462891 24.714132308959961 A 0.69725437832114834 0.69725437832114834 0 0 0 9.3492774963378906 24.998477935791016 A 0.23402032460111694 0.23402032460111694 0 0 0 9.5197772979736328 25.087051391601563 A 0.2710558463447364 0.2710558463447364 0 0 0 9.6865482330322266 25.03571891784668 A 0.48507974880067878 0.48507974880067878 0 0 0 9.8799371719360352 24.724987030029297 A 0.48507901604415632 0.48507901604415632 0 0 0 10.073325157165527 25.03571891784668 A 0.27105568585026985 0.27105568585026985 0 0 0 10.240096092224121 25.08704948425293 A 0.23402038784047793 0.23402038784047793 0 0 0 10.410595893859863 24.998479843139648 A 0.69725508082783061 0.69725508082783061 0 0 0 10.567206382751465 24.714132308959961 A 2.1382123304719887 2.1382123304719887 0 0 1 10.672341346740723 24.302534103393555 A 0.52907065172171497 0.52907065172171497 0 0 1 10.966493606567383 24.017675399780273 A 3.9566876059284626 3.9566876059284626 0 0 0 10.816322326660156 25.34174919128418 L 8.9435510635375977 25.34174919128418 A 3.9566879707826508 3.9566879707826508 0 0 0 8.7933807373046875 24.017677307128906 M 7.3742561340332031 24.79945182800293 A 1.0792746588353066 1.0792746588353066 0 0 1 7.4130454063415527 25.028280258178711 A 0.53479232088424822 0.53479232088424822 0 0 1 7.3949246406555176 25.187088012695313 A 0.54880535001347275 0.54880535001347275 0 0 1 7.5272445678710938 25.043169021606445 A 1.2449540498658143 1.2449540498658143 0 0 1 7.6939353942871094 24.939533233642578 A 14.24631966908211 14.24631966908211 0 0 0 7.9063835144042969 24.830852508544922 A 0.5916721239021564 0.5916721239021564 0 0 0 8.1093997955322266 24.672121047973633 A 2.5323561529972269 2.5323561529972269 0 0 1 8.1514253616333008 24.722030639648437 A 0.64068307383143552 0.64068307383143552 0 0 0 8.1102313995361328 24.951730728149414 A 0.29395815041161771 0.29395815041161771 0 0 0 8.1645889282226562 25.131479263305664 A 0.24836078730949501 0.24836078730949501 0 0 0 8.2743396759033203 25.215461730957031 A 0.31042981079273074 0.31042981079273074 0 0 0 8.3174934387207031 25.230195999145508 A 0.60042659977256863 0.60042659977256863 0 0 0 8.4139223098754883 25.24921989440918 A 6.0595465391291086 6.0595465391291086 0 0 1 8.5471830368041992 25.268619537353516 A 0.52438195123232867 0.52438195123232867 0 0 1 8.7010259628295898 25.316900253295898 A 3.2963999466681497 3.2963999466681497 0 0 1 8.6994342803955078 25.34174919128418 L 8.3054342269897461 25.34174919128418 A 0.93573637715158087 0.93573637715158087 0 0 0 8.2420673370361328 25.282688140869141 A 0.57176617061102764 0.57176617061102764 0 0 0 7.9240202903747559 25.164873123168945 A 0.90261892046396197 0.90261892046396197 0 0 0 7.7323174476623535 25.170629501342773 A 1.3489868942732932 1.3489868942732932 0 0 0 7.3682994842529297 25.268899917602539 A 0.66865745773492336 0.66865745773492336 0 0 1 7.1297378540039062 24.798061370849609 A 3.1751815350135972 3.1751815350135972 0 0 1 7.2932777404785156 24.046989440917969 A 2.5321547013923231 2.5321547013923231 0 0 1 7.3971080780029297 24.100025177001953 A 0.40360556435450579 0.40360556435450579 0 0 0 7.2844018936157227 24.418987274169922 A 0.96341758983576931 0.96341758983576931 0 0 0 7.3192296028137207 24.604433059692383 A 45.459485408229305 45.459485408229305 0 0 0 7.3742537498474121 24.799448013305664 M 6.9029355049133301 25.34174919128418 L 6.5781073570251465 25.34174919128418 A 0.95852365633634362 0.95852365633634362 0 0 1 6.9008550643920898 24.937408447265625 A 3.9604951180012011 3.9604951180012011 0 0 0 6.9029359817504883 25.34174919128418 M 7.121605396270752 25.34174919128418 A 3.2962221910100116 3.2962221910100116 0 0 1 7.1141533851623535 25.142021179199219 A 0.515619137940174 0.515619137940174 0 0 1 7.2615413665771484 25.341751098632812 L 7.121605396270752 25.34174919128418 M 13.267315864562988 25.119440078735352 A 3.4116150403163776 3.4116150403163776 0 0 1 13.793704032897949 25.079347610473633 A 2.0256778607285262 2.0256778607285262 0 0 0 14.107298851013184 25.078794479370117 A 0.54358642304966742 0.54358642304966742 0 0 0 14.583806991577148 24.732782363891602 A 1.1442961198669541 1.1442961198669541 0 0 0 14.64993953704834 24.194242477416992 A 0.64312298330050854 0.64312298330050854 0 0 1 14.85850715637207 24.095209121704102 A 3.8642626562715474 3.8642626562715474 0 0 0 14.723855972290039 25.133209228515625 A 0.37410874259171745 0.37410874259171745 0 0 1 14.557631492614746 25.311624526977539 A 0.5215647955911149 0.5215647955911149 0 0 0 14.324691772460937 25.196605682373047 A 0.21670260973787783 0.21670260973787783 0 0 0 14.148472785949707 25.239360809326172 A 0.35090594183425217 0.35090594183425217 0 0 0 14.061505317687988 25.34174919128418 L 13.522392272949219 25.34174919128418 A 2.0326883476306032 2.0326883476306032 0 0 1 13.267313957214355 25.119440078735352 M 13.205599784851074 25.06745719909668 A 1.8687784622830717 1.8687784622830717 0 0 1 12.934439659118652 24.697336196899414 A 2.0748380348040891 2.0748380348040891 0 0 1 13.168878555297852 24.65471076965332 A 0.63387770752196049 0.63387770752196049 0 0 0 13.28911018371582 24.625225067138672 A 0.26619949907947021 0.26619949907947021 0 0 0 13.387394905090332 24.568170547485352 A 3.4645820104173555 3.4645820104173555 0 0 1 13.30341911315918 24.868841171264648 A 0.96202113413135226 0.96202113413135226 0 0 1 13.205599784851074 25.06745719909668 M 13.465214729309082 24.272529602050781 A 0.67549942373415262 0.67549942373415262 0 0 0 13.42475700378418 24.12714958190918 A 0.23841615253167306 0.23841615253167306 0 0 0 13.571115493774414 24.082267761230469 A 0.61783291857020228 0.61783291857020228 0 0 0 13.465214729309082 24.272527694702148 M 12.856938362121582 25.34174919128418 A 3.9604952760745804 3.9604952760745804 0 0 0 12.85901927947998 24.937410354614258 A 0.95852328717308666 0.95852328717308666 0 0 1 13.181766510009766 25.34174919128418 L 12.856938362121582 25.34174919128418 M 12.645720481872559 25.142023086547852 A 3.2962228248167018 3.2962228248167018 0 0 1 12.638267517089844 25.34174919128418 L 12.498332023620605 25.34174919128418 A 0.51561925443088952 0.51561925443088952 0 0 1 12.645720481872559 25.142023086547852 M 15.067436218261719 25.077470779418945 A 0.65195137796097391 0.65195137796097391 0 0 1 14.986098289489746 24.798063278198242 A 3.3109839493820723 3.3109839493820723 0 0 1 15.067436218261719 24.325262069702148 L 15.067437171936035 25.077470779418945 M 14.417214393615723 23.71232795715332 A 1.9484215258091424 1.9484215258091424 0 0 1 14.968835830688477 23.747861862182617 A 1.6262436498992972 1.6262436498992972 0 0 1 14.714859008789063 23.932525634765625 A 0.30573145701094118 0.30573145701094118 0 0 1 14.567305564880371 23.981941223144531 A 0.32507444243660744 0.32507444243660744 0 0 1 14.416353225708008 23.944290161132812 A 0.54886958602762925 0.54886958602762925 0 0 0 14.192893028259277 23.88878059387207 A 1.0433751804902183 1.0433751804902183 0 0 1 14.417214393615723 23.712326049804687 M 13.885219573974609 23.889888763427734 A 0.56156479211006727 0.56156479211006727 0 0 0 13.682110786437988 23.975042343139648 A 0.62286204086638675 0.62286204086638675 0 0 0 13.736110687255859 23.894006729125977 A 2.1278544201104594 2.1278544201104594 0 0 1 14.098199844360352 23.764322280883789 A 0.76356791974935823 0.76356791974935823 0 0 1 14.106000900268555 23.878438949584961 A 0.79932955188179255 0.79932955188179255 0 0 0 13.885218620300293 23.889888763427734 M 14.576702117919922 25.422737121582031 A 0.5163496393106265 0.5163496393106265 0 0 1 14.729264259338379 25.326595306396484 A 3.9604959433728801 3.9604959433728801 0 0 0 14.733433723449707 25.394828796386719 A 0.47468324473684703 0.47468324473684703 0 0 1 14.386601448059082 25.802036285400391 A 1.0983386160269992 1.0983386160269992 0 0 0 14.213031768798828 25.835494995117188 A 0.6982433203709324 0.6982433203709324 0 0 0 14.190958023071289 25.788242340087891 A 0.80252779389527285 0.80252779389527285 0 0 0 14.159244537353516 25.731761932373047 A 0.61227806633251503 0.61227806633251503 0 0 0 14.108248710632324 25.660371780395508 A 1.809386530829548 1.809386530829548 0 0 0 14.217753410339355 25.69556999206543 A 0.28347297720984699 0.28347297720984699 0 0 0 14.374478340148926 25.698877334594727 A 0.24489939138869368 0.24489939138869368 0 0 0 14.510985374450684 25.588624954223633 A 0.48127246952729724 0.48127246952729724 0 0 0 14.576703071594238 25.422737121582031 M 15.067437171936035 25.34174919128418 L 14.978009223937988 25.34174919128418 A 3.3042863113793355 3.3042863113793355 0 0 1 14.970514297485352 25.142023086547852 A 0.5451489317866075 0.5451489317866075 0 0 1 15.067436218261719 25.247690200805664 L 15.067437171936035 25.34174919128418 M 15.754937171936035 26.02924919128418 L 15.754937171936035 0.27925005555152893 L 4.004936695098877 0.27925005555152893 L 4.004936695098877 26.02924919128418 L 15.754937171936035 26.02924919128418 +tkpath::transform scale 19.35483870967742 -19.35483870967742 +.c move all -1 -29 + +# ------------------------------ + +# hxej_001 +M 32.005416870117187 11.378271102905273 L 32.005416870117187 11.378271102905273 A 0.21875 0.21875 0 0 1 32.005416870117187 10.940771102905273 L 32.317916870117188 10.940771102905273 A 0.21875 0.21875 0 1 1 32.317916870117188 11.378271102905273 L 32.005416870117187 11.378271102905273 M 30.50541877746582 11.378271102905273 L 30.50541877746582 11.378271102905273 A 0.21875 0.21875 0 0 1 30.50541877746582 10.940771102905273 L 30.81791877746582 10.940771102905273 A 0.21875 0.21875 0 1 1 30.81791877746582 11.378271102905273 L 30.50541877746582 11.378271102905273 M 32.005416870117187 37.378273010253906 L 32.005416870117187 37.378273010253906 A 0.21875 0.21875 0 0 1 32.005416870117187 36.940773010253906 L 32.317916870117188 36.940773010253906 A 0.21875 0.21875 0 1 1 32.317916870117188 37.378273010253906 L 32.005416870117187 37.378273010253906 M 30.505416870117188 37.378273010253906 L 30.505416870117188 37.378273010253906 A 0.21875 0.21875 0 0 1 30.505416870117188 36.940773010253906 L 30.817916870117188 36.940773010253906 A 0.21875 0.21875 0 1 1 30.817916870117188 37.378273010253906 L 30.505416870117188 37.378273010253906 M 11.353067398071289 22.365718841552734 L 11.353067398071289 22.365718841552734 A 0.125 0.125 0 0 1 11.353067398071289 22.115718841552734 L 11.603067398071289 22.115718841552734 A 0.125 0.125 0 1 1 11.603067398071289 22.365718841552734 L 11.353067398071289 22.365718841552734 M 7.3530678749084473 22.365718841552734 L 7.3530678749084473 22.365718841552734 A 0.125 0.125 0 0 1 7.3530678749084473 22.115718841552734 L 7.6030678749084473 22.115718841552734 A 0.125 0.125 0 1 1 7.6030678749084473 22.365718841552734 L 7.3530678749084473 22.365718841552734 M 7.3530673980712891 26.265819549560547 L 7.3530673980712891 26.265819549560547 A 0.125 0.125 0 0 1 7.3530673980712891 26.015819549560547 L 7.6030673980712891 26.015819549560547 A 0.125 0.125 0 1 1 7.6030673980712891 26.265819549560547 L 7.3530673980712891 26.265819549560547 M 11.353067398071289 26.265819549560547 L 11.353067398071289 26.265819549560547 A 0.125 0.125 0 0 1 11.353067398071289 26.015819549560547 L 11.603067398071289 26.015819549560547 A 0.125 0.125 0 1 1 11.603067398071289 26.265819549560547 L 11.353067398071289 26.265819549560547 M 7.1035671234130859 25.628318786621094 L 7.1035671234130859 24.190719604492188 L 7.1035676002502441 22.753318786621094 A 0.25 0.25 0 0 1 7.3535676002502441 22.503318786621094 L 11.478567123413086 22.503318786621094 A 0.25 0.25 0 0 1 11.728567123413086 22.753318786621094 L 11.728567123413086 25.628318786621094 A 0.25 0.25 0 0 1 11.478567123413086 25.878318786621094 L 7.3535671234130859 25.878318786621094 A 0.25 0.25 0 0 1 7.1035671234130859 25.628318786621094 M 34.253765106201172 44.159523010253906 L 34.253768920898438 4.1595215797424316 L 5.1655693054199219 4.1595191955566406 A 1.0000000000001137 1.0000000000001137 0 0 0 4.1655693054199219 5.1595187187194824 L 4.1655659675598145 43.159519195556641 A 1.0 1.0 0 0 0 5.1655659675598145 44.159519195556641 L 34.253765106201172 44.159523010253906 +M 5.54669189453125 46.065769195556641 L 5.54669189453125 46.065769195556641 A 0.21875 0.21875 0 1 1 5.54669189453125 46.503269195556641 L 5.23419189453125 46.503269195556641 A 0.21875 0.21875 0 0 1 5.23419189453125 46.065769195556641 L 5.54669189453125 46.065769195556641 M 23.42169189453125 46.065769195556641 L 23.42169189453125 46.065769195556641 A 0.21875 0.21875 0 1 1 23.42169189453125 46.503269195556641 L 23.10919189453125 46.503269195556641 A 0.21875 0.21875 0 0 1 23.10919189453125 46.065769195556641 L 23.42169189453125 46.065769195556641 M 24.51544189453125 45.034519195556641 L 4.14044189453125 45.034519195556641 L 4.14044189453125 47.534519195556641 L 24.51544189453125 47.534519195556641 L 24.51544189453125 45.034519195556641 +M 25.702888488769531 46.721942901611328 L 25.702888488769531 46.721942901611328 A 0.1875 0.1875 0 0 1 26.077888488769531 46.721942901611328 L 26.077888488769531 47.346942901611328 A 0.1875 0.1875 0 1 1 25.702888488769531 47.346942901611328 L 25.702888488769531 46.721942901611328 M 25.702888488769531 45.471942901611328 L 25.702888488769531 45.471942901611328 A 0.1875 0.1875 0 0 1 26.077888488769531 45.471942901611328 L 26.077888488769531 46.096942901611328 A 0.1875 0.1875 0 1 1 25.702888488769531 46.096942901611328 L 25.702888488769531 45.471942901611328 M 29.358888626098633 46.409442901611328 L 29.358888626098633 46.409442901611328 M 29.952888488769531 45.81544303894043 A 0.59399986267089844 0.59399986267089844 0 1 1 29.952888488769531 47.003442764282227 A 0.59399986267089844 0.59399986267089844 0 1 1 29.952888488769531 45.81544303894043 M 25.640487670898438 45.034542083740234 L 25.390487670898437 45.284542083740234 L 25.390388488769531 47.534442901611328 L 25.640388488769531 47.784442901611328 L 30.702888488769531 47.784442901611328 L 30.952888488769531 47.534442901611328 L 30.952888488769531 45.284442901611328 L 30.702888488769531 45.034442901611328 L 25.640388488769531 45.034442901611328 +M 32.79638671875 45.459922790527344 L 32.79638671875 45.459922790527344 A 0.15649795532226563 0.15649795532226563 0 1 1 32.79638671875 45.772922515869141 L 32.359390258789063 45.772922515869141 A 0.15650177001953125 0.15650177001953125 0 0 1 32.359390258789063 45.459922790527344 L 32.79638671875 45.459922790527344 M 32.765388488769531 46.991321563720703 L 32.765388488769531 46.991321563720703 A 0.1875 0.1875 0 1 1 32.765388488769531 47.366321563720703 L 32.390388488769531 47.366321563720703 A 0.1875 0.1875 0 0 1 32.390388488769531 46.991321563720703 L 32.765388488769531 46.991321563720703 M 32.79638671875 47.834922790527344 L 32.79638671875 47.834922790527344 A 0.15649795532226563 0.15649795532226563 0 1 1 32.79638671875 48.147922515869141 L 32.359390258789063 48.147922515869141 A 0.15650177001953125 0.15650177001953125 0 0 1 32.359390258789063 47.834922790527344 L 32.79638671875 47.834922790527344 M 31.827888488769531 48.284523010253906 A 0.25 0.25 0 0 0 32.077888488769531 48.534523010253906 L 33.077888488769531 48.534523010253906 A 0.25 0.25 0 0 0 33.327888488769531 48.284523010253906 L 33.327888488769531 45.284523010253906 A 0.25 0.25 0 0 0 33.077888488769531 45.034523010253906 L 32.077888488769531 45.034523010253906 A 0.25 0.25 0 0 0 31.827888488769531 45.284523010253906 L 31.827888488769531 48.284523010253906 +M 37.598712921142578 4.3379020690917969 L 37.598712921142578 4.3379020690917969 A 0.21875 0.21875 0 0 1 38.036212921142578 4.3379020690917969 L 38.036212921142578 4.6504020690917969 A 0.21875 0.21875 0 1 1 37.598712921142578 4.6504020690917969 L 37.598712921142578 4.3379020690917969 M 36.475612640380859 4.3379020690917969 L 36.475612640380859 4.3379020690917969 A 0.21875 0.21875 0 0 1 36.913112640380859 4.3379020690917969 L 36.913112640380859 4.6504020690917969 A 0.21875 0.21875 0 1 1 36.475612640380859 4.6504020690917969 L 36.475612640380859 4.3379020690917969 M 37.270763397216797 7.0566520690917969 L 37.270763397216797 7.0566520690917969 A 0.25 0.25 0 1 1 37.270763397216797 7.5566520690917969 L 36.770763397216797 7.5566520690917969 A 0.25 0.25 0 0 1 36.770763397216797 7.0566520690917969 L 37.270763397216797 7.0566520690917969 M 37.270763397216797 9.0566520690917969 L 37.270763397216797 9.0566520690917969 A 0.25 0.25 0 1 1 37.270763397216797 9.5566520690917969 L 36.770763397216797 9.5566520690917969 A 0.25 0.25 0 0 1 36.770763397216797 9.0566520690917969 L 37.270763397216797 9.0566520690917969 M 37.770763397216797 11.056652069091797 L 37.770763397216797 11.056652069091797 A 0.25 0.25 0 1 1 37.770763397216797 11.556652069091797 L 37.270763397216797 11.556652069091797 A 0.25 0.25 0 0 1 37.270763397216797 11.056652069091797 L 37.770763397216797 11.056652069091797 M 37.770763397216797 13.056652069091797 L 37.770763397216797 13.056652069091797 A 0.25 0.25 0 1 1 37.770763397216797 13.556652069091797 L 37.270763397216797 13.556652069091797 A 0.25 0.25 0 0 1 37.270763397216797 13.056652069091797 L 37.770763397216797 13.056652069091797 M 37.270759582519531 30.431652069091797 L 37.270759582519531 30.431652069091797 A 0.25 0.25 0 1 1 37.270759582519531 30.931652069091797 L 36.770759582519531 30.931652069091797 A 0.25 0.25 0 0 1 36.770759582519531 30.431652069091797 L 37.270759582519531 30.431652069091797 M 37.270759582519531 32.431652069091797 L 37.270759582519531 32.431652069091797 A 0.25 0.25 0 1 1 37.270759582519531 32.931652069091797 L 36.770759582519531 32.931652069091797 A 0.25 0.25 0 0 1 36.770759582519531 32.431652069091797 L 37.270759582519531 32.431652069091797 M 37.770759582519531 34.431552886962891 L 37.770759582519531 34.431552886962891 A 0.25 0.25 0 1 1 37.770759582519531 34.931552886962891 L 37.270759582519531 34.931552886962891 A 0.25 0.25 0 0 1 37.270759582519531 34.431552886962891 L 37.770759582519531 34.431552886962891 M 37.770759582519531 36.431552886962891 L 37.770759582519531 36.431552886962891 A 0.25 0.25 0 1 1 37.770759582519531 36.931552886962891 L 37.270759582519531 36.931552886962891 A 0.25 0.25 0 0 1 37.270759582519531 36.431552886962891 L 37.770759582519531 36.431552886962891 M 36.472511291503906 39.337902069091797 L 36.472511291503906 39.337902069091797 A 0.21875 0.21875 0 0 1 36.910011291503906 39.337902069091797 L 36.910011291503906 39.650402069091797 A 0.21875 0.21875 0 1 1 36.472511291503906 39.650402069091797 L 36.472511291503906 39.337902069091797 M 37.597511291503906 39.337902069091797 L 37.597511291503906 39.337902069091797 A 0.21875 0.21875 0 0 1 38.035011291503906 39.337902069091797 L 38.035011291503906 39.650402069091797 A 0.21875 0.21875 0 1 1 37.597511291503906 39.650402069091797 L 37.597511291503906 39.337902069091797 M 38.628761291503906 40.056652069091797 L 39.378761291503906 38.931652069091797 L 39.378761291503906 5.0566520690917969 L 38.628761291503906 3.9316520690917969 L 35.878761291503906 3.9316520690917969 L 35.128761291503906 5.0566520690917969 L 35.128761291503906 38.931652069091797 L 35.878761291503906 40.056652069091797 L 38.628761291503906 40.056652069091797 +M 37.159961700439453 46.556652069091797 L 37.159961700439453 46.556652069091797 A 0.125 0.125 0 0 1 37.409961700439453 46.556652069091797 L 37.409961700439453 46.806652069091797 A 0.125 0.125 0 1 1 37.159961700439453 46.806652069091797 L 37.159961700439453 46.556652069091797 M 35.284961700439453 46.556652069091797 L 35.284961700439453 46.556652069091797 A 0.125 0.125 0 0 1 35.534961700439453 46.556652069091797 L 35.534961700439453 46.806652069091797 A 0.125 0.125 0 1 1 35.284961700439453 46.806652069091797 L 35.284961700439453 46.556652069091797 M 35.722461700439453 43.884651184082031 L 35.722461700439453 43.884651184082031 M 35.722461700439453 43.884651184082031 A 0.17200088500976563 0.17200088500976563 0 1 1 35.722461700439453 44.228652954101563 A 0.17200088500976563 0.17200088500976563 0 1 1 35.722461700439453 43.884651184082031 M 36.972461700439453 43.884651184082031 L 36.972461700439453 43.884651184082031 M 36.972461700439453 43.884651184082031 A 0.17200088500976563 0.17200088500976563 0 1 1 36.972461700439453 44.228652954101563 A 0.17200088500976563 0.17200088500976563 0 1 1 36.972461700439453 43.884651184082031 M 36.972461700439453 41.259651184082031 L 36.972461700439453 41.259651184082031 M 36.972461700439453 41.259651184082031 A 0.17200088500976563 0.17200088500976563 0 1 1 36.972461700439453 41.603652954101563 A 0.17200088500976563 0.17200088500976563 0 1 1 36.972461700439453 41.259651184082031 M 35.722461700439453 41.259651184082031 L 35.722461700439453 41.259651184082031 M 35.722461700439453 41.259651184082031 A 0.17200088500976563 0.17200088500976563 0 1 1 35.722461700439453 41.603652954101563 A 0.17200088500976563 0.17200088500976563 0 1 1 35.722461700439453 41.259651184082031 M 37.441261291503906 47.181652069091797 A 0.125 0.125 0 0 0 37.566261291503906 47.056652069091797 L 37.566261291503906 41.056652069091797 A 0.125 0.125 0 0 0 37.441261291503906 40.931652069091797 L 35.253761291503906 40.931652069091797 A 0.125 0.125 0 0 0 35.128761291503906 41.056652069091797 L 35.128761291503906 47.056652069091797 A 0.125 0.125 0 0 0 35.253761291503906 47.181652069091797 L 37.441261291503906 47.181652069091797 +M 36.077888488769531 48.806652069091797 A 0.375 0.375 0 1 0 36.077888488769531 48.056652069091797 L 34.202888488769531 48.056652069091797 L 34.202888488769531 48.806652069091797 L 36.077888488769531 48.806652069091797 +M 39.253761291503906 45.431652069091797 L 39.253761291503906 45.431652069091797 A 0.125 0.125 0 1 1 39.253761291503906 45.681652069091797 L 39.003761291503906 45.681652069091797 A 0.125 0.125 0 0 1 39.003761291503906 45.431652069091797 L 39.253761291503906 45.431652069091797 M 39.253761291503906 41.181652069091797 L 39.253761291503906 41.181652069091797 A 0.125 0.125 0 1 1 39.253761291503906 41.431652069091797 L 39.003761291503906 41.431652069091797 A 0.125 0.125 0 0 1 39.003761291503906 41.181652069091797 L 39.253761291503906 41.181652069091797 M 38.441261291503906 40.931652069091797 L 38.441261291503906 45.931652069091797 L 39.316261291503906 45.931652069091797 A 0.25 0.25 0 0 0 39.566261291503906 45.681652069091797 L 39.566261291503906 41.181652069091797 A 0.25 0.25 0 0 0 39.316261291503906 40.931652069091797 L 38.441261291503906 40.931652069091797 +M 1.5400009155273437 1.6959981918334961 L 1.5400009155273437 1.6959981918334961 M 1.5400009155273437 1.3839981555938721 A 0.15600001811981201 0.15600001811981201 0 1 1 1.5400009155273437 1.6959981918334961 A 0.15600001811981201 0.15600001811981201 0 1 1 1.5400009155273437 1.3839981555938721 M 1.5400005578994751 9.9459981918334961 L 1.5400005578994751 9.9459981918334961 M 1.5400005578994751 9.633997917175293 A 0.15600013732910156 0.15600013732910156 0 1 1 1.5400005578994751 9.9459981918334961 A 0.15600013732910156 0.15600013732910156 0 1 1 1.5400005578994751 9.633997917175293 M 1.5400002002716064 18.195999145507813 L 1.5400002002716064 18.195999145507813 M 1.5400002002716064 17.883998870849609 A 0.15600013732910156 0.15600013732910156 0 1 1 1.5400002002716064 18.195999145507813 A 0.15600013732910156 0.15600013732910156 0 1 1 1.5400002002716064 17.883998870849609 M 1.5399998426437378 26.570999145507812 L 1.5399998426437378 26.570999145507812 M 1.5399998426437378 26.258998870849609 A 0.15600013732910156 0.15600013732910156 0 1 1 1.5399998426437378 26.570999145507812 A 0.15600013732910156 0.15600013732910156 0 1 1 1.5399998426437378 26.258998870849609 M 1.5399994850158691 34.945995330810547 L 1.5399994850158691 34.945995330810547 M 1.5399994850158691 34.633998870849609 A 0.15599822998046875 0.15599822998046875 0 1 1 1.5399994850158691 34.945995330810547 A 0.15599822998046875 0.15599822998046875 0 1 1 1.5399994850158691 34.633998870849609 M 1.5399990081787109 43.195995330810547 L 1.5399990081787109 43.195995330810547 M 1.5399991273880005 42.883998870849567 A 0.1559982299805143 0.1559982299805143 0 1 1 1.5399991273880005 43.19599533081059 A 0.1559982299805143 0.1559982299805143 0 1 1 1.5399991273880005 42.883998870849567 M 1.5399986505508423 51.445995330810547 L 1.5399986505508423 51.445995330810547 M 1.5399987697601318 51.133998870849567 A 0.1559982299805143 0.1559982299805143 0 1 1 1.5399987697601318 51.44599533081059 A 0.1559982299805143 0.1559982299805143 0 1 1 1.5399987697601318 51.133998870849567 M 9.7899990081787109 51.445995330810547 L 9.7899990081787109 51.445995330810547 M 9.7899990081787109 51.133998870849609 A 0.15599822998046875 0.15599822998046875 0 1 1 9.7899990081787109 51.445995330810547 A 0.15599822998046875 0.15599822998046875 0 1 1 9.7899990081787109 51.133998870849609 M 18.039999008178711 51.445995330810547 L 18.039999008178711 51.445995330810547 M 18.039999008178711 51.133998870849609 A 0.15599822998046875 0.15599822998046875 0 1 1 18.039999008178711 51.445995330810547 A 0.15599822998046875 0.15599822998046875 0 1 1 18.039999008178711 51.133998870849609 M 26.289999008178711 51.445999145507813 L 26.289999008178711 51.445999145507813 M 26.289999008178711 51.134002685546875 A 0.15599822998046875 0.15599822998046875 0 1 1 26.289999008178711 51.445999145507813 A 0.15599822998046875 0.15599822998046875 0 1 1 26.289999008178711 51.134002685546875 M 34.539997100830078 51.445999145507813 L 34.539997100830078 51.445999145507813 M 34.539997100830078 51.134002685546875 A 0.15599822998046875 0.15599822998046875 0 1 1 34.539997100830078 51.445999145507813 A 0.15599822998046875 0.15599822998046875 0 1 1 34.539997100830078 51.134002685546875 M 42.789997100830078 51.445999145507813 L 42.789997100830078 51.445999145507813 M 42.789997100830078 51.134002685546875 A 0.15599822998046875 0.15599822998046875 0 1 1 42.789997100830078 51.445999145507813 A 0.15599822998046875 0.15599822998046875 0 1 1 42.789997100830078 51.134002685546875 M 42.790000915527344 43.195999145507813 L 42.790000915527344 43.195999145507813 M 42.790000915527344 42.884002685546875 A 0.15599822998046875 0.15599822998046875 0 1 1 42.790000915527344 43.195999145507813 A 0.15599822998046875 0.15599822998046875 0 1 1 42.790000915527344 42.884002685546875 M 42.790000915527344 34.945999145507813 L 42.790000915527344 34.945999145507813 M 42.790000915527344 34.634002685546875 A 0.15599822998046875 0.15599822998046875 0 1 1 42.790000915527344 34.945999145507813 A 0.15599822998046875 0.15599822998046875 0 1 1 42.790000915527344 34.634002685546875 M 42.790000915527344 26.571001052856445 L 42.790000915527344 26.571001052856445 M 42.790000915527344 26.259000778198242 A 0.15600013732910156 0.15600013732910156 0 1 1 42.790000915527344 26.571001052856445 A 0.15600013732910156 0.15600013732910156 0 1 1 42.790000915527344 26.259000778198242 M 42.790000915527344 18.196001052856445 L 42.790000915527344 18.196001052856445 M 42.790000915527344 17.884000778198242 A 0.15600013732910156 0.15600013732910156 0 1 1 42.790000915527344 18.196001052856445 A 0.15600013732910156 0.15600013732910156 0 1 1 42.790000915527344 17.884000778198242 M 42.790000915527344 9.9460000991821289 L 42.790000915527344 9.9460000991821289 M 42.790000915527344 9.6339998245239258 A 0.15600013732910156 0.15600013732910156 0 1 1 42.790000915527344 9.9460000991821289 A 0.15600013732910156 0.15600013732910156 0 1 1 42.790000915527344 9.6339998245239258 M 42.790000915527344 1.6959999799728394 L 42.790000915527344 1.6959999799728394 M 42.790000915527344 1.3839999437332153 A 0.15600001811981201 0.15600001811981201 0 1 1 42.790000915527344 1.6959999799728394 A 0.15600001811981201 0.15600001811981201 0 1 1 42.790000915527344 1.3839999437332153 M 9.7900009155273437 1.6959985494613647 L 9.7900009155273437 1.6959985494613647 M 9.7900009155273437 1.3839985132217407 A 0.15600001811981201 0.15600001811981201 0 1 1 9.7900009155273437 1.6959985494613647 A 0.15600001811981201 0.15600001811981201 0 1 1 9.7900009155273437 1.3839985132217407 M 18.040000915527344 1.6959989070892334 L 18.040000915527344 1.6959989070892334 M 18.040000915527344 1.3839988708496094 A 0.15600001811981201 0.15600001811981201 0 1 1 18.040000915527344 1.6959989070892334 A 0.15600001811981201 0.15600001811981201 0 1 1 18.040000915527344 1.3839988708496094 M 26.290000915527344 1.6959992647171021 L 26.290000915527344 1.6959992647171021 M 26.290000915527344 1.383999228477478 A 0.15600001811981201 0.15600001811981201 0 1 1 26.290000915527344 1.6959992647171021 A 0.15600001811981201 0.15600001811981201 0 1 1 26.290000915527344 1.383999228477478 M 34.540000915527344 1.6959996223449707 L 34.540000915527344 1.6959996223449707 M 34.540000915527344 1.3839995861053467 A 0.15600001811981201 0.15600001811981201 0 1 1 34.540000915527344 1.6959996223449707 A 0.15600001811981201 0.15600001811981201 0 1 1 34.540000915527344 1.3839995861053467 M 5.4774990081787109 49.914997100830078 A 2.5625002384185791 2.5625002384185791 0 0 1 2.9149987697601318 47.352497100830078 L 2.9150006771087646 5.4774980545043945 A 2.5625002384185791 2.5625002384185791 0 0 1 5.4775009155273437 2.9149982929229736 L 38.352500915527344 2.9149997234344482 A 2.5625 2.5625 0 0 1 40.915000915527344 5.4774999618530273 L 40.914997100830078 47.352500915527344 A 2.5625 2.5625 0 0 1 38.352497100830078 49.915000915527344 L 21.914999008178711 49.915000915527344 L 5.4774990081787109 49.914997100830078 M 0.91500091552734375 0.91499817371368408 L 0.91499871015548706 51.914997100830078 L 43.164997100830078 51.915000915527344 L 43.165000915527344 0.91500002145767212 L 0.91500091552734375 0.91499817371368408 +M 9.4150009155273437 53.539997100830078 L 9.4150009155273437 53.539997100830078 M 9.1650009155273437 53.289997100830078 A 0.25 0.25 0 1 1 9.1650009155273437 53.789997100830078 A 0.25 0.25 0 1 1 9.1650009155273437 53.289997100830078 M 9.4150009155273437 55.977497100830078 L 9.4150009155273437 55.977497100830078 M 9.1650009155273437 55.727497100830078 A 0.25 0.25 0 1 1 9.1650009155273437 56.227497100830078 A 0.25 0.25 0 1 1 9.1650009155273437 55.727497100830078 M 9.9150009155273437 57.789997100830078 L 9.9150009155273437 52.789997100830078 L 1.1650009155273437 52.789997100830078 A 0.25 0.25 0 0 0 0.91500091552734375 53.039997100830078 L 0.91500091552734375 57.539997100830078 A 0.25 0.25 0 0 0 1.1650009155273437 57.789997100830078 L 9.9150009155273437 57.789997100830078 +M 11.949897766113281 52.789997100830078 A 0.375 0.375 0 0 0 11.949897766113281 53.539997100830078 L 13.824897766113281 53.539997100830078 L 13.824897766113281 52.789997100830078 L 11.949897766113281 52.789997100830078 +M 15.074897766113281 52.790000915527344 A 0.375 0.375 0 0 0 15.074897766113281 53.540000915527344 L 16.949897766113281 53.540000915527344 L 16.949897766113281 52.790000915527344 L 15.074897766113281 52.790000915527344 +M 18.199897766113281 52.790000915527344 A 0.375 0.375 0 0 0 18.199897766113281 53.540000915527344 L 20.074897766113281 53.540000915527344 L 20.074897766113281 52.790000915527344 L 18.199897766113281 52.790000915527344 +M 21.324897766113281 52.790000915527344 A 0.375 0.375 0 0 0 21.324897766113281 53.540000915527344 L 23.199897766113281 53.540000915527344 L 23.199897766113281 52.790000915527344 L 21.324897766113281 52.790000915527344 +M 24.449897766113281 52.790000915527344 A 0.375 0.375 0 0 0 24.449897766113281 53.540000915527344 L 26.324897766113281 53.540000915527344 L 26.324897766113281 52.790000915527344 L 24.449897766113281 52.790000915527344 +M 27.574897766113281 52.790000915527344 A 0.375 0.375 0 0 0 27.574897766113281 53.540000915527344 L 29.449897766113281 53.540000915527344 L 29.449897766113281 52.790000915527344 L 27.574897766113281 52.790000915527344 +M 30.699897766113281 52.790000915527344 A 0.375 0.375 0 0 0 30.699897766113281 53.540000915527344 L 32.574897766113281 53.540000915527344 L 32.574897766113281 52.790000915527344 L 30.699897766113281 52.790000915527344 +M 33.824897766113281 52.790000915527344 A 0.375 0.375 0 0 0 33.824897766113281 53.540000915527344 L 35.699897766113281 53.540000915527344 L 35.699897766113281 52.790000915527344 L 33.824897766113281 52.790000915527344 +M 36.949897766113281 52.790000915527344 A 0.375 0.375 0 0 0 36.949897766113281 53.540000915527344 L 38.824897766113281 53.540000915527344 L 38.824897766113281 52.790000915527344 L 36.949897766113281 52.790000915527344 +M 40.418899536132813 57.290000915527344 L 40.418899536132813 57.290000915527344 M 40.199897766113281 57.070999145507813 A 0.21900177001953125 0.21900177001953125 0 1 1 40.199897766113281 57.509002685546875 A 0.21900177001953125 0.21900177001953125 0 1 1 40.199897766113281 57.070999145507813 M 44.418899536132813 57.290000915527344 L 44.418899536132813 57.290000915527344 M 44.199897766113281 57.070999145507813 A 0.21900177001953125 0.21900177001953125 0 1 1 44.199897766113281 57.509002685546875 A 0.21900177001953125 0.21900177001953125 0 1 1 44.199897766113281 57.070999145507813 M 44.418899536132813 53.290000915527344 L 44.418899536132813 53.290000915527344 M 44.199897766113281 53.070999145507813 A 0.21900177001953125 0.21900177001953125 0 1 1 44.199897766113281 53.509002685546875 A 0.21900177001953125 0.21900177001953125 0 1 1 44.199897766113281 53.070999145507813 M 40.418899536132813 53.290000915527344 L 40.418899536132813 53.290000915527344 M 40.199897766113281 53.070999145507813 A 0.21900177001953125 0.21900177001953125 0 1 1 40.199897766113281 53.509002685546875 A 0.21900177001953125 0.21900177001953125 0 1 1 40.199897766113281 53.070999145507813 M 39.699897766113281 57.790000915527344 L 44.699897766113281 57.790000915527344 L 44.699897766113281 52.790000915527344 L 39.699897766113281 52.790000915527344 L 39.699897766113281 57.790000915527344 +M 46.685653686523438 37.914993286132812 L 46.685653686523438 37.914993286132812 A 0.1875 0.1875 0 1 1 46.685653686523438 38.289993286132812 L 46.060653686523438 38.289993286132812 A 0.1875 0.1875 0 0 1 46.060653686523438 37.914993286132812 L 46.685653686523438 37.914993286132812 M 47.935653686523438 37.914993286132812 L 47.935653686523438 37.914993286132812 A 0.1875 0.1875 0 1 1 47.935653686523438 38.289993286132812 L 47.310653686523438 38.289993286132812 A 0.1875 0.1875 0 0 1 47.310653686523438 37.914993286132812 L 47.935653686523438 37.914993286132812 M 46.998153686523438 41.570991516113281 L 46.998153686523438 41.570991516113281 M 46.998153686523438 41.570991516113281 A 0.59400177001953125 0.59400177001953125 0 1 1 46.998153686523438 42.758995056152344 A 0.59400177001953125 0.59400177001953125 0 1 1 46.998153686523438 41.570991516113281 M 48.373054504394531 37.852592468261719 L 48.123054504394531 37.602592468261719 L 45.873153686523438 37.602493286132812 L 45.623153686523438 37.852493286132812 L 45.623153686523438 42.914993286132813 L 45.873153686523438 43.164993286132813 L 48.123153686523438 43.164993286132813 L 48.373153686523438 42.914993286132813 L 48.373153686523438 37.852493286132812 +M 51.319660186767578 40.09039306640625 L 51.319660186767578 40.09039306640625 A 0.15649795532226563 0.15649795532226563 0 1 1 51.319660186767578 40.403392791748047 L 50.882663726806641 40.403392791748047 A 0.15650177001953125 0.15650177001953125 0 0 1 50.882663726806641 40.09039306640625 L 51.319660186767578 40.09039306640625 M 51.288661956787109 41.621791839599609 L 51.288661956787109 41.621791839599609 A 0.1875 0.1875 0 1 1 51.288661956787109 41.996791839599609 L 50.913661956787109 41.996791839599609 A 0.1875 0.1875 0 0 1 50.913661956787109 41.621791839599609 L 51.288661956787109 41.621791839599609 M 51.319660186767578 42.46539306640625 L 51.319660186767578 42.46539306640625 A 0.15649795532226563 0.15649795532226563 0 1 1 51.319660186767578 42.778392791748047 L 50.882663726806641 42.778392791748047 A 0.15650177001953125 0.15650177001953125 0 0 1 50.882663726806641 42.46539306640625 L 51.319660186767578 42.46539306640625 M 50.351161956787109 42.914993286132813 A 0.25 0.25 0 0 0 50.601161956787109 43.164993286132813 L 51.601161956787109 43.164993286132813 A 0.25 0.25 0 0 0 51.851161956787109 42.914993286132813 L 51.851161956787109 39.914993286132812 A 0.25 0.25 0 0 0 51.601161956787109 39.664993286132812 L 50.601161956787109 39.664993286132812 A 0.25 0.25 0 0 0 50.351161956787109 39.914993286132812 L 50.351161956787109 42.914993286132813 +M 53.476165771484375 40.852809906005859 A 0.375 0.375 0 0 0 52.726165771484375 40.852809906005859 L 52.726165771484375 42.727809906005859 L 53.476165771484375 42.727809906005859 L 53.476165771484375 40.852809906005859 +M 56.226161956787109 43.027252197265625 A 0.375 0.375 0 1 0 56.226161956787109 42.277252197265625 L 54.351161956787109 42.277252197265625 L 54.351161956787109 43.027252197265625 L 56.226161956787109 43.027252197265625 +M 64.607177734375 6.5232195854187012 L 64.607177734375 6.5232195854187012 A 0.21875 0.21875 0 1 1 64.169677734375 6.5232195854187012 L 64.169677734375 6.3357195854187012 A 0.21875 0.21875 0 0 1 64.607177734375 6.3357195854187012 L 64.607177734375 6.5232195854187012 M 64.388427734375 10.460969924926758 L 64.388427734375 10.460969924926758 M 64.388427734375 10.022970199584961 A 0.21899986267089844 0.21899986267089844 0 1 1 64.388427734375 10.460969924926758 A 0.21899986267089844 0.21899986267089844 0 1 1 64.388427734375 10.022970199584961 M 64.013435363769531 5.9294695854187012 A 0.12499618530273438 0.12499618530273438 0 0 0 63.888431549072266 6.0544695854187012 L 63.888431549072266 10.741970062255859 A 0.125 0.125 0 0 0 64.013427734375 10.866970062255859 L 64.763427734375 10.866970062255859 A 0.125 0.125 0 0 0 64.888427734375 10.741970062255859 L 64.888427734375 6.0544695854187012 A 0.12500000023283064 0.12500000023283064 0 0 0 64.763435363769531 5.9294695854187012 L 64.013435363769531 5.9294695854187012 +M 64.607177734375 12.335719108581543 L 64.607177734375 12.335719108581543 A 0.21875 0.21875 0 1 1 64.169677734375 12.335719108581543 L 64.169677734375 12.148219108581543 A 0.21875 0.21875 0 0 1 64.607177734375 12.148219108581543 L 64.607177734375 12.335719108581543 M 64.388427734375 16.273469924926758 L 64.388427734375 16.273469924926758 M 64.388427734375 15.835470199584961 A 0.21899986267089844 0.21899986267089844 0 1 1 64.388427734375 16.273469924926758 A 0.21899986267089844 0.21899986267089844 0 1 1 64.388427734375 15.835470199584961 M 64.013435363769531 11.741969108581543 A 0.12499618530273438 0.12499618530273438 0 0 0 63.888431549072266 11.866969108581543 L 63.888431549072266 16.554470062255859 A 0.125 0.125 0 0 0 64.013427734375 16.679470062255859 L 64.763427734375 16.679470062255859 A 0.125 0.125 0 0 0 64.888427734375 16.554470062255859 L 64.888427734375 11.866969108581543 A 0.12500000023283064 0.12500000023283064 0 0 0 64.763435363769531 11.741969108581543 L 64.013435363769531 11.741969108581543 +M 64.607177734375 18.148218154907227 L 64.607177734375 18.148218154907227 A 0.21875 0.21875 0 1 1 64.169677734375 18.148218154907227 L 64.169677734375 17.960718154907227 A 0.21875 0.21875 0 0 1 64.607177734375 17.960718154907227 L 64.607177734375 18.148218154907227 M 64.388427734375 22.085968017578125 L 64.388427734375 22.085968017578125 M 64.388427734375 21.647968292236328 A 0.21899986267089844 0.21899986267089844 0 1 1 64.388427734375 22.085968017578125 A 0.21899986267089844 0.21899986267089844 0 1 1 64.388427734375 21.647968292236328 M 64.013427734375 17.554468154907227 A 0.125 0.125 0 0 0 63.888427734375 17.679468154907227 L 63.888427734375 22.366968154907227 A 0.125 0.125 0 0 0 64.013427734375 22.491968154907227 L 64.763427734375 22.491968154907227 A 0.125 0.125 0 0 0 64.888427734375 22.366968154907227 L 64.888427734375 17.679468154907227 A 0.125 0.125 0 0 0 64.763427734375 17.554468154907227 L 64.013427734375 17.554468154907227 +M 64.138420104980469 25.241962432861328 A 0.375 0.375 0 1 0 64.888420104980469 25.241962432861328 L 64.888420104980469 23.366962432861328 L 64.138420104980469 23.366962432861328 L 64.138420104980469 25.241962432861328 +M 73.356925964355469 5.4934558868408203 L 73.356925964355469 5.4934558868408203 M 73.825927734375 5.0244541168212891 A 0.46900177001953125 0.46900177001953125 0 1 1 73.825927734375 5.9624576568603516 A 0.46900177001953125 0.46900177001953125 0 1 1 73.825927734375 5.0244541168212891 M 72.755424499511719 5.4934558868408203 L 72.755424499511719 5.4934558868408203 M 72.888427734375 5.3604526519775391 A 0.13300323486328125 0.13300323486328125 0 1 1 72.888427734375 5.6264591217041016 A 0.13300323486328125 0.13300323486328125 0 1 1 72.888427734375 5.3604526519775391 M 74.630325317382813 5.4934558868408203 L 74.630325317382813 5.4934558868408203 M 74.763328552246094 5.3604526519775391 A 0.13300323486328125 0.13300323486328125 0 1 1 74.763328552246094 5.6264591217041016 A 0.13300323486328125 0.13300323486328125 0 1 1 74.763328552246094 5.3604526519775391 M 74.630325317382813 24.49345588684082 L 74.630325317382813 24.49345588684082 M 74.763328552246094 24.360452651977539 A 0.13300323486328125 0.13300323486328125 0 1 1 74.763328552246094 24.626459121704102 A 0.13300323486328125 0.13300323486328125 0 1 1 74.763328552246094 24.360452651977539 M 73.356925964355469 24.49345588684082 L 73.356925964355469 24.49345588684082 M 73.825927734375 24.024454116821289 A 0.46900177001953125 0.46900177001953125 0 1 1 73.825927734375 24.962457656860352 A 0.46900177001953125 0.46900177001953125 0 1 1 73.825927734375 24.024454116821289 M 72.755424499511719 24.49345588684082 L 72.755424499511719 24.49345588684082 M 72.888427734375 24.360452651977539 A 0.13300323486328125 0.13300323486328125 0 1 1 72.888427734375 24.626459121704102 A 0.13300323486328125 0.13300323486328125 0 1 1 72.888427734375 24.360452651977539 M 67.138427734375 15.243454933166504 L 67.138427734375 15.243454933166504 A 0.25 0.25 0 0 1 67.138427734375 14.743454933166504 L 67.638427734375 14.743454933166504 A 0.25 0.25 0 1 1 67.638427734375 15.243454933166504 L 67.138427734375 15.243454933166504 M 86.388427734375 25.868457794189453 L 86.388427734375 4.1184568405151367 L 66.513427734375 4.1184549331665039 A 0.75 0.75 0 0 0 65.763427734375 4.8684549331665039 L 65.763427734375 25.11845588684082 A 0.75 0.75 0 0 0 66.513427734375 25.86845588684082 L 86.388427734375 25.868457794189453 +M 64.267234802246094 27.475948333740234 L 64.267234802246094 27.475948333740234 M 64.267234802246094 27.475948333740234 A 0.1875 0.1875 0 1 1 64.267234802246094 27.850948333740234 A 0.1875 0.1875 0 1 1 64.267234802246094 27.475948333740234 M 64.267234802246094 34.350948333740234 L 64.267234802246094 34.350948333740234 M 64.267234802246094 34.350948333740234 A 0.1875 0.1875 0 1 1 64.267234802246094 34.725948333740234 A 0.1875 0.1875 0 1 1 64.267234802246094 34.350948333740234 M 63.767234802246094 34.788448333740234 L 64.517234802246094 35.538448333740234 L 65.779335021972656 35.538448333740234 A 0.18750039429828044 0.18750039429828044 0 0 0 65.873085021972656 35.513328552246094 L 71.689834594726563 32.154949188232422 A 0.18749237061517043 0.18749237061517043 0 0 0 71.78363037109375 31.992647171020508 L 71.783638000488281 30.209247589111328 A 0.18749874248717799 0.18749874248717799 0 0 0 71.689888000488281 30.046869277954102 L 65.873237609863281 26.688549041748047 A 0.1875 0.1875 0 0 0 65.779533386230469 26.663448333740234 L 64.517234802246094 26.663448333740234 L 63.767234802246094 27.413448333740234 L 63.767234802246094 34.788448333740234 +M 65.836906433105469 36.413448333740234 A 0.375 0.375 0 0 0 65.836906433105469 37.163448333740234 L 67.711906433105469 37.163448333740234 L 67.711906433105469 36.413448333740234 L 65.836906433105469 36.413448333740234 +M 71.513427734375 28.618457794189453 A 0.375 0.375 0 1 0 72.263427734375 28.618457794189453 L 72.263427734375 26.743457794189453 L 71.513427734375 26.743457794189453 L 71.513427734375 28.618457794189453 +M 68.838478088378906 36.056026458740234 L 68.838478088378906 36.056026458740234 M 68.971481323242188 35.923023223876953 A 0.13300323486328125 0.13300323486328125 0 1 1 68.971481323242188 36.189029693603516 A 0.13300323486328125 0.13300323486328125 0 1 1 68.971481323242188 35.923023223876953 M 72.283981323242188 35.118526458740234 A 0.25 0.25 0 0 0 72.033981323242187 34.868526458740234 L 68.971481323242188 34.868526458740234 A 0.25 0.25 0 0 0 68.721481323242188 35.118526458740234 L 68.721481323242188 35.660724639892578 A 0.12499817319742106 0.12499817319742106 0 0 1 68.715065002441406 35.700252532958984 L 68.602882385253906 36.036827087402344 A 0.125 0.125 0 0 0 68.596481323242187 36.076324462890625 L 68.596481323242187 36.306026458740234 A 0.125 0.125 0 0 0 68.721481323242188 36.431026458740234 L 70.085884094238281 36.431026458740234 A 0.12500009784703969 0.12500009784703969 0 0 0 70.107002258300781 36.429229736328125 L 72.180084228515625 36.073825836181641 A 0.125 0.125 0 0 0 72.283981323242188 35.950626373291016 L 72.283981323242188 35.118526458740234 +M 74.075927734375 31.493461608886719 L 74.075927734375 31.493461608886719 A 0.1875 0.1875 0 1 1 74.075927734375 31.868461608886719 L 73.700927734375 31.868461608886719 A 0.1875 0.1875 0 0 1 73.700927734375 31.493461608886719 L 74.075927734375 31.493461608886719 M 74.075927734375 27.493461608886719 L 74.075927734375 27.493461608886719 A 0.1875 0.1875 0 1 1 74.075927734375 27.868461608886719 L 73.700927734375 27.868461608886719 A 0.1875 0.1875 0 0 1 73.700927734375 27.493461608886719 L 74.075927734375 27.493461608886719 M 85.825927734375 27.493461608886719 L 85.825927734375 27.493461608886719 A 0.1875 0.1875 0 1 1 85.825927734375 27.868461608886719 L 85.450927734375 27.868461608886719 A 0.1875 0.1875 0 0 1 85.450927734375 27.493461608886719 L 85.825927734375 27.493461608886719 M 85.825927734375 31.493461608886719 L 85.825927734375 31.493461608886719 A 0.1875 0.1875 0 1 1 85.825927734375 31.868461608886719 L 85.450927734375 31.868461608886719 A 0.1875 0.1875 0 0 1 85.450927734375 31.493461608886719 L 85.825927734375 31.493461608886719 M 74.601844787597656 32.581851959228516 A 0.125 0.125 0 0 0 74.690231323242188 32.618461608886719 L 84.836631774902344 32.618461608886719 A 0.12500013486707759 0.12500013486707759 0 0 0 84.925018310546875 32.581851959228516 L 85.101829528808594 32.405059814453125 A 0.125 0.125 0 0 1 85.190231323242188 32.368461608886719 L 86.086631774902344 32.368461608886719 A 0.12499743743966908 0.12499743743966908 0 0 0 86.175018310546875 32.33184814453125 L 86.351829528808594 32.155059814453125 A 0.125 0.125 0 0 0 86.388427734375 32.066661834716797 L 86.388427734375 27.295261383056641 A 0.12500418100091226 0.12500418100091226 0 0 0 86.351821899414063 27.206872940063477 L 86.175033569335938 27.030061721801758 A 0.125 0.125 0 0 0 86.086631774902344 26.993461608886719 L 85.190231323242188 26.993461608886719 A 0.12499878614609745 0.12499878614609745 0 0 1 85.101844787597656 26.956850051879883 L 84.925033569335938 26.780061721801758 A 0.125 0.125 0 0 0 84.836631774902344 26.743461608886719 L 74.690231323242188 26.743461608886719 A 0.12499743743966908 0.12499743743966908 0 0 0 74.601844787597656 26.780075073242188 L 74.425033569335937 26.95686149597168 A 0.125 0.125 0 0 1 74.336631774902344 26.993461608886719 L 73.440231323242188 26.993461608886719 A 0.12499743743966908 0.12499743743966908 0 0 0 73.351844787597656 27.030075073242188 L 73.175033569335938 27.20686149597168 A 0.125 0.125 0 0 0 73.138427734375 27.295261383056641 L 73.138427734375 32.066661834716797 A 0.12499743743966908 0.12499743743966908 0 0 0 73.175041198730469 32.155048370361328 L 73.351829528808594 32.331863403320312 A 0.12500000023283064 0.12500000023283064 0 0 0 73.440238952636719 32.368461608886719 L 74.336631774902344 32.368461608886719 A 0.12500013486707759 0.12500013486707759 0 0 1 74.425018310546875 32.405071258544922 L 74.601829528808594 32.581863403320312 +M 73.47845458984375 34.305965423583984 L 73.47845458984375 34.305965423583984 A 0.125 0.125 0 1 1 73.22845458984375 34.305965423583984 L 73.22845458984375 34.055965423583984 A 0.125 0.125 0 0 1 73.47845458984375 34.055965423583984 L 73.47845458984375 34.305965423583984 M 77.72845458984375 34.305965423583984 L 77.72845458984375 34.305965423583984 A 0.125 0.125 0 1 1 77.47845458984375 34.305965423583984 L 77.47845458984375 34.055965423583984 A 0.125 0.125 0 0 1 77.72845458984375 34.055965423583984 L 77.72845458984375 34.305965423583984 M 77.97845458984375 33.493465423583984 L 72.97845458984375 33.493465423583984 L 72.97845458984375 34.368465423583984 A 0.25 0.25 0 0 0 73.22845458984375 34.618465423583984 L 77.72845458984375 34.618465423583984 A 0.25 0.25 0 0 0 77.97845458984375 34.368465423583984 L 77.97845458984375 33.493465423583984 +M 83.93212890625 37.602500915527344 A 0.375 0.375 0 0 0 83.93212890625 38.352500915527344 L 85.80712890625 38.352500915527344 L 85.80712890625 37.602500915527344 L 83.93212890625 37.602500915527344 +M 85.721115112304687 39.977500915527344 L 85.721115112304687 39.977500915527344 M 85.940116882324219 39.758499145507812 A 0.21900177001953125 0.21900177001953125 0 1 1 85.940116882324219 40.196502685546875 A 0.21900177001953125 0.21900177001953125 0 1 1 85.940116882324219 39.758499145507812 M 78.221115112304688 39.977500915527344 L 78.221115112304688 39.977500915527344 M 78.440116882324219 39.758499145507812 A 0.21900177001953125 0.21900177001953125 0 1 1 78.440116882324219 40.196502685546875 A 0.21900177001953125 0.21900177001953125 0 1 1 78.440116882324219 39.758499145507812 M 77.690116882324219 39.727500915527344 L 77.690116882324219 40.727500915527344 L 86.690116882324219 40.727500915527344 L 86.690116882324219 39.727500915527344 A 0.5 0.5 0 0 0 86.190116882324219 39.227500915527344 L 78.190116882324219 39.227500915527344 A 0.5 0.5 0 0 0 77.690116882324219 39.727500915527344 +M 90.263427734375 6.938725471496582 L 90.263427734375 6.938725471496582 M 90.263427734375 6.6267251968383789 A 0.15600013732910156 0.15600013732910156 0 1 1 90.263427734375 6.938725471496582 A 0.15600013732910156 0.15600013732910156 0 1 1 90.263427734375 6.6267251968383789 M 91.763427734375 7.2827253341674805 L 91.763427734375 7.2827253341674805 M 91.763427734375 6.2827253341674805 A 0.5 0.5 0 1 1 91.763427734375 7.2827253341674805 A 0.5 0.5 0 1 1 91.763427734375 6.2827253341674805 M 93.263427734375 6.938725471496582 L 93.263427734375 6.938725471496582 M 93.263427734375 6.6267261505126953 A 0.15599966049194336 0.15599966049194336 0 1 1 93.263427734375 6.938725471496582 A 0.15599966049194336 0.15599966049194336 0 1 1 93.263427734375 6.6267261505126953 M 87.263427734375 15.97022533416748 L 88.263427734375 15.97022533416748 L 88.263427734375 16.220226287841797 L 95.263427734375 16.220226287841797 L 95.263427734375 15.97022533416748 L 96.263427734375 15.97022533416748 L 96.263427734375 6.0327258110046387 A 0.5 0.5 0 0 0 95.763427734375 5.5327258110046387 L 87.763427734375 5.5327253341674805 A 0.5 0.5 0 0 0 87.263427734375 6.0327253341674805 L 87.263427734375 15.97022533416748 +M 87.263427734375 27.220226287841797 L 96.013427734375 27.220226287841797 L 96.013427734375 17.095226287841797 L 87.263427734375 17.095226287841797 L 87.263427734375 27.220226287841797 +M 93.482437133789063 28.970226287841797 L 93.482437133789063 28.970226287841797 M 93.763435363769531 28.689228057861328 A 0.28099822998046875 0.28099822998046875 0 1 1 93.763435363769531 29.251224517822266 A 0.28099822998046875 0.28099822998046875 0 1 1 93.763435363769531 28.689228057861328 M 87.982437133789063 28.970226287841797 L 87.982437133789063 28.970226287841797 M 88.263435363769531 28.689228057861328 A 0.28099822998046875 0.28099822998046875 0 1 1 88.263435363769531 29.251224517822266 A 0.28099822998046875 0.28099822998046875 0 1 1 88.263435363769531 28.689228057861328 M 87.263435363769531 28.095226287841797 L 87.263435363769531 28.970226287841797 A 0.625 0.625 0 0 0 87.888435363769531 29.595226287841797 L 94.138435363769531 29.595226287841797 A 0.625 0.625 0 0 0 94.763435363769531 28.970226287841797 L 94.763435363769531 28.095226287841797 L 87.263435363769531 28.095226287841797 +M 89.138435363769531 31.220226287841797 A 0.375 0.375 0 1 0 89.138435363769531 30.470226287841797 L 87.263435363769531 30.470226287841797 L 87.263435363769531 31.220226287841797 L 89.138435363769531 31.220226287841797 +M 95.125259399414063 34.602493286132813 A 0.375 0.375 0 0 0 95.125259399414063 35.352493286132812 L 97.000259399414063 35.352493286132812 L 97.000259399414063 34.602493286132813 L 95.125259399414063 34.602493286132813 +M 89.306625366210938 40.196495056152344 L 89.306625366210938 40.196495056152344 M 89.306625366210938 39.758491516113281 A 0.21900177001953125 0.21900177001953125 0 1 1 89.306625366210938 40.196495056152344 A 0.21900177001953125 0.21900177001953125 0 1 1 89.306625366210938 39.758491516113281 M 89.306625366210938 37.196495056152344 L 89.306625366210938 37.196495056152344 M 89.306625366210938 36.758491516113281 A 0.21900177001953125 0.21900177001953125 0 1 1 89.306625366210938 37.196495056152344 A 0.21900177001953125 0.21900177001953125 0 1 1 89.306625366210938 36.758491516113281 M 96.806625366210937 37.196495056152344 L 96.806625366210937 37.196495056152344 M 96.806625366210937 36.758491516113281 A 0.21900177001953125 0.21900177001953125 0 1 1 96.806625366210937 37.196495056152344 A 0.21900177001953125 0.21900177001953125 0 1 1 96.806625366210937 36.758491516113281 M 96.806625366210937 40.196495056152344 L 96.806625366210937 40.196495056152344 M 96.806625366210937 39.758491516113281 A 0.21900177001953125 0.21900177001953125 0 1 1 96.806625366210937 40.196495056152344 A 0.21900177001953125 0.21900177001953125 0 1 1 96.806625366210937 39.758491516113281 M 89.306625366210938 36.227493286132813 A 0.75 0.75 0 0 0 88.556625366210938 36.977493286132812 L 88.556625366210938 39.977493286132813 A 0.75 0.75 0 0 0 89.306625366210938 40.727493286132812 L 96.806625366210937 40.727493286132812 A 0.75 0.75 0 0 0 97.556625366210937 39.977493286132813 L 97.556625366210937 36.977493286132812 A 0.75 0.75 0 0 0 96.806625366210937 36.227493286132813 L 89.306625366210938 36.227493286132813 +M 99.150375366210937 34.388999938964844 L 99.150375366210937 34.388999938964844 A 0.21875 0.21875 0 1 1 98.712875366210938 34.388999938964844 L 98.712875366210938 34.201499938964844 A 0.21875 0.21875 0 0 1 99.150375366210937 34.201499938964844 L 99.150375366210937 34.388999938964844 M 98.931625366210937 38.326751708984375 L 98.931625366210937 38.326751708984375 M 98.931625366210937 37.888748168945313 A 0.21900177001953125 0.21900177001953125 0 1 1 98.931625366210937 38.326751708984375 A 0.21900177001953125 0.21900177001953125 0 1 1 98.931625366210937 37.888748168945313 M 98.556625366210937 33.795249938964844 A 0.125 0.125 0 0 0 98.431625366210937 33.920249938964844 L 98.431625366210937 38.607749938964844 A 0.125 0.125 0 0 0 98.556625366210937 38.732749938964844 L 99.306625366210938 38.732749938964844 A 0.125 0.125 0 0 0 99.431625366210937 38.607749938964844 L 99.431625366210937 33.920249938964844 A 0.125 0.125 0 0 0 99.306625366210938 33.795249938964844 L 98.556625366210937 33.795249938964844 +M 55.884914398193359 36.688999176025391 L 55.884914398193359 36.688999176025391 M 55.884914398193359 36.688999176025391 A 0.17200088500976563 0.17200088500976563 0 1 1 55.884914398193359 37.033000946044922 A 0.17200088500976563 0.17200088500976563 0 1 1 55.884914398193359 36.688999176025391 M 57.851715087890625 33.282398223876953 L 57.851715087890625 33.282398223876953 M 57.851715087890625 33.282398223876953 A 0.17200088500976563 0.17200088500976563 0 1 1 57.851715087890625 33.626399993896484 A 0.17200088500976563 0.17200088500976563 0 1 1 57.851715087890625 33.282398223876953 M 54.445114135742188 31.315597534179688 L 54.445114135742188 31.315597534179688 M 54.445114135742188 31.315597534179688 A 0.17200088500976563 0.17200088500976563 0 1 1 54.445114135742188 31.659599304199219 A 0.17200088500976563 0.17200088500976563 0 1 1 54.445114135742188 31.315597534179688 M 52.478317260742187 34.722198486328125 L 52.478317260742187 34.722198486328125 M 52.478317260742187 34.722198486328125 A 0.17200088500976563 0.17200088500976563 0 1 1 52.478317260742187 35.066200256347656 A 0.17200088500976563 0.17200088500976563 0 1 1 52.478317260742187 34.722198486328125 M 94.040115356445312 3.2275004386901855 A 3.3125 3.3125 0 0 1 97.352615356445312 6.5400004386901855 L 97.352516174316406 27.869300842285156 A 3.3124979610640852 3.3124979610640852 0 0 1 94.897682189941406 31.068866729736328 L 67.022613525390625 38.540000915527344 A 3.3125000000790745 3.3125000000790745 0 0 1 62.852516174316406 35.340522766113281 L 62.852516174316406 6.5399999618530273 A 3.3125 3.3125 0 0 1 66.165016174316406 3.2274999618530273 L 80.102516174316406 3.2275002002716064 L 94.040016174316406 3.2275004386901855 M 57.572525024414063 33.793048858642578 A 2.9999998475929375 2.9999998475929375 0 0 0 58.216316223144531 35.226753234863281 A 0.65619960248180631 0.65619960248180631 0 0 1 57.60211181640625 36.290451049804688 A 3.0000002031568562 3.0000002031568562 0 0 0 56.038665771484375 36.449916839599609 A 2.4375019073486328 2.4375019073486328 0 1 1 55.165016174316406 31.736799240112305 A 2.4374978958458797 2.4374978958458797 0 0 1 57.572521209716797 33.793098449707031 M 44.040016174316406 33.875984191894531 A 0.50000050457285405 0.50000050457285405 0 0 0 44.290447235107422 34.309261322021484 L 59.485816955566406 43.061801910400391 A 0.50000050422360842 0.50000050422360842 0 0 0 59.864768981933594 43.111454010009766 L 99.169517517089844 32.576900482177734 A 0.50000000001455192 0.50000000001455192 0 0 0 99.540115356445313 32.093902587890625 L 99.540016174316406 1.4150004386901855 A 0.50000005960464478 0.50000005960464478 0 0 0 99.040115356445313 0.91500037908554077 L 93.540016174316406 0.915000319480896 L 93.540016174316406 1.915000319480896 L 90.790016174316406 1.915000319480896 L 90.790016174316406 0.91500025987625122 L 73.165016174316406 0.91500008106231689 L 73.165016174316406 1.9150000810623169 L 70.415016174316406 1.9150000810623169 L 70.415016174316406 0.91500002145767212 L 52.790016174316406 0.91499984264373779 L 52.790016174316406 1.9149998426437378 L 50.040016174316406 1.9149998426437378 L 50.040016174316406 0.91499978303909302 L 44.540016174316406 0.91499972343444824 A 0.5 0.5 0 0 0 44.040016174316406 1.4149997234344482 L 44.040016174316406 33.875999450683594 +M 47.744396209716797 48.883792877197266 L 47.744396209716797 48.883792877197266 M 47.824897766113281 48.803291320800781 A 0.080501556396484375 0.080501556396484375 0 1 1 47.824897766113281 48.96429443359375 A 0.080501556396484375 0.080501556396484375 0 1 1 47.824897766113281 48.803291320800781 M 51.494396209716797 48.883792877197266 L 51.494396209716797 48.883792877197266 M 51.574897766113281 48.803291320800781 A 0.080501556396484375 0.080501556396484375 0 1 1 51.574897766113281 48.96429443359375 A 0.080501556396484375 0.080501556396484375 0 1 1 51.574897766113281 48.803291320800781 M 51.494396209716797 45.196193695068359 L 51.494396209716797 45.196193695068359 M 51.574897766113281 45.115692138671875 A 0.080501556396484375 0.080501556396484375 0 1 1 51.574897766113281 45.276695251464844 A 0.080501556396484375 0.080501556396484375 0 1 1 51.574897766113281 45.115692138671875 M 47.744396209716797 45.196193695068359 L 47.744396209716797 45.196193695068359 M 47.824897766113281 45.115692138671875 A 0.080501556396484375 0.080501556396484375 0 1 1 47.824897766113281 45.276695251464844 A 0.080501556396484375 0.080501556396484375 0 1 1 47.824897766113281 45.115692138671875 M 47.533596038818359 45.539993286132813 A 0.125 0.125 0 0 1 47.658596038818359 45.414993286132812 L 47.918598175048828 45.414993286132812 A 0.15620040893554688 0.15620040893554688 0 0 1 48.231098175048828 45.414993286132812 L 51.721096038818359 45.414993286132812 A 0.125 0.125 0 0 1 51.846096038818359 45.539993286132813 L 51.846096038818359 48.539993286132813 A 0.125 0.125 0 0 1 51.721096038818359 48.664993286132813 L 48.231098175048828 48.664993286132813 A 0.15620040893554688 0.15620040893554688 0 1 1 47.918697357177734 48.664993286132813 L 47.658596038818359 48.664993286132813 A 0.125 0.125 0 0 1 47.533596038818359 48.539993286132813 L 47.533596038818359 47.039993286132812 L 47.533596038818359 45.539993286132813 M 46.074897766113281 44.039993286132813 A 0.5 0.5 0 0 0 45.574897766113281 44.539993286132812 L 45.574897766113281 54.539993286132812 A 0.5 0.5 0 0 0 46.074897766113281 55.039993286132812 L 63.324996948242188 55.039993286132812 L 63.324996948242188 51.415092468261719 L 63.574897766113281 51.415191650390625 L 63.574897766113281 47.664894104003906 L 63.324996948242188 47.664894104003906 L 63.324996948242188 44.039993286132813 L 46.074897766113281 44.039993286132813 +M 46.200004577636719 57.789993286132813 A 0.375 0.375 0 1 0 46.950004577636719 57.789993286132813 L 46.950004577636719 55.914993286132812 L 46.200004577636719 55.914993286132812 L 46.200004577636719 57.789993286132813 +M 47.825000762939453 57.789993286132813 A 0.375 0.375 0 1 0 48.575000762939453 57.789993286132813 L 48.575000762939453 55.914993286132812 L 47.825000762939453 55.914993286132812 L 47.825000762939453 57.789993286132813 +M 49.449996948242188 57.789993286132813 A 0.375 0.375 0 1 0 50.199996948242187 57.789993286132813 L 50.199996948242187 55.914993286132812 L 49.449996948242188 55.914993286132812 L 49.449996948242188 57.789993286132813 +M 51.074993133544922 57.789993286132813 A 0.375 0.375 0 1 0 51.824993133544922 57.789993286132813 L 51.824993133544922 55.914993286132812 L 51.074993133544922 55.914993286132812 L 51.074993133544922 57.789993286132813 +M 54.949996948242188 55.914993286132812 L 52.699996948242188 55.914993286132812 L 52.699996948242188 58.539993286132812 L 53.262496948242188 58.539993286132812 L 53.262496948242188 57.227493286132813 A 0.5625 0.5625 0 0 1 54.387496948242187 57.227493286132813 L 54.387496948242187 58.539993286132812 L 54.949996948242188 58.539993286132812 L 54.949996948242188 55.914993286132812 +M 62.043998718261719 56.789993286132812 L 62.043998718261719 56.789993286132812 M 62.324996948242188 56.508995056152344 A 0.28099822998046875 0.28099822998046875 0 1 1 62.324996948242188 57.070991516113281 A 0.28099822998046875 0.28099822998046875 0 1 1 62.324996948242188 56.508995056152344 M 56.543994903564453 56.789993286132812 L 56.543994903564453 56.789993286132812 M 56.824996948242187 56.508991241455078 A 0.28100204467773438 0.28100204467773438 0 1 1 56.824996948242187 57.070995330810547 A 0.28100204467773438 0.28100204467773438 0 1 1 56.824996948242187 56.508991241455078 M 55.824996948242188 55.914993286132812 L 55.824996948242188 56.789993286132812 A 0.625 0.625 0 0 0 56.449996948242187 57.414993286132813 L 62.699996948242187 57.414993286132813 A 0.625 0.625 0 0 0 63.324996948242188 56.789993286132812 L 63.324996948242188 55.914993286132812 L 55.824996948242188 55.914993286132812 +M 59.825000762939453 59.039989471435547 A 0.375 0.375 0 1 0 59.825000762939453 58.289989471435547 L 57.950000762939453 58.289989471435547 L 57.950000762939453 59.039989471435547 L 59.825000762939453 59.039989471435547 +M 62.950000762939453 59.039993286132812 A 0.375 0.375 0 1 0 62.950000762939453 58.289993286132813 L 61.075000762939453 58.289993286132813 L 61.075000762939453 59.039993286132812 L 62.950000762939453 59.039993286132812 +M 65.324897766113281 46.961708068847656 L 65.324897766113281 46.961708068847656 A 0.25 0.25 0 0 1 65.824897766113281 46.961708068847656 L 65.824897766113281 47.461708068847656 A 0.25 0.25 0 1 1 65.324897766113281 47.461708068847656 L 65.324897766113281 46.961708068847656 M 64.449897766113281 48.211708068847656 L 67.199897766113281 48.211708068847656 L 67.199897766113281 42.711708068847656 L 65.199897766113281 42.711708068847656 L 64.49029541015625 44.3673095703125 A 0.5 0.5 0 0 0 64.449897766113281 44.564308166503906 L 64.449897766113281 48.211708068847656 +M 66.574897766113281 51.104587554931641 L 66.574897766113281 51.104587554931641 A 0.25 0.25 0 0 1 67.074897766113281 51.104587554931641 L 67.074897766113281 51.604587554931641 A 0.25 0.25 0 1 1 66.574897766113281 51.604587554931641 L 66.574897766113281 51.104587554931641 M 64.824897766113281 52.104587554931641 L 64.824897766113281 52.104587554931641 A 0.25 0.25 0 0 1 65.324897766113281 52.104587554931641 L 65.324897766113281 52.604587554931641 A 0.25 0.25 0 1 1 64.824897766113281 52.604587554931641 L 64.824897766113281 52.104587554931641 M 67.201835632324219 52.311779022216797 A 0.5 0.5 0 0 0 67.449897766113281 51.879890441894531 L 67.449897766113281 49.229587554931641 A 2.5 2.5 0 0 1 64.449897766113281 49.229587554931641 L 64.449897766113281 53.046588897705078 A 0.50000043424351381 0.50000043424351381 0 0 0 65.201835632324219 53.478477478027344 L 67.201797485351563 52.311790466308594 +M 90.684089660644531 42.227500915527344 L 90.684089660644531 42.227500915527344 M 90.996589660644531 41.915000915527344 A 0.3125 0.3125 0 1 1 90.996589660644531 42.540000915527344 A 0.3125 0.3125 0 1 1 90.996589660644531 41.915000915527344 M 90.684089660644531 52.790000915527344 L 90.684089660644531 52.790000915527344 M 90.996589660644531 52.477500915527344 A 0.3125 0.3125 0 1 1 90.996589660644531 53.102500915527344 A 0.3125 0.3125 0 1 1 90.996589660644531 52.477500915527344 M 72.684089660644531 42.227497100830078 L 72.684089660644531 42.227497100830078 M 72.996589660644531 41.914997100830078 A 0.3125 0.3125 0 1 1 72.996589660644531 42.539997100830078 A 0.3125 0.3125 0 1 1 72.996589660644531 41.914997100830078 M 72.684089660644531 52.789997100830078 L 72.684089660644531 52.789997100830078 M 72.996589660644531 52.477497100830078 A 0.3125 0.3125 0 1 1 72.996589660644531 53.102497100830078 A 0.3125 0.3125 0 1 1 72.996589660644531 52.477497100830078 M 94.907966613769531 41.639106750488281 A 0.12500000093132257 0.12500000093132257 0 0 0 94.819572448730469 41.602500915527344 L 69.173583984375 41.602497100830078 A 0.12499743743966908 0.12499743743966908 0 0 0 69.085197448730469 41.639110565185547 L 68.533485412597656 42.190898895263672 A 0.125 0.125 0 0 0 68.496788024902344 42.279296875 L 68.496788024902344 52.738197326660156 A 0.12500013486707759 0.12500013486707759 0 0 0 68.533401489257813 52.826587677001953 L 69.085189819335938 53.378398895263672 A 0.125 0.125 0 0 0 69.173583984375 53.414997100830078 L 79.996589660644531 53.415000915527344 A 0.125 0.125 0 0 0 80.121589660644531 53.290000915527344 L 80.121589660644531 52.040000915527344 A 0.5 0.5 0 0 1 80.621589660644531 51.540000915527344 L 83.371589660644531 51.540000915527344 A 0.5 0.5 0 0 1 83.871589660644531 52.040000915527344 L 83.871589660644531 53.290000915527344 A 0.125 0.125 0 0 0 83.996589660644531 53.415000915527344 L 94.819587707519531 53.415000915527344 A 0.12499743790533992 0.12499743790533992 0 0 0 94.907966613769531 53.378395080566406 L 95.459686279296875 52.826602935791016 A 0.125 0.125 0 0 0 95.496383666992188 52.738201141357422 L 95.496391296386719 42.279300689697266 A 0.12499743743966908 0.12499743743966908 0 0 0 95.45977783203125 42.190914154052734 L 94.907989501953125 41.63909912109375 +M 98.24639892578125 42.852493286132813 L 98.24639892578125 42.852493286132813 A 0.25 0.25 0 1 1 97.74639892578125 42.852493286132813 L 97.74639892578125 42.352493286132812 A 0.25 0.25 0 0 1 98.24639892578125 42.352493286132812 L 98.24639892578125 42.852493286132813 M 99.12139892578125 41.602493286132813 L 96.37139892578125 41.602493286132813 L 96.37139892578125 47.102493286132813 L 98.37139892578125 47.102493286132813 L 99.081001281738281 45.446891784667969 A 0.5 0.5 0 0 0 99.12139892578125 45.249893188476562 L 99.12139892578125 41.602493286132813 +M 97.55889892578125 51.422992706298828 L 97.55889892578125 51.422992706298828 M 97.55889892578125 51.156993865966797 A 0.13299942016601563 0.13299942016601563 0 1 1 97.55889892578125 51.422992706298828 A 0.13299942016601563 0.13299942016601563 0 1 1 97.55889892578125 51.156993865966797 M 96.62139892578125 47.977493286132813 A 0.25 0.25 0 0 0 96.37139892578125 48.227493286132813 L 96.37139892578125 51.289993286132813 A 0.25 0.25 0 0 0 96.62139892578125 51.539993286132813 L 97.163597106933594 51.539993286132813 A 0.12499817319742106 0.12499817319742106 0 0 1 97.203125 51.546409606933594 L 97.539695739746094 51.658592224121094 A 0.125 0.125 0 0 0 97.579200744628906 51.664993286132813 L 97.80889892578125 51.664993286132813 A 0.125 0.125 0 0 0 97.93389892578125 51.539993286132813 L 97.93389892578125 50.175594329833984 A 0.12499698253664557 0.12499698253664557 0 0 0 97.932098388671875 50.154472351074219 L 97.576698303222656 48.081394195556641 A 0.125 0.125 0 0 0 97.453498840332031 47.977493286132813 L 96.62139892578125 47.977493286132813 +M 102.78169250488281 58.263393402099609 L 102.78169250488281 58.263393402099609 M 102.59419250488281 58.075893402099609 A 0.1875 0.1875 0 1 1 102.59419250488281 58.450893402099609 A 0.1875 0.1875 0 1 1 102.59419250488281 58.075893402099609 M 102.78169250488281 55.013393402099609 L 102.78169250488281 55.013393402099609 M 102.59419250488281 54.825893402099609 A 0.1875 0.1875 0 1 1 102.59419250488281 55.200893402099609 A 0.1875 0.1875 0 1 1 102.59419250488281 54.825893402099609 M 100.32618713378906 53.825893402099609 L 100.32618713378906 53.825893402099609 M 100.04518890380859 53.544895172119141 A 0.28099822998046875 0.28099822998046875 0 1 1 100.04518890380859 54.106891632080078 A 0.28099822998046875 0.28099822998046875 0 1 1 100.04518890380859 53.544895172119141 M 100.32618713378906 56.950992584228516 L 100.32618713378906 56.950992584228516 M 100.04518890380859 56.669994354248047 A 0.28099822998046875 0.28099822998046875 0 1 1 100.04518890380859 57.231990814208984 A 0.28099822998046875 0.28099822998046875 0 1 1 100.04518890380859 56.669994354248047 M 97.326187133789063 56.950992584228516 L 97.326187133789063 56.950992584228516 M 97.045188903808594 56.669994354248047 A 0.28099822998046875 0.28099822998046875 0 1 1 97.045188903808594 57.231990814208984 A 0.28099822998046875 0.28099822998046875 0 1 1 97.045188903808594 56.669994354248047 M 97.326187133789063 53.825893402099609 L 97.326187133789063 53.825893402099609 M 97.045188903808594 53.544895172119141 A 0.28099822998046875 0.28099822998046875 0 1 1 97.045188903808594 54.106891632080078 A 0.28099822998046875 0.28099822998046875 0 1 1 97.045188903808594 53.544895172119141 M 94.683692932128906 55.013393402099609 L 94.683692932128906 55.013393402099609 M 94.496192932128906 54.825893402099609 A 0.1875 0.1875 0 1 1 94.496192932128906 55.200893402099609 A 0.1875 0.1875 0 1 1 94.496192932128906 54.825893402099609 M 94.683692932128906 58.263393402099609 L 94.683692932128906 58.263393402099609 M 94.496192932128906 58.075893402099609 A 0.1875 0.1875 0 1 1 94.496192932128906 58.450893402099609 A 0.1875 0.1875 0 1 1 94.496192932128906 58.075893402099609 M 93.806190490722656 54.450893402099609 L 93.806190490722656 58.825893402099609 L 95.027091979980469 58.825893402099609 A 0.12500128387978338 0.12500128387978338 0 0 0 95.112220764160156 58.792427062988281 L 96.384193420410156 57.609394073486328 A 0.125 0.125 0 0 1 96.469291687011719 57.575992584228516 L 100.62109375 57.575992584228516 A 0.12499608820935521 0.12499608820935521 0 0 1 100.70621490478516 57.609458923339844 L 101.97818756103516 58.792392730712891 A 0.125 0.125 0 0 0 102.06329345703125 58.825893402099609 L 103.28418731689453 58.825893402099609 L 103.28418731689453 54.450893402099609 L 102.06329345703125 54.450893402099609 A 0.12500128387978338 0.12500128387978338 0 0 1 101.97816467285156 54.417427062988281 L 100.70619201660156 53.234394073486328 A 0.125 0.125 0 0 0 100.62109375 53.200893402099609 L 96.469291687011719 53.200893402099609 A 0.12500128387978338 0.12500128387978338 0 0 0 96.384162902832031 53.234359741210938 L 95.112190246582031 54.417392730712891 A 0.125 0.125 0 0 1 95.027091979980469 54.450893402099609 L 93.806190490722656 54.450893402099609 +M 112.06136322021484 52.946250915527344 L 112.06136322021484 52.946250915527344 A 0.28125 0.28125 0 0 1 112.06136322021484 52.383750915527344 L 112.49886322021484 52.383750915527344 A 0.28125 0.28125 0 1 1 112.49886322021484 52.946250915527344 L 112.06136322021484 52.946250915527344 M 103.31136322021484 52.946250915527344 L 103.31136322021484 52.946250915527344 A 0.28125 0.28125 0 0 1 103.31136322021484 52.383750915527344 L 103.74886322021484 52.383750915527344 A 0.28125 0.28125 0 1 1 103.74886322021484 52.946250915527344 L 103.31136322021484 52.946250915527344 M 103.31136322021484 1.9462500810623169 L 103.31136322021484 1.9462500810623169 A 0.28125 0.28125 0 0 1 103.31136322021484 1.3837500810623169 L 103.74886322021484 1.3837500810623169 A 0.28125 0.28125 0 1 1 103.74886322021484 1.9462500810623169 L 103.31136322021484 1.9462500810623169 M 112.06136322021484 1.9462504386901855 L 112.06136322021484 1.9462504386901855 A 0.28125 0.28125 0 0 1 112.06136322021484 1.3837504386901855 L 112.49886322021484 1.3837504386901855 A 0.28125 0.28125 0 1 1 112.49886322021484 1.9462504386901855 L 112.06136322021484 1.9462504386901855 M 100.41511535644531 21.290000915527344 A 0.125 0.125 0 0 0 100.54011535644531 21.415000915527344 L 100.66511535644531 21.415000915527344 A 0.5 0.5 0 0 1 101.16511535644531 21.915000915527344 A 0.5 0.5 0 0 1 100.66511535644531 22.415000915527344 L 100.54011535644531 22.415000915527344 A 0.125 0.125 0 0 0 100.41511535644531 22.540000915527344 L 100.41511535644531 33.290000915527344 A 0.125 0.125 0 0 0 100.54011535644531 33.415000915527344 L 100.66511535644531 33.415000915527344 A 0.5 0.5 0 0 1 101.16511535644531 33.915000915527344 A 0.5 0.5 0 0 1 100.66511535644531 34.415000915527344 L 100.54011535644531 34.415000915527344 A 0.125 0.125 0 0 0 100.41511535644531 34.540000915527344 L 100.41511535644531 45.290000915527344 A 0.125 0.125 0 0 0 100.54011535644531 45.415000915527344 L 100.66511535644531 45.415000915527344 A 0.5 0.5 0 0 1 101.16511535644531 45.915000915527344 A 0.5 0.5 0 0 1 100.66511535644531 46.415000915527344 L 100.54011535644531 46.415000915527344 A 0.125 0.125 0 0 0 100.41511535644531 46.540000915527344 L 100.41511535644531 50.415000915527344 A 0.75 0.75 0 0 0 101.16511535644531 51.165000915527344 L 101.66511535644531 51.165000915527344 A 0.25 0.25 0 0 1 101.91511535644531 51.415000915527344 L 101.91511535644531 52.665000915527344 A 0.75 0.75 0 0 0 102.66511535644531 53.415000915527344 L 113.14511108398437 53.415000915527344 A 0.75 0.75 0 0 0 113.89511108398437 52.665000915527344 L 113.89511108398437 51.415000915527344 A 0.25 0.25 0 0 1 114.14511108398437 51.165000915527344 L 114.64511108398437 51.165000915527344 A 0.75 0.75 0 0 0 115.39511108398437 50.415000915527344 L 115.39511108398437 46.540000915527344 A 0.125 0.125 0 0 0 115.27011108398437 46.415000915527344 L 115.14511108398437 46.415000915527344 A 0.5 0.5 0 0 1 114.64511108398437 45.915000915527344 A 0.5 0.5 0 0 1 115.14511108398437 45.415000915527344 L 115.27011108398437 45.415000915527344 A 0.125 0.125 0 0 0 115.39511108398437 45.290000915527344 L 115.39511108398437 34.540000915527344 A 0.125 0.125 0 0 0 115.27011108398437 34.415000915527344 L 115.14511108398437 34.415000915527344 A 0.5 0.5 0 0 1 114.64511108398437 33.915000915527344 A 0.5 0.5 0 0 1 115.14511108398437 33.415000915527344 L 115.27011108398437 33.415000915527344 A 0.125 0.125 0 0 0 115.39511108398437 33.290000915527344 L 115.39511108398437 22.540000915527344 A 0.125 0.125 0 0 0 115.27011108398437 22.415000915527344 L 115.14511108398437 22.415000915527344 A 0.5 0.5 0 0 1 114.64511108398437 21.915000915527344 A 0.5 0.5 0 0 1 115.14511108398437 21.415000915527344 L 115.27011108398437 21.415000915527344 A 0.125 0.125 0 0 0 115.39511108398437 21.290000915527344 L 115.39511108398437 3.9150006771087646 A 0.75000000003880507 0.75000000003880507 0 0 0 114.64511871337891 3.1650006771087646 L 114.14511871337891 3.1650006771087646 A 0.25000000000011369 0.25000000000011369 0 0 1 113.89511871337891 2.9150004386901855 L 113.89511871337891 1.6650005578994751 A 0.75000005960464478 0.75000005960464478 0 0 0 113.14511871337891 0.91500049829483032 L 102.66511535644531 0.91500008106231689 A 0.75 0.75 0 0 0 101.91511535644531 1.6650000810623169 L 101.91511535644531 2.9149999618530273 A 0.25 0.25 0 0 1 101.66511535644531 3.1649999618530273 L 101.16511535644531 3.1649999618530273 A 0.75 0.75 0 0 0 100.41511535644531 3.9149999618530273 L 100.41511535644531 21.290000915527344 +M 106.03419494628906 56.430500030517578 L 106.03419494628906 56.430500030517578 M 106.03419494628906 55.899501800537109 A 0.26549911499023438 0.26549911499023438 0 1 1 106.03419494628906 56.430500030517578 A 0.26549911499023438 0.26549911499023438 0 1 1 106.03419494628906 55.899501800537109 M 104.40919494628906 54.290000915527344 A 0.25 0.25 0 0 0 104.15919494628906 54.540000915527344 L 104.15919494628906 57.790000915527344 A 0.25 0.25 0 0 0 104.40919494628906 58.040000915527344 L 107.65919494628906 58.040000915527344 A 0.25 0.25 0 0 0 107.90919494628906 57.790000915527344 L 107.90919494628906 56.290000915527344 L 107.78419494628906 56.290000915527344 A 0.125 0.125 0 0 1 107.78419494628906 56.040000915527344 L 107.90919494628906 56.040000915527344 L 107.90919494628906 54.540000915527344 A 0.25 0.25 0 0 0 107.65919494628906 54.290000915527344 L 104.40919494628906 54.290000915527344 +M 109.97169494628906 57.735500335693359 L 109.97169494628906 57.735500335693359 M 109.97169494628906 57.469501495361328 A 0.13299942016601563 0.13299942016601563 0 1 1 109.97169494628906 57.735500335693359 A 0.13299942016601563 0.13299942016601563 0 1 1 109.97169494628906 57.469501495361328 M 109.03419494628906 54.290000915527344 A 0.25 0.25 0 0 0 108.78419494628906 54.540000915527344 L 108.78419494628906 57.602500915527344 A 0.25 0.25 0 0 0 109.03419494628906 57.852500915527344 L 109.57639312744141 57.852500915527344 A 0.12499817319742106 0.12499817319742106 0 0 1 109.61592102050781 57.858917236328125 L 109.95249176025391 57.971099853515625 A 0.125 0.125 0 0 0 109.99199676513672 57.977500915527344 L 110.22169494628906 57.977500915527344 A 0.125 0.125 0 0 0 110.34669494628906 57.852500915527344 L 110.34669494628906 56.488101959228516 A 0.12499698253664557 0.12499698253664557 0 0 0 110.34489440917969 56.46697998046875 L 109.98949432373047 54.393901824951172 A 0.125 0.125 0 0 0 109.86629486083984 54.290000915527344 L 109.03419494628906 54.290000915527344 +M 111.49161529541016 54.532001495361328 L 111.49161529541016 54.532001495361328 M 111.49161529541016 54.532001495361328 A 0.13299942016601563 0.13299942016601563 0 1 1 111.49161529541016 54.798000335693359 A 0.13299942016601563 0.13299942016601563 0 1 1 111.49161529541016 54.532001495361328 M 112.42911529541016 57.977500915527344 A 0.25 0.25 0 0 0 112.67911529541016 57.727500915527344 L 112.67911529541016 54.665000915527344 A 0.25 0.25 0 0 0 112.42911529541016 54.415000915527344 L 111.88691711425781 54.415000915527344 A 0.12499817319742106 0.12499817319742106 0 0 1 111.84738922119141 54.408584594726563 L 111.51081848144531 54.296401977539062 A 0.125 0.125 0 0 0 111.4713134765625 54.290000915527344 L 111.24161529541016 54.290000915527344 A 0.125 0.125 0 0 0 111.11661529541016 54.415000915527344 L 111.11661529541016 55.779399871826172 A 0.12499698253664557 0.12499698253664557 0 0 0 111.11841583251953 55.800521850585938 L 111.47381591796875 57.873600006103516 A 0.125 0.125 0 0 0 111.59701538085937 57.977500915527344 L 112.42911529541016 57.977500915527344 +M 114.74161529541016 57.735500335693359 L 114.74161529541016 57.735500335693359 M 114.74161529541016 57.469501495361328 A 0.13299942016601563 0.13299942016601563 0 1 1 114.74161529541016 57.735500335693359 A 0.13299942016601563 0.13299942016601563 0 1 1 114.74161529541016 57.469501495361328 M 113.80411529541016 54.290000915527344 A 0.25 0.25 0 0 0 113.55411529541016 54.540000915527344 L 113.55411529541016 57.602500915527344 A 0.25 0.25 0 0 0 113.80411529541016 57.852500915527344 L 114.3463134765625 57.852500915527344 A 0.12499817319742106 0.12499817319742106 0 0 1 114.38584136962891 57.858917236328125 L 114.722412109375 57.971099853515625 A 0.125 0.125 0 0 0 114.76191711425781 57.977500915527344 L 114.99161529541016 57.977500915527344 A 0.125 0.125 0 0 0 115.11661529541016 57.852500915527344 L 115.11661529541016 56.488101959228516 A 0.12499698253664557 0.12499698253664557 0 0 0 115.11481475830078 56.46697998046875 L 114.75941467285156 54.393901824951172 A 0.125 0.125 0 0 0 114.63621520996094 54.290000915527344 L 113.80411529541016 54.290000915527344 +M 118.02011108398437 53.665000915527344 L 118.02011108398437 53.665000915527344 M 118.02011108398437 53.665000915527344 A 0.25 0.25 0 1 1 118.02011108398437 54.165000915527344 A 0.25 0.25 0 1 1 118.02011108398437 53.665000915527344 M 118.02011108398437 43.665000915527344 L 118.02011108398437 43.665000915527344 M 118.02011108398437 43.665000915527344 A 0.25 0.25 0 1 1 118.02011108398437 44.165000915527344 A 0.25 0.25 0 1 1 118.02011108398437 43.665000915527344 M 118.02011108398437 33.665000915527344 L 118.02011108398437 33.665000915527344 M 118.02011108398437 33.665000915527344 A 0.25 0.25 0 1 1 118.02011108398437 34.165000915527344 A 0.25 0.25 0 1 1 118.02011108398437 33.665000915527344 M 118.02011108398437 13.665000915527344 L 118.02011108398437 13.665000915527344 M 118.02011108398437 13.665000915527344 A 0.25 0.25 0 1 1 118.02011108398437 14.165000915527344 A 0.25 0.25 0 1 1 118.02011108398437 13.665000915527344 M 118.02011108398437 3.6650009155273437 L 118.02011108398437 3.6650009155273437 M 118.02011108398437 3.6650009155273437 A 0.25 0.25 0 1 1 118.02011108398437 4.1650009155273437 A 0.25 0.25 0 1 1 118.02011108398437 3.6650009155273437 M 118.02011108398437 23.665000915527344 L 118.02011108398437 23.665000915527344 M 118.02011108398437 23.665000915527344 A 0.25 0.25 0 1 1 118.02011108398437 24.165000915527344 A 0.25 0.25 0 1 1 118.02011108398437 23.665000915527344 M 116.27011108398437 56.915000915527344 L 120.02011108398437 56.915000915527344 L 120.02011108398437 0.91500091552734375 L 116.27011108398437 0.91500085592269897 L 116.27011108398437 56.915000915527344 +M 117.86661529541016 58.539997100830078 A 0.375 0.375 0 1 0 117.86661529541016 57.789997100830078 L 115.99161529541016 57.789997100830078 L 115.99161529541016 58.539997100830078 L 117.86661529541016 58.539997100830078 +tkpath::transform scale 6.4000000000000004 -6.4000000000000004 +.c move all 2 -62 + +# ------------------------------ + diff --git a/pd/tkpath/demos/prect.tcl b/pd/tkpath/demos/prect.tcl new file mode 100644 index 0000000000000000000000000000000000000000..48810fb71d3d571b37e0b0f8122d175cec5acfdc --- /dev/null +++ b/pd/tkpath/demos/prect.tcl @@ -0,0 +1,24 @@ +package require tkpath 0.3.0 + +set t .c_prect +destroy $t +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + +$w create prect 20 20 180 80 -rx 6 -stroke "#c8c8c8" -fill "#e6e6e6" +$w create prect 200 20 260 80 -rx 6 -stroke "#a19de2" -fill "#d6d6ff" + +$w create prect 20 100 180 180 -rx 6 -stroke "#9ac790" -fill "#cae2c5" +$w create prect 200 100 260 180 -rx 6 -stroke "#e2a19d" -fill "#ffd6d6" + +$w create prect 20 200 260 380 -stroke "#999999" -tags hit +$w create prect 40 220 100 360 -rx 16 -stroke "#666666" -strokewidth 3 -fill "#bdbdbd" + +$w create prect 150 240 170 260 -stroke "" -fill red +$w create prect 150 270 170 290 -stroke "" -fill green +$w create prect 150 300 170 320 -stroke "" -fill blue + +$w create prect 280 200 360 380 -rx 20 -strokewidth 1 -strokedasharray {8 4 12} + +bind $w <Button-1> {puts "distance to gray prect=[%W distance hit %x %y]"} diff --git a/pd/tkpath/demos/randlines.tcl b/pd/tkpath/demos/randlines.tcl new file mode 100644 index 0000000000000000000000000000000000000000..1bd8e272274bdfdebb21d1eb4a8ca9cff53326a7 --- /dev/null +++ b/pd/tkpath/demos/randlines.tcl @@ -0,0 +1,22 @@ +package require tkpath 0.3.0 + +set t .c_randlines +toplevel $t +set w $t.c +set size 400 +pack [tkp::canvas $w -width $size -height $size -bg white] + +set x0 10 +set y0 10 +for {set i 0} {$i < 100} {incr i} { + set x [expr {($size - 20)*rand() + 10}] + set y [expr {($size - 20)*rand() + 10}] + set red [expr {int(255*rand())}] + set green [expr {int(255*rand())}] + set blue [expr {int(255*rand())}] + set color [format "#%02x%02x%02x" $red $green $blue] + $w create pline $x0 $y0 $x $y -stroke $color -strokewidth 2 + set x0 $x + set y0 $y +} + diff --git a/pd/tkpath/demos/sheetmetal.tcl b/pd/tkpath/demos/sheetmetal.tcl new file mode 100644 index 0000000000000000000000000000000000000000..9918f5a6c6a882642bfb9c226037a8ba1d432a8c --- /dev/null +++ b/pd/tkpath/demos/sheetmetal.tcl @@ -0,0 +1,89 @@ +package require tkpath 0.3 + +# Data from Jeff Godfrey Magestic Systems, Inc. + +set i 0 +set pathA([incr i]) {M 32.01 11.38 L 32.01 11.38 A 0.2188 0.2188 0 0 1 32.01 10.94 L 32.32 10.94 A 0.2188 0.2188 0 1 1 32.32 11.38 L 32.01 11.38 M 30.51 11.38 L 30.51 11.38 A 0.2188 0.2188 0 0 1 30.51 10.94 L 30.82 10.94 A 0.2188 0.2188 0 1 1 30.82 11.38 L 30.51 11.38 M 32.01 37.38 L 32.01 37.38 A 0.2188 0.2188 0 0 1 32.01 36.94 L 32.32 36.94 A 0.2188 0.2188 0 1 1 32.32 37.38 L 32.01 37.38 M 30.51 37.38 L 30.51 37.38 A 0.2188 0.2188 0 0 1 30.51 36.94 L 30.82 36.94 A 0.2188 0.2188 0 1 1 30.82 37.38 L 30.51 37.38 M 11.35 22.37 L 11.35 22.37 A 0.125 0.125 0 0 1 11.35 22.12 L 11.6 22.12 A 0.125 0.125 0 1 1 11.6 22.37 L 11.35 22.37 M 7.353 22.37 L 7.353 22.37 A 0.125 0.125 0 0 1 7.353 22.12 L 7.603 22.12 A 0.125 0.125 0 1 1 7.603 22.37 L 7.353 22.37 M 7.353 26.27 L 7.353 26.27 A 0.125 0.125 0 0 1 7.353 26.02 L 7.603 26.02 A 0.125 0.125 0 1 1 7.603 26.27 L 7.353 26.27 M 11.35 26.27 L 11.35 26.27 A 0.125 0.125 0 0 1 11.35 26.02 L 11.6 26.02 A 0.125 0.125 0 1 1 11.6 26.27 L 11.35 26.27 M 7.104 25.63 L 7.104 24.19 L 7.104 22.75 A 0.25 0.25 0 0 1 7.354 22.5 L 11.48 22.5 A 0.25 0.25 0 0 1 11.73 22.75 L 11.73 25.63 A 0.25 0.25 0 0 1 11.48 25.88 L 7.354 25.88 A 0.25 0.25 0 0 1 7.104 25.63 M 34.25 44.16 L 34.25 4.16 L 5.166 4.16 A 1 1 0 0 0 4.166 5.16 L 4.166 43.16 A 1 1 0 0 0 5.166 44.16 L 34.25 44.16 z} +set pathA([incr i]) {M 5.547 46.07 L 5.547 46.07 A 0.2188 0.2188 0 1 1 5.547 46.5 L 5.234 46.5 A 0.2188 0.2188 0 0 1 5.234 46.07 L 5.547 46.07 M 23.42 46.07 L 23.42 46.07 A 0.2188 0.2188 0 1 1 23.42 46.5 L 23.11 46.5 A 0.2188 0.2188 0 0 1 23.11 46.07 L 23.42 46.07 M 24.52 45.03 L 4.14 45.03 L 4.14 47.53 L 24.52 47.53 L 24.52 45.03 z} +set pathA([incr i]) {M 25.7 46.72 L 25.7 46.72 A 0.1875 0.1875 0 0 1 26.08 46.72 L 26.08 47.35 A 0.1875 0.1875 0 1 1 25.7 47.35 L 25.7 46.72 M 25.7 45.47 L 25.7 45.47 A 0.1875 0.1875 0 0 1 26.08 45.47 L 26.08 46.1 A 0.1875 0.1875 0 1 1 25.7 46.1 L 25.7 45.47 M 29.36 46.41 L 29.36 46.41 M 29.95 45.82 A 0.594 0.594 0 1 1 29.95 47 A 0.594 0.594 0 1 1 29.95 45.82 M 25.64 45.03 L 25.39 45.28 L 25.39 47.53 L 25.64 47.78 L 30.7 47.78 L 30.95 47.53 L 30.95 45.28 L 30.7 45.03 L 25.64 45.03 z} +set pathA([incr i]) {M 32.8 45.46 L 32.8 45.46 A 0.1565 0.1565 0 1 1 32.8 45.77 L 32.36 45.77 A 0.1565 0.1565 0 0 1 32.36 45.46 L 32.8 45.46 M 32.77 46.99 L 32.77 46.99 A 0.1875 0.1875 0 1 1 32.77 47.37 L 32.39 47.37 A 0.1875 0.1875 0 0 1 32.39 46.99 L 32.77 46.99 M 32.8 47.83 L 32.8 47.83 A 0.1565 0.1565 0 1 1 32.8 48.15 L 32.36 48.15 A 0.1565 0.1565 0 0 1 32.36 47.83 L 32.8 47.83 M 31.83 48.28 A 0.25 0.25 0 0 0 32.08 48.53 L 33.08 48.53 A 0.25 0.25 0 0 0 33.33 48.28 L 33.33 45.28 A 0.25 0.25 0 0 0 33.08 45.03 L 32.08 45.03 A 0.25 0.25 0 0 0 31.83 45.28 L 31.83 48.28 z} +set pathA([incr i]) {M 37.6 4.338 L 37.6 4.338 A 0.2188 0.2188 0 0 1 38.04 4.338 L 38.04 4.65 A 0.2188 0.2188 0 1 1 37.6 4.65 L 37.6 4.338 M 36.48 4.338 L 36.48 4.338 A 0.2188 0.2188 0 0 1 36.91 4.338 L 36.91 4.65 A 0.2188 0.2188 0 1 1 36.48 4.65 L 36.48 4.338 M 37.27 7.057 L 37.27 7.057 A 0.25 0.25 0 1 1 37.27 7.557 L 36.77 7.557 A 0.25 0.25 0 0 1 36.77 7.057 L 37.27 7.057 M 37.27 9.057 L 37.27 9.057 A 0.25 0.25 0 1 1 37.27 9.557 L 36.77 9.557 A 0.25 0.25 0 0 1 36.77 9.057 L 37.27 9.057 M 37.77 11.06 L 37.77 11.06 A 0.25 0.25 0 1 1 37.77 11.56 L 37.27 11.56 A 0.25 0.25 0 0 1 37.27 11.06 L 37.77 11.06 M 37.77 13.06 L 37.77 13.06 A 0.25 0.25 0 1 1 37.77 13.56 L 37.27 13.56 A 0.25 0.25 0 0 1 37.27 13.06 L 37.77 13.06 M 37.27 30.43 L 37.27 30.43 A 0.25 0.25 0 1 1 37.27 30.93 L 36.77 30.93 A 0.25 0.25 0 0 1 36.77 30.43 L 37.27 30.43 M 37.27 32.43 L 37.27 32.43 A 0.25 0.25 0 1 1 37.27 32.93 L 36.77 32.93 A 0.25 0.25 0 0 1 36.77 32.43 L 37.27 32.43 M 37.77 34.43 L 37.77 34.43 A 0.25 0.25 0 1 1 37.77 34.93 L 37.27 34.93 A 0.25 0.25 0 0 1 37.27 34.43 L 37.77 34.43 M 37.77 36.43 L 37.77 36.43 A 0.25 0.25 0 1 1 37.77 36.93 L 37.27 36.93 A 0.25 0.25 0 0 1 37.27 36.43 L 37.77 36.43 M 36.47 39.34 L 36.47 39.34 A 0.2188 0.2188 0 0 1 36.91 39.34 L 36.91 39.65 A 0.2188 0.2188 0 1 1 36.47 39.65 L 36.47 39.34 M 37.6 39.34 L 37.6 39.34 A 0.2188 0.2188 0 0 1 38.04 39.34 L 38.04 39.65 A 0.2188 0.2188 0 1 1 37.6 39.65 L 37.6 39.34 M 38.63 40.06 L 39.38 38.93 L 39.38 5.057 L 38.63 3.932 L 35.88 3.932 L 35.13 5.057 L 35.13 38.93 L 35.88 40.06 L 38.63 40.06 z} +set pathA([incr i]) {M 37.16 46.56 L 37.16 46.56 A 0.125 0.125 0 0 1 37.41 46.56 L 37.41 46.81 A 0.125 0.125 0 1 1 37.16 46.81 L 37.16 46.56 M 35.28 46.56 L 35.28 46.56 A 0.125 0.125 0 0 1 35.53 46.56 L 35.53 46.81 A 0.125 0.125 0 1 1 35.28 46.81 L 35.28 46.56 M 35.72 43.88 L 35.72 43.88 M 35.72 43.88 A 0.172 0.172 0 1 1 35.72 44.23 A 0.172 0.172 0 1 1 35.72 43.88 M 36.97 43.88 L 36.97 43.88 M 36.97 43.88 A 0.172 0.172 0 1 1 36.97 44.23 A 0.172 0.172 0 1 1 36.97 43.88 M 36.97 41.26 L 36.97 41.26 M 36.97 41.26 A 0.172 0.172 0 1 1 36.97 41.6 A 0.172 0.172 0 1 1 36.97 41.26 M 35.72 41.26 L 35.72 41.26 M 35.72 41.26 A 0.172 0.172 0 1 1 35.72 41.6 A 0.172 0.172 0 1 1 35.72 41.26 M 37.44 47.18 A 0.125 0.125 0 0 0 37.57 47.06 L 37.57 41.06 A 0.125 0.125 0 0 0 37.44 40.93 L 35.25 40.93 A 0.125 0.125 0 0 0 35.13 41.06 L 35.13 47.06 A 0.125 0.125 0 0 0 35.25 47.18 L 37.44 47.18 z} +set pathA([incr i]) {M 36.08 48.81 A 0.375 0.375 0 1 0 36.08 48.06 L 34.2 48.06 L 34.2 48.81 L 36.08 48.81 z} +set pathA([incr i]) {M 39.25 45.43 L 39.25 45.43 A 0.125 0.125 0 1 1 39.25 45.68 L 39 45.68 A 0.125 0.125 0 0 1 39 45.43 L 39.25 45.43 M 39.25 41.18 L 39.25 41.18 A 0.125 0.125 0 1 1 39.25 41.43 L 39 41.43 A 0.125 0.125 0 0 1 39 41.18 L 39.25 41.18 M 38.44 40.93 L 38.44 45.93 L 39.32 45.93 A 0.25 0.25 0 0 0 39.57 45.68 L 39.57 41.18 A 0.25 0.25 0 0 0 39.32 40.93 L 38.44 40.93 z} +set pathA([incr i]) {M 1.54 1.696 L 1.54 1.696 M 1.54 1.384 A 0.156 0.156 0 1 1 1.54 1.696 A 0.156 0.156 0 1 1 1.54 1.384 M 1.54 9.946 L 1.54 9.946 M 1.54 9.634 A 0.156 0.156 0 1 1 1.54 9.946 A 0.156 0.156 0 1 1 1.54 9.634 M 1.54 18.2 L 1.54 18.2 M 1.54 17.88 A 0.156 0.156 0 1 1 1.54 18.2 A 0.156 0.156 0 1 1 1.54 17.88 M 1.54 26.57 L 1.54 26.57 M 1.54 26.26 A 0.156 0.156 0 1 1 1.54 26.57 A 0.156 0.156 0 1 1 1.54 26.26 M 1.54 34.95 L 1.54 34.95 M 1.54 34.63 A 0.156 0.156 0 1 1 1.54 34.95 A 0.156 0.156 0 1 1 1.54 34.63 M 1.54 43.2 L 1.54 43.2 M 1.54 42.88 A 0.156 0.156 0 1 1 1.54 43.2 A 0.156 0.156 0 1 1 1.54 42.88 M 1.54 51.45 L 1.54 51.45 M 1.54 51.13 A 0.156 0.156 0 1 1 1.54 51.45 A 0.156 0.156 0 1 1 1.54 51.13 M 9.79 51.45 L 9.79 51.45 M 9.79 51.13 A 0.156 0.156 0 1 1 9.79 51.45 A 0.156 0.156 0 1 1 9.79 51.13 M 18.04 51.45 L 18.04 51.45 M 18.04 51.13 A 0.156 0.156 0 1 1 18.04 51.45 A 0.156 0.156 0 1 1 18.04 51.13 M 26.29 51.45 L 26.29 51.45 M 26.29 51.13 A 0.156 0.156 0 1 1 26.29 51.45 A 0.156 0.156 0 1 1 26.29 51.13 M 34.54 51.45 L 34.54 51.45 M 34.54 51.13 A 0.156 0.156 0 1 1 34.54 51.45 A 0.156 0.156 0 1 1 34.54 51.13 M 42.79 51.45 L 42.79 51.45 M 42.79 51.13 A 0.156 0.156 0 1 1 42.79 51.45 A 0.156 0.156 0 1 1 42.79 51.13 M 42.79 43.2 L 42.79 43.2 M 42.79 42.88 A 0.156 0.156 0 1 1 42.79 43.2 A 0.156 0.156 0 1 1 42.79 42.88 M 42.79 34.95 L 42.79 34.95 M 42.79 34.63 A 0.156 0.156 0 1 1 42.79 34.95 A 0.156 0.156 0 1 1 42.79 34.63 M 42.79 26.57 L 42.79 26.57 M 42.79 26.26 A 0.156 0.156 0 1 1 42.79 26.57 A 0.156 0.156 0 1 1 42.79 26.26 M 42.79 18.2 L 42.79 18.2 M 42.79 17.88 A 0.156 0.156 0 1 1 42.79 18.2 A 0.156 0.156 0 1 1 42.79 17.88 M 42.79 9.946 L 42.79 9.946 M 42.79 9.634 A 0.156 0.156 0 1 1 42.79 9.946 A 0.156 0.156 0 1 1 42.79 9.634 M 42.79 1.696 L 42.79 1.696 M 42.79 1.384 A 0.156 0.156 0 1 1 42.79 1.696 A 0.156 0.156 0 1 1 42.79 1.384 M 9.79 1.696 L 9.79 1.696 M 9.79 1.384 A 0.156 0.156 0 1 1 9.79 1.696 A 0.156 0.156 0 1 1 9.79 1.384 M 18.04 1.696 L 18.04 1.696 M 18.04 1.384 A 0.156 0.156 0 1 1 18.04 1.696 A 0.156 0.156 0 1 1 18.04 1.384 M 26.29 1.696 L 26.29 1.696 M 26.29 1.384 A 0.156 0.156 0 1 1 26.29 1.696 A 0.156 0.156 0 1 1 26.29 1.384 M 34.54 1.696 L 34.54 1.696 M 34.54 1.384 A 0.156 0.156 0 1 1 34.54 1.696 A 0.156 0.156 0 1 1 34.54 1.384 M 5.477 49.91 A 2.563 2.563 0 0 1 2.915 47.35 L 2.915 5.477 A 2.563 2.563 0 0 1 5.478 2.915 L 38.35 2.915 A 2.562 2.562 0 0 1 40.92 5.477 L 40.91 47.35 A 2.562 2.562 0 0 1 38.35 49.92 L 21.91 49.92 L 5.477 49.91 M 0.915 0.915 L 0.915 51.91 L 43.16 51.92 L 43.17 0.915 L 0.915 0.915 z} +set pathA([incr i]) {M 9.415 53.54 L 9.415 53.54 M 9.165 53.29 A 0.25 0.25 0 1 1 9.165 53.79 A 0.25 0.25 0 1 1 9.165 53.29 M 9.415 55.98 L 9.415 55.98 M 9.165 55.73 A 0.25 0.25 0 1 1 9.165 56.23 A 0.25 0.25 0 1 1 9.165 55.73 M 9.915 57.79 L 9.915 52.79 L 1.165 52.79 A 0.25 0.25 0 0 0 0.915 53.04 L 0.915 57.54 A 0.25 0.25 0 0 0 1.165 57.79 L 9.915 57.79 z} +set pathA([incr i]) {M 11.95 52.79 A 0.375 0.375 0 0 0 11.95 53.54 L 13.82 53.54 L 13.82 52.79 L 11.95 52.79 z} +set pathA([incr i]) {M 15.07 52.79 A 0.375 0.375 0 0 0 15.07 53.54 L 16.95 53.54 L 16.95 52.79 L 15.07 52.79 z} +set pathA([incr i]) {M 18.2 52.79 A 0.375 0.375 0 0 0 18.2 53.54 L 20.07 53.54 L 20.07 52.79 L 18.2 52.79 z} +set pathA([incr i]) {M 21.32 52.79 A 0.375 0.375 0 0 0 21.32 53.54 L 23.2 53.54 L 23.2 52.79 L 21.32 52.79 z} +set pathA([incr i]) {M 24.45 52.79 A 0.375 0.375 0 0 0 24.45 53.54 L 26.32 53.54 L 26.32 52.79 L 24.45 52.79 z} +set pathA([incr i]) {M 27.57 52.79 A 0.375 0.375 0 0 0 27.57 53.54 L 29.45 53.54 L 29.45 52.79 L 27.57 52.79 z} +set pathA([incr i]) {M 30.7 52.79 A 0.375 0.375 0 0 0 30.7 53.54 L 32.57 53.54 L 32.57 52.79 L 30.7 52.79 z} +set pathA([incr i]) {M 33.82 52.79 A 0.375 0.375 0 0 0 33.82 53.54 L 35.7 53.54 L 35.7 52.79 L 33.82 52.79 z} +set pathA([incr i]) {M 36.95 52.79 A 0.375 0.375 0 0 0 36.95 53.54 L 38.82 53.54 L 38.82 52.79 L 36.95 52.79 z} +set pathA([incr i]) {M 40.42 57.29 L 40.42 57.29 M 40.2 57.07 A 0.219 0.219 0 1 1 40.2 57.51 A 0.219 0.219 0 1 1 40.2 57.07 M 44.42 57.29 L 44.42 57.29 M 44.2 57.07 A 0.219 0.219 0 1 1 44.2 57.51 A 0.219 0.219 0 1 1 44.2 57.07 M 44.42 53.29 L 44.42 53.29 M 44.2 53.07 A 0.219 0.219 0 1 1 44.2 53.51 A 0.219 0.219 0 1 1 44.2 53.07 M 40.42 53.29 L 40.42 53.29 M 40.2 53.07 A 0.219 0.219 0 1 1 40.2 53.51 A 0.219 0.219 0 1 1 40.2 53.07 M 39.7 57.79 L 44.7 57.79 L 44.7 52.79 L 39.7 52.79 L 39.7 57.79 z} +set pathA([incr i]) {M 46.69 37.91 L 46.69 37.91 A 0.1875 0.1875 0 1 1 46.69 38.29 L 46.06 38.29 A 0.1875 0.1875 0 0 1 46.06 37.91 L 46.69 37.91 M 47.94 37.91 L 47.94 37.91 A 0.1875 0.1875 0 1 1 47.94 38.29 L 47.31 38.29 A 0.1875 0.1875 0 0 1 47.31 37.91 L 47.94 37.91 M 47 41.57 L 47 41.57 M 47 41.57 A 0.594 0.594 0 1 1 47 42.76 A 0.594 0.594 0 1 1 47 41.57 M 48.37 37.85 L 48.12 37.6 L 45.87 37.6 L 45.62 37.85 L 45.62 42.91 L 45.87 43.16 L 48.12 43.16 L 48.37 42.91 L 48.37 37.85 z} +set pathA([incr i]) {M 51.32 40.09 L 51.32 40.09 A 0.1565 0.1565 0 1 1 51.32 40.4 L 50.88 40.4 A 0.1565 0.1565 0 0 1 50.88 40.09 L 51.32 40.09 M 51.29 41.62 L 51.29 41.62 A 0.1875 0.1875 0 1 1 51.29 42 L 50.91 42 A 0.1875 0.1875 0 0 1 50.91 41.62 L 51.29 41.62 M 51.32 42.47 L 51.32 42.47 A 0.1565 0.1565 0 1 1 51.32 42.78 L 50.88 42.78 A 0.1565 0.1565 0 0 1 50.88 42.47 L 51.32 42.47 M 50.35 42.91 A 0.25 0.25 0 0 0 50.6 43.16 L 51.6 43.16 A 0.25 0.25 0 0 0 51.85 42.91 L 51.85 39.91 A 0.25 0.25 0 0 0 51.6 39.66 L 50.6 39.66 A 0.25 0.25 0 0 0 50.35 39.91 L 50.35 42.91 z} +set pathA([incr i]) {M 53.48 40.85 A 0.375 0.375 0 0 0 52.73 40.85 L 52.73 42.73 L 53.48 42.73 L 53.48 40.85 z} +set pathA([incr i]) {M 56.23 43.03 A 0.375 0.375 0 1 0 56.23 42.28 L 54.35 42.28 L 54.35 43.03 L 56.23 43.03 z} +set pathA([incr i]) {M 64.61 6.523 L 64.61 6.523 A 0.2188 0.2188 0 1 1 64.17 6.523 L 64.17 6.336 A 0.2188 0.2188 0 0 1 64.61 6.336 L 64.61 6.523 M 64.39 10.46 L 64.39 10.46 M 64.39 10.02 A 0.219 0.219 0 1 1 64.39 10.46 A 0.219 0.219 0 1 1 64.39 10.02 M 64.01 5.929 A 0.125 0.125 0 0 0 63.89 6.054 L 63.89 10.74 A 0.125 0.125 0 0 0 64.01 10.87 L 64.76 10.87 A 0.125 0.125 0 0 0 64.89 10.74 L 64.89 6.054 A 0.125 0.125 0 0 0 64.76 5.929 L 64.01 5.929 z} +set pathA([incr i]) {M 64.61 12.34 L 64.61 12.34 A 0.2188 0.2188 0 1 1 64.17 12.34 L 64.17 12.15 A 0.2188 0.2188 0 0 1 64.61 12.15 L 64.61 12.34 M 64.39 16.27 L 64.39 16.27 M 64.39 15.84 A 0.219 0.219 0 1 1 64.39 16.27 A 0.219 0.219 0 1 1 64.39 15.84 M 64.01 11.74 A 0.125 0.125 0 0 0 63.89 11.87 L 63.89 16.55 A 0.125 0.125 0 0 0 64.01 16.68 L 64.76 16.68 A 0.125 0.125 0 0 0 64.89 16.55 L 64.89 11.87 A 0.125 0.125 0 0 0 64.76 11.74 L 64.01 11.74 z} +set pathA([incr i]) {M 64.61 18.15 L 64.61 18.15 A 0.2188 0.2188 0 1 1 64.17 18.15 L 64.17 17.96 A 0.2188 0.2188 0 0 1 64.61 17.96 L 64.61 18.15 M 64.39 22.09 L 64.39 22.09 M 64.39 21.65 A 0.219 0.219 0 1 1 64.39 22.09 A 0.219 0.219 0 1 1 64.39 21.65 M 64.01 17.55 A 0.125 0.125 0 0 0 63.89 17.68 L 63.89 22.37 A 0.125 0.125 0 0 0 64.01 22.49 L 64.76 22.49 A 0.125 0.125 0 0 0 64.89 22.37 L 64.89 17.68 A 0.125 0.125 0 0 0 64.76 17.55 L 64.01 17.55 z} +set pathA([incr i]) {M 64.14 25.24 A 0.375 0.375 0 1 0 64.89 25.24 L 64.89 23.37 L 64.14 23.37 L 64.14 25.24 z} +set pathA([incr i]) {M 73.36 5.493 L 73.36 5.493 M 73.83 5.024 A 0.469 0.469 0 1 1 73.83 5.962 A 0.469 0.469 0 1 1 73.83 5.024 M 72.76 5.493 L 72.76 5.493 M 72.89 5.36 A 0.133 0.133 0 1 1 72.89 5.626 A 0.133 0.133 0 1 1 72.89 5.36 M 74.63 5.493 L 74.63 5.493 M 74.76 5.36 A 0.133 0.133 0 1 1 74.76 5.626 A 0.133 0.133 0 1 1 74.76 5.36 M 74.63 24.49 L 74.63 24.49 M 74.76 24.36 A 0.133 0.133 0 1 1 74.76 24.63 A 0.133 0.133 0 1 1 74.76 24.36 M 73.36 24.49 L 73.36 24.49 M 73.83 24.02 A 0.469 0.469 0 1 1 73.83 24.96 A 0.469 0.469 0 1 1 73.83 24.02 M 72.76 24.49 L 72.76 24.49 M 72.89 24.36 A 0.133 0.133 0 1 1 72.89 24.63 A 0.133 0.133 0 1 1 72.89 24.36 M 67.14 15.24 L 67.14 15.24 A 0.25 0.25 0 0 1 67.14 14.74 L 67.64 14.74 A 0.25 0.25 0 1 1 67.64 15.24 L 67.14 15.24 M 86.39 25.87 L 86.39 4.118 L 66.51 4.118 A 0.75 0.75 0 0 0 65.76 4.868 L 65.76 25.12 A 0.75 0.75 0 0 0 66.51 25.87 L 86.39 25.87 z} +set pathA([incr i]) {M 64.27 27.48 L 64.27 27.48 M 64.27 27.48 A 0.1875 0.1875 0 1 1 64.27 27.85 A 0.1875 0.1875 0 1 1 64.27 27.48 M 64.27 34.35 L 64.27 34.35 M 64.27 34.35 A 0.1875 0.1875 0 1 1 64.27 34.73 A 0.1875 0.1875 0 1 1 64.27 34.35 M 63.77 34.79 L 64.52 35.54 L 65.78 35.54 A 0.1875 0.1875 0 0 0 65.87 35.51 L 71.69 32.15 A 0.1875 0.1875 0 0 0 71.78 31.99 L 71.78 30.21 A 0.1875 0.1875 0 0 0 71.69 30.05 L 65.87 26.69 A 0.1875 0.1875 0 0 0 65.78 26.66 L 64.52 26.66 L 63.77 27.41 L 63.77 34.79 z} +set pathA([incr i]) {M 65.84 36.41 A 0.375 0.375 0 0 0 65.84 37.16 L 67.71 37.16 L 67.71 36.41 L 65.84 36.41 z} +set pathA([incr i]) {M 71.51 28.62 A 0.375 0.375 0 1 0 72.26 28.62 L 72.26 26.74 L 71.51 26.74 L 71.51 28.62 z} +set pathA([incr i]) {M 68.84 36.06 L 68.84 36.06 M 68.97 35.92 A 0.133 0.133 0 1 1 68.97 36.19 A 0.133 0.133 0 1 1 68.97 35.92 M 72.28 35.12 A 0.25 0.25 0 0 0 72.03 34.87 L 68.97 34.87 A 0.25 0.25 0 0 0 68.72 35.12 L 68.72 35.66 A 0.125 0.125 0 0 1 68.72 35.7 L 68.6 36.04 A 0.125 0.125 0 0 0 68.6 36.08 L 68.6 36.31 A 0.125 0.125 0 0 0 68.72 36.43 L 70.09 36.43 A 0.125 0.125 0 0 0 70.11 36.43 L 72.18 36.07 A 0.125 0.125 0 0 0 72.28 35.95 L 72.28 35.12 z} +set pathA([incr i]) {M 74.08 31.49 L 74.08 31.49 A 0.1875 0.1875 0 1 1 74.08 31.87 L 73.7 31.87 A 0.1875 0.1875 0 0 1 73.7 31.49 L 74.08 31.49 M 74.08 27.49 L 74.08 27.49 A 0.1875 0.1875 0 1 1 74.08 27.87 L 73.7 27.87 A 0.1875 0.1875 0 0 1 73.7 27.49 L 74.08 27.49 M 85.83 27.49 L 85.83 27.49 A 0.1875 0.1875 0 1 1 85.83 27.87 L 85.45 27.87 A 0.1875 0.1875 0 0 1 85.45 27.49 L 85.83 27.49 M 85.83 31.49 L 85.83 31.49 A 0.1875 0.1875 0 1 1 85.83 31.87 L 85.45 31.87 A 0.1875 0.1875 0 0 1 85.45 31.49 L 85.83 31.49 M 74.6 32.58 A 0.125 0.125 0 0 0 74.69 32.62 L 84.84 32.62 A 0.125 0.125 0 0 0 84.93 32.58 L 85.1 32.41 A 0.125 0.125 0 0 1 85.19 32.37 L 86.09 32.37 A 0.125 0.125 0 0 0 86.18 32.33 L 86.35 32.16 A 0.125 0.125 0 0 0 86.39 32.07 L 86.39 27.3 A 0.125 0.125 0 0 0 86.35 27.21 L 86.18 27.03 A 0.125 0.125 0 0 0 86.09 26.99 L 85.19 26.99 A 0.125 0.125 0 0 1 85.1 26.96 L 84.93 26.78 A 0.125 0.125 0 0 0 84.84 26.74 L 74.69 26.74 A 0.125 0.125 0 0 0 74.6 26.78 L 74.43 26.96 A 0.125 0.125 0 0 1 74.34 26.99 L 73.44 26.99 A 0.125 0.125 0 0 0 73.35 27.03 L 73.18 27.21 A 0.125 0.125 0 0 0 73.14 27.3 L 73.14 32.07 A 0.125 0.125 0 0 0 73.18 32.16 L 73.35 32.33 A 0.125 0.125 0 0 0 73.44 32.37 L 74.34 32.37 A 0.125 0.125 0 0 1 74.43 32.41 L 74.6 32.58 z} +set pathA([incr i]) {M 73.48 34.31 L 73.48 34.31 A 0.125 0.125 0 1 1 73.23 34.31 L 73.23 34.06 A 0.125 0.125 0 0 1 73.48 34.06 L 73.48 34.31 M 77.73 34.31 L 77.73 34.31 A 0.125 0.125 0 1 1 77.48 34.31 L 77.48 34.06 A 0.125 0.125 0 0 1 77.73 34.06 L 77.73 34.31 M 77.98 33.49 L 72.98 33.49 L 72.98 34.37 A 0.25 0.25 0 0 0 73.23 34.62 L 77.73 34.62 A 0.25 0.25 0 0 0 77.98 34.37 L 77.98 33.49 z} +set pathA([incr i]) {M 83.93 37.6 A 0.375 0.375 0 0 0 83.93 38.35 L 85.81 38.35 L 85.81 37.6 L 83.93 37.6 z} +set pathA([incr i]) {M 85.72 39.98 L 85.72 39.98 M 85.94 39.76 A 0.219 0.219 0 1 1 85.94 40.2 A 0.219 0.219 0 1 1 85.94 39.76 M 78.22 39.98 L 78.22 39.98 M 78.44 39.76 A 0.219 0.219 0 1 1 78.44 40.2 A 0.219 0.219 0 1 1 78.44 39.76 M 77.69 39.73 L 77.69 40.73 L 86.69 40.73 L 86.69 39.73 A 0.5 0.5 0 0 0 86.19 39.23 L 78.19 39.23 A 0.5 0.5 0 0 0 77.69 39.73 z} +set pathA([incr i]) {M 90.26 6.939 L 90.26 6.939 M 90.26 6.627 A 0.156 0.156 0 1 1 90.26 6.939 A 0.156 0.156 0 1 1 90.26 6.627 M 91.76 7.283 L 91.76 7.283 M 91.76 6.283 A 0.5 0.5 0 1 1 91.76 7.283 A 0.5 0.5 0 1 1 91.76 6.283 M 93.26 6.939 L 93.26 6.939 M 93.26 6.627 A 0.156 0.156 0 1 1 93.26 6.939 A 0.156 0.156 0 1 1 93.26 6.627 M 87.26 15.97 L 88.26 15.97 L 88.26 16.22 L 95.26 16.22 L 95.26 15.97 L 96.26 15.97 L 96.26 6.033 A 0.5 0.5 0 0 0 95.76 5.533 L 87.76 5.533 A 0.5 0.5 0 0 0 87.26 6.033 L 87.26 15.97 z} +set pathA([incr i]) {M 87.26 27.22 L 96.01 27.22 L 96.01 17.1 L 87.26 17.1 L 87.26 27.22 z} +set pathA([incr i]) {M 93.48 28.97 L 93.48 28.97 M 93.76 28.69 A 0.281 0.281 0 1 1 93.76 29.25 A 0.281 0.281 0 1 1 93.76 28.69 M 87.98 28.97 L 87.98 28.97 M 88.26 28.69 A 0.281 0.281 0 1 1 88.26 29.25 A 0.281 0.281 0 1 1 88.26 28.69 M 87.26 28.1 L 87.26 28.97 A 0.625 0.625 0 0 0 87.89 29.6 L 94.14 29.6 A 0.625 0.625 0 0 0 94.76 28.97 L 94.76 28.1 L 87.26 28.1 z} +set pathA([incr i]) {M 89.14 31.22 A 0.375 0.375 0 1 0 89.14 30.47 L 87.26 30.47 L 87.26 31.22 L 89.14 31.22 z} +set pathA([incr i]) {M 95.13 34.6 A 0.375 0.375 0 0 0 95.13 35.35 L 97 35.35 L 97 34.6 L 95.13 34.6 z} +set pathA([incr i]) {M 89.31 40.2 L 89.31 40.2 M 89.31 39.76 A 0.219 0.219 0 1 1 89.31 40.2 A 0.219 0.219 0 1 1 89.31 39.76 M 89.31 37.2 L 89.31 37.2 M 89.31 36.76 A 0.219 0.219 0 1 1 89.31 37.2 A 0.219 0.219 0 1 1 89.31 36.76 M 96.81 37.2 L 96.81 37.2 M 96.81 36.76 A 0.219 0.219 0 1 1 96.81 37.2 A 0.219 0.219 0 1 1 96.81 36.76 M 96.81 40.2 L 96.81 40.2 M 96.81 39.76 A 0.219 0.219 0 1 1 96.81 40.2 A 0.219 0.219 0 1 1 96.81 39.76 M 89.31 36.23 A 0.75 0.75 0 0 0 88.56 36.98 L 88.56 39.98 A 0.75 0.75 0 0 0 89.31 40.73 L 96.81 40.73 A 0.75 0.75 0 0 0 97.56 39.98 L 97.56 36.98 A 0.75 0.75 0 0 0 96.81 36.23 L 89.31 36.23 z} +set pathA([incr i]) {M 99.15 34.39 L 99.15 34.39 A 0.2188 0.2188 0 1 1 98.71 34.39 L 98.71 34.2 A 0.2188 0.2188 0 0 1 99.15 34.2 L 99.15 34.39 M 98.93 38.33 L 98.93 38.33 M 98.93 37.89 A 0.219 0.219 0 1 1 98.93 38.33 A 0.219 0.219 0 1 1 98.93 37.89 M 98.56 33.8 A 0.125 0.125 0 0 0 98.43 33.92 L 98.43 38.61 A 0.125 0.125 0 0 0 98.56 38.73 L 99.31 38.73 A 0.125 0.125 0 0 0 99.43 38.61 L 99.43 33.92 A 0.125 0.125 0 0 0 99.31 33.8 L 98.56 33.8 z} +set pathA([incr i]) {M 55.88 36.69 L 55.88 36.69 M 55.88 36.69 A 0.172 0.172 0 1 1 55.88 37.03 A 0.172 0.172 0 1 1 55.88 36.69 M 57.85 33.28 L 57.85 33.28 M 57.85 33.28 A 0.172 0.172 0 1 1 57.85 33.63 A 0.172 0.172 0 1 1 57.85 33.28 M 54.45 31.32 L 54.45 31.32 M 54.45 31.32 A 0.172 0.172 0 1 1 54.45 31.66 A 0.172 0.172 0 1 1 54.45 31.32 M 52.48 34.72 L 52.48 34.72 M 52.48 34.72 A 0.172 0.172 0 1 1 52.48 35.07 A 0.172 0.172 0 1 1 52.48 34.72 M 94.04 3.228 A 3.312 3.312 0 0 1 97.35 6.54 L 97.35 27.87 A 3.312 3.312 0 0 1 94.9 31.07 L 67.02 38.54 A 3.313 3.313 0 0 1 62.85 35.34 L 62.85 6.54 A 3.312 3.312 0 0 1 66.17 3.227 L 80.1 3.228 L 94.04 3.228 M 57.57 33.79 A 3 3 0 0 0 58.22 35.23 A 0.6562 0.6562 0 0 1 57.6 36.29 A 3 3 0 0 0 56.04 36.45 A 2.438 2.438 0 1 1 55.17 31.74 A 2.437 2.437 0 0 1 57.57 33.79 M 44.04 33.88 A 0.5 0.5 0 0 0 44.29 34.31 L 59.49 43.06 A 0.5 0.5 0 0 0 59.86 43.11 L 99.17 32.58 A 0.5 0.5 0 0 0 99.54 32.09 L 99.54 1.415 A 0.5 0.5 0 0 0 99.04 0.915 L 93.54 0.915 L 93.54 1.915 L 90.79 1.915 L 90.79 0.915 L 73.17 0.915 L 73.17 1.915 L 70.42 1.915 L 70.42 0.915 L 52.79 0.915 L 52.79 1.915 L 50.04 1.915 L 50.04 0.915 L 44.54 0.915 A 0.5 0.5 0 0 0 44.04 1.415 L 44.04 33.88 z} +set pathA([incr i]) {M 47.74 48.88 L 47.74 48.88 M 47.82 48.8 A 0.0805 0.0805 0 1 1 47.82 48.96 A 0.0805 0.0805 0 1 1 47.82 48.8 M 51.49 48.88 L 51.49 48.88 M 51.57 48.8 A 0.0805 0.0805 0 1 1 51.57 48.96 A 0.0805 0.0805 0 1 1 51.57 48.8 M 51.49 45.2 L 51.49 45.2 M 51.57 45.12 A 0.0805 0.0805 0 1 1 51.57 45.28 A 0.0805 0.0805 0 1 1 51.57 45.12 M 47.74 45.2 L 47.74 45.2 M 47.82 45.12 A 0.0805 0.0805 0 1 1 47.82 45.28 A 0.0805 0.0805 0 1 1 47.82 45.12 M 47.53 45.54 A 0.125 0.125 0 0 1 47.66 45.41 L 47.92 45.41 A 0.1562 0.1562 0 0 1 48.23 45.41 L 51.72 45.41 A 0.125 0.125 0 0 1 51.85 45.54 L 51.85 48.54 A 0.125 0.125 0 0 1 51.72 48.66 L 48.23 48.66 A 0.1562 0.1562 0 1 1 47.92 48.66 L 47.66 48.66 A 0.125 0.125 0 0 1 47.53 48.54 L 47.53 47.04 L 47.53 45.54 M 46.07 44.04 A 0.5 0.5 0 0 0 45.57 44.54 L 45.57 54.54 A 0.5 0.5 0 0 0 46.07 55.04 L 63.32 55.04 L 63.32 51.42 L 63.57 51.42 L 63.57 47.66 L 63.32 47.66 L 63.32 44.04 L 46.07 44.04 z} +set pathA([incr i]) {M 46.2 57.79 A 0.375 0.375 0 1 0 46.95 57.79 L 46.95 55.91 L 46.2 55.91 L 46.2 57.79 z} +set pathA([incr i]) {M 47.83 57.79 A 0.375 0.375 0 1 0 48.58 57.79 L 48.58 55.91 L 47.83 55.91 L 47.83 57.79 z} +set pathA([incr i]) {M 49.45 57.79 A 0.375 0.375 0 1 0 50.2 57.79 L 50.2 55.91 L 49.45 55.91 L 49.45 57.79 z} +set pathA([incr i]) {M 51.07 57.79 A 0.375 0.375 0 1 0 51.82 57.79 L 51.82 55.91 L 51.07 55.91 L 51.07 57.79 z} +set pathA([incr i]) {M 54.95 55.91 L 52.7 55.91 L 52.7 58.54 L 53.26 58.54 L 53.26 57.23 A 0.5625 0.5625 0 0 1 54.39 57.23 L 54.39 58.54 L 54.95 58.54 L 54.95 55.91 z} +set pathA([incr i]) {M 62.04 56.79 L 62.04 56.79 M 62.32 56.51 A 0.281 0.281 0 1 1 62.32 57.07 A 0.281 0.281 0 1 1 62.32 56.51 M 56.54 56.79 L 56.54 56.79 M 56.82 56.51 A 0.281 0.281 0 1 1 56.82 57.07 A 0.281 0.281 0 1 1 56.82 56.51 M 55.82 55.91 L 55.82 56.79 A 0.625 0.625 0 0 0 56.45 57.41 L 62.7 57.41 A 0.625 0.625 0 0 0 63.32 56.79 L 63.32 55.91 L 55.82 55.91 z} +set pathA([incr i]) {M 59.83 59.04 A 0.375 0.375 0 1 0 59.83 58.29 L 57.95 58.29 L 57.95 59.04 L 59.83 59.04 z} +set pathA([incr i]) {M 62.95 59.04 A 0.375 0.375 0 1 0 62.95 58.29 L 61.08 58.29 L 61.08 59.04 L 62.95 59.04 z} +set pathA([incr i]) {M 65.32 46.96 L 65.32 46.96 A 0.25 0.25 0 0 1 65.82 46.96 L 65.82 47.46 A 0.25 0.25 0 1 1 65.32 47.46 L 65.32 46.96 M 64.45 48.21 L 67.2 48.21 L 67.2 42.71 L 65.2 42.71 L 64.49 44.37 A 0.5 0.5 0 0 0 64.45 44.56 L 64.45 48.21 z} +set pathA([incr i]) {M 66.57 51.1 L 66.57 51.1 A 0.25 0.25 0 0 1 67.07 51.1 L 67.07 51.6 A 0.25 0.25 0 1 1 66.57 51.6 L 66.57 51.1 M 64.82 52.1 L 64.82 52.1 A 0.25 0.25 0 0 1 65.32 52.1 L 65.32 52.6 A 0.25 0.25 0 1 1 64.82 52.6 L 64.82 52.1 M 67.2 52.31 A 0.5 0.5 0 0 0 67.45 51.88 L 67.45 49.23 A 2.5 2.5 0 0 1 64.45 49.23 L 64.45 53.05 A 0.5 0.5 0 0 0 65.2 53.48 L 67.2 52.31 z} +set pathA([incr i]) {M 90.68 42.23 L 90.68 42.23 M 91 41.92 A 0.3125 0.3125 0 1 1 91 42.54 A 0.3125 0.3125 0 1 1 91 41.92 M 90.68 52.79 L 90.68 52.79 M 91 52.48 A 0.3125 0.3125 0 1 1 91 53.1 A 0.3125 0.3125 0 1 1 91 52.48 M 72.68 42.23 L 72.68 42.23 M 73 41.91 A 0.3125 0.3125 0 1 1 73 42.54 A 0.3125 0.3125 0 1 1 73 41.91 M 72.68 52.79 L 72.68 52.79 M 73 52.48 A 0.3125 0.3125 0 1 1 73 53.1 A 0.3125 0.3125 0 1 1 73 52.48 M 94.91 41.64 A 0.125 0.125 0 0 0 94.82 41.6 L 69.17 41.6 A 0.125 0.125 0 0 0 69.09 41.64 L 68.53 42.19 A 0.125 0.125 0 0 0 68.5 42.28 L 68.5 52.74 A 0.125 0.125 0 0 0 68.53 52.83 L 69.09 53.38 A 0.125 0.125 0 0 0 69.17 53.41 L 80 53.42 A 0.125 0.125 0 0 0 80.12 53.29 L 80.12 52.04 A 0.5 0.5 0 0 1 80.62 51.54 L 83.37 51.54 A 0.5 0.5 0 0 1 83.87 52.04 L 83.87 53.29 A 0.125 0.125 0 0 0 84 53.42 L 94.82 53.42 A 0.125 0.125 0 0 0 94.91 53.38 L 95.46 52.83 A 0.125 0.125 0 0 0 95.5 52.74 L 95.5 42.28 A 0.125 0.125 0 0 0 95.46 42.19 L 94.91 41.64 z} +set pathA([incr i]) {M 98.25 42.85 L 98.25 42.85 A 0.25 0.25 0 1 1 97.75 42.85 L 97.75 42.35 A 0.25 0.25 0 0 1 98.25 42.35 L 98.25 42.85 M 99.12 41.6 L 96.37 41.6 L 96.37 47.1 L 98.37 47.1 L 99.08 45.45 A 0.5 0.5 0 0 0 99.12 45.25 L 99.12 41.6 z} +set pathA([incr i]) {M 97.56 51.42 L 97.56 51.42 M 97.56 51.16 A 0.133 0.133 0 1 1 97.56 51.42 A 0.133 0.133 0 1 1 97.56 51.16 M 96.62 47.98 A 0.25 0.25 0 0 0 96.37 48.23 L 96.37 51.29 A 0.25 0.25 0 0 0 96.62 51.54 L 97.16 51.54 A 0.125 0.125 0 0 1 97.2 51.55 L 97.54 51.66 A 0.125 0.125 0 0 0 97.58 51.66 L 97.81 51.66 A 0.125 0.125 0 0 0 97.93 51.54 L 97.93 50.18 A 0.125 0.125 0 0 0 97.93 50.15 L 97.58 48.08 A 0.125 0.125 0 0 0 97.45 47.98 L 96.62 47.98 z} +set pathA([incr i]) {M 102.8 58.26 L 102.8 58.26 M 102.6 58.08 A 0.1875 0.1875 0 1 1 102.6 58.45 A 0.1875 0.1875 0 1 1 102.6 58.08 M 102.8 55.01 L 102.8 55.01 M 102.6 54.83 A 0.1875 0.1875 0 1 1 102.6 55.2 A 0.1875 0.1875 0 1 1 102.6 54.83 M 100.3 53.83 L 100.3 53.83 M 100 53.54 A 0.281 0.281 0 1 1 100 54.11 A 0.281 0.281 0 1 1 100 53.54 M 100.3 56.95 L 100.3 56.95 M 100 56.67 A 0.281 0.281 0 1 1 100 57.23 A 0.281 0.281 0 1 1 100 56.67 M 97.33 56.95 L 97.33 56.95 M 97.05 56.67 A 0.281 0.281 0 1 1 97.05 57.23 A 0.281 0.281 0 1 1 97.05 56.67 M 97.33 53.83 L 97.33 53.83 M 97.05 53.54 A 0.281 0.281 0 1 1 97.05 54.11 A 0.281 0.281 0 1 1 97.05 53.54 M 94.68 55.01 L 94.68 55.01 M 94.5 54.83 A 0.1875 0.1875 0 1 1 94.5 55.2 A 0.1875 0.1875 0 1 1 94.5 54.83 M 94.68 58.26 L 94.68 58.26 M 94.5 58.08 A 0.1875 0.1875 0 1 1 94.5 58.45 A 0.1875 0.1875 0 1 1 94.5 58.08 M 93.81 54.45 L 93.81 58.83 L 95.03 58.83 A 0.125 0.125 0 0 0 95.11 58.79 L 96.38 57.61 A 0.125 0.125 0 0 1 96.47 57.58 L 100.6 57.58 A 0.125 0.125 0 0 1 100.7 57.61 L 102 58.79 A 0.125 0.125 0 0 0 102.1 58.83 L 103.3 58.83 L 103.3 54.45 L 102.1 54.45 A 0.125 0.125 0 0 1 102 54.42 L 100.7 53.23 A 0.125 0.125 0 0 0 100.6 53.2 L 96.47 53.2 A 0.125 0.125 0 0 0 96.38 53.23 L 95.11 54.42 A 0.125 0.125 0 0 1 95.03 54.45 L 93.81 54.45 z} +set pathA([incr i]) {M 112.1 52.95 L 112.1 52.95 A 0.2812 0.2812 0 0 1 112.1 52.38 L 112.5 52.38 A 0.2812 0.2812 0 1 1 112.5 52.95 L 112.1 52.95 M 103.3 52.95 L 103.3 52.95 A 0.2812 0.2812 0 0 1 103.3 52.38 L 103.7 52.38 A 0.2812 0.2812 0 1 1 103.7 52.95 L 103.3 52.95 M 103.3 1.946 L 103.3 1.946 A 0.2812 0.2812 0 0 1 103.3 1.384 L 103.7 1.384 A 0.2812 0.2812 0 1 1 103.7 1.946 L 103.3 1.946 M 112.1 1.946 L 112.1 1.946 A 0.2812 0.2812 0 0 1 112.1 1.384 L 112.5 1.384 A 0.2812 0.2812 0 1 1 112.5 1.946 L 112.1 1.946 M 100.4 21.29 A 0.125 0.125 0 0 0 100.5 21.42 L 100.7 21.42 A 0.5 0.5 0 0 1 101.2 21.92 A 0.5 0.5 0 0 1 100.7 22.42 L 100.5 22.42 A 0.125 0.125 0 0 0 100.4 22.54 L 100.4 33.29 A 0.125 0.125 0 0 0 100.5 33.42 L 100.7 33.42 A 0.5 0.5 0 0 1 101.2 33.92 A 0.5 0.5 0 0 1 100.7 34.42 L 100.5 34.42 A 0.125 0.125 0 0 0 100.4 34.54 L 100.4 45.29 A 0.125 0.125 0 0 0 100.5 45.42 L 100.7 45.42 A 0.5 0.5 0 0 1 101.2 45.92 A 0.5 0.5 0 0 1 100.7 46.42 L 100.5 46.42 A 0.125 0.125 0 0 0 100.4 46.54 L 100.4 50.42 A 0.75 0.75 0 0 0 101.2 51.17 L 101.7 51.17 A 0.25 0.25 0 0 1 101.9 51.42 L 101.9 52.67 A 0.75 0.75 0 0 0 102.7 53.42 L 113.1 53.42 A 0.75 0.75 0 0 0 113.9 52.67 L 113.9 51.42 A 0.25 0.25 0 0 1 114.1 51.17 L 114.6 51.17 A 0.75 0.75 0 0 0 115.4 50.42 L 115.4 46.54 A 0.125 0.125 0 0 0 115.3 46.42 L 115.1 46.42 A 0.5 0.5 0 0 1 114.6 45.92 A 0.5 0.5 0 0 1 115.1 45.42 L 115.3 45.42 A 0.125 0.125 0 0 0 115.4 45.29 L 115.4 34.54 A 0.125 0.125 0 0 0 115.3 34.42 L 115.1 34.42 A 0.5 0.5 0 0 1 114.6 33.92 A 0.5 0.5 0 0 1 115.1 33.42 L 115.3 33.42 A 0.125 0.125 0 0 0 115.4 33.29 L 115.4 22.54 A 0.125 0.125 0 0 0 115.3 22.42 L 115.1 22.42 A 0.5 0.5 0 0 1 114.6 21.92 A 0.5 0.5 0 0 1 115.1 21.42 L 115.3 21.42 A 0.125 0.125 0 0 0 115.4 21.29 L 115.4 3.915 A 0.75 0.75 0 0 0 114.6 3.165 L 114.1 3.165 A 0.25 0.25 0 0 1 113.9 2.915 L 113.9 1.665 A 0.75 0.75 0 0 0 113.1 0.915 L 102.7 0.915 A 0.75 0.75 0 0 0 101.9 1.665 L 101.9 2.915 A 0.25 0.25 0 0 1 101.7 3.165 L 101.2 3.165 A 0.75 0.75 0 0 0 100.4 3.915 L 100.4 21.29 z} +set pathA([incr i]) {M 106 56.43 L 106 56.43 M 106 55.9 A 0.2655 0.2655 0 1 1 106 56.43 A 0.2655 0.2655 0 1 1 106 55.9 M 104.4 54.29 A 0.25 0.25 0 0 0 104.2 54.54 L 104.2 57.79 A 0.25 0.25 0 0 0 104.4 58.04 L 107.7 58.04 A 0.25 0.25 0 0 0 107.9 57.79 L 107.9 56.29 L 107.8 56.29 A 0.125 0.125 0 0 1 107.8 56.04 L 107.9 56.04 L 107.9 54.54 A 0.25 0.25 0 0 0 107.7 54.29 L 104.4 54.29 z} +set pathA([incr i]) {M 110 57.74 L 110 57.74 M 110 57.47 A 0.133 0.133 0 1 1 110 57.74 A 0.133 0.133 0 1 1 110 57.47 M 109 54.29 A 0.25 0.25 0 0 0 108.8 54.54 L 108.8 57.6 A 0.25 0.25 0 0 0 109 57.85 L 109.6 57.85 A 0.125 0.125 0 0 1 109.6 57.86 L 110 57.97 A 0.125 0.125 0 0 0 110 57.98 L 110.2 57.98 A 0.125 0.125 0 0 0 110.3 57.85 L 110.3 56.49 A 0.125 0.125 0 0 0 110.3 56.47 L 110 54.39 A 0.125 0.125 0 0 0 109.9 54.29 L 109 54.29 z} +set pathA([incr i]) {M 111.5 54.53 L 111.5 54.53 M 111.5 54.53 A 0.133 0.133 0 1 1 111.5 54.8 A 0.133 0.133 0 1 1 111.5 54.53 M 112.4 57.98 A 0.25 0.25 0 0 0 112.7 57.73 L 112.7 54.67 A 0.25 0.25 0 0 0 112.4 54.42 L 111.9 54.42 A 0.125 0.125 0 0 1 111.8 54.41 L 111.5 54.3 A 0.125 0.125 0 0 0 111.5 54.29 L 111.2 54.29 A 0.125 0.125 0 0 0 111.1 54.42 L 111.1 55.78 A 0.125 0.125 0 0 0 111.1 55.8 L 111.5 57.87 A 0.125 0.125 0 0 0 111.6 57.98 L 112.4 57.98 z} +set pathA([incr i]) {M 114.7 57.74 L 114.7 57.74 M 114.7 57.47 A 0.133 0.133 0 1 1 114.7 57.74 A 0.133 0.133 0 1 1 114.7 57.47 M 113.8 54.29 A 0.25 0.25 0 0 0 113.6 54.54 L 113.6 57.6 A 0.25 0.25 0 0 0 113.8 57.85 L 114.3 57.85 A 0.125 0.125 0 0 1 114.4 57.86 L 114.7 57.97 A 0.125 0.125 0 0 0 114.8 57.98 L 115 57.98 A 0.125 0.125 0 0 0 115.1 57.85 L 115.1 56.49 A 0.125 0.125 0 0 0 115.1 56.47 L 114.8 54.39 A 0.125 0.125 0 0 0 114.6 54.29 L 113.8 54.29 z} +set pathA([incr i]) {M 118 53.67 L 118 53.67 M 118 53.67 A 0.25 0.25 0 1 1 118 54.17 A 0.25 0.25 0 1 1 118 53.67 M 118 43.67 L 118 43.67 M 118 43.67 A 0.25 0.25 0 1 1 118 44.17 A 0.25 0.25 0 1 1 118 43.67 M 118 33.67 L 118 33.67 M 118 33.67 A 0.25 0.25 0 1 1 118 34.17 A 0.25 0.25 0 1 1 118 33.67 M 118 13.67 L 118 13.67 M 118 13.67 A 0.25 0.25 0 1 1 118 14.17 A 0.25 0.25 0 1 1 118 13.67 M 118 3.665 L 118 3.665 M 118 3.665 A 0.25 0.25 0 1 1 118 4.165 A 0.25 0.25 0 1 1 118 3.665 M 118 23.67 L 118 23.67 M 118 23.67 A 0.25 0.25 0 1 1 118 24.17 A 0.25 0.25 0 1 1 118 23.67 M 116.3 56.92 L 120 56.92 L 120 0.915 L 116.3 0.915 L 116.3 56.92 z} +set pathA([incr i]) {M 117.9 58.54 A 0.375 0.375 0 1 0 117.9 57.79 L 116 57.79 L 116 58.54 L 117.9 58.54 z} + +set t .c_sheetmetal +destroy $t +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 800 -height 400 -bg black -highlightthickness 0] + +set g1 [$w gradient create linear -stops {{0 "#bababa"} {1 "#454545"}} -lineartransition {0 0 0 1}] + +foreach i [lsort [array names pathA]] { + set id [$w create path $pathA($i) -fill $g1 -stroke white] +} + +# We just scale the root element which implicitly rescales all its descendants. +$w scale 0 0 0 6.4 6.4 + + diff --git a/pd/tkpath/demos/splines.tcl b/pd/tkpath/demos/splines.tcl new file mode 100644 index 0000000000000000000000000000000000000000..fc8cd28ee2718e2694e006538c314f87decae512 --- /dev/null +++ b/pd/tkpath/demos/splines.tcl @@ -0,0 +1,27 @@ +package require tkpath 0.3.0 + +set t .c_splines +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + +$w create text 160 80 -text "Quadratic spline" -anchor w +$w create text 160 100 -text "M 20 100 Q 80 20 140 100" -anchor w +$w create path "M 20 100 L 80 20 140 100" -stroke blue -strokewidth 1 +$w create path "M 20 100 Q 80 20 140 100" -stroke black -strokewidth 3 +$w create path "M 15 100 h 10 m -5 -5 v 10" -stroke red +$w create path "M 75 20 h 10 m -5 -5 v 10" -stroke red +$w create path "M 135 100 h 10 m -5 -5 v 10" -stroke red + +$w create text 160 220 -text "Cubic spline" -anchor w +$w create text 160 240 -text "M 20 250 C 60 140 100 380 140 250" -anchor w +$w create path "M 20 250 L 60 140 100 380 140 250" -stroke blue -strokewidth 1 +$w create path "M 20 250 C 60 140 100 380 140 250" -stroke black -strokewidth 3 +$w create path "M 15 250 h 10 m -5 -5 v 10" -stroke red +$w create path "M 55 140 h 10 m -5 -5 v 10" -stroke red +$w create path "M 95 380 h 10 m -5 -5 v 10" -stroke red +$w create path "M 135 250 h 10 m -5 -5 v 10" -stroke red + + + + diff --git a/pd/tkpath/demos/style.tcl b/pd/tkpath/demos/style.tcl new file mode 100644 index 0000000000000000000000000000000000000000..bee3ebc8778c1e7ae5cf3fc2c72a13cc45893567 --- /dev/null +++ b/pd/tkpath/demos/style.tcl @@ -0,0 +1,42 @@ +package require tkpath 0.3.0 + +set t .c_style +destroy $t +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg white] + +proc filteropts {w S} { + set opts [list] + foreach spec [$w style config $S] { + lassign $spec name - - dvalue value + if {$dvalue ne $value} { + lappend opts $name $value + } + } + return $opts +} + +set S1 [$w style create -stroke "#c8c8c8" -fill "#e6e6e6"] +set S2 [$w style create -stroke "#a19de2" -fill "#d6d6ff"] +set S3 [$w style create -stroke "#9ac790" -fill "#cae2c5"] +set S4 [$w style create -stroke "#e2a19d" -fill "#ffd6d6"] +set S5 [$w style create -stroke "#666666" -strokewidth 3 -fill "#bdbdbd"] + +foreach S [$w style names] { + puts "style $S : [filteropts $w $S]" +} + +$w create prect 20 20 180 80 -rx 6 -style $S1 +$w create prect 200 20 260 80 -rx 6 -style $S2 +$w create prect 20 100 180 180 -rx 6 -style $S3 +$w create prect 200 100 260 180 -rx 6 -style $S4 + +$w create prect 20 200 260 380 -stroke "#999999" +$w create prect 40 220 100 360 -rx 16 -style $S5 + + +$w create prect 150 240 170 260 -stroke "" -fill red +$w create prect 150 270 170 290 -stroke "" -fill green +$w create prect 150 300 170 320 -stroke "" -fill blue + diff --git a/pd/tkpath/demos/text.tcl b/pd/tkpath/demos/text.tcl new file mode 100644 index 0000000000000000000000000000000000000000..56925eda97650103c0c2d02cc5aaadd9c8d4b8df --- /dev/null +++ b/pd/tkpath/demos/text.tcl @@ -0,0 +1,17 @@ +package require tkpath 0.3.0 + +set t .c_text +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 400 -height 400 -bg "#c6ceef" -highlightthickness 0] + +$w create ptext 200 360 -text "X" -fontsize 400 -fill "" \ + -stroke gray -strokewidth 2 -textanchor middle +$w create ptext 0 0 -text "Coccinella" -fontfamily Helvetica -fontsize 64 \ + -fill white -fillopacity 0.7 -matrix {{1 0.3} {-0.3 1} {50 80}} \ + -stroke gray -strokewidth 2 +$w create ptext 200 300 -text "Made by Mats" -fontfamily Times -fontsize 40 \ + -fill white -textanchor middle + + + diff --git a/pd/tkpath/demos/tiger.tcl b/pd/tkpath/demos/tiger.tcl new file mode 100644 index 0000000000000000000000000000000000000000..be0718bc5ab070e1b560841f2eb712cc015f7952 --- /dev/null +++ b/pd/tkpath/demos/tiger.tcl @@ -0,0 +1,255 @@ +# Drawing from +# +# Note that the drawing is presumably copyrighted by someone. + +package require tkpath 0.3.0 + +set t .c_tiger +toplevel $t +set w $t.c +pack [tkp::canvas $w -width 600 -height 600 -bg white] + + +$w create path {M -122.304 84.285 C -122.304 84.285 -122.203 86.179 -123.027 86.16 C -123.851 86.141 -140.305 38.066 -160.833 40.309 C -160.833 40.309 -143.05 32.956 -122.304 84.285 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -118.774 81.262 C -118.774 81.262 -119.323 83.078 -120.092 82.779 C -120.86 82.481 -119.977 31.675 -140.043 26.801 C -140.043 26.801 -120.82 25.937 -118.774 81.262 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -91.284 123.59 C -91.284 123.59 -89.648 124.55 -90.118 125.227 C -90.589 125.904 -139.763 113.102 -149.218 131.459 C -149.218 131.459 -145.539 112.572 -91.284 123.59 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -94.093 133.801 C -94.093 133.801 -92.237 134.197 -92.471 134.988 C -92.704 135.779 -143.407 139.121 -146.597 159.522 C -146.597 159.522 -149.055 140.437 -94.093 133.801 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -98.304 128.276 C -98.304 128.276 -96.526 128.939 -96.872 129.687 C -97.218 130.435 -147.866 126.346 -153.998 146.064 C -153.998 146.064 -153.646 126.825 -98.304 128.276 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -109.009 110.072 C -109.009 110.072 -107.701 111.446 -108.34 111.967 C -108.979 112.488 -152.722 86.634 -166.869 101.676 C -166.869 101.676 -158.128 84.533 -109.009 110.072 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -116.554 114.263 C -116.554 114.263 -115.098 115.48 -115.674 116.071 C -116.25 116.661 -162.638 95.922 -174.992 112.469 C -174.992 112.469 -168.247 94.447 -116.554 114.263 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -119.154 118.335 C -119.154 118.335 -117.546 119.343 -118.036 120.006 C -118.526 120.669 -167.308 106.446 -177.291 124.522 C -177.291 124.522 -173.066 105.749 -119.154 118.335 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -108.42 118.949 C -108.42 118.949 -107.298 120.48 -107.999 120.915 C -108.7 121.35 -148.769 90.102 -164.727 103.207 C -164.727 103.207 -153.862 87.326 -108.42 118.949 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -128.2 90 C -128.2 90 -127.6 91.8 -128.4 92 C -129.2 92.2 -157.8 50.2 -177.001 57.8 C -177.001 57.8 -161.8 46 -128.2 90 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -127.505 96.979 C -127.505 96.979 -126.53 98.608 -127.269 98.975 C -128.007 99.343 -164.992 64.499 -182.101 76.061 C -182.101 76.061 -169.804 61.261 -127.505 96.979 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -127.62 101.349 C -127.62 101.349 -126.498 102.88 -127.199 103.315 C -127.9 103.749 -167.969 72.502 -183.927 85.607 C -183.927 85.607 -173.062 69.726 -127.62 101.349 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -129.83 103.065 C -129.327 109.113 -128.339 115.682 -126.6 118.801 C -126.6 118.801 -130.2 131.201 -121.4 144.401 C -121.4 144.401 -121.8 151.601 -120.2 154.801 C -120.2 154.801 -116.2 163.201 -111.4 164.001 C -107.516 164.648 -98.793 167.717 -88.932 169.121 C -88.932 169.121 -71.8 183.201 -75 196.001 C -75 196.001 -75.4 212.401 -79 214.001 C -79 214.001 -67.4 202.801 -77 219.601 L -81.4 238.401 C -81.4 238.401 -55.8 216.801 -71.4 235.201 L -81.4 261.201 C -81.4 261.201 -61.8 242.801 -69 251.201 L -72.2 260.001 C -72.2 260.001 -29 232.801 -59.8 262.401 C -59.8 262.401 -51.8 258.801 -47.4 261.601 C -47.4 261.601 -40.6 260.401 -41.4 262.001 C -41.4 262.001 -62.2 272.401 -65.8 290.801 C -65.8 290.801 -57.4 280.801 -60.6 291.601 L -60.2 303.201 C -60.2 303.201 -56.2 281.601 -56.6 319.201 C -56.6 319.201 -37.4 301.201 -49 322.001 L -49 338.801 C -49 338.801 -33.8 322.401 -40.2 335.201 C -40.2 335.201 -30.2 326.401 -34.2 341.601 C -34.2 341.601 -35 352.001 -30.6 340.801 C -30.6 340.801 -14.6 310.201 -20.6 336.401 C -20.6 336.401 -21.4 355.601 -16.6 340.801 C -16.6 340.801 -16.2 351.201 -7 358.401 C -7 358.401 -8.2 307.601 4.6 343.601 L 8.6 360.001 C 8.6 360.001 11.4 350.801 11 345.601 C 11 345.601 25.8 329.201 19 353.601 C 19 353.601 34.2 330.801 31 344.001 C 31 344.001 23.4 360.001 25 364.801 C 25 364.801 41.8 330.001 43 328.401 C 43 328.401 41 370.802 51.8 334.801 C 51.8 334.801 57.4 346.801 54.6 351.201 C 54.6 351.201 62.6 343.201 61.8 340.001 C 61.8 340.001 66.4 331.801 69.2 345.401 C 69.2 345.401 71 354.801 72.6 351.601 C 72.6 351.601 76.6 375.602 77.8 352.801 C 77.8 352.801 79.4 339.201 72.2 327.601 C 72.2 327.601 73 324.401 70.2 320.401 C 70.2 320.401 83.8 342.001 76.6 313.201 C 76.6 313.201 87.801 321.201 89.001 321.201 C 89.001 321.201 75.4 298.001 84.2 302.801 C 84.2 302.801 79 292.401 97.001 304.401 C 97.001 304.401 81 288.401 98.601 298.001 C 98.601 298.001 106.601 304.401 99.001 294.401 C 99.001 294.401 84.6 278.401 106.601 296.401 C 106.601 296.401 118.201 312.801 119.001 315.601 C 119.001 315.601 109.001 286.401 104.601 283.601 C 104.601 283.601 113.001 247.201 154.201 262.801 C 154.201 262.801 161.001 280.001 165.401 261.601 C 165.401 261.601 178.201 255.201 189.401 282.801 C 189.401 282.801 193.401 269.201 192.601 266.401 C 192.601 266.401 199.401 267.601 198.601 266.401 C 198.601 266.401 211.801 270.801 213.001 270.001 C 213.001 270.001 219.801 276.801 220.201 273.201 C 220.201 273.201 229.401 276.001 227.401 272.401 C 227.401 272.401 236.201 288.001 236.601 291.601 L 239.001 277.601 L 241.001 280.401 C 241.001 280.401 242.601 272.801 241.801 271.601 C 241.001 270.401 261.801 278.401 266.601 299.201 L 268.601 307.601 C 268.601 307.601 274.601 292.801 273.001 288.801 C 273.001 288.801 278.201 289.601 278.601 294.001 C 278.601 294.001 282.601 270.801 277.801 264.801 C 277.801 264.801 282.201 264.001 283.401 267.601 L 283.401 260.401 C 283.401 260.401 290.601 261.201 290.601 258.801 C 290.601 258.801 295.001 254.801 297.001 259.601 C 297.001 259.601 284.601 224.401 303.001 243.601 C 303.001 243.601 310.201 254.401 306.601 235.601 C 303.001 216.801 299.001 215.201 303.801 214.801 C 303.801 214.801 304.601 211.201 302.601 209.601 C 300.601 208.001 303.801 209.601 303.801 209.601 C 303.801 209.601 308.601 213.601 303.401 191.601 C 303.401 191.601 309.801 193.201 297.801 164.001 C 297.801 164.001 300.601 161.601 296.601 153.201 C 296.601 153.201 304.601 157.601 307.401 156.001 C 307.401 156.001 307.001 154.401 303.801 150.401 C 303.801 150.401 282.201 95.6 302.601 117.601 C 302.601 117.601 314.451 131.151 308.051 108.351 C 308.051 108.351 298.94 84.341 299.717 80.045 L -129.83 103.065 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 299.717 80.245 C 300.345 80.426 302.551 81.55 303.801 83.2 C 303.801 83.2 310.601 94 305.401 75.6 C 305.401 75.6 296.201 46.8 305.001 58 C 305.001 58 311.001 65.2 307.801 51.6 C 303.936 35.173 301.401 28.8 301.401 28.8 C 301.401 28.8 313.001 33.6 286.201 -6 L 295.001 -2.4 C 295.001 -2.4 275.401 -42 253.801 -47.2 L 245.801 -53.2 C 245.801 -53.2 284.201 -91.2 271.401 -128 C 271.401 -128 264.601 -133.2 255.001 -124 C 255.001 -124 248.601 -119.2 242.601 -120.8 C 242.601 -120.8 211.801 -119.6 209.801 -119.6 C 207.801 -119.6 173.001 -156.8 107.401 -139.2 C 107.401 -139.2 102.201 -137.2 97.801 -138.4 C 97.801 -138.4 79.4 -154.4 30.6 -131.6 C 30.6 -131.6 20.6 -129.6 19 -129.6 C 17.4 -129.6 14.6 -129.6 6.6 -123.2 C -1.4 -116.8 -1.8 -116 -3.8 -114.4 C -3.8 -114.4 -20.2 -103.2 -25 -102.4 C -25 -102.4 -36.6 -96 -41 -86 L -44.6 -84.8 C -44.6 -84.8 -46.2 -77.6 -46.6 -76.4 C -46.6 -76.4 -51.4 -72.8 -52.2 -67.2 C -52.2 -67.2 -61 -61.2 -60.6 -56.8 C -60.6 -56.8 -62.2 -51.6 -63 -46.8 C -63 -46.8 -70.2 -42 -69.4 -39.2 C -69.4 -39.2 -77 -25.2 -75.8 -18.4 C -75.8 -18.4 -82.2 -18.8 -85 -16.4 C -85 -16.4 -85.8 -11.6 -87.4 -11.2 C -87.4 -11.2 -90.2 -10 -87.8 -6 C -87.8 -6 -89.4 -3.2 -89.8 -1.6 C -89.8 -1.6 -89 1.2 -93.4 6.8 C -93.4 6.8 -99.8 25.6 -97.8 30.8 C -97.8 30.8 -97.4 35.6 -100.2 37.2 C -100.2 37.2 -103.8 36.8 -95.4 48.8 C -95.4 48.8 -94.6 50 -97.8 52.4 C -97.8 52.4 -115 56 -117.4 72.4 C -117.4 72.4 -131 87.2 -131 92.4 C -131 94.705 -130.729 97.852 -130.03 102.465 C -130.03 102.465 -130.6 110.801 -103 111.601 C -75.4 112.401 299.717 80.245 299.717 80.245 z} -tags _tmp_transform -fill #cc7226 -stroke #000000 +$w create path {M -115.6 102.6 C -140.6 63.2 -126.2 119.601 -126.2 119.601 C -117.4 154.001 12.2 116.401 12.2 116.401 C 12.2 116.401 181.001 86 192.201 82 C 203.401 78 298.601 84.4 298.601 84.4 L 293.001 67.6 C 228.201 21.2 209.001 44.4 195.401 40.4 C 181.801 36.4 184.201 46 181.001 46.8 C 177.801 47.6 138.601 22.8 132.201 23.6 C 125.801 24.4 100.459 0.649 115.401 32.4 C 131.401 66.4 57 71.6 40.2 60.4 C 23.4 49.2 47.4 78.8 47.4 78.8 C 65.8 98.8 31.4 82 31.4 82 C -3 69.2 -27 94.8 -30.2 95.6 C -33.4 96.4 -38.2 99.6 -39 93.2 C -39.8 86.8 -47.31 70.099 -79 96.4 C -99 113.001 -112.8 91 -112.8 91 L -115.6 102.6 z} -tags _tmp_transform -fill #cc7226 -stroke {} +$w create path {M 133.51 25.346 C 127.11 26.146 101.743 2.407 116.71 34.146 C 133.31 69.346 58.31 73.346 41.51 62.146 C 24.709 50.946 48.71 80.546 48.71 80.546 C 67.11 100.546 32.709 83.746 32.709 83.746 C -1.691 70.946 -25.691 96.546 -28.891 97.346 C -32.091 98.146 -36.891 101.346 -37.691 94.946 C -38.491 88.546 -45.87 72.012 -77.691 98.146 C -98.927 115.492 -112.418 94.037 -112.418 94.037 L -115.618 104.146 C -140.618 64.346 -125.546 122.655 -125.546 122.655 C -116.745 157.056 13.509 118.146 13.509 118.146 C 13.509 118.146 182.31 87.746 193.51 83.746 C 204.71 79.746 299.038 86.073 299.038 86.073 L 293.51 68.764 C 228.71 22.364 210.31 46.146 196.71 42.146 C 183.11 38.146 185.51 47.746 182.31 48.546 C 179.11 49.346 139.91 24.546 133.51 25.346 z} -tags _tmp_transform -fill #e87f3a -stroke {} +$w create path {M 134.819 27.091 C 128.419 27.891 103.685 3.862 118.019 35.891 C 134.219 72.092 59.619 75.092 42.819 63.892 C 26.019 52.692 50.019 82.292 50.019 82.292 C 68.419 102.292 34.019 85.492 34.019 85.492 C -0.381 72.692 -24.382 98.292 -27.582 99.092 C -30.782 99.892 -35.582 103.092 -36.382 96.692 C -37.182 90.292 -44.43 73.925 -76.382 99.892 C -98.855 117.983 -112.036 97.074 -112.036 97.074 L -115.636 105.692 C -139.436 66.692 -124.891 125.71 -124.891 125.71 C -116.091 160.11 14.819 119.892 14.819 119.892 C 14.819 119.892 183.619 89.492 194.819 85.492 C 206.019 81.492 299.474 87.746 299.474 87.746 L 294.02 69.928 C 229.219 23.528 211.619 47.891 198.019 43.891 C 184.419 39.891 186.819 49.491 183.619 50.292 C 180.419 51.092 141.219 26.291 134.819 27.091 z} -tags _tmp_transform -fill #ea8c4d -stroke {} +$w create path {M 136.128 28.837 C 129.728 29.637 104.999 5.605 119.328 37.637 C 136.128 75.193 60.394 76.482 44.128 65.637 C 27.328 54.437 51.328 84.037 51.328 84.037 C 69.728 104.037 35.328 87.237 35.328 87.237 C 0.928 74.437 -23.072 100.037 -26.272 100.837 C -29.472 101.637 -34.272 104.837 -35.072 98.437 C -35.872 92.037 -42.989 75.839 -75.073 101.637 C -98.782 120.474 -111.655 100.11 -111.655 100.11 L -115.655 107.237 C -137.455 70.437 -124.236 128.765 -124.236 128.765 C -115.436 163.165 16.128 121.637 16.128 121.637 C 16.128 121.637 184.928 91.237 196.129 87.237 C 207.329 83.237 299.911 89.419 299.911 89.419 L 294.529 71.092 C 229.729 24.691 212.929 49.637 199.329 45.637 C 185.728 41.637 188.128 51.237 184.928 52.037 C 181.728 52.837 142.528 28.037 136.128 28.837 z} -tags _tmp_transform -fill #ec9961 -stroke {} +$w create path {M 137.438 30.583 C 131.037 31.383 106.814 7.129 120.637 39.383 C 137.438 78.583 62.237 78.583 45.437 67.383 C 28.637 56.183 52.637 85.783 52.637 85.783 C 71.037 105.783 36.637 88.983 36.637 88.983 C 2.237 76.183 -21.763 101.783 -24.963 102.583 C -28.163 103.383 -32.963 106.583 -33.763 100.183 C -34.563 93.783 -41.548 77.752 -73.763 103.383 C -98.709 122.965 -111.273 103.146 -111.273 103.146 L -115.673 108.783 C -135.473 73.982 -123.582 131.819 -123.582 131.819 C -114.782 166.22 17.437 123.383 17.437 123.383 C 17.437 123.383 186.238 92.983 197.438 88.983 C 208.638 84.983 300.347 91.092 300.347 91.092 L 295.038 72.255 C 230.238 25.855 214.238 51.383 200.638 47.383 C 187.038 43.383 189.438 52.983 186.238 53.783 C 183.038 54.583 143.838 29.783 137.438 30.583 z} -tags _tmp_transform -fill #eea575 -stroke {} +$w create path {M 138.747 32.328 C 132.347 33.128 106.383 9.677 121.947 41.128 C 141.147 79.928 63.546 80.328 46.746 69.128 C 29.946 57.928 53.946 87.528 53.946 87.528 C 72.346 107.528 37.946 90.728 37.946 90.728 C 3.546 77.928 -20.454 103.528 -23.654 104.328 C -26.854 105.128 -31.654 108.328 -32.454 101.928 C -33.254 95.528 -40.108 79.665 -72.454 105.128 C -98.636 125.456 -110.891 106.183 -110.891 106.183 L -115.691 110.328 C -133.691 77.128 -122.927 134.874 -122.927 134.874 C -114.127 169.274 18.746 125.128 18.746 125.128 C 18.746 125.128 187.547 94.728 198.747 90.728 C 209.947 86.728 300.783 92.764 300.783 92.764 L 295.547 73.419 C 230.747 27.019 215.547 53.128 201.947 49.128 C 188.347 45.128 190.747 54.728 187.547 55.528 C 184.347 56.328 145.147 31.528 138.747 32.328 z} -tags _tmp_transform -fill #f1b288 -stroke {} +$w create path {M 140.056 34.073 C 133.655 34.873 107.313 11.613 123.255 42.873 C 143.656 82.874 64.855 82.074 48.055 70.874 C 31.255 59.674 55.255 89.274 55.255 89.274 C 73.655 109.274 39.255 92.474 39.255 92.474 C 4.855 79.674 -19.145 105.274 -22.345 106.074 C -25.545 106.874 -30.345 110.074 -31.145 103.674 C -31.945 97.274 -38.668 81.578 -71.145 106.874 C -98.564 127.947 -110.509 109.219 -110.509 109.219 L -115.709 111.874 C -131.709 81.674 -122.273 137.929 -122.273 137.929 C -113.473 172.329 20.055 126.874 20.055 126.874 C 20.055 126.874 188.856 96.474 200.056 92.474 C 211.256 88.474 301.22 94.437 301.22 94.437 L 296.056 74.583 C 231.256 28.183 216.856 54.874 203.256 50.874 C 189.656 46.873 192.056 56.474 188.856 57.274 C 185.656 58.074 146.456 33.273 140.056 34.073 z} -tags _tmp_transform -fill #f3bf9c -stroke {} +$w create path {M 141.365 35.819 C 134.965 36.619 107.523 13.944 124.565 44.619 C 146.565 84.219 66.164 83.819 49.364 72.619 C 32.564 61.419 56.564 91.019 56.564 91.019 C 74.964 111.019 40.564 94.219 40.564 94.219 C 6.164 81.419 -17.836 107.019 -21.036 107.819 C -24.236 108.619 -29.036 111.819 -29.836 105.419 C -30.636 99.019 -37.227 83.492 -69.836 108.619 C -98.491 130.438 -110.127 112.256 -110.127 112.256 L -115.727 113.419 C -130.128 85.019 -121.618 140.983 -121.618 140.983 C -112.818 175.384 21.364 128.619 21.364 128.619 C 21.364 128.619 190.165 98.219 201.365 94.219 C 212.565 90.219 301.656 96.11 301.656 96.11 L 296.565 75.746 C 231.765 29.346 218.165 56.619 204.565 52.619 C 190.965 48.619 193.365 58.219 190.165 59.019 C 186.965 59.819 147.765 35.019 141.365 35.819 z} -tags _tmp_transform -fill #f5ccb0 -stroke {} +$w create path {M 142.674 37.565 C 136.274 38.365 108.832 15.689 125.874 46.365 C 147.874 85.965 67.474 85.565 50.674 74.365 C 33.874 63.165 57.874 92.765 57.874 92.765 C 76.274 112.765 41.874 95.965 41.874 95.965 C 7.473 83.165 -16.527 108.765 -19.727 109.565 C -22.927 110.365 -27.727 113.565 -28.527 107.165 C -29.327 100.765 -35.786 85.405 -68.527 110.365 C -98.418 132.929 -109.745 115.293 -109.745 115.293 L -115.745 114.965 C -129.346 88.564 -120.963 144.038 -120.963 144.038 C -112.163 178.438 22.673 130.365 22.673 130.365 C 22.673 130.365 191.474 99.965 202.674 95.965 C 213.874 91.965 302.093 97.783 302.093 97.783 L 297.075 76.91 C 232.274 30.51 219.474 58.365 205.874 54.365 C 192.274 50.365 194.674 59.965 191.474 60.765 C 188.274 61.565 149.074 36.765 142.674 37.565 z} -tags _tmp_transform -fill #f8d8c4 -stroke {} +$w create path {M 143.983 39.31 C 137.583 40.11 110.529 17.223 127.183 48.11 C 149.183 88.91 68.783 87.31 51.983 76.11 C 35.183 64.91 59.183 94.51 59.183 94.51 C 77.583 114.51 43.183 97.71 43.183 97.71 C 8.783 84.91 -15.217 110.51 -18.417 111.31 C -21.618 112.11 -26.418 115.31 -27.218 108.91 C -28.018 102.51 -34.346 87.318 -67.218 112.11 C -98.345 135.42 -109.363 118.329 -109.363 118.329 L -115.764 116.51 C -128.764 92.51 -120.309 147.093 -120.309 147.093 C -111.509 181.493 23.983 132.11 23.983 132.11 C 23.983 132.11 192.783 101.71 203.983 97.71 C 215.183 93.71 302.529 99.456 302.529 99.456 L 297.583 78.074 C 232.783 31.673 220.783 60.11 207.183 56.11 C 193.583 52.11 195.983 61.71 192.783 62.51 C 189.583 63.31 150.383 38.51 143.983 39.31 z} -tags _tmp_transform -fill #fae5d7 -stroke {} +$w create path {M 145.292 41.055 C 138.892 41.855 112.917 18.411 128.492 49.855 C 149.692 92.656 70.092 89.056 53.292 77.856 C 36.492 66.656 60.492 96.256 60.492 96.256 C 78.892 116.256 44.492 99.456 44.492 99.456 C 10.092 86.656 -13.908 112.256 -17.108 113.056 C -20.308 113.856 -25.108 117.056 -25.908 110.656 C -26.708 104.256 -32.905 89.232 -65.908 113.856 C -98.273 137.911 -108.982 121.365 -108.982 121.365 L -115.782 118.056 C -128.582 94.856 -119.654 150.147 -119.654 150.147 C -110.854 184.547 25.292 133.856 25.292 133.856 C 25.292 133.856 194.093 103.456 205.293 99.456 C 216.493 95.456 302.965 101.128 302.965 101.128 L 298.093 79.237 C 233.292 32.837 222.093 61.856 208.493 57.856 C 194.893 53.855 197.293 63.456 194.093 64.256 C 190.892 65.056 151.692 40.255 145.292 41.055 z} -tags _tmp_transform -fill #fcf2eb -stroke {} +$w create path {M -115.8 119.601 C -128.6 97.6 -119 153.201 -119 153.201 C -110.2 187.601 26.6 135.601 26.6 135.601 C 26.6 135.601 195.401 105.2 206.601 101.2 C 217.801 97.2 303.401 102.8 303.401 102.8 L 298.601 80.4 C 233.801 34 223.401 63.6 209.801 59.6 C 196.201 55.6 198.601 65.2 195.401 66 C 192.201 66.8 153.001 42 146.601 42.8 C 140.201 43.6 114.981 19.793 129.801 51.6 C 152.028 99.307 69.041 89.227 54.6 79.6 C 37.8 68.4 61.8 98 61.8 98 C 80.2 118.001 45.8 101.2 45.8 101.2 C 11.4 88.4 -12.6 114.001 -15.8 114.801 C -19 115.601 -23.8 118.801 -24.6 112.401 C -25.4 106 -31.465 91.144 -64.6 115.601 C -98.2 140.401 -108.6 124.401 -108.6 124.401 L -115.8 119.601 z} -tags _tmp_transform -fill #ffffff -stroke {} +$w create path {M -74.2 149.601 C -74.2 149.601 -81.4 161.201 -60.6 174.401 C -60.6 174.401 -59.2 175.801 -77.2 171.601 C -77.2 171.601 -83.4 169.601 -85 159.201 C -85 159.201 -89.8 154.801 -94.6 149.201 C -99.4 143.601 -74.2 149.601 -74.2 149.601 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 65.8 102 C 65.8 102 83.498 128.821 82.9 133.601 C 81.6 144.001 81.4 153.601 84.6 157.601 C 87.801 161.601 96.601 194.801 96.601 194.801 C 96.601 194.801 96.201 196.001 108.601 158.001 C 108.601 158.001 120.201 142.001 100.201 123.601 C 100.201 123.601 65 94.8 65.8 102 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -54.2 176.401 C -54.2 176.401 -43 183.601 -57.4 214.801 L -51 212.401 C -51 212.401 -51.8 223.601 -55 226.001 L -47.8 222.801 C -47.8 222.801 -43 230.801 -47 235.601 C -47 235.601 -30.2 243.601 -31 250.001 C -31 250.001 -24.6 242.001 -28.6 235.601 C -32.6 229.201 -39.8 233.201 -39 214.801 L -47.8 218.001 C -47.8 218.001 -42.2 209.201 -42.2 202.801 L -50.2 205.201 C -50.2 205.201 -34.731 178.623 -45.4 177.201 C -51.4 176.401 -54.2 176.401 -54.2 176.401 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -21.8 193.201 C -21.8 193.201 -19 188.801 -21.8 189.601 C -24.6 190.401 -55.8 205.201 -61.8 214.801 C -61.8 214.801 -27.4 190.401 -21.8 193.201 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -11.4 201.201 C -11.4 201.201 -8.6 196.801 -11.4 197.601 C -14.2 198.401 -45.4 213.201 -51.4 222.801 C -51.4 222.801 -17 198.401 -11.4 201.201 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 1.8 186.001 C 1.8 186.001 4.6 181.601 1.8 182.401 C -1 183.201 -32.2 198.001 -38.2 207.601 C -38.2 207.601 -3.8 183.201 1.8 186.001 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -21.4 229.601 C -21.4 229.601 -21.4 223.601 -24.2 224.401 C -27 225.201 -63 242.801 -69 252.401 C -69 252.401 -27 226.801 -21.4 229.601 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -20.2 218.801 C -20.2 218.801 -19 214.001 -21.8 214.801 C -23.8 214.801 -50.2 226.401 -56.2 236.001 C -56.2 236.001 -26.6 214.401 -20.2 218.801 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -34.6 266.401 L -44.6 274.001 C -44.6 274.001 -34.2 266.401 -30.6 267.601 C -30.6 267.601 -37.4 278.801 -38.2 284.001 C -38.2 284.001 -27.8 271.201 -22.2 271.601 C -22.2 271.601 -14.6 272.001 -14.6 282.801 C -14.6 282.801 -9 272.401 -5.8 272.801 C -5.8 272.801 -4.6 279.201 -5.8 286.001 C -5.8 286.001 -1.8 278.401 2.2 280.001 C 2.2 280.001 8.6 278.001 7.8 289.601 C 7.8 289.601 7.8 300.001 7 302.801 C 7 302.801 12.6 276.401 15 276.001 C 15 276.001 23 274.801 27.8 283.601 C 27.8 283.601 23.8 276.001 28.6 278.001 C 28.6 278.001 39.4 279.601 42.6 286.401 C 42.6 286.401 35.8 274.401 41.4 277.601 C 41.4 277.601 48.2 277.601 49.4 284.001 C 49.4 284.001 57.8 305.201 59.8 306.801 C 59.8 306.801 52.2 285.201 53.8 285.201 C 53.8 285.201 51.8 273.201 57 288.001 C 57 288.001 53.8 274.001 59.4 274.801 C 65 275.601 69.4 285.601 77.8 283.201 C 77.8 283.201 87.401 288.801 89.401 219.601 L -34.6 266.401 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -29.8 173.601 C -29.8 173.601 -15 167.601 25 173.601 C 25 173.601 32.2 174.001 39 165.201 C 45.8 156.401 72.6 149.201 79 151.201 L 88.601 157.601 L 89.401 158.801 C 89.401 158.801 101.801 169.201 102.201 176.801 C 102.601 184.401 87.801 232.401 78.2 248.401 C 68.6 264.401 59 276.801 39.8 274.401 C 39.8 274.401 19 270.401 -6.6 274.401 C -6.6 274.401 -35.8 272.801 -38.6 264.801 C -41.4 256.801 -27.4 241.601 -27.4 241.601 C -27.4 241.601 -23 233.201 -24.2 218.801 C -25.4 204.401 -25 176.401 -29.8 173.601 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -7.8 175.601 C 0.6 194.001 -29 259.201 -29 259.201 C -31 260.801 -16.34 266.846 -6.2 264.401 C 4.746 261.763 45 266.001 45 266.001 C 68.6 250.401 81.4 206.001 81.4 206.001 C 81.4 206.001 91.801 182.001 74.2 178.801 C 56.6 175.601 -7.8 175.601 -7.8 175.601 z} -tags _tmp_transform -fill #e5668c -stroke {} +$w create path {M -9.831 206.497 C -6.505 193.707 -4.921 181.906 -7.8 175.601 C -7.8 175.601 54.6 182.001 65.8 161.201 C 70.041 153.326 84.801 184.001 84.4 193.601 C 84.4 193.601 21.4 208.001 6.6 196.801 L -9.831 206.497 z} -tags _tmp_transform -fill #b23259 -stroke {} +$w create path {M -5.4 222.801 C -5.4 222.801 -3.4 230.001 -5.8 234.001 C -5.8 234.001 -7.4 234.801 -8.6 235.201 C -8.6 235.201 -7.4 238.801 -1.4 240.401 C -1.4 240.401 0.6 244.801 3 245.201 C 5.4 245.601 10.2 251.201 14.2 250.001 C 18.2 248.801 29.4 244.801 29.4 244.801 C 29.4 244.801 35 241.601 43.8 245.201 C 43.8 245.201 46.175 244.399 46.6 240.401 C 47.1 235.701 50.2 232.001 52.2 230.001 C 54.2 228.001 63.8 215.201 62.6 214.801 C 61.4 214.401 -5.4 222.801 -5.4 222.801 z} -tags _tmp_transform -fill #a5264c -stroke {} +$w create path {M -9.8 174.401 C -9.8 174.401 -12.6 196.801 -9.4 205.201 C -6.2 213.601 -7 215.601 -7.8 219.601 C -8.6 223.601 -4.2 233.601 1.4 239.601 L 13.4 241.201 C 13.4 241.201 28.6 237.601 37.8 240.401 C 37.8 240.401 46.794 241.744 50.2 226.801 C 50.2 226.801 55 220.401 62.2 217.601 C 69.4 214.801 76.6 173.201 72.6 165.201 C 68.6 157.201 54.2 152.801 38.2 168.401 C 22.2 184.001 20.2 167.201 -9.8 174.401 z} -tags _tmp_transform -fill #ff727f -stroke #000000 +$w create path {M -8.2 249.201 C -8.2 249.201 -9 247.201 -13.4 246.801 C -13.4 246.801 -35.8 243.201 -44.2 230.801 C -44.2 230.801 -51 225.201 -46.6 236.801 C -46.6 236.801 -36.2 257.201 -29.4 260.001 C -29.4 260.001 -13 264.001 -8.2 249.201 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M 71.742 185.229 C 72.401 177.323 74.354 168.709 72.6 165.201 C 66.154 152.307 49.181 157.695 38.2 168.401 C 22.2 184.001 20.2 167.201 -9.8 174.401 C -9.8 174.401 -11.545 188.364 -10.705 198.376 C -10.705 198.376 26.6 186.801 27.4 192.401 C 27.4 192.401 29 189.201 38.2 189.201 C 47.4 189.201 70.142 188.029 71.742 185.229 z} -tags _tmp_transform -fill #cc3f4c -stroke {} +$w create path {M 28.6 175.201 C 28.6 175.201 33.4 180.001 29.8 189.601 C 29.8 189.601 15.4 205.601 17.4 219.601} -tags _tmp_transform -fill black -stroke #a51926 +$w create path {M -19.4 260.001 C -19.4 260.001 -23.8 247.201 -15 254.001 C -15 254.001 -10.2 256.001 -11.4 257.601 C -12.6 259.201 -18.2 263.201 -19.4 260.001 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -14.36 261.201 C -14.36 261.201 -17.88 250.961 -10.84 256.401 C -10.84 256.401 -6.419 258.849 -7.96 259.281 C -12.52 260.561 -7.96 263.121 -14.36 261.201 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -9.56 261.201 C -9.56 261.201 -13.08 250.961 -6.04 256.401 C -6.04 256.401 -1.665 258.711 -3.16 259.281 C -6.52 260.561 -3.16 263.121 -9.56 261.201 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -2.96 261.401 C -2.96 261.401 -6.48 251.161 0.56 256.601 C 0.56 256.601 4.943 258.933 3.441 259.481 C 0.48 260.561 3.441 263.321 -2.96 261.401 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M 3.52 261.321 C 3.52 261.321 0 251.081 7.041 256.521 C 7.041 256.521 10.881 258.121 9.921 259.401 C 8.961 260.681 9.921 263.241 3.52 261.321 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M 10.2 262.001 C 10.2 262.001 5.4 249.601 14.6 256.001 C 14.6 256.001 19.4 258.001 18.2 259.601 C 17 261.201 18.2 264.401 10.2 262.001 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -18.2 244.801 C -18.2 244.801 -5 242.001 1 245.201 C 1 245.201 7 246.401 8.2 246.001 C 9.4 245.601 12.6 245.201 12.6 245.201} -tags _tmp_transform -fill black -stroke #a5264c +$w create path {M 15.8 253.601 C 15.8 253.601 27.8 240.001 39.8 244.401 C 46.816 246.974 45.8 243.601 46.6 240.801 C 47.4 238.001 47.6 233.801 52.6 230.801} -tags _tmp_transform -fill black -stroke #a5264c +$w create path {M 33 237.601 C 33 237.601 29 226.801 26.2 239.601 C 23.4 252.401 20.2 256.001 18.6 258.801 C 18.6 258.801 18.6 264.001 27 263.601 C 27 263.601 37.8 263.201 38.2 260.401 C 38.6 257.601 37 246.001 33 237.601 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M 47 244.801 C 47 244.801 50.6 242.401 53 243.601} -tags _tmp_transform -fill black -stroke #a5264c +$w create path {M 53.5 228.401 C 53.5 228.401 56.4 223.501 61.2 222.701} -tags _tmp_transform -fill black -stroke #a5264c +$w create path {M -25.8 265.201 C -25.8 265.201 -7.8 268.401 -3.4 266.801 C -3.4 266.801 5.4 266.801 -3 268.801 C -3 268.801 -15.8 268.801 -23.8 267.601 C -23.8 267.601 -35.4 262.001 -25.8 265.201 z} -tags _tmp_transform -fill #b2b2b2 -stroke {} +$w create path {M -11.8 172.001 C -11.8 172.001 5.8 172.001 7.8 172.801 C 7.8 172.801 15 203.601 11.4 211.201 C 11.4 211.201 10.2 214.001 7.4 208.401 C 7.4 208.401 -11 175.601 -14.2 173.601 C -17.4 171.601 -13 172.001 -11.8 172.001 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -88.9 169.301 C -88.9 169.301 -80 171.001 -67.4 173.601 C -67.4 173.601 -62.6 196.001 -59.4 200.801 C -56.2 205.601 -59.8 205.601 -63.4 202.801 C -67 200.001 -81.8 186.001 -83.8 181.601 C -85.8 177.201 -88.9 169.301 -88.9 169.301 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -67.039 173.818 C -67.039 173.818 -61.239 175.366 -60.23 177.581 C -59.222 179.795 -61.432 183.092 -61.432 183.092 C -61.432 183.092 -62.432 186.397 -63.634 184.235 C -64.836 182.072 -67.708 174.412 -67.039 173.818 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -67 173.601 C -67 173.601 -63.4 178.801 -59.8 178.801 C -56.2 178.801 -55.818 178.388 -53 179.001 C -48.4 180.001 -48.8 178.001 -42.2 179.201 C -39.56 179.681 -37 178.801 -34.2 180.001 C -31.4 181.201 -28.2 180.401 -27 178.401 C -25.8 176.401 -21 172.201 -21 172.201 C -21 172.201 -33.8 174.001 -36.6 174.801 C -36.6 174.801 -59 176.001 -67 173.601 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -22.4 173.801 C -22.4 173.801 -28.85 177.301 -29.25 179.701 C -29.65 182.101 -24 185.801 -24 185.801 C -24 185.801 -21.25 190.401 -20.65 188.001 C -20.05 185.601 -21.6 174.201 -22.4 173.801 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -59.885 179.265 C -59.885 179.265 -52.878 190.453 -52.661 179.242 C -52.661 179.242 -52.104 177.984 -53.864 177.962 C -59.939 177.886 -58.418 173.784 -59.885 179.265 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -52.707 179.514 C -52.707 179.514 -44.786 190.701 -45.422 179.421 C -45.422 179.421 -45.415 179.089 -47.168 178.936 C -51.915 178.522 -51.57 174.004 -52.707 179.514 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -45.494 179.522 C -45.494 179.522 -37.534 190.15 -38.203 180.484 C -38.203 180.484 -38.084 179.251 -39.738 178.95 C -43.63 178.244 -43.841 174.995 -45.494 179.522 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -38.618 179.602 C -38.618 179.602 -30.718 191.163 -30.37 181.382 C -30.37 181.382 -28.726 180.004 -30.472 179.782 C -36.29 179.042 -35.492 174.588 -38.618 179.602 z} -tags _tmp_transform -fill #ffffcc -stroke #000000 +$w create path {M -74.792 183.132 L -82.45 181.601 C -85.05 176.601 -87.15 170.451 -87.15 170.451 C -87.15 170.451 -80.8 171.451 -68.3 174.251 C -68.3 174.251 -67.424 177.569 -65.952 183.364 L -74.792 183.132 z} -tags _tmp_transform -fill #e5e5b2 -stroke {} +$w create path {M -9.724 178.47 C -11.39 175.964 -12.707 174.206 -13.357 173.8 C -16.37 171.917 -12.227 172.294 -11.098 172.294 C -11.098 172.294 5.473 172.294 7.356 173.047 C 7.356 173.047 7.88 175.289 8.564 178.68 C 8.564 178.68 -1.524 176.67 -9.724 178.47 z} -tags _tmp_transform -fill #e5e5b2 -stroke {} +$w create path {M 43.88 40.321 C 71.601 44.281 97.121 8.641 98.881 -1.04 C 100.641 -10.72 90.521 -22.6 90.521 -22.6 C 91.841 -25.68 87.001 -39.76 81.721 -49 C 76.441 -58.24 60.54 -57.266 43 -58.24 C 27.16 -59.12 8.68 -35.8 7.36 -34.04 C 6.04 -32.28 12.2 6.001 13.52 11.721 C 14.84 17.441 12.2 43.841 12.2 43.841 C 46.44 34.741 16.16 36.361 43.88 40.321 z} -tags _tmp_transform -fill #cc7226 -stroke {} +$w create path {M 8.088 -33.392 C 6.792 -31.664 12.84 5.921 14.136 11.537 C 15.432 17.153 12.84 43.073 12.84 43.073 C 45.512 34.193 16.728 35.729 43.944 39.617 C 71.161 43.505 96.217 8.513 97.945 -0.992 C 99.673 -10.496 89.737 -22.16 89.737 -22.16 C 91.033 -25.184 86.281 -39.008 81.097 -48.08 C 75.913 -57.152 60.302 -56.195 43.08 -57.152 C 27.528 -58.016 9.384 -35.12 8.088 -33.392 z} -tags _tmp_transform -fill #ea8e51 -stroke {} +$w create path {M 8.816 -32.744 C 7.544 -31.048 13.48 5.841 14.752 11.353 C 16.024 16.865 13.48 42.305 13.48 42.305 C 44.884 33.145 17.296 35.097 44.008 38.913 C 70.721 42.729 95.313 8.385 97.009 -0.944 C 98.705 -10.272 88.953 -21.72 88.953 -21.72 C 90.225 -24.688 85.561 -38.256 80.473 -47.16 C 75.385 -56.064 60.063 -55.125 43.16 -56.064 C 27.896 -56.912 10.088 -34.44 8.816 -32.744 z} -tags _tmp_transform -fill #efaa7c -stroke {} +$w create path {M 9.544 -32.096 C 8.296 -30.432 14.12 5.761 15.368 11.169 C 16.616 16.577 14.12 41.537 14.12 41.537 C 43.556 32.497 17.864 34.465 44.072 38.209 C 70.281 41.953 94.409 8.257 96.073 -0.895 C 97.737 -10.048 88.169 -21.28 88.169 -21.28 C 89.417 -24.192 84.841 -37.504 79.849 -46.24 C 74.857 -54.976 59.824 -54.055 43.24 -54.976 C 28.264 -55.808 10.792 -33.76 9.544 -32.096 z} -tags _tmp_transform -fill #f4c6a8 -stroke {} +$w create path {M 10.272 -31.448 C 9.048 -29.816 14.76 5.681 15.984 10.985 C 17.208 16.289 14.76 40.769 14.76 40.769 C 42.628 31.849 18.432 33.833 44.136 37.505 C 69.841 41.177 93.505 8.129 95.137 -0.848 C 96.769 -9.824 87.385 -20.84 87.385 -20.84 C 88.609 -23.696 84.121 -36.752 79.225 -45.32 C 74.329 -53.888 59.585 -52.985 43.32 -53.888 C 28.632 -54.704 11.496 -33.08 10.272 -31.448 z} -tags _tmp_transform -fill #f9e2d3 -stroke {} +$w create path {M 44.2 36.8 C 69.4 40.4 92.601 8 94.201 -0.8 C 95.801 -9.6 86.601 -20.4 86.601 -20.4 C 87.801 -23.2 83.4 -36 78.6 -44.4 C 73.8 -52.8 59.346 -51.914 43.4 -52.8 C 29 -53.6 12.2 -32.4 11 -30.8 C 9.8 -29.2 15.4 5.6 16.6 10.8 C 17.8 16 15.4 40 15.4 40 C 40.9 31.4 19 33.2 44.2 36.8 z} -tags _tmp_transform -fill #ffffff -stroke {} +$w create path {M 90.601 2.8 C 90.601 2.8 62.8 10.4 51.2 8.8 C 51.2 8.8 35.4 2.2 26.6 24 C 26.6 24 23 31.2 21 33.2 C 19 35.2 90.601 2.8 90.601 2.8 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 94.401 0.6 C 94.401 0.6 65.4 12.8 55.4 12.4 C 55.4 12.4 39 7.8 30.6 22.4 C 30.6 22.4 22.2 31.6 19 33.2 C 19 33.2 18.6 34.8 25 30.8 L 35.4 36 C 35.4 36 50.2 45.6 59.8 29.6 C 59.8 29.6 63.8 18.4 63.8 16.4 C 63.8 14.4 85 8.8 86.601 8.4 C 88.201 8 94.801 3.8 94.401 0.6 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 47 36.514 C 40.128 36.514 31.755 32.649 31.755 26.4 C 31.755 20.152 40.128 13.887 47 13.887 C 53.874 13.887 59.446 18.952 59.446 25.2 C 59.446 31.449 53.874 36.514 47 36.514 z} -tags _tmp_transform -fill #99cc32 -stroke {} +$w create path {M 43.377 19.83 C 38.531 20.552 33.442 22.055 33.514 21.839 C 35.054 17.22 41.415 13.887 47 13.887 C 51.296 13.887 55.084 15.865 57.32 18.875 C 57.32 18.875 52.004 18.545 43.377 19.83 z} -tags _tmp_transform -fill #659900 -stroke {} +$w create path {M 55.4 19.6 C 55.4 19.6 51 16.4 51 18.6 C 51 18.6 54.6 23 55.4 19.6 z} -tags _tmp_transform -fill #ffffff -stroke {} +$w create path {M 45.4 27.726 C 42.901 27.726 40.875 25.7 40.875 23.2 C 40.875 20.701 42.901 18.675 45.4 18.675 C 47.9 18.675 49.926 20.701 49.926 23.2 C 49.926 25.7 47.9 27.726 45.4 27.726 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -58.6 14.4 C -58.6 14.4 -61.8 -6.8 -59.4 -11.2 C -59.4 -11.2 -48.6 -21.2 -49 -24.8 C -49 -24.8 -49.4 -42.8 -50.6 -43.6 C -51.8 -44.4 -59.4 -50.4 -65.4 -44 C -65.4 -44 -75.8 -26 -75 -19.6 L -75 -17.6 C -75 -17.6 -82.6 -18 -84.2 -16 C -84.2 -16 -85.4 -10.8 -86.6 -10.4 C -86.6 -10.4 -89.4 -8 -87.4 -5.2 C -87.4 -5.2 -89.4 -2.8 -89 1.2 L -81.4 5.2 C -81.4 5.2 -79.4 19.6 -68.6 24.8 C -63.764 27.129 -60.6 20.4 -58.6 14.4 z} -tags _tmp_transform -fill #cc7226 -stroke {} +$w create path {M -59.6 12.56 C -59.6 12.56 -62.48 -6.52 -60.32 -10.48 C -60.32 -10.48 -50.6 -19.48 -50.96 -22.72 C -50.96 -22.72 -51.32 -38.92 -52.4 -39.64 C -53.48 -40.36 -60.32 -45.76 -65.72 -40 C -65.72 -40 -75.08 -23.8 -74.36 -18.04 L -74.36 -16.24 C -74.36 -16.24 -81.2 -16.6 -82.64 -14.8 C -82.64 -14.8 -83.72 -10.12 -84.8 -9.76 C -84.8 -9.76 -87.32 -7.6 -85.52 -5.08 C -85.52 -5.08 -87.32 -2.92 -86.96 0.68 L -80.12 4.28 C -80.12 4.28 -78.32 17.24 -68.6 21.92 C -64.248 24.015 -61.4 17.96 -59.6 12.56 z} -tags _tmp_transform -fill #ffffff -stroke {} +$w create path {M -51.05 -42.61 C -52.14 -43.47 -59.63 -49.24 -65.48 -43 C -65.48 -43 -75.62 -25.45 -74.84 -19.21 L -74.84 -17.26 C -74.84 -17.26 -82.25 -17.65 -83.81 -15.7 C -83.81 -15.7 -84.98 -10.63 -86.15 -10.24 C -86.15 -10.24 -88.88 -7.9 -86.93 -5.17 C -86.93 -5.17 -88.88 -2.83 -88.49 1.07 L -81.08 4.97 C -81.08 4.97 -79.13 19.01 -68.6 24.08 C -63.886 26.35 -60.8 19.79 -58.85 13.94 C -58.85 13.94 -61.97 -6.73 -59.63 -11.02 C -59.63 -11.02 -49.1 -20.77 -49.49 -24.28 C -49.49 -24.28 -49.88 -41.83 -51.05 -42.61 z} -tags _tmp_transform -fill #eb955c -stroke {} +$w create path {M -51.5 -41.62 C -52.48 -42.54 -59.86 -48.08 -65.56 -42 C -65.56 -42 -75.44 -24.9 -74.68 -18.82 L -74.68 -16.92 C -74.68 -16.92 -81.9 -17.3 -83.42 -15.4 C -83.42 -15.4 -84.56 -10.46 -85.7 -10.08 C -85.7 -10.08 -88.36 -7.8 -86.46 -5.14 C -86.46 -5.14 -88.36 -2.86 -87.98 0.94 L -80.76 4.74 C -80.76 4.74 -78.86 18.42 -68.6 23.36 C -64.006 25.572 -61 19.18 -59.1 13.48 C -59.1 13.48 -62.14 -6.66 -59.86 -10.84 C -59.86 -10.84 -49.6 -20.34 -49.98 -23.76 C -49.98 -23.76 -50.36 -40.86 -51.5 -41.62 z} -tags _tmp_transform -fill #f2b892 -stroke {} +$w create path {M -51.95 -40.63 C -52.82 -41.61 -60.09 -46.92 -65.64 -41 C -65.64 -41 -75.26 -24.35 -74.52 -18.43 L -74.52 -16.58 C -74.52 -16.58 -81.55 -16.95 -83.03 -15.1 C -83.03 -15.1 -84.14 -10.29 -85.25 -9.92 C -85.25 -9.92 -87.84 -7.7 -85.99 -5.11 C -85.99 -5.11 -87.84 -2.89 -87.47 0.81 L -80.44 4.51 C -80.44 4.51 -78.59 17.83 -68.6 22.64 C -64.127 24.794 -61.2 18.57 -59.35 13.02 C -59.35 13.02 -62.31 -6.59 -60.09 -10.66 C -60.09 -10.66 -50.1 -19.91 -50.47 -23.24 C -50.47 -23.24 -50.84 -39.89 -51.95 -40.63 z} -tags _tmp_transform -fill #f8dcc8 -stroke {} +$w create path {M -59.6 12.46 C -59.6 12.46 -62.48 -6.52 -60.32 -10.48 C -60.32 -10.48 -50.6 -19.48 -50.96 -22.72 C -50.96 -22.72 -51.32 -38.92 -52.4 -39.64 C -53.16 -40.68 -60.32 -45.76 -65.72 -40 C -65.72 -40 -75.08 -23.8 -74.36 -18.04 L -74.36 -16.24 C -74.36 -16.24 -81.2 -16.6 -82.64 -14.8 C -82.64 -14.8 -83.72 -10.12 -84.8 -9.76 C -84.8 -9.76 -87.32 -7.6 -85.52 -5.08 C -85.52 -5.08 -87.32 -2.92 -86.96 0.68 L -80.12 4.28 C -80.12 4.28 -78.32 17.24 -68.6 21.92 C -64.248 24.015 -61.4 17.86 -59.6 12.46 z} -tags _tmp_transform -fill #ffffff -stroke {} +$w create path {M -62.7 6.2 C -62.7 6.2 -84.3 -4 -85.2 -4.8 C -85.2 -4.8 -76.1 3.4 -75.3 3.4 C -74.5 3.4 -62.7 6.2 -62.7 6.2 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -79.8 0 C -79.8 0 -61.4 3.6 -61.4 8 C -61.4 10.912 -61.643 24.331 -67 22.8 C -75.4 20.4 -71.8 6 -79.8 0 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -71.4 3.8 C -71.4 3.8 -62.422 5.274 -61.4 8 C -60.8 9.6 -60.137 17.908 -65.6 19 C -70.152 19.911 -72.382 9.69 -71.4 3.8 z} -tags _tmp_transform -fill #99cc32 -stroke {} +$w create path {M 14.595 46.349 C 14.098 44.607 15.409 44.738 17.2 44.2 C 19.2 43.6 31.4 39.8 32.2 37.2 C 33 34.6 46.2 39 46.2 39 C 48 39.8 52.4 42.4 52.4 42.4 C 57.2 43.6 63.8 44 63.8 44 C 66.2 45 69.6 47.8 69.6 47.8 C 84.2 58 96.601 50.8 96.601 50.8 C 116.601 44.2 110.601 27 110.601 27 C 107.601 18 110.801 14.6 110.801 14.6 C 111.001 10.8 118.201 17.2 118.201 17.2 C 120.801 21.4 121.601 26.4 121.601 26.4 C 129.601 37.6 126.201 19.8 126.201 19.8 C 126.401 18.8 123.601 15.2 123.601 14 C 123.601 12.8 121.801 9.4 121.801 9.4 C 118.801 6 121.201 -1 121.201 -1 C 123.001 -14.8 120.801 -13 120.801 -13 C 119.601 -14.8 110.401 -4.8 110.401 -4.8 C 108.201 -1.4 102.201 0.2 102.201 0.2 C 99.401 2 96.001 0.6 96.001 0.6 C 93.401 0.2 87.801 7.2 87.801 7.2 C 90.601 7 93.001 11.4 95.401 11.6 C 97.801 11.8 99.601 9.2 101.201 8.6 C 102.801 8 105.601 13.8 105.601 13.8 C 106.001 16.4 100.401 21.2 100.401 21.2 C 100.001 25.8 98.401 24.2 98.401 24.2 C 95.401 23.6 94.201 27.4 93.201 32 C 92.201 36.6 88.001 37 88.001 37 C 86.401 44.4 85.2 41.4 85.2 41.4 C 85 35.8 79 41.6 79 41.6 C 77.8 43.6 73.2 41.4 73.2 41.4 C 66.4 39.4 68.8 37.4 68.8 37.4 C 70.6 35.2 81.8 37.4 81.8 37.4 C 84 35.8 76 31.8 76 31.8 C 75.4 30 76.4 25.6 76.4 25.6 C 77.6 22.4 84.4 16.8 84.4 16.8 C 93.801 15.6 91.001 14 91.001 14 C 84.801 8.8 79 16.4 79 16.4 C 76.8 22.6 59.4 37.6 59.4 37.6 C 54.6 41 57.2 34.2 53.2 37.6 C 49.2 41 28.6 32 28.6 32 C 17.038 30.807 14.306 46.549 10.777 43.429 C 10.777 43.429 16.195 51.949 14.595 46.349 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 209.401 -120 C 209.401 -120 183.801 -112 181.001 -93.2 C 181.001 -93.2 178.601 -70.4 199.001 -52.8 C 199.001 -52.8 199.401 -46.4 201.401 -43.2 C 201.401 -43.2 199.801 -38.4 218.601 -46 L 245.801 -54.4 C 245.801 -54.4 252.201 -56.8 257.401 -65.6 C 262.601 -74.4 277.801 -93.2 274.201 -118.4 C 274.201 -118.4 275.401 -129.6 269.401 -130 C 269.401 -130 261.001 -131.6 253.801 -124 C 253.801 -124 247.001 -120.8 244.601 -121.2 L 209.401 -120 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 264.022 -120.99 C 264.022 -120.99 266.122 -129.92 261.282 -125.08 C 261.282 -125.08 254.242 -119.36 246.761 -119.36 C 246.761 -119.36 232.241 -117.16 227.841 -103.96 C 227.841 -103.96 223.881 -77.12 231.801 -71.4 C 231.801 -71.4 236.641 -63.92 243.681 -70.52 C 250.722 -77.12 266.222 -107.35 264.022 -120.99 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 263.648 -120.632 C 263.648 -120.632 265.738 -129.376 260.986 -124.624 C 260.986 -124.624 254.074 -119.008 246.729 -119.008 C 246.729 -119.008 232.473 -116.848 228.153 -103.888 C 228.153 -103.888 224.265 -77.536 232.041 -71.92 C 232.041 -71.92 236.793 -64.576 243.705 -71.056 C 250.618 -77.536 265.808 -107.24 263.648 -120.632 z} -tags _tmp_transform -fill #323232 -stroke {} +$w create path {M 263.274 -120.274 C 263.274 -120.274 265.354 -128.832 260.69 -124.168 C 260.69 -124.168 253.906 -118.656 246.697 -118.656 C 246.697 -118.656 232.705 -116.536 228.465 -103.816 C 228.465 -103.816 224.649 -77.952 232.281 -72.44 C 232.281 -72.44 236.945 -65.232 243.729 -71.592 C 250.514 -77.952 265.394 -107.13 263.274 -120.274 z} -tags _tmp_transform -fill #666666 -stroke {} +$w create path {M 262.9 -119.916 C 262.9 -119.916 264.97 -128.288 260.394 -123.712 C 260.394 -123.712 253.738 -118.304 246.665 -118.304 C 246.665 -118.304 232.937 -116.224 228.777 -103.744 C 228.777 -103.744 225.033 -78.368 232.521 -72.96 C 232.521 -72.96 237.097 -65.888 243.753 -72.128 C 250.41 -78.368 264.98 -107.02 262.9 -119.916 z} -tags _tmp_transform -fill #999999 -stroke {} +$w create path {M 262.526 -119.558 C 262.526 -119.558 264.586 -127.744 260.098 -123.256 C 260.098 -123.256 253.569 -117.952 246.633 -117.952 C 246.633 -117.952 233.169 -115.912 229.089 -103.672 C 229.089 -103.672 225.417 -78.784 232.761 -73.48 C 232.761 -73.48 237.249 -66.544 243.777 -72.664 C 250.305 -78.784 264.566 -106.91 262.526 -119.558 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 262.151 -119.2 C 262.151 -119.2 264.201 -127.2 259.801 -122.8 C 259.801 -122.8 253.401 -117.6 246.601 -117.6 C 246.601 -117.6 233.401 -115.6 229.401 -103.6 C 229.401 -103.6 225.801 -79.2 233.001 -74 C 233.001 -74 237.401 -67.2 243.801 -73.2 C 250.201 -79.2 264.151 -106.8 262.151 -119.2 z} -tags _tmp_transform -fill #ffffff -stroke {} +$w create path {M 50.6 84 C 50.6 84 30.2 64.8 22.2 64 C 22.2 64 -12.2 60 -27 78 C -27 78 -9.4 57.6 18.2 63.2 C 18.2 63.2 -3.4 58.8 -15.8 62 C -15.8 62 -32.6 62 -42.2 76 L -45 80.8 C -45 80.8 -41 66 -22.6 60 C -22.6 60 0.2 55.2 11 60 C 11 60 -10.6 53.2 -20.6 55.2 C -20.6 55.2 -51 52.8 -63.8 79.2 C -63.8 79.2 -59.8 64.8 -45 57.6 C -45 57.6 -31.4 48.8 -11 51.6 C -11 51.6 3.4 54.8 8.6 57.2 C 13.8 59.6 12.6 56.8 4.2 52 C 4.2 52 -1.4 42 -15.4 42.4 C -15.4 42.4 -58.2 46 -68.6 58 C -68.6 58 -55 46.8 -44.6 44 C -44.6 44 -22.2 36 -13.8 36.8 C -13.8 36.8 11 37.8 18.6 33.8 C 18.6 33.8 7.4 38.8 10.6 42 C 13.8 45.2 20.6 52.8 20.6 54 C 20.6 55.2 44.8 77.3 48.4 81.7 L 50.6 84 z} -tags _tmp_transform -fill #992600 -stroke {} +$w create path {M 189 278 C 189 278 173.5 241.5 161 232 C 161 232 187 248 190.5 266 C 190.5 266 190.5 276 189 278 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 236 285.5 C 236 285.5 209.5 230.5 191 206.5 C 191 206.5 234.5 244 239.5 270.5 L 240 276 L 237 273.5 C 237 273.5 236.5 282.5 236 285.5 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 292.5 237 C 292.5 237 230 177.5 228.5 175 C 228.5 175 289 241 292 248.5 C 292 248.5 290 239.5 292.5 237 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 104 280.5 C 104 280.5 123.5 228.5 142.5 251 C 142.5 251 157.5 261 157 264 C 157 264 153 257.5 135 258 C 135 258 116 255 104 280.5 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 294.5 153 C 294.5 153 249.5 124.5 242 123 C 230.193 120.639 291.5 152 296.5 162.5 C 296.5 162.5 298.5 160 294.5 153 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 143.801 259.601 C 143.801 259.601 164.201 257.601 171.001 250.801 L 175.401 254.401 L 193.001 216.001 L 196.601 221.201 C 196.601 221.201 211.001 206.401 210.201 198.401 C 209.401 190.401 223.001 204.401 223.001 204.401 C 223.001 204.401 222.201 192.801 229.401 199.601 C 229.401 199.601 227.001 184.001 235.401 192.001 C 235.401 192.001 224.864 161.844 247.401 187.601 C 253.001 194.001 248.601 187.201 248.601 187.201 C 248.601 187.201 222.601 139.201 244.201 153.601 C 244.201 153.601 246.201 130.801 245.001 126.401 C 243.801 122.001 241.801 99.6 237.001 94.4 C 232.201 89.2 237.401 87.6 243.001 92.8 C 243.001 92.8 231.801 68.8 245.001 80.8 C 245.001 80.8 241.401 65.6 237.001 62.8 C 237.001 62.8 231.401 45.6 246.601 56.4 C 246.601 56.4 242.201 44 239.001 40.8 C 239.001 40.8 227.401 13.2 234.601 18 L 239.001 21.6 C 239.001 21.6 232.201 7.6 238.601 12 C 245.001 16.4 245.001 16 245.001 16 C 245.001 16 223.801 -17.2 244.201 0.4 C 244.201 0.4 236.042 -13.518 232.601 -20.4 C 232.601 -20.4 213.801 -40.8 228.201 -34.4 L 233.001 -32.8 C 233.001 -32.8 224.201 -42.8 216.201 -44.4 C 208.201 -46 218.601 -52.4 225.001 -50.4 C 231.401 -48.4 247.001 -40.8 247.001 -40.8 C 247.001 -40.8 259.801 -22 263.801 -21.6 C 263.801 -21.6 243.801 -29.2 249.801 -21.2 C 249.801 -21.2 264.201 -7.2 257.001 -7.6 C 257.001 -7.6 251.001 -0.4 255.801 8.4 C 255.801 8.4 237.342 -9.991 252.201 15.6 L 259.001 32 C 259.001 32 234.601 7.2 245.801 29.2 C 245.801 29.2 263.001 52.8 265.001 53.2 C 267.001 53.6 271.401 62.4 271.401 62.4 L 267.001 60.4 L 272.201 69.2 C 272.201 69.2 261.001 57.2 267.001 70.4 L 272.601 84.8 C 272.601 84.8 252.201 62.8 265.801 92.4 C 265.801 92.4 249.401 87.2 258.201 104.4 C 258.201 104.4 256.601 120.401 257.001 125.601 C 257.401 130.801 258.601 159.201 254.201 167.201 C 249.801 175.201 260.201 194.401 262.201 198.401 C 264.201 202.401 267.801 213.201 259.001 204.001 C 250.201 194.801 254.601 200.401 256.601 209.201 C 258.601 218.001 264.601 233.601 263.801 239.201 C 263.801 239.201 262.601 240.401 259.401 236.801 C 259.401 236.801 244.601 214.001 246.201 228.401 C 246.201 228.401 245.001 236.401 241.801 245.201 C 241.801 245.201 238.601 256.001 238.601 247.201 C 238.601 247.201 235.401 230.401 232.601 238.001 C 229.801 245.601 226.201 251.601 223.401 254.001 C 220.601 256.401 215.401 233.601 214.201 244.001 C 214.201 244.001 202.201 231.601 197.401 248.001 L 185.801 264.401 C 185.801 264.401 185.401 252.001 184.201 258.001 C 184.201 258.001 154.201 264.001 143.801 259.601 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 109.401 -97.2 C 109.401 -97.2 97.801 -105.2 93.801 -104.8 C 89.801 -104.4 121.401 -113.6 162.601 -86 C 162.601 -86 167.401 -83.2 171.001 -83.6 C 171.001 -83.6 174.201 -81.2 171.401 -77.6 C 171.401 -77.6 162.601 -68 173.801 -56.8 C 173.801 -56.8 192.201 -50 186.601 -58.8 C 186.601 -58.8 197.401 -54.8 199.801 -50.8 C 202.201 -46.8 201.001 -50.8 201.001 -50.8 C 201.001 -50.8 194.601 -58 188.601 -63.2 C 188.601 -63.2 183.401 -65.2 180.601 -73.6 C 177.801 -82 175.401 -92 179.801 -95.2 C 179.801 -95.2 175.801 -90.8 176.601 -94.8 C 177.401 -98.8 181.001 -102.4 182.601 -102.8 C 184.201 -103.2 200.601 -119 207.401 -119.4 C 207.401 -119.4 198.201 -118 195.201 -119 C 192.201 -120 165.601 -131.4 159.601 -132.6 C 159.601 -132.6 142.801 -139.2 154.801 -137.2 C 154.801 -137.2 190.601 -133.4 208.801 -120.2 C 208.801 -120.2 201.601 -128.6 183.201 -135.6 C 183.201 -135.6 161.001 -148.2 125.801 -143.2 C 125.801 -143.2 108.001 -140 100.201 -138.2 C 100.201 -138.2 97.601 -138.8 97.001 -139.2 C 96.401 -139.6 84.6 -148.6 57 -141.6 C 57 -141.6 40 -137 31.4 -132.2 C 31.4 -132.2 16.2 -131 12.6 -127.8 C 12.6 -127.8 -6 -113.2 -8 -112.4 C -10 -111.6 -21.4 -104 -22.2 -103.6 C -22.2 -103.6 2.4 -110.2 4.8 -112.6 C 7.2 -115 24.6 -117.6 27 -116.2 C 29.4 -114.8 37.8 -115.4 28.2 -114.8 C 28.2 -114.8 103.801 -100 104.601 -98 C 105.401 -96 109.401 -97.2 109.401 -97.2 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 180.801 -106.4 C 180.801 -106.4 170.601 -113.8 168.601 -113.8 C 166.601 -113.8 154.201 -124 150.001 -123.6 C 145.801 -123.2 133.601 -133.2 106.201 -125 C 106.201 -125 105.601 -127 109.201 -127.8 C 109.201 -127.8 115.601 -130 116.001 -130.6 C 116.001 -130.6 136.201 -134.8 143.401 -131.2 C 143.401 -131.2 152.601 -128.6 158.801 -122.4 C 158.801 -122.4 170.001 -119.2 173.201 -120.2 C 173.201 -120.2 182.001 -118 182.401 -116.2 C 182.401 -116.2 188.201 -113.2 186.401 -110.6 C 186.401 -110.6 186.801 -109 180.801 -106.4 z} -tags _tmp_transform -fill #cc7226 -stroke {} +$w create path {M 168.33 -108.509 C 169.137 -107.877 170.156 -107.779 170.761 -106.97 C 170.995 -106.656 170.706 -106.33 170.391 -106.233 C 169.348 -105.916 168.292 -106.486 167.15 -105.898 C 166.748 -105.691 166.106 -105.873 165.553 -106.022 C 163.921 -106.463 162.092 -106.488 160.401 -105.8 C 158.416 -106.929 156.056 -106.345 153.975 -107.346 C 153.917 -107.373 153.695 -107.027 153.621 -107.054 C 150.575 -108.199 146.832 -107.916 144.401 -110.2 C 141.973 -110.612 139.616 -111.074 137.188 -111.754 C 135.37 -112.263 133.961 -113.252 132.341 -114.084 C 130.964 -114.792 129.507 -115.314 127.973 -115.686 C 126.11 -116.138 124.279 -116.026 122.386 -116.546 C 122.293 -116.571 122.101 -116.227 122.019 -116.254 C 121.695 -116.362 121.405 -116.945 121.234 -116.892 C 119.553 -116.37 118.065 -117.342 116.401 -117 C 115.223 -118.224 113.495 -117.979 111.949 -118.421 C 108.985 -119.269 105.831 -117.999 102.801 -119 C 106.914 -120.842 111.601 -119.61 115.663 -121.679 C 117.991 -122.865 120.653 -121.763 123.223 -122.523 C 123.71 -122.667 124.401 -122.869 124.801 -122.2 C 124.935 -122.335 125.117 -122.574 125.175 -122.546 C 127.625 -121.389 129.94 -120.115 132.422 -119.049 C 132.763 -118.903 133.295 -119.135 133.547 -118.933 C 135.067 -117.717 137.01 -117.82 138.401 -116.6 C 140.099 -117.102 141.892 -116.722 143.621 -117.346 C 143.698 -117.373 143.932 -117.032 143.965 -117.054 C 145.095 -117.802 146.25 -117.531 147.142 -117.227 C 147.48 -117.112 148.143 -116.865 148.448 -116.791 C 149.574 -116.515 150.43 -116.035 151.609 -115.852 C 151.723 -115.834 151.908 -116.174 151.98 -116.146 C 153.103 -115.708 154.145 -115.764 154.801 -114.6 C 154.936 -114.735 155.101 -114.973 155.183 -114.946 C 156.21 -114.608 156.859 -113.853 157.96 -113.612 C 158.445 -113.506 159.057 -112.88 159.633 -112.704 C 162.025 -111.973 163.868 -110.444 166.062 -109.549 C 166.821 -109.239 167.697 -109.005 168.33 -108.509 z} -tags _tmp_transform -fill #cc7226 -stroke {} +$w create path {M 91.696 -122.739 C 89.178 -124.464 86.81 -125.57 84.368 -127.356 C 84.187 -127.489 83.827 -127.319 83.625 -127.441 C 82.618 -128.05 81.73 -128.631 80.748 -129.327 C 80.209 -129.709 79.388 -129.698 78.88 -129.956 C 76.336 -131.248 73.707 -131.806 71.2 -133 C 71.882 -133.638 73.004 -133.394 73.6 -134.2 C 73.795 -133.92 74.033 -133.636 74.386 -133.827 C 76.064 -134.731 77.914 -134.884 79.59 -134.794 C 81.294 -134.702 83.014 -134.397 84.789 -134.125 C 85.096 -134.078 85.295 -133.555 85.618 -133.458 C 87.846 -132.795 90.235 -133.32 92.354 -132.482 C 93.945 -131.853 95.515 -131.03 96.754 -129.755 C 97.006 -129.495 96.681 -129.194 96.401 -129 C 96.789 -129.109 97.062 -128.903 97.173 -128.59 C 97.257 -128.351 97.257 -128.049 97.173 -127.81 C 97.061 -127.498 96.782 -127.397 96.408 -127.346 C 95.001 -127.156 96.773 -128.536 96.073 -128.088 C 94.8 -127.274 95.546 -125.868 94.801 -124.6 C 94.521 -124.794 94.291 -125.012 94.401 -125.4 C 94.635 -124.878 94.033 -124.588 93.865 -124.272 C 93.48 -123.547 92.581 -122.132 91.696 -122.739 z} -tags _tmp_transform -fill #cc7226 -stroke {} +$w create path {M 59.198 -115.391 C 56.044 -116.185 52.994 -116.07 49.978 -117.346 C 49.911 -117.374 49.688 -117.027 49.624 -117.054 C 48.258 -117.648 47.34 -118.614 46.264 -119.66 C 45.351 -120.548 43.693 -120.161 42.419 -120.648 C 42.095 -120.772 41.892 -121.284 41.591 -121.323 C 40.372 -121.48 39.445 -122.429 38.4 -123 C 40.736 -123.795 43.147 -123.764 45.609 -124.148 C 45.722 -124.166 45.867 -123.845 46 -123.845 C 46.136 -123.845 46.266 -124.066 46.4 -124.2 C 46.595 -123.92 46.897 -123.594 47.154 -123.848 C 47.702 -124.388 48.258 -124.198 48.798 -124.158 C 48.942 -124.148 49.067 -123.845 49.2 -123.845 C 49.336 -123.845 49.467 -124.156 49.6 -124.156 C 49.736 -124.155 49.867 -123.845 50 -123.845 C 50.136 -123.845 50.266 -124.066 50.4 -124.2 C 51.092 -123.418 51.977 -123.972 52.799 -123.793 C 53.837 -123.566 54.104 -122.418 55.178 -122.12 C 59.893 -120.816 64.03 -118.671 68.393 -116.584 C 68.7 -116.437 68.91 -116.189 68.8 -115.8 C 69.067 -115.8 69.38 -115.888 69.57 -115.756 C 70.628 -115.024 71.669 -114.476 72.366 -113.378 C 72.582 -113.039 72.253 -112.632 72.02 -112.684 C 67.591 -113.679 63.585 -114.287 59.198 -115.391 z} -tags _tmp_transform -fill #cc7226 -stroke {} +$w create path {M 45.338 -71.179 C 43.746 -72.398 43.162 -74.429 42.034 -76.221 C 41.82 -76.561 42.094 -76.875 42.411 -76.964 C 42.971 -77.123 43.514 -76.645 43.923 -76.443 C 45.668 -75.581 47.203 -74.339 49.2 -74.2 C 51.19 -71.966 55.45 -71.581 55.457 -68.2 C 55.458 -67.341 54.03 -68.259 53.6 -67.4 C 51.149 -68.403 48.76 -68.3 46.38 -69.767 C 45.763 -70.148 46.093 -70.601 45.338 -71.179 z} -tags _tmp_transform -fill #cc7226 -stroke {} +$w create path {M 17.8 -123.756 C 17.935 -123.755 24.966 -123.522 24.949 -123.408 C 24.904 -123.099 17.174 -122.05 16.81 -122.22 C 16.646 -122.296 9.134 -119.866 9 -120 C 9.268 -120.135 17.534 -123.756 17.8 -123.756 z} -tags _tmp_transform -fill #cc7226 -stroke {} +$w create path {M 33.2 -114 C 33.2 -114 18.4 -112.2 14 -111 C 9.6 -109.8 -9 -102.2 -12 -100.2 C -12 -100.2 -25.4 -94.8 -42.4 -74.8 C -42.4 -74.8 -34.8 -78.2 -32.6 -81 C -32.6 -81 -19 -93.6 -19.2 -91 C -19.2 -91 -7 -99.6 -7.6 -97.4 C -7.6 -97.4 16.8 -108.6 14.8 -105.4 C 14.8 -105.4 36.4 -110 35.4 -108 C 35.4 -108 54.2 -103.6 51.4 -103.4 C 51.4 -103.4 45.6 -102.2 52 -98.6 C 52 -98.6 48.6 -94.2 43.2 -98.2 C 37.8 -102.2 40.8 -100 35.8 -99 C 35.8 -99 33.2 -98.2 28.6 -102.2 C 28.6 -102.2 23 -106.8 14.2 -103.2 C 14.2 -103.2 -16.4 -90.6 -18.4 -90 C -18.4 -90 -22 -87.2 -24.4 -83.6 C -24.4 -83.6 -30.2 -79.2 -33.2 -77.8 C -33.2 -77.8 -46 -66.2 -47.2 -64.8 C -47.2 -64.8 -50.6 -59.6 -51.4 -59.2 C -51.4 -59.2 -45 -63 -43 -65 C -43 -65 -29 -75 -23.6 -75.8 C -23.6 -75.8 -19.2 -78.8 -18.4 -80.2 C -18.4 -80.2 -4 -89.4 0.2 -89.4 C 0.2 -89.4 9.4 -84.2 11.8 -91.2 C 11.8 -91.2 17.6 -93 23.2 -91.8 C 23.2 -91.8 26.4 -94.4 25.6 -96.6 C 25.6 -96.6 27.2 -98.4 28.2 -94.6 C 28.2 -94.6 31.6 -91 36.4 -93 C 36.4 -93 40.4 -93.2 38.4 -90.8 C 38.4 -90.8 34 -87 22.2 -86.8 C 22.2 -86.8 9.8 -86.2 -6.6 -78.6 C -6.6 -78.6 -36.4 -68.2 -45.6 -57.8 C -45.6 -57.8 -52 -49 -57.4 -47.8 C -57.4 -47.8 -63.2 -47 -69.2 -39.6 C -69.2 -39.6 -59.4 -45.4 -50.4 -45.4 C -50.4 -45.4 -46.4 -47.8 -50.2 -44.2 C -50.2 -44.2 -53.8 -36.6 -52.2 -31.2 C -52.2 -31.2 -52.8 -26 -53.6 -24.4 C -53.6 -24.4 -61.4 -11.6 -61.4 -9.2 C -61.4 -6.8 -60.2 3 -59.8 3.6 C -59.4 4.2 -60.8 2 -57 4.4 C -53.2 6.8 -50.4 8.4 -49.6 11.2 C -48.8 14 -51.6 5.8 -51.8 4 C -52 2.2 -56.2 -5 -55.4 -7.4 C -55.4 -7.4 -54.4 -6.4 -53.6 -5 C -53.6 -5 -54.2 -5.6 -53.6 -9.2 C -53.6 -9.2 -52.8 -14.4 -51.4 -17.6 C -50 -20.8 -48 -24.6 -47.6 -25.4 C -47.2 -26.2 -47.2 -32 -45.8 -29.4 L -42.4 -26.8 C -42.4 -26.8 -45.2 -29.4 -43 -31.6 C -43 -31.6 -44 -37.2 -42.2 -39.8 C -42.2 -39.8 -35.2 -48.2 -33.6 -49.2 C -32 -50.2 -33.4 -49.8 -33.4 -49.8 C -33.4 -49.8 -27.4 -54 -33.2 -52.4 C -33.2 -52.4 -37.2 -50.8 -40.2 -50.8 C -40.2 -50.8 -47.8 -48.8 -43.8 -53 C -39.8 -57.2 -29.8 -62.6 -26 -62.4 L -25.2 -60.8 L -14 -63.2 L -15.2 -62.4 C -15.2 -62.4 -15.4 -62.6 -11.2 -63 C -7 -63.4 -1.2 -62 0.2 -63.8 C 1.6 -65.6 5 -66.6 4.6 -65.2 C 4.2 -63.8 4 -61.8 4 -61.8 C 4 -61.8 9 -67.6 8.4 -65.4 C 7.8 -63.2 -0.4 -58 -1.8 -51.8 L 8.6 -60 L 12.2 -63 C 12.2 -63 15.8 -60.8 16 -62.4 C 16.2 -64 20.8 -69.8 22 -69.6 C 23.2 -69.4 25.2 -72.2 25 -69.6 C 24.8 -67 32.4 -61.6 32.4 -61.6 C 32.4 -61.6 35.6 -63.4 37 -62 C 38.4 -60.6 42.6 -81.8 42.6 -81.8 L 67.6 -92.4 L 111.201 -95.8 L 94.201 -102.6 L 33.2 -114 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 51.4 85 C 51.4 85 36.4 68.2 28 65.6 C 28 65.6 14.6 58.8 -10 66.6} -tags _tmp_transform -fill black -stroke #4c0000 +$w create path {M 24.8 64.2 C 24.8 64.2 -0.4 56.2 -15.8 60.4 C -15.8 60.4 -34.2 62.4 -42.6 76.2} -tags _tmp_transform -fill black -stroke #4c0000 +$w create path {M 21.2 63 C 21.2 63 4.2 55.8 -10.6 53.6 C -10.6 53.6 -27.2 51 -43.8 58.2 C -43.8 58.2 -56 64.2 -61.4 74.4} -tags _tmp_transform -fill black -stroke #4c0000 +$w create path {M 22.2 63.4 C 22.2 63.4 6.8 52.4 5.8 51 C 5.8 51 -1.2 40 -14.2 39.6 C -14.2 39.6 -35.6 40.4 -52.8 48.4} -tags _tmp_transform -fill black -stroke #4c0000 +$w create path {M 20.895 54.407 C 22.437 55.87 49.4 84.8 49.4 84.8 C 84.6 121.401 56.6 87.2 56.6 87.2 C 49 82.4 39.8 63.6 39.8 63.6 C 38.6 60.8 53.8 70.8 53.8 70.8 C 57.8 71.6 71.4 90.8 71.4 90.8 C 64.6 88.4 69.4 95.6 69.4 95.6 C 72.2 97.6 92.601 113.201 92.601 113.201 C 96.201 117.201 100.201 118.801 100.201 118.801 C 114.201 113.601 107.801 126.801 107.801 126.801 C 110.201 133.601 115.801 122.001 115.801 122.001 C 127.001 105.2 110.601 107.601 110.601 107.601 C 80.6 110.401 73.8 94.4 73.8 94.4 C 71.4 92 80.2 94.4 80.2 94.4 C 88.601 96.4 73 82 73 82 C 75.4 82 84.6 88.8 84.6 88.8 C 95.001 98 97.001 96 97.001 96 C 115.001 87.2 125.401 94.8 125.401 94.8 C 127.401 96.4 121.801 103.2 123.401 108.401 C 125.001 113.601 129.801 126.001 129.801 126.001 C 127.401 127.601 127.801 138.401 127.801 138.401 C 144.601 161.601 135.001 159.601 135.001 159.601 C 119.401 159.201 134.201 166.801 134.201 166.801 C 137.401 168.801 146.201 176.001 146.201 176.001 C 143.401 174.801 141.801 180.001 141.801 180.001 C 146.601 184.001 143.801 188.801 143.801 188.801 C 137.801 190.001 136.601 194.001 136.601 194.001 C 143.401 202.001 133.401 202.401 133.401 202.401 C 137.001 206.801 132.201 218.801 132.201 218.801 C 127.401 218.801 121.001 224.401 121.001 224.401 C 123.401 229.201 113.001 234.801 113.001 234.801 C 104.601 236.401 107.401 243.201 107.401 243.201 C 99.401 249.201 97.001 265.201 97.001 265.201 C 96.201 275.601 93.801 278.801 99.001 276.801 C 104.201 274.801 103.401 262.401 103.401 262.401 C 98.601 246.801 141.401 230.801 141.401 230.801 C 145.401 229.201 146.201 224.001 146.201 224.001 C 148.201 224.401 157.001 232.001 157.001 232.001 C 164.601 243.201 165.001 234.001 165.001 234.001 C 166.201 230.401 164.601 224.401 164.601 224.401 C 170.601 202.801 156.601 196.401 156.601 196.401 C 146.601 162.801 160.601 171.201 160.601 171.201 C 163.401 176.801 174.201 182.001 174.201 182.001 L 177.801 179.601 C 176.201 174.801 184.601 168.801 184.601 168.801 C 187.401 175.201 193.401 167.201 193.401 167.201 C 197.001 142.801 209.401 157.201 209.401 157.201 C 213.401 158.401 214.601 151.601 214.601 151.601 C 218.201 141.201 214.601 127.601 214.601 127.601 C 218.201 127.201 227.801 133.201 227.801 133.201 C 230.601 129.601 221.401 112.801 225.401 115.201 C 229.401 117.601 233.801 119.201 233.801 119.201 C 234.601 117.201 224.601 104.801 224.601 104.801 C 220.201 102 215.001 81.6 215.001 81.6 C 222.201 85.2 212.201 70 212.201 70 C 212.201 66.8 218.201 55.6 218.201 55.6 C 217.401 48.8 218.201 49.2 218.201 49.2 C 221.001 50.4 229.001 52 222.201 45.6 C 215.401 39.2 223.001 34.4 223.001 34.4 C 227.401 31.6 213.801 32 213.801 32 C 208.601 27.6 209.001 23.6 209.001 23.6 C 217.001 25.6 202.601 11.2 200.201 7.6 C 197.801 4 207.401 -1.2 207.401 -1.2 C 220.601 -4.8 209.001 -8 209.001 -8 C 189.401 -7.6 200.201 -18.4 200.201 -18.4 C 206.201 -18 204.601 -20.4 204.601 -20.4 C 199.401 -21.6 189.801 -28 189.801 -28 C 185.801 -31.6 189.401 -30.8 189.401 -30.8 C 206.201 -29.6 177.401 -40.8 177.401 -40.8 C 185.401 -40.8 167.401 -51.2 167.401 -51.2 C 165.401 -52.8 162.201 -60.4 162.201 -60.4 C 156.201 -65.6 151.401 -72.4 151.401 -72.4 C 151.001 -76.8 146.201 -81.6 146.201 -81.6 C 134.601 -95.2 129.001 -94.8 129.001 -94.8 C 114.201 -98.4 109.001 -97.6 109.001 -97.6 L 56.2 -93.2 C 29.8 -80.4 37.6 -59.4 37.6 -59.4 C 44 -51 53.2 -54.8 53.2 -54.8 C 57.8 -61 69.4 -58.8 69.4 -58.8 C 89.801 -55.6 87.201 -59.2 87.201 -59.2 C 84.801 -63.8 68.6 -70 68.4 -70.6 C 68.2 -71.2 59.4 -74.6 59.4 -74.6 C 56.4 -75.8 52 -85 52 -85 C 48.8 -88.4 64.6 -82.6 64.6 -82.6 C 63.4 -81.6 70.8 -77.6 70.8 -77.6 C 88.201 -78.6 98.801 -67.8 98.801 -67.8 C 109.601 -51.2 109.801 -59.4 109.801 -59.4 C 112.601 -68.8 100.801 -90 100.801 -90 C 101.201 -92 109.401 -85.4 109.401 -85.4 C 110.801 -87.4 111.601 -81.6 111.601 -81.6 C 111.801 -79.2 115.601 -71.2 115.601 -71.2 C 118.401 -58.2 122.001 -65.6 122.001 -65.6 L 126.601 -56.2 C 128.001 -53.6 122.001 -46 122.001 -46 C 121.801 -43.2 122.601 -43.4 117.001 -35.8 C 111.401 -28.2 114.801 -23.8 114.801 -23.8 C 113.401 -17.2 122.201 -17.6 122.201 -17.6 C 124.801 -15.4 128.201 -15.4 128.201 -15.4 C 130.001 -13.4 132.401 -14 132.401 -14 C 134.001 -17.8 140.201 -15.8 140.201 -15.8 C 141.601 -18.2 149.801 -18.6 149.801 -18.6 C 150.801 -21.2 151.201 -22.8 154.601 -23.4 C 158.001 -24 133.401 -67 133.401 -67 C 139.801 -67.8 131.601 -80.2 131.601 -80.2 C 129.401 -86.8 140.801 -72.2 143.001 -70.8 C 145.201 -69.4 146.201 -67.2 144.601 -67.4 C 143.001 -67.6 141.201 -65.4 142.601 -65.2 C 144.001 -65 157.001 -50 160.401 -39.8 C 163.801 -29.6 169.801 -25.6 176.001 -19.6 C 182.201 -13.6 181.401 10.6 181.401 10.6 C 181.001 19.4 187.001 30 187.001 30 C 189.001 33.8 184.801 52 184.801 52 C 182.801 54.2 184.201 55 184.201 55 C 185.201 56.2 192.001 69.4 192.001 69.4 C 190.201 69.2 193.801 72.8 193.801 72.8 C 199.001 78.8 192.601 75.8 192.601 75.8 C 186.601 74.2 193.601 84 193.601 84 C 194.801 85.8 185.801 81.2 185.801 81.2 C 176.601 80.6 188.201 87.8 188.201 87.8 C 196.801 95 185.401 90.6 185.401 90.6 C 180.801 88.8 184.001 95.6 184.001 95.6 C 187.201 97.2 204.401 104.2 204.401 104.2 C 204.801 108.001 201.801 113.001 201.801 113.001 C 202.201 117.001 200.001 120.401 200.001 120.401 C 198.801 128.601 198.201 129.401 198.201 129.401 C 194.001 129.601 186.601 143.401 186.601 143.401 C 184.801 146.001 174.601 158.001 174.601 158.001 C 172.601 165.001 154.601 157.801 154.601 157.801 C 148.001 161.201 150.001 157.801 150.001 157.801 C 149.601 155.601 154.401 149.601 154.401 149.601 C 161.401 147.001 158.801 136.201 158.801 136.201 C 162.801 134.801 151.601 132.001 151.801 130.801 C 152.001 129.601 157.801 128.201 157.801 128.201 C 165.801 126.201 161.401 123.801 161.401 123.801 C 160.801 119.801 163.801 114.201 163.801 114.201 C 175.401 113.401 163.801 97.2 163.801 97.2 C 153.001 89.6 152.001 83.8 152.001 83.8 C 164.601 75.6 156.401 63.2 156.601 59.6 C 156.801 56 158.001 34.4 158.001 34.4 C 156.001 28.2 153.001 14.6 153.001 14.6 C 155.201 9.4 162.601 -3.2 162.601 -3.2 C 165.401 -7.4 174.201 -12.2 172.001 -15.2 C 169.801 -18.2 162.001 -16.4 162.001 -16.4 C 154.201 -17.8 154.801 -12.6 154.801 -12.6 C 153.201 -11.6 152.401 -6.6 152.401 -6.6 C 151.68 1.333 142.801 7.6 142.801 7.6 C 131.601 13.8 140.801 17.8 140.801 17.8 C 146.801 24.4 137.001 24.6 137.001 24.6 C 126.001 22.8 134.201 33 134.201 33 C 145.001 45.8 142.001 48.6 142.001 48.6 C 131.801 49.6 144.401 58.8 144.401 58.8 C 144.401 58.8 143.601 56.8 143.801 58.6 C 144.001 60.4 147.001 64.6 147.801 66.6 C 148.601 68.6 144.601 68.8 144.601 68.8 C 145.201 78.4 129.801 74.2 129.801 74.2 C 129.801 74.2 129.801 74.2 128.201 74.4 C 126.601 74.6 115.401 73.8 109.601 71.6 C 103.801 69.4 97.001 69.4 97.001 69.4 C 97.001 69.4 93.001 71.2 85.4 71 C 77.8 70.8 69.8 73.6 69.8 73.6 C 65.4 73.2 74 68.8 74.2 69 C 74.4 69.2 80 63.6 72 64.2 C 50.203 65.835 39.4 55.6 39.4 55.6 C 37.4 54.2 34.8 51.4 34.8 51.4 C 24.8 49.4 36.2 63.8 36.2 63.8 C 37.4 65.2 36 66.2 36 66.2 C 35.2 64.6 27.4 59.2 27.4 59.2 C 24.589 58.227 23.226 56.893 20.895 54.407 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -3 42.8 C -3 42.8 8.6 48.4 11.2 51.2 C 13.8 54 27.8 65.4 27.8 65.4 C 27.8 65.4 22.4 63.4 19.8 61.6 C 17.2 59.8 6.4 51.6 6.4 51.6 C 6.4 51.6 2.6 45.6 -3 42.8 z} -tags _tmp_transform -fill #4c0000 -stroke {} +$w create path {M -61.009 11.603 C -60.672 11.455 -61.196 8.743 -61.4 8.2 C -62.422 5.474 -71.4 4 -71.4 4 C -71.627 5.365 -71.682 6.961 -71.576 8.599 C -71.576 8.599 -66.708 14.118 -61.009 11.603 z} -tags _tmp_transform -fill #99cc32 -stroke {} +$w create path {M -61.009 11.403 C -61.458 11.561 -61.024 8.669 -61.2 8.2 C -62.222 5.474 -71.4 3.9 -71.4 3.9 C -71.627 5.265 -71.682 6.861 -71.576 8.499 C -71.576 8.499 -67.308 13.618 -61.009 11.403 z} -tags _tmp_transform -fill #659900 -stroke {} +$w create path {M -65.4 11.546 C -66.025 11.546 -66.531 10.406 -66.531 9 C -66.531 7.595 -66.025 6.455 -65.4 6.455 C -64.775 6.455 -64.268 7.595 -64.268 9 C -64.268 10.406 -64.775 11.546 -65.4 11.546 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -65.4 9 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -111 109.601 C -111 109.601 -116.6 119.601 -91.8 113.601 C -91.8 113.601 -77.8 112.401 -75.4 110.001 C -74.2 110.801 -65.834 113.734 -63 114.401 C -56.2 116.001 -47.8 106 -47.8 106 C -47.8 106 -43.2 95.5 -40.4 95.5 C -37.6 95.5 -40.8 97.1 -40.8 97.1 C -40.8 97.1 -47.4 107.201 -47 108.801 C -47 108.801 -52.2 128.801 -68.2 129.601 C -68.2 129.601 -84.35 130.551 -83 136.401 C -83 136.401 -74.2 134.001 -71.8 136.401 C -71.8 136.401 -61 136.001 -69 142.401 L -75.8 154.001 C -75.8 154.001 -75.66 157.919 -85.8 154.401 C -95.6 151.001 -105.9 138.101 -105.9 138.101 C -105.9 138.101 -121.85 123.551 -111 109.601 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -112.2 113.601 C -112.2 113.601 -114.2 123.201 -77.4 112.801 C -77.4 112.801 -73 112.801 -70.6 113.601 C -68.2 114.401 -56.2 117.201 -54.2 116.001 C -54.2 116.001 -61.4 129.601 -73 128.001 C -73 128.001 -86.2 129.601 -85.8 134.401 C -85.8 134.401 -81.8 141.601 -77 144.001 C -77 144.001 -74.2 146.401 -74.6 149.601 C -75 152.801 -77.8 154.401 -79.8 155.201 C -81.8 156.001 -85 152.801 -86.6 152.801 C -88.2 152.801 -96.6 146.401 -101 141.601 C -105.4 136.801 -113.8 124.801 -113.4 122.001 C -113 119.201 -112.2 113.601 -112.2 113.601 z} -tags _tmp_transform -fill #e59999 -stroke {} +$w create path {M -109 131.051 C -106.4 135.001 -103.2 139.201 -101 141.601 C -96.6 146.401 -88.2 152.801 -86.6 152.801 C -85 152.801 -81.8 156.001 -79.8 155.201 C -77.8 154.401 -75 152.801 -74.6 149.601 C -74.2 146.401 -77 144.001 -77 144.001 C -80.066 142.468 -82.806 138.976 -84.385 136.653 C -84.385 136.653 -84.2 139.201 -89.4 138.401 C -94.6 137.601 -99.8 134.801 -101.4 131.601 C -103 128.401 -105.4 126.001 -103.8 129.601 C -102.2 133.201 -99.8 136.801 -98.2 137.201 C -96.6 137.601 -97 138.801 -99.4 138.401 C -101.8 138.001 -104.6 137.601 -109 132.401 z} -tags _tmp_transform -fill #b26565 -stroke {} +$w create path {M -111.6 110.001 C -111.6 110.001 -109.8 96.4 -108.6 92.4 C -108.6 92.4 -109.4 85.6 -107 81.4 C -104.6 77.2 -102.6 71 -99.6 65.6 C -96.6 60.2 -96.4 56.2 -92.4 54.6 C -88.4 53 -82.4 44.4 -79.6 43.4 C -76.8 42.4 -77 43.2 -77 43.2 C -77 43.2 -70.2 28.4 -56.6 32.4 C -56.6 32.4 -72.8 29.6 -57 20.2 C -57 20.2 -61.8 21.3 -58.5 14.3 C -56.299 9.632 -56.8 16.4 -67.8 28.2 C -67.8 28.2 -72.8 36.8 -78 39.8 C -83.2 42.8 -95.2 49.8 -96.4 53.6 C -97.6 57.4 -100.8 63.2 -102.8 64.8 C -104.8 66.4 -107.6 70.6 -108 74 C -108 74 -109.2 78 -110.6 79.2 C -112 80.4 -112.2 83.6 -112.2 85.6 C -112.2 87.6 -114.2 90.4 -114 92.8 C -114 92.8 -113.2 111.801 -113.6 113.801 L -111.6 110.001 z} -tags _tmp_transform -fill #992600 -stroke {} +$w create path {M -120.2 114.601 C -120.2 114.601 -122.2 113.201 -126.6 119.201 C -126.6 119.201 -119.3 152.201 -119.3 153.601 C -119.3 153.601 -118.2 151.501 -119.5 144.301 C -120.8 137.101 -121.7 124.401 -121.7 124.401 L -120.2 114.601 z} -tags _tmp_transform -fill #ffffff -stroke {} +$w create path {M -98.6 54 C -98.6 54 -116.2 57.2 -115.8 86.4 L -116.6 111.201 C -116.6 111.201 -117.8 85.6 -119 84 C -120.2 82.4 -116.2 71.2 -119.4 77.2 C -119.4 77.2 -133.4 91.2 -125.4 112.401 C -125.4 112.401 -123.9 115.701 -126.9 111.101 C -126.9 111.101 -131.5 98.5 -130.4 92.1 C -130.4 92.1 -130.2 89.9 -128.3 87.1 C -128.3 87.1 -119.7 75.4 -117 73.1 C -117 73.1 -115.2 58.7 -99.8 53.5 C -99.8 53.5 -94.1 51.2 -98.6 54 z} -tags _tmp_transform -fill #992600 -stroke {} +$w create path {M 40.8 -12.2 C 41.46 -12.554 41.451 -13.524 42.031 -13.697 C 43.18 -14.041 43.344 -15.108 43.862 -15.892 C 44.735 -17.211 44.928 -18.744 45.51 -20.235 C 45.782 -20.935 45.809 -21.89 45.496 -22.55 C 44.322 -25.031 43.62 -27.48 42.178 -29.906 C 41.91 -30.356 41.648 -31.15 41.447 -31.748 C 40.984 -33.132 39.727 -34.123 38.867 -35.443 C 38.579 -35.884 39.104 -36.809 38.388 -36.893 C 37.491 -36.998 36.042 -37.578 35.809 -36.552 C 35.221 -33.965 36.232 -31.442 37.2 -29 C 36.418 -28.308 36.752 -27.387 36.904 -26.62 C 37.614 -23.014 36.416 -19.662 35.655 -16.188 C 35.632 -16.084 35.974 -15.886 35.946 -15.824 C 34.724 -13.138 33.272 -10.693 31.453 -8.312 C 30.695 -7.32 29.823 -6.404 29.326 -5.341 C 28.958 -4.554 28.55 -3.588 28.8 -2.6 C 25.365 0.18 23.115 4.025 20.504 7.871 C 20.042 8.551 20.333 9.76 20.884 10.029 C 21.697 10.427 22.653 9.403 23.123 8.557 C 23.512 7.859 23.865 7.209 24.356 6.566 C 24.489 6.391 24.31 5.972 24.445 5.851 C 27.078 3.504 28.747 0.568 31.2 -1.8 C 33.15 -2.129 34.687 -3.127 36.435 -4.14 C 36.743 -4.319 37.267 -4.07 37.557 -4.265 C 39.31 -5.442 39.308 -7.478 39.414 -9.388 C 39.464 -10.272 39.66 -11.589 40.8 -12.2 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 31.959 -16.666 C 32.083 -16.743 31.928 -17.166 32.037 -17.382 C 32.199 -17.706 32.602 -17.894 32.764 -18.218 C 32.873 -18.434 32.71 -18.814 32.846 -18.956 C 35.179 -21.403 35.436 -24.427 34.4 -27.4 C 35.424 -28.02 35.485 -29.282 35.06 -30.129 C 34.207 -31.829 34.014 -33.755 33.039 -35.298 C 32.237 -36.567 30.659 -37.811 29.288 -36.508 C 28.867 -36.108 28.546 -35.321 28.824 -34.609 C 28.888 -34.446 29.173 -34.3 29.146 -34.218 C 29.039 -33.894 28.493 -33.67 28.487 -33.398 C 28.457 -31.902 27.503 -30.391 28.133 -29.062 C 28.905 -27.433 29.724 -25.576 30.4 -23.8 C 29.166 -21.684 30.199 -19.235 28.446 -17.358 C 28.31 -17.212 28.319 -16.826 28.441 -16.624 C 28.733 -16.138 29.139 -15.732 29.625 -15.44 C 29.827 -15.319 30.175 -15.317 30.375 -15.441 C 30.953 -15.803 31.351 -16.29 31.959 -16.666 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 94.771 -26.977 C 96.16 -25.185 96.45 -22.39 94.401 -21 C 94.951 -17.691 98.302 -19.67 100.401 -20.2 C 100.292 -20.588 100.519 -20.932 100.802 -20.937 C 101.859 -20.952 102.539 -21.984 103.601 -21.8 C 104.035 -23.357 105.673 -24.059 106.317 -25.439 C 108.043 -29.134 107.452 -33.407 104.868 -36.653 C 104.666 -36.907 104.883 -37.424 104.759 -37.786 C 104.003 -39.997 101.935 -40.312 100.001 -41 C 98.824 -44.875 98.163 -48.906 96.401 -52.6 C 94.787 -52.85 94.089 -54.589 92.752 -55.309 C 91.419 -56.028 90.851 -54.449 90.892 -53.403 C 90.899 -53.198 91.351 -52.974 91.181 -52.609 C 91.105 -52.445 90.845 -52.334 90.845 -52.2 C 90.846 -52.065 91.067 -51.934 91.201 -51.8 C 90.283 -50.98 88.86 -50.503 88.565 -49.358 C 87.611 -45.648 90.184 -42.523 91.852 -39.322 C 92.443 -38.187 91.707 -36.916 90.947 -35.708 C 90.509 -35.013 90.617 -33.886 90.893 -33.03 C 91.645 -30.699 93.236 -28.96 94.771 -26.977 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 57.611 -8.591 C 56.124 -6.74 52.712 -4.171 55.629 -2.243 C 55.823 -2.114 56.193 -2.11 56.366 -2.244 C 58.387 -3.809 60.39 -4.712 62.826 -5.294 C 62.95 -5.323 63.224 -4.856 63.593 -5.017 C 65.206 -5.72 67.216 -5.662 68.4 -7 C 72.167 -6.776 75.732 -7.892 79.123 -9.2 C 80.284 -9.648 81.554 -10.207 82.755 -10.709 C 84.131 -11.285 85.335 -12.213 86.447 -13.354 C 86.58 -13.49 86.934 -13.4 87.201 -13.4 C 87.161 -14.263 88.123 -14.39 88.37 -15.012 C 88.462 -15.244 88.312 -15.64 88.445 -15.742 C 90.583 -17.372 91.503 -19.39 90.334 -21.767 C 90.049 -22.345 89.8 -22.963 89.234 -23.439 C 88.149 -24.35 87.047 -23.496 86 -23.8 C 85.841 -23.172 85.112 -23.344 84.726 -23.146 C 83.867 -22.707 82.534 -23.292 81.675 -22.854 C 80.313 -22.159 79.072 -21.99 77.65 -21.613 C 77.338 -21.531 76.56 -21.627 76.4 -21 C 76.266 -21.134 76.118 -21.368 76.012 -21.346 C 74.104 -20.95 72.844 -20.736 71.543 -19.044 C 71.44 -18.911 70.998 -19.09 70.839 -18.955 C 69.882 -18.147 69.477 -16.913 68.376 -16.241 C 68.175 -16.118 67.823 -16.286 67.629 -16.157 C 66.983 -15.726 66.616 -15.085 65.974 -14.638 C 65.645 -14.409 65.245 -14.734 65.277 -14.99 C 65.522 -16.937 66.175 -18.724 65.6 -20.6 C 67.677 -23.12 70.194 -25.069 72 -27.8 C 72.015 -29.966 72.707 -32.112 72.594 -34.189 C 72.584 -34.382 72.296 -35.115 72.17 -35.462 C 71.858 -36.316 72.764 -37.382 71.92 -38.106 C 70.516 -39.309 69.224 -38.433 68.4 -37 C 66.562 -36.61 64.496 -35.917 62.918 -37.151 C 61.911 -37.938 61.333 -38.844 60.534 -39.9 C 59.549 -41.202 59.884 -42.638 59.954 -44.202 C 59.96 -44.33 59.645 -44.466 59.645 -44.6 C 59.646 -44.735 59.866 -44.866 60 -45 C 59.294 -45.626 59.019 -46.684 58 -47 C 58.305 -48.092 57.629 -48.976 56.758 -49.278 C 54.763 -49.969 53.086 -48.057 51.194 -47.984 C 50.68 -47.965 50.213 -49.003 49.564 -49.328 C 49.132 -49.544 48.428 -49.577 48.066 -49.311 C 47.378 -48.807 46.789 -48.693 46.031 -48.488 C 44.414 -48.052 43.136 -46.958 41.656 -46.103 C 40.171 -45.246 39.216 -43.809 38.136 -42.489 C 37.195 -41.337 37.059 -38.923 38.479 -38.423 C 40.322 -37.773 41.626 -40.476 43.592 -40.15 C 43.904 -40.099 44.11 -39.788 44 -39.4 C 44.389 -39.291 44.607 -39.52 44.8 -39.8 C 45.658 -38.781 46.822 -38.444 47.76 -37.571 C 48.73 -36.667 50.476 -37.085 51.491 -36.088 C 53.02 -34.586 52.461 -31.905 54.4 -30.6 C 53.814 -29.287 53.207 -28.01 52.872 -26.583 C 52.59 -25.377 53.584 -24.18 54.795 -24.271 C 56.053 -24.365 56.315 -25.124 56.8 -26.2 C 57.067 -25.933 57.536 -25.636 57.495 -25.42 C 57.038 -23.033 56.011 -21.04 55.553 -18.609 C 55.494 -18.292 55.189 -18.09 54.8 -18.2 C 54.332 -14.051 50.28 -11.657 47.735 -8.492 C 47.332 -7.99 47.328 -6.741 47.737 -6.338 C 49.14 -4.951 51.1 -6.497 52.8 -7 C 53.013 -8.206 53.872 -9.148 55.204 -9.092 C 55.46 -9.082 55.695 -9.624 56.019 -9.754 C 56.367 -9.892 56.869 -9.668 57.155 -9.866 C 58.884 -11.061 60.292 -12.167 62.03 -13.356 C 62.222 -13.487 62.566 -13.328 62.782 -13.436 C 63.107 -13.598 63.294 -13.985 63.617 -14.17 C 63.965 -14.37 64.207 -14.08 64.4 -13.8 C 63.754 -13.451 63.75 -12.494 63.168 -12.292 C 62.393 -12.024 61.832 -11.511 61.158 -11.064 C 60.866 -10.871 60.207 -11.119 60.103 -10.94 C 59.505 -9.912 58.321 -9.474 57.611 -8.591 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 2.2 -58 C 2.2 -58 -7.038 -60.872 -18.2 -35.2 C -18.2 -35.2 -20.6 -30 -23 -28 C -25.4 -26 -36.6 -22.4 -38.6 -18.4 L -49 -2.4 C -49 -2.4 -34.2 -18.4 -31 -20.8 C -31 -20.8 -23 -29.2 -26.2 -22.4 C -26.2 -22.4 -40.2 -11.6 -39 -2.4 C -39 -2.4 -44.6 12 -45.4 14 C -45.4 14 -29.4 -18 -27 -19.2 C -24.6 -20.4 -23.4 -20.4 -24.6 -16.8 C -25.8 -13.2 -26.2 3.2 -29 5.2 C -29 5.2 -21 -15.2 -21.8 -18.4 C -21.8 -18.4 -18.6 -22 -16.2 -16.8 L -17.4 -0.8 L -13 11.2 C -13 11.2 -15.4 0 -13.8 -15.6 C -13.8 -15.6 -15.8 -26 -11.8 -20.4 C -7.8 -14.8 1.8 -8.8 1.8 -4 C 1.8 -4 -3.4 -21.6 -12.6 -26.4 L -16.6 -20.4 L -17.8 -22.4 C -17.8 -22.4 -21.4 -23.2 -17 -30 C -12.6 -36.8 -13 -37.6 -13 -37.6 C -13 -37.6 -6.6 -30.4 -5 -30.4 C -5 -30.4 8.2 -38 9.4 -13.6 C 9.4 -13.6 16.2 -28 7 -34.8 C 7 -34.8 -7.8 -36.8 -6.6 -42 L 0.6 -54.4 C 4.2 -59.6 2.6 -56.8 2.6 -56.8 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -17.8 -41.6 C -17.8 -41.6 -30.6 -41.6 -33.8 -36.4 L -41 -26.8 C -41 -26.8 -23.8 -36.8 -19.8 -38 C -15.8 -39.2 -17.8 -41.6 -17.8 -41.6 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -57.8 -35.2 C -57.8 -35.2 -59.8 -34 -60.2 -31.2 C -60.6 -28.4 -63 -28 -62.2 -25.2 C -61.4 -22.4 -59.4 -20 -59.4 -24 C -59.4 -28 -57.8 -30 -57 -31.2 C -56.2 -32.4 -54.6 -36.8 -57.8 -35.2 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -66.6 26 C -66.6 26 -75 22 -78.2 18.4 C -81.4 14.8 -80.948 19.966 -85.8 19.6 C -91.647 19.159 -90.6 3.2 -90.6 3.2 L -94.6 10.8 C -94.6 10.8 -95.8 25.2 -87.8 22.8 C -83.893 21.628 -82.6 23.2 -84.2 24 C -85.8 24.8 -78.6 25.2 -81.4 26.8 C -84.2 28.4 -69.8 23.2 -72.2 33.6 L -66.6 26 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -79.2 40.4 C -79.2 40.4 -94.6 44.8 -98.2 35.2 C -98.2 35.2 -103 37.6 -100.8 40.6 C -98.6 43.6 -97.4 44 -97.4 44 C -97.4 44 -92 45.2 -92.6 46 C -93.2 46.8 -95.6 50.2 -95.6 50.2 C -95.6 50.2 -85.4 44.2 -79.2 40.4 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 149.201 118.601 C 148.774 120.735 147.103 121.536 145.201 122.201 C 143.284 121.243 140.686 118.137 138.801 120.201 C 138.327 119.721 137.548 119.661 137.204 118.999 C 136.739 118.101 137.011 117.055 136.669 116.257 C 136.124 114.985 135.415 113.619 135.601 112.201 C 137.407 111.489 138.002 109.583 137.528 107.82 C 137.459 107.563 137.03 107.366 137.23 107.017 C 137.416 106.694 137.734 106.467 138.001 106.2 C 137.866 106.335 137.721 106.568 137.61 106.548 C 137 106.442 137.124 105.805 137.254 105.418 C 137.839 103.672 139.853 103.408 141.201 104.6 C 141.457 104.035 141.966 104.229 142.401 104.2 C 142.351 103.621 142.759 103.094 142.957 102.674 C 143.475 101.576 145.104 102.682 145.901 102.07 C 146.977 101.245 148.04 100.546 149.118 101.149 C 150.927 102.162 152.636 103.374 153.835 105.115 C 154.41 105.949 154.65 107.23 154.592 108.188 C 154.554 108.835 153.173 108.483 152.83 109.412 C 152.185 111.16 154.016 111.679 154.772 113.017 C 154.97 113.366 154.706 113.67 154.391 113.768 C 153.98 113.896 153.196 113.707 153.334 114.16 C 154.306 117.353 151.55 118.031 149.201 118.601 z} -tags _tmp_transform -fill #ffffff -stroke {} +$w create path {M 139.6 138.201 C 139.593 136.463 137.992 134.707 139.201 133.001 C 139.336 133.135 139.467 133.356 139.601 133.356 C 139.736 133.356 139.867 133.135 140.001 133.001 C 141.496 135.217 145.148 136.145 145.006 138.991 C 144.984 139.438 143.897 140.356 144.801 141.001 C 142.988 142.349 142.933 144.719 142.001 146.601 C 140.763 146.315 139.551 145.952 138.401 145.401 C 138.753 143.915 138.636 142.231 139.456 140.911 C 139.89 140.213 139.603 139.134 139.6 138.201 z} -tags _tmp_transform -fill #ffffff -stroke {} +$w create path {M -26.6 129.201 C -26.6 129.201 -43.458 139.337 -29.4 124.001 C -20.6 114.401 -10.6 108.801 -10.6 108.801 C -10.6 108.801 -0.2 104.4 3.4 103.2 C 7 102 22.2 96.8 25.4 96.4 C 28.6 96 38.2 92 45 96 C 51.8 100 59.8 104.4 59.8 104.4 C 59.8 104.4 43.4 96 39.8 98.4 C 36.2 100.8 29 100.4 23 103.6 C 23 103.6 8.2 108.001 5 110.001 C 1.8 112.001 -8.6 123.601 -10.2 122.801 C -11.8 122.001 -9.8 121.601 -8.6 118.801 C -7.4 116.001 -9.4 114.401 -17.4 120.801 C -25.4 127.201 -26.6 129.201 -26.6 129.201 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -19.195 123.234 C -19.195 123.234 -17.785 110.194 -9.307 111.859 C -9.307 111.859 -1.081 107.689 1.641 105.721 C 1.641 105.721 9.78 104.019 11.09 103.402 C 29.569 94.702 44.288 99.221 44.835 98.101 C 45.381 96.982 65.006 104.099 68.615 108.185 C 69.006 108.628 58.384 102.588 48.686 100.697 C 40.413 99.083 18.811 100.944 7.905 106.48 C 4.932 107.989 -4.013 113.773 -6.544 113.662 C -9.075 113.55 -19.195 123.234 -19.195 123.234 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -23 148.801 C -23 148.801 -38.2 146.401 -21.4 144.801 C -21.4 144.801 -3.4 142.801 0.6 137.601 C 0.6 137.601 14.2 128.401 17 128.001 C 19.8 127.601 49.8 120.401 50.2 118.001 C 50.6 115.601 56.2 115.601 57.8 116.401 C 59.4 117.201 58.6 118.401 55.8 119.201 C 53 120.001 21.8 136.401 15.4 137.601 C 9 138.801 -2.6 146.401 -7.4 147.601 C -12.2 148.801 -23 148.801 -23 148.801 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -3.48 141.403 C -3.48 141.403 -12.062 140.574 -3.461 139.755 C -3.461 139.755 5.355 136.331 7.403 133.668 C 7.403 133.668 14.367 128.957 15.8 128.753 C 17.234 128.548 31.194 124.861 31.399 123.633 C 31.604 122.404 65.67 109.823 70.09 113.013 C 73.001 115.114 63.1 113.437 53.466 117.847 C 52.111 118.467 18.258 133.054 14.981 133.668 C 11.704 134.283 5.765 138.174 3.307 138.788 C 0.85 139.403 -3.48 141.403 -3.48 141.403 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -11.4 143.601 C -11.4 143.601 -6.2 143.201 -7.4 144.801 C -8.6 146.401 -11 145.601 -11 145.601 L -11.4 143.601 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -18.6 145.201 C -18.6 145.201 -13.4 144.801 -14.6 146.401 C -15.8 148.001 -18.2 147.201 -18.2 147.201 L -18.6 145.201 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -29 146.801 C -29 146.801 -23.8 146.401 -25 148.001 C -26.2 149.601 -28.6 148.801 -28.6 148.801 L -29 146.801 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -36.6 147.601 C -36.6 147.601 -31.4 147.201 -32.6 148.801 C -33.8 150.401 -36.2 149.601 -36.2 149.601 L -36.6 147.601 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 1.8 108.001 C 1.8 108.001 6.2 108.001 5 109.601 C 3.8 111.201 0.6 110.801 0.6 110.801 L 1.8 108.001 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -8.2 113.601 C -8.2 113.601 -1.694 111.46 -4.2 114.801 C -5.4 116.401 -7.8 115.601 -7.8 115.601 L -8.2 113.601 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -19.4 118.401 C -19.4 118.401 -14.2 118.001 -15.4 119.601 C -16.6 121.201 -19 120.401 -19 120.401 L -19.4 118.401 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -27 124.401 C -27 124.401 -21.8 124.001 -23 125.601 C -24.2 127.201 -26.6 126.401 -26.6 126.401 L -27 124.401 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -33.8 129.201 C -33.8 129.201 -28.6 128.801 -29.8 130.401 C -31 132.001 -33.4 131.201 -33.4 131.201 L -33.8 129.201 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 5.282 135.598 C 5.282 135.598 12.203 135.066 10.606 137.195 C 9.009 139.325 5.814 138.26 5.814 138.26 L 5.282 135.598 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 15.682 130.798 C 15.682 130.798 22.603 130.266 21.006 132.395 C 19.409 134.525 16.214 133.46 16.214 133.46 L 15.682 130.798 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 26.482 126.398 C 26.482 126.398 33.403 125.866 31.806 127.995 C 30.209 130.125 27.014 129.06 27.014 129.06 L 26.482 126.398 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 36.882 121.598 C 36.882 121.598 43.803 121.066 42.206 123.195 C 40.609 125.325 37.414 124.26 37.414 124.26 L 36.882 121.598 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 9.282 103.598 C 9.282 103.598 16.203 103.066 14.606 105.195 C 13.009 107.325 9.014 107.06 9.014 107.06 L 9.282 103.598 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 19.282 100.398 C 19.282 100.398 26.203 99.866 24.606 101.995 C 23.009 104.125 18.614 103.86 18.614 103.86 L 19.282 100.398 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -3.4 140.401 C -3.4 140.401 1.8 140.001 0.6 141.601 C -0.6 143.201 -3 142.401 -3 142.401 L -3.4 140.401 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -76.6 41.2 C -76.6 41.2 -81 50 -81.4 53.2 C -81.4 53.2 -80.6 44.4 -79.4 42.4 C -78.2 40.4 -76.6 41.2 -76.6 41.2 z} -tags _tmp_transform -fill #992600 -stroke {} +$w create path {M -95 55.2 C -95 55.2 -98.2 69.6 -97.8 72.4 C -97.8 72.4 -99 60.8 -98.6 59.6 C -98.2 58.4 -95 55.2 -95 55.2 z} -tags _tmp_transform -fill #992600 -stroke {} +$w create path {M -74.2 -19.4 L -74.4 -16.2 L -76.6 -16 C -76.6 -16 -62.4 -3.4 -61.8 4.2 C -61.8 4.2 -61 -4 -74.2 -19.4 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -70.216 -18.135 C -70.647 -18.551 -70.428 -19.296 -70.836 -19.556 C -71.645 -20.072 -69.538 -20.129 -69.766 -20.845 C -70.149 -22.051 -69.962 -22.072 -70.084 -23.348 C -70.141 -23.946 -69.553 -25.486 -69.168 -25.926 C -67.722 -27.578 -69.046 -30.51 -67.406 -32.061 C -67.102 -32.35 -66.726 -32.902 -66.441 -33.32 C -65.782 -34.283 -64.598 -34.771 -63.648 -35.599 C -63.33 -35.875 -63.531 -36.702 -62.962 -36.61 C -62.248 -36.495 -61.007 -36.625 -61.052 -35.784 C -61.165 -33.664 -62.494 -31.944 -63.774 -30.276 C -63.323 -29.572 -63.781 -28.937 -64.065 -28.38 C -65.4 -25.76 -65.211 -22.919 -65.385 -20.079 C -65.39 -19.994 -65.697 -19.916 -65.689 -19.863 C -65.336 -17.528 -64.752 -15.329 -63.873 -13.1 C -63.507 -12.17 -63.036 -11.275 -62.886 -10.348 C -62.775 -9.662 -62.672 -8.829 -63.08 -8.124 C -61.045 -5.234 -62.354 -2.583 -61.185 0.948 C -60.978 1.573 -59.286 3.487 -59.749 3.326 C -62.262 2.455 -62.374 2.057 -62.551 1.304 C -62.697 0.681 -63.027 -0.696 -63.264 -1.298 C -63.328 -1.462 -63.499 -3.346 -63.577 -3.468 C -65.09 -5.85 -63.732 -5.674 -65.102 -8.032 C -66.53 -8.712 -67.496 -9.816 -68.619 -10.978 C -68.817 -11.182 -67.674 -11.906 -67.855 -12.119 C -68.947 -13.408 -70.1 -14.175 -69.764 -15.668 C -69.609 -16.358 -69.472 -17.415 -70.216 -18.135 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -73.8 -16.4 C -73.8 -16.4 -73.4 -9.6 -71 -8 C -68.6 -6.4 -69.8 -7.2 -73 -8.4 C -76.2 -9.6 -75 -10.4 -75 -10.4 C -75 -10.4 -77.8 -10 -75.4 -8 C -73 -6 -69.4 -3.6 -71 -3.6 C -72.6 -3.6 -80.2 -7.6 -80.2 -10.4 C -80.2 -13.2 -81.2 -17.3 -81.2 -17.3 C -81.2 -17.3 -80.1 -18.1 -75.3 -18 C -75.3 -18 -73.9 -17.3 -73.8 -16.4 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -74.6 2.2 C -74.6 2.2 -83.12 -0.591 -101.6 2.8 C -101.6 2.8 -92.569 0.722 -73.8 3 C -63.5 4.25 -74.6 2.2 -74.6 2.2 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -72.502 2.129 C -72.502 2.129 -80.748 -1.389 -99.453 0.392 C -99.453 0.392 -90.275 -0.897 -71.774 2.995 C -61.62 5.131 -72.502 2.129 -72.502 2.129 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -70.714 2.222 C -70.714 2.222 -78.676 -1.899 -97.461 -1.514 C -97.461 -1.514 -88.213 -2.118 -70.052 3.14 C -60.086 6.025 -70.714 2.222 -70.714 2.222 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -69.444 2.445 C -69.444 2.445 -76.268 -1.862 -93.142 -2.96 C -93.142 -2.96 -84.803 -2.79 -68.922 3.319 C -60.206 6.672 -69.444 2.445 -69.444 2.445 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 45.84 12.961 C 45.84 12.961 44.91 13.605 45.124 12.424 C 45.339 11.243 73.547 -1.927 77.161 -1.677 C 77.161 -1.677 46.913 11.529 45.84 12.961 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 42.446 13.6 C 42.446 13.6 41.57 14.315 41.691 13.121 C 41.812 11.927 68.899 -3.418 72.521 -3.452 C 72.521 -3.452 43.404 12.089 42.446 13.6 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 39.16 14.975 C 39.16 14.975 38.332 15.747 38.374 14.547 C 38.416 13.348 58.233 -2.149 68.045 -4.023 C 68.045 -4.023 50.015 4.104 39.16 14.975 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 36.284 16.838 C 36.284 16.838 35.539 17.532 35.577 16.453 C 35.615 15.373 53.449 1.426 62.28 -0.26 C 62.28 -0.26 46.054 7.054 36.284 16.838 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 4.6 164.801 C 4.6 164.801 -10.6 162.401 6.2 160.801 C 6.2 160.801 24.2 158.801 28.2 153.601 C 28.2 153.601 41.8 144.401 44.6 144.001 C 47.4 143.601 63.8 140.001 64.2 137.601 C 64.6 135.201 70.6 132.801 72.2 133.601 C 73.8 134.401 73.8 143.601 71 144.401 C 68.2 145.201 49.4 152.401 43 153.601 C 36.6 154.801 25 162.401 20.2 163.601 C 15.4 164.801 4.6 164.801 4.6 164.801 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 77.6 127.401 C 77.6 127.401 74.6 129.001 73.4 131.601 C 73.4 131.601 67 142.201 52.8 145.401 C 52.8 145.401 29.8 154.401 22 156.401 C 22 156.401 8.6 161.401 1.2 160.601 C 1.2 160.601 -5.8 160.801 0.4 162.401 C 0.4 162.401 20.6 160.401 24 158.601 C 24 158.601 39.6 153.401 42.6 150.801 C 45.6 148.201 63.8 143.201 66 141.201 C 68.2 139.201 78 130.801 77.6 127.401 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 18.882 158.911 C 18.882 158.911 24.111 158.685 22.958 160.234 C 21.805 161.784 19.357 160.91 19.357 160.91 L 18.882 158.911 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 11.68 160.263 C 11.68 160.263 16.908 160.037 15.756 161.586 C 14.603 163.136 12.155 162.263 12.155 162.263 L 11.68 160.263 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 1.251 161.511 C 1.251 161.511 6.48 161.284 5.327 162.834 C 4.174 164.383 1.726 163.51 1.726 163.51 L 1.251 161.511 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -6.383 162.055 C -6.383 162.055 -1.154 161.829 -2.307 163.378 C -3.46 164.928 -5.908 164.054 -5.908 164.054 L -6.383 162.055 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 35.415 151.513 C 35.415 151.513 42.375 151.212 40.84 153.274 C 39.306 155.336 36.047 154.174 36.047 154.174 L 35.415 151.513 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 45.73 147.088 C 45.73 147.088 51.689 143.787 51.155 148.849 C 50.885 151.405 46.362 149.749 46.362 149.749 L 45.73 147.088 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 54.862 144.274 C 54.862 144.274 62.021 140.573 60.287 146.035 C 59.509 148.485 55.493 146.935 55.493 146.935 L 54.862 144.274 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 64.376 139.449 C 64.376 139.449 68.735 134.548 69.801 141.21 C 70.207 143.748 65.008 142.11 65.008 142.11 L 64.376 139.449 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 26.834 155.997 C 26.834 155.997 32.062 155.77 30.91 157.32 C 29.757 158.869 27.308 157.996 27.308 157.996 L 26.834 155.997 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 62.434 34.603 C 62.434 34.603 61.708 35.268 61.707 34.197 C 61.707 33.127 79.191 19.863 88.034 18.479 C 88.034 18.479 71.935 25.208 62.434 34.603 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 65.4 98.4 C 65.4 98.4 87.401 120.801 96.601 124.401 C 96.601 124.401 105.801 135.601 101.801 161.601 C 101.801 161.601 98.601 169.201 95.401 148.401 C 95.401 148.401 98.601 123.201 87.401 139.201 C 87.401 139.201 79 129.301 85.4 129.601 C 85.4 129.601 88.601 131.601 89.001 130.001 C 89.401 128.401 81.4 114.801 64.2 100.4 C 47 86 65.4 98.4 65.4 98.4 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M 7 137.201 C 7 137.201 6.8 135.401 8.6 136.201 C 10.4 137.001 104.601 143.201 136.201 167.201 C 136.201 167.201 91.001 144.001 7 137.201 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 17.4 132.801 C 17.4 132.801 17.2 131.001 19 131.801 C 20.8 132.601 157.401 131.601 181.001 164.001 C 181.001 164.001 159.001 138.801 17.4 132.801 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 29 128.801 C 29 128.801 28.8 127.001 30.6 127.801 C 32.4 128.601 205.801 115.601 229.401 148.001 C 229.401 148.001 219.801 122.401 29 128.801 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 39 124.001 C 39 124.001 38.8 122.201 40.6 123.001 C 42.4 123.801 164.601 85.2 188.201 117.601 C 188.201 117.601 174.801 93 39 124.001 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -19 146.801 C -19 146.801 -19.2 145.001 -17.4 145.801 C -15.6 146.601 2.2 148.801 4.2 187.601 C 4.2 187.601 -3 145.601 -19 146.801 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -27.8 148.401 C -27.8 148.401 -28 146.601 -26.2 147.401 C -24.4 148.201 -10.2 143.601 -13 182.401 C -13 182.401 -11.8 147.201 -27.8 148.401 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -35.8 148.801 C -35.8 148.801 -36 147.001 -34.2 147.801 C -32.4 148.601 -17 149.201 -29.4 171.601 C -29.4 171.601 -19.8 147.601 -35.8 148.801 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 11.526 104.465 C 11.526 104.465 11.082 106.464 12.631 105.247 C 28.699 92.622 61.141 33.72 116.826 28.086 C 116.826 28.086 78.518 15.976 11.526 104.465 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 22.726 102.665 C 22.726 102.665 21.363 101.472 23.231 100.847 C 25.099 100.222 137.541 27.72 176.826 35.686 C 176.826 35.686 149.719 28.176 22.726 102.665 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 1.885 108.767 C 1.885 108.767 1.376 110.366 3.087 109.39 C 12.062 104.27 15.677 47.059 59.254 45.804 C 59.254 45.804 26.843 31.09 1.885 108.767 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -18.038 119.793 C -18.038 119.793 -19.115 121.079 -17.162 120.825 C -6.916 119.493 14.489 78.222 58.928 83.301 C 58.928 83.301 26.962 68.955 -18.038 119.793 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -6.8 113.667 C -6.8 113.667 -7.611 115.136 -5.742 114.511 C 4.057 111.237 17.141 66.625 61.729 63.078 C 61.729 63.078 27.603 55.135 -6.8 113.667 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -25.078 124.912 C -25.078 124.912 -25.951 125.954 -24.369 125.748 C -16.07 124.669 1.268 91.24 37.264 95.354 C 37.264 95.354 11.371 83.734 -25.078 124.912 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -32.677 130.821 C -32.677 130.821 -33.682 131.866 -32.091 131.748 C -27.923 131.439 2.715 98.36 21.183 113.862 C 21.183 113.862 9.168 95.139 -32.677 130.821 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 36.855 98.898 C 36.855 98.898 35.654 97.543 37.586 97.158 C 39.518 96.774 160.221 39.061 198.184 51.927 C 198.184 51.927 172.243 41.053 36.855 98.898 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 3.4 163.201 C 3.4 163.201 3.2 161.401 5 162.201 C 6.8 163.001 22.2 163.601 9.8 186.001 C 9.8 186.001 19.4 162.001 3.4 163.201 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 13.8 161.601 C 13.8 161.601 13.6 159.801 15.4 160.601 C 17.2 161.401 35 163.601 37 202.401 C 37 202.401 29.8 160.401 13.8 161.601 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 20.6 160.001 C 20.6 160.001 20.4 158.201 22.2 159.001 C 24 159.801 48.6 163.201 72.2 195.601 C 72.2 195.601 36.6 158.801 20.6 160.001 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 28.225 157.972 C 28.225 157.972 27.788 156.214 29.678 156.768 C 31.568 157.322 52.002 155.423 90.099 189.599 C 90.099 189.599 43.924 154.656 28.225 157.972 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 38.625 153.572 C 38.625 153.572 38.188 151.814 40.078 152.368 C 41.968 152.922 76.802 157.423 128.499 192.399 C 128.499 192.399 54.324 150.256 38.625 153.572 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -1.8 142.001 C -1.8 142.001 -2 140.201 -0.2 141.001 C 1.6 141.801 55 144.401 85.4 171.201 C 85.4 171.201 50.499 146.426 -1.8 142.001 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -11.8 146.001 C -11.8 146.001 -12 144.201 -10.2 145.001 C -8.4 145.801 16.2 149.201 39.8 181.601 C 39.8 181.601 4.2 144.801 -11.8 146.001 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 49.503 148.962 C 49.503 148.962 48.938 147.241 50.864 147.655 C 52.79 148.068 87.86 150.004 141.981 181.098 C 141.981 181.098 64.317 146.704 49.503 148.962 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 57.903 146.562 C 57.903 146.562 57.338 144.841 59.264 145.255 C 61.19 145.668 96.26 147.604 150.381 178.698 C 150.381 178.698 73.317 143.904 57.903 146.562 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M 67.503 141.562 C 67.503 141.562 66.938 139.841 68.864 140.255 C 70.79 140.668 113.86 145.004 203.582 179.298 C 203.582 179.298 82.917 138.904 67.503 141.562 z} -tags _tmp_transform -fill #ffffff -stroke #000000 +$w create path {M -43.8 148.401 C -43.8 148.401 -38.6 148.001 -39.8 149.601 C -41 151.201 -43.4 150.401 -43.4 150.401 L -43.8 148.401 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -13 162.401 C -13 162.401 -7.8 162.001 -9 163.601 C -10.2 165.201 -12.6 164.401 -12.6 164.401 L -13 162.401 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -21.8 162.001 C -21.8 162.001 -16.6 161.601 -17.8 163.201 C -19 164.801 -21.4 164.001 -21.4 164.001 L -21.8 162.001 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -117.169 150.182 C -117.169 150.182 -112.124 151.505 -113.782 152.624 C -115.439 153.744 -117.446 152.202 -117.446 152.202 L -117.169 150.182 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -115.169 140.582 C -115.169 140.582 -110.124 141.905 -111.782 143.024 C -113.439 144.144 -115.446 142.602 -115.446 142.602 L -115.169 140.582 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -122.369 136.182 C -122.369 136.182 -117.324 137.505 -118.982 138.624 C -120.639 139.744 -122.646 138.202 -122.646 138.202 L -122.369 136.182 z} -tags _tmp_transform -fill #000000 -stroke {} +$w create path {M -42.6 211.201 C -42.6 211.201 -44.2 211.201 -48.2 213.201 C -50.2 213.201 -61.4 216.801 -67 226.801 C -67 226.801 -54.6 217.201 -42.6 211.201 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 45.116 303.847 C 45.257 304.105 45.312 304.525 45.604 304.542 C 46.262 304.582 47.495 304.883 47.37 304.247 C 46.522 299.941 45.648 295.004 41.515 293.197 C 40.876 292.918 39.434 293.331 39.36 294.215 C 39.233 295.739 39.116 297.088 39.425 298.554 C 39.725 299.975 41.883 299.985 42.8 298.601 C 43.736 300.273 44.168 302.116 45.116 303.847 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 34.038 308.581 C 34.786 309.994 34.659 311.853 36.074 312.416 C 36.814 312.71 38.664 311.735 38.246 310.661 C 37.444 308.6 37.056 306.361 35.667 304.55 C 35.467 304.288 35.707 303.755 35.547 303.427 C 34.953 302.207 33.808 301.472 32.4 301.801 C 31.285 304.004 32.433 306.133 33.955 307.842 C 34.091 307.994 33.925 308.37 34.038 308.581 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -5.564 303.391 C -5.672 303.014 -5.71 302.551 -5.545 302.23 C -5.014 301.197 -4.221 300.075 -4.558 299.053 C -4.906 297.997 -6.022 298.179 -6.672 298.748 C -7.807 299.742 -7.856 301.568 -8.547 302.927 C -8.743 303.313 -8.692 303.886 -9.133 304.277 C -9.607 304.698 -10.047 306.222 -9.951 306.793 C -9.898 307.106 -10.081 317.014 -9.859 316.751 C -9.24 316.018 -6.19 306.284 -6.121 305.392 C -6.064 304.661 -5.332 304.196 -5.564 303.391 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -31.202 296.599 C -28.568 294.1 -25.778 291.139 -26.22 287.427 C -26.336 286.451 -28.111 286.978 -28.298 287.824 C -29.1 291.449 -31.139 294.11 -33.707 296.502 C -35.903 298.549 -37.765 304.893 -38 305.401 C -34.303 300.145 -32.046 297.399 -31.202 296.599 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -44.776 290.635 C -44.253 290.265 -44.555 289.774 -44.338 289.442 C -43.385 287.984 -42.084 286.738 -42.066 285 C -42.063 284.723 -42.441 284.414 -42.776 284.638 C -43.053 284.822 -43.395 284.952 -43.503 285.082 C -45.533 287.531 -46.933 290.202 -48.376 293.014 C -48.559 293.371 -49.703 297.862 -49.39 297.973 C -49.151 298.058 -47.431 293.877 -47.221 293.763 C -45.958 293.077 -45.946 291.462 -44.776 290.635 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -28.043 310.179 C -27.599 309.31 -26.023 308.108 -26.136 307.219 C -26.254 306.291 -25.786 304.848 -26.698 305.536 C -27.955 306.484 -31.404 307.833 -31.674 313.641 C -31.7 314.212 -28.726 311.519 -28.043 310.179 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -13.6 293.001 C -13.2 292.333 -12.492 292.806 -12.033 292.543 C -11.385 292.171 -10.774 291.613 -10.482 290.964 C -9.512 288.815 -7.743 286.995 -7.6 284.601 C -9.091 283.196 -9.77 285.236 -10.4 286.201 C -11.723 284.554 -12.722 286.428 -14.022 286.947 C -14.092 286.975 -14.305 286.628 -14.38 286.655 C -15.557 287.095 -16.237 288.176 -17.235 288.957 C -17.406 289.091 -17.811 288.911 -17.958 289.047 C -18.61 289.65 -19.583 289.975 -19.863 290.657 C -20.973 293.364 -24.113 295.459 -26 303.001 C -25.619 303.91 -21.488 296.359 -21.001 295.661 C -20.165 294.465 -20.047 297.322 -18.771 296.656 C -18.72 296.629 -18.534 296.867 -18.4 297.001 C -18.206 296.721 -17.988 296.492 -17.6 296.601 C -17.6 296.201 -17.734 295.645 -17.533 295.486 C -16.296 294.509 -16.38 293.441 -15.6 292.201 C -15.142 292.99 -14.081 292.271 -13.6 293.001 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 46.2 347.401 C 46.2 347.401 53.6 327.001 49.2 315.801 C 49.2 315.801 60.6 337.401 56 348.601 C 56 348.601 55.6 338.201 51.6 333.201 C 51.6 333.201 47.6 346.001 46.2 347.401 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 31.4 344.801 C 31.4 344.801 36.8 336.001 28.8 317.601 C 28.8 317.601 28 338.001 21.2 349.001 C 21.2 349.001 35.4 328.801 31.4 344.801 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 21.4 342.801 C 21.4 342.801 21.2 322.801 21.6 319.801 C 21.6 319.801 17.8 336.401 7.6 346.001 C 7.6 346.001 22 334.001 21.4 342.801 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 11.8 310.801 C 11.8 310.801 17.8 324.401 7.8 342.801 C 7.8 342.801 14.2 330.601 9.4 323.601 C 9.4 323.601 12 320.201 11.8 310.801 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -7.4 342.401 C -7.4 342.401 -8.4 326.801 -6.6 324.601 C -6.6 324.601 -6.4 318.201 -6.8 317.201 C -6.8 317.201 -2.8 311.001 -2.6 318.401 C -2.6 318.401 -1.2 326.201 1.6 330.801 C 1.6 330.801 5.2 336.201 5 342.601 C 5 342.601 -5 312.401 -7.4 342.401 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -11 314.801 C -11 314.801 -17.6 325.601 -19.4 344.601 C -19.4 344.601 -20.8 338.401 -17 324.001 C -17 324.001 -12.8 308.601 -11 314.801 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -32.8 334.601 C -32.8 334.601 -27.8 329.201 -26.4 324.201 C -26.4 324.201 -22.8 308.401 -29.2 317.001 C -29.2 317.001 -29 325.001 -37.2 332.401 C -37.2 332.401 -32.4 330.001 -32.8 334.601 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -38.6 329.601 C -38.6 329.601 -35.2 312.201 -34.4 311.401 C -34.4 311.401 -32.6 308.001 -35.4 311.201 C -35.4 311.201 -44.2 330.401 -48.2 337.001 C -48.2 337.001 -40.2 327.801 -38.6 329.601 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -44.4 313.001 C -44.4 313.001 -32.8 290.601 -54.6 316.401 C -54.6 316.401 -43.6 306.601 -44.4 313.001 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -59.8 298.401 C -59.8 298.401 -55 279.601 -52.4 279.801 C -52.4 279.801 -44.2 270.801 -50.8 281.401 C -50.8 281.401 -56.8 291.001 -56.2 300.801 C -56.2 300.801 -56.8 291.201 -59.8 298.401 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 270.5 287 C 270.5 287 258.5 277 256 273.5 C 256 273.5 269.5 292 269.5 299 C 269.5 299 272 291.5 270.5 287 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 276 265 C 276 265 255 250 251.5 242.5 C 251.5 242.5 278 272 278 276.5 C 278 276.5 278.5 267.5 276 265 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 293 111 C 293 111 281 103 279.5 105 C 279.5 105 290 111.5 292.5 120 C 292.5 120 291 111 293 111 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M 301.5 191.5 L 284 179.5 C 284 179.5 303 196.5 303.5 200.5 L 301.5 191.5 z} -tags _tmp_transform -fill #cccccc -stroke {} +$w create path {M -89.25 169 L -67.25 173.75} -tags _tmp_transform -fill black -stroke #000000 +$w create path {M -39 331 C -39 331 -39.5 327.5 -48.5 338} -tags _tmp_transform -fill black -stroke #000000 +$w create path {M -33.5 336 C -33.5 336 -31.5 329.5 -38 334} -tags _tmp_transform -fill black -stroke #000000 +$w create path {M 20.5 344.5 C 20.5 344.5 22 333.5 10.5 346.5} -tags _tmp_transform -fill black -stroke #000000 + +$w move _tmp_transform 200 200 + diff --git a/pd/tkpath/demos/transforms.tcl b/pd/tkpath/demos/transforms.tcl new file mode 100644 index 0000000000000000000000000000000000000000..54499e588218b43b332a0837b244ae0850208e3a --- /dev/null +++ b/pd/tkpath/demos/transforms.tcl @@ -0,0 +1 @@ +package require tkpath 0.3.0 set t .c_transforms destroy $t toplevel $t set w $t.c pack [tkp::canvas $w -bg white -width 480 -height 300] set mskewx1 [::tkp::transform skewx 0.3] set mskewx2 [::tkp::transform skewx 0.5] set mrot [::tkp::transform rotate [expr 3.1415/4] 100 100] set g1 [$w gradient create linear -stops {{0 lightblue} {1 blue}}] $w create path "M 10 10 h 200 v 50 h -200 z" -fill $g1 -matrix $mskewx1 set g2 [$w gradient create linear -stops {{0 #f60} {1 #ff6}}] $w create path "M 10 70 h 200 v 50 h -200 z" -fill $g2 -matrix $mrot set g4 [$w gradient create linear -stops {{0 white} {0.5 black} {1 white}}] $w create path "M 10 220 h 200 v 50 h -200 z" -fill $g4 -matrix $mskewx2 \ No newline at end of file diff --git a/pd/tkpath/demos/trees.gif b/pd/tkpath/demos/trees.gif new file mode 100644 index 0000000000000000000000000000000000000000..7c364abb8098b3ecc5850ec61dfc6417d6392d77 Binary files /dev/null and b/pd/tkpath/demos/trees.gif differ diff --git a/pd/tkpath/doc/README.txt b/pd/tkpath/doc/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..af18fdeb165f8d89fb675319c69bcc6a298c68ed --- /dev/null +++ b/pd/tkpath/doc/README.txt @@ -0,0 +1,521 @@ + + tkpath README + _____________ + +This package implements a canvas widget which supports all features of the +original canvas but adds a number of additional things. There are a +number of new item types that are modelled after its SVG counterpart, +see http://www.w3.org/TR/SVG11/. In addition, all items are put in a tree +structure with a persistent root item with id 0. All other items are +descendants of this root item. The standard canvas items will always be a +child of the root item. The tkpath items, described below, are by default +a child of the root item, but can be configured to be a child of any group +item using the -parent option. + +There can be subtle differences compared to the original canvas. +One such situation is where an option value has switched from an integer +to float (double). + + o Syntax: The canvas is created using: + + ::tkp::canvas pathName ?options? + + It creates a command as usual: + + pathName option ?arg arg ...? + + o The canvas tree structure: + + 0---- + 1 + 2 + 3 + 4 + 5---- + 6 + 7 + 8---- + 9 + 10 + 11 + 12 + + o Additional commands + + pathName ancestors tagOrId + Returns a list of item id's of the first item matching tagOrId + starting with the root item with id 0. + + pathName children tagOrId + Lists all children of the first item matching tagOrId. + + pathName depth tagOrId + Returns the depth in the tree hierarchy of the first + item matching tagOrId. The root item has depth 0 and children + of the root has depth 1 and so on. + + pathName distance tagOrId x y + Returns the closest distance between the point (x, y) and the first + item matching tagOrId. + + pathName firstchild tagOrId + Returns the first child item of the first item matching tagOrId. + Applies only for groups. + + pathName gradient command ?options? + See tkp::gradient for the commands. The gradients created with this + command are local to the canvas instance. Only gradients defined + this way can be used. + + pathName lastchild tagOrId + Returns the last child item of the first item matching tagOrId. + Applies only for groups. + + pathName nextsibling tagOrId + Returns the next sibling item of the first item matching tagOrId. + If tagOrId is the last child we return empty. + + pathName parent tagOrId + Returns the parent item of the first item matching tagOrId. This + command works for all items, also for the standard ones. It is + therefore better to use this than 'cget id -parent' which is only + supported for the new tkpath items. + + pathName prevsibling tagOrId + Returns the previous sibling item of the first item matching tagOrId. + If tagOrId is the first child we return empty. + pathName style cmd ?options? + See tkp::style for the commands. The styles created with this + command are local to the canvas instance. Only styles defined + this way can be used. + + pathName types + List all item types defined in canvas. + + o Additional options + + -tagstyle expr|exact|glob Not implemented. + + o Commands affected by changes + + lower/raise: + movement is constrained to siblings. If reference tagOrId + not given it defaults to first/last item of the root items children. + Items which are not siblings to the reference tagOrId are silently + ignored. Good or bad? + + find above/below: + is constrained to siblings. Good or bad? + + scale/move: + if you apply scale or move on a group item it will apply this to all its + descendants, also to child group items in a recursive way. + + tag "all": + Note that this presently also includes the root item which can result in some + unexpected behavior. In many case you can operate on the root item (0) instead. + As an example, if you want to move all items in canvas, then do: + pathName move 0 x y + and similar for scale etc. + + o New items + + There are various differences compared to SVG. + The display attribute names are adapted to tcl conventions, see below. + Also, SVG is web oriented and therefore tolerates parameter errors to some + degree, while tk is a programming tool and typically generates errors + if parameters are wrong. Some syntax changes have also been made. One such is + the -matrix option where we have delegated specific transforms to our support + functions in tkpath.tcl. Where the SVG tag names coincide with the ordinary + canvas item names we have added a "p" in front of its name instead. + + New items: + circle + ellipse + group + path + pimage + pline + polyline + ppolygon + prect + ptext + + o The options + + The options can be separated into a few groups depending on the nature + of an item for which they apply. Not all are implemented. + + Fill (fillOptions): + -fill color|gradientToken this is either a usual tk color + or the name of a gradient + -fillopacity float (0,1) + -fillrule nonzero|evenodd + + Stroke (strokeOptions): + -stroke color + -strokedasharray dashArray + -strokelinecap + -strokelinejoin + -strokemiterlimit float + -strokeopacity float (0,1) + -strokewidth float + + Generic (genericOptions): + -matrix {{a b} {c d} {tx ty}} + -parent tagOrId + -state + -style styleToken + -tags tagList + + A matrix is specified by a double list as {{a b} {c d} {tx ty}}. + There are utility functions to create a matrix using simpler transformations, + such as rotation, translation etc. + + The styleToken is a style created with 'pathName style create'. + It's options take precedence over any other options set directly. + This is how SVG works (bad?). Currently all a style's options ever set + are recorded in a cumulative way using a mask. Even if an option is set + to its default it takes precedence over an items option. + + o The group item + + A group item is merely a placeholder for other items, similar to how a + frame widget is a container for other widgets. It is a building block for + the tree structure. Unlike other items, and unlike frame widgets, it + doesn't display anything. It has no coordinates which is an additional + difference. The root item is a special group item with id 0 and tags + equal to "root". The root group can be configured like other items, but + its -tags and -parent options are read only. + Options set in a group are inherited by its children but they never override + options explicitly set in children. This also applies to group items configured + with a -style. + + .c create group ?fillOptions strokeOptions genericOptions? + + o The path item + + The path specification must be a single list and not concateneted with + the rest of the command: + + right: .c create path {M 10 10 h 10 v 10 h -10 z} -fill blue + wrong: .c create path M 10 10 h 10 v 10 h -10 z -fill blue ;# Error + + Furthermore, coordinates are pixel coordinates and nothing else. + SVG: It implements the complete syntax of the path elements d attribute with + one major difference: all separators must be whitespace, no commas, no + implicit assumptions; all instructions and numbers must form a tcl list. + + .c create path pathSpec ?fillOptions strokeOptions genericOptions? + + All path specifications are normalized initially to the fundamental atoms + M, L, A, Q, and C, all upper case. When you use the canvas 'coords' command + it is the normalized path spec that is returned. Bad? + + Visualize this as a pen which always has a current coordinate after + the first M. Coordinates are floats: + + M x y Put the pen on the paper at specified coordinate. + Must be the first atom but can appear any time later. + The pen doesn't draw anything when moved to this point. + L x y Draw a straight line to the given coordinate. + H x Draw a horizontal line to the given x coordinate. + V y Draw a vertical line to the given y coordinate. + A rx ry phi largeArc sweep x y + Draw an elliptical arc from the current point to (x, y). + The points are on an ellipse with x-radius rx and y-radius ry. + The ellipse is rotated by phi degrees. If the arc is less than + 180 degrees, largeArc is zero, else it is one. If the arc is to be + drawn in cw direction, sweep is one, and zero for the ccw + direction. + NB: the start and end points may not coincide else the result + is undefined. If you want to make a circle just do two + 180 degree arcs. + Q x1 y1 x y + Draw a qadratic Bezier curve from the current point to (x, y) + using control point (x1, y1). + T x y Draw a qadratic Bezier curve from the current point to (x, y) + The control point will be the reflection of the previous Q atoms + control point. This makes smooth paths. + C x1 y1 x2 y2 x y + Draw a cubic Bezier curve from the current point to (x, y) + using control points (x1, y1) and (x2, y2). + S x2 y2 x y + Draw a cubic Bezier curve from the current point to (x, y), using + (x2, y2) as the control point for this new endpoint. The first + control point will be the reflection of the previous C atoms + ending control point. This makes smooth paths. + Z Close path by drawing from the current point to the preceeding M + point. + + You may use lower case characters for all atoms which then means that all + coordinates, where relevant, are interpreted as coordinates relative the + current point. + + o The prect item + + This is a rectangle item with optionally rounded corners. + Item specific options: + + -rx corner x-radius, or if -ry not given it sets the uniform radius. + -ry corner y-radius + + .c create prect x1 y1 x2 y2 ?-rx -ry fillOptions strokeOptions genericOptions? + + o The circle item + + A plain circle item. Item specific options: + + -r its radius; defaults to zero + + .c create circle cx cy ?-r fillOptions strokeOptions genericOptions? + + o The ellipse item + + An ellipse item. Item specific options: + + -rx its x-radius + -ry its y-radius + + .c create ellipse cx cy ?-rx -ry fillOptions strokeOptions genericOptions? + + o The pline item + + Makes a single segment straight line. + + .c create pline x1 y1 x2 y2 ?strokeOptions genericOptions? + + o The polyline item + + Makes a multiple segment line with open ends. + + .c create polyline x1 y1 x2 y2 .... ?strokeOptions genericOptions? + + o The ppolygon item + + Makes a closed polygon. + + .c create ppolygon x1 y1 x2 y2 .... ?fillOptions strokeOptions genericOptions? + + o The pimage item + + This displays an image in the canvas anchored nw. If -width or -height is + nonzero then the image is scaled to this size prior to any affine transform. + + .c create pimage x y ?-image -width -height genericOptions? + + o The ptext item + + Displays text as expected. Note that the x coordinate marks the baseline + of the text. Gradient fills unsupported so far. Especially the font + handling and settings will likely be developed further. + Editing not implemented. The default font family and size is platform dependent. + + .c create ptext x y ?-text string -textanchor start|middle|end? + ?-fontfamily fontname -fontsize float? + ?fillOptions strokeOptions genericOptions? + + o The Matrix + + Each tkpath item has a -matrix option which defines the local coordinate + system for that item. It is defined as a double list {{a b} {c d} {tx ty}} + (better with a flat list {a b c d tx ty} ?) where a simple scaling + is {{sx 0} {0 sy} {0 0}}, a translation {{1 0} {0 1} {tx ty}}, and a + rotation around origin with an angle 'a' is {{cos(a) sin(a)} {-sin(a) cos{a}} {0 0}}. + The simplest way to interpret this is to design an extra coordinate + system according to the matrix, and then draw the item in that system. + + Inheritance works differently for the -matrix option than for the other + options which are just overwritten. Instead any set -matrix option + starting from the root, via any number of group items, to the actual + item being displayed, are nested. That is, any defined matrices from + the root down define a sequence of coordinate transformations. + + o Antialiasing, if available, is controlled by the variable tkp::antialias. + Switch on with: + set tkp::antialias 1 + + o The command tkp::pixelalign says how the platform graphics library draw + when we specify integer coordinates. Some libraries position a one pixel + wide line exactly at the pixel boundaries, and smears it out, if + antialiasing, over the adjecent pixels. This can look blurred since a + one pixel wide black line suddenly becomes a two pixel wide grey line. + It seems that cairo and quartz (MacOSX) do this, while gdi+ on Windows + doesn't. This command just provides the info for you so you may take + actions. Either you can manually position lines with odd integer widths + at the center of pixels (adding 0.5), or set the ::tkp::depixelize equal + to 1, see below. + + o With the boolean variable ::tkp::depixelize equal to 1 we try to adjust + coordinates for objects with integer line widths so that lines ... + + o Styles are created and configured using: + + tkp::style cmd ?options? + + tkp::style cget token option + Returns the value of an option. + + tkp::style configure token ?option? ?value option value...? + Configures the object in the usual tcl way. + + tkp::style create ?fillOptions strokeOptions? + Creates a style object and returns its token. + + tkp::style delete token + Deletes the object. + + tkp::style inuse token + If any item is configured with the style token 1 is + returned, else 0. + + tkp::style names + Returns all existing tokens. + + The same options as for the item are supported with the exception of -style, + -state, and -tags. + + + o Gradients can be of two types, linear and radial. They are created and + configured using: + + tkp::gradient command ?options? + + tkp::gradient cget token option + Returns the value of an option. + + tkp::gradient configure token ?option? ?value option value...? + Configures the object in the usual tcl way. + + tkp::gradient create type ?-key value ...? + Creates a linear gradient object with type any of linear or radial + and returns its token. + + tkp::gradient delete token + Deletes the object. + + tkp::gradient inuse token + If any item is configured with the gradient token 1 is + returned, else 0. + + tkp::gradient names + Returns all existing tokens. + + tkp::gradient type token + Returns the type (linear|radial) of the gradient. + + The options for linear gradients are: + -method pad|repeat|reflect partial implementation; defaults to pad + -stops {stopSpec ?stopSpec...?} + where stopSpec is a list {offset color ?opacity?}. + All offsets must be ordered and run from 0 to 1. + -lineartransition {x1 y1 x2 y2} + specifies the transtion vector relative the items bounding box. + Depending on -units it gets interpreted differently. + If -units is 'bbox' coordinates run from 0 to 1 and are relative + the items bounding box. If -units is 'userspace' then they are + defined in absolute coordinates but in the space of the items + coordinate system. It defaults to {0 0 1 0}, left to right. + -matrix {{a b} {c d} {tx ty}} + sets a specific transformation for the gradient pattern only. + NB: not sure about the order transforms, see -units. + -units bbox|userspace sets the units of the transition coordinates. + See above. Defaults to bbox. + + The options for radial gradients are the same as for linear gradients + except that the -lineartransition is replaced by a -radialtransition: + -radialtransition {cx cy ?r? ?fx fy?} + specifies the transition circles relative the items bounding box + and run from 0 to 1. They default to {0.5 0.5 0.5 0.5 0.5}. + cx,cy is the center of the end circle and fx,fy the center of the + start point. + + + o In memory drawing surface + + tkp::surface new width height + + creates an in memory drawing surface. Its format is platform dependent. + It returns a token which is a new command. + + tkp::surface names + + lists the existing surface tokens. + + The surface token commands are: + + $token copy imageName + + copies the surface to an existing image (photo) and returns the name of + the image so you can do: + set image [$token copy [image create photo]] + See Tk_PhotoPutBlock for how it affects the existing image. + + The boolean variable tkp::premultiplyalpha controls how the copy + action handles surfaces with the alpha component premultiplied. If 1 the + copy process correctly handles any format with premultiplied alpha. This + gets the highest quality for antialiasing and correct results for partial + transparency. It is also slower. If 0 the alpha values are not remultiplied + and the result is wrong for transparent regions, and gives poor antialiasing + effects. But it is faster. The default is 1. + + $token create type coords ?options? + + draws the item of type to the surface. All item types except the group + and the corresponding options as described above are supported, + except the canvas specific -tags and -state. + + $token destroy + + destroys surface. + + $token erase x y width height + + erases the indicated area to transparent. + + $token height + $token width + + returns height and width respectively. + + Note that the surface behaves different from the canvas widget. When you have put + an item there there is no way to configure it or to remove it. If you have done + a mistake then you have to erase the complete surface and start all over. + Better to experiment on the canvas and then reproduce your drawing to a surface + when you are satisfied with it. + + NB: gdi+ seems unable to produce antialiasing effects here but there seems + to be no gdi+ specific way of drawing in memory bitmaps but had to call + CreateDIBSection() which is a Win32 GDI API. + + + o Helper function for making transformation matrices: + + tkp::transform cmd ?args? + + tkp::transform rotate angle ?centerX centerY? + + tkp::transform scale factorXY ?factorY? + + tkp::transform skewx angle + + tkp::transform skewy angle + + tkp::transform translate x y + + + o Known issues: + + - See the TODO file and comments marked "@@@" in the C sources. + + + o Further documentation: + + - http://www.w3.org/TR/SVG11/ + + - http://cairographics.org + +Copyright (c) 2005-2008 Mats Bengtsson + +BSD style license. + diff --git a/pd/tkpath/doc/code.txt b/pd/tkpath/doc/code.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c6cfc9bf54a137fa5185fbcabed693402ae6c5b --- /dev/null +++ b/pd/tkpath/doc/code.txt @@ -0,0 +1,20 @@ + +The code is suposed to be structured as following: + + utils: generic support functions + style: depends on utils + gradient: depends on utils + path: depends on style + gradient + canvas: depends on path + surface: depends on path + +The idea is that path drawing should be kept completely independent from +any canvas code. This makes it possible to use path drawing as a tile +element, in a memory surface, or just anywhere else. + +The naming convention isn't that precise. Functions and records that have +some kind of generality typically have names Tk_Path* or TkPath*. + +This note is mainly written for myself to help remember that I must +try to follow it. Work in progress... + diff --git a/pd/tkpath/doc/tiger.png b/pd/tkpath/doc/tiger.png new file mode 100644 index 0000000000000000000000000000000000000000..e8cfe39efdcc928ac84ca231d9dce6ead5051b07 Binary files /dev/null and b/pd/tkpath/doc/tiger.png differ diff --git a/pd/tkpath/generic/path.c b/pd/tkpath/generic/path.c new file mode 100644 index 0000000000000000000000000000000000000000..9a4e5060cc382c9fe120eea169c2698c0815852b --- /dev/null +++ b/pd/tkpath/generic/path.c @@ -0,0 +1,157 @@ +/* + * path.c -- + * + * This file is main for the tkpath package. + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * $Id: path.c,v 1.39 2012/07/05 06:41:15 petasis Exp $ + */ + +#include "tkp.h" +#include "tkIntPath.h" + +#ifdef _WIN32 +#include <windows.h> +#endif + +/* Keep patch level release numbers odd and set even only on release. */ +#define TKPATH_VERSION "0.3" +#define TKPATH_PATCHLEVEL "0.3.2" +#define TKPATH_REQUIRE "8.5" + +int gAntiAlias = 1; +int gSurfaceCopyPremultiplyAlpha = 1; +int gDepixelize = 1; +Tcl_Interp *gInterp = NULL; + +extern int PixelAlignObjCmd(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* CONST objv[]); +extern int SurfaceInit(Tcl_Interp *interp); + + +#ifdef _WIN32 + BOOL APIENTRY + DllMain( HINSTANCE hInst, /* Library instance handle. */ + DWORD reason, /* Reason this function is being called. */ + LPVOID reserved /* Not used. */ ) + { + return TRUE; + } +#endif + + +/* + *---------------------------------------------------------------------- + * + * Tkpath_Init -- + * + * Initializer for the tkpath package. + * + * Results: + * A standard Tcl result. + * + * Side Effects: + * Tcl commands created + * + *---------------------------------------------------------------------- + */ +#ifdef __cplusplus +extern "C" { +#endif +#if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) + __declspec(dllexport) +#endif + +int Tkpath_Init(Tcl_Interp *interp) /* Tcl interpreter. */ +{ + +#if defined(USE_TCL_STUBS) + if (Tcl_InitStubs(interp, TKPATH_REQUIRE, 0) == NULL) { + return TCL_ERROR; + } +#endif + if (Tcl_PkgRequire(interp, "Tcl", TKPATH_REQUIRE, 0) == NULL) { + return TCL_ERROR; + } +#if defined(USE_TK_STUBS) + if (Tk_InitStubs(interp, TKPATH_REQUIRE, 0) == NULL) { + return TCL_ERROR; + } +#endif + if (Tcl_PkgRequire(interp, "Tk", TKPATH_REQUIRE, 0) == NULL) { + return TCL_ERROR; + } + if (Tcl_CreateNamespace(interp, "::tkp", NULL, NULL) == NULL) { + Tcl_ResetResult(interp); + } + Tcl_CreateObjCommand(interp, "::tkp::canvas", Tk_PathCanvasObjCmd, + (ClientData) Tk_MainWindow(interp), NULL); + + gInterp = interp; + + /* + * Link the ::tkp::antialias variable to control antialiasing. + */ + if (Tcl_LinkVar(interp, "::tkp::antialias", + (char *) &gAntiAlias, TCL_LINK_BOOLEAN) != TCL_OK) { + Tcl_ResetResult(interp); + } + + /* + * With gSurfaceCopyPremultiplyAlpha true we ignore the "premultiply alpha" + * and use RGB as is. Else we need to divide each RGB with alpha + * to get "true" values. + */ + if (Tcl_LinkVar(interp, "::tkp::premultiplyalpha", + (char *) &gSurfaceCopyPremultiplyAlpha, TCL_LINK_BOOLEAN) != TCL_OK) { + Tcl_ResetResult(interp); + } + if (Tcl_LinkVar(interp, "::tkp::depixelize", + (char *) &gDepixelize, TCL_LINK_BOOLEAN) != TCL_OK) { + Tcl_ResetResult(interp); + } + Tcl_CreateObjCommand(interp, "::tkp::pixelalign", + PixelAlignObjCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + + /* + * Make separate gradient objects, similar to SVG. + */ + PathGradientInit(interp); + SurfaceInit(interp); + + /* + * Style object. + */ + PathStyleInit(interp); + + return Tcl_PkgProvide(interp, "tkpath", TKPATH_PATCHLEVEL); +} + +/* + *---------------------------------------------------------------------- + * + * Tkpath_SafeInit -- + * + * This is just to provide a "safe" entry point (that is not safe!). + * + * Results: + * A standard Tcl result. + * + * Side Effects: + * Tcl commands created + * + *---------------------------------------------------------------------- + */ +#if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) + __declspec(dllexport) +#endif + +int Tkpath_SafeInit(Tcl_Interp *interp) { return Tkpath_Init(interp); } +int Tkpath_Unload(Tcl_Interp *interp) { return TCL_ERROR; } +int Tkpath_SafeUnload(Tcl_Interp *interp) { return Tkpath_Unload( interp ); } +#ifdef __cplusplus +} +#endif +/*--------------------------------------------------------------------------------*/ diff --git a/pd/tkpath/generic/pkgIndex.tcl b/pd/tkpath/generic/pkgIndex.tcl new file mode 100755 index 0000000000000000000000000000000000000000..8b40ea86ec8daf53172d16eaf465313517c9c005 --- /dev/null +++ b/pd/tkpath/generic/pkgIndex.tcl @@ -0,0 +1 @@ +package ifneeded QuickTimeTcl 3.1 [list load [file join $dir QuickTimeTcl3.1.dylib]] diff --git a/pd/tkpath/generic/tkCanvEllipse.c b/pd/tkpath/generic/tkCanvEllipse.c new file mode 100644 index 0000000000000000000000000000000000000000..25f973149fc314a8683c068383bae94bb2a18de5 --- /dev/null +++ b/pd/tkpath/generic/tkCanvEllipse.c @@ -0,0 +1,637 @@ +/* + * tkCanvEllipse.c -- + * + * This file implements the circle and ellipse canvas items modelled after its + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2007-2008 Mats Bengtsson + * + * $Id: tkCanvEllipse.c,v 1.30 2010/04/30 10:16:00 ebrunel Exp $ + */ + +#include "tkIntPath.h" +#include "tkpCanvas.h" +#include "tkCanvPathUtil.h" +#include "tkPathStyle.h" + +/* For debugging. */ +extern Tcl_Interp *gInterp; + +/* + * The structure below defines the record for each circle and ellipse item. + */ + +typedef struct EllipseItem { + Tk_PathItemEx headerEx; /* Generic stuff that's the same for all + * path types. MUST BE FIRST IN STRUCTURE. */ + char type; /* Circle or ellipse. */ + double center[2]; /* Center coord. */ + double rx; /* Radius. Circle uses rx for overall radius. */ + double ry; +} EllipseItem; + +enum { + kOvalTypeCircle, + kOvalTypeEllipse +}; + +/* + * Prototypes for procedures defined in this file: + */ + +static void ComputeEllipseBbox(Tk_PathCanvas canvas, EllipseItem *ellPtr); +static int ConfigureEllipse(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int CreateAny(Tcl_Interp *interp, Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[], char type); +static int CreateCircle(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int CreateEllipse(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeleteEllipse(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayEllipse(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height); +static void EllipseBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int mask); +static int EllipseCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int EllipseToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double EllipseToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int EllipseToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScaleEllipse(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslateEllipse(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); + + +enum { + ELLIPSE_OPTION_INDEX_RX = (1L << (PATH_STYLE_OPTION_INDEX_END + 0)), + ELLIPSE_OPTION_INDEX_RY = (1L << (PATH_STYLE_OPTION_INDEX_END + 1)), + ELLIPSE_OPTION_INDEX_R = (1L << (PATH_STYLE_OPTION_INDEX_END + 2)), +}; + +PATH_STYLE_CUSTOM_OPTION_RECORDS +PATH_CUSTOM_OPTION_TAGS +PATH_OPTION_STRING_TABLES_FILL +PATH_OPTION_STRING_TABLES_STROKE +PATH_OPTION_STRING_TABLES_STATE + +#define PATH_OPTION_SPEC_R(typeName) \ + {TK_OPTION_DOUBLE, "-rx", NULL, NULL, \ + "0.0", -1, Tk_Offset(typeName, rx), \ + 0, 0, ELLIPSE_OPTION_INDEX_R} + +#define PATH_OPTION_SPEC_RX(typeName) \ + {TK_OPTION_DOUBLE, "-rx", NULL, NULL, \ + "0.0", -1, Tk_Offset(typeName, rx), \ + 0, 0, ELLIPSE_OPTION_INDEX_RX} + +#define PATH_OPTION_SPEC_RY(typeName) \ + {TK_OPTION_DOUBLE, "-ry", NULL, NULL, \ + "0.0", -1, Tk_Offset(typeName, ry), \ + 0, 0, ELLIPSE_OPTION_INDEX_RY} + +static Tk_OptionSpec optionSpecsCircle[] = { + PATH_OPTION_SPEC_CORE(Tk_PathItemEx), + PATH_OPTION_SPEC_PARENT, + PATH_OPTION_SPEC_STYLE_FILL(Tk_PathItemEx, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(Tk_PathItemEx), + PATH_OPTION_SPEC_STYLE_STROKE(Tk_PathItemEx, "black"), + PATH_OPTION_SPEC_R(EllipseItem), + PATH_OPTION_SPEC_END +}; + +static Tk_OptionSpec optionSpecsEllipse[] = { + PATH_OPTION_SPEC_CORE(Tk_PathItemEx), + PATH_OPTION_SPEC_PARENT, + PATH_OPTION_SPEC_STYLE_FILL(Tk_PathItemEx, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(Tk_PathItemEx), + PATH_OPTION_SPEC_STYLE_STROKE(Tk_PathItemEx, "black"), + PATH_OPTION_SPEC_RX(EllipseItem), + PATH_OPTION_SPEC_RY(EllipseItem), + PATH_OPTION_SPEC_END +}; + +static Tk_OptionTable optionTableCircle = NULL; +static Tk_OptionTable optionTableEllipse = NULL; + +/* + * The structures below define the 'circle' and 'ellipse' item types by means + * of procedures that can be invoked by generic item code. + */ + +Tk_PathItemType tkCircleType = { + "circle", /* name */ + sizeof(EllipseItem), /* itemSize */ + CreateCircle, /* createProc */ + optionSpecsCircle, /* optionSpecs */ + ConfigureEllipse, /* configureProc */ + EllipseCoords, /* coordProc */ + DeleteEllipse, /* deleteProc */ + DisplayEllipse, /* displayProc */ + 0, /* flags */ + EllipseBbox, /* bboxProc */ + EllipseToPoint, /* pointProc */ + EllipseToArea, /* areaProc */ + EllipseToPostscript, /* postscriptProc */ + ScaleEllipse, /* scaleProc */ + TranslateEllipse, /* translateProc */ + (Tk_PathItemIndexProc *) NULL, /* indexProc */ + (Tk_PathItemCursorProc *) NULL, /* icursorProc */ + (Tk_PathItemSelectionProc *) NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) NULL, /* insertProc */ + (Tk_PathItemDCharsProc *) NULL, /* dTextProc */ + (Tk_PathItemType *) NULL, /* nextPtr */ +}; + +Tk_PathItemType tkEllipseType = { + "ellipse", /* name */ + sizeof(EllipseItem), /* itemSize */ + CreateEllipse, /* createProc */ + optionSpecsEllipse, /* optionSpecs */ + ConfigureEllipse, /* configureProc */ + EllipseCoords, /* coordProc */ + DeleteEllipse, /* deleteProc */ + DisplayEllipse, /* displayProc */ + 0, /* flags */ + EllipseBbox, /* bboxProc */ + EllipseToPoint, /* pointProc */ + EllipseToArea, /* areaProc */ + EllipseToPostscript, /* postscriptProc */ + ScaleEllipse, /* scaleProc */ + TranslateEllipse, /* translateProc */ + (Tk_PathItemIndexProc *) NULL, /* indexProc */ + (Tk_PathItemCursorProc *) NULL, /* icursorProc */ + (Tk_PathItemSelectionProc *) NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) NULL, /* insertProc */ + (Tk_PathItemDCharsProc *) NULL, /* dTextProc */ + (Tk_PathItemType *) NULL, /* nextPtr */ +}; + +static int +CreateCircle(Tcl_Interp *interp, Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + return CreateAny(interp, canvas, itemPtr, objc, objv, kOvalTypeCircle); +} + +static int +CreateEllipse(Tcl_Interp *interp, Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + return CreateAny(interp, canvas, itemPtr, objc, objv, kOvalTypeEllipse); +} + +static int +CreateAny(Tcl_Interp *interp, Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[], char type) +{ + EllipseItem *ellPtr = (EllipseItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &ellPtr->headerEx; + Tk_OptionTable optionTable; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + gInterp = interp; + + /* + * Carry out initialization that is needed to set defaults and to + * allow proper cleanup after errors during the the remainder of + * this procedure. + */ + TkPathInitStyle(&itemExPtr->style); + itemExPtr->canvas = canvas; + itemExPtr->styleObj = NULL; + itemExPtr->styleInst = NULL; + ellPtr->type = type; + + if (ellPtr->type == kOvalTypeCircle) { + if (optionTableCircle == NULL) { + optionTableCircle = Tk_CreateOptionTable(interp, optionSpecsCircle); + } + optionTable = optionTableCircle; + } else { + if (optionTableEllipse == NULL) { + optionTableEllipse = Tk_CreateOptionTable(interp, optionSpecsEllipse); + } + optionTable = optionTableEllipse; + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) ellPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + for (i = 1; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + if (CoordsForPointItems(interp, canvas, ellPtr->center, i, objv) != TCL_OK) { + goto error; + } + if (ConfigureEllipse(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { + return TCL_OK; + } + + error: + /* + * NB: We must unlink the item here since the TkPathCanvasItemExConfigure() + * link it to the root by default. + */ + TkPathCanvasItemDetach(itemPtr); + DeleteEllipse(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +static int +EllipseCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + EllipseItem *ellPtr = (EllipseItem *) itemPtr; + int result; + + result = CoordsForPointItems(interp, canvas, ellPtr->center, objc, objv); + if ((result == TCL_OK) && ((objc == 1) || (objc == 2))) { + ComputeEllipseBbox(canvas, ellPtr); + } + return result; +} + +static PathRect +GetBareBbox(EllipseItem *ellPtr) +{ + PathRect bbox; + + bbox.x1 = ellPtr->center[0] - ellPtr->rx; + bbox.y1 = ellPtr->center[1] - ellPtr->ry; + bbox.x2 = ellPtr->center[0] + ellPtr->rx; + bbox.y2 = ellPtr->center[1] + ellPtr->ry; + return bbox; +} + +static void +ComputeEllipseBbox(Tk_PathCanvas canvas, EllipseItem *ellPtr) +{ + Tk_PathItemEx *itemExPtr = &ellPtr->headerEx; + Tk_PathItem *itemPtr = &itemExPtr->header; + Tk_PathStyle style; + Tk_PathState state = itemExPtr->header.state; + PathRect totalBbox, bbox; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + itemExPtr->header.x1 = itemExPtr->header.x2 = + itemExPtr->header.y1 = itemExPtr->header.y2 = -1; + return; + } + style = TkPathCanvasInheritStyle(itemPtr, kPathMergeStyleNotFill); + bbox = GetBareBbox(ellPtr); + totalBbox = GetGenericPathTotalBboxFromBare(NULL, &style, &bbox); + SetGenericPathHeaderBbox(&itemExPtr->header, style.matrixPtr, &totalBbox); + TkPathCanvasFreeInheritedStyle(&style); +} + +static int +ConfigureEllipse(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[], int flags) +{ + EllipseItem *ellPtr = (EllipseItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &ellPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + Tk_Window tkwin; + //Tk_PathState state; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int mask, error; + + tkwin = Tk_PathCanvasTkwin(canvas); + for (error = 0; error <= 1; error++) { + if (!error) { + Tk_OptionTable optionTable; + optionTable = (ellPtr->type == kOvalTypeCircle) ? optionTableCircle : optionTableEllipse; + if (Tk_SetOptions(interp, (char *) ellPtr, optionTable, + objc, objv, tkwin, &savedOptions, &mask) != TCL_OK) { + continue; + } + } else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + if (TkPathCanvasItemExConfigure(interp, canvas, itemExPtr, mask) != TCL_OK) { + continue; + } + + /* + * If we reach this on the first pass we are OK and continue below. + */ + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + stylePtr->mask |= mask; + } + + stylePtr->strokeOpacity = MAX(0.0, MIN(1.0, stylePtr->strokeOpacity)); + stylePtr->fillOpacity = MAX(0.0, MIN(1.0, stylePtr->fillOpacity)); + ellPtr->rx = MAX(0.0, ellPtr->rx); + ellPtr->ry = MAX(0.0, ellPtr->ry); + if (ellPtr->type == kOvalTypeCircle) { + /* Practical. */ + ellPtr->ry = ellPtr->rx; + } +#if 0 // From old code. Needed? + state = itemPtr->state; + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + return TCL_OK; + } +#endif + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + ComputeEllipseBbox(canvas, ellPtr); + return TCL_OK; + } +} + +static void +DeleteEllipse(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display) +{ + EllipseItem *ellPtr = (EllipseItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &ellPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + Tk_OptionTable optionTable; + + if (stylePtr->fill != NULL) { + TkPathFreePathColor(stylePtr->fill); + } + if (itemExPtr->styleInst != NULL) { + TkPathFreeStyle(itemExPtr->styleInst); + } + optionTable = (ellPtr->type == kOvalTypeCircle) ? optionTableCircle : optionTableEllipse; + Tk_FreeConfigOptions((char *) itemPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +static void +DisplayEllipse(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height) +{ + EllipseItem *ellPtr = (EllipseItem *) itemPtr; + TMatrix m = GetCanvasTMatrix(canvas); + PathRect bbox; + PathAtom *atomPtr; + EllipseAtom ellAtom; + Tk_PathStyle style; + + /* === EB - 23-apr-2010: register coordinate offsets */ + TkPathSetCoordOffsets(m.tx, m.ty); + /* === */ + + /* + * We create the atom on the fly to save some memory. + */ + atomPtr = (PathAtom *)&ellAtom; + atomPtr->nextPtr = NULL; + atomPtr->type = PATH_ATOM_ELLIPSE; + ellAtom.cx = ellPtr->center[0]; + ellAtom.cy = ellPtr->center[1]; + ellAtom.rx = ellPtr->rx; + ellAtom.ry = ellPtr->ry; + + bbox = GetBareBbox(ellPtr); + style = TkPathCanvasInheritStyle(itemPtr, 0); + TkPathDrawPath(Tk_PathCanvasTkwin(canvas), drawable, atomPtr, &style, &m, &bbox); + TkPathCanvasFreeInheritedStyle(&style); +} + +static void +EllipseBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask) +{ + EllipseItem *ellPtr = (EllipseItem *) itemPtr; + ComputeEllipseBbox(canvas, ellPtr); +} + +static double +EllipseToPoint(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *pointPtr) +{ + EllipseItem *ellPtr = (EllipseItem *) itemPtr; + Tk_PathStyle style; + TMatrix *mPtr; + double bareOval[4]; + double width, dist; + int rectiLinear = 0; + int haveDist = 0; + int filled; + + style = TkPathCanvasInheritStyle(itemPtr, 0); + filled = HaveAnyFillFromPathColor(style.fill); + width = 0.0; + if (style.strokeColor != NULL) { + width = style.strokeWidth; + } + mPtr = style.matrixPtr; + if (mPtr == NULL) { + rectiLinear = 1; + bareOval[0] = ellPtr->center[0] - ellPtr->rx; + bareOval[1] = ellPtr->center[1] - ellPtr->ry; + bareOval[2] = ellPtr->center[0] + ellPtr->rx; + bareOval[3] = ellPtr->center[1] + ellPtr->ry; + + /* For tiny points make it simple. */ + if ((ellPtr->rx <= 2.0) && (ellPtr->ry <= 2.0)) { + dist = hypot(ellPtr->center[0] - pointPtr[0], ellPtr->center[1] - pointPtr[1]); + dist = MAX(0.0, dist - (ellPtr->rx + ellPtr->ry)/2.0); + haveDist = 1; + } + } else if (TMATRIX_IS_RECTILINEAR(mPtr)) { + double rx, ry; + + /* This is a situation we can treat in a simplified way. Apply the transform here. */ + rectiLinear = 1; + bareOval[0] = mPtr->a * (ellPtr->center[0] - ellPtr->rx) + mPtr->tx; + bareOval[1] = mPtr->d * (ellPtr->center[1] - ellPtr->ry) + mPtr->ty; + bareOval[2] = mPtr->a * (ellPtr->center[0] + ellPtr->rx) + mPtr->tx; + bareOval[3] = mPtr->d * (ellPtr->center[1] + ellPtr->ry) + mPtr->ty; + + /* For tiny points make it simple. */ + rx = fabs(bareOval[0] - bareOval[2])/2.0; + ry = fabs(bareOval[1] - bareOval[3])/2.0; + if ((rx <= 2.0) && (ry <= 2.0)) { + dist = hypot((bareOval[0] + bareOval[2]/2.0) - pointPtr[0], + (bareOval[1] + bareOval[3]/2.0) - pointPtr[1]); + dist = MAX(0.0, dist - (rx + ry)/2.0); + haveDist = 1; + } + } + if (!haveDist) { + if (rectiLinear) { + dist = TkOvalToPoint(bareOval, width, filled, pointPtr); + } else { + PathAtom *atomPtr; + EllipseAtom ellAtom; + + /* + * We create the atom on the fly to save some memory. + */ + atomPtr = (PathAtom *)&ellAtom; + atomPtr->nextPtr = NULL; + atomPtr->type = PATH_ATOM_ELLIPSE; + ellAtom.cx = ellPtr->center[0]; + ellAtom.cy = ellPtr->center[1]; + ellAtom.rx = ellPtr->rx; + ellAtom.ry = ellPtr->ry; + dist = GenericPathToPoint(canvas, itemPtr, &style, atomPtr, + kPathNumSegmentsEllipse+1, pointPtr); + } + } + TkPathCanvasFreeInheritedStyle(&style); + return dist; +} + +static int +EllipseToArea(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *areaPtr) +{ + EllipseItem *ellPtr = (EllipseItem *) itemPtr; + Tk_PathStyle style; + TMatrix *mPtr; + double bareOval[4], halfWidth; + int rectiLinear = 0; + int result; + + style = TkPathCanvasInheritStyle(itemPtr, 0); + halfWidth = 0.0; + if (style.strokeColor != NULL) { + halfWidth = style.strokeWidth/2.0; + } + mPtr = style.matrixPtr; + if (mPtr == NULL) { + rectiLinear = 1; + bareOval[0] = ellPtr->center[0] - ellPtr->rx; + bareOval[1] = ellPtr->center[1] - ellPtr->ry; + bareOval[2] = ellPtr->center[0] + ellPtr->rx; + bareOval[3] = ellPtr->center[1] + ellPtr->ry; + } else if (TMATRIX_IS_RECTILINEAR(mPtr)) { + + /* This is a situation we can treat in a simplified way. Apply the transform here. */ + rectiLinear = 1; + bareOval[0] = mPtr->a * (ellPtr->center[0] - ellPtr->rx) + mPtr->tx; + bareOval[1] = mPtr->d * (ellPtr->center[1] - ellPtr->ry) + mPtr->ty; + bareOval[2] = mPtr->a * (ellPtr->center[0] + ellPtr->rx) + mPtr->tx; + bareOval[3] = mPtr->d * (ellPtr->center[1] + ellPtr->ry) + mPtr->ty; + } + + if (rectiLinear) { + double oval[4]; + + /* @@@ Assuming untransformed strokes */ + oval[0] = bareOval[0] - halfWidth; + oval[1] = bareOval[1] - halfWidth; + oval[2] = bareOval[2] + halfWidth; + oval[3] = bareOval[3] + halfWidth; + + result = TkOvalToArea(oval, areaPtr); + + /* + * If the rectangle appears to overlap the oval and the oval + * isn't filled, do one more check to see if perhaps all four + * of the rectangle's corners are totally inside the oval's + * unfilled center, in which case we should return "outside". + */ + if ((result == 0) && (style.strokeColor != NULL) + && !HaveAnyFillFromPathColor(style.fill)) { + double width, height; + double xDelta1, yDelta1, xDelta2, yDelta2; + + width = (bareOval[2] - bareOval[0])/2.0 - halfWidth; + height = (bareOval[3] - bareOval[1])/2.0 - halfWidth; + if ((width <= 0.0) || (height <= 0.0)) { + return 0; + } + xDelta1 = (areaPtr[0] - ellPtr->center[0])/width; + xDelta1 *= xDelta1; + yDelta1 = (areaPtr[1] - ellPtr->center[1])/height; + yDelta1 *= yDelta1; + xDelta2 = (areaPtr[2] - ellPtr->center[0])/width; + xDelta2 *= xDelta2; + yDelta2 = (areaPtr[3] - ellPtr->center[1])/height; + yDelta2 *= yDelta2; + if (((xDelta1 + yDelta1) < 1.0) + && ((xDelta1 + yDelta2) < 1.0) + && ((xDelta2 + yDelta1) < 1.0) + && ((xDelta2 + yDelta2) < 1.0)) { + result = -1; + } + } + } else { + PathAtom *atomPtr; + EllipseAtom ellAtom; + + /* + * We create the atom on the fly to save some memory. + */ + atomPtr = (PathAtom *)&ellAtom; + atomPtr->nextPtr = NULL; + atomPtr->type = PATH_ATOM_ELLIPSE; + ellAtom.cx = ellPtr->center[0]; + ellAtom.cy = ellPtr->center[1]; + ellAtom.rx = ellPtr->rx; + ellAtom.ry = ellPtr->ry; + result = GenericPathToArea(canvas, itemPtr, &style, atomPtr, + kPathNumSegmentsEllipse+1, areaPtr); + } + TkPathCanvasFreeInheritedStyle(&style); + return result; +} + +static int +EllipseToPostscript(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass) +{ + return TCL_ERROR; +} + +static void +ScaleEllipse(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY) +{ + EllipseItem *ellPtr = (EllipseItem *) itemPtr; + + ellPtr->center[0] = originX + scaleX*(ellPtr->center[0] - originX); + ellPtr->center[1] = originY + scaleY*(ellPtr->center[1] - originY); + ellPtr->rx *= scaleX; + ellPtr->ry *= scaleY; + ScaleItemHeader(itemPtr, originX, originY, scaleX, scaleY); +} + +static void +TranslateEllipse(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double deltaX, double deltaY) +{ + EllipseItem *ellPtr = (EllipseItem *) itemPtr; + + ellPtr->center[0] += deltaX; + ellPtr->center[1] += deltaY; + TranslateItemHeader(itemPtr, deltaX, deltaY); +} + +/*----------------------------------------------------------------------*/ + diff --git a/pd/tkpath/generic/tkCanvGradient.c b/pd/tkpath/generic/tkCanvGradient.c new file mode 100644 index 0000000000000000000000000000000000000000..429e57914789f30029951e9bb4bdaa1363a16088 --- /dev/null +++ b/pd/tkpath/generic/tkCanvGradient.c @@ -0,0 +1,162 @@ +/* + * tkCanvGradients.c -- + * + * This file implements some glue between gradient objects and the canvas widget. + * + * Copyright (c) 2008 Mats Bengtsson + * + * TODO: o Add tkwin option here and there so we can free stop colors! + * + * $Id: tkCanvGradient.c,v 1.3 2012/07/04 19:43:18 petasis Exp $ + */ + +#include "tkIntPath.h" +#include "tkpCanvas.h" + +static char * kGradientNameBase = "gradient"; + +static CONST char *gradientCmds[] = { + "cget", "configure", "create", "delete", "inuse", "names", "type", + (char *) NULL +}; + +enum { + kPathGradientCmdCget = 0L, + kPathGradientCmdConfigure, + kPathGradientCmdCreate, + kPathGradientCmdDelete, + kPathGradientCmdInUse, + kPathGradientCmdNames, + kPathGradientCmdType +}; + +/* + *---------------------------------------------------------------------- + * + * CanvasGradientObjCmd -- + * + * Implements the 'pathName gradient' command using the canvas local state. + * + * Results: + * Standard Tcl result + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +int +CanvasGradientObjCmd(Tcl_Interp* interp, TkPathCanvas *canvasPtr, + int objc, Tcl_Obj* CONST objv[]) +{ + int index; + int result = TCL_OK; + + /* + * objv[2] is the subcommand: cget | configure | create | delete | names | type + */ + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], gradientCmds, "command", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + switch (index) { + + case kPathGradientCmdCget: { + if (objc != 5) { + Tcl_WrongNumArgs(interp, 3, objv, "name option"); + return TCL_ERROR; + } + result = PathGradientCget(interp, canvasPtr->tkwin, objc-3, objv+3, + &canvasPtr->gradientTable); + break; + } + + case kPathGradientCmdConfigure: { + if (objc < 4) { + Tcl_WrongNumArgs(interp, 3, objv, "name ?option? ?value option value...?"); + return TCL_ERROR; + } + result = PathGradientConfigure(interp, canvasPtr->tkwin, objc-3, objv+3, + &canvasPtr->gradientTable); + break; + } + + case kPathGradientCmdCreate: { + char str[255]; + + if (objc < 4) { + Tcl_WrongNumArgs(interp, 3, objv, "type ?option value...?"); + return TCL_ERROR; + } + sprintf(str, "%s%d", kGradientNameBase, canvasPtr->gradientUid++); + result = PathGradientCreate(interp, canvasPtr->tkwin, objc-3, objv+3, + &canvasPtr->gradientTable, str); + break; + } + + case kPathGradientCmdDelete: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "name"); + return TCL_ERROR; + } + result = PathGradientDelete(interp, objv[3], &canvasPtr->gradientTable); + break; + } + + case kPathGradientCmdInUse: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "name"); + return TCL_ERROR; + } + result = PathGradientInUse(interp, objv[3], &canvasPtr->gradientTable); + break; + } + + case kPathGradientCmdNames: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + return TCL_ERROR; + } + PathGradientNames(interp, &canvasPtr->gradientTable); + break; + } + + case kPathGradientCmdType: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "name"); + return TCL_ERROR; + } + result = PathGradientType(interp, objv[3], &canvasPtr->gradientTable); + break; + } + } + return result; +} + +/* + * CanvasGradientsFree -- + * + * Used by canvas Destroy handler to clean up all gradients. + * Note that items clean up all their gradient instances themeselves. + */ +void +CanvasGradientsFree(TkPathCanvas *canvasPtr) +{ + Tcl_HashEntry *hPtr; + Tcl_HashSearch search; + TkPathGradientMaster *gradientPtr = NULL; + + hPtr = Tcl_FirstHashEntry(&canvasPtr->gradientTable, &search); + while (hPtr != NULL) { + gradientPtr = (TkPathGradientMaster*) Tcl_GetHashValue(hPtr); + Tcl_DeleteHashEntry(hPtr); + PathGradientMasterFree(gradientPtr); + hPtr = Tcl_NextHashEntry(&search); + } +} + diff --git a/pd/tkpath/generic/tkCanvGroup.c b/pd/tkpath/generic/tkCanvGroup.c new file mode 100644 index 0000000000000000000000000000000000000000..653fabdb49e8c8521faed83e271857bdc9ee1cef --- /dev/null +++ b/pd/tkpath/generic/tkCanvGroup.c @@ -0,0 +1,371 @@ +/* + * tkCanvGroup.c -- + * + * This file implements a line canvas item modelled after its + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2008 Mats Bengtsson + * + * $Id: tkCanvGroup.c,v 1.9 2008/07/23 07:08:37 matben Exp $ + */ + +#include <float.h> +#include "tkIntPath.h" +#include "tkpCanvas.h" +#include "tkCanvPathUtil.h" +#include "tkPathStyle.h" + +/* For debugging. */ +extern Tcl_Interp *gInterp; + +enum { + /* When childs update themself so they set all + * its ancestors dirty bbox flag so they know + * when they need to recompute its bbox. */ + GROUP_FLAG_DIRTY_BBOX = (1L << 0) +}; + +/* + * The structure below defines the record for each path item. + */ + +typedef struct GroupItem { + Tk_PathItemEx headerEx; /* Generic stuff that's the same for all + * path types. MUST BE FIRST IN STRUCTURE. */ + PathRect totalBbox; /* Bounding box including stroke. + * Untransformed coordinates. */ + long flags; /* Various flags, see enum. */ +} GroupItem; + + +/* + * Prototypes for procedures defined in this file: + */ + +void GroupUpdateBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr); +static int ConfigureGroup(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int CreateGroup(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeleteGroup(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayGroup(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height); +static void GroupBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int flags); +static int GroupCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int GroupToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double GroupToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int GroupToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScaleGroup(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslateGroup(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); + + +PATH_STYLE_CUSTOM_OPTION_RECORDS +PATH_CUSTOM_OPTION_TAGS +PATH_OPTION_STRING_TABLES_FILL +PATH_OPTION_STRING_TABLES_STROKE +PATH_OPTION_STRING_TABLES_STATE + +static Tk_OptionSpec optionSpecs[] = { + PATH_OPTION_SPEC_CORE(Tk_PathItemEx), + PATH_OPTION_SPEC_PARENT, + PATH_OPTION_SPEC_STYLE_FILL(Tk_PathItemEx, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(Tk_PathItemEx), + PATH_OPTION_SPEC_STYLE_STROKE(Tk_PathItemEx, "black"), + PATH_OPTION_SPEC_END +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * The structures below defines the 'prect' item type by means + * of procedures that can be invoked by generic item code. + */ + +Tk_PathItemType tkGroupType = { + "group", /* name */ + sizeof(GroupItem), /* itemSize */ + CreateGroup, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigureGroup, /* configureProc */ + GroupCoords, /* coordProc */ + DeleteGroup, /* deleteProc */ + DisplayGroup, /* displayProc */ + 0, /* flags */ + GroupBbox, /* bboxProc */ + GroupToPoint, /* pointProc */ + GroupToArea, /* areaProc */ + GroupToPostscript, /* postscriptProc */ + ScaleGroup, /* scaleProc */ + TranslateGroup, /* translateProc */ + (Tk_PathItemIndexProc *) NULL, /* indexProc */ + (Tk_PathItemCursorProc *) NULL, /* icursorProc */ + (Tk_PathItemSelectionProc *) NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) NULL, /* insertProc */ + (Tk_PathItemDCharsProc *) NULL, /* dTextProc */ + (Tk_PathItemType *) NULL, /* nextPtr */ +}; + + +static int +CreateGroup(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + GroupItem *groupPtr = (GroupItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &groupPtr->headerEx; + + /* + * Carry out initialization that is needed to set defaults and to + * allow proper cleanup after errors during the the remainder of + * this procedure. + */ + TkPathInitStyle(&itemExPtr->style); + itemExPtr->canvas = canvas; + itemExPtr->styleObj = NULL; + itemExPtr->styleInst = NULL; + groupPtr->totalBbox = NewEmptyPathRect(); + groupPtr->flags = 0L; + itemExPtr->header.x1 = itemExPtr->header.x2 = + itemExPtr->header.y1 = itemExPtr->header.y2 = -1; + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) groupPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + if (ConfigureGroup(interp, canvas, itemPtr, objc, objv, 0) == TCL_OK) { + return TCL_OK; + } + +error: + /* + * NB: We must unlink the item here since the TkPathCanvasItemExConfigure() + * link it to the root by default. + */ + TkPathCanvasItemDetach(itemPtr); + DeleteGroup(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +static int +ConfigureGroup(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags) +{ + GroupItem *groupPtr = (GroupItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &groupPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + Tk_Window tkwin; + //Tk_PathState state; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int error, mask; + + tkwin = Tk_PathCanvasTkwin(canvas); + for (error = 0; error <= 1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char *) groupPtr, optionTable, + objc, objv, tkwin, &savedOptions, &mask) != TCL_OK) { + continue; + } + } else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + if (TkPathCanvasItemExConfigure(interp, canvas, itemExPtr, mask) != TCL_OK) { + continue; + } + + /* + * Root item's -tags and -parent is read only. + */ + if (itemPtr->id == 0) { + if (mask & PATH_CORE_OPTION_PARENT) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("root items -parent is not configurable", -1)); + continue; + } + if (mask & PATH_CORE_OPTION_TAGS) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("root items -tags is not configurable", -1)); + continue; + } + } + + /* + * If we reach this on the first pass we are OK and continue below. + */ + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + stylePtr->mask |= mask; + } + stylePtr->strokeOpacity = MAX(0.0, MIN(1.0, stylePtr->strokeOpacity)); + stylePtr->fillOpacity = MAX(0.0, MIN(1.0, stylePtr->fillOpacity)); + + /* + * We must notify all children to update themself + * since they may inherit features. + */ + if (!error) { + GroupItemConfigured(canvas, itemPtr, mask); + } +#if 0 // From old code. Needed? + state = itemPtr->state; + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + return TCL_OK; + } +#endif + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + return TCL_OK; + } +} + +static void +DeleteGroup(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display) +{ + GroupItem *groupPtr = (GroupItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &groupPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + + if (stylePtr->fill != NULL) { + TkPathFreePathColor(stylePtr->fill); + } + if (itemExPtr->styleInst != NULL) { + TkPathFreeStyle(itemExPtr->styleInst); + } + Tk_FreeConfigOptions((char *) itemPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +static void +DisplayGroup(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height) +{ + /* Empty. */ +} + +static void +GroupBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int flags) +{ + /* Empty. */ +} + +static int +GroupCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + Tcl_SetObjResult(interp, + Tcl_NewStringObj("group items have no coords", -1)); + return TCL_ERROR; +} + +static int +GroupToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr) +{ + /* + * This says that the group is entirely outside any area. + */ + return -1; +} + +static double +GroupToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr) +{ + /* + * This says that the group is nowhere. + */ + return DBL_MAX; +} + +static int +GroupToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass) +{ + return TCL_ERROR; +} + +static void +ScaleGroup(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY) +{ + CanvasScaleGroup(canvas, itemPtr, originX, originY, scaleX, scaleY); + /* @@@ TODO: we could handle bbox ourselves? */ +} + +static void +TranslateGroup(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY) +{ + CanvasTranslateGroup(canvas, itemPtr, deltaX, deltaY); + /* @@@ TODO: we could handle bbox ourselves? */ +} + +/* + *---------------------------------------------------------------------- + * + * TkPathCanvasSetGroupDirtyBbox -- + * + * This function is invoked by canvas code to tell us that one or + * more of our childrens have changed somehow so that our bbox + * need to be recomputed next time TkPathCanvasUpdateGroupBbox + * is called. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkPathCanvasSetGroupDirtyBbox(Tk_PathItem *itemPtr) +{ + GroupItem *groupPtr = (GroupItem *) itemPtr; + groupPtr->flags &= GROUP_FLAG_DIRTY_BBOX; +} + +void +TkPathCanvasUpdateGroupBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr) +{ + GroupItem *groupPtr = (GroupItem *) itemPtr; + + if (groupPtr->flags & GROUP_FLAG_DIRTY_BBOX) { + TkPathCanvasGroupBbox(canvas, itemPtr, + &itemPtr->x1, &itemPtr->y1, &itemPtr->x2, &itemPtr->y2); + groupPtr->flags &= ~GROUP_FLAG_DIRTY_BBOX; + } +} + + diff --git a/pd/tkpath/generic/tkCanvPath.c b/pd/tkpath/generic/tkCanvPath.c new file mode 100644 index 0000000000000000000000000000000000000000..c770d2239dcaed35c13907cec257d6c981917a67 --- /dev/null +++ b/pd/tkpath/generic/tkCanvPath.c @@ -0,0 +1,991 @@ +/* + * tkCanvPath.c -- + * + * This file implements a path canvas item modelled after its + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * $Id: tkCanvPath.c,v 1.55 2012/07/04 19:43:18 petasis Exp $ + */ + +#include "tkIntPath.h" +#include "tkCanvPathUtil.h" +#include "tkpCanvas.h" +#include "tkPathStyle.h" + +int gDebugLevel = 2; + +#define PATH_DEBUG 0 + +/* Values for the PathItem's flag. */ + +enum { + kPathItemNeedNewNormalizedPath = (1L << 0) +}; + +/* + * The structure below defines the record for each path item. + */ + +typedef struct PathItem { + Tk_PathItemEx headerEx; /* Generic stuff that's the same for all + * path types. MUST BE FIRST IN STRUCTURE. */ + Tcl_Obj *pathObjPtr; /* The object containing the path definition. */ + int pathLen; + Tcl_Obj *normPathObjPtr;/* The object containing the normalized path. */ + PathAtom *atomPtr; + PathRect bbox; /* Bounding box with zero width outline. + * Untransformed coordinates. */ + PathRect totalBbox; /* Bounding box including stroke. + * Untransformed coordinates. */ + int maxNumSegments; /* Max number of straight segments (for subpath) + * needed for Area and Point functions. */ + long flags; /* Various flags, see enum. */ +} PathItem; + + +/* + * Prototypes for procedures defined in this file: + */ + +static void ComputePathBbox(Tk_PathCanvas canvas, PathItem *pathPtr); +static int ConfigurePath(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int CreatePath(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int ProcessPath(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int PathCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeletePath(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayPath(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable dst, + int x, int y, int width, int height); +static void PathBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int mask); +static int PathToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *areaPtr); +static double PathToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int PathToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScalePath(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslatePath(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); + +/* Support functions. */ + +static int GetSubpathMaxNumSegments(PathAtom *atomPtr); + + +PATH_STYLE_CUSTOM_OPTION_RECORDS +PATH_CUSTOM_OPTION_TAGS +PATH_OPTION_STRING_TABLES_FILL +PATH_OPTION_STRING_TABLES_STROKE +PATH_OPTION_STRING_TABLES_STATE + +static Tk_OptionSpec optionSpecs[] = { + PATH_OPTION_SPEC_CORE(Tk_PathItemEx), + PATH_OPTION_SPEC_PARENT, + PATH_OPTION_SPEC_STYLE_FILL(Tk_PathItemEx, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(Tk_PathItemEx), + PATH_OPTION_SPEC_STYLE_STROKE(Tk_PathItemEx, "black"), + PATH_OPTION_SPEC_END +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * The structures below defines the 'path' item type by means + * of procedures that can be invoked by generic item code. + */ + +Tk_PathItemType tkPathType = { + "path", /* name */ + sizeof(PathItem), /* itemSize */ + CreatePath, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigurePath, /* configureProc */ + PathCoords, /* coordProc */ + DeletePath, /* deleteProc */ + DisplayPath, /* displayProc */ + 0, /* flags */ + PathBbox, /* bboxProc */ + PathToPoint, /* pointProc */ + PathToArea, /* areaProc */ + PathToPostscript, /* postscriptProc */ + ScalePath, /* scaleProc */ + TranslatePath, /* translateProc */ + (Tk_PathItemIndexProc *) NULL, /* indexProc */ + (Tk_PathItemCursorProc *) NULL, /* icursorProc */ + (Tk_PathItemSelectionProc *) NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) NULL, /* insertProc */ + (Tk_PathItemDCharsProc *) NULL, /* dTextProc */ + (Tk_PathItemType *) NULL, /* nextPtr */ +}; + +void +DebugPrintf(Tcl_Interp *interp, int level, char *fmt, ...) +{ + va_list args; + char tmpstr[256]; + + if (level > gDebugLevel) { + return; + } + va_start( args, fmt ); + vsprintf( tmpstr, fmt, args ); + Tcl_VarEval( interp, "puts \"", tmpstr, "\"", (char *) NULL ); + va_end (args ); +} + +/* Be sure rect is not empty (see above) before doing this. */ +static void +NormalizePathRect(PathRect *r) +{ + double min, max; + + min = MIN(r->x1, r->x2); + max = MAX(r->x1, r->x2); + r->x1 = min; + r->x2 = max; + min = MIN(r->y1, r->y2); + max = MAX(r->y1, r->y2); + r->y1 = min; + r->y2 = max; +} + +/* + +++ This starts the canvas item part +++ + */ + +/* + *-------------------------------------------------------------- + * + * CreatePath -- + * + * This procedure is invoked to create a new line 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 + * the interp's result; in this case itemPtr is left uninitialized, + * so it can be safely freed by the caller. + * + * Side effects: + * A new line item is created. + * + *-------------------------------------------------------------- + */ + +static int +CreatePath( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to create. */ + int objc, /* Number of elements in objv. */ + Tcl_Obj *CONST objv[]) /* Arguments describing the item. */ +{ + PathItem *pathPtr = (PathItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &pathPtr->headerEx; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed to set defaults and to + * allow proper cleanup after errors during the the remainder of + * this procedure. + */ + TkPathInitStyle(&itemExPtr->style); + itemExPtr->canvas = canvas; + itemExPtr->styleObj = NULL; + itemExPtr->styleInst = NULL; + pathPtr->pathObjPtr = NULL; + pathPtr->pathLen = 0; + pathPtr->normPathObjPtr = NULL; + pathPtr->atomPtr = NULL; + pathPtr->bbox = NewEmptyPathRect(); + pathPtr->totalBbox = NewEmptyPathRect(); + pathPtr->maxNumSegments = 0; + pathPtr->flags = 0L; + + /* Forces a computation of the normalized path in PathCoords. */ + pathPtr->flags |= kPathItemNeedNewNormalizedPath; + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) pathPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + /* + * The first argument must be the path definition list. + */ + + if (ProcessPath(interp, canvas, itemPtr, 1, objv) != TCL_OK) { + goto error; + } + if (ConfigurePath(interp, canvas, itemPtr, objc-1, objv+1, 0) == TCL_OK) { + return TCL_OK; + } + + error: + /* + * NB: We must unlink the item here since the TkPathCanvasItemExConfigure() + * link it to the root by default. + */ + TkPathCanvasItemDetach(itemPtr); + DeletePath(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * ProcessPath -- + * + * Does the main job of processing the drawing path in 'PathCoords' + * but doesn't do the bbox calculation since this cannot be done + * before we have callaed 'ConfigurePath' because we need + * the inherited style. + * + * Results: + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. + * + * Side effects: + * The coordinates for the given item may be changed. + * + *-------------------------------------------------------------- + */ + +static int +ProcessPath( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item whose coordinates are to be + * read or modified. */ + int objc, /* */ + Tcl_Obj *CONST objv[]) /* */ +{ + PathItem *pathPtr = (PathItem *) itemPtr; + PathAtom *atomPtr = NULL; + int result, len; + + if (objc == 0) { + /* @@@ We have an option here if to return the normalized or original path. */ + //Tcl_SetObjResult(interp, pathPtr->pathObjPtr); + + /* We may need to recompute the normalized path from the atoms. */ + if (pathPtr->flags & kPathItemNeedNewNormalizedPath) { + if (pathPtr->normPathObjPtr != NULL) { + Tcl_DecrRefCount(pathPtr->normPathObjPtr); + } + TkPathNormalize(interp, pathPtr->atomPtr, &(pathPtr->normPathObjPtr)); + Tcl_IncrRefCount(pathPtr->normPathObjPtr); + pathPtr->flags &= ~kPathItemNeedNewNormalizedPath; + } + Tcl_SetObjResult(interp, pathPtr->normPathObjPtr); + return TCL_OK; + } else if (objc == 1) { + result = TkPathParseToAtoms(interp, objv[0], &atomPtr, &len); + if (result == TCL_OK) { + + /* Free any old atoms. */ + if (pathPtr->atomPtr != NULL) { + TkPathFreeAtoms(pathPtr->atomPtr); + } + pathPtr->atomPtr = atomPtr; + pathPtr->pathLen = len; + if (pathPtr->pathObjPtr != NULL) { + Tcl_DecrRefCount(pathPtr->pathObjPtr); + } + pathPtr->pathObjPtr = objv[0]; + pathPtr->maxNumSegments = GetSubpathMaxNumSegments(atomPtr); + Tcl_IncrRefCount(pathPtr->pathObjPtr); + } + return result; + } else { + Tcl_WrongNumArgs(interp, 0, objv, "pathName coords id ?pathSpec?"); + return TCL_ERROR; + } +} + +/* + *-------------------------------------------------------------- + * + * PathCoords -- + * + * This procedure is invoked to process the "coords" widget + * command on lines. See the user documentation for details + * on what it does. + * + * Results: + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. + * + * Side effects: + * The coordinates for the given item may be changed. + * + *-------------------------------------------------------------- + */ + +static int +PathCoords( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item whose coordinates are to be + * read or modified. */ + int objc, /* */ + Tcl_Obj *CONST objv[]) /* */ +{ + PathItem *pathPtr = (PathItem *) itemPtr; + int result; + + result = ProcessPath(interp, canvas, itemPtr, objc, objv); + if ((result == TCL_OK) && (objc == 1)) { + ComputePathBbox(canvas, pathPtr); + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * ComputePathBbox -- + * + * This procedure is invoked to compute the bounding box of + * all the pixels that may be drawn as part of a path. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header + * for itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +ComputePathBbox( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + PathItem *pathPtr) /* Item whose bbox is to be + * recomputed. */ +{ + Tk_PathItemEx *itemExPtr = &pathPtr->headerEx; + Tk_PathItem *itemPtr = &itemExPtr->header; + Tk_PathStyle style; + Tk_PathState state = itemExPtr->header.state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (pathPtr->pathObjPtr == NULL || (pathPtr->pathLen < 4) || (state == TK_PATHSTATE_HIDDEN)) { + itemExPtr->header.x1 = itemExPtr->header.x2 = + itemExPtr->header.y1 = itemExPtr->header.y2 = -1; + return; + } + style = TkPathCanvasInheritStyle(itemPtr, kPathMergeStyleNotFill); + + /* + * Get an approximation of the path's bounding box + * assuming zero stroke width. + */ + pathPtr->bbox = GetGenericBarePathBbox(pathPtr->atomPtr); + pathPtr->totalBbox = GetGenericPathTotalBboxFromBare(pathPtr->atomPtr, + &style, &pathPtr->bbox); + SetGenericPathHeaderBbox(&itemExPtr->header, style.matrixPtr, &pathPtr->totalBbox); + TkPathCanvasFreeInheritedStyle(&style); +} + +/* + *-------------------------------------------------------------- + * + * ConfigurePath -- + * + * This procedure is invoked to configure various aspects + * of a line item such as its background color. + * + * Results: + * A standard Tcl result code. If an error occurs, then + * an error message is left in the interp's result. + * + * Side effects: + * Configuration information, such as colors and stipple + * patterns, may be set for itemPtr. + * + *-------------------------------------------------------------- + */ + +static int +ConfigurePath( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Line item to reconfigure. */ + int objc, /* Number of elements in objv. */ + Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ + int flags) /* Flags to pass to Tk_ConfigureWidget. */ +{ + PathItem *pathPtr = (PathItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &pathPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + Tk_Window tkwin; + //Tk_PathState state; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int mask, error; + + tkwin = Tk_PathCanvasTkwin(canvas); + for (error = 0; error <= 1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char *) pathPtr, optionTable, + objc, objv, tkwin, &savedOptions, &mask) != TCL_OK) { + continue; + } + } else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + if (TkPathCanvasItemExConfigure(interp, canvas, itemExPtr, mask) != TCL_OK) { + continue; + } + + /* + * If we reach this on the first pass we are OK and continue below. + */ + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + stylePtr->mask |= mask; + } + + stylePtr->strokeOpacity = MAX(0.0, MIN(1.0, stylePtr->strokeOpacity)); + stylePtr->fillOpacity = MAX(0.0, MIN(1.0, stylePtr->fillOpacity)); + +#if 0 // From old code. Needed? + state = itemPtr->state; + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + //ComputePathBbox(canvas, pathPtr); + return TCL_OK; + } +#endif + /* + * Recompute bounding box for path. + */ + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + ComputePathBbox(canvas, pathPtr); + return TCL_OK; + } +} + +/* + *-------------------------------------------------------------- + * + * DeletePath -- + * + * This procedure is called to clean up the data structure + * associated with a line item. + * + * Results: + * None. + * + * Side effects: + * Resources associated with itemPtr are released. + * + *-------------------------------------------------------------- + */ + +static void +DeletePath( + Tk_PathCanvas canvas, /* Info about overall canvas widget. */ + Tk_PathItem *itemPtr, /* Item that is being deleted. */ + Display *display) /* Display containing window for + * canvas. */ +{ + PathItem *pathPtr = (PathItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &pathPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + + if (stylePtr->fill != NULL) { + TkPathFreePathColor(stylePtr->fill); + } + if (itemExPtr->styleInst != NULL) { + TkPathFreeStyle(itemExPtr->styleInst); + } + if (pathPtr->pathObjPtr != NULL) { + Tcl_DecrRefCount(pathPtr->pathObjPtr); + } + if (pathPtr->normPathObjPtr != NULL) { + Tcl_DecrRefCount(pathPtr->normPathObjPtr); + } + if (pathPtr->atomPtr != NULL) { + TkPathFreeAtoms(pathPtr->atomPtr); + pathPtr->atomPtr = NULL; + } + Tk_FreeConfigOptions((char *) pathPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +/* + *-------------------------------------------------------------- + * + * DisplayPath -- + * + * This procedure is invoked to draw a line item in a given + * drawable. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation + * information in canvas. + * + *-------------------------------------------------------------- + */ + +static void +DisplayPath( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + Tk_PathItem *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, int y, /* Describes region of canvas that */ + int width, int height) /* must be redisplayed (not used). */ +{ + PathItem *pathPtr = (PathItem *) itemPtr; + TMatrix m = GetCanvasTMatrix(canvas); + Tk_PathStyle style; + + /* === EB - 23-apr-2010: register coordinate offsets */ + TkPathSetCoordOffsets(m.tx, m.ty); + /* === */ + + if (pathPtr->pathLen > 2) { + style = TkPathCanvasInheritStyle(itemPtr, 0); + TkPathDrawPath(Tk_PathCanvasTkwin(canvas), drawable, pathPtr->atomPtr, + &style, &m, &pathPtr->bbox); + TkPathCanvasFreeInheritedStyle(&style); + } +} + +static void +PathBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask) +{ + PathItem *pathPtr = (PathItem *) itemPtr; + /* + * Try to be economical here. + */ + if ((mask & PATH_STYLE_OPTION_MATRIX) || + (mask & PATH_STYLE_OPTION_STROKE) || + (mask & PATH_STYLE_OPTION_STROKE_WIDTH) || + (mask & PATH_CORE_OPTION_PARENT) || + (mask & PATH_CORE_OPTION_STYLENAME)) { + ComputePathBbox(canvas, pathPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * PathToPoint -- + * + * Computes the distance from a given point to a given + * line, 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 line. If the + * point isn't inside the line then the return value is the + * distance from the point to the line. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static double +PathToPoint( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + double *pointPtr) /* Pointer to x and y coordinates. */ +{ + PathItem *pathPtr = (PathItem *) itemPtr; + PathAtom *atomPtr = pathPtr->atomPtr; + Tk_PathStyle style; + double dist; + + style = TkPathCanvasInheritStyle(itemPtr, 0); + dist = GenericPathToPoint(canvas, itemPtr, &style, atomPtr, + pathPtr->maxNumSegments, pointPtr); + TkPathCanvasFreeInheritedStyle(&style); + return dist; +} + +/**********************************/ + +double +TkLineToPoint2( + double end1Ptr[2], /* Coordinates of first end-point of line. */ + double end2Ptr[2], /* Coordinates of second end-point of line. */ + double pointPtr[2]) /* Points to coords for point. */ +{ + double dx, dy, a2, b2, c2; + + /* + * Compute the point on the line that is closest to the + * point. Use Pythagoras! + * Notation: + * a = distance between end1 and end2 + * b = distance between end1 and point + * c = distance between end2 and point + * + * point + * |\ + * | \ + * b | \ c + * | \ + * |----\ + * end1 a end2 + * + * If angle between a and b is 90 degrees: c2 = a2 + b2 + * If larger then c2 > a2 + b2 and end1 is closest to point + * Similar for end2 with b and c interchanged. + */ + + dx = end1Ptr[0] - end2Ptr[0]; + dy = end1Ptr[1] - end2Ptr[1]; + a2 = dx*dx + dy*dy; + + dx = end1Ptr[0] - pointPtr[0]; + dy = end1Ptr[1] - pointPtr[1]; + b2 = dx*dx + dy*dy; + + dx = end2Ptr[0] - pointPtr[0]; + dy = end2Ptr[1] - pointPtr[1]; + c2 = dx*dx + dy*dy; + + if (c2 >= a2 + b2) { + return sqrt(b2); + } else if (b2 >= a2 + c2) { + return sqrt(c2); + } else { + double delta; + + /* + * The closest point is found at the point between end1 and end2 + * that is perp to point. delta is the distance from end1 along + * that line which is closest to point. + */ + delta = (a2 + b2 - c2)/(2.0*sqrt(a2)); + return sqrt(MAX(0.0, b2 - delta*delta)); + } +} + +/* + * Get maximum number of segments needed to describe path. + * Needed to see if we can use static space or need to allocate more. + */ + +static int +GetArcNumSegments(double currentX, double currentY, ArcAtom *arc) +{ + int result; + int ntheta, nlength; + int numSteps; /* Number of curve points to + * generate. */ + double cx, cy, rx, ry; + double theta1, dtheta; + + result = EndpointToCentralArcParameters( + currentX, currentY, + arc->x, arc->y, arc->radX, arc->radY, + DEGREES_TO_RADIANS * arc->angle, + arc->largeArcFlag, arc->sweepFlag, + &cx, &cy, &rx, &ry, + &theta1, &dtheta); + if (result == kPathArcLine) { + return 2; + } else if (result == kPathArcSkip) { + return 0; + } + + /* Estimate the number of steps needed. + * Max 10 degrees or length 50. + */ + ntheta = (int) (dtheta/5.0 + 0.5); + nlength = (int) (0.5*(rx + ry)*dtheta/50 + 0.5); + numSteps = MAX(4, MAX(ntheta, nlength));; + return numSteps; +} + +static int +GetSubpathMaxNumSegments(PathAtom *atomPtr) +{ + int num; + int maxNumSegments; + double currentX = 0.0, currentY = 0.0; + double startX = 0.0, startY = 0.0; + MoveToAtom *move; + LineToAtom *line; + ArcAtom *arc; + QuadBezierAtom *quad; + CurveToAtom *curve; + + num = 0; + maxNumSegments = 0; + + while (atomPtr != NULL) { + + switch (atomPtr->type) { + case PATH_ATOM_M: { + move = (MoveToAtom *) atomPtr; + num = 1; + currentX = move->x; + currentY = move->y; + startX = currentX; + startY = currentY; + break; + } + case PATH_ATOM_L: { + line = (LineToAtom *) atomPtr; + num++; + currentX = line->x; + currentY = line->y; + break; + } + case PATH_ATOM_A: { + arc = (ArcAtom *) atomPtr; + num += GetArcNumSegments(currentX, currentY, arc); + currentX = arc->x; + currentY = arc->y; + break; + } + case PATH_ATOM_Q: { + quad = (QuadBezierAtom *) atomPtr; + num += kPathNumSegmentsQuadBezier; + currentX = quad->anchorX; + currentY = quad->anchorY; + break; + } + case PATH_ATOM_C: { + curve = (CurveToAtom *) atomPtr; + num += kPathNumSegmentsCurveTo; + currentX = curve->anchorX; + currentY = curve->anchorY; + break; + } + case PATH_ATOM_Z: { + num++; + currentX = startX; + currentY = startY; + break; + } + case PATH_ATOM_ELLIPSE: + case PATH_ATOM_RECT: { + /* Empty. */ + break; + } + } + if (num > maxNumSegments) { + maxNumSegments = num; + } + atomPtr = atomPtr->nextPtr; + } + return maxNumSegments; +} + +/* + *-------------------------------------------------------------- + * + * PathToArea -- + * + * This procedure is called to determine whether an item + * lies entirely inside, entirely outside, or overlapping + * a given rectangular area. + * + * Each subpath is treated in turn. Generate straight line + * segments for each subpath and treat it as a polygon. + * + * 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. + * + *-------------------------------------------------------------- + */ + +static int +PathToArea( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against line. */ + double *areaPtr) /* Pointer to array of four coordinates + * (x1, y1, x2, y2) describing rectangular + * area. */ +{ + PathItem *pathPtr = (PathItem *) itemPtr; + Tk_PathStyle style; + int area; + + style = TkPathCanvasInheritStyle(itemPtr, 0); + area = GenericPathToArea(canvas, itemPtr, &style, + pathPtr->atomPtr, pathPtr->maxNumSegments, areaPtr); + TkPathCanvasFreeInheritedStyle(&style); + return area; +} + +/* + *-------------------------------------------------------------- + * + * ScalePath -- + * + * This procedure is invoked to rescale a path item. + * + * Results: + * None. + * + * Side effects: + * The line 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 +ScalePath( + Tk_PathCanvas canvas, /* Canvas containing line. */ + Tk_PathItem *itemPtr, /* Path to be scaled. */ + double originX, double originY, /* Origin about which to scale rect. */ + double scaleX, /* Amount to scale in X direction. */ + double scaleY) /* Amount to scale in Y direction. */ +{ + PathItem *pathPtr = (PathItem *) itemPtr; + PathAtom *atomPtr = pathPtr->atomPtr; + PathRect r; + + /* @@@ TODO: Arc atoms with nonzero rotation angle is WRONG! */ + + ScalePathAtoms(atomPtr, originX, originY, scaleX, scaleY); + + /* + * Set flags bit so we know that PathCoords need to update the + * normalized path before being used. + */ + pathPtr->flags |= kPathItemNeedNewNormalizedPath; + + /* Just scale the bbox'es as well. */ + ScalePathRect(&pathPtr->bbox, originX, originY, scaleX, scaleY); + NormalizePathRect(&pathPtr->bbox); + + ScalePathRect(&pathPtr->totalBbox, originX, originY, scaleX, scaleY); + NormalizePathRect(&r); + ScaleItemHeader(itemPtr, originX, originY, scaleX, scaleY); +} + +/* + *-------------------------------------------------------------- + * + * TranslatePath -- + * + * This procedure is called to move a path by a given amount. + * + * Results: + * None. + * + * Side effects: + * The position of the line is offset by (xDelta, yDelta), and + * the bounding box is updated in the generic part of the item + * structure. + * + *-------------------------------------------------------------- + */ + +static void +TranslatePath( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item that is being moved. */ + double deltaX, /* Amount by which item is to be */ + double deltaY) /* moved. */ +{ + PathItem *pathPtr = (PathItem *) itemPtr; + PathAtom *atomPtr = pathPtr->atomPtr; + + TranslatePathAtoms(atomPtr, deltaX, deltaY); + + /* + * Set flags bit so we know that PathCoords need to update the + * normalized path before being used. + */ + pathPtr->flags |= kPathItemNeedNewNormalizedPath; + + /* Just translate the bbox'es as well. */ + TranslatePathRect(&pathPtr->bbox, deltaX, deltaY); + TranslatePathRect(&pathPtr->totalBbox, deltaX, deltaY); + TranslateItemHeader(itemPtr, deltaX, deltaY); +} + +/* + *-------------------------------------------------------------- + * + * PathToPostscript -- + * + * This procedure is called to generate Postscript for + * path items. + * + * Results: + * The return value is a standard Tcl result. If an error + * occurs in generating Postscript then an error message is + * left in the interp's 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 +PathToPostscript( + Tcl_Interp *interp, /* Leave Postscript or error message + * here. */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + Tk_PathItem *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. */ +{ + return TCL_ERROR; +} + + diff --git a/pd/tkpath/generic/tkCanvPathUtil.c b/pd/tkpath/generic/tkCanvPathUtil.c new file mode 100644 index 0000000000000000000000000000000000000000..dc10e0996be3a50b795ac25d13e2101864d8f942 --- /dev/null +++ b/pd/tkpath/generic/tkCanvPathUtil.c @@ -0,0 +1,2769 @@ +/* + * tkCanvPathUtil.c -- + * + * This file implements a path canvas item modelled after its + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2008 Mats Bengtsson + * + * $Id: tkCanvPathUtil.c,v 1.34 2008/08/10 08:02:17 matben Exp $ + */ + +#include "tkPathStyle.h" +#include "tkpCanvas.h" +#include "tkCanvPathUtil.h" + +/* For debugging. */ +extern Tcl_Interp *gInterp; + +/* + * For wider strokes we must make a more detailed analysis + * when doing hit tests and area tests. + */ +#define kPathStrokeThicknessLimit 4.0 + +#define MAX_NUM_STATIC_SEGMENTS 2000 +/* @@@ Should this be moved inside the function instead? */ +static double staticSpace[2*MAX_NUM_STATIC_SEGMENTS]; + + +static void MakeSubPathSegments(PathAtom **atomPtrPtr, double *polyPtr, + int *numPointsPtr, int *numStrokesPtr, TMatrix *matrixPtr); +static int SubPathToArea(Tk_PathStyle *stylePtr, double *polyPtr, int numPoints, + int numStrokes, double *rectPtr, int inside); + + +/* + *-------------------------------------------------------------- + * + * CoordsForPointItems -- + * + * Used as coordProc for items that have plain single point coords. + * + * Results: + * Standard tcl result. + * + * Side effects: + * May store new coords in rectPtr. + * + *-------------------------------------------------------------- + */ + +int +CoordsForPointItems( + Tcl_Interp *interp, + Tk_PathCanvas canvas, + double *pointPtr, /* Sets or gets the point here. */ + int objc, + Tcl_Obj *CONST objv[]) +{ + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(pointPtr[0]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(pointPtr[1]); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if ((objc == 1) || (objc == 2)) { + double x, y; + + if (objc==1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected 0 or 2", -1)); + return TCL_ERROR; + } + } + if ((Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[0], &x) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[1], &y) != TCL_OK)) { + return TCL_ERROR; + } + pointPtr[0] = x; + pointPtr[1] = y; + } else { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected 0 or 2", -1)); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * CoordsForRectangularItems -- + * + * Used as coordProc for items that have rectangular coords. + * + * Results: + * Standard tcl result. + * + * Side effects: + * May store new coords in rectPtr. + * + *-------------------------------------------------------------- + */ + +int +CoordsForRectangularItems( + Tcl_Interp *interp, + Tk_PathCanvas canvas, + PathRect *rectPtr, /* Sets or gets the box here. */ + int objc, + Tcl_Obj *CONST objv[]) +{ + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(rectPtr->x1); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(rectPtr->y1); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(rectPtr->x2); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(rectPtr->y2); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if ((objc == 1) || (objc == 4)) { + double x1, y1, x2, y2; + + if (objc==1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 4) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected 0 or 4", -1)); + return TCL_ERROR; + } + } + if ((Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[0], &x1) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[1], &y1) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[2], &x2) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[3], &y2) != TCL_OK)) { + return TCL_ERROR; + } + + /* + * Get an approximation of the path's bounding box + * assuming zero width outline (stroke). + * Normalize the corners! + */ + rectPtr->x1 = MIN(x1, x2); + rectPtr->y1 = MIN(y1, y2); + rectPtr->x2 = MAX(x1, x2); + rectPtr->y2 = MAX(y1, y2); + } else { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected 0 or 4", -1)); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * GetBareArcBbox + * + * Gets an overestimate of the bounding box rectangle of + * an arc defined using central parametrization assuming + * zero stroke width. + * Untransformed coordinates! + * Note: 1) all angles clockwise direction! + * 2) all angles in radians. + * + * Results: + * A PathRect. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static PathRect +GetBareArcBbox(double cx, double cy, double rx, double ry, + double theta1, double dtheta, double phi) +{ + PathRect r = {1.0e36, 1.0e36, -1.0e36, -1.0e36}; /* Empty rect. */ + double start, extent, stop, stop2PI; + double cosStart, sinStart, cosStop, sinStop; + + /* Keep 0 <= start, extent < 2pi + * and 0 <= stop < 4pi */ + if (dtheta >= 0.0) { + start = theta1; + extent = dtheta; + } else { + start = theta1 + dtheta; + extent = -1.0*dtheta; + } + if (start < 0.0) { + start += 2.0*M_PI; + if (start < 0.0) { + start += 2.0*M_PI; + } + } + if (start >= 2.0*M_PI) { + start -= 2.0*M_PI; + } + stop = start + extent; + stop2PI = stop - 2.0*M_PI; + cosStart = cos(start); + sinStart = sin(start); + cosStop = cos(stop); + sinStop = sin(stop); + + /* + * Compute bbox for phi = 0. + * Put everything at (0,0) and shift to (cx,cy) at the end. + * Look for extreme points of arc: + * 1) start and stop points + * 2) any intersections of x and y axes + * Count both first and second "turns". + */ + + IncludePointInRect(&r, rx*cosStart, ry*sinStart); + IncludePointInRect(&r, rx*cosStop, ry*sinStop); + if (((start < M_PI/2.0) && (stop > M_PI/2.0)) || (stop2PI > M_PI/2.0)) { + IncludePointInRect(&r, 0.0, ry); + } + if (((start < M_PI) && (stop > M_PI)) || (stop2PI > M_PI)) { + IncludePointInRect(&r, -rx, 0.0); + } + if (((start < 3.0*M_PI/2.0) && (stop > 3.0*M_PI/2.0)) || (stop2PI > 3.0*M_PI/2.0)) { + IncludePointInRect(&r, 0.0, -ry); + } + if (stop > 2.0*M_PI) { + IncludePointInRect(&r, rx, 0.0); + } + + /* + * Rotate the bbox above to get an overestimate of extremas. + */ + if (fabs(phi) > 1e-6) { + double cosPhi, sinPhi; + double x, y; + PathRect rrot = {1.0e36, 1.0e36, -1.0e36, -1.0e36}; + + cosPhi = cos(phi); + sinPhi = sin(phi); + x = r.x1*cosPhi - r.y1*sinPhi; + y = r.x1*sinPhi + r.y1*cosPhi; + IncludePointInRect(&rrot, x, y); + + x = r.x2*cosPhi - r.y1*sinPhi; + y = r.x2*sinPhi + r.y1*cosPhi; + IncludePointInRect(&rrot, x, y); + + x = r.x1*cosPhi - r.y2*sinPhi; + y = r.x1*sinPhi + r.y2*cosPhi; + IncludePointInRect(&rrot, x, y); + + x = r.x2*cosPhi - r.y2*sinPhi; + y = r.x2*sinPhi + r.y2*cosPhi; + IncludePointInRect(&rrot, x, y); + + r = rrot; + } + + /* Shift rect to arc center. */ + r.x1 += cx; + r.y1 += cy; + r.x2 += cx; + r.y2 += cy; + return r; +} + +/* + *-------------------------------------------------------------- + * + * GetGenericBarePathBbox + * + * Gets an overestimate of the bounding box rectangle of + * a path assuming zero stroke width. + * Untransformed coordinates! + * + * Results: + * A PathRect. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +PathRect +GetGenericBarePathBbox(PathAtom *atomPtr) +{ + double x1, y1, x2, y2, x3, y3, x4, y4, x5, y5; + double currentX, currentY; + PathRect r = {1.0e36, 1.0e36, -1.0e36, -1.0e36}; + + currentX = 0.0; + currentY = 0.0; + + while (atomPtr != NULL) { + + switch (atomPtr->type) { + case PATH_ATOM_M: { + MoveToAtom *move = (MoveToAtom *) atomPtr; + + IncludePointInRect(&r, move->x, move->y); + currentX = move->x; + currentY = move->y; + break; + } + case PATH_ATOM_L: { + LineToAtom *line = (LineToAtom *) atomPtr; + + IncludePointInRect(&r, line->x, line->y); + currentX = line->x; + currentY = line->y; + break; + } + case PATH_ATOM_A: { + ArcAtom *arc = (ArcAtom *) atomPtr; + int result; + double cx, cy, rx, ry; + double theta1, dtheta; + + result = EndpointToCentralArcParameters( + currentX, currentY, + arc->x, arc->y, arc->radX, arc->radY, + DEGREES_TO_RADIANS * arc->angle, + arc->largeArcFlag, arc->sweepFlag, + &cx, &cy, &rx, &ry, + &theta1, &dtheta); + if (result == kPathArcLine) { + IncludePointInRect(&r, arc->x, arc->y); + } else if (result == kPathArcOK) { + PathRect arcRect; + + arcRect = GetBareArcBbox(cx, cy, rx, ry, theta1, dtheta, + DEGREES_TO_RADIANS * arc->angle); + IncludePointInRect(&r, arcRect.x1, arcRect.y1); + IncludePointInRect(&r, arcRect.x2, arcRect.y2); + } + currentX = arc->x; + currentY = arc->y; + break; + } + case PATH_ATOM_Q: { + QuadBezierAtom *quad = (QuadBezierAtom *) atomPtr; + + x1 = (currentX + quad->ctrlX)/2.0; + y1 = (currentY + quad->ctrlY)/2.0; + x2 = (quad->ctrlX + quad->anchorX)/2.0; + y2 = (quad->ctrlY + quad->anchorY)/2.0; + IncludePointInRect(&r, x1, y1); + IncludePointInRect(&r, x2, y2); + currentX = quad->anchorX; + currentY = quad->anchorY; + IncludePointInRect(&r, currentX, currentY); + break; + } + case PATH_ATOM_C: { + CurveToAtom *curve = (CurveToAtom *) atomPtr; + + x1 = (currentX + curve->ctrlX1)/2.0; + y1 = (currentY + curve->ctrlY1)/2.0; + x2 = (curve->ctrlX1 + curve->ctrlX2)/2.0; + y2 = (curve->ctrlY1 + curve->ctrlY2)/2.0; + x3 = (curve->ctrlX2 + curve->anchorX)/2.0; + y3 = (curve->ctrlY2 + curve->anchorY)/2.0; + IncludePointInRect(&r, x1, y1); + IncludePointInRect(&r, x3, y3); + x4 = (x1 + x2)/2.0; + y4 = (y1 + y2)/2.0; + x5 = (x2 + x3)/2.0; + y5 = (y2 + y3)/2.0; + IncludePointInRect(&r, x4, y4); + IncludePointInRect(&r, x5, y5); + currentX = curve->anchorX; + currentY = curve->anchorY; + IncludePointInRect(&r, currentX, currentY); + break; + } + case PATH_ATOM_Z: { + /* empty */ + break; + } + case PATH_ATOM_ELLIPSE: { + EllipseAtom *ell = (EllipseAtom *) atomPtr; + IncludePointInRect(&r, ell->cx - ell->rx, ell->cy - ell->ry); + IncludePointInRect(&r, ell->cx + ell->rx, ell->cy + ell->ry); + break; + } + case PATH_ATOM_RECT: { + RectAtom *rect = (RectAtom *) atomPtr; + IncludePointInRect(&r, rect->x, rect->y); + IncludePointInRect(&r, rect->x + rect->width, rect->y + rect->height); + break; + } + } + atomPtr = atomPtr->nextPtr; + } + return r; +} + +static void +CopyPoint(double ptSrc[2], double ptDst[2]) +{ + ptDst[0] = ptSrc[0]; + ptDst[1] = ptSrc[1]; +} + +/* + *-------------------------------------------------------------- + * + * PathGetMiterPoint -- + * + * Given three points forming an angle, compute the + * coordinates of the outside point of the mitered corner + * formed by a line of a given width at that angle. + * + * Results: + * If the angle formed by the three points is less than + * 11 degrees then 0 is returned and m isn't modified. + * Otherwise 1 is returned and the point of the "sharp" + * edge is returned. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +PathGetMiterPoint( + double p1[], /* Points to x- and y-coordinates of point + * before vertex. */ + double p0[], /* Points to x- and y-coordinates of vertex + * for mitered joint. */ + double p2[], /* Points to x- and y-coordinates of point + * after vertex. */ + double width, /* Width of line. */ + double sinThetaLimit,/* Sinus of theta miter limit. */ + double m[]) /* The miter point; the sharp edge. */ +{ + double n1[2], n2[2]; /* The normalized vectors. */ + double len1, len2; + double sinTheta; + + /* + * A little geometry: + * p0 + * /\ + * n1 / \ n2 + * / \ + * p1 p2 + * + * n1 = (p0-p1)/|p0-p1| + * n2 = (p0-p2)/|p0-p2| + * + * theta is the angle between n1 and n2 which is identical + * to the angle of the corner. We keep 0 <= theta <= PI so + * that sin(theta) is never negative. If you consider the triangle + * formed by the bisection (mid line) and any of the lines, + * then theta/2 is the angle of that triangle. + * Define: + * + * n = (n1+n2)/|n1+n2| + * + * Simple geometry gives: + * + * |n1+n2| = 2cos(theta/2) + * + * and similar if d is the distance from p0 to the miter point: + * + * d = (w/2)/(sin(theta/2) + * + * where w is the line width. + * For the miter point p we then get: + * n1+n2 w/2 + * p = p0 + n*d = ------------- . ------------ + * 2cos(theta/2) sin(theta/2) + * + * Using sin(2a) = 2sin(a)cos(a) we get: + * + * p = p0 + w/(2sin(theta)) * (n1 + n2) + * + * Use the cross product to get theta as: a x b = |a| |b| sin(angle) as: + * + * sin(theta) = |n1x*n2y - n1y*n2x| + */ + + /* n1 points from p1 to p0. */ + n1[0] = p0[0] - p1[0]; + n1[1] = p0[1] - p1[1]; + len1 = hypot(n1[0], n1[1]); + if (len1 < 1e-6) { + return 0; + } + n1[0] /= len1; + n1[1] /= len1; + + /* n2 points from p2 to p0. */ + n2[0] = p0[0] - p2[0]; + n2[1] = p0[1] - p2[1]; + len2 = hypot(n2[0], n2[1]); + if (len2 < 1e-6) { + return 0; + } + n2[0] /= len2; + n2[1] /= len2; + + sinTheta = fabs(n1[0]*n2[1] - n1[1]*n2[0]); + if (sinTheta < sinThetaLimit) { + return 0; + } + m[0] = p0[0] + width/(2.0*sinTheta) * (n1[0] + n2[0]); + m[1] = p0[1] + width/(2.0*sinTheta) * (n1[1] + n2[1]); + + return 1; +} + +static void +IncludeMiterPointsInRect(double p1[2], double p2[2], double p3[2], PathRect *bounds, + double width, double sinThetaLimit) +{ + double m[2]; + + if (PathGetMiterPoint(p1, p2, p3, width, sinThetaLimit, m)) { + IncludePointInRect(bounds, m[0], m[1]); + } +} + +static PathRect +GetMiterBbox(PathAtom *atomPtr, double width, double miterLimit) +{ + int npts; + double p1[2], p2[2], p3[2]; + double current[2], second[2]; + double sinThetaLimit; + PathRect bounds = {1.0e36, 1.0e36, -1.0e36, -1.0e36}; + + npts = 0; + current[0] = 0.0; + current[1] = 0.0; + second[0] = 0.0; + second[1] = 0.0; + + /* Find sin(thetaLimit) which is needed to get miter points: + * miterLimit = 1/sin(theta/2) =approx 2/theta + */ + if (miterLimit > 8) { + /* theta: + * Exact: 0.250655662336 + * Approx: 0.25 + */ + sinThetaLimit = 2.0/miterLimit; + } else if (miterLimit > 2) { + sinThetaLimit = sin(2*asin(1.0/miterLimit)); + } else { + return bounds; + } + + while (atomPtr != NULL) { + + switch (atomPtr->type) { + case PATH_ATOM_M: { + MoveToAtom *move = (MoveToAtom *) atomPtr; + current[0] = move->x; + current[1] = move->y; + p1[0] = move->x; + p1[1] = move->y; + npts = 1; + break; + } + case PATH_ATOM_L: { + LineToAtom *line = (LineToAtom *) atomPtr; + current[0] = line->x; + current[1] = line->y; + CopyPoint(p2, p3); + CopyPoint(p1, p2); + p1[0] = line->x; + p1[1] = line->y; + npts++; + if (npts >= 3) { + IncludeMiterPointsInRect(p1, p2, p3, &bounds, width, sinThetaLimit); + } + break; + } + case PATH_ATOM_A: { + ArcAtom *arc = (ArcAtom *) atomPtr; + current[0] = arc->x; + current[1] = arc->y; + /* @@@ TODO */ + break; + } + case PATH_ATOM_Q: { + QuadBezierAtom *quad = (QuadBezierAtom *) atomPtr; + current[0] = quad->anchorX; + current[1] = quad->anchorY; + /* The control point(s) form the tangent lines at ends. */ + CopyPoint(p2, p3); + CopyPoint(p1, p2); + p1[0] = quad->ctrlX; + p1[1] = quad->ctrlY; + npts++; + if (npts >= 3) { + IncludeMiterPointsInRect(p1, p2, p3, &bounds, width, sinThetaLimit); + } + CopyPoint(p1, p2); + p1[0] = quad->anchorX; + p1[1] = quad->anchorY; + npts += 2; + break; + } + case PATH_ATOM_C: { + CurveToAtom *curve = (CurveToAtom *) atomPtr; + current[0] = curve->anchorX; + current[1] = curve->anchorY; + /* The control point(s) form the tangent lines at ends. */ + CopyPoint(p2, p3); + CopyPoint(p1, p2); + p1[0] = curve->ctrlX1; + p1[1] = curve->ctrlY1; + npts++; + if (npts >= 3) { + IncludeMiterPointsInRect(p1, p2, p3, &bounds, width, sinThetaLimit); + } + p1[0] = curve->ctrlX2; + p1[1] = curve->ctrlY2; + p1[0] = curve->anchorX; + p1[1] = curve->anchorX; + npts += 2; + break; + } + case PATH_ATOM_Z: { + CloseAtom *close = (CloseAtom *) atomPtr; + current[0] = close->x; + current[1] = close->y; + CopyPoint(p2, p3); + CopyPoint(p1, p2); + p1[0] = close->x; + p1[1] = close->y; + npts++; + if (npts >= 3) { + IncludeMiterPointsInRect(p1, p2, p3, &bounds, width, sinThetaLimit); + } + /* Check also the joint of first segment with the last segment. */ + CopyPoint(p2, p3); + CopyPoint(p1, p2); + CopyPoint(second, p1); + if (npts >= 3) { + IncludeMiterPointsInRect(p1, p2, p3, &bounds, width, sinThetaLimit); + } + break; + } + case PATH_ATOM_ELLIPSE: + case PATH_ATOM_RECT: { + /* Empty. */ + break; + } + } + if (npts == 2) { + CopyPoint(current, second); + } + atomPtr = atomPtr->nextPtr; + } + + return bounds; +} + +/* + *-------------------------------------------------------------- + * + * GetGenericPathTotalBboxFromBare -- + * + * This procedure calculates the items total bbox from the + * bare bbox. Untransformed coords! + * + * Results: + * PathRect. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +PathRect +GetGenericPathTotalBboxFromBare(PathAtom *atomPtr, Tk_PathStyle *stylePtr, PathRect *bboxPtr) +{ + double fudge = 1.0; + double width = 0.0; + PathRect rect = *bboxPtr; + + if (stylePtr->strokeColor != NULL) { + width = stylePtr->strokeWidth; + if (width < 1.0) { + width = 1.0; + } + rect.x1 -= width; + rect.x2 += width; + rect.y1 -= width; + rect.y2 += width; + } + + /* Add the miter corners if necessary. */ + if (atomPtr && (stylePtr->joinStyle == JoinMiter) + && (stylePtr->strokeWidth > 1.0)) { + PathRect miterBox; + miterBox = GetMiterBbox(atomPtr, width, stylePtr->miterLimit); + if (!IsPathRectEmpty(&miterBox)) { + IncludePointInRect(&rect, miterBox.x1, miterBox.y1); + IncludePointInRect(&rect, miterBox.x2, miterBox.y2); + } + } + + /* + * Add one (or two if antialiasing) more pixel of fudge factor just to be safe + * (e.g. X may round differently than we do). + */ + + if (gAntiAlias) { + fudge = 2; + } + rect.x1 -= fudge; + rect.x2 += fudge; + rect.y1 -= fudge; + rect.y2 += fudge; + + return rect; +} + +/* + *-------------------------------------------------------------- + * + * SetGenericPathHeaderBbox -- + * + * This procedure sets the (transformed) bbox in the items header. + * It is a (too?) conservative measure. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header + * for itemPtr. + * + *-------------------------------------------------------------- + */ + +void +SetGenericPathHeaderBbox( + Tk_PathItem *headerPtr, + TMatrix *mPtr, + PathRect *totalBboxPtr) +{ + PathRect rect; + + rect = *totalBboxPtr; + + if (mPtr != NULL) { + double x, y; + PathRect r = NewEmptyPathRect(); + + /* Take each four corners in turn. */ + x = rect.x1, y = rect.y1; + PathApplyTMatrix(mPtr, &x, &y); + IncludePointInRect(&r, x, y); + + x = rect.x2, y = rect.y1; + PathApplyTMatrix(mPtr, &x, &y); + IncludePointInRect(&r, x, y); + + x = rect.x1, y = rect.y2; + PathApplyTMatrix(mPtr, &x, &y); + IncludePointInRect(&r, x, y); + + x = rect.x2, y = rect.y2; + PathApplyTMatrix(mPtr, &x, &y); + IncludePointInRect(&r, x, y); + rect = r; + } + headerPtr->x1 = (int) rect.x1; + headerPtr->x2 = (int) rect.x2; + headerPtr->y1 = (int) rect.y1; + headerPtr->y2 = (int) rect.y2; +} + +/* + *-------------------------------------------------------------- + * + * GenericPathToPoint -- + * + * Computes the distance from a given point to a given + * line, 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 line. If the + * point isn't inside the line then the return value is the + * distance from the point to the line. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +double +GenericPathToPoint( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + Tk_PathStyle *stylePtr, + PathAtom *atomPtr, + int maxNumSegments, + double *pointPtr) /* Pointer to x and y coordinates. */ +{ + int numPoints, numStrokes; + int isclosed; + int intersections, nonzerorule; + int sumIntersections = 0, sumNonzerorule = 0; + double *polyPtr; + double bestDist, radius, width, dist; + Tk_PathState state = itemPtr->state; + TMatrix *matrixPtr = stylePtr->matrixPtr; + + bestDist = 1.0e36; + + if (state == TK_PATHSTATE_HIDDEN) { + return bestDist; + } + if (!HaveAnyFillFromPathColor(stylePtr->fill) && (stylePtr->strokeColor == NULL)) { + return bestDist; + } + if (atomPtr == NULL) { + return bestDist; + } + + /* + * Do we need more memory or can we use static space? + */ + if (maxNumSegments > MAX_NUM_STATIC_SEGMENTS) { + polyPtr = (double *) ckalloc((unsigned) (2*maxNumSegments*sizeof(double))); + } else { + polyPtr = staticSpace; + } + width = stylePtr->strokeWidth; + if (width < 1.0) { + width = 1.0; + } + radius = width/2.0; + + /* + * Loop through each subpath, creating the approximate polyline, + * and do the *ToPoint functions. + * + * Note: Strokes can be treated independently for each subpath, + * but fills cannot since subpaths may intersect creating + * "holes". + */ + + while (atomPtr != NULL) { + MakeSubPathSegments(&atomPtr, polyPtr, &numPoints, &numStrokes, matrixPtr); + isclosed = 0; + if (numStrokes == numPoints) { + isclosed = 1; + } + + /* + * This gives the min distance to the *stroke* AND the + * number of intersections of the two types. + */ + dist = PathPolygonToPointEx(polyPtr, numPoints, pointPtr, + &intersections, &nonzerorule); + sumIntersections += intersections; + sumNonzerorule += nonzerorule; + if ((stylePtr->strokeColor != NULL) && (stylePtr->strokeWidth <= kPathStrokeThicknessLimit)) { + + /* + * This gives the distance to a zero width polyline. + * Use a simple scheme to adjust for a small width. + */ + dist -= radius; + } + if (dist < bestDist) { + bestDist = dist; + } + if (bestDist <= 0.0) { + bestDist = 0.0; + goto done; + } + + /* + * For wider strokes we must make a more detailed analysis. + * Yes, there is an infinitesimal overlap to the above just + * to be on the safe side. + */ + if ((stylePtr->strokeColor != NULL) && (stylePtr->strokeWidth >= kPathStrokeThicknessLimit)) { + dist = PathThickPolygonToPoint(stylePtr->joinStyle, stylePtr->capStyle, + width, isclosed, polyPtr, numPoints, pointPtr); + if (dist < bestDist) { + bestDist = dist; + } + if (bestDist <= 0.0) { + bestDist = 0.0; + goto done; + } + } + } + + /* + * We've processed all of the points. + * EvenOddRule: If the number of intersections is odd, + * the point is inside the polygon. + * WindingRule (nonzero): If the number of directed intersections + * are nonzero, then inside. + */ + if (HaveAnyFillFromPathColor(stylePtr->fill)) { + if ((stylePtr->fillRule == EvenOddRule) && (sumIntersections & 0x1)) { + bestDist = 0.0; + } else if ((stylePtr->fillRule == WindingRule) && (sumNonzerorule != 0)) { + bestDist = 0.0; + } + } + +done: + if (polyPtr != staticSpace) { + ckfree((char *) polyPtr); + } + return bestDist; +} + +/* + *-------------------------------------------------------------- + * + * GenericPathToArea -- + * + * This procedure is called to determine whether an item + * lies entirely inside, entirely outside, or overlapping + * a given rectangular area. + * + * Each subpath is treated in turn. Generate straight line + * segments for each subpath and treat it as a polygon. + * + * 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. + * + *-------------------------------------------------------------- + */ + +int +GenericPathToArea( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against line. */ + Tk_PathStyle *stylePtr, + PathAtom *atomPtr, + int maxNumSegments, + double *areaPtr) /* Pointer to array of four coordinates + * (x1, y1, x2, y2) describing rectangular + * area. */ +{ + 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. */ + int numPoints = 0; + int numStrokes = 0; + int isclosed = 0; + double *polyPtr; + double currentT[2]; + Tk_PathState state = itemPtr->state; + TMatrix *matrixPtr = stylePtr->matrixPtr; + MoveToAtom *move; + +#if 0 + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } +#endif + if (state == TK_PATHSTATE_HIDDEN) { + return -1; + } + if ((GetColorFromPathColor(stylePtr->fill) == NULL) && (stylePtr->strokeColor == NULL)) { + return -1; + } + if (atomPtr == NULL) { + return -1; + } + + /* + * Do we need more memory or can we use static space? + */ + if (maxNumSegments > MAX_NUM_STATIC_SEGMENTS) { + polyPtr = (double *) ckalloc((unsigned) (2*maxNumSegments*sizeof(double))); + } else { + polyPtr = staticSpace; + } + + /* A 'M' atom must be first, may show up later as well. */ + if (atomPtr->type != PATH_ATOM_M) { + return -1; + } + move = (MoveToAtom *) atomPtr; + PathApplyTMatrixToPoint(matrixPtr, &(move->x), currentT); + + /* + * This defines the starting point. It is either -1 or 1. + * If any subseqent segment has a different 'inside' + * then return 0 since one port (in|out)side and another + * (out|in)side + */ + inside = -1; + if ((currentT[0] >= areaPtr[0]) && (currentT[0] <= areaPtr[2]) + && (currentT[1] >= areaPtr[1]) && (currentT[1] <= areaPtr[3])) { + inside = 1; + } + + while (atomPtr != NULL) { + MakeSubPathSegments(&atomPtr, polyPtr, &numPoints, &numStrokes, matrixPtr); + isclosed = 0; + if (numStrokes == numPoints) { + isclosed = 1; + } + if (SubPathToArea(stylePtr, polyPtr, numPoints, numStrokes, + areaPtr, inside) != inside) { + inside = 0; + goto done; + } + } + +done: + if (polyPtr != staticSpace) { + ckfree((char *) polyPtr); + } + return inside; +} + +/* + *-------------------------------------------------------------- + * + * ArcSegments -- + * + * Given the arc parameters it makes a sequence if line segments. + * All angles in radians! + * Note that segments are transformed! + * + * Results: + * The array at *coordPtr gets filled in with 2*numSteps + * coordinates, which correspond to the arc. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static void +ArcSegments( + CentralArcPars *arcPars, + TMatrix *matrixPtr, + int includeFirst, /* Should the first point be included? */ + int numSteps, /* Number of curve segments to + * generate. */ + register double *coordPtr) /* Where to put new points. */ +{ + int i; + int istart = 1 - includeFirst; + double cosPhi, sinPhi; + double cosAlpha, sinAlpha; + double alpha, dalpha, theta1; + double cx, cy, rx, ry; + + cosPhi = cos(arcPars->phi); + sinPhi = sin(arcPars->phi); + cx = arcPars->cx; + cy = arcPars->cy; + rx = arcPars->rx; + ry = arcPars->ry; + theta1 = arcPars->theta1; + dalpha = arcPars->dtheta/numSteps; + + for (i = istart; i <= numSteps; i++, coordPtr += 2) { + alpha = theta1 + i*dalpha; + cosAlpha = cos(alpha); + sinAlpha = sin(alpha); + coordPtr[0] = cx + rx*cosAlpha*cosPhi - ry*sinAlpha*sinPhi; + coordPtr[1] = cy + rx*cosAlpha*sinPhi + ry*sinAlpha*cosPhi; + PathApplyTMatrix(matrixPtr, coordPtr, coordPtr+1); + } +} + +/* + * Get maximum number of segments needed to describe path. + * Needed to see if we can use static space or need to allocate more. + */ + +static int +GetArcNumSegments(double currentX, double currentY, ArcAtom *arc) +{ + int result; + int ntheta, nlength; + int numSteps; /* Number of curve points to + * generate. */ + double cx, cy, rx, ry; + double theta1, dtheta; + + result = EndpointToCentralArcParameters( + currentX, currentY, + arc->x, arc->y, arc->radX, arc->radY, + DEGREES_TO_RADIANS * arc->angle, + arc->largeArcFlag, arc->sweepFlag, + &cx, &cy, &rx, &ry, + &theta1, &dtheta); + if (result == kPathArcLine) { + return 2; + } else if (result == kPathArcSkip) { + return 0; + } + + /* Estimate the number of steps needed. + * Max 10 degrees or length 50. + */ + ntheta = (int) (dtheta/5.0 + 0.5); + nlength = (int) (0.5*(rx + ry)*dtheta/50 + 0.5); + numSteps = MAX(4, MAX(ntheta, nlength));; + return numSteps; +} + +/* + *-------------------------------------------------------------- + * + * CurveSegments -- + * + * Given four control points, create a larger set of points + * for a cubic Bezier spline based on the points. + * + * Results: + * The array at *coordPtr gets filled in with 2*numSteps + * coordinates, which correspond to the Bezier spline defined + * by the four control points. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +CurveSegments( + double control[], /* Array of coordinates for four + * control points: x0, y0, x1, y1, + * ... x3 y3. */ + int includeFirst, /* Should the first point be included? */ + int numSteps, /* Number of curve segments to + * generate. */ + register double *coordPtr) /* Where to put new points. */ +{ + int i; + int istart = 1 - includeFirst; + double u, u2, u3, t, t2, t3; + + /* + * We should use the 'de Castlejau' algorithm to iterate + * line segments until a certain tolerance. + */ + + for (i = istart; i <= numSteps; i++, coordPtr += 2) { + t = ((double) i)/((double) numSteps); + t2 = t*t; + t3 = t2*t; + u = 1.0 - t; + u2 = u*u; + u3 = u2*u; + coordPtr[0] = control[0]*u3 + + 3.0 * (control[2]*t*u2 + control[4]*t2*u) + control[6]*t3; + coordPtr[1] = control[1]*u3 + + 3.0 * (control[3]*t*u2 + control[5]*t2*u) + control[7]*t3; + } +} + +/* + *-------------------------------------------------------------- + * + * QuadBezierSegments -- + * + * Given three control points, create a larger set of points + * for a quadratic Bezier spline based on the points. + * + * Results: + * The array at *coordPtr gets filled in with 2*numSteps + * coordinates, which correspond to the quadratic Bezier spline defined + * by the control points. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static void +QuadBezierSegments( + double control[], /* Array of coordinates for three + * control points: x0, y0, x1, y1, + * x2, y2. */ + int includeFirst, /* Should the first point be included? */ + int numSteps, /* Number of curve segments to + * generate. */ + register double *coordPtr) /* Where to put new points. */ +{ + int i; + int istart = 1 - includeFirst; + double u, u2, t, t2; + + for (i = istart; i <= numSteps; i++, coordPtr += 2) { + t = ((double) i)/((double) numSteps); + t2 = t*t; + u = 1.0 - t; + u2 = u*u; + coordPtr[0] = control[0]*u2 + 2.0 * control[2]*t*u + control[4]*t2; + coordPtr[1] = control[1]*u2 + 2.0 * control[3]*t*u + control[5]*t2; + } +} + +static void +EllipseSegments( + double center[], + double rx, double ry, + double angle, /* Angle of rotated ellipse. */ + int numSteps, /* Number of curve segments to + * generate. */ + register double *coordPtr) /* Where to put new points. */ +{ + double phi, delta; + double cosA, sinA; + double cosPhi, sinPhi; + + cosA = cos(angle); + sinA = sin(angle); + delta = 2*M_PI/(numSteps-1); + + for (phi = 0.0; phi <= 2*M_PI+1e-6; phi += delta, coordPtr += 2) { + cosPhi = cos(phi); + sinPhi = sin(phi); + coordPtr[0] = center[0] + rx*cosA*cosPhi - ry*sinA*sinPhi; + coordPtr[1] = center[1] + rx*sinA*cosPhi + ry*cosA*sinPhi; + } +} + +/* + *-------------------------------------------------------------- + * + * AddArcSegments, AddQuadBezierSegments, AddCurveToSegments, + * AddEllipseToSegments -- + * + * Adds a number of points along the arc (curve) to coordPtr + * representing straight line segments. + * + * Results: + * Number of points added. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +AddArcSegments( + TMatrix *matrixPtr, + double current[2], /* Current point. */ + ArcAtom *arc, + double *coordPtr) /* Where to put the points. */ +{ + int result; + int numPoints; + CentralArcPars arcPars; + double cx, cy, rx, ry; + double theta1, dtheta; + + /* + * Note: The arc parametrization used cannot generally + * be transformed. Need to transform each line segment separately! + */ + + result = EndpointToCentralArcParameters( + current[0], current[1], + arc->x, arc->y, arc->radX, arc->radY, + DEGREES_TO_RADIANS * arc->angle, + arc->largeArcFlag, arc->sweepFlag, + &cx, &cy, &rx, &ry, + &theta1, &dtheta); + if (result == kPathArcLine) { + double pts[2]; + + pts[0] = arc->x; + pts[1] = arc->y; + PathApplyTMatrix(matrixPtr, pts, pts+1); + coordPtr[0] = pts[0]; + coordPtr[1] = pts[1]; + return 1; + } else if (result == kPathArcSkip) { + return 0; + } + + arcPars.cx = cx; + arcPars.cy = cy; + arcPars.rx = rx; + arcPars.ry = ry; + arcPars.theta1 = theta1; + arcPars.dtheta = dtheta; + arcPars.phi = arc->angle; + + numPoints = GetArcNumSegments(current[0], current[1], arc); + ArcSegments(&arcPars, matrixPtr, 0, numPoints, coordPtr); + + return numPoints; +} + +static int +AddQuadBezierSegments( + TMatrix *matrixPtr, + double current[2], /* Current point. */ + QuadBezierAtom *quad, + double *coordPtr) /* Where to put the points. */ +{ + int numPoints; /* Number of curve points to + * generate. */ + double control[6]; + + PathApplyTMatrixToPoint(matrixPtr, current, control); + PathApplyTMatrixToPoint(matrixPtr, &(quad->ctrlX), control+2); + PathApplyTMatrixToPoint(matrixPtr, &(quad->anchorX), control+4); + + numPoints = kPathNumSegmentsQuadBezier; + QuadBezierSegments(control, 0, numPoints, coordPtr); + + return numPoints; +} + +static int +AddCurveToSegments( + TMatrix *matrixPtr, + double current[2], /* Current point. */ + CurveToAtom *curve, + double *coordPtr) +{ + int numSteps; /* Number of curve points to + * generate. */ + double control[8]; + + PathApplyTMatrixToPoint(matrixPtr, current, control); + PathApplyTMatrixToPoint(matrixPtr, &(curve->ctrlX1), control+2); + PathApplyTMatrixToPoint(matrixPtr, &(curve->ctrlX2), control+4); + PathApplyTMatrixToPoint(matrixPtr, &(curve->anchorX), control+6); + + numSteps = kPathNumSegmentsCurveTo; + CurveSegments(control, 1, numSteps, coordPtr); + + return numSteps; +} + +static int +AddEllipseToSegments( + TMatrix *matrixPtr, + EllipseAtom *ellipse, + double *coordPtr) +{ + int numSteps; + double rx, ry, angle; + double c[2], crx[2], cry[2]; + double p[2]; + + /* + * We transform the three points: c, c+rx, c+ry + * and then compute the parameters for the transformed ellipse. + * This is because an affine transform of an ellipse is still an ellipse. + */ + p[0] = ellipse->cx; + p[1] = ellipse->cy; + PathApplyTMatrixToPoint(matrixPtr, p, c); + p[0] = ellipse->cx + ellipse->rx; + p[1] = ellipse->cy; + PathApplyTMatrixToPoint(matrixPtr, p, crx); + p[0] = ellipse->cx; + p[1] = ellipse->cy + ellipse->ry; + PathApplyTMatrixToPoint(matrixPtr, p, cry); + rx = hypot(crx[0]-c[0], crx[1]-c[1]); + ry = hypot(cry[0]-c[0], cry[1]-c[1]); + angle = atan2(crx[1]-c[1], crx[0]-c[0]); + + /* Note we add 1 here since we need both start and stop points. + * Small things wont need so many segments. + * Approximate circumference: 4(rx+ry) + */ + if (rx+ry < 2.1) { + numSteps = 1; + } else if (rx+ry < 4) { + numSteps = 3; + } else if (rx+ry < kPathNumSegmentsEllipse) { + numSteps = (int)(rx+ry+2); + } else { + numSteps = kPathNumSegmentsEllipse + 1; + } + EllipseSegments(c, rx, ry, angle, numSteps, coordPtr); + + return numSteps; +} + +static int +AddRectToSegments( + TMatrix *matrixPtr, + RectAtom *rect, + double *coordPtr) +{ + int i; + double p[8]; + + p[0] = rect->x; + p[1] = rect->y; + p[2] = rect->x + rect->width; + p[3] = rect->y; + p[4] = rect->x + rect->width; + p[5] = rect->y + rect->height; + p[6] = rect->x; + p[7] = rect->y + rect->height; + + for (i = 0; i <= 8; i += 2, coordPtr += 2) { + PathApplyTMatrix(matrixPtr, p, p+1); + coordPtr[0] = p[0]; + coordPtr[1] = p[1]; + } + return 4; +} + +/* + *-------------------------------------------------------------- + * + * MakeSubPathSegments -- + * + * Supposed to be a generic segment generator that can be used + * by both Area and Point functions. + * + * Results: + * Points filled into polyPtr... + * + * Side effects: + * Pointer *atomPtrPtr may be updated. + * + *-------------------------------------------------------------- + */ + +static void +MakeSubPathSegments(PathAtom **atomPtrPtr, double *polyPtr, + int *numPointsPtr, int *numStrokesPtr, TMatrix *matrixPtr) +{ + int first = 1; + int numPoints; + int numStrokes; + int numAdded; + int isclosed = 0; + double current[2]; /* Current untransformed point. */ + double *currentTPtr; /* Pointer to the transformed current point. */ + double *coordPtr; + PathAtom *atomPtr; + + /* @@@ Note that for unfilled paths we could have made a progressive + * area (point) check which may be faster since we may stop when 0 (overlapping). + * For filled paths we cannot rely on this since the area rectangle + * may be entirely enclosed in the path and still overlapping. + * (Need better explanation!) + */ + + /* + * Check each segment of the path. + * Any transform matrix is applied at the last stage when comparing to rect. + * 'current' is always untransformed coords. + */ + + current[0] = 0.0; + current[1] = 0.0; + numPoints = 0; + numStrokes = 0; + isclosed = 0; + atomPtr = *atomPtrPtr; + coordPtr = NULL; + + while (atomPtr != NULL) { + + switch (atomPtr->type) { + case PATH_ATOM_M: { + MoveToAtom *move = (MoveToAtom *) atomPtr; + + /* A 'M' atom must be first, may show up later as well. */ + + if (first) { + coordPtr = polyPtr; + current[0] = move->x; + current[1] = move->y; + PathApplyTMatrixToPoint(matrixPtr, current, coordPtr); + currentTPtr = coordPtr; + coordPtr += 2; + numPoints = 1; + } else { + + /* + * We have finalized a subpath. + */ + goto done; + } + first = 0; + break; + } + case PATH_ATOM_L: { + LineToAtom *line = (LineToAtom *) atomPtr; + + PathApplyTMatrixToPoint(matrixPtr, &(line->x), coordPtr); + current[0] = line->x; + current[1] = line->y; + currentTPtr = coordPtr; + coordPtr += 2; + numPoints++;; + break; + } + case PATH_ATOM_A: { + ArcAtom *arc = (ArcAtom *) atomPtr; + + numAdded = AddArcSegments(matrixPtr, current, arc, coordPtr); + coordPtr += 2 * numAdded; + numPoints += numAdded; + current[0] = arc->x; + current[1] = arc->y; + currentTPtr = coordPtr; + break; + } + case PATH_ATOM_Q: { + QuadBezierAtom *quad = (QuadBezierAtom *) atomPtr; + + numAdded = AddQuadBezierSegments(matrixPtr, current, + quad, coordPtr); + coordPtr += 2 * numAdded; + numPoints += numAdded; + current[0] = quad->anchorX; + current[1] = quad->anchorY; + currentTPtr = coordPtr; + break; + } + case PATH_ATOM_C: { + CurveToAtom *curve = (CurveToAtom *) atomPtr; + + numAdded = AddCurveToSegments(matrixPtr, current, + curve, coordPtr); + coordPtr += 2 * numAdded; + numPoints += numAdded; + current[0] = curve->anchorX; + current[1] = curve->anchorY; + currentTPtr = coordPtr; + break; + } + case PATH_ATOM_Z: { + CloseAtom *close = (CloseAtom *) atomPtr; + + /* Just add the first point to the end. */ + coordPtr[0] = polyPtr[0]; + coordPtr[1] = polyPtr[1]; + coordPtr += 2; + numPoints++; + current[0] = close->x; + current[1] = close->y; + isclosed = 1; + break; + } + case PATH_ATOM_ELLIPSE: { + EllipseAtom *ellipse = (EllipseAtom *) atomPtr; + + if (first) { + coordPtr = polyPtr; + } + numAdded = AddEllipseToSegments(matrixPtr, ellipse, coordPtr); + coordPtr += 2 * numAdded; + numPoints += numAdded; + if (first) { + /* Not sure about this. Never used anyway! */ + current[0] = ellipse->cx + ellipse->rx; + current[1] = ellipse->cy; + } + break; + } + case PATH_ATOM_RECT: { + RectAtom *rect = (RectAtom *) atomPtr; + + if (first) { + coordPtr = polyPtr; + } + numAdded = AddRectToSegments(matrixPtr, rect, coordPtr); + coordPtr += 2 * numAdded; + numPoints += numAdded; + current[0] = rect->x; + current[1] = rect->y; + break; + } + } + atomPtr = atomPtr->nextPtr; + } + +done: + if (numPoints > 1) { + if (isclosed) { + numStrokes = numPoints; + } else { + numStrokes = numPoints - 1; + } + } + *numPointsPtr = numPoints; + *numStrokesPtr = numStrokes; + *atomPtrPtr = atomPtr; + + return; +} + +/* + *-------------------------------------------------------------- + * + * SubPathToArea -- + * + * This procedure is called to determine whether a subpath + * 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. + * + *-------------------------------------------------------------- + */ + +static int +SubPathToArea( + Tk_PathStyle *stylePtr, + double *polyPtr, + int numPoints, /* Total number of points. First one + * is duplicated in the last. */ + int numStrokes, /* The number of strokes which is one less + * than numPoints if path not closed. */ + double *rectPtr, + int inside) /* This is the current inside status. */ +{ + double width; + + /* @@@ There is an open question how a closed unfilled polygon + * completely enclosing the area rect should be counted. + * While the tk canvas polygon item counts it as intersecting (0), + * the line item counts it as outside (-1). + */ + + if (HaveAnyFillFromPathColor(stylePtr->fill)) { + + /* This checks a closed polygon with zero width for inside. + * If area rect completely enclosed it returns intersecting (0). + */ + if (TkPolygonToArea(polyPtr, numPoints, rectPtr) != inside) { + return 0; + } + } + if (stylePtr->strokeColor != NULL) { + width = stylePtr->strokeWidth; + if (width < 1.0) { + width = 1.0; + } + if (stylePtr->strokeWidth > kPathStrokeThicknessLimit) { + if (TkThickPolyLineToArea(polyPtr, numPoints, + width, stylePtr->capStyle, + stylePtr->joinStyle, rectPtr) != inside) { + return 0; + } + } else { + if (PathPolyLineToArea(polyPtr, numPoints, rectPtr) != inside) { + return 0; + } + } + } + return inside; +} + +/*---------------------------*/ + +/* + *-------------------------------------------------------------- + * + * TranslatePathAtoms -- + * + * This procedure is called to translate a linked list of path atoms. + * + * Results: + * None. + * + * Side effects: + * Path atoms changed. + * + *-------------------------------------------------------------- + */ + +void +TranslatePathAtoms( + PathAtom *atomPtr, + double deltaX, /* Amount by which item is to be */ + double deltaY) /* moved. */ +{ + while (atomPtr != NULL) { + switch (atomPtr->type) { + case PATH_ATOM_M: { + MoveToAtom *move = (MoveToAtom *) atomPtr; + + move->x += deltaX; + move->y += deltaY; + break; + } + case PATH_ATOM_L: { + LineToAtom *line = (LineToAtom *) atomPtr; + + line->x += deltaX; + line->y += deltaY; + break; + } + case PATH_ATOM_A: { + ArcAtom *arc = (ArcAtom *) atomPtr; + + arc->x += deltaX; + arc->y += deltaY; + break; + } + case PATH_ATOM_Q: { + QuadBezierAtom *quad = (QuadBezierAtom *) atomPtr; + + quad->ctrlX += deltaX; + quad->ctrlY += deltaY; + quad->anchorX += deltaX; + quad->anchorY += deltaY; + break; + } + case PATH_ATOM_C: { + CurveToAtom *curve = (CurveToAtom *) atomPtr; + + curve->ctrlX1 += deltaX; + curve->ctrlY1 += deltaY; + curve->ctrlX2 += deltaX; + curve->ctrlY2 += deltaY; + curve->anchorX += deltaX; + curve->anchorY += deltaY; + break; + } + case PATH_ATOM_Z: { + CloseAtom *close = (CloseAtom *) atomPtr; + + close->x += deltaX; + close->y += deltaY; + break; + } + case PATH_ATOM_ELLIPSE: + case PATH_ATOM_RECT: { + Tcl_Panic("PATH_ATOM_ELLIPSE PATH_ATOM_RECT are not supported for TranslatePathAtoms"); + break; + } + } + atomPtr = atomPtr->nextPtr; + } +} + +/* + *-------------------------------------------------------------- + * + * ScalePathAtoms -- + * + * This procedure is called to scale a linked list of path atoms. + * The following transformation is applied to all point + * coordinates: + * x' = originX + scaleX*(x-originX) + * y' = originY + scaleY*(y-originY) + * + * Results: + * None. + * + * Side effects: + * Path atoms changed. + * + *-------------------------------------------------------------- + */ + +void +ScalePathAtoms( + PathAtom *atomPtr, + double originX, double originY, /* Origin about which to scale rect. */ + double scaleX, /* Amount to scale in X direction. */ + double scaleY) /* Amount to scale in Y direction. */ +{ + while (atomPtr != NULL) { + switch (atomPtr->type) { + case PATH_ATOM_M: { + MoveToAtom *move = (MoveToAtom *) atomPtr; + + move->x = originX + scaleX*(move->x - originX); + move->y = originY + scaleY*(move->y - originY); + break; + } + case PATH_ATOM_L: { + LineToAtom *line = (LineToAtom *) atomPtr; + + line->x = originX + scaleX*(line->x - originX); + line->y = originY + scaleY*(line->y - originY); + break; + } + case PATH_ATOM_A: { + ArcAtom *arc = (ArcAtom *) atomPtr; + /* + * @@@ TODO: This is a very much simplified math which is WRONG! + */ + if (fabs(fmod(arc->angle, 180.0)) < 0.001) { + arc->radX = scaleX*arc->radX; + arc->radY = scaleY*arc->radY; + } else if (fabs(fmod(arc->angle, 90.0)) < 0.001) { + arc->radX = scaleY*arc->radX; + arc->radY = scaleX*arc->radY; + } else { + double angle; + double nx, ny; + + if (scaleX == 0.0) Tcl_Panic("singularity when scaling arc atom"); + angle = atan(scaleY/scaleX * tan(arc->angle * DEGREES_TO_RADIANS)); + nx = cos(arc->angle * DEGREES_TO_RADIANS); + ny = sin(arc->angle * DEGREES_TO_RADIANS); + + arc->angle = angle * RADIANS_TO_DEGREES; + arc->radX = arc->radX * hypot( scaleX*nx, scaleY*ny); + arc->radY = arc->radY * hypot(-scaleX*ny, scaleY*nx); + /* DebugPrintf(gInterp, 1, "arc->angle=%f, nx=%f, ny=%f, arc->radX=%f, arc->radY=%f\n", + arc->angle, nx, ny, arc->radX, arc->radY); */ + + } + arc->x = originX + scaleX*(arc->x - originX); + arc->y = originY + scaleY*(arc->y - originY); + break; + } + case PATH_ATOM_Q: { + QuadBezierAtom *quad = (QuadBezierAtom *) atomPtr; + + quad->ctrlX = originX + scaleX*(quad->ctrlX - originX); + quad->ctrlY = originY + scaleY*(quad->ctrlY - originY); + quad->anchorX = originX + scaleX*(quad->anchorX - originX); + quad->anchorY = originY + scaleY*(quad->anchorY - originY); + break; + } + case PATH_ATOM_C: { + CurveToAtom *curve = (CurveToAtom *) atomPtr; + + curve->ctrlX1 = originX + scaleX*(curve->ctrlX1 - originX); + curve->ctrlY1 = originY + scaleY*(curve->ctrlY1 - originY); + curve->ctrlX2 = originX + scaleX*(curve->ctrlX2 - originX); + curve->ctrlY2 = originY + scaleY*(curve->ctrlY2 - originY); + curve->anchorX = originX + scaleX*(curve->anchorX - originX); + curve->anchorY = originY + scaleY*(curve->anchorY - originY); + break; + } + case PATH_ATOM_Z: { + CloseAtom *close = (CloseAtom *) atomPtr; + + close->x = originX + scaleX*(close->x - originX); + close->y = originY + scaleY*(close->y - originY); + break; + } + case PATH_ATOM_ELLIPSE: + case PATH_ATOM_RECT: { + Tcl_Panic("PATH_ATOM_ELLIPSE PATH_ATOM_RECT are not supported for ScalePathAtoms"); + break; + } + } + atomPtr = atomPtr->nextPtr; + } +} + +/*------------------*/ + +TMatrix +GetCanvasTMatrix(Tk_PathCanvas canvas) +{ + short originX, originY; + TMatrix m = kPathUnitTMatrix; + + /* @@@ Any scaling involved as well??? */ + Tk_PathCanvasDrawableCoords(canvas, 0.0, 0.0, &originX, &originY); + m.tx = originX; + m.ty = originY; + return m; +} + +PathRect +NewEmptyPathRect(void) +{ + PathRect r; + + r.x1 = 1.0e36; + r.y1 = 1.0e36; + r.x2 = -1.0e36; + r.y2 = -1.0e36; + return r; +} + +int +IsPathRectEmpty(PathRect *r) +{ + if ((r->x2 >= r->x1) && (r->y2 >= r->y1)) { + return 0; + } else { + return 1; + } +} + +void +IncludePointInRect(PathRect *r, double x, double y) +{ + r->x1 = MIN(r->x1, x); + r->y1 = MIN(r->y1, y); + r->x2 = MAX(r->x2, x); + r->y2 = MAX(r->y2, y); +} + +void +TranslatePathRect(PathRect *r, double deltaX, double deltaY) +{ + r->x1 += deltaX; + r->x2 += deltaX; + r->y1 += deltaY; + r->y2 += deltaY; +} + +void +ScalePathRect(PathRect *r, double originX, double originY, + double scaleX, double scaleY) +{ + r->x1 = originX + scaleX*(r->x1 - originX); + r->x2 = originX + scaleX*(r->x2 - originX); + r->y1 = originY + scaleY*(r->y1 - originY); + r->y2 = originY + scaleY*(r->y2 - originY); +} + +void +TranslateItemHeader(Tk_PathItem *itemPtr, double deltaX, double deltaY) +{ + /* @@@ TODO: Beware for cumulated round-off errors! */ + /* If all coords == -1 the item is hidden. */ + if ((itemPtr->x1 != -1) || (itemPtr->x2 != -1) || + (itemPtr->y1 != -1) || (itemPtr->y2 != -1)) { + itemPtr->x1 += (int) deltaX; + itemPtr->x2 += (int) deltaX; + itemPtr->y1 += (int) deltaY; + itemPtr->y2 += (int) deltaY; + } +} + +void +ScaleItemHeader(Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY) +{ + /* @@@ TODO: Beware for cumulated round-off errors! */ + /* If all coords == -1 the item is hidden. */ + if ((itemPtr->x1 != -1) || (itemPtr->x2 != -1) || + (itemPtr->y1 != -1) || (itemPtr->y2 != -1)) { + int min, max; + + itemPtr->x1 = (int) (originX + scaleX*(itemPtr->x1 - originX)); + itemPtr->x2 = (int) (originX + scaleX*(itemPtr->x2 - originX)); + itemPtr->y1 = (int) (originY + scaleY*(itemPtr->y1 - originY)); + itemPtr->y2 = (int) (originY + scaleY*(itemPtr->y2 - originY)); + + min = MIN(itemPtr->x1, itemPtr->x2); + max = MAX(itemPtr->x1, itemPtr->x2); + itemPtr->x1 = min; + itemPtr->x2 = max; + min = MIN(itemPtr->y1, itemPtr->y2); + max = MAX(itemPtr->y1, itemPtr->y2); + itemPtr->y1 = min; + itemPtr->y2 = max; + } +} + +/* + *-------------------------------------------------------------- + * + * PathPolyLineToArea -- + * + * Determine whether an open polygon lies entirely inside, entirely + * outside, or overlapping a given rectangular area. + * Identical to TkPolygonToArea except that it returns outside (-1) + * if completely encompassing the area rect. + * + * Results: + * -1 is returned if the polygon given by polyPtr and numPoints + * is entirely outside the rectangle given by rectPtr. 0 is + * returned if the polygon overlaps the rectangle, and 1 is + * returned if the polygon is entirely inside the rectangle. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +PathPolyLineToArea( + double *polyPtr, /* Points to an array coordinates for + * closed polygon: x0, y0, x1, y1, ... + * The polygon may be self-intersecting. */ + int numPoints, /* Total number of points at *polyPtr. */ + register double *rectPtr) /* Points to coords for rectangle, in the + * order x1, y1, x2, y2. X1 and y1 must + * be lower-left corner. */ +{ + int state; /* State of all edges seen so far (-1 means + * outside, 1 means inside, won't ever be + * 0). */ + int count; + register double *pPtr; + + /* + * Iterate over all of the edges of the polygon and test them + * against the rectangle. Can quit as soon as the state becomes + * "intersecting". + */ + + state = TkLineToArea(polyPtr, polyPtr+2, rectPtr); + if (state == 0) { + return 0; + } + for (pPtr = polyPtr+2, count = numPoints-1; count >= 2; + pPtr += 2, count--) { + if (TkLineToArea(pPtr, pPtr+2, rectPtr) != state) { + return 0; + } + } + return state; +} + +/* + *-------------------------------------------------------------- + * + * PathThickPolygonToPoint -- + * + * Computes the distance from a given point to a given + * thick polyline (open or closed), 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 line. If the + * point isn't inside the line then the return value is the + * distance from the point to the line. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +double +PathThickPolygonToPoint( + int joinStyle, int capStyle, + double width, + int isclosed, + double *polyPtr, /* Points to an array coordinates for + * the polygon: x0, y0, x1, y1, ... + * The polygon may be self-intersecting. */ + int numPoints, /* Total number of points at *polyPtr. */ + double *pointPtr) /* Points to coords for point. */ +{ + int count; + int project; + int testrounding; + int changedMiterToBevel; /* Non-zero means that a mitered corner + * had to be treated as beveled after all + * because the angle was < 11 degrees. */ + double bestDist; /* Closest distance between point and + * any edge in polygon. */ + double dist, radius; + double *coordPtr; + double poly[10]; + + bestDist = 1.0e36; + radius = width/2.0; + project = 0; + if (!isclosed) { + project = (capStyle == CapProjecting); + } + + /* + * The overall idea is to iterate through all of the edges of + * the line, 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 = polyPtr; count >= 2; + count--, coordPtr += 2) { + + /* + * If rounding is done around the first point then compute + * the distance between the point and the point. + */ + testrounding = 0; + if (isclosed) { + testrounding = (joinStyle == JoinRound); + } else { + testrounding = (((capStyle == CapRound) && (count == numPoints)) + || ((joinStyle == JoinRound) && (count != numPoints))); + } + if (testrounding) { + dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) + - radius; + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } 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) width, + project, poly, poly+2); + } else if ((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) width, 0, + poly, poly+2); + + /* + * If this line 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 ((joinStyle == JoinBevel) || changedMiterToBevel) { + poly[8] = poly[0]; + poly[9] = poly[1]; + dist = TkPolygonToPoint(poly, 5, pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } + changedMiterToBevel = 0; + } + } + if (count == 2) { + TkGetButtPoints(coordPtr, coordPtr+2, (double) width, + project, poly+4, poly+6); + } else if (joinStyle == JoinMiter) { + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + (double) width, poly+4, poly+6) == 0) { + changedMiterToBevel = 1; + TkGetButtPoints(coordPtr, coordPtr+2, (double) width, + 0, poly+4, poly+6); + } + } else { + TkGetButtPoints(coordPtr, coordPtr+2, (double) 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 donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } + } + + /* + * If caps are rounded, check the distance to the cap around the + * final end point of the line. + */ + if (!isclosed && (capStyle == CapRound)) { + dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) + - width/2.0; + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } + } + +donepoint: + + return bestDist; +} + +/* + *-------------------------------------------------------------- + * + * PathPolygonToPointEx -- + * + * Compute the distance from a point to a polygon. This is + * essentially identical to TkPolygonToPoint with two exceptions: + * 1) It returns the closest distance to the *stroke*, + * any fill unrecognized. + * 2) It returns both number of total intersections, and + * the number of directed crossings, nonzerorule. + * + * Results: + * The return value is 0.0 if the point referred to by + * pointPtr is within the polygon referred to by polyPtr + * and numPoints. Otherwise the return value is the + * distance of the point from the polygon. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +double +PathPolygonToPointEx( + double *polyPtr, /* Points to an array coordinates for + * the polygon: x0, y0, x1, y1, ... + * The polygon may be self-intersecting. + * If a fillRule is used the last point + * must duplicate the first one. */ + int numPoints, /* Total number of points at *polyPtr. */ + double *pointPtr, /* Points to coords for point. */ + int *intersectionsPtr,/* (out) The number of intersections. */ + int *nonzerorulePtr)/* (out) The number of intersections + * considering crossing direction. */ +{ + double bestDist; /* Closest distance between point and + * any edge in polygon. */ + int intersections; /* Number of edges in the polygon that + * intersect a ray extending vertically + * upwards from the point to infinity. */ + int nonzerorule; /* As 'intersections' except that it adds + * one if crossing right to left, and + * subtracts one if crossing left to right. */ + int count; + register double *pPtr; + + /* + * Iterate through all of the edges in the polygon, updating + * bestDist and intersections. + * + * TRICKY POINT: when computing intersections, include left + * x-coordinate of line within its range, but not y-coordinate. + * Otherwise if the point lies exactly below a vertex we'll + * count it as two intersections. + */ + + bestDist = 1.0e36; + intersections = 0; + nonzerorule = 0; + + for (count = numPoints, pPtr = polyPtr; count > 1; count--, pPtr += 2) { + double x, y, dist; + + /* + * Compute the point on the current edge closest to the point + * and update the intersection count. This must be done + * separately for vertical edges, horizontal edges, and + * other edges. + */ + + if (pPtr[2] == pPtr[0]) { + + /* + * Vertical edge. + */ + + x = pPtr[0]; + if (pPtr[1] >= pPtr[3]) { + y = MIN(pPtr[1], pointPtr[1]); + y = MAX(y, pPtr[3]); + } else { + y = MIN(pPtr[3], pointPtr[1]); + y = MAX(y, pPtr[1]); + } + } else if (pPtr[3] == pPtr[1]) { + + /* + * Horizontal edge. + */ + + y = pPtr[1]; + if (pPtr[0] >= pPtr[2]) { + x = MIN(pPtr[0], pointPtr[0]); + x = MAX(x, pPtr[2]); + if ((pointPtr[1] < y) && (pointPtr[0] < pPtr[0]) + && (pointPtr[0] >= pPtr[2])) { + intersections++; + nonzerorule++; + } + } else { + x = MIN(pPtr[2], pointPtr[0]); + x = MAX(x, pPtr[0]); + if ((pointPtr[1] < y) && (pointPtr[0] < pPtr[2]) + && (pointPtr[0] >= pPtr[0])) { + intersections++; + nonzerorule--; + } + } + } else { + double m1, b1, m2, b2; + int lower; /* Non-zero means point below line. */ + + /* + * The edge is neither horizontal nor vertical. Convert the + * edge to a line equation of the form y = m1*x + b1. Then + * compute a line perpendicular to this edge but passing + * through the point, also in the form y = m2*x + b2. + */ + + m1 = (pPtr[3] - pPtr[1])/(pPtr[2] - pPtr[0]); + b1 = pPtr[1] - m1*pPtr[0]; + m2 = -1.0/m1; + b2 = pointPtr[1] - m2*pointPtr[0]; + x = (b2 - b1)/(m1 - m2); + y = m1*x + b1; + if (pPtr[0] > pPtr[2]) { + if (x > pPtr[0]) { + x = pPtr[0]; + y = pPtr[1]; + } else if (x < pPtr[2]) { + x = pPtr[2]; + y = pPtr[3]; + } + } else { + if (x > pPtr[2]) { + x = pPtr[2]; + y = pPtr[3]; + } else if (x < pPtr[0]) { + x = pPtr[0]; + y = pPtr[1]; + } + } + lower = (m1*pointPtr[0] + b1) > pointPtr[1]; + if (lower && (pointPtr[0] >= MIN(pPtr[0], pPtr[2])) + && (pointPtr[0] < MAX(pPtr[0], pPtr[2]))) { + intersections++; + if (pPtr[0] >= pPtr[2]) { + nonzerorule++; + } else { + nonzerorule--; + } + } + } + + /* + * Compute the distance to the closest point, and see if that + * is the best distance seen so far. + */ + + dist = hypot(pointPtr[0] - x, pointPtr[1] - y); + if (dist < bestDist) { + bestDist = dist; + } + } + *intersectionsPtr = intersections; + *nonzerorulePtr = nonzerorule; + + return bestDist; +} + +/* + *-------------------------------------------------------------- + * + * PathRectToPoint -- + * + * Computes the distance from a given point to a given + * rectangle, in canvas units. + * + * Results: + * The return value is 0 if the point whose x and y coordinates + * are pointPtr[0] and pointPtr[1] is inside the rectangle. If the + * point isn't inside the rectangle then the return value is the + * distance from the point to the rectangle. If item is filled, + * then anywhere in the interior is considered "inside"; if + * item isn't filled, then "inside" means only the area + * occupied by the outline. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +double +PathRectToPoint( + double rectPtr[], /* Bare rectangle. */ + double width, /* Width of stroke, or 0. */ + int filled, /* Is rectangle filled. */ + double pointPtr[]) /* Pointer to x and y coordinates. */ +{ + double xDiff, yDiff, x1, y1, x2, y2, inc, tmp; + + /* + * Generate a new larger rectangle that includes the border + * width, if there is one. + */ + + inc = width/2.0; + x1 = rectPtr[0] - inc; + y1 = rectPtr[1] - inc; + x2 = rectPtr[2] + inc; + y2 = rectPtr[3] + inc; + + /* + * If the point is inside the rectangle, handle specially: + * distance is 0 if rectangle is filled, otherwise compute + * distance to nearest edge of rectangle and subtract width + * of edge. + */ + + if ((pointPtr[0] >= x1) && (pointPtr[0] < x2) + && (pointPtr[1] >= y1) && (pointPtr[1] < y2)) { + //if (filled || (rectPtr->outline.gc == None)) { + if (filled) { + return 0.0; + } + xDiff = pointPtr[0] - x1; + tmp = x2 - pointPtr[0]; + if (tmp < xDiff) { + xDiff = tmp; + } + yDiff = pointPtr[1] - y1; + tmp = y2 - pointPtr[1]; + if (tmp < yDiff) { + yDiff = tmp; + } + if (yDiff < xDiff) { + xDiff = yDiff; + } + xDiff -= width; + if (xDiff < 0.0) { + return 0.0; + } + return xDiff; + } + + /* + * Point is outside rectangle. + */ + + if (pointPtr[0] < x1) { + xDiff = x1 - pointPtr[0]; + } else if (pointPtr[0] > x2) { + xDiff = pointPtr[0] - x2; + } else { + xDiff = 0; + } + + if (pointPtr[1] < y1) { + yDiff = y1 - pointPtr[1]; + } else if (pointPtr[1] > y2) { + yDiff = pointPtr[1] - y2; + } else { + yDiff = 0; + } + + return hypot(xDiff, yDiff); +} + +/* + *-------------------------------------------------------------- + * + * PathRectToArea -- + * + * This procedure is called to determine whether an rectangle + * lies entirely inside, entirely outside, or overlapping + * another given rectangle. + * + * Results: + * -1 is returned if the rectangle is entirely outside the area + * given by rectPtr, 0 if it overlaps, and 1 if it is entirely + * inside the given area. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +PathRectToArea( + double rectPtr[], /* Bare rectangle. */ + double width, /* Width of stroke, or 0. */ + int filled, /* Is rectangle filled. */ + double *areaPtr) /* Pointer to array of four coordinates + * (x1, y1, x2, y2) describing rectangular + * area. */ +{ + double halfWidth = width/2.0; + + if ((areaPtr[2] <= (rectPtr[0] - halfWidth)) + || (areaPtr[0] >= (rectPtr[2] + halfWidth)) + || (areaPtr[3] <= (rectPtr[1] - halfWidth)) + || (areaPtr[1] >= (rectPtr[3] + halfWidth))) { + return -1; + } + if (!filled && (width > 0.0) + && (areaPtr[0] >= (rectPtr[0] + halfWidth)) + && (areaPtr[1] >= (rectPtr[1] + halfWidth)) + && (areaPtr[2] <= (rectPtr[2] - halfWidth)) + && (areaPtr[3] <= (rectPtr[3] - halfWidth))) { + return -1; + } + if ((areaPtr[0] <= (rectPtr[0] - halfWidth)) + && (areaPtr[1] <= (rectPtr[1] - halfWidth)) + && (areaPtr[2] >= (rectPtr[2] + halfWidth)) + && (areaPtr[3] >= (rectPtr[3] + halfWidth))) { + return 1; + } + return 0; +} + +int +PathRectToAreaWithMatrix(PathRect bbox, TMatrix *mPtr, double *areaPtr) +{ + int rectiLinear = 0; + double rect[4]; + + if (mPtr == NULL) { + rectiLinear = 1; + rect[0] = bbox.x1; + rect[1] = bbox.y1; + rect[2] = bbox.x2; + rect[3] = bbox.y2; + } else if (TMATRIX_IS_RECTILINEAR(mPtr)) { + rectiLinear = 1; + rect[0] = mPtr->a * bbox.x1 + mPtr->tx; + rect[1] = mPtr->d * bbox.y1 + mPtr->ty; + rect[2] = mPtr->a * bbox.x2 + mPtr->tx; + rect[3] = mPtr->d * bbox.y2 + mPtr->ty; + } + if (rectiLinear) { + return PathRectToArea(rect, 0.0, 1, areaPtr); + } else { + double polyPtr[10]; + + /* polyPtr: Points to an array coordinates for closed polygon: x0, y0, x1, y1, ... */ + /* Construct all four corners. */ + polyPtr[0] = bbox.x1, polyPtr[1] = bbox.y1; + polyPtr[2] = bbox.x2, polyPtr[3] = bbox.y1; + polyPtr[4] = bbox.x2, polyPtr[5] = bbox.y2; + polyPtr[6] = bbox.x1, polyPtr[7] = bbox.y2; + PathApplyTMatrix(mPtr, polyPtr, polyPtr+1); + PathApplyTMatrix(mPtr, polyPtr+2, polyPtr+3); + PathApplyTMatrix(mPtr, polyPtr+4, polyPtr+5); + PathApplyTMatrix(mPtr, polyPtr+6, polyPtr+7); + + return TkPolygonToArea(polyPtr, 4, areaPtr); + } +} + +double +PathRectToPointWithMatrix(PathRect bbox, TMatrix *mPtr, double *pointPtr) +{ + int rectiLinear = 0; + double dist; + double rect[4]; + + if (mPtr == NULL) { + rectiLinear = 1; + rect[0] = bbox.x1; + rect[1] = bbox.y1; + rect[2] = bbox.x2; + rect[3] = bbox.y2; + } else if (TMATRIX_IS_RECTILINEAR(mPtr)) { + rectiLinear = 1; + rect[0] = mPtr->a * bbox.x1 + mPtr->tx; + rect[1] = mPtr->d * bbox.y1 + mPtr->ty; + rect[2] = mPtr->a * bbox.x2 + mPtr->tx; + rect[3] = mPtr->d * bbox.y2 + mPtr->ty; + } + if (rectiLinear) { + dist = PathRectToPoint(rect, 0.0, 1, pointPtr); + } else { + int intersections, rule; + double polyPtr[10]; + + /* Construct all four corners. + * First and last must be identical since closed. + */ + polyPtr[0] = bbox.x1, polyPtr[1] = bbox.y1; + polyPtr[2] = bbox.x2, polyPtr[3] = bbox.y1; + polyPtr[4] = bbox.x2, polyPtr[5] = bbox.y2; + polyPtr[6] = bbox.x1, polyPtr[7] = bbox.y2; + PathApplyTMatrix(mPtr, polyPtr, polyPtr+1); + PathApplyTMatrix(mPtr, polyPtr+2, polyPtr+3); + PathApplyTMatrix(mPtr, polyPtr+4, polyPtr+5); + PathApplyTMatrix(mPtr, polyPtr+6, polyPtr+7); + polyPtr[8] = polyPtr[0], polyPtr[9] = polyPtr[1]; + + dist = PathPolygonToPointEx(polyPtr, 5, pointPtr, &intersections, &rule); + if (intersections % 2 == 1) { + dist = 0.0; + } + } + return dist; +} + +/* + *-------------------------------------------------------------- + * + * TkPathCanvasItemExConfigure -- + * + * Takes care of the custom item configuration of the Tk_PathItemEx + * part of any item with style. + * + * Results: + * Standard Tcl result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkPathCanvasItemExConfigure(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItemEx *itemExPtr, int mask) +{ + Tk_Window tkwin; + Tk_PathItem *parentPtr; + Tk_PathItem *itemPtr = (Tk_PathItem *) itemExPtr; + Tk_PathStyle *stylePtr = &itemExPtr->style; + + tkwin = Tk_PathCanvasTkwin(canvas); + if (mask & PATH_CORE_OPTION_PARENT) { + if (TkPathCanvasFindGroup(interp, canvas, itemPtr->parentObj, &parentPtr) != TCL_OK) { + return TCL_ERROR; + } + TkPathCanvasSetParent(parentPtr, itemPtr); + } else if ((itemPtr->id != 0) && (itemPtr->parentPtr == NULL)) { + /* + * If item not root and parent not set we must set it to root by default. + */ + CanvasSetParentToRoot(itemPtr); + } + + /* + * If we have got a style name it's options take precedence + * over the actual path configuration options. This is how SVG does it. + * Good or bad? + */ + if (mask & PATH_CORE_OPTION_STYLENAME) { + TkPathStyleInst *styleInst = NULL; + + if (itemExPtr->styleObj != NULL) { + styleInst = TkPathGetStyle(interp, Tcl_GetString(itemExPtr->styleObj), + TkPathCanvasStyleTable(canvas), PathStyleChangedProc, + (ClientData) itemExPtr); + if (styleInst == NULL) { + return TCL_ERROR; + } + } else { + styleInst = NULL; + } + if (itemExPtr->styleInst != NULL) { + TkPathFreeStyle(itemExPtr->styleInst); + } + itemExPtr->styleInst = styleInst; + } + + /* + * Just translate the 'fillObj' (string) to a TkPathColor. + * We MUST have this last in the chain of custom option checks! + */ + if (mask & PATH_STYLE_OPTION_FILL) { + TkPathColor *fillPtr = NULL; + + if (stylePtr->fillObj != NULL) { + fillPtr = TkPathGetPathColor(interp, tkwin, stylePtr->fillObj, + TkPathCanvasGradientTable(canvas), PathGradientChangedProc, + (ClientData) itemExPtr); + if (fillPtr == NULL) { + return TCL_ERROR; + } + } else { + fillPtr = NULL; + } + /* Free any old and store the new. */ + if (stylePtr->fill != NULL) { + TkPathFreePathColor(stylePtr->fill); + } + stylePtr->fill = fillPtr; + } + return TCL_OK; +} + +void +PathGradientChangedProc(ClientData clientData, int flags) +{ + Tk_PathItemEx *itemExPtr = (Tk_PathItemEx *)clientData; + Tk_PathItem *itemPtr = (Tk_PathItem *) itemExPtr; + Tk_PathStyle *stylePtr = &(itemExPtr->style); + + if (flags) { + if (flags & PATH_GRADIENT_FLAG_DELETE) { + TkPathFreePathColor(stylePtr->fill); + stylePtr->fill = NULL; + Tcl_DecrRefCount(stylePtr->fillObj); + stylePtr->fillObj = NULL; + } + if (itemPtr->typePtr == &tkGroupType) { + GroupItemConfigured(itemExPtr->canvas, itemPtr, + PATH_STYLE_OPTION_FILL); + } else { + Tk_PathCanvasEventuallyRedraw(itemExPtr->canvas, + itemExPtr->header.x1, itemExPtr->header.y1, + itemExPtr->header.x2, itemExPtr->header.y2); + } + } +} + +void +PathStyleChangedProc(ClientData clientData, int flags) +{ + Tk_PathItemEx *itemExPtr = (Tk_PathItemEx *)clientData; + Tk_PathItem *itemPtr = (Tk_PathItem *) itemExPtr; + + if (flags) { + if (flags & PATH_STYLE_FLAG_DELETE) { + TkPathFreeStyle(itemExPtr->styleInst); + itemExPtr->styleInst = NULL; + Tcl_DecrRefCount(itemExPtr->styleObj); + itemExPtr->styleObj = NULL; + } + if (itemPtr->typePtr == &tkGroupType) { + GroupItemConfigured(itemExPtr->canvas, itemPtr, + PATH_CORE_OPTION_STYLENAME); // Not completely correct... + } else { + Tk_PathCanvasEventuallyRedraw(itemExPtr->canvas, + itemExPtr->header.x1, itemExPtr->header.y1, + itemExPtr->header.x2, itemExPtr->header.y2); + } + } +} + +/*--------------------------------------------------------------------------*/ diff --git a/pd/tkpath/generic/tkCanvPathUtil.h b/pd/tkpath/generic/tkCanvPathUtil.h new file mode 100644 index 0000000000000000000000000000000000000000..03d271001424d77c99a6308777c295aedfd7ee2f --- /dev/null +++ b/pd/tkpath/generic/tkCanvPathUtil.h @@ -0,0 +1,105 @@ +/* + * tkCanvPathUtil.h -- + * + * Header for support functions common to many path canvas items. + * + * Copyright (c) 2007-2008 Mats Bengtsson + * + * $Id: tkCanvPathUtil.h,v 1.24 2008/07/16 13:17:28 matben Exp $ + */ + +#ifndef INCLUDED_TKCANVPATHUTIL_H +#define INCLUDED_TKCANVPATHUTIL_H + +#include "tkIntPath.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int CoordsForPointItems(Tcl_Interp *interp, Tk_PathCanvas canvas, + double *pointPtr, int objc, Tcl_Obj *CONST objv[]); +int CoordsForRectangularItems(Tcl_Interp *interp, Tk_PathCanvas canvas, + PathRect *rectPtr, int objc, Tcl_Obj *CONST objv[]); +PathRect GetGenericBarePathBbox(PathAtom *atomPtr); +PathRect GetGenericPathTotalBboxFromBare(PathAtom *atomPtr, Tk_PathStyle *stylePtr, PathRect *bboxPtr); +void SetGenericPathHeaderBbox(Tk_PathItem *headerPtr, TMatrix *mPtr, + PathRect *totalBboxPtr); +TMatrix GetCanvasTMatrix(Tk_PathCanvas canvas); +PathRect NewEmptyPathRect(void); +int IsPathRectEmpty(PathRect *r); +void IncludePointInRect(PathRect *r, double x, double y); +double GenericPathToPoint(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Tk_PathStyle *stylePtr, + PathAtom *atomPtr, int maxNumSegments, double *pointPtr); +int GenericPathToArea(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Tk_PathStyle *stylePtr, + PathAtom * atomPtr, int maxNumSegments, double *areaPtr); +void TranslatePathAtoms(PathAtom *atomPtr, double deltaX, double deltaY); +void ScalePathAtoms(PathAtom *atomPtr, double originX, double originY, + double scaleX, double scaleY); +void TranslatePathRect(PathRect *r, double deltaX, double deltaY); +void ScalePathRect(PathRect *r, double originX, double originY, + double scaleX, double scaleY); +void TranslateItemHeader(Tk_PathItem *itemPtr, double deltaX, double deltaY); +void ScaleItemHeader(Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); + +/* + * The canvas 'Area' and 'Point' functions. + */ +int PathPolyLineToArea(double *polyPtr, int numPoints, register double *rectPtr); +double PathThickPolygonToPoint(int joinStyle, int capStyle, double width, + int isclosed, double *polyPtr, int numPoints, double *pointPtr); +double PathPolygonToPointEx(double *polyPtr, int numPoints, double *pointPtr, + int *intersectionsPtr, int *nonzerorulePtr); +double PathRectToPoint(double rectPtr[], double width, int filled, double pointPtr[]); +int PathRectToArea(double rectPtr[], double width, int filled, double *areaPtr); +int PathRectToAreaWithMatrix(PathRect bbox, TMatrix *mPtr, double *areaPtr); +double PathRectToPointWithMatrix(PathRect bbox, TMatrix *mPtr, double *pointPtr); + + +/* + * New API option parsing. + */ + +#define PATH_DEF_STATE "normal" + +/* These MUST be kept in sync with Tk_PathState! */ + +#define PATH_OPTION_STRING_TABLES_STATE \ + static char *stateStrings[] = { \ + "active", "disabled", "normal", "hidden", NULL \ + }; + +#define PATH_CUSTOM_OPTION_TAGS \ + static Tk_ObjCustomOption tagsCO = { \ + "tags", \ + Tk_PathCanvasTagsOptionSetProc, \ + Tk_PathCanvasTagsOptionGetProc, \ + Tk_PathCanvasTagsOptionRestoreProc, \ + Tk_PathCanvasTagsOptionFreeProc, \ + (ClientData) NULL \ + }; + +#define PATH_OPTION_SPEC_PARENT \ + {TK_OPTION_STRING, "-parent", NULL, NULL, \ + "0", Tk_Offset(Tk_PathItem, parentObj), -1, \ + 0, 0, PATH_CORE_OPTION_PARENT} + +#define PATH_OPTION_SPEC_CORE(typeName) \ + {TK_OPTION_STRING_TABLE, "-state", NULL, NULL, \ + PATH_DEF_STATE, -1, Tk_Offset(Tk_PathItem, state), \ + 0, (ClientData) stateStrings, 0}, \ + {TK_OPTION_STRING, "-style", (char *) NULL, (char *) NULL, \ + "", Tk_Offset(typeName, styleObj), -1, \ + TK_OPTION_NULL_OK, 0, PATH_CORE_OPTION_STYLENAME}, \ + {TK_OPTION_CUSTOM, "-tags", NULL, NULL, \ + NULL, -1, Tk_Offset(Tk_PathItem, pathTagsPtr), \ + TK_OPTION_NULL_OK, (ClientData) &tagsCO, PATH_CORE_OPTION_TAGS} + + +#ifdef __cplusplus +} +#endif + +#endif // INCLUDED_TKCANVPATHUTIL_H + diff --git a/pd/tkpath/generic/tkCanvPimage.c b/pd/tkpath/generic/tkCanvPimage.c new file mode 100644 index 0000000000000000000000000000000000000000..fdc7b1137aa706b66725f8b0369dbaba7c82dad0 --- /dev/null +++ b/pd/tkpath/generic/tkCanvPimage.c @@ -0,0 +1,565 @@ +/* + * tkCanvPimage.c -- + * + * This file implements an image canvas item modelled after its + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2007-2008 Mats Bengtsson + * + * $Id: tkCanvPimage.c,v 1.27 2010/04/30 10:16:00 ebrunel Exp $ + */ + +#include "tkIntPath.h" +#include "tkpCanvas.h" +#include "tkCanvPathUtil.h" +#include "tkPathStyle.h" + +/* For debugging. */ +extern Tcl_Interp *gInterp; + + +/* + * The structure below defines the record for each path item. + */ + +typedef struct PimageItem { + Tk_PathItem header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + Tk_PathCanvas canvas; /* Canvas containing item. */ + double fillOpacity; + TMatrix *matrixPtr; /* a b default (NULL): 1 0 + c d 0 1 + tx ty 0 0 */ + Tcl_Obj *styleObj; /* Object with style name. */ + struct TkPathStyleInst *styleInst; + /* Pointer to first in list of instances + * derived from this style name. */ + double coord[2]; /* nw coord. */ + Tcl_Obj *imageObj; /* Object describing the -image option. + * NULL means no image right now. */ + Tk_Image image; /* Image to display in window, or NULL if + * no image at present. */ + Tk_PhotoHandle photo; + double width; /* If 0 use natural width or height. */ + double height; + PathRect bbox; /* Bounding box with zero width outline. + * Untransformed coordinates. */ +} PimageItem; + + +/* + * Prototypes for procedures defined in this file: + */ + +static void ComputePimageBbox(Tk_PathCanvas canvas, PimageItem *pimagePtr); +static int ConfigurePimage(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int CreatePimage(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeletePimage(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayPimage(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height); +static void PimageBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask); +static int PimageCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int PimageToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double PimageToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int PimageToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScalePimage(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslatePimage(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); +static void ImageChangedProc _ANSI_ARGS_((ClientData clientData, + int x, int y, int width, int height, int imgWidth, + int imgHeight)); +void PimageStyleChangedProc(ClientData clientData, int flags); + + +enum { + PIMAGE_OPTION_INDEX_FILLOPACITY = (1L << (PATH_STYLE_OPTION_INDEX_END + 1)), + PIMAGE_OPTION_INDEX_HEIGHT = (1L << (PATH_STYLE_OPTION_INDEX_END + 2)), + PIMAGE_OPTION_INDEX_IMAGE = (1L << (PATH_STYLE_OPTION_INDEX_END + 3)), + PIMAGE_OPTION_INDEX_MATRIX = (1L << (PATH_STYLE_OPTION_INDEX_END + 4)), + PIMAGE_OPTION_INDEX_WIDTH = (1L << (PATH_STYLE_OPTION_INDEX_END + 5)) +}; + +PATH_STYLE_CUSTOM_OPTION_MATRIX +PATH_CUSTOM_OPTION_TAGS +PATH_OPTION_STRING_TABLES_STATE + +#define PATH_OPTION_SPEC_FILLOPACITY \ + {TK_OPTION_DOUBLE, "-fillopacity", NULL, NULL, \ + "1.0", -1, Tk_Offset(PimageItem, fillOpacity), \ + 0, 0, PIMAGE_OPTION_INDEX_FILLOPACITY} + +#define PATH_OPTION_SPEC_HEIGHT \ + {TK_OPTION_DOUBLE, "-height", NULL, NULL, \ + "0", -1, Tk_Offset(PimageItem, height), \ + 0, 0, PIMAGE_OPTION_INDEX_HEIGHT} + +#define PATH_OPTION_SPEC_IMAGE \ + {TK_OPTION_STRING, "-image", NULL, NULL, \ + NULL, Tk_Offset(PimageItem, imageObj), -1, \ + TK_OPTION_NULL_OK, 0, PIMAGE_OPTION_INDEX_IMAGE} + +#define PATH_OPTION_SPEC_MATRIX \ + {TK_OPTION_CUSTOM, "-matrix", NULL, NULL, \ + NULL, -1, Tk_Offset(PimageItem, matrixPtr), \ + TK_OPTION_NULL_OK, (ClientData) &matrixCO, \ + PIMAGE_OPTION_INDEX_MATRIX} + +#define PATH_OPTION_SPEC_WIDTH \ + {TK_OPTION_DOUBLE, "-width", NULL, NULL, \ + "0", -1, Tk_Offset(PimageItem, width), \ + 0, 0, PIMAGE_OPTION_INDEX_WIDTH} + +static Tk_OptionSpec optionSpecs[] = { + PATH_OPTION_SPEC_CORE(PimageItem), + PATH_OPTION_SPEC_PARENT, + PATH_OPTION_SPEC_MATRIX, + PATH_OPTION_SPEC_FILLOPACITY, + PATH_OPTION_SPEC_HEIGHT, + PATH_OPTION_SPEC_IMAGE, + PATH_OPTION_SPEC_WIDTH, + PATH_OPTION_SPEC_END +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * The structures below defines the 'prect' item type by means + * of procedures that can be invoked by generic item code. + */ + +Tk_PathItemType tkPimageType = { + "pimage", /* name */ + sizeof(PimageItem), /* itemSize */ + CreatePimage, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigurePimage, /* configureProc */ + PimageCoords, /* coordProc */ + DeletePimage, /* deleteProc */ + DisplayPimage, /* displayProc */ + 0, /* flags */ + PimageBbox, /* bboxProc */ + PimageToPoint, /* pointProc */ + PimageToArea, /* areaProc */ + PimageToPostscript, /* postscriptProc */ + ScalePimage, /* scaleProc */ + TranslatePimage, /* translateProc */ + (Tk_PathItemIndexProc *) NULL, /* indexProc */ + (Tk_PathItemCursorProc *) NULL, /* icursorProc */ + (Tk_PathItemSelectionProc *) NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) NULL, /* insertProc */ + (Tk_PathItemDCharsProc *) NULL, /* dTextProc */ + (Tk_PathItemType *) NULL, /* nextPtr */ +}; + + + +static int +CreatePimage(Tcl_Interp *interp, Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PimageItem *pimagePtr = (PimageItem *) itemPtr; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed to set defaults and to + * allow proper cleanup after errors during the the remainder of + * this procedure. + */ + pimagePtr->canvas = canvas; + pimagePtr->styleObj = NULL; + pimagePtr->fillOpacity = 1.0; + pimagePtr->matrixPtr = NULL; + pimagePtr->styleInst = NULL; + pimagePtr->imageObj = NULL; + pimagePtr->image = NULL; + pimagePtr->photo = NULL; + pimagePtr->height = 0; + pimagePtr->width = 0; + pimagePtr->bbox = NewEmptyPathRect(); + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) pimagePtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + for (i = 1; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + if (CoordsForPointItems(interp, canvas, pimagePtr->coord, i, objv) != TCL_OK) { + goto error; + } + if (ConfigurePimage(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { + return TCL_OK; + } + + error: + /* + * NB: We must unlink the item here since the ConfigurePimage() + * link it to the root by default. + */ + TkPathCanvasItemDetach(itemPtr); + DeletePimage(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +static int +PimageCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PimageItem *pimagePtr = (PimageItem *) itemPtr; + int result; + + result = CoordsForPointItems(interp, canvas, pimagePtr->coord, objc, objv); + if ((result == TCL_OK) && ((objc == 1) || (objc == 2))) { + ComputePimageBbox(canvas, pimagePtr); + } + return result; +} + +/* + * This is just a convenience function to obtain any style matrix. + */ + +static TMatrix +GetTMatrix(PimageItem *pimagePtr) +{ + TMatrix *matrixPtr; + Tk_PathStyle *stylePtr; + TMatrix matrix = TkPathCanvasInheritTMatrix((Tk_PathItem *) pimagePtr); + + matrixPtr = pimagePtr->matrixPtr; + if (pimagePtr->styleInst != NULL) { + stylePtr = pimagePtr->styleInst->masterPtr; + if (stylePtr->mask & PATH_STYLE_OPTION_MATRIX) { + matrixPtr = stylePtr->matrixPtr; + } + } + if (matrixPtr != NULL) { + MMulTMatrix(matrixPtr, &matrix); + } + return matrix; +} + +void +ComputePimageBbox(Tk_PathCanvas canvas, PimageItem *pimagePtr) +{ + Tk_PathState state = pimagePtr->header.state; + TMatrix matrix; + int width = 0, height = 0; + PathRect bbox; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (pimagePtr->image == NULL) { + pimagePtr->header.x1 = pimagePtr->header.x2 = + pimagePtr->header.y1 = pimagePtr->header.y2 = -1; + return; + } + Tk_SizeOfImage(pimagePtr->image, &width, &height); + if (pimagePtr->width > 0.0) { + width = (int) (pimagePtr->width + 1.0); + } + if (pimagePtr->height > 0.0) { + height = (int) (pimagePtr->height + 1.0); + } + bbox.x1 = pimagePtr->coord[0]; + bbox.y1 = pimagePtr->coord[1]; + bbox.x2 = bbox.x1 + width; + bbox.y2 = bbox.y1 + height; + pimagePtr->bbox = bbox; + matrix = GetTMatrix(pimagePtr); + SetGenericPathHeaderBbox(&pimagePtr->header, &matrix, &bbox); +} + +static int +ConfigurePimage(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[], int flags) +{ + PimageItem *pimagePtr = (PimageItem *) itemPtr; + Tk_Window tkwin; + Tk_Image image; + Tk_PhotoHandle photo; + Tk_SavedOptions savedOptions; + Tk_PathItem *parentPtr; + Tcl_Obj *errorResult = NULL; + int error, mask; + + tkwin = Tk_PathCanvasTkwin(canvas); + for (error = 0; error <= 1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char *) pimagePtr, optionTable, + objc, objv, tkwin, &savedOptions, &mask) != TCL_OK) { + continue; + } + } else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + /* + * Take each custom option, not handled in Tk_SetOptions, in turn. + */ + if (mask & PATH_CORE_OPTION_PARENT) { + if (TkPathCanvasFindGroup(interp, canvas, itemPtr->parentObj, &parentPtr) != TCL_OK) { + continue; + } + TkPathCanvasSetParent(parentPtr, itemPtr); + } else if ((itemPtr->id != 0) && (itemPtr->parentPtr == NULL)) { + /* + * If item not root and parent not set we must set it to root by default. + */ + CanvasSetParentToRoot(itemPtr); + } + + /* + * If we have got a style name it's options take precedence + * over the actual path configuration options. This is how SVG does it. + * Good or bad? + */ + if (mask & PATH_CORE_OPTION_STYLENAME) { + TkPathStyleInst *styleInst = NULL; + + if (pimagePtr->styleObj != NULL) { + styleInst = TkPathGetStyle(interp, Tcl_GetString(pimagePtr->styleObj), + TkPathCanvasStyleTable(canvas), PimageStyleChangedProc, + (ClientData) itemPtr); + if (styleInst == NULL) { + continue; + } + } else { + styleInst = NULL; + } + if (pimagePtr->styleInst != NULL) { + TkPathFreeStyle(pimagePtr->styleInst); + } + pimagePtr->styleInst = styleInst; + } + + /* + * Create the image. Save the old image around and don't free it + * until after the new one is allocated. This keeps the reference + * count from going to zero so the image doesn't have to be recreated + * if it hasn't changed. + */ + if (mask & PIMAGE_OPTION_INDEX_IMAGE) { + if (pimagePtr->imageObj != NULL) { + image = Tk_GetImage(interp, tkwin, + Tcl_GetString(pimagePtr->imageObj), + ImageChangedProc, (ClientData) pimagePtr); + if (image == NULL) { + continue; + } + photo = Tk_FindPhoto(interp, Tcl_GetString(pimagePtr->imageObj)); + if (photo == NULL) { + continue; + } + } else { + image = NULL; + photo = NULL; + } + if (pimagePtr->image != NULL) { + Tk_FreeImage(pimagePtr->image); + } + pimagePtr->image = image; + pimagePtr->photo = photo; + } + + /* + * If we reach this on the first pass we are OK and continue below. + */ + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + } + pimagePtr->fillOpacity = MAX(0.0, MIN(1.0, pimagePtr->fillOpacity)); + +#if 0 // From old code. Needed? + state = itemPtr->state; + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + return TCL_OK; + } +#endif + /* + * Recompute bounding box for path. + */ + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + ComputePimageBbox(canvas, pimagePtr); + return TCL_OK; + } +} + +static void +DeletePimage(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display) +{ + PimageItem *pimagePtr = (PimageItem *) itemPtr; + + if (pimagePtr->styleInst != NULL) { + TkPathFreeStyle(pimagePtr->styleInst); + } + if (pimagePtr->image != NULL) { + Tk_FreeImage(pimagePtr->image); + } + Tk_FreeConfigOptions((char *) pimagePtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +static void +DisplayPimage(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height) +{ + PimageItem *pimagePtr = (PimageItem *) itemPtr; + TMatrix m; + TkPathContext ctx; + + /* === EB - 23-apr-2010: register coordinate offsets */ + m = GetCanvasTMatrix(canvas); + TkPathSetCoordOffsets(m.tx, m.ty); + ctx = TkPathInit(Tk_PathCanvasTkwin(canvas), drawable); + /* === */ + + TkPathPushTMatrix(ctx, &m); + m = GetTMatrix(pimagePtr); + TkPathPushTMatrix(ctx, &m); + /* @@@ Maybe we should taking care of x, y etc.? */ + TkPathImage(ctx, pimagePtr->image, pimagePtr->photo, + pimagePtr->coord[0], pimagePtr->coord[1], + pimagePtr->width, pimagePtr->height); + TkPathFree(ctx); +} + +static void +PimageBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask) +{ + PimageItem *pimagePtr = (PimageItem *) itemPtr; + ComputePimageBbox(canvas, pimagePtr); +} + +static double +PimageToPoint(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *pointPtr) +{ + PimageItem *pimagePtr = (PimageItem *) itemPtr; + TMatrix m = GetTMatrix(pimagePtr); + return PathRectToPointWithMatrix(pimagePtr->bbox, &m, pointPtr); +} + +static int +PimageToArea(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *areaPtr) +{ + PimageItem *pimagePtr = (PimageItem *) itemPtr; + TMatrix m = GetTMatrix(pimagePtr); + return PathRectToAreaWithMatrix(pimagePtr->bbox, &m, areaPtr); +} + +static int +PimageToPostscript(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass) +{ + return TCL_ERROR; +} + +static void +ScalePimage(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY) +{ + /* Skip? */ +} + +static void +TranslatePimage(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double deltaX, double deltaY) +{ + PimageItem *pimagePtr = (PimageItem *) itemPtr; + + /* Just translate the bbox'es as well. */ + TranslatePathRect(&(pimagePtr->bbox), deltaX, deltaY); + pimagePtr->coord[0] += deltaX; + pimagePtr->coord[1] += deltaY; + TranslateItemHeader(itemPtr, deltaX, deltaY); +} + +static void +ImageChangedProc( + ClientData clientData, /* Pointer to canvas item for image. */ + int x, int y, /* Upper left pixel (within image) + * that must be redisplayed. */ + int width, int height, /* Dimensions of area to redisplay + * (may be <= 0). */ + int imgWidth, int imgHeight)/* New dimensions of image. */ +{ + PimageItem *pimagePtr = (PimageItem *) clientData; + + /* + * If the image's size changed and it's not anchored at its + * northwest corner then just redisplay the entire area of the + * image. This is a bit over-conservative, but we need to do + * something because a size change also means a position change. + */ + + /* @@@ MUST consider our own width and height settings as well and TMatrix. */ + + if (((pimagePtr->header.x2 - pimagePtr->header.x1) != imgWidth) + || ((pimagePtr->header.y2 - pimagePtr->header.y1) != imgHeight)) { + x = y = 0; + width = imgWidth; + height = imgHeight; + Tk_PathCanvasEventuallyRedraw(pimagePtr->canvas, pimagePtr->header.x1, + pimagePtr->header.y1, pimagePtr->header.x2, pimagePtr->header.y2); + } + ComputePimageBbox(pimagePtr->canvas, pimagePtr); + Tk_PathCanvasEventuallyRedraw(pimagePtr->canvas, pimagePtr->header.x1 + x, + pimagePtr->header.y1 + y, (int) (pimagePtr->header.x1 + x + width), + (int) (pimagePtr->header.y1 + y + height)); +} + +void +PimageStyleChangedProc(ClientData clientData, int flags) +{ + Tk_PathItem *itemPtr = (Tk_PathItem *) clientData; + PimageItem *pimagePtr = (PimageItem *) itemPtr; + + if (flags) { + if (flags & PATH_STYLE_FLAG_DELETE) { + TkPathFreeStyle(pimagePtr->styleInst); + pimagePtr->styleInst = NULL; + Tcl_DecrRefCount(pimagePtr->styleObj); + pimagePtr->styleObj = NULL; + } + Tk_PathCanvasEventuallyRedraw(pimagePtr->canvas, + itemPtr->x1, itemPtr->y1, + itemPtr->x2, itemPtr->y2); + } +} + +/*----------------------------------------------------------------------*/ + diff --git a/pd/tkpath/generic/tkCanvPline.c b/pd/tkpath/generic/tkCanvPline.c new file mode 100644 index 0000000000000000000000000000000000000000..b1f8ce7dc7a1b531bb3665dfbc882b62711acd7b --- /dev/null +++ b/pd/tkpath/generic/tkCanvPline.c @@ -0,0 +1,430 @@ +/* + * tkCanvPline.c -- + * + * This file implements a line canvas item modelled after its + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2007-2008 Mats Bengtsson + * + * $Id: tkCanvPline.c,v 1.25 2010/04/30 10:16:00 ebrunel Exp $ + */ + +#include "tkIntPath.h" +#include "tkpCanvas.h" +#include "tkCanvPathUtil.h" +#include "tkPathStyle.h" + +/* For debugging. */ +extern Tcl_Interp *gInterp; + +/* + * The structure below defines the record for each path item. + */ + +typedef struct PlineItem { + Tk_PathItemEx headerEx; /* Generic stuff that's the same for all + * path types. MUST BE FIRST IN STRUCTURE. */ + PathRect coords; /* Coordinates (unorders bare bbox). */ + PathRect totalBbox; /* Bounding box including stroke. + * Untransformed coordinates. */ +} PlineItem; + + +/* + * Prototypes for procedures defined in this file: + */ + +static void ComputePlineBbox(Tk_PathCanvas canvas, PlineItem *plinePtr); +static int ConfigurePline(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int CreatePline(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeletePline(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayPline(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height); +static void PlineBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask); +static int ProcessCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, Tcl_Obj *CONST objv[]); +static int PlineCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int PlineToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double PlineToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int PlineToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScalePline(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslatePline(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); +static PathAtom * MakePathAtoms(PlineItem *plinePtr); + +PATH_STYLE_CUSTOM_OPTION_MATRIX +PATH_STYLE_CUSTOM_OPTION_DASH +PATH_CUSTOM_OPTION_TAGS +PATH_OPTION_STRING_TABLES_STROKE +PATH_OPTION_STRING_TABLES_STATE + +static Tk_OptionSpec optionSpecs[] = { + PATH_OPTION_SPEC_CORE(Tk_PathItemEx), + PATH_OPTION_SPEC_PARENT, + PATH_OPTION_SPEC_STYLE_MATRIX(Tk_PathItemEx), + PATH_OPTION_SPEC_STYLE_STROKE(Tk_PathItemEx, "black"), + PATH_OPTION_SPEC_END +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * The structures below defines the 'prect' item type by means + * of procedures that can be invoked by generic item code. + */ + +Tk_PathItemType tkPlineType = { + "pline", /* name */ + sizeof(PlineItem), /* itemSize */ + CreatePline, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigurePline, /* configureProc */ + PlineCoords, /* coordProc */ + DeletePline, /* deleteProc */ + DisplayPline, /* displayProc */ + 0, /* flags */ + PlineBbox, /* bboxProc */ + PlineToPoint, /* pointProc */ + PlineToArea, /* areaProc */ + PlineToPostscript, /* postscriptProc */ + ScalePline, /* scaleProc */ + TranslatePline, /* translateProc */ + (Tk_PathItemIndexProc *) NULL, /* indexProc */ + (Tk_PathItemCursorProc *) NULL, /* icursorProc */ + (Tk_PathItemSelectionProc *) NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) NULL, /* insertProc */ + (Tk_PathItemDCharsProc *) NULL, /* dTextProc */ + (Tk_PathItemType *) NULL, /* nextPtr */ +}; + +static int +CreatePline(Tcl_Interp *interp, Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &plinePtr->headerEx; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed to set defaults and to + * allow proper cleanup after errors during the the remainder of + * this procedure. + */ + TkPathInitStyle(&itemExPtr->style); + itemExPtr->canvas = canvas; + itemExPtr->styleObj = NULL; + itemExPtr->styleInst = NULL; + plinePtr->totalBbox = NewEmptyPathRect(); + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) plinePtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + for (i = 1; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + if (ProcessCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { + goto error; + } + if (ConfigurePline(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { + return TCL_OK; + } + + error: + /* + * NB: We must unlink the item here since the TkPathCanvasItemExConfigure() + * link it to the root by default. + */ + TkPathCanvasItemDetach(itemPtr); + DeletePline(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +static int +ProcessCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + PathRect *p = &plinePtr->coords; + + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(p->x1); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(p->y1); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(p->x2); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(p->y2); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if ((objc == 1) || (objc == 4)) { + if (objc==1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 4) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected 0 or 4", -1)); + return TCL_ERROR; + } + } + if ((Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[0], &p->x1) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[1], &p->y1) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[2], &p->x2) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[3], &p->y2) != TCL_OK)) { + return TCL_ERROR; + } + } else { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected 0 or 4", -1)); + return TCL_ERROR; + } + return TCL_OK; +} + +static int +PlineCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + int result; + + result = ProcessCoords(interp, canvas, itemPtr, objc, objv); + if ((result == TCL_OK) && (objc == 1)) { + ComputePlineBbox(canvas, plinePtr); + } + return result; +} + +static void +ComputePlineBbox(Tk_PathCanvas canvas, PlineItem *plinePtr) +{ + Tk_PathItemEx *itemExPtr = &plinePtr->headerEx; + Tk_PathItem *itemPtr = &itemExPtr->header; + Tk_PathStyle style; + Tk_PathState state = itemExPtr->header.state; + PathRect r; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + itemExPtr->header.x1 = itemExPtr->header.x2 = + itemExPtr->header.y1 = itemExPtr->header.y2 = -1; + return; + } + style = TkPathCanvasInheritStyle(itemPtr, kPathMergeStyleNotFill); + r.x1 = MIN(plinePtr->coords.x1, plinePtr->coords.x2); + r.x2 = MAX(plinePtr->coords.x1, plinePtr->coords.x2); + r.y1 = MIN(plinePtr->coords.y1, plinePtr->coords.y2); + r.y2 = MAX(plinePtr->coords.y1, plinePtr->coords.y2); + plinePtr->totalBbox = GetGenericPathTotalBboxFromBare(NULL, &style, &r); + SetGenericPathHeaderBbox(&itemExPtr->header, style.matrixPtr, &plinePtr->totalBbox); + TkPathCanvasFreeInheritedStyle(&style); +} + +static int +ConfigurePline(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[], int flags) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &plinePtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + Tk_Window tkwin; + //Tk_PathState state; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int error, mask; + + tkwin = Tk_PathCanvasTkwin(canvas); + for (error = 0; error <= 1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char *) plinePtr, optionTable, + objc, objv, tkwin, &savedOptions, &mask) != TCL_OK) { + continue; + } + } else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + if (TkPathCanvasItemExConfigure(interp, canvas, itemExPtr, mask) != TCL_OK) { + continue; + } + + /* + * If we reach this on the first pass we are OK and continue below. + */ + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + stylePtr->mask |= mask; + } + +#if 0 // From old code. Needed? + state = itemPtr->state; + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + return TCL_OK; + } +#endif + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + ComputePlineBbox(canvas, plinePtr); + return TCL_OK; + } +} + +static PathAtom * +MakePathAtoms(PlineItem *plinePtr) +{ + PathAtom *atomPtr; + + atomPtr = NewMoveToAtom(plinePtr->coords.x1, plinePtr->coords.y1); + atomPtr->nextPtr = NewLineToAtom(plinePtr->coords.x2, plinePtr->coords.y2); + return atomPtr; +} + +static void +DeletePline(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &plinePtr->headerEx; + + if (itemExPtr->styleInst != NULL) { + TkPathFreeStyle(itemExPtr->styleInst); + } + Tk_FreeConfigOptions((char *) itemPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +static void +DisplayPline(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + TMatrix m = GetCanvasTMatrix(canvas); + PathRect r; + PathAtom *atomPtr; + Tk_PathStyle style; + + /* === EB - 23-apr-2010: register coordinate offsets */ + TkPathSetCoordOffsets(m.tx, m.ty); + /* === */ + + r.x1 = MIN(plinePtr->coords.x1, plinePtr->coords.x2); + r.x2 = MAX(plinePtr->coords.x1, plinePtr->coords.x2); + r.y1 = MIN(plinePtr->coords.y1, plinePtr->coords.y2); + r.y2 = MAX(plinePtr->coords.y1, plinePtr->coords.y2); + + atomPtr = MakePathAtoms(plinePtr); + style = TkPathCanvasInheritStyle(itemPtr, kPathMergeStyleNotFill); + TkPathDrawPath(Tk_PathCanvasTkwin(canvas), drawable, atomPtr, &style, &m, &r); + TkPathFreeAtoms(atomPtr); + TkPathCanvasFreeInheritedStyle(&style); +} + +static void +PlineBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + ComputePlineBbox(canvas, plinePtr); +} + +static double +PlineToPoint(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *pointPtr) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + Tk_PathStyle style; + PathAtom *atomPtr; + double point; + + style = TkPathCanvasInheritStyle(itemPtr, kPathMergeStyleNotFill); + + /* @@@ Perhaps we should do a simplified treatment here instead of the generic. */ + atomPtr = MakePathAtoms(plinePtr); + point = GenericPathToPoint(canvas, itemPtr, &style, + atomPtr, 2, pointPtr); + TkPathFreeAtoms(atomPtr); + TkPathCanvasFreeInheritedStyle(&style); + return point; +} + +static int +PlineToArea(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *areaPtr) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + Tk_PathStyle style; + PathAtom *atomPtr; + int area; + + style = TkPathCanvasInheritStyle(itemPtr, kPathMergeStyleNotFill); + + /* @@@ Perhaps we should do a simplified treatment here instead of the generic. */ + atomPtr = MakePathAtoms(plinePtr); + area = GenericPathToArea(canvas, itemPtr, &style, + atomPtr, 2, areaPtr); + TkPathFreeAtoms(atomPtr); + TkPathCanvasFreeInheritedStyle(&style); + return area; +} + +static int +PlineToPostscript(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass) +{ + return TCL_ERROR; /* @@@ Anyone? */ +} + +static void +ScalePline(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + + ScalePathRect(&plinePtr->totalBbox, originX, originY, scaleX, scaleY); + ScalePathRect(&plinePtr->coords, originX, originY, scaleX, scaleY); + ScaleItemHeader(itemPtr, originX, originY, scaleX, scaleY); +} + +static void +TranslatePline(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double deltaX, double deltaY) +{ + PlineItem *plinePtr = (PlineItem *) itemPtr; + + /* Just translate the bbox as well. */ + TranslatePathRect(&plinePtr->totalBbox, deltaX, deltaY); + TranslatePathRect(&plinePtr->coords, deltaX, deltaY); + TranslateItemHeader(itemPtr, deltaX, deltaY); +} + +/*----------------------------------------------------------------------*/ + diff --git a/pd/tkpath/generic/tkCanvPpoly.c b/pd/tkpath/generic/tkCanvPpoly.c new file mode 100644 index 0000000000000000000000000000000000000000..e03f31eb402b13e2eb871b666261058291239979 --- /dev/null +++ b/pd/tkpath/generic/tkCanvPpoly.c @@ -0,0 +1,575 @@ +/* + * tkCanvPpolygon.c -- + * + * This file implements polygon and polyline canvas items modelled after its + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2007-2008 Mats Bengtsson + * + * $Id: tkCanvPpoly.c,v 1.25 2010/04/30 10:16:00 ebrunel Exp $ + */ + +#include "tkIntPath.h" +#include "tkpCanvas.h" +#include "tkCanvPathUtil.h" +#include "tkPathStyle.h" + +/* For debugging. */ +extern Tcl_Interp *gInterp; + +/* + * The structure below defines the record for each path item. + */ + +typedef struct PpolyItem { + Tk_PathItemEx headerEx; /* Generic stuff that's the same for all + * path types. MUST BE FIRST IN STRUCTURE. */ + char type; /* Polyline or polygon. */ + PathAtom *atomPtr; + PathRect bbox; /* Bounding box with zero width outline. + * Untransformed coordinates. */ + PathRect totalBbox; /* Bounding box including stroke. + * Untransformed coordinates. */ + int maxNumSegments; /* Max number of straight segments (for subpath) + * needed for Area and Point functions. */ +} PpolyItem; + +enum { + kPpolyTypePolyline, + kPpolyTypePolygon +}; + + +/* + * Prototypes for procedures defined in this file: + */ + +static void ComputePpolyBbox(Tk_PathCanvas canvas, PpolyItem *ppolyPtr); +static int ConfigurePpoly(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +int CoordsForPolygonline(Tcl_Interp *interp, Tk_PathCanvas canvas, int closed, + int objc, Tcl_Obj *CONST objv[], PathAtom **atomPtrPtr, int *lenPtr); +static int CreateAny(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[], char type); +static int CreatePolyline(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int CreatePpolygon(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeletePpoly(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display); +static void DisplayPpoly(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height); +static void PpolyBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask); +static int PpolyCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int PpolyToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double PpolyToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int PpolyToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScalePpoly(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslatePpoly(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); + + +PATH_STYLE_CUSTOM_OPTION_RECORDS +PATH_CUSTOM_OPTION_TAGS +PATH_OPTION_STRING_TABLES_FILL +PATH_OPTION_STRING_TABLES_STROKE +PATH_OPTION_STRING_TABLES_STATE + +static Tk_OptionSpec optionSpecsPolyline[] = { + PATH_OPTION_SPEC_CORE(Tk_PathItemEx), + PATH_OPTION_SPEC_PARENT, + PATH_OPTION_SPEC_STYLE_FILL(Tk_PathItemEx, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(Tk_PathItemEx), + PATH_OPTION_SPEC_STYLE_STROKE(Tk_PathItemEx, "black"), + PATH_OPTION_SPEC_END +}; + +static Tk_OptionSpec optionSpecsPpolygon[] = { + PATH_OPTION_SPEC_CORE(Tk_PathItemEx), + PATH_OPTION_SPEC_PARENT, + PATH_OPTION_SPEC_STYLE_FILL(Tk_PathItemEx, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(Tk_PathItemEx), + PATH_OPTION_SPEC_STYLE_STROKE(Tk_PathItemEx, "black"), + PATH_OPTION_SPEC_END +}; + +static Tk_OptionTable optionTablePolyline = NULL; +static Tk_OptionTable optionTablePpolygon = NULL; + +/* + * The structures below defines the 'polyline' item type by means + * of procedures that can be invoked by generic item code. + */ + +Tk_PathItemType tkPolylineType = { + "polyline", /* name */ + sizeof(PpolyItem), /* itemSize */ + CreatePolyline, /* createProc */ + optionSpecsPolyline, /* OptionSpecs */ + ConfigurePpoly, /* configureProc */ + PpolyCoords, /* coordProc */ + DeletePpoly, /* deleteProc */ + DisplayPpoly, /* displayProc */ + 0, /* flags */ + PpolyBbox, /* bboxProc */ + PpolyToPoint, /* pointProc */ + PpolyToArea, /* areaProc */ + PpolyToPostscript, /* postscriptProc */ + ScalePpoly, /* scaleProc */ + TranslatePpoly, /* translateProc */ + (Tk_PathItemIndexProc *) NULL, /* indexProc */ + (Tk_PathItemCursorProc *) NULL, /* icursorProc */ + (Tk_PathItemSelectionProc *) NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) NULL, /* insertProc */ + (Tk_PathItemDCharsProc *) NULL, /* dTextProc */ + (Tk_PathItemType *) NULL, /* nextPtr */ +}; + +Tk_PathItemType tkPpolygonType = { + "ppolygon", /* name */ + sizeof(PpolyItem), /* itemSize */ + CreatePpolygon, /* createProc */ + optionSpecsPpolygon, /* OptionSpecs */ + ConfigurePpoly, /* configureProc */ + PpolyCoords, /* coordProc */ + DeletePpoly, /* deleteProc */ + DisplayPpoly, /* displayProc */ + 0, /* flags */ + PpolyBbox, /* bboxProc */ + PpolyToPoint, /* pointProc */ + PpolyToArea, /* areaProc */ + PpolyToPostscript, /* postscriptProc */ + ScalePpoly, /* scaleProc */ + TranslatePpoly, /* translateProc */ + (Tk_PathItemIndexProc *) NULL, /* indexProc */ + (Tk_PathItemCursorProc *) NULL, /* icursorProc */ + (Tk_PathItemSelectionProc *) NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) NULL, /* insertProc */ + (Tk_PathItemDCharsProc *) NULL, /* dTextProc */ + (Tk_PathItemType *) NULL, /* nextPtr */ +}; + + +static int +CreatePolyline(Tcl_Interp *interp, Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + return CreateAny(interp, canvas, itemPtr, objc, objv, kPpolyTypePolyline); +} + +static int +CreatePpolygon(Tcl_Interp *interp, Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + return CreateAny(interp, canvas, itemPtr, objc, objv, kPpolyTypePolygon); +} + +static int +CreateAny(Tcl_Interp *interp, Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[], char type) +{ + PpolyItem *ppolyPtr = (PpolyItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &ppolyPtr->headerEx; + Tk_OptionTable optionTable; + int i, len; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed to set defaults and to + * allow proper cleanup after errors during the the remainder of + * this procedure. + */ + TkPathInitStyle(&itemExPtr->style); + itemExPtr->canvas = canvas; + itemExPtr->styleObj = NULL; + itemExPtr->styleInst = NULL; + ppolyPtr->atomPtr = NULL; + ppolyPtr->type = type; + ppolyPtr->bbox = NewEmptyPathRect(); + ppolyPtr->totalBbox = NewEmptyPathRect(); + ppolyPtr->maxNumSegments = 0; + + if (ppolyPtr->type == kPpolyTypePolyline) { + if (optionTablePolyline == NULL) { + optionTablePolyline = Tk_CreateOptionTable(interp, optionSpecsPolyline); + } + optionTable = optionTablePolyline; + } else { + if (optionTablePpolygon == NULL) { + optionTablePpolygon = Tk_CreateOptionTable(interp, optionSpecsPpolygon); + } + optionTable = optionTablePpolygon; + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) ppolyPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + for (i = 1; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + if (CoordsForPolygonline(interp, canvas, + (ppolyPtr->type == kPpolyTypePolyline) ? 0 : 1, + i, objv, &(ppolyPtr->atomPtr), &len) != TCL_OK) { + goto error; + } + ppolyPtr->maxNumSegments = len; + + if (ConfigurePpoly(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { + return TCL_OK; + } + + error: + /* + * NB: We must unlink the item here since the TkPathCanvasItemExConfigure() + * link it to the root by default. + */ + TkPathCanvasItemDetach(itemPtr); + DeletePpoly(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +static int +PpolyCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PpolyItem *ppolyPtr = (PpolyItem *) itemPtr; + int len, closed; + + closed = (ppolyPtr->type == kPpolyTypePolyline) ? 0 : 1; + if (CoordsForPolygonline(interp, canvas, closed, objc, objv, + &(ppolyPtr->atomPtr), &len) != TCL_OK) { + return TCL_ERROR; + } + ppolyPtr->maxNumSegments = len; + ComputePpolyBbox(canvas, ppolyPtr); + return TCL_OK; +} + +void +ComputePpolyBbox(Tk_PathCanvas canvas, PpolyItem *ppolyPtr) +{ + Tk_PathItemEx *itemExPtr = &ppolyPtr->headerEx; + Tk_PathItem *itemPtr = &itemExPtr->header; + Tk_PathStyle style; + Tk_PathState state = itemExPtr->header.state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if ((ppolyPtr->atomPtr == NULL) || (state == TK_PATHSTATE_HIDDEN)) { + itemExPtr->header.x1 = itemExPtr->header.x2 = + itemExPtr->header.y1 = itemExPtr->header.y2 = -1; + return; + } + style = TkPathCanvasInheritStyle(itemPtr, kPathMergeStyleNotFill); + ppolyPtr->bbox = GetGenericBarePathBbox(ppolyPtr->atomPtr); + ppolyPtr->totalBbox = GetGenericPathTotalBboxFromBare(ppolyPtr->atomPtr, + &style, &ppolyPtr->bbox); + SetGenericPathHeaderBbox(&itemExPtr->header, style.matrixPtr, &ppolyPtr->totalBbox); + TkPathCanvasFreeInheritedStyle(&style); +} + +static int +ConfigurePpoly(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[], int flags) +{ + PpolyItem *ppolyPtr = (PpolyItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &ppolyPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + Tk_Window tkwin; + //Tk_PathState state; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int mask, error; + + tkwin = Tk_PathCanvasTkwin(canvas); + for (error = 0; error <= 1; error++) { + if (!error) { + Tk_OptionTable optionTable; + optionTable = (ppolyPtr->type == kPpolyTypePolyline) ? optionTablePolyline : optionTablePpolygon; + if (Tk_SetOptions(interp, (char *) ppolyPtr, optionTable, + objc, objv, tkwin, &savedOptions, &mask) != TCL_OK) { + continue; + } + } else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + if (TkPathCanvasItemExConfigure(interp, canvas, itemExPtr, mask) != TCL_OK) { + continue; + } + + /* + * If we reach this on the first pass we are OK and continue below. + */ + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + stylePtr->mask |= mask; + } + stylePtr->strokeOpacity = MAX(0.0, MIN(1.0, stylePtr->strokeOpacity)); + +#if 0 // From old code. Needed? + state = itemPtr->state; + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + return TCL_OK; + } +#endif + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + ComputePpolyBbox(canvas, ppolyPtr); + return TCL_OK; + } +} + +static void +DeletePpoly(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display) +{ + PpolyItem *ppolyPtr = (PpolyItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &ppolyPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + Tk_OptionTable optionTable; + + if (stylePtr->fill != NULL) { + TkPathFreePathColor(stylePtr->fill); + } + if (itemExPtr->styleInst != NULL) { + TkPathFreeStyle(itemExPtr->styleInst); + } + if (ppolyPtr->atomPtr != NULL) { + TkPathFreeAtoms(ppolyPtr->atomPtr); + ppolyPtr->atomPtr = NULL; + } + optionTable = (ppolyPtr->type == kPpolyTypePolyline) ? optionTablePolyline : optionTablePpolygon; + Tk_FreeConfigOptions((char *) itemPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +static void +DisplayPpoly(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height) +{ + PpolyItem *ppolyPtr = (PpolyItem *) itemPtr; + TMatrix m = GetCanvasTMatrix(canvas); + Tk_PathStyle style; + + /* === EB - 23-apr-2010: register coordinate offsets */ + TkPathSetCoordOffsets(m.tx, m.ty); + /* === */ + + style = TkPathCanvasInheritStyle(itemPtr, 0); + TkPathDrawPath(Tk_PathCanvasTkwin(canvas), drawable, ppolyPtr->atomPtr, &style, + &m, &ppolyPtr->bbox); + TkPathCanvasFreeInheritedStyle(&style); +} + +static void +PpolyBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask) +{ + PpolyItem *ppolyPtr = (PpolyItem *) itemPtr; + ComputePpolyBbox(canvas, ppolyPtr); +} + +static double +PpolyToPoint(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *pointPtr) +{ + PpolyItem *ppolyPtr = (PpolyItem *) itemPtr; + Tk_PathStyle style; + double dist; + long flags; + + flags = (ppolyPtr->type == kPpolyTypePolyline) ? kPathMergeStyleNotFill : 0; + style = TkPathCanvasInheritStyle(itemPtr, flags); + dist = GenericPathToPoint(canvas, itemPtr, &style, ppolyPtr->atomPtr, + ppolyPtr->maxNumSegments, pointPtr); + TkPathCanvasFreeInheritedStyle(&style); + return dist; +} + +static int +PpolyToArea(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *areaPtr) +{ + PpolyItem *ppolyPtr = (PpolyItem *) itemPtr; + Tk_PathStyle style; + int area; + long flags; + + flags = (ppolyPtr->type == kPpolyTypePolyline) ? kPathMergeStyleNotFill : 0; + style = TkPathCanvasInheritStyle(itemPtr, flags); + area = GenericPathToArea(canvas, itemPtr, &style, + ppolyPtr->atomPtr, ppolyPtr->maxNumSegments, areaPtr); + TkPathCanvasFreeInheritedStyle(&style); + return area; +} + +static int +PpolyToPostscript(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass) +{ + return TCL_ERROR; +} + +static void +ScalePpoly(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY) +{ + PpolyItem *ppolyPtr = (PpolyItem *) itemPtr; + + ScalePathAtoms(ppolyPtr->atomPtr, originX, originY, scaleX, scaleY); + ScalePathRect(&ppolyPtr->bbox, originX, originY, scaleX, scaleY); + ScalePathRect(&ppolyPtr->totalBbox, originX, originY, scaleX, scaleY); + ScaleItemHeader(itemPtr, originX, originY, scaleX, scaleY); +} + +static void +TranslatePpoly(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double deltaX, double deltaY) +{ + PpolyItem *ppolyPtr = (PpolyItem *) itemPtr; + + TranslatePathAtoms(ppolyPtr->atomPtr, deltaX, deltaY); + TranslatePathRect(&ppolyPtr->bbox, deltaX, deltaY); + TranslatePathRect(&ppolyPtr->totalBbox, deltaX, deltaY); + TranslateItemHeader(itemPtr, deltaX, deltaY); +} + +/* + *-------------------------------------------------------------- + * + * CoordsForPolygonline -- + * + * Used as coordProc for polyline and polygon items. + * + * Results: + * Standard tcl result. + * + * Side effects: + * May store new atoms in atomPtrPtr and max number of points + * in lenPtr. + * + *-------------------------------------------------------------- + */ + +int +CoordsForPolygonline( + Tcl_Interp *interp, + Tk_PathCanvas canvas, + int closed, /* Polyline (0) or polygon (1) */ + int objc, + Tcl_Obj *CONST objv[], + PathAtom **atomPtrPtr, + int *lenPtr) +{ + PathAtom *atomPtr = *atomPtrPtr; + + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewListObj(0, (Tcl_Obj **) NULL); + + while (atomPtr != NULL) { + switch (atomPtr->type) { + case PATH_ATOM_M: { + MoveToAtom *move = (MoveToAtom *) atomPtr; + Tcl_ListObjAppendElement(interp, obj, Tcl_NewDoubleObj(move->x)); + Tcl_ListObjAppendElement(interp, obj, Tcl_NewDoubleObj(move->y)); + break; + } + case PATH_ATOM_L: { + LineToAtom *line = (LineToAtom *) atomPtr; + Tcl_ListObjAppendElement(interp, obj, Tcl_NewDoubleObj(line->x)); + Tcl_ListObjAppendElement(interp, obj, Tcl_NewDoubleObj(line->y)); + break; + } + case PATH_ATOM_Z: { + + break; + } + default: { + /* empty */ + } + } + atomPtr = atomPtr->nextPtr; + } + Tcl_SetObjResult(interp, obj); + return TCL_OK; + } + if (objc == 1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } + } + if (objc & 1) { + char buf[64 + TCL_INTEGER_SPACE]; + sprintf(buf, "wrong # coordinates: expected an even number, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } else if (objc < 4) { + char buf[64 + TCL_INTEGER_SPACE]; + sprintf(buf, "wrong # coordinates: expected at least 4, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } else { + int i; + double x, y; + double firstX = 0.0, firstY = 0.0; + PathAtom *firstAtomPtr = NULL; + + /* + * Free any old stuff. + */ + if (atomPtr != NULL) { + TkPathFreeAtoms(atomPtr); + atomPtr = NULL; + } + for (i = 0; i < objc; i += 2) { + if (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[i], &x) != TCL_OK) { + /* @@@ error recovery? */ + return TCL_ERROR; + } + if (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[i+1], &y) != TCL_OK) { + return TCL_ERROR; + } + if (i == 0) { + firstX = x; + firstY = y; + atomPtr = NewMoveToAtom(x, y); + firstAtomPtr = atomPtr; + } else { + atomPtr->nextPtr = NewLineToAtom(x, y); + atomPtr = atomPtr->nextPtr; + } + } + if (closed) { + atomPtr->nextPtr = NewCloseAtom(firstX, firstY); + } + *atomPtrPtr = firstAtomPtr; + *lenPtr = i/2 + 2; + } + return TCL_OK; +} + +/*----------------------------------------------------------------------*/ + diff --git a/pd/tkpath/generic/tkCanvPrect.c b/pd/tkpath/generic/tkCanvPrect.c new file mode 100644 index 0000000000000000000000000000000000000000..514c577fbf6864d16c73f93a9424f4a4b9577fb5 --- /dev/null +++ b/pd/tkpath/generic/tkCanvPrect.c @@ -0,0 +1,480 @@ +/* + * tkCanvPrect.c -- + * + * This file implements a rectangle canvas item modelled after its + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2007-2008 Mats Bengtsson + * + * $Id: tkCanvPrect.c,v 1.28 2010/04/30 10:16:00 ebrunel Exp $ + */ + +#include "tkIntPath.h" +#include "tkpCanvas.h" +#include "tkCanvPathUtil.h" +#include "tkPathStyle.h" + +/* For debugging. */ +extern Tcl_Interp *gInterp; + +/* + * The structure below defines the record for each path item. + */ + +typedef struct PrectItem { + Tk_PathItemEx headerEx; /* Generic stuff that's the same for all + * path types. MUST BE FIRST IN STRUCTURE. */ + double rx; /* Radius of corners. */ + double ry; + PathRect rect; /* Bounding box with zero width outline. + * Untransformed coordinates. */ + PathRect totalBbox; /* Bounding box including stroke. + * Untransformed coordinates. */ + int maxNumSegments; /* Max number of straight segments (for subpath) + * needed for Area and Point functions. */ +} PrectItem; + +/* + * Prototypes for procedures defined in this file: + */ + +static void ComputePrectBbox(Tk_PathCanvas canvas, PrectItem *prectPtr); +static int ConfigurePrect(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int CreatePrect(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeletePrect(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayPrect(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height); +static void PrectBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask); +static int PrectCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int PrectToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double PrectToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int PrectToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScalePrect(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslatePrect(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); +static PathAtom * MakePathAtoms(PrectItem *prectPtr); + + +enum { + PRECT_OPTION_INDEX_RX = (1L << (PATH_STYLE_OPTION_INDEX_END + 0)), + PRECT_OPTION_INDEX_RY = (1L << (PATH_STYLE_OPTION_INDEX_END + 1)), +}; + +PATH_STYLE_CUSTOM_OPTION_RECORDS +PATH_CUSTOM_OPTION_TAGS +PATH_OPTION_STRING_TABLES_FILL +PATH_OPTION_STRING_TABLES_STROKE +PATH_OPTION_STRING_TABLES_STATE + +#define PATH_OPTION_SPEC_RX(typeName) \ + {TK_OPTION_DOUBLE, "-rx", NULL, NULL, \ + "0.0", -1, Tk_Offset(typeName, rx), \ + 0, 0, PRECT_OPTION_INDEX_RX} + +#define PATH_OPTION_SPEC_RY(typeName) \ + {TK_OPTION_DOUBLE, "-ry", NULL, NULL, \ + "0.0", -1, Tk_Offset(typeName, ry), \ + 0, 0, PRECT_OPTION_INDEX_RY} + +static Tk_OptionSpec optionSpecs[] = { + PATH_OPTION_SPEC_CORE(Tk_PathItemEx), + PATH_OPTION_SPEC_PARENT, + PATH_OPTION_SPEC_STYLE_FILL(Tk_PathItemEx, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(Tk_PathItemEx), + PATH_OPTION_SPEC_STYLE_STROKE(Tk_PathItemEx, "black"), + PATH_OPTION_SPEC_RX(PrectItem), + PATH_OPTION_SPEC_RY(PrectItem), + PATH_OPTION_SPEC_END +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * The structures below defines the 'prect' item type by means + * of procedures that can be invoked by generic item code. + */ + +Tk_PathItemType tkPrectType = { + "prect", /* name */ + sizeof(PrectItem), /* itemSize */ + CreatePrect, /* createProc */ + optionSpecs, /* optionSpecs OBSOLTE !!! ??? */ + ConfigurePrect, /* configureProc */ + PrectCoords, /* coordProc */ + DeletePrect, /* deleteProc */ + DisplayPrect, /* displayProc */ + 0, /* flags */ + PrectBbox, /* bboxProc */ + PrectToPoint, /* pointProc */ + PrectToArea, /* areaProc */ + PrectToPostscript, /* postscriptProc */ + ScalePrect, /* scaleProc */ + TranslatePrect, /* translateProc */ + (Tk_PathItemIndexProc *) NULL, /* indexProc */ + (Tk_PathItemCursorProc *) NULL, /* icursorProc */ + (Tk_PathItemSelectionProc *) NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) NULL, /* insertProc */ + (Tk_PathItemDCharsProc *) NULL, /* dTextProc */ + (Tk_PathItemType *) NULL, /* nextPtr */ +}; + + +static int +CreatePrect(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PrectItem *prectPtr = (PrectItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &prectPtr->headerEx; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed to set defaults and to + * allow proper cleanup after errors during the the remainder of + * this procedure. + */ + TkPathInitStyle(&itemExPtr->style); + itemExPtr->canvas = canvas; + itemExPtr->styleObj = NULL; + itemExPtr->styleInst = NULL; + prectPtr->rect = NewEmptyPathRect(); + prectPtr->totalBbox = NewEmptyPathRect(); + prectPtr->maxNumSegments = 100; /* Crude overestimate. */ + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) prectPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + for (i = 1; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + if (CoordsForRectangularItems(interp, canvas, &prectPtr->rect, i, objv) != TCL_OK) { + goto error; + } + if (ConfigurePrect(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { + return TCL_OK; + } + + error: + /* + * NB: We must unlink the item here since the TkPathCanvasItemExConfigure() + * link it to the root by default. + */ + TkPathCanvasItemDetach(itemPtr); + DeletePrect(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +static int +PrectCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PrectItem *prectPtr = (PrectItem *) itemPtr; + int result; + + result = CoordsForRectangularItems(interp, canvas, &prectPtr->rect, objc, objv); + if ((result == TCL_OK) && ((objc == 1) || (objc == 4))) { + ComputePrectBbox(canvas, prectPtr); + } + return result; +} + +void +ComputePrectBbox(Tk_PathCanvas canvas, PrectItem *prectPtr) +{ + Tk_PathItemEx *itemExPtr = &prectPtr->headerEx; + Tk_PathItem *itemPtr = &itemExPtr->header; + Tk_PathStyle style; + Tk_PathState state = itemExPtr->header.state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + itemExPtr->header.x1 = itemExPtr->header.x2 = + itemExPtr->header.y1 = itemExPtr->header.y2 = -1; + return; + } + style = TkPathCanvasInheritStyle(itemPtr, kPathMergeStyleNotFill); + prectPtr->totalBbox = GetGenericPathTotalBboxFromBare(NULL, &style, &prectPtr->rect); + SetGenericPathHeaderBbox(&itemExPtr->header, style.matrixPtr, &prectPtr->totalBbox); + TkPathCanvasFreeInheritedStyle(&style); +} + +static int +ConfigurePrect(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[], int flags) +{ + PrectItem *prectPtr = (PrectItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &prectPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + Tk_Window tkwin; + //Tk_PathState state; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int error, mask; + + tkwin = Tk_PathCanvasTkwin(canvas); + for (error = 0; error <= 1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char *) prectPtr, optionTable, + objc, objv, tkwin, &savedOptions, &mask) != TCL_OK) { + continue; + } + } else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + if (TkPathCanvasItemExConfigure(interp, canvas, itemExPtr, mask) != TCL_OK) { + continue; + } + + /* + * If we reach this on the first pass we are OK and continue below. + */ + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + stylePtr->mask |= mask; + } + stylePtr->strokeOpacity = MAX(0.0, MIN(1.0, stylePtr->strokeOpacity)); + stylePtr->fillOpacity = MAX(0.0, MIN(1.0, stylePtr->fillOpacity)); + prectPtr->rx = MAX(0.0, prectPtr->rx); + prectPtr->ry = MAX(0.0, prectPtr->ry); + +#if 0 // From old code. Needed? + state = itemPtr->state; + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + return TCL_OK; + } +#endif + /* + * Recompute bounding box for path. + */ + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + ComputePrectBbox(canvas, prectPtr); + return TCL_OK; + } +} + +static PathAtom * +MakePathAtoms(PrectItem *prectPtr) +{ + PathAtom *atomPtr; + double points[4]; + + points[0] = prectPtr->rect.x1; + points[1] = prectPtr->rect.y1; + points[2] = prectPtr->rect.x2; + points[3] = prectPtr->rect.y2; + TkPathMakePrectAtoms(points, prectPtr->rx, prectPtr->ry, &atomPtr); + return atomPtr; +} + +static void +DeletePrect(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display) +{ + PrectItem *prectPtr = (PrectItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &prectPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + + if (stylePtr->fill != NULL) { + TkPathFreePathColor(stylePtr->fill); + } + if (itemExPtr->styleInst != NULL) { + TkPathFreeStyle(itemExPtr->styleInst); + } + Tk_FreeConfigOptions((char *) itemPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +static void +DisplayPrect(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height) +{ + PrectItem *prectPtr = (PrectItem *) itemPtr; + TMatrix m = GetCanvasTMatrix(canvas); + PathAtom *atomPtr; + Tk_PathStyle style; + + /* === EB - 23-apr-2010: register coordinate offsets */ + TkPathSetCoordOffsets(m.tx, m.ty); + /* === */ + + style = TkPathCanvasInheritStyle(itemPtr, 0); + atomPtr = MakePathAtoms(prectPtr); + TkPathDrawPath(Tk_PathCanvasTkwin(canvas), drawable, atomPtr, + &style, &m, &prectPtr->rect); + TkPathFreeAtoms(atomPtr); + TkPathCanvasFreeInheritedStyle(&style); +} + +static void +PrectBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask) +{ + PrectItem *prectPtr = (PrectItem *) itemPtr; + ComputePrectBbox(canvas, prectPtr); +} + +static double +PrectToPoint(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *pointPtr) +{ + PrectItem *prectPtr = (PrectItem *) itemPtr; + Tk_PathStyle style; + TMatrix *mPtr; + PathRect *rectPtr = &prectPtr->rect; + double bareRect[4]; + double width, dist; + int rectiLinear = 0; + int filled; + + style = TkPathCanvasInheritStyle(itemPtr, 0); + filled = HaveAnyFillFromPathColor(style.fill); + width = 0.0; + if (style.strokeColor != NULL) { + width = style.strokeWidth; + } + mPtr = style.matrixPtr; + + /* Try to be economical about this for pure rectangles. */ + if ((prectPtr->rx <= 1.0) && (prectPtr->ry <= 1.0)) { + if (mPtr == NULL) { + rectiLinear = 1; + bareRect[0] = rectPtr->x1; + bareRect[1] = rectPtr->y1; + bareRect[2] = rectPtr->x2; + bareRect[3] = rectPtr->y2; + } else if (TMATRIX_IS_RECTILINEAR(mPtr)) { + + /* This is a situation we can treat in a simplified way. Apply the transform here. */ + rectiLinear = 1; + bareRect[0] = mPtr->a * rectPtr->x1 + mPtr->tx; + bareRect[1] = mPtr->d * rectPtr->y1 + mPtr->ty; + bareRect[2] = mPtr->a * rectPtr->x2 + mPtr->tx; + bareRect[3] = mPtr->d * rectPtr->y2 + mPtr->ty; + } + } + if (rectiLinear) { + dist = PathRectToPoint(bareRect, width, filled, pointPtr); + } else { + PathAtom *atomPtr = MakePathAtoms(prectPtr); + dist = GenericPathToPoint(canvas, itemPtr, &style, atomPtr, + prectPtr->maxNumSegments, pointPtr); + TkPathFreeAtoms(atomPtr); + } + TkPathCanvasFreeInheritedStyle(&style); + return dist; +} + +static int +PrectToArea(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *areaPtr) +{ + PrectItem *prectPtr = (PrectItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &prectPtr->headerEx; + Tk_PathStyle style = itemExPtr->style; /* NB: We *copy* the style for temp usage. */ + TMatrix *mPtr; + PathRect *rectPtr = &(prectPtr->rect); + double bareRect[4]; + double width; + int rectiLinear = 0; + int filled, area; + + style = TkPathCanvasInheritStyle(itemPtr, 0); + filled = HaveAnyFillFromPathColor(style.fill); + width = 0.0; + if (style.strokeColor != NULL) { + width = style.strokeWidth; + } + mPtr = style.matrixPtr; + + /* Try to be economical about this for pure rectangles. */ + if ((prectPtr->rx <= 1.0) && (prectPtr->ry <= 1.0)) { + if (mPtr == NULL) { + rectiLinear = 1; + bareRect[0] = rectPtr->x1; + bareRect[1] = rectPtr->y1; + bareRect[2] = rectPtr->x2; + bareRect[3] = rectPtr->y2; + } else if (TMATRIX_IS_RECTILINEAR(mPtr)) { + + /* This is a situation we can treat in a simplified way. Apply the transform here. */ + rectiLinear = 1; + bareRect[0] = mPtr->a * rectPtr->x1 + mPtr->tx; + bareRect[1] = mPtr->d * rectPtr->y1 + mPtr->ty; + bareRect[2] = mPtr->a * rectPtr->x2 + mPtr->tx; + bareRect[3] = mPtr->d * rectPtr->y2 + mPtr->ty; + } + } + if (rectiLinear) { + area = PathRectToArea(bareRect, width, filled, areaPtr); + } else { + PathAtom *atomPtr = MakePathAtoms(prectPtr); + area = GenericPathToArea(canvas, itemPtr, &style, + atomPtr, prectPtr->maxNumSegments, areaPtr); + TkPathFreeAtoms(atomPtr); + } + TkPathCanvasFreeInheritedStyle(&style); + return area; +} + +static int +PrectToPostscript(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass) +{ + return TCL_ERROR; /* @@@ Anyone? */ +} + +static void +ScalePrect(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY) +{ + PrectItem *prectPtr = (PrectItem *) itemPtr; + + ScalePathRect(&prectPtr->rect, originX, originY, scaleX, scaleY); + ScaleItemHeader(itemPtr, originX, originY, scaleX, scaleY); +} + +static void +TranslatePrect(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double deltaX, double deltaY) +{ + PrectItem *prectPtr = (PrectItem *) itemPtr; + + /* Just translate the bbox'es as well. */ + TranslatePathRect(&prectPtr->rect, deltaX, deltaY); + TranslatePathRect(&prectPtr->totalBbox, deltaX, deltaY); + TranslateItemHeader(itemPtr, deltaX, deltaY); +} + +/*----------------------------------------------------------------------*/ + diff --git a/pd/tkpath/generic/tkCanvPtext.c b/pd/tkpath/generic/tkCanvPtext.c new file mode 100644 index 0000000000000000000000000000000000000000..ba79067ec78f5a91d813ccd2c11d4fd907c80445 --- /dev/null +++ b/pd/tkpath/generic/tkCanvPtext.c @@ -0,0 +1,598 @@ +/* + * tkCanvPtext.c -- + * + * This file implements a text canvas item modelled after its + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2007-2008 Mats Bengtsson + * + * $Id: tkCanvPtext.c,v 1.26 2010/04/30 10:16:00 ebrunel Exp $ + */ + +#include "tkIntPath.h" +#include "tkpCanvas.h" +#include "tkCanvPathUtil.h" +#include "tkPathStyle.h" + +/* For debugging. */ +extern Tcl_Interp *gInterp; + +/* + * The structure below defines the record for each path item. + */ + +typedef struct PtextItem { + Tk_PathItemEx headerEx; /* Generic stuff that's the same for all + * path types. MUST BE FIRST IN STRUCTURE. */ + Tk_PathTextStyle textStyle; + int textAnchor; + double x; + double y; + PathRect bbox; /* Bounding box with zero width outline. + * Untransformed coordinates. */ + Tcl_Obj *utf8Obj; /* The actual text to display; UTF-8 */ + int numChars; /* Length of text in characters. */ + int numBytes; /* Length of text in bytes. */ + void *custom; /* Place holder for platform dependent stuff. */ +} PtextItem; + + +/* + * Prototypes for procedures defined in this file: + */ + +static void ComputePtextBbox(Tk_PathCanvas canvas, PtextItem *ptextPtr); +static int ConfigurePtext(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int CreatePtext(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeletePtext(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayPtext(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height); +static void PtextBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask); +static int PtextCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static int ProcessPtextCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, Tcl_Obj *CONST objv[]); +static int PtextToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double PtextToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int PtextToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScalePtext(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslatePtext(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); +#if 0 +static void PtextDeleteChars(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int first, int last); +#endif + +enum { + PRECT_OPTION_INDEX_FONTFAMILY = (1L << (PATH_STYLE_OPTION_INDEX_END + 0)), + PRECT_OPTION_INDEX_FONTSIZE = (1L << (PATH_STYLE_OPTION_INDEX_END + 1)), + PRECT_OPTION_INDEX_TEXT = (1L << (PATH_STYLE_OPTION_INDEX_END + 2)), + PRECT_OPTION_INDEX_TEXTANCHOR = (1L << (PATH_STYLE_OPTION_INDEX_END + 3)), +}; + +PATH_STYLE_CUSTOM_OPTION_RECORDS +PATH_CUSTOM_OPTION_TAGS +PATH_OPTION_STRING_TABLES_FILL +PATH_OPTION_STRING_TABLES_STROKE +PATH_OPTION_STRING_TABLES_STATE + +/* + * Best would be to extract font information from the named font "TkDefaultFont" + * but the option defaults need static strings. Perhaps using NULL + * and extracting family and size dynamically? + */ +#if defined(__WIN32__) || defined(_WIN32) || \ + defined(__CYGWIN__) || defined(__MINGW32__) +# define DEF_PATHCANVTEXT_FONTFAMILY "Tahoma" +# define DEF_PATHCANVTEXT_FONTSIZE "8" +#else +# if defined(MAC_OSX_TK) +# define DEF_PATHCANVTEXT_FONTFAMILY "Lucida Grande" +# define DEF_PATHCANVTEXT_FONTSIZE "13" +# else +# define DEF_PATHCANVTEXT_FONTFAMILY "Helvetica" +# define DEF_PATHCANVTEXT_FONTSIZE "12" +# endif +#endif + +/* + * The enum kPathTextAnchorStart... MUST be kept in sync! + */ +static char *textAnchorST[] = { + "start", "middle", "end", NULL +}; + +#define PATH_OPTION_SPEC_FONTFAMILY \ + {TK_OPTION_STRING, "-fontfamily", NULL, NULL, \ + DEF_PATHCANVTEXT_FONTFAMILY, -1, Tk_Offset(PtextItem, textStyle.fontFamily), \ + 0, 0, PRECT_OPTION_INDEX_FONTFAMILY} + +#define PATH_OPTION_SPEC_FONTSIZE \ + {TK_OPTION_DOUBLE, "-fontsize", NULL, NULL, \ + DEF_PATHCANVTEXT_FONTSIZE, -1, Tk_Offset(PtextItem, textStyle.fontSize), \ + 0, 0, PRECT_OPTION_INDEX_FONTSIZE} + +#define PATH_OPTION_SPEC_TEXT \ + {TK_OPTION_STRING, "-text", NULL, NULL, \ + NULL, Tk_Offset(PtextItem, utf8Obj), -1, \ + TK_OPTION_NULL_OK, 0, PRECT_OPTION_INDEX_TEXT} + +#define PATH_OPTION_SPEC_TEXTANCHOR \ + {TK_OPTION_STRING_TABLE, "-textanchor", NULL, NULL, \ + "start", -1, Tk_Offset(PtextItem, textAnchor), \ + 0, (ClientData) textAnchorST, 0} + +static Tk_OptionSpec optionSpecs[] = { + PATH_OPTION_SPEC_CORE(Tk_PathItemEx), + PATH_OPTION_SPEC_PARENT, + PATH_OPTION_SPEC_STYLE_FILL(Tk_PathItemEx, "black"), + PATH_OPTION_SPEC_STYLE_MATRIX(Tk_PathItemEx), + PATH_OPTION_SPEC_STYLE_STROKE(Tk_PathItemEx, ""), + PATH_OPTION_SPEC_FONTFAMILY, + PATH_OPTION_SPEC_FONTSIZE, + PATH_OPTION_SPEC_TEXT, + PATH_OPTION_SPEC_TEXTANCHOR, + PATH_OPTION_SPEC_END +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * The structures below defines the 'prect' item type by means + * of procedures that can be invoked by generic item code. + */ + +Tk_PathItemType tkPtextType = { + "ptext", /* name */ + sizeof(PtextItem), /* itemSize */ + CreatePtext, /* createProc */ + optionSpecs, /* configSpecs */ + ConfigurePtext, /* configureProc */ + PtextCoords, /* coordProc */ + DeletePtext, /* deleteProc */ + DisplayPtext, /* displayProc */ + 0, /* flags */ + PtextBbox, /* bboxProc */ + PtextToPoint, /* pointProc */ + PtextToArea, /* areaProc */ + PtextToPostscript, /* postscriptProc */ + ScalePtext, /* scaleProc */ + TranslatePtext, /* translateProc */ + (Tk_PathItemIndexProc *) NULL, /* indexProc */ + (Tk_PathItemCursorProc *) NULL, /* icursorProc */ + (Tk_PathItemSelectionProc *) NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) NULL, /* insertProc */ + (Tk_PathItemDCharsProc *) NULL, /* dTextProc */ + (Tk_PathItemType *) NULL, /* nextPtr */ +}; + + +static int +CreatePtext(Tcl_Interp *interp, Tk_PathCanvas canvas, + struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &ptextPtr->headerEx; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed to set defaults and to + * allow proper cleanup after errors during the the remainder of + * this procedure. + */ + TkPathInitStyle(&itemExPtr->style); + itemExPtr->canvas = canvas; + itemExPtr->styleObj = NULL; + itemExPtr->styleInst = NULL; + ptextPtr->bbox = NewEmptyPathRect(); + ptextPtr->utf8Obj = NULL; + ptextPtr->numChars = 0; + ptextPtr->numBytes = 0; + ptextPtr->textAnchor = kPathTextAnchorStart; + ptextPtr->textStyle.fontFamily = NULL; + ptextPtr->textStyle.fontSize = 0.0; + ptextPtr->custom = NULL; + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) ptextPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + for (i = 1; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + if (ProcessPtextCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { + goto error; + } + if (ConfigurePtext(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { + return TCL_OK; + } + +error: + /* + * NB: We must unlink the item here since the TkPathCanvasItemExConfigure() + * link it to the root by default. + */ + TkPathCanvasItemDetach(itemPtr); + DeletePtext(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +static int +ProcessPtextCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(ptextPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(ptextPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (objc < 3) { + if (objc == 1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 2) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("wrong # coordinates: expected 0 or 2", -1)); + return TCL_ERROR; + } + } + if ((Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[0], &ptextPtr->x) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[1], &ptextPtr->y) != TCL_OK)) { + return TCL_ERROR; + } + } else { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("wrong # coordinates: expected 0 or 2", -1)); + return TCL_ERROR; + } + return TCL_OK; +} + + +static int +PtextCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + int result; + + result = ProcessPtextCoords(interp, canvas, itemPtr, objc, objv); + if ((result == TCL_OK) && (objc > 0) && (objc < 3)) { + ComputePtextBbox(canvas, ptextPtr); + } + return result; +} + +void +ComputePtextBbox(Tk_PathCanvas canvas, PtextItem *ptextPtr) +{ + Tk_PathItemEx *itemExPtr = &ptextPtr->headerEx; + Tk_PathItem *itemPtr = &itemExPtr->header; + Tk_PathStyle style; + Tk_PathState state = itemExPtr->header.state; + double width; + PathRect bbox, r; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (ptextPtr->utf8Obj == NULL || (state == TK_PATHSTATE_HIDDEN)) { + itemExPtr->header.x1 = itemExPtr->header.x2 = + itemExPtr->header.y1 = itemExPtr->header.y2 = -1; + return; + } + style = TkPathCanvasInheritStyle(itemPtr, kPathMergeStyleNotFill); + r = TkPathTextMeasureBbox(&ptextPtr->textStyle, + Tcl_GetString(ptextPtr->utf8Obj), ptextPtr->custom); + width = r.x2 - r.x1; + switch (ptextPtr->textAnchor) { + case kPathTextAnchorStart: + bbox.x1 = ptextPtr->x; + bbox.x2 = bbox.x1 + width; + break; + case kPathTextAnchorMiddle: + bbox.x1 = ptextPtr->x - width/2; + bbox.x2 = ptextPtr->x + width/2; + break; + case kPathTextAnchorEnd: + bbox.x1 = ptextPtr->x - width; + bbox.x2 = ptextPtr->x; + break; + } + bbox.y1 = ptextPtr->y + r.y1; // r.y1 is negative! + bbox.y2 = ptextPtr->y + r.y2; + + /* Fudge for antialiasing etc. */ + bbox.x1 -= 1.0; + bbox.y1 -= 1.0; + bbox.x2 += 1.0; + bbox.y2 += 1.0; + if (style.strokeColor) { + double halfWidth = style.strokeWidth/2; + bbox.x1 -= halfWidth; + bbox.y1 -= halfWidth; + bbox.x2 += halfWidth; + bbox.x2 += halfWidth; + } + ptextPtr->bbox = bbox; + SetGenericPathHeaderBbox(&itemExPtr->header, style.matrixPtr, &bbox); + TkPathCanvasFreeInheritedStyle(&style); +} + +static int +ConfigurePtext(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[], int flags) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &ptextPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + Tk_Window tkwin; + //Tk_PathState state; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int error, mask; + + tkwin = Tk_PathCanvasTkwin(canvas); + for (error = 0; error <= 1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char *) ptextPtr, optionTable, + objc, objv, tkwin, &savedOptions, &mask) != TCL_OK) { + continue; + } + } else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + /* + * Since we have -fill default equal to black we need to force + * setting the fill member of the style. + */ + if (TkPathCanvasItemExConfigure(interp, canvas, itemExPtr, mask | PATH_STYLE_OPTION_FILL) != TCL_OK) { + continue; + } + // @@@ TkPathTextConfig needs to be reworked! + if (ptextPtr->utf8Obj != NULL) { + if (TkPathTextConfig(interp, &(ptextPtr->textStyle), + Tcl_GetString(ptextPtr->utf8Obj), &ptextPtr->custom) != TCL_OK) { + continue; + } + } + + /* + * If we reach this on the first pass we are OK and continue below. + */ + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + stylePtr->mask |= mask; + } + + stylePtr->strokeOpacity = MAX(0.0, MIN(1.0, stylePtr->strokeOpacity)); + if (ptextPtr->utf8Obj != NULL) { + ptextPtr->numBytes = Tcl_GetCharLength(ptextPtr->utf8Obj); + ptextPtr->numChars = Tcl_NumUtfChars(Tcl_GetString(ptextPtr->utf8Obj), + ptextPtr->numBytes); + } else { + ptextPtr->numBytes = 0; + ptextPtr->numChars = 0; + } +#if 0 // From old code. Needed? + state = itemPtr->state; + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + return TCL_OK; + } +#endif + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + ComputePtextBbox(canvas, ptextPtr); + return TCL_OK; + } +} + +static void +DeletePtext(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &ptextPtr->headerEx; + Tk_PathStyle *stylePtr = &itemExPtr->style; + + if (stylePtr->fill != NULL) { + TkPathFreePathColor(stylePtr->fill); + } + if (itemExPtr->styleInst != NULL) { + TkPathFreeStyle(itemExPtr->styleInst); + } + TkPathTextFree(&(ptextPtr->textStyle), ptextPtr->custom); + Tk_FreeConfigOptions((char *) ptextPtr, optionTable, + Tk_PathCanvasTkwin(canvas)); +} + +static void +DisplayPtext(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, Display *display, Drawable drawable, + int x, int y, int width, int height) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + Tk_PathItemEx *itemExPtr = &ptextPtr->headerEx; + Tk_PathStyle style; + TMatrix m = GetCanvasTMatrix(canvas); + TkPathContext ctx; + + /* === EB - 23-apr-2010: register coordinate offsets */ + TkPathSetCoordOffsets(m.tx, m.ty); + /* === */ + + if (ptextPtr->utf8Obj == NULL) { + return; + } + + /* + * The defaults for -fill and -stroke differ for the ptext item. + */ + style = TkPathCanvasInheritStyle(itemPtr, 0); + if (!(style.mask & PATH_STYLE_OPTION_FILL)) { + style.fill = itemExPtr->style.fill; + } + if (!(style.mask & PATH_STYLE_OPTION_STROKE)) { + style.strokeColor = itemExPtr->style.strokeColor; + } + + ctx = TkPathInit(Tk_PathCanvasTkwin(canvas), drawable); + + TkPathPushTMatrix(ctx, &m); + if (style.matrixPtr != NULL) { + TkPathPushTMatrix(ctx, style.matrixPtr); + } + TkPathBeginPath(ctx, &style); + /* @@@ We need to handle gradients as well here! + Wait to see what the other APIs have to say. + */ + TkPathTextDraw(ctx, &style, &ptextPtr->textStyle, ptextPtr->bbox.x1, ptextPtr->y, + Tcl_GetString(ptextPtr->utf8Obj), ptextPtr->custom); + TkPathEndPath(ctx); + TkPathFree(ctx); + TkPathCanvasFreeInheritedStyle(&style); +} + +static void +PtextBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + ComputePtextBbox(canvas, ptextPtr); +} + +static double +PtextToPoint(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *pointPtr) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + Tk_PathStyle style; + double dist; + + style = TkPathCanvasInheritStyle(itemPtr, + kPathMergeStyleNotFill | kPathMergeStyleNotStroke); + dist = PathRectToPointWithMatrix(ptextPtr->bbox, style.matrixPtr, pointPtr); + TkPathCanvasFreeInheritedStyle(&style); + return dist; +} + +static int +PtextToArea(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double *areaPtr) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + Tk_PathStyle style; + int area; + + style = TkPathCanvasInheritStyle(itemPtr, + kPathMergeStyleNotFill | kPathMergeStyleNotStroke); + area = PathRectToAreaWithMatrix(ptextPtr->bbox, style.matrixPtr, areaPtr); + TkPathCanvasFreeInheritedStyle(&style); + return area; +} + +static int +PtextToPostscript(Tcl_Interp *interp, Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass) +{ + return TCL_ERROR; +} + +static void +ScalePtext(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + + ptextPtr->x = originX + scaleX*(ptextPtr->x - originX); + ptextPtr->y = originY + scaleY*(ptextPtr->y - originY); + ScalePathRect(&ptextPtr->bbox, originX, originY, scaleX, scaleY); + ScaleItemHeader(itemPtr, originX, originY, scaleX, scaleY); +} + +static void +TranslatePtext(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, double deltaX, double deltaY) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + + ptextPtr->x += deltaX; + ptextPtr->y += deltaY; + TranslatePathRect(&ptextPtr->bbox, deltaX, deltaY); + TranslateItemHeader(itemPtr, deltaX, deltaY); +} + +#if 0 // TODO +static void +PtextDeleteChars(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int first, int last) +{ + PtextItem *ptextPtr = (PtextItem *) itemPtr; + int byteIndex, byteCount, charsRemoved; + char *new, *text; + + text = ptextPtr->utf8; + if (first < 0) { + first = 0; + } + if (last >= ptextPtr->numChars) { + last = ptextPtr->numChars - 1; + } + if (first > last) { + return; + } + charsRemoved = last + 1 - first; + + byteIndex = Tcl_UtfAtIndex(text, first) - text; + byteCount = Tcl_UtfAtIndex(text + byteIndex, charsRemoved) - (text + byteIndex); + + new = (char *) ckalloc((unsigned) (ptextPtr->numBytes + 1 - byteCount)); + memcpy(new, text, (size_t) byteIndex); + strcpy(new + byteIndex, text + byteIndex + byteCount); + + ckfree(text); + ptextPtr->utf8 = new; + ptextPtr->numChars -= charsRemoved; + ptextPtr->numBytes -= byteCount; + + //TkPathTextConfig(interp, &(ptextPtr->textStyle), ptextPtr->utf8, &(ptextPtr->custom)); + ComputePtextBbox(canvas, ptextPtr); + return; +} +#endif + +/*----------------------------------------------------------------------*/ + diff --git a/pd/tkpath/generic/tkCanvStyle.c b/pd/tkpath/generic/tkCanvStyle.c new file mode 100644 index 0000000000000000000000000000000000000000..824ff7dda0db126721d38b615739120dd1c0c2cc --- /dev/null +++ b/pd/tkpath/generic/tkCanvStyle.c @@ -0,0 +1,128 @@ +/* + * tkCanvStyle.c -- + * + * This file implements some glue between style objects and the canvas widget. + * + * Copyright (c) 2008 Mats Bengtsson + * + * $Id: tkCanvStyle.c,v 1.2 2008/06/05 12:51:58 matben Exp $ + */ + +#include "tkIntPath.h" +#include "tkpCanvas.h" + +static char * kStyleNameBase = "style"; + +static CONST char *styleCmds[] = { + "cget", "configure", "create", "delete", "inuse", "names", + (char *) NULL +}; + +enum { + kPathStyleCmdCget = 0L, + kPathStyleCmdConfigure, + kPathStyleCmdCreate, + kPathStyleCmdDelete, + kPathStyleCmdInUse, + kPathStyleCmdNames +}; + +/* + *---------------------------------------------------------------------- + * + * CanvasStyleObjCmd -- + * + * Implements the 'pathName style' command using the canvas local state. + * + * Results: + * Standard Tcl result + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +int +CanvasStyleObjCmd(Tcl_Interp* interp, TkPathCanvas *canvasPtr, + int objc, Tcl_Obj* CONST objv[]) +{ + int index; + int result = TCL_OK; + + /* + * objv[2] is the subcommand: cget | configure | create | delete | names + */ + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], styleCmds, "command", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + switch (index) { + + case kPathStyleCmdCget: { + if (objc != 5) { + Tcl_WrongNumArgs(interp, 3, objv, "name option"); + return TCL_ERROR; + } + result = PathStyleCget(interp, canvasPtr->tkwin, objc-3, objv+3, + &canvasPtr->styleTable); + break; + } + + case kPathStyleCmdConfigure: { + if (objc < 4) { + Tcl_WrongNumArgs(interp, 3, objv, "name ?option? ?value option value...?"); + return TCL_ERROR; + } + result = PathStyleConfigure(interp, canvasPtr->tkwin, objc-3, objv+3, + &canvasPtr->styleTable, &canvasPtr->gradientTable); + break; + } + + case kPathStyleCmdCreate: { + char str[255]; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?option value...?"); + return TCL_ERROR; + } + sprintf(str, "%s%d", kStyleNameBase, canvasPtr->styleUid++); + result = PathStyleCreate(interp, canvasPtr->tkwin, objc-3, objv+3, + &canvasPtr->styleTable, &canvasPtr->gradientTable, str); + break; + } + + case kPathStyleCmdDelete: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "name"); + return TCL_ERROR; + } + result = PathStyleDelete(interp, objv[3], &canvasPtr->styleTable, + canvasPtr->tkwin); + break; + } + + case kPathStyleCmdInUse: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "name"); + return TCL_ERROR; + } + result = PathStyleInUse(interp, objv[3], &canvasPtr->styleTable); + break; + } + + case kPathStyleCmdNames: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + return TCL_ERROR; + } + PathStyleNames(interp, &canvasPtr->styleTable); + break; + } + } + return result; +} diff --git a/pd/tkpath/generic/tkIntPath.h b/pd/tkpath/generic/tkIntPath.h new file mode 100644 index 0000000000000000000000000000000000000000..790942b3e6e7b6fdcde439b81f73b3021b3fde29 --- /dev/null +++ b/pd/tkpath/generic/tkIntPath.h @@ -0,0 +1,489 @@ +/* + * tkIntPath.h -- + * + * Header file for the internals of the tkpath package. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * $Id: tkIntPath.h,v 1.52 2010/04/30 10:16:00 ebrunel Exp $ + */ + +#ifndef INCLUDED_TKINTPATH_H +#define INCLUDED_TKINTPATH_H + +#include "tkPath.h" + +/* + * For C++ compilers, use extern "C" + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * From tclInt.h version 1.118.2.11 + * Ensure WORDS_BIGENDIAN is defined correcly: + * Needs to happen here in addition to configure to work with + * fat compiles on Darwin (i.e. ppc and i386 at the same time). + */ + +#ifndef WORDS_BIGENDIAN +# ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +# endif +# ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +# endif +# ifdef BYTE_ORDER +# ifdef BIG_ENDIAN +# if BYTE_ORDER == BIG_ENDIAN +# define WORDS_BIGENDIAN +# endif +# endif +# ifdef LITTLE_ENDIAN +# if BYTE_ORDER == LITTLE_ENDIAN +# undef WORDS_BIGENDIAN +# endif +# endif +# endif +#endif + + +#ifndef MIN +# define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +# define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef ABS +# define ABS(a) (((a) >= 0) ? (a) : -1*(a)) +#endif +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif +#define DEGREES_TO_RADIANS (M_PI/180.0) +#define RADIANS_TO_DEGREES (180.0/M_PI) + + +/* + * This can be useful to estimate the segmentation detail necessary. + * A conservative measure. + */ +#define TMATRIX_ABS_MAX(mPtr) MAX(fabs(mPtr->a), MAX(fabs(mPtr->b), MAX(fabs(mPtr->c), fabs(mPtr->d)))) + +/* + * This can be used for simplifying Area and Point functions. + */ +#define TMATRIX_IS_RECTILINEAR(mPtr) (fabs(mPtr->b) == 0.0) && (fabs(mPtr->c) == 0.0) + +#define TMATRIX_DETERMINANT(mPtr) (mPtr->a * mPtr->d - mPtr->c * mPtr->d) + +/* + * Iff stroke width is an integer, widthCode=1,2, move coordinate + * to pixel boundary if even stroke width, widthCode=2, + * or to pixel center if odd stroke width, widthCode=1. + */ +#define PATH_DEPIXELIZE(widthCode,x) (!(widthCode) ? (x) : ((int) (floor((x) + 0.001)) + (((widthCode) == 1) ? 0.5 : 0))); + +#define GetColorFromPathColor(pcol) (((pcol != NULL) && (pcol->color != NULL)) ? pcol->color : NULL ) +#define GetGradientMasterFromPathColor(pcol) (((pcol != NULL) && (pcol->gradientInstPtr != NULL)) ? pcol->gradientInstPtr->masterPtr : NULL ) +#define HaveAnyFillFromPathColor(pcol) (((pcol != NULL) && ((pcol->color != NULL) || (pcol->gradientInstPtr != NULL))) ? 1 : 0 ) + +/* + * So far we use a fixed number of straight line segments when + * doing various things, but it would be better to use the de Castlejau + * algorithm to iterate these segments. + */ +#define kPathNumSegmentsCurveTo 18 +#define kPathNumSegmentsQuadBezier 12 +#define kPathNumSegmentsMax 18 +#define kPathNumSegmentsEllipse 48 + +#define kPathUnitTMatrix {1.0, 0.0, 0.0, 1.0, 0.0, 0.0} + +/* + * Flag bits for gradient and style changes. + */ +enum { + PATH_GRADIENT_FLAG_CONFIGURE = (1L << 0), + PATH_GRADIENT_FLAG_DELETE +}; + +enum { + PATH_STYLE_FLAG_CONFIGURE = (1L << 0), + PATH_STYLE_FLAG_DELETE +}; + +extern int gAntiAlias; + +enum { + kPathTextAnchorStart = 0L, + kPathTextAnchorMiddle, + kPathTextAnchorEnd +}; + +/* These MUST be kept in sync with methodST and unitsST! */ +enum { + kPathGradientMethodPad = 0L, + kPathGradientMethodRepeat, + kPathGradientMethodReflect +}; +enum { + kPathGradientUnitsBoundingBox = 0L, + kPathGradientUnitsUserSpace +}; + +enum { + kPathArcOK, + kPathArcLine, + kPathArcSkip +}; + +typedef struct PathBox { + double x; + double y; + double width; + double height; +} PathBox; + +typedef struct CentralArcPars { + double cx; + double cy; + double rx; + double ry; + double theta1; + double dtheta; + double phi; +} CentralArcPars; + +typedef struct LookupTable { + int from; + int to; +} LookupTable; + +/* + * Records used for parsing path to a linked list of primitive + * drawing instructions. + * + * PathAtom: vaguely modelled after Tk_PathItem. Each atom has a PathAtom record + * in its first position, padded with type specific data. + */ + +typedef struct MoveToAtom { + PathAtom pathAtom; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + double x; + double y; +} MoveToAtom; + +typedef struct LineToAtom { + PathAtom pathAtom; + double x; + double y; +} LineToAtom; + +typedef struct ArcAtom { + PathAtom pathAtom; + double radX; + double radY; + double angle; /* In degrees! */ + char largeArcFlag; + char sweepFlag; + double x; + double y; +} ArcAtom; + +typedef struct QuadBezierAtom { + PathAtom pathAtom; + double ctrlX; + double ctrlY; + double anchorX; + double anchorY; +} QuadBezierAtom; + +typedef struct CurveToAtom { + PathAtom pathAtom; + double ctrlX1; + double ctrlY1; + double ctrlX2; + double ctrlY2; + double anchorX; + double anchorY; +} CurveToAtom; + +typedef struct CloseAtom { + PathAtom pathAtom; + double x; + double y; +} CloseAtom; + +typedef struct EllipseAtom { + PathAtom pathAtom; + double cx; + double cy; + double rx; + double ry; +} EllipseAtom; + +typedef struct RectAtom { + PathAtom pathAtom; + double x; + double y; + double width; + double height; +} RectAtom; + +/* + * Flags for 'TkPathStyleMergeStyles'. + */ + +enum { + kPathMergeStyleNotFill = 0L, + kPathMergeStyleNotStroke +}; + +/* + * The actual path drawing commands which are all platform specific. + */ + +/* === EB - 23-apr-2010: added function to register coordinate offsets */ +/* Should be called before TkPathInit for correct sizing of drawing region*/ +void TkPathSetCoordOffsets(double dx, double dy); +/* === */ +TkPathContext TkPathInit(Tk_Window tkwin, Drawable d); +TkPathContext TkPathInitSurface(int width, int height); +void TkPathBeginPath(TkPathContext ctx, Tk_PathStyle *stylePtr); +void TkPathEndPath(TkPathContext ctx); +void TkPathMoveTo(TkPathContext ctx, double x, double y); +void TkPathLineTo(TkPathContext ctx, double x, double y); +void TkPathArcTo(TkPathContext ctx, double rx, double ry, double angle, + char largeArcFlag, char sweepFlag, double x, double y); +void TkPathQuadBezier(TkPathContext ctx, double ctrlX, double ctrlY, double x, double y); +void TkPathCurveTo(TkPathContext ctx, double ctrlX1, double ctrlY1, + double ctrlX2, double ctrlY2, double x, double y); +void TkPathArcToUsingBezier(TkPathContext ctx, double rx, double ry, + double phiDegrees, char largeArcFlag, char sweepFlag, + double x2, double y2); +void TkPathRect(TkPathContext ctx, double x, double y, double width, double height); +void TkPathOval(TkPathContext ctx, double cx, double cy, double rx, double ry); +void TkPathClosePath(TkPathContext ctx); +void TkPathImage(TkPathContext ctx, Tk_Image image, Tk_PhotoHandle photo, + double x, double y, double width, double height); +int TkPathTextConfig(Tcl_Interp *interp, Tk_PathTextStyle *textStylePtr, char *utf8, void **customPtr); +void TkPathTextDraw(TkPathContext ctx, Tk_PathStyle *style, + Tk_PathTextStyle *textStylePtr, double x, double y, char *utf8, void *custom); +void TkPathTextFree(Tk_PathTextStyle *textStylePtr, void *custom); +PathRect TkPathTextMeasureBbox(Tk_PathTextStyle *textStylePtr, char *utf8, void *custom); +void TkPathSurfaceErase(TkPathContext ctx, double x, double y, double width, double height); +void TkPathSurfaceToPhoto(Tcl_Interp *interp, TkPathContext ctx, Tk_PhotoHandle photo); + +/* + * General path drawing using linked list of path atoms. + */ +void TkPathDrawPath(Tk_Window tkwin, Drawable drawable, + PathAtom *atomPtr, Tk_PathStyle *stylePtr, TMatrix *mPtr, + PathRect *bboxPtr); +void TkPathPaintPath(TkPathContext context, PathAtom *atomPtr, + Tk_PathStyle *stylePtr, PathRect *bboxPtr); +PathRect TkPathGetTotalBbox(PathAtom *atomPtr, Tk_PathStyle *stylePtr); + +void TkPathMakePrectAtoms(double *pointsPtr, double rx, double ry, PathAtom **atomPtrPtr); +TkPathColor * TkPathNewPathColor(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *nameObj); +void TkPathFreePathColor(TkPathColor *colorPtr); +TkPathColor * TkPathGetPathColor(Tcl_Interp *interp, Tk_Window tkwin, + Tcl_Obj *nameObj, Tcl_HashTable *tablePtr, + TkPathGradientChangedProc *changeProc, ClientData clientData); + +/* + * From the generic tk code normally in tkIntDecls.h + */ + +void TkPathIncludePoint(register Tk_PathItem *itemPtr, double *pointPtr); +void TkPathBezierScreenPoints(Tk_PathCanvas canvas, double control[], + int numSteps, register XPoint *xPointPtr); +void TkPathBezierPoints(double control[], int numSteps, + register double *coordPtr); +int TkPathMakeBezierCurve(Tk_PathCanvas canvas, double *pointPtr, + int numPoints, int numSteps, XPoint xPoints[], double dblPoints[]); +int TkPathMakeRawCurve(Tk_PathCanvas canvas, double *pointPtr, + int numPoints, int numSteps, XPoint xPoints[], double dblPoints[]); +void TkPathMakeBezierPostscript(Tcl_Interp *interp, Tk_PathCanvas canvas, + double *pointPtr, int numPoints); +void TkPathMakeRawCurvePostscript(Tcl_Interp *interp, Tk_PathCanvas canvas, + double *pointPtr, int numPoints); +void TkPathFillPolygon(Tk_PathCanvas canvas, double *coordPtr, int numPoints, + Display *display, Drawable drawable, GC gc, GC outlineGC); + +/* + * Various stuff. + */ + +int TableLookup(LookupTable *map, int n, int from); +void PathParseDashToArray(Tk_Dash *dash, double width, int *len, float **arrayPtrPtr); +void PathApplyTMatrix(TMatrix *m, double *x, double *y); +void PathApplyTMatrixToPoint(TMatrix *m, double in[2], double out[2]); +void PathInverseTMatrix(TMatrix *m, TMatrix *mi); +void MMulTMatrix(TMatrix *m1, TMatrix *m2); +void PathCopyBitsARGB(unsigned char *from, unsigned char *to, + int width, int height, int bytesPerRow); +void PathCopyBitsBGRA(unsigned char *from, unsigned char *to, + int width, int height, int bytesPerRow); +void PathCopyBitsPremultipliedAlphaRGBA(unsigned char *from, unsigned char *to, + int width, int height, int bytesPerRow); +void PathCopyBitsPremultipliedAlphaARGB(unsigned char *from, unsigned char *to, + int width, int height, int bytesPerRow); +void PathCopyBitsPremultipliedAlphaBGRA(unsigned char *from, unsigned char *to, + int width, int height, int bytesPerRow); + +int ObjectIsEmpty(Tcl_Obj *objPtr); +int PathGetTMatrix(Tcl_Interp* interp, CONST char *list, TMatrix *matrixPtr); +int PathGetTclObjFromTMatrix(Tcl_Interp* interp, TMatrix *matrixPtr, + Tcl_Obj **listObjPtrPtr); + +int EndpointToCentralArcParameters( + double x1, double y1, double x2, double y2, /* The endpoints. */ + double rx, double ry, /* Radius. */ + double phi, char largeArcFlag, char sweepFlag, + double *cxPtr, double *cyPtr, /* Out. */ + double *rxPtr, double *ryPtr, + double *theta1Ptr, double *dthetaPtr); + +MODULE_SCOPE int TkPathGenericCmdDispatcher( + Tcl_Interp* interp, + Tk_Window tkwin, + int objc, + Tcl_Obj* CONST objv[], + char *baseName, + int *baseNameUIDPtr, + Tcl_HashTable *hashTablePtr, + Tk_OptionTable optionTable, + char *(*createAndConfigProc)(Tcl_Interp *interp, char *name, int objc, Tcl_Obj *CONST objv[]), + void (*configNotifyProc)(char *recordPtr, int mask, int objc, Tcl_Obj *CONST objv[]), + void (*freeProc)(Tcl_Interp *interp, char *recordPtr)); +void PathStyleInit(Tcl_Interp* interp); +void PathGradientInit(Tcl_Interp* interp); +MODULE_SCOPE void TkPathStyleMergeStyles(Tk_PathStyle *srcStyle, Tk_PathStyle *dstStyle, + long flags); +MODULE_SCOPE int TkPathStyleMergeStyleStatic(Tcl_Interp* interp, Tcl_Obj *styleObj, + Tk_PathStyle *dstStyle, long flags); +MODULE_SCOPE void PathGradientPaint(TkPathContext ctx, PathRect *bbox, + TkPathGradientMaster *gradientStylePtr, int fillRule); + + +MODULE_SCOPE Tk_PathSmoothMethod tkPathBezierSmoothMethod; + +MODULE_SCOPE int Tk_PathCanvasObjCmd(ClientData clientData, + Tcl_Interp *interp, int argc, Tcl_Obj *const objv[]); + +/* + * Gradient support functions. + */ + +MODULE_SCOPE int PathGradientCget(Tcl_Interp *interp, Tk_Window tkwin, + int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *hashTablePtr); +MODULE_SCOPE int PathGradientConfigure(Tcl_Interp *interp, Tk_Window tkwin, + int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *hashTablePtr); +MODULE_SCOPE int PathGradientCreate(Tcl_Interp *interp, Tk_Window tkwin, + int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *hashTablePtr, char *tokenName); +MODULE_SCOPE int PathGradientDelete(Tcl_Interp *interp, Tcl_Obj *obj, + Tcl_HashTable *hashTablePtr); +MODULE_SCOPE int PathGradientInUse(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_HashTable *tablePtr); +MODULE_SCOPE void PathGradientNames(Tcl_Interp *interp, Tcl_HashTable *hashTablePtr); +MODULE_SCOPE int PathGradientType(Tcl_Interp *interp, Tcl_Obj *obj, + Tcl_HashTable *hashTablePtr); +MODULE_SCOPE void PathGradientMasterFree(TkPathGradientMaster *gradientPtr); + +/* + * Style support functions. + */ + +MODULE_SCOPE int PathStyleCget(Tcl_Interp *interp, Tk_Window tkwin, + int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *hashTablePtr); +MODULE_SCOPE int PathStyleConfigure(Tcl_Interp *interp, Tk_Window tkwin, + int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *hashTablePtr, Tcl_HashTable *gradTablePtr); +MODULE_SCOPE int PathStyleCreate(Tcl_Interp *interp, Tk_Window tkwin, + int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *styleTablePtr, + Tcl_HashTable *gradTablePtr, char *tokenName); +MODULE_SCOPE int PathStyleDelete(Tcl_Interp *interp, Tcl_Obj *obj, + Tcl_HashTable *hashTablePtr, Tk_Window tkwin); +MODULE_SCOPE int PathStyleInUse(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_HashTable *tablePtr); +MODULE_SCOPE void PathStyleNames(Tcl_Interp *interp, Tcl_HashTable *hashTablePtr); + +/* + * As TK_OPTION_PIXELS but double internal value instead of int. + */ + +MODULE_SCOPE int Tk_PathPixelOptionSetProc(ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, + char *recordPtr, int internalOffset, char *oldInternalPtr, int flags); +MODULE_SCOPE Tcl_Obj * Tk_PathPixelOptionGetProc(ClientData clientData, + Tk_Window tkwin, char *recordPtr, int internalOffset); +MODULE_SCOPE void Tk_PathPixelOptionRestoreProc(ClientData clientData, + Tk_Window tkwin, char *internalPtr, char *oldInternalPtr); + +MODULE_SCOPE int Tk_DashOptionSetProc(ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, + char *recordPtr, int internalOffset, char *oldInternalPtr, + int flags); +MODULE_SCOPE Tcl_Obj * Tk_DashOptionGetProc(ClientData clientData, + Tk_Window tkwin, char *recordPtr, int internalOffset); +MODULE_SCOPE void Tk_DashOptionRestoreProc(ClientData clientData, + Tk_Window tkwin, char *internalPtr, char *oldInternalPtr); +MODULE_SCOPE void Tk_DashOptionFreeProc(ClientData clientData, + Tk_Window tkwin, char *internalPtr); + +MODULE_SCOPE int TkPathOffsetOptionSetProc(ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, + char *recordPtr, int internalOffset, char *oldInternalPtr, + int flags); +MODULE_SCOPE Tcl_Obj * TkPathOffsetOptionGetProc(ClientData clientData, + Tk_Window tkwin, char *recordPtr, int internalOffset); +MODULE_SCOPE void TkPathOffsetOptionRestoreProc(ClientData clientData, + Tk_Window tkwin, char *internalPtr, char *oldInternalPtr); +MODULE_SCOPE void TkPathOffsetOptionFreeProc(ClientData clientData, + Tk_Window tkwin, char *internalPtr); + +MODULE_SCOPE int TkPathSmoothOptionSetProc(ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, + char *recordPtr, int internalOffset, char *oldInternalPtr, + int flags); +MODULE_SCOPE Tcl_Obj * TkPathSmoothOptionGetProc(ClientData clientData, + Tk_Window tkwin, char *recordPtr, int internalOffset); +MODULE_SCOPE void TkPathSmoothOptionRestoreProc(ClientData clientData, + Tk_Window tkwin, char *internalPtr, char *oldInternalPtr); + +MODULE_SCOPE int TkPathPostscriptImage(Tcl_Interp *interp, Tk_Window tkwin, + Tk_PostscriptInfo psInfo, XImage *ximage, + int x, int y, int width, int height); +MODULE_SCOPE void PathStylesFree(Tk_Window tkwin, Tcl_HashTable *hashTablePtr); +MODULE_SCOPE TkPathColor * TkPathGetPathColorStatic(Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj *nameObj); + +/* + * Support functions for gradient instances. + */ +MODULE_SCOPE TkPathGradientInst *TkPathGetGradient(Tcl_Interp *interp, CONST char *name, + Tcl_HashTable *tablePtr, TkPathGradientChangedProc *changeProc, + ClientData clientData); +MODULE_SCOPE void TkPathFreeGradient(TkPathGradientInst *gradientPtr); +MODULE_SCOPE void TkPathGradientChanged(TkPathGradientMaster *masterPtr, int flags); + +MODULE_SCOPE void TkPathStyleChanged(Tk_PathStyle *masterPtr, int flags); + +/* + * end block for C++ + */ + +#ifdef __cplusplus +} +#endif + +#endif // INCLUDED_TKINTPATH_H + diff --git a/pd/tkpath/generic/tkPath.c b/pd/tkpath/generic/tkPath.c new file mode 100644 index 0000000000000000000000000000000000000000..f84853162234ffe1887a8e496a3b6ead6305bf6c --- /dev/null +++ b/pd/tkpath/generic/tkPath.c @@ -0,0 +1,1010 @@ +/* + * tkPath.c -- + * + * This file implements a path drawing model + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * It contains the generic parts that do not refer to the canvas. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * $Id: tkPath.c,v 1.18 2012/07/04 19:43:18 petasis Exp $ + */ + +#include "tkIntPath.h" + +/* For debugging. */ +extern Tcl_Interp *gInterp; + +static const char kPathSyntaxError[] = "syntax error in path definition"; + + +int +PixelAlignObjCmd(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* CONST objv[]) +{ + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(TkPathPixelAlign())); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * GetPathInstruction -- + * + * Gets the path instruction at position index of objv. + * If unrecognized instruction returns PATH_NEXT_ERROR. + * + * Results: + * A PATH_NEXT_* result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetPathInstruction(Tcl_Interp *interp, Tcl_Obj *CONST objv[], int index, char *c) +{ + int len; + int result; + char *str; + + *c = '\0'; + str = Tcl_GetStringFromObj(objv[index], &len); + if (isalpha(str[0])) { + if (len != 1) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(kPathSyntaxError, -1)); + result = PATH_NEXT_ERROR; + } else { + switch (str[0]) { + case 'M': case 'm': case 'L': case 'l': + case 'H': case 'h': case 'V': case 'v': + case 'A': case 'a': case 'Q': case 'q': + case 'T': case 't': case 'C': case 'c': + case 'S': case 's': case 'Z': case 'z': + result = PATH_NEXT_INSTRUCTION; + *c = str[0]; + break; + default: + Tcl_SetObjResult(interp, Tcl_NewStringObj(kPathSyntaxError, -1)); + result = PATH_NEXT_ERROR; + break; + } + } + } else { + result = PATH_NEXT_OTHER; + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * GetPathDouble, GetPathBoolean, GetPathPoint, GetPathTwoPoints, + * GetPathThreePoints, GetPathArcParameters -- + * + * Gets a certain number of numbers from objv. + * Increments indexPtr by the number of numbers extracted + * if succesful, else it is unchanged. + * + * Results: + * A standard tcl result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetPathDouble(Tcl_Interp *interp, Tcl_Obj *CONST objv[], int len, int *indexPtr, double *zPtr) +{ + int result; + + if (*indexPtr > len - 1) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(kPathSyntaxError, -1)); + result = TCL_ERROR; + } else { + result = Tcl_GetDoubleFromObj(interp, objv[*indexPtr], zPtr); + if (result == TCL_OK) { + (*indexPtr)++; + } + } + return result; +} + +static int +GetPathBoolean(Tcl_Interp *interp, Tcl_Obj *CONST objv[], int len, int *indexPtr, char *boolPtr) +{ + int result; + int boolean; + + if (*indexPtr > len - 1) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(kPathSyntaxError, -1)); + result = TCL_ERROR; + } else { + result = Tcl_GetBooleanFromObj(interp, objv[*indexPtr], &boolean); + if (result == TCL_OK) { + (*indexPtr)++; + *boolPtr = boolean; + } + } + return result; +} + +static int +GetPathPoint(Tcl_Interp *interp, Tcl_Obj *CONST objv[], int len, int *indexPtr, + double *xPtr, double *yPtr) +{ + int result = TCL_OK; + int indIn = *indexPtr; + + if (*indexPtr > len - 2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(kPathSyntaxError, -1)); + result = TCL_ERROR; + } else if (Tcl_GetDoubleFromObj(interp, objv[(*indexPtr)++], xPtr) != TCL_OK) { + *indexPtr = indIn; + result = TCL_ERROR; + } else if (Tcl_GetDoubleFromObj(interp, objv[(*indexPtr)++], yPtr) != TCL_OK) { + *indexPtr = indIn; + result = TCL_ERROR; + } + return result; +} + +static int +GetPathTwoPoints(Tcl_Interp *interp, Tcl_Obj *CONST objv[], int len, int *indexPtr, + double *x1Ptr, double *y1Ptr, double *x2Ptr, double *y2Ptr) +{ + int result; + int indIn = *indexPtr; + + result = GetPathPoint(interp, objv, len, indexPtr, x1Ptr, y1Ptr); + if (result == TCL_OK) { + if (GetPathPoint(interp, objv, len, indexPtr, x2Ptr, y2Ptr) != TCL_OK) { + *indexPtr = indIn; + result = TCL_ERROR; + } + } + return result; +} + +static int +GetPathThreePoints(Tcl_Interp *interp, Tcl_Obj *CONST objv[], int len, int *indexPtr, + double *x1Ptr, double *y1Ptr, double *x2Ptr, double *y2Ptr, + double *x3Ptr, double *y3Ptr) +{ + int result; + int indIn = *indexPtr; + + result = GetPathPoint(interp, objv, len, indexPtr, x1Ptr, y1Ptr); + if (result == TCL_OK) { + if (GetPathPoint(interp, objv, len, indexPtr, x2Ptr, y2Ptr) != TCL_OK) { + *indexPtr = indIn; + result = TCL_ERROR; + } else if (GetPathPoint(interp, objv, len, indexPtr, x3Ptr, y3Ptr) != TCL_OK) { + *indexPtr = indIn; + result = TCL_ERROR; + } + } + return result; +} + +static int +GetPathArcParameters(Tcl_Interp *interp, Tcl_Obj *CONST objv[], int len, int *indexPtr, + double *radXPtr, double *radYPtr, double *anglePtr, + char *largeArcFlagPtr, char *sweepFlagPtr, + double *xPtr, double *yPtr) +{ + int result; + int indIn = *indexPtr; + + result = GetPathPoint(interp, objv, len, indexPtr, radXPtr, radYPtr); + if (result == TCL_OK) { + if (GetPathDouble(interp, objv, len, indexPtr, anglePtr) != TCL_OK) { + *indexPtr = indIn; + result = TCL_ERROR; + } else if (GetPathBoolean(interp, objv, len, indexPtr, largeArcFlagPtr) != TCL_OK) { + *indexPtr = indIn; + result = TCL_ERROR; + } else if (GetPathBoolean(interp, objv, len, indexPtr, sweepFlagPtr) != TCL_OK) { + *indexPtr = indIn; + result = TCL_ERROR; + } else if (GetPathPoint(interp, objv, len, indexPtr, xPtr, yPtr) != TCL_OK) { + *indexPtr = indIn; + result = TCL_ERROR; + } + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * NewMoveToAtom, NewLineToAtom, NewArcAtom, NewQuadBezierAtom, + * NewCurveToAtom, NewCloseAtom -- + * + * Creates a PathAtom of the specified type using the given + * parameters. It updates the currentX and currentY. + * + * Results: + * A PathAtom pointer. + * + * Side effects: + * Memory allocated. + * + *-------------------------------------------------------------- + */ + +PathAtom * +NewMoveToAtom(double x, double y) +{ + PathAtom *atomPtr; + MoveToAtom *moveToAtomPtr; + + moveToAtomPtr = (MoveToAtom *) ckalloc((unsigned) (sizeof(MoveToAtom))); + atomPtr = (PathAtom *) moveToAtomPtr; + atomPtr->type = PATH_ATOM_M; + atomPtr->nextPtr = NULL; + moveToAtomPtr->x = x; + moveToAtomPtr->y = y; + return atomPtr; +} + +PathAtom * +NewLineToAtom(double x, double y) +{ + PathAtom *atomPtr; + LineToAtom *lineToAtomPtr; + + lineToAtomPtr = (LineToAtom *) ckalloc((unsigned) (sizeof(LineToAtom))); + atomPtr = (PathAtom *) lineToAtomPtr; + atomPtr->type = PATH_ATOM_L; + atomPtr->nextPtr = NULL; + lineToAtomPtr->x = x; + lineToAtomPtr->y = y; + return atomPtr; +} + +PathAtom * +NewArcAtom(double radX, double radY, + double angle, char largeArcFlag, char sweepFlag, double x, double y) +{ + PathAtom *atomPtr; + ArcAtom *arcAtomPtr; + + arcAtomPtr = (ArcAtom *) ckalloc((unsigned) (sizeof(ArcAtom))); + atomPtr = (PathAtom *) arcAtomPtr; + atomPtr->type = PATH_ATOM_A; + atomPtr->nextPtr = NULL; + arcAtomPtr->radX = radX; + arcAtomPtr->radY = radY; + arcAtomPtr->angle = angle; + arcAtomPtr->largeArcFlag = largeArcFlag; + arcAtomPtr->sweepFlag = sweepFlag; + arcAtomPtr->x = x; + arcAtomPtr->y = y; + return atomPtr; +} + +PathAtom * +NewQuadBezierAtom(double ctrlX, double ctrlY, double anchorX, double anchorY) +{ + PathAtom *atomPtr; + QuadBezierAtom *quadBezierAtomPtr; + + quadBezierAtomPtr = (QuadBezierAtom *) ckalloc((unsigned) (sizeof(QuadBezierAtom))); + atomPtr = (PathAtom *) quadBezierAtomPtr; + atomPtr->type = PATH_ATOM_Q; + atomPtr->nextPtr = NULL; + quadBezierAtomPtr->ctrlX = ctrlX; + quadBezierAtomPtr->ctrlY = ctrlY; + quadBezierAtomPtr->anchorX = anchorX; + quadBezierAtomPtr->anchorY = anchorY; + return atomPtr; +} + +PathAtom * +NewCurveToAtom(double ctrlX1, double ctrlY1, double ctrlX2, double ctrlY2, + double anchorX, double anchorY) +{ + PathAtom *atomPtr; + CurveToAtom *curveToAtomPtr; + + curveToAtomPtr = (CurveToAtom *) ckalloc((unsigned) (sizeof(CurveToAtom))); + atomPtr = (PathAtom *) curveToAtomPtr; + atomPtr->type = PATH_ATOM_C; + atomPtr->nextPtr = NULL; + curveToAtomPtr->ctrlX1 = ctrlX1; + curveToAtomPtr->ctrlY1 = ctrlY1; + curveToAtomPtr->ctrlX2 = ctrlX2; + curveToAtomPtr->ctrlY2 = ctrlY2; + curveToAtomPtr->anchorX = anchorX; + curveToAtomPtr->anchorY = anchorY; + return atomPtr; +} + +PathAtom * +NewRectAtom(double pointsPtr[]) +{ + PathAtom *atomPtr; + RectAtom *rectAtomPtr; + + rectAtomPtr = (RectAtom *) ckalloc((unsigned) (sizeof(RectAtom))); + atomPtr = (PathAtom *) rectAtomPtr; + atomPtr->nextPtr = NULL; + atomPtr->type = PATH_ATOM_RECT; + rectAtomPtr->x = pointsPtr[0]; + rectAtomPtr->y = pointsPtr[1]; + rectAtomPtr->width = pointsPtr[2] - pointsPtr[0]; + rectAtomPtr->height = pointsPtr[3] - pointsPtr[1]; + return atomPtr; +} + +PathAtom * +NewCloseAtom(double x, double y) +{ + PathAtom *atomPtr; + CloseAtom *closeAtomPtr; + + closeAtomPtr = (CloseAtom *) ckalloc((unsigned) (sizeof(CloseAtom))); + atomPtr = (PathAtom *) closeAtomPtr; + atomPtr->type = PATH_ATOM_Z; + atomPtr->nextPtr = NULL; + closeAtomPtr->x = x; + closeAtomPtr->y = y; + return atomPtr; +} + +/* + *-------------------------------------------------------------- + * + * TkPathParseToAtoms + * + * Takes a tcl list of values which defines the path item and + * parses them into a linked list of path atoms. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +int +TkPathParseToAtoms(Tcl_Interp *interp, Tcl_Obj *listObjPtr, PathAtom **atomPtrPtr, int *lenPtr) +{ + char currentInstr; /* current instruction (M, l, c, etc.) */ + char lastInstr; /* previous instruction */ + int len; + int currentInd; + int index; + int next; + int relative; + double currentX, currentY; /* current point */ + double startX, startY; /* the current moveto point */ + double ctrlX, ctrlY; /* last control point, for s, S, t, T */ + double x, y; + Tcl_Obj **objv; + PathAtom *atomPtr = NULL; + PathAtom *currentAtomPtr = NULL; + + *atomPtrPtr = NULL; + currentX = 0.0; + currentY = 0.0; + startX = 0.0; + startY = 0.0; + ctrlX = 0.0; + ctrlY = 0.0; + lastInstr = 'M'; /* If first instruction is missing it defaults to M ? */ + relative = 0; + + if (Tcl_ListObjGetElements(interp, listObjPtr, lenPtr, &objv) != TCL_OK) { + return TCL_ERROR; + } + len = *lenPtr; + + /* First some error checking. Necessary??? */ + if (len < 3) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "path specification too short", -1)); + return TCL_ERROR; + } + if ((GetPathInstruction(interp, objv, 0, ¤tInstr) != PATH_NEXT_INSTRUCTION) || + (toupper(currentInstr) != 'M')) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "path must start with M or m", -1)); + return TCL_ERROR; + } + currentInd = 1; + if (GetPathPoint(interp, objv, len, ¤tInd, &x, &y) != TCL_OK) { + return TCL_ERROR; + } + currentInd = 0; + + while (currentInd < len) { + + next = GetPathInstruction(interp, objv, currentInd, ¤tInstr); + if (next == PATH_NEXT_ERROR) { + goto error; + } else if (next == PATH_NEXT_INSTRUCTION) { + relative = islower(currentInstr); + currentInd++; + } else if (next == PATH_NEXT_OTHER) { + + /* Use rule to find instruction to use. */ + if (lastInstr == 'M') { + currentInstr = 'L'; + } else if (lastInstr == 'm') { + currentInstr = 'l'; + } else { + currentInstr = lastInstr; + } + relative = islower(currentInstr); + } + index = currentInd; + + switch (currentInstr) { + + case 'M': case 'm': { + if (GetPathPoint(interp, objv, len, &index, &x, &y) != TCL_OK) { + goto error; + } + if (relative) { + x += currentX; + y += currentY; + } + atomPtr = NewMoveToAtom(x, y); + if (currentAtomPtr == NULL) { + *atomPtrPtr = atomPtr; + } else { + currentAtomPtr->nextPtr = atomPtr; + } + currentAtomPtr = atomPtr; + currentX = x; + currentY = y; + startX = x; + startY = y; + break; + } + + case 'L': case 'l': { + if (index > len - 2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(kPathSyntaxError, -1)); + goto error; + } + if (GetPathPoint(interp, objv, len, &index, &x, &y) == TCL_OK) { + if (relative) { + x += currentX; + y += currentY; + } + atomPtr = NewLineToAtom(x, y); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + currentX = x; + currentY = y; + } else { + goto error; + } + break; + } + + case 'A': case 'a': { + double radX, radY, angle; + char largeArcFlag, sweepFlag; + + if (GetPathArcParameters(interp, objv, len, &index, + &radX, &radY, &angle, &largeArcFlag, &sweepFlag, + &x, &y) == TCL_OK) { + if (relative) { + x += currentX; + y += currentY; + } + atomPtr = NewArcAtom(radX, radY, angle, largeArcFlag, sweepFlag, x, y); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + currentX = x; + currentY = y; + } else { + goto error; + } + break; + } + + case 'C': case 'c': { + double x1, y1, x2, y2; /* The two control points. */ + + if (index > len - 6) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(kPathSyntaxError, -1)); + goto error; + } + if (GetPathThreePoints(interp, objv, len, &index, &x1, &y1, &x2, &y2, &x, &y) == TCL_OK) { + if (relative) { + x1 += currentX; + y1 += currentY; + x2 += currentX; + y2 += currentY; + x += currentX; + y += currentY; + } + atomPtr = NewCurveToAtom(x1, y1, x2, y2, x, y); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + ctrlX = x2; /* Keep track of the last control point. */ + ctrlY = y2; + currentX = x; + currentY = y; + } else { + goto error; + } + break; + } + + case 'S': case 's': { + double x1, y1; /* The first control point. */ + double x2, y2; /* The second control point. */ + + if ((toupper(lastInstr) == 'C') || (toupper(lastInstr) == 'S')) { + /* The first controlpoint is the reflection of the last one about the current point: */ + x1 = 2 * currentX - ctrlX; + y1 = 2 * currentY - ctrlY; + } else { + /* The first controlpoint is equal to the current point: */ + x1 = currentX; + y1 = currentY; + } + if (index > len - 4) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(kPathSyntaxError, -1)); + goto error; + } + if (GetPathTwoPoints(interp, objv, len, &index, &x2, &y2, &x, &y) == TCL_OK) { + if (relative) { + x2 += currentX; + y2 += currentY; + x += currentX; + y += currentY; + } + atomPtr = NewCurveToAtom(x1, y1, x2, y2, x, y); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + ctrlX = x2; /* Keep track of the last control point. */ + ctrlY = y2; + currentX = x; + currentY = y; + } else { + goto error; + } + break; + } + + case 'Q': case 'q': { + double x1, y1; /* The control point. */ + + if (GetPathTwoPoints(interp, objv, len, &index, &x1, &y1, &x, &y) == TCL_OK) { + if (relative) { + x1 += currentX; + y1 += currentY; + x += currentX; + y += currentY; + } + atomPtr = NewQuadBezierAtom(x1, y1, x, y); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + ctrlX = x1; /* Keep track of the last control point. */ + ctrlY = y1; + currentX = x; + currentY = y; + } else { + goto error; + } + break; + } + + case 'T': case 't': { + double x1, y1; /* The control point. */ + + if ((toupper(lastInstr) == 'Q') || (toupper(lastInstr) == 'T')) { + /* The controlpoint is the reflection of the last one about the current point: */ + x1 = 2 * currentX - ctrlX; + y1 = 2 * currentY - ctrlY; + } else { + /* The controlpoint is equal to the current point: */ + x1 = currentX; + y1 = currentY; + } + if (GetPathPoint(interp, objv, len, &index, &x, &y) == TCL_OK) { + if (relative) { + x += currentX; + y += currentY; + } + atomPtr = NewQuadBezierAtom(x1, y1, x, y); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + ctrlX = x1; /* Keep track of the last control point. */ + ctrlY = y1; + currentX = x; + currentY = y; + } else { + goto error; + } + break; + } + + case 'H': { + while ((index < len) && + (GetPathDouble(interp, objv, len, &index, &x) == TCL_OK)) + ; + atomPtr = NewLineToAtom(x, currentY); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + currentX = x; + break; + } + + case 'h': { + double z; + + x = currentX; + while ((index < len) && + (GetPathDouble(interp, objv, len, &index, &z) == TCL_OK)) { + x += z; + } + atomPtr = NewLineToAtom(x, currentY); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + currentX = x; + break; + } + + case 'V': { + while ((index < len) && + (GetPathDouble(interp, objv, len, &index, &y) == TCL_OK)) + ; + atomPtr = NewLineToAtom(currentX, y); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + currentY = y; + break; + } + + case 'v': { + double z; + + y = currentY; + while ((index < len) && + (GetPathDouble(interp, objv, len, &index, &z) == TCL_OK)) { + y += z; + } + atomPtr = NewLineToAtom(currentX, y); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + currentY = y; + break; + } + + case 'Z': case 'z': { + atomPtr = NewCloseAtom(startX, startY); + currentAtomPtr->nextPtr = atomPtr; + currentAtomPtr = atomPtr; + currentX = startX; + currentY = startY; + break; + } + + default: { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unrecognized path instruction", -1)); + goto error; + } + } + currentInd = index; + lastInstr = currentInstr; + } + + /* When we parse coordinates there may be some junk result + * left in the interpreter to be cleared out. */ + Tcl_ResetResult(interp); + return TCL_OK; + +error: + + TkPathFreeAtoms(*atomPtrPtr); + *atomPtrPtr = NULL; + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * TkPathFreeAtoms + * + * Frees up all memory allocated for the path atoms. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +TkPathFreeAtoms(PathAtom *pathAtomPtr) +{ + PathAtom *tmpAtomPtr; + + while (pathAtomPtr != NULL) { + tmpAtomPtr = pathAtomPtr; + pathAtomPtr = tmpAtomPtr->nextPtr; + ckfree((char *) tmpAtomPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * TkPathNormalize + * + * Takes a list of PathAtoms and creates a tcl list where + * elements have a standard form. All upper case instructions, + * no repeates. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * New list returned in listObjPtrPtr. + * + *-------------------------------------------------------------- + */ + +int +TkPathNormalize(Tcl_Interp *interp, PathAtom *atomPtr, Tcl_Obj **listObjPtrPtr) +{ + Tcl_Obj *normObjPtr; + + normObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); + + while (atomPtr != NULL) { + + switch (atomPtr->type) { + case PATH_ATOM_M: { + MoveToAtom *move = (MoveToAtom *) atomPtr; + + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewStringObj("M", -1)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(move->x)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(move->y)); + break; + } + case PATH_ATOM_L: { + LineToAtom *line = (LineToAtom *) atomPtr; + + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewStringObj("L", -1)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(line->x)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(line->y)); + break; + } + case PATH_ATOM_A: { + ArcAtom *arc = (ArcAtom *) atomPtr; + + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewStringObj("A", -1)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(arc->radX)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(arc->radY)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(arc->angle)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewBooleanObj(arc->largeArcFlag)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewBooleanObj(arc->sweepFlag)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(arc->x)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(arc->y)); + break; + } + case PATH_ATOM_Q: { + QuadBezierAtom *quad = (QuadBezierAtom *) atomPtr; + + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewStringObj("Q", -1)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(quad->ctrlX)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(quad->ctrlY)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(quad->anchorX)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(quad->anchorY)); + break; + } + case PATH_ATOM_C: { + CurveToAtom *curve = (CurveToAtom *) atomPtr; + + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewStringObj("C", -1)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(curve->ctrlX1)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(curve->ctrlY1)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(curve->ctrlX2)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(curve->ctrlY2)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(curve->anchorX)); + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewDoubleObj(curve->anchorY)); + break; + } + case PATH_ATOM_Z: { + Tcl_ListObjAppendElement(interp, normObjPtr, Tcl_NewStringObj("Z", -1)); + break; + } + case PATH_ATOM_ELLIPSE: + case PATH_ATOM_RECT: { + /* Empty. */ + break; + } + } + atomPtr = atomPtr->nextPtr; + } + *listObjPtrPtr = normObjPtr; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TkPathMakePath + * + * Defines the path using the PathAtom. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * Defines the current path in drawable. + * + *-------------------------------------------------------------- + */ + +int +TkPathMakePath( + TkPathContext context, + PathAtom *atomPtr, + Tk_PathStyle *stylePtr) +{ + TkPathBeginPath(context, stylePtr); + + while (atomPtr != NULL) { + + switch (atomPtr->type) { + case PATH_ATOM_M: { + MoveToAtom *move = (MoveToAtom *) atomPtr; + TkPathMoveTo(context, move->x, move->y); + break; + } + case PATH_ATOM_L: { + LineToAtom *line = (LineToAtom *) atomPtr; + TkPathLineTo(context, line->x, line->y); + break; + } + case PATH_ATOM_A: { + ArcAtom *arc = (ArcAtom *) atomPtr; + TkPathArcTo(context, arc->radX, arc->radY, arc->angle, + arc->largeArcFlag, arc->sweepFlag, + arc->x, arc->y); + break; + } + case PATH_ATOM_Q: { + QuadBezierAtom *quad = (QuadBezierAtom *) atomPtr; + TkPathQuadBezier(context, + quad->ctrlX, quad->ctrlY, + quad->anchorX, quad->anchorY); + break; + } + case PATH_ATOM_C: { + CurveToAtom *curve = (CurveToAtom *) atomPtr; + TkPathCurveTo(context, + curve->ctrlX1, curve->ctrlY1, + curve->ctrlX2, curve->ctrlY2, + curve->anchorX, curve->anchorY); + break; + } + case PATH_ATOM_Z: { + TkPathClosePath(context); + break; + } + case PATH_ATOM_ELLIPSE: { + EllipseAtom *ell = (EllipseAtom *) atomPtr; + TkPathOval(context, ell->cx, ell->cy, ell->rx, ell->ry); + break; + } + case PATH_ATOM_RECT: { + RectAtom *rect = (RectAtom *) atomPtr; + TkPathRect(context, rect->x, rect->y, rect->width, rect->height); + break; + } + } + atomPtr = atomPtr->nextPtr; + } + TkPathEndPath(context); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TkPathArcToUsingBezier + * + * Translates an ArcTo drawing into a sequence of CurveTo. + * Helper function for the platform specific drawing code. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +TkPathArcToUsingBezier(TkPathContext ctx, + double rx, double ry, + double phiDegrees, /* The rotation angle in degrees! */ + char largeArcFlag, char sweepFlag, double x2, double y2) +{ + int result; + int i, segments; + double x1, y1; + double cx, cy; + double theta1, dtheta, phi; + double sinPhi, cosPhi; + double delta, t; + PathPoint pt; + + TkPathGetCurrentPosition(ctx, &pt); + x1 = pt.x; + y1 = pt.y; + + /* All angles except phi is in radians! */ + phi = phiDegrees * DEGREES_TO_RADIANS; + + /* Check return value and take action. */ + result = EndpointToCentralArcParameters(x1, y1, + x2, y2, rx, ry, phi, largeArcFlag, sweepFlag, + &cx, &cy, &rx, &ry, + &theta1, &dtheta); + if (result == kPathArcSkip) { + return; + } else if (result == kPathArcLine) { + TkPathLineTo(ctx, x2, y2); + return; + } + sinPhi = sin(phi); + cosPhi = cos(phi); + + /* Convert into cubic bezier segments <= 90deg (from mozilla/svg; not checked) */ + segments = (int) ceil(fabs(dtheta/(M_PI/2.0))); + delta = dtheta/segments; + t = 8.0/3.0 * sin(delta/4.0) * sin(delta/4.0) / sin(delta/2.0); + + for (i = 0; i < segments; ++i) { + double cosTheta1 = cos(theta1); + double sinTheta1 = sin(theta1); + double theta2 = theta1 + delta; + double cosTheta2 = cos(theta2); + double sinTheta2 = sin(theta2); + + /* a) calculate endpoint of the segment: */ + double xe = cosPhi * rx*cosTheta2 - sinPhi * ry*sinTheta2 + cx; + double ye = sinPhi * rx*cosTheta2 + cosPhi * ry*sinTheta2 + cy; + + /* b) calculate gradients at start/end points of segment: */ + double dx1 = t * ( - cosPhi * rx*sinTheta1 - sinPhi * ry*cosTheta1); + double dy1 = t * ( - sinPhi * rx*sinTheta1 + cosPhi * ry*cosTheta1); + + double dxe = t * ( cosPhi * rx*sinTheta2 + sinPhi * ry*cosTheta2); + double dye = t * ( sinPhi * rx*sinTheta2 - cosPhi * ry*cosTheta2); + + /* c) draw the cubic bezier: */ + TkPathCurveTo(ctx, x1+dx1, y1+dy1, xe+dxe, ye+dye, xe, ye); + + /* do next segment */ + theta1 = theta2; + x1 = (float) xe; + y1 = (float) ye; + } +} + +/*-----------------------------------------------------------------------*/ + + diff --git a/pd/tkpath/generic/tkPath.h b/pd/tkpath/generic/tkPath.h new file mode 100644 index 0000000000000000000000000000000000000000..f9c8e0eb772326a5a2fba3587eef0f08c79be57f --- /dev/null +++ b/pd/tkpath/generic/tkPath.h @@ -0,0 +1,329 @@ +/* + * tkPath.h -- + * + * This file implements a path drawing model + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * $Id: tkPath.h,v 1.32 2008/06/14 14:23:25 matben Exp $ + */ + +#ifndef INCLUDED_TKPATH_H +#define INCLUDED_TKPATH_H + +#include <tkInt.h> +#include "tkPort.h" +#include "tkp.h" + +/* + * For C++ compilers, use extern "C" + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The enum below defines the valid types for the PathAtom's. + */ + +typedef enum { + PATH_ATOM_M = 'M', + PATH_ATOM_L = 'L', + PATH_ATOM_A = 'A', + PATH_ATOM_Q = 'Q', + PATH_ATOM_C = 'C', + PATH_ATOM_Z = 'Z', + PATH_ATOM_ELLIPSE = '1', /* These are not a standard atoms + * since they are more complex (molecule). + * Not all features supported for these! */ + PATH_ATOM_RECT = '2' +} PathAtomType; + +enum { + PATH_NEXT_ERROR, + PATH_NEXT_INSTRUCTION, + PATH_NEXT_OTHER +}; + +typedef struct PathPoint { + double x; + double y; +} PathPoint; + +typedef struct PathRect { + double x1; + double y1; + double x2; + double y2; +} PathRect; + +/* + * The transformation matrix: + * | a b 0 | + * | c d 0 | + * | tx ty 1 | + */ + +typedef struct TMatrix { + double a, b, c, d; + double tx, ty; +} TMatrix; + +/* + * Records used for parsing path to a linked list of primitive + * drawing instructions. + * + * PathAtom: vaguely modelled after Tk_PathItem. Each atom has a PathAtom record + * in its first position, padded with type specific data. + */ + +typedef struct PathAtom { + PathAtomType type; /* Type of PathAtom. */ + struct PathAtom *nextPtr; /* Next PathAtom along the path. */ +} PathAtom; + +typedef void (TkPathGradientChangedProc)(ClientData clientData, int flags); +typedef void (TkPathStyleChangedProc)(ClientData clientData, int flags); + +/* + * Records for gradient fills. + * We need a separate GradientStopArray to simplify option parsing. + */ + +typedef struct GradientStop { + double offset; + XColor *color; + double opacity; +} GradientStop; + +typedef struct GradientStopArray { + int nstops; + GradientStop **stops; /* Array of pointers to GradientStop. */ +} GradientStopArray; + +typedef struct LinearGradientFill { + PathRect *transitionPtr; /* Actually not a proper rect but a vector. */ + int method; + int fillRule; /* Not yet used. */ + int units; + GradientStopArray *stopArrPtr; +} LinearGradientFill; + +typedef struct RadialTransition { + double centerX; + double centerY; + double radius; + double focalX; + double focalY; +} RadialTransition; + +typedef struct RadialGradientFill { + RadialTransition *radialPtr; + int method; + int fillRule; /* Not yet used. */ + int units; + GradientStopArray *stopArrPtr; +} RadialGradientFill; + +enum { + kPathGradientTypeLinear = 0L, + kPathGradientTypeRadial +}; + +/* + * This is the main record for a gradient object. + */ +typedef struct TkPathGradientMaster { + int type; /* Any of kPathGradientTypeLinear or kPathGradientTypeRadial */ + Tk_OptionTable optionTable; + Tk_Uid name; + Tcl_Obj *transObj; + Tcl_Obj *stopsObj; + TMatrix *matrixPtr; /* a b default (NULL): 1 0 + c d 0 1 + tx ty 0 0 */ + + struct TkPathGradientInst *instancePtr; + /* Pointer to first in list of instances + * derived from this gradient name. */ + union { /* Depending on the 'type'. */ + LinearGradientFill linearFill; + RadialGradientFill radialFill; + }; +} TkPathGradientMaster; + +/* + * This defines an instance of a gradient with specified name and hash table. + */ +typedef struct TkPathGradientInst { + struct TkPathGradientMaster *masterPtr; + /* Each instance also points to the actual + * TkPathGradientMaster in order to remove itself + * from its linked list. */ + TkPathGradientChangedProc *changeProc; + /* Code in item to call when gradient changes + * in a way that affects redisplay. */ + ClientData clientData; /* Argument to pass to changeProc. */ + struct TkPathGradientInst *nextPtr; + /* Next in list of all gradient instances + * associated with the same gradient name. */ +} TkPathGradientInst; + +/* + * Only one of color and gradientInstPtr must be non NULL! + */ +typedef struct TkPathColor { + XColor *color; /* Foreground color for filling. */ + TkPathGradientInst *gradientInstPtr; + /* This is an instance of a gradient. + * It points to the actual gradient object, the master. */ +} TkPathColor; + +/* + * Opaque platform dependent struct. + */ + +typedef XID TkPathContext; + +/* + * Information used for parsing configuration options. + * Mask bits for options changed. + */ + +enum { + PATH_STYLE_OPTION_FILL = (1L << 0), + PATH_STYLE_OPTION_FILL_OFFSET = (1L << 1), + PATH_STYLE_OPTION_FILL_OPACITY = (1L << 2), + PATH_STYLE_OPTION_FILL_RULE = (1L << 3), + PATH_STYLE_OPTION_FILL_STIPPLE = (1L << 4), + PATH_STYLE_OPTION_MATRIX = (1L << 5), + PATH_STYLE_OPTION_STROKE = (1L << 6), + PATH_STYLE_OPTION_STROKE_DASHARRAY = (1L << 7), + PATH_STYLE_OPTION_STROKE_LINECAP = (1L << 8), + PATH_STYLE_OPTION_STROKE_LINEJOIN = (1L << 9), + PATH_STYLE_OPTION_STROKE_MITERLIMIT = (1L << 10), + PATH_STYLE_OPTION_STROKE_OFFSET = (1L << 11), + PATH_STYLE_OPTION_STROKE_OPACITY = (1L << 12), + PATH_STYLE_OPTION_STROKE_STIPPLE = (1L << 13), + PATH_STYLE_OPTION_STROKE_WIDTH = (1L << 14), + PATH_CORE_OPTION_PARENT = (1L << 15), + PATH_CORE_OPTION_STYLENAME = (1L << 16), + PATH_CORE_OPTION_TAGS = (1L << 17), +}; + +#define PATH_STYLE_OPTION_INDEX_END 17 /* Use this for item specific flags */ + +typedef struct Tk_PathStyle { + Tk_OptionTable optionTable; /* Not used for canvas. */ + Tk_Uid name; /* Not used for canvas. */ + int mask; /* Bits set for actual options modified. */ + XColor *strokeColor; /* Stroke color. */ + double strokeWidth; /* Width of stroke. */ + double strokeOpacity; + int offset; /* Dash offset */ + Tk_PathDash *dashPtr; /* Dash pattern. */ + int capStyle; /* Cap style for stroke. */ + int joinStyle; /* Join style for stroke. */ + double miterLimit; + Tcl_Obj *fillObj; /* This is just used for option parsing. */ + TkPathColor *fill; /* Record XColor + TkPathGradientInst. */ + double fillOpacity; + int fillRule; /* WindingRule or EvenOddRule. */ + TMatrix *matrixPtr; /* a b default (NULL): 1 0 + c d 0 1 + tx ty 0 0 */ + struct TkPathStyleInst *instancePtr; + /* Pointer to first in list of instances + * derived from this style name. */ +} Tk_PathStyle; + +/* + * This defines an instance of a style with specified name and hash table. + */ +typedef struct TkPathStyleInst { + struct Tk_PathStyle *masterPtr; + /* Each instance also points to the actual + * Tk_PathStyle in order to remove itself + * from its linked list. */ + TkPathStyleChangedProc *changeProc; + /* Code in item to call when style changes + * in a way that affects redisplay. */ + ClientData clientData; /* Argument to pass to changeProc. */ + struct TkPathStyleInst *nextPtr; + /* Next in list of all style instances + * associated with the same style name. */ +} TkPathStyleInst; + +// @@@ TODO: Much more to be added here! */ + +typedef struct Tk_PathTextStyle { + char *fontFamily; + double fontSize; +} Tk_PathTextStyle; + +/* + * Functions to create path atoms. + */ + +PathAtom * NewMoveToAtom(double x, double y); +PathAtom * NewLineToAtom(double x, double y); +PathAtom * NewArcAtom(double radX, double radY, + double angle, char largeArcFlag, char sweepFlag, double x, double y); +PathAtom * NewQuadBezierAtom(double ctrlX, double ctrlY, double anchorX, double anchorY); +PathAtom * NewCurveToAtom(double ctrlX1, double ctrlY1, double ctrlX2, double ctrlY2, + double anchorX, double anchorY); +PathAtom * NewRectAtom(double pointsPtr[]); +PathAtom * NewCloseAtom(double x, double y); + +/* + * Functions that process lists and atoms. + */ + +int TkPathParseToAtoms(Tcl_Interp *interp, Tcl_Obj *listObjPtr, PathAtom **atomPtrPtr, int *lenPtr); +void TkPathFreeAtoms(PathAtom *pathAtomPtr); +int TkPathNormalize(Tcl_Interp *interp, PathAtom *atomPtr, Tcl_Obj **listObjPtrPtr); +int TkPathMakePath(Drawable drawable, PathAtom *atomPtr, Tk_PathStyle *stylePtr); + +/* + * Stroke, fill, clip etc. + */ + +void TkPathClipToPath(TkPathContext ctx, int fillRule); +void TkPathReleaseClipToPath(TkPathContext ctx); +void TkPathStroke(TkPathContext ctx, Tk_PathStyle *style); +void TkPathFill(TkPathContext ctx, Tk_PathStyle *style); +void TkPathFillAndStroke(TkPathContext ctx, Tk_PathStyle *style); +int TkPathGetCurrentPosition(TkPathContext ctx, PathPoint *ptPtr); +int TkPathBoundingBox(TkPathContext ctx, PathRect *rPtr); +void TkPathPaintLinearGradient(TkPathContext ctx, PathRect *bbox, + LinearGradientFill *fillPtr, int fillRule, TMatrix *matrixPtr); +void TkPathPaintRadialGradient(TkPathContext ctx, PathRect *bbox, + RadialGradientFill *fillPtr, int fillRule, TMatrix *mPtr); +void TkPathFree(TkPathContext ctx); +int TkPathDrawingDestroysPath(void); +int TkPathPixelAlign(void); +void TkPathPushTMatrix(TkPathContext ctx, TMatrix *mPtr); +void TkPathSaveState(TkPathContext ctx); +void TkPathRestoreState(TkPathContext ctx); + +/* + * Utilities for creating and deleting Tk_PathStyles. + */ + +void TkPathInitStyle(Tk_PathStyle *style); +void TkPathDeleteStyle(Tk_PathStyle *style); +int TkPathConfigStyle(Tcl_Interp* interp, Tk_PathStyle *stylePtr, int objc, Tcl_Obj* CONST objv[]); + +/* + * end block for C++ + */ + +#ifdef __cplusplus +} +#endif + +#endif // INCLUDED_TKPATH_H + + diff --git a/pd/tkpath/generic/tkPathGradient.c b/pd/tkpath/generic/tkPathGradient.c new file mode 100644 index 0000000000000000000000000000000000000000..0102d2432d0087af9b2099844bebacb2b12fbdbc --- /dev/null +++ b/pd/tkpath/generic/tkPathGradient.c @@ -0,0 +1,1053 @@ +/* + * tkPathGradient.c -- + * + * This file implements gradient objects used when drawing paths. + * See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * TODO: o Add tkwin option here and there so we can free stop colors! + * + * $Id: tkPathGradient.c,v 1.4 2012/07/04 19:43:18 petasis Exp $ + */ + +#include "tkIntPath.h" +#include "tkPathStyle.h" + +/* + * Hash table to keep track of gradient fills. + * This is used for globally defined gradients. + */ + +Tcl_HashTable *gGradientHashPtr = NULL; + +static Tk_OptionTable linearOptionTable = NULL; +static Tk_OptionTable radialOptionTable = NULL; +static int gGradientNameUid = 0; +static char * kGradientNameBase = "tkp::gradient"; + +static int GradientObjCmd(ClientData clientData, Tcl_Interp* interp, + int objc, Tcl_Obj* CONST objv[]); + +/* + * Custom option processing code. + */ + +static char * +ComputeSlotAddress( + char *recordPtr, /* Pointer to the start of a record. */ + int offset) /* Offset of a slot within that record; may be < 0. */ +{ + if (offset >= 0) { + return recordPtr + offset; + } else { + return NULL; + } +} + +/* + * Procedures for processing the transition option of the linear gradient fill. + */ + +static int LinTransitionSet( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + * internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; + int objEmpty = 0; + Tcl_Obj *valuePtr; + double z[4] = {0.0, 0.0, 1.0, 0.0}; /* Defaults according to SVG. */ + PathRect *newrc = NULL; + + valuePtr = *value; + internalPtr = ComputeSlotAddress(recordPtr, internalOffset); + objEmpty = ObjectIsEmpty(valuePtr); + + /* + * Important: the new value for the transition is not yet + * stored into the style! transObj may be NULL! + * The new value is stored in style *after* we return TCL_OK. + */ + if ((flags & TK_OPTION_NULL_OK) && objEmpty) { + valuePtr = NULL; + } else { + int i, len; + Tcl_Obj **objv; + + if (Tcl_ListObjGetElements(interp, valuePtr, &len, &objv) != TCL_OK) { + return TCL_ERROR; + } + if (len != 4) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "-lineartransition must have four elements", -1)); + return TCL_ERROR; + } + for (i = 0; i < 4; i++) { + if (Tcl_GetDoubleFromObj(interp, objv[i], z+i) != TCL_OK) { + return TCL_ERROR; + } + } + newrc = (PathRect *) ckalloc(sizeof(PathRect)); + newrc->x1 = z[0]; + newrc->y1 = z[1]; + newrc->x2 = z[2]; + newrc->y2 = z[3]; + } + if (internalPtr != NULL) { + *((PathRect **) oldInternalPtr) = *((PathRect **) internalPtr); + *((PathRect **) internalPtr) = newrc; + } + return TCL_OK; +} + +static void +LinTransitionRestore( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(PathRect **)internalPtr = *(PathRect **)oldInternalPtr; +} + +static void +LinTransitionFree( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr) /* Pointer to storage for value. */ +{ + if (*((char **) internalPtr) != NULL) { + ckfree(*((char **) internalPtr)); + *((char **) internalPtr) = NULL; + } +} + +static Tk_ObjCustomOption linTransitionCO = +{ + "lineartransition", + LinTransitionSet, + NULL, + LinTransitionRestore, + LinTransitionFree, + (ClientData) NULL +}; + +static int RadTransitionSet( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; + int objEmpty = 0; + Tcl_Obj *valuePtr; + double z[5] = {0.5, 0.5, 0.5, 0.5, 0.5}; + RadialTransition *newrc = NULL; + + valuePtr = *value; + internalPtr = ComputeSlotAddress(recordPtr, internalOffset); + objEmpty = ObjectIsEmpty(valuePtr); + + if ((flags & TK_OPTION_NULL_OK) && objEmpty) { + valuePtr = NULL; + } else { + int i, len; + Tcl_Obj **objv; + + if (Tcl_ListObjGetElements(interp, valuePtr, &len, &objv) != TCL_OK) { + return TCL_ERROR; + } + if ((len == 1) || (len == 4) || (len > 5)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "-radialtransition must be a list {cx cy ?r? ?fx fy?}", -1)); + return TCL_ERROR; + } + for (i = 0; i < len; i++) { + if (Tcl_GetDoubleFromObj(interp, objv[i], z+i) != TCL_OK) { + return TCL_ERROR; + } + } + newrc = (RadialTransition *) ckalloc(sizeof(RadialTransition)); + newrc->centerX = z[0]; + newrc->centerY = z[1]; + newrc->radius = z[2]; + newrc->focalX = z[3]; + newrc->focalY = z[4]; + } + if (internalPtr != NULL) { + *((RadialTransition **) oldInternalPtr) = *((RadialTransition **) internalPtr); + *((RadialTransition **) internalPtr) = newrc; + } + return TCL_OK; +} + +static void +RadTransitionRestore( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(RadialTransition **)internalPtr = *(RadialTransition **)oldInternalPtr; +} + +static void +RadTransitionFree( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr) /* Pointer to storage for value. */ +{ + if (*((char **) internalPtr) != NULL) { + ckfree(*((char **) internalPtr)); + *((char **) internalPtr) = NULL; + } +} + +static Tk_ObjCustomOption radTransitionCO = +{ + "radialtransition", + RadTransitionSet, + NULL, + RadTransitionRestore, + RadTransitionFree, + (ClientData) NULL +}; + +static GradientStop * +NewGradientStop(double offset, XColor *color, double opacity) +{ + GradientStop *stopPtr; + + stopPtr = (GradientStop *) ckalloc(sizeof(GradientStop)); + memset(stopPtr, '\0', sizeof(GradientStop)); + stopPtr->offset = offset; + stopPtr->color = color; + stopPtr->opacity = opacity; + return stopPtr; +} + +static GradientStopArray *NewGradientStopArray(int nstops) +{ + GradientStopArray *stopArrPtr; + GradientStop **stops; + + stopArrPtr = (GradientStopArray *) ckalloc(sizeof(GradientStopArray)); + memset(stopArrPtr, '\0', sizeof(GradientStopArray)); + + /* Array of *pointers* to GradientStop. */ + stops = (GradientStop **) ckalloc(nstops*sizeof(GradientStop *)); + memset(stops, '\0', nstops*sizeof(GradientStop *)); + stopArrPtr->nstops = nstops; + stopArrPtr->stops = stops; + return stopArrPtr; +} + +static void +FreeAllStops(GradientStop **stops, int nstops) +{ + int i; + for (i = 0; i < nstops; i++) { + if (stops[i] != NULL) { + /* @@@ Free color? */ + ckfree((char *) (stops[i])); + } + } + ckfree((char *) stops); +} + +static void +FreeStopArray(GradientStopArray *stopArrPtr) +{ + if (stopArrPtr != NULL) { + FreeAllStops(stopArrPtr->stops, stopArrPtr->nstops); + ckfree((char *) stopArrPtr); + } +} + +/* + * The stops are a list of stop lists where each stop list is: + * {offset color ?opacity?} + */ +static int StopsSet( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; + int i, nstops, stopLen; + int objEmpty = 0; + Tcl_Obj *valuePtr; + double offset, lastOffset, opacity; + Tcl_Obj **objv; + Tcl_Obj *stopObj; + Tcl_Obj *obj; + XColor *color; + GradientStopArray *newrc = NULL; + + valuePtr = *value; + internalPtr = ComputeSlotAddress(recordPtr, internalOffset); + objEmpty = ObjectIsEmpty(valuePtr); + + if ((flags & TK_OPTION_NULL_OK) && objEmpty) { + valuePtr = NULL; + } else { + + /* Deal with each stop list in turn. */ + if (Tcl_ListObjGetElements(interp, valuePtr, &nstops, &objv) != TCL_OK) { + return TCL_ERROR; + } + newrc = NewGradientStopArray(nstops); + lastOffset = 0.0; + + for (i = 0; i < nstops; i++) { + stopObj = objv[i]; + if (Tcl_ListObjLength(interp, stopObj, &stopLen) != TCL_OK) { + goto error; + } + if ((stopLen == 2) || (stopLen == 3)) { + Tcl_ListObjIndex(interp, stopObj, 0, &obj); + if (Tcl_GetDoubleFromObj(interp, obj, &offset) != TCL_OK) { + goto error; + } + if ((offset < 0.0) || (offset > 1.0)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "stop offsets must be in the range 0.0 to 1.0", -1)); + goto error; + } + if (offset < lastOffset) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "stop offsets must be ordered", -1)); + goto error; + } + Tcl_ListObjIndex(interp, stopObj, 1, &obj); + color = Tk_AllocColorFromObj(interp, Tk_MainWindow(interp), obj); + if (color == NULL) { + Tcl_AppendResult(interp, "color \"", + Tcl_GetStringFromObj(obj, NULL), + "\" doesn't exist", NULL); + goto error; + } + if (stopLen == 3) { + Tcl_ListObjIndex(interp, stopObj, 2, &obj); + if (Tcl_GetDoubleFromObj(interp, obj, &opacity) != TCL_OK) { + goto error; + } + } else { + opacity = 1.0; + } + + /* Make new stop. */ + newrc->stops[i] = NewGradientStop(offset, color, opacity); + lastOffset = offset; + } else { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "stop list not {offset color ?opacity?}", -1)); + goto error; + } + } + } + if (internalPtr != NULL) { + *((GradientStopArray **) oldInternalPtr) = *((GradientStopArray **) internalPtr); + *((GradientStopArray **) internalPtr) = newrc; + } + return TCL_OK; + +error: + if (newrc != NULL) { + FreeStopArray(newrc); + } + return TCL_ERROR; +} + +static void +StopsRestore( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(GradientStopArray **)internalPtr = *(GradientStopArray **)oldInternalPtr; +} + +static void StopsFree( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr) +{ + if (*((char **) internalPtr) != NULL) { + FreeStopArray(*(GradientStopArray **)internalPtr); + } +} + +static Tk_ObjCustomOption stopsCO = +{ + "stops", + StopsSet, + NULL, + StopsRestore, + StopsFree, + (ClientData) NULL +}; + +/* + * The following table defines the legal values for the -method option. + * The enum kPathGradientMethodPad... MUST be kept in sync! + */ + +static char *methodST[] = { + "pad", "repeat", "reflect", NULL +}; +static char *unitsST[] = { + "bbox", "userspace", NULL +}; + +PATH_STYLE_CUSTOM_OPTION_MATRIX + +static Tk_OptionSpec linGradientStyleOptionSpecs[] = { + {TK_OPTION_STRING_TABLE, "-method", NULL, NULL, + "pad", -1, Tk_Offset(TkPathGradientMaster, linearFill.method), + 0, (ClientData) methodST, 0}, + {TK_OPTION_STRING_TABLE, "-units", NULL, NULL, + "bbox", -1, Tk_Offset(TkPathGradientMaster, linearFill.units), + 0, (ClientData) unitsST, 0}, + {TK_OPTION_CUSTOM, "-stops", NULL, NULL, + NULL, Tk_Offset(TkPathGradientMaster, stopsObj), + Tk_Offset(TkPathGradientMaster, linearFill.stopArrPtr), + TK_OPTION_NULL_OK, (ClientData) &stopsCO, 0}, + {TK_OPTION_CUSTOM, "-lineartransition", NULL, NULL, + NULL, Tk_Offset(TkPathGradientMaster, transObj), + Tk_Offset(TkPathGradientMaster, linearFill.transitionPtr), + TK_OPTION_NULL_OK, (ClientData) &linTransitionCO, 0}, + {TK_OPTION_CUSTOM, "-matrix", NULL, NULL, + NULL, -1, Tk_Offset(TkPathGradientMaster, matrixPtr), + TK_OPTION_NULL_OK, (ClientData) &matrixCO, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +static Tk_OptionSpec radGradientStyleOptionSpecs[] = { + {TK_OPTION_STRING_TABLE, "-method", NULL, NULL, + "pad", -1, Tk_Offset(TkPathGradientMaster, radialFill.method), + 0, (ClientData) methodST, 0}, + {TK_OPTION_STRING_TABLE, "-units", NULL, NULL, + "bbox", -1, Tk_Offset(TkPathGradientMaster, radialFill.units), + 0, (ClientData) unitsST, 0}, + {TK_OPTION_CUSTOM, "-stops", NULL, NULL, + NULL, Tk_Offset(TkPathGradientMaster, stopsObj), + Tk_Offset(TkPathGradientMaster, radialFill.stopArrPtr), + TK_OPTION_NULL_OK, (ClientData) &stopsCO, 0}, + {TK_OPTION_CUSTOM, "-radialtransition", NULL, NULL, + NULL, Tk_Offset(TkPathGradientMaster, transObj), + Tk_Offset(TkPathGradientMaster, radialFill.radialPtr), + TK_OPTION_NULL_OK, (ClientData) &radTransitionCO, 0}, + {TK_OPTION_CUSTOM, "-matrix", NULL, NULL, + NULL, -1, Tk_Offset(TkPathGradientMaster, matrixPtr), + TK_OPTION_NULL_OK, (ClientData) &matrixCO, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +#if 0 +static void +FormatResult(Tcl_Interp *interp, char *fmt, ...) +{ + va_list ap; + char buf[256]; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + Tcl_SetResult(interp, buf, TCL_VOLATILE); +} +#endif + +void +PathGradientPaint(TkPathContext ctx, PathRect *bbox, + TkPathGradientMaster *gradientPtr, int fillRule) +{ + if (!ObjectIsEmpty(gradientPtr->stopsObj)) { + if (gradientPtr->type == kPathGradientTypeLinear) { + TkPathPaintLinearGradient(ctx, bbox, &gradientPtr->linearFill, + fillRule, gradientPtr->matrixPtr); + } else { + TkPathPaintRadialGradient(ctx, bbox, &gradientPtr->radialFill, + fillRule, gradientPtr->matrixPtr); + } + } +} + +void +PathGradientInit(Tcl_Interp* interp) +{ + /* + fixme roger: 04/07/2008 + + Don't recreate the Gradient Tables for + slave interps -- otherwise will void + existing gradients in the main interp... + + THERE IS NO FREE FOR THESE HASH TABLES... + */ + + if (NULL == gGradientHashPtr) { + gGradientHashPtr = (Tcl_HashTable *) ckalloc( sizeof(Tcl_HashTable) ); + Tcl_InitHashTable(gGradientHashPtr, TCL_STRING_KEYS); + } + + /* + * The option table must only be made once and not for each instance. + */ + + if (NULL == linearOptionTable) { + linearOptionTable = Tk_CreateOptionTable(interp, + linGradientStyleOptionSpecs); + } + if (NULL == radialOptionTable ) { + radialOptionTable = Tk_CreateOptionTable(interp, + radGradientStyleOptionSpecs); + } + + /* + fixme roger 04/07 ... above, + + Tables have to be restructured to be accessed via clientData + for each interp... that will close this issue. + */ + + Tcl_CreateObjCommand(interp, "::tkp::gradient", + GradientObjCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); +} + +static int +FindGradientMaster(Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_HashTable *tablePtr, + TkPathGradientMaster **g) +{ + Tcl_HashEntry *hPtr; + char *name = Tcl_GetString(nameObj); + *g = NULL; + hPtr = Tcl_FindHashEntry(tablePtr, name); + if (hPtr == NULL) { + Tcl_Obj *resultObj; + resultObj = Tcl_NewStringObj("gradient \"", -1); + Tcl_AppendStringsToObj(resultObj, name, "\" doesn't exist", (char *) NULL); + Tcl_SetObjResult(interp, resultObj); + return TCL_ERROR; + } + *g = (TkPathGradientMaster *) Tcl_GetHashValue(hPtr); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * PathGradientCget, Configure, Create, Delete, InUse, Names, Type -- + * + * These functions implement gradient object commands in a generic way. + * The Tcl_HashTable defines the gradient namespace. + * + * Results: + * Varies: typically a standard tcl result or void. + * + * Side effects: + * Varies. + * + *-------------------------------------------------------------- + */ + +int +PathGradientCget(Tcl_Interp *interp, Tk_Window tkwin, int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *tablePtr) +{ + TkPathGradientMaster *gradientPtr = NULL; + Tcl_Obj *resultObj = NULL; + + if (FindGradientMaster(interp, objv[0], tablePtr, &gradientPtr) != TCL_OK) { + return TCL_ERROR; + } + resultObj = Tk_GetOptionValue(interp, (char *)gradientPtr, + gradientPtr->optionTable, objv[1], tkwin); + if (resultObj == NULL) { + return TCL_ERROR; + } else { + Tcl_SetObjResult(interp, resultObj); + } + return TCL_OK; +} + +int +PathGradientConfigure(Tcl_Interp *interp, Tk_Window tkwin, int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *tablePtr) +{ + TkPathGradientMaster *gradientPtr = NULL; + int mask; + Tcl_Obj *resultObj = NULL; + + if (FindGradientMaster(interp, objv[0], tablePtr, &gradientPtr) != TCL_OK) { + return TCL_ERROR; + } + if (objc <= 2) { + resultObj = Tk_GetOptionInfo(interp, (char *)gradientPtr, + gradientPtr->optionTable, + (objc == 1) ? (Tcl_Obj *) NULL : objv[1], tkwin); + if (resultObj == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, resultObj); + } else { + if (Tk_SetOptions(interp, (char *)gradientPtr, gradientPtr->optionTable, + objc - 1, objv + 1, tkwin, NULL, &mask) != TCL_OK) { + return TCL_ERROR; + } + } + TkPathGradientChanged(gradientPtr, PATH_GRADIENT_FLAG_CONFIGURE); + return TCL_OK; +} + +/* GradientCreate: objv starts with 'type' */ + +int +PathGradientCreate(Tcl_Interp *interp, Tk_Window tkwin, int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *tablePtr, char *tokenName) +{ + char *typeStr; + int isNew; + int type; + int mask; + Tcl_HashEntry *hPtr; + TkPathGradientMaster *gradientPtr = NULL; + + typeStr = Tcl_GetString(objv[0]); + if (strcmp(typeStr, "linear") == 0) { + type = kPathGradientTypeLinear; + } else if (strcmp(typeStr, "radial") == 0) { + type = kPathGradientTypeRadial; + } else { + Tcl_Obj *resultObj; + resultObj = Tcl_NewStringObj("unrecognized type \"", -1); + Tcl_AppendStringsToObj(resultObj, typeStr, "\", must be \"linear\" or \"radial\"", + (char *) NULL); + Tcl_SetObjResult(interp, resultObj); + return TCL_ERROR; + } + gradientPtr = (TkPathGradientMaster *) ckalloc(sizeof(TkPathGradientMaster)); + memset(gradientPtr, '\0', sizeof(TkPathGradientMaster)); + + /* + * Create the option table for this class. If it has already + * been created, the cached pointer will be returned. + */ + if (type == kPathGradientTypeLinear) { + gradientPtr->optionTable = linearOptionTable; + } else { + gradientPtr->optionTable = radialOptionTable; + } + gradientPtr->type = type; + gradientPtr->name = Tk_GetUid(tokenName); + gradientPtr->matrixPtr = NULL; + gradientPtr->instancePtr = NULL; + + /* + * Set default transition vector in case not set. + */ + if (type == kPathGradientTypeLinear) { + PathRect *transitionPtr; + + transitionPtr = (PathRect *) ckalloc(sizeof(PathRect)); + gradientPtr->linearFill.transitionPtr = transitionPtr; + transitionPtr->x1 = 0.0; + transitionPtr->y1 = 0.0; + transitionPtr->x2 = 1.0; + transitionPtr->y2 = 0.0; + } else { + RadialTransition *tPtr; + + tPtr = (RadialTransition *) ckalloc(sizeof(RadialTransition)); + gradientPtr->radialFill.radialPtr = tPtr; + tPtr->centerX = 0.5; + tPtr->centerY = 0.5; + tPtr->radius = 0.5; + tPtr->focalX = 0.5; + tPtr->focalY = 0.5; + } + if (Tk_InitOptions(interp, (char *)gradientPtr, + gradientPtr->optionTable, tkwin) != TCL_OK) { + ckfree((char *)gradientPtr); + return TCL_ERROR; + } + if (Tk_SetOptions(interp, (char *)gradientPtr, gradientPtr->optionTable, + objc - 1, objv + 1, tkwin, NULL, &mask) != TCL_OK) { + Tk_FreeConfigOptions((char *)gradientPtr, gradientPtr->optionTable, NULL); + ckfree((char *)gradientPtr); + return TCL_ERROR; + } + hPtr = Tcl_CreateHashEntry(tablePtr, tokenName, &isNew); + Tcl_SetHashValue(hPtr, gradientPtr); + Tcl_SetObjResult(interp, Tcl_NewStringObj(tokenName, -1)); + return TCL_OK; +} + +int +PathGradientDelete(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_HashTable *tablePtr) +{ + TkPathGradientMaster *gradientPtr = NULL; + + if (FindGradientMaster(interp, obj, tablePtr, &gradientPtr) != TCL_OK) { + return TCL_ERROR; + } + TkPathGradientChanged(gradientPtr, PATH_GRADIENT_FLAG_DELETE); + Tcl_DeleteHashEntry(Tcl_FindHashEntry(tablePtr, Tcl_GetString(obj))); + PathGradientMasterFree(gradientPtr); + return TCL_OK; +} + +int +PathGradientInUse(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_HashTable *tablePtr) +{ + TkPathGradientMaster *gradientPtr = NULL; + + if (FindGradientMaster(interp, obj, tablePtr, &gradientPtr) != TCL_OK) { + return TCL_ERROR; + } + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), gradientPtr->instancePtr != NULL); + return TCL_OK; +} + +void +PathGradientNames(Tcl_Interp *interp, Tcl_HashTable *tablePtr) +{ + char *name; + Tcl_HashEntry *hPtr; + Tcl_Obj *listObj; + Tcl_HashSearch search; + + listObj = Tcl_NewListObj(0, NULL); + hPtr = Tcl_FirstHashEntry(tablePtr, &search); + while (hPtr != NULL) { + name = (char *) Tcl_GetHashKey(tablePtr, hPtr); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(name, -1)); + hPtr = Tcl_NextHashEntry(&search); + } + Tcl_SetObjResult(interp, listObj); +} + +int +PathGradientType(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_HashTable *tablePtr) +{ + TkPathGradientMaster *gradientPtr = NULL; + + if (FindGradientMaster(interp, obj, tablePtr, &gradientPtr) != TCL_OK) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, Tcl_NewStringObj( + (gradientPtr->type == kPathGradientTypeLinear) ? "linear" : "radial", -1)); + return TCL_OK; +} + +static CONST char *gradientCmds[] = { + "cget", "configure", "create", "delete", "inuse", "names", "type", + (char *) NULL +}; + +enum { + kPathGradientCmdCget = 0L, + kPathGradientCmdConfigure, + kPathGradientCmdCreate, + kPathGradientCmdDelete, + kPathGradientCmdInUse, + kPathGradientCmdNames, + kPathGradientCmdType +}; + +/* + *---------------------------------------------------------------------- + * + * GradientObjCmd -- + * + * Implements the tkp::gradient command using gGradientHashPtr. + * + * Results: + * Standard Tcl result + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +int +GradientObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) +{ + int index; + Tk_Window tkwin = Tk_MainWindow(interp); /* Should have been the canvas. */ + int result = TCL_OK; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "command ?arg arg...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], gradientCmds, "command", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + switch (index) { + + case kPathGradientCmdCget: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "option"); + return TCL_ERROR; + } + result = PathGradientCget(interp, tkwin, objc-2, objv+2, gGradientHashPtr); + break; + } + + case kPathGradientCmdConfigure: { + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name ?option? ?value option value...?"); + return TCL_ERROR; + } + result = PathGradientConfigure(interp, tkwin, objc-2, objv+2, gGradientHashPtr); + break; + } + + case kPathGradientCmdCreate: { + char str[255]; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "type ?option value...?"); + return TCL_ERROR; + } + sprintf(str, "%s%d", kGradientNameBase, gGradientNameUid++); + result = PathGradientCreate(interp, tkwin, objc-2, objv+2, gGradientHashPtr, str); + break; + } + + case kPathGradientCmdDelete: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + result = PathGradientDelete(interp, objv[2], gGradientHashPtr); + break; + } + + case kPathGradientCmdInUse: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + result = PathGradientInUse(interp, objv[2], gGradientHashPtr); + break; + } + + case kPathGradientCmdNames: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + PathGradientNames(interp, gGradientHashPtr); + break; + } + + case kPathGradientCmdType: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + result = PathGradientType(interp, objv[2], gGradientHashPtr); + break; + } + } + return result; +} + + +void +PathGradientMasterFree(TkPathGradientMaster *gradientPtr) +{ + Tk_FreeConfigOptions((char *) gradientPtr, gradientPtr->optionTable, NULL); + ckfree((char *) gradientPtr); +} + +/* + *---------------------------------------------------------------------- + * + * TkPathGetPathColorStatic -- + * + * Looks up named color or gradient in the global (static) gradient + * hash table. Used by the surface command to parse its -fill option. + * Else see TkPathGetPathColor. + * + * Results: + * Pointer to a TkPathColor struct or returns NULL on error + * and leaves an error message. + * + * Side effects: + * TkPathColor malloced if OK. + * + *---------------------------------------------------------------------- + */ + +TkPathColor * +TkPathGetPathColorStatic(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *nameObj) +{ + return TkPathGetPathColor(interp, tkwin, nameObj, gGradientHashPtr, NULL, NULL); +} + +/* + * These functions are called by users of gradients, typically items, + * that make instances of gradients from a gradient object (master). + */ + +/* + *---------------------------------------------------------------------- + * + * TkPathGetGradient -- + * + * This function is invoked by an item when it wants to use a particular + * gradient for a particular hash table. Compare Tk_GetImage. + * + * Results: + * The return value is a token for the gradient. If there is no gradient by the + * given name, then NULL is returned and an error message is left in the + * interp's result. + * + * Side effects: + * Tk records the fact that the item is using the gradient, and it will + * invoke changeProc later if the item needs redisplay. The caller must + * eventually invoke TkPathFreeGradient when it no longer needs the gradient. + * + *---------------------------------------------------------------------- + */ + +TkPathGradientInst * +TkPathGetGradient( + Tcl_Interp *interp, + CONST char *name, + Tcl_HashTable *tablePtr, + TkPathGradientChangedProc *changeProc, + ClientData clientData) +{ + Tcl_HashEntry *hPtr; + TkPathGradientInst *gradientPtr; + TkPathGradientMaster *masterPtr; + + hPtr = Tcl_FindHashEntry(tablePtr, name); + if (hPtr == NULL) { + if (interp != NULL) { + Tcl_Obj *resultObj; + resultObj = Tcl_NewStringObj("gradient \"", -1); + Tcl_AppendStringsToObj(resultObj, name, "\" doesn't exist", (char *) NULL); + Tcl_SetObjResult(interp, resultObj); + } + return NULL; + } + masterPtr = (TkPathGradientMaster *) Tcl_GetHashValue(hPtr); + gradientPtr = (TkPathGradientInst *) ckalloc(sizeof(TkPathGradientInst)); + gradientPtr->masterPtr = masterPtr; + gradientPtr->changeProc = changeProc; + gradientPtr->clientData = clientData; + gradientPtr->nextPtr = masterPtr->instancePtr; + masterPtr->instancePtr = gradientPtr; + return gradientPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkPathFreeGradient -- + * + * This function is invoked by an item when it no longer needs a gradient + * acquired by a previous call to TkPathGetGradient. For each call to + * TkPathGetGradient there must be exactly one call to TkPathFreeGradient. + * Compare Tk_FreeImage. + * + * Results: + * None. + * + * Side effects: + * The association between the gradient and the item is removed. + * + *---------------------------------------------------------------------- + */ + +void +TkPathFreeGradient( + TkPathGradientInst *gradientPtr) +{ + TkPathGradientMaster *masterPtr = gradientPtr->masterPtr; + TkPathGradientInst *walkPtr; + + walkPtr = masterPtr->instancePtr; + if (walkPtr == gradientPtr) { + masterPtr->instancePtr = gradientPtr->nextPtr; + } else { + while(walkPtr->nextPtr != gradientPtr) { + walkPtr = walkPtr->nextPtr; + } + walkPtr->nextPtr = gradientPtr->nextPtr; + } + ckfree((char *)gradientPtr); +} + +/* + *---------------------------------------------------------------------- + * + * TkPathGradientChanged -- + * + * This function is called by a gradient manager whenever something has + * happened that requires the gradient to be redrawn or it has been deleted. + * Compare Tk_ImageChanged, + * + * Results: + * None. + * + * Side effects: + * Any items that display the gradient are notified so that they can + * redisplay themselves as appropriate. + * + *---------------------------------------------------------------------- + */ + +void +TkPathGradientChanged(TkPathGradientMaster *masterPtr, int flags) +{ + TkPathGradientInst *walkPtr, *nextPtr; + + if (flags) { + /* + * NB: We may implicitly call TkPathFreeGradient if being deleted! + * Therefore cache the nextPtr before invoking changeProc. + */ + for (walkPtr = masterPtr->instancePtr; walkPtr != NULL; ) { + nextPtr = walkPtr->nextPtr; + if (walkPtr->changeProc != NULL) { + (*walkPtr->changeProc)(walkPtr->clientData, flags); + } + walkPtr = nextPtr; + } + } +} diff --git a/pd/tkpath/generic/tkPathStyle.c b/pd/tkpath/generic/tkPathStyle.c new file mode 100644 index 0000000000000000000000000000000000000000..ef89e7bee4c9705d5ad4fb33d857074e2b9b4e1c --- /dev/null +++ b/pd/tkpath/generic/tkPathStyle.c @@ -0,0 +1,1250 @@ +/* + * tkPathStyle.c -- + * + * This file implements style objects used when drawing paths. + * See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * Note: It would be best to have this in the canvas widget as a special + * object, but I see no way of doing this without touching + * the canvas code. + * + * Note: When a style object is modified or destroyed the corresponding + * items are not notified. They will only notice any change when + * they need to redisplay. + * + * $Id: tkPathStyle.c,v 1.32 2012/07/04 19:43:18 petasis Exp $ + */ + +#include "tkIntPath.h" +#include "tkPathStyle.h" + +extern Tcl_HashTable *gGradientHashPtr; + +static Tcl_HashTable *gStyleHashPtr; +static Tk_OptionTable styleOptionTable; +static int gStyleNameUid = 0; +static char *kStyleNameBase = "tkp::style"; + +/* + * Declarationd for functions local to this file. + */ + +static int StyleObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]); + +/* + * Custom option processing code. + */ + +/* + * The -matrix custom option. + */ + +int MatrixSetOption( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; /* Points to location in record where + * internal representation of value should + * be stored, or NULL. */ + char *list; + int length; + Tcl_Obj *valuePtr; + TMatrix *newPtr; + + valuePtr = *value; + if (internalOffset >= 0) { + internalPtr = recordPtr + internalOffset; + } else { + internalPtr = NULL; + } + if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + } + if (internalPtr != NULL) { + if (valuePtr != NULL) { + list = Tcl_GetStringFromObj(valuePtr, &length); + newPtr = (TMatrix *) ckalloc(sizeof(TMatrix)); + if (PathGetTMatrix(interp, list, newPtr) != TCL_OK) { + ckfree((char *) newPtr); + return TCL_ERROR; + } + } else { + newPtr = NULL; + } + *((TMatrix **) oldInternalPtr) = *((TMatrix **) internalPtr); + *((TMatrix **) internalPtr) = newPtr; + } + return TCL_OK; +} + +Tcl_Obj * +MatrixGetOption( + ClientData clientData, + Tk_Window tkwin, + char *recordPtr, /* Pointer to widget record. */ + int internalOffset) /* Offset within *recordPtr containing the + * value. */ +{ + char *internalPtr; + TMatrix *matrixPtr; + Tcl_Obj *listObj; + + /* @@@ An alternative to this could be to have an objOffset in option table. */ + internalPtr = recordPtr + internalOffset; + matrixPtr = *((TMatrix **) internalPtr); + PathGetTclObjFromTMatrix(NULL, matrixPtr, &listObj); + return listObj; +} + +void +MatrixRestoreOption( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(TMatrix **)internalPtr = *(TMatrix **)oldInternalPtr; +} + +void +MatrixFreeOption( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr) /* Pointer to storage for value. */ +{ + if (*((char **) internalPtr) != NULL) { + ckfree(*((char **) internalPtr)); + *((char **) internalPtr) = NULL; + } +} + +/* Return NULL on error and leave error message */ + +Tk_PathDash * +TkPathDashNew(Tcl_Interp *interp, Tcl_Obj *dashObjPtr) +{ + Tk_PathDash *dashPtr; + int objc, i; + double value; + Tcl_Obj **objv; + + dashPtr = (Tk_PathDash *) ckalloc(sizeof(Tk_PathDash)); + dashPtr->number = 0; + dashPtr->array = NULL; + if (Tcl_ListObjGetElements(interp, dashObjPtr, &objc, (Tcl_Obj ***) &objv) != TCL_OK) { + goto error; + } + dashPtr->number = objc; + dashPtr->array = (float *) ckalloc(objc * sizeof(float)); + for (i = 0; i < objc; i++) { + if (Tcl_GetDoubleFromObj(interp, objv[i], &value) != TCL_OK) { + goto error; + } + dashPtr->array[i] = (float) value; + } + return dashPtr; + +error: + TkPathDashFree(dashPtr); + return NULL; +} + +void +TkPathDashFree(Tk_PathDash *dashPtr) +{ + if (dashPtr->array) { + ckfree((char *) dashPtr->array); + } + ckfree((char *) dashPtr); +} + +/* + * The -strokedasharray custom option. + */ + +/* + *-------------------------------------------------------------- + * + * Tk_PathDashOptionSetProc, Tk_PathDashOptionGetProc, + * Tk_PathDashOptionRestoreProc, Tk_PathDashOptionRestoreProc -- + * + * These functions are invoked during option processing to handle + * "-strokedasharray" option for canvas objects. + * + * Results: + * According to the Tk_ObjCustomOption struct. + * + * Side effects: + * Memory allocated or freed. + * + *-------------------------------------------------------------- + */ + +int Tk_PathDashOptionSetProc( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; /* Points to location in record where + * internal representation of value should + * be stored, or NULL. */ + Tcl_Obj *valuePtr; + Tk_PathDash *newPtr = NULL; + + valuePtr = *value; + if (internalOffset >= 0) { + internalPtr = recordPtr + internalOffset; + } else { + internalPtr = NULL; + } + if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + } + if (internalPtr != NULL) { + if (valuePtr != NULL) { + newPtr = TkPathDashNew(interp, valuePtr); + if (newPtr == NULL) { + return TCL_ERROR; + } + } + *((Tk_PathDash **) oldInternalPtr) = *((Tk_PathDash **) internalPtr); + *((Tk_PathDash **) internalPtr) = newPtr; + } + return TCL_OK; +} + +Tcl_Obj * +Tk_PathDashOptionGetProc( + ClientData clientData, + Tk_Window tkwin, + char *recordPtr, /* Pointer to widget record. */ + int internalOffset) /* Offset within *recordPtr containing the + * value. */ +{ + Tk_PathDash *dashPtr = (Tk_PathDash *) (recordPtr + internalOffset); + Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); + int i; + + for (i = 0; i < dashPtr->number; i++) { + Tcl_ListObjAppendElement(NULL, listObj, Tcl_NewDoubleObj(dashPtr->array[i])); + } + return listObj; +} + +void +Tk_PathDashOptionRestoreProc( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(Tk_PathDash **)internalPtr = *(Tk_PathDash **)oldInternalPtr; +} + +void +Tk_PathDashOptionFreeProc( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr) /* Pointer to storage for value. */ +{ + if (*((char **) internalPtr) != NULL) { + TkPathDashFree(*(Tk_PathDash **) internalPtr); + *((char **) internalPtr) = NULL; + } +} + +/* + * Combined XColor and gradient name in a TkPathColor record. + */ + +int PathColorSetOption( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; /* Points to location in record where + * internal representation of value should + * be stored, or NULL. */ + Tcl_Obj *valuePtr; + TkPathColor *newPtr = NULL; + + valuePtr = *value; + if (internalOffset >= 0) { + internalPtr = recordPtr + internalOffset; + } else { + internalPtr = NULL; + } + if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + } + if (internalPtr != NULL) { + if (valuePtr != NULL) { + newPtr = TkPathNewPathColor(interp, tkwin, valuePtr); + if (newPtr == NULL) { + return TCL_ERROR; + } + } else { + newPtr = NULL; + } + *((TkPathColor **) oldInternalPtr) = *((TkPathColor **) internalPtr); + *((TkPathColor **) internalPtr) = newPtr; + } + return TCL_OK; +} + +Tcl_Obj * +PathColorGetOption( + ClientData clientData, + Tk_Window tkwin, + char *recordPtr, /* Pointer to widget record. */ + int internalOffset) /* Offset within *recordPtr containing the + * value. */ +{ + char *internalPtr; + Tcl_Obj *objPtr = NULL; + TkPathColor *pathColor = NULL; + + internalPtr = recordPtr + internalOffset; + pathColor = *((TkPathColor **) internalPtr); + if (pathColor != NULL) { + if (pathColor->color) { + objPtr = Tcl_NewStringObj(Tk_NameOfColor(pathColor->color), -1); + } else if (pathColor->gradientInstPtr) { + objPtr = Tcl_NewStringObj(pathColor->gradientInstPtr->masterPtr->name, -1); + } + } + return objPtr; +} + +void +PathColorRestoreOption( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(TkPathColor **)internalPtr = *(TkPathColor **)oldInternalPtr; +} + +void +PathColorFreeOption( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr) /* Pointer to storage for value. */ +{ + if (*((char **) internalPtr) != NULL) { + TkPathFreePathColor(*(TkPathColor **) internalPtr); + *((char **) internalPtr) = NULL; + } +} + +PATH_STYLE_CUSTOM_OPTION_RECORDS +PATH_OPTION_STRING_TABLES_FILL +PATH_OPTION_STRING_TABLES_STROKE + +// @@@ TODO: BAD I had to duplicate this record here and in tkPathStyle.h. +// Else I get problems with Tk_Offset and records. + +static Tk_OptionSpec styleOptionSpecs[] = { + {TK_OPTION_STRING, "-fill", NULL, NULL, + "", Tk_Offset(Tk_PathStyle, fillObj), -1, + TK_OPTION_NULL_OK, 0, PATH_STYLE_OPTION_FILL}, + {TK_OPTION_DOUBLE, "-fillopacity", NULL, NULL, + "1.0", -1, Tk_Offset(Tk_PathStyle, fillOpacity), 0, 0, + PATH_STYLE_OPTION_FILL_OPACITY}, + {TK_OPTION_STRING_TABLE, "-fillrule", NULL, NULL, + "nonzero", -1, Tk_Offset(Tk_PathStyle, fillRule), + 0, (ClientData) fillRuleST, PATH_STYLE_OPTION_FILL_RULE}, + {TK_OPTION_CUSTOM, "-matrix", NULL, NULL, + NULL, -1, Tk_Offset(Tk_PathStyle, matrixPtr), + TK_OPTION_NULL_OK, (ClientData) &matrixCO, PATH_STYLE_OPTION_MATRIX}, + {TK_OPTION_COLOR, "-stroke", NULL, NULL, + "black", -1, Tk_Offset(Tk_PathStyle, strokeColor), TK_OPTION_NULL_OK, 0, + PATH_STYLE_OPTION_STROKE}, + {TK_OPTION_CUSTOM, "-strokedasharray", NULL, NULL, + NULL, -1, Tk_Offset(Tk_PathStyle, dashPtr), + TK_OPTION_NULL_OK, (ClientData) &dashCO, PATH_STYLE_OPTION_STROKE_DASHARRAY}, + {TK_OPTION_STRING_TABLE, "-strokelinecap", NULL, NULL, + "butt", -1, Tk_Offset(Tk_PathStyle, capStyle), + 0, (ClientData) lineCapST, PATH_STYLE_OPTION_STROKE_LINECAP}, + {TK_OPTION_STRING_TABLE, "-strokelinejoin", NULL, NULL, + "round", -1, Tk_Offset(Tk_PathStyle, joinStyle), + 0, (ClientData) lineJoinST, PATH_STYLE_OPTION_STROKE_LINEJOIN}, + {TK_OPTION_DOUBLE, "-strokemiterlimit", NULL, NULL, + "4.0", -1, Tk_Offset(Tk_PathStyle, miterLimit), 0, 0, + PATH_STYLE_OPTION_STROKE_MITERLIMIT}, + {TK_OPTION_DOUBLE, "-strokeopacity", NULL, NULL, + "1.0", -1, Tk_Offset(Tk_PathStyle, strokeOpacity), 0, 0, + PATH_STYLE_OPTION_STROKE_OPACITY}, + {TK_OPTION_DOUBLE, "-strokewidth", NULL, NULL, + "1.0", -1, Tk_Offset(Tk_PathStyle, strokeWidth), 0, 0, + PATH_STYLE_OPTION_STROKE_WIDTH}, + + /* @@@ TODO: When this comes into canvas code we should add a -tags option here??? */ + + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +void +PathStyleInit(Tcl_Interp *interp) +{ + gStyleHashPtr = (Tcl_HashTable *) ckalloc( sizeof(Tcl_HashTable) ); + Tcl_InitHashTable(gStyleHashPtr, TCL_STRING_KEYS); + + /* + * The option table must only be made once and not for each instance. + */ + styleOptionTable = Tk_CreateOptionTable(interp, styleOptionSpecs); + + Tcl_CreateObjCommand(interp, "tkp::style", + StyleObjCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); +} + +/* + * StyleGradientProc: callback to style when gradient changes. + */ + +static void +StyleGradientProc(ClientData clientData, int flags) +{ + Tk_PathStyle *stylePtr = (Tk_PathStyle *)clientData; + + if (flags) { + if (flags & PATH_GRADIENT_FLAG_DELETE) { + TkPathFreePathColor(stylePtr->fill); + stylePtr->fill = NULL; + Tcl_DecrRefCount(stylePtr->fillObj); + stylePtr->fillObj = NULL; + } + TkPathStyleChanged(stylePtr, flags); + } +} + +static void +PathStyleFree(Tk_PathStyle *stylePtr, Tk_Window tkwin) +{ + if (stylePtr->fill != NULL) { + TkPathFreePathColor(stylePtr->fill); + } + Tk_FreeConfigOptions((char *) stylePtr, stylePtr->optionTable, tkwin); + ckfree((char *) stylePtr); +} + +static int +FindPathStyle(Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_HashTable *tablePtr, Tk_PathStyle **s) +{ + Tcl_HashEntry *hPtr; + char *name = Tcl_GetString(nameObj); + *s = NULL; + hPtr = Tcl_FindHashEntry(tablePtr, name); + if (hPtr == NULL) { + Tcl_Obj *resultObj; + resultObj = Tcl_NewStringObj("style \"", -1); + Tcl_AppendStringsToObj(resultObj, name, "\" doesn't exist", (char *) NULL); + Tcl_SetObjResult(interp, resultObj); + return TCL_ERROR; + } + *s = (Tk_PathStyle *) Tcl_GetHashValue(hPtr); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * PathStyleCget, Configure, Create, Delete, InUse, Names -- + * + * These functions implement style object commands in a generic way. + * The Tcl_HashTable defines the style namespace. + * + * Results: + * Varies: typically a standard tcl result or void. + * + * Side effects: + * Varies. + * + *-------------------------------------------------------------- + */ + +int +PathStyleCget(Tcl_Interp *interp, Tk_Window tkwin, int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *tablePtr) +{ + Tk_PathStyle *stylePtr = NULL; + Tcl_Obj *resultObj = NULL; + + if (FindPathStyle(interp, objv[0], tablePtr, &stylePtr) != TCL_OK) { + return TCL_ERROR; + } + resultObj = Tk_GetOptionValue(interp, (char *)stylePtr, + stylePtr->optionTable, objv[1], tkwin); + if (resultObj == NULL) { + return TCL_ERROR; + } else { + Tcl_SetObjResult(interp, resultObj); + } + return TCL_OK; +} + +int +PathStyleConfigure(Tcl_Interp *interp, Tk_Window tkwin, int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *styleTablePtr, Tcl_HashTable *gradTablePtr) +{ + int mask; + Tk_PathStyle *stylePtr = NULL; + Tcl_Obj *resultObj = NULL; + + if (FindPathStyle(interp, objv[0], styleTablePtr, &stylePtr) != TCL_OK) { + return TCL_ERROR; + } + if (objc <= 2) { + resultObj = Tk_GetOptionInfo(interp, (char *)stylePtr, + stylePtr->optionTable, + (objc == 1) ? (Tcl_Obj *) NULL : objv[1], tkwin); + if (resultObj == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, resultObj); + } else { + TkPathColor *fillPtr = NULL; + + // @@@ TODO: loop error to recover using savedOptions! + if (Tk_SetOptions(interp, (char *)stylePtr, stylePtr->optionTable, + objc - 1, objv + 1, tkwin, NULL, &mask) != TCL_OK) { + return TCL_ERROR; + } + if (stylePtr->fillObj != NULL) { + fillPtr = TkPathGetPathColor(interp, tkwin, stylePtr->fillObj, + gradTablePtr, StyleGradientProc, (ClientData) stylePtr); + if (fillPtr == NULL) { + return TCL_ERROR; + } + } else { + fillPtr = NULL; + } + /* Free any old and store the new. */ + if (stylePtr->fill != NULL) { + TkPathFreePathColor(stylePtr->fill); + } + stylePtr->fill = fillPtr; + /* + * Let mask be the cumalative options set. + */ + stylePtr->mask |= mask; + } + TkPathStyleChanged(stylePtr, PATH_STYLE_FLAG_CONFIGURE); + return TCL_OK; +} + +int +PathStyleCreate(Tcl_Interp *interp, Tk_Window tkwin, int objc, Tcl_Obj * CONST objv[], + Tcl_HashTable *styleTablePtr, Tcl_HashTable *gradTablePtr, char *tokenName) +{ + int isNew; + int mask; + Tcl_HashEntry *hPtr; + Tk_PathStyle *stylePtr = NULL; + TkPathColor *fillPtr = NULL; + + stylePtr = (Tk_PathStyle *) ckalloc(sizeof(Tk_PathStyle)); + memset(stylePtr, '\0', sizeof(Tk_PathStyle)); + + /* Fill in defaults. */ + TkPathInitStyle(stylePtr); + + /* + * Create the option table for this class. If it has already + * been created, the cached pointer will be returned. + */ + stylePtr->optionTable = styleOptionTable; + stylePtr->name = Tk_GetUid(tokenName); + + if (Tk_InitOptions(interp, (char *)stylePtr, + stylePtr->optionTable, tkwin) != TCL_OK) { + ckfree((char *)stylePtr); + return TCL_ERROR; + } + if (Tk_SetOptions(interp, (char *)stylePtr, stylePtr->optionTable, + objc, objv, tkwin, NULL, &mask) != TCL_OK) { + Tk_FreeConfigOptions((char *)stylePtr, stylePtr->optionTable, NULL); + ckfree((char *)stylePtr); + return TCL_ERROR; + } + if (stylePtr->fillObj != NULL) { + fillPtr = TkPathGetPathColor(interp, tkwin, stylePtr->fillObj, + gradTablePtr, StyleGradientProc, (ClientData) stylePtr); + if (fillPtr == NULL) { + Tk_FreeConfigOptions((char *)stylePtr, stylePtr->optionTable, NULL); + ckfree((char *)stylePtr); + return TCL_ERROR; + } + } else { + fillPtr = NULL; + } + stylePtr->fill = fillPtr; + + /* + * Let mask be the cumalative options set. + */ + stylePtr->mask |= mask; + hPtr = Tcl_CreateHashEntry(styleTablePtr, tokenName, &isNew); + Tcl_SetHashValue(hPtr, stylePtr); + Tcl_SetObjResult(interp, Tcl_NewStringObj(tokenName, -1)); + return TCL_OK; +} + +int +PathStyleDelete(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_HashTable *tablePtr, Tk_Window tkwin) +{ + Tk_PathStyle *stylePtr = NULL; + + if (FindPathStyle(interp, obj, tablePtr, &stylePtr) != TCL_OK) { + return TCL_ERROR; + } + TkPathStyleChanged(stylePtr, PATH_STYLE_FLAG_DELETE); + Tcl_DeleteHashEntry(Tcl_FindHashEntry(tablePtr, Tcl_GetString(obj))); + PathStyleFree(stylePtr, tkwin); + return TCL_OK; +} + +int +PathStyleInUse(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_HashTable *tablePtr) +{ + Tk_PathStyle *stylePtr = NULL; + + if (FindPathStyle(interp, obj, tablePtr, &stylePtr) != TCL_OK) { + return TCL_ERROR; + } + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), stylePtr->instancePtr != NULL); + return TCL_OK; +} + +void +PathStyleNames(Tcl_Interp *interp, Tcl_HashTable *tablePtr) +{ + char *name; + Tcl_HashEntry *hPtr; + Tcl_Obj *listObj; + Tcl_HashSearch search; + + listObj = Tcl_NewListObj(0, NULL); + hPtr = Tcl_FirstHashEntry(tablePtr, &search); + while (hPtr != NULL) { + name = (char *) Tcl_GetHashKey(tablePtr, hPtr); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(name, -1)); + hPtr = Tcl_NextHashEntry(&search); + } + Tcl_SetObjResult(interp, listObj); +} + +/* + *---------------------------------------------------------------------- + * + * TkPathConfigStyle -- + * + * Parses a list of Tcl objects to an already allocated Tk_PathStyle. + * + * Results: + * Standard Tcl result + * + * Side effects: + * Options allocated. Use Tk_FreeConfigOptions when finished. + * + *---------------------------------------------------------------------- + */ + +int +TkPathConfigStyle(Tcl_Interp *interp, Tk_PathStyle *stylePtr, int objc, Tcl_Obj * CONST objv[]) +{ + Tk_Window tkwin = Tk_MainWindow(interp); + stylePtr->optionTable = styleOptionTable; + if (Tk_InitOptions(interp, (char *)stylePtr, styleOptionTable, tkwin) != TCL_OK) { + return TCL_ERROR; + } + if (Tk_SetOptions(interp, (char *)stylePtr, styleOptionTable, + objc, objv, tkwin, NULL, NULL) != TCL_OK) { + Tk_FreeConfigOptions((char *)stylePtr, styleOptionTable, NULL); + return TCL_ERROR; + } + return TCL_OK; +} + +static CONST char *styleCmds[] = { + "cget", "configure", "create", "delete", "inuse", "names", + (char *) NULL +}; + +enum { + kPathStyleCmdCget = 0L, + kPathStyleCmdConfigure, + kPathStyleCmdCreate, + kPathStyleCmdDelete, + kPathStyleCmdInUse, + kPathStyleCmdNames +}; + +/* + *---------------------------------------------------------------------- + * + * StyleObjCmd -- + * + * This implements the standalone tkp::style command. + * + * Results: + * Standard Tcl result + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +static int +StyleObjCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj * CONST objv[] ) +{ + int index; + int result = TCL_OK; + Tk_Window tkwin = Tk_MainWindow(interp); + + /* + * objv[1] is the subcommand: cget | configure | create | delete | names + */ + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "command ?arg arg...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], styleCmds, "command", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + switch (index) { + + case kPathStyleCmdCget: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "name option"); + return TCL_ERROR; + } + result = PathStyleCget(interp, tkwin, objc-2, objv+2, gStyleHashPtr); + break; + } + + case kPathStyleCmdConfigure: { + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name ?option? ?value option value...?"); + return TCL_ERROR; + } + result = PathStyleConfigure(interp, tkwin, objc-2, objv+2, + gStyleHashPtr, gGradientHashPtr); + break; + } + + case kPathStyleCmdCreate: { + char str[255]; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "?option value...?"); + return TCL_ERROR; + } + sprintf(str, "%s%d", kStyleNameBase, gStyleNameUid++); + result = PathStyleCreate(interp, tkwin, objc-2, objv+2, + gStyleHashPtr, gGradientHashPtr, str); + break; + } + + case kPathStyleCmdDelete: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + result = PathStyleDelete(interp, objv[2], gStyleHashPtr, tkwin); + break; + } + + case kPathStyleCmdInUse: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + result = PathStyleInUse(interp, objv[2], gStyleHashPtr); + break; + } + + case kPathStyleCmdNames: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + PathStyleNames(interp, gStyleHashPtr); + break; + } + } + return result; +} + +void +PathStylesFree(Tk_Window tkwin, Tcl_HashTable *hashTablePtr) +{ + Tcl_HashEntry *hPtr; + Tcl_HashSearch search; + char *recordPtr; + + hPtr = Tcl_FirstHashEntry(hashTablePtr, &search); + while (hPtr != NULL) { + recordPtr = (char *) Tcl_GetHashValue(hPtr); + Tcl_DeleteHashEntry(hPtr); + PathStyleFree((Tk_PathStyle *)recordPtr, tkwin); + hPtr = Tcl_NextHashEntry(&search); + } +} + +#if 0 +static void +CopyXColor(Tk_Window tkwin, XColor **dstPtrPtr, XColor *srcPtr) +{ + XColor *dstPtr; + XColor *colorPtr = NULL; + + dstPtr = *dstPtrPtr; + if ((dstPtr == NULL) && (srcPtr == NULL)) { + /* empty */ + } else if (dstPtr == NULL) { + colorPtr = Tk_GetColorByValue(tkwin, srcPtr); + } else { + Tk_FreeColor(dstPtr); + colorPtr = Tk_GetColorByValue(tkwin, srcPtr); + } + *dstPtrPtr = colorPtr; +} +#endif + +#if 0 +static void +CopyTMatrix(TMatrix **dstPtrPtr, TMatrix *srcPtr) +{ + TMatrix *dstPtr; + TMatrix *matrixPtr = NULL; + + dstPtr = *dstPtrPtr; + if ((dstPtr == NULL) && (srcPtr == NULL)) { + /* empty */ + } else if (dstPtr == NULL) { + matrixPtr = (TMatrix *) ckalloc(sizeof(TMatrix)); + *matrixPtr = *srcPtr; + } else { + *matrixPtr = *srcPtr; + } + *dstPtrPtr = matrixPtr; +} +#endif + +#if 0 +static void +CopyTkDash(Tk_PathDash *dstPtr, Tk_PathDash *srcPtr) +{ + int i; + float *dptr, *sptr; + + if (dstPtr != NULL) { + TkPathDashFree(dstPtr); + } + dstPtr->number = srcPtr->number; + dptr = dstPtr->array; + sptr = srcPtr->array; + for (i = 0; i < srcPtr->number; i++) { + *dptr++ = *sptr++; + } +} +#endif + +#if 0 +static void +CopyPathColor(Tk_Window tkwin, TkPathColor **dstPtrPtr, TkPathColor *srcPtr) +{ + TkPathColor *dstPtr; + TkPathColor *pathColorPtr = NULL; + + dstPtr = *dstPtrPtr; + if ((dstPtr == NULL) && (srcPtr == NULL)) { + /* empty */ + } else { + if (dstPtr != NULL) { + TkPathFreePathColor(dstPtr); + } + pathColorPtr = (TkPathColor *) ckalloc(sizeof(TkPathColor)); + pathColorPtr->color = NULL; + pathColorPtr->gradientName = NULL; + if (srcPtr->color != NULL) { + pathColorPtr->color = Tk_GetColorByValue(tkwin, srcPtr->color); + + // @@@ TODO + } else if (srcPtr->gradientName != NULL) { + pathColorPtr->gradientName = (char *) ckalloc(strlen(srcPtr->gradientName) + 1); + strcpy(pathColorPtr->gradientName, srcPtr->gradientName); + } + } + *dstPtrPtr = pathColorPtr; +} +#endif + +/* + *-------------------------------------------------------------- + * + * TkPathStyleMergeStyleStatic -- + * + * Looks up the named style in styleObj in the globally defined + * style hash table. + * Overwrites values in dstStyle if set in styleObj. + * This is indicated by the mask of the srcStyle. + * This just copy pointers. For short lived style records only! + * + * Results: + * Standard Tcl result. + * + * Side effects: + * Changes *values* in dstStyle. Leaves any error string in interp. + * + *-------------------------------------------------------------- + */ + +int +TkPathStyleMergeStyleStatic(Tcl_Interp* interp, Tcl_Obj *styleObj, Tk_PathStyle *dstStyle, long flags) +{ + Tcl_HashEntry *hPtr; + Tk_PathStyle *srcStyle; + + if (styleObj == NULL) { + return TCL_OK; + } + hPtr = Tcl_FindHashEntry(gStyleHashPtr, Tcl_GetString(styleObj)); + if (hPtr == NULL) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "the global style \"", Tcl_GetString(styleObj), + "\" does not exist", NULL); + return TCL_ERROR; + } + srcStyle = (Tk_PathStyle *) Tcl_GetHashValue(hPtr); + TkPathStyleMergeStyles(srcStyle, dstStyle, flags); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TkPathStyleMergeStyles -- + * + * Overwrites values in dstStyle if set in srcStyle. + * This is indicated by the mask of the srcStyle. + * This just copy pointers. For short lived style records only! + * Be sure to NEVER free any pointers in this style since we + * don't own theme! + * + * Results: + * None. + * + * Side effects: + * Changes *values* in dstStyle. + * + *-------------------------------------------------------------- + */ + +void +TkPathStyleMergeStyles( + Tk_PathStyle *srcStyle, + Tk_PathStyle *dstStyle, + long flags) +{ + int mask = srcStyle->mask; + + if (mask == 0) { + return; + } + + /* + * Go through all options set in srcStylePtr and merge + * these into dstStylePtr. + */ + if (!(flags & kPathMergeStyleNotFill)) { + if (mask & PATH_STYLE_OPTION_FILL) { + dstStyle->fill = srcStyle->fill; + } + if (mask & PATH_STYLE_OPTION_FILL_OFFSET) { + /* @@@ TODO */ + } + if (mask & PATH_STYLE_OPTION_FILL_OPACITY) { + dstStyle->fillOpacity = srcStyle->fillOpacity; + } + if (mask & PATH_STYLE_OPTION_FILL_RULE) { + dstStyle->fillRule = srcStyle->fillRule; + } + if (mask & PATH_STYLE_OPTION_FILL_STIPPLE) { + /* @@@ TODO */ + } + } + if (mask & PATH_STYLE_OPTION_MATRIX) { + dstStyle->matrixPtr = srcStyle->matrixPtr; + } + if (!(flags & kPathMergeStyleNotStroke)) { + if (mask & PATH_STYLE_OPTION_STROKE) { + dstStyle->strokeColor = srcStyle->strokeColor; + } + if (mask & PATH_STYLE_OPTION_STROKE_DASHARRAY) { + dstStyle->dashPtr = srcStyle->dashPtr; + } + if (mask & PATH_STYLE_OPTION_STROKE_LINECAP) { + dstStyle->capStyle = srcStyle->capStyle; + } + if (mask & PATH_STYLE_OPTION_STROKE_LINEJOIN) { + dstStyle->joinStyle = srcStyle->joinStyle; + } + if (mask & PATH_STYLE_OPTION_STROKE_MITERLIMIT) { + dstStyle->miterLimit = srcStyle->miterLimit; + } + if (mask & PATH_STYLE_OPTION_STROKE_OFFSET) { + /* @@@ TODO */ + } + if (mask & PATH_STYLE_OPTION_STROKE_OPACITY) { + dstStyle->strokeOpacity = srcStyle->strokeOpacity; + } + if (mask & PATH_STYLE_OPTION_STROKE_STIPPLE) { + /* @@@ TODO */ + } + if (mask & PATH_STYLE_OPTION_STROKE_WIDTH) { + dstStyle->strokeWidth = srcStyle->strokeWidth; + } + } + dstStyle->mask |= mask; +} + +/* + *-------------------------------------------------------------- + * + * TkPathInitStyle + * + * This procedure initializes the Tk_PathStyle structure + * with default values. + * + * Results: + * None + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +void +TkPathInitStyle(Tk_PathStyle *style) +{ + memset(style, '\0', sizeof(Tk_PathStyle)); + + style->mask = 0; + style->strokeColor = NULL; + style->strokeWidth = 1.0; + style->strokeOpacity = 1.0; + style->offset = 0; + style->dashPtr = NULL; + style->capStyle = CapButt; + style->joinStyle = JoinRound; + + style->fillOpacity = 1.0; + style->fillRule = WindingRule; + style->fillObj = NULL; + style->fill = NULL; + style->matrixPtr = NULL; + style->instancePtr = NULL; +} + +/* + *-------------------------------------------------------------- + * + * TkPathDeleteStyle + * + * This procedure frees all memory in the Tk_PathStyle structure + * that is not freed by Tk_FreeConfigOptions. + * + * Results: + * None + * + * Side effects: + * Memory freed + * + *-------------------------------------------------------------- + */ + +void +TkPathDeleteStyle(Tk_PathStyle *style) +{ + if (style->fill != NULL) { + TkPathFreePathColor(style->fill); + } +} + + +/* + * These functions are called by users of styles, typically items, + * that make instances of styles from a style object (master). + */ + +/* + *---------------------------------------------------------------------- + * + * TkPathGetStyle -- + * + * This function is invoked by an item when it wants to use a particular + * style for a particular hash table. Compare Tk_GetImage. + * + * Results: + * The return value is a token for the style. If there is no style by the + * given name, then NULL is returned and an error message is left in the + * interp's result. + * + * Side effects: + * Tk records the fact that the item is using the style, and it will + * invoke changeProc later if the item needs redisplay. The caller must + * eventually invoke TkPathFreeStyle when it no longer needs the style. + * + *---------------------------------------------------------------------- + */ + +TkPathStyleInst * +TkPathGetStyle( + Tcl_Interp *interp, + CONST char *name, + Tcl_HashTable *tablePtr, + TkPathGradientChangedProc *changeProc, + ClientData clientData) +{ + Tcl_HashEntry *hPtr; + TkPathStyleInst *stylePtr; + Tk_PathStyle *masterPtr; + + hPtr = Tcl_FindHashEntry(tablePtr, name); + if (hPtr == NULL) { + if (interp != NULL) { + Tcl_Obj *resultObj; + resultObj = Tcl_NewStringObj("style \"", -1); + Tcl_AppendStringsToObj(resultObj, name, "\" doesn't exist", (char *) NULL); + Tcl_SetObjResult(interp, resultObj); + } + return NULL; + } + masterPtr = (Tk_PathStyle *) Tcl_GetHashValue(hPtr); + stylePtr = (TkPathStyleInst *) ckalloc(sizeof(TkPathStyleInst)); + stylePtr->masterPtr = masterPtr; + stylePtr->changeProc = changeProc; + stylePtr->clientData = clientData; + stylePtr->nextPtr = masterPtr->instancePtr; + masterPtr->instancePtr = stylePtr; + return stylePtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkPathFreeStyle -- + * + * This function is invoked by an item when it no longer needs a gradient + * acquired by a previous call to TkPathGetGradient. For each call to + * TkPathGetGradient there must be exactly one call to TkPathFreeGradient. + * Compare Tk_FreeImage. + * + * Results: + * None. + * + * Side effects: + * The association between the gradient and the item is removed. + * + *---------------------------------------------------------------------- + */ + +void +TkPathFreeStyle( + TkPathStyleInst *stylePtr) +{ + Tk_PathStyle *masterPtr = stylePtr->masterPtr; + TkPathStyleInst *walkPtr; + + walkPtr = masterPtr->instancePtr; + if (walkPtr == stylePtr) { + masterPtr->instancePtr = stylePtr->nextPtr; + } else { + while(walkPtr->nextPtr != stylePtr) { + walkPtr = walkPtr->nextPtr; + } + walkPtr->nextPtr = stylePtr->nextPtr; + } + ckfree((char *)stylePtr); +} + +/* + *---------------------------------------------------------------------- + * + * TkPathStyleChanged -- + * + * This function is called by a style manager whenever something has + * happened that requires the style to be redrawn or it has been deleted. + * Compare Tk_ImageChanged, + * + * Results: + * None. + * + * Side effects: + * Any items that display the style are notified so that they can + * redisplay themselves as appropriate. + * + *---------------------------------------------------------------------- + */ + +void +TkPathStyleChanged(Tk_PathStyle *masterPtr, int flags) +{ + TkPathStyleInst *walkPtr, *nextPtr; + + if (flags) { + /* + * NB: We may implicitly call TkPathFreeGradient if being deleted! + * Therefore cache the nextPtr before invoking changeProc. + */ + for (walkPtr = masterPtr->instancePtr; walkPtr != NULL; ) { + nextPtr = walkPtr->nextPtr; + if (walkPtr->changeProc != NULL) { + (*walkPtr->changeProc)(walkPtr->clientData, flags); + } + walkPtr = nextPtr; + } + } +} + +/*-------------------------------------------------------------------*/ + diff --git a/pd/tkpath/generic/tkPathStyle.h b/pd/tkpath/generic/tkPathStyle.h new file mode 100644 index 0000000000000000000000000000000000000000..4a122c3a09c0f36c19796fa154e5c2b279f3995e --- /dev/null +++ b/pd/tkpath/generic/tkPathStyle.h @@ -0,0 +1,154 @@ +/* + * tkPathStyle.h -- + * + * This file contains definitions for style objects used when drawing paths. + * Mostly used for option parsing. + * + * Copyright (c) 2007-2008 Mats Bengtsson + * + * $Id: tkPathStyle.h,v 1.5 2008/06/03 08:08:17 matben Exp $ + */ + +#include "tkIntPath.h" + + +int MatrixSetOption(ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, + Tcl_Obj **value, char *recordPtr, int internalOffset, char *oldInternalPtr, int flags); +Tcl_Obj * MatrixGetOption(ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset); +void MatrixRestoreOption(ClientData clientData, Tk_Window tkwin, char *internalPtr, char *oldInternalPtr); +void MatrixFreeOption(ClientData clientData, Tk_Window tkwin, char *internalPtr); +int PathColorSetOption(ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, + Tcl_Obj **value, char *recordPtr, int internalOffset, char *oldInternalPtr, int flags); +Tcl_Obj * PathColorGetOption(ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset); +void PathColorRestoreOption(ClientData clientData, Tk_Window tkwin, char *internalPtr, char *oldInternalPtr); +void PathColorFreeOption(ClientData clientData, Tk_Window tkwin, char *internalPtr); + +MODULE_SCOPE int Tk_PathDashOptionSetProc(ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, + char *recordPtr, int internalOffset, char *oldInternalPtr, int flags); +MODULE_SCOPE Tcl_Obj * Tk_PathDashOptionGetProc(ClientData clientData, + Tk_Window tkwin, char *recordPtr, int internalOffset); +MODULE_SCOPE void Tk_PathDashOptionRestoreProc(ClientData clientData, + Tk_Window tkwin, char *internalPtr, char *oldInternalPtr); +MODULE_SCOPE void Tk_PathDashOptionFreeProc(ClientData clientData, + Tk_Window tkwin, char *internalPtr); + + +MODULE_SCOPE Tk_PathDash * TkPathDashNew(Tcl_Interp *interp, Tcl_Obj *dashObjPtr); +MODULE_SCOPE void TkPathDashFree(Tk_PathDash *dashPtr); + +MODULE_SCOPE TkPathStyleInst *TkPathGetStyle(Tcl_Interp *interp, CONST char *name, + Tcl_HashTable *tablePtr, TkPathStyleChangedProc *changeProc, + ClientData clientData); +MODULE_SCOPE void TkPathFreeStyle(TkPathStyleInst *stylePtr); +MODULE_SCOPE void TkPathStyleChanged(Tk_PathStyle *masterPtr, int flags); + + +#define PATH_STYLE_CUSTOM_OPTION_MATRIX \ + static Tk_ObjCustomOption matrixCO = { \ + "matrix", \ + MatrixSetOption, \ + MatrixGetOption, \ + MatrixRestoreOption, \ + MatrixFreeOption, \ + (ClientData) NULL \ + }; + +#define PATH_STYLE_CUSTOM_OPTION_DASH \ + static Tk_ObjCustomOption dashCO = { \ + "dasharray", \ + Tk_PathDashOptionSetProc, \ + Tk_PathDashOptionGetProc, \ + Tk_PathDashOptionRestoreProc, \ + Tk_PathDashOptionFreeProc, \ + (ClientData) NULL \ + }; + +#define PATH_STYLE_CUSTOM_OPTION_PATHCOLOR \ + static Tk_ObjCustomOption pathColorCO = { \ + "pathcolor", \ + PathColorSetOption, \ + PathColorGetOption, \ + PathColorRestoreOption, \ + PathColorFreeOption, \ + (ClientData) NULL \ + }; + +#define PATH_STYLE_CUSTOM_OPTION_RECORDS \ + PATH_STYLE_CUSTOM_OPTION_MATRIX \ + PATH_STYLE_CUSTOM_OPTION_DASH + + +/* + * These must be kept in sync with defines in X.h! + */ + +#define PATH_OPTION_STRING_TABLES_FILL \ + static char *fillRuleST[] = { \ + "evenodd", "nonzero", (char *) NULL \ + }; + +#define PATH_OPTION_STRING_TABLES_STROKE \ + static char *lineCapST[] = { \ + "notlast", "butt", "round", "projecting", (char *) NULL \ + }; \ + static char *lineJoinST[] = { \ + "miter", "round", "bevel", (char *) NULL \ + }; + + +#define PATH_OPTION_SPEC_STYLENAME(typeName) \ + {TK_OPTION_STRING, "-style", NULL, NULL, \ + "", Tk_Offset(typeName, styleObj), -1, TK_OPTION_NULL_OK, 0, 0} + +/* + * This assumes that we have a Tk_PathStyle struct element named 'style'. + */ + +#define PATH_OPTION_SPEC_STYLE_FILL(typeName, theColor) \ + {TK_OPTION_STRING, "-fill", NULL, NULL, \ + theColor, Tk_Offset(typeName, style.fillObj), -1, \ + TK_OPTION_NULL_OK, 0, PATH_STYLE_OPTION_FILL}, \ + {TK_OPTION_DOUBLE, "-fillopacity", NULL, NULL, \ + "1.0", -1, Tk_Offset(typeName, style.fillOpacity), 0, 0, \ + PATH_STYLE_OPTION_FILL_OPACITY}, \ + {TK_OPTION_STRING_TABLE, "-fillrule", NULL, NULL, \ + "nonzero", -1, Tk_Offset(typeName, style.fillRule), \ + 0, (ClientData) fillRuleST, PATH_STYLE_OPTION_FILL_RULE} + +#define PATH_OPTION_SPEC_STYLE_MATRIX(typeName) \ + {TK_OPTION_CUSTOM, "-matrix", NULL, NULL, \ + NULL, -1, Tk_Offset(typeName, style.matrixPtr), \ + TK_OPTION_NULL_OK, (ClientData) &matrixCO, PATH_STYLE_OPTION_MATRIX} + +#define PATH_OPTION_SPEC_STYLE_STROKE(typeName, theColor) \ + {TK_OPTION_COLOR, "-stroke", NULL, NULL, \ + theColor, -1, Tk_Offset(typeName, style.strokeColor), \ + TK_OPTION_NULL_OK, 0, PATH_STYLE_OPTION_STROKE}, \ + {TK_OPTION_CUSTOM, "-strokedasharray", NULL, NULL, \ + NULL, -1, Tk_Offset(typeName, style.dashPtr), \ + 0, (ClientData) &dashCO, \ + PATH_STYLE_OPTION_STROKE_DASHARRAY}, \ + {TK_OPTION_STRING_TABLE, "-strokelinecap", NULL, NULL, \ + "butt", -1, Tk_Offset(typeName, style.capStyle), \ + 0, (ClientData) lineCapST, PATH_STYLE_OPTION_STROKE_LINECAP}, \ + {TK_OPTION_STRING_TABLE, "-strokelinejoin", NULL, NULL, \ + "round", -1, Tk_Offset(typeName, style.joinStyle), \ + 0, (ClientData) lineJoinST, PATH_STYLE_OPTION_STROKE_LINEJOIN}, \ + {TK_OPTION_DOUBLE, "-strokemiterlimit", NULL, NULL, \ + "4.0", -1, Tk_Offset(typeName, style.miterLimit), 0, 0, \ + PATH_STYLE_OPTION_STROKE_MITERLIMIT}, \ + {TK_OPTION_DOUBLE, "-strokeopacity", NULL, NULL, \ + "1.0", -1, Tk_Offset(typeName, style.strokeOpacity), 0, 0, \ + PATH_STYLE_OPTION_STROKE_OPACITY}, \ + {TK_OPTION_DOUBLE, "-strokewidth", NULL, NULL, \ + "1.0", -1, Tk_Offset(typeName, style.strokeWidth), 0, 0, \ + PATH_STYLE_OPTION_STROKE_WIDTH} + +#define PATH_OPTION_SPEC_END \ + {TK_OPTION_END, NULL, NULL, NULL, \ + NULL, 0, -1, 0, (ClientData) NULL, 0} + + + + diff --git a/pd/tkpath/generic/tkPathSurface.c b/pd/tkpath/generic/tkPathSurface.c new file mode 100644 index 0000000000000000000000000000000000000000..2e86d0f43cefc1c999eee3d77beac85243639f5a --- /dev/null +++ b/pd/tkpath/generic/tkPathSurface.c @@ -0,0 +1,1048 @@ +/* + * tkPathSurface.c -- + * + * This file implements style objects used when drawing paths. + * See http://www.w3.org/TR/SVG11/. + * + * Copyright (c) 2007-2008 Mats Bengtsson + * + * $Id: tkPathSurface.c,v 1.28 2012/07/04 19:43:18 petasis Exp $ + */ + +#include "tkIntPath.h" +#include "tkPathStyle.h" + +typedef struct PathSurface { + TkPathContext ctx; + char *token; + int width; + int height; +} PathSurface; + +static Tcl_HashTable *surfaceHashPtr = NULL; + +static int StaticSurfaceObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]); +static int NamesSurfaceObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]); +static int NewSurfaceObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]); +static int SurfaceObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]); +static int SurfaceCopyObjCmd(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]); +static int SurfaceDestroyObjCmd(Tcl_Interp* interp, PathSurface *surfacePtr); +static void SurfaceDeletedProc(ClientData clientData); +static int SurfaceCreateObjCmd(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]); +static int SurfaceEraseObjCmd(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]); + +static int SurfaceCreateEllipse(Tcl_Interp* interp, PathSurface *surfacePtr, int type, int objc, Tcl_Obj* CONST objv[]); +static int SurfaceCreatePath(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]); +static int SurfaceCreatePimage(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]); +static int SurfaceCreatePline(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]); +static int SurfaceCreatePpoly(Tcl_Interp* interp, PathSurface *surfacePtr, int type, int objc, Tcl_Obj* CONST objv[]); +static int SurfaceCreatePrect(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]); +static int SurfaceCreatePtext(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]); +static void SurfaceInitOptions(Tcl_Interp* interp); + +static int uid = 0; +static char *kSurfaceNameBase = "tkp::surface"; + +int +SurfaceInit(Tcl_Interp *interp) +{ + surfaceHashPtr = (Tcl_HashTable *) ckalloc( sizeof(Tcl_HashTable) ); + Tcl_InitHashTable(surfaceHashPtr, TCL_STRING_KEYS); + + Tcl_CreateObjCommand(interp, "::tkp::surface", + StaticSurfaceObjCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + SurfaceInitOptions(interp); + return TCL_OK; +} + +static CONST char *staticSurfaceCmds[] = { + "names", "new", (char *) NULL +}; + +enum { + kPathStaticSurfaceCmdNames = 0L, + kPathStaticSurfaceCmdNew +}; + +static int +StaticSurfaceObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) +{ + int index; + int result = TCL_OK; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "command ?arg arg...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], staticSurfaceCmds, "command", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + switch (index) { + case kPathStaticSurfaceCmdNames: { + result = NamesSurfaceObjCmd(clientData, interp, objc, objv); + break; + } + case kPathStaticSurfaceCmdNew: { + result = NewSurfaceObjCmd(clientData, interp, objc, objv); + break; + } + } + return result; +} + +static int +NamesSurfaceObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) +{ + char *name; + Tcl_HashEntry *hPtr; + Tcl_Obj *listObj; + Tcl_HashSearch search; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + listObj = Tcl_NewListObj(0, NULL); + hPtr = Tcl_FirstHashEntry(surfaceHashPtr, &search); + while (hPtr != NULL) { + name = (char *) Tcl_GetHashKey(surfaceHashPtr, hPtr); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(name, -1)); + hPtr = Tcl_NextHashEntry(&search); + } + Tcl_SetObjResult(interp, listObj); + return TCL_OK; +} + +static int +NewSurfaceObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) +{ + TkPathContext ctx; + PathSurface *surfacePtr; + Tcl_HashEntry *hPtr; + char str[255]; + int width, height; + int isNew; + int result = TCL_OK; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "width height"); + return TCL_ERROR; + } + if (Tcl_GetIntFromObj(interp, objv[2], &width) != TCL_OK) { + return TCL_ERROR; + } + if (Tcl_GetIntFromObj(interp, objv[3], &height) != TCL_OK) { + return TCL_ERROR; + } + + ctx = TkPathInitSurface(width, height); + if (ctx == 0) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("Failed in TkPathInitSurface", -1)); + return TCL_ERROR; + } + + sprintf(str, "%s%d", kSurfaceNameBase, uid++); + surfacePtr = (PathSurface *) ckalloc( sizeof(PathSurface) ); + surfacePtr->token = (char *) ckalloc( (unsigned int)strlen(str) + 1 ); + strcpy(surfacePtr->token, str); + surfacePtr->ctx = ctx; + surfacePtr->width = width; + surfacePtr->height = height; + Tcl_CreateObjCommand(interp, str, SurfaceObjCmd, (ClientData) surfacePtr, SurfaceDeletedProc); + + hPtr = Tcl_CreateHashEntry(surfaceHashPtr, str, &isNew); + Tcl_SetHashValue(hPtr, surfacePtr); + Tcl_SetObjResult(interp, Tcl_NewStringObj(str, -1)); + return result; +} + +static CONST char *surfaceCmds[] = { + "copy", "create", "destroy", + "erase", "height", "width", + (char *) NULL +}; + +enum { + kPathSurfaceCmdCopy = 0L, + kPathSurfaceCmdCreate, + kPathSurfaceCmdDestroy, + kPathSurfaceCmdErase, + kPathSurfaceCmdHeight, + kPathSurfaceCmdWidth +}; + +static int +SurfaceObjCmd(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) +{ + PathSurface *surfacePtr = (PathSurface *) clientData; + int index; + int result = TCL_OK; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "command ?arg arg...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], surfaceCmds, "command", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + switch (index) { + case kPathSurfaceCmdCopy: { + result = SurfaceCopyObjCmd(interp, surfacePtr, objc, objv); + break; + } + case kPathSurfaceCmdCreate: { + result = SurfaceCreateObjCmd(interp, surfacePtr, objc, objv); + break; + } + case kPathSurfaceCmdDestroy: { + result = SurfaceDestroyObjCmd(interp, surfacePtr); + break; + } + case kPathSurfaceCmdErase: { + result = SurfaceEraseObjCmd(interp, surfacePtr, objc, objv); + break; + } + case kPathSurfaceCmdHeight: + case kPathSurfaceCmdWidth: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, Tcl_NewIntObj( + (index == kPathSurfaceCmdHeight) ? surfacePtr->height : surfacePtr->width)); + break; + } + } + return result; +} + +static int +SurfaceCopyObjCmd(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]) +{ + Tk_PhotoHandle photo; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "image"); + return TCL_ERROR; + } + photo = Tk_FindPhoto( interp, Tcl_GetString(objv[2]) ); + if (photo == NULL) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("didn't find that image", -1)); + return TCL_ERROR; + } + TkPathSurfaceToPhoto(interp, surfacePtr->ctx, photo); + Tcl_SetObjResult(interp, objv[2]); + return TCL_OK; +} + +static int +SurfaceDestroyObjCmd(Tcl_Interp* interp, PathSurface *surfacePtr) +{ + Tcl_DeleteCommand(interp, surfacePtr->token); + return TCL_OK; +} + +static void +SurfaceDeletedProc(ClientData clientData) +{ + PathSurface *surfacePtr = (PathSurface *) clientData; + Tcl_HashEntry *hPtr; + + hPtr = Tcl_FindHashEntry(surfaceHashPtr, surfacePtr->token); + if (hPtr != NULL) { + Tcl_DeleteHashEntry(hPtr); + } + TkPathFree(surfacePtr->ctx); + ckfree(surfacePtr->token); + ckfree((char *)surfacePtr); +} + +// @@@ TODO: should we have a group item? + +static CONST char *surfaceItemCmds[] = { + "circle", "ellipse", "path", + "pimage", "pline", "polyline", + "ppolygon", "prect", "ptext", + (char *) NULL +}; + +enum { + kPathSurfaceItemCircle = 0L, + kPathSurfaceItemEllipse, + kPathSurfaceItemPath, + kPathSurfaceItemPimage, + kPathSurfaceItemPline, + kPathSurfaceItemPolyline, + kPathSurfaceItemPpolygon, + kPathSurfaceItemPrect, + kPathSurfaceItemPtext +}; + +static int +SurfaceCreateObjCmd(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]) +{ + int index; + int result = TCL_OK; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "type ?arg arg...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], surfaceItemCmds, "type", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + + switch (index) { + case kPathSurfaceItemCircle: + case kPathSurfaceItemEllipse: { + result = SurfaceCreateEllipse(interp, surfacePtr, index, objc, objv); + break; + } + case kPathSurfaceItemPath: { + result = SurfaceCreatePath(interp, surfacePtr, objc, objv); + break; + } + case kPathSurfaceItemPimage: { + result = SurfaceCreatePimage(interp, surfacePtr, objc, objv); + break; + } + case kPathSurfaceItemPline: { + result = SurfaceCreatePline(interp, surfacePtr, objc, objv); + break; + } + case kPathSurfaceItemPolyline: + case kPathSurfaceItemPpolygon: { + result = SurfaceCreatePpoly(interp, surfacePtr, index, objc, objv); + break; + } + case kPathSurfaceItemPrect: { + result = SurfaceCreatePrect(interp, surfacePtr, objc, objv); + break; + } + case kPathSurfaceItemPtext: { + result = SurfaceCreatePtext(interp, surfacePtr, objc, objv); + break; + } + } + return result; +} + +static Tk_OptionTable gOptionTableCircle; +static Tk_OptionTable gOptionTableEllipse; +static Tk_OptionTable gOptionTablePath; +static Tk_OptionTable gOptionTablePimage; +static Tk_OptionTable gOptionTablePline; +static Tk_OptionTable gOptionTablePolyline; +static Tk_OptionTable gOptionTablePpolygon; +static Tk_OptionTable gOptionTablePrect; +static Tk_OptionTable gOptionTablePtext; + +PATH_STYLE_CUSTOM_OPTION_RECORDS + +#define PATH_OPTION_SPEC_R(typeName) \ + {TK_OPTION_DOUBLE, "-r", (char *) NULL, (char *) NULL, \ + "0.0", -1, Tk_Offset(typeName, rx), 0, 0, 0} + +#define PATH_OPTION_SPEC_RX(typeName) \ + {TK_OPTION_DOUBLE, "-rx", (char *) NULL, (char *) NULL, \ + "0.0", -1, Tk_Offset(typeName, rx), 0, 0, 0} + +#define PATH_OPTION_SPEC_RY(typeName) \ + {TK_OPTION_DOUBLE, "-ry", (char *) NULL, (char *) NULL, \ + "0.0", -1, Tk_Offset(typeName, ry), 0, 0, 0} + +typedef struct SurfGenericItem { + Tcl_Obj *styleObj; + Tk_PathStyle style; +} SurfGenericItem; + +static int +GetPointCoords(Tcl_Interp *interp, double *pointPtr, int objc, Tcl_Obj *CONST objv[]) +{ + if ((objc == 1) || (objc == 2)) { + double x, y; + + if (objc==1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected 2", -1)); + return TCL_ERROR; + } + } + if ((Tcl_GetDoubleFromObj(interp, objv[0], &x) != TCL_OK) + || (Tcl_GetDoubleFromObj(interp, objv[1], &y) != TCL_OK)) { + return TCL_ERROR; + } + pointPtr[0] = x; + pointPtr[1] = y; + } else { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected 2", -1)); + return TCL_ERROR; + } + return TCL_OK; +} + +static int +GetTwoPointsCoords(Tcl_Interp *interp, double *pointsPtr, int objc, Tcl_Obj *CONST objv[]) +{ + if ((objc == 1) || (objc == 4)) { + double x1, y1, x2, y2; + + if (objc==1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 4) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected 4", -1)); + return TCL_ERROR; + } + } + if ((Tcl_GetDoubleFromObj(interp, objv[0], &x1) != TCL_OK) + || (Tcl_GetDoubleFromObj(interp, objv[1], &y1) != TCL_OK) + || (Tcl_GetDoubleFromObj(interp, objv[2], &x2) != TCL_OK) + || (Tcl_GetDoubleFromObj(interp, objv[3], &y2) != TCL_OK)) { + return TCL_ERROR; + } + pointsPtr[0] = x1; + pointsPtr[1] = y1; + pointsPtr[2] = x2; + pointsPtr[3] = y2; + } else { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected 4", -1)); + return TCL_ERROR; + } + return TCL_OK; +} + +static int +MakePolyAtoms(Tcl_Interp *interp, int closed, int objc, Tcl_Obj *CONST objv[], PathAtom **atomPtrPtr) +{ + PathAtom *atomPtr = NULL; + + if (objc == 1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } + } + if (objc & 1) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected an even number", -1)); + return TCL_ERROR; + } else if (objc < 4) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # coordinates: expected at least 4", -1)); + return TCL_ERROR; + } else { + int i; + double x, y; + double firstX = 0.0, firstY = 0.0; + PathAtom *firstAtomPtr = NULL; + + for (i = 0; i < objc; i += 2) { + if ((Tcl_GetDoubleFromObj(interp, objv[i], &x) != TCL_OK) + || (Tcl_GetDoubleFromObj(interp, objv[i+1], &y) != TCL_OK)) { + TkPathFreeAtoms(atomPtr); + return TCL_ERROR; + } + if (i == 0) { + firstX = x; + firstY = y; + atomPtr = NewMoveToAtom(x, y); + firstAtomPtr = atomPtr; + } else { + atomPtr->nextPtr = NewLineToAtom(x, y); + atomPtr = atomPtr->nextPtr; + } + } + if (closed) { + atomPtr->nextPtr = NewCloseAtom(firstX, firstY); + } + *atomPtrPtr = firstAtomPtr; + } + return TCL_OK; +} + +static int +GetFirstOptionIndex(int objc, Tcl_Obj* CONST objv[]) +{ + int i; + for (i = 1; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + return i; +} + +static int +SurfaceParseOptions(Tcl_Interp *interp, char *recordPtr, + Tk_OptionTable table, int objc, Tcl_Obj* CONST objv[]) +{ + Tk_Window tkwin = Tk_MainWindow(interp); + if (Tk_InitOptions(interp, recordPtr, table, tkwin) != TCL_OK) { + return TCL_ERROR; + } + if (Tk_SetOptions(interp, recordPtr, table, + objc, objv, tkwin, NULL, NULL) != TCL_OK) { + Tk_FreeConfigOptions(recordPtr, table, tkwin); + return TCL_ERROR; + } + return TCL_OK; +} + +typedef struct SurfEllipseItem { + Tcl_Obj *styleObj; + Tk_PathStyle style; + double rx, ry; +} SurfEllipseItem; + +PATH_OPTION_STRING_TABLES_FILL +PATH_OPTION_STRING_TABLES_STROKE + +static Tk_OptionSpec circleOptionSpecs[] = { + PATH_OPTION_SPEC_STYLENAME(SurfEllipseItem), + PATH_OPTION_SPEC_STYLE_FILL(SurfEllipseItem, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(SurfEllipseItem), + PATH_OPTION_SPEC_STYLE_STROKE(SurfEllipseItem, "black"), + PATH_OPTION_SPEC_R(SurfEllipseItem), + PATH_OPTION_SPEC_END +}; + +static Tk_OptionSpec ellipseOptionSpecs[] = { + PATH_OPTION_SPEC_STYLENAME(SurfEllipseItem), + PATH_OPTION_SPEC_STYLE_FILL(SurfEllipseItem, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(SurfEllipseItem), + PATH_OPTION_SPEC_STYLE_STROKE(SurfEllipseItem, "black"), + PATH_OPTION_SPEC_RX(SurfEllipseItem), + PATH_OPTION_SPEC_RY(SurfEllipseItem), + PATH_OPTION_SPEC_END +}; + +static int +SurfaceCreateEllipse(Tcl_Interp* interp, PathSurface *surfacePtr, int type, int objc, Tcl_Obj* CONST objv[]) +{ + TkPathContext context = surfacePtr->ctx; + int i; + double center[2]; + PathAtom *atomPtr; + EllipseAtom ellAtom; + PathRect bbox; + SurfEllipseItem ellipse; + Tk_PathStyle *style = &ellipse.style; + Tk_PathStyle mergedStyle; + int result = TCL_OK; + + ellipse.styleObj = NULL; + i = GetFirstOptionIndex(objc, objv); + TkPathInitStyle(style); + if (GetPointCoords(interp, center, i-3, objv+3) != TCL_OK) { + goto bail; + } + if (SurfaceParseOptions(interp, (char *)&ellipse, + (type == kPathSurfaceItemCircle) ? gOptionTableCircle : gOptionTableEllipse, + objc-i, objv+i) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + if (style->fillObj != NULL) { + style->fill = TkPathGetPathColorStatic(interp, Tk_MainWindow(interp), style->fillObj); + if (style->fill == NULL) { + result = TCL_ERROR; + goto bail; + } + } + + /* + * NB: We *copy* the style for temp usage. + * Only values and pointers are copied so we shall not free this style. + */ + mergedStyle = ellipse.style; + if (TkPathStyleMergeStyleStatic(interp, ellipse.styleObj, &mergedStyle, 0) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + ellipse.rx = MAX(0.0, ellipse.rx); + ellipse.ry = MAX(0.0, ellipse.ry); + atomPtr = (PathAtom *)&ellAtom; + atomPtr->nextPtr = NULL; + atomPtr->type = PATH_ATOM_ELLIPSE; + ellAtom.cx = center[0]; + ellAtom.cy = center[1]; + ellAtom.rx = ellipse.rx; + ellAtom.ry = (type == kPathSurfaceItemCircle) ? ellipse.rx : ellipse.ry; + TkPathSaveState(context); + TkPathPushTMatrix(context, mergedStyle.matrixPtr); + if (TkPathMakePath(context, atomPtr, &mergedStyle) != TCL_OK) { + TkPathRestoreState(context); + result = TCL_ERROR; + goto bail; + } + bbox = TkPathGetTotalBbox(atomPtr, &mergedStyle); + TkPathPaintPath(context, atomPtr, &mergedStyle, &bbox); + TkPathRestoreState(context); + +bail: + TkPathDeleteStyle(&ellipse.style); + Tk_FreeConfigOptions((char *)&ellipse, + (type == kPathSurfaceItemCircle) ? gOptionTableCircle : gOptionTableEllipse, + Tk_MainWindow(interp)); + return result; +} + +static Tk_OptionSpec pathOptionSpecs[] = { + PATH_OPTION_SPEC_STYLENAME(SurfGenericItem), + PATH_OPTION_SPEC_STYLE_FILL(SurfGenericItem, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(SurfGenericItem), + PATH_OPTION_SPEC_STYLE_STROKE(SurfGenericItem, "black"), + PATH_OPTION_SPEC_END +}; + +static int +SurfaceCreatePath(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]) +{ + TkPathContext context = surfacePtr->ctx; + PathAtom *atomPtr = NULL; + PathRect bbox; + SurfGenericItem item; + Tk_PathStyle *style = &item.style; + Tk_PathStyle mergedStyle; + int len; + int result = TCL_OK; + + item.styleObj = NULL; + TkPathInitStyle(&item.style); + if (TkPathParseToAtoms(interp, objv[3], &atomPtr, &len) != TCL_OK) { + return TCL_ERROR; + } + if (SurfaceParseOptions(interp, (char *)&item, gOptionTablePath, objc-4, objv+4) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + if (style->fillObj != NULL) { + style->fill = TkPathGetPathColorStatic(interp, Tk_MainWindow(interp), style->fillObj); + if (style->fill == NULL) { + result = TCL_ERROR; + goto bail; + } + } + mergedStyle = item.style; + if (TkPathStyleMergeStyleStatic(interp, item.styleObj, &mergedStyle, 0) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + TkPathSaveState(context); + TkPathPushTMatrix(context, mergedStyle.matrixPtr); + if (TkPathMakePath(context, atomPtr, &mergedStyle) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + bbox = TkPathGetTotalBbox(atomPtr, &mergedStyle); + TkPathPaintPath(context, atomPtr, &mergedStyle, &bbox); + +bail: + TkPathDeleteStyle(style); + TkPathFreeAtoms(atomPtr); + TkPathRestoreState(context); + Tk_FreeConfigOptions((char *)&item, gOptionTablePath, Tk_MainWindow(interp)); + return result; +} + +typedef struct SurfPimageItem { + char *imageName; + double height; + double width; + TMatrix *matrixPtr; + Tcl_Obj *styleObj; /* We only use matrixPtr from style. */ +} SurfPimageItem; + +static Tk_OptionSpec pimageOptionSpecs[] = { + {TK_OPTION_DOUBLE, "-height", (char *) NULL, (char *) NULL, + "0", -1, Tk_Offset(SurfPimageItem, height), 0, 0, 0}, + {TK_OPTION_CUSTOM, "-matrix", (char *) NULL, (char *) NULL, + (char *) NULL, -1, Tk_Offset(SurfPimageItem, matrixPtr), + TK_OPTION_NULL_OK, (ClientData) &matrixCO, 0}, + {TK_OPTION_STRING, "-image", (char *) NULL, (char *) NULL, + "", -1, Tk_Offset(SurfPimageItem, imageName), TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-style", (char *) NULL, (char *) NULL, + "", Tk_Offset(SurfPimageItem, styleObj), -1, TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_DOUBLE, "-width", (char *) NULL, (char *) NULL, + "0", -1, Tk_Offset(SurfPimageItem, width), 0, 0, 0}, + PATH_OPTION_SPEC_END +}; + +static int +SurfaceCreatePimage(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]) +{ + TkPathContext context = surfacePtr->ctx; + SurfPimageItem item; + Tk_Image image; + Tk_PhotoHandle photo; + Tk_PathStyle style; + double point[2]; + int i; + int result = TCL_OK; + + item.imageName = NULL; + item.matrixPtr = NULL; + TkPathInitStyle(&style); + i = GetFirstOptionIndex(objc, objv); + if (GetPointCoords(interp, point, i-3, objv+3) != TCL_OK) { + return TCL_ERROR; + } + if (SurfaceParseOptions(interp, (char *)&item, gOptionTablePimage, objc-i, objv+i) != TCL_OK) { + return TCL_ERROR; + } + style.matrixPtr = item.matrixPtr; + if (TkPathStyleMergeStyleStatic(interp, item.styleObj, &style, 0) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + if (item.imageName != NULL) { + photo = Tk_FindPhoto(interp, item.imageName); + if (photo == NULL) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("no photo with the given name", -1)); + result = TCL_ERROR; + goto bail; + } + image = Tk_GetImage(interp, Tk_MainWindow(interp), item.imageName, NULL, (ClientData) NULL); + TkPathSaveState(context); + TkPathPushTMatrix(context, style.matrixPtr); + TkPathImage(context, image, photo, point[0], point[1], item.width, item.height); + Tk_FreeImage(image); + TkPathRestoreState(context); + } + +bail: + Tk_FreeConfigOptions((char *)&item, gOptionTablePimage, Tk_MainWindow(interp)); + return result; +} + +static Tk_OptionSpec plineOptionSpecs[] = { + PATH_OPTION_SPEC_STYLENAME(SurfGenericItem), + PATH_OPTION_SPEC_STYLE_MATRIX(SurfGenericItem), + PATH_OPTION_SPEC_STYLE_STROKE(SurfGenericItem, "black"), + PATH_OPTION_SPEC_END +}; + +static int +SurfaceCreatePline(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]) +{ + TkPathContext context = surfacePtr->ctx; + int i; + PathRect bbox; + SurfGenericItem item; + PathAtom *atomPtr = NULL; + Tk_PathStyle mergedStyle; + double points[4]; + int result = TCL_OK; + + item.styleObj = NULL; + i = GetFirstOptionIndex(objc, objv); + TkPathInitStyle(&item.style); + if (GetTwoPointsCoords(interp, points, i-3, objv+3) != TCL_OK) { + return TCL_ERROR; + } + if (SurfaceParseOptions(interp, (char *)&item, gOptionTablePline, objc-i, objv+i) != TCL_OK) { + return TCL_ERROR; + } + mergedStyle = item.style; + if (TkPathStyleMergeStyleStatic(interp, item.styleObj, &mergedStyle, 0) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + atomPtr = NewMoveToAtom(points[0], points[1]); + atomPtr->nextPtr = NewLineToAtom(points[2], points[3]); + TkPathSaveState(context); + TkPathPushTMatrix(context, mergedStyle.matrixPtr); + if (TkPathMakePath(context, atomPtr, &mergedStyle) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + bbox = TkPathGetTotalBbox(atomPtr, &mergedStyle); + TkPathPaintPath(context, atomPtr, &mergedStyle, &bbox); + +bail: + TkPathDeleteStyle(&item.style); + TkPathFreeAtoms(atomPtr); + TkPathRestoreState(context); + Tk_FreeConfigOptions((char *)&item, gOptionTablePline, Tk_MainWindow(interp)); + return result; +} + +static Tk_OptionSpec polylineOptionSpecs[] = { + PATH_OPTION_SPEC_STYLENAME(SurfGenericItem), + PATH_OPTION_SPEC_STYLE_MATRIX(SurfGenericItem), + PATH_OPTION_SPEC_STYLE_STROKE(SurfGenericItem, "black"), + PATH_OPTION_SPEC_END +}; + +static Tk_OptionSpec ppolygonOptionSpecs[] = { + PATH_OPTION_SPEC_STYLENAME(SurfGenericItem), + PATH_OPTION_SPEC_STYLE_FILL(SurfGenericItem, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(SurfGenericItem), + PATH_OPTION_SPEC_STYLE_STROKE(SurfGenericItem, "black"), + PATH_OPTION_SPEC_END +}; + +static int +SurfaceCreatePpoly(Tcl_Interp* interp, PathSurface *surfacePtr, int type, int objc, Tcl_Obj* CONST objv[]) +{ + TkPathContext context = surfacePtr->ctx; + int i; + PathRect bbox; + SurfGenericItem item; + Tk_PathStyle *style = &item.style; + Tk_PathStyle mergedStyle; + PathAtom *atomPtr = NULL; + int result = TCL_OK; + + item.styleObj = NULL; + i = GetFirstOptionIndex(objc, objv); + TkPathInitStyle(style); + if (MakePolyAtoms(interp, (type == kPathSurfaceItemPolyline) ? 0 : 1, + i-3, objv+3, &atomPtr) != TCL_OK) { + return TCL_ERROR; + } + if (SurfaceParseOptions(interp, (char *)&item, + (type == kPathSurfaceItemPolyline) ? gOptionTablePolyline : gOptionTablePpolygon, + objc-i, objv+i) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + if (style->fillObj != NULL) { + style->fill = TkPathGetPathColorStatic(interp, Tk_MainWindow(interp), style->fillObj); + if (style->fill == NULL) { + result = TCL_ERROR; + goto bail; + } + } + mergedStyle = item.style; + if (TkPathStyleMergeStyleStatic(interp, item.styleObj, &mergedStyle, 0) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + TkPathSaveState(context); + TkPathPushTMatrix(context, mergedStyle.matrixPtr); + if (TkPathMakePath(context, atomPtr, &mergedStyle) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + bbox = TkPathGetTotalBbox(atomPtr, &mergedStyle); + TkPathPaintPath(context, atomPtr, &mergedStyle, &bbox); + +bail: + TkPathDeleteStyle(style); + TkPathFreeAtoms(atomPtr); + TkPathRestoreState(context); + Tk_FreeConfigOptions((char *)&item, + (type == kPathSurfaceItemPolyline) ? gOptionTablePolyline : gOptionTablePpolygon, + Tk_MainWindow(interp)); + return result; +} + +typedef struct SurfPrectItem { + Tcl_Obj *styleObj; + Tk_PathStyle style; + double rx, ry; +} SurfPrectItem; + +static Tk_OptionSpec prectOptionSpecs[] = { + PATH_OPTION_SPEC_STYLENAME(SurfPrectItem), + PATH_OPTION_SPEC_STYLE_FILL(SurfPrectItem, ""), + PATH_OPTION_SPEC_STYLE_MATRIX(SurfPrectItem), + PATH_OPTION_SPEC_STYLE_STROKE(SurfPrectItem, "black"), + PATH_OPTION_SPEC_RX(SurfPrectItem), + PATH_OPTION_SPEC_RY(SurfPrectItem), + PATH_OPTION_SPEC_END +}; + +static int +SurfaceCreatePrect(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]) +{ + TkPathContext context = surfacePtr->ctx; + int i; + SurfPrectItem prect; + Tk_PathStyle *style = &prect.style; + Tk_PathStyle mergedStyle; + PathRect bbox; + PathAtom *atomPtr = NULL; + double points[4]; + int result = TCL_OK; + + prect.styleObj = NULL; + i = GetFirstOptionIndex(objc, objv); + TkPathInitStyle(style); + if (GetTwoPointsCoords(interp, points, i-3, objv+3) != TCL_OK) { + return TCL_ERROR; + } + if (SurfaceParseOptions(interp, (char *)&prect, gOptionTablePrect, objc-i, objv+i) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + if (style->fillObj != NULL) { + style->fill = TkPathGetPathColorStatic(interp, Tk_MainWindow(interp), style->fillObj); + if (style->fill == NULL) { + result = TCL_ERROR; + goto bail; + } + } + mergedStyle = prect.style; + if (TkPathStyleMergeStyleStatic(interp, prect.styleObj, &mergedStyle, 0) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + prect.rx = MAX(0.0, prect.rx); + prect.ry = MAX(0.0, prect.ry); + TkPathSaveState(context); + TkPathPushTMatrix(context, mergedStyle.matrixPtr); + TkPathMakePrectAtoms(points, prect.rx, prect.ry, &atomPtr); + if (TkPathMakePath(context, atomPtr, &mergedStyle) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + bbox = TkPathGetTotalBbox(atomPtr, &mergedStyle); + TkPathPaintPath(context, atomPtr, &mergedStyle, &bbox); + +bail: + TkPathDeleteStyle(&prect.style); + TkPathFreeAtoms(atomPtr); + TkPathRestoreState(context); + Tk_FreeConfigOptions((char *)&prect, gOptionTablePrect, Tk_MainWindow(interp)); + return result; +} + +typedef struct SurfPtextItem { + Tcl_Obj *styleObj; + Tk_PathStyle style; + Tk_PathTextStyle textStyle; + int textAnchor; + double x; + double y; + char *utf8; /* The actual text to display; UTF-8 */ +} SurfPtextItem; + +static char *textAnchorST[] = { + "start", "middle", "end", (char *) NULL +}; + +static Tk_OptionSpec ptextOptionSpecs[] = { + {TK_OPTION_STRING, "-fontfamily", (char *) NULL, (char *) NULL, + "Helvetica", -1, Tk_Offset(SurfPtextItem, textStyle.fontFamily), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_DOUBLE, "-fontsize", (char *) NULL, (char *) NULL, + "12.0", -1, Tk_Offset(SurfPtextItem, textStyle.fontSize), 0, 0, 0}, + {TK_OPTION_STRING, "-text", (char *) NULL, (char *) NULL, + "", -1, Tk_Offset(SurfPtextItem, utf8), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-textanchor", (char *) NULL, (char *) NULL, + "start", -1, Tk_Offset(SurfPtextItem, textAnchor), + 0, (ClientData) textAnchorST, 0}, + PATH_OPTION_SPEC_STYLENAME(SurfPtextItem), + PATH_OPTION_SPEC_STYLE_FILL(SurfPtextItem, "black"), + PATH_OPTION_SPEC_STYLE_MATRIX(SurfPtextItem), + PATH_OPTION_SPEC_STYLE_STROKE(SurfPtextItem, ""), + PATH_OPTION_SPEC_END +}; + +static int +SurfaceCreatePtext(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]) +{ + TkPathContext context = surfacePtr->ctx; + int i; + double point[2]; + SurfPtextItem item; + Tk_PathStyle *style = &item.style; + Tk_PathStyle mergedStyle; + PathRect r; + void *custom = NULL; + int result = TCL_OK; + + item.styleObj = NULL; + item.textAnchor = kPathTextAnchorStart; + item.utf8 = NULL; + item.textStyle.fontFamily = NULL; + i = GetFirstOptionIndex(objc, objv); + TkPathInitStyle(&item.style); + if (GetPointCoords(interp, point, i-3, objv+3) != TCL_OK) { + return TCL_ERROR; + } + if (SurfaceParseOptions(interp, (char *)&item, gOptionTablePtext, objc-i, objv+i) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + if (style->fillObj != NULL) { + style->fill = TkPathGetPathColorStatic(interp, Tk_MainWindow(interp), style->fillObj); + if (style->fill == NULL) { + result = TCL_ERROR; + goto bail; + } + } + if (TkPathTextConfig(interp, &item.textStyle, item.utf8, &custom) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + mergedStyle = item.style; + if (TkPathStyleMergeStyleStatic(interp, item.styleObj, &mergedStyle, 0) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + r = TkPathTextMeasureBbox(&item.textStyle, item.utf8, custom); + switch (item.textAnchor) { + case kPathTextAnchorMiddle: + point[0] -= (r.x2 - r.x1)/2; + break; + case kPathTextAnchorEnd: + point[0] -= (r.x2 - r.x1); + break; + } + TkPathSaveState(context); + TkPathPushTMatrix(context, mergedStyle.matrixPtr); + TkPathBeginPath(context, &mergedStyle); + TkPathTextDraw(context, &mergedStyle, &item.textStyle, point[0], point[1], item.utf8, custom); + TkPathEndPath(context); + TkPathTextFree(&item.textStyle, custom); + +bail: + TkPathDeleteStyle(style); + TkPathRestoreState(context); + Tk_FreeConfigOptions((char *)&item, gOptionTablePtext, Tk_MainWindow(interp)); + return result; +} + +static void +SurfaceInitOptions(Tcl_Interp* interp) +{ + gOptionTableCircle = Tk_CreateOptionTable(interp, circleOptionSpecs); + gOptionTableEllipse = Tk_CreateOptionTable(interp, ellipseOptionSpecs); + gOptionTablePath = Tk_CreateOptionTable(interp, pathOptionSpecs); + gOptionTablePimage = Tk_CreateOptionTable(interp, pimageOptionSpecs); + gOptionTablePline = Tk_CreateOptionTable(interp, plineOptionSpecs); + gOptionTablePolyline = Tk_CreateOptionTable(interp, polylineOptionSpecs); + gOptionTablePpolygon = Tk_CreateOptionTable(interp, ppolygonOptionSpecs); + gOptionTablePrect = Tk_CreateOptionTable(interp, prectOptionSpecs); + gOptionTablePtext = Tk_CreateOptionTable(interp, ptextOptionSpecs); +} + +static int +SurfaceEraseObjCmd(Tcl_Interp* interp, PathSurface *surfacePtr, int objc, Tcl_Obj* CONST objv[]) +{ + double x, y, width, height; + + if (objc != 6) { + Tcl_WrongNumArgs(interp, 2, objv, "x y width height"); + return TCL_ERROR; + } + if ((Tcl_GetDoubleFromObj(interp, objv[2], &x) != TCL_OK) || + (Tcl_GetDoubleFromObj(interp, objv[3], &y) != TCL_OK) || + (Tcl_GetDoubleFromObj(interp, objv[4], &width) != TCL_OK) || + (Tcl_GetDoubleFromObj(interp, objv[5], &height) != TCL_OK)) { + return TCL_ERROR; + } + TkPathSurfaceErase(surfacePtr->ctx, x, y, width, height); + return TCL_OK; +} diff --git a/pd/tkpath/generic/tkPathTkDraw.c b/pd/tkpath/generic/tkPathTkDraw.c new file mode 100644 index 0000000000000000000000000000000000000000..dc554d5a3b14f4821bec3310c7300311b440e2b2 --- /dev/null +++ b/pd/tkpath/generic/tkPathTkDraw.c @@ -0,0 +1,498 @@ +/* + * tkPathTkDraw.c -- + * + * This file implements a path canvas item modelled after its + * SVG counterpart. See http://www.w3.org/TR/SVG11/. + * + * Note: + * This is supposed to be a minimal implementation using + * Tk drawing only. It fails in a number of places such as + * filled and overlapping subpaths. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * $Id: tkPathTkDraw.c,v 1.25 2008/05/22 06:18:21 matben Exp $ + */ + +#include "tkIntPath.h" + +#define _PATH_N_BUFFER_POINTS 2000 + +extern int gAntiAlias; + +extern void CurveSegments(double control[], int includeFirst, int numSteps, register double *coordPtr); + +/* + * Each subpath is reconstructed as a number of straight line segments. + * These are always stored as transformed coordinates. + */ +typedef struct _PathSegments { + int npoints; /* Number of points in points array. */ + double *points; /* The actual point coordinates. */ + int size; /* The number of _points_ allocated in points array. */ + int isclosed; + struct _PathSegments *next; +} _PathSegments; + +/* + * A placeholder for the context we are working in. + * The current and lastMove are always original untransformed coordinates. + */ +typedef struct TkPathContext_ { + Display *display; + Drawable drawable; + double current[2]; + double lastMove[2]; + int hasCurrent; + TMatrix *m; + _PathSegments *segm; + _PathSegments *currentSegm; +} TkPathContext_; + + +static TkPathContext_* _NewPathContext(Tk_Window tkwin, Drawable drawable) +{ + TkPathContext_ *ctx; + + ctx = (TkPathContext_ *) ckalloc(sizeof(TkPathContext_)); + ctx->display = Tk_Display(tkwin); + ctx->drawable = drawable; + ctx->current[0] = 0.0; + ctx->current[1] = 0.0; + ctx->lastMove[0] = 0.0; + ctx->lastMove[1] = 0.0; + ctx->hasCurrent = 0; + ctx->m = NULL; + ctx->segm = NULL; + ctx->currentSegm = NULL; + return ctx; +} + +static _PathSegments* _NewPathSegments(void) +{ + _PathSegments *segm; + + segm = (_PathSegments *) ckalloc(sizeof(_PathSegments)); + segm->npoints = 0; + segm->points = (double *) ckalloc((unsigned) (2*_PATH_N_BUFFER_POINTS*sizeof(double))); + segm->size = _PATH_N_BUFFER_POINTS; + segm->isclosed = 0; + segm->next = NULL; + return segm; +} + +static void _PathContextFree(TkPathContext_ *ctx) +{ + _PathSegments *tmpSegm, *segm; + + segm = ctx->segm; + while (segm != NULL) { + tmpSegm = segm; + segm = tmpSegm->next; + ckfree((char *) tmpSegm->points); + ckfree((char *) tmpSegm); + } + if (ctx->m != NULL) { + ckfree((char *) ctx->m); + } + ckfree((char *) ctx); +} + +static void _CheckCoordSpace(_PathSegments *segm, int numPoints) +{ + if (segm->npoints + numPoints >= segm->size) { + double *points; + points = (double *) ckrealloc((char *)segm->points, 2*(segm->size + _PATH_N_BUFFER_POINTS)*sizeof(double)); + segm->points = points; + } +} + +TkPathContext TkPathInit(Tk_Window tkwin, Drawable d) +{ + return (TkPathContext) _NewPathContext(tkwin, d); +} + +TkPathContext TkPathInitSurface(int width, int height) +{ + +} + +void +TkPathPushTMatrix(TkPathContext ctx, TMatrix *m) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + + if (m == NULL) { + return; + } + if (context->m == NULL) { + context->m = (TMatrix *) ckalloc(sizeof(TMatrix)); + *(context->m) = *m; + } else { + TMatrix tmp = *(context->m); + TMatrix *p = context->m; + + p->a = m->a*tmp.a + m->b*tmp.c; + p->b = m->a*tmp.b + m->b*tmp.d; + p->c = m->c*tmp.a + m->d*tmp.c; + p->d = m->c*tmp.b + m->d*tmp.d; + p->tx = m->tx*tmp.a + m->ty*tmp.c + tmp.tx; + p->ty = m->tx*tmp.b + m->ty*tmp.d + tmp.ty; + } +} + +void TkPathSaveState(TkPathContext ctx) +{ + +} + +void TkPathRestoreState(TkPathContext ctx) +{ + +} + +void TkPathBeginPath(TkPathContext ctx, Tk_PathStyle *style) +{ + /* TkPathContext_ *context = (TkPathContext_ *) ctx; */ + /* empty */ +} + +void TkPathMoveTo(TkPathContext ctx, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + double *coordPtr; + _PathSegments *segm; + + segm = _NewPathSegments(); + if (context->segm == NULL) { + context->segm = segm; + } else { + context->currentSegm->next = segm; + } + context->currentSegm = segm; + context->hasCurrent = 1; + context->current[0] = x; + context->current[1] = y; + context->lastMove[0] = x; + context->lastMove[1] = y; + coordPtr = segm->points; + PathApplyTMatrixToPoint(context->m, context->current, coordPtr); + segm->npoints = 1; +} + +void TkPathLineTo(TkPathContext ctx, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + double *coordPtr; + _PathSegments *segm; + + segm = context->currentSegm; + _CheckCoordSpace(segm, 1); + context->current[0] = x; + context->current[1] = y; + coordPtr = segm->points + 2*segm->npoints; + PathApplyTMatrixToPoint(context->m, context->current, coordPtr); + (segm->npoints)++; +} + +void TkPathQuadBezier(TkPathContext ctx, double ctrlX, double ctrlY, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + double cx, cy; + double x31, y31, x32, y32; + + cx = context->current[0]; + cy = context->current[1]; + + // conversion of quadratic bezier curve to cubic bezier curve: (mozilla/svg) + /* Unchecked! Must be an approximation! */ + x31 = cx + (ctrlX - cx) * 2 / 3; + y31 = cy + (ctrlY - cy) * 2 / 3; + x32 = ctrlX + (x - ctrlX) / 3; + y32 = ctrlY + (y - ctrlY) / 3; + + TkPathCurveTo(ctx, x31, y31, x32, y32, x, y); +} + +void TkPathCurveTo(TkPathContext ctx, double x1, double y1, + double x2, double y2, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + int numSteps; + double *coordPtr; + double control[8]; + double xc, yc; + _PathSegments *segm; + + xc = x; + yc = y; + + PathApplyTMatrixToPoint(context->m, context->current, control); + PathApplyTMatrix(context->m, &x1, &y1); + PathApplyTMatrix(context->m, &x2, &y2); + PathApplyTMatrix(context->m, &x, &y); + control[2] = x1; + control[3] = y1; + control[4] = x2; + control[5] = y2; + control[6] = x; + control[7] = y; + + numSteps = kPathNumSegmentsCurveTo; + segm = context->currentSegm; + _CheckCoordSpace(segm, numSteps); + coordPtr = segm->points + 2*segm->npoints; + CurveSegments(control, 0, numSteps, coordPtr); + segm->npoints += numSteps; + context->current[0] = xc; + context->current[1] = yc; +} + +void TkPathArcTo(TkPathContext ctx, + double rx, double ry, + double phiDegrees, /* The rotation angle in degrees! */ + char largeArcFlag, char sweepFlag, double x, double y) +{ + TkPathArcToUsingBezier(ctx, rx, ry, phiDegrees, largeArcFlag, sweepFlag, x, y); +} + +void +TkPathRect(TkPathContext ctx, double x, double y, double width, double height) +{ + TkPathMoveTo(ctx, x, y); + TkPathLineTo(ctx, x+width, y); + TkPathLineTo(ctx, x+width, y+height); + TkPathLineTo(ctx, x, y+height); + TkPathClosePath(ctx); +} + +void +TkPathOval(TkPathContext ctx, double cx, double cy, double rx, double ry) +{ + /* @@@ I'm sure this could be made much more efficient. */ + TkPathMoveTo(ctx, cx+rx, cy); + TkPathArcToUsingBezier(ctx, rx, ry, 0.0, 1, 1, cx-rx, cy); + TkPathArcToUsingBezier(ctx, rx, ry, 0.0, 1, 1, cx+rx, cy); + TkPathClosePath(ctx); +} + +void +TkPathImage(TkPathContext ctx, Tk_Image image, Tk_PhotoHandle photo, double x, double y, double width, double height) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + int iwidth, iheight; + + if (image == NULL) { + return; + } + PathApplyTMatrix(context->m, &x, &y); + Tk_SizeOfImage(image, &iwidth, &iheight); + Tk_RedrawImage(image, 0, 0, iwidth, iheight, context->drawable, (int)x, (int)y); +} + +void TkPathClosePath(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + double *coordPtr; + _PathSegments *segm; + + segm = context->currentSegm; + _CheckCoordSpace(segm, 1); + segm->isclosed = 1; + context->current[0] = context->lastMove[0]; + context->current[1] = context->lastMove[1]; + coordPtr = segm->points + 2*segm->npoints; + PathApplyTMatrixToPoint(context->m, context->current, coordPtr); + (segm->npoints)++; +} + +/* + * There is no need to reproduce the Tk drawing code here since we can't do + * anything different. + */ + +int +TkPathTextConfig(Tcl_Interp *interp, Tk_PathTextStyle *textStylePtr, char *utf8, void **customPtr) +{ + return TCL_OK; +} + +void +TkPathTextDraw(TkPathContext ctx, Tk_PathStyle *style, Tk_PathTextStyle *textStylePtr, double x, double y, char *utf8, void *custom) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + +} + +void +TkPathTextFree(Tk_PathTextStyle *textStylePtr, void *custom) +{ + +} + +PathRect +TkPathTextMeasureBbox(Tk_PathTextStyle *textStylePtr, char *utf8, void *custom) +{ + PathRect r = {0, 0, 0, 0}; + return r; +} + +void +TkPathSurfaceErase(TkPathContext ctx, double x, double y, double width, double height) +{ + +} + +void +TkPathSurfaceToPhoto(Tcl_Interp *interp, TkPathContext ctx, Tk_PhotoHandle photo) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + +} + +void TkPathClipToPath(TkPathContext ctx, int fillRule) +{ + /* empty */ +} + +void TkPathReleaseClipToPath(TkPathContext ctx) +{ + /* empty */ +} + +/* @@@ This is a very much simplified version of TkPathCanvTranslatePath that + * doesn't do any clipping and no translation since we do that with + * the more general affine matrix transform. + */ +static void _DoubleCoordsToXPointArray(int npoints, double *coordArr, XPoint *outArr) +{ + int i; + double x, y; + + for(i = 0; i < npoints; i++){ + x = coordArr[i*2]; + y = coordArr[i*2+1]; + + if (x > 0) { + x += 0.5; + } else { + x -= 0.5; + } + outArr[i].x = (short) x; + + if (y > 0) { + y += 0.5; + } else { + y -= 0.5; + } + outArr[i].y = (short) y; + } +} + +void TkPathStroke(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + int numPoints; + XPoint *pointPtr; + _PathSegments *segm; + + segm = context->segm; + while (segm != NULL) { + numPoints = segm->npoints; + pointPtr = (XPoint *)ckalloc((unsigned)(numPoints * sizeof(XPoint))); + _DoubleCoordsToXPointArray(numPoints, segm->points, pointPtr); + XDrawLines(context->display, context->drawable, style->strokeGC, pointPtr, numPoints, + CoordModeOrigin); + ckfree((char *) pointPtr); + segm = segm->next; + } +} + +void TkPathFill(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + int numPoints; + XPoint *pointPtr; + _PathSegments *segm; + + segm = context->segm; + while (segm != NULL) { + numPoints = segm->npoints; + pointPtr = (XPoint *)ckalloc((unsigned)(numPoints * sizeof(XPoint))); + _DoubleCoordsToXPointArray(numPoints, segm->points, pointPtr); + XFillPolygon(context->display, context->drawable, style->fillGC, pointPtr, numPoints, + Complex, CoordModeOrigin); + ckfree((char *) pointPtr); + segm = segm->next; + } +} + +void TkPathFillAndStroke(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + int numPoints; + XPoint *pointPtr; + _PathSegments *segm; + + segm = context->segm; + while (segm != NULL) { + numPoints = segm->npoints; + pointPtr = (XPoint *)ckalloc((unsigned)(numPoints * sizeof(XPoint))); + _DoubleCoordsToXPointArray(numPoints, segm->points, pointPtr); + XFillPolygon(context->display, context->drawable, style->fillGC, pointPtr, numPoints, + Complex, CoordModeOrigin); + XDrawLines(context->display, context->drawable, style->strokeGC, pointPtr, numPoints, + CoordModeOrigin); + ckfree((char *) pointPtr); + segm = segm->next; + } +} + +void TkPathEndPath(TkPathContext ctx) +{ + /* empty */ +} + +void TkPathFree(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + _PathContextFree(context); +} + +int TkPathDrawingDestroysPath(void) +{ + return 0; +} + +int +TkPathPixelAlign(void) +{ + return 1; +} + +int TkPathGetCurrentPosition(TkPathContext ctx, PathPoint *pt) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + pt->x = context->current[0]; + pt->y = context->current[1]; + return TCL_OK; +} + +int TkPathBoundingBox(TkPathContext ctx, PathRect *rPtr) +{ + return TCL_ERROR; +} + +void TkPathPaintLinearGradient(TkPathContext ctx, PathRect *bbox, LinearGradientFill *fillPtr, int fillRule, TMatrix *mPtr) +{ + /* TkPathContext_ *context = (TkPathContext_ *) ctx; */ + /* The Tk X11 compatibility layer does not have tha ability to set up + * clipping to pixmap which is needed here, I believe. + */ +} + +void +TkPathPaintRadialGradient(TkPathContext ctx, PathRect *bbox, RadialGradientFill *fillPtr, int fillRule, TMatrix *mPtr) +{ +} + diff --git a/pd/tkpath/generic/tkPathUtil.c b/pd/tkpath/generic/tkPathUtil.c new file mode 100644 index 0000000000000000000000000000000000000000..07b309c27067a5975ae6e1f2d0d17ed0b70882be --- /dev/null +++ b/pd/tkpath/generic/tkPathUtil.c @@ -0,0 +1,1224 @@ +/* + * tkPathUtil.h -- + * + * This file contains support functions for tkpath. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * $Id: tkPathUtil.c,v 1.30 2012/07/04 19:43:18 petasis Exp $ + */ + +#include <float.h> +#include "tkIntPath.h" +#include "tkCanvPathUtil.h" + +#define DOUBLE_EQUALS(x,y) (fabs((x) - (y)) < DBL_EPSILON) + +/* + *-------------------------------------------------------------- + * + * TkPathMakePrectAtoms -- + * + * Makes the path atoms for a rounded rectangle, prect. + * + * Results: + * None. Path atoms in atomPtrPtr. + * + * Side effects: + * Path atom memory allocated. + * + *-------------------------------------------------------------- + */ + +void +TkPathMakePrectAtoms(double *pointsPtr, double rx, double ry, PathAtom **atomPtrPtr) +{ + PathAtom *atomPtr = NULL; + PathAtom *firstAtomPtr = NULL; + int round = 1; + double epsilon = 1e-6; + double x = MIN(pointsPtr[0], pointsPtr[2]); + double y = MIN(pointsPtr[1], pointsPtr[3]); + double width = fabs(pointsPtr[0] - pointsPtr[2]); + double height = fabs(pointsPtr[1] - pointsPtr[3]); + + /* If only one of rx or ry is zero this implies that both shall be nonzero. */ + if (rx < epsilon && ry < epsilon) { + round = 0; + } else if (rx < epsilon) { + rx = ry; + } else if (ry < epsilon) { + ry = rx; + } + if (round) { + + /* There are certain constraints on rx and ry. */ + rx = MIN(rx, width/2.0); + ry = MIN(ry, height/2.0); + + atomPtr = NewMoveToAtom(x+rx, y); + firstAtomPtr = atomPtr; + atomPtr->nextPtr = NewLineToAtom(x+width-rx, y); + atomPtr = atomPtr->nextPtr; + atomPtr->nextPtr = NewArcAtom(rx, ry, 0.0, 0, 1, x+width, y+ry); + atomPtr = atomPtr->nextPtr; + atomPtr->nextPtr = NewLineToAtom(x+width, y+height-ry); + atomPtr = atomPtr->nextPtr; + atomPtr->nextPtr = NewArcAtom(rx, ry, 0.0, 0, 1, x+width-rx, y+height); + atomPtr = atomPtr->nextPtr; + atomPtr->nextPtr = NewLineToAtom(x+rx, y+height); + atomPtr = atomPtr->nextPtr; + atomPtr->nextPtr = NewArcAtom(rx, ry, 0.0, 0, 1, x, y+height-ry); + atomPtr = atomPtr->nextPtr; + atomPtr->nextPtr = NewLineToAtom(x, y+ry); + atomPtr = atomPtr->nextPtr; + atomPtr->nextPtr = NewArcAtom(rx, ry, 0.0, 0, 1, x+rx, y); + atomPtr = atomPtr->nextPtr; + atomPtr->nextPtr = NewCloseAtom(x, y); + *atomPtrPtr = firstAtomPtr; + } else { + atomPtr = NewRectAtom(pointsPtr); + *atomPtrPtr = atomPtr; + } +} + +/* + *-------------------------------------------------------------- + * + * TkPathDrawPath -- + * + * This procedure is invoked to draw a line item in a given + * drawable. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation + * information in canvas. + * + *-------------------------------------------------------------- + */ + +void +TkPathDrawPath( + Tk_Window tkwin, /* Tk window. */ + Drawable drawable, /* Pixmap or window in which to draw + * item. */ + PathAtom *atomPtr, /* The actual path as a linked list + * of PathAtoms. */ + Tk_PathStyle *stylePtr, /* The paths style. */ + TMatrix *mPtr, /* Typically used for canvas offsets. */ + PathRect *bboxPtr) /* The bare (untransformed) bounding box + * (assuming zero stroke width) */ +{ + TkPathContext context; + + /* + * Define the path in the drawable using the path drawing functions. + * Any transform matrix need to be considered and canvas drawable + * offset must always be taken into account. Note the order! + */ + + context = TkPathInit(tkwin, drawable); + if (mPtr != NULL) { + TkPathPushTMatrix(context, mPtr); + } + if (stylePtr->matrixPtr != NULL) { + TkPathPushTMatrix(context, stylePtr->matrixPtr); + } + if (TkPathMakePath(context, atomPtr, stylePtr) != TCL_OK) { + return; + } + TkPathPaintPath(context, atomPtr, stylePtr, bboxPtr); + TkPathFree(context); +} + +/* + *-------------------------------------------------------------- + * + * TkPathPaintPath -- + * + * This procedure is invoked to paint a path in a given context. + * + * Results: + * None. + * + * Side effects: + * Any path defined in the context is painted. + * + *-------------------------------------------------------------- + */ + +void +TkPathPaintPath( + TkPathContext context, + PathAtom *atomPtr, /* The actual path as a linked list + * of PathAtoms. */ + Tk_PathStyle *stylePtr, /* The paths style. */ + PathRect *bboxPtr) +{ + TkPathGradientMaster *gradientPtr = GetGradientMasterFromPathColor(stylePtr->fill); + + if (gradientPtr != NULL) { + TkPathClipToPath(context, stylePtr->fillRule); + PathGradientPaint(context, bboxPtr, gradientPtr, stylePtr->fillRule); + + /* NB: Both CoreGraphics on MacOSX and Win32 GDI (and cairo from 1.0) + * clear the current path when setting clipping. Need therefore + * to redo the path. + */ + if (TkPathDrawingDestroysPath()) { + TkPathMakePath(context, atomPtr, stylePtr); + } + + /* We shall remove the path clipping here! */ + TkPathReleaseClipToPath(context); + } + + if ((GetColorFromPathColor(stylePtr->fill) != NULL) && (stylePtr->strokeColor != NULL)) { + TkPathFillAndStroke(context, stylePtr); + } else if (GetColorFromPathColor(stylePtr->fill) != NULL) { + TkPathFill(context, stylePtr); + } else if (stylePtr->strokeColor != NULL) { + TkPathStroke(context, stylePtr); + } +} + +PathRect +TkPathGetTotalBbox(PathAtom *atomPtr, Tk_PathStyle *stylePtr) +{ + PathRect bare, total; + + bare = GetGenericBarePathBbox(atomPtr); + total = GetGenericPathTotalBboxFromBare(atomPtr, stylePtr, &bare); + return total; +} + +/* Return NULL on error and leave error message */ + +// @@@ OBSOLETE SOON!!! +// As a temporary mean before trashing it we ignore gradients. + +TkPathColor * +TkPathNewPathColor(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *nameObj) +{ + char *name; + TkPathColor *colorPtr; + XColor *color = NULL; + + name = Tcl_GetStringFromObj(nameObj, NULL); + colorPtr = (TkPathColor *) ckalloc(sizeof(TkPathColor)); + colorPtr->color = NULL; + colorPtr->gradientInstPtr = NULL; + + color = Tk_AllocColorFromObj(interp, tkwin, nameObj); + if (color == NULL) { + char tmp[256]; + ckfree((char *) colorPtr); + sprintf(tmp, "unrecognized color or gradient name \"%s\"", name); + Tcl_SetObjResult(interp, Tcl_NewStringObj(tmp, -1)); + return NULL; + } + colorPtr->color = color; + return colorPtr; +} + +/* + *-------------------------------------------------------------- + * + * TkPathGetPathColor -- + * + * Parses a string in nameObj to either a valid XColor or + * looks up a gradient name for the hash table tablePtr. + * Makes a new TkPathColor struct from a string value. + * Like Tk_GetImage() but for TkPathColor instead of Tk_Image. + * + * Results: + * Pointer to a TkPathColor struct or returns NULL on error + * and leaves an error message. + * + * Side effects: + * TkPathColor malloced if OK. + * + *-------------------------------------------------------------- + */ + +TkPathColor * +TkPathGetPathColor(Tcl_Interp *interp, Tk_Window tkwin, + Tcl_Obj *nameObj, Tcl_HashTable *tablePtr, + TkPathGradientChangedProc *changeProc, ClientData clientData) +{ + char *name; + TkPathColor *colorPtr; + XColor *color = NULL; + TkPathGradientInst *gradientInstPtr; + + name = Tcl_GetString(nameObj); + colorPtr = (TkPathColor *) ckalloc(sizeof(TkPathColor)); + + /* + * Only one of them can be non NULL. + */ + colorPtr->color = NULL; + colorPtr->gradientInstPtr = NULL; + + gradientInstPtr = TkPathGetGradient(interp, name, tablePtr, changeProc, clientData); + if (gradientInstPtr != NULL) { + colorPtr->gradientInstPtr = gradientInstPtr; + } else { + Tcl_ResetResult(interp); + color = Tk_AllocColorFromObj(interp, tkwin, nameObj); + if (color == NULL) { + Tcl_Obj *resultObj; + ckfree((char *) colorPtr); + resultObj = Tcl_NewStringObj("unrecognized color or gradient name \"", -1); + Tcl_AppendStringsToObj(resultObj, name, "\"", (char *) NULL); + Tcl_SetObjResult(interp, resultObj); + return NULL; + } + colorPtr->color = color; + } + return colorPtr; +} + +void +TkPathFreePathColor(TkPathColor *colorPtr) +{ + if (colorPtr != NULL) { + if (colorPtr->color != NULL) { + Tk_FreeColor(colorPtr->color); + } else if (colorPtr->gradientInstPtr != NULL) { + TkPathFreeGradient(colorPtr->gradientInstPtr); + } + ckfree((char *) colorPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * PathCopyBitsARGB, PathCopyBitsBGRA -- + * + * Copies bitmap data from these formats to RGBA. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +PathCopyBitsARGB(unsigned char *from, unsigned char *to, + int width, int height, int bytesPerRow) +{ + unsigned char *src, *dst; + int i, j; + + /* Copy XRGB to RGBX in one shot, alphas in a loop. */ + memcpy(to, from+1, height*bytesPerRow-1); + + for (i = 0; i < height; i++) { + src = from + i*bytesPerRow; + dst = to + i*bytesPerRow; + /* @@@ Keep ARGB format in photo? */ + for (j = 0; j < width; j++, src += 4, dst += 4) { + *(dst+3) = *src; + } + } +} + +void +PathCopyBitsBGRA(unsigned char *from, unsigned char *to, + int width, int height, int bytesPerRow) +{ + unsigned char *src, *dst; + int i, j; + + /* Copy BGRA -> RGBA */ + for (i = 0; i < height; i++) { + src = from + i*bytesPerRow; + dst = to + i*bytesPerRow; + for (j = 0; j < width; j++, src += 4) { + /* RED */ + *dst++ = *(src+2); + /* GREEN */ + *dst++ = *(src+1); + /* BLUE */ + *dst++ = *src; + /* ALPHA */ + *dst++ = *(src+3); + } + } +} + +/* + *-------------------------------------------------------------- + * + * PathCopyBitsPremultipliedAlphaRGBA, PathCopyBitsPremultipliedAlphaARGB -- + * + * Copies bitmap data that have alpha premultiplied into a bitmap + * with "true" RGB values need for Tk_Photo. The source format is + * either RGBA or ARGB, but destination always RGBA used for photos. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +PathCopyBitsPremultipliedAlphaRGBA(unsigned char *from, unsigned char *to, + int width, int height, int bytesPerRow) +{ + unsigned char *src, *dst, alpha; + int i, j; + + /* Copy src RGBA with premulitplied alpha to "plain" RGBA. */ + for (i = 0; i < height; i++) { + src = from + i*bytesPerRow; + dst = to + i*bytesPerRow; + for (j = 0; j < width; j++) { + alpha = *(src+3); + if (alpha == 0xFF || alpha == 0x00) { + memcpy(dst, src, 4); + src += 4; + dst += 4; + } else { + /* dst = 255*src/alpha */ + *dst++ = (*src++*255)/alpha; + *dst++ = (*src++*255)/alpha; + *dst++ = (*src++*255)/alpha; + *dst++ = alpha; + src++; + } + } + } +} + +// UNTESTED! +void +PathCopyBitsPremultipliedAlphaARGB(unsigned char *from, unsigned char *to, + int width, int height, int bytesPerRow) +{ + unsigned char *src, *dst, alpha; + int i, j; + + /* Copy src ARGB with premulitplied alpha to "plain" RGBA. */ + for (i = 0; i < height; i++) { + src = from + i*bytesPerRow; + dst = to + i*bytesPerRow; + for (j = 0; j < width; j++) { + alpha = *src; + if (alpha == 0xFF || alpha == 0x00) { + memcpy(dst, src+1, 3); + *(dst+3) = alpha; + src += 4; + dst += 4; + } else { + /* dst = 255*src/alpha */ + *(dst+3) = alpha; + src++; + *dst = ((*src << 8) - *src)/alpha; + dst++, src++; + *dst = ((*src << 8) - *src)/alpha; + dst++, src++; + *dst = ((*src << 8) - *src)/alpha; + dst++, dst++, src++; + } + } + } +} + +void +PathCopyBitsPremultipliedAlphaBGRA(unsigned char *from, unsigned char *to, + int width, int height, int bytesPerRow) +{ + unsigned char *src, *dst, alpha; + int i, j; + + /* Copy src BGRA with premulitplied alpha to "plain" RGBA. */ + for (i = 0; i < height; i++) { + src = from + i*bytesPerRow; + dst = to + i*bytesPerRow; + for (j = 0; j < width; j++, src += 4) { + alpha = *(src+3); + if (alpha == 0xFF || alpha == 0x00) { + /* RED */ + *dst++ = *(src+2); + /* GREEN */ + *dst++ = *(src+1); + /* BLUE */ + *dst++ = *src; + /* ALPHA */ + *dst++ = *(src+3); + } else { + /* dst = 255*src/alpha */ + /* RED */ + *dst++ = (*(src+2)*255)/alpha; + /* GREEN */ + *dst++ = (*(src+1)*255)/alpha; + /* BLUE */ + *dst++ = (*(src+0)*255)/alpha; + /* ALPHA */ + *dst++ = alpha; + } + } + } +} + +/* from mozilla */ +static double +CalcVectorAngle(double ux, double uy, double vx, double vy) +{ + double ta = atan2(uy, ux); + double tb = atan2(vy, vx); + if (tb >= ta) { + return tb-ta; + } else { + return 2.0*M_PI - (ta-tb); + } +} + +/* + *-------------------------------------------------------------- + * + * CentralToEndpointArcParameters + * + * Conversion from center to endpoint parameterization. + * All angles in radians! + * From: http://www.w3.org/TR/2003/REC-SVG11-20030114 + * + * Results: + * Arc specific return code. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +CentralToEndpointArcParameters( + double cx, double cy, double rx, double ry, /* In pars. */ + double theta1, double dtheta, double phi, + double *x1Ptr, double *y1Ptr, /* Out. */ + double *x2Ptr, double *y2Ptr, + char *largeArcFlagPtr, char *sweepFlagPtr) +{ + double theta2; + double sinPhi, cosPhi; + double sinTheta1, cosTheta1; + double sinTheta2, cosTheta2; + + theta2 = theta1 + dtheta; + sinPhi = sin(phi); + cosPhi = cos(phi); + sinTheta1 = sin(theta1); + cosTheta1 = cos(theta1); + sinTheta2 = sin(theta2); + cosTheta2 = cos(theta2); + + /* F.6.4 Conversion from center to endpoint parameterization. */ + *x1Ptr = cx + rx * cosTheta1 * cosPhi - ry * sinTheta1 * sinPhi; + *y1Ptr = cy + rx * cosTheta1 * sinPhi + ry * sinTheta1 * cosPhi; + *x2Ptr = cx + rx * cosTheta2 * cosPhi - ry * sinTheta2 * sinPhi; + *y2Ptr = cy + rx * cosTheta2 * sinPhi + ry * sinTheta2 * cosPhi; + + *largeArcFlagPtr = (dtheta > M_PI) ? 1 : 0; + *sweepFlagPtr = (dtheta > 0.0) ? 1 : 0; + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * EndpointToCentralArcParameters + * + * Conversion from endpoint to center parameterization. + * All angles in radians! + * From: http://www.w3.org/TR/2003/REC-SVG11-20030114 + * + * Results: + * Arc specific return code. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +EndpointToCentralArcParameters( + double x1, double y1, double x2, double y2, /* The endpoints. */ + double rx, double ry, /* Radius. */ + double phi, char largeArcFlag, char sweepFlag, + double *cxPtr, double *cyPtr, /* Out. */ + double *rxPtr, double *ryPtr, + double *theta1Ptr, double *dthetaPtr) +{ + double sinPhi, cosPhi; + double dx, dy; + double x1dash, y1dash; + double cxdash, cydash; + double cx, cy; + double numerator, root; + double theta1, dtheta; + + /* 1. Treat out-of-range parameters as described in + * http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes + * + * If the endpoints (x1, y1) and (x2, y2) are identical, then this + * is equivalent to omitting the elliptical arc segment entirely + */ + if (DOUBLE_EQUALS(x1, x2) && DOUBLE_EQUALS(y1, y2)) { + return kPathArcSkip; + } + + /* If rx = 0 or ry = 0 then this arc is treated as a straight line + * segment (a "lineto") joining the endpoints. + */ + if (rx == 0.0f || ry == 0.0f) { + return kPathArcLine; + } + + /* If rx or ry have negative signs, these are dropped; the absolute + * value is used instead. + */ + if (rx < 0.0) rx = -rx; + if (ry < 0.0) ry = -ry; + + if (largeArcFlag != 0) largeArcFlag = 1; + if (sweepFlag != 0) sweepFlag = 1; + + /* 2. convert to center parameterization as shown in + * http://www.w3.org/TR/SVG/implnote.html + */ + sinPhi = sin(phi); + cosPhi = cos(phi); + dx = (x1-x2)/2.0; + dy = (y1-y2)/2.0; + x1dash = cosPhi * dx + sinPhi * dy; + y1dash = -sinPhi * dx + cosPhi * dy; + + /* Compute cx' and cy'. */ + numerator = rx*rx*ry*ry - rx*rx*y1dash*y1dash - ry*ry*x1dash*x1dash; + if (numerator < 0.0) { + + /* If rx , ry and are such that there is no solution (basically, + * the ellipse is not big enough to reach from (x1, y1) to (x2, + * y2)) then the ellipse is scaled up uniformly until there is + * exactly one solution (until the ellipse is just big enough). + * -> find factor s, such that numerator' with rx'=s*rx and + * ry'=s*ry becomes 0 : + */ + float s = (float) sqrt(1.0 - numerator/(rx*rx*ry*ry)); + + rx *= s; + ry *= s; + root = 0.0; + } else { + root = (largeArcFlag == sweepFlag ? -1.0 : 1.0) * + sqrt( numerator/(rx*rx*y1dash*y1dash + ry*ry*x1dash*x1dash) ); + } + + cxdash = root*rx*y1dash/ry; + cydash = -root*ry*x1dash/rx; + + /* Compute cx and cy from cx' and cy'. */ + cx = cosPhi * cxdash - sinPhi * cydash + (x1+x2)/2.0; + cy = sinPhi * cxdash + cosPhi * cydash + (y1+y2)/2.0; + + /* Compute start angle and extent. */ + theta1 = CalcVectorAngle(1.0, 0.0, (x1dash-cxdash)/rx, (y1dash-cydash)/ry); + dtheta = CalcVectorAngle( + (x1dash-cxdash)/rx, (y1dash-cydash)/ry, + (-x1dash-cxdash)/rx, (-y1dash-cydash)/ry); + if (!sweepFlag && (dtheta > 0.0)) { + dtheta -= 2.0*M_PI; + } else if (sweepFlag && (dtheta < 0.0)) { + dtheta += 2.0*M_PI; + } + *cxPtr = cx; + *cyPtr = cy; + *rxPtr = rx; + *ryPtr = ry; + *theta1Ptr = theta1; + *dthetaPtr = dtheta; + + return kPathArcOK; +} + +/* + *-------------------------------------------------------------- + * + * TableLooup + * + * Look up an index from a statically allocated table of ints. + * + * Results: + * integer + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +int +TableLookup(LookupTable *map, int n, int from) +{ + int i = 0; + + while ((i < n) && (from != map[i].from)) + i++; + if (i == n) { + return map[0].to; + } else { + return map[i].to; + } +} + +/* + * Miscellaneous matrix utilities. + */ + +void +PathApplyTMatrix(TMatrix *m, double *x, double *y) +{ + if (m != NULL) { + double tmpx = *x; + double tmpy = *y; + *x = tmpx*m->a + tmpy*m->c + m->tx; + *y = tmpx*m->b + tmpy*m->d + m->ty; + } +} + +void +PathApplyTMatrixToPoint(TMatrix *m, double in[2], double out[2]) +{ + if (m == NULL) { + out[0] = in[0]; + out[1] = in[1]; + } else { + out[0] = in[0]*m->a + in[1]*m->c + m->tx; + out[1] = in[0]*m->b + in[1]*m->d + m->ty; + } +} + +void +PathInverseTMatrix(TMatrix *m, TMatrix *mi) +{ + double det; + + /* @@@ We need error checking for det = 0 */ + det = m->a * m->d - m->b * m->c; + mi->a = m->d/det; + mi->b = -m->b/det; + mi->c = -m->c/det; + mi->d = m->a/det; + mi->tx = (m->c * m->ty - m->d * m->tx)/det; + mi->ty = (m->b * m->tx - m->a * m->ty)/det; +} + +/* + *---------------------------------------------------------------------- + * + * MMulTMatrix -- + * + * Multiplies (concatenates) two matrices together and puts the + * result in m2. + * + * Results: + * None. + * + * Side effects: + * TMatrix m2 modified + * + *---------------------------------------------------------------------- + */ + +void +MMulTMatrix(TMatrix *m1, TMatrix *m2) +{ + if (m1 == NULL) { + return; + } + if (m2 == NULL) { + /* Panic! */ + } else { + TMatrix tmp = *m2; + TMatrix *p = m2; + + p->a = m1->a*tmp.a + m1->b*tmp.c; + p->b = m1->a*tmp.b + m1->b*tmp.d; + p->c = m1->c*tmp.a + m1->d*tmp.c; + p->d = m1->c*tmp.b + m1->d*tmp.d; + p->tx = m1->tx*tmp.a + m1->ty*tmp.c + tmp.tx; + p->ty = m1->tx*tmp.b + m1->ty*tmp.d + tmp.ty; + } +} + +/* + *---------------------------------------------------------------------- + * + * PathGetTMatrix -- + * + * Parses a Tcl list (in string) into a TMatrix record. + * + * Results: + * Standard Tcl result + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +int +PathGetTMatrix( + Tcl_Interp* interp, + CONST char *list, /* Object containg the lists for the matrix. */ + TMatrix *matrixPtr) /* Where to store TMatrix corresponding + * to list. Must be allocated! */ +{ + CONST char **argv = NULL; + CONST char **rowArgv = NULL; + int i, j, argc, rowArgc; + int result = TCL_OK; + double tmp[3][2]; + + /* Check matrix consistency. */ + if (Tcl_SplitList(interp, list, &argc, &argv) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + if (argc != 3) { + Tcl_AppendResult(interp, "matrix \"", list, "\" is inconsistent", + (char *) NULL); + result = TCL_ERROR; + goto bail; + } + + /* Take each row in turn. */ + for (i = 0; i < 3; i++) { + if (Tcl_SplitList(interp, argv[i], &rowArgc, &rowArgv) != TCL_OK) { + result = TCL_ERROR; + goto bail; + } + if (rowArgc != 2) { + Tcl_AppendResult(interp, "matrix \"", list, "\" is inconsistent", + (char *) NULL); + result = TCL_ERROR; + goto bail; + } + for (j = 0; j < 2; j++) { + if (Tcl_GetDouble(interp, rowArgv[j], &(tmp[i][j])) != TCL_OK) { + Tcl_AppendResult(interp, "matrix \"", list, "\" is inconsistent", + (char *) NULL); + result = TCL_ERROR; + goto bail; + } + } + if (rowArgv != NULL) { + Tcl_Free((char *) rowArgv); + rowArgv = NULL; + } + } + + /* Check that the matrix is not close to being singular. */ + if (fabs(tmp[0][0]*tmp[1][1] - tmp[0][1]*tmp[1][0]) < 1e-6) { + Tcl_AppendResult(interp, "matrix \"", list, "\" is close to singular", + (char *) NULL); + result = TCL_ERROR; + goto bail; + } + + /* Matrix. */ + matrixPtr->a = tmp[0][0]; + matrixPtr->b = tmp[0][1]; + matrixPtr->c = tmp[1][0]; + matrixPtr->d = tmp[1][1]; + matrixPtr->tx = tmp[2][0]; + matrixPtr->ty = tmp[2][1]; + +bail: + if (argv != NULL) { + Tcl_Free((char *) argv); + } + if (rowArgv != NULL) { + Tcl_Free((char *) rowArgv); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * PathGetTclObjFromTMatrix -- + * + * Parses a TMatrix record into a list object. + * + * Results: + * Standard Tcl result + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +int +PathGetTclObjFromTMatrix( + Tcl_Interp* interp, + TMatrix *matrixPtr, + Tcl_Obj **listObjPtrPtr) +{ + Tcl_Obj *listObj, *subListObj; + + /* @@@ Error handling remains. */ + + listObj = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); + if (matrixPtr != NULL) { + subListObj = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); + Tcl_ListObjAppendElement(interp, subListObj, Tcl_NewDoubleObj(matrixPtr->a)); + Tcl_ListObjAppendElement(interp, subListObj, Tcl_NewDoubleObj(matrixPtr->b)); + Tcl_ListObjAppendElement(interp, listObj, subListObj); + + subListObj = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); + Tcl_ListObjAppendElement(interp, subListObj, Tcl_NewDoubleObj(matrixPtr->c)); + Tcl_ListObjAppendElement(interp, subListObj, Tcl_NewDoubleObj(matrixPtr->d)); + Tcl_ListObjAppendElement(interp, listObj, subListObj); + + subListObj = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); + Tcl_ListObjAppendElement(interp, subListObj, Tcl_NewDoubleObj(matrixPtr->tx)); + Tcl_ListObjAppendElement(interp, subListObj, Tcl_NewDoubleObj(matrixPtr->ty)); + Tcl_ListObjAppendElement(interp, listObj, subListObj); + } + *listObjPtrPtr = listObj; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TkPathGenericCmdDispatcher -- + * + * Supposed to be a generic command dispatcher. + * + * Results: + * Standard Tcl result + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +static CONST char *genericCmds[] = { + "cget", "configure", "create", "delete", "names", + (char *) NULL +}; + +enum { + kPathGenericCmdCget = 0L, + kPathGenericCmdConfigure, + kPathGenericCmdCreate, + kPathGenericCmdDelete, + kPathGenericCmdNames +}; + +int +TkPathGenericCmdDispatcher( + Tcl_Interp* interp, + Tk_Window tkwin, + int objc, + Tcl_Obj* CONST objv[], + char *baseName, + int *baseNameUIDPtr, + Tcl_HashTable *hashTablePtr, + Tk_OptionTable optionTable, + char *(*createAndConfigProc)(Tcl_Interp *interp, char *name, int objc, Tcl_Obj *CONST objv[]), + void (*configNotifyProc)(char *recordPtr, int mask, int objc, Tcl_Obj *CONST objv[]), + void (*freeProc)(Tcl_Interp *interp, char *recordPtr)) +{ + char *name; + char *recordPtr; + int result = TCL_OK; + int index; + int mask; + Tcl_HashEntry *hPtr; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "command ?arg arg...?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[1], genericCmds, "command", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + + switch (index) { + + case kPathGenericCmdCget: { + Tcl_Obj *resultObjPtr = NULL; + + if (objc != 4) { + Tcl_WrongNumArgs( interp, 3, objv, "option" ); + return TCL_ERROR; + } + name = Tcl_GetString(objv[2]); + hPtr = Tcl_FindHashEntry(hashTablePtr, name); + if (hPtr == NULL) { + Tcl_AppendResult(interp, + "object \"", name, "\" doesn't exist", NULL); + return TCL_ERROR; + } + recordPtr = (char *) Tcl_GetHashValue(hPtr); + resultObjPtr = Tk_GetOptionValue(interp, recordPtr, optionTable, objv[3], tkwin); + if (resultObjPtr == NULL) { + result = TCL_ERROR; + } else { + Tcl_SetObjResult( interp, resultObjPtr ); + } + break; + } + + case kPathGenericCmdConfigure: { + Tcl_Obj *resultObjPtr = NULL; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name ?option? ?value option value...?"); + return TCL_ERROR; + } + name = Tcl_GetString(objv[2]); + hPtr = Tcl_FindHashEntry(hashTablePtr, name); + if (hPtr == NULL) { + Tcl_AppendResult(interp, + "object \"", name, "\" doesn't exist", NULL); + return TCL_ERROR; + } + recordPtr = (char *) Tcl_GetHashValue(hPtr); + if (objc <= 4) { + resultObjPtr = Tk_GetOptionInfo(interp, recordPtr, + optionTable, + (objc == 3) ? (Tcl_Obj *) NULL : objv[3], + tkwin); + if (resultObjPtr == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, resultObjPtr); + } else { + if (Tk_SetOptions(interp, recordPtr, optionTable, objc - 3, objv + 3, + tkwin, NULL, &mask) != TCL_OK) { + return TCL_ERROR; + } + if (configNotifyProc != NULL) { + (*configNotifyProc)(recordPtr, mask, objc - 3, objv + 3); + } + } + break; + } + + case kPathGenericCmdCreate: { + + /* + * Create with auto generated unique name. + */ + char str[255]; + int isNew; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?option value...?"); + return TCL_ERROR; + } + sprintf(str, "%s%d", baseName, *baseNameUIDPtr); + (*baseNameUIDPtr)++; + recordPtr = (*createAndConfigProc)(interp, str, objc - 2, objv + 2); + if (recordPtr == NULL) { + return TCL_ERROR; + } + + if (Tk_InitOptions(interp, recordPtr, optionTable, tkwin) != TCL_OK) { + ckfree(recordPtr); + return TCL_ERROR; + } + if (Tk_SetOptions(interp, recordPtr, optionTable, + objc - 2, objv + 2, tkwin, NULL, &mask) != TCL_OK) { + Tk_FreeConfigOptions(recordPtr, optionTable, tkwin); + ckfree(recordPtr); + return TCL_ERROR; + } + if (configNotifyProc != NULL) { + (*configNotifyProc)(recordPtr, mask, objc - 2, objv + 2); + } + + hPtr = Tcl_CreateHashEntry(hashTablePtr, str, &isNew); + Tcl_SetHashValue(hPtr, recordPtr); + Tcl_SetObjResult(interp, Tcl_NewStringObj(str, -1)); + break; + } + + case kPathGenericCmdDelete: { + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + name = Tcl_GetString(objv[2]); + hPtr = Tcl_FindHashEntry(hashTablePtr, name); + recordPtr = (char *) Tcl_GetHashValue(hPtr); + if (hPtr != NULL) { + Tcl_DeleteHashEntry(hPtr); + } + Tk_FreeConfigOptions(recordPtr, optionTable, tkwin); + (*freeProc)(interp, recordPtr); + break; + } + + case kPathGenericCmdNames: { + Tcl_Obj *listObj; + Tcl_HashSearch search; + + listObj = Tcl_NewListObj(0, NULL); + hPtr = Tcl_FirstHashEntry(hashTablePtr, &search); + while (hPtr != NULL) { + name = (char *) Tcl_GetHashKey(hashTablePtr, hPtr); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(name, -1)); + hPtr = Tcl_NextHashEntry(&search); + } + Tcl_SetObjResult(interp, listObj); + break; + } + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * ObjectIsEmpty -- + * + * This procedure tests whether the string value of an object is + * empty. + * + * Results: + * The return value is 1 if the string value of objPtr has length + * zero, and 0 otherwise. + * + * Side effects: + * May cause object shimmering, since this function can force a + * conversion to a string object. + * + *---------------------------------------------------------------------- + */ + +int +ObjectIsEmpty( + Tcl_Obj *objPtr) /* Object to test. May be NULL. */ +{ + int length; + + if (objPtr == NULL) { + return 1; + } + if (objPtr->bytes != NULL) { + return (objPtr->length == 0); + } + Tcl_GetStringFromObj(objPtr, &length); + return (length == 0); +} + +static int +DashConvertToFloats ( + float *d, /* The resulting dashes. (Out) */ + CONST char *p, /* A string of "_-,." */ + size_t n, + double width) +{ + int result = 0; + int size; + + if (n < 0) { + n = strlen(p); + } + while (n-- && *p) { + switch (*p++) { + case ' ': + if (result) { + if (d) { + d[-1] += (float) (width + 1.0); + } + continue; + } else { + return 0; + } + break; + case '_': + size = 8; + break; + case '-': + size = 6; + break; + case ',': + size = 4; + break; + case '.': + size = 2; + break; + default: + return -1; + } + if (d) { + *d++ = size * (float) width; + *d++ = 4 * (float) width; + } + result += 2; + } + return result; +} + +void +PathParseDashToArray(Tk_Dash *dash, double width, int *len, float **arrayPtrPtr) +{ + char *pt; + int i; + float *arrPtr = NULL; + + if (dash->number == 0) { + *len = 0; + } else if (dash->number < 0) { + + /* Any of . , - _ verbatim. */ + i = -1*dash->number; + pt = (i > (int)sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + arrPtr = (float *) ckalloc(2*i*sizeof(float)); + i = DashConvertToFloats(arrPtr, pt, i, width); + if (i < 0) { + /* This should never happen since syntax already checked. */ + *len = 0; + } else { + *len = i; + } + } else { + pt = (dash->number > (int)sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; + *len = dash->number; + arrPtr = (float *) ckalloc(dash->number * sizeof(float)); + for (i = 0; i < dash->number; i++) { + + /* We could optionally multiply with 'width' here. */ + arrPtr[i] = pt[i]; + } + } + *arrayPtrPtr = arrPtr; +} + +/*-------------------------------------------------------------------------*/ + diff --git a/pd/tkpath/generic/tkp.h b/pd/tkpath/generic/tkp.h new file mode 100644 index 0000000000000000000000000000000000000000..d61f796b3a274300bae771f6f83123b23162b8d2 --- /dev/null +++ b/pd/tkpath/generic/tkp.h @@ -0,0 +1,411 @@ +/* + * tkp.h -- + * + * This file includes stuff from tk.h which we need + * in a modified form and to make the tkp::canvas self contained. + * + * $Id: tkp.h,v 1.6 2008/07/16 13:17:33 matben Exp $ + */ + +#ifndef INCLUDED_TKP_H +#define INCLUDED_TKP_H + +#include "tk.h" + +/* + * For C++ compilers, use extern "C" + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Tk_PathCanvas_ is just a dummy which is never defined anywhere. + * This happens to work because Tk_PathCanvas is a pointer. + * Its reason is to hide the internals of TkPathCanvas to item code. + */ +typedef struct Tk_PathCanvas_ *Tk_PathCanvas; + + +/* + *-------------------------------------------------------------- + * + * Procedure prototypes and structures used for defining new canvas items: + * + *-------------------------------------------------------------- + */ + +typedef enum { + TK_PATHSTATE_NULL = -1, TK_PATHSTATE_ACTIVE, TK_PATHSTATE_DISABLED, + TK_PATHSTATE_NORMAL, TK_PATHSTATE_HIDDEN +} Tk_PathState; + + +typedef struct Tk_PathSmoothMethod { + char *name; + int (*coordProc) _ANSI_ARGS_((Tk_PathCanvas canvas, + double *pointPtr, int numPoints, int numSteps, + XPoint xPoints[], double dblPoints[])); + void (*postscriptProc) _ANSI_ARGS_((Tcl_Interp *interp, + Tk_PathCanvas canvas, double *coordPtr, + int numPoints, int numSteps)); +} Tk_PathSmoothMethod; + +/* + * For each item in a canvas widget there exists one record with the following + * structure. Each actual item is represented by a record with the following + * stuff at its beginning, plus additional type-specific stuff after that. + */ + +#define TK_PATHTAG_SPACE 3 + +typedef struct Tk_PathTags { + Tk_Uid *tagPtr; /* Pointer to array of tags. */ + int tagSpace; /* Total amount of tag space available at + * tagPtr. */ + int numTags; /* Number of tag slots actually used at + * *tagPtr. */ +} Tk_PathTags; + +typedef struct Tk_PathItem { + int id; /* Unique identifier for this item (also + * serves as first tag for item). */ + Tk_OptionTable optionTable; /* Option table */ + struct Tk_PathItem *nextPtr;/* Next sibling in display list of this group. + * Later items in list are drawn on + * top of earlier ones. */ + struct Tk_PathItem *prevPtr;/* Previous sibling in display list of this group. */ + struct Tk_PathItem *parentPtr; + /* Parent of item or NULL if root. */ + struct Tk_PathItem *firstChildPtr; + /* First child item, only for groups. */ + struct Tk_PathItem *lastChildPtr; + /* Last child item, only for groups. */ + Tcl_Obj *parentObj; /* */ + Tk_PathTags *pathTagsPtr; /* Allocated struct for storing tags. + * This is needed by the custom option handling. */ + +//#ifdef USE_OLD_CODE + Tk_Uid staticTagSpace[TK_PATHTAG_SPACE]; + /* Built-in space for limited # of tags. */ + Tk_Uid *tagPtr; /* Pointer to array of tags. Usually points to + * staticTagSpace, but may point to malloc-ed + * space if there are lots of tags. */ + int tagSpace; /* Total amount of tag space available at + * tagPtr. */ + int numTags; /* Number of tag slots actually used at + * *tagPtr. */ +//#endif + + struct Tk_PathItemType *typePtr;/* Table of procedures that implement this + * type of item. */ + int x1, y1, x2, y2; /* Bounding box for item, in integer canvas + * units. Set by item-specific code and + * guaranteed to contain every pixel drawn in + * item. Item area includes x1 and y1 but not + * x2 and y2. */ + Tk_PathState state; /* State of item. */ + char *reserved1; /* reserved for future use */ + int redraw_flags; /* Some flags used in the canvas */ + + /* + *------------------------------------------------------------------ + * Starting here is additional type-specific stuff; see the declarations + * for individual types to see what is part of each type. The actual space + * below is determined by the "itemInfoSize" of the type's Tk_PathItemType + * record. + *------------------------------------------------------------------ + */ +} Tk_PathItem; + +/* + * Flag bits for canvases (redraw_flags): + * + * TK_ITEM_STATE_DEPENDANT - 1 means that object needs to be redrawn if the + * canvas state changes. + * TK_ITEM_DONT_REDRAW - 1 means that the object redraw is already been + * prepared, so the general canvas code doesn't + * need to do that any more. + */ + +#define TK_ITEM_STATE_DEPENDANT 1 +#define TK_ITEM_DONT_REDRAW 2 + +/* + * Records of the following type are used to describe a type of item (e.g. + * lines, circles, etc.) that can form part of a canvas widget. + */ + +typedef int Tk_PathItemCreateProc(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int argc, + Tcl_Obj *const objv[]); +typedef int Tk_PathItemConfigureProc(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int argc, + Tcl_Obj *const objv[], int flags); +typedef int Tk_PathItemCoordProc(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int argc, + Tcl_Obj *const argv[]); +typedef void Tk_PathItemDeleteProc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +typedef void Tk_PathItemDisplayProc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable dst, + int x, int y, int width, int height); +typedef void TkPathItemBboxProc(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int mask); +typedef double Tk_PathItemPointProc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *pointPtr); +typedef int Tk_PathItemAreaProc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +typedef int Tk_PathItemPostscriptProc(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +typedef void Tk_PathItemScaleProc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +typedef void Tk_PathItemTranslateProc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); +typedef int Tk_PathItemIndexProc(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, char *indexString, + int *indexPtr); +typedef void Tk_PathItemCursorProc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int index); +typedef int Tk_PathItemSelectionProc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int offset, char *buffer, + int maxBytes); +typedef void Tk_PathItemInsertProc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int beforeThis, char *string); +typedef void Tk_PathItemDCharsProc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int first, int last); + +#ifndef __NO_OLD_CONFIG + +typedef struct Tk_PathItemType { + char *name; /* The name of this type of item, such as + * "line". */ + int itemSize; /* Total amount of space needed for item's + * record. */ + Tk_PathItemCreateProc *createProc; + /* Procedure to create a new item of this + * type. */ + Tk_OptionSpec *optionSpecs; /* Pointer to array of option specs for + * this type. Used for returning option + * info. */ + Tk_PathItemConfigureProc *configProc; + /* Procedure to call to change configuration + * options. */ + Tk_PathItemCoordProc *coordProc;/* Procedure to call to get and set the item's + * coordinates. */ + Tk_PathItemDeleteProc *deleteProc; + /* Procedure to delete existing item of this + * type. */ + Tk_PathItemDisplayProc *displayProc; + /* Procedure to display items of this type. */ + int alwaysRedraw; /* Non-zero means displayProc should be called + * even when the item has been moved + * off-screen. */ + TkPathItemBboxProc *bboxProc; + /* Procedure that is invoked by group items + * on its children when it has reconfigured in + * any way that affect the childrens bbox display. */ + Tk_PathItemPointProc *pointProc; + /* Computes distance from item to a given + * point. */ + Tk_PathItemAreaProc *areaProc; + /* Computes whether item is inside, outside, + * or overlapping an area. */ + Tk_PathItemPostscriptProc *postscriptProc; + /* Procedure to write a Postscript description + * for items of this type. */ + Tk_PathItemScaleProc *scaleProc;/* Procedure to rescale items of this type. */ + Tk_PathItemTranslateProc *translateProc; + /* Procedure to translate items of this + * type. */ + Tk_PathItemIndexProc *indexProc;/* Procedure to determine index of indicated + * character. NULL if item doesn't support + * indexing. */ + Tk_PathItemCursorProc *icursorProc; + /* Procedure to set insert cursor posn to just + * before a given position. */ + Tk_PathItemSelectionProc *selectionProc; + /* Procedure to return selection (in STRING + * format) when it is in this item. */ + Tk_PathItemInsertProc *insertProc; + /* Procedure to insert something into an + * item. */ + Tk_PathItemDCharsProc *dCharsProc; + /* Procedure to delete characters from an + * item. */ + struct Tk_PathItemType *nextPtr;/* Used to link types together into a list. */ + char *reserved1; /* Reserved for future extension. */ + int reserved2; /* Carefully compatible with */ + char *reserved3; /* Jan Nijtmans dash patch */ + char *reserved4; +} Tk_PathItemType; + +#endif + +/* + * The following structure provides information about the selection and the + * insertion cursor. It is needed by only a few items, such as those that + * display text. It is shared by the generic canvas code and the item-specific + * code, but most of the fields should be written only by the canvas generic + * code. + */ + +typedef struct Tk_PathCanvasTextInfo { + Tk_3DBorder selBorder; /* Border and background for selected + * characters. Read-only to items.*/ + int selBorderWidth; /* Width of border around selection. Read-only + * to items. */ + XColor *selFgColorPtr; /* Foreground color for selected text. + * Read-only to items. */ + Tk_PathItem *selItemPtr; /* Pointer to selected item. NULL means + * selection isn't in this canvas. Writable by + * items. */ + int selectFirst; /* Character index of first selected + * character. Writable by items. */ + int selectLast; /* Character index of last selected character. + * Writable by items. */ + Tk_PathItem *anchorItemPtr; /* Item corresponding to "selectAnchor": not + * necessarily selItemPtr. Read-only to + * items. */ + int selectAnchor; /* Character index of fixed end of selection + * (i.e. "select to" operation will use this + * as one end of the selection). Writable by + * items. */ + Tk_3DBorder insertBorder; /* Used to draw vertical bar for insertion + * cursor. Read-only to items. */ + int insertWidth; /* Total width of insertion cursor. Read-only + * to items. */ + int insertBorderWidth; /* Width of 3-D border around insert cursor. + * Read-only to items. */ + Tk_PathItem *focusItemPtr; /* Item that currently has the input focus, or + * NULL if no such item. Read-only to items. */ + int gotFocus; /* Non-zero means that the canvas widget has + * the input focus. Read-only to items.*/ + int cursorOn; /* Non-zero means that an insertion cursor + * should be displayed in focusItemPtr. + * Read-only to items.*/ +} Tk_PathCanvasTextInfo; + +/* + * Structures used for Dashing and Outline. + */ +typedef struct Tk_PathDash { + int number; + float *array; +} Tk_PathDash; + +/* + * Bit fields in Tk_Offset->flags: + */ + +#if 0 + +#define TK_OFFSET_INDEX 1 +#define TK_OFFSET_RELATIVE 2 +#define TK_OFFSET_LEFT 4 +#define TK_OFFSET_CENTER 8 +#define TK_OFFSET_RIGHT 16 +#define TK_OFFSET_TOP 32 +#define TK_OFFSET_MIDDLE 64 +#define TK_OFFSET_BOTTOM 128 + +#endif + +typedef struct Tk_PathOutline { + GC gc; /* Graphics context. */ + double width; /* Width of outline. */ + double activeWidth; /* Width of outline. */ + double disabledWidth; /* Width of outline. */ + int offset; /* Dash offset. */ + Tk_Dash *dashPtr; /* Dash pattern. */ + Tk_Dash *activeDashPtr; /* Dash pattern if state is active. */ + Tk_Dash *disabledDashPtr; /* Dash pattern if state is disabled. */ + + VOID *reserved1; /* Reserved for future expansion. */ + VOID *reserved2; + VOID *reserved3; + Tk_TSOffset *tsoffsetPtr; /* Stipple offset for outline. */ + XColor *color; /* Outline color. */ + XColor *activeColor; /* Outline color if state is active. */ + XColor *disabledColor; /* Outline color if state is disabled. */ + Pixmap stipple; /* Outline Stipple pattern. */ + Pixmap activeStipple; /* Outline Stipple pattern if state is + * active. */ + Pixmap disabledStipple; /* Outline Stipple pattern if state is + * disabled. */ +} Tk_PathOutline; + + +/* + * Functions normally in the tk stubs table. + */ + +/* From tkpCanvUtil.c */ + +Tk_Window Tk_PathCanvasTkwin(Tk_PathCanvas canvas); +void Tk_CreatePathItemType(Tk_PathItemType *typePtr); +void Tk_PathCreateSmoothMethod(Tcl_Interp * interp, + Tk_PathSmoothMethod * method); +int Tk_PathConfigOutlineGC(XGCValues *gcValues, Tk_PathCanvas canvas, + Tk_PathItem *item, Tk_PathOutline *outline); +int Tk_PathChangeOutlineGC(Tk_PathCanvas canvas, Tk_PathItem *item, + Tk_PathOutline *outline); +int Tk_PathResetOutlineGC(Tk_PathCanvas canvas, Tk_PathItem *item, + Tk_PathOutline *outline); +int Tk_PathCanvasPsOutline(Tk_PathCanvas canvas, Tk_PathItem *item, + Tk_PathOutline *outline); +void Tk_PathCanvasDrawableCoords(Tk_PathCanvas canvas, + double x, double y, short *drawableXPtr, short *drawableYPtr); +void Tk_PathCanvasWindowCoords(Tk_PathCanvas canvas, + double x, double y, short *screenXPtr, short *screenYPtr); +int Tk_PathCanvasGetCoord(Tcl_Interp *interp, Tk_PathCanvas canvas, + CONST char *string, double *doublePtr); +int Tk_PathCanvasGetCoordFromObj(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tcl_Obj *obj, double *doublePtr); +void Tk_PathCanvasSetStippleOrigin(Tk_PathCanvas canvas, GC gc); +void Tk_PathCanvasSetOffset(Tk_PathCanvas canvas, GC gc, Tk_TSOffset *offset); +Tk_PathCanvasTextInfo * Tk_PathCanvasGetTextInfo(Tk_PathCanvas canvas); +int Tk_PathCanvasTagsParseProc( ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, CONST char *value, char *widgRec, int offset); +char * Tk_PathCanvasTagsPrintProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset, Tcl_FreeProc **freeProcPtr); +void Tk_PathCreateSmoothMethod(Tcl_Interp *interp, Tk_PathSmoothMethod *smooth); +void Tk_PathCreateOutline(Tk_PathOutline *outline); +void Tk_PathDeleteOutline(Display *display, Tk_PathOutline *outline); + +int Tk_PathCanvasTagsOptionSetProc(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, + int internalOffset, char *oldInternalPtr, int flags); +Tcl_Obj * Tk_PathCanvasTagsOptionGetProc(ClientData clientData, Tk_Window tkwin, + char *recordPtr, int internalOffset); +void Tk_PathCanvasTagsOptionRestoreProc(ClientData clientData, + Tk_Window tkwin, char *internalPtr, char *oldInternalPtr); +void Tk_PathCanvasTagsOptionFreeProc(ClientData clientData, + Tk_Window tkwin, char *internalPtr); + +/* From tkpCanvas.c */ + +void Tk_PathCanvasEventuallyRedraw(Tk_PathCanvas canvas, + int x1, int y1, int x2, int y2); +int Tk_PathCanvasPsColor(Tcl_Interp *interp, Tk_PathCanvas canvas, + XColor *colorPtr); +int Tk_PathCanvasPsFont(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_Font tkfont); +int Tk_PathCanvasPsBitmap(Tcl_Interp *interp, Tk_PathCanvas canvas, + Pixmap bitmap, int startX, int startY, int width, int height); +int Tk_PathCanvasPsStipple(Tcl_Interp *interp, Tk_PathCanvas canvas, + Pixmap bitmap); +double Tk_PathCanvasPsY(Tk_PathCanvas canvas, double y); +void Tk_PathCanvasPsPath(Tcl_Interp *interp, Tk_PathCanvas canvas, + double *coordPtr, int numPoints); + + + +#ifdef __cplusplus +} +#endif + +#endif // end INCLUDED_TKP_H + diff --git a/pd/tkpath/generic/tkpCanvArc.c b/pd/tkpath/generic/tkpCanvArc.c new file mode 100644 index 0000000000000000000000000000000000000000..1596540dfbb876f95c92ff20a31141e7a8c30e8a --- /dev/null +++ b/pd/tkpath/generic/tkpCanvArc.c @@ -0,0 +1,2034 @@ +/* + * tkpCanvArc.c -- + * + * This file implements arc items for canvas widgets. + * + * Copyright (c) 1992-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvArc.c,v 1.5 2008/07/22 09:41:35 matben Exp $ + */ + +#include <stdio.h> +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" + +/* + * The structure below defines the record for each arc item. + */ + +typedef enum { + PIESLICE_STYLE, CHORD_STYLE, ARC_STYLE +} Style; + +typedef struct ArcItem { + Tk_PathItem header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + Tk_PathOutline outline; /* Outline structure */ + double bbox[4]; /* Coordinates (x1, y1, x2, y2) of bounding + * box for oval of which arc is a piece. */ + double start; /* Angle at which arc begins, in degrees + * between 0 and 360. */ + double extent; /* Extent of arc (angular distance from start + * to end of arc) in degrees between -360 and + * 360. */ + double *outlinePtr; /* Points to (x,y) coordinates for points that + * define one or two closed polygons + * representing the portion of the outline + * that isn't part of the arc (the V-shape for + * a pie slice or a line-like segment for a + * chord). Malloc'ed. */ + int numOutlinePoints; /* Number of points at outlinePtr. Zero means + * no space allocated. */ + Tk_TSOffset *tsoffsetPtr; + XColor *fillColor; /* Color for filling arc (used for drawing + * outline too when style is "arc"). NULL + * means don't fill arc. */ + XColor *activeFillColor; /* Color for filling arc (used for drawing + * outline too when style is "arc" and state + * is "active"). NULL means use fillColor. */ + XColor *disabledFillColor; /* Color for filling arc (used for drawing + * outline too when style is "arc" and state + * is "disabled". NULL means use fillColor */ + Pixmap fillStipple; /* Stipple bitmap for filling item. */ + Pixmap activeFillStipple; /* Stipple bitmap for filling item if state is + * active. */ + Pixmap disabledFillStipple; /* Stipple bitmap for filling item if state is + * disabled. */ + Style style; /* How to draw arc: arc, chord, or + * pieslice. */ + GC fillGC; /* Graphics context for filling item. */ + double center1[2]; /* Coordinates of center of arc outline at + * start (see ComputeArcOutline). */ + double center2[2]; /* Coordinates of center of arc outline at + * start+extent (see ComputeArcOutline). */ +} ArcItem; + +/* + * The definitions below define the sizes of the polygons used to display + * outline information for various styles of arcs: + */ + +#define CHORD_OUTLINE_PTS 7 +#define PIE_OUTLINE1_PTS 6 +#define PIE_OUTLINE2_PTS 7 + +/* + * Information used for parsing configuration specs. If you change any of the + * default strings, be sure to change the corresponding default values in + * CreateLine. + */ + +#define PATH_DEF_STATE "normal" + +/* These MUST be kept in sync with enums! X.h */ + +static char *stateStrings[] = { + "active", "disabled", "normal", "hidden", NULL +}; + +static char *arcStyleStrings[] = { + "pieslice", "chord", "arc", NULL +}; + +static Tk_ObjCustomOption dashCO = { + "dash", + Tk_DashOptionSetProc, + Tk_DashOptionGetProc, + Tk_DashOptionRestoreProc, + Tk_DashOptionFreeProc, + (ClientData) NULL +}; + +static Tk_ObjCustomOption offsetCO = { + "offset", + TkPathOffsetOptionSetProc, + TkPathOffsetOptionGetProc, + TkPathOffsetOptionRestoreProc, + TkPathOffsetOptionFreeProc, + (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) +}; + +static Tk_ObjCustomOption pixelCO = { + "pixel", + Tk_PathPixelOptionSetProc, + Tk_PathPixelOptionGetProc, + Tk_PathPixelOptionRestoreProc, + NULL, + (ClientData) NULL +}; + +static Tk_ObjCustomOption tagsCO = { + "tags", + Tk_PathCanvasTagsOptionSetProc, + Tk_PathCanvasTagsOptionGetProc, + Tk_PathCanvasTagsOptionRestoreProc, + Tk_PathCanvasTagsOptionFreeProc, + (ClientData) NULL +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_CUSTOM, "-activedash", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, outline.activeDashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_COLOR, "-activefill", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, activeFillColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-activeoutline", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, outline.activeColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-activeoutlinestipple", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, outline.activeStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-activestipple", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, activeFillStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-activewidth", NULL, NULL, + "0.0", -1, Tk_Offset(ArcItem, outline.activeWidth), + 0, &pixelCO, 0}, + {TK_OPTION_CUSTOM, "-dash", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, outline.dashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_PIXELS, "-dashoffset", NULL, NULL, + "0", -1, Tk_Offset(ArcItem, outline.offset), + 0, 0, 0}, + {TK_OPTION_CUSTOM, "-disableddash", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, outline.disabledDashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_COLOR, "-disabledfill", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, disabledFillColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-disabledoutline", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, outline.disabledColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-disabledoutlinestipple", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, outline.disabledStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-disabledstipple", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, disabledFillStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-disabledwidth", NULL, NULL, + "0.0", -1, Tk_Offset(ArcItem, outline.disabledWidth), + 0, &pixelCO, 0}, + {TK_OPTION_DOUBLE, "-extent", NULL, NULL, + "90", -1, Tk_Offset(ArcItem, extent), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-fill", NULL, NULL, + "black", -1, Tk_Offset(ArcItem, fillColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-offset", NULL, NULL, + "0,0", -1, Tk_Offset(ArcItem, tsoffsetPtr), + 0, &offsetCO, 0}, + {TK_OPTION_COLOR, "-outline", NULL, NULL, + "black", -1, Tk_Offset(ArcItem, outline.color), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-outlineoffset", NULL, NULL, + "0,0", -1, Tk_Offset(ArcItem, outline.tsoffsetPtr), + 0, &offsetCO, 0}, + {TK_OPTION_BITMAP, "-outlinestipple", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, outline.stipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_DOUBLE, "-start", NULL, NULL, + "0", -1, Tk_Offset(ArcItem, start), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", NULL, NULL, + PATH_DEF_STATE, -1, Tk_Offset(Tk_PathItem, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_BITMAP, "-stipple", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, fillStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-style", NULL, NULL, + NULL, -1, Tk_Offset(ArcItem, style), + TK_OPTION_NULL_OK, (ClientData) &arcStyleStrings, 0}, + {TK_OPTION_CUSTOM, "-tags", NULL, NULL, + NULL, -1, Tk_Offset(Tk_PathItem, pathTagsPtr), + TK_OPTION_NULL_OK, (ClientData) &tagsCO, 0}, + {TK_OPTION_CUSTOM, "-width", NULL, NULL, + "1.0", -1, Tk_Offset(ArcItem, outline.width), 0, &pixelCO, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * Prototypes for functions defined in this file: + */ + +static void ComputeArcBbox(Tk_PathCanvas canvas, ArcItem *arcPtr); +static int ConfigureArc(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int CreateArc(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeleteArc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayArc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable dst, + int x, int y, int width, int height); +static int ArcCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, Tcl_Obj *CONST objv[]); +static int ArcToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double ArcToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int ArcToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScaleArc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslateArc(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); +static int AngleInRange(double x, double y, + double start, double extent); +static void ComputeArcOutline(Tk_PathCanvas canvas, ArcItem *arcPtr); +static int HorizLineToArc(double x1, double x2, + double y, double rx, double ry, + double start, double extent); +static int VertLineToArc(double x, double y1, + double y2, double rx, double ry, + double start, double extent); + +/* + * The structures below defines the arc item types by means of functions that + * can be invoked by generic item code. + */ + +Tk_PathItemType tkArcType = { + "arc", /* name */ + sizeof(ArcItem), /* itemSize */ + CreateArc, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigureArc, /* configureProc */ + ArcCoords, /* coordProc */ + DeleteArc, /* deleteProc */ + DisplayArc, /* displayProc */ + 0, /* flags */ + NULL, /* bboxProc */ + ArcToPoint, /* pointProc */ + ArcToArea, /* areaProc */ + ArcToPostscript, /* postscriptProc */ + ScaleArc, /* scaleProc */ + TranslateArc, /* translateProc */ + NULL, /* indexProc */ + NULL, /* icursorProc */ + NULL, /* selectionProc */ + NULL, /* insertProc */ + NULL, /* dTextProc */ + NULL, /* nextPtr */ +}; + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +/* + *-------------------------------------------------------------- + * + * CreateArc -- + * + * This function is invoked to create a new arc 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 the interp's result; in this + * case itemPtr is left uninitialized, so it can be safely freed by the + * caller. + * + * Side effects: + * A new arc item is created. + * + *-------------------------------------------------------------- + */ + +static int +CreateArc( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas to hold new item. */ + Tk_PathItem *itemPtr, /* Record to hold new item; header has been + * initialized by caller. */ + int objc, /* Number of arguments in objv. */ + Tcl_Obj *CONST objv[]) /* Arguments describing arc. */ +{ + ArcItem *arcPtr = (ArcItem *) itemPtr; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed in order to clean up after + * errors during the the remainder of this function. + */ + + Tk_PathCreateOutline(&(arcPtr->outline)); + arcPtr->start = 0; + arcPtr->extent = 90; + arcPtr->outlinePtr = NULL; + arcPtr->numOutlinePoints = 0; + arcPtr->tsoffsetPtr = NULL; + arcPtr->fillColor = NULL; + arcPtr->activeFillColor = NULL; + arcPtr->disabledFillColor = NULL; + arcPtr->fillStipple = None; + arcPtr->activeFillStipple = None; + arcPtr->disabledFillStipple = None; + arcPtr->style = PIESLICE_STYLE; + arcPtr->fillGC = None; + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) arcPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + /* + * Process the arguments to fill in the item record. + */ + + for (i = 1; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + if (ArcCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { + goto error; + } + if (ConfigureArc(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { + return TCL_OK; + } + + error: + DeleteArc(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * ArcCoords -- + * + * This function is invoked to process the "coords" widget command on + * arcs. See the user documentation for details on what it does. + * + * Results: + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. + * + * Side effects: + * The coordinates for the given item may be changed. + * + *-------------------------------------------------------------- + */ + +static int +ArcCoords( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item whose coordinates are to be read or + * modified. */ + int objc, /* Number of coordinates supplied in objv. */ + Tcl_Obj *CONST objv[]) /* Array of coordinates: x1, y1, x2, y2, ... */ +{ + ArcItem *arcPtr = (ArcItem *) itemPtr; + + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(arcPtr->bbox[0]); + + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(arcPtr->bbox[1]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(arcPtr->bbox[2]); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(arcPtr->bbox[3]); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if ((objc == 1)||(objc == 4)) { + if (objc==1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 4) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 4, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[0], + &arcPtr->bbox[0]) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[1], + &arcPtr->bbox[1]) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[2], + &arcPtr->bbox[2]) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[3], + &arcPtr->bbox[3]) != TCL_OK)) { + return TCL_ERROR; + } + ComputeArcBbox(canvas, arcPtr); + } else { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 4, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ConfigureArc -- + * + * This function is invoked to configure various aspects of a arc item, + * such as its outline and fill colors. + * + * Results: + * A standard Tcl result code. If an error occurs, then an error message + * is left in the interp's result. + * + * Side effects: + * Configuration information, such as colors and stipple patterns, may be + * set for itemPtr. + * + *-------------------------------------------------------------- + */ + +static int +ConfigureArc( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Arc item to reconfigure. */ + int objc, /* Number of elements in objv. */ + Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ + int flags) /* Flags to pass to Tk_ConfigureWidget. */ +{ + ArcItem *arcPtr = (ArcItem *) itemPtr; + XGCValues gcValues; + GC newGC; + unsigned long mask; + int i; + Tk_Window tkwin; + Tk_TSOffset *tsoffset; + XColor *color; + Pixmap stipple; + Tk_PathState state; + + tkwin = Tk_PathCanvasTkwin(canvas); + if (TCL_OK != Tk_SetOptions(interp, (char *) arcPtr, optionTable, + objc, objv, tkwin, NULL, NULL)) { + return TCL_ERROR; + } + + state = itemPtr->state; + + /* + * A few of the options require additional processing, such as style and + * graphics contexts. + */ + + if (arcPtr->outline.activeWidth > arcPtr->outline.width || + (arcPtr->outline.activeDashPtr != NULL + && arcPtr->outline.activeDashPtr->number != 0) || + arcPtr->outline.activeColor != NULL || + arcPtr->outline.activeStipple != None || + arcPtr->activeFillColor != NULL || + arcPtr->activeFillStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + tsoffset = arcPtr->outline.tsoffsetPtr; + if (tsoffset != NULL) { + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (arcPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) ((arcPtr->bbox[0]+arcPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (arcPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (arcPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) ((arcPtr->bbox[1]+arcPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (arcPtr->bbox[2] + 0.5); + } + } + + i = (int) (arcPtr->start/360.0); + arcPtr->start -= i*360.0; + if (arcPtr->start < 0) { + arcPtr->start += 360.0; + } + i = (int) (arcPtr->extent/360.0); + arcPtr->extent -= i*360.0; + + mask = Tk_PathConfigOutlineGC(&gcValues, canvas, itemPtr, &(arcPtr->outline)); + if (mask) { + gcValues.cap_style = CapButt; + mask |= GCCapStyle; + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = None; + } + if (arcPtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), arcPtr->outline.gc); + } + arcPtr->outline.gc = newGC; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state==TK_PATHSTATE_HIDDEN) { + ComputeArcBbox(canvas, arcPtr); + return TCL_OK; + } + + color = arcPtr->fillColor; + stipple = arcPtr->fillStipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->activeFillColor!=NULL) { + color = arcPtr->activeFillColor; + } + if (arcPtr->activeFillStipple!=None) { + stipple = arcPtr->activeFillStipple; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (arcPtr->disabledFillColor!=NULL) { + color = arcPtr->disabledFillColor; + } + if (arcPtr->disabledFillStipple!=None) { + stipple = arcPtr->disabledFillStipple; + } + } + + if (arcPtr->style == ARC_STYLE) { + newGC = None; + } else if (color == NULL) { + newGC = None; + } else { + gcValues.foreground = color->pixel; + if (arcPtr->style == CHORD_STYLE) { + gcValues.arc_mode = ArcChord; + } else { + gcValues.arc_mode = ArcPieSlice; + } + mask = GCForeground|GCArcMode; + if (stipple != None) { + gcValues.stipple = stipple; + gcValues.fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } + if (arcPtr->fillGC != None) { + Tk_FreeGC(Tk_Display(tkwin), arcPtr->fillGC); + } + arcPtr->fillGC = newGC; + + tsoffset = arcPtr->tsoffsetPtr; + if (tsoffset != NULL) { + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (arcPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) ((arcPtr->bbox[0]+arcPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (arcPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (arcPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) ((arcPtr->bbox[1]+arcPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (arcPtr->bbox[3] + 0.5); + } + } + + ComputeArcBbox(canvas, arcPtr); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * DeleteArc -- + * + * This function is called to clean up the data structure associated with + * an arc item. + * + * Results: + * None. + * + * Side effects: + * Resources associated with itemPtr are released. + * + *-------------------------------------------------------------- + */ + +static void +DeleteArc( + Tk_PathCanvas canvas, /* Info about overall canvas. */ + Tk_PathItem *itemPtr, /* Item that is being deleted. */ + Display *display) /* Display containing window for canvas. */ +{ + ArcItem *arcPtr = (ArcItem *) itemPtr; + + if (arcPtr->numOutlinePoints != 0) { + ckfree((char *) arcPtr->outlinePtr); + } + if (arcPtr->fillGC != None) { + Tk_FreeGC(display, arcPtr->fillGC); + } + Tk_FreeConfigOptions((char *) arcPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +/* + *-------------------------------------------------------------- + * + * ComputeArcBbox -- + * + * This function is invoked to compute the bounding box of all the pixels + * that may be drawn as part of an arc. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header for itemPtr. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static void +ComputeArcBbox( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + ArcItem *arcPtr) /* Item whose bbox is to be recomputed. */ +{ + double tmp, center[2], point[2]; + double width; + Tk_PathState state = arcPtr->header.state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = arcPtr->outline.width; + if (width < 1.0) { + width = 1.0; + } + if (state==TK_PATHSTATE_HIDDEN) { + arcPtr->header.x1 = arcPtr->header.x2 = + arcPtr->header.y1 = arcPtr->header.y2 = -1; + return; + } else if (((TkPathCanvas *)canvas)->currentItemPtr == (Tk_PathItem *) arcPtr) { + if (arcPtr->outline.activeWidth>width) { + width = arcPtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (arcPtr->outline.disabledWidth>0) { + width = arcPtr->outline.disabledWidth; + } + } + + /* + * Make sure that the first coordinates are the lowest ones. + */ + + if (arcPtr->bbox[1] > arcPtr->bbox[3]) { + double tmp = arcPtr->bbox[3]; + + arcPtr->bbox[3] = arcPtr->bbox[1]; + arcPtr->bbox[1] = tmp; + } + if (arcPtr->bbox[0] > arcPtr->bbox[2]) { + double tmp = arcPtr->bbox[2]; + + arcPtr->bbox[2] = arcPtr->bbox[0]; + arcPtr->bbox[0] = tmp; + } + + ComputeArcOutline(canvas,arcPtr); + + /* + * To compute the bounding box, start with the the bbox formed by the two + * endpoints of the arc. Then add in the center of the arc's oval (if + * relevant) and the 3-o'clock, 6-o'clock, 9-o'clock, and 12-o'clock + * positions, if they are relevant. + */ + + arcPtr->header.x1 = arcPtr->header.x2 = (int) arcPtr->center1[0]; + arcPtr->header.y1 = arcPtr->header.y2 = (int) arcPtr->center1[1]; + TkPathIncludePoint((Tk_PathItem *) arcPtr, arcPtr->center2); + center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2; + center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2; + if (arcPtr->style == PIESLICE_STYLE) { + TkPathIncludePoint((Tk_PathItem *) arcPtr, center); + } + + tmp = -arcPtr->start; + if (tmp < 0) { + tmp += 360.0; + } + if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { + point[0] = arcPtr->bbox[2]; + point[1] = center[1]; + TkPathIncludePoint((Tk_PathItem *) arcPtr, point); + } + tmp = 90.0 - arcPtr->start; + if (tmp < 0) { + tmp += 360.0; + } + if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { + point[0] = center[0]; + point[1] = arcPtr->bbox[1]; + TkPathIncludePoint((Tk_PathItem *) arcPtr, point); + } + tmp = 180.0 - arcPtr->start; + if (tmp < 0) { + tmp += 360.0; + } + if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { + point[0] = arcPtr->bbox[0]; + point[1] = center[1]; + TkPathIncludePoint((Tk_PathItem *) arcPtr, point); + } + tmp = 270.0 - arcPtr->start; + if (tmp < 0) { + tmp += 360.0; + } + if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { + point[0] = center[0]; + point[1] = arcPtr->bbox[3]; + TkPathIncludePoint((Tk_PathItem *) arcPtr, point); + } + + /* + * Lastly, expand by the width of the arc (if the arc's outline is being + * drawn) and add one extra pixel just for safety. + */ + + if (arcPtr->outline.gc == None) { + tmp = 1; + } else { + tmp = (int) ((width + 1.0)/2.0 + 1); + } + arcPtr->header.x1 -= (int) tmp; + arcPtr->header.y1 -= (int) tmp; + arcPtr->header.x2 += (int) tmp; + arcPtr->header.y2 += (int) tmp; +} + +/* + *-------------------------------------------------------------- + * + * DisplayArc -- + * + * This function is invoked to draw an arc item in a given drawable. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation information in + * canvas. + * + *-------------------------------------------------------------- + */ + +static void +DisplayArc( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + Tk_PathItem *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, int y, /* Describes region of canvas that must be */ + int width, int height) /* redisplayed (not used). */ +{ + ArcItem *arcPtr = (ArcItem *) itemPtr; + short x1, y1, x2, y2; + int start, extent, dashnumber; + double lineWidth; + Tk_PathState state = itemPtr->state; + Pixmap stipple; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + lineWidth = arcPtr->outline.width; + if (lineWidth < 1.0) { + lineWidth = 1.0; + } + if (arcPtr->outline.dashPtr != NULL) { + dashnumber = arcPtr->outline.dashPtr->number; + } else { + dashnumber = 0; + } + stipple = arcPtr->fillStipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeWidth>lineWidth) { + lineWidth = arcPtr->outline.activeWidth; + } + if ((arcPtr->outline.activeDashPtr != NULL) && + (arcPtr->outline.activeDashPtr->number != 0)) { + dashnumber = arcPtr->outline.activeDashPtr->number; + } + if (arcPtr->activeFillStipple != None) { + stipple = arcPtr->activeFillStipple; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (arcPtr->outline.disabledWidth > 0) { + lineWidth = arcPtr->outline.disabledWidth; + } + if ((arcPtr->outline.disabledDashPtr != NULL) && + (arcPtr->outline.disabledDashPtr->number != 0)) { + dashnumber = arcPtr->outline.disabledDashPtr->number; + } + if (arcPtr->disabledFillStipple != None) { + stipple = arcPtr->disabledFillStipple; + } + } + + /* + * Compute the screen coordinates of the bounding box for the item, plus + * integer values for the angles. + */ + + Tk_PathCanvasDrawableCoords(canvas, arcPtr->bbox[0], arcPtr->bbox[1], + &x1, &y1); + Tk_PathCanvasDrawableCoords(canvas, arcPtr->bbox[2], arcPtr->bbox[3], + &x2, &y2); + if (x2 <= x1) { + x2 = x1+1; + } + if (y2 <= y1) { + y2 = y1+1; + } + start = (int) ((64*arcPtr->start) + 0.5); + extent = (int) ((64*arcPtr->extent) + 0.5); + + /* + * Display filled arc first (if wanted), then outline. If the extent is + * zero then don't invoke XFillArc or XDrawArc, since this causes some + * window servers to crash and should be a no-op anyway. + */ + + if ((arcPtr->fillGC != None) && (extent != 0)) { + if (stipple != None) { + int w = 0; + int h = 0; + Tk_TSOffset tsoffset, *tsoffsetPtr; + + tsoffset.flags = 0; + tsoffset.xoffset = 0; + tsoffset.yoffset = 0; + tsoffsetPtr = arcPtr->tsoffsetPtr; + if (tsoffsetPtr != NULL) { + int flags = tsoffsetPtr->flags; + + if (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE)) { + Tk_SizeOfBitmap(display, stipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset = *tsoffsetPtr; + tsoffset.xoffset -= w; + tsoffset.yoffset -= h; + } + Tk_PathCanvasSetOffset(canvas, arcPtr->fillGC, &tsoffset); + } + XFillArc(display, drawable, arcPtr->fillGC, x1, y1, (unsigned) (x2-x1), + (unsigned) (y2-y1), start, extent); + if (stipple != None) { + XSetTSOrigin(display, arcPtr->fillGC, 0, 0); + } + } + if (arcPtr->outline.gc != None) { + Tk_PathChangeOutlineGC(canvas, itemPtr, &arcPtr->outline); + + if (extent != 0) { + XDrawArc(display, drawable, arcPtr->outline.gc, x1, y1, + (unsigned) (x2-x1), (unsigned) (y2-y1), start, extent); + } + + /* + * If the outline width is very thin, don't use polygons to draw the + * linear parts of the outline (this often results in nothing being + * displayed); just draw lines instead. The same is done if the + * outline is dashed, because then polygons don't work. + */ + + if (lineWidth < 1.5 || dashnumber != 0) { + Tk_PathCanvasDrawableCoords(canvas, arcPtr->center1[0], + arcPtr->center1[1], &x1, &y1); + Tk_PathCanvasDrawableCoords(canvas, arcPtr->center2[0], + arcPtr->center2[1], &x2, &y2); + + if (arcPtr->style == CHORD_STYLE) { + XDrawLine(display, drawable, arcPtr->outline.gc, + x1, y1, x2, y2); + } else if (arcPtr->style == PIESLICE_STYLE) { + short cx, cy; + + Tk_PathCanvasDrawableCoords(canvas, + (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0, + (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0, &cx, &cy); + XDrawLine(display, drawable, arcPtr->outline.gc, + cx, cy, x1, y1); + XDrawLine(display, drawable, arcPtr->outline.gc, + cx, cy, x2, y2); + } + } else { + if (arcPtr->style == CHORD_STYLE) { + TkPathFillPolygon(canvas, arcPtr->outlinePtr, CHORD_OUTLINE_PTS, + display, drawable, arcPtr->outline.gc, None); + } else if (arcPtr->style == PIESLICE_STYLE) { + TkPathFillPolygon(canvas, arcPtr->outlinePtr, PIE_OUTLINE1_PTS, + display, drawable, arcPtr->outline.gc, None); + TkPathFillPolygon(canvas, arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, + PIE_OUTLINE2_PTS, display, drawable, + arcPtr->outline.gc, None); + } + } + + Tk_PathResetOutlineGC(canvas, itemPtr, &(arcPtr->outline)); + } +} + +/* + *-------------------------------------------------------------- + * + * ArcToPoint -- + * + * Computes the distance from a given point to a given arc, in canvas + * units. + * + * Results: + * The return value is 0 if the point whose x and y coordinates are + * coordPtr[0] and coordPtr[1] is inside the arc. If the point isn't + * inside the arc then the return value is the distance from the point to + * the arc. If itemPtr is filled, then anywhere in the interior is + * considered "inside"; if itemPtr isn't filled, then "inside" means only + * the area occupied by the outline. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static double +ArcToPoint( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + double *pointPtr) /* Pointer to x and y coordinates. */ +{ + ArcItem *arcPtr = (ArcItem *) itemPtr; + double vertex[2], pointAngle, diff, dist, newDist; + double poly[8], polyDist, width, t1, t2; + int filled, angleInRange; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = (double) arcPtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeWidth>width) { + width = (double) arcPtr->outline.activeWidth; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (arcPtr->outline.disabledWidth>0) { + width = (double) arcPtr->outline.disabledWidth; + } + } + + /* + * See if the point is within the angular range of the arc. Remember, X + * angles are backwards from the way we'd normally think of them. Also, + * compensate for any eccentricity of the oval. + */ + + vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; + vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; + t1 = arcPtr->bbox[3] - arcPtr->bbox[1]; + if (t1 != 0.0) { + t1 = (pointPtr[1] - vertex[1]) / t1; + } + t2 = arcPtr->bbox[2] - arcPtr->bbox[0]; + if (t2 != 0.0) { + t2 = (pointPtr[0] - vertex[0]) / t2; + } + if ((t1 == 0.0) && (t2 == 0.0)) { + pointAngle = 0; + } else { + pointAngle = -atan2(t1, t2)*180/PI; + } + diff = pointAngle - arcPtr->start; + diff -= ((int) (diff/360.0) * 360.0); + if (diff < 0) { + diff += 360.0; + } + angleInRange = (diff <= arcPtr->extent) || + ((arcPtr->extent < 0) && ((diff - 360.0) >= arcPtr->extent)); + + /* + * Now perform different tests depending on what kind of arc we're dealing + * with. + */ + + if (arcPtr->style == ARC_STYLE) { + if (angleInRange) { + return TkOvalToPoint(arcPtr->bbox, width, 0, pointPtr); + } + dist = hypot(pointPtr[0] - arcPtr->center1[0], + pointPtr[1] - arcPtr->center1[1]); + newDist = hypot(pointPtr[0] - arcPtr->center2[0], + pointPtr[1] - arcPtr->center2[1]); + if (newDist < dist) { + return newDist; + } + return dist; + } + + if ((arcPtr->fillGC != None) || (arcPtr->outline.gc == None)) { + filled = 1; + } else { + filled = 0; + } + if (arcPtr->outline.gc == None) { + width = 0.0; + } + + if (arcPtr->style == PIESLICE_STYLE) { + if (width > 1.0) { + dist = TkPolygonToPoint(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, + pointPtr); + newDist = TkPolygonToPoint(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, + PIE_OUTLINE2_PTS, pointPtr); + } else { + dist = TkLineToPoint(vertex, arcPtr->center1, pointPtr); + newDist = TkLineToPoint(vertex, arcPtr->center2, pointPtr); + } + if (newDist < dist) { + dist = newDist; + } + if (angleInRange) { + newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr); + if (newDist < dist) { + dist = newDist; + } + } + return dist; + } + + /* + * This is a chord-style arc. We have to deal specially with the + * triangular piece that represents the difference between a chord-style + * arc and a pie-slice arc (for small angles this piece is excluded here + * where it would be included for pie slices; for large angles the piece + * is included here but would be excluded for pie slices). + */ + + if (width > 1.0) { + dist = TkPolygonToPoint(arcPtr->outlinePtr, CHORD_OUTLINE_PTS, + pointPtr); + } else { + dist = TkLineToPoint(arcPtr->center1, arcPtr->center2, pointPtr); + } + poly[0] = poly[6] = vertex[0]; + poly[1] = poly[7] = vertex[1]; + poly[2] = arcPtr->center1[0]; + poly[3] = arcPtr->center1[1]; + poly[4] = arcPtr->center2[0]; + poly[5] = arcPtr->center2[1]; + polyDist = TkPolygonToPoint(poly, 4, pointPtr); + if (angleInRange) { + if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0) + || (polyDist > 0.0)) { + newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr); + if (newDist < dist) { + dist = newDist; + } + } + } else { + if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)) { + if (filled && (polyDist < dist)) { + dist = polyDist; + } + } + } + return dist; +} + +/* + *-------------------------------------------------------------- + * + * ArcToArea -- + * + * This function is called to determine whether an item lies entirely + * inside, entirely outside, or overlapping a given area. + * + * Results: + * -1 is returned if the item is entirely outside the area given by + * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given + * area. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +ArcToArea( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against arc. */ + double *rectPtr) /* Pointer to array of four coordinates (x1, + * y1, x2, y2) describing rectangular area. */ +{ + ArcItem *arcPtr = (ArcItem *) itemPtr; + double rx, ry; /* Radii for transformed oval: these define an + * oval centered at the origin. */ + double tRect[4]; /* Transformed version of x1, y1, x2, y2, for + * coord. system where arc is centered on the + * origin. */ + double center[2], width, angle, tmp; + double points[20], *pointPtr; + int numPoints, filled; + int inside; /* Non-zero means every test so far suggests + * that arc is inside rectangle. 0 means every + * test so far shows arc to be outside of + * rectangle. */ + int newInside; + Tk_PathState state = itemPtr->state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + width = (double) arcPtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeWidth>width) { + width = (double) arcPtr->outline.activeWidth; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (arcPtr->outline.disabledWidth>0) { + width = (double) arcPtr->outline.disabledWidth; + } + } + + if ((arcPtr->fillGC != None) || (arcPtr->outline.gc == None)) { + filled = 1; + } else { + filled = 0; + } + if (arcPtr->outline.gc == None) { + width = 0.0; + } + + /* + * Transform both the arc and the rectangle so that the arc's oval is + * centered on the origin. + */ + + center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; + center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; + tRect[0] = rectPtr[0] - center[0]; + tRect[1] = rectPtr[1] - center[1]; + tRect[2] = rectPtr[2] - center[0]; + tRect[3] = rectPtr[3] - center[1]; + rx = arcPtr->bbox[2] - center[0] + width/2.0; + ry = arcPtr->bbox[3] - center[1] + width/2.0; + + /* + * Find the extreme points of the arc and see whether these are all inside + * the rectangle (in which case we're done), partly in and partly out (in + * which case we're done), or all outside (in which case we have more work + * to do). The extreme points include the following, which are checked in + * order: + * + * 1. The outside points of the arc, corresponding to start and extent. + * 2. The center of the arc (but only in pie-slice mode). + * 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc includes + * those angles). + */ + + pointPtr = points; + angle = -arcPtr->start*(PI/180.0); + pointPtr[0] = rx*cos(angle); + pointPtr[1] = ry*sin(angle); + angle += -arcPtr->extent*(PI/180.0); + pointPtr[2] = rx*cos(angle); + pointPtr[3] = ry*sin(angle); + numPoints = 2; + pointPtr += 4; + + if ((arcPtr->style == PIESLICE_STYLE) && (arcPtr->extent < 180.0)) { + pointPtr[0] = 0.0; + pointPtr[1] = 0.0; + numPoints++; + pointPtr += 2; + } + + tmp = -arcPtr->start; + if (tmp < 0) { + tmp += 360.0; + } + if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { + pointPtr[0] = rx; + pointPtr[1] = 0.0; + numPoints++; + pointPtr += 2; + } + tmp = 90.0 - arcPtr->start; + if (tmp < 0) { + tmp += 360.0; + } + if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { + pointPtr[0] = 0.0; + pointPtr[1] = -ry; + numPoints++; + pointPtr += 2; + } + tmp = 180.0 - arcPtr->start; + if (tmp < 0) { + tmp += 360.0; + } + if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { + pointPtr[0] = -rx; + pointPtr[1] = 0.0; + numPoints++; + pointPtr += 2; + } + tmp = 270.0 - arcPtr->start; + if (tmp < 0) { + tmp += 360.0; + } + if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) { + pointPtr[0] = 0.0; + pointPtr[1] = ry; + numPoints++; + } + + /* + * Now that we've located the extreme points, loop through them all to see + * which are inside the rectangle. + */ + + inside = (points[0] > tRect[0]) && (points[0] < tRect[2]) + && (points[1] > tRect[1]) && (points[1] < tRect[3]); + for (pointPtr = points+2; numPoints > 1; pointPtr += 2, numPoints--) { + newInside = (pointPtr[0] > tRect[0]) && (pointPtr[0] < tRect[2]) + && (pointPtr[1] > tRect[1]) && (pointPtr[1] < tRect[3]); + if (newInside != inside) { + return 0; + } + } + + if (inside) { + return 1; + } + + /* + * So far, oval appears to be outside rectangle, but can't yet tell for + * sure. Next, test each of the four sides of the rectangle against the + * bounding region for the arc. If any intersections are found, then + * return "overlapping". First, test against the polygon(s) forming the + * sides of a chord or pie-slice. + */ + + if (arcPtr->style == PIESLICE_STYLE) { + if (width >= 1.0) { + if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS, + rectPtr) != -1) { + return 0; + } + if (TkPolygonToArea(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, + PIE_OUTLINE2_PTS, rectPtr) != -1) { + return 0; + } + } else { + if ((TkLineToArea(center, arcPtr->center1, rectPtr) != -1) || + (TkLineToArea(center, arcPtr->center2, rectPtr) != -1)) { + return 0; + } + } + } else if (arcPtr->style == CHORD_STYLE) { + if (width >= 1.0) { + if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS, + rectPtr) != -1) { + return 0; + } + } else { + if (TkLineToArea(arcPtr->center1, arcPtr->center2, + rectPtr) != -1) { + return 0; + } + } + } + + /* + * Next check for overlap between each of the four sides and the outer + * perimiter of the arc. If the arc isn't filled, then also check the + * inner perimeter of the arc. + */ + + if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start, + arcPtr->extent) + || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry, + arcPtr->start, arcPtr->extent) + || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry, + arcPtr->start, arcPtr->extent) + || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry, + arcPtr->start, arcPtr->extent)) { + return 0; + } + if ((width > 1.0) && !filled) { + rx -= width; + ry -= width; + if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start, + arcPtr->extent) + || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry, + arcPtr->start, arcPtr->extent) + || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry, + arcPtr->start, arcPtr->extent) + || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry, + arcPtr->start, arcPtr->extent)) { + return 0; + } + } + + /* + * The arc still appears to be totally disjoint from the rectangle, but + * it's also possible that the rectangle is totally inside the arc. Do one + * last check, which is to check one point of the rectangle to see if it's + * inside the arc. If it is, we've got overlap. If it isn't, the arc's + * really outside the rectangle. + */ + + if (ArcToPoint(canvas, itemPtr, rectPtr) == 0.0) { + return 0; + } + return -1; +} + +/* + *-------------------------------------------------------------- + * + * ScaleArc -- + * + * This function is invoked to rescale an arc item. + * + * Results: + * None. + * + * Side effects: + * The arc 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 +ScaleArc( + Tk_PathCanvas canvas, /* Canvas containing arc. */ + Tk_PathItem *itemPtr, /* Arc to be scaled. */ + double originX, /* Origin about which to scale rect. */ + double originY, + double scaleX, /* Amount to scale in X direction. */ + double scaleY) /* Amount to scale in Y direction. */ +{ + ArcItem *arcPtr = (ArcItem *) itemPtr; + + arcPtr->bbox[0] = originX + scaleX*(arcPtr->bbox[0] - originX); + arcPtr->bbox[1] = originY + scaleY*(arcPtr->bbox[1] - originY); + arcPtr->bbox[2] = originX + scaleX*(arcPtr->bbox[2] - originX); + arcPtr->bbox[3] = originY + scaleY*(arcPtr->bbox[3] - originY); + ComputeArcBbox(canvas, arcPtr); +} + +/* + *-------------------------------------------------------------- + * + * TranslateArc -- + * + * This function is called to move an arc by a given amount. + * + * Results: + * None. + * + * Side effects: + * The position of the arc is offset by (xDelta, yDelta), and the + * bounding box is updated in the generic part of the item structure. + * + *-------------------------------------------------------------- + */ + +static void +TranslateArc( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item that is being moved. */ + double deltaX, /* Amount by which item is to be moved. */ + double deltaY) +{ + ArcItem *arcPtr = (ArcItem *) itemPtr; + + arcPtr->bbox[0] += deltaX; + arcPtr->bbox[1] += deltaY; + arcPtr->bbox[2] += deltaX; + arcPtr->bbox[3] += deltaY; + ComputeArcBbox(canvas, arcPtr); +} + +/* + *-------------------------------------------------------------- + * + * ComputeArcOutline -- + * + * This function creates a polygon describing everything in the outline + * for an arc except what's in the curved part. For a "pie slice" arc + * this is a V-shaped chunk, and for a "chord" arc this is a linear chunk + * (with cutaway corners). For "arc" arcs, this stuff isn't relevant. + * + * Results: + * None. + * + * Side effects: + * The information at arcPtr->outlinePtr gets modified, and storage for + * arcPtr->outlinePtr may be allocated or freed. + * + *-------------------------------------------------------------- + */ + +static void +ComputeArcOutline( + Tk_PathCanvas canvas, /* Information about overall canvas. */ + ArcItem *arcPtr) /* Information about arc. */ +{ + double sin1, cos1, sin2, cos2, angle, width, halfWidth; + double boxWidth, boxHeight; + double vertex[2], corner1[2], corner2[2]; + double *outlinePtr; + Tk_PathState state = arcPtr->header.state; + + /* + * Make sure that the outlinePtr array is large enough to hold either a + * chord or pie-slice outline. + */ + + if (arcPtr->numOutlinePoints == 0) { + arcPtr->outlinePtr = (double *) ckalloc((unsigned) + (26 * sizeof(double))); + arcPtr->numOutlinePoints = 22; + } + outlinePtr = arcPtr->outlinePtr; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + /* + * First compute the two points that lie at the centers of the ends of the + * curved arc segment, which are marked with X's in the figure below: + * + * + * * * * + * * * + * * * * * + * * * * * + * * * * * + * X * * X + * + * The code is tricky because the arc can be ovular in shape. It computes + * the position for a unit circle, and then scales to fit the shape of the + * arc's bounding box. + * + * Also, watch out because angles go counter-clockwise like you might + * expect, but the y-coordinate system is inverted. To handle this, just + * negate the angles in all the computations. + */ + + boxWidth = arcPtr->bbox[2] - arcPtr->bbox[0]; + boxHeight = arcPtr->bbox[3] - arcPtr->bbox[1]; + angle = -arcPtr->start*PI/180.0; + sin1 = sin(angle); + cos1 = cos(angle); + angle -= arcPtr->extent*PI/180.0; + sin2 = sin(angle); + cos2 = cos(angle); + vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0; + vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0; + arcPtr->center1[0] = vertex[0] + cos1*boxWidth/2.0; + arcPtr->center1[1] = vertex[1] + sin1*boxHeight/2.0; + arcPtr->center2[0] = vertex[0] + cos2*boxWidth/2.0; + arcPtr->center2[1] = vertex[1] + sin2*boxHeight/2.0; + + /* + * Next compute the "outermost corners" of the arc, which are marked with + * X's in the figure below: + * + * * * * + * * * + * * * * * + * * * * * + * X * * X + * * * + * + * The code below is tricky because it has to handle eccentricity in the + * shape of the oval. The key in the code below is to realize that the + * slope of the line from arcPtr->center1 to corner1 is (boxWidth*sin1) + * divided by (boxHeight*cos1), and similarly for arcPtr->center2 and + * corner2. These formulas can be computed from the formula for the oval. + */ + + width = arcPtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == (Tk_PathItem *) arcPtr) { + if (arcPtr->outline.activeWidth>arcPtr->outline.width) { + width = arcPtr->outline.activeWidth; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (arcPtr->outline.disabledWidth>arcPtr->outline.width) { + width = arcPtr->outline.disabledWidth; + } + } + halfWidth = width/2.0; + + if (((boxWidth*sin1) == 0.0) && ((boxHeight*cos1) == 0.0)) { + angle = 0.0; + } else { + angle = atan2(boxWidth*sin1, boxHeight*cos1); + } + corner1[0] = arcPtr->center1[0] + cos(angle)*halfWidth; + corner1[1] = arcPtr->center1[1] + sin(angle)*halfWidth; + if (((boxWidth*sin2) == 0.0) && ((boxHeight*cos2) == 0.0)) { + angle = 0.0; + } else { + angle = atan2(boxWidth*sin2, boxHeight*cos2); + } + corner2[0] = arcPtr->center2[0] + cos(angle)*halfWidth; + corner2[1] = arcPtr->center2[1] + sin(angle)*halfWidth; + + /* + * For a chord outline, generate a six-sided polygon with three points for + * each end of the chord. The first and third points for each end are butt + * points generated on either side of the center point. The second point + * is the corner point. + */ + + if (arcPtr->style == CHORD_STYLE) { + outlinePtr[0] = outlinePtr[12] = corner1[0]; + outlinePtr[1] = outlinePtr[13] = corner1[1]; + TkGetButtPoints(arcPtr->center2, arcPtr->center1, + width, 0, outlinePtr+10, outlinePtr+2); + outlinePtr[4] = arcPtr->center2[0] + outlinePtr[2] + - arcPtr->center1[0]; + outlinePtr[5] = arcPtr->center2[1] + outlinePtr[3] + - arcPtr->center1[1]; + outlinePtr[6] = corner2[0]; + outlinePtr[7] = corner2[1]; + outlinePtr[8] = arcPtr->center2[0] + outlinePtr[10] + - arcPtr->center1[0]; + outlinePtr[9] = arcPtr->center2[1] + outlinePtr[11] + - arcPtr->center1[1]; + } else if (arcPtr->style == PIESLICE_STYLE) { + /* + * For pie slices, generate two polygons, one for each side of the pie + * slice. The first arm has a shape like this, where the center of the + * oval is X, arcPtr->center1 is at Y, and corner1 is at Z: + * + * _____________________ + * | \ + * | \ + * X Y Z + * | / + * |_____________________/ + */ + + TkGetButtPoints(arcPtr->center1, vertex, width, 0, + outlinePtr, outlinePtr+2); + outlinePtr[4] = arcPtr->center1[0] + outlinePtr[2] - vertex[0]; + outlinePtr[5] = arcPtr->center1[1] + outlinePtr[3] - vertex[1]; + outlinePtr[6] = corner1[0]; + outlinePtr[7] = corner1[1]; + outlinePtr[8] = arcPtr->center1[0] + outlinePtr[0] - vertex[0]; + outlinePtr[9] = arcPtr->center1[1] + outlinePtr[1] - vertex[1]; + outlinePtr[10] = outlinePtr[0]; + outlinePtr[11] = outlinePtr[1]; + + /* + * The second arm has a shape like this: + * + * ______________________ + * / \ + * / \ + * Z Y X / + * \ / + * \______________________/ + * + * Similar to above X is the center of the oval/circle, Y is + * arcPtr->center2, and Z is corner2. The extra jog out to the left of + * X is needed in or to produce a butted joint with the first arm; the + * corner to the right of X is one of the first two points of the + * first arm, depending on extent. + */ + + TkGetButtPoints(arcPtr->center2, vertex, width, 0, + outlinePtr+12, outlinePtr+16); + if ((arcPtr->extent > 180) || + ((arcPtr->extent < 0) && (arcPtr->extent > -180))) { + outlinePtr[14] = outlinePtr[0]; + outlinePtr[15] = outlinePtr[1]; + } else { + outlinePtr[14] = outlinePtr[2]; + outlinePtr[15] = outlinePtr[3]; + } + outlinePtr[18] = arcPtr->center2[0] + outlinePtr[16] - vertex[0]; + outlinePtr[19] = arcPtr->center2[1] + outlinePtr[17] - vertex[1]; + outlinePtr[20] = corner2[0]; + outlinePtr[21] = corner2[1]; + outlinePtr[22] = arcPtr->center2[0] + outlinePtr[12] - vertex[0]; + outlinePtr[23] = arcPtr->center2[1] + outlinePtr[13] - vertex[1]; + outlinePtr[24] = outlinePtr[12]; + outlinePtr[25] = outlinePtr[13]; + } +} + +/* + *-------------------------------------------------------------- + * + * HorizLineToArc -- + * + * Determines whether a horizontal line segment intersects a given arc. + * + * Results: + * The return value is 1 if the given line intersects the infinitely-thin + * arc section defined by rx, ry, start, and extent, and 0 otherwise. + * Only the perimeter of the arc is checked: interior areas (e.g. chord + * or pie-slice) are not checked. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +HorizLineToArc( + double x1, double x2, /* X-coords of endpoints of line segment. X1 + * must be <= x2. */ + double y, /* Y-coordinate of line segment. */ + double rx, double ry, /* These x- and y-radii define an oval + * centered at the origin. */ + double start, double extent)/* Angles that define extent of arc, in the + * standard fashion for this module. */ +{ + double tmp, x; + double tx, ty; /* Coordinates of intersection point in + * transformed coordinate system. */ + + /* + * Compute the x-coordinate of one possible intersection point between the + * arc and the line. Use a transformed coordinate system where the oval is + * a unit circle centered at the origin. Then scale back to get actual + * x-coordinate. + */ + + ty = y/ry; + tmp = 1 - ty*ty; + if (tmp < 0) { + return 0; + } + tx = sqrt(tmp); + x = tx*rx; + + /* + * Test both intersection points. + */ + + if ((x >= x1) && (x <= x2) && AngleInRange(tx, ty, start, extent)) { + return 1; + } + if ((-x >= x1) && (-x <= x2) && AngleInRange(-tx, ty, start, extent)) { + return 1; + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * VertLineToArc -- + * + * Determines whether a vertical line segment intersects a given arc. + * + * Results: + * The return value is 1 if the given line intersects the infinitely-thin + * arc section defined by rx, ry, start, and extent, and 0 otherwise. + * Only the perimeter of the arc is checked: interior areas (e.g. chord + * or pie-slice) are not checked. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +VertLineToArc( + double x, /* X-coordinate of line segment. */ + double y1, double y2, /* Y-coords of endpoints of line segment. Y1 + * must be <= y2. */ + double rx, double ry, /* These x- and y-radii define an oval + * centered at the origin. */ + double start, double extent)/* Angles that define extent of arc, in the + * standard fashion for this module. */ +{ + double tmp, y; + double tx, ty; /* Coordinates of intersection point in + * transformed coordinate system. */ + + /* + * Compute the y-coordinate of one possible intersection point between the + * arc and the line. Use a transformed coordinate system where the oval is + * a unit circle centered at the origin. Then scale back to get actual + * y-coordinate. + */ + + tx = x/rx; + tmp = 1 - tx*tx; + if (tmp < 0) { + return 0; + } + ty = sqrt(tmp); + y = ty*ry; + + /* + * Test both intersection points. + */ + + if ((y > y1) && (y < y2) && AngleInRange(tx, ty, start, extent)) { + return 1; + } + if ((-y > y1) && (-y < y2) && AngleInRange(tx, -ty, start, extent)) { + return 1; + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * AngleInRange -- + * + * Determine whether the angle from the origin to a given point is within + * a given range. + * + * Results: + * The return value is 1 if the angle from (0,0) to (x,y) is in the range + * given by start and extent, where angles are interpreted in the + * standard way for ovals (meaning backwards from normal interpretation). + * Otherwise the return value is 0. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +AngleInRange( + double x, double y, /* Coordinate of point; angle measured from + * origin to here, relative to x-axis. */ + double start, /* First angle, degrees, >=0, <=360. */ + double extent) /* Size of arc in degrees >=-360, <=360. */ +{ + double diff; + + if ((x == 0.0) && (y == 0.0)) { + return 1; + } + diff = -atan2(y, x); + diff = diff*(180.0/PI) - start; + while (diff > 360.0) { + diff -= 360.0; + } + while (diff < 0.0) { + diff += 360.0; + } + if (extent >= 0) { + return diff <= extent; + } + return (diff-360.0) >= extent; +} + +/* + *-------------------------------------------------------------- + * + * ArcToPostscript -- + * + * This function is called to generate Postscript for arc items. + * + * Results: + * The return value is a standard Tcl result. If an error occurs in + * generating Postscript then an error message is left in the interp's + * 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 +ArcToPostscript( + Tcl_Interp *interp, /* Leave Postscript or error message here. */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + Tk_PathItem *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. */ +{ + ArcItem *arcPtr = (ArcItem *) itemPtr; + char buffer[400]; + double y1, y2, ang1, ang2; + XColor *color; + Pixmap stipple; + XColor *fillColor; + Pixmap fillStipple; + Tk_PathState state = itemPtr->state; + + y1 = Tk_PathCanvasPsY(canvas, arcPtr->bbox[1]); + y2 = Tk_PathCanvasPsY(canvas, arcPtr->bbox[3]); + ang1 = arcPtr->start; + ang2 = ang1 + arcPtr->extent; + if (ang2 < ang1) { + ang1 = ang2; + ang2 = arcPtr->start; + } + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + color = arcPtr->outline.color; + stipple = arcPtr->outline.stipple; + fillColor = arcPtr->fillColor; + fillStipple = arcPtr->fillStipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (arcPtr->outline.activeColor!=NULL) { + color = arcPtr->outline.activeColor; + } + if (arcPtr->outline.activeStipple!=None) { + stipple = arcPtr->outline.activeStipple; + } + if (arcPtr->activeFillColor!=NULL) { + fillColor = arcPtr->activeFillColor; + } + if (arcPtr->activeFillStipple!=None) { + fillStipple = arcPtr->activeFillStipple; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (arcPtr->outline.disabledColor!=NULL) { + color = arcPtr->outline.disabledColor; + } + if (arcPtr->outline.disabledStipple!=None) { + stipple = arcPtr->outline.disabledStipple; + } + if (arcPtr->disabledFillColor!=NULL) { + fillColor = arcPtr->disabledFillColor; + } + if (arcPtr->disabledFillStipple!=None) { + fillStipple = arcPtr->disabledFillStipple; + } + } + + /* + * If the arc is filled, output Postscript for the interior region of the + * arc. + */ + + if (arcPtr->fillGC != None) { + sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n", + (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2, + (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2); + Tcl_AppendResult(interp, buffer, NULL); + if (arcPtr->style == CHORD_STYLE) { + sprintf(buffer, "0 0 1 %.15g %.15g arc closepath\nsetmatrix\n", + ang1, ang2); + } else { + sprintf(buffer, + "0 0 moveto 0 0 1 %.15g %.15g arc closepath\nsetmatrix\n", + ang1, ang2); + } + Tcl_AppendResult(interp, buffer, NULL); + if (Tk_PathCanvasPsColor(interp, canvas, fillColor) != TCL_OK) { + return TCL_ERROR; + } + if (fillStipple != None) { + Tcl_AppendResult(interp, "clip ", NULL); + if (Tk_PathCanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { + return TCL_ERROR; + } + if (arcPtr->outline.gc != None) { + Tcl_AppendResult(interp, "grestore gsave\n", NULL); + } + } else { + Tcl_AppendResult(interp, "fill\n", NULL); + } + } + + /* + * If there's an outline for the arc, draw it. + */ + + if (arcPtr->outline.gc != None) { + sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n", + (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2, + (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2); + Tcl_AppendResult(interp, buffer, NULL); + sprintf(buffer, "0 0 1 %.15g %.15g", ang1, ang2); + Tcl_AppendResult(interp, buffer, + " arc\nsetmatrix\n0 setlinecap\n", NULL); + if (Tk_PathCanvasPsOutline(canvas, itemPtr, &(arcPtr->outline)) != TCL_OK){ + return TCL_ERROR; + } + if (arcPtr->style != ARC_STYLE) { + Tcl_AppendResult(interp, "grestore gsave\n", NULL); + if (arcPtr->style == CHORD_STYLE) { + Tk_PathCanvasPsPath(interp, canvas, arcPtr->outlinePtr, + CHORD_OUTLINE_PTS); + } else { + Tk_PathCanvasPsPath(interp, canvas, arcPtr->outlinePtr, + PIE_OUTLINE1_PTS); + if (Tk_PathCanvasPsColor(interp, canvas, color) + != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "clip ", NULL); + if (Tk_PathCanvasPsStipple(interp, canvas, stipple) != TCL_OK){ + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "fill\n", NULL); + } + Tcl_AppendResult(interp, "grestore gsave\n", NULL); + Tk_PathCanvasPsPath(interp, canvas, + arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS, + PIE_OUTLINE2_PTS); + } + if (Tk_PathCanvasPsColor(interp, canvas, color) + != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "clip ", NULL); + if (Tk_PathCanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "fill\n", NULL); + } + } + } + + return TCL_OK; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/pd/tkpath/generic/tkpCanvBmap.c b/pd/tkpath/generic/tkpCanvBmap.c new file mode 100644 index 0000000000000000000000000000000000000000..24477f61e53e380198289209251ca1e548f8d635 --- /dev/null +++ b/pd/tkpath/generic/tkpCanvBmap.c @@ -0,0 +1,980 @@ +/* + * tkpCanvBmap.c -- + * + * This file implements bitmap items for canvas widgets. + * + * Copyright (c) 1992-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvBmap.c,v 1.2 2008/06/21 14:58:42 matben Exp $ + */ + +#include <stdio.h> +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" + +/* + * The structure below defines the record for each bitmap item. + */ + +typedef struct BitmapItem { + Tk_PathItem header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + double x, y; /* Coordinates of positioning point for + * bitmap. */ + Tk_Anchor anchor; /* Where to anchor bitmap relative to (x,y) */ + Pixmap bitmap; /* Bitmap to display in window. */ + Pixmap activeBitmap; /* Bitmap to display in window. */ + Pixmap disabledBitmap; /* Bitmap to display in window. */ + XColor *fgColor; /* Foreground color to use for bitmap. */ + XColor *activeFgColor; /* Foreground color to use for bitmap. */ + XColor *disabledFgColor; /* Foreground color to use for bitmap. */ + XColor *bgColor; /* Background color to use for bitmap. */ + XColor *activeBgColor; /* Background color to use for bitmap. */ + XColor *disabledBgColor; /* Background color to use for bitmap. */ + GC gc; /* Graphics context to use for drawing bitmap + * on screen. */ +} BitmapItem; + +/* + * Information used for parsing configuration specs. If you change any of the + * default strings, be sure to change the corresponding default values in + * CreateLine. + */ + +#define PATH_DEF_STATE "normal" + +/* These MUST be kept in sync with enums! X.h */ + +static char *stateStrings[] = { + "active", "disabled", "normal", "hidden", NULL +}; + +static Tk_ObjCustomOption tagsCO = { + "tags", + Tk_PathCanvasTagsOptionSetProc, + Tk_PathCanvasTagsOptionGetProc, + Tk_PathCanvasTagsOptionRestoreProc, + Tk_PathCanvasTagsOptionFreeProc, + (ClientData) NULL +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_COLOR, "-activebackground", NULL, NULL, + NULL, -1, Tk_Offset(BitmapItem, activeBgColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-activebitmap", NULL, NULL, + NULL, -1, Tk_Offset(BitmapItem, activeBitmap), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-activeforeground", NULL, NULL, + NULL, -1, Tk_Offset(BitmapItem, activeFgColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_ANCHOR, "-anchor", NULL, NULL, + "center", -1, Tk_Offset(BitmapItem, anchor), 0, 0, 0}, + {TK_OPTION_COLOR, "-background", NULL, NULL, + NULL, -1, Tk_Offset(BitmapItem, bgColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-bitmap", NULL, NULL, + NULL, -1, Tk_Offset(BitmapItem, bitmap), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-disabledbackground", NULL, NULL, + NULL, -1, Tk_Offset(BitmapItem, disabledBgColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-disabledbitmap", NULL, NULL, + NULL, -1, Tk_Offset(BitmapItem, disabledBitmap), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-disabledforeground", NULL, NULL, + NULL, -1, Tk_Offset(BitmapItem, disabledFgColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-foreground", NULL, NULL, + "black", -1, Tk_Offset(BitmapItem, fgColor), + 0, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", NULL, NULL, + PATH_DEF_STATE, -1, Tk_Offset(Tk_PathItem, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_CUSTOM, "-tags", NULL, NULL, + NULL, -1, Tk_Offset(Tk_PathItem, pathTagsPtr), + TK_OPTION_NULL_OK, (ClientData) &tagsCO, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * Prototypes for functions defined in this file: + */ + +static int BitmapCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[]); +static int BitmapToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double BitmapToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int BitmapToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ComputeBitmapBbox(Tk_PathCanvas canvas, + BitmapItem *bmapPtr); +static int ConfigureBitmap(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int TkcCreateBitmap(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeleteBitmap(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayBitmap(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable dst, + int x, int y, int width, int height); +static void ScaleBitmap(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslateBitmap(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + double deltaX, double deltaY); + +/* + * The structures below defines the bitmap item type in terms of functions + * that can be invoked by generic item code. + */ + +Tk_PathItemType tkBitmapType = { + "bitmap", /* name */ + sizeof(BitmapItem), /* itemSize */ + TkcCreateBitmap, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigureBitmap, /* configureProc */ + BitmapCoords, /* coordProc */ + DeleteBitmap, /* deleteProc */ + DisplayBitmap, /* displayProc */ + 0, /* flags */ + NULL, /* bboxProc */ + BitmapToPoint, /* pointProc */ + BitmapToArea, /* areaProc */ + BitmapToPostscript, /* postscriptProc */ + ScaleBitmap, /* scaleProc */ + TranslateBitmap, /* translateProc */ + NULL, /* indexProc */ + NULL, /* icursorProc */ + NULL, /* selectionProc */ + NULL, /* insertProc */ + NULL, /* dTextProc */ + NULL, /* nextPtr */ +}; + +/* + *-------------------------------------------------------------- + * + * TkcCreateBitmap -- + * + * This function is invoked to create a new bitmap 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 the interp's result; in this + * case itemPtr is left uninitialized, so it can be safely freed by the + * caller. + * + * Side effects: + * A new bitmap item is created. + * + *-------------------------------------------------------------- + */ + +static int +TkcCreateBitmap( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas to hold new item. */ + Tk_PathItem *itemPtr, /* Record to hold new item; header has been + * initialized by caller. */ + int objc, /* Number of arguments in objv. */ + Tcl_Obj *CONST objv[]) /* Arguments describing rectangle. */ +{ + BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Initialize item's record. + */ + + bmapPtr->anchor = TK_ANCHOR_CENTER; + bmapPtr->bitmap = None; + bmapPtr->activeBitmap = None; + bmapPtr->disabledBitmap = None; + bmapPtr->fgColor = NULL; + bmapPtr->activeFgColor = NULL; + bmapPtr->disabledFgColor = NULL; + bmapPtr->bgColor = NULL; + bmapPtr->activeBgColor = NULL; + bmapPtr->disabledBgColor = NULL; + bmapPtr->gc = None; + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) bmapPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + /* + * Process the arguments to fill in the item record. Only 1 (list) or 2 (x + * y) coords are allowed. + */ + + if (objc == 1) { + i = 1; + } else { + char *arg = Tcl_GetString(objv[1]); + i = 2; + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + i = 1; + } + } + if (BitmapCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { + goto error; + } + if (ConfigureBitmap(interp, canvas, itemPtr, objc-i, objv+i, 0) + == TCL_OK) { + return TCL_OK; + } + + error: + DeleteBitmap(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * BitmapCoords -- + * + * This function is invoked to process the "coords" widget command on + * bitmap items. See the user documentation for details on what it does. + * + * Results: + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. + * + * Side effects: + * The coordinates for the given item may be changed. + * + *-------------------------------------------------------------- + */ + +static int +BitmapCoords( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item whose coordinates are to be read or + * modified. */ + int objc, /* Number of coordinates supplied in objv. */ + Tcl_Obj *CONST objv[]) /* Array of coordinates: x1, y1, x2, y2, ... */ +{ + BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewObj(); + + Tcl_Obj *subobj = Tcl_NewDoubleObj(bmapPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(bmapPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (objc < 3) { + if (objc == 1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 2) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[0], + &bmapPtr->x) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[1], + &bmapPtr->y) != TCL_OK)) { + return TCL_ERROR; + } + ComputeBitmapBbox(canvas, bmapPtr); + } else { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ConfigureBitmap -- + * + * This function is invoked to configure various aspects of a bitmap + * item, such as its anchor position. + * + * Results: + * A standard Tcl result code. If an error occurs, then an error message + * is left in the interp's result. + * + * Side effects: + * Configuration information may be set for itemPtr. + * + *-------------------------------------------------------------- + */ + +static int +ConfigureBitmap( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Bitmap item to reconfigure. */ + int objc, /* Number of elements in objv. */ + Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ + int flags) /* Flags to pass to Tk_ConfigureWidget. */ +{ + BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + XGCValues gcValues; + GC newGC; + Tk_Window tkwin; + unsigned long mask; + XColor *fgColor; + XColor *bgColor; + Pixmap bitmap; + Tk_PathState state; + + tkwin = Tk_PathCanvasTkwin(canvas); + if (TCL_OK != Tk_SetOptions(interp, (char *) bmapPtr, optionTable, + objc, objv, tkwin, NULL, NULL)) { + return TCL_ERROR; + } + + /* + * A few of the options require additional processing, such as those that + * determine the graphics context. + */ + + state = itemPtr->state; + + if (bmapPtr->activeFgColor!=NULL || + bmapPtr->activeBgColor!=NULL || + bmapPtr->activeBitmap!=None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + ComputeBitmapBbox(canvas, bmapPtr); + return TCL_OK; + } + fgColor = bmapPtr->fgColor; + bgColor = bmapPtr->bgColor; + bitmap = bmapPtr->bitmap; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (bmapPtr->activeFgColor!=NULL) { + fgColor = bmapPtr->activeFgColor; + } + if (bmapPtr->activeBgColor!=NULL) { + bgColor = bmapPtr->activeBgColor; + } + if (bmapPtr->activeBitmap!=None) { + bitmap = bmapPtr->activeBitmap; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (bmapPtr->disabledFgColor!=NULL) { + fgColor = bmapPtr->disabledFgColor; + } + if (bmapPtr->disabledBgColor!=NULL) { + bgColor = bmapPtr->disabledBgColor; + } + if (bmapPtr->disabledBitmap!=None) { + bitmap = bmapPtr->disabledBitmap; + } + } + + if (bitmap == None) { + newGC = None; + } else { + gcValues.foreground = fgColor->pixel; + mask = GCForeground; + if (bgColor != NULL) { + gcValues.background = bgColor->pixel; + mask |= GCBackground; + } else { + gcValues.clip_mask = bitmap; + mask |= GCClipMask; + } + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } + if (bmapPtr->gc != None) { + Tk_FreeGC(Tk_Display(tkwin), bmapPtr->gc); + } + bmapPtr->gc = newGC; + + ComputeBitmapBbox(canvas, bmapPtr); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * DeleteBitmap -- + * + * This function is called to clean up the data structure associated with + * a bitmap item. + * + * Results: + * None. + * + * Side effects: + * Resources associated with itemPtr are released. + * + *-------------------------------------------------------------- + */ + +static void +DeleteBitmap( + Tk_PathCanvas canvas, /* Info about overall canvas widget. */ + Tk_PathItem *itemPtr, /* Item that is being deleted. */ + Display *display) /* Display containing window for canvas. */ +{ + Tk_FreeConfigOptions((char *) itemPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +/* + *-------------------------------------------------------------- + * + * ComputeBitmapBbox -- + * + * This function is invoked to compute the bounding box of all the pixels + * that may be drawn as part of a bitmap item. This function is where the + * child bitmap's placement is computed. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header for itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +ComputeBitmapBbox( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + BitmapItem *bmapPtr) /* Item whose bbox is to be recomputed. */ +{ + int width, height; + int x, y; + Pixmap bitmap; + Tk_PathState state = bmapPtr->header.state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + bitmap = bmapPtr->bitmap; + if (((TkPathCanvas *)canvas)->currentItemPtr == (Tk_PathItem *)bmapPtr) { + if (bmapPtr->activeBitmap!=None) { + bitmap = bmapPtr->activeBitmap; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (bmapPtr->disabledBitmap!=None) { + bitmap = bmapPtr->disabledBitmap; + } + } + + x = (int) (bmapPtr->x + ((bmapPtr->x >= 0) ? 0.5 : - 0.5)); + y = (int) (bmapPtr->y + ((bmapPtr->y >= 0) ? 0.5 : - 0.5)); + + if (state==TK_PATHSTATE_HIDDEN || bitmap == None) { + bmapPtr->header.x1 = bmapPtr->header.x2 = x; + bmapPtr->header.y1 = bmapPtr->header.y2 = y; + return; + } + + /* + * Compute location and size of bitmap, using anchor information. + */ + + Tk_SizeOfBitmap(Tk_Display(Tk_PathCanvasTkwin(canvas)), bitmap, + &width, &height); + switch (bmapPtr->anchor) { + case TK_ANCHOR_N: + x -= width/2; + break; + case TK_ANCHOR_NE: + x -= width; + break; + case TK_ANCHOR_E: + x -= width; + y -= height/2; + break; + case TK_ANCHOR_SE: + x -= width; + y -= height; + break; + case TK_ANCHOR_S: + x -= width/2; + y -= height; + break; + case TK_ANCHOR_SW: + y -= height; + break; + case TK_ANCHOR_W: + y -= height/2; + break; + case TK_ANCHOR_NW: + break; + case TK_ANCHOR_CENTER: + x -= width/2; + y -= height/2; + break; + } + + /* + * Store the information in the item header. + */ + + bmapPtr->header.x1 = x; + bmapPtr->header.y1 = y; + bmapPtr->header.x2 = x + width; + bmapPtr->header.y2 = y + height; +} + +/* + *-------------------------------------------------------------- + * + * DisplayBitmap -- + * + * This function is invoked to draw a bitmap item in a given drawable. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation information in + * canvas. + * + *-------------------------------------------------------------- + */ + +static void +DisplayBitmap( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + Tk_PathItem *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, int y, int width, int height) + /* Describes region of canvas that must be + * redisplayed (not used). */ +{ + BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + int bmapX, bmapY, bmapWidth, bmapHeight; + short drawableX, drawableY; + Pixmap bitmap; + Tk_PathState state = itemPtr->state; + + /* + * If the area being displayed doesn't cover the whole bitmap, then only + * redisplay the part of the bitmap that needs redisplay. + */ + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + bitmap = bmapPtr->bitmap; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (bmapPtr->activeBitmap!=None) { + bitmap = bmapPtr->activeBitmap; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (bmapPtr->disabledBitmap!=None) { + bitmap = bmapPtr->disabledBitmap; + } + } + + if (bitmap != None) { + if (x > bmapPtr->header.x1) { + bmapX = x - bmapPtr->header.x1; + bmapWidth = bmapPtr->header.x2 - x; + } else { + bmapX = 0; + if ((x+width) < bmapPtr->header.x2) { + bmapWidth = x + width - bmapPtr->header.x1; + } else { + bmapWidth = bmapPtr->header.x2 - bmapPtr->header.x1; + } + } + if (y > bmapPtr->header.y1) { + bmapY = y - bmapPtr->header.y1; + bmapHeight = bmapPtr->header.y2 - y; + } else { + bmapY = 0; + if ((y+height) < bmapPtr->header.y2) { + bmapHeight = y + height - bmapPtr->header.y1; + } else { + bmapHeight = bmapPtr->header.y2 - bmapPtr->header.y1; + } + } + Tk_PathCanvasDrawableCoords(canvas, + (double) (bmapPtr->header.x1 + bmapX), + (double) (bmapPtr->header.y1 + bmapY), + &drawableX, &drawableY); + + /* + * Must modify the mask origin within the graphics context to line up + * with the bitmap's origin (in order to make bitmaps with + * "-background {}" work right). + */ + + XSetClipOrigin(display, bmapPtr->gc, drawableX - bmapX, + drawableY - bmapY); + XCopyPlane(display, bitmap, drawable, + bmapPtr->gc, bmapX, bmapY, (unsigned int) bmapWidth, + (unsigned int) bmapHeight, drawableX, drawableY, 1); + XSetClipOrigin(display, bmapPtr->gc, 0, 0); + } +} + +/* + *-------------------------------------------------------------- + * + * BitmapToPoint -- + * + * Computes the distance from a given point to a given rectangle, in + * canvas units. + * + * Results: + * The return value is 0 if the point whose x and y coordinates are + * coordPtr[0] and coordPtr[1] is inside the bitmap. If the point isn't + * inside the bitmap then the return value is the distance from the point + * to the bitmap. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static double +BitmapToPoint( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + double *coordPtr) /* Pointer to x and y coordinates. */ +{ + BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + double x1, x2, y1, y2, xDiff, yDiff; + + x1 = bmapPtr->header.x1; + y1 = bmapPtr->header.y1; + x2 = bmapPtr->header.x2; + y2 = bmapPtr->header.y2; + + /* + * Point is outside rectangle. + */ + + if (coordPtr[0] < x1) { + xDiff = x1 - coordPtr[0]; + } else if (coordPtr[0] > x2) { + xDiff = coordPtr[0] - x2; + } else { + xDiff = 0; + } + + if (coordPtr[1] < y1) { + yDiff = y1 - coordPtr[1]; + } else if (coordPtr[1] > y2) { + yDiff = coordPtr[1] - y2; + } else { + yDiff = 0; + } + + return hypot(xDiff, yDiff); +} + +/* + *-------------------------------------------------------------- + * + * BitmapToArea -- + * + * This function is called to determine whether an item lies entirely + * inside, entirely outside, or overlapping a given rectangle. + * + * Results: + * -1 is returned if the item is entirely outside the area given by + * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given + * area. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +BitmapToArea( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against rectangle. */ + double *rectPtr) /* Pointer to array of four coordinates + * (x1,y1,x2,y2) describing rectangular + * area. */ +{ + BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + + if ((rectPtr[2] <= bmapPtr->header.x1) + || (rectPtr[0] >= bmapPtr->header.x2) + || (rectPtr[3] <= bmapPtr->header.y1) + || (rectPtr[1] >= bmapPtr->header.y2)) { + return -1; + } + if ((rectPtr[0] <= bmapPtr->header.x1) + && (rectPtr[1] <= bmapPtr->header.y1) + && (rectPtr[2] >= bmapPtr->header.x2) + && (rectPtr[3] >= bmapPtr->header.y2)) { + return 1; + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * ScaleBitmap -- + * + * This function is invoked to rescale a bitmap item in a canvas. It is + * one of the standard item functions for bitmap items, and is invoked by + * the generic canvas code. + * + * Results: + * None. + * + * Side effects: + * The item referred to by itemPtr is rescaled so that the following + * transformation is applied to all point coordinates: + * x' = originX + scaleX*(x-originX) + * y' = originY + scaleY*(y-originY) + * + *-------------------------------------------------------------- + */ + +static void +ScaleBitmap( + Tk_PathCanvas canvas, /* Canvas containing rectangle. */ + Tk_PathItem *itemPtr, /* Rectangle to be scaled. */ + double originX, double originY, + /* Origin about which to scale item. */ + double scaleX, /* Amount to scale in X direction. */ + double scaleY) /* Amount to scale in Y direction. */ +{ + BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + + bmapPtr->x = originX + scaleX*(bmapPtr->x - originX); + bmapPtr->y = originY + scaleY*(bmapPtr->y - originY); + ComputeBitmapBbox(canvas, bmapPtr); +} + +/* + *-------------------------------------------------------------- + * + * TranslateBitmap -- + * + * This function is called to move an item by a given amount. + * + * Results: + * None. + * + * Side effects: + * The position of the item is offset by (xDelta, yDelta), and the + * bounding box is updated in the generic part of the item structure. + * + *-------------------------------------------------------------- + */ + +static void +TranslateBitmap( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item that is being moved. */ + double deltaX, double deltaY) + /* Amount by which item is to be moved. */ +{ + BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + + bmapPtr->x += deltaX; + bmapPtr->y += deltaY; + ComputeBitmapBbox(canvas, bmapPtr); +} + +/* + *-------------------------------------------------------------- + * + * BitmapToPostscript -- + * + * This function is called to generate Postscript for bitmap items. + * + * Results: + * The return value is a standard Tcl result. If an error occurs in + * generating Postscript then an error message is left in the interp's + * 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 +BitmapToPostscript( + Tcl_Interp *interp, /* Leave Postscript or error message here. */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + Tk_PathItem *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. */ +{ + BitmapItem *bmapPtr = (BitmapItem *) itemPtr; + double x, y; + int width, height, rowsAtOnce, rowsThisTime; + int curRow; + char buffer[100 + TCL_DOUBLE_SPACE * 2 + TCL_INTEGER_SPACE * 4]; + XColor *fgColor; + XColor *bgColor; + Pixmap bitmap; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + fgColor = bmapPtr->fgColor; + bgColor = bmapPtr->bgColor; + bitmap = bmapPtr->bitmap; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (bmapPtr->activeFgColor!=NULL) { + fgColor = bmapPtr->activeFgColor; + } + if (bmapPtr->activeBgColor!=NULL) { + bgColor = bmapPtr->activeBgColor; + } + if (bmapPtr->activeBitmap!=None) { + bitmap = bmapPtr->activeBitmap; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (bmapPtr->disabledFgColor!=NULL) { + fgColor = bmapPtr->disabledFgColor; + } + if (bmapPtr->disabledBgColor!=NULL) { + bgColor = bmapPtr->disabledBgColor; + } + if (bmapPtr->disabledBitmap!=None) { + bitmap = bmapPtr->disabledBitmap; + } + } + + if (bitmap == None) { + return TCL_OK; + } + + /* + * Compute the coordinates of the lower-left corner of the bitmap, taking + * into account the anchor position for the bitmp. + */ + + x = bmapPtr->x; + y = Tk_PathCanvasPsY(canvas, bmapPtr->y); + Tk_SizeOfBitmap(Tk_Display(Tk_PathCanvasTkwin(canvas)), bitmap, + &width, &height); + switch (bmapPtr->anchor) { + case TK_ANCHOR_NW: y -= height; break; + case TK_ANCHOR_N: x -= width/2.0; y -= height; break; + case TK_ANCHOR_NE: x -= width; y -= height; break; + case TK_ANCHOR_E: x -= width; y -= height/2.0; break; + case TK_ANCHOR_SE: x -= width; break; + case TK_ANCHOR_S: x -= width/2.0; break; + case TK_ANCHOR_SW: break; + case TK_ANCHOR_W: y -= height/2.0; break; + case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; + } + + /* + * Color the background, if there is one. + */ + + if (bgColor != NULL) { + sprintf(buffer, + "%.15g %.15g moveto %d 0 rlineto 0 %d rlineto %d %s\n", + x, y, width, height, -width, "0 rlineto closepath"); + Tcl_AppendResult(interp, buffer, NULL); + if (Tk_PathCanvasPsColor(interp, canvas, bgColor) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(interp, "fill\n", NULL); + } + + /* + * Draw the bitmap, if there is a foreground color. If the bitmap is very + * large, then chop it up into multiple bitmaps, each consisting of one or + * more rows. This is needed because Postscript can't handle single + * strings longer than 64 KBytes long. + */ + + if (fgColor != NULL) { + if (Tk_PathCanvasPsColor(interp, canvas, fgColor) != TCL_OK) { + return TCL_ERROR; + } + if (width > 60000) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "can't generate Postscript", + " for bitmaps more than 60000 pixels wide", NULL); + return TCL_ERROR; + } + rowsAtOnce = 60000/width; + if (rowsAtOnce < 1) { + rowsAtOnce = 1; + } + sprintf(buffer, "%.15g %.15g translate\n", x, y+height); + Tcl_AppendResult(interp, buffer, NULL); + for (curRow = 0; curRow < height; curRow += rowsAtOnce) { + rowsThisTime = rowsAtOnce; + if (rowsThisTime > (height - curRow)) { + rowsThisTime = height - curRow; + } + sprintf(buffer, "0 -%.15g translate\n%d %d true matrix {\n", + (double) rowsThisTime, width, rowsThisTime); + Tcl_AppendResult(interp, buffer, NULL); + if (Tk_PathCanvasPsBitmap(interp, canvas, bitmap, + 0, curRow, width, rowsThisTime) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(interp, "\n} imagemask\n", NULL); + } + } + return TCL_OK; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/pd/tkpath/generic/tkpCanvImg.c b/pd/tkpath/generic/tkpCanvImg.c new file mode 100644 index 0000000000000000000000000000000000000000..65485c63c3eaf69c1ee3a9d20107ed752b99ce07 --- /dev/null +++ b/pd/tkpath/generic/tkpCanvImg.c @@ -0,0 +1,950 @@ +/* + * tkCanvImg.c -- + * + * This file implements image items for canvas widgets. + * + * Copyright (c) 1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvImg.c,v 1.2 2008/06/21 14:58:42 matben Exp $ + */ + +#include <stdio.h> +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" + +/* + * The structure below defines the record for each image item. + */ + +typedef struct ImageItem { + Tk_PathItem header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + Tk_PathCanvas canvas; /* Canvas containing the image. */ + double x, y; /* Coordinates of positioning point for + * image. */ + Tk_Anchor anchor; /* Where to anchor image relative to (x,y). */ + char *imageString; /* String describing -image option + * (malloc-ed). NULL means no image right + * now. */ + char *activeImageString; /* String describing -activeimage option. + * NULL means no image right now. */ + char *disabledImageString; /* String describing -disabledimage option. + * NULL means no image right now. */ + Tk_Image image; /* Image to display in window, or NULL if no + * image at present. */ + Tk_Image activeImage; /* Image to display in window, or NULL if no + * image at present. */ + Tk_Image disabledImage; /* Image to display in window, or NULL if no + * image at present. */ +} ImageItem; + +/* + * Information used for parsing configuration specs. If you change any of the + * default strings, be sure to change the corresponding default values in + * CreateLine. + */ + +#define PATH_DEF_STATE "normal" + +/* These MUST be kept in sync with enums! X.h */ + +static char *stateStrings[] = { + "active", "disabled", "normal", "hidden", NULL +}; + +static Tk_ObjCustomOption tagsCO = { + "tags", + Tk_PathCanvasTagsOptionSetProc, + Tk_PathCanvasTagsOptionGetProc, + Tk_PathCanvasTagsOptionRestoreProc, + Tk_PathCanvasTagsOptionFreeProc, + (ClientData) NULL +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_STRING, "-activeimage", NULL, NULL, + NULL, -1, Tk_Offset(ImageItem, activeImageString), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_ANCHOR, "-anchor", NULL, NULL, + "center", -1, Tk_Offset(ImageItem, anchor), 0, 0, 0}, + {TK_OPTION_STRING, "-disabledimage", NULL, NULL, + NULL, -1, Tk_Offset(ImageItem, disabledImageString), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-image", NULL, NULL, + NULL, -1, Tk_Offset(ImageItem, imageString), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", NULL, NULL, + PATH_DEF_STATE, -1, Tk_Offset(Tk_PathItem, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_CUSTOM, "-tags", NULL, NULL, + NULL, -1, Tk_Offset(Tk_PathItem, pathTagsPtr), + TK_OPTION_NULL_OK, (ClientData) &tagsCO, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * Prototypes for functions defined in this file: + */ + +static void ImageChangedProc(ClientData clientData, + int x, int y, int width, int height, int imgWidth, + int imgHeight); +static int ImageCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int argc, + Tcl_Obj *CONST argv[]); +static int ImageToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double ImageToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int ImageToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ComputeImageBbox(Tk_PathCanvas canvas, ImageItem *imgPtr); +static int ConfigureImage(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int argc, + Tcl_Obj *CONST argv[], int flags); +static int CreateImage(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int argc, Tcl_Obj *CONST argv[]); +static void DeleteImage(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayImage(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable dst, + int x, int y, int width, int height); +static void ScaleImage(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslateImage(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); + +/* + * The structures below defines the image item type in terms of functions that + * can be invoked by generic item code. + */ + +Tk_PathItemType tkImageType = { + "image", /* name */ + sizeof(ImageItem), /* itemSize */ + CreateImage, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigureImage, /* configureProc */ + ImageCoords, /* coordProc */ + DeleteImage, /* deleteProc */ + DisplayImage, /* displayProc */ + 0, /* flags */ + NULL, /* bboxProc */ + ImageToPoint, /* pointProc */ + ImageToArea, /* areaProc */ + ImageToPostscript, /* postscriptProc */ + ScaleImage, /* scaleProc */ + TranslateImage, /* translateProc */ + NULL, /* indexProc */ + NULL, /* icursorProc */ + NULL, /* selectionProc */ + NULL, /* insertProc */ + NULL, /* dTextProc */ + NULL, /* nextPtr */ +}; + +/* + *-------------------------------------------------------------- + * + * CreateImage -- + * + * This function is invoked to create a new image 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 the interp's result; in this + * case itemPtr is left uninitialized, so it can be safely freed by the + * caller. + * + * Side effects: + * A new image item is created. + * + *-------------------------------------------------------------- + */ + +static int +CreateImage( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas to hold new item. */ + Tk_PathItem *itemPtr, /* Record to hold new item; header has been + * initialized by caller. */ + int objc, /* Number of arguments in objv. */ + Tcl_Obj *CONST objv[]) /* Arguments describing rectangle. */ +{ + ImageItem *imgPtr = (ImageItem *) itemPtr; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Initialize item's record. + */ + + imgPtr->canvas = canvas; + imgPtr->anchor = TK_ANCHOR_CENTER; + imgPtr->imageString = NULL; + imgPtr->activeImageString = NULL; + imgPtr->disabledImageString = NULL; + imgPtr->image = NULL; + imgPtr->activeImage = NULL; + imgPtr->disabledImage = NULL; + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) imgPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + /* + * Process the arguments to fill in the item record. Only 1 (list) or 2 (x + * y) coords are allowed. + */ + + if (objc == 1) { + i = 1; + } else { + char *arg = Tcl_GetString(objv[1]); + i = 2; + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + i = 1; + } + } + if ((ImageCoords(interp, canvas, itemPtr, i, objv) != TCL_OK)) { + goto error; + } + if (ConfigureImage(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { + return TCL_OK; + } + + error: + DeleteImage(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * ImageCoords -- + * + * This function is invoked to process the "coords" widget command on + * image items. See the user documentation for details on what it does. + * + * Results: + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. + * + * Side effects: + * The coordinates for the given item may be changed. + * + *-------------------------------------------------------------- + */ + +static int +ImageCoords( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item whose coordinates are to be read or + * modified. */ + int objc, /* Number of coordinates supplied in objv. */ + Tcl_Obj *CONST objv[]) /* Array of coordinates: x1, y1, x2, y2, ... */ +{ + ImageItem *imgPtr = (ImageItem *) itemPtr; + + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewObj(); + + Tcl_Obj *subobj = Tcl_NewDoubleObj(imgPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(imgPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (objc < 3) { + if (objc==1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 2) { + char buf[64]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[0], &imgPtr->x) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[1], + &imgPtr->y) != TCL_OK)) { + return TCL_ERROR; + } + ComputeImageBbox(canvas, imgPtr); + } else { + char buf[64]; + + sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ConfigureImage -- + * + * This function is invoked to configure various aspects of an image + * item, such as its anchor position. + * + * Results: + * A standard Tcl result code. If an error occurs, then an error message + * is left in the interp's result. + * + * Side effects: + * Configuration information may be set for itemPtr. + * + *-------------------------------------------------------------- + */ + +static int +ConfigureImage( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Image item to reconfigure. */ + int objc, /* Number of elements in objv. */ + Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ + int flags) /* Flags to pass to Tk_ConfigureWidget. */ +{ + ImageItem *imgPtr = (ImageItem *) itemPtr; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + Tk_Window tkwin; + Tk_Image image; + int error; + + tkwin = Tk_PathCanvasTkwin(canvas); + + /* + * The following loop is potentially executed twice. During the first pass + * configuration options get set to their new values. If there is an error + * in this pass, we execute a second pass to restore all the options to + * their previous values. + */ + + for (error = 0; error <= 1; error++) { + if (!error) { + /* + * First pass: set options to new values. + */ + + if (Tk_SetOptions(interp, (char *) imgPtr, + optionTable, objc, objv, tkwin, + &savedOptions, NULL) != TCL_OK) { + continue; + } + } else { + /* + * Second pass: restore options to old values. + */ + + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + /* + * Create the image. Save the old image around and don't free it until + * after the new one is allocated. This keeps the reference count from + * going to zero so the image doesn't have to be recreated if it hasn't + * changed. + */ + + if (imgPtr->activeImageString != NULL) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + /* image */ + if (imgPtr->imageString != NULL) { + image = Tk_GetImage(interp, tkwin, imgPtr->imageString, + ImageChangedProc, (ClientData) imgPtr); + if (image == NULL) { + continue; + } + } else { + image = NULL; + } + if (imgPtr->image != NULL) { + Tk_FreeImage(imgPtr->image); + } + imgPtr->image = image; + + /* active image */ + if (imgPtr->activeImageString != NULL) { + image = Tk_GetImage(interp, tkwin, imgPtr->activeImageString, + ImageChangedProc, (ClientData) imgPtr); + if (image == NULL) { + continue; + } + } else { + image = NULL; + } + if (imgPtr->activeImage != NULL) { + Tk_FreeImage(imgPtr->activeImage); + } + imgPtr->activeImage = image; + + /* disabled image */ + if (imgPtr->disabledImageString != NULL) { + image = Tk_GetImage(interp, tkwin, imgPtr->disabledImageString, + ImageChangedProc, (ClientData) imgPtr); + if (image == NULL) { + continue; + } + } else { + image = NULL; + } + if (imgPtr->disabledImage != NULL) { + Tk_FreeImage(imgPtr->disabledImage); + } + imgPtr->disabledImage = image; + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + } + ComputeImageBbox(canvas, imgPtr); + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + return TCL_OK; + } +} + +/* + *-------------------------------------------------------------- + * + * DeleteImage -- + * + * This function is called to clean up the data structure associated with + * a image item. + * + * Results: + * None. + * + * Side effects: + * Resources associated with itemPtr are released. + * + *-------------------------------------------------------------- + */ + +static void +DeleteImage( + Tk_PathCanvas canvas, /* Info about overall canvas widget. */ + Tk_PathItem *itemPtr, /* Item that is being deleted. */ + Display *display) /* Display containing window for canvas. */ +{ + ImageItem *imgPtr = (ImageItem *) itemPtr; + + if (imgPtr->image != NULL) { + Tk_FreeImage(imgPtr->image); + } + if (imgPtr->activeImage != NULL) { + Tk_FreeImage(imgPtr->activeImage); + } + if (imgPtr->disabledImage != NULL) { + Tk_FreeImage(imgPtr->disabledImage); + } + Tk_FreeConfigOptions((char *) imgPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +/* + *-------------------------------------------------------------- + * + * ComputeImageBbox -- + * + * This function is invoked to compute the bounding box of all the pixels + * that may be drawn as part of a image item. This function is where the + * child image's placement is computed. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header for itemPtr. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static void +ComputeImageBbox( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + ImageItem *imgPtr) /* Item whose bbox is to be recomputed. */ +{ + int width, height; + int x, y; + Tk_Image image; + Tk_PathState state = imgPtr->header.state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + image = imgPtr->image; + if (((TkPathCanvas *)canvas)->currentItemPtr == (Tk_PathItem *)imgPtr) { + if (imgPtr->activeImage != NULL) { + image = imgPtr->activeImage; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (imgPtr->disabledImage != NULL) { + image = imgPtr->disabledImage; + } + } + + x = (int) (imgPtr->x + ((imgPtr->x >= 0) ? 0.5 : - 0.5)); + y = (int) (imgPtr->y + ((imgPtr->y >= 0) ? 0.5 : - 0.5)); + + if ((state == TK_PATHSTATE_HIDDEN) || (image == None)) { + imgPtr->header.x1 = imgPtr->header.x2 = x; + imgPtr->header.y1 = imgPtr->header.y2 = y; + return; + } + + /* + * Compute location and size of image, using anchor information. + */ + + Tk_SizeOfImage(image, &width, &height); + switch (imgPtr->anchor) { + case TK_ANCHOR_N: + x -= width/2; + break; + case TK_ANCHOR_NE: + x -= width; + break; + case TK_ANCHOR_E: + x -= width; + y -= height/2; + break; + case TK_ANCHOR_SE: + x -= width; + y -= height; + break; + case TK_ANCHOR_S: + x -= width/2; + y -= height; + break; + case TK_ANCHOR_SW: + y -= height; + break; + case TK_ANCHOR_W: + y -= height/2; + break; + case TK_ANCHOR_NW: + break; + case TK_ANCHOR_CENTER: + x -= width/2; + y -= height/2; + break; + } + + /* + * Store the information in the item header. + */ + + imgPtr->header.x1 = x; + imgPtr->header.y1 = y; + imgPtr->header.x2 = x + width; + imgPtr->header.y2 = y + height; +} + +/* + *-------------------------------------------------------------- + * + * DisplayImage -- + * + * This function is invoked to draw a image item in a given drawable. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation information in + * canvas. + * + *-------------------------------------------------------------- + */ + +static void +DisplayImage( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + Tk_PathItem *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, int y, int width, int height) + /* Describes region of canvas that must be + * redisplayed (not used). */ +{ + ImageItem *imgPtr = (ImageItem *) itemPtr; + short drawableX, drawableY; + Tk_Image image; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + image = imgPtr->image; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (imgPtr->activeImage != NULL) { + image = imgPtr->activeImage; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (imgPtr->disabledImage != NULL) { + image = imgPtr->disabledImage; + } + } + + if (image == NULL) { + return; + } + + /* + * Translate the coordinates to those of the image, then redisplay it. + */ + + Tk_PathCanvasDrawableCoords(canvas, (double) x, (double) y, + &drawableX, &drawableY); + Tk_RedrawImage(image, x - imgPtr->header.x1, y - imgPtr->header.y1, + width, height, drawable, drawableX, drawableY); +} + +/* + *-------------------------------------------------------------- + * + * ImageToPoint -- + * + * Computes the distance from a given point to a given rectangle, in + * canvas units. + * + * Results: + * The return value is 0 if the point whose x and y coordinates are + * coordPtr[0] and coordPtr[1] is inside the image. If the point isn't + * inside the image then the return value is the distance from the point + * to the image. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static double +ImageToPoint( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + double *coordPtr) /* Pointer to x and y coordinates. */ +{ + ImageItem *imgPtr = (ImageItem *) itemPtr; + double x1, x2, y1, y2, xDiff, yDiff; + + x1 = imgPtr->header.x1; + y1 = imgPtr->header.y1; + x2 = imgPtr->header.x2; + y2 = imgPtr->header.y2; + + /* + * Point is outside rectangle. + */ + + if (coordPtr[0] < x1) { + xDiff = x1 - coordPtr[0]; + } else if (coordPtr[0] > x2) { + xDiff = coordPtr[0] - x2; + } else { + xDiff = 0; + } + + if (coordPtr[1] < y1) { + yDiff = y1 - coordPtr[1]; + } else if (coordPtr[1] > y2) { + yDiff = coordPtr[1] - y2; + } else { + yDiff = 0; + } + + return hypot(xDiff, yDiff); +} + +/* + *-------------------------------------------------------------- + * + * ImageToArea -- + * + * This function is called to determine whether an item lies entirely + * inside, entirely outside, or overlapping a given rectangle. + * + * Results: + * -1 is returned if the item is entirely outside the area given by + * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given + * area. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +ImageToArea( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against rectangle. */ + double *rectPtr) /* Pointer to array of four coordinates + * (x1,y1,x2,y2) describing rectangular + * area. */ +{ + ImageItem *imgPtr = (ImageItem *) itemPtr; + + if ((rectPtr[2] <= imgPtr->header.x1) + || (rectPtr[0] >= imgPtr->header.x2) + || (rectPtr[3] <= imgPtr->header.y1) + || (rectPtr[1] >= imgPtr->header.y2)) { + return -1; + } + if ((rectPtr[0] <= imgPtr->header.x1) + && (rectPtr[1] <= imgPtr->header.y1) + && (rectPtr[2] >= imgPtr->header.x2) + && (rectPtr[3] >= imgPtr->header.y2)) { + return 1; + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * ImageToPostscript -- + * + * This function is called to generate Postscript for image 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 +ImageToPostscript( + Tcl_Interp *interp, /* Leave Postscript or error message here. */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + Tk_PathItem *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.*/ +{ + ImageItem *imgPtr = (ImageItem *)itemPtr; + Tk_Window canvasWin = Tk_PathCanvasTkwin(canvas); + + char buffer[256]; + double x, y; + int width, height; + Tk_Image image; + Tk_PathState state = itemPtr->state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + image = imgPtr->image; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (imgPtr->activeImage != NULL) { + image = imgPtr->activeImage; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (imgPtr->disabledImage != NULL) { + image = imgPtr->disabledImage; + } + } + if (image == NULL) { + /* + * Image item without actual image specified. + */ + + return TCL_OK; + } + Tk_SizeOfImage(image, &width, &height); + + /* + * Compute the coordinates of the lower-left corner of the image, taking + * into account the anchor position for the image. + */ + + x = imgPtr->x; + y = Tk_PathCanvasPsY(canvas, imgPtr->y); + + switch (imgPtr->anchor) { + case TK_ANCHOR_NW: y -= height; break; + case TK_ANCHOR_N: x -= width/2.0; y -= height; break; + case TK_ANCHOR_NE: x -= width; y -= height; break; + case TK_ANCHOR_E: x -= width; y -= height/2.0; break; + case TK_ANCHOR_SE: x -= width; break; + case TK_ANCHOR_S: x -= width/2.0; break; + case TK_ANCHOR_SW: break; + case TK_ANCHOR_W: y -= height/2.0; break; + case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; + } + + if (!prepass) { + sprintf(buffer, "%.15g %.15g", x, y); + Tcl_AppendResult(interp, buffer, " translate\n", NULL); + } + + return Tk_PostscriptImage(image, interp, canvasWin, + ((TkPathCanvas *) canvas)->psInfo, 0, 0, width, height, prepass); +} + +/* + *-------------------------------------------------------------- + * + * ScaleImage -- + * + * This function is invoked to rescale an item. + * + * Results: + * None. + * + * Side effects: + * The item referred to by itemPtr is rescaled so that the following + * transformation is applied to all point coordinates: + * x' = originX + scaleX*(x-originX) + * y' = originY + scaleY*(y-originY) + * + *-------------------------------------------------------------- + */ + +static void +ScaleImage( + Tk_PathCanvas canvas, /* Canvas containing rectangle. */ + Tk_PathItem *itemPtr, /* Rectangle to be scaled. */ + double originX, double originY, + /* Origin about which to scale rect. */ + double scaleX, /* Amount to scale in X direction. */ + double scaleY) /* Amount to scale in Y direction. */ +{ + ImageItem *imgPtr = (ImageItem *) itemPtr; + + imgPtr->x = originX + scaleX*(imgPtr->x - originX); + imgPtr->y = originY + scaleY*(imgPtr->y - originY); + ComputeImageBbox(canvas, imgPtr); +} + +/* + *-------------------------------------------------------------- + * + * TranslateImage -- + * + * This function is called to move an item by a given amount. + * + * Results: + * None. + * + * Side effects: + * The position of the item is offset by (xDelta, yDelta), and the + * bounding box is updated in the generic part of the item structure. + * + *-------------------------------------------------------------- + */ + +static void +TranslateImage( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item that is being moved. */ + double deltaX, double deltaY) + /* Amount by which item is to be moved. */ +{ + ImageItem *imgPtr = (ImageItem *) itemPtr; + + imgPtr->x += deltaX; + imgPtr->y += deltaY; + ComputeImageBbox(canvas, imgPtr); +} + +/* + *---------------------------------------------------------------------- + * + * ImageChangedProc -- + * + * This function is invoked by the image code whenever the manager for an + * image does something that affects the image's size or how it is + * displayed. + * + * Results: + * None. + * + * Side effects: + * Arranges for the canvas to get redisplayed. + * + *---------------------------------------------------------------------- + */ + +static void +ImageChangedProc( + ClientData clientData, /* Pointer to canvas item for image. */ + int x, int y, /* Upper left pixel (within image) that must + * be redisplayed. */ + int width, int height, /* Dimensions of area to redisplay (may be <= + * 0). */ + int imgWidth, int imgHeight)/* New dimensions of image. */ +{ + ImageItem *imgPtr = (ImageItem *) clientData; + + /* + * If the image's size changed and it's not anchored at its northwest + * corner then just redisplay the entire area of the image. This is a bit + * over-conservative, but we need to do something because a size change + * also means a position change. + */ + + if (((imgPtr->header.x2 - imgPtr->header.x1) != imgWidth) + || ((imgPtr->header.y2 - imgPtr->header.y1) != imgHeight)) { + x = y = 0; + width = imgWidth; + height = imgHeight; + Tk_PathCanvasEventuallyRedraw(imgPtr->canvas, imgPtr->header.x1, + imgPtr->header.y1, imgPtr->header.x2, imgPtr->header.y2); + } + ComputeImageBbox(imgPtr->canvas, imgPtr); + Tk_PathCanvasEventuallyRedraw(imgPtr->canvas, imgPtr->header.x1 + x, + imgPtr->header.y1 + y, (int) (imgPtr->header.x1 + x + width), + (int) (imgPtr->header.y1 + y + height)); +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/pd/tkpath/generic/tkpCanvLine.c b/pd/tkpath/generic/tkpCanvLine.c new file mode 100644 index 0000000000000000000000000000000000000000..799170b9859dcef87d009283affa0a6a90734ac5 --- /dev/null +++ b/pd/tkpath/generic/tkpCanvLine.c @@ -0,0 +1,2405 @@ +/* + * tkpCanvLine.c -- + * + * This file implements line items for canvas widgets. + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-1999 by Scriptics Corporation. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvLine.c,v 1.5 2008/07/22 09:41:35 matben Exp $ + */ + +#include <stdio.h> +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" + +/* + * The structure below defines the record for each line item. + */ + +typedef enum { + ARROWS_NONE, ARROWS_FIRST, ARROWS_LAST, ARROWS_BOTH +} Arrows; + +typedef struct LineItem { + Tk_PathItem header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + Tk_PathOutline outline; /* Outline structure */ + Tk_PathCanvas canvas; /* Canvas containing item. Needed for parsing + * arrow shapes. */ + int numPoints; /* Number of points in line (always >= 0). */ + double *coordPtr; /* Pointer to malloc-ed array containing x- + * and y-coords of all points in line. + * X-coords are even-valued indices, y-coords + * are corresponding odd-valued indices. If + * the line 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. */ + int capStyle; /* Cap style for line. */ + int joinStyle; /* Join style for line. */ + GC arrowGC; /* Graphics context for drawing arrowheads. */ + Arrows arrow; /* Indicates whether or not to draw arrowheads: + * "none", "first", "last", or "both". */ + Tcl_Obj *arrowShapeObj; /* NULL or list of three canvas lengths. */ + double *firstArrowPtr; /* Points to array of PTS_IN_ARROW points + * describing polygon for arrowhead at first + * point in line. 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 line (PTS_IN_ARROW points, first + * of which is tip). Malloc'ed. NULL means no + * arrowhead at last point. */ + Tk_PathSmoothMethod *smooth;/* Non-zero means draw line smoothed (i.e. + * with Bezier splines). */ + int splineSteps; /* Number of steps in each spline segment. */ +} LineItem; + +/* + * Number of points in an arrowHead: + */ + +#define PTS_IN_ARROW 6 + +/* + * Prototypes for functions defined in this file: + */ + +static int ArrowheadPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, LineItem *linePtr, + double *arrowPtr); +static void ComputeLineBbox(Tk_PathCanvas canvas, LineItem *linePtr); +static int ConfigureLine(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int ConfigureArrows(Tk_PathCanvas canvas, LineItem *linePtr); +static int CreateLine(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeleteLine(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayLine(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable dst, + int x, int y, int width, int height); +static int GetLineIndex(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + Tcl_Obj *obj, int *indexPtr); +static int LineCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void LineDeleteCoords(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int first, int last); +static void LineInsert(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int beforeThis, Tcl_Obj *obj); +static int LineToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double LineToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *coordPtr); +static int LineToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScaleLine(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslateLine(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); + +static int ArrowShapeOptionSetProc(ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, + char *recordPtr, int internalOffset, char *oldInternalPtr, + int flags); +static Tcl_Obj * ArrowShapeOptionGetProc(ClientData clientData, + Tk_Window tkwin, char *recordPtr, int internalOffset); + +/* + * Information used for parsing configuration specs. If you change any of the + * default strings, be sure to change the corresponding default values in + * CreateLine. + */ + +#define PATH_DEF_STATE "normal" + +/* These MUST be kept in sync with enums! X.h */ + +static char *arrowStrings[] = { + "none", "first", "last", "both", NULL +}; + +static char *stateStrings[] = { + "active", "disabled", "normal", "hidden", NULL +}; + +static char *lineCapStrings[] = { + "notlast", "butt", "round", "projecting", NULL +}; + +static char *joinStyleStrings[] = { + "miter", "round", "bevel", NULL +}; + +static Tk_ObjCustomOption arrowShapeCO = { + "arrowshape", + ArrowShapeOptionSetProc, + ArrowShapeOptionGetProc, + NULL, + NULL, + (ClientData) NULL +}; + +static Tk_ObjCustomOption dashCO = { + "dash", + Tk_DashOptionSetProc, + Tk_DashOptionGetProc, + Tk_DashOptionRestoreProc, + Tk_DashOptionFreeProc, + (ClientData) NULL +}; + +static Tk_ObjCustomOption offsetCO = { + "offset", + TkPathOffsetOptionSetProc, + TkPathOffsetOptionGetProc, + TkPathOffsetOptionRestoreProc, + TkPathOffsetOptionFreeProc, + (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) +}; + +static Tk_ObjCustomOption pixelCO = { + "pixel", + Tk_PathPixelOptionSetProc, + Tk_PathPixelOptionGetProc, + Tk_PathPixelOptionRestoreProc, + NULL, + (ClientData) NULL +}; + +static Tk_ObjCustomOption smoothCO = { + "smooth", + TkPathSmoothOptionSetProc, + TkPathSmoothOptionGetProc, + TkPathSmoothOptionRestoreProc, + NULL, + (ClientData) NULL +}; + +static Tk_ObjCustomOption tagsCO = { + "tags", + Tk_PathCanvasTagsOptionSetProc, + Tk_PathCanvasTagsOptionGetProc, + Tk_PathCanvasTagsOptionRestoreProc, + Tk_PathCanvasTagsOptionFreeProc, + (ClientData) NULL +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_CUSTOM, "-activedash", NULL, NULL, + NULL, -1, Tk_Offset(LineItem, outline.activeDashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_COLOR, "-activefill", NULL, NULL, + NULL, -1, Tk_Offset(LineItem, outline.activeColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-activestipple", NULL, NULL, + NULL, -1, Tk_Offset(LineItem, outline.activeStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-activewidth", NULL, NULL, + "0.0", -1, Tk_Offset(LineItem, outline.activeWidth), + 0, &pixelCO, 0}, + {TK_OPTION_STRING_TABLE, "-arrow", NULL, NULL, + "none", -1, Tk_Offset(LineItem, arrow), + 0, (ClientData) arrowStrings, 0}, + {TK_OPTION_CUSTOM, "-arrowshape", NULL, NULL, + "8 10 3", Tk_Offset(LineItem, arrowShapeObj), -1, + 0, &arrowShapeCO, 0}, + {TK_OPTION_STRING_TABLE, "-capstyle", NULL, NULL, + "butt", -1, Tk_Offset(LineItem, capStyle), + 0, (ClientData) lineCapStrings, 0}, + {TK_OPTION_CUSTOM, "-dash", NULL, NULL, + NULL, -1, Tk_Offset(LineItem, outline.dashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_PIXELS, "-dashoffset", NULL, NULL, + "0", -1, Tk_Offset(LineItem, outline.offset), + 0, 0, 0}, + {TK_OPTION_CUSTOM, "-disableddash", NULL, NULL, + NULL, -1, Tk_Offset(LineItem, outline.disabledDashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_COLOR, "-disabledfill", NULL, NULL, + NULL, -1, Tk_Offset(LineItem, outline.disabledColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-disabledstipple", NULL, NULL, + NULL, -1, Tk_Offset(LineItem, outline.disabledStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-disabledwidth", NULL, NULL, + "0.0", -1, Tk_Offset(LineItem, outline.disabledWidth), + 0, &pixelCO, 0}, + {TK_OPTION_COLOR, "-fill", NULL, NULL, + "black", -1, Tk_Offset(LineItem, outline.color), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-joinstyle", NULL, NULL, + "round", -1, Tk_Offset(LineItem, joinStyle), + 0, (ClientData) joinStyleStrings, 0}, + {TK_OPTION_CUSTOM, "-offset", NULL, NULL, + "0,0", -1, Tk_Offset(LineItem, outline.tsoffsetPtr), + 0, &offsetCO, 0}, + {TK_OPTION_CUSTOM, "-smooth", NULL, NULL, + "0", -1, Tk_Offset(LineItem, smooth), + 0, &smoothCO, 0}, + {TK_OPTION_INT, "-splinesteps", NULL, NULL, + "12", -1, Tk_Offset(LineItem, splineSteps), 0, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", NULL, NULL, + PATH_DEF_STATE, -1, Tk_Offset(Tk_PathItem, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_BITMAP, "-stipple", NULL, NULL, + NULL, -1, Tk_Offset(LineItem, outline.stipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-tags", NULL, NULL, + NULL, -1, Tk_Offset(Tk_PathItem, pathTagsPtr), + TK_OPTION_NULL_OK, (ClientData) &tagsCO, 0}, + {TK_OPTION_CUSTOM, "-width", NULL, NULL, + "1.0", -1, Tk_Offset(LineItem, outline.width), 0, &pixelCO, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * The structures below defines the line item type by means of functions that + * can be invoked by generic item code. + */ + +Tk_PathItemType tkLineType = { + "line", /* name */ + sizeof(LineItem), /* itemSize */ + CreateLine, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigureLine, /* configureProc */ + LineCoords, /* coordProc */ + DeleteLine, /* deleteProc */ + DisplayLine, /* displayProc */ + 0, /* flags */ + NULL, /* bboxProc */ + LineToPoint, /* pointProc */ + LineToArea, /* areaProc */ + LineToPostscript, /* postscriptProc */ + ScaleLine, /* scaleProc */ + TranslateLine, /* translateProc */ + (Tk_PathItemIndexProc *) GetLineIndex,/* indexProc */ + NULL, /* icursorProc */ + NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) LineInsert,/* insertProc */ + LineDeleteCoords, /* dTextProc */ + NULL, /* nextPtr */ +}; + +/* + * 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 + +/* + *-------------------------------------------------------------- + * + * CreateLine -- + * + * This function is invoked to create a new line 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 the interp's result; in this + * case itemPtr is left uninitialized, so it can be safely freed by the + * caller. + * + * Side effects: + * A new line item is created. + * + *-------------------------------------------------------------- + */ + +static int +CreateLine( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas to hold new item. */ + Tk_PathItem *itemPtr, /* Record to hold new item; header has been + * initialized by caller. */ + int objc, /* Number of arguments in objv. */ + Tcl_Obj *CONST objv[]) /* Arguments describing line. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed to set defaults and to allow + * proper cleanup after errors during the the remainder of this function. + */ + + Tk_PathCreateOutline(&(linePtr->outline)); + linePtr->canvas = canvas; + linePtr->numPoints = 0; + linePtr->coordPtr = NULL; + linePtr->capStyle = CapButt; + linePtr->joinStyle = JoinRound; + linePtr->arrowGC = None; + linePtr->arrow = ARROWS_NONE; + linePtr->arrowShapeObj = NULL; + linePtr->firstArrowPtr = NULL; + linePtr->lastArrowPtr = NULL; + linePtr->smooth = NULL; + linePtr->splineSteps = 12; + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) linePtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + /* + * 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 = 1; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + if (LineCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { + goto error; + } + if (ConfigureLine(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { + return TCL_OK; + } + + error: + DeleteLine(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * LineCoords -- + * + * This function is invoked to process the "coords" widget command on + * lines. See the user documentation for details on what it does. + * + * Results: + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. + * + * Side effects: + * The coordinates for the given item may be changed. + * + *-------------------------------------------------------------- + */ + +static int +LineCoords( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item whose coordinates are to be read or + * modified. */ + int objc, /* Number of coordinates supplied in objv. */ + Tcl_Obj *CONST objv[]) /* Array of coordinates: x1, y1, x2, y2, ... */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + int i, numPoints; + double *coordPtr; + + if (objc == 0) { + int numCoords; + Tcl_Obj *subobj, *obj = Tcl_NewObj(); + + numCoords = 2*linePtr->numPoints; + if (linePtr->firstArrowPtr != NULL) { + coordPtr = linePtr->firstArrowPtr; + } else { + coordPtr = linePtr->coordPtr; + } + for (i = 0; i < numCoords; i++, coordPtr++) { + if (i == 2) { + coordPtr = linePtr->coordPtr+2; + } + if ((linePtr->lastArrowPtr != NULL) && (i == (numCoords-2))) { + coordPtr = linePtr->lastArrowPtr; + } + subobj = Tcl_NewDoubleObj(*coordPtr); + Tcl_ListObjAppendElement(interp, obj, subobj); + } + Tcl_SetObjResult(interp, obj); + return TCL_OK; + } + if (objc == 1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } + } + if (objc & 1) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected an even number, got %d", + objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } else if (objc < 4) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected at least 4, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } else { + numPoints = objc/2; + if (linePtr->numPoints != numPoints) { + coordPtr = (double *) + ckalloc((unsigned) (sizeof(double) * objc)); + if (linePtr->coordPtr != NULL) { + ckfree((char *) linePtr->coordPtr); + } + linePtr->coordPtr = coordPtr; + linePtr->numPoints = numPoints; + } + coordPtr = linePtr->coordPtr; + for (i = 0; i <objc; i++) { + if (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[i], + coordPtr++) != TCL_OK) { + return TCL_ERROR; + } + } + + /* + * Update arrowheads by throwing away any existing arrow-head + * information and calling ConfigureArrows to recompute it. + */ + + if (linePtr->firstArrowPtr != NULL) { + ckfree((char *) linePtr->firstArrowPtr); + linePtr->firstArrowPtr = NULL; + } + if (linePtr->lastArrowPtr != NULL) { + ckfree((char *) linePtr->lastArrowPtr); + linePtr->lastArrowPtr = NULL; + } + if (linePtr->arrow != ARROWS_NONE) { + ConfigureArrows(canvas, linePtr); + } + ComputeLineBbox(canvas, linePtr); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ConfigureLine -- + * + * This function is invoked to configure various aspects of a line item + * such as its background color. + * + * Results: + * A standard Tcl result code. If an error occurs, then an error message + * is left in the interp's result. + * + * Side effects: + * Configuration information, such as colors and stipple patterns, may be + * set for itemPtr. + * + *-------------------------------------------------------------- + */ + +static int +ConfigureLine( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Line item to reconfigure. */ + int objc, /* Number of elements in objv. */ + Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ + int flags) /* Flags to pass to Tk_ConfigureWidget. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + XGCValues gcValues; + GC newGC, arrowGC; + unsigned long mask; + Tk_Window tkwin; + Tk_PathState state; + + tkwin = Tk_PathCanvasTkwin(canvas); + if (TCL_OK != Tk_SetOptions(interp, (char *) linePtr, optionTable, + objc, objv, tkwin, NULL, NULL)) { + return TCL_ERROR; + } + + /* + * A few of the options require additional processing, such as graphics + * contexts. + */ + + state = itemPtr->state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + if (linePtr->outline.activeWidth > linePtr->outline.width || + (linePtr->outline.activeDashPtr != NULL + && linePtr->outline.activeDashPtr->number != 0) || + linePtr->outline.activeColor != NULL || + linePtr->outline.activeStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + mask = Tk_PathConfigOutlineGC(&gcValues, canvas, itemPtr, + &(linePtr->outline)); + if (mask) { + if (linePtr->arrow == ARROWS_NONE) { + gcValues.cap_style = linePtr->capStyle; + mask |= GCCapStyle; + } + gcValues.join_style = linePtr->joinStyle; + mask |= GCJoinStyle; + newGC = Tk_GetGC(tkwin, mask, &gcValues); +#ifdef MAC_OSX_TK + /* + * Mac OS X CG drawing needs access to linewidth even for + * arrow fills (as linewidth controls antialiasing). + */ + mask |= GCLineWidth; +#else + gcValues.line_width = 0; +#endif + arrowGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = arrowGC = None; + } + if (linePtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), linePtr->outline.gc); + } + if (linePtr->arrowGC != None) { + Tk_FreeGC(Tk_Display(tkwin), linePtr->arrowGC); + } + linePtr->outline.gc = newGC; + linePtr->arrowGC = arrowGC; + + /* + * Keep spline parameters within reasonable limits. + */ + + if (linePtr->splineSteps < 1) { + linePtr->splineSteps = 1; + } else if (linePtr->splineSteps > 100) { + linePtr->splineSteps = 100; + } + + if ((!linePtr->numPoints) || (state==TK_PATHSTATE_HIDDEN)) { + ComputeLineBbox(canvas, linePtr); + return TCL_OK; + } + + /* + * Setup arrowheads, if needed. If arrowheads are turned off, restore the + * line's endpoints (they were shortened when the arrowheads were added). + */ + + if ((linePtr->firstArrowPtr != NULL) && (linePtr->arrow != ARROWS_FIRST) + && (linePtr->arrow != ARROWS_BOTH)) { + linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; + linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; + ckfree((char *) linePtr->firstArrowPtr); + linePtr->firstArrowPtr = NULL; + } + if ((linePtr->lastArrowPtr != NULL) && (linePtr->arrow != ARROWS_LAST) + && (linePtr->arrow != ARROWS_BOTH)) { + int i; + + i = 2*(linePtr->numPoints-1); + linePtr->coordPtr[i] = linePtr->lastArrowPtr[0]; + linePtr->coordPtr[i+1] = linePtr->lastArrowPtr[1]; + ckfree((char *) linePtr->lastArrowPtr); + linePtr->lastArrowPtr = NULL; + } + if (linePtr->arrow != ARROWS_NONE) { + ConfigureArrows(canvas, linePtr); + } + + /* + * Recompute bounding box for line. + */ + + ComputeLineBbox(canvas, linePtr); + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * DeleteLine -- + * + * This function is called to clean up the data structure associated with + * a line item. + * + * Results: + * None. + * + * Side effects: + * Resources associated with itemPtr are released. + * + *-------------------------------------------------------------- + */ + +static void +DeleteLine( + Tk_PathCanvas canvas, /* Info about overall canvas widget. */ + Tk_PathItem *itemPtr, /* Item that is being deleted. */ + Display *display) /* Display containing window for canvas. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + + if (linePtr->coordPtr != NULL) { + ckfree((char *) linePtr->coordPtr); + } + if (linePtr->arrowGC != None) { + Tk_FreeGC(display, linePtr->arrowGC); + } + if (linePtr->firstArrowPtr != NULL) { + ckfree((char *) linePtr->firstArrowPtr); + } + if (linePtr->lastArrowPtr != NULL) { + ckfree((char *) linePtr->lastArrowPtr); + } + Tk_FreeConfigOptions((char *) linePtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +/* + *-------------------------------------------------------------- + * + * ComputeLineBbox -- + * + * This function is invoked to compute the bounding box of all the pixels + * that may be drawn as part of a line. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header for itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +ComputeLineBbox( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + LineItem *linePtr) /* Item whose bbos is to be recomputed. */ +{ + double *coordPtr; + int i, intWidth; + double width; + Tk_PathState state = linePtr->header.state; + Tk_TSOffset *tsoffset; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + if (!(linePtr->numPoints) || (state==TK_PATHSTATE_HIDDEN)) { + linePtr->header.x1 = -1; + linePtr->header.x2 = -1; + linePtr->header.y1 = -1; + linePtr->header.y2 = -1; + return; + } + + width = linePtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == (Tk_PathItem *)linePtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + + coordPtr = linePtr->coordPtr; + linePtr->header.x1 = linePtr->header.x2 = (int) *coordPtr; + linePtr->header.y1 = linePtr->header.y2 = (int) coordPtr[1]; + + /* + * Compute the bounding box of all the points in the line, then expand in + * all directions by the line'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. eDon't do anything special for curves. This causes an + * additional overestimate in the bounding box, but is faster. + */ + + for (i = 1, coordPtr = linePtr->coordPtr+2; i < linePtr->numPoints; + i++, coordPtr += 2) { + TkPathIncludePoint((Tk_PathItem *) linePtr, coordPtr); + } + width = linePtr->outline.width; + if (width < 1.0) { + width = 1.0; + } + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { + TkPathIncludePoint((Tk_PathItem *) linePtr, linePtr->firstArrowPtr); + } + if (linePtr->arrow != ARROWS_FIRST) { + TkPathIncludePoint((Tk_PathItem *) linePtr, linePtr->lastArrowPtr); + } + } + + tsoffset = linePtr->outline.tsoffsetPtr; + if (tsoffset != NULL) { + if (tsoffset->flags & TK_OFFSET_INDEX) { + double *coordPtr = linePtr->coordPtr + (tsoffset->flags & ~TK_OFFSET_INDEX); + if (tsoffset->flags <= 0) { + coordPtr = linePtr->coordPtr; + if ((linePtr->arrow == ARROWS_FIRST) || (linePtr->arrow == ARROWS_BOTH)) { + coordPtr = linePtr->firstArrowPtr; + } + } + if (tsoffset->flags > (linePtr->numPoints * 2)) { + coordPtr = linePtr->coordPtr + (linePtr->numPoints * 2); + if ((linePtr->arrow == ARROWS_LAST) || (linePtr->arrow == ARROWS_BOTH)) { + coordPtr = linePtr->lastArrowPtr; + } + } + tsoffset->xoffset = (int) (coordPtr[0] + 0.5); + tsoffset->yoffset = (int) (coordPtr[1] + 0.5); + } else { + if (tsoffset->flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = linePtr->header.x1; + } else if (tsoffset->flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (linePtr->header.x1 + linePtr->header.x2)/2; + } else if (tsoffset->flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = linePtr->header.x2; + } + if (tsoffset->flags & TK_OFFSET_TOP) { + tsoffset->yoffset = linePtr->header.y1; + } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (linePtr->header.y1 + linePtr->header.y2)/2; + } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = linePtr->header.y2; + } + } + } + + intWidth = (int) (width + 0.5); + linePtr->header.x1 -= intWidth; + linePtr->header.x2 += intWidth; + linePtr->header.y1 -= intWidth; + linePtr->header.y2 += intWidth; + + if (linePtr->numPoints == 1) { + linePtr->header.x1 -= 1; + linePtr->header.x2 += 1; + linePtr->header.y1 -= 1; + linePtr->header.y2 += 1; + return; + } + + /* + * For mitered lines, 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 (linePtr->joinStyle == JoinMiter) { + for (i = linePtr->numPoints, coordPtr = linePtr->coordPtr; i >= 3; + i--, coordPtr += 2) { + double miter[4]; + int j; + + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + width, miter, miter+2)) { + for (j = 0; j < 4; j += 2) { + TkPathIncludePoint((Tk_PathItem *) linePtr, miter+j); + } + } + } + } + + /* + * Add in the sizes of arrowheads, if any. + */ + + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkPathIncludePoint((Tk_PathItem *) linePtr, coordPtr); + } + } + if (linePtr->arrow != ARROWS_FIRST) { + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkPathIncludePoint((Tk_PathItem *) linePtr, coordPtr); + } + } + } + + /* + * Add one more pixel of fudge factor just to be safe (e.g. X may round + * differently than we do). + */ + + linePtr->header.x1 -= 1; + linePtr->header.x2 += 1; + linePtr->header.y1 -= 1; + linePtr->header.y2 += 1; +} + +/* + *-------------------------------------------------------------- + * + * DisplayLine -- + * + * This function is invoked to draw a line item in a given drawable. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation information in + * canvas. + * + *-------------------------------------------------------------- + */ + +static void +DisplayLine( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + Tk_PathItem *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, int y, int width, int height) + /* Describes region of canvas that must be + * redisplayed (not used). */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + XPoint staticPoints[MAX_STATIC_POINTS*3]; + XPoint *pointPtr; + double linewidth; + int numPoints; + Tk_PathState state = itemPtr->state; + + if ((!linePtr->numPoints)||(linePtr->outline.gc==None)) { + return; + } + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + linewidth = linePtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth != linewidth) { + linewidth = linePtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (linePtr->outline.disabledWidth != linewidth) { + linewidth = linePtr->outline.disabledWidth; + } + } + /* + * Build up an array of points in screen coordinates. Use a static array + * unless the line has an enormous number of points; in this case, + * dynamically allocate an array. For smoothed lines, generate the curve + * points on each redisplay. + */ + + if ((linePtr->smooth) && (linePtr->numPoints > 2)) { + numPoints = linePtr->smooth->coordProc(canvas, NULL, + linePtr->numPoints, linePtr->splineSteps, NULL, NULL); + } else { + numPoints = linePtr->numPoints; + } + + if (numPoints <= MAX_STATIC_POINTS) { + pointPtr = staticPoints; + } else { + pointPtr = (XPoint *)ckalloc((unsigned)(numPoints * 3*sizeof(XPoint))); + } + + if ((linePtr->smooth) && (linePtr->numPoints > 2)) { + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, + linePtr->numPoints, linePtr->splineSteps, pointPtr, NULL); + } else { + numPoints = TkPathCanvTranslatePath((TkPathCanvas*)canvas, numPoints, + linePtr->coordPtr, 0, pointPtr); + } + + /* + * Display line, the free up line 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 (Tk_PathChangeOutlineGC(canvas, itemPtr, &(linePtr->outline))) { + Tk_PathCanvasSetOffset(canvas, linePtr->arrowGC, linePtr->outline.tsoffsetPtr); + } + if (numPoints>1) { + XDrawLines(display, drawable, linePtr->outline.gc, pointPtr, numPoints, + CoordModeOrigin); + } else { + int intwidth = (int) (linewidth + 0.5); + if (intwidth<1) { + intwidth=1; + } + XFillArc(display, drawable, linePtr->outline.gc, + pointPtr->x - intwidth/2, pointPtr->y - intwidth/2, + (unsigned int)intwidth+1, (unsigned int)intwidth+1, 0, 64*360); + } + if (pointPtr != staticPoints) { + ckfree((char *) pointPtr); + } + + /* + * Display arrowheads, if they are wanted. + */ + + if (linePtr->firstArrowPtr != NULL) { + TkPathFillPolygon(canvas, linePtr->firstArrowPtr, PTS_IN_ARROW, + display, drawable, linePtr->arrowGC, NULL); + } + if (linePtr->lastArrowPtr != NULL) { + TkPathFillPolygon(canvas, linePtr->lastArrowPtr, PTS_IN_ARROW, + display, drawable, linePtr->arrowGC, NULL); + } + if (Tk_PathResetOutlineGC(canvas, itemPtr, &(linePtr->outline))) { + XSetTSOrigin(display, linePtr->arrowGC, 0, 0); + } +} + +/* + *-------------------------------------------------------------- + * + * LineInsert -- + * + * Insert coords into a line item at a given index. + * + * Results: + * None. + * + * Side effects: + * The coords in the given item is modified. + * + *-------------------------------------------------------------- + */ + +static void +LineInsert( + Tk_PathCanvas canvas, /* Canvas containing text item. */ + Tk_PathItem *itemPtr, /* Line item to be modified. */ + int beforeThis, /* Index before which new coordinates are to + * be inserted. */ + Tcl_Obj *obj) /* New coordinates to be inserted. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + int length, objc, i; + double *newCoordPtr, *coordPtr; + Tk_PathState state = itemPtr->state; + Tcl_Obj **objv; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + if (!obj || (Tcl_ListObjGetElements(NULL, obj, &objc, &objv) != TCL_OK) + || !objc || objc&1) { + return; + } + length = 2*linePtr->numPoints; + if (beforeThis < 0) { + beforeThis = 0; + } + if (beforeThis > length) { + beforeThis = length; + } + if (linePtr->firstArrowPtr != NULL) { + linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; + linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; + } + if (linePtr->lastArrowPtr != NULL) { + linePtr->coordPtr[length-2] = linePtr->lastArrowPtr[0]; + linePtr->coordPtr[length-1] = linePtr->lastArrowPtr[1]; + } + newCoordPtr = (double *) + ckalloc(sizeof(double) * (unsigned)(length + objc)); + for (i=0; i<beforeThis; i++) { + newCoordPtr[i] = linePtr->coordPtr[i]; + } + for (i=0; i<objc; i++) { + if (Tcl_GetDoubleFromObj(NULL, objv[i], + &newCoordPtr[i + beforeThis]) != TCL_OK) { + Tcl_ResetResult(((TkPathCanvas *)canvas)->interp); + ckfree((char *) newCoordPtr); + return; + } + } + + for (i=beforeThis; i<length; i++) { + newCoordPtr[i+objc] = linePtr->coordPtr[i]; + } + if (linePtr->coordPtr) { + ckfree((char *)linePtr->coordPtr); + } + linePtr->coordPtr = newCoordPtr; + linePtr->numPoints = (length + objc)/2; + + if ((length>3) && (state != TK_PATHSTATE_HIDDEN)) { + /* + * This is some optimizing code that will result that only the part of + * the polygon that changed (and the objects that are overlapping with + * that part) need to be redrawn. A special flag is set that instructs + * the general canvas code not to redraw the whole object. If this + * flag is not set, the canvas will do the redrawing, otherwise I have + * to do it here. + */ + + itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW; + + if (beforeThis>0) {beforeThis -= 2; objc+=2; } + if ((beforeThis+objc)<length) objc+=2; + if (linePtr->smooth) { + if(beforeThis>0) { + beforeThis-=2; objc+=2; + } + if((beforeThis+objc+2)<length) { + objc+=2; + } + } + itemPtr->x1 = itemPtr->x2 = (int) linePtr->coordPtr[beforeThis]; + itemPtr->y1 = itemPtr->y2 = (int) linePtr->coordPtr[beforeThis+1]; + if ((linePtr->firstArrowPtr != NULL) && (beforeThis<1)) { + /* + * Include old first arrow. + */ + + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkPathIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && ((beforeThis+objc)>=length)) { + /* + * Include old last arrow. + */ + + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkPathIncludePoint(itemPtr, coordPtr); + } + } + coordPtr = linePtr->coordPtr+beforeThis+2; + for (i=2; i<objc; i+=2) { + TkPathIncludePoint(itemPtr, coordPtr); + coordPtr+=2; + } + } + if (linePtr->firstArrowPtr != NULL) { + ckfree((char *) linePtr->firstArrowPtr); + linePtr->firstArrowPtr = NULL; + } + if (linePtr->lastArrowPtr != NULL) { + ckfree((char *) linePtr->lastArrowPtr); + linePtr->lastArrowPtr = NULL; + } + if (linePtr->arrow != ARROWS_NONE) { + ConfigureArrows(canvas, linePtr); + } + + if (itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW) { + double width; + int intWidth; + + if ((linePtr->firstArrowPtr != NULL) && (beforeThis>2)) { + /* + * Include new first arrow. + */ + + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkPathIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && (beforeThis+objc < length-2)) { + /* + * Include new right arrow. + */ + + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkPathIncludePoint(itemPtr, coordPtr); + } + } + width = linePtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + intWidth = (int) (width + 0.5); + if (intWidth < 1) { + intWidth = 1; + } + itemPtr->x1 -= intWidth; itemPtr->y1 -= intWidth; + itemPtr->x2 += intWidth; itemPtr->y2 += intWidth; + Tk_PathCanvasEventuallyRedraw(canvas, itemPtr->x1, itemPtr->y1, + itemPtr->x2, itemPtr->y2); + } + + ComputeLineBbox(canvas, linePtr); +} + +/* + *-------------------------------------------------------------- + * + * LineDeleteCoords -- + * + * Delete one or more coordinates from a line item. + * + * Results: + * None. + * + * Side effects: + * Characters between "first" and "last", inclusive, get deleted from + * itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +LineDeleteCoords( + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Item in which to delete characters. */ + int first, /* Index of first character to delete. */ + int last) /* Index of last character to delete. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + int count, i, first1, last1; + int length = 2*linePtr->numPoints; + double *coordPtr; + Tk_PathState state = itemPtr->state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + first &= -2; + last &= -2; + + if (first < 0) { + first = 0; + } + if (last >= length) { + last = length-2; + } + if (first > last) { + return; + } + if (linePtr->firstArrowPtr != NULL) { + linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; + linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; + } + if (linePtr->lastArrowPtr != NULL) { + linePtr->coordPtr[length-2] = linePtr->lastArrowPtr[0]; + linePtr->coordPtr[length-1] = linePtr->lastArrowPtr[1]; + } + first1 = first; last1 = last; + if(first1>0) first1 -= 2; + if(last1<length-2) last1 += 2; + if (linePtr->smooth) { + if(first1>0) first1 -= 2; + if(last1<length-2) last1 += 2; + } + + if((first1<2) && (last1 >= length-2)) { + /* + * This is some optimizing code that will result that only the part of + * the line that changed (and the objects that are overlapping with + * that part) need to be redrawn. A special flag is set that instructs + * the general canvas code not to redraw the whole object. If this + * flag is set, the redrawing has to be done here, otherwise the + * general Canvas code will take care of it. + */ + + itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW; + itemPtr->x1 = itemPtr->x2 = (int) linePtr->coordPtr[first1]; + itemPtr->y1 = itemPtr->y2 = (int) linePtr->coordPtr[first1+1]; + if ((linePtr->firstArrowPtr != NULL) && (first1<2)) { + /* + * Include old first arrow. + */ + + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkPathIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && (last1>=length-2)) { + /* + * Include old last arrow. + */ + + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkPathIncludePoint(itemPtr, coordPtr); + } + } + coordPtr = linePtr->coordPtr+first1+2; + for (i=first1+2; i<=last1; i+=2) { + TkPathIncludePoint(itemPtr, coordPtr); + coordPtr+=2; + } + } + + count = last + 2 - first; + for (i=last+2; i<length; i++) { + linePtr->coordPtr[i-count] = linePtr->coordPtr[i]; + } + linePtr->numPoints -= count/2; + if (linePtr->firstArrowPtr != NULL) { + ckfree((char *) linePtr->firstArrowPtr); + linePtr->firstArrowPtr = NULL; + } + if (linePtr->lastArrowPtr != NULL) { + ckfree((char *) linePtr->lastArrowPtr); + linePtr->lastArrowPtr = NULL; + } + if (linePtr->arrow != ARROWS_NONE) { + ConfigureArrows(canvas, linePtr); + } + if(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW) { + double width; + int intWidth; + + if ((linePtr->firstArrowPtr != NULL) && (first1<4)) { + /* + * Include new first arrow. + */ + + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkPathIncludePoint(itemPtr, coordPtr); + } + } + if ((linePtr->lastArrowPtr != NULL) && (last1>(length-4))) { + /* + * Include new right arrow. + */ + + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + TkPathIncludePoint(itemPtr, coordPtr); + } + } + width = linePtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + intWidth = (int) (width + 0.5); + if (intWidth < 1) { + intWidth = 1; + } + itemPtr->x1 -= intWidth; itemPtr->y1 -= intWidth; + itemPtr->x2 += intWidth; itemPtr->y2 += intWidth; + Tk_PathCanvasEventuallyRedraw(canvas, itemPtr->x1, itemPtr->y1, + itemPtr->x2, itemPtr->y2); + } + ComputeLineBbox(canvas, linePtr); +} + +/* + *-------------------------------------------------------------- + * + * LineToPoint -- + * + * Computes the distance from a given point to a given line, 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 line. If the point isn't + * inside the line then the return value is the distance from the point + * to the line. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static double +LineToPoint( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + double *pointPtr) /* Pointer to x and y coordinates. */ +{ + Tk_PathState state = itemPtr->state; + LineItem *linePtr = (LineItem *) itemPtr; + double *coordPtr, *linePoints; + double staticSpace[2*MAX_STATIC_POINTS]; + double poly[10]; + double bestDist, dist, width; + 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.0e36; + + /* + * Handle smoothed lines by generating an expanded set of points against + * which to do the check. + */ + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = linePtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + + if ((linePtr->smooth) && (linePtr->numPoints > 2)) { + numPoints = linePtr->smooth->coordProc(canvas, NULL, + linePtr->numPoints, linePtr->splineSteps, NULL, NULL); + if (numPoints <= MAX_STATIC_POINTS) { + linePoints = staticSpace; + } else { + linePoints = (double *) ckalloc((unsigned) + (2*numPoints*sizeof(double))); + } + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, + linePtr->numPoints, linePtr->splineSteps, NULL, linePoints); + } else { + numPoints = linePtr->numPoints; + linePoints = linePtr->coordPtr; + } + + if (width < 1.0) { + width = 1.0; + } + + if (!numPoints || itemPtr->state==TK_PATHSTATE_HIDDEN) { + return bestDist; + } else if (numPoints == 1) { + bestDist = hypot(linePoints[0]-pointPtr[0], linePoints[1]-pointPtr[1]) + - width/2.0; + if (bestDist < 0) bestDist = 0; + return bestDist; + } + + /* + * The overall idea is to iterate through all of the edges of the line, + * 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 = linePoints; count >= 2; + count--, coordPtr += 2) { + /* + * If rounding is done around the first point then compute the + * distance between the point and the point. + */ + + if (((linePtr->capStyle == CapRound) && (count == numPoints)) + || ((linePtr->joinStyle == JoinRound) + && (count != numPoints))) { + dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) + - 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, width, + linePtr->capStyle == CapProjecting, poly, poly+2); + } else if ((linePtr->joinStyle == JoinMiter) && !changedMiterToBevel) { + poly[0] = poly[6]; + poly[1] = poly[7]; + poly[2] = poly[4]; + poly[3] = poly[5]; + } else { + TkGetButtPoints(coordPtr+2, coordPtr, width, 0, poly, poly+2); + + /* + * If this line 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 ((linePtr->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, width, + linePtr->capStyle == CapProjecting, poly+4, poly+6); + } else if (linePtr->joinStyle == JoinMiter) { + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + width, poly+4, poly+6) == 0) { + changedMiterToBevel = 1; + TkGetButtPoints(coordPtr, coordPtr+2, width, 0, + poly+4, poly+6); + } + } else { + TkGetButtPoints(coordPtr, coordPtr+2, 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 line. + */ + + if (linePtr->capStyle == CapRound) { + dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) + - 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 (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { + dist = TkPolygonToPoint(linePtr->firstArrowPtr, PTS_IN_ARROW, + pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto done; + } else if (dist < bestDist) { + bestDist = dist; + } + } + if (linePtr->arrow != ARROWS_FIRST) { + dist = TkPolygonToPoint(linePtr->lastArrowPtr, PTS_IN_ARROW, + pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto done; + } else if (dist < bestDist) { + bestDist = dist; + } + } + } + + done: + if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) { + ckfree((char *) linePoints); + } + return bestDist; +} + +/* + *-------------------------------------------------------------- + * + * LineToArea -- + * + * This function 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 +LineToArea( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against line. */ + double *rectPtr) +{ + LineItem *linePtr = (LineItem *) itemPtr; + double staticSpace[2*MAX_STATIC_POINTS]; + double *linePoints; + int numPoints, result; + double radius, width; + Tk_PathState state = itemPtr->state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + width = linePtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + + radius = (width+1.0)/2.0; + + if ((state==TK_PATHSTATE_HIDDEN) || !linePtr->numPoints) { + return -1; + } else if (linePtr->numPoints == 1) { + double oval[4]; + + oval[0] = linePtr->coordPtr[0]-radius; + oval[1] = linePtr->coordPtr[1]-radius; + oval[2] = linePtr->coordPtr[0]+radius; + oval[3] = linePtr->coordPtr[1]+radius; + return TkOvalToArea(oval, rectPtr); + } + + /* + * Handle smoothed lines by generating an expanded set of points against + * which to do the check. + */ + + if ((linePtr->smooth) && (linePtr->numPoints > 2)) { + numPoints = linePtr->smooth->coordProc(canvas, NULL, + linePtr->numPoints, linePtr->splineSteps, NULL, NULL); + if (numPoints <= MAX_STATIC_POINTS) { + linePoints = staticSpace; + } else { + linePoints = (double *) ckalloc((unsigned) + (2*numPoints*sizeof(double))); + } + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, + linePtr->numPoints, linePtr->splineSteps, NULL, linePoints); + } else { + numPoints = linePtr->numPoints; + linePoints = linePtr->coordPtr; + } + + /* + * Check the segments of the line. + */ + + if (width < 1.0) { + width = 1.0; + } + + result = TkThickPolyLineToArea(linePoints, numPoints, + width, linePtr->capStyle, linePtr->joinStyle, + rectPtr); + if (result == 0) { + goto done; + } + + /* + * Check arrowheads, if any. + */ + + if (linePtr->arrow != ARROWS_NONE) { + if (linePtr->arrow != ARROWS_LAST) { + if (TkPolygonToArea(linePtr->firstArrowPtr, PTS_IN_ARROW, + rectPtr) != result) { + result = 0; + goto done; + } + } + if (linePtr->arrow != ARROWS_FIRST) { + if (TkPolygonToArea(linePtr->lastArrowPtr, PTS_IN_ARROW, + rectPtr) != result) { + result = 0; + goto done; + } + } + } + + done: + if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) { + ckfree((char *) linePoints); + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * ScaleLine -- + * + * This function is invoked to rescale a line item. + * + * Results: + * None. + * + * Side effects: + * The line 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 +ScaleLine( + Tk_PathCanvas canvas, /* Canvas containing line. */ + Tk_PathItem *itemPtr, /* Line to be scaled. */ + double originX, double originY, + /* Origin about which to scale rect. */ + double scaleX, /* Amount to scale in X direction. */ + double scaleY) /* Amount to scale in Y direction. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + double *coordPtr; + int i; + + /* + * Delete any arrowheads before scaling all the points (so that the + * end-points of the line get restored). + */ + + if (linePtr->firstArrowPtr != NULL) { + linePtr->coordPtr[0] = linePtr->firstArrowPtr[0]; + linePtr->coordPtr[1] = linePtr->firstArrowPtr[1]; + ckfree((char *) linePtr->firstArrowPtr); + linePtr->firstArrowPtr = NULL; + } + if (linePtr->lastArrowPtr != NULL) { + int i; + + i = 2*(linePtr->numPoints-1); + linePtr->coordPtr[i] = linePtr->lastArrowPtr[0]; + linePtr->coordPtr[i+1] = linePtr->lastArrowPtr[1]; + ckfree((char *) linePtr->lastArrowPtr); + linePtr->lastArrowPtr = NULL; + } + for (i = 0, coordPtr = linePtr->coordPtr; i < linePtr->numPoints; + i++, coordPtr += 2) { + coordPtr[0] = originX + scaleX*(*coordPtr - originX); + coordPtr[1] = originY + scaleY*(coordPtr[1] - originY); + } + if (linePtr->arrow != ARROWS_NONE) { + ConfigureArrows(canvas, linePtr); + } + ComputeLineBbox(canvas, linePtr); +} + +/* + *-------------------------------------------------------------- + * + * GetLineIndex -- + * + * Parse an index into a line item and return either its value or an + * error. + * + * Results: + * A standard Tcl result. If all went well, then *indexPtr is filled in + * with the index (into itemPtr) corresponding to string. Otherwise an + * error message is left in interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetLineIndex( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item for which the index is being + * specified. */ + Tcl_Obj *obj, /* Specification of a particular coord in + * itemPtr's line. */ + int *indexPtr) /* Where to store converted index. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + int length; + char *string = Tcl_GetStringFromObj(obj, &length); + + if (string[0] == 'e') { + if (strncmp(string, "end", (unsigned) length) == 0) { + *indexPtr = 2*linePtr->numPoints; + } else { + /* + * Some of the paths here leave messages in interp->result, so we + * have to clear it out before storing our own message. + */ + + badIndex: + Tcl_SetResult(interp, NULL, TCL_STATIC); + Tcl_AppendResult(interp, "bad index \"", string, "\"", NULL); + return TCL_ERROR; + } + } else if (string[0] == '@') { + int i; + double x ,y, bestDist, dist, *coordPtr; + char *end, *p; + + p = string+1; + x = strtod(p, &end); + if ((end == p) || (*end != ',')) { + goto badIndex; + } + p = end+1; + y = strtod(p, &end); + if ((end == p) || (*end != 0)) { + goto badIndex; + } + bestDist = 1.0e36; + coordPtr = linePtr->coordPtr; + *indexPtr = 0; + for(i=0; i<linePtr->numPoints; i++) { + dist = hypot(coordPtr[0] - x, coordPtr[1] - y); + if (dist<bestDist) { + bestDist = dist; + *indexPtr = 2*i; + } + coordPtr += 2; + } + } else { + if (Tcl_GetIntFromObj(interp, obj, indexPtr) != TCL_OK) { + goto badIndex; + } + *indexPtr &= -2; /* if index is odd, make it even */ + if (*indexPtr < 0){ + *indexPtr = 0; + } else if (*indexPtr > (2*linePtr->numPoints)) { + *indexPtr = (2*linePtr->numPoints); + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TranslateLine -- + * + * This function is called to move a line by a given amount. + * + * Results: + * None. + * + * Side effects: + * The position of the line is offset by (xDelta, yDelta), and the + * bounding box is updated in the generic part of the item structure. + * + *-------------------------------------------------------------- + */ + +static void +TranslateLine( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item that is being moved. */ + double deltaX, double deltaY) + /* Amount by which item is to be moved. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + double *coordPtr; + int i; + + for (i = 0, coordPtr = linePtr->coordPtr; i < linePtr->numPoints; + i++, coordPtr += 2) { + coordPtr[0] += deltaX; + coordPtr[1] += deltaY; + } + if (linePtr->firstArrowPtr != NULL) { + for (i = 0, coordPtr = linePtr->firstArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + coordPtr[0] += deltaX; + coordPtr[1] += deltaY; + } + } + if (linePtr->lastArrowPtr != NULL) { + for (i = 0, coordPtr = linePtr->lastArrowPtr; i < PTS_IN_ARROW; + i++, coordPtr += 2) { + coordPtr[0] += deltaX; + coordPtr[1] += deltaY; + } + } + ComputeLineBbox(canvas, linePtr); +} + +/* + *-------------------------------------------------------------- + * + * ArrowShapeOptionSetProc, ... -- + * + * This function is invoked during option processing to handle "-arrowshape" + * options for canvas items. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * . + * + *-------------------------------------------------------------- + */ + +static int +ArrowShapeOptionSetProc( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; /* Points to location in record where + * internal representation of value should + * be stored, or NULL. */ + Tcl_Obj *valuePtr; + Tcl_Obj *newPtr; + Tcl_Obj **objv; + int objc; + double dvalue; + + valuePtr = *value; + if (internalOffset >= 0) { + internalPtr = recordPtr + internalOffset; + } else { + internalPtr = NULL; + } + if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + newPtr = NULL; + } + if (internalPtr != NULL) { + if (valuePtr != NULL) { + if (Tcl_ListObjGetElements(interp, valuePtr, &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + goto error; + } + if (objc != 3) { + goto error; + } + /* + * We just verify that they are OK. + * No internal storage! + */ + if ((Tk_GetMMFromObj(interp, tkwin, objv[0], &dvalue) != TCL_OK) + || (Tk_GetMMFromObj(interp, tkwin, objv[1], &dvalue) + != TCL_OK) + || (Tk_GetMMFromObj(interp, tkwin, objv[2], &dvalue) + != TCL_OK)) { + goto error; + } + } + } + return TCL_OK; + +error: + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "bad arrow shape \"", Tcl_GetString(valuePtr), + "\": must be list with three numbers", NULL); + return TCL_ERROR; +} + +static Tcl_Obj * +ArrowShapeOptionGetProc( + ClientData clientData, + Tk_Window tkwin, + char *recordPtr, /* Pointer to widget record. */ + int internalOffset) /* Offset within *recordPtr containing the + * value. */ +{ + return (Tcl_Obj *)(recordPtr + internalOffset); +} + +/* + *-------------------------------------------------------------- + * + * ConfigureArrows -- + * + * If arrowheads have been requested for a line, this function makes + * arrangements for the arrowheads. + * + * Results: + * Always returns TCL_OK. + * + * Side effects: + * Information in linePtr 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 line are adjusted so that a + * thick line doesn't stick out past the arrowheads. + * + *-------------------------------------------------------------- + */ + +static int +ConfigureArrows( + Tk_PathCanvas canvas, /* Canvas in which arrows will be displayed + * (interp and tkwin fields are needed). */ + LineItem *linePtr) /* Item to configure for arrows. */ +{ + double *poly, *coordPtr; + double dx, dy, length, sinTheta, cosTheta, temp; + double fracHeight; /* Line width as fraction of arrowhead + * width. */ + double backup; /* Distance to backup end points so the line + * ends in the middle of the arrowhead. */ + double vertX, vertY; /* Position of arrowhead vertex. */ + double shapeA, shapeB, shapeC; + /* Adjusted coordinates (see explanation + * below). */ + double width; + Tk_PathState state = linePtr->header.state; + Tk_Window tkwin; + Tcl_Obj *objPtr; + + tkwin = Tk_PathCanvasTkwin(canvas); + + if (linePtr->numPoints <2) { + return TCL_OK; + } + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = linePtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == (Tk_PathItem *)linePtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + } + + /* + * The code below makes a tiny increase in the shape parameters for the + * line. This is a bit of a hack, but it seems to result in displays that + * more closely approximate the specified parameters. Without the + * adjustment, the arrows come out smaller than expected. + */ + + Tcl_ListObjIndex(NULL, linePtr->arrowShapeObj, 0, &objPtr); + Tk_GetMMFromObj(NULL, tkwin, objPtr, &shapeA); + shapeA *= ((TkPathCanvas *)canvas)->pixelsPerMM; + shapeA += 0.001; + Tcl_ListObjIndex(NULL, linePtr->arrowShapeObj, 1, &objPtr); + Tk_GetMMFromObj(NULL, tkwin, objPtr, &shapeB); + shapeB *= ((TkPathCanvas *)canvas)->pixelsPerMM; + shapeB += 0.001; + Tcl_ListObjIndex(NULL, linePtr->arrowShapeObj, 2, &objPtr); + Tk_GetMMFromObj(NULL, tkwin, objPtr, &shapeC); + shapeC *= ((TkPathCanvas *)canvas)->pixelsPerMM; + shapeC += 0.001 + width/2.0; + + /* + * If there's an arrowhead on the first point of the line, compute its + * polygon and adjust the first point of the line so that the line doesn't + * stick out past the leading edge of the arrowhead. + */ + + fracHeight = (width/2.0)/shapeC; + backup = fracHeight*shapeB + shapeA*(1.0 - fracHeight)/2.0; + if (linePtr->arrow != ARROWS_LAST) { + poly = linePtr->firstArrowPtr; + if (poly == NULL) { + poly = (double *) ckalloc((unsigned) + (2*PTS_IN_ARROW*sizeof(double))); + poly[0] = poly[10] = linePtr->coordPtr[0]; + poly[1] = poly[11] = linePtr->coordPtr[1]; + linePtr->firstArrowPtr = poly; + } + dx = poly[0] - linePtr->coordPtr[2]; + dy = poly[1] - linePtr->coordPtr[3]; + length = hypot(dx, dy); + if (length == 0) { + sinTheta = cosTheta = 0.0; + } else { + sinTheta = dy/length; + cosTheta = dx/length; + } + vertX = poly[0] - shapeA*cosTheta; + vertY = poly[1] - shapeA*sinTheta; + temp = shapeC*sinTheta; + poly[2] = poly[0] - shapeB*cosTheta + temp; + poly[8] = poly[2] - 2*temp; + temp = shapeC*cosTheta; + poly[3] = poly[1] - shapeB*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 line are inside the arrowhead. + */ + + linePtr->coordPtr[0] = poly[0] - backup*cosTheta; + linePtr->coordPtr[1] = poly[1] - backup*sinTheta; + } + + /* + * Similar arrowhead calculation for the last point of the line. + */ + + if (linePtr->arrow != ARROWS_FIRST) { + coordPtr = linePtr->coordPtr + 2*(linePtr->numPoints-2); + poly = linePtr->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]; + linePtr->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] - shapeA*cosTheta; + vertY = poly[1] - shapeA*sinTheta; + temp = shapeC * sinTheta; + poly[2] = poly[0] - shapeB*cosTheta + temp; + poly[8] = poly[2] - 2*temp; + temp = shapeC * cosTheta; + poly[3] = poly[1] - shapeB*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; +} + +/* + *-------------------------------------------------------------- + * + * LineToPostscript -- + * + * This function is called to generate Postscript for line items. + * + * Results: + * The return value is a standard Tcl result. If an error occurs in + * generating Postscript then an error message is left in the interp's + * 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 +LineToPostscript( + Tcl_Interp *interp, /* Leave Postscript or error message here. */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + Tk_PathItem *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. */ +{ + LineItem *linePtr = (LineItem *) itemPtr; + char buffer[64 + TCL_INTEGER_SPACE]; + char *style; + + double width; + XColor *color; + Pixmap stipple; + Tk_PathState state = itemPtr->state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = linePtr->outline.width; + color = linePtr->outline.color; + stipple = linePtr->outline.stipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (linePtr->outline.activeWidth>width) { + width = linePtr->outline.activeWidth; + } + if (linePtr->outline.activeColor!=NULL) { + color = linePtr->outline.activeColor; + } + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.activeStipple; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (linePtr->outline.disabledWidth>0) { + width = linePtr->outline.disabledWidth; + } + if (linePtr->outline.disabledColor!=NULL) { + color = linePtr->outline.disabledColor; + } + if (linePtr->outline.disabledStipple!=None) { + stipple = linePtr->outline.disabledStipple; + } + } + + if (color == NULL || linePtr->numPoints<1 || linePtr->coordPtr==NULL) { + return TCL_OK; + } + + if (linePtr->numPoints==1) { + sprintf(buffer, "%.15g %.15g translate %.15g %.15g", + linePtr->coordPtr[0], Tk_PathCanvasPsY(canvas, linePtr->coordPtr[1]), + width/2.0, width/2.0); + Tcl_AppendResult(interp, "matrix currentmatrix\n",buffer, + " scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", NULL); + if (Tk_PathCanvasPsColor(interp, canvas, color) != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "clip ", NULL); + if (Tk_PathCanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "fill\n", NULL); + } + return TCL_OK; + } + /* + * Generate a path for the line's center-line (do this differently for + * straight lines and smoothed lines). + */ + + if ((!linePtr->smooth) || (linePtr->numPoints < 3)) { + Tk_PathCanvasPsPath(interp, canvas, linePtr->coordPtr, linePtr->numPoints); + } else { + if ((stipple == None) && linePtr->smooth->postscriptProc) { + linePtr->smooth->postscriptProc(interp, canvas, + linePtr->coordPtr, linePtr->numPoints, linePtr->splineSteps); + } 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 TkPathMakeBezierPostscript won't work + * for stippled curves. Instead, generate all of the intermediate + * points here and output them into the Postscript file with + * "lineto"s instead. + */ + + double staticPoints[2*MAX_STATIC_POINTS]; + double *pointPtr; + int numPoints; + + numPoints = linePtr->smooth->coordProc(canvas, NULL, + linePtr->numPoints, linePtr->splineSteps, NULL, NULL); + pointPtr = staticPoints; + if (numPoints > MAX_STATIC_POINTS) { + pointPtr = (double *) ckalloc((unsigned) + (numPoints * 2 * sizeof(double))); + } + numPoints = linePtr->smooth->coordProc(canvas, linePtr->coordPtr, + linePtr->numPoints, linePtr->splineSteps, NULL, pointPtr); + Tk_PathCanvasPsPath(interp, canvas, pointPtr, numPoints); + if (pointPtr != staticPoints) { + ckfree((char *) pointPtr); + } + } + } + + /* + * Set other line-drawing parameters and stroke out the line. + */ + + style = "0 setlinecap\n"; + if (linePtr->capStyle == CapRound) { + style = "1 setlinecap\n"; + } else if (linePtr->capStyle == CapProjecting) { + style = "2 setlinecap\n"; + } + Tcl_AppendResult(interp, style, NULL); + style = "0 setlinejoin\n"; + if (linePtr->joinStyle == JoinRound) { + style = "1 setlinejoin\n"; + } else if (linePtr->joinStyle == JoinBevel) { + style = "2 setlinejoin\n"; + } + Tcl_AppendResult(interp, style, NULL); + + if (Tk_PathCanvasPsOutline(canvas, itemPtr, &(linePtr->outline)) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Output polygons for the arrowheads, if there are any. + */ + + if (linePtr->firstArrowPtr != NULL) { + if (stipple != None) { + Tcl_AppendResult(interp, "grestore gsave\n", NULL); + } + if (ArrowheadPostscript(interp, canvas, linePtr, + linePtr->firstArrowPtr) != TCL_OK) { + return TCL_ERROR; + } + } + if (linePtr->lastArrowPtr != NULL) { + if (stipple != None) { + Tcl_AppendResult(interp, "grestore gsave\n", NULL); + } + if (ArrowheadPostscript(interp, canvas, linePtr, + linePtr->lastArrowPtr) != TCL_OK) { + return TCL_ERROR; + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ArrowheadPostscript -- + * + * This function is called to generate Postscript for an arrowhead for a + * line item. + * + * Results: + * The return value is a standard Tcl result. If an error occurs in + * generating Postscript then an error message is left in the interp's + * 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( + Tcl_Interp *interp, /* Leave Postscript or error message here. */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + LineItem *linePtr, /* Line item for which Postscript is being + * generated. */ + double *arrowPtr) /* Pointer to first of five points describing + * arrowhead polygon. */ +{ + Pixmap stipple; + Tk_PathState state = linePtr->header.state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + stipple = linePtr->outline.stipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == (Tk_PathItem *)linePtr) { + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.activeStipple; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (linePtr->outline.activeStipple!=None) { + stipple = linePtr->outline.disabledStipple; + } + } + + Tk_PathCanvasPsPath(interp, canvas, arrowPtr, PTS_IN_ARROW); + if (stipple != None) { + Tcl_AppendResult(interp, "clip ", NULL); + if (Tk_PathCanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "fill\n", NULL); + } + return TCL_OK; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/pd/tkpath/generic/tkpCanvPoly.c b/pd/tkpath/generic/tkpCanvPoly.c new file mode 100644 index 0000000000000000000000000000000000000000..1d88f3a85e1e16eb4ad61705b7713273291b5c8f --- /dev/null +++ b/pd/tkpath/generic/tkpCanvPoly.c @@ -0,0 +1,2002 @@ +/* + * tkpCanvPoly.c -- + * + * This file implements polygon items for canvas widgets. + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-2000 Ajuba Solutions. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvPoly.c,v 1.6 2010/03/10 22:47:37 petasis Exp $ + */ + +#include <stdio.h> +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" + +/* + * The structure below defines the record for each polygon item. + */ + +typedef struct PolygonItem { + Tk_PathItem header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + Tk_PathOutline outline; /* Outline structure */ + int numPoints; /* Number of points in polygon. Polygon is + * always closed. */ + int pointsAllocated; /* Number of points for which space is + * allocated at *coordPtr. */ + double *coordPtr; /* Pointer to malloc-ed array containing x- + * and y-coords of all points in polygon. + * X-coords are even-valued indices, y-coords + * are corresponding odd-valued indices. */ + int joinStyle; /* Join style for outline */ + Tk_TSOffset *tsoffsetPtr; + XColor *fillColor; /* Foreground color for polygon. */ + XColor *activeFillColor; /* Foreground color for polygon if state is + * active. */ + XColor *disabledFillColor; /* Foreground color for polygon if state is + * disabled. */ + Pixmap fillStipple; /* Stipple bitmap for filling polygon. */ + Pixmap activeFillStipple; /* Stipple bitmap for filling polygon if state + * is active. */ + Pixmap disabledFillStipple; /* Stipple bitmap for filling polygon if state + * is disabled. */ + GC fillGC; /* Graphics context for filling polygon. */ + Tk_PathSmoothMethod *smooth; /* Non-zero means draw shape smoothed (i.e. + * with Bezier splines). */ + int splineSteps; /* Number of steps in each spline segment. */ + int autoClosed; /* Zero means the given polygon was closed, + one means that we auto closed it. */ +} PolygonItem; + +/* + * Information used for parsing configuration specs. If you change any of the + * default strings, be sure to change the corresponding default values in + * CreateLine. + */ + +#define PATH_DEF_STATE "normal" + +/* These MUST be kept in sync with enums! X.h */ + +static char *stateStrings[] = { + "active", "disabled", "normal", "hidden", NULL +}; + +static char *joinStyleStrings[] = { + "miter", "round", "bevel", NULL +}; + +static Tk_ObjCustomOption dashCO = { + "dash", + Tk_DashOptionSetProc, + Tk_DashOptionGetProc, + Tk_DashOptionRestoreProc, + Tk_DashOptionFreeProc, + (ClientData) NULL +}; + +static Tk_ObjCustomOption offsetCO = { + "offset", + TkPathOffsetOptionSetProc, + TkPathOffsetOptionGetProc, + TkPathOffsetOptionRestoreProc, + TkPathOffsetOptionFreeProc, + (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) +}; + +static Tk_ObjCustomOption pixelCO = { + "pixel", + Tk_PathPixelOptionSetProc, + Tk_PathPixelOptionGetProc, + Tk_PathPixelOptionRestoreProc, + NULL, + (ClientData) NULL +}; + +static Tk_ObjCustomOption smoothCO = { + "smooth", + TkPathSmoothOptionSetProc, + TkPathSmoothOptionGetProc, + TkPathSmoothOptionRestoreProc, + NULL, + (ClientData) NULL +}; + +static Tk_ObjCustomOption tagsCO = { + "tags", + Tk_PathCanvasTagsOptionSetProc, + Tk_PathCanvasTagsOptionGetProc, + Tk_PathCanvasTagsOptionRestoreProc, + Tk_PathCanvasTagsOptionFreeProc, + (ClientData) NULL +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_CUSTOM, "-activedash", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, outline.activeDashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_COLOR, "-activefill", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, activeFillColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-activeoutline", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, outline.activeColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-activeoutlinestipple", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, outline.activeStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-activestipple", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, activeFillStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-activewidth", NULL, NULL, + "0.0", -1, Tk_Offset(PolygonItem, outline.activeWidth), + 0, &pixelCO, 0}, + {TK_OPTION_CUSTOM, "-dash", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, outline.dashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_PIXELS, "-dashoffset", NULL, NULL, + "0", -1, Tk_Offset(PolygonItem, outline.offset), + 0, 0, 0}, + {TK_OPTION_CUSTOM, "-disableddash", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, outline.disabledDashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_COLOR, "-disabledfill", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, disabledFillColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-disabledoutline", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, outline.disabledColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-disabledoutlinestipple", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, outline.disabledStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-disabledstipple", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, disabledFillStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-disabledwidth", NULL, NULL, + "0.0", -1, Tk_Offset(PolygonItem, outline.disabledWidth), + 0, &pixelCO, 0}, + {TK_OPTION_COLOR, "-fill", NULL, NULL, + "black", -1, Tk_Offset(PolygonItem, fillColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-joinstyle", NULL, NULL, + "round", -1, Tk_Offset(PolygonItem, joinStyle), + 0, (ClientData) joinStyleStrings, 0}, + {TK_OPTION_CUSTOM, "-offset", NULL, NULL, + "0,0", -1, Tk_Offset(PolygonItem, tsoffsetPtr), + 0, &offsetCO, 0}, + {TK_OPTION_COLOR, "-outline", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, outline.color), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-outlineoffset", NULL, NULL, + "0,0", -1, Tk_Offset(PolygonItem, outline.tsoffsetPtr), + 0, &offsetCO, 0}, + {TK_OPTION_BITMAP, "-outlinestipple", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, outline.stipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-smooth", NULL, NULL, + "0", -1, Tk_Offset(PolygonItem, smooth), + 0, &smoothCO, 0}, + {TK_OPTION_INT, "-splinesteps", NULL, NULL, + "12", -1, Tk_Offset(PolygonItem, splineSteps), 0, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", NULL, NULL, + PATH_DEF_STATE, -1, Tk_Offset(Tk_PathItem, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_BITMAP, "-stipple", NULL, NULL, + NULL, -1, Tk_Offset(PolygonItem, fillStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-tags", NULL, NULL, + NULL, -1, Tk_Offset(Tk_PathItem, pathTagsPtr), + TK_OPTION_NULL_OK, (ClientData) &tagsCO, 0}, + {TK_OPTION_CUSTOM, "-width", NULL, NULL, + "1.0", -1, Tk_Offset(PolygonItem, outline.width), 0, &pixelCO, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * Prototypes for functions defined in this file: + */ + +static void ComputePolygonBbox(Tk_PathCanvas canvas, + PolygonItem *polyPtr); +static int ConfigurePolygon(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int CreatePolygon(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeletePolygon(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayPolygon(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable dst, + int x, int y, int width, int height); +static int GetPolygonIndex(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + Tcl_Obj *obj, int *indexPtr); +static int PolygonCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void PolygonDeleteCoords(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int first, int last); +static void PolygonInsert(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int beforeThis, Tcl_Obj *obj); +static int PolygonToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double PolygonToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *pointPtr); +static int PolygonToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void ScalePolygon(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslatePolygon(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); + +/* + * The structures below defines the polygon item type by means of functions + * that can be invoked by generic item code. + */ + +Tk_PathItemType tkPolygonType = { + "polygon", /* name */ + sizeof(PolygonItem), /* itemSize */ + CreatePolygon, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigurePolygon, /* configureProc */ + PolygonCoords, /* coordProc */ + DeletePolygon, /* deleteProc */ + DisplayPolygon, /* displayProc */ + 0, /* flags */ + NULL, /* bboxProc */ + PolygonToPoint, /* pointProc */ + PolygonToArea, /* areaProc */ + PolygonToPostscript, /* postscriptProc */ + ScalePolygon, /* scaleProc */ + TranslatePolygon, /* translateProc */ + (Tk_PathItemIndexProc *) GetPolygonIndex,/* indexProc */ + NULL, /* icursorProc */ + NULL, /* selectionProc */ + (Tk_PathItemInsertProc *) PolygonInsert,/* insertProc */ + PolygonDeleteCoords, /* dTextProc */ + NULL, /* nextPtr */ +}; + +/* + * 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 + +/* + *-------------------------------------------------------------- + * + * CreatePolygon -- + * + * This function is invoked to create a new polygon 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 the interp's result; in this + * case itemPtr is left uninitialized, so it can be safely freed by the + * caller. + * + * Side effects: + * A new polygon item is created. + * + *-------------------------------------------------------------- + */ + +static int +CreatePolygon( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas to hold new item. */ + Tk_PathItem *itemPtr, /* Record to hold new item; header has been + * initialized by caller. */ + int objc, /* Number of arguments in objv. */ + Tcl_Obj *CONST objv[]) /* Arguments describing polygon. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed in order to clean up after + * errors during the the remainder of this function. + */ + + Tk_PathCreateOutline(&polyPtr->outline); + polyPtr->numPoints = 0; + polyPtr->pointsAllocated = 0; + polyPtr->coordPtr = NULL; + polyPtr->joinStyle = JoinRound; + polyPtr->tsoffsetPtr = NULL; + polyPtr->fillColor = NULL; + polyPtr->activeFillColor = NULL; + polyPtr->disabledFillColor = NULL; + polyPtr->fillStipple = None; + polyPtr->activeFillStipple = None; + polyPtr->disabledFillStipple = None; + polyPtr->fillGC = None; + polyPtr->smooth = NULL; + polyPtr->splineSteps = 12; + polyPtr->autoClosed = 0; + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) polyPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + /* + * 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 = 0; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + if (i && PolygonCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { + goto error; + } + + if (ConfigurePolygon(interp, canvas, itemPtr, objc-i, objv+i, 0) + == TCL_OK) { + return TCL_OK; + } + + error: + DeletePolygon(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * PolygonCoords -- + * + * This function is invoked to process the "coords" widget command on + * polygons. See the user documentation for details on what it does. + * + * Results: + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. + * + * Side effects: + * The coordinates for the given item may be changed. + * + *-------------------------------------------------------------- + */ + +static int +PolygonCoords( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item whose coordinates are to be read or + * modified. */ + int objc, /* Number of coordinates supplied in objv. */ + Tcl_Obj *CONST objv[]) /* Array of coordinates: x1, y1, x2, y2, ... */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + int i, numPoints; + + if (objc == 0) { + /* + * Print the coords used to create the polygon. If we auto closed the + * polygon then we don't report the last point. + */ + + Tcl_Obj *subobj, *obj = Tcl_NewObj(); + + for (i = 0; i < 2*(polyPtr->numPoints - polyPtr->autoClosed); i++) { + subobj = Tcl_NewDoubleObj(polyPtr->coordPtr[i]); + Tcl_ListObjAppendElement(interp, obj, subobj); + } + Tcl_SetObjResult(interp, obj); + return TCL_OK; + } + if (objc == 1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } + } + if (objc & 1) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected an even number, got %d", + objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } else { + numPoints = objc/2; + if (polyPtr->pointsAllocated <= numPoints) { + if (polyPtr->coordPtr != NULL) { + ckfree((char *) polyPtr->coordPtr); + } + + /* + * One extra point gets allocated here, because we always add + * another point to close the polygon. + */ + + polyPtr->coordPtr = (double *) ckalloc((unsigned) + (sizeof(double) * (objc+2))); + polyPtr->pointsAllocated = numPoints+1; + } + for (i = objc-1; i >= 0; i--) { + if (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[i], + &polyPtr->coordPtr[i]) != TCL_OK) { + return TCL_ERROR; + } + } + polyPtr->numPoints = numPoints; + polyPtr->autoClosed = 0; + + /* + * Close the polygon if it isn't already closed. + */ + + if (objc>2 && ((polyPtr->coordPtr[objc-2] != polyPtr->coordPtr[0]) + || (polyPtr->coordPtr[objc-1] != polyPtr->coordPtr[1]))) { + polyPtr->autoClosed = 1; + polyPtr->numPoints++; + polyPtr->coordPtr[objc] = polyPtr->coordPtr[0]; + polyPtr->coordPtr[objc+1] = polyPtr->coordPtr[1]; + } + ComputePolygonBbox(canvas, polyPtr); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ConfigurePolygon -- + * + * This function is invoked to configure various aspects of a polygon + * item such as its background color. + * + * Results: + * A standard Tcl result code. If an error occurs, then an error message + * is left in the interp's result. + * + * Side effects: + * Configuration information, such as colors and stipple patterns, may be + * set for itemPtr. + * + *-------------------------------------------------------------- + */ + +static int +ConfigurePolygon( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Polygon item to reconfigure. */ + int objc, /* Number of elements in objv. */ + Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ + int flags) /* Flags to pass to Tk_ConfigureWidget. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + XGCValues gcValues; + GC newGC; + unsigned long mask; + Tk_Window tkwin; + XColor *color; + Pixmap stipple; + Tk_PathState state; + + tkwin = Tk_PathCanvasTkwin(canvas); + if (TCL_OK != Tk_SetOptions(interp, (char *) polyPtr, optionTable, + objc, objv, tkwin, NULL, NULL)) { + return TCL_ERROR; + } + + /* + * A few of the options require additional processing, such as graphics + * contexts. + */ + + state = itemPtr->state; + + if (polyPtr->outline.activeWidth > polyPtr->outline.width || + (polyPtr->outline.activeDashPtr != NULL && + polyPtr->outline.activeDashPtr->number != 0) || + polyPtr->outline.activeColor != NULL || + polyPtr->outline.activeStipple != None || + polyPtr->activeFillColor != NULL || + polyPtr->activeFillStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state==TK_PATHSTATE_HIDDEN) { + ComputePolygonBbox(canvas, polyPtr); + return TCL_OK; + } + + mask = Tk_PathConfigOutlineGC(&gcValues, canvas, itemPtr, &(polyPtr->outline)); + if (mask) { + gcValues.cap_style = CapRound; + gcValues.join_style = polyPtr->joinStyle; + mask |= GCCapStyle|GCJoinStyle; + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = None; + } + if (polyPtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), polyPtr->outline.gc); + } + polyPtr->outline.gc = newGC; + + color = polyPtr->fillColor; + stipple = polyPtr->fillStipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->activeFillColor!=NULL) { + color = polyPtr->activeFillColor; + } + if (polyPtr->activeFillStipple!=None) { + stipple = polyPtr->activeFillStipple; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (polyPtr->disabledFillColor!=NULL) { + color = polyPtr->disabledFillColor; + } + if (polyPtr->disabledFillStipple!=None) { + stipple = polyPtr->disabledFillStipple; + } + } + + if (color == NULL) { + newGC = None; + } else { + gcValues.foreground = color->pixel; + mask = GCForeground; + if (stipple != None) { + gcValues.stipple = stipple; + gcValues.fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } +#ifdef MAC_OSX_TK + /* + * Mac OS X CG drawing needs access to the outline linewidth + * even for fills (as linewidth controls antialiasing). + */ + gcValues.line_width = polyPtr->outline.gc != None ? + polyPtr->outline.gc->line_width : 0; + mask |= GCLineWidth; +#endif + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } + if (polyPtr->fillGC != None) { + Tk_FreeGC(Tk_Display(tkwin), polyPtr->fillGC); + } + polyPtr->fillGC = newGC; + + /* + * Keep spline parameters within reasonable limits. + */ + + if (polyPtr->splineSteps < 1) { + polyPtr->splineSteps = 1; + } else if (polyPtr->splineSteps > 100) { + polyPtr->splineSteps = 100; + } + + ComputePolygonBbox(canvas, polyPtr); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * DeletePolygon -- + * + * This function is called to clean up the data structure associated with + * a polygon item. + * + * Results: + * None. + * + * Side effects: + * Resources associated with itemPtr are released. + * + *-------------------------------------------------------------- + */ + +static void +DeletePolygon( + Tk_PathCanvas canvas, /* Info about overall canvas widget. */ + Tk_PathItem *itemPtr, /* Item that is being deleted. */ + Display *display) /* Display containing window for canvas. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + + Tk_PathDeleteOutline(display,&(polyPtr->outline)); + if (polyPtr->coordPtr != NULL) { + ckfree((char *) polyPtr->coordPtr); + polyPtr->coordPtr = NULL; + } + if (polyPtr->fillGC != None) { + Tk_FreeGC(display, polyPtr->fillGC); + polyPtr->fillGC = None; + } + Tk_FreeConfigOptions((char *) itemPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +/* + *-------------------------------------------------------------- + * + * ComputePolygonBbox -- + * + * This function is invoked to compute the bounding box of all the pixels + * that may be drawn as part of a polygon. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header for itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +ComputePolygonBbox( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + PolygonItem *polyPtr) /* Item whose bbox is to be recomputed. */ +{ + double *coordPtr; + int i; + double width; + Tk_PathState state = polyPtr->header.state; + Tk_TSOffset *tsoffset; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + width = polyPtr->outline.width; + if (polyPtr->coordPtr == NULL || (polyPtr->numPoints < 1) || (state==TK_PATHSTATE_HIDDEN)) { + polyPtr->header.x1 = polyPtr->header.x2 = + polyPtr->header.y1 = polyPtr->header.y2 = -1; + return; + } + if (((TkPathCanvas *)canvas)->currentItemPtr == (Tk_PathItem *)polyPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } + + coordPtr = polyPtr->coordPtr; + polyPtr->header.x1 = polyPtr->header.x2 = (int) *coordPtr; + polyPtr->header.y1 = polyPtr->header.y2 = (int) coordPtr[1]; + + /* + * Compute the bounding box of all the points in the polygon, then expand + * in all directions by the outline'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 = polyPtr->coordPtr+2; i < polyPtr->numPoints-1; + i++, coordPtr += 2) { + TkPathIncludePoint((Tk_PathItem *) polyPtr, coordPtr); + } + + tsoffset = polyPtr->tsoffsetPtr; + if (tsoffset != NULL) { + if (tsoffset->flags & TK_OFFSET_INDEX) { + int index = tsoffset->flags & ~TK_OFFSET_INDEX; + if (tsoffset->flags == INT_MAX) { + index = (polyPtr->numPoints - polyPtr->autoClosed) * 2; + if (index < 0) { + index = 0; + } + } + index %= (polyPtr->numPoints - polyPtr->autoClosed) * 2; + if (index < 0) { + index += (polyPtr->numPoints - polyPtr->autoClosed) * 2; + } + tsoffset->xoffset = (int) (polyPtr->coordPtr[index] + 0.5); + tsoffset->yoffset = (int) (polyPtr->coordPtr[index+1] + 0.5); + } else { + if (tsoffset->flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = polyPtr->header.x1; + } else if (tsoffset->flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (polyPtr->header.x1 + polyPtr->header.x2)/2; + } else if (tsoffset->flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = polyPtr->header.x2; + } + if (tsoffset->flags & TK_OFFSET_TOP) { + tsoffset->yoffset = polyPtr->header.y1; + } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (polyPtr->header.y1 + polyPtr->header.y2)/2; + } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = polyPtr->header.y2; + } + } + } + + if (polyPtr->outline.gc != None) { + tsoffset = polyPtr->outline.tsoffsetPtr; + if (tsoffset != NULL) { + if (tsoffset->flags & TK_OFFSET_INDEX) { + int index = tsoffset->flags & ~TK_OFFSET_INDEX; + + if (tsoffset->flags == INT_MAX) { + index = (polyPtr->numPoints - 1) * 2; + } + index %= (polyPtr->numPoints - 1) * 2; + if (index < 0) { + index += (polyPtr->numPoints - 1) * 2; + } + tsoffset->xoffset = (int) (polyPtr->coordPtr[index] + 0.5); + tsoffset->yoffset = (int) (polyPtr->coordPtr[index+1] + 0.5); + } else { + if (tsoffset->flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = polyPtr->header.x1; + } else if (tsoffset->flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (polyPtr->header.x1 + polyPtr->header.x2)/2; + } else if (tsoffset->flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = polyPtr->header.x2; + } + if (tsoffset->flags & TK_OFFSET_TOP) { + tsoffset->yoffset = polyPtr->header.y1; + } else if (tsoffset->flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (polyPtr->header.y1 + polyPtr->header.y2)/2; + } else if (tsoffset->flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = polyPtr->header.y2; + } + } + } + + i = (int) ((width+1.5)/2.0); + polyPtr->header.x1 -= i; + polyPtr->header.x2 += i; + polyPtr->header.y1 -= i; + polyPtr->header.y2 += i; + + /* + * For mitered lines, 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 (polyPtr->joinStyle == JoinMiter) { + double miter[4]; + int j; + + coordPtr = polyPtr->coordPtr; + if (polyPtr->numPoints>3) { + if (TkGetMiterPoints(coordPtr+2*(polyPtr->numPoints-2), + coordPtr, coordPtr+2, width, + miter, miter+2)) { + for (j = 0; j < 4; j += 2) { + TkPathIncludePoint((Tk_PathItem *) polyPtr, miter+j); + } + } + } + for (i = polyPtr->numPoints ; i >= 3; i--, coordPtr += 2) { + + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + width, miter, miter+2)) { + for (j = 0; j < 4; j += 2) { + TkPathIncludePoint((Tk_PathItem *) polyPtr, miter+j); + } + } + } + } + } + + /* + * Add one more pixel of fudge factor just to be safe (e.g. X may round + * differently than we do). + */ + + polyPtr->header.x1 -= 1; + polyPtr->header.x2 += 1; + polyPtr->header.y1 -= 1; + polyPtr->header.y2 += 1; +} + +/* + *-------------------------------------------------------------- + * + * TkPathFillPolygon -- + * + * This function is invoked to convert a polygon to screen coordinates + * and display it using a particular GC. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation information in + * canvas. + * + *-------------------------------------------------------------- + */ + +void +TkPathFillPolygon( + Tk_PathCanvas canvas, /* Canvas whose coordinate system is to be + * used for drawing. */ + double *coordPtr, /* Array of coordinates for polygon: x1, y1, + * x2, y2, .... */ + int numPoints, /* Twice this many coordinates are present at + * *coordPtr. */ + Display *display, /* Display on which to draw polygon. */ + Drawable drawable, /* Pixmap or window in which to draw + * polygon. */ + GC gc, /* Graphics context for drawing. */ + GC outlineGC) /* If not None, use this to draw an outline + * around the polygon after filling it. */ +{ + XPoint staticPoints[MAX_STATIC_POINTS]; + XPoint *pointPtr; + XPoint *pPtr; + int i; + + /* + * Build up an array of points in screen coordinates. Use a static array + * unless the polygon has an enormous number of points; in this case, + * dynamically allocate an array. + */ + + if (numPoints <= MAX_STATIC_POINTS) { + pointPtr = staticPoints; + } else { + pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint))); + } + + for (i=0, pPtr=pointPtr ; i<numPoints; i+=1, coordPtr+=2, pPtr++) { + Tk_PathCanvasDrawableCoords(canvas, coordPtr[0], coordPtr[1], &pPtr->x, + &pPtr->y); + } + + /* + * Display polygon, then free up polygon storage if it was dynamically + * allocated. + */ + + if (gc != None && numPoints>3) { + XFillPolygon(display, drawable, gc, pointPtr, numPoints, Complex, + CoordModeOrigin); + } + if (outlineGC != None) { + XDrawLines(display, drawable, outlineGC, pointPtr, + numPoints, CoordModeOrigin); + } + if (pointPtr != staticPoints) { + ckfree((char *) pointPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * DisplayPolygon -- + * + * This function is invoked to draw a polygon item in a given drawable. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation information in + * canvas. + * + *-------------------------------------------------------------- + */ + +static void +DisplayPolygon( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + Tk_PathItem *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, int y, int width, int height) + /* Describes region of canvas that must be + * redisplayed (not used). */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + Tk_PathState state = itemPtr->state; + Pixmap stipple = polyPtr->fillStipple; + double linewidth = polyPtr->outline.width; + + if (((polyPtr->fillGC == None) && (polyPtr->outline.gc == None)) || + (polyPtr->numPoints < 1) || + (polyPtr->numPoints < 3 && polyPtr->outline.gc == None)) { + return; + } + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>linewidth) { + linewidth = polyPtr->outline.activeWidth; + } + if (polyPtr->activeFillStipple != None) { + stipple = polyPtr->activeFillStipple; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + linewidth = polyPtr->outline.disabledWidth; + } + if (polyPtr->disabledFillStipple != None) { + stipple = polyPtr->disabledFillStipple; + } + } + + /* + * 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 ((stipple != None) && (polyPtr->fillGC != None)) { + int w = 0; + int h = 0; + Tk_TSOffset tsoffset, *tsoffsetPtr; + + tsoffset.flags = 0; + tsoffset.xoffset = 0; + tsoffset.yoffset = 0; + tsoffsetPtr = polyPtr->tsoffsetPtr; + if (tsoffsetPtr != NULL) { + int flags = tsoffsetPtr->flags; + + if (!(flags & TK_OFFSET_INDEX) && (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) { + Tk_SizeOfBitmap(display, stipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset = *tsoffsetPtr; + } + tsoffset.xoffset -= w; + tsoffset.yoffset -= h; + Tk_PathCanvasSetOffset(canvas, polyPtr->fillGC, &tsoffset); + } + Tk_PathChangeOutlineGC(canvas, itemPtr, &(polyPtr->outline)); + + if(polyPtr->numPoints < 3) { + short x,y; + int intLineWidth = (int) (linewidth + 0.5); + + if (intLineWidth < 1) { + intLineWidth = 1; + } + Tk_PathCanvasDrawableCoords(canvas, polyPtr->coordPtr[0], + polyPtr->coordPtr[1], &x,&y); + XFillArc(display, drawable, polyPtr->outline.gc, + x - intLineWidth/2, y - intLineWidth/2, + (unsigned int)intLineWidth+1, (unsigned int)intLineWidth+1, + 0, 64*360); + } else if (!polyPtr->smooth || polyPtr->numPoints < 4) { + TkPathFillPolygon(canvas, polyPtr->coordPtr, polyPtr->numPoints, + display, drawable, polyPtr->fillGC, polyPtr->outline.gc); + } else { + int numPoints; + XPoint staticPoints[MAX_STATIC_POINTS]; + XPoint *pointPtr; + + /* + * This is a smoothed polygon. Display using a set of generated spline + * points rather than the original points. + */ + + numPoints = polyPtr->smooth->coordProc(canvas, NULL, + polyPtr->numPoints, polyPtr->splineSteps, NULL, NULL); + if (numPoints <= MAX_STATIC_POINTS) { + pointPtr = staticPoints; + } else { + pointPtr = (XPoint *) ckalloc((unsigned) + (numPoints * sizeof(XPoint))); + } + numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, + polyPtr->numPoints, polyPtr->splineSteps, pointPtr, NULL); + if (polyPtr->fillGC != None) { + XFillPolygon(display, drawable, polyPtr->fillGC, pointPtr, + numPoints, Complex, CoordModeOrigin); + } + if (polyPtr->outline.gc != None) { + XDrawLines(display, drawable, polyPtr->outline.gc, pointPtr, + numPoints, CoordModeOrigin); + } + if (pointPtr != staticPoints) { + ckfree((char *) pointPtr); + } + } + Tk_PathResetOutlineGC(canvas, itemPtr, &(polyPtr->outline)); + if ((stipple != None) && (polyPtr->fillGC != None)) { + XSetTSOrigin(display, polyPtr->fillGC, 0, 0); + } +} + +/* + *-------------------------------------------------------------- + * + * PolygonInsert -- + * + * Insert coords into a polugon item at a given index. + * + * Results: + * None. + * + * Side effects: + * The coords in the given item is modified. + * + *-------------------------------------------------------------- + */ + +static void +PolygonInsert( + Tk_PathCanvas canvas, /* Canvas containing text item. */ + Tk_PathItem *itemPtr, /* Line item to be modified. */ + int beforeThis, /* Index before which new coordinates are to + * be inserted. */ + Tcl_Obj *obj) /* New coordinates to be inserted. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + int length, objc, i; + Tcl_Obj **objv; + double *newCoordPtr; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + if (!obj || (Tcl_ListObjGetElements(NULL, obj, &objc, &objv) != TCL_OK) + || !objc || objc&1) { + return; + } + length = 2*(polyPtr->numPoints - polyPtr->autoClosed); + while (beforeThis>length) { + beforeThis -= length; + } + while (beforeThis<0) { + beforeThis += length; + } + newCoordPtr = (double *) + ckalloc(sizeof(double) * (unsigned)(length + 2 + objc)); + for (i=0; i<beforeThis; i++) { + newCoordPtr[i] = polyPtr->coordPtr[i]; + } + for (i=0; i<objc; i++) { + if (Tcl_GetDoubleFromObj(NULL, objv[i], + &newCoordPtr[i+beforeThis]) != TCL_OK){ + ckfree((char *) newCoordPtr); + return; + } + } + + for (i=beforeThis; i<length; i++) { + newCoordPtr[i+objc] = polyPtr->coordPtr[i]; + } + if (polyPtr->coordPtr) { + ckfree((char *) polyPtr->coordPtr); + } + length += objc; + polyPtr->coordPtr = newCoordPtr; + polyPtr->numPoints = (length/2) + polyPtr->autoClosed; + + /* + * Close the polygon if it isn't already closed, or remove autoclosing if + * the user's coordinates are now closed. + */ + + if (polyPtr->autoClosed) { + if ((newCoordPtr[length-2] == newCoordPtr[0]) + && (newCoordPtr[length-1] == newCoordPtr[1])) { + polyPtr->autoClosed = 0; + polyPtr->numPoints--; + } + } else { + if ((newCoordPtr[length-2] != newCoordPtr[0]) + || (newCoordPtr[length-1] != newCoordPtr[1])) { + polyPtr->autoClosed = 1; + polyPtr->numPoints++; + } + } + + newCoordPtr[length] = newCoordPtr[0]; + newCoordPtr[length+1] = newCoordPtr[1]; + if (((length-objc)>3) && (state != TK_PATHSTATE_HIDDEN)) { + /* + * This is some optimizing code that will result that only the part of + * the polygon that changed (and the objects that are overlapping with + * that part) need to be redrawn. A special flag is set that instructs + * the general canvas code not to redraw the whole object. If this + * flag is not set, the canvas will do the redrawing, otherwise I have + * to do it here. + */ + + double width; + int j; + itemPtr->redraw_flags |= TK_ITEM_DONT_REDRAW; + + /* + * The header elements that normally are used for the bounding box, + * are now used to calculate the bounding box for only the part that + * has to be redrawn. That doesn't matter, because afterwards the + * bounding box has to be re-calculated anyway. + */ + + itemPtr->x1 = itemPtr->x2 = (int) polyPtr->coordPtr[beforeThis]; + itemPtr->y1 = itemPtr->y2 = (int) polyPtr->coordPtr[beforeThis+1]; + beforeThis-=2; objc+=4; + if (polyPtr->smooth) { + beforeThis-=2; + objc+=4; + } + + /* + * Be careful; beforeThis could now be negative + */ + + for (i=beforeThis; i<beforeThis+objc; i+=2) { + j = i; + if (j<0) { + j += length; + } else if (j>=length) { + j -= length; + } + TkPathIncludePoint(itemPtr, polyPtr->coordPtr+j); + } + width = polyPtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth > width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (polyPtr->outline.disabledWidth > 0.0) { + width = polyPtr->outline.disabledWidth; + } + } + itemPtr->x1 -= (int) width; itemPtr->y1 -= (int) width; + itemPtr->x2 += (int) width; itemPtr->y2 += (int) width; + Tk_PathCanvasEventuallyRedraw(canvas, + itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2); + } + + ComputePolygonBbox(canvas, polyPtr); +} + +/* + *-------------------------------------------------------------- + * + * PolygonDeleteCoords -- + * + * Delete one or more coordinates from a polygon item. + * + * Results: + * None. + * + * Side effects: + * Characters between "first" and "last", inclusive, get deleted from + * itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +PolygonDeleteCoords( + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Item in which to delete characters. */ + int first, /* Index of first character to delete. */ + int last) /* Index of last character to delete. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + int count, i; + int length = 2*(polyPtr->numPoints - polyPtr->autoClosed); + + while (first>=length) { + first -= length; + } + while (first<0) { + first += length; + } + while (last>=length) { + last -= length; + } + while (last<0) { + last += length; + } + + first &= -2; + last &= -2; + + count = last + 2 - first; + if (count<=0) { + count += length; + } + + if (count >= length) { + polyPtr->numPoints = 0; + if (polyPtr->coordPtr != NULL) { + ckfree((char *) polyPtr->coordPtr); + } + ComputePolygonBbox(canvas, polyPtr); + return; + } + + if (last>=first) { + for(i=last+2; i<length; i++) { + polyPtr->coordPtr[i-count] = polyPtr->coordPtr[i]; + } + } else { + for(i=last; i<=first; i++) { + polyPtr->coordPtr[i-last] = polyPtr->coordPtr[i]; + } + } + polyPtr->coordPtr[length-count] = polyPtr->coordPtr[0]; + polyPtr->coordPtr[length-count+1] = polyPtr->coordPtr[1]; + polyPtr->numPoints -= count/2; + ComputePolygonBbox(canvas, polyPtr); +} + +/* + *-------------------------------------------------------------- + * + * PolygonToPoint -- + * + * Computes the distance from a given point to a given polygon, 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 polygon. If the point isn't + * inside the polygon then the return value is the distance from the + * point to the polygon. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static double +PolygonToPoint( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + double *pointPtr) /* Pointer to x and y coordinates. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + double *coordPtr, *polyPoints; + double staticSpace[2*MAX_STATIC_POINTS]; + double poly[10]; + double radius; + 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. */ + double width; + Tk_PathState state = itemPtr->state; + + bestDist = 1.0e36; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + width = polyPtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } + radius = width/2.0; + + /* + * Handle smoothed polygons by generating an expanded set of points + * against which to do the check. + */ + + if ((polyPtr->smooth) && (polyPtr->numPoints>2)) { + numPoints = polyPtr->smooth->coordProc(canvas, NULL, + polyPtr->numPoints, polyPtr->splineSteps, NULL, + NULL); + if (numPoints <= MAX_STATIC_POINTS) { + polyPoints = staticSpace; + } else { + polyPoints = (double *) ckalloc((unsigned) + (2*numPoints*sizeof(double))); + } + numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, + polyPtr->numPoints, polyPtr->splineSteps, NULL, + polyPoints); + } else { + numPoints = polyPtr->numPoints; + polyPoints = polyPtr->coordPtr; + } + + bestDist = TkPolygonToPoint(polyPoints, numPoints, pointPtr); + if (bestDist<=0.0) { + goto donepoint; + } + if ((polyPtr->outline.gc != None) && (polyPtr->joinStyle == JoinRound)) { + dist = bestDist - radius; + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else { + bestDist = dist; + } + } + + if ((polyPtr->outline.gc == None) || (width <= 1)) { + goto donepoint; + } + + /* + * The overall idea is to iterate through all of the edges of the line, + * 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 = polyPoints; count >= 2; + count--, coordPtr += 2) { + /* + * If rounding is done around the first point then compute the + * distance between the point and the point. + */ + + if (polyPtr->joinStyle == JoinRound) { + dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1]) + - radius; + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } 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) width, + 0, poly, poly+2); + } else if ((polyPtr->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) width, 0, + poly, poly+2); + + /* + * If this line 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 ((polyPtr->joinStyle == JoinBevel) || changedMiterToBevel) { + poly[8] = poly[0]; + poly[9] = poly[1]; + dist = TkPolygonToPoint(poly, 5, pointPtr); + if (dist <= 0.0) { + bestDist = 0.0; + goto donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } + changedMiterToBevel = 0; + } + } + if (count == 2) { + TkGetButtPoints(coordPtr, coordPtr+2, (double) width, + 0, poly+4, poly+6); + } else if (polyPtr->joinStyle == JoinMiter) { + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + (double) width, poly+4, poly+6) == 0) { + changedMiterToBevel = 1; + TkGetButtPoints(coordPtr, coordPtr+2, (double) width, 0, + poly+4, poly+6); + } + } else { + TkGetButtPoints(coordPtr, coordPtr+2, (double) 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 donepoint; + } else if (dist < bestDist) { + bestDist = dist; + } + } + + donepoint: + if ((polyPoints != staticSpace) && polyPoints != polyPtr->coordPtr) { + ckfree((char *) polyPoints); + } + return bestDist; +} + +/* + *-------------------------------------------------------------- + * + * PolygonToArea -- + * + * This function 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 given by + * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given + * area. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +PolygonToArea( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against polygon. */ + double *rectPtr) /* Pointer to array of four coordinates + * (x1,y1,x2,y2) describing rectangular + * area. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + double *coordPtr; + double staticSpace[2*MAX_STATIC_POINTS]; + double *polyPoints, 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. */ + double width; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = polyPtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + } + + radius = width/2.0; + inside = -1; + + if ((state==TK_PATHSTATE_HIDDEN) || polyPtr->numPoints<2) { + return -1; + } else if (polyPtr->numPoints <3) { + double oval[4]; + + oval[0] = polyPtr->coordPtr[0]-radius; + oval[1] = polyPtr->coordPtr[1]-radius; + oval[2] = polyPtr->coordPtr[0]+radius; + oval[3] = polyPtr->coordPtr[1]+radius; + return TkOvalToArea(oval, rectPtr); + } + + /* + * Handle smoothed polygons by generating an expanded set of points + * against which to do the check. + */ + + if (polyPtr->smooth) { + numPoints = polyPtr->smooth->coordProc(canvas, NULL, + polyPtr->numPoints, polyPtr->splineSteps, NULL, NULL); + if (numPoints <= MAX_STATIC_POINTS) { + polyPoints = staticSpace; + } else { + polyPoints = (double *) + ckalloc((unsigned) (2*numPoints*sizeof(double))); + } + numPoints = polyPtr->smooth->coordProc(canvas, polyPtr->coordPtr, + polyPtr->numPoints, polyPtr->splineSteps, NULL, polyPoints); + } else { + numPoints = polyPtr->numPoints; + polyPoints = polyPtr->coordPtr; + } + + /* + * Simple test to see if we are in the polygon. Polygons are different + * from othe canvas items in that they register points being inside even + * if it isn't filled. + */ + + inside = TkPolygonToArea(polyPoints, numPoints, rectPtr); + if (inside==0) { + goto donearea; + } + + if (polyPtr->outline.gc == None) { + goto donearea; + } + + /* + * Iterate through all of the edges of the line, 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, coordPtr = polyPoints; 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 (polyPtr->joinStyle == JoinRound) { + 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 donearea; + } + } + + /* + * 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, width, 0, poly, poly+2); + } else if ((polyPtr->joinStyle == JoinMiter) && !changedMiterToBevel) { + poly[0] = poly[6]; + poly[1] = poly[7]; + poly[2] = poly[4]; + poly[3] = poly[5]; + } else { + TkGetButtPoints(coordPtr+2, coordPtr, 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 ((polyPtr->joinStyle == JoinBevel) || changedMiterToBevel) { + poly[8] = poly[0]; + poly[9] = poly[1]; + if (TkPolygonToArea(poly, 5, rectPtr) != inside) { + inside = 0; + goto donearea; + } + changedMiterToBevel = 0; + } + } + if (count == 2) { + TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, poly+6); + } else if (polyPtr->joinStyle == JoinMiter) { + if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4, + width, poly+4, poly+6) == 0) { + changedMiterToBevel = 1; + TkGetButtPoints(coordPtr, coordPtr+2, width,0, poly+4, poly+6); + } + } else { + TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, poly+6); + } + poly[8] = poly[0]; + poly[9] = poly[1]; + if (TkPolygonToArea(poly, 5, rectPtr) != inside) { + inside = 0; + goto donearea; + } + } + + donearea: + if ((polyPoints != staticSpace) && (polyPoints != polyPtr->coordPtr)) { + ckfree((char *) polyPoints); + } + return inside; +} + +/* + *-------------------------------------------------------------- + * + * ScalePolygon -- + * + * This function is invoked to rescale a polygon item. + * + * Results: + * None. + * + * Side effects: + * The polygon 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 +ScalePolygon( + Tk_PathCanvas canvas, /* Canvas containing polygon. */ + Tk_PathItem *itemPtr, /* Polygon to be scaled. */ + double originX, double originY, + /* Origin about which to scale rect. */ + double scaleX, /* Amount to scale in X direction. */ + double scaleY) /* Amount to scale in Y direction. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + double *coordPtr; + int i; + + for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints; + i++, coordPtr += 2) { + *coordPtr = originX + scaleX*(*coordPtr - originX); + coordPtr[1] = originY + scaleY*(coordPtr[1] - originY); + } + ComputePolygonBbox(canvas, polyPtr); +} + +/* + *-------------------------------------------------------------- + * + * GetPolygonIndex -- + * + * Parse an index into a polygon item and return either its value or an + * error. + * + * Results: + * A standard Tcl result. If all went well, then *indexPtr is filled in + * with the index (into itemPtr) corresponding to string. Otherwise an + * error message is left in interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetPolygonIndex( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item for which the index is being + * specified. */ + Tcl_Obj *obj, /* Specification of a particular coord in + * itemPtr's line. */ + int *indexPtr) /* Where to store converted index. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + int length; + char *string = Tcl_GetStringFromObj(obj, &length); + + if (string[0] == 'e') { + if (strncmp(string, "end", (unsigned)length) == 0) { + *indexPtr = 2*(polyPtr->numPoints - polyPtr->autoClosed); + } else { + /* + * Some of the paths here leave messages in interp->result, so we + * have to clear it out before storing our own message. + */ + + badIndex: + Tcl_SetResult(interp, NULL, TCL_STATIC); + Tcl_AppendResult(interp, "bad index \"", string, "\"", NULL); + return TCL_ERROR; + } + } else if (string[0] == '@') { + int i; + double x ,y, bestDist, dist, *coordPtr; + char *end, *p; + + p = string+1; + x = strtod(p, &end); + if ((end == p) || (*end != ',')) { + goto badIndex; + } + p = end+1; + y = strtod(p, &end); + if ((end == p) || (*end != 0)) { + goto badIndex; + } + bestDist = 1.0e36; + coordPtr = polyPtr->coordPtr; + *indexPtr = 0; + for(i=0; i<(polyPtr->numPoints-1); i++) { + dist = hypot(coordPtr[0] - x, coordPtr[1] - y); + if (dist<bestDist) { + bestDist = dist; + *indexPtr = 2*i; + } + coordPtr += 2; + } + } else { + int count = 2*(polyPtr->numPoints - polyPtr->autoClosed); + + if (Tcl_GetIntFromObj(interp, obj, indexPtr) != TCL_OK) { + goto badIndex; + } + *indexPtr &= -2; /* if odd, make it even */ + if (count) { + if (*indexPtr > 0) { + *indexPtr = ((*indexPtr - 2) % count) + 2; + } else { + *indexPtr = -((-(*indexPtr)) % count); + } + } else { + *indexPtr = 0; + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TranslatePolygon -- + * + * This function is called to move a polygon by a given amount. + * + * Results: + * None. + * + * Side effects: + * The position of the polygon is offset by (xDelta, yDelta), and the + * bounding box is updated in the generic part of the item structure. + * + *-------------------------------------------------------------- + */ + +static void +TranslatePolygon( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item that is being moved. */ + double deltaX, double deltaY) + /* Amount by which item is to be moved. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + double *coordPtr; + int i; + + for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints; + i++, coordPtr += 2) { + *coordPtr += deltaX; + coordPtr[1] += deltaY; + } + ComputePolygonBbox(canvas, polyPtr); +} + +/* + *-------------------------------------------------------------- + * + * PolygonToPostscript -- + * + * This function is called to generate Postscript for polygon items. + * + * Results: + * The return value is a standard Tcl result. If an error occurs in + * generating Postscript then an error message is left in the interp's + * 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 +PolygonToPostscript( + Tcl_Interp *interp, /* Leave Postscript or error message here. */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + Tk_PathItem *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. */ +{ + PolygonItem *polyPtr = (PolygonItem *) itemPtr; + char *style; + XColor *color; + XColor *fillColor; + Pixmap stipple; + Pixmap fillStipple; + Tk_PathState state = itemPtr->state; + double width; + + if (polyPtr->numPoints<2 || polyPtr->coordPtr==NULL) { + return TCL_OK; + } + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + width = polyPtr->outline.width; + color = polyPtr->outline.color; + stipple = polyPtr->fillStipple; + fillColor = polyPtr->fillColor; + fillStipple = polyPtr->fillStipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (polyPtr->outline.activeWidth>width) { + width = polyPtr->outline.activeWidth; + } + if (polyPtr->outline.activeColor!=NULL) { + color = polyPtr->outline.activeColor; + } + if (polyPtr->outline.activeStipple!=None) { + stipple = polyPtr->outline.activeStipple; + } + if (polyPtr->activeFillColor!=NULL) { + fillColor = polyPtr->activeFillColor; + } + if (polyPtr->activeFillStipple!=None) { + fillStipple = polyPtr->activeFillStipple; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (polyPtr->outline.disabledWidth>0.0) { + width = polyPtr->outline.disabledWidth; + } + if (polyPtr->outline.disabledColor!=NULL) { + color = polyPtr->outline.disabledColor; + } + if (polyPtr->outline.disabledStipple!=None) { + stipple = polyPtr->outline.disabledStipple; + } + if (polyPtr->disabledFillColor!=NULL) { + fillColor = polyPtr->disabledFillColor; + } + if (polyPtr->disabledFillStipple!=None) { + fillStipple = polyPtr->disabledFillStipple; + } + } + if (polyPtr->numPoints==2) { + char string[128]; + if (color == NULL) { + return TCL_OK; + } + + sprintf(string, "%.15g %.15g translate %.15g %.15g", + polyPtr->coordPtr[0], Tk_PathCanvasPsY(canvas, polyPtr->coordPtr[1]), + width/2.0, width/2.0); + Tcl_AppendResult(interp, "matrix currentmatrix\n",string, + " scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", NULL); + if (Tk_PathCanvasPsColor(interp, canvas, color) != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "clip ", NULL); + if (Tk_PathCanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "fill\n", NULL); + } + return TCL_OK; + } + + /* + * Fill the area of the polygon. + */ + + if (fillColor != NULL && polyPtr->numPoints>3) { + if (!polyPtr->smooth || !polyPtr->smooth->postscriptProc) { + Tk_PathCanvasPsPath(interp, canvas, polyPtr->coordPtr, + polyPtr->numPoints); + } else { + polyPtr->smooth->postscriptProc(interp, canvas, polyPtr->coordPtr, + polyPtr->numPoints, polyPtr->splineSteps); + } + if (Tk_PathCanvasPsColor(interp, canvas, fillColor) != TCL_OK) { + return TCL_ERROR; + } + if (fillStipple != None) { + Tcl_AppendResult(interp, "eoclip ", NULL); + if (Tk_PathCanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { + return TCL_ERROR; + } + if (color != NULL) { + Tcl_AppendResult(interp, "grestore gsave\n", NULL); + } + } else { + Tcl_AppendResult(interp, "eofill\n", NULL); + } + } + + /* + * Now draw the outline, if there is one. + */ + + if (color != NULL) { + if (!polyPtr->smooth || !polyPtr->smooth->postscriptProc) { + Tk_PathCanvasPsPath(interp, canvas, polyPtr->coordPtr, + polyPtr->numPoints); + } else { + polyPtr->smooth->postscriptProc(interp, canvas, polyPtr->coordPtr, + polyPtr->numPoints, polyPtr->splineSteps); + } + + if (polyPtr->joinStyle == JoinRound) { + style = "1"; + } else if (polyPtr->joinStyle == JoinBevel) { + style = "2"; + } else { + style = "0"; + } + Tcl_AppendResult(interp, style," setlinejoin 1 setlinecap\n", NULL); + if (Tk_PathCanvasPsOutline(canvas, itemPtr, + &(polyPtr->outline)) != TCL_OK) { + return TCL_ERROR; + } + } + return TCL_OK; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/pd/tkpath/generic/tkpCanvPs.c b/pd/tkpath/generic/tkpCanvPs.c new file mode 100644 index 0000000000000000000000000000000000000000..8023b83cd8572c78b032b2dde19337cf241906fa --- /dev/null +++ b/pd/tkpath/generic/tkpCanvPs.c @@ -0,0 +1,1012 @@ +/* + * tkpCanvPs.c -- + * + * This module provides Postscript output support for canvases, including + * the "postscript" widget command plus a few utility functions used for + * generating Postscript. + * + * NB: A number of duplicate functions have been cleaned out from this file. + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvPs.c,v 1.3 2012/07/04 19:43:18 petasis Exp $ + */ + +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" + +/* + * See tkCanvas.h for key data structures used to implement canvases. + */ + +/* + * The following definition is used in generating postscript for images and + * windows. + */ + +typedef struct TkColormapData { /* Hold color information for a window */ + int separated; /* Whether to use separate color bands */ + int color; /* Whether window is color or black/white */ + int ncolors; /* Number of color values stored */ + XColor *colors; /* Pixel value -> RGB mappings */ + int red_mask, green_mask, blue_mask; /* Masks and shifts for each */ + int red_shift, green_shift, blue_shift; /* color band */ +} TkColormapData; + +/* + * One of the following structures is created to keep track of Postscript + * output being generated. It consists mostly of information provided on the + * widget command line. + */ + +typedef struct TkPostscriptInfo { + int x, y, width, height; /* Area to print, in canvas pixel + * coordinates. */ + int x2, y2; /* x+width and y+height. */ + char *pageXString; /* String value of "-pagex" option or NULL. */ + char *pageYString; /* String value of "-pagey" option or NULL. */ + double pageX, pageY; /* Postscript coordinates (in points) + * corresponding to pageXString and + * pageYString. Don't forget that y-values + * grow upwards for Postscript! */ + char *pageWidthString; /* Printed width of output. */ + char *pageHeightString; /* Printed height of output. */ + double scale; /* Scale factor for conversion: each pixel + * maps into this many points. */ + Tk_Anchor pageAnchor; /* How to anchor bbox on Postscript page. */ + int rotate; /* Non-zero means output should be rotated on + * page (landscape mode). */ + char *fontVar; /* If non-NULL, gives name of global variable + * containing font mapping information. + * Malloc'ed. */ + char *colorVar; /* If non-NULL, give name of global variable + * containing color mapping information. + * Malloc'ed. */ + char *colorMode; /* Mode for handling colors: "monochrome", + * "gray", or "color". Malloc'ed. */ + int colorLevel; /* Numeric value corresponding to colorMode: 0 + * for mono, 1 for gray, 2 for color. */ + char *fileName; /* Name of file in which to write Postscript; + * NULL means return Postscript info as + * result. Malloc'ed. */ + char *channelName; /* If -channel is specified, the name of the + * channel to use. */ + Tcl_Channel chan; /* Open channel corresponding to fileName. */ + Tcl_HashTable fontTable; /* Hash table containing names of all font + * families used in output. The hash table + * values are not used. */ + int prepass; /* Non-zero means that we're currently in the + * pre-pass that collects font information, so + * the Postscript generated isn't relevant. */ + int prolog; /* Non-zero means output should contain the + * file prolog.ps in the header. */ +} TkPostscriptInfo; + +/* + * The table below provides a template that's used to process arguments to the + * canvas "postscript" command and fill in TkPostscriptInfo structures. + */ + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_STRING, "-colormap", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, colorVar), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-colormode", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, colorMode), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-file", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, fileName), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-channel", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, channelName), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-fontmap", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, fontVar), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-height", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, height), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_ANCHOR, "-pageanchor", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, pageAnchor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-pageheight", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, pageHeightString), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-pagewidth", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, pageWidthString), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-pagex", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, pageXString), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-pagey", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, pageYString), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-prolog", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, prolog), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-rotate", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, rotate), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-width", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, width), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-x", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, x), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-y", NULL, NULL, + NULL, -1, Tk_Offset(TkPostscriptInfo, y), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * Forward declarations for functions defined later in this file: + */ + +static int GetPostscriptPoints(Tcl_Interp *interp, + char *string, double *doublePtr); + +/* + *-------------------------------------------------------------- + * + * TkCanvPostscriptCmd -- + * + * This function is invoked to process the "postscript" options of the + * widget command for canvas widgets. See the user documentation for + * details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +TkCanvPostscriptCmd( + TkPathCanvas *canvasPtr, /* Information about canvas widget. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[]) /* Argument strings. Caller has already parsed + * this command enough to know that argv[1] is + * "postscript". */ +{ + TkPostscriptInfo psInfo, *psInfoPtr = &psInfo; + Tk_PostscriptInfo oldInfoPtr; + int result; + Tk_PathItem *itemPtr; +#define STRING_LENGTH 400 + char string[STRING_LENGTH+1]; + CONST char *p; + time_t now; + size_t length; + Tk_Window tkwin = canvasPtr->tkwin; + Tcl_HashSearch search; + Tcl_HashEntry *hPtr; + Tcl_DString buffer; + char psenccmd[] = "::tk::ensure_psenc_is_loaded"; + int deltaX = 0, deltaY = 0; /* Offset of lower-left corner of area to be + * marked up, measured in canvas units from + * the positioning point on the page (reflects + * anchor position). Initial values needed + * only to stop compiler warnings. */ + + /* + * Initialize the data structure describing Postscript generation, then + * process all the arguments to fill the data structure in. + */ + + result = Tcl_EvalEx(interp,psenccmd,-1,TCL_EVAL_GLOBAL); + if (result != TCL_OK) { + return result; + } + oldInfoPtr = canvasPtr->psInfo; + canvasPtr->psInfo = (Tk_PostscriptInfo) psInfoPtr; + psInfo.x = canvasPtr->xOrigin; + psInfo.y = canvasPtr->yOrigin; + psInfo.width = -1; + psInfo.height = -1; + psInfo.pageXString = NULL; + psInfo.pageYString = NULL; + psInfo.pageX = 72*4.25; + psInfo.pageY = 72*5.5; + psInfo.pageWidthString = NULL; + psInfo.pageHeightString = NULL; + psInfo.scale = 1.0; + psInfo.pageAnchor = TK_ANCHOR_CENTER; + psInfo.rotate = 0; + psInfo.fontVar = NULL; + psInfo.colorVar = NULL; + psInfo.colorMode = NULL; + psInfo.colorLevel = 0; + psInfo.fileName = NULL; + psInfo.channelName = NULL; + psInfo.chan = NULL; + psInfo.prepass = 0; + psInfo.prolog = 1; + + Tcl_InitHashTable(&psInfo.fontTable, TCL_STRING_KEYS); + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + if (Tk_InitOptions(interp, (char *) &psInfo, optionTable, tkwin) != TCL_OK) { + goto cleanup; + } + if (Tk_SetOptions(interp, (char *) &psInfo, optionTable, + objc-2, objv+2, tkwin, NULL, NULL) != TCL_OK) { + goto cleanup; + } + + if (psInfo.width == -1) { + psInfo.width = Tk_Width(tkwin); + } + if (psInfo.height == -1) { + psInfo.height = Tk_Height(tkwin); + } + psInfo.x2 = psInfo.x + psInfo.width; + psInfo.y2 = psInfo.y + psInfo.height; + + if (psInfo.pageXString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageXString, + &psInfo.pageX) != TCL_OK) { + goto cleanup; + } + } + if (psInfo.pageYString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageYString, + &psInfo.pageY) != TCL_OK) { + goto cleanup; + } + } + if (psInfo.pageWidthString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageWidthString, + &psInfo.scale) != TCL_OK) { + goto cleanup; + } + psInfo.scale /= psInfo.width; + } else if (psInfo.pageHeightString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageHeightString, + &psInfo.scale) != TCL_OK) { + goto cleanup; + } + psInfo.scale /= psInfo.height; + } else { + psInfo.scale = (72.0/25.4)*WidthMMOfScreen(Tk_Screen(tkwin)); + psInfo.scale /= WidthOfScreen(Tk_Screen(tkwin)); + } + switch (psInfo.pageAnchor) { + case TK_ANCHOR_NW: + case TK_ANCHOR_W: + case TK_ANCHOR_SW: + deltaX = 0; + break; + case TK_ANCHOR_N: + case TK_ANCHOR_CENTER: + case TK_ANCHOR_S: + deltaX = -psInfo.width/2; + break; + case TK_ANCHOR_NE: + case TK_ANCHOR_E: + case TK_ANCHOR_SE: + deltaX = -psInfo.width; + break; + } + switch (psInfo.pageAnchor) { + case TK_ANCHOR_NW: + case TK_ANCHOR_N: + case TK_ANCHOR_NE: + deltaY = - psInfo.height; + break; + case TK_ANCHOR_W: + case TK_ANCHOR_CENTER: + case TK_ANCHOR_E: + deltaY = -psInfo.height/2; + break; + case TK_ANCHOR_SW: + case TK_ANCHOR_S: + case TK_ANCHOR_SE: + deltaY = 0; + break; + } + + if (psInfo.colorMode == NULL) { + psInfo.colorLevel = 2; + } else { + length = strlen(psInfo.colorMode); + if (strncmp(psInfo.colorMode, "monochrome", length) == 0) { + psInfo.colorLevel = 0; + } else if (strncmp(psInfo.colorMode, "gray", length) == 0) { + psInfo.colorLevel = 1; + } else if (strncmp(psInfo.colorMode, "color", length) == 0) { + psInfo.colorLevel = 2; + } else { + Tcl_AppendResult(interp, "bad color mode \"", psInfo.colorMode, + "\": must be monochrome, gray, or color", NULL); + goto cleanup; + } + } + + if (psInfo.fileName != NULL) { + /* + * Check that -file and -channel are not both specified. + */ + + if (psInfo.channelName != NULL) { + Tcl_AppendResult(interp, "can't specify both -file", + " and -channel", NULL); + result = TCL_ERROR; + goto cleanup; + } + + /* + * Check that we are not in a safe interpreter. If we are, disallow + * the -file specification. + */ + + if (Tcl_IsSafe(interp)) { + Tcl_AppendResult(interp, "can't specify -file in a", + " safe interpreter", NULL); + result = TCL_ERROR; + goto cleanup; + } + + p = Tcl_TranslateFileName(interp, psInfo.fileName, &buffer); + if (p == NULL) { + goto cleanup; + } + psInfo.chan = Tcl_OpenFileChannel(interp, p, "w", 0666); + Tcl_DStringFree(&buffer); + if (psInfo.chan == NULL) { + goto cleanup; + } + } + + if (psInfo.channelName != NULL) { + int mode; + + /* + * Check that the channel is found in this interpreter and that it is + * open for writing. + */ + + psInfo.chan = Tcl_GetChannel(interp, psInfo.channelName, &mode); + if (psInfo.chan == (Tcl_Channel) NULL) { + result = TCL_ERROR; + goto cleanup; + } + if ((mode & TCL_WRITABLE) == 0) { + Tcl_AppendResult(interp, "channel \"", psInfo.channelName, + "\" wasn't opened for writing", NULL); + result = TCL_ERROR; + goto cleanup; + } + } + + /* + * Make a pre-pass over all of the items, generating Postscript and then + * throwing it away. The purpose of this pass is just to collect + * information about all the fonts in use, so that we can output font + * information in the proper form required by the Document Structuring + * Conventions. + */ + + psInfo.prepass = 1; + for (itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + if ((itemPtr->x1 >= psInfo.x2) || (itemPtr->x2 < psInfo.x) + || (itemPtr->y1 >= psInfo.y2) || (itemPtr->y2 < psInfo.y)) { + continue; + } + if (itemPtr->typePtr->postscriptProc == NULL) { + continue; + } + result = (*itemPtr->typePtr->postscriptProc)(interp, + (Tk_PathCanvas) canvasPtr, itemPtr, 1); + Tcl_ResetResult(interp); + if (result != TCL_OK) { + /* + * An error just occurred. Just skip out of this loop. There's no + * need to report the error now; it can be reported later (errors + * can happen later that don't happen now, so we still have to + * check for errors later anyway). + */ + break; + } + } + psInfo.prepass = 0; + + /* + * Generate the header and prolog for the Postscript. + */ + + if (psInfo.prolog) { + Tcl_AppendResult(interp, "%!PS-Adobe-3.0 EPSF-3.0\n", + "%%Creator: Tk Canvas Widget\n", NULL); +#ifdef HAVE_PW_GECOS + if (!Tcl_IsSafe(interp)) { + struct passwd *pwPtr = getpwuid(getuid()); /* INTL: Native. */ + + Tcl_AppendResult(interp, "%%For: ", + (pwPtr != NULL) ? pwPtr->pw_gecos : "Unknown", "\n", NULL); + endpwent(); + } +#endif /* HAVE_PW_GECOS */ + Tcl_AppendResult(interp, "%%Title: Window ", Tk_PathName(tkwin), "\n", + NULL); + time(&now); + Tcl_AppendResult(interp, "%%CreationDate: ", + ctime(&now), NULL); /* INTL: Native. */ + if (!psInfo.rotate) { + sprintf(string, "%d %d %d %d", + (int) (psInfo.pageX + psInfo.scale*deltaX), + (int) (psInfo.pageY + psInfo.scale*deltaY), + (int) (psInfo.pageX + psInfo.scale*(deltaX + psInfo.width) + + 1.0), + (int) (psInfo.pageY + psInfo.scale*(deltaY + psInfo.height) + + 1.0)); + } else { + sprintf(string, "%d %d %d %d", + (int) (psInfo.pageX - psInfo.scale*(deltaY+psInfo.height)), + (int) (psInfo.pageY + psInfo.scale*deltaX), + (int) (psInfo.pageX - psInfo.scale*deltaY + 1.0), + (int) (psInfo.pageY + psInfo.scale*(deltaX + psInfo.width) + + 1.0)); + } + Tcl_AppendResult(interp, "%%BoundingBox: ", string, "\n", NULL); + Tcl_AppendResult(interp, "%%Pages: 1\n", + "%%DocumentData: Clean7Bit\n", NULL); + Tcl_AppendResult(interp, "%%Orientation: ", + psInfo.rotate ? "Landscape\n" : "Portrait\n", NULL); + p = "%%DocumentNeededResources: font "; + for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + Tcl_AppendResult(interp, p, + Tcl_GetHashKey(&psInfo.fontTable, hPtr), "\n", NULL); + p = "%%+ font "; + } + Tcl_AppendResult(interp, "%%EndComments\n\n", NULL); + + /* + * Insert the prolog + */ + + Tcl_AppendResult(interp, Tcl_GetVar(interp,"::tk::ps_preamable", + TCL_GLOBAL_ONLY), NULL); + + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); + Tcl_ResetResult(canvasPtr->interp); + } + + /* + * Document setup: set the color level and include fonts. + */ + + sprintf(string, "/CL %d def\n", psInfo.colorLevel); + Tcl_AppendResult(interp, "%%BeginSetup\n", string, NULL); + for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + Tcl_AppendResult(interp, "%%IncludeResource: font ", + Tcl_GetHashKey(&psInfo.fontTable, hPtr), "\n", NULL); + } + Tcl_AppendResult(interp, "%%EndSetup\n\n", NULL); + + /* + * Page setup: move to page positioning point, rotate if needed, set + * scale factor, offset for proper anchor position, and set clip + * region. + */ + + Tcl_AppendResult(interp, "%%Page: 1 1\n", "save\n", NULL); + sprintf(string, "%.1f %.1f translate\n", psInfo.pageX, psInfo.pageY); + Tcl_AppendResult(interp, string, NULL); + if (psInfo.rotate) { + Tcl_AppendResult(interp, "90 rotate\n", NULL); + } + sprintf(string, "%.4g %.4g scale\n", psInfo.scale, psInfo.scale); + Tcl_AppendResult(interp, string, NULL); + sprintf(string, "%d %d translate\n", deltaX - psInfo.x, deltaY); + Tcl_AppendResult(interp, string, NULL); + sprintf(string, + "%d %.15g moveto %d %.15g lineto %d %.15g lineto %d %.15g", + psInfo.x, Tk_PostscriptY((double)psInfo.y, + (Tk_PostscriptInfo)psInfoPtr), + psInfo.x2, Tk_PostscriptY((double)psInfo.y, + (Tk_PostscriptInfo)psInfoPtr), + psInfo.x2, Tk_PostscriptY((double)psInfo.y2, + (Tk_PostscriptInfo)psInfoPtr), + psInfo.x, Tk_PostscriptY((double)psInfo.y2, + (Tk_PostscriptInfo)psInfoPtr)); + Tcl_AppendResult(interp, string, + " lineto closepath clip newpath\n", NULL); + } + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); + Tcl_ResetResult(canvasPtr->interp); + } + + /* + * Iterate through all the items, having each relevant one draw itself. + * Quit if any of the items returns an error. + */ + + result = TCL_OK; + for (itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + if ((itemPtr->x1 >= psInfo.x2) || (itemPtr->x2 < psInfo.x) + || (itemPtr->y1 >= psInfo.y2) || (itemPtr->y2 < psInfo.y)) { + continue; + } + if (itemPtr->typePtr->postscriptProc == NULL) { + continue; + } + if (itemPtr->state == TK_PATHSTATE_HIDDEN) { + continue; + } + Tcl_AppendResult(interp, "gsave\n", NULL); + result = (*itemPtr->typePtr->postscriptProc)(interp, + (Tk_PathCanvas) canvasPtr, itemPtr, 0); + if (result != TCL_OK) { + char msg[64 + TCL_INTEGER_SPACE]; + + sprintf(msg, "\n (generating Postscript for item %d)", + itemPtr->id); + Tcl_AddErrorInfo(interp, msg); + goto cleanup; + } + Tcl_AppendResult(interp, "grestore\n", NULL); + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); + Tcl_ResetResult(interp); + } + } + + /* + * Output page-end information, such as commands to print the page and + * document trailer stuff. + */ + + if (psInfo.prolog) { + Tcl_AppendResult(interp, "restore showpage\n\n", + "%%Trailer\nend\n%%EOF\n", NULL); + } + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_GetStringResult(interp), -1); + Tcl_ResetResult(canvasPtr->interp); + } + + /* + * Clean up psInfo to release malloc'ed stuff. + */ + + cleanup: + if ((psInfo.chan != NULL) && (psInfo.channelName == NULL)) { + Tcl_Close(interp, psInfo.chan); + } + Tcl_DeleteHashTable(&psInfo.fontTable); + canvasPtr->psInfo = (Tk_PostscriptInfo) oldInfoPtr; + Tk_FreeConfigOptions((char *) &psInfo, optionTable, tkwin); + return result; +} + +/* + *-------------------------------------------------------------- + * + * GetPostscriptPoints -- + * + * Given a string, returns the number of Postscript points corresponding + * to that string. + * + * Results: + * The return value is a standard Tcl return result. If TCL_OK is + * returned, then everything went well and the screen distance is stored + * at *doublePtr; otherwise TCL_ERROR is returned and an error message is + * left in the interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetPostscriptPoints( + Tcl_Interp *interp, /* Use this for error reporting. */ + char *string, /* String describing a screen distance. */ + double *doublePtr) /* Place to store converted result. */ +{ + char *end; + double d; + + d = strtod(string, &end); + if (end == string) { + goto error; + } + while ((*end != '\0') && isspace(UCHAR(*end))) { + end++; + } + switch (*end) { + case 'c': + d *= 72.0/2.54; + end++; + break; + case 'i': + d *= 72.0; + end++; + break; + case 'm': + d *= 72.0/25.4; + end++; + break; + case 0: + break; + case 'p': + end++; + break; + default: + goto error; + } + while ((*end != '\0') && isspace(UCHAR(*end))) { + end++; + } + if (*end != 0) { + goto error; + } + *doublePtr = d; + return TCL_OK; + + error: + Tcl_AppendResult(interp, "bad distance \"", string, "\"", NULL); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * TkImageGetColor -- + * + * This function converts a pixel value to three floating point numbers, + * representing the amount of red, green, and blue in that pixel on the + * screen. It makes use of colormap data passed as an argument, and + * should work for all Visual types. + * + * This implementation is bogus on Windows because the colormap data is + * never filled in. Instead all postscript generated data coming through + * here is expected to be RGB color data. To handle lower bit-depth + * images properly, XQueryColors must be implemented for Windows. + * + * Results: + * Returns red, green, and blue color values in the range 0 to 1. There + * are no error returns. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +#ifdef WIN32 +#include <windows.h> + +/* + * We could just define these instead of pulling in windows.h. + #define GetRValue(rgb) ((BYTE)(rgb)) + #define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >> 8)) + #define GetBValue(rgb) ((BYTE)((rgb)>>16)) + */ + +#else /* !WIN32 */ + +#define GetRValue(rgb) ((rgb & cdata->red_mask) >> cdata->red_shift) +#define GetGValue(rgb) ((rgb & cdata->green_mask) >> cdata->green_shift) +#define GetBValue(rgb) ((rgb & cdata->blue_mask) >> cdata->blue_shift) + +#endif /* WIN32 */ + +#if defined(WIN32) || defined(MAC_OSX_TK) +static void +TkImageGetColor( + TkColormapData *cdata, /* Colormap data */ + unsigned long pixel, /* Pixel value to look up */ + double *red, double *green, double *blue) + /* Color data to return */ +{ + *red = (double) GetRValue(pixel) / 255.0; + *green = (double) GetGValue(pixel) / 255.0; + *blue = (double) GetBValue(pixel) / 255.0; +} +#else /* ! (WIN32 || MAC_OSX_TK) */ +static void +TkImageGetColor( + TkColormapData *cdata, /* Colormap data */ + unsigned long pixel, /* Pixel value to look up */ + double *red, double *green, double *blue) + /* Color data to return */ +{ + if (cdata->separated) { + int r = GetRValue(pixel); + int g = GetGValue(pixel); + int b = GetBValue(pixel); + + *red = cdata->colors[r].red / 65535.0; + *green = cdata->colors[g].green / 65535.0; + *blue = cdata->colors[b].blue / 65535.0; + } else { + *red = cdata->colors[pixel].red / 65535.0; + *green = cdata->colors[pixel].green / 65535.0; + *blue = cdata->colors[pixel].blue / 65535.0; + } +} +#endif /* WIN32 || MAC_OSX_TK */ + +/* + *-------------------------------------------------------------- + * + * TkPathPostscriptImage -- + * + * This function is called to output the contents of an image in + * Postscript, using a format appropriate for the current color mode + * (i.e. one bit per pixel in monochrome, one byte per pixel in gray, and + * three bytes per pixel in color). + * + * Results: + * Returns a standard Tcl return value. If an error occurs then an error + * message will be left in interp->result. If no error occurs, then + * additional Postscript will be appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkPathPostscriptImage( + Tcl_Interp *interp, + Tk_Window tkwin, + Tk_PostscriptInfo psInfo, /* postscript info */ + XImage *ximage, /* Image to draw */ + int x, int y, /* First pixel to output */ + int width, int height) /* Width and height of area */ +{ + TkPostscriptInfo *psInfoPtr = (TkPostscriptInfo *) psInfo; + char buffer[256]; + int xx, yy, band, maxRows; + double red, green, blue; + int bytesPerLine=0, maxWidth=0; + int level = psInfoPtr->colorLevel; + Colormap cmap; + int i, ncolors; + Visual *visual; + TkColormapData cdata; + + if (psInfoPtr->prepass) { + return TCL_OK; + } + + cmap = Tk_Colormap(tkwin); + visual = Tk_Visual(tkwin); + + /* + * Obtain information about the colormap, ie the mapping between pixel + * values and RGB values. The code below should work for all Visual types. + */ + + ncolors = visual->map_entries; + cdata.colors = (XColor *) ckalloc(sizeof(XColor) * ncolors); + cdata.ncolors = ncolors; + +#if defined(__cplusplus) || defined(c_plusplus) + if (visual->c_class == DirectColor || visual->c_class == TrueColor) { +#else + int class; /* class of screen (monochrome, etc.) */ + if (visual->class == DirectColor || visual->class == TrueColor) { +#endif + cdata.separated = 1; + cdata.red_mask = visual->red_mask; + cdata.green_mask = visual->green_mask; + cdata.blue_mask = visual->blue_mask; + cdata.red_shift = 0; + cdata.green_shift = 0; + cdata.blue_shift = 0; + + while ((0x0001 & (cdata.red_mask >> cdata.red_shift)) == 0) { + cdata.red_shift ++; + } + while ((0x0001 & (cdata.green_mask >> cdata.green_shift)) == 0) { + cdata.green_shift ++; + } + while ((0x0001 & (cdata.blue_mask >> cdata.blue_shift)) == 0) { + cdata.blue_shift ++; + } + + for (i = 0; i < ncolors; i ++) { + cdata.colors[i].pixel = + ((i << cdata.red_shift) & cdata.red_mask) | + ((i << cdata.green_shift) & cdata.green_mask) | + ((i << cdata.blue_shift) & cdata.blue_mask); + } + } else { + cdata.separated=0; + for (i = 0; i < ncolors; i ++) { + cdata.colors[i].pixel = i; + } + } + +#if defined(__cplusplus) || defined(c_plusplus) + if (visual->c_class == StaticGray || visual->c_class == GrayScale) { +#else + if (visual->class == StaticGray || visual->class == GrayScale) { +#endif + cdata.color = 0; + } else { + cdata.color = 1; + } + + XQueryColors(Tk_Display(tkwin), cmap, cdata.colors, ncolors); + + /* + * Figure out which color level to use (possibly lower than the one + * specified by the user). For example, if the user specifies color with + * monochrome screen, use gray or monochrome mode instead. + */ + + if (!cdata.color && level == 2) { + level = 1; + } + + if (!cdata.color && cdata.ncolors == 2) { + level = 0; + } + + /* + * Check that at least one row of the image can be represented with a + * string less than 64 KB long (this is a limit in the Postscript + * interpreter). + */ + + switch (level) { + case 0: bytesPerLine = (width + 7) / 8; maxWidth = 240000; break; + case 1: bytesPerLine = width; maxWidth = 60000; break; + case 2: bytesPerLine = 3 * width; maxWidth = 20000; break; + } + + if (bytesPerLine > 60000) { + Tcl_ResetResult(interp); + sprintf(buffer, + "Can't generate Postscript for images more than %d pixels wide", + maxWidth); + Tcl_AppendResult(interp, buffer, NULL); + ckfree((char *) cdata.colors); + return TCL_ERROR; + } + + maxRows = 60000 / bytesPerLine; + + for (band = height-1; band >= 0; band -= maxRows) { + int rows = (band >= maxRows) ? maxRows : band + 1; + int lineLen = 0; + + switch (level) { + case 0: + sprintf(buffer, "%d %d 1 matrix {\n<", width, rows); + Tcl_AppendResult(interp, buffer, NULL); + break; + case 1: + sprintf(buffer, "%d %d 8 matrix {\n<", width, rows); + Tcl_AppendResult(interp, buffer, NULL); + break; + case 2: + sprintf(buffer, "%d %d 8 matrix {\n<", width, rows); + Tcl_AppendResult(interp, buffer, NULL); + break; + } + for (yy = band; yy > band - rows; yy--) { + switch (level) { + case 0: { + /* + * Generate data for image in monochrome mode. No attempt at + * dithering is made--instead, just set a threshold. + */ + + unsigned char mask = 0x80; + unsigned char data = 0x00; + + for (xx = x; xx< x+width; xx++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + if (0.30 * red + 0.59 * green + 0.11 * blue > 0.5) { + data |= mask; + } + mask >>= 1; + if (mask == 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, NULL); + lineLen += 2; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", NULL); + } + mask=0x80; + data=0x00; + } + } + if ((width % 8) != 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, NULL); + mask=0x80; + data=0x00; + } + break; + } + case 1: + /* + * Generate data in gray mode; in this case, take a weighted + * sum of the red, green, and blue values. + */ + + for (xx = x; xx < x+width; xx ++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + sprintf(buffer, "%02X", (int) floor(0.5 + 255.0 * + (0.30 * red + 0.59 * green + 0.11 * blue))); + Tcl_AppendResult(interp, buffer, NULL); + lineLen += 2; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", NULL); + } + } + break; + case 2: + /* + * Finally, color mode. Here, just output the red, green, and + * blue values directly. + */ + + for (xx = x; xx < x+width; xx++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + sprintf(buffer, "%02X%02X%02X", + (int) floor(0.5 + 255.0 * red), + (int) floor(0.5 + 255.0 * green), + (int) floor(0.5 + 255.0 * blue)); + Tcl_AppendResult(interp, buffer, NULL); + lineLen += 6; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", NULL); + } + } + break; + } + } + switch (level) { + case 0: case 1: + sprintf(buffer, ">\n} image\n"); break; + case 2: + sprintf(buffer, ">\n} false 3 colorimage\n"); break; + } + Tcl_AppendResult(interp, buffer, NULL); + sprintf(buffer, "0 %d translate\n", rows); + Tcl_AppendResult(interp, buffer, NULL); + } + ckfree((char *) cdata.colors); + return TCL_OK; +} + + + + + diff --git a/pd/tkpath/generic/tkpCanvText.c b/pd/tkpath/generic/tkpCanvText.c new file mode 100644 index 0000000000000000000000000000000000000000..56cd99b4868f9d18aa2987d39edc43ff8103b518 --- /dev/null +++ b/pd/tkpath/generic/tkpCanvText.c @@ -0,0 +1,1528 @@ +/* + * tkpCanvText.c -- + * + * This file implements text items for canvas widgets. + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvText.c,v 1.8 2008/07/16 13:17:33 matben Exp $ + */ + +#include <stdio.h> +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" +#include "default.h" + +/* + * The structure below defines the record for each text item. + */ + +typedef struct TextItem { + Tk_PathItem header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + Tk_PathCanvasTextInfo *textInfoPtr; + /* Pointer to a structure containing + * information about the selection and + * insertion cursor. The structure is owned by + * (and shared with) the generic canvas + * code. */ + /* + * Fields that are set by widget commands other than "configure". + */ + + double x, y; /* Positioning point for text. */ + int insertPos; /* Character index of character just before + * which the insertion cursor is displayed. */ + + /* + * Configuration settings that are updated by Tk_ConfigureWidget. + */ + + Tk_Anchor anchor; /* Where to anchor text relative to (x,y). */ + Tk_TSOffset *tsoffsetPtr; + XColor *color; /* Color for text. */ + XColor *activeColor; /* Color for text. */ + XColor *disabledColor; /* Color for text. */ + Tk_Font tkfont; /* Font for drawing text. */ + Tk_Justify justify; /* Justification mode for text. */ + Pixmap stipple; /* Stipple bitmap for text, or None. */ + Pixmap activeStipple; /* Stipple bitmap for text, or None. */ + Pixmap disabledStipple; /* Stipple bitmap for text, or None. */ + char *text; /* Text for item (malloc-ed). */ + int width; /* Width of lines for word-wrap, pixels. Zero + * means no word-wrap. */ + int underline; /* Index of character to put underline beneath + * or -1 for no underlining. */ + + /* + * Fields whose values are derived from the current values of the + * configuration settings above. + */ + + int numChars; /* Length of text in characters. */ + int numBytes; /* Length of text in bytes. */ + Tk_TextLayout textLayout; /* Cached text layout information. */ + int leftEdge; /* Pixel location of the left edge of the text + * item; where the left border of the text + * layout is drawn. */ + int rightEdge; /* Pixel just to right of right edge of area + * of text item. Used for selecting up to end + * of line. */ + GC gc; /* Graphics context for drawing text. */ + GC selTextGC; /* Graphics context for selected text. */ + GC cursorOffGC; /* If not None, this gives a graphics context + * to use to draw the insertion cursor when + * it's off. Used if the selection and + * insertion cursor colors are the same. */ +} TextItem; + +#define PATH_DEF_STATE "normal" + +/* These MUST be kept in sync with enums! X.h */ + +static char *stateStrings[] = { + "active", "disabled", "normal", "hidden", NULL +}; + +static Tk_ObjCustomOption offsetCO = { + "offset", + TkPathOffsetOptionSetProc, + TkPathOffsetOptionGetProc, + TkPathOffsetOptionRestoreProc, + TkPathOffsetOptionFreeProc, + (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) +}; + +static Tk_ObjCustomOption tagsCO = { + "tags", + Tk_PathCanvasTagsOptionSetProc, + Tk_PathCanvasTagsOptionGetProc, + Tk_PathCanvasTagsOptionRestoreProc, + Tk_PathCanvasTagsOptionFreeProc, + (ClientData) NULL +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_COLOR, "-activefill", NULL, NULL, + NULL, -1, Tk_Offset(TextItem, activeColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-activestipple", NULL, NULL, + NULL, -1, Tk_Offset(TextItem, activeStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_ANCHOR, "-anchor", NULL, NULL, + "center", -1, Tk_Offset(TextItem, anchor), 0, 0, 0}, + {TK_OPTION_COLOR, "-disabledfill", NULL, NULL, + NULL, -1, Tk_Offset(TextItem, disabledColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-disabledstipple", NULL, NULL, + NULL, -1, Tk_Offset(TextItem, disabledStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-fill", NULL, NULL, + "black", -1, Tk_Offset(TextItem, color), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_FONT, "-font", NULL, NULL, + DEF_CANVTEXT_FONT, -1, Tk_Offset(TextItem, tkfont), + 0, 0, 0}, + {TK_OPTION_JUSTIFY, "-justify", NULL, NULL, + "left", -1, Tk_Offset(TextItem, justify), + 0, 0, 0}, + {TK_OPTION_CUSTOM, "-offset", NULL, NULL, + "0,0", -1, Tk_Offset(TextItem, tsoffsetPtr), + 0, &offsetCO, 0}, + {TK_OPTION_STRING_TABLE, "-state", NULL, NULL, + PATH_DEF_STATE, -1, Tk_Offset(Tk_PathItem, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_BITMAP, "-stipple", NULL, NULL, + NULL, -1, Tk_Offset(TextItem, stipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-tags", NULL, NULL, + NULL, -1, Tk_Offset(Tk_PathItem, pathTagsPtr), + TK_OPTION_NULL_OK, (ClientData) &tagsCO, 0}, + {TK_OPTION_STRING, "-text", NULL, NULL, + "", -1, Tk_Offset(TextItem, text), + 0, 0, 0}, /* Do not use TK_OPTION_NULL_OK + * here since the text layout + * goes crazy! */ + {TK_OPTION_INT, "-underline", NULL, NULL, + "-1", -1, Tk_Offset(TextItem, underline), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-width", NULL, NULL, + "0", -1, Tk_Offset(TextItem, width), 0, 0, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * Prototypes for functions defined in this file: + */ + +static void ComputeTextBbox(Tk_PathCanvas canvas, TextItem *textPtr); +static int ConfigureText(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int argc, + Tcl_Obj *CONST objv[], int flags); +static int CreateText(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int argc, Tcl_Obj *CONST objv[]); +static void DeleteText(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayCanvText(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable dst, + int x, int y, int width, int height); +static int GetSelText(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int offset, char *buffer, + int maxBytes); +static int GetTextIndex(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + Tcl_Obj *obj, int *indexPtr); +static void ScaleText(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void SetTextCursor(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int index); +static int TextCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int argc, Tcl_Obj *CONST objv[]); +static void TextDeleteChars(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int first, int last); +static void TextInsert(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int beforeThis, char *string); +static int TextToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static double TextToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *pointPtr); +static int TextToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static void TranslateText(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); + +/* + * The structures below defines the rectangle and oval item types by means of + * functions that can be invoked by generic item code. + */ + +Tk_PathItemType tkTextType = { + "text", /* name */ + sizeof(TextItem), /* itemSize */ + CreateText, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigureText, /* configureProc */ + TextCoords, /* coordProc */ + DeleteText, /* deleteProc */ + DisplayCanvText, /* displayProc */ + 0, /* flags */ + NULL, /* bboxProc */ + TextToPoint, /* pointProc */ + TextToArea, /* areaProc */ + TextToPostscript, /* postscriptProc */ + ScaleText, /* scaleProc */ + TranslateText, /* translateProc */ + (Tk_PathItemIndexProc *) GetTextIndex,/* indexProc */ + SetTextCursor, /* icursorProc */ + GetSelText, /* selectionProc */ + TextInsert, /* insertProc */ + TextDeleteChars, /* dTextProc */ + NULL, /* nextPtr */ +}; + +/* + *-------------------------------------------------------------- + * + * CreateText -- + * + * This function is invoked to create a new text 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 the interp's result; in this case + * itemPtr is left uninitialized so it can be safely freed by the caller. + * + * Side effects: + * A new text item is created. + * + *-------------------------------------------------------------- + */ + +static int +CreateText( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas to hold new item. */ + Tk_PathItem *itemPtr, /* Record to hold new item; header has been + * initialized by caller. */ + int objc, /* Number of arguments in objv. */ + Tcl_Obj *CONST objv[]) /* Arguments describing rectangle. */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed in order to clean up after + * errors during the the remainder of this function. + */ + + textPtr->textInfoPtr = Tk_PathCanvasGetTextInfo(canvas); + textPtr->insertPos = 0; + textPtr->anchor = TK_ANCHOR_CENTER; + textPtr->tsoffsetPtr = NULL; + textPtr->color = NULL; + textPtr->activeColor = NULL; + textPtr->disabledColor = NULL; + textPtr->tkfont = NULL; + textPtr->justify = TK_JUSTIFY_LEFT; + textPtr->stipple = None; + textPtr->activeStipple = None; + textPtr->disabledStipple = None; + textPtr->text = NULL; + textPtr->width = 0; + textPtr->underline = -1; + + textPtr->numChars = 0; + textPtr->numBytes = 0; + textPtr->textLayout = NULL; + textPtr->leftEdge = 0; + textPtr->rightEdge = 0; + textPtr->gc = None; + textPtr->selTextGC = None; + textPtr->cursorOffGC = None; + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) textPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + /* + * Process the arguments to fill in the item record. Only 1 (list) or 2 (x + * y) coords are allowed. + */ + + if (objc == 1) { + i = 1; + } else { + char *arg = Tcl_GetString(objv[1]); + + i = 2; + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + i = 1; + } + } + if ((TextCoords(interp, canvas, itemPtr, i, objv) != TCL_OK)) { + goto error; + } + if (ConfigureText(interp, canvas, itemPtr, objc-i, objv+i, 0) == TCL_OK) { + return TCL_OK; + } + + error: + DeleteText(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * TextCoords -- + * + * This function is invoked to process the "coords" widget command on + * text items. See the user documentation for details on what it does. + * + * Results: + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. + * + * Side effects: + * The coordinates for the given item may be changed. + * + *-------------------------------------------------------------- + */ + +static int +TextCoords( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item whose coordinates are to be read or + * modified. */ + int objc, /* Number of coordinates supplied in objv. */ + Tcl_Obj *CONST objv[]) /* Array of coordinates: x1, y1, x2, y2, ... */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewObj(); + + Tcl_Obj *subobj = Tcl_NewDoubleObj(textPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(textPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (objc < 3) { + if (objc==1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 2) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[0], + &textPtr->x) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[1], + &textPtr->y) != TCL_OK)) { + return TCL_ERROR; + } + ComputeTextBbox(canvas, textPtr); + } else { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ConfigureText -- + * + * This function is invoked to configure various aspects of a text item, + * such as its border and background colors. + * + * Results: + * A standard Tcl result code. If an error occurs, then an error message + * is left in the interp's result. + * + * Side effects: + * Configuration information, such as colors and stipple patterns, may be + * set for itemPtr. + * + *-------------------------------------------------------------- + */ + +static int +ConfigureText( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Rectangle item to reconfigure. */ + int objc, /* Number of elements in objv. */ + Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ + int flags) /* Flags to pass to Tk_ConfigureWidget. */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + XGCValues gcValues; + GC newGC, newSelGC; + unsigned long mask; + Tk_Window tkwin; + Tk_PathCanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; + XColor *selBgColorPtr; + XColor *color; + Pixmap stipple; + Tk_PathState state; + + tkwin = Tk_PathCanvasTkwin(canvas); + if (TCL_OK != Tk_SetOptions(interp, (char *) textPtr, optionTable, + objc, objv, tkwin, NULL, NULL)) { + return TCL_ERROR; + } + + /* + * A few of the options require additional processing, such as graphics + * contexts. + */ + + state = itemPtr->state; + + if (textPtr->activeColor != NULL || textPtr->activeStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + color = textPtr->color; + stipple = textPtr->stipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (textPtr->activeColor!=NULL) { + color = textPtr->activeColor; + } + if (textPtr->activeStipple!=None) { + stipple = textPtr->activeStipple; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (textPtr->disabledColor!=NULL) { + color = textPtr->disabledColor; + } + if (textPtr->disabledStipple!=None) { + stipple = textPtr->disabledStipple; + } + } + + newGC = newSelGC = None; + if (textPtr->tkfont != NULL) { + gcValues.font = Tk_FontId(textPtr->tkfont); + mask = GCFont; + if (color != NULL) { + gcValues.foreground = color->pixel; + mask |= GCForeground; + if (stipple != None) { + gcValues.stipple = stipple; + gcValues.fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } + mask &= ~(GCTile|GCFillStyle|GCStipple); + if (stipple != None) { + gcValues.stipple = stipple; + gcValues.fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } + if (textInfoPtr->selFgColorPtr != NULL) { + gcValues.foreground = textInfoPtr->selFgColorPtr->pixel; + } + newSelGC = Tk_GetGC(tkwin, mask|GCForeground, &gcValues); + } + if (textPtr->gc != None) { + Tk_FreeGC(Tk_Display(tkwin), textPtr->gc); + } + textPtr->gc = newGC; + if (textPtr->selTextGC != None) { + Tk_FreeGC(Tk_Display(tkwin), textPtr->selTextGC); + } + textPtr->selTextGC = newSelGC; + + selBgColorPtr = Tk_3DBorderColor(textInfoPtr->selBorder); + if (Tk_3DBorderColor(textInfoPtr->insertBorder)->pixel + == selBgColorPtr->pixel) { + if (selBgColorPtr->pixel == BlackPixelOfScreen(Tk_Screen(tkwin))) { + gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin)); + } else { + gcValues.foreground = BlackPixelOfScreen(Tk_Screen(tkwin)); + } + newGC = Tk_GetGC(tkwin, GCForeground, &gcValues); + } else { + newGC = None; + } + if (textPtr->cursorOffGC != None) { + Tk_FreeGC(Tk_Display(tkwin), textPtr->cursorOffGC); + } + textPtr->cursorOffGC = newGC; + + + /* + * If the text was changed, move the selection and insertion indices to + * keep them inside the item. + */ + textPtr->numBytes = (int) strlen(textPtr->text); + textPtr->numChars = Tcl_NumUtfChars(textPtr->text, textPtr->numBytes); + if (textInfoPtr->selItemPtr == itemPtr) { + + if (textInfoPtr->selectFirst >= textPtr->numChars) { + textInfoPtr->selItemPtr = NULL; + } else { + if (textInfoPtr->selectLast >= textPtr->numChars) { + textInfoPtr->selectLast = textPtr->numChars - 1; + } + if ((textInfoPtr->anchorItemPtr == itemPtr) + && (textInfoPtr->selectAnchor >= textPtr->numChars)) { + textInfoPtr->selectAnchor = textPtr->numChars - 1; + } + } + } + if (textPtr->insertPos >= textPtr->numChars) { + textPtr->insertPos = textPtr->numChars; + } + + ComputeTextBbox(canvas, textPtr); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * DeleteText -- + * + * This function is called to clean up the data structure associated with + * a text item. + * + * Results: + * None. + * + * Side effects: + * Resources associated with itemPtr are released. + * + *-------------------------------------------------------------- + */ + +static void +DeleteText( + Tk_PathCanvas canvas, /* Info about overall canvas widget. */ + Tk_PathItem *itemPtr, /* Item that is being deleted. */ + Display *display) /* Display containing window for canvas. */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + + Tk_FreeTextLayout(textPtr->textLayout); + if (textPtr->gc != None) { + Tk_FreeGC(display, textPtr->gc); + } + if (textPtr->selTextGC != None) { + Tk_FreeGC(display, textPtr->selTextGC); + } + if (textPtr->cursorOffGC != None) { + Tk_FreeGC(display, textPtr->cursorOffGC); + } + Tk_FreeConfigOptions((char *) itemPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +/* + *-------------------------------------------------------------- + * + * ComputeTextBbox -- + * + * This function is invoked to compute the bounding box of all the pixels + * that may be drawn as part of a text item. In addition, it recomputes + * all of the geometry information used to display a text item or check + * for mouse hits. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header for itemPtr, + * and the linePtr structure is regenerated for itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +ComputeTextBbox( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + TextItem *textPtr) /* Item whose bbox is to be recomputed. */ +{ + Tk_PathCanvasTextInfo *textInfoPtr; + int leftX, topY, width, height, fudge; + Tk_PathState state = textPtr->header.state; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + Tk_FreeTextLayout(textPtr->textLayout); + textPtr->textLayout = Tk_ComputeTextLayout(textPtr->tkfont, + textPtr->text, textPtr->numChars, textPtr->width, + textPtr->justify, 0, &width, &height); + + if (state == TK_PATHSTATE_HIDDEN || textPtr->color == NULL) { + width = height = 0; + } + + /* + * Use overall geometry information to compute the top-left corner of the + * bounding box for the text item. + */ + + leftX = (int) floor(textPtr->x + 0.5); + topY = (int) floor(textPtr->y + 0.5); + switch (textPtr->anchor) { + case TK_ANCHOR_NW: + case TK_ANCHOR_N: + case TK_ANCHOR_NE: + break; + + case TK_ANCHOR_W: + case TK_ANCHOR_CENTER: + case TK_ANCHOR_E: + topY -= height / 2; + break; + + case TK_ANCHOR_SW: + case TK_ANCHOR_S: + case TK_ANCHOR_SE: + topY -= height; + break; + } + switch (textPtr->anchor) { + case TK_ANCHOR_NW: + case TK_ANCHOR_W: + case TK_ANCHOR_SW: + break; + + case TK_ANCHOR_N: + case TK_ANCHOR_CENTER: + case TK_ANCHOR_S: + leftX -= width / 2; + break; + + case TK_ANCHOR_NE: + case TK_ANCHOR_E: + case TK_ANCHOR_SE: + leftX -= width; + break; + } + + textPtr->leftEdge = leftX; + textPtr->rightEdge = leftX + width; + + /* + * Last of all, update the bounding box for the item. The item's bounding + * box includes the bounding box of all its lines, plus an extra fudge + * factor for the cursor border (which could potentially be quite large). + */ + + textInfoPtr = textPtr->textInfoPtr; + fudge = (textInfoPtr->insertWidth + 1) / 2; + if (textInfoPtr->selBorderWidth > fudge) { + fudge = textInfoPtr->selBorderWidth; + } + textPtr->header.x1 = leftX - fudge; + textPtr->header.y1 = topY; + textPtr->header.x2 = leftX + width + fudge; + textPtr->header.y2 = topY + height; +} + +/* + *-------------------------------------------------------------- + * + * DisplayCanvText -- + * + * This function is invoked to draw a text item in a given drawable. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation information in + * canvas. + * + *-------------------------------------------------------------- + */ + +static void +DisplayCanvText( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + Tk_PathItem *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, int y, int width, int height) + /* Describes region of canvas that must be + * redisplayed (not used). */ +{ + TextItem *textPtr; + Tk_PathCanvasTextInfo *textInfoPtr; + int selFirstChar, selLastChar; + short drawableX, drawableY; + Pixmap stipple; + Tk_PathState state = itemPtr->state; + + textPtr = (TextItem *) itemPtr; + textInfoPtr = textPtr->textInfoPtr; + + if(state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + stipple = textPtr->stipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (textPtr->activeStipple!=None) { + stipple = textPtr->activeStipple; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (textPtr->disabledStipple!=None) { + stipple = textPtr->disabledStipple; + } + } + + if (textPtr->gc == None) { + return; + } + + /* + * 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 (stipple != None) { + Tk_PathCanvasSetOffset(canvas, textPtr->gc, textPtr->tsoffsetPtr); + } + + selFirstChar = -1; + selLastChar = 0; /* lint. */ + + if (textInfoPtr->selItemPtr == itemPtr) { + selFirstChar = textInfoPtr->selectFirst; + selLastChar = textInfoPtr->selectLast; + if (selLastChar > textPtr->numChars) { + selLastChar = textPtr->numChars - 1; + } + if ((selFirstChar >= 0) && (selFirstChar <= selLastChar)) { + int xFirst, yFirst, hFirst; + int xLast, yLast, wLast; + + /* + * Draw a special background under the selection. + */ + + Tk_CharBbox(textPtr->textLayout, selFirstChar, &xFirst, &yFirst, + NULL, &hFirst); + Tk_CharBbox(textPtr->textLayout, selLastChar, &xLast, &yLast, + &wLast, NULL); + + /* + * If the selection spans the end of this line, then display + * selection background all the way to the end of the line. + * However, for the last line we only want to display up to the + * last character, not the end of the line. + */ + + x = xFirst; + height = hFirst; + for (y = yFirst ; y <= yLast; y += height) { + if (y == yLast) { + width = xLast + wLast - x; + } else { + width = textPtr->rightEdge - textPtr->leftEdge - x; + } + Tk_PathCanvasDrawableCoords(canvas, + (double) (textPtr->leftEdge + x + - textInfoPtr->selBorderWidth), + (double) (textPtr->header.y1 + y), + &drawableX, &drawableY); + Tk_Fill3DRectangle(Tk_PathCanvasTkwin(canvas), drawable, + textInfoPtr->selBorder, drawableX, drawableY, + width + 2 * textInfoPtr->selBorderWidth, + height, textInfoPtr->selBorderWidth, TK_RELIEF_RAISED); + x = 0; + } + } + } + + /* + * If the insertion point should be displayed, then draw a special + * background for the cursor before drawing the text. Note: if we're the + * cursor item but the cursor is turned off, then redraw background over + * the area of the cursor. This guarantees that the selection won't make + * the cursor invisible on mono displays, where both are drawn in the same + * color. + */ + + if ((textInfoPtr->focusItemPtr == itemPtr) && (textInfoPtr->gotFocus)) { + if (Tk_CharBbox(textPtr->textLayout, textPtr->insertPos, + &x, &y, NULL, &height)) { + Tk_PathCanvasDrawableCoords(canvas, + (double) (textPtr->leftEdge + x + - (textInfoPtr->insertWidth / 2)), + (double) (textPtr->header.y1 + y), + &drawableX, &drawableY); + Tk_SetCaretPos(Tk_PathCanvasTkwin(canvas), drawableX, drawableY, + height); + if (textInfoPtr->cursorOn) { + Tk_Fill3DRectangle(Tk_PathCanvasTkwin(canvas), drawable, + textInfoPtr->insertBorder, + drawableX, drawableY, + textInfoPtr->insertWidth, height, + textInfoPtr->insertBorderWidth, TK_RELIEF_RAISED); + } else if (textPtr->cursorOffGC != None) { + /* + * Redraw the background over the area of the cursor, even + * though the cursor is turned off. This guarantees that the + * selection won't make the cursor invisible on mono displays, + * where both may be drawn in the same color. + */ + + XFillRectangle(display, drawable, textPtr->cursorOffGC, + drawableX, drawableY, + (unsigned) textInfoPtr->insertWidth, + (unsigned) height); + } + } + } + + /* + * If there is no selected text or the selected text foreground is the + * same as the regular text foreground, then draw one text string. If + * there is selected text and the foregrounds differ, draw the regular + * text up to the selection, draw the selection, then draw the rest of the + * regular text. Drawing the regular text and then the selected text over + * it would causes problems with anti-aliased text because the two + * anti-aliasing colors would blend together. + */ + + Tk_PathCanvasDrawableCoords(canvas, (double) textPtr->leftEdge, + (double) textPtr->header.y1, &drawableX, &drawableY); + + if ((selFirstChar >= 0) && (textPtr->selTextGC != textPtr->gc)) { + Tk_DrawTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, + drawableX, drawableY, 0, selFirstChar); + Tk_DrawTextLayout(display, drawable, textPtr->selTextGC, + textPtr->textLayout, drawableX, drawableY, selFirstChar, + selLastChar + 1); + Tk_DrawTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, + drawableX, drawableY, selLastChar + 1, -1); + } else { + Tk_DrawTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, + drawableX, drawableY, 0, -1); + } + Tk_UnderlineTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, + drawableX, drawableY, textPtr->underline); + + if (stipple != None) { + XSetTSOrigin(display, textPtr->gc, 0, 0); + } +} + +/* + *-------------------------------------------------------------- + * + * TextInsert -- + * + * Insert characters into a text item at a given position. + * + * Results: + * None. + * + * Side effects: + * The text in the given item is modified. The cursor and selection + * positions are also modified to reflect the insertion. + * + *-------------------------------------------------------------- + */ + +static void +TextInsert( + Tk_PathCanvas canvas, /* Canvas containing text item. */ + Tk_PathItem *itemPtr, /* Text item to be modified. */ + int index, /* Character index before which string is to + * be inserted. */ + char *string) /* New characters to be inserted. */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + int byteIndex, byteCount, charsAdded; + char *newStr, *text; + Tk_PathCanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; + + string = Tcl_GetStringFromObj((Tcl_Obj *) string, &byteCount); + + text = textPtr->text; + + if (index < 0) { + index = 0; + } + if (index > textPtr->numChars) { + index = textPtr->numChars; + } + byteIndex = Tcl_UtfAtIndex(text, index) - text; + byteCount = (int) strlen(string); + if (byteCount == 0) { + return; + } + + newStr = (char *) ckalloc((unsigned) textPtr->numBytes + byteCount + 1); + memcpy(newStr, text, (size_t) byteIndex); + strcpy(newStr + byteIndex, string); + strcpy(newStr + byteIndex + byteCount, text + byteIndex); + + ckfree(text); + textPtr->text = newStr; + charsAdded = Tcl_NumUtfChars(string, byteCount); + textPtr->numChars += charsAdded; + textPtr->numBytes += byteCount; + + /* + * Inserting characters invalidates indices such as those for the + * selection and cursor. Update the indices appropriately. + */ + + if (textInfoPtr->selItemPtr == itemPtr) { + if (textInfoPtr->selectFirst >= index) { + textInfoPtr->selectFirst += charsAdded; + } + if (textInfoPtr->selectLast >= index) { + textInfoPtr->selectLast += charsAdded; + } + if ((textInfoPtr->anchorItemPtr == itemPtr) + && (textInfoPtr->selectAnchor >= index)) { + textInfoPtr->selectAnchor += charsAdded; + } + } + if (textPtr->insertPos >= index) { + textPtr->insertPos += charsAdded; + } + ComputeTextBbox(canvas, textPtr); +} + +/* + *-------------------------------------------------------------- + * + * TextDeleteChars -- + * + * Delete one or more characters from a text item. + * + * Results: + * None. + * + * Side effects: + * Characters between "first" and "last", inclusive, get deleted from + * itemPtr, and things like the selection position get updated. + * + *-------------------------------------------------------------- + */ + +static void +TextDeleteChars( + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Item in which to delete characters. */ + int first, /* Character index of first character to + * delete. */ + int last) /* Character index of last character to delete + * (inclusive). */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + int byteIndex, byteCount, charsRemoved; + char *newStr, *text; + Tk_PathCanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; + + text = textPtr->text; + if (first < 0) { + first = 0; + } + if (last >= textPtr->numChars) { + last = textPtr->numChars - 1; + } + if (first > last) { + return; + } + charsRemoved = last + 1 - first; + + byteIndex = Tcl_UtfAtIndex(text, first) - text; + byteCount = Tcl_UtfAtIndex(text + byteIndex, charsRemoved) + - (text + byteIndex); + + newStr = (char *) ckalloc((unsigned) (textPtr->numBytes + 1 - byteCount)); + memcpy(newStr, text, (size_t) byteIndex); + strcpy(newStr + byteIndex, text + byteIndex + byteCount); + + ckfree(text); + textPtr->text = newStr; + textPtr->numChars -= charsRemoved; + textPtr->numBytes -= byteCount; + + /* + * Update indexes for the selection and cursor to reflect the renumbering + * of the remaining characters. + */ + + if (textInfoPtr->selItemPtr == itemPtr) { + if (textInfoPtr->selectFirst > first) { + textInfoPtr->selectFirst -= charsRemoved; + if (textInfoPtr->selectFirst < first) { + textInfoPtr->selectFirst = first; + } + } + if (textInfoPtr->selectLast >= first) { + textInfoPtr->selectLast -= charsRemoved; + if (textInfoPtr->selectLast < first - 1) { + textInfoPtr->selectLast = first - 1; + } + } + if (textInfoPtr->selectFirst > textInfoPtr->selectLast) { + textInfoPtr->selItemPtr = NULL; + } + if ((textInfoPtr->anchorItemPtr == itemPtr) + && (textInfoPtr->selectAnchor > first)) { + textInfoPtr->selectAnchor -= charsRemoved; + if (textInfoPtr->selectAnchor < first) { + textInfoPtr->selectAnchor = first; + } + } + } + if (textPtr->insertPos > first) { + textPtr->insertPos -= charsRemoved; + if (textPtr->insertPos < first) { + textPtr->insertPos = first; + } + } + ComputeTextBbox(canvas, textPtr); + return; +} + +/* + *-------------------------------------------------------------- + * + * TextToPoint -- + * + * Computes the distance from a given point to a given text item, 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 text item. If the point + * isn't inside the text item then the return value is the distance from + * the point to the text item. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static double +TextToPoint( + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + double *pointPtr) /* Pointer to x and y coordinates. */ +{ + TextItem *textPtr; + Tk_PathState state = itemPtr->state; + double value; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + textPtr = (TextItem *) itemPtr; + value = (double) Tk_DistanceToTextLayout(textPtr->textLayout, + (int) pointPtr[0] - textPtr->leftEdge, + (int) pointPtr[1] - textPtr->header.y1); + + if ((state == TK_PATHSTATE_HIDDEN) || (textPtr->color == NULL) || + (textPtr->text == NULL) || (*textPtr->text == 0)) { + value = 1.0e36; + } + return value; +} + +/* + *-------------------------------------------------------------- + * + * TextToArea -- + * + * This function is called to determine whether an item lies entirely + * inside, entirely outside, or overlapping a given rectangle. + * + * Results: + * -1 is returned if the item is entirely outside the area given by + * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given + * area. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +TextToArea( + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Item to check against rectangle. */ + double *rectPtr) /* Pointer to array of four coordinates + * (x1,y1,x2,y2) describing rectangular + * area. */ +{ + TextItem *textPtr; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + textPtr = (TextItem *) itemPtr; + return Tk_IntersectTextLayout(textPtr->textLayout, + (int) (rectPtr[0] + 0.5) - textPtr->leftEdge, + (int) (rectPtr[1] + 0.5) - textPtr->header.y1, + (int) (rectPtr[2] - rectPtr[0] + 0.5), + (int) (rectPtr[3] - rectPtr[1] + 0.5)); +} + +/* + *-------------------------------------------------------------- + * + * ScaleText -- + * + * This function is invoked to rescale a text item. + * + * Results: + * None. + * + * Side effects: + * Scales the position of the text, but not the size of the font for the + * text. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static void +ScaleText( + Tk_PathCanvas canvas, /* Canvas containing rectangle. */ + Tk_PathItem *itemPtr, /* Rectangle to be scaled. */ + double originX, double originY, + /* Origin about which to scale rect. */ + double scaleX, /* Amount to scale in X direction. */ + double scaleY) /* Amount to scale in Y direction. */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + + textPtr->x = originX + scaleX*(textPtr->x - originX); + textPtr->y = originY + scaleY*(textPtr->y - originY); + ComputeTextBbox(canvas, textPtr); + return; +} + +/* + *-------------------------------------------------------------- + * + * TranslateText -- + * + * This function is called to move a text item by a given amount. + * + * Results: + * None. + * + * Side effects: + * The position of the text item is offset by (xDelta, yDelta), and the + * bounding box is updated in the generic part of the item structure. + * + *-------------------------------------------------------------- + */ + +static void +TranslateText( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item that is being moved. */ + double deltaX, double deltaY) + /* Amount by which item is to be moved. */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + + textPtr->x += deltaX; + textPtr->y += deltaY; + ComputeTextBbox(canvas, textPtr); +} + +/* + *-------------------------------------------------------------- + * + * GetTextIndex -- + * + * Parse an index into a text item and return either its value or an + * error. + * + * Results: + * A standard Tcl result. If all went well, then *indexPtr is filled in + * with the index (into itemPtr) corresponding to string. Otherwise an + * error message is left in the interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetTextIndex( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item for which the index is being + * specified. */ + Tcl_Obj *obj, /* Specification of a particular character in + * itemPtr's text. */ + int *indexPtr) /* Where to store converted character + * index. */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + int length; + int c; + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + Tk_PathCanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; + char *string = Tcl_GetStringFromObj(obj, &length); + + c = string[0]; + + if ((c == 'e') && (strncmp(string, "end", (unsigned) length) == 0)) { + *indexPtr = textPtr->numChars; + } else if ((c == 'i') + && (strncmp(string, "insert", (unsigned) length) == 0)) { + *indexPtr = textPtr->insertPos; + } else if ((c == 's') && (length >= 5) + && (strncmp(string, "sel.first", (unsigned) length) == 0)) { + if (textInfoPtr->selItemPtr != itemPtr) { + Tcl_SetResult(interp, "selection isn't in item", TCL_STATIC); + return TCL_ERROR; + } + *indexPtr = textInfoPtr->selectFirst; + } else if ((c == 's') && (length >= 5) + && (strncmp(string, "sel.last", (unsigned) length) == 0)) { + if (textInfoPtr->selItemPtr != itemPtr) { + Tcl_SetResult(interp, "selection isn't in item", TCL_STATIC); + return TCL_ERROR; + } + *indexPtr = textInfoPtr->selectLast; + } else if (c == '@') { + int x, y; + double tmp; + char *end, *p; + + p = string+1; + tmp = strtod(p, &end); + if ((end == p) || (*end != ',')) { + goto badIndex; + } + x = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5); + p = end+1; + tmp = strtod(p, &end); + if ((end == p) || (*end != 0)) { + goto badIndex; + } + y = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5); + *indexPtr = Tk_PointToChar(textPtr->textLayout, + x + canvasPtr->scrollX1 - textPtr->leftEdge, + y + canvasPtr->scrollY1 - textPtr->header.y1); + } else if (Tcl_GetIntFromObj(NULL, obj, indexPtr) == TCL_OK) { + if (*indexPtr < 0){ + *indexPtr = 0; + } else if (*indexPtr > textPtr->numChars) { + *indexPtr = textPtr->numChars; + } + } else { + /* + * Some of the paths here leave messages in the interp's result, so we + * have to clear it out before storing our own message. + */ + + badIndex: + Tcl_SetResult(interp, NULL, TCL_STATIC); + Tcl_AppendResult(interp, "bad index \"", string, "\"", NULL); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * SetTextCursor -- + * + * Set the position of the insertion cursor in this item. + * + * Results: + * None. + * + * Side effects: + * The cursor position will change. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static void +SetTextCursor( + Tk_PathCanvas canvas, /* Record describing canvas widget. */ + Tk_PathItem *itemPtr, /* Text item in which cursor position is to be + * set. */ + int index) /* Character index of character just before + * which cursor is to be positioned. */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + + if (index < 0) { + textPtr->insertPos = 0; + } else if (index > textPtr->numChars) { + textPtr->insertPos = textPtr->numChars; + } else { + textPtr->insertPos = index; + } +} + +/* + *-------------------------------------------------------------- + * + * GetSelText -- + * + * This function is invoked to return the selected portion of a text + * item. It is only called when this item has the selection. + * + * 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 +GetSelText( + Tk_PathCanvas canvas, /* Canvas containing selection. */ + Tk_PathItem *itemPtr, /* Text item containing selection. */ + int offset, /* Byte 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. */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + int byteCount; + char *text; + CONST char *selStart, *selEnd; + Tk_PathCanvasTextInfo *textInfoPtr = textPtr->textInfoPtr; + + if ((textInfoPtr->selectFirst < 0) || + (textInfoPtr->selectFirst > textInfoPtr->selectLast)) { + return 0; + } + text = textPtr->text; + selStart = Tcl_UtfAtIndex(text, textInfoPtr->selectFirst); + selEnd = Tcl_UtfAtIndex(selStart, + textInfoPtr->selectLast + 1 - textInfoPtr->selectFirst); + byteCount = selEnd - selStart - offset; + if (byteCount > maxBytes) { + byteCount = maxBytes; + } + if (byteCount <= 0) { + return 0; + } + memcpy(buffer, selStart + offset, (size_t) byteCount); + buffer[byteCount] = '\0'; + return byteCount; +} + +/* + *-------------------------------------------------------------- + * + * TextToPostscript -- + * + * This function is called to generate Postscript for text items. + * + * Results: + * The return value is a standard Tcl result. If an error occurs in + * generating Postscript then an error message is left in the interp's + * 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 +TextToPostscript( + Tcl_Interp *interp, /* Leave Postscript or error message here. */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + Tk_PathItem *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. */ +{ + TextItem *textPtr = (TextItem *) itemPtr; + int x, y; + Tk_FontMetrics fm; + char *justify; + char buffer[500]; + XColor *color; + Pixmap stipple; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + color = textPtr->color; + stipple = textPtr->stipple; + if (state == TK_PATHSTATE_HIDDEN || textPtr->color == NULL || + textPtr->text == NULL || *textPtr->text == 0) { + return TCL_OK; + } else if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (textPtr->activeColor!=NULL) { + color = textPtr->activeColor; + } + if (textPtr->activeStipple!=None) { + stipple = textPtr->activeStipple; + } + } else if (state==TK_PATHSTATE_DISABLED) { + if (textPtr->disabledColor!=NULL) { + color = textPtr->disabledColor; + } + if (textPtr->disabledStipple!=None) { + stipple = textPtr->disabledStipple; + } + } + + if (Tk_PathCanvasPsFont(interp, canvas, textPtr->tkfont) != TCL_OK) { + return TCL_ERROR; + } + if (prepass != 0) { + return TCL_OK; + } + if (Tk_PathCanvasPsColor(interp, canvas, color) != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "/StippleText {\n ", NULL); + Tk_PathCanvasPsStipple(interp, canvas, stipple); + Tcl_AppendResult(interp, "} bind def\n", NULL); + } + + sprintf(buffer, "%.15g %.15g [\n", textPtr->x, + Tk_PathCanvasPsY(canvas, textPtr->y)); + Tcl_AppendResult(interp, buffer, NULL); + + Tk_TextLayoutToPostscript(interp, textPtr->textLayout); + + x = 0; y = 0; justify = NULL; /* lint. */ + switch (textPtr->anchor) { + case TK_ANCHOR_NW: x = 0; y = 0; break; + case TK_ANCHOR_N: x = 1; y = 0; break; + case TK_ANCHOR_NE: x = 2; y = 0; break; + case TK_ANCHOR_E: x = 2; y = 1; break; + case TK_ANCHOR_SE: x = 2; y = 2; break; + case TK_ANCHOR_S: x = 1; y = 2; break; + case TK_ANCHOR_SW: x = 0; y = 2; break; + case TK_ANCHOR_W: x = 0; y = 1; break; + case TK_ANCHOR_CENTER: x = 1; y = 1; break; + } + switch (textPtr->justify) { + case TK_JUSTIFY_LEFT: justify = "0"; break; + case TK_JUSTIFY_CENTER: justify = "0.5"; break; + case TK_JUSTIFY_RIGHT: justify = "1"; break; + } + + Tk_GetFontMetrics(textPtr->tkfont, &fm); + sprintf(buffer, "] %d %g %g %s %s DrawText\n", + fm.linespace, x / -2.0, y / 2.0, justify, + ((stipple == None) ? "false" : "true")); + Tcl_AppendResult(interp, buffer, NULL); + + return TCL_OK; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/pd/tkpath/generic/tkpCanvUtil.c b/pd/tkpath/generic/tkpCanvUtil.c new file mode 100644 index 0000000000000000000000000000000000000000..5f5f1557425e1cb0176155cab6c4f755e22f6d95 --- /dev/null +++ b/pd/tkpath/generic/tkpCanvUtil.c @@ -0,0 +1,2237 @@ +/* + * tkpCanvUtil.c -- + * + * This file contains a collection of utility functions used by the + * implementations of various canvas item types. + * + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvUtil.c,v 1.13 2010/03/10 22:47:37 petasis Exp $ + */ + +#include "tkInt.h" +#include "tkpCanvas.h" +#include "tkIntPath.h" +#include "tkPathStyle.h" +#include <assert.h> + +/* + * Structures defined only in this file. + */ + +typedef struct SmoothAssocData { + struct SmoothAssocData *nextPtr; + /* Pointer to next SmoothAssocData. */ + Tk_PathSmoothMethod smooth; /* Name and functions associated with this + * option. */ +} SmoothAssocData; + +Tk_PathSmoothMethod tkPathBezierSmoothMethod = { + "true", + TkPathMakeBezierCurve, + (void (*) (Tcl_Interp *interp, Tk_PathCanvas canvas, double *coordPtr, + int numPoints, int numSteps)) TkPathMakeBezierPostscript, +}; +static Tk_PathSmoothMethod tkPathRawSmoothMethod = { + "raw", + TkPathMakeRawCurve, + (void (*) (Tcl_Interp *interp, Tk_PathCanvas canvas, double *coordPtr, + int numPoints, int numSteps)) TkPathMakeRawCurvePostscript, +}; + +/* + * Function forward-declarations. + */ + +static void SmoothMethodCleanupProc(ClientData clientData, + Tcl_Interp *interp); +static SmoothAssocData * InitSmoothMethods(Tcl_Interp *interp); +static int FindSmoothMethod(Tcl_Interp *interp, Tcl_Obj *valueObj, + Tk_PathSmoothMethod **smoothPtr); +static int DashConvert(char *l, CONST char *p, int n, + double width); +static void TranslateAndAppendCoords(TkPathCanvas *canvPtr, + double x, double y, XPoint *outArr, int numOut); + +static Tk_Dash * TkDashNew(Tcl_Interp *interp, Tcl_Obj *dashObj); +static void TkDashFree(Tk_Dash *dashPtr); + +#ifndef ABS +# define ABS(a) (((a) >= 0) ? (a) : -1*(a)) +#endif + +/* + *---------------------------------------------------------------------- + * + * Tk_PathCanvasTkwin -- + * + * Given a token for a canvas, this function returns the widget that + * represents the canvas. + * + * Results: + * The return value is a handle for the widget. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tk_Window +Tk_PathCanvasTkwin( + Tk_PathCanvas canvas) /* Token for the canvas. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + return canvasPtr->tkwin; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_PathCanvasDrawableCoords -- + * + * Given an (x,y) coordinate pair within a canvas, this function + * returns the corresponding coordinates at which the point should + * be drawn in the drawable used for display. + * + * Results: + * There is no return value. The values at *drawableXPtr and + * *drawableYPtr are filled in with the coordinates at which x and y + * should be drawn. These coordinates are clipped to fit within a + * "short", since this is what X uses in most cases for drawing. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tk_PathCanvasDrawableCoords( + Tk_PathCanvas canvas, /* Token for the canvas. */ + double x, /* Coordinates in canvas space. */ + double y, + short *drawableXPtr, /* Screen coordinates are stored here. */ + short *drawableYPtr) +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + double tmp; + + tmp = x - canvasPtr->drawableXOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + if (tmp > 32767) { + *drawableXPtr = 32767; + } else if (tmp < -32768) { + *drawableXPtr = -32768; + } else { + *drawableXPtr = (short) tmp; + } + + tmp = y - canvasPtr->drawableYOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + if (tmp > 32767) { + *drawableYPtr = 32767; + } else if (tmp < -32768) { + *drawableYPtr = -32768; + } else { + *drawableYPtr = (short) tmp; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_PathCanvasWindowCoords -- + * + * Given an (x,y) coordinate pair within a canvas, this function returns + * the corresponding coordinates in the canvas's window. + * + * Results: + * There is no return value. The values at *screenXPtr and *screenYPtr + * are filled in with the coordinates at which (x,y) appears in the + * canvas's window. These coordinates are clipped to fit within a + * "short", since this is what X uses in most cases for drawing. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tk_PathCanvasWindowCoords( + Tk_PathCanvas canvas, /* Token for the canvas. */ + double x, /* Coordinates in canvas space. */ + double y, + short *screenXPtr, /* Screen coordinates are stored here. */ + short *screenYPtr) +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + double tmp; + + tmp = x - canvasPtr->xOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + if (tmp > 32767) { + *screenXPtr = 32767; + } else if (tmp < -32768) { + *screenXPtr = -32768; + } else { + *screenXPtr = (short) tmp; + } + + tmp = y - canvasPtr->yOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + if (tmp > 32767) { + *screenYPtr = 32767; + } else if (tmp < -32768) { + *screenYPtr = -32768; + } else { + *screenYPtr = (short) tmp; + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasGetCoord -- + * + * Given a string, returns a floating-point canvas coordinate + * corresponding to that string. + * + * Results: + * The return value is a standard Tcl return result. If TCL_OK is + * returned, then everything went well and the canvas coordinate is + * stored at *doublePtr; otherwise TCL_ERROR is returned and an error + * message is left in the interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathCanvasGetCoord( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas to which coordinate applies. */ + CONST char *string, /* Describes coordinate (any screen coordinate + * form may be used here). */ + double *doublePtr) /* Place to store converted coordinate. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + + if (Tk_GetScreenMM(canvasPtr->interp, canvasPtr->tkwin, string, + doublePtr) != TCL_OK) { + return TCL_ERROR; + } + *doublePtr *= canvasPtr->pixelsPerMM; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasGetCoordFromObj -- + * + * Given a string, returns a floating-point canvas coordinate + * corresponding to that string. + * + * Results: + * The return value is a standard Tcl return result. If TCL_OK is + * returned, then everything went well and the canvas coordinate is + * stored at *doublePtr; otherwise TCL_ERROR is returned and an error + * message is left in interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathCanvasGetCoordFromObj( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas to which coordinate applies. */ + Tcl_Obj *obj, /* Describes coordinate (any screen coordinate + * form may be used here). */ + double *doublePtr) /* Place to store converted coordinate. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + + if (Tk_GetMMFromObj(canvasPtr->interp, canvasPtr->tkwin, obj, + doublePtr) != TCL_OK) { + return TCL_ERROR; + } + *doublePtr *= canvasPtr->pixelsPerMM; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_PathCanvasSetStippleOrigin -- + * + * This function sets the stipple origin in a graphics context so that + * stipples drawn with the GC will line up with other stipples previously + * drawn in the canvas. + * + * Results: + * None. + * + * Side effects: + * The graphics context is modified. + * + *---------------------------------------------------------------------- + */ + +void +Tk_PathCanvasSetStippleOrigin( + Tk_PathCanvas canvas, /* Token for a canvas. */ + GC gc) /* Graphics context that is about to be used + * to draw a stippled pattern as part of + * redisplaying the canvas. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + + XSetTSOrigin(canvasPtr->display, gc, -canvasPtr->drawableXOrigin, + -canvasPtr->drawableYOrigin); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_PathCanvasSetOffset -- + * + * This function sets the stipple offset in a graphics context so that + * stipples drawn with the GC will line up with other stipples with the + * same offset. + * + * Results: + * None. + * + * Side effects: + * The graphics context is modified. + * + *---------------------------------------------------------------------- + */ + +void +Tk_PathCanvasSetOffset( + Tk_PathCanvas canvas, /* Token for a canvas. */ + GC gc, /* Graphics context that is about to be used + * to draw a stippled pattern as part of + * redisplaying the canvas. */ + Tk_TSOffset *offset) /* Offset (may be NULL pointer)*/ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + int flags = 0; + int x = - canvasPtr->drawableXOrigin; + int y = - canvasPtr->drawableYOrigin; + + if (offset != NULL) { + flags = offset->flags; + x += offset->xoffset; + y += offset->yoffset; + } + if ((flags & TK_OFFSET_RELATIVE) && !(flags & TK_OFFSET_INDEX)) { + Tk_SetTSOrigin(canvasPtr->tkwin, gc, x - canvasPtr->xOrigin, + y - canvasPtr->yOrigin); + } else { + XSetTSOrigin(canvasPtr->display, gc, x, y); + } +} + +int +TkPathCanvasGetDepth(Tk_PathItem *itemPtr) +{ + int depth = 0; + Tk_PathItem *walkPtr = itemPtr; + + while (walkPtr->parentPtr != NULL) { + depth++; + walkPtr = walkPtr->parentPtr; + } + return depth; +} + +/* + *---------------------------------------------------------------------- + * + * TkPathCanvasInheritStyle -- + * + * This function returns the style which is inherited from the + * parents of the itemPtr using cascading from the root item. + * Must use TkPathCanvasFreeInheritedStyle when done. + * + * Results: + * Tk_PathStyle. + * + * Side effects: + * May allocate memory for matrix. + * + *---------------------------------------------------------------------- + */ + +Tk_PathStyle +TkPathCanvasInheritStyle(Tk_PathItem *itemPtr, long flags) +{ + int depth, i, anyMatrix = 0; + Tk_PathItem *walkPtr; + Tk_PathItemEx *itemExPtr; + Tk_PathItemEx **parents; + Tk_PathStyle style; + TMatrix matrix = kPathUnitTMatrix; + + depth = TkPathCanvasGetDepth(itemPtr); + parents = (Tk_PathItemEx **) ckalloc(depth*sizeof(Tk_PathItemEx *)); + + walkPtr = itemPtr, i = 0; + while (walkPtr->parentPtr != NULL) { + parents[i] = (Tk_PathItemEx *) walkPtr->parentPtr; + walkPtr = walkPtr->parentPtr, i++; + } + + /* + * Cascade the style from the root item to the closest parent. + * Start by just making a copy of the root's style. + */ + itemExPtr = parents[depth-1]; + style = itemExPtr->style; + + for (i = depth-1; i >= 0; i--) { + itemExPtr = parents[i]; + + /* The order of these two merges decides which take precedence. */ + if (i < depth-1) { + TkPathStyleMergeStyles(&itemExPtr->style, &style, flags); + } + if (itemExPtr->styleInst != NULL) { + TkPathStyleMergeStyles(itemExPtr->styleInst->masterPtr, &style, flags); + } + if (style.matrixPtr != NULL) { + anyMatrix = 1; + MMulTMatrix(style.matrixPtr, &matrix); + } + /* + * We set matrix to NULL to detect if set in group. + */ + style.matrixPtr = NULL; + } + + /* + * Merge the parents style with the actual items style. + * The order of these two merges decides which take precedence. + */ + itemExPtr = (Tk_PathItemEx *) itemPtr; + TkPathStyleMergeStyles(&itemExPtr->style, &style, flags); + if (itemExPtr->styleInst != NULL) { + TkPathStyleMergeStyles(itemExPtr->styleInst->masterPtr, &style, flags); + } + if (style.matrixPtr != NULL) { + anyMatrix = 1; + MMulTMatrix(style.matrixPtr, &matrix); + } + if (anyMatrix) { + style.matrixPtr = (TMatrix *) ckalloc(sizeof(TMatrix)); + memcpy(style.matrixPtr, &matrix, sizeof(TMatrix)); + } + ckfree((char *) parents); + return style; +} + +void +TkPathCanvasFreeInheritedStyle(Tk_PathStyle *stylePtr) +{ + if (stylePtr->matrixPtr != NULL) { + ckfree((char *) stylePtr->matrixPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkPathCanvasInheritTMatrix -- + * + * Does the same job as TkPathCanvasInheritStyle but for the + * TMatrix only. No memory allocated. + * Note that we don't do the last step of concatenating the items + * own TMatrix since that depends on its specific storage. + * + * Results: + * TMatrix. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TMatrix +TkPathCanvasInheritTMatrix(Tk_PathItem *itemPtr) +{ + int depth, i; + Tk_PathItem *walkPtr; + Tk_PathItemEx *itemExPtr; + Tk_PathItemEx **parents; + Tk_PathStyle *stylePtr; + TMatrix matrix = kPathUnitTMatrix, *matrixPtr = NULL; + + depth = TkPathCanvasGetDepth(itemPtr); + parents = (Tk_PathItemEx **) ckalloc(depth*sizeof(Tk_PathItemEx *)); + + walkPtr = itemPtr, i = 0; + while (walkPtr->parentPtr != NULL) { + parents[i] = (Tk_PathItemEx *) walkPtr->parentPtr; + walkPtr = walkPtr->parentPtr, i++; + } + + for (i = depth-1; i >= 0; i--) { + itemExPtr = parents[i]; + + /* The order of these two merges decides which take precedence. */ + matrixPtr = itemExPtr->style.matrixPtr; + if (itemExPtr->styleInst != NULL) { + stylePtr = itemExPtr->styleInst->masterPtr; + if (stylePtr->mask & PATH_STYLE_OPTION_MATRIX) { + matrixPtr = stylePtr->matrixPtr; + } + } + if (matrixPtr != NULL) { + MMulTMatrix(matrixPtr, &matrix); + } + } + ckfree((char *) parents); + return matrix; +} + +/* TkPathCanvasGradientTable etc.: this is just accessor functions to hide + the internals of the TkPathCanvas */ + +Tcl_HashTable * +TkPathCanvasGradientTable(Tk_PathCanvas canvas) +{ + return &((TkPathCanvas *)canvas)->gradientTable; +} + +Tcl_HashTable * +TkPathCanvasStyleTable(Tk_PathCanvas canvas) +{ + return &((TkPathCanvas *)canvas)->styleTable; +} + +Tk_PathState +TkPathCanvasState(Tk_PathCanvas canvas) +{ + return ((TkPathCanvas *)canvas)->canvas_state; +} + +Tk_PathItem * +TkPathCanvasCurrentItem(Tk_PathCanvas canvas) +{ + return ((TkPathCanvas *)canvas)->currentItemPtr; +} + +Tk_PathItem * +TkPathCanvasParentItem(Tk_PathItem *itemPtr) +{ + return itemPtr->parentPtr; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_PathCanvasGetTextInfo -- + * + * This function returns a pointer to a structure containing information + * about the selection and insertion cursor for a canvas widget. Items + * such as text items save the pointer and use it to share access to the + * information with the generic canvas code. + * + * Results: + * The return value is a pointer to the structure holding text + * information for the canvas. Most of the fields should not be modified + * outside the generic canvas code; see the user documentation for + * details. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tk_PathCanvasTextInfo * +Tk_PathCanvasGetTextInfo( + Tk_PathCanvas canvas) /* Token for the canvas widget. */ +{ + return &((TkPathCanvas *) canvas)->textInfo; +} + +/* + *---------------------------------------------------------------------- + * + * TkPathAllocTagsFromObj -- + * + * Create a new Tk_PathTags record and fill it with a tag object list. + * + * Results: + * A pointer to Tk_PathTags record or NULL if failed. + * + * Side effects: + * New Tk_PathTags possibly allocated. + * + *---------------------------------------------------------------------- + */ + +Tk_PathTags * +TkPathAllocTagsFromObj( + Tcl_Interp *interp, + Tcl_Obj *valuePtr) /* If NULL we just create an empty Tk_PathTags struct. */ +{ + Tk_PathTags *tagsPtr; + int objc, i, len; + Tcl_Obj **objv; + + if (ObjectIsEmpty(valuePtr)) { + objc = 0; + } else if (Tcl_ListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK) { + return NULL; + } + len = MAX(objc, TK_PATHTAG_SPACE); + tagsPtr = (Tk_PathTags *) ckalloc(sizeof(Tk_PathTags)); + tagsPtr->tagSpace = len; + tagsPtr->numTags = objc; + tagsPtr->tagPtr = (Tk_Uid *) ckalloc((unsigned) (len * sizeof(Tk_Uid))); + for (i = 0; i < objc; i++) { + tagsPtr->tagPtr[i] = Tk_GetUid(Tcl_GetStringFromObj(objv[i], NULL)); + } + return tagsPtr; +} + +static void +TkPathFreeTags(Tk_PathTags *tagsPtr) +{ + if (tagsPtr->tagPtr != NULL) { + ckfree((char *) tagsPtr->tagPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasTagsOptionSetProc -- + * + * This function is invoked during option processing to handle "-tags" + * options for canvas items. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The tags for a given item get replaced by those indicated in the value + * argument. + * + *-------------------------------------------------------------- + */ + +int Tk_PathCanvasTagsOptionSetProc( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; /* Points to location in record where + * internal representation of value should + * be stored, or NULL. */ + Tcl_Obj *valuePtr; + Tk_PathTags *newPtr = NULL; + + valuePtr = *value; + if (internalOffset >= 0) { + internalPtr = recordPtr + internalOffset; + } else { + internalPtr = NULL; + } + if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + newPtr = NULL; + } + if (internalPtr != NULL) { + if (valuePtr != NULL) { + newPtr = TkPathAllocTagsFromObj(interp, valuePtr); + if (newPtr == NULL) { + return TCL_ERROR; + } + } + *((Tk_PathTags **) oldInternalPtr) = *((Tk_PathTags **) internalPtr); + *((Tk_PathTags **) internalPtr) = newPtr; + } + return TCL_OK; +} + +Tcl_Obj * +Tk_PathCanvasTagsOptionGetProc( + ClientData clientData, + Tk_Window tkwin, + char *recordPtr, /* Pointer to widget record. */ + int internalOffset) /* Offset within *recordPtr containing the + * value. */ +{ + Tk_PathTags *tagsPtr; + Tcl_Obj *listObj; + int i; + + tagsPtr = *((Tk_PathTags **) (recordPtr + internalOffset)); + listObj = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); + if (tagsPtr != NULL) { + for (i = 0; i < tagsPtr->numTags; i++) { + Tcl_ListObjAppendElement(NULL, listObj, + Tcl_NewStringObj((char *) tagsPtr->tagPtr[i], -1)); + } + } + return listObj; +} + +void +Tk_PathCanvasTagsOptionRestoreProc( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(Tk_PathTags **)internalPtr = *(Tk_PathTags **)oldInternalPtr; +} + +void +Tk_PathCanvasTagsOptionFreeProc( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr) /* Pointer to storage for value. */ +{ + Tk_PathTags *tagsPtr; + + tagsPtr = *((Tk_PathTags **) internalPtr); + if (tagsPtr != NULL) { + TkPathFreeTags(tagsPtr); + ckfree(*((char **) internalPtr)); + *((char **) internalPtr) = NULL; + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasTagsParseProc -- + * + * This function is invoked during option processing to handle "-tags" + * options for canvas items. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The tags for a given item get replaced by those indicated in the value + * argument. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathCanvasTagsParseProc( + ClientData clientData, /* Not used.*/ + Tcl_Interp *interp, /* Used for reporting errors. */ + Tk_Window tkwin, /* Window containing canvas widget. */ + CONST char *value, /* Value of option (list of tag names). */ + char *widgRec, /* Pointer to record for item. */ + int offset) /* Offset into item (ignored). */ +{ + register Tk_PathItem *itemPtr = (Tk_PathItem *) widgRec; + int argc, i; + CONST char **argv; + Tk_Uid *newPtr; + + /* + * Break the value up into the individual tag names. + */ + + if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Make sure that there's enough space in the item to hold the tag names. + */ + + if (itemPtr->tagSpace < argc) { + newPtr = (Tk_Uid *) ckalloc((unsigned) (argc * sizeof(Tk_Uid))); + for (i = itemPtr->numTags-1; i >= 0; i--) { + newPtr[i] = itemPtr->tagPtr[i]; + } + if (itemPtr->tagPtr != itemPtr->staticTagSpace) { + ckfree((char *) itemPtr->tagPtr); + } + itemPtr->tagPtr = newPtr; + itemPtr->tagSpace = argc; + } + itemPtr->numTags = argc; + for (i = 0; i < argc; i++) { + itemPtr->tagPtr[i] = Tk_GetUid(argv[i]); + } + ckfree((char *) argv); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasTagsPrintProc -- + * + * This function is invoked by the Tk configuration code to produce a + * printable string for the "-tags" configuration option for canvas + * items. + * + * Results: + * The return value is a string describing all the tags for the item + * referred to by "widgRec". In addition, *freeProcPtr is filled in with + * the address of a function to call to free the result string when it's + * no longer needed (or NULL to indicate that the string doesn't need to + * be freed). + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +char * +Tk_PathCanvasTagsPrintProc( + ClientData clientData, /* Ignored. */ + Tk_Window tkwin, /* Window containing canvas widget. */ + char *widgRec, /* Pointer to record for item. */ + int offset, /* Ignored. */ + Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with + * information about how to reclaim storage + * for return string. */ +{ + register Tk_PathItem *itemPtr = (Tk_PathItem *) widgRec; + + if (itemPtr->numTags == 0) { + *freeProcPtr = NULL; + return ""; + } + if (itemPtr->numTags == 1) { + *freeProcPtr = NULL; + return (char *) itemPtr->tagPtr[0]; + } + *freeProcPtr = TCL_DYNAMIC; + return Tcl_Merge(itemPtr->numTags, (CONST char **) itemPtr->tagPtr); +} + +/* Return NULL on error and leave error message */ + +static Tk_Dash * +TkDashNew(Tcl_Interp *interp, Tcl_Obj *dashObj) +{ + Tk_Dash *dashPtr; + + dashPtr = (Tk_Dash *) ckalloc(sizeof(Tk_Dash)); + /* + * NB: Tk_GetDash tries to free any existing pattern unless we zero this. + */ + dashPtr->number = 0; + if (Tk_GetDash(interp, Tcl_GetString(dashObj), dashPtr) != TCL_OK) { + goto error; + } + return dashPtr; + +error: + TkDashFree(dashPtr); + return NULL; +} + +static void +TkDashFree(Tk_Dash *dashPtr) +{ + if (dashPtr != NULL) { + if (ABS(dashPtr->number) > sizeof(char *)) { + ckfree((char *) dashPtr->pattern.pt); + } + ckfree((char *) dashPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_DashOptionSetProc, Tk_DashOptionGetProc, + * Tk_DashOptionRestoreProc, Tk_DashOptionRestoreProc -- + * + * These functions are invoked during option processing to handle + * "-dash", "-activedash" and "-disableddash" + * options for canvas objects. + * + * Results: + * According to the Tk_ObjCustomOption struct. + * + * Side effects: + * Memory allocated or freed. + * + *-------------------------------------------------------------- + */ + +int Tk_DashOptionSetProc( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; /* Points to location in record where + * internal representation of value should + * be stored, or NULL. */ + Tcl_Obj *valuePtr; + Tk_Dash *newPtr = NULL; + + valuePtr = *value; + if (internalOffset >= 0) { + internalPtr = recordPtr + internalOffset; + } else { + internalPtr = NULL; + } + if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + newPtr = NULL; + } + if (internalPtr != NULL) { + if (valuePtr != NULL) { + newPtr = TkDashNew(interp, valuePtr); + if (newPtr == NULL) { + return TCL_ERROR; + } + } + *((Tk_Dash **) oldInternalPtr) = *((Tk_Dash **) internalPtr); + *((Tk_Dash **) internalPtr) = newPtr; + } + return TCL_OK; +} + +Tcl_Obj * +Tk_DashOptionGetProc( + ClientData clientData, + Tk_Window tkwin, + char *recordPtr, /* Pointer to widget record. */ + int internalOffset) /* Offset within *recordPtr containing the + * value. */ +{ + Tk_Dash *dashPtr; + Tcl_Obj *objPtr = NULL; + char *buffer = NULL; + char *p; + int i; + + dashPtr = *((Tk_Dash **) (recordPtr + internalOffset)); + + if (dashPtr != NULL) { + i = dashPtr->number; + if (i < 0) { + i = -i; + buffer = (char *) ckalloc((unsigned int) (i+1)); + p = (i > (int)sizeof(char *)) ? dashPtr->pattern.pt : dashPtr->pattern.array; + memcpy(buffer, p, (unsigned int) i); + buffer[i] = 0; + } else if (!i) { + buffer = (char *) ckalloc(1); + buffer[0] = '\0'; + } else { + buffer = (char *)ckalloc((unsigned int) (4*i)); + p = (i > (int)sizeof(char *)) ? dashPtr->pattern.pt : dashPtr->pattern.array; + sprintf(buffer, "%d", *p++ & 0xff); + while(--i) { + sprintf(buffer+strlen(buffer), " %d", *p++ & 0xff); + } + } + objPtr = Tcl_NewStringObj(buffer, -1); + } + if (buffer != NULL) { + ckfree((char *) buffer); + } + return objPtr; +} + +void +Tk_DashOptionRestoreProc( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(Tk_Dash **)internalPtr = *(Tk_Dash **)oldInternalPtr; +} + +void +Tk_DashOptionFreeProc( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr) /* Pointer to storage for value. */ +{ + if (*((char **) internalPtr) != NULL) { + TkDashFree(*(Tk_Dash **) internalPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * InitSmoothMethods -- + * + * This function is invoked to set up the initial state of the list of + * "-smooth" methods. It should only be called when the list installed + * in the interpreter is NULL. + * + * Results: + * Pointer to the start of the list of default smooth methods. + * + * Side effects: + * A linked list of smooth methods is created and attached to the + * interpreter's association key "smoothPathMethod" + * + *-------------------------------------------------------------- + */ + +static SmoothAssocData * +InitSmoothMethods( + Tcl_Interp *interp) +{ + SmoothAssocData *methods, *ptr; + + methods = (SmoothAssocData *) ckalloc(sizeof(SmoothAssocData)); + methods->smooth.name = tkPathRawSmoothMethod.name; + methods->smooth.coordProc = tkPathRawSmoothMethod.coordProc; + methods->smooth.postscriptProc = tkPathRawSmoothMethod.postscriptProc; + + methods->nextPtr = (SmoothAssocData *) ckalloc(sizeof(SmoothAssocData)); + + ptr = methods->nextPtr; + ptr->smooth.name = tkPathBezierSmoothMethod.name; + ptr->smooth.coordProc = tkPathBezierSmoothMethod.coordProc; + ptr->smooth.postscriptProc = tkPathBezierSmoothMethod.postscriptProc; + ptr->nextPtr = NULL; + + Tcl_SetAssocData(interp, "smoothPathMethod", SmoothMethodCleanupProc, + (ClientData) methods); + return methods; +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCreateSmoothMethod -- + * + * This function is invoked to add additional values for the "-smooth" + * option to the list. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * In the future "-smooth <name>" will be accepted as smooth method for + * the line and polygon. + * + *-------------------------------------------------------------- + */ + +void +Tk_PathCreateSmoothMethod( + Tcl_Interp *interp, + Tk_PathSmoothMethod *smooth) +{ + SmoothAssocData *methods, *typePtr2, *prevPtr, *ptr; + methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothPathMethod", + NULL); + + /* + * Initialize if we were not previously initialized. + */ + + if (methods == NULL) { + methods = InitSmoothMethods(interp); + } + + /* + * If there's already a smooth method with the given name, remove it. + */ + + for (typePtr2 = methods, prevPtr = NULL; typePtr2 != NULL; + prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) { + if (!strcmp(typePtr2->smooth.name, smooth->name)) { + if (prevPtr == NULL) { + methods = typePtr2->nextPtr; + } else { + prevPtr->nextPtr = typePtr2->nextPtr; + } + ckfree((char *) typePtr2); + break; + } + } + ptr = (SmoothAssocData *) ckalloc(sizeof(SmoothAssocData)); + ptr->smooth.name = smooth->name; + ptr->smooth.coordProc = smooth->coordProc; + ptr->smooth.postscriptProc = smooth->postscriptProc; + ptr->nextPtr = methods; + Tcl_SetAssocData(interp, "smoothPathMethod", SmoothMethodCleanupProc, + (ClientData) ptr); +} + +/* + *---------------------------------------------------------------------- + * + * SmoothMethodCleanupProc -- + * + * This function is invoked whenever an interpreter is deleted to + * cleanup the smooth methods. + * + * Results: + * None. + * + * Side effects: + * Smooth methods are removed. + * + *---------------------------------------------------------------------- + */ + +static void +SmoothMethodCleanupProc( + ClientData clientData, /* Points to "smoothPathMethod" AssocData for the + * interpreter. */ + Tcl_Interp *interp) /* Interpreter that is being deleted. */ +{ + SmoothAssocData *ptr, *methods = (SmoothAssocData *) clientData; + + while (methods != NULL) { + methods = (ptr = methods)->nextPtr; + ckfree((char *) ptr); + } +} + +static int +FindSmoothMethod(Tcl_Interp *interp, + Tcl_Obj *valueObj, + Tk_PathSmoothMethod **smoothPtr) /* Place to store converted result. */ +{ + Tk_PathSmoothMethod *smooth = NULL; + int b; + char *value; + size_t length; + SmoothAssocData *methods; + + value = Tcl_GetString(valueObj); + length = strlen(value); + methods = (SmoothAssocData *) Tcl_GetAssocData(interp, "smoothPathMethod", + NULL); + + /* + * Not initialized yet; fix that now. + */ + + if (methods == NULL) { + methods = InitSmoothMethods(interp); + } + + /* + * Backward compatability hack. + */ + + if (strncmp(value, "bezier", length) == 0) { + smooth = &tkPathBezierSmoothMethod; + } + + /* + * Search the list of installed smooth methods. + */ + + while (methods != NULL) { + if (strncmp(value, methods->smooth.name, length) == 0) { + if (smooth != NULL) { + Tcl_AppendResult(interp, "ambiguous smooth method \"", value, + "\"", NULL); + return TCL_ERROR; + } + smooth = &methods->smooth; + } + methods = methods->nextPtr; + } + if (smooth) { + *smoothPtr = smooth; + return TCL_OK; + } + + /* + * Did not find it. Try parsing as a boolean instead. + */ + + if (Tcl_GetBooleanFromObj(interp, valueObj, &b) != TCL_OK) { + return TCL_ERROR; + } + *smoothPtr = b ? &tkPathBezierSmoothMethod : NULL; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TkPathSmoothOptionSetProc -- + * + * This function is invoked during option processing to handle "-smooth" + * options for canvas items. + * + * Results: + * A standard Tcl return value. + * + * Side effects: + * The smooth option for a given item gets replaced by the value + * indicated in the value argument. + * + *-------------------------------------------------------------- + */ + +int +TkPathSmoothOptionSetProc( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; /* Points to location in record where + * internal representation of value should + * be stored, or NULL. */ + Tcl_Obj *valuePtr; + Tk_PathSmoothMethod *newPtr = NULL; + + valuePtr = *value; + if (internalOffset >= 0) { + internalPtr = recordPtr + internalOffset; + } else { + internalPtr = NULL; + } + if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + newPtr = NULL; + } + if (internalPtr != NULL) { + if (valuePtr != NULL) { + if (FindSmoothMethod(interp, valuePtr, &newPtr) != TCL_OK) { + return TCL_ERROR; + } + } + *((Tk_PathSmoothMethod **) oldInternalPtr) = *((Tk_PathSmoothMethod **) internalPtr); + *((Tk_PathSmoothMethod **) internalPtr) = newPtr; + } + return TCL_OK; +} + +Tcl_Obj * +TkPathSmoothOptionGetProc( + ClientData clientData, + Tk_Window tkwin, + char *recordPtr, /* Pointer to widget record. */ + int internalOffset) /* Offset within *recordPtr containing the + * value. */ +{ + Tk_PathSmoothMethod *smooth; + + smooth = *((Tk_PathSmoothMethod **) (recordPtr + internalOffset)); + return (smooth) ? Tcl_NewStringObj(smooth->name, -1) : Tcl_NewBooleanObj(0); +} + +void +TkPathSmoothOptionRestoreProc( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(Tk_PathSmoothMethod **)internalPtr = *(Tk_PathSmoothMethod **)oldInternalPtr; +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCreateOutline + * + * This function initializes the Tk_PathOutline structure with default + * values. + * + * Results: + * None + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +void +Tk_PathCreateOutline( + Tk_PathOutline *outline) /* Outline structure to be filled in. */ +{ + outline->gc = None; + outline->width = 1.0; + outline->activeWidth = 0.0; + outline->disabledWidth = 0.0; + outline->offset = 0; + outline->dashPtr = NULL; + outline->activeDashPtr = NULL; + outline->disabledDashPtr = NULL; + outline->tsoffsetPtr = NULL; + outline->color = NULL; + outline->activeColor = NULL; + outline->disabledColor = NULL; + outline->stipple = None; + outline->activeStipple = None; + outline->disabledStipple = None; +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathDeleteOutline + * + * This function frees all memory that might be allocated and referenced + * in the Tk_PathOutline structure. + * + * Results: + * None + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +/* @@@ I don't belive this should ever be called since the memory is handled by Option! */ + +void +Tk_PathDeleteOutline( + Display *display, /* Display containing window. */ + Tk_PathOutline *outline) +{ + if (outline->gc != None) { + Tk_FreeGC(display, outline->gc); + outline->gc = None; + } + if (outline->color != NULL) { + Tk_FreeColor(outline->color); + outline->color = NULL; + } + if (outline->activeColor != NULL) { + Tk_FreeColor(outline->activeColor); + outline->activeColor = NULL; + } + if (outline->disabledColor != NULL) { + Tk_FreeColor(outline->disabledColor); + outline->disabledColor = NULL; + } + if (outline->stipple != None) { + Tk_FreeBitmap(display, outline->stipple); + outline->stipple = None; + } + if (outline->activeStipple != None) { + Tk_FreeBitmap(display, outline->activeStipple); + outline->activeStipple = None; + } + if (outline->disabledStipple != None) { + Tk_FreeBitmap(display, outline->disabledStipple); + outline->disabledStipple = None; + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathConfigOutlineGC + * + * This function should be called in the canvas object during the + * configure command. The graphics context description in gcValues is + * updated according to the information in the dash structure, as far as + * possible. + * + * Results: + * The return-value is a mask, indicating which elements of gcValues have + * been updated. 0 means there is no outline. + * + * Side effects: + * GC information in gcValues is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathConfigOutlineGC( + XGCValues *gcValues, + Tk_PathCanvas canvas, + Tk_PathItem *item, + Tk_PathOutline *outline) +{ + int mask = 0; + double width; + Tk_Dash *dashPtr; + XColor *color; + Pixmap stipple; + Tk_PathState state = item->state; + + if (outline->width < 0.0) { + outline->width = 0.0; + } + if (outline->activeWidth < 0.0) { + outline->activeWidth = 0.0; + } + if (outline->disabledWidth < 0) { + outline->disabledWidth = 0.0; + } + if (state==TK_PATHSTATE_HIDDEN) { + return 0; + } + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dashPtr = outline->dashPtr; + color = outline->color; + stipple = outline->stipple; + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (((TkPathCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth>width) { + width = outline->activeWidth; + } + if (outline->activeDashPtr != NULL) { + dashPtr = outline->activeDashPtr; + } + if (outline->activeColor!=NULL) { + color = outline->activeColor; + } + if (outline->activeStipple!=None) { + stipple = outline->activeStipple; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (outline->disabledWidth>0) { + width = outline->disabledWidth; + } + if (outline->disabledDashPtr != NULL) { + dashPtr = outline->disabledDashPtr; + } + if (outline->disabledColor!=NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple!=None) { + stipple = outline->disabledStipple; + } + } + + if (color==NULL) { + return 0; + } + + gcValues->line_width = (int) (width + 0.5); + if (color != NULL) { + gcValues->foreground = color->pixel; + mask = GCForeground|GCLineWidth; + if (stipple != None) { + gcValues->stipple = stipple; + gcValues->fill_style = FillStippled; + mask |= GCStipple|GCFillStyle; + } + } + if (mask && (dashPtr != NULL)) { + gcValues->line_style = LineOnOffDash; + gcValues->dash_offset = outline->offset; + if (dashPtr->number >= 2) { + gcValues->dashes = 4; + } else if (dashPtr->number > 0) { + gcValues->dashes = dashPtr->pattern.array[0]; + } else { + gcValues->dashes = (char) (4 * width); + } + mask |= GCLineStyle|GCDashList|GCDashOffset; + } + return mask; +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathChangeOutlineGC + * + * Updates the GC to represent the full information of the dash + * structure. Partly this is already done in Tk_PathConfigOutlineGC(). This + * function should be called just before drawing the dashed item. + * + * Results: + * 1 if there is a stipple pattern, and 0 otherwise. + * + * Side effects: + * GC is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathChangeOutlineGC( + Tk_PathCanvas canvas, + Tk_PathItem *item, + Tk_PathOutline *outline) +{ + CONST char *p; + double width; + Tk_Dash *dashPtr; + XColor *color; + Pixmap stipple; + Tk_PathState state = item->state; + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dashPtr = outline->dashPtr; + color = outline->color; + stipple = outline->stipple; + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (((TkPathCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth > width) { + width = outline->activeWidth; + } + if (outline->activeDashPtr != NULL) { + dashPtr = outline->activeDashPtr; + } + if (outline->activeColor != NULL) { + color = outline->activeColor; + } + if (outline->activeStipple != None) { + stipple = outline->activeStipple; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (outline->disabledWidth > width) { + width = outline->disabledWidth; + } + if (outline->disabledDashPtr != NULL) { + dashPtr = outline->disabledDashPtr; + } + if (outline->disabledColor != NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple != None) { + stipple = outline->disabledStipple; + } + } + if (color == NULL) { + return 0; + } + if (dashPtr != NULL) { + if ((dashPtr->number <- 1) || + ((dashPtr->number == -1) && (dashPtr->pattern.array[1] != ','))) { + char *q; + int i = -dashPtr->number; + + p = (i > (int)sizeof(char *)) ? dashPtr->pattern.pt : dashPtr->pattern.array; + q = (char *) ckalloc(2*(unsigned int)i); + i = DashConvert(q, p, i, width); + XSetDashes(((TkPathCanvas *)canvas)->display, outline->gc, + outline->offset, q, i); + ckfree(q); + } else if (dashPtr->number > 2 || (dashPtr->number == 2 && + (dashPtr->pattern.array[0] != dashPtr->pattern.array[1]))) { + p = (dashPtr->number > (int)sizeof(char *)) + ? dashPtr->pattern.pt : dashPtr->pattern.array; + XSetDashes(((TkPathCanvas *)canvas)->display, outline->gc, + outline->offset, p, dashPtr->number); + } + } + if (stipple != None) { + int w=0; int h=0; + Tk_TSOffset *tsoffset = outline->tsoffsetPtr; + int flags = tsoffset->flags; + if (!(flags & TK_OFFSET_INDEX) && + (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE))) { + Tk_SizeOfBitmap(((TkPathCanvas *)canvas)->display, stipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset->xoffset -= w; + tsoffset->yoffset -= h; + Tk_PathCanvasSetOffset(canvas, outline->gc, tsoffset); + tsoffset->xoffset += w; + tsoffset->yoffset += h; + return 1; + } + return 0; +} + + +/* + *-------------------------------------------------------------- + * + * Tk_PathResetOutlineGC + * + * Restores the GC to the situation before Tk_ChangeDashGC() was called. + * This function should be called just after the dashed item is drawn, + * because the GC is supposed to be read-only. + * + * Results: + * 1 if there is a stipple pattern, and 0 otherwise. + * + * Side effects: + * GC is updated. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathResetOutlineGC( + Tk_PathCanvas canvas, + Tk_PathItem *item, + Tk_PathOutline *outline) +{ + char dashList; + double width; + Tk_Dash *dashPtr; + XColor *color; + Pixmap stipple; + Tk_PathState state = item->state; + + width = outline->width; + if (width < 1.0) { + width = 1.0; + } + dashPtr = outline->dashPtr; + color = outline->color; + stipple = outline->stipple; + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (((TkPathCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth > width) { + width = outline->activeWidth; + } + if (outline->activeDashPtr != NULL) { + dashPtr = outline->activeDashPtr; + } + if (outline->activeColor != NULL) { + color = outline->activeColor; + } + if (outline->activeStipple != None) { + stipple = outline->activeStipple; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (outline->disabledWidth > width) { + width = outline->disabledWidth; + } + if (outline->disabledDashPtr != NULL) { + dashPtr = outline->disabledDashPtr; + } + if (outline->disabledColor != NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple != None) { + stipple = outline->disabledStipple; + } + } + if (color == NULL) { + return 0; + } + + if (dashPtr != NULL) { + if ((dashPtr->number > 2) || (dashPtr->number < -1) || (dashPtr->number == 2 && + (dashPtr->pattern.array[0] != dashPtr->pattern.array[1])) || + ((dashPtr->number == -1) && (dashPtr->pattern.array[1] != ','))) { + if (dashPtr->number < 0) { + dashList = (int) (4 * width + 0.5); + } else if (dashPtr->number < 3) { + dashList = dashPtr->pattern.array[0]; + } else { + dashList = 4; + } + XSetDashes(((TkPathCanvas *)canvas)->display, outline->gc, + outline->offset, &dashList , 1); + } + } + if (stipple != None) { + XSetTSOrigin(((TkPathCanvas *)canvas)->display, outline->gc, 0, 0); + return 1; + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasPsOutline + * + * Creates the postscript command for the correct Outline-information + * (width, dash, color and stipple). + * + * Results: + * TCL_OK if succeeded, otherwise TCL_ERROR. + * + * Side effects: + * canvas->interp->result contains the postscript string, or an error + * message if the result was TCL_ERROR. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathCanvasPsOutline( + Tk_PathCanvas canvas, + Tk_PathItem *item, + Tk_PathOutline *outline) +{ + char string[41]; + char pattern[11]; + int i; + char *ptr; + char *str = string; + char *lptr = pattern; + Tcl_Interp *interp = ((TkPathCanvas *)canvas)->interp; + double width; + Tk_Dash *dashPtr; + XColor *color; + Pixmap stipple; + Tk_PathState state = item->state; + + width = outline->width; + dashPtr = outline->dashPtr; + color = outline->color; + stipple = outline->stipple; + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + if (((TkPathCanvas *)canvas)->currentItemPtr == item) { + if (outline->activeWidth > width) { + width = outline->activeWidth; + } + if (outline->activeDashPtr != NULL) { + dashPtr = outline->activeDashPtr; + } + if (outline->activeColor != NULL) { + color = outline->activeColor; + } + if (outline->activeStipple != None) { + stipple = outline->activeStipple; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (outline->disabledWidth > 0) { + width = outline->disabledWidth; + } + if (outline->disabledDashPtr != NULL) { + dashPtr = outline->disabledDashPtr; + } + if (outline->disabledColor != NULL) { + color = outline->disabledColor; + } + if (outline->disabledStipple != None) { + stipple = outline->disabledStipple; + } + } + sprintf(string, "%.15g setlinewidth\n", width); + Tcl_AppendResult(interp, string, NULL); + + if (dashPtr != NULL) { + if (dashPtr->number > 10) { + str = (char *)ckalloc((unsigned int) (1 + 4*dashPtr->number)); + } else if (dashPtr->number < -5) { + str = (char *)ckalloc((unsigned int) (1 - 8*dashPtr->number)); + lptr = (char *)ckalloc((unsigned int) (1 - 2*dashPtr->number)); + } + ptr = (ABS(dashPtr->number) > sizeof(char *)) ? + dashPtr->pattern.pt : dashPtr->pattern.array; + if (dashPtr->number > 0) { + char *ptr0 = ptr; + + sprintf(str, "[%d", *ptr++ & 0xff); + i = dashPtr->number-1; + while (i--) { + sprintf(str+strlen(str), " %d", *ptr++ & 0xff); + } + Tcl_AppendResult(interp, str, NULL); + if (dashPtr->number&1) { + Tcl_AppendResult(interp, " ", str+1, NULL); + } + sprintf(str, "] %d setdash\n", outline->offset); + Tcl_AppendResult(interp, str, NULL); + ptr = ptr0; + } else if (dashPtr->number < 0) { + if ((i = DashConvert(lptr, ptr, -dashPtr->number, width)) != 0) { + char *lptr0 = lptr; + + sprintf(str, "[%d", *lptr++ & 0xff); + while (--i) { + sprintf(str+strlen(str), " %d", *lptr++ & 0xff); + } + Tcl_AppendResult(interp, str, NULL); + sprintf(str, "] %d setdash\n", outline->offset); + Tcl_AppendResult(interp, str, NULL); + lptr = lptr0; + } + } else { + Tcl_AppendResult(interp, "[] 0 setdash\n", NULL); + } + } else { + Tcl_AppendResult(interp, "[] 0 setdash\n", NULL); + } + + if (str != string) { + ckfree(str); + } + if (lptr != pattern) { + ckfree(lptr); + } + if (Tk_PathCanvasPsColor(interp, canvas, color) != TCL_OK) { + return TCL_ERROR; + } + if (stipple != None) { + Tcl_AppendResult(interp, "StrokeClip ", NULL); + if (Tk_PathCanvasPsStipple(interp, canvas, stipple) != TCL_OK) { + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "stroke\n", NULL); + } + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * DashConvert + * + * Converts a character-like dash-list (e.g. "-..") into an X11-style. l + * must point to a string that holds room to at least 2*n characters. If + * l == NULL, this function can be used for syntax checking only. + * + * Results: + * The length of the resulting X11 compatible dash-list. -1 if failed. + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +static int +DashConvert( + char *l, /* Must be at least 2*n chars long, or NULL to + * indicate "just check syntax". */ + CONST char *p, /* String to parse. */ + int n, /* Length of string to parse, or -1 to + * indicate that strlen() should be used. */ + double width) /* Width of line. */ +{ + int result = 0; + int size, intWidth; + + if (n<0) { + n = (int) strlen(p); + } + intWidth = (int) (width + 0.5); + if (intWidth < 1) { + intWidth = 1; + } + while (n-- && *p) { + switch (*p++) { + case ' ': + if (result) { + if (l) { + l[-1] += intWidth + 1; + } + continue; + } + return 0; + case '_': + size = 8; + break; + case '-': + size = 6; + break; + case ',': + size = 4; + break; + case '.': + size = 2; + break; + default: + return -1; + } + if (l) { + *l++ = size * intWidth; + *l++ = 4 * intWidth; + } + result += 2; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TranslateAndAppendCoords -- + * + * This is a helper routine for TkPathCanvTranslatePath() below. + * + * Given an (x,y) coordinate pair within a canvas, this function computes + * the corresponding coordinates at which the point should be drawn in + * the drawable used for display. Those coordinates are then written into + * outArr[numOut*2] and outArr[numOut*2+1]. + * + * Results: + * There is no return value. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +TranslateAndAppendCoords( + TkPathCanvas *canvPtr, /* The canvas. */ + double x, /* Coordinates in canvas space. */ + double y, + XPoint *outArr, /* Write results into this array */ + int numOut) /* Num of prior entries in outArr[] */ +{ + double tmp; + + tmp = x - canvPtr->drawableXOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + outArr[numOut].x = (short) tmp; + + tmp = y - canvPtr->drawableYOrigin; + if (tmp > 0) { + tmp += 0.5; + } else { + tmp -= 0.5; + } + outArr[numOut].y = (short) tmp; +} + +/* + *-------------------------------------------------------------- + * + * TkPathCanvTranslatePath + * + * Translate a line or polygon path so that all vertices are within a + * rectangle that is 1000 pixels larger than the total size of the canvas + * window. This will prevent pixel coordinates from overflowing the + * 16-bit integer size limitation imposed by most windowing systems. + * + * coordPtr must point to an array of doubles, two doubles per vertex. + * There are a total of numVertex vertices, or 2*numVertex entries in + * coordPtr. The result vertices written into outArr have their + * coordinate origin shifted to canvPtr->drawableXOrigin by + * canvPtr->drawableYOrigin. There might be as many as 3 times more + * output vertices than there are input vertices. The calling function + * should allocate space accordingly. + * + * This routine limits the width and height of a canvas window to 31767 + * pixels. At the highest resolution display devices available today (210 + * ppi in Jan 2003) that's a window that is over 13 feet wide and tall. + * Should be enough for the near future. + * + * Results: + * Clipped and translated path vertices are written into outArr[]. There + * might be as many as twice the vertices in outArr[] as there are in + * coordPtr[]. The return value is the number of vertices actually + * written into outArr[]. + * + * Side effects: + * None + * + *-------------------------------------------------------------- + */ + +int +TkPathCanvTranslatePath( + TkPathCanvas *canvPtr, /* The canvas */ + int numVertex, /* Number of vertices specified by + * coordArr[] */ + double *coordArr, /* X and Y coordinates for each vertex */ + int closedPath, /* True if this is a closed polygon */ + XPoint *outArr) /* Write results here, if not NULL */ +{ + int numOutput = 0; /* Number of output coordinates */ + double lft, rgh; /* Left and right sides of the bounding box */ + double top, btm; /* Top and bottom sizes of the bounding box */ + double *tempArr; /* Temporary storage used by the clipper */ + double *a, *b, *t; /* Pointers to parts of the temporary + * storage */ + int i, j; /* Loop counters */ + int maxOutput; /* Maximum number of outputs that we will + * allow */ + double limit[4]; /* Boundries at which clipping occurs */ + double staticSpace[480]; /* Temp space from the stack */ + + /* + * Constrain all vertices of the path to be within a box that is no larger + * than 32000 pixels wide or height. The top-left corner of this clipping + * box is 1000 pixels above and to the left of the top left corner of the + * window on which the canvas is displayed. + * + * This means that a canvas will not display properly on a canvas window + * that is larger than 31000 pixels wide or high. That is not a problem + * today, but might someday become a factor for ultra-high resolutions + * displays. + * + * The X11 protocol allows us (in theory) to expand the size of the + * clipping box to 32767 pixels. But we have found experimentally that + * XFree86 sometimes fails to draw lines correctly if they are longer than + * about 32500 pixels. So we have left a little margin in the size to mask + * that bug. + */ + + lft = canvPtr->xOrigin - 1000.0; + top = canvPtr->yOrigin - 1000.0; + rgh = lft + 32000.0; + btm = top + 32000.0; + + /* + * Try the common case first - no clipping. Loop over the input + * coordinates and translate them into appropriate output coordinates. + * But if a vertex outside of the bounding box is seen, break out of the + * loop. + * + * Most of the time, no clipping is needed, so this one loop is sufficient + * to do the translation. + */ + + for (i=0; i<numVertex; i++){ + double x, y; + + x = coordArr[i*2]; + y = coordArr[i*2+1]; + if (x<lft || x>rgh || y<top || y>btm) { + break; + } + TranslateAndAppendCoords(canvPtr, x, y, outArr, numOutput++); + } + if (i == numVertex){ + assert(numOutput == numVertex); + return numOutput; + } + + /* + * If we reach this point, it means that some clipping is required. Begin + * by allocating some working storage - at least 6 times as much space as + * coordArr[] requires. Divide this space into two separate arrays a[] and + * b[]. Initialize a[] to be equal to coordArr[]. + */ + + if (numVertex*12 <= (int)(sizeof(staticSpace)/sizeof(staticSpace[0]))) { + tempArr = staticSpace; + } else { + tempArr = (double *)ckalloc(numVertex*12*sizeof(tempArr[0])); + } + for (i=0; i<numVertex*2; i++){ + tempArr[i] = coordArr[i]; + } + a = tempArr; + b = &tempArr[numVertex*6]; + + /* + * We will make four passes through the input data. On each pass, we copy + * the contents of a[] over into b[]. As we copy, we clip any line + * segments that extend to the right past xClip then we rotate the + * coordinate system 90 degrees clockwise. After each pass is complete, we + * interchange a[] and b[] in preparation for the next pass. + * + * Each pass clips line segments that extend beyond a single side of the + * bounding box, and four passes rotate the coordinate system back to its + * original value. I'm not an expert on graphics algorithms, but I think + * this is called Cohen-Sutherland polygon clipping. + * + * The limit[] array contains the xClip value used for each of the four + * passes. + */ + + limit[0] = rgh; + limit[1] = -top; + limit[2] = -lft; + limit[3] = btm; + + /* + * This is the loop that makes the four passes through the data. + */ + + maxOutput = numVertex*3; + for (j=0; j<4; j++){ + double xClip = limit[j]; + int inside = a[0]<xClip; + double priorY = a[1]; + numOutput = 0; + + /* + * Clip everything to the right of xClip. Store the results in b[] + * rotated by 90 degrees clockwise. + */ + + for (i=0; i<numVertex; i++){ + double x = a[i*2]; + double y = a[i*2+1]; + + if (x >= xClip) { + /* + * The current vertex is to the right of xClip. + */ + + if (inside) { + /* + * If the current vertex is to the right of xClip but the + * previous vertex was left of xClip, then draw a line + * segment from the previous vertex to until it intersects + * the vertical at xClip. + */ + + double x0, y0, yN; + + assert(i > 0); + x0 = a[i*2-2]; + y0 = a[i*2-1]; + yN = y0 + (y - y0)*(xClip-x0)/(x-x0); + b[numOutput*2] = -yN; + b[numOutput*2+1] = xClip; + numOutput++; + assert(numOutput <= maxOutput); + priorY = yN; + inside = 0; + } else if (i == 0) { + /* + * If the first vertex is to the right of xClip, add a + * vertex that is the projection of the first vertex onto + * the vertical xClip line. + */ + + b[0] = -y; + b[1] = xClip; + numOutput = 1; + priorY = y; + } + } else { + /* + * The current vertex is to the left of xClip + */ + if (!inside) { + /* If the current vertex is on the left of xClip and one + * or more prior vertices where to the right, then we have + * to draw a line segment along xClip that extends from + * the spot where we first crossed from left to right to + * the spot where we cross back from right to left. + */ + + double x0, y0, yN; + + assert(i > 0); + x0 = a[i*2-2]; + y0 = a[i*2-1]; + yN = y0 + (y - y0)*(xClip-x0)/(x-x0); + if (yN != priorY) { + b[numOutput*2] = -yN; + b[numOutput*2+1] = xClip; + numOutput++; + assert(numOutput <= maxOutput); + } + inside = 1; + } + b[numOutput*2] = -y; + b[numOutput*2+1] = x; + numOutput++; + assert(numOutput <= maxOutput); + } + } + + /* + * Interchange a[] and b[] in preparation for the next pass. + */ + + t = a; + a = b; + b = t; + numVertex = numOutput; + } + + /* + * All clipping is now finished. Convert the coordinates from doubles into + * XPoints and translate the origin for the drawable. + */ + + for (i=0; i<numVertex; i++){ + TranslateAndAppendCoords(canvPtr, a[i*2], a[i*2+1], outArr, i); + } + if (tempArr != staticSpace) { + ckfree((char *) tempArr); + } + return numOutput; +} + + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/pd/tkpath/generic/tkpCanvWind.c b/pd/tkpath/generic/tkpCanvWind.c new file mode 100644 index 0000000000000000000000000000000000000000..84be095106f99b9536275ce10987eb06f3f406f6 --- /dev/null +++ b/pd/tkpath/generic/tkpCanvWind.c @@ -0,0 +1,1110 @@ +/* + * tkpCanvWind.c -- + * + * This file implements window items for canvas widgets. + * + * Copyright (c) 1992-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvWind.c,v 1.4 2008/07/14 08:21:26 matben Exp $ + */ + +#include <stdio.h> +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" + +/* + * The structure below defines the record for each window item. + */ + +typedef struct WindowItem { + Tk_PathItem header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + double x, y; /* Coordinates of positioning point for + * window. */ + Tk_Window tkwin; /* Window associated with item. NULL means + * window has been destroyed. */ + int width; /* Width to use for window (<= 0 means use + * window's requested width). */ + int height; /* Width to use for window (<= 0 means use + * window's requested width). */ + Tk_Anchor anchor; /* Where to anchor window relative to + * (x,y). */ + Tk_PathCanvas canvas; /* Canvas containing this item. */ +} WindowItem; + +#define PATH_DEF_STATE "normal" + +static char *stateStrings[] = { + "active", "disabled", "normal", "hidden", NULL +}; + +static Tk_ObjCustomOption tagsCO = { + "tags", + Tk_PathCanvasTagsOptionSetProc, + Tk_PathCanvasTagsOptionGetProc, + Tk_PathCanvasTagsOptionRestoreProc, + Tk_PathCanvasTagsOptionFreeProc, + (ClientData) NULL +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_ANCHOR, "-anchor", NULL, NULL, + "center", -1, Tk_Offset(WindowItem, anchor), 0, 0, 0}, + {TK_OPTION_PIXELS, "-height", NULL, NULL, + "0", -1, Tk_Offset(WindowItem, height), 0, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", NULL, NULL, + PATH_DEF_STATE, -1, Tk_Offset(Tk_PathItem, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_CUSTOM, "-tags", NULL, NULL, + NULL, -1, Tk_Offset(Tk_PathItem, pathTagsPtr), + TK_OPTION_NULL_OK, (ClientData) &tagsCO, 0}, + {TK_OPTION_PIXELS, "-width", NULL, NULL, + "0", -1, Tk_Offset(WindowItem, width), 0, 0, 0}, + {TK_OPTION_WINDOW, "-window", NULL, NULL, + NULL, -1, Tk_Offset(WindowItem, tkwin), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * Prototypes for functions defined in this file: + */ + +static void ComputeWindowBbox(Tk_PathCanvas canvas, + WindowItem *winItemPtr); +static int ConfigureWinItem(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[], int flags); +static int CreateWinItem(Tcl_Interp *interp, + Tk_PathCanvas canvas, struct Tk_PathItem *itemPtr, + int objc, Tcl_Obj *CONST objv[]); +static void DeleteWinItem(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display); +static void DisplayWinItem(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, Display *display, Drawable dst, + int x, int y, int width, int height); +static void ScaleWinItem(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double originX, double originY, + double scaleX, double scaleY); +static void TranslateWinItem(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); +static int WinItemCoords(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int objc, + Tcl_Obj *CONST objv[]); +static void WinItemLostSlaveProc(ClientData clientData, + Tk_Window tkwin); +static void WinItemRequestProc(ClientData clientData, + Tk_Window tkwin); +static void WinItemStructureProc(ClientData clientData, + XEvent *eventPtr); +static int WinItemToArea(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *rectPtr); +static int WinItemToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static double WinItemToPoint(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double *pointPtr); +#ifdef X_GetImage +static int xerrorhandler(ClientData clientData, XErrorEvent *e); +#endif +static int CanvasPsWindow(Tcl_Interp *interp, + Tk_Window tkwin, Tk_PathCanvas canvas, double x, + double y, int width, int height); + +/* + * The structure below defines the window item type by means of functions + * that can be invoked by generic item code. + */ + +Tk_PathItemType tkWindowType = { + "window", /* name */ + sizeof(WindowItem), /* itemSize */ + CreateWinItem, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigureWinItem, /* configureProc */ + WinItemCoords, /* coordProc */ + DeleteWinItem, /* deleteProc */ + DisplayWinItem, /* displayProc */ + 1, /* flags */ + NULL, /* bboxProc */ + WinItemToPoint, /* pointProc */ + WinItemToArea, /* areaProc */ + WinItemToPostscript, /* postscriptProc */ + ScaleWinItem, /* scaleProc */ + TranslateWinItem, /* translateProc */ + NULL, /* indexProc */ + NULL, /* cursorProc */ + NULL, /* selectionProc */ + NULL, /* insertProc */ + NULL, /* dTextProc */ + NULL, /* nextPtr */ +}; + +/* + * The structure below defines the official type record for the canvas (as + * geometry manager): + */ + +static const Tk_GeomMgr canvasGeomType = { + "canvas", /* name */ + WinItemRequestProc, /* requestProc */ + WinItemLostSlaveProc, /* lostSlaveProc */ +}; + +/* + *-------------------------------------------------------------- + * + * CreateWinItem -- + * + * This function is invoked to create a new window 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 the interp's result; in this + * case itemPtr is left uninitialized, so it can be safely freed by the + * caller. + * + * Side effects: + * A new window item is created. + * + *-------------------------------------------------------------- + */ + +static int +CreateWinItem( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Canvas to hold new item. */ + Tk_PathItem *itemPtr, /* Record to hold new item; header has been + * initialized by caller. */ + int objc, /* Number of arguments in objv. */ + Tcl_Obj *CONST objv[]) /* Arguments describing window. */ +{ + WindowItem *winItemPtr = (WindowItem *) itemPtr; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Initialize item's record. + */ + + winItemPtr->tkwin = NULL; + winItemPtr->width = 0; + winItemPtr->height = 0; + winItemPtr->anchor = TK_ANCHOR_CENTER; + winItemPtr->canvas = canvas; + + if (optionTable == NULL) { + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) winItemPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + /* + * Process the arguments to fill in the item record. Only 1 (list) or 2 (x + * y) coords are allowed. + */ + + if (objc == 1) { + i = 1; + } else { + char *arg = Tcl_GetString(objv[1]); + i = 2; + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + i = 1; + } + } + if (WinItemCoords(interp, canvas, itemPtr, i, objv) != TCL_OK) { + goto error; + } + if (ConfigureWinItem(interp, canvas, itemPtr, objc-i, objv+i, 0) + == TCL_OK) { + return TCL_OK; + } + + error: + DeleteWinItem(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * WinItemCoords -- + * + * This function is invoked to process the "coords" widget command on + * window items. See the user documentation for details on what it does. + * + * Results: + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. + * + * Side effects: + * The coordinates for the given item may be changed. + * + *-------------------------------------------------------------- + */ + +static int +WinItemCoords( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item whose coordinates are to be read or + * modified. */ + int objc, /* Number of coordinates supplied in objv. */ + Tcl_Obj *CONST objv[]) /* Array of coordinates: x1, y1, x2, y2, ... */ +{ + WindowItem *winItemPtr = (WindowItem *) itemPtr; + + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(winItemPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(winItemPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (objc < 3) { + if (objc==1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } else if (objc != 2) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[0], &winItemPtr->x) + != TCL_OK) || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[1], + &winItemPtr->y) != TCL_OK)) { + return TCL_ERROR; + } + ComputeWindowBbox(canvas, winItemPtr); + } else { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 2, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ConfigureWinItem -- + * + * This function is invoked to configure various aspects of a window + * item, such as its anchor position. + * + * Results: + * A standard Tcl result code. If an error occurs, then an error message + * is left in the interp's result. + * + * Side effects: + * Configuration information may be set for itemPtr. + * + *-------------------------------------------------------------- + */ + +static int +ConfigureWinItem( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Window item to reconfigure. */ + int objc, /* Number of elements in objv. */ + Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ + int flags) /* Flags to pass to Tk_ConfigureWidget. */ +{ + WindowItem *winItemPtr = (WindowItem *) itemPtr; + Tk_Window oldWindow; + Tk_Window canvasTkwin; + + oldWindow = winItemPtr->tkwin; + canvasTkwin = Tk_PathCanvasTkwin(canvas); + if (TCL_OK != Tk_SetOptions(interp, (char *) winItemPtr, optionTable, + objc, objv, canvasTkwin, NULL, NULL)) { + return TCL_ERROR; + } + + /* + * A few of the options require additional processing. + */ + + if (oldWindow != winItemPtr->tkwin) { + if (oldWindow != NULL) { + Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, + WinItemStructureProc, (ClientData) winItemPtr); + Tk_ManageGeometry(oldWindow, NULL, (ClientData) NULL); + Tk_UnmaintainGeometry(oldWindow, canvasTkwin); + Tk_UnmapWindow(oldWindow); + } + if (winItemPtr->tkwin != NULL) { + Tk_Window ancestor, parent; + + /* + * Make sure that the canvas is either the parent of the window + * associated with the item or a descendant of that parent. Also, + * don't allow a top-of-hierarchy window to be managed inside a + * canvas. + */ + + parent = Tk_Parent(winItemPtr->tkwin); + for (ancestor = canvasTkwin; ; + ancestor = Tk_Parent(ancestor)) { + if (ancestor == parent) { + break; + } + if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_HIERARCHY) { + badWindow: + Tcl_AppendResult(interp, "can't use ", + Tk_PathName(winItemPtr->tkwin), + " in a window item of this canvas", NULL); + winItemPtr->tkwin = NULL; + return TCL_ERROR; + } + } + if (((Tk_FakeWin *) (winItemPtr->tkwin))->flags & TK_TOP_HIERARCHY) { + goto badWindow; + } + if (winItemPtr->tkwin == canvasTkwin) { + goto badWindow; + } + Tk_CreateEventHandler(winItemPtr->tkwin, StructureNotifyMask, + WinItemStructureProc, (ClientData) winItemPtr); + Tk_ManageGeometry(winItemPtr->tkwin, &canvasGeomType, + (ClientData) winItemPtr); + } + } + if ((winItemPtr->tkwin != NULL) + && (itemPtr->state == TK_PATHSTATE_HIDDEN)) { + if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { + Tk_UnmapWindow(winItemPtr->tkwin); + } else { + Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); + } + } + + ComputeWindowBbox(canvas, winItemPtr); + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * DeleteWinItem -- + * + * This function is called to clean up the data structure associated with + * a window item. + * + * Results: + * None. + * + * Side effects: + * Resources associated with itemPtr are released. + * + *-------------------------------------------------------------- + */ + +static void +DeleteWinItem( + Tk_PathCanvas canvas, /* Overall info about widget. */ + Tk_PathItem *itemPtr, /* Item that is being deleted. */ + Display *display) /* Display containing window for canvas. */ +{ + WindowItem *winItemPtr = (WindowItem *) itemPtr; + Tk_Window canvasTkwin = Tk_PathCanvasTkwin(canvas); + + if (winItemPtr->tkwin != NULL) { + Tk_DeleteEventHandler(winItemPtr->tkwin, StructureNotifyMask, + WinItemStructureProc, (ClientData) winItemPtr); + Tk_ManageGeometry(winItemPtr->tkwin, NULL, + (ClientData) NULL); + if (canvasTkwin != Tk_Parent(winItemPtr->tkwin)) { + Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); + } + Tk_UnmapWindow(winItemPtr->tkwin); + } + Tk_FreeConfigOptions((char *) itemPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +/* + *-------------------------------------------------------------- + * + * ComputeWindowBbox -- + * + * This function is invoked to compute the bounding box of all the pixels + * that may be drawn as part of a window item. This function is where the + * child window's placement is computed. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header for itemPtr. + * + *-------------------------------------------------------------- + */ + +static void +ComputeWindowBbox( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + WindowItem *winItemPtr) /* Item whose bbox is to be recomputed. */ +{ + int width, height, x, y; + Tk_PathState state = winItemPtr->header.state; + + x = (int) (winItemPtr->x + ((winItemPtr->x >= 0) ? 0.5 : - 0.5)); + y = (int) (winItemPtr->y + ((winItemPtr->y >= 0) ? 0.5 : - 0.5)); + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if ((winItemPtr->tkwin == NULL) || (state == TK_PATHSTATE_HIDDEN)) { + /* + * There is no window for this item yet. Just give it a 1x1 bounding + * box. Don't give it a 0x0 bounding box; there are strange cases + * where this bounding box might be used as the dimensions of the + * window, and 0x0 causes problems under X. + */ + + winItemPtr->header.x1 = x; + winItemPtr->header.x2 = winItemPtr->header.x1 + 1; + winItemPtr->header.y1 = y; + winItemPtr->header.y2 = winItemPtr->header.y1 + 1; + return; + } + + /* + * Compute dimensions of window. + */ + + width = winItemPtr->width; + if (width <= 0) { + width = Tk_ReqWidth(winItemPtr->tkwin); + if (width <= 0) { + width = 1; + } + } + height = winItemPtr->height; + if (height <= 0) { + height = Tk_ReqHeight(winItemPtr->tkwin); + if (height <= 0) { + height = 1; + } + } + + /* + * Compute location of window, using anchor information. + */ + + switch (winItemPtr->anchor) { + case TK_ANCHOR_N: + x -= width/2; + break; + case TK_ANCHOR_NE: + x -= width; + break; + case TK_ANCHOR_E: + x -= width; + y -= height/2; + break; + case TK_ANCHOR_SE: + x -= width; + y -= height; + break; + case TK_ANCHOR_S: + x -= width/2; + y -= height; + break; + case TK_ANCHOR_SW: + y -= height; + break; + case TK_ANCHOR_W: + y -= height/2; + break; + case TK_ANCHOR_NW: + break; + case TK_ANCHOR_CENTER: + x -= width/2; + y -= height/2; + break; + } + + /* + * Store the information in the item header. + */ + + winItemPtr->header.x1 = x; + winItemPtr->header.y1 = y; + winItemPtr->header.x2 = x + width; + winItemPtr->header.y2 = y + height; +} + +/* + *-------------------------------------------------------------- + * + * DisplayWinItem -- + * + * This function is invoked to "draw" a window item in a given drawable. + * Since the window draws itself, we needn't do any actual redisplay + * here. However, this function takes care of actually repositioning the + * child window so that it occupies the correct screen position. + * + * Results: + * None. + * + * Side effects: + * The child window's position may get changed. Note: this function gets + * called both when a window needs to be displayed and when it ceases to + * be visible on the screen (e.g. it was scrolled or moved off-screen or + * the enclosing canvas is unmapped). + * + *-------------------------------------------------------------- + */ + +static void +DisplayWinItem( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + Tk_PathItem *itemPtr, /* Item to be displayed. */ + Display *display, /* Display on which to draw item. */ + Drawable drawable, /* Pixmap or window in which to draw item. */ + int regionX, int regionY, int regionWidth, int regionHeight) + /* Describes region of canvas that must be + * redisplayed (not used). */ +{ + WindowItem *winItemPtr = (WindowItem *) itemPtr; + int width, height; + short x, y; + Tk_Window canvasTkwin = Tk_PathCanvasTkwin(canvas); + Tk_PathState state = itemPtr->state; + + if (winItemPtr->tkwin == NULL) { + return; + } + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + /* + * A drawable of None is used by the canvas UnmapNotify handler + * to indicate that we should no longer display ourselves. + */ + if (state == TK_PATHSTATE_HIDDEN || drawable == None) { + if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { + Tk_UnmapWindow(winItemPtr->tkwin); + } else { + Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); + } + return; + } + Tk_PathCanvasWindowCoords(canvas, (double) winItemPtr->header.x1, + (double) winItemPtr->header.y1, &x, &y); + width = winItemPtr->header.x2 - winItemPtr->header.x1; + height = winItemPtr->header.y2 - winItemPtr->header.y1; + + /* + * If the window is completely out of the visible area of the canvas then + * unmap it. This code used not to be present (why unmap the window if it + * isn't visible anyway?) but this could cause the window to suddenly + * reappear if the canvas window got resized. + */ + + if (((x + width) <= 0) || ((y + height) <= 0) + || (x >= Tk_Width(canvasTkwin)) || (y >= Tk_Height(canvasTkwin))) { + if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { + Tk_UnmapWindow(winItemPtr->tkwin); + } else { + Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); + } + return; + } + + /* + * Reposition and map the window (but in different ways depending on + * whether the canvas is the window's parent). + */ + + if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) { + if ((x != Tk_X(winItemPtr->tkwin)) || (y != Tk_Y(winItemPtr->tkwin)) + || (width != Tk_Width(winItemPtr->tkwin)) + || (height != Tk_Height(winItemPtr->tkwin))) { + Tk_MoveResizeWindow(winItemPtr->tkwin, x, y, width, height); + } + Tk_MapWindow(winItemPtr->tkwin); + } else { + Tk_MaintainGeometry(winItemPtr->tkwin, canvasTkwin, x, y, + width, height); + } +} + +/* + *-------------------------------------------------------------- + * + * WinItemToPoint -- + * + * Computes the distance from a given point to a given window, in canvas + * units. + * + * Results: + * The return value is 0 if the point whose x and y coordinates are + * coordPtr[0] and coordPtr[1] is inside the window. If the point isn't + * inside the window then the return value is the distance from the point + * to the window. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static double +WinItemToPoint( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + double *pointPtr) /* Pointer to x and y coordinates. */ +{ + WindowItem *winItemPtr = (WindowItem *) itemPtr; + double x1, x2, y1, y2, xDiff, yDiff; + + x1 = winItemPtr->header.x1; + y1 = winItemPtr->header.y1; + x2 = winItemPtr->header.x2; + y2 = winItemPtr->header.y2; + + /* + * Point is outside window. + */ + + if (pointPtr[0] < x1) { + xDiff = x1 - pointPtr[0]; + } else if (pointPtr[0] >= x2) { + xDiff = pointPtr[0] + 1 - x2; + } else { + xDiff = 0; + } + + if (pointPtr[1] < y1) { + yDiff = y1 - pointPtr[1]; + } else if (pointPtr[1] >= y2) { + yDiff = pointPtr[1] + 1 - y2; + } else { + yDiff = 0; + } + + return hypot(xDiff, yDiff); +} + +/* + *-------------------------------------------------------------- + * + * WinItemToArea -- + * + * This function is called to determine whether an item lies entirely + * inside, entirely outside, or overlapping a given rectangle. + * + * Results: + * -1 is returned if the item is entirely outside the area given by + * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given + * area. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +WinItemToArea( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against rectangle. */ + double *rectPtr) /* Pointer to array of four coordinates + * (x1,y1,x2,y2) describing rectangular + * area. */ +{ + WindowItem *winItemPtr = (WindowItem *) itemPtr; + + if ((rectPtr[2] <= winItemPtr->header.x1) + || (rectPtr[0] >= winItemPtr->header.x2) + || (rectPtr[3] <= winItemPtr->header.y1) + || (rectPtr[1] >= winItemPtr->header.y2)) { + return -1; + } + if ((rectPtr[0] <= winItemPtr->header.x1) + && (rectPtr[1] <= winItemPtr->header.y1) + && (rectPtr[2] >= winItemPtr->header.x2) + && (rectPtr[3] >= winItemPtr->header.y2)) { + return 1; + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * xerrorhandler -- + * + * This is a dummy function to catch X11 errors during an attempt to + * print a canvas window. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +#ifdef X_GetImage +static int +xerrorhandler( + ClientData clientData, + XErrorEvent *e) +{ + return 0; +} +#endif + + +/* + *-------------------------------------------------------------- + * + * WinItemToPostscript -- + * + * This function is called to generate Postscript for window 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 +WinItemToPostscript( + Tcl_Interp *interp, /* Leave Postscript or error message here. */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + Tk_PathItem *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. */ +{ + WindowItem *winItemPtr = (WindowItem *)itemPtr; + + double x, y; + int width, height; + Tk_Window tkwin = winItemPtr->tkwin; + + if (prepass || winItemPtr->tkwin == NULL) { + return TCL_OK; + } + + width = Tk_Width(tkwin); + height = Tk_Height(tkwin); + + /* + * Compute the coordinates of the lower-left corner of the window, taking + * into account the anchor position for the window. + */ + + x = winItemPtr->x; + y = Tk_PathCanvasPsY(canvas, winItemPtr->y); + + switch (winItemPtr->anchor) { + case TK_ANCHOR_NW: y -= height; break; + case TK_ANCHOR_N: x -= width/2.0; y -= height; break; + case TK_ANCHOR_NE: x -= width; y -= height; break; + case TK_ANCHOR_E: x -= width; y -= height/2.0; break; + case TK_ANCHOR_SE: x -= width; break; + case TK_ANCHOR_S: x -= width/2.0; break; + case TK_ANCHOR_SW: break; + case TK_ANCHOR_W: y -= height/2.0; break; + case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; + } + + return CanvasPsWindow(interp, tkwin, canvas, x, y, width, height); +} + +static int +CanvasPsWindow( + Tcl_Interp *interp, /* Leave Postscript or error message here. */ + Tk_Window tkwin, /* window to be printed */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + double x, double y, /* origin of window. */ + int width, int height) /* width/height of window. */ +{ + char buffer[256]; + XImage *ximage; + int result; + Tcl_DString buffer1, buffer2; +#ifdef X_GetImage + Tk_ErrorHandler handle; +#endif + + sprintf(buffer, "\n%%%% %s item (%s, %d x %d)\n%.15g %.15g translate\n", + Tk_Class(tkwin), Tk_PathName(tkwin), width, height, x, y); + Tcl_AppendResult(interp, buffer, NULL); + + /* + * First try if the widget has its own "postscript" command. If it exists, + * this will produce much better postscript than when a pixmap is used. + */ + + Tcl_DStringInit(&buffer1); + Tcl_DStringInit(&buffer2); + Tcl_DStringGetResult(interp, &buffer2); + sprintf(buffer, "%s postscript -prolog 0\n", Tk_PathName(tkwin)); + result = Tcl_Eval(interp, buffer); + Tcl_DStringGetResult(interp, &buffer1); + Tcl_DStringResult(interp, &buffer2); + Tcl_DStringFree(&buffer2); + + if (result == TCL_OK) { + Tcl_AppendResult(interp, "50 dict begin\nsave\ngsave\n", NULL); + sprintf(buffer, "0 %d moveto %d 0 rlineto 0 -%d rlineto -%d", + height, width, height, width); + Tcl_AppendResult(interp, buffer, NULL); + Tcl_AppendResult(interp, " 0 rlineto closepath\n", + "1.000 1.000 1.000 setrgbcolor AdjustColor\nfill\ngrestore\n", + Tcl_DStringValue(&buffer1), "\nrestore\nend\n\n\n", NULL); + Tcl_DStringFree(&buffer1); + + return result; + } + Tcl_DStringFree(&buffer1); + + /* + * If the window is off the screen it will generate a BadMatch/XError. We + * catch any BadMatch errors here + */ + +#ifdef X_GetImage + handle = Tk_CreateErrorHandler(Tk_Display(tkwin), BadMatch, + X_GetImage, -1, xerrorhandler, (ClientData) tkwin); +#endif + + /* + * Generate an XImage from the window. We can then read pixel values out + * of the XImage. + */ + + ximage = XGetImage(Tk_Display(tkwin), Tk_WindowId(tkwin), 0, 0, + (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); + +#ifdef X_GetImage + Tk_DeleteErrorHandler(handle); +#endif + + if (ximage == NULL) { + return TCL_OK; + } + + result = TkPathPostscriptImage(interp, tkwin, + ((TkPathCanvas *)canvas)->psInfo, ximage, 0, 0, width, height); + + XDestroyImage(ximage); + return result; +} + +/* + *-------------------------------------------------------------- + * + * ScaleWinItem -- + * + * This function is invoked to rescale a window item. + * + * Results: + * None. + * + * Side effects: + * The window 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 +ScaleWinItem( + Tk_PathCanvas canvas, /* Canvas containing window. */ + Tk_PathItem *itemPtr, /* Window to be scaled. */ + double originX, double originY, + /* Origin about which to scale window. */ + double scaleX, /* Amount to scale in X direction. */ + double scaleY) /* Amount to scale in Y direction. */ +{ + WindowItem *winItemPtr = (WindowItem *) itemPtr; + + winItemPtr->x = originX + scaleX*(winItemPtr->x - originX); + winItemPtr->y = originY + scaleY*(winItemPtr->y - originY); + if (winItemPtr->width > 0) { + winItemPtr->width = (int) (scaleX*winItemPtr->width); + } + if (winItemPtr->height > 0) { + winItemPtr->height = (int) (scaleY*winItemPtr->height); + } + ComputeWindowBbox(canvas, winItemPtr); +} + +/* + *-------------------------------------------------------------- + * + * TranslateWinItem -- + * + * This function is called to move a window by a given amount. + * + * Results: + * None. + * + * Side effects: + * The position of the window is offset by (xDelta, yDelta), and the + * bounding box is updated in the generic part of the item structure. + * + *-------------------------------------------------------------- + */ + +static void +TranslateWinItem( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item that is being moved. */ + double deltaX, double deltaY) + /* Amount by which item is to be moved. */ +{ + WindowItem *winItemPtr = (WindowItem *) itemPtr; + + winItemPtr->x += deltaX; + winItemPtr->y += deltaY; + ComputeWindowBbox(canvas, winItemPtr); +} + +/* + *-------------------------------------------------------------- + * + * WinItemStructureProc -- + * + * This function is invoked whenever StructureNotify events occur for a + * window that's managed as part of a canvas window item. This function's + * only purpose is to clean up when windows are deleted. + * + * Results: + * None. + * + * Side effects: + * The window is disassociated from the window item when it is deleted. + * + *-------------------------------------------------------------- + */ + +static void +WinItemStructureProc( + ClientData clientData, /* Pointer to record describing window item. */ + XEvent *eventPtr) /* Describes what just happened. */ +{ + WindowItem *winItemPtr = (WindowItem *) clientData; + + if (eventPtr->type == DestroyNotify) { + winItemPtr->tkwin = NULL; + } +} + +/* + *-------------------------------------------------------------- + * + * WinItemRequestProc -- + * + * This function is invoked whenever a window that's associated with a + * window canvas item changes its requested dimensions. + * + * Results: + * None. + * + * Side effects: + * The size and location on the screen of the window may change, + * depending on the options specified for the window item. + * + *-------------------------------------------------------------- + */ + +static void +WinItemRequestProc( + ClientData clientData, /* Pointer to record for window item. */ + Tk_Window tkwin) /* Window that changed its desired size. */ +{ + WindowItem *winItemPtr = (WindowItem *) clientData; + + ComputeWindowBbox(winItemPtr->canvas, winItemPtr); + + /* + * A drawable argument of None to DisplayWinItem is used by the canvas + * UnmapNotify handler to indicate that we should no longer display + * ourselves, so need to pass a (bogus) non-zero drawable value here. + */ + DisplayWinItem(winItemPtr->canvas, (Tk_PathItem *) winItemPtr, NULL, + (Drawable) -1, 0, 0, 0, 0); +} + +/* + *-------------------------------------------------------------- + * + * WinItemLostSlaveProc -- + * + * This function 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 canvas-related information about the slave. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static void +WinItemLostSlaveProc( + ClientData clientData, /* WindowItem structure for slave window that + * was stolen away. */ + Tk_Window tkwin) /* Tk's handle for the slave window. */ +{ + WindowItem *winItemPtr = (WindowItem *) clientData; + Tk_Window canvasTkwin = Tk_PathCanvasTkwin(winItemPtr->canvas); + + Tk_DeleteEventHandler(winItemPtr->tkwin, StructureNotifyMask, + WinItemStructureProc, (ClientData) winItemPtr); + if (canvasTkwin != Tk_Parent(winItemPtr->tkwin)) { + Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin); + } + Tk_UnmapWindow(winItemPtr->tkwin); + winItemPtr->tkwin = NULL; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/pd/tkpath/generic/tkpCanvas.c b/pd/tkpath/generic/tkpCanvas.c new file mode 100644 index 0000000000000000000000000000000000000000..9c80e3ba43a994c2715696a8ae59a41ae7d65d4c --- /dev/null +++ b/pd/tkpath/generic/tkpCanvas.c @@ -0,0 +1,6704 @@ +/* + * tkpCanvas.c -- + * + * This module implements canvas widgets for the Tk toolkit. A canvas + * displays a background and a collection of graphical objects such as + * rectangles, lines, and texts. + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-1999 by Scriptics Corporation. + * Copyright (c) 2008 Mats Bengtsson + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvas.c,v 1.16 2012/07/04 19:43:18 petasis Exp $ + */ + +/* #define USE_OLD_TAG_SEARCH 1 */ + +#ifdef MAC_OSX_TK +#define TK_PATH_NO_DOUBLE_BUFFERING +#endif + +#include "default.h" +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" +#ifdef TK_PATH_NO_DOUBLE_BUFFERING +#ifdef MAC_OSX_TK +#include "tkMacOSXInt.h" +#endif +#endif /* TK_PATH_NO_DOUBLE_BUFFERING */ + +/* For debugging. */ +extern Tcl_Interp *gInterp; + +/* + * See tkpCanvas.h for key data structures used to implement canvases. + */ + +#ifdef USE_OLD_TAG_SEARCH + +/* + * The structure defined below is used to keep track of a tag search in + * progress. No field should be accessed by anyone other than StartTagSearch + * and NextItem. + */ + +typedef struct TagSearch { + TkPathCanvas *canvasPtr; /* Canvas widget being searched. */ + Tk_Uid tag; /* Tag to search for. 0 means return all + * items. */ + Tk_PathItem *currentPtr; /* Pointer to last item returned. */ + Tk_PathItem *lastPtr; /* The item right before the currentPtr is + * tracked so if the currentPtr is deleted we + * don't have to start from the beginning. */ + int searchOver; /* Non-zero means NextItem should always + * return NULL. */ +} TagSearch; + +#else /* USE_OLD_TAG_SEARCH */ +/* + * The structure defined below is used to keep track of a tag search in + * progress. No field should be accessed by anyone other than TagSearchScan, + * TagSearchFirst, TagSearchNext, TagSearchScanExpr, TagSearchEvalExpr, + * TagSearchExprInit, TagSearchExprDestroy, TagSearchDestroy. + * ( + * Not quite accurate: the TagSearch structure is also accessed from: + * CanvasWidgetCmd, FindItems, RelinkItems + * The only instances of the structure are owned by: + * CanvasWidgetCmd + * CanvasWidgetCmd is the only function that calls: + * FindItems, RelinkItems + * CanvasWidgetCmd, FindItems, RelinkItems, are the only functions that call + * TagSearch* + * ) + */ + +typedef struct TagSearch { + TkPathCanvas *canvasPtr; /* Canvas widget being searched. */ + Tk_PathItem *currentPtr; /* Pointer to last item returned. */ + Tk_PathItem *lastPtr; /* The item right before the currentPtr is + * tracked so if the currentPtr is deleted we + * don't have to start from the beginning. */ + int searchOver; /* Non-zero means NextItem should always + * return NULL. */ + int type; /* Search type (see #defs below) */ + int id; /* Item id for searches by id */ + char *string; /* Tag expression string */ + int stringIndex; /* Current position in string scan */ + int stringLength; /* Length of tag expression string */ + char *rewritebuffer; /* Tag string (after removing escapes) */ + unsigned int rewritebufferAllocated; + /* Available space for rewrites. */ + TagSearchExpr *expr; /* Compiled tag expression. */ +} TagSearch; + +/* + * Values for the TagSearch type field. + */ + +#define SEARCH_TYPE_EMPTY 0 /* Looking for empty tag */ +#define SEARCH_TYPE_ID 1 /* Looking for an item by id */ +#define SEARCH_TYPE_ALL 2 /* Looking for all items */ +#define SEARCH_TYPE_TAG 3 /* Looking for an item by simple tag */ +#define SEARCH_TYPE_EXPR 4 /* Compound search */ +#define SEARCH_TYPE_ROOT 5 /* Looking for the root item */ + +#endif /* USE_OLD_TAG_SEARCH */ + +#define PATH_DEF_STATE "normal" + +/* These MUST be kept in sync with enums! X.h */ + +static char *stateStrings[] = { + "active", "disabled", "normal", "hidden", NULL +}; + +static char *tagStyleStrings[] = { + "exact", "expr", "glob", NULL +}; + +static Tk_ObjCustomOption offsetCO = { + "offset", + TkPathOffsetOptionSetProc, + TkPathOffsetOptionGetProc, + TkPathOffsetOptionRestoreProc, + TkPathOffsetOptionFreeProc, + (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_BORDER, "-background", "background", "Background", + DEF_CANVAS_BG_COLOR, -1, Tk_Offset(TkPathCanvas, bgBorder), + 0, (ClientData) DEF_CANVAS_BG_MONO, 0}, + {TK_OPTION_SYNONYM, "-bd", NULL, NULL, + NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bg", NULL, NULL, + NULL, 0, -1, 0, (ClientData) "-background", 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_CANVAS_BORDER_WIDTH, Tk_Offset(TkPathCanvas, borderWidthPtr), + Tk_Offset(TkPathCanvas, borderWidth), 0, 0, 0}, + {TK_OPTION_DOUBLE, "-closeenough", "closeEnough", "CloseEnough", + DEF_CANVAS_CLOSE_ENOUGH, -1, Tk_Offset(TkPathCanvas, closeEnough), + 0, 0, 0}, + {TK_OPTION_BOOLEAN, "-confine", "confine", "Confine", + DEF_CANVAS_CONFINE, -1, Tk_Offset(TkPathCanvas, confine), + 0, 0, 0}, + {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", + DEF_CANVAS_CURSOR, -1, Tk_Offset(TkPathCanvas, cursor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-height", "height", "Height", + DEF_CANVAS_HEIGHT, -1, Tk_Offset(TkPathCanvas, height), + 0, 0, 0}, + {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", + "HighlightBackground", DEF_CANVAS_HIGHLIGHT_BG, + -1, Tk_Offset(TkPathCanvas, highlightBgColorPtr), + 0, 0, 0}, + {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", + DEF_CANVAS_HIGHLIGHT, -1, Tk_Offset(TkPathCanvas, highlightColorPtr), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", + "HighlightThickness", DEF_CANVAS_HIGHLIGHT_WIDTH, + Tk_Offset(TkPathCanvas, highlightWidthPtr), + Tk_Offset(TkPathCanvas, highlightWidth), 0, 0, 0}, + {TK_OPTION_BORDER, "-insertbackground", "insertBackground", "Foreground", + DEF_CANVAS_INSERT_BG, -1, Tk_Offset(TkPathCanvas, textInfo.insertBorder), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-insertborderwidth", "insertBorderWidth", + "BorderWidth", DEF_CANVAS_INSERT_BD_COLOR, -1, + Tk_Offset(TkPathCanvas, textInfo.insertBorderWidth), + 0, (ClientData) DEF_CANVAS_INSERT_BD_MONO, 0}, + {TK_OPTION_INT, "-insertofftime", "insertOffTime", "OffTime", + DEF_CANVAS_INSERT_OFF_TIME, -1, Tk_Offset(TkPathCanvas, insertOffTime), + 0, 0, 0}, + {TK_OPTION_INT, "-insertontime", "insertOnTime", "OnTime", + DEF_CANVAS_INSERT_ON_TIME, -1, Tk_Offset(TkPathCanvas, insertOnTime), + 0, 0, 0}, + {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth", + DEF_CANVAS_INSERT_WIDTH, -1, Tk_Offset(TkPathCanvas, textInfo.insertWidth), + 0, 0, 0}, + {TK_OPTION_CUSTOM, "-offset", "offset", "Offset", + "0,0", -1, Tk_Offset(TkPathCanvas, tsoffsetPtr), + 0, &offsetCO, 0}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_CANVAS_RELIEF, -1, Tk_Offset(TkPathCanvas, relief), + 0, 0, 0}, + {TK_OPTION_STRING, "-scrollregion", "scrollRegion", "ScrollRegion", + DEF_CANVAS_SCROLL_REGION, -1, Tk_Offset(TkPathCanvas, regionString), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground", + DEF_CANVAS_SELECT_COLOR, -1, Tk_Offset(TkPathCanvas, textInfo.selBorder), + 0, (ClientData) DEF_CANVAS_SELECT_MONO, 0}, + {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth", + "BorderWidth", DEF_CANVAS_SELECT_BD_COLOR, -1, + Tk_Offset(TkPathCanvas, textInfo.selBorderWidth), + 0, (ClientData) DEF_CANVAS_SELECT_BD_MONO, 0}, + {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background", + DEF_CANVAS_SELECT_FG_COLOR, -1, Tk_Offset(TkPathCanvas, textInfo.selFgColorPtr), + TK_OPTION_NULL_OK, (ClientData) DEF_CANVAS_SELECT_FG_MONO, 0}, + {TK_OPTION_STRING_TABLE, "-state", "state", "State", + PATH_DEF_STATE, -1, Tk_Offset(TkPathCanvas, canvas_state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_STRING_TABLE, "-tagstyle", NULL, NULL, + "expr", -1, Tk_Offset(TkPathCanvas, tagStyle), + 0, (ClientData) tagStyleStrings, 0}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_CANVAS_TAKE_FOCUS, -1, Tk_Offset(TkPathCanvas, takeFocus), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-width", "width", "Width", + DEF_CANVAS_WIDTH, -1, Tk_Offset(TkPathCanvas, width), + 0, 0, 0}, + {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", + DEF_CANVAS_X_SCROLL_CMD, -1, Tk_Offset(TkPathCanvas, xScrollCmd), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-xscrollincrement", "xScrollIncrement", + "ScrollIncrement", + DEF_CANVAS_X_SCROLL_INCREMENT, -1, Tk_Offset(TkPathCanvas, xScrollIncrement), + 0, 0, 0}, + {TK_OPTION_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", + DEF_CANVAS_Y_SCROLL_CMD, -1, Tk_Offset(TkPathCanvas, yScrollCmd), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_PIXELS, "-yscrollincrement", "yScrollIncrement", + "ScrollIncrement", + DEF_CANVAS_Y_SCROLL_INCREMENT, -1, Tk_Offset(TkPathCanvas, yScrollIncrement), + 0, 0, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +static Tk_OptionTable optionTable = NULL; + +/* + * List of all the item types known at present. This is *global* and is + * protected by typeListMutex. + */ + +static Tk_PathItemType *typeList = NULL;/* NULL means initialization hasn't + * been done yet. */ +TCL_DECLARE_MUTEX(typeListMutex) + +#ifndef USE_OLD_TAG_SEARCH +/* + * Uids for operands in compiled advanced tag search expressions. + * Initialization is done by GetStaticUids() + */ + +typedef struct { + Tk_Uid allUid; /* "all" */ + Tk_Uid currentUid; /* "current" */ + Tk_Uid rootUid; /* "root" */ + Tk_Uid andUid; + Tk_Uid orUid; + Tk_Uid xorUid; + Tk_Uid parenUid; + Tk_Uid negparenUid; + Tk_Uid endparenUid; + Tk_Uid tagvalUid; + Tk_Uid negtagvalUid; +} SearchUids; + +static Tcl_ThreadDataKey dataKey; +static SearchUids * GetStaticUids(void); +#endif /* USE_OLD_TAG_SEARCH */ + +/* + * Prototypes for functions defined later in this file: + */ + +static void CanvasBindProc(ClientData clientData, + XEvent *eventPtr); +static void CanvasBlinkProc(ClientData clientData); +static void CanvasCmdDeletedProc(ClientData clientData); +static void CanvasDoEvent(TkPathCanvas *canvasPtr, XEvent *eventPtr); +static void CanvasEventProc(ClientData clientData, + XEvent *eventPtr); +static int CanvasFetchSelection(ClientData clientData, int offset, + char *buffer, int maxBytes); +static Tk_PathItem * CanvasFindClosest(TkPathCanvas *canvasPtr, + double coords[2]); +static void CanvasFocusProc(TkPathCanvas *canvasPtr, int gotFocus); +static void CanvasLostSelection(ClientData clientData); +static void CanvasSelectTo(TkPathCanvas *canvasPtr, + Tk_PathItem *itemPtr, int index); +static void CanvasSetOrigin(TkPathCanvas *canvasPtr, + int xOrigin, int yOrigin); +static void CanvasUpdateScrollbars(TkPathCanvas *canvasPtr); +static int CanvasWidgetCmd(ClientData clientData, + Tcl_Interp *interp, int argc, + Tcl_Obj *CONST *argv); +static void PathCanvasWorldChanged( + ClientData instanceData); +static int ConfigureCanvas(Tcl_Interp *interp, + TkPathCanvas *canvasPtr, int argc, + Tcl_Obj *CONST *argv, int flags); +static void DestroyCanvas(char *memPtr); +static void DisplayCanvas(ClientData clientData); +static void DoItem(Tcl_Interp *interp, + Tk_PathItem *itemPtr, Tk_Uid tag); +static void EventuallyRedrawItem(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr); + +static Tcl_Obj * UnshareObj(Tcl_Obj *objPtr); +static Tk_PathItem * ItemIteratorSubNext(Tk_PathItem *itemPtr, Tk_PathItem *groupPtr); +static void ItemAddToParent(Tk_PathItem *parentPtr, Tk_PathItem *itemPtr); +static void ItemDelete(TkPathCanvas *canvasPtr, Tk_PathItem *itemPtr); +static int ItemCreate(Tcl_Interp *interp, TkPathCanvas *canvasPtr, + Tk_PathItemType *typePtr, int isRoot, Tk_PathItem **itemPtrPtr, + int objc, Tcl_Obj *CONST objv[]); +static int ItemGetNumTags(Tk_PathItem *itemPtr); +static void SetAncestorsDirtyBbox(Tk_PathItem *itemPtr); + +static void DebugGetItemInfo(Tk_PathItem *itemPtr, char *s); + +#ifdef USE_OLD_TAG_SEARCH +static int FindItems(Tcl_Interp *interp, TkPathCanvas *canvasPtr, + int argc, Tcl_Obj *CONST *argv, + Tcl_Obj *newTagObj, int first); +#else /* USE_OLD_TAG_SEARCH */ +static int FindItems(Tcl_Interp *interp, TkPathCanvas *canvasPtr, + int argc, Tcl_Obj *CONST *argv, + Tcl_Obj *newTagObj, int first, + TagSearch **searchPtrPtr); +#endif /* USE_OLD_TAG_SEARCH */ +static int FindArea(Tcl_Interp *interp, TkPathCanvas *canvasPtr, + Tcl_Obj *CONST *argv, Tk_Uid uid, int enclosed); +static double GridAlign(double coord, double spacing); +static CONST char** TkGetStringsFromObjs(int argc, Tcl_Obj *CONST *objv); +static void InitCanvas(void); +#ifdef USE_OLD_TAG_SEARCH +static Tk_PathItem * NextItem(TagSearch *searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ +static void PickCurrentItem(TkPathCanvas *canvasPtr, XEvent *eventPtr); +static Tcl_Obj * ScrollFractions(int screen1, + int screen2, int object1, int object2); +#ifdef USE_OLD_TAG_SEARCH +static void RelinkItems(TkPathCanvas *canvasPtr, + Tcl_Obj *tag, Tk_PathItem *prevPtr); +static Tk_PathItem * StartTagSearch(TkPathCanvas *canvasPtr, + Tcl_Obj *tag, TagSearch *searchPtr); +#else /* USE_OLD_TAG_SEARCH */ +static int RelinkItems(TkPathCanvas *canvasPtr, Tcl_Obj *tag, + Tk_PathItem *prevPtr, TagSearch **searchPtrPtr); +static void TagSearchExprInit(TagSearchExpr **exprPtrPtr); +static void TagSearchExprDestroy(TagSearchExpr *expr); +static void TagSearchDestroy(TagSearch *searchPtr); +static int TagSearchScan(TkPathCanvas *canvasPtr, + Tcl_Obj *tag, TagSearch **searchPtrPtr); +static int TagSearchScanExpr(Tcl_Interp *interp, + TagSearch *searchPtr, TagSearchExpr *expr); +static int TagSearchEvalExpr(TagSearchExpr *expr, + Tk_PathItem *itemPtr); +static Tk_PathItem * TagSearchFirst(TagSearch *searchPtr); +static Tk_PathItem * TagSearchNext(TagSearch *searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ + +/* + * The structure below defines canvas class behavior by means of functions + * that can be invoked from generic window code. + */ + +static Tk_ClassProcs canvasClass = { + sizeof(Tk_ClassProcs), /* size */ + PathCanvasWorldChanged, /* worldChangedProc */ +}; + +/* + * Macros that significantly simplify all code that finds items. + */ + +#ifdef USE_OLD_TAG_SEARCH + +#define FIRST_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \ + (itemPtr) = StartTagSearch(canvasPtr,(objPtr),&search) + +#define FOR_EVERY_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \ + for ((itemPtr) = StartTagSearch(canvasPtr, (objPtr), &search); \ + (itemPtr) != NULL; (itemPtr) = NextItem(&search)) + +#else /* USE_OLD_TAG_SEARCH */ + +#define FIRST_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \ + if ((result = TagSearchScan(canvasPtr,(objPtr),(searchPtrPtr))) != TCL_OK) { \ + errorExitClause; \ + } \ + itemPtr = TagSearchFirst(*(searchPtrPtr)); + +#define FOR_EVERY_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \ + if ((result = TagSearchScan(canvasPtr,(objPtr),(searchPtrPtr))) != TCL_OK) { \ + errorExitClause; \ + } \ + for (itemPtr = TagSearchFirst(*(searchPtrPtr)); \ + itemPtr != NULL; itemPtr = TagSearchNext(*(searchPtrPtr))) + +#endif /* USE_OLD_TAG_SEARCH */ + + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasObjCmd -- + * + * This function is invoked to process the "canvas" Tcl command. See the + * user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathCanvasObjCmd( + ClientData clientData, /* Main window associated with interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int argc, /* Number of arguments. */ + Tcl_Obj *CONST argv[]) /* Argument objects. */ +{ + Tk_Window tkwin = (Tk_Window) clientData; + TkPathCanvas *canvasPtr; + Tk_Window newWin; + Tk_PathItem *rootItemPtr; + + if (typeList == NULL) { + InitCanvas(); + } + + if (argc < 2) { + Tcl_WrongNumArgs(interp, 1, argv, "pathName ?options?"); + return TCL_ERROR; + } + + newWin = Tk_CreateWindowFromPath(interp, tkwin, Tcl_GetString(argv[1]), NULL); + if (newWin == NULL) { + return TCL_ERROR; + } + + /* + * Create the option table for this widget class. If it has already been + * created, the cached pointer will be returned. + */ + + optionTable = Tk_CreateOptionTable(interp, optionSpecs); + + /* + * Initialize fields that won't be initialized by ConfigureCanvas, or + * which ConfigureCanvas expects to have reasonable values (e.g. resource + * pointers). + */ + + canvasPtr = (TkPathCanvas *) ckalloc(sizeof(TkPathCanvas)); + canvasPtr->optionTable = optionTable; + canvasPtr->tkwin = newWin; + canvasPtr->display = Tk_Display(newWin); + canvasPtr->interp = interp; + canvasPtr->widgetCmd = Tcl_CreateObjCommand(interp, + Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd, + (ClientData) canvasPtr, CanvasCmdDeletedProc); + canvasPtr->rootItemPtr = NULL; /* root item created below. */ + canvasPtr->borderWidthPtr = NULL; + canvasPtr->borderWidth = 0; + canvasPtr->bgBorder = NULL; + canvasPtr->relief = TK_RELIEF_FLAT; + canvasPtr->highlightWidthPtr = NULL; + canvasPtr->highlightWidth = 0; + canvasPtr->highlightBgColorPtr = NULL; + canvasPtr->highlightColorPtr = NULL; + canvasPtr->inset = 0; + canvasPtr->pixmapGC = None; + canvasPtr->width = None; + canvasPtr->height = None; + canvasPtr->confine = 0; + canvasPtr->textInfo.selBorder = NULL; + canvasPtr->textInfo.selBorderWidth = 0; + canvasPtr->textInfo.selFgColorPtr = NULL; + canvasPtr->textInfo.selItemPtr = NULL; + canvasPtr->textInfo.selectFirst = -1; + canvasPtr->textInfo.selectLast = -1; + canvasPtr->textInfo.anchorItemPtr = NULL; + canvasPtr->textInfo.selectAnchor = 0; + canvasPtr->textInfo.insertBorder = NULL; + canvasPtr->textInfo.insertWidth = 0; + canvasPtr->textInfo.insertBorderWidth = 0; + canvasPtr->textInfo.focusItemPtr = NULL; + canvasPtr->textInfo.gotFocus = 0; + canvasPtr->textInfo.cursorOn = 0; + canvasPtr->insertOnTime = 0; + canvasPtr->insertOffTime = 0; + canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; + canvasPtr->xOrigin = canvasPtr->yOrigin = 0; + canvasPtr->drawableXOrigin = canvasPtr->drawableYOrigin = 0; + canvasPtr->bindingTable = NULL; + canvasPtr->currentItemPtr = NULL; + canvasPtr->newCurrentPtr = NULL; + canvasPtr->closeEnough = 0.0; + canvasPtr->pickEvent.type = LeaveNotify; + canvasPtr->pickEvent.xcrossing.x = 0; + canvasPtr->pickEvent.xcrossing.y = 0; + canvasPtr->state = 0; + canvasPtr->xScrollCmd = NULL; + canvasPtr->yScrollCmd = NULL; + canvasPtr->scrollX1 = 0; + canvasPtr->scrollY1 = 0; + canvasPtr->scrollX2 = 0; + canvasPtr->scrollY2 = 0; + canvasPtr->regionString = NULL; + canvasPtr->xScrollIncrement = 0; + canvasPtr->yScrollIncrement = 0; + canvasPtr->scanX = 0; + canvasPtr->scanXOrigin = 0; + canvasPtr->scanY = 0; + canvasPtr->scanYOrigin = 0; + canvasPtr->hotPtr = NULL; + canvasPtr->hotPrevPtr = NULL; + canvasPtr->cursor = None; + canvasPtr->takeFocus = NULL; + canvasPtr->pixelsPerMM = WidthOfScreen(Tk_Screen(newWin)); + canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(newWin)); + canvasPtr->flags = 0; + canvasPtr->nextId = 1; /* id = 0 reserved for root item */ + canvasPtr->psInfo = NULL; + canvasPtr->canvas_state = TK_PATHSTATE_NORMAL; + canvasPtr->tsoffsetPtr = NULL; + canvasPtr->styleUid = 0; + canvasPtr->gradientUid = 0; +#ifndef USE_OLD_TAG_SEARCH + canvasPtr->bindTagExprs = NULL; +#endif + + Tcl_InitHashTable(&canvasPtr->idTable, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(&canvasPtr->styleTable, TCL_STRING_KEYS); + Tcl_InitHashTable(&canvasPtr->gradientTable, TCL_STRING_KEYS); + + Tk_SetClass(canvasPtr->tkwin, "PathCanvas"); + Tk_SetClassProcs(canvasPtr->tkwin, &canvasClass, (ClientData) canvasPtr); + Tk_CreateEventHandler(canvasPtr->tkwin, + ExposureMask|StructureNotifyMask|FocusChangeMask, + CanvasEventProc, (ClientData) canvasPtr); + Tk_CreateEventHandler(canvasPtr->tkwin, KeyPressMask|KeyReleaseMask + |ButtonPressMask|ButtonReleaseMask|EnterWindowMask + |LeaveWindowMask|PointerMotionMask|VirtualEventMask, + CanvasBindProc, (ClientData) canvasPtr); + Tk_CreateSelHandler(canvasPtr->tkwin, XA_PRIMARY, XA_STRING, + CanvasFetchSelection, (ClientData) canvasPtr, XA_STRING); + + if (Tk_InitOptions(interp, (char *) canvasPtr, optionTable, canvasPtr->tkwin) + != TCL_OK) { + Tk_DestroyWindow(canvasPtr->tkwin); + return TCL_ERROR; + } + if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) { + goto error; + } + + /* + * Create the root item as a group item. + * Need to set the tag "root" by hand since its configProc + * forbids this for the root item. + */ + ItemCreate(interp, canvasPtr, &tkGroupType, 1, &rootItemPtr, 0, NULL); + rootItemPtr->pathTagsPtr = TkPathAllocTagsFromObj(NULL, + Tcl_NewStringObj("root", -1)); + canvasPtr->rootItemPtr = rootItemPtr; + + Tcl_SetResult(interp, Tk_PathName(canvasPtr->tkwin), TCL_STATIC); + return TCL_OK; + + error: + Tk_DestroyWindow(canvasPtr->tkwin); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * CanvasWidgetCmd -- + * + * This function 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 +CanvasWidgetCmd( + ClientData clientData, /* Information about canvas widget. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *CONST objv[]) /* Argument objects. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) clientData; + int c, result; + Tcl_Obj *resultObjPtr; + Tk_PathItem *itemPtr = NULL;/* Initialization needed only to prevent + * compiler warning. */ +#ifdef USE_OLD_TAG_SEARCH + TagSearch search; +#else /* USE_OLD_TAG_SEARCH */ + TagSearch *searchPtr = NULL;/* Allocated by first TagSearchScan, freed by + * TagSearchDestroy */ +#endif /* USE_OLD_TAG_SEARCH */ + + int index; + static CONST char *optionStrings[] = { + "addtag", "ancestors", "bbox", "bind", "canvasx", + "canvasy", "cget", "children", "configure", "coords", + "create", "dchars", "delete", + "depth", "distance", "dtag", + "find", "firstchild", "focus", "gettags", + "gradient", "icursor", + "index", "insert", "itemcget", "itemconfigure", "lastchild", + "lower", "move", "nextsibling", + "parent", "prevsibling", "postscript", "raise", + "scale", "scan", "select", "style", + "type", "types", + "xview", "yview", +#if 1 + "debugtree", +#endif + NULL + }; + enum options { + CANV_ADDTAG, CANV_ANCESTORS, CANV_BBOX, CANV_BIND, CANV_CANVASX, + CANV_CANVASY, CANV_CGET, CANV_CHILDREN, CANV_CONFIGURE, CANV_COORDS, + CANV_CREATE, CANV_DCHARS, CANV_DELETE, + CANV_DEPTH, CANV_DISTANCE, CANV_DTAG, + CANV_FIND, CANV_FIRSTCHILD, CANV_FOCUS, CANV_GETTAGS, + CANV_GRADIENT, CANV_ICURSOR, + CANV_INDEX, CANV_INSERT, CANV_ITEMCGET, CANV_ITEMCONFIGURE, CANV_LASTCHILD, + CANV_LOWER, CANV_MOVE, CANV_NEXTSIBLING, + CANV_PARENT, CANV_PREVSIBLING, CANV_POSTSCRIPT, CANV_RAISE, + CANV_SCALE, CANV_SCAN, CANV_SELECT, CANV_STYLE, + CANV_TYPE, CANV_TYPES, + CANV_XVIEW, CANV_YVIEW, +#if 1 + CANV_DEBUGTREE, +#endif + }; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + Tcl_Preserve((ClientData) canvasPtr); + + result = TCL_OK; + switch ((enum options) index) { + case CANV_ADDTAG: { + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, "tag searchCommand ?arg arg ...?"); + result = TCL_ERROR; + goto done; + } +#ifdef USE_OLD_TAG_SEARCH + result = FindItems(interp, canvasPtr, objc, objv, objv[2], 3); +#else /* USE_OLD_TAG_SEARCH */ + result = FindItems(interp, canvasPtr, objc, objv, objv[2], 3, &searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + case CANV_ANCESTORS: { + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + Tcl_Obj *listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); + Tcl_Obj *obj; + Tk_PathItem *walkPtr; + + walkPtr = itemPtr->parentPtr; + while (walkPtr != NULL) { + + /* + * Insert items higher in the tree first. + */ + obj = Tcl_NewIntObj(walkPtr->id); + Tcl_ListObjReplace(NULL, listPtr, 0, 0, 1, &obj); + walkPtr = walkPtr->parentPtr; + } + Tcl_SetObjResult(interp, listPtr); + } else { + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(objv[2]), + "\" doesn't match any items", NULL); + goto done; + } + break; + } + case CANV_BBOX: { + int i, gotAny; + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; /* Initializations needed only + * to prevent overcautious + * compiler warnings. */ + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?tagOrId ...?"); + result = TCL_ERROR; + goto done; + } + gotAny = 0; + for (i = 2; i < objc; i++) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, goto done) { + + /* + * Groups bbox are only updated lazily, when needed. + */ + if (itemPtr->firstChildPtr != NULL) { + TkPathCanvasGroupBbox((Tk_PathCanvas) canvasPtr, itemPtr, + &itemPtr->x1, &itemPtr->y1, &itemPtr->x2, &itemPtr->y2); + } + if ((itemPtr->x1 >= itemPtr->x2) + || (itemPtr->y1 >= itemPtr->y2)) { + continue; + } + if (!gotAny) { + x1 = itemPtr->x1; + y1 = itemPtr->y1; + x2 = itemPtr->x2; + y2 = itemPtr->y2; + gotAny = 1; + } else { + if (itemPtr->x1 < x1) { + x1 = itemPtr->x1; + } + if (itemPtr->y1 < y1) { + y1 = itemPtr->y1; + } + if (itemPtr->x2 > x2) { + x2 = itemPtr->x2; + } + if (itemPtr->y2 > y2) { + y2 = itemPtr->y2; + } + } + } + } + if (gotAny) { + Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); + + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(x1)); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(y1)); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(x2)); + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(y2)); + Tcl_SetObjResult(interp, listObj); + } + break; + } + case CANV_BIND: { + ClientData object; + + if ((objc < 3) || (objc > 5)) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?sequence? ?command?"); + result = TCL_ERROR; + goto done; + } + + /* + * Figure out what object to use for the binding (individual item vs. + * tag). + */ + + object = 0; +#ifdef USE_OLD_TAG_SEARCH + if (isdigit(UCHAR(Tcl_GetString(objv[2])[0]))) { + int id; + char *end; + Tcl_HashEntry *entryPtr; + + id = strtoul(Tcl_GetString(objv[2]), &end, 0); + if (*end != 0) { + goto bindByTag; + } + entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id); + if (entryPtr != NULL) { + itemPtr = (Tk_PathItem *) Tcl_GetHashValue(entryPtr); + object = (ClientData) itemPtr; + } + + if (object == 0) { + Tcl_AppendResult(interp, "item \"", Tcl_GetString(objv[2]), + "\" doesn't exist", NULL); + result = TCL_ERROR; + goto done; + } + } else { + bindByTag: + object = (ClientData) Tk_GetUid(Tcl_GetString(objv[2])); + } +#else /* USE_OLD_TAG_SEARCH */ + result = TagSearchScan(canvasPtr, objv[2], &searchPtr); + if (result != TCL_OK) { + goto done; + } + if (searchPtr->type == SEARCH_TYPE_ID) { + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, + (char *) INT2PTR(searchPtr->id)); + if (entryPtr != NULL) { + itemPtr = (Tk_PathItem *) Tcl_GetHashValue(entryPtr); + object = (ClientData) itemPtr; + } + + if (object == 0) { + Tcl_AppendResult(interp, "item \"", Tcl_GetString(objv[2]), + "\" doesn't exist", NULL); + result = TCL_ERROR; + goto done; + } + } else { + object = (ClientData) searchPtr->expr->uid; + } +#endif /* USE_OLD_TAG_SEARCH */ + + /* + * Make a binding table if the canvas doesn't already have one. + */ + + if (canvasPtr->bindingTable == NULL) { + canvasPtr->bindingTable = Tk_CreateBindingTable(interp); + } + + if (objc == 5) { + int append = 0; + unsigned long mask; + char* argv4 = Tcl_GetString(objv[4]); + + if (argv4[0] == 0) { + result = Tk_DeleteBinding(interp, canvasPtr->bindingTable, + object, Tcl_GetString(objv[3])); + goto done; + } +#ifndef USE_OLD_TAG_SEARCH + if (searchPtr->type == SEARCH_TYPE_EXPR) { + /* + * If new tag expression, then insert in linked list. + */ + + TagSearchExpr *expr, **lastPtr; + + lastPtr = &(canvasPtr->bindTagExprs); + while ((expr = *lastPtr) != NULL) { + if (expr->uid == searchPtr->expr->uid) { + break; + } + lastPtr = &(expr->next); + } + if (!expr) { + /* + * Transfer ownership of expr to bindTagExprs list. + */ + + *lastPtr = searchPtr->expr; + searchPtr->expr->next = NULL; + + /* + * Flag in TagSearch that expr has changed ownership so + * that TagSearchDestroy doesn't try to free it. + */ + + searchPtr->expr = NULL; + } + } +#endif /* not USE_OLD_TAG_SEARCH */ + if (argv4[0] == '+') { + argv4++; + append = 1; + } + mask = Tk_CreateBinding(interp, canvasPtr->bindingTable, + object, Tcl_GetString(objv[3]), argv4, append); + if (mask == 0) { + result = TCL_ERROR; + goto done; + } + if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask + |Button2MotionMask|Button3MotionMask|Button4MotionMask + |Button5MotionMask|ButtonPressMask|ButtonReleaseMask + |EnterWindowMask|LeaveWindowMask|KeyPressMask + |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) { + Tk_DeleteBinding(interp, canvasPtr->bindingTable, + object, Tcl_GetString(objv[3])); + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "requested illegal events; ", + "only key, button, motion, enter, leave, and virtual ", + "events may be used", NULL); + result = TCL_ERROR; + goto done; + } + } else if (objc == 4) { + CONST char *command; + + command = Tk_GetBinding(interp, canvasPtr->bindingTable, + object, Tcl_GetString(objv[3])); + if (command == NULL) { + CONST char *string; + + string = Tcl_GetStringResult(interp); + + /* + * Ignore missing binding errors. This is a special hack that + * relies on the error message returned by FindSequence in + * tkBind.c. + */ + + if (string[0] != '\0') { + result = TCL_ERROR; + goto done; + } else { + Tcl_ResetResult(interp); + } + } else { + Tcl_SetResult(interp, (char *) command, TCL_STATIC); + } + } else { + Tk_GetAllBindings(interp, canvasPtr->bindingTable, object); + } + break; + } + case CANV_CANVASX: { + int x; + double grid; + char buf[TCL_DOUBLE_SPACE]; + + if ((objc < 3) || (objc > 4)) { + Tcl_WrongNumArgs(interp, 2, objv, "screenx ?gridspacing?"); + result = TCL_ERROR; + goto done; + } + if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, objv[2], &x) != TCL_OK) { + result = TCL_ERROR; + goto done; + } + if (objc == 4) { + if (Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, objv[3], + &grid) != TCL_OK) { + result = TCL_ERROR; + goto done; + } + } else { + grid = 0.0; + } + x += canvasPtr->xOrigin; + Tcl_PrintDouble(interp, GridAlign((double) x, grid), buf); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + break; + } + case CANV_CANVASY: { + int y; + double grid; + char buf[TCL_DOUBLE_SPACE]; + + if ((objc < 3) || (objc > 4)) { + Tcl_WrongNumArgs(interp, 2, objv, "screeny ?gridspacing?"); + result = TCL_ERROR; + goto done; + } + if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, objv[2], &y) != TCL_OK) { + result = TCL_ERROR; + goto done; + } + if (objc == 4) { + if (Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, + objv[3], &grid) != TCL_OK) { + result = TCL_ERROR; + goto done; + } + } else { + grid = 0.0; + } + y += canvasPtr->yOrigin; + Tcl_PrintDouble(interp, GridAlign((double) y, grid), buf); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + break; + } + case CANV_CGET: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); + result = TCL_ERROR; + goto done; + } + resultObjPtr = Tk_GetOptionValue(interp, (char *) canvasPtr, + canvasPtr->optionTable, objv[2], canvasPtr->tkwin); + if (resultObjPtr == NULL) { + goto done; + } else { + Tcl_SetObjResult(interp, resultObjPtr); + } + break; + } + case CANV_CHILDREN: { + Tcl_Obj *listObj; + Tk_PathItem *childPtr; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + listObj = Tcl_NewListObj(0, NULL); + childPtr = itemPtr->firstChildPtr; + while (childPtr != NULL) { + Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(childPtr->id)); + childPtr = childPtr->nextPtr; + } + Tcl_SetObjResult(interp, listObj); + } else { + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(objv[3]), + "\" doesn't match any items", NULL); + goto done; + } + break; + } + case CANV_CONFIGURE: { + if (objc <= 3) { + resultObjPtr = Tk_GetOptionInfo(interp, (char *) canvasPtr, + canvasPtr->optionTable, (objc == 3) ? objv[2] : NULL, + canvasPtr->tkwin); + if (resultObjPtr == NULL) { + goto done; + } else { + Tcl_SetObjResult(interp, resultObjPtr); + } + } else { + result = ConfigureCanvas(interp, canvasPtr, objc-2, objv+2, + TK_CONFIG_ARGV_ONLY); + } + break; + } + case CANV_COORDS: { + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?x y x y ...?"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + if (objc != 3) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + } + if (itemPtr->typePtr->coordProc != NULL) { + result = (*itemPtr->typePtr->coordProc)(interp, + (Tk_PathCanvas) canvasPtr, itemPtr, objc-3, objv+3); + } + if (objc != 3) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + } + } + break; + } + case CANV_CREATE: { + Tk_PathItemType *typePtr; + Tk_PathItemType *matchPtr = NULL; + Tk_PathItem *itemPtr; + char *arg; + int length; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "type ?arg arg ...?"); + result = TCL_ERROR; + goto done; + } + arg = Tcl_GetStringFromObj(objv[2], &length); + c = arg[0]; + Tcl_MutexLock(&typeListMutex); + for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) { + if ((c == typePtr->name[0]) + && (strncmp(arg, typePtr->name, (unsigned)length) == 0)) { + if (matchPtr != NULL) { + Tcl_MutexUnlock(&typeListMutex); + badType: + Tcl_AppendResult(interp, + "unknown or ambiguous item type \"",arg,"\"",NULL); + result = TCL_ERROR; + goto done; + } + matchPtr = typePtr; + } + } + /* + * Can unlock now because we no longer look at the fields of + * the matched item type that are potentially modified by + * other threads. + */ + Tcl_MutexUnlock(&typeListMutex); + if (matchPtr == NULL) { + goto badType; + } + if ((strncmp("group", matchPtr->name, (unsigned)length) != 0) && + (objc < 4)) { + /* + * Allow more specific error return. Groups have no coords. + */ + Tcl_WrongNumArgs(interp, 3, objv, "coords ?arg arg ...?"); + result = TCL_ERROR; + goto done; + } + typePtr = matchPtr; + + result = ItemCreate(interp, canvasPtr, typePtr, 0, &itemPtr, objc-3, objv+3); + if (result != TCL_OK) { + result = TCL_ERROR; + goto done; + } + canvasPtr->hotPtr = itemPtr; + canvasPtr->hotPrevPtr = itemPtr->prevPtr; + + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + canvasPtr->flags |= REPICK_NEEDED; + Tcl_SetObjResult(interp, Tcl_NewIntObj(itemPtr->id)); + break; + } + case CANV_DCHARS: { + int first, last; + int x1,x2,y1,y2; + + if ((objc != 4) && (objc != 5)) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId first ?last?"); + result = TCL_ERROR; + goto done; + } + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + if ((itemPtr->typePtr->indexProc == NULL) + || (itemPtr->typePtr->dCharsProc == NULL)) { + continue; + } + result = itemPtr->typePtr->indexProc(interp, + (Tk_PathCanvas) canvasPtr, itemPtr, (char *) objv[3], + &first); + if (result != TCL_OK) { + goto done; + } + if (objc == 5) { + result = itemPtr->typePtr->indexProc(interp, + (Tk_PathCanvas) canvasPtr, itemPtr, (char *) objv[4], + &last); + if (result != TCL_OK) { + goto done; + } + } else { + last = first; + } + + /* + * Redraw both item's old and new areas: it's possible that a + * delete could result in a new area larger than the old area. + * Except if the insertProc sets the TK_ITEM_DONT_REDRAW flag, + * nothing more needs to be done. + */ + + x1 = itemPtr->x1; y1 = itemPtr->y1; + x2 = itemPtr->x2; y2 = itemPtr->y2; + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; + (*itemPtr->typePtr->dCharsProc)((Tk_PathCanvas) canvasPtr, + itemPtr, first, last); + if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) { + Tk_PathCanvasEventuallyRedraw((Tk_PathCanvas) canvasPtr, + x1, y1, x2, y2); + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + } + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; + } + break; + } + case CANV_DEBUGTREE: { + Tk_PathItem *walkPtr, *tmpPtr; + char tmp[256], info[256], *s; + int depth; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + result = TCL_ERROR; + goto done; + } + for (walkPtr = canvasPtr->rootItemPtr; walkPtr != NULL; + walkPtr = TkPathCanvasItemIteratorNext(walkPtr)) { + depth = 0; + tmpPtr = walkPtr; + while (tmpPtr->parentPtr != NULL) { + depth++; + tmpPtr = tmpPtr->parentPtr; + } + if (walkPtr->firstChildPtr != NULL) { + s = "----"; + } else { + s = ""; + } + info[0] = '\0'; + DebugGetItemInfo(walkPtr, info); + sprintf(tmp, "%*d%s\t%s (itemPtr=%p)\n", 4*depth+3, walkPtr->id, s, info, walkPtr); + Tcl_WriteChars(Tcl_GetChannel(interp, "stdout", NULL), tmp, -1); + } + break; + } + case CANV_DELETE: { + int i; + + /* + * Since deletinga group item implicitly deletes all its children + * we may unintentionally try to delete an item more than once. + * We therefore flatten (parent = root) all items first. + */ + for (i = 2; i < objc; i++) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, goto done) { + if (itemPtr->id == 0) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("the root item cannot be deleted", -1)); + result = TCL_ERROR; + goto done; + } + /* + * This will also delete all its descendants by + * recursive calls. + */ + ItemDelete(canvasPtr, itemPtr); + } + } + break; + } + case CANV_DEPTH: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + Tcl_SetObjResult(interp, Tcl_NewIntObj(TkPathCanvasGetDepth(itemPtr))); + } else { + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(objv[2]), + "\" doesn't match any items", NULL); + goto done; + } + break; + } + case CANV_DISTANCE: { + double point[2], dist; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId x y"); + result = TCL_ERROR; + goto done; + } + if ((Tcl_GetDoubleFromObj(interp, objv[3], &point[0]) != TCL_OK) || + (Tcl_GetDoubleFromObj(interp, objv[4], &point[1]) != TCL_OK)) { + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + dist = (*itemPtr->typePtr->pointProc)((Tk_PathCanvas) canvasPtr, itemPtr, point); + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(dist)); + } else { + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(objv[2]), + "\" doesn't match any items", NULL); + goto done; + } + break; + } + case CANV_DTAG: { + Tk_PathTags *ptagsPtr; + Tk_Uid tag; + int i; + + if ((objc != 3) && (objc != 4)) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?tagToDelete?"); + result = TCL_ERROR; + goto done; + } + if (objc == 4) { + tag = Tk_GetUid(Tcl_GetString(objv[3])); + } else { + tag = Tk_GetUid(Tcl_GetString(objv[2])); + } + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + ptagsPtr = itemPtr->pathTagsPtr; + if (ptagsPtr != NULL) { + for (i = ptagsPtr->numTags-1; i >= 0; i--) { + if (ptagsPtr->tagPtr[i] == tag) { + ptagsPtr->tagPtr[i] = ptagsPtr->tagPtr[ptagsPtr->numTags-1]; + ptagsPtr->numTags--; + } + } + } + } + break; + } + case CANV_FIND: { + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "searchCommand ?arg arg ...?"); + result = TCL_ERROR; + goto done; + } +#ifdef USE_OLD_TAG_SEARCH + result = FindItems(interp, canvasPtr, objc, objv, NULL, 2); +#else /* USE_OLD_TAG_SEARCH */ + result = FindItems(interp, canvasPtr, objc, objv, NULL, 2, + &searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + case CANV_FIRSTCHILD: { + Tk_PathItem *childPtr; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + childPtr = itemPtr->firstChildPtr; + if (childPtr != NULL) { + Tcl_SetObjResult(interp, Tcl_NewIntObj(childPtr->id)); + } + } else { + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(objv[3]), + "\" doesn't match any items", NULL); + goto done; + } + break; + } + case CANV_FOCUS: { + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?tagOrId?"); + result = TCL_ERROR; + goto done; + } + itemPtr = canvasPtr->textInfo.focusItemPtr; + if (objc == 2) { + if (itemPtr != NULL) { + char buf[TCL_INTEGER_SPACE]; + + sprintf(buf, "%d", itemPtr->id); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + } + goto done; + } + if ((itemPtr != NULL) && (canvasPtr->textInfo.gotFocus)) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + } + if (Tcl_GetString(objv[2])[0] == 0) { + canvasPtr->textInfo.focusItemPtr = NULL; + goto done; + } + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + if (itemPtr->typePtr->icursorProc != NULL) { + break; + } + } + if (itemPtr == NULL) { + goto done; + } + canvasPtr->textInfo.focusItemPtr = itemPtr; + if (canvasPtr->textInfo.gotFocus) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + } + break; + } + case CANV_GETTAGS: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + int i; + Tk_PathTags *ptagsPtr; + +#ifdef USE_OLD_CODE + for (i = 0; i < itemPtr->numTags; i++) { + Tcl_AppendElement(interp, (char *) itemPtr->tagPtr[i]); + } +#else + ptagsPtr = itemPtr->pathTagsPtr; + if (ptagsPtr != NULL) { + for (i = 0; i < ptagsPtr->numTags; i++) { + Tcl_AppendElement(interp, (char *) ptagsPtr->tagPtr[i]); + } + } +#endif + } + break; + } + case CANV_GRADIENT: { + result = CanvasGradientObjCmd(interp, canvasPtr, objc, objv); + break; + } + case CANV_ICURSOR: { + int index; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId index"); + result = TCL_ERROR; + goto done; + } + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + if ((itemPtr->typePtr->indexProc == NULL) + || (itemPtr->typePtr->icursorProc == NULL)) { + goto done; + } + result = itemPtr->typePtr->indexProc(interp, + (Tk_PathCanvas) canvasPtr, itemPtr, (char *) objv[3], + &index); + if (result != TCL_OK) { + goto done; + } + (*itemPtr->typePtr->icursorProc)((Tk_PathCanvas) canvasPtr, itemPtr, + index); + if ((itemPtr == canvasPtr->textInfo.focusItemPtr) + && (canvasPtr->textInfo.cursorOn)) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + } + } + break; + } + case CANV_INDEX: { + int index; + char buf[TCL_INTEGER_SPACE]; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId string"); + result = TCL_ERROR; + goto done; + } + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + if (itemPtr->typePtr->indexProc != NULL) { + break; + } + } + if (itemPtr == NULL) { + Tcl_AppendResult(interp, "can't find an indexable item \"", + Tcl_GetString(objv[2]), "\"", NULL); + result = TCL_ERROR; + goto done; + } + result = itemPtr->typePtr->indexProc(interp, (Tk_PathCanvas) canvasPtr, + itemPtr, (char *) objv[3], &index); + if (result != TCL_OK) { + goto done; + } + sprintf(buf, "%d", index); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + break; + } + case CANV_INSERT: { + int beforeThis; + int x1,x2,y1,y2; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId beforeThis string"); + result = TCL_ERROR; + goto done; + } + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + if ((itemPtr->typePtr->indexProc == NULL) + || (itemPtr->typePtr->insertProc == NULL)) { + continue; + } + result = itemPtr->typePtr->indexProc(interp, + (Tk_PathCanvas) canvasPtr, itemPtr, (char *) objv[3], + &beforeThis); + if (result != TCL_OK) { + goto done; + } + + /* + * Redraw both item's old and new areas: it's possible that an + * insertion could result in a new area either larger or smaller + * than the old area. Except if the insertProc sets the + * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done. + */ + + x1 = itemPtr->x1; y1 = itemPtr->y1; + x2 = itemPtr->x2; y2 = itemPtr->y2; + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; + (*itemPtr->typePtr->insertProc)((Tk_PathCanvas) canvasPtr, + itemPtr, beforeThis, (char *) objv[4]); + if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) { + Tk_PathCanvasEventuallyRedraw((Tk_PathCanvas) canvasPtr, + x1, y1, x2, y2); + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + } + itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW; + } + break; + } + case CANV_ITEMCGET: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId option"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + resultObjPtr = Tk_GetOptionValue(canvasPtr->interp, (char *) itemPtr, + itemPtr->optionTable, objv[3], canvasPtr->tkwin); + if (resultObjPtr == NULL) { + result = TCL_ERROR; + goto done; + } else { + Tcl_SetObjResult(interp, resultObjPtr); + } + } + break; + } + case CANV_ITEMCONFIGURE: { + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?option value ...?"); + result = TCL_ERROR; + goto done; + } + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + if (objc <= 4) { + resultObjPtr = Tk_GetOptionInfo(canvasPtr->interp, (char *) itemPtr, + itemPtr->optionTable, (objc == 4) ? objv[3] : NULL, + canvasPtr->tkwin); + if (resultObjPtr == NULL) { + result = TCL_ERROR; + goto done; + } else { + Tcl_SetObjResult(interp, resultObjPtr); + } + } else { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + result = (*itemPtr->typePtr->configProc)(interp, + (Tk_PathCanvas) canvasPtr, itemPtr, objc-3, objv+3, + TK_CONFIG_ARGV_ONLY); + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + canvasPtr->flags |= REPICK_NEEDED; + } + if ((result != TCL_OK) || (objc < 5)) { + break; + } + } + break; + } + case CANV_LASTCHILD: { + Tk_PathItem *childPtr; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + childPtr = itemPtr->lastChildPtr; + if (childPtr != NULL) { + Tcl_SetObjResult(interp, Tcl_NewIntObj(childPtr->id)); + } + } else { + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(objv[3]), + "\" doesn't match any items", NULL); + goto done; + } + break; + } + case CANV_LOWER: { + Tk_PathItem *itemPtr; + + if ((objc != 3) && (objc != 4)) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?belowThis?"); + result = TCL_ERROR; + goto done; + } + + /* + * First find the item just after which we'll insert the named items. + */ + + if (objc == 3) { + itemPtr = NULL; + } else { + FIRST_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done); + if (itemPtr == NULL) { + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(objv[3]), + "\" doesn't match any items", NULL); + goto done; + } + itemPtr = itemPtr->prevPtr; + } +#ifdef USE_OLD_TAG_SEARCH + RelinkItems(canvasPtr, objv[2], itemPtr); +#else /* USE_OLD_TAG_SEARCH */ + result = RelinkItems(canvasPtr, objv[2], itemPtr, &searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + case CANV_MOVE: { + double xAmount, yAmount; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId xAmount yAmount"); + result = TCL_ERROR; + goto done; + } + if ((Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, objv[3], + &xAmount) != TCL_OK) || (Tk_PathCanvasGetCoordFromObj(interp, + (Tk_PathCanvas) canvasPtr, objv[4], &yAmount) != TCL_OK)) { + result = TCL_ERROR; + goto done; + } + + /* === EB - 22-apr-2010: round the deltas to the nearest integer to avoid round-off errors */ + xAmount = (double)((int)(xAmount + (xAmount > 0 ? 0.5 : -0.5))); + yAmount = (double)((int)(yAmount + (yAmount > 0 ? 0.5 : -0.5))); + /* === */ + + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + (void) (*itemPtr->typePtr->translateProc)((Tk_PathCanvas) canvasPtr, + itemPtr, xAmount, yAmount); + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + canvasPtr->flags |= REPICK_NEEDED; + } + break; + } + case CANV_NEXTSIBLING: { + Tk_PathItem *nextPtr; + + // @@@ TODO: add optional argument like TreeCtrl has. + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + nextPtr = itemPtr->nextPtr; + if (nextPtr != NULL) { + Tcl_SetObjResult(interp, Tcl_NewIntObj(nextPtr->id)); + } + } else { + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(objv[2]), + "\" doesn't match any items", NULL); + goto done; + } + break; + } + case CANV_PARENT: { + int id; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "id"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + if (itemPtr->id == 0) { + id = -1; // @@@ TODO: What else to return? */ + } else { + id = itemPtr->parentPtr->id; + } + Tcl_SetObjResult(interp, Tcl_NewIntObj(id)); + } else { + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(objv[2]), + "\" doesn't match any items", NULL); + goto done; + } + break; + } + case CANV_POSTSCRIPT: { + result = TkCanvPostscriptCmd(canvasPtr, interp, objc, objv); + break; + } + case CANV_PREVSIBLING: { + Tk_PathItem *prevPtr; + + // @@@ TODO: add optional argument like TreeCtrl has. + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + prevPtr = itemPtr->prevPtr; + if (prevPtr != NULL) { + Tcl_SetObjResult(interp, Tcl_NewIntObj(prevPtr->id)); + } + } else { + Tcl_AppendResult(interp, "tag \"", Tcl_GetString(objv[2]), + "\" doesn't match any items", NULL); + goto done; + } + break; + } + case CANV_RAISE: { + Tk_PathItem *prevPtr; + + if ((objc != 3) && (objc != 4)) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?aboveThis?"); + result = TCL_ERROR; + goto done; + } + + /* + * First find the item just after which we'll insert the named items. + */ + + if (objc == 3) { + prevPtr = canvasPtr->rootItemPtr->lastChildPtr; + } else { + prevPtr = NULL; + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done) { + prevPtr = itemPtr; + } + if (prevPtr == NULL) { + Tcl_AppendResult(interp, "tagOrId \"", Tcl_GetString(objv[3]), + "\" doesn't match any items", NULL); + result = TCL_ERROR; + goto done; + } + } +#ifdef USE_OLD_TAG_SEARCH + RelinkItems(canvasPtr, objv[2], prevPtr); +#else /* USE_OLD_TAG_SEARCH */ + result = RelinkItems(canvasPtr, objv[2], prevPtr, &searchPtr); +#endif /* USE_OLD_TAG_SEARCH */ + break; + } + case CANV_SCALE: { + double xOrigin, yOrigin, xScale, yScale; + + if (objc != 7) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId xOrigin yOrigin xScale yScale"); + result = TCL_ERROR; + goto done; + } + if ((Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, + objv[3], &xOrigin) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, + objv[4], &yOrigin) != TCL_OK) + || (Tcl_GetDoubleFromObj(interp, objv[5], &xScale) != TCL_OK) + || (Tcl_GetDoubleFromObj(interp, objv[6], &yScale) != TCL_OK)) { + result = TCL_ERROR; + goto done; + } + if ((xScale == 0.0) || (yScale == 0.0)) { + Tcl_SetResult(interp, "scale factor cannot be zero", TCL_STATIC); + result = TCL_ERROR; + goto done; + } + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + (void) (*itemPtr->typePtr->scaleProc)((Tk_PathCanvas) canvasPtr, + itemPtr, xOrigin, yOrigin, xScale, yScale); + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + canvasPtr->flags |= REPICK_NEEDED; + } + break; + } + case CANV_SCAN: { + int x, y, gain = 10; + static CONST char *optionStrings[] = { + "mark", "dragto", NULL + }; + + if (objc < 5) { + Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y ?dragGain?"); + result = TCL_ERROR; + } else if (Tcl_GetIndexFromObj(interp, objv[2], optionStrings, + "scan option", 0, &index) != TCL_OK) { + result = TCL_ERROR; + } else if ((objc != 5) && (objc != 5+index)) { + Tcl_WrongNumArgs(interp, 3, objv, index?"x y ?gain?":"x y"); + result = TCL_ERROR; + } else if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) + || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)){ + result = TCL_ERROR; + } else if ((objc == 6) && + (Tcl_GetIntFromObj(interp, objv[5], &gain) != TCL_OK)) { + result = TCL_ERROR; + } else if (!index) { + canvasPtr->scanX = x; + canvasPtr->scanXOrigin = canvasPtr->xOrigin; + canvasPtr->scanY = y; + canvasPtr->scanYOrigin = canvasPtr->yOrigin; + } else { + int newXOrigin, newYOrigin, tmp; + + /* + * Compute a new view origin for the canvas, amplifying the + * mouse motion. + */ + + tmp = canvasPtr->scanXOrigin - gain*(x - canvasPtr->scanX) + - canvasPtr->scrollX1; + newXOrigin = canvasPtr->scrollX1 + tmp; + tmp = canvasPtr->scanYOrigin - gain*(y - canvasPtr->scanY) + - canvasPtr->scrollY1; + newYOrigin = canvasPtr->scrollY1 + tmp; + CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin); + } + break; + } + case CANV_SELECT: { + int index, optionindex; + static CONST char *optionStrings[] = { + "adjust", "clear", "from", "item", "to", NULL + }; + enum options { + CANV_ADJUST, CANV_CLEAR, CANV_FROM, CANV_ITEM, CANV_TO + }; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option ?tagOrId? ?arg?"); + result = TCL_ERROR; + goto done; + } + if (objc >= 4) { + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done) { + if ((itemPtr->typePtr->indexProc != NULL) + && (itemPtr->typePtr->selectionProc != NULL)){ + break; + } + } + if (itemPtr == NULL) { + Tcl_AppendResult(interp, + "can't find an indexable and selectable item \"", + Tcl_GetString(objv[3]), "\"", NULL); + result = TCL_ERROR; + goto done; + } + } + if (objc == 5) { + result = itemPtr->typePtr->indexProc(interp, + (Tk_PathCanvas) canvasPtr, itemPtr, (char *) objv[4], + &index); + if (result != TCL_OK) { + goto done; + } + } + if (Tcl_GetIndexFromObj(interp, objv[2], optionStrings, + "select option", 0, &optionindex) != TCL_OK) { + result = TCL_ERROR; + goto done; + } + switch ((enum options) optionindex) { + case CANV_ADJUST: + if (objc != 5) { + Tcl_WrongNumArgs(interp, 3, objv, "tagOrId index"); + result = TCL_ERROR; + goto done; + } + if (canvasPtr->textInfo.selItemPtr == itemPtr) { + if (index < (canvasPtr->textInfo.selectFirst + + canvasPtr->textInfo.selectLast)/2) { + canvasPtr->textInfo.selectAnchor = + canvasPtr->textInfo.selectLast + 1; + } else { + canvasPtr->textInfo.selectAnchor = + canvasPtr->textInfo.selectFirst; + } + } + CanvasSelectTo(canvasPtr, itemPtr, index); + break; + case CANV_CLEAR: + if (objc != 3) { + Tcl_AppendResult(interp, 3, objv, NULL); + result = TCL_ERROR; + goto done; + } + if (canvasPtr->textInfo.selItemPtr != NULL) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, + canvasPtr->textInfo.selItemPtr); + canvasPtr->textInfo.selItemPtr = NULL; + } + goto done; + break; + case CANV_FROM: + if (objc != 5) { + Tcl_WrongNumArgs(interp, 3, objv, "tagOrId index"); + result = TCL_ERROR; + goto done; + } + canvasPtr->textInfo.anchorItemPtr = itemPtr; + canvasPtr->textInfo.selectAnchor = index; + break; + case CANV_ITEM: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + result = TCL_ERROR; + goto done; + } + if (canvasPtr->textInfo.selItemPtr != NULL) { + Tcl_SetObjResult(interp, + Tcl_NewIntObj(canvasPtr->textInfo.selItemPtr->id)); + } + break; + case CANV_TO: + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "tagOrId index"); + result = TCL_ERROR; + goto done; + } + CanvasSelectTo(canvasPtr, itemPtr, index); + break; + } + break; + } + case CANV_STYLE: { + result = CanvasStyleObjCmd(interp, canvasPtr, objc, objv); + break; + } + case CANV_TYPE: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "tag"); + result = TCL_ERROR; + goto done; + } + FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done); + if (itemPtr != NULL) { + Tcl_SetResult(interp, itemPtr->typePtr->name, TCL_STATIC); + } + break; + } + case CANV_TYPES: { + Tk_PathItemType *typePtr; + Tcl_Obj *listObj; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + result = TCL_ERROR; + goto done; + } + listObj = Tcl_NewListObj(0, NULL); + Tcl_MutexLock(&typeListMutex); + for (typePtr = typeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + Tcl_ListObjAppendElement(interp, listObj, + Tcl_NewStringObj(typePtr->name, -1)); + } + Tcl_MutexUnlock(&typeListMutex); + Tcl_SetObjResult(interp, listObj); + break; + } + case CANV_XVIEW: { + int count, type; + int newX = 0; /* Initialization needed only to prevent + * gcc warnings. */ + double fraction; + + if (objc == 2) { + Tcl_SetObjResult(interp, ScrollFractions( + canvasPtr->xOrigin + canvasPtr->inset, + canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin) + - canvasPtr->inset, canvasPtr->scrollX1, + canvasPtr->scrollX2)); + } else { + CONST char **args = TkGetStringsFromObjs(objc, objv); + type = Tk_GetScrollInfo(interp, objc, args, &fraction, &count); + if (args != NULL) { + ckfree((char *) args); + } + switch (type) { + case TK_SCROLL_ERROR: + result = TCL_ERROR; + goto done; + case TK_SCROLL_MOVETO: + newX = canvasPtr->scrollX1 - canvasPtr->inset + + (int) (fraction * (canvasPtr->scrollX2 + - canvasPtr->scrollX1) + 0.5); + break; + case TK_SCROLL_PAGES: + newX = (int) (canvasPtr->xOrigin + count * .9 + * (Tk_Width(canvasPtr->tkwin) - 2*canvasPtr->inset)); + break; + case TK_SCROLL_UNITS: + if (canvasPtr->xScrollIncrement > 0) { + newX = canvasPtr->xOrigin + + count*canvasPtr->xScrollIncrement; + } else { + newX = (int) (canvasPtr->xOrigin + count * .1 + * (Tk_Width(canvasPtr->tkwin) + - 2*canvasPtr->inset)); + } + break; + } + CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin); + } + break; + } + case CANV_YVIEW: { + int count, type; + int newY = 0; /* Initialization needed only to prevent + * gcc warnings. */ + double fraction; + + if (objc == 2) { + Tcl_SetObjResult(interp, ScrollFractions( + canvasPtr->yOrigin + canvasPtr->inset, + canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin) + - canvasPtr->inset, + canvasPtr->scrollY1, canvasPtr->scrollY2)); + } else { + CONST char **args = TkGetStringsFromObjs(objc, objv); + type = Tk_GetScrollInfo(interp, objc, args, &fraction, &count); + if (args != NULL) { + ckfree((char *) args); + } + switch (type) { + case TK_SCROLL_ERROR: + result = TCL_ERROR; + goto done; + case TK_SCROLL_MOVETO: + newY = canvasPtr->scrollY1 - canvasPtr->inset + + (int) (fraction*(canvasPtr->scrollY2 + - canvasPtr->scrollY1) + 0.5); + break; + case TK_SCROLL_PAGES: + newY = (int) (canvasPtr->yOrigin + count * .9 + * (Tk_Height(canvasPtr->tkwin) + - 2*canvasPtr->inset)); + break; + case TK_SCROLL_UNITS: + if (canvasPtr->yScrollIncrement > 0) { + newY = canvasPtr->yOrigin + + count*canvasPtr->yScrollIncrement; + } else { + newY = (int) (canvasPtr->yOrigin + count * .1 + * (Tk_Height(canvasPtr->tkwin) + - 2*canvasPtr->inset)); + } + break; + } + CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY); + } + break; + } + } + + done: +#ifndef USE_OLD_TAG_SEARCH + TagSearchDestroy(searchPtr); +#endif /* not USE_OLD_TAG_SEARCH */ + Tcl_Release((ClientData) canvasPtr); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * DestroyCanvas -- + * + * This function is invoked by Tcl_EventuallyFree or Tcl_Release to clean + * up the internal structure of a canvas at a safe time (when no-one is + * using it anymore). + * + * Results: + * None. + * + * Side effects: + * Everything associated with the canvas is freed up. + * + *---------------------------------------------------------------------- + */ + +static void +DestroyCanvas( + char *memPtr) /* Info about canvas widget. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) memPtr; + Tk_PathItem *itemPtr, *prevItemPtr, *lastPtr = NULL; +#ifndef USE_OLD_TAG_SEARCH + TagSearchExpr *expr, *next; +#endif + + /* + * Free up all of the items in the canvas. + * NB: We need to traverse the tree from the last item + * until reached the root item. + */ + + for (itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + lastPtr = itemPtr; + } + for (itemPtr = lastPtr; itemPtr != NULL; ) { + prevItemPtr = TkPathCanvasItemIteratorPrev(itemPtr); + (*itemPtr->typePtr->deleteProc)((Tk_PathCanvas) canvasPtr, itemPtr, + canvasPtr->display); + ckfree((char *) itemPtr); + itemPtr = prevItemPtr; + } + + /* + * Free up all the stuff that requires special handling, then let + * Tk_FreeOptions handle all the standard option-related stuff. + */ + + Tcl_DeleteHashTable(&canvasPtr->idTable); + + // @@@ TODO: tkwin = NULL! + PathStylesFree(canvasPtr->tkwin, &canvasPtr->styleTable); + Tcl_DeleteHashTable(&canvasPtr->styleTable); + + CanvasGradientsFree(canvasPtr); + Tcl_DeleteHashTable(&canvasPtr->gradientTable); + + if (canvasPtr->pixmapGC != None) { + Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC); + } +#ifndef USE_OLD_TAG_SEARCH + expr = canvasPtr->bindTagExprs; + while (expr) { + next = expr->next; + TagSearchExprDestroy(expr); + expr = next; + } +#endif /* USE_OLD_TAG_SEARCH */ + Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler); + if (canvasPtr->bindingTable != NULL) { + Tk_DeleteBindingTable(canvasPtr->bindingTable); + } + Tk_FreeConfigOptions((char *) canvasPtr, canvasPtr->optionTable, + canvasPtr->tkwin); + canvasPtr->tkwin = NULL; + ckfree((char *) canvasPtr); +} + +/* + *---------------------------------------------------------------------- + * + * ConfigureCanvas -- + * + * This function is called to process an objv/objc list, plus the Tk + * option database, in order to configure (or reconfigure) a canvas + * widget. + * + * 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, such as colors, border width, etc. get set + * for canvasPtr; old resources get freed, if there were any. + * + *---------------------------------------------------------------------- + */ + +static int +ConfigureCanvas( + Tcl_Interp *interp, /* Used for error reporting. */ + TkPathCanvas *canvasPtr, /* Information about widget; may or may not + * already have values for some fields. */ + int objc, /* Number of valid entries in objv. */ + Tcl_Obj *CONST objv[], /* Argument objects. */ + int flags) /* Flags to pass to Tk_ConfigureWidget. */ +{ + XGCValues gcValues; + GC newGC; + Tk_SavedOptions savedOptions; + Tcl_Obj *errorResult = NULL; + int error; + + /* + * The following loop is potentially executed twice. During the first pass + * configuration options get set to their new values. If there is an error + * in this pass, we execute a second pass to restore all the options to + * their previous values. + */ + + for (error = 0; error <= 1; error++) { + if (!error) { + /* + * First pass: set options to new values. + */ + + if (Tk_SetOptions(interp, (char *) canvasPtr, + canvasPtr->optionTable, objc, objv, + canvasPtr->tkwin, &savedOptions, NULL) != TCL_OK) { + continue; + } + } else { + /* + * Second pass: restore options to old values. + */ + + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + if ((canvasPtr->flags & CANVAS_DELETED)) { + + /* + * From tkButton.c_ + * Somehow canvas was deleted - just abort now. [Bug #824479] + */ + return TCL_ERROR; + } + + /* + * Recompute the scroll region. + */ + // @@@ TODO: Revise this code since I'm not completely sure!!! + + canvasPtr->scrollX1 = 0; + canvasPtr->scrollY1 = 0; + canvasPtr->scrollX2 = 0; + canvasPtr->scrollY2 = 0; + if (canvasPtr->regionString != NULL) { + int argc2; + CONST char **argv2; + + if (Tcl_SplitList(canvasPtr->interp, canvasPtr->regionString, + &argc2, &argv2) != TCL_OK) { + ckfree((char *) argv2); + continue; + } + if (argc2 != 4) { + Tcl_AppendResult(interp, "bad scrollRegion \"", + canvasPtr->regionString, "\"", NULL); + ckfree((char *) argv2); + continue; + } + if ((Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin, + argv2[0], &canvasPtr->scrollX1) != TCL_OK) + || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin, + argv2[1], &canvasPtr->scrollY1) != TCL_OK) + || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin, + argv2[2], &canvasPtr->scrollX2) != TCL_OK) + || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin, + argv2[3], &canvasPtr->scrollY2) != TCL_OK)) { + ckfree((char *) argv2); + continue; + } + } + + /* + * A few options need special processing, such as setting the background + * from a 3-D border and creating a GC for copying bits to the screen. + */ + + Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder); + + if (canvasPtr->highlightWidth < 0) { + canvasPtr->highlightWidth = 0; + } + canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth; + + gcValues.function = GXcopy; + gcValues.graphics_exposures = False; + gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel; + newGC = Tk_GetGC(canvasPtr->tkwin, + GCFunction|GCGraphicsExposures|GCForeground, &gcValues); + if (canvasPtr->pixmapGC != None) { + Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC); + } + canvasPtr->pixmapGC = newGC; + + /* + * Reset the desired dimensions for the window. + */ + + Tk_GeometryRequest(canvasPtr->tkwin, canvasPtr->width + 2*canvasPtr->inset, + canvasPtr->height + 2*canvasPtr->inset); + + /* + * Restart the cursor timing sequence in case the on-time or off-time just + * changed. + */ + + if (canvasPtr->textInfo.gotFocus) { + CanvasFocusProc(canvasPtr, 1); + } + + // @@@ TODO: I don't see anywhere this is used. Nothing in man page. */ + if (canvasPtr->tsoffsetPtr != NULL) { + flags = canvasPtr->tsoffsetPtr->flags; + if (flags & TK_OFFSET_LEFT) { + canvasPtr->tsoffsetPtr->xoffset = 0; + } else if (flags & TK_OFFSET_CENTER) { + canvasPtr->tsoffsetPtr->xoffset = canvasPtr->width/2; + } else if (flags & TK_OFFSET_RIGHT) { + canvasPtr->tsoffsetPtr->xoffset = canvasPtr->width; + } + if (flags & TK_OFFSET_TOP) { + canvasPtr->tsoffsetPtr->yoffset = 0; + } else if (flags & TK_OFFSET_MIDDLE) { + canvasPtr->tsoffsetPtr->yoffset = canvasPtr->height/2; + } else if (flags & TK_OFFSET_BOTTOM) { + canvasPtr->tsoffsetPtr->yoffset = canvasPtr->height; + } + } + + /* + * If we reach this on the first pass we are OK and continue below. + */ + break; + } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + } + + /* + * Reset the canvas's origin (this is a no-op unless confine mode has just + * been turned on or the scroll region has changed). + */ + + CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin); + canvasPtr->flags |= UPDATE_SCROLLBARS|REDRAW_BORDERS; + Tk_PathCanvasEventuallyRedraw((Tk_PathCanvas) canvasPtr, + canvasPtr->xOrigin, canvasPtr->yOrigin, + canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), + canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); + if (error) { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } else { + return TCL_OK; + } +} + +/* + *--------------------------------------------------------------------------- + * + * PathCanvasWorldChanged -- + * + * This function is called when the world has changed in some way and the + * widget needs to recompute all its graphics contexts and determine its + * new geometry. + * + * Results: + * None. + * + * Side effects: + * Configures all items in the canvas with a empty argc/argv, for the + * side effect of causing all the items to recompute their geometry and + * to be redisplayed. + * + *--------------------------------------------------------------------------- + */ + +static void +PathCanvasWorldChanged( + ClientData instanceData) /* Information about widget. */ +{ + TkPathCanvas *canvasPtr; + Tk_PathItem *itemPtr; + int result; + + canvasPtr = (TkPathCanvas *) instanceData; + itemPtr = canvasPtr->rootItemPtr; + for ( ; itemPtr != NULL; itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + result = (*itemPtr->typePtr->configProc)(canvasPtr->interp, + (Tk_PathCanvas) canvasPtr, itemPtr, 0, NULL, + TK_CONFIG_ARGV_ONLY); + if (result != TCL_OK) { + Tcl_ResetResult(canvasPtr->interp); + } + } + canvasPtr->flags |= REPICK_NEEDED; + Tk_PathCanvasEventuallyRedraw((Tk_PathCanvas) canvasPtr, + canvasPtr->xOrigin, canvasPtr->yOrigin, + canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), + canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); +} + +/* + * This is a very crude trick to get TkpClipDrawableToRect. + */ +#ifdef TK_PATH_NO_DOUBLE_BUFFERING + +void +TkpClipDrawableToRect( + Display *display, + Drawable d, + int x, int y, + int width, int height) +{ + MacDrawable *macDraw = (MacDrawable *) d; + + if (width < 0 && height < 0) { + macDraw->drawRect = CGRectNull; + macDraw->flags &= ~TK_CLIPPED_DRAW; + } else { + macDraw->drawRect = CGRectMake(x, y, width, height); + macDraw->flags |= TK_CLIPPED_DRAW; + } +} + +#endif + +/* + *-------------------------------------------------------------- + * + * DisplayCanvas -- + * + * This function redraws the contents of a canvas window. It is invoked + * as a do-when-idle handler, so it only runs when there's nothing else + * for the application to do. + * + * Results: + * None. + * + * Side effects: + * Information appears on the screen. + * + *-------------------------------------------------------------- + */ + +static void +DisplayCanvas( + ClientData clientData) /* Information about widget. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) clientData; + Tk_Window tkwin = canvasPtr->tkwin; + Tk_PathItem *itemPtr; + Pixmap pixmap; + int screenX1, screenX2, screenY1, screenY2, width, height; + int flags; + + if (canvasPtr->flags & CANVAS_DELETED) { + return; + } + if (!Tk_IsMapped(tkwin)) { + goto done; + } + + /* + * Choose a new current item if that is needed (this could cause event + * handlers to be invoked). + */ + + while (canvasPtr->flags & REPICK_NEEDED) { + Tcl_Preserve((ClientData) canvasPtr); + canvasPtr->flags &= ~REPICK_NEEDED; + PickCurrentItem(canvasPtr, &canvasPtr->pickEvent); + flags = canvasPtr->flags; + Tcl_Release((ClientData) canvasPtr); + if (flags & CANVAS_DELETED) { + return; + } + } + + /* + * Scan through the item list, registering the bounding box for all items + * that didn't do that for the final coordinates yet. This can be + * determined by the FORCE_REDRAW flag. + */ + + for (itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + if (itemPtr->redraw_flags & FORCE_REDRAW) { + itemPtr->redraw_flags &= ~FORCE_REDRAW; + EventuallyRedrawItem((Tk_PathCanvas)canvasPtr, itemPtr); + itemPtr->redraw_flags &= ~FORCE_REDRAW; + } + } + + /* + * Compute the intersection between the area that needs redrawing and the + * area that's visible on the screen. + */ + + if ((canvasPtr->redrawX1 < canvasPtr->redrawX2) + && (canvasPtr->redrawY1 < canvasPtr->redrawY2)) { + screenX1 = canvasPtr->xOrigin + canvasPtr->inset; + screenY1 = canvasPtr->yOrigin + canvasPtr->inset; + screenX2 = canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset; + screenY2 = canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset; + if (canvasPtr->redrawX1 > screenX1) { + screenX1 = canvasPtr->redrawX1; + } + if (canvasPtr->redrawY1 > screenY1) { + screenY1 = canvasPtr->redrawY1; + } + if (canvasPtr->redrawX2 < screenX2) { + screenX2 = canvasPtr->redrawX2; + } + if (canvasPtr->redrawY2 < screenY2) { + screenY2 = canvasPtr->redrawY2; + } + if ((screenX1 >= screenX2) || (screenY1 >= screenY2)) { + goto borders; + } + + width = screenX2 - screenX1; + height = screenY2 - screenY1; + +#ifndef TK_PATH_NO_DOUBLE_BUFFERING + /* + * Redrawing is done in a temporary pixmap that is allocated here and + * freed at the end of the function. All drawing is done to the + * pixmap, and the pixmap is copied to the screen at the end of the + * function. The temporary pixmap serves two purposes: + * + * 1. It provides a smoother visual effect (no clearing and gradual + * redraw will be visible to users). + * 2. It allows us to redraw only the objects that overlap the redraw + * area. Otherwise incorrect results could occur from redrawing + * things that stick outside of the redraw area (we'd have to + * redraw everything in order to make the overlaps look right). + * + * Some tricky points about the pixmap: + * + * 1. We only allocate a large enough pixmap to hold the area that has + * to be redisplayed. This saves time in in the X server for large + * objects that cover much more than the area being redisplayed: + * only the area of the pixmap will actually have to be redrawn. + * 2. Some X servers (e.g. the one for DECstations) have troubles with + * with characters that overlap an edge of the pixmap (on the DEC + * servers, as of 8/18/92, such characters are drawn one pixel too + * far to the right). To handle this problem, make the pixmap a bit + * larger than is absolutely needed so that for normal-sized fonts + * the characters that overlap the edge of the pixmap will be + * outside the area we care about. + */ + + 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)); +#else + canvasPtr->drawableXOrigin = canvasPtr->xOrigin; + canvasPtr->drawableYOrigin = canvasPtr->yOrigin; + pixmap = Tk_WindowId(tkwin); + TkpClipDrawableToRect(Tk_Display(tkwin), pixmap, + screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin, + width, height); +#endif /* TK_PATH_NO_DOUBLE_BUFFERING */ + + /* + * Clear the area to be redrawn. + */ + + XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC, + screenX1 - canvasPtr->drawableXOrigin, + screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width, + (unsigned int) height); + + /* + * Scan through the item list, redrawing those items that need it. An + * item must be redraw if either (a) it intersects the smaller + * on-screen area or (b) it intersects the full canvas area and its + * type requests that it be redrawn always (e.g. so subwindows can be + * unmapped when they move off-screen). + */ + + for (itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + if ((itemPtr->x1 >= screenX2) + || (itemPtr->y1 >= screenY2) + || (itemPtr->x2 < screenX1) + || (itemPtr->y2 < screenY1)) { + if (!(itemPtr->typePtr->alwaysRedraw & 1) + || (itemPtr->x1 >= canvasPtr->redrawX2) + || (itemPtr->y1 >= canvasPtr->redrawY2) + || (itemPtr->x2 < canvasPtr->redrawX1) + || (itemPtr->y2 < canvasPtr->redrawY1)) { + continue; + } + } + if (itemPtr->state == TK_PATHSTATE_HIDDEN || + (itemPtr->state == TK_PATHSTATE_NULL && + canvasPtr->canvas_state == TK_PATHSTATE_HIDDEN)) { + continue; + } + (*itemPtr->typePtr->displayProc)((Tk_PathCanvas) canvasPtr, itemPtr, + canvasPtr->display, pixmap, screenX1, screenY1, width, + height); + } + +#ifndef TK_PATH_NO_DOUBLE_BUFFERING + /* + * Copy from the temporary pixmap to the screen, then free up the + * temporary pixmap. + */ + + XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin), + canvasPtr->pixmapGC, + screenX1 - canvasPtr->drawableXOrigin, + screenY1 - canvasPtr->drawableYOrigin, + (unsigned int) width, (unsigned int) height, + screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin); + Tk_FreePixmap(Tk_Display(tkwin), pixmap); +#else + TkpClipDrawableToRect(Tk_Display(tkwin), pixmap, 0, 0, -1, -1); +#endif /* TK_PATH_NO_DOUBLE_BUFFERING */ + } + + /* + * Draw the window borders, if needed. + */ + + borders: + if (canvasPtr->flags & REDRAW_BORDERS) { + canvasPtr->flags &= ~REDRAW_BORDERS; + if (canvasPtr->borderWidth > 0) { + Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), + canvasPtr->bgBorder, canvasPtr->highlightWidth, + canvasPtr->highlightWidth, + Tk_Width(tkwin) - 2*canvasPtr->highlightWidth, + Tk_Height(tkwin) - 2*canvasPtr->highlightWidth, + canvasPtr->borderWidth, canvasPtr->relief); + } + if (canvasPtr->highlightWidth != 0) { + GC fgGC, bgGC; + + bgGC = Tk_GCForColor(canvasPtr->highlightBgColorPtr, + Tk_WindowId(tkwin)); + if (canvasPtr->textInfo.gotFocus) { + fgGC = Tk_GCForColor(canvasPtr->highlightColorPtr, + Tk_WindowId(tkwin)); + TkpDrawHighlightBorder(tkwin, fgGC, bgGC, + canvasPtr->highlightWidth, Tk_WindowId(tkwin)); + } else { + TkpDrawHighlightBorder(tkwin, bgGC, bgGC, + canvasPtr->highlightWidth, Tk_WindowId(tkwin)); + } + } + } + + done: + canvasPtr->flags &= ~(REDRAW_PENDING|BBOX_NOT_EMPTY); + canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0; + canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0; + if (canvasPtr->flags & UPDATE_SCROLLBARS) { + CanvasUpdateScrollbars(canvasPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * CanvasEventProc -- + * + * This function is invoked by the Tk dispatcher for various events on + * canvases. + * + * Results: + * None. + * + * Side effects: + * When the window gets deleted, internal structures get cleaned up. + * When it gets exposed, it is redisplayed. + * + *-------------------------------------------------------------- + */ + +static void +CanvasEventProc( + ClientData clientData, /* Information about window. */ + XEvent *eventPtr) /* Information about event. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) clientData; + + if (eventPtr->type == Expose) { + int x, y; + + x = eventPtr->xexpose.x + canvasPtr->xOrigin; + y = eventPtr->xexpose.y + canvasPtr->yOrigin; + Tk_PathCanvasEventuallyRedraw((Tk_PathCanvas) canvasPtr, x, y, + x + eventPtr->xexpose.width, + y + eventPtr->xexpose.height); + if ((eventPtr->xexpose.x < canvasPtr->inset) + || (eventPtr->xexpose.y < canvasPtr->inset) + || ((eventPtr->xexpose.x + eventPtr->xexpose.width) + > (Tk_Width(canvasPtr->tkwin) - canvasPtr->inset)) + || ((eventPtr->xexpose.y + eventPtr->xexpose.height) + > (Tk_Height(canvasPtr->tkwin) - canvasPtr->inset))) { + canvasPtr->flags |= REDRAW_BORDERS; + } + } else if (eventPtr->type == DestroyNotify) { + if (!(canvasPtr->flags & CANVAS_DELETED)) { + canvasPtr->flags |= CANVAS_DELETED; + Tcl_DeleteCommandFromToken(canvasPtr->interp, + canvasPtr->widgetCmd); + if (canvasPtr->flags & REDRAW_PENDING) { + Tcl_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr); + } + Tcl_EventuallyFree((ClientData) canvasPtr, + (Tcl_FreeProc *) DestroyCanvas); + } + } else if (eventPtr->type == ConfigureNotify) { + canvasPtr->flags |= UPDATE_SCROLLBARS; + + /* + * The call below is needed in order to recenter the canvas if it's + * confined and its scroll region is smaller than the window. + */ + + CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin); + Tk_PathCanvasEventuallyRedraw((Tk_PathCanvas) canvasPtr, canvasPtr->xOrigin, + canvasPtr->yOrigin, + canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), + canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); + canvasPtr->flags |= REDRAW_BORDERS; + } else if (eventPtr->type == FocusIn) { + if (eventPtr->xfocus.detail != NotifyInferior) { + CanvasFocusProc(canvasPtr, 1); + } + } else if (eventPtr->type == FocusOut) { + if (eventPtr->xfocus.detail != NotifyInferior) { + CanvasFocusProc(canvasPtr, 0); + } + } else if (eventPtr->type == UnmapNotify) { + Tk_PathItem *itemPtr; + + /* + * Special hack: if the canvas is unmapped, then must notify all items + * with "alwaysRedraw" set, so that they know that they are no longer + * displayed. + */ + + for (itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + if (itemPtr->typePtr->alwaysRedraw & 1) { + (*itemPtr->typePtr->displayProc)((Tk_PathCanvas) canvasPtr, + itemPtr, canvasPtr->display, None, 0, 0, 0, 0); + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * CanvasCmdDeletedProc -- + * + * This function 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 +CanvasCmdDeletedProc( + ClientData clientData) /* Pointer to widget record for widget. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) clientData; + + /* + * This function 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 function destroys the + * widget. + */ + + if (!(canvasPtr->flags & CANVAS_DELETED)) { + Tk_DestroyWindow(canvasPtr->tkwin); + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasEventuallyRedraw -- + * + * Arrange for part or all of a canvas widget to redrawn at some + * convenient time in the future. + * + * Results: + * None. + * + * Side effects: + * The screen will eventually be refreshed. + * + *-------------------------------------------------------------- + */ + +void +Tk_PathCanvasEventuallyRedraw( + Tk_PathCanvas canvas, /* Information about widget. */ + int x1, int y1, /* Upper left corner of area to redraw. Pixels + * on edge are redrawn. */ + int x2, int y2) /* Lower right corner of area to redraw. + * Pixels on edge are not redrawn. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + Tk_Window tkwin = canvasPtr->tkwin; + + if ((canvasPtr->flags & CANVAS_DELETED) || !Tk_IsMapped(tkwin)) { + return; + } + if ((x1 >= x2) || (y1 >= y2) || + (x2 < canvasPtr->xOrigin) || (y2 < canvasPtr->yOrigin) || + (x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) || + (y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) { + return; + } + if (canvasPtr->flags & BBOX_NOT_EMPTY) { + if (x1 <= canvasPtr->redrawX1) { + canvasPtr->redrawX1 = x1; + } + if (y1 <= canvasPtr->redrawY1) { + canvasPtr->redrawY1 = y1; + } + if (x2 >= canvasPtr->redrawX2) { + canvasPtr->redrawX2 = x2; + } + if (y2 >= canvasPtr->redrawY2) { + canvasPtr->redrawY2 = y2; + } + } else { + canvasPtr->redrawX1 = x1; + canvasPtr->redrawY1 = y1; + canvasPtr->redrawX2 = x2; + canvasPtr->redrawY2 = y2; + canvasPtr->flags |= BBOX_NOT_EMPTY; + } + if (!(canvasPtr->flags & REDRAW_PENDING)) { + Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr); + canvasPtr->flags |= REDRAW_PENDING; + } +} + +/* + *-------------------------------------------------------------- + * + * EventuallyRedrawItem -- + * + * Arrange for part or all of a canvas widget to redrawn at some + * convenient time in the future. + * + * Results: + * None. + * + * Side effects: + * The screen will eventually be refreshed. + * + *-------------------------------------------------------------- + */ + +static void +EventuallyRedrawItem( + Tk_PathCanvas canvas, /* Information about widget. */ + Tk_PathItem *itemPtr) /* Item to be redrawn. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2) || + (itemPtr->x2 < canvasPtr->xOrigin) || + (itemPtr->y2 < canvasPtr->yOrigin) || + (itemPtr->x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) || + (itemPtr->y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) { + if (!(itemPtr->typePtr->alwaysRedraw & 1)) { + return; + } + } + if (!(itemPtr->redraw_flags & FORCE_REDRAW)) { + if (canvasPtr->flags & BBOX_NOT_EMPTY) { + if (itemPtr->x1 <= canvasPtr->redrawX1) { + canvasPtr->redrawX1 = itemPtr->x1; + } + if (itemPtr->y1 <= canvasPtr->redrawY1) { + canvasPtr->redrawY1 = itemPtr->y1; + } + if (itemPtr->x2 >= canvasPtr->redrawX2) { + canvasPtr->redrawX2 = itemPtr->x2; + } + if (itemPtr->y2 >= canvasPtr->redrawY2) { + canvasPtr->redrawY2 = itemPtr->y2; + } + } else { + canvasPtr->redrawX1 = itemPtr->x1; + canvasPtr->redrawY1 = itemPtr->y1; + canvasPtr->redrawX2 = itemPtr->x2; + canvasPtr->redrawY2 = itemPtr->y2; + canvasPtr->flags |= BBOX_NOT_EMPTY; + } + itemPtr->redraw_flags |= FORCE_REDRAW; + } + SetAncestorsDirtyBbox(itemPtr); + if (!(canvasPtr->flags & REDRAW_PENDING)) { + Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr); + canvasPtr->flags |= REDRAW_PENDING; + } +} + +/* + *---------------------------------------------------------------------- + * + * GroupItemConfigured -- + * + * Schedules all children of a group for redisplay in a recursive way. + * + * Results: + * None. + * + * Side effects: + * A number of items scheduled for redisplay. + * + *---------------------------------------------------------------------- + */ + +void +GroupItemConfigured(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask) +{ + Tk_PathItem *walkPtr; + + for (walkPtr = itemPtr->firstChildPtr; walkPtr != NULL; walkPtr = walkPtr->nextPtr) { + EventuallyRedrawItem(canvas, walkPtr); + if (walkPtr->typePtr->bboxProc != NULL) { + (*walkPtr->typePtr->bboxProc)(canvas, walkPtr, mask); + /* + * Only if the item responds to the bboxProc we need to redraw it. + */ + EventuallyRedrawItem(canvas, walkPtr); + } + if (walkPtr->typePtr == &tkGroupType) { + /* + * Call ourself recursively for each group. + * @@@ An alternative would be to have this call in the group's + * own bbox proc. + */ + GroupItemConfigured(canvas, walkPtr, mask); + } + } +} + +/* + *-------------------------------------------------------------- + * + * Tk_CreatePathItemType -- + * + * This function may be invoked to add a new kind of canvas element to + * the core item types supported by Tk. + * + * Results: + * None. + * + * Side effects: + * From now on, the new item type will be useable in canvas widgets + * (e.g. typePtr->name can be used as the item type in "create" widget + * commands). If there was already a type with the same name as in + * typePtr, it is replaced with the new type. + * + *-------------------------------------------------------------- + */ + +void +Tk_CreatePathItemType( + Tk_PathItemType *typePtr) /* Information about item type; storage must + * be statically allocated (must live + * forever). */ +{ + Tk_PathItemType *typePtr2, *prevPtr; + + if (typeList == NULL) { + InitCanvas(); + } + + /* + * If there's already an item type with the given name, remove it. + */ + + Tcl_MutexLock(&typeListMutex); + for (typePtr2 = typeList, prevPtr = NULL; typePtr2 != NULL; + prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) { + if (strcmp(typePtr2->name, typePtr->name) == 0) { + if (prevPtr == NULL) { + typeList = typePtr2->nextPtr; + } else { + prevPtr->nextPtr = typePtr2->nextPtr; + } + break; + } + } + typePtr->nextPtr = typeList; + typeList = typePtr; + Tcl_MutexUnlock(&typeListMutex); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_PathGetItemTypes -- + * + * This function returns a pointer to the list of all item types. Note + * that this is inherently thread-unsafe, but since item types are only + * ever registered very rarely this is unlikely to be a problem in + * practice. + * + * Results: + * The return value is a pointer to the first in the list of item types + * currently supported by canvases. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tk_PathItemType * +Tk_PathGetItemTypes(void) +{ + if (typeList == NULL) { + InitCanvas(); + } + return typeList; +} + +/* + *---------------------------------------------------------------------- + * + * TkPathCanvasSetParent -- + * + * Appends an item as the last sibling to a parent item. + * May unlink any existing linkage. + * + * Results: + * Standard tcl result. + * + * Side effects: + * Links in item in display list. + * + *---------------------------------------------------------------------- + */ + +void +TkPathCanvasSetParent(Tk_PathItem *parentPtr, Tk_PathItem *itemPtr) +{ + + /* + * Unlink any present parent, then link in again. + */ + if (itemPtr->parentPtr != NULL) { + TkPathCanvasItemDetach(itemPtr); + } + ItemAddToParent(parentPtr, itemPtr); + + /* + * We may have configured -parent with a tag but need to return an id. + */ + itemPtr->parentObj = UnshareObj(itemPtr->parentObj); + Tcl_SetIntObj(itemPtr->parentObj, parentPtr->id); +} + +void +CanvasSetParentToRoot(Tk_PathItem *itemPtr) +{ + Tk_PathItemEx *itemExPtr = (Tk_PathItemEx *)itemPtr; + Tk_PathCanvas canvas = itemExPtr->canvas; + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + TkPathCanvasSetParent(canvasPtr->rootItemPtr, itemPtr); +} + +/* + *---------------------------------------------------------------------- + * + * TkPathCanvasFindGroup -- + * + * Searches for the first group item described by the tagOrId parentObj. + * + * Results: + * Standard tcl result. parentPtrPtr filled in on success. + * + * Side effects: + * Leaves any error result in interp. + * + *---------------------------------------------------------------------- + */ + +int +TkPathCanvasFindGroup(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tcl_Obj *parentObj, Tk_PathItem **parentPtrPtr) +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + Tk_PathItem *parentPtr; + int result = TCL_OK; + TagSearch *searchPtr = NULL;/* Allocated by first TagSearchScan, freed by + * TagSearchDestroy */ + + if (parentObj != NULL) { + if ((result = TagSearchScan(canvasPtr, parentObj, &searchPtr)) != TCL_OK) { + return TCL_ERROR; + } + parentPtr = TagSearchFirst(searchPtr); + if (parentPtr == NULL) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "tag \"", Tcl_GetString(parentObj), + "\" doesn't match any items", NULL); + result = TCL_ERROR; + } else if (strcmp(parentPtr->typePtr->name, "group") != 0) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "tag \"", Tcl_GetString(parentObj), + "\" is not a group item", NULL); + result = TCL_ERROR; + } else { + *parentPtrPtr = parentPtr; + } + TagSearchDestroy(searchPtr); + } + return result; +} + +void +CanvasTranslateGroup(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + double deltaX, double deltaY) +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + Tk_PathItem *walkPtr; + + /* === EB - 22-apr-2010: round the deltas to the nearest integer to avoid round-off errors */ + deltaX = (double)((int)(deltaX + (deltaX > 0 ? 0.5 : -0.5))); + deltaY = (double)((int)(deltaY + (deltaY > 0 ? 0.5 : -0.5))); + /* === */ + + /* + * Invoke all its childs translateProc. Any child groups will call this + * function recursively. + */ + for (walkPtr = itemPtr->firstChildPtr; walkPtr != NULL; walkPtr = walkPtr->nextPtr) { + EventuallyRedrawItem(canvas, walkPtr); + (void) (*walkPtr->typePtr->translateProc)(canvas, walkPtr, deltaX, deltaY); + EventuallyRedrawItem(canvas, walkPtr); + canvasPtr->flags |= REPICK_NEEDED; + } +} + +void +CanvasScaleGroup(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + double originX, double originY, double scaleX, double scaleY) +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) canvas; + Tk_PathItem *walkPtr; + + /* + * Invoke all its childs scaleProc. Any child groups will call this + * function recursively. + */ + for (walkPtr = itemPtr->firstChildPtr; walkPtr != NULL; walkPtr = walkPtr->nextPtr) { + EventuallyRedrawItem(canvas, walkPtr); + (void) (*walkPtr->typePtr->scaleProc)(canvas, walkPtr, + originX, originY, scaleX, scaleY); + EventuallyRedrawItem(canvas, walkPtr); + canvasPtr->flags |= REPICK_NEEDED; + } +} + +/* + *---------------------------------------------------------------------- + * + * SetAncestorsDirtyBbox -- + * + * Used by items when they need a redisplay for some reason + * so that its ancestor groups know that they need to compute + * a new bbox when requested. + * + * Results: + * None. + * + * Side effects: + * Groups get their dirty bbox flag set. + * + *---------------------------------------------------------------------- + */ + +static void +SetAncestorsDirtyBbox(Tk_PathItem *itemPtr) +{ + Tk_PathItem *walkPtr; + + walkPtr = itemPtr->parentPtr; + while (walkPtr != NULL) { + TkPathCanvasSetGroupDirtyBbox(walkPtr); + walkPtr = walkPtr->parentPtr; + } +} + +void +TkPathCanvasGroupBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int *x1Ptr, int *y1Ptr, int *x2Ptr, int *y2Ptr) +{ + int gotAny = 0; + Tk_PathItem *walkPtr; + int x1 = -1, y1 = -1, x2 = -1, y2 = -1; + + for (walkPtr = itemPtr->firstChildPtr; walkPtr != NULL; + walkPtr = walkPtr->nextPtr) { + + /* + * Make sure sub groups have its bbox updated. + * We may be called recursively. + */ + if (walkPtr->firstChildPtr != NULL) { + TkPathCanvasUpdateGroupBbox(canvas, walkPtr); + } + if ((walkPtr->x1 >= walkPtr->x2) + || (walkPtr->y1 >= walkPtr->y2)) { + continue; + } + if (!gotAny) { + x1 = walkPtr->x1; + y1 = walkPtr->y1; + x2 = walkPtr->x2; + y2 = walkPtr->y2; + gotAny = 1; + } else { + if (walkPtr->x1 < x1) { x1 = walkPtr->x1; } + if (walkPtr->y1 < y1) { y1 = walkPtr->y1; } + if (walkPtr->x2 > x2) { x2 = walkPtr->x2; } + if (walkPtr->y2 > y2) { y2 = walkPtr->y2; } + } + } + *x1Ptr = x1, *y1Ptr = y1, *x2Ptr = x2, *y2Ptr = y2; +} + +/* + *---------------------------------------------------------------------- + * + * InitCanvas -- + * + * This function is invoked to perform once-only-ever initialization for + * the module, such as setting up the type table. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +InitCanvas(void) +{ + Tcl_MutexLock(&typeListMutex); + if (typeList != NULL) { + Tcl_MutexUnlock(&typeListMutex); + return; + } + typeList = &tkRectangleType; + tkRectangleType.nextPtr = &tkTextType; + tkTextType.nextPtr = &tkLineType; + tkLineType.nextPtr = &tkPolygonType; + tkPolygonType.nextPtr = &tkImageType; + tkImageType.nextPtr = &tkOvalType; + tkOvalType.nextPtr = &tkBitmapType; + tkBitmapType.nextPtr = &tkArcType; + tkArcType.nextPtr = &tkWindowType; + tkWindowType.nextPtr = NULL; + + /* + * tkpath specific item types. + */ + + tkWindowType.nextPtr = &tkPathType; + tkPathType.nextPtr = &tkPrectType; + tkPrectType.nextPtr = &tkPlineType; + tkPlineType.nextPtr = &tkPolylineType; + tkPolylineType.nextPtr = &tkPpolygonType; + tkPpolygonType.nextPtr = &tkCircleType; + tkCircleType.nextPtr = &tkEllipseType; + tkEllipseType.nextPtr = &tkPimageType; + tkPimageType.nextPtr = &tkPtextType; + tkPtextType.nextPtr = &tkGroupType; + tkGroupType.nextPtr = NULL; + + Tcl_MutexUnlock(&typeListMutex); +} + +/* + *-------------------------------------------------------------- + * + * ItemCreate -- + * + * Creates a new item, configures it, and add it to the display tree. + * It remains for the calling code to call EventuallyRedrawItem + * and a few more canvas admin stuff. + * The item's creatProc may leave any error message in interp. + * + * Results: + * Standard Tcl result and a new item pointer in itemPtrPtr. + * + * Side effects: + * Item allocated, configured, and linked into display list. + * + *-------------------------------------------------------------- + */ + +static int +ItemCreate(Tcl_Interp *interp, TkPathCanvas *canvasPtr, + Tk_PathItemType *typePtr, int isRoot, Tk_PathItem **itemPtrPtr, + int objc, Tcl_Obj *CONST objv[]) +{ + Tk_PathItem *itemPtr; + Tcl_HashEntry *entryPtr; + int isNew = 0; + int result; + + itemPtr = (Tk_PathItem *) ckalloc((unsigned) typePtr->itemSize); + if (isRoot) { + itemPtr->id = 0; + } else { + itemPtr->id = canvasPtr->nextId; + canvasPtr->nextId++; + } + itemPtr->typePtr = typePtr; + itemPtr->state = TK_PATHSTATE_NULL; + itemPtr->redraw_flags = 0; + itemPtr->optionTable = NULL; + itemPtr->pathTagsPtr = NULL; + itemPtr->nextPtr = NULL; + itemPtr->prevPtr = NULL; + itemPtr->firstChildPtr = NULL; + itemPtr->lastChildPtr = NULL; + + /* + * This is just to be able to detect if createProc processes + * any -parent option. + * NB: It is absolutely vital to set parentObj to NULL + * else option free bails. + */ + itemPtr->parentPtr = NULL; + itemPtr->parentObj = NULL; + + result = (*typePtr->createProc)(interp, (Tk_PathCanvas) canvasPtr, + itemPtr, objc, objv); + if (result != TCL_OK) { + ckfree((char *) itemPtr); + return TCL_ERROR; + } + entryPtr = Tcl_CreateHashEntry(&canvasPtr->idTable, + (char *) INT2PTR(itemPtr->id), &isNew); + Tcl_SetHashValue(entryPtr, itemPtr); + + /* + * If item's createProc didn't put it in the display list we do. + * Typically done only for the tk::canvas items which don't have + * a -parent option. + */ + if (!isRoot && (itemPtr->parentPtr == NULL)) { + ItemAddToParent(canvasPtr->rootItemPtr, itemPtr); + } + itemPtr->redraw_flags |= FORCE_REDRAW; + *itemPtrPtr = itemPtr; + + return TCL_OK; +} + +static Tcl_Obj *UnshareObj(Tcl_Obj *objPtr) +{ + if (Tcl_IsShared(objPtr)) { + Tcl_Obj *newObj = Tcl_DuplicateObj(objPtr); + Tcl_DecrRefCount(objPtr); + Tcl_IncrRefCount(newObj); + return newObj; + } + return objPtr; +} + +/* + *-------------------------------------------------------------- + * + * TkPathCanvasItemIteratorNext -- + * + * Convinience function to obtain the next item in the item tree. + * + * Results: + * Tk_PathItem pointer. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +Tk_PathItem * +TkPathCanvasItemIteratorNext(Tk_PathItem *itemPtr) +{ + if (itemPtr->firstChildPtr != NULL) { + return itemPtr->firstChildPtr; + } + while (itemPtr->nextPtr == NULL) { + itemPtr = itemPtr->parentPtr; + if (itemPtr == NULL) { /* root item */ + return NULL; + } + } + return itemPtr->nextPtr; +} + +Tk_PathItem * +TkPathCanvasItemIteratorPrev(Tk_PathItem *itemPtr) +{ + Tk_PathItem *walkPtr; + + if (itemPtr->parentPtr == NULL) { /* root item */ + return NULL; + } else { + walkPtr = itemPtr->parentPtr; + if (itemPtr->prevPtr != NULL) { + walkPtr = itemPtr->prevPtr; + while (walkPtr != NULL && walkPtr->lastChildPtr != NULL) { + walkPtr = walkPtr->lastChildPtr; + } + } + return walkPtr; + } +} + +/* + *-------------------------------------------------------------- + * + * ItemIteratorSubNext -- + * + * Convinience function to obtain the next item in the item tree. + * It is similar to ItemIteratorSubNext except that it is limited + * to descendants of groupPtr. + * + * Results: + * Tk_PathItem pointer. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static Tk_PathItem * +ItemIteratorSubNext(Tk_PathItem *itemPtr, Tk_PathItem *groupPtr) +{ + Tk_PathItem *stopPtr = groupPtr->parentPtr; + + if (itemPtr->firstChildPtr != NULL) { + return itemPtr->firstChildPtr; + } + while (itemPtr->nextPtr == NULL) { + itemPtr = itemPtr->parentPtr; + if (itemPtr == NULL) { /* root item */ + return NULL; + } else if (stopPtr == itemPtr->parentPtr) { + return NULL; + } + } + return itemPtr->nextPtr; +} + +static int +ItemGetNumTags(Tk_PathItem *itemPtr) +{ + if (itemPtr->pathTagsPtr != NULL) { + return itemPtr->pathTagsPtr->numTags; + } else { + return 0; + } +} + +/* + *-------------------------------------------------------------- + * + * TkPathCanvasItemDetach -- + * + * Splice out (unlink) an item from the display list. + * + * Results: + * None. + * + * Side effects: + * Item will be unlinked from the display list. + * + *-------------------------------------------------------------- + */ + +void +TkPathCanvasItemDetach(Tk_PathItem *itemPtr) +{ + Tk_PathItem *parentPtr; + + if (itemPtr->prevPtr != NULL) { + itemPtr->prevPtr->nextPtr = itemPtr->nextPtr; + } + if (itemPtr->nextPtr != NULL) { + itemPtr->nextPtr->prevPtr = itemPtr->prevPtr; + } + parentPtr = itemPtr->parentPtr; + if ((parentPtr != NULL) && (parentPtr->firstChildPtr == itemPtr)) { + parentPtr->firstChildPtr = itemPtr->nextPtr; + if (parentPtr->firstChildPtr == NULL) { + parentPtr->lastChildPtr = NULL; + } + } + if ((parentPtr != NULL) && (parentPtr->lastChildPtr == itemPtr)) { + parentPtr->lastChildPtr = itemPtr->prevPtr; + } + + /* + * This signals an orfan item. + */ + itemPtr->nextPtr = itemPtr->prevPtr = itemPtr->parentPtr = NULL; +} + +/* + *-------------------------------------------------------------- + * + * ItemAddToParent -- + * + * Appends an item as the last sibling to a parent item. + * It doesn't do any unlinking from a previous tree position. + * + * Results: + * None. + * + * Side effects: + * Display list updated. + * + *-------------------------------------------------------------- + */ + +static void +ItemAddToParent(Tk_PathItem *parentPtr, Tk_PathItem *itemPtr) +{ + itemPtr->nextPtr = NULL; + itemPtr->prevPtr = parentPtr->lastChildPtr; + if (parentPtr->lastChildPtr != NULL) { + parentPtr->lastChildPtr->nextPtr = itemPtr; + } else { + parentPtr->firstChildPtr = itemPtr; + } + parentPtr->lastChildPtr = itemPtr; + itemPtr->parentPtr = parentPtr; +} + +/* + *---------------------------------------------------------------------- + * + * ItemDelete -- + * + * Recursively frees all resources associated with an Item and its + * descendants and removes it from display list. + * + * Results: + * None. + * + * Side effects: + * Items are removed from their parent and freed. + * + *---------------------------------------------------------------------- + */ + +static void +ItemDelete(TkPathCanvas *canvasPtr, Tk_PathItem *itemPtr) +{ + Tcl_HashEntry *entryPtr; + + /* + * Remove any children by recursively calling us. + * NB: This is very tricky code! Children updates + * the itemPtr->firstChildPtr here via calls + * to TkPathCanvasItemDetach. + */ + while (itemPtr->firstChildPtr != NULL) { + ItemDelete(canvasPtr, itemPtr->firstChildPtr); + } + + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + if (canvasPtr->bindingTable != NULL) { + Tk_DeleteAllBindings(canvasPtr->bindingTable, + (ClientData) itemPtr); + } + + /* + * The item type deleteProc is responsible for calling + * Tk_FreeConfigOptions which will implicitly also clean up + * the Tk_PathTags via its custom free proc. + */ + (*itemPtr->typePtr->deleteProc)((Tk_PathCanvas) canvasPtr, itemPtr, + canvasPtr->display); + + entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, + (char *) INT2PTR(itemPtr->id)); + Tcl_DeleteHashEntry(entryPtr); + TkPathCanvasItemDetach(itemPtr); + + if (itemPtr == canvasPtr->currentItemPtr) { + canvasPtr->currentItemPtr = NULL; + canvasPtr->flags |= REPICK_NEEDED; + } + if (itemPtr == canvasPtr->newCurrentPtr) { + canvasPtr->newCurrentPtr = NULL; + canvasPtr->flags |= REPICK_NEEDED; + } + if (itemPtr == canvasPtr->textInfo.focusItemPtr) { + canvasPtr->textInfo.focusItemPtr = NULL; + } + if (itemPtr == canvasPtr->textInfo.selItemPtr) { + canvasPtr->textInfo.selItemPtr = NULL; + } + if ((itemPtr == canvasPtr->hotPtr) + || (itemPtr == canvasPtr->hotPrevPtr)) { + canvasPtr->hotPtr = NULL; + } + ckfree((char *) itemPtr); +} + +static void +DebugGetItemInfo(Tk_PathItem *itemPtr, char *s) +{ + Tk_PathItem *p = itemPtr; + char tmp[256]; + + sprintf(tmp, " parentPtr->id=%d\t", (p->parentPtr ? p->parentPtr->id : -1)); + strcat(s, tmp); + sprintf(tmp, " prevPtr->id=%d\t", (p->prevPtr ? p->prevPtr->id : -1)); + strcat(s, tmp); + sprintf(tmp, " nextPtr->id=%d\t", (p->nextPtr ? p->nextPtr->id : -1)); + strcat(s, tmp); + sprintf(tmp, " firstChildPtr->id=%d\t", (p->firstChildPtr ? p->firstChildPtr->id : -1)); + strcat(s, tmp); + sprintf(tmp, " lastChildPtr->id=%d\t", (p->lastChildPtr ? p->lastChildPtr->id : -1)); + strcat(s, tmp); +} + +#ifdef USE_OLD_TAG_SEARCH +/* + *-------------------------------------------------------------- + * + * StartTagSearch -- + * + * This function 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_PathItem * +StartTagSearch( + TkPathCanvas *canvasPtr, /* Canvas whose items are to be searched. */ + Tcl_Obj *tagObj, /* Object giving tag value. */ + TagSearch *searchPtr) /* Record describing tag search; will be + * initialized here. */ +{ + int id; + Tk_PathItem *itemPtr, *lastPtr; + Tk_Uid *tagPtr; + Tk_Uid uid; + char *tag = Tcl_GetString(tagObj); + int count; + TkWindow *tkwin; + TkDisplay *dispPtr; + Tk_PathTags *ptagsPtr; + + tkwin = (TkWindow *) canvasPtr->tkwin; + dispPtr = tkwin->dispPtr; + + /* + * 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; + Tcl_HashEntry *entryPtr; + + dispPtr->numIdSearches++; + id = strtoul(tag, &end, 0); + if (*end == 0) { + itemPtr = canvasPtr->hotPtr; + lastPtr = canvasPtr->hotPrevPtr; + if ((itemPtr == NULL) || (itemPtr->id != id) || (lastPtr == NULL) + || (TkPathCanvasItemIteratorNext(lastPtr) != itemPtr)) { + dispPtr->numSlowSearches++; + entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id); + if (entryPtr != NULL) { + itemPtr = (Tk_PathItem *)Tcl_GetHashValue(entryPtr); + lastPtr = itemPtr->prevPtr; + } else { + lastPtr = itemPtr = NULL; + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + canvasPtr->hotPtr = itemPtr; + canvasPtr->hotPrevPtr = lastPtr; + return itemPtr; + } + } + + searchPtr->tag = uid = Tk_GetUid(tag); + if (uid == Tk_GetUid("all")) { + /* + * All items match. + */ + + searchPtr->tag = NULL; + searchPtr->lastPtr = NULL; + searchPtr->currentPtr = canvasPtr->rootItemPtr; + return canvasPtr->rootItemPtr; + } else if (uid == Tk_GetUid("root")) { + itemPtr = canvasPtr->rootItemPtr; + lastPtr = NULL; + searchPtr->searchOver = 1; + searchPtr->currentPtr = itemPtr: + searchPtr->lastPtr = lastPtr; + canvasPtr->hotPtr = itemPtr; + canvasPtr->hotPrevPtr = lastPtr; + return itemPtr; + } + + /* + * None of the above. Search for an item with a matching tag. + */ + for (lastPtr = NULL, itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + lastPtr = itemPtr, itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + ptagsPtr = itemPtr->pathTagsPtr; + if (ptagsPtr != NULL) { + for (tagPtr = ptagsPtr->tagPtr, count = ptagsPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; +} + +/* + *-------------------------------------------------------------- + * + * NextItem -- + * + * This function 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 function will + * return the next item. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static Tk_PathItem * +NextItem( + TagSearch *searchPtr) /* Record describing search in progress. */ +{ + Tk_PathItem *itemPtr, *lastPtr; + int count; + Tk_Uid uid; + Tk_Uid *tagPtr; + Tk_PathTags *ptagsPtr; + + /* + * Find next item in list (this may not actually be a suitable one to + * return), and return if there are no items left. + */ + + lastPtr = searchPtr->lastPtr; + if (lastPtr == NULL) { + itemPtr = searchPtr->canvasPtr->rootItemPtr; + } else { + itemPtr = TkPathCanvasItemIteratorNext(lastPtr); + } + + 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 lastPtr; just return its new successor (i.e. do nothing + * here). + */ + } else { + lastPtr = itemPtr; + itemPtr = TkPathCanvasItemIteratorNext(lastPtr); + } + + /* + * Handle special case of "all" search by returning next item. + */ + + uid = searchPtr->tag; + if (uid == NULL) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + + /* + * Look for an item with a particular tag. + */ + for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + ptagsPtr = itemPtr->pathTagsPtr; + if (ptagsPtr != NULL) { + for (tagPtr = ptagsPtr->tagPtr, count = ptagsPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; +} + +#else /* !USE_OLD_TAG_SEARCH */ +/* + *---------------------------------------------------------------------- + * + * GetStaticUids -- + * + * This function is invoked to return a structure filled with the Uids + * used when doing tag searching. If it was never before called in the + * current thread, it initializes the structure for that thread (uids are + * only ever local to one thread [Bug 1114977]). + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static SearchUids * +GetStaticUids(void) +{ + SearchUids *searchUids = (SearchUids *) + Tcl_GetThreadData(&dataKey, sizeof(SearchUids)); + + if (searchUids->allUid == NULL) { + searchUids->allUid = Tk_GetUid("all"); + searchUids->currentUid = Tk_GetUid("current"); + searchUids->rootUid = Tk_GetUid("root"); + searchUids->andUid = Tk_GetUid("&&"); + searchUids->orUid = Tk_GetUid("||"); + searchUids->xorUid = Tk_GetUid("^"); + searchUids->parenUid = Tk_GetUid("("); + searchUids->endparenUid = Tk_GetUid(")"); + searchUids->negparenUid = Tk_GetUid("!("); + searchUids->tagvalUid = Tk_GetUid("!!"); + searchUids->negtagvalUid = Tk_GetUid("!"); + } + return searchUids; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchExprInit -- + * + * This function allocates and initializes one TagSearchExpr struct. + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static void +TagSearchExprInit( + TagSearchExpr **exprPtrPtr) +{ + TagSearchExpr* expr = *exprPtrPtr; + + if (! expr) { + expr = (TagSearchExpr *) ckalloc(sizeof(TagSearchExpr)); + expr->allocated = 0; + expr->uids = NULL; + expr->next = NULL; + } + expr->uid = NULL; + expr->index = 0; + expr->length = 0; + *exprPtrPtr = expr; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchExprDestroy -- + * + * This function destroys one TagSearchExpr structure. + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static void +TagSearchExprDestroy( + TagSearchExpr *expr) +{ + if (expr) { + if (expr->uids) { + ckfree((char *)expr->uids); + } + ckfree((char *)expr); + } +} + +/* + *-------------------------------------------------------------- + * + * TagSearchScan -- + * + * This function is called to initiate an enumeration of all items in a + * given canvas that contain a tag that matches the tagOrId expression. + * + * Results: + * The return value indicates if the tagOrId expression was successfully + * scanned (syntax). The information at *searchPtr is initialized such + * that a call to TagSearchFirst, followed by successive calls to + * TagSearchNext will return 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. + * + *-------------------------------------------------------------- + */ + +static int +TagSearchScan( + TkPathCanvas *canvasPtr, /* Canvas whose items are to be searched. */ + Tcl_Obj *tagObj, /* Object giving tag value. */ + TagSearch **searchPtrPtr) /* Record describing tag search; will be + * initialized here. */ +{ + char *tag = Tcl_GetString(tagObj); + int i; + TagSearch *searchPtr; + + /* + * Initialize the search. + */ + + if (*searchPtrPtr) { + searchPtr = *searchPtrPtr; + } else { + /* + * Allocate primary search struct on first call. + */ + + *searchPtrPtr = searchPtr = (TagSearch *) ckalloc(sizeof(TagSearch)); + searchPtr->expr = NULL; + + /* + * Allocate buffer for rewritten tags (after de-escaping). + */ + + searchPtr->rewritebufferAllocated = 100; + searchPtr->rewritebuffer = + (char *) ckalloc(searchPtr->rewritebufferAllocated); + } + TagSearchExprInit(&(searchPtr->expr)); + + /* + * How long is the tagOrId? + */ + + searchPtr->stringLength = (int) strlen(tag); + + /* + * Make sure there is enough buffer to hold rewritten tags. + */ + + if ((unsigned int)searchPtr->stringLength >= + searchPtr->rewritebufferAllocated) { + searchPtr->rewritebufferAllocated = searchPtr->stringLength + 100; + searchPtr->rewritebuffer = (char *) + ckrealloc(searchPtr->rewritebuffer, + searchPtr->rewritebufferAllocated); + } + + /* + * Initialize search. + */ + + searchPtr->canvasPtr = canvasPtr; + searchPtr->searchOver = 0; + searchPtr->type = SEARCH_TYPE_EMPTY; + + /* + * 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 (searchPtr->stringLength && isdigit(UCHAR(*tag))) { + char *end; + + searchPtr->id = strtoul(tag, &end, 0); + if (*end == 0) { + searchPtr->type = SEARCH_TYPE_ID; + return TCL_OK; + } + } + + /* + * For all other tags and tag expressions convert to a UID. This UID is + * kept forever, but this should be thought of as a cache rather than as a + * memory leak. + */ + searchPtr->expr->uid = Tk_GetUid(tag); + + /* + * Short circuit impossible searches for null tags. + */ + + if (searchPtr->stringLength == 0) { + return TCL_OK; + } + + /* + * Pre-scan tag for at least one unquoted "&&" "||" "^" "!" + * if not found then use string as simple tag + */ + + for (i = 0; i < searchPtr->stringLength ; i++) { + if (tag[i] == '"') { + i++; + for ( ; i < searchPtr->stringLength; i++) { + if (tag[i] == '\\') { + i++; + continue; + } + if (tag[i] == '"') { + break; + } + } + } else if ((tag[i] == '&' && tag[i+1] == '&') + || (tag[i] == '|' && tag[i+1] == '|') + || (tag[i] == '^') + || (tag[i] == '!')) { + searchPtr->type = SEARCH_TYPE_EXPR; + break; + } + } + + searchPtr->string = tag; + searchPtr->stringIndex = 0; + if (searchPtr->type == SEARCH_TYPE_EXPR) { + /* + * An operator was found in the prescan, so now compile the tag + * expression into array of Tk_Uid flagging any syntax errors found. + */ + + if (TagSearchScanExpr(canvasPtr->interp, searchPtr, + searchPtr->expr) != TCL_OK) { + /* + * Syntax error in tag expression. The result message was set by + * TagSearchScanExpr. + */ + + return TCL_ERROR; + } + searchPtr->expr->length = searchPtr->expr->index; + } else if (searchPtr->expr->uid == GetStaticUids()->allUid) { + /* + * All items match. + */ + + searchPtr->type = SEARCH_TYPE_ALL; + } else if (searchPtr->expr->uid == GetStaticUids()->rootUid) { + searchPtr->type = SEARCH_TYPE_ROOT; + } else { + /* + * Optimized single-tag search + */ + + searchPtr->type = SEARCH_TYPE_TAG; + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchDestroy -- + * + * This function destroys any dynamic structures that may have been + * allocated by TagSearchScan. + * + * Results: + * None + * + * Side effects: + * Deallocates memory. + * + *-------------------------------------------------------------- + */ + +static void +TagSearchDestroy( + TagSearch *searchPtr) /* Record describing tag search */ +{ + if (searchPtr) { + TagSearchExprDestroy(searchPtr->expr); + ckfree((char *)searchPtr->rewritebuffer); + ckfree((char *)searchPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * TagSearchScanExpr -- + * + * This recursive function is called to scan a tag expression and compile + * it into an array of Tk_Uids. + * + * Results: + * The return value indicates if the tagOrId expression was successfully + * scanned (syntax). The information at *searchPtr is initialized such + * that a call to TagSearchFirst, followed by successive calls to + * TagSearchNext will return items that match tag. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +TagSearchScanExpr( + Tcl_Interp *interp, /* Current interpreter. */ + TagSearch *searchPtr, /* Search data */ + TagSearchExpr *expr) /* compiled expression result */ +{ + int looking_for_tag; /* When true, scanner expects next char(s) to + * be a tag, else operand expected */ + int found_tag; /* One or more tags found */ + int found_endquote; /* For quoted tag string parsing */ + int negate_result; /* Pending negation of next tag value */ + char *tag; /* Tag from tag expression string */ + char c; + SearchUids *searchUids; /* Collection of uids for basic search + * expression terms. */ + + searchUids = GetStaticUids(); + negate_result = 0; + found_tag = 0; + looking_for_tag = 1; + while (searchPtr->stringIndex < searchPtr->stringLength) { + c = searchPtr->string[searchPtr->stringIndex++]; + + if (expr->allocated == expr->index) { + expr->allocated += 15; + if (expr->uids) { + expr->uids = (Tk_Uid *) + ckrealloc((char *)(expr->uids), + (expr->allocated)*sizeof(Tk_Uid)); + } else { + expr->uids = (Tk_Uid *) + ckalloc((expr->allocated)*sizeof(Tk_Uid)); + } + } + + if (looking_for_tag) { + + switch (c) { + case ' ': /* ignore unquoted whitespace */ + case '\t': + case '\n': + case '\r': + break; + + case '!': /* negate next tag or subexpr */ + if (looking_for_tag > 1) { + Tcl_AppendResult(interp, + "Too many '!' in tag search expression", + NULL); + return TCL_ERROR; + } + looking_for_tag++; + negate_result = 1; + break; + + case '(': /* scan (negated) subexpr recursively */ + if (negate_result) { + expr->uids[expr->index++] = searchUids->negparenUid; + negate_result = 0; + } else { + expr->uids[expr->index++] = searchUids->parenUid; + } + if (TagSearchScanExpr(interp, searchPtr, expr) != TCL_OK) { + /* + * Result string should be already set by nested call to + * tag_expr_scan() + */ + + return TCL_ERROR; + } + looking_for_tag = 0; + found_tag = 1; + break; + + case '"': /* quoted tag string */ + if (negate_result) { + expr->uids[expr->index++] = searchUids->negtagvalUid; + negate_result = 0; + } else { + expr->uids[expr->index++] = searchUids->tagvalUid; + } + tag = searchPtr->rewritebuffer; + found_endquote = 0; + while (searchPtr->stringIndex < searchPtr->stringLength) { + c = searchPtr->string[searchPtr->stringIndex++]; + if (c == '\\') { + c = searchPtr->string[searchPtr->stringIndex++]; + } + if (c == '"') { + found_endquote = 1; + break; + } + *tag++ = c; + } + if (! found_endquote) { + Tcl_AppendResult(interp, + "Missing endquote in tag search expression", + NULL); + return TCL_ERROR; + } + if (! (tag - searchPtr->rewritebuffer)) { + Tcl_AppendResult(interp, + "Null quoted tag string in tag search expression", + NULL); + return TCL_ERROR; + } + *tag++ = '\0'; + expr->uids[expr->index++] = + Tk_GetUid(searchPtr->rewritebuffer); + looking_for_tag = 0; + found_tag = 1; + break; + + case '&': /* illegal chars when looking for tag */ + case '|': + case '^': + case ')': + Tcl_AppendResult(interp, + "Unexpected operator in tag search expression", + NULL); + return TCL_ERROR; + + default: /* unquoted tag string */ + if (negate_result) { + expr->uids[expr->index++] = searchUids->negtagvalUid; + negate_result = 0; + } else { + expr->uids[expr->index++] = searchUids->tagvalUid; + } + tag = searchPtr->rewritebuffer; + *tag++ = c; + + /* + * Copy rest of tag, including any embedded whitespace. + */ + + while (searchPtr->stringIndex < searchPtr->stringLength) { + c = searchPtr->string[searchPtr->stringIndex]; + if (c == '!' || c == '&' || c == '|' || c == '^' + || c == '(' || c == ')' || c == '"') { + break; + } + *tag++ = c; + searchPtr->stringIndex++; + } + + /* + * Remove trailing whitespace. + */ + + while (1) { + c = *--tag; + + /* + * There must have been one non-whitespace char, so this + * will terminate. + */ + + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { + break; + } + } + *++tag = '\0'; + expr->uids[expr->index++] = + Tk_GetUid(searchPtr->rewritebuffer); + looking_for_tag = 0; + found_tag = 1; + } + + } else { /* ! looking_for_tag */ + switch (c) { + case ' ': /* ignore whitespace */ + case '\t': + case '\n': + case '\r': + break; + + case '&': /* AND operator */ + c = searchPtr->string[searchPtr->stringIndex++]; + if (c != '&') { + Tcl_AppendResult(interp, + "Singleton '&' in tag search expression", + NULL); + return TCL_ERROR; + } + expr->uids[expr->index++] = searchUids->andUid; + looking_for_tag = 1; + break; + + case '|': /* OR operator */ + c = searchPtr->string[searchPtr->stringIndex++]; + if (c != '|') { + Tcl_AppendResult(interp, + "Singleton '|' in tag search expression", + NULL); + return TCL_ERROR; + } + expr->uids[expr->index++] = searchUids->orUid; + looking_for_tag = 1; + break; + + case '^' : /* XOR operator */ + expr->uids[expr->index++] = searchUids->xorUid; + looking_for_tag = 1; + break; + + case ')' : /* end subexpression */ + expr->uids[expr->index++] = searchUids->endparenUid; + goto breakwhile; + + default: /* syntax error */ + Tcl_AppendResult(interp, + "Invalid boolean operator in tag search expression", + NULL); + return TCL_ERROR; + } + } + } + + breakwhile: + if (found_tag && ! looking_for_tag) { + return TCL_OK; + } + Tcl_AppendResult(interp, "Missing tag in tag search expression", NULL); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchEvalExpr -- + * + * This recursive function is called to eval a tag expression. + * + * Results: + * The return value indicates if the tagOrId expression successfully + * matched the tags of the current item. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +TagSearchEvalExpr( + TagSearchExpr *expr, /* Search expression */ + Tk_PathItem *itemPtr) /* Item being test for match */ +{ + int looking_for_tag; /* When true, scanner expects next char(s) to + * be a tag, else operand expected. */ + int negate_result; /* Pending negation of next tag value */ + Tk_Uid uid; + Tk_Uid *tagPtr; + Tk_PathTags *ptagsPtr; + int count; + int result; /* Value of expr so far */ + int parendepth; + SearchUids *searchUids; /* Collection of uids for basic search + * expression terms. */ + + searchUids = GetStaticUids(); + result = 0; /* just to keep the compiler quiet */ + + negate_result = 0; + looking_for_tag = 1; + while (expr->index < expr->length) { + uid = expr->uids[expr->index++]; + if (looking_for_tag) { + if (uid == searchUids->tagvalUid) { +/* + * assert(expr->index < expr->length); + */ + uid = expr->uids[expr->index++]; + result = 0; + + /* + * set result 1 if tag is found in item's tags + */ + + ptagsPtr = itemPtr->pathTagsPtr; + if (ptagsPtr != NULL) { + for (tagPtr = ptagsPtr->tagPtr, count = ptagsPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + result = 1; + break; + } + } + } + } else if (uid == searchUids->negtagvalUid) { + negate_result = ! negate_result; +/* + * assert(expr->index < expr->length); + */ + uid = expr->uids[expr->index++]; + result = 0; + + /* + * set result 1 if tag is found in item's tags + */ + ptagsPtr = itemPtr->pathTagsPtr; + if (ptagsPtr != NULL) { + for (tagPtr = ptagsPtr->tagPtr, count = ptagsPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + result = 1; + break; + } + } + } + } else if (uid == searchUids->parenUid) { + /* + * Evaluate subexpressions with recursion + */ + + result = TagSearchEvalExpr(expr, itemPtr); + + } else if (uid == searchUids->negparenUid) { + negate_result = ! negate_result; + + /* + * Evaluate subexpressions with recursion + */ + + result = TagSearchEvalExpr(expr, itemPtr); +/* + * } else { + * assert(0); + */ + } + if (negate_result) { + result = ! result; + negate_result = 0; + } + looking_for_tag = 0; + } else { /* ! looking_for_tag */ + if (((uid == searchUids->andUid) && (!result)) || + ((uid == searchUids->orUid) && result)) { + /* + * Short circuit expression evaluation. + * + * if result before && is 0, or result before || is 1, then + * the expression is decided and no further evaluation is + * needed. + */ + + parendepth = 0; + while (expr->index < expr->length) { + uid = expr->uids[expr->index++]; + if (uid == searchUids->tagvalUid || + uid == searchUids->negtagvalUid) { + expr->index++; + continue; + } + if (uid == searchUids->parenUid || + uid == searchUids->negparenUid) { + parendepth++; + continue; + } + if (uid == searchUids->endparenUid) { + parendepth--; + if (parendepth < 0) { + break; + } + } + } + return result; + + } else if (uid == searchUids->xorUid) { + /* + * If the previous result was 1 then negate the next result. + */ + + negate_result = result; + + } else if (uid == searchUids->endparenUid) { + return result; +/* + * } else { + * assert(0); + */ + } + looking_for_tag = 1; + } + } +/* + * assert(! looking_for_tag); + */ + return result; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchFirst -- + * + * This function is called to get the first item item that matches a + * preestablished search predicate that was set by TagSearchScan. + * + * Results: + * The return value is a pointer to the first item, or NULL if there is + * no such item. The information at *searchPtr is updated such that + * successive calls to TagSearchNext will return successive items. + * + * 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. + * + *-------------------------------------------------------------- + */ + +static Tk_PathItem * +TagSearchFirst( + TagSearch *searchPtr) /* Record describing tag search */ +{ + Tk_PathItem *itemPtr, *lastPtr; + Tk_Uid uid, *tagPtr; + Tk_PathTags *ptagsPtr; + int count; + + /* + * Short circuit impossible searches for null tags. + */ + + if (searchPtr->stringLength == 0) { + return NULL; + } + + /* + * 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 (searchPtr->type == SEARCH_TYPE_ID) { + Tcl_HashEntry *entryPtr; + + itemPtr = searchPtr->canvasPtr->hotPtr; + lastPtr = searchPtr->canvasPtr->hotPrevPtr; + if ((itemPtr == NULL) || (itemPtr->id != searchPtr->id) + || (lastPtr == NULL) || (TkPathCanvasItemIteratorNext(lastPtr) != itemPtr)) { + entryPtr = Tcl_FindHashEntry(&searchPtr->canvasPtr->idTable, + (char *) INT2PTR(searchPtr->id)); + if (entryPtr != NULL) { + itemPtr = (Tk_PathItem *)Tcl_GetHashValue(entryPtr); + lastPtr = TkPathCanvasItemIteratorPrev(itemPtr); + } else { + lastPtr = itemPtr = NULL; + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + searchPtr->canvasPtr->hotPtr = itemPtr; + searchPtr->canvasPtr->hotPrevPtr = lastPtr; + return itemPtr; + } + + if (searchPtr->type == SEARCH_TYPE_ALL) { + /* + * All items match. + */ + + searchPtr->lastPtr = NULL; + searchPtr->currentPtr = searchPtr->canvasPtr->rootItemPtr; + return searchPtr->canvasPtr->rootItemPtr; + } + if (searchPtr->type == SEARCH_TYPE_ROOT) { + itemPtr = searchPtr->canvasPtr->rootItemPtr; + lastPtr = NULL; + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + searchPtr->canvasPtr->hotPtr = itemPtr; + searchPtr->canvasPtr->hotPrevPtr = lastPtr; + return itemPtr; + } + + if (searchPtr->type == SEARCH_TYPE_TAG) { + /* + * Optimized single-tag search + */ + + uid = searchPtr->expr->uid; + for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->rootItemPtr; + itemPtr != NULL; lastPtr = itemPtr, itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + ptagsPtr = itemPtr->pathTagsPtr; + if (ptagsPtr != NULL) { + for (tagPtr = ptagsPtr->tagPtr, count = ptagsPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + } + } else { + + /* + * None of the above. Search for an item matching the tag expression. + */ + + for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->rootItemPtr; + itemPtr != NULL; lastPtr = itemPtr, itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + searchPtr->expr->index = 0; + if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; +} + +/* + *-------------------------------------------------------------- + * + * TagSearchNext -- + * + * This function returns successive items that match a given tag; it + * should be called only after TagSearchFirst has been used to begin a + * search. + * + * Results: + * The return value is a pointer to the next item that matches the tag + * expr specified to TagSearchScan, or NULL if no such item exists. + * *SearchPtr is updated so that the next call to this function will + * return the next item. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static Tk_PathItem * +TagSearchNext( + TagSearch *searchPtr) /* Record describing search in progress. */ +{ + Tk_PathItem *itemPtr, *lastPtr; + Tk_PathTags *ptagsPtr; + Tk_Uid uid, *tagPtr; + int count; + + /* + * Find next item in list (this may not actually be a suitable one to + * return), and return if there are no items left. + */ + + lastPtr = searchPtr->lastPtr; + if (lastPtr == NULL) { + itemPtr = searchPtr->canvasPtr->rootItemPtr; + } else { + itemPtr = TkPathCanvasItemIteratorNext(lastPtr); + } + 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 lastPtr; just return its new successor (i.e. do nothing + * here). + */ + } else { + lastPtr = itemPtr; + itemPtr = TkPathCanvasItemIteratorNext(lastPtr); + } + + if (searchPtr->type == SEARCH_TYPE_ALL) { + /* + * All items match. + */ + + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + + if (searchPtr->type == SEARCH_TYPE_TAG) { + /* + * Optimized single-tag search + */ + + uid = searchPtr->expr->uid; + for (; itemPtr != NULL; lastPtr = itemPtr, itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + ptagsPtr = itemPtr->pathTagsPtr; + if (ptagsPtr != NULL) { + for (tagPtr = ptagsPtr->tagPtr, count = ptagsPtr->numTags; + count > 0; tagPtr++, count--) { + if (*tagPtr == uid) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; + } + + /* + * Else.... evaluate tag expression + */ + + for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + searchPtr->expr->index = 0; + if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) { + searchPtr->lastPtr = lastPtr; + searchPtr->currentPtr = itemPtr; + return itemPtr; + } + } + searchPtr->lastPtr = lastPtr; + searchPtr->searchOver = 1; + return NULL; +} +#endif /* USE_OLD_TAG_SEARCH */ + +/* + *-------------------------------------------------------------- + * + * DoItem -- + * + * This is a utility function called by FindItems. It either adds + * itemPtr's id to the result forming in interp, or it adds a new tag to + * itemPtr, depending on the value of tag. + * + * Results: + * None. + * + * Side effects: + * If tag is NULL then itemPtr's id is added as a list element to the + * interp's result; otherwise tag is added to itemPtr's list of tags. + * + *-------------------------------------------------------------- + */ + +static void +DoItem( + Tcl_Interp *interp, /* Interpreter in which to (possibly) record + * item id. */ + Tk_PathItem *itemPtr, /* Item to (possibly) modify. */ + Tk_Uid tag) /* Tag to add to those already present for + * item, or NULL. */ +{ + Tk_Uid *tagPtr; + Tk_PathTags *ptagsPtr; + int count; + + /* + * Handle the "add-to-result" case and return, if appropriate. + */ + + if (tag == NULL) { + char msg[TCL_INTEGER_SPACE]; + + sprintf(msg, "%d", itemPtr->id); + Tcl_AppendElement(interp, msg); + return; + } + + /* + * Do not add if already there. + */ + + ptagsPtr = itemPtr->pathTagsPtr; + if (ptagsPtr != NULL) { + for (tagPtr = ptagsPtr->tagPtr, count = ptagsPtr->numTags; + count > 0; tagPtr++, count--) { + if (tag == *tagPtr) { + return; + } + } + } + + /* + * Grow the tag space if there's no more room left in the current block. + */ + + if (itemPtr->pathTagsPtr == NULL) { + ptagsPtr = TkPathAllocTagsFromObj(NULL, NULL); + itemPtr->pathTagsPtr = ptagsPtr; + tagPtr = ptagsPtr->tagPtr; + } else { + ptagsPtr = itemPtr->pathTagsPtr; + if (ptagsPtr->tagSpace == ptagsPtr->numTags) { + Tk_Uid *newTagPtr; + + ptagsPtr->tagSpace += 5; + newTagPtr = (Tk_Uid *) + ckalloc((unsigned) (ptagsPtr->tagSpace * sizeof(Tk_Uid))); + memcpy((void *) newTagPtr, ptagsPtr->tagPtr, + ptagsPtr->numTags * sizeof(Tk_Uid)); + ckfree((char *) ptagsPtr->tagPtr); + ptagsPtr->tagPtr = newTagPtr; + } + + /* NB: This returns the first free tag address. */ + tagPtr = &ptagsPtr->tagPtr[ptagsPtr->numTags]; + } + + /* + * Add in the new tag. + */ + + *tagPtr = tag; + ptagsPtr->numTags++; +} + +/* + *-------------------------------------------------------------- + * + * FindItems -- + * + * This function does all the work of implementing the "find" and + * "addtag" options of the canvas widget command, which locate items that + * have certain features (location, tags, position in display list, etc.) + * + * Results: + * A standard Tcl return value. If newTag is NULL, then a list of ids + * from all the items that match objc/objv is returned in the interp's + * result. If newTag is NULL, then the normal the interp's result is an + * empty string. If an error occurs, then the interp's result will hold + * an error message. + * + * Side effects: + * If newTag is non-NULL, then all the items that match the information + * in objc/objv have that tag added to their lists of tags. + * + *-------------------------------------------------------------- + */ + +static int +FindItems( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + TkPathCanvas *canvasPtr, /* Canvas whose items are to be searched. */ + int objc, /* Number of entries in argv. Must be greater + * than zero. */ + Tcl_Obj *CONST *objv, /* Arguments that describe what items to + * search for (see user doc on "find" and + * "addtag" options). */ + Tcl_Obj *newTag, /* If non-NULL, gives new tag to set on all + * found items; if NULL, then ids of found + * items are returned in the interp's + * result. */ + int first /* For error messages: gives number of + * elements of objv which are already + * handled. */ +#ifndef USE_OLD_TAG_SEARCH + ,TagSearch **searchPtrPtr /* From CanvasWidgetCmd local vars*/ +#endif /* not USE_OLD_TAG_SEARCH */ + ) +{ +#ifdef USE_OLD_TAG_SEARCH + TagSearch search; +#endif /* USE_OLD_TAG_SEARCH */ + Tk_PathItem *itemPtr; + Tk_Uid uid; + int index, result; + static CONST char *optionStrings[] = { + "above", "all", "below", "closest", + "enclosed", "overlapping", "withtag", NULL + }; + enum options { + CANV_ABOVE, CANV_ALL, CANV_BELOW, CANV_CLOSEST, + CANV_ENCLOSED, CANV_OVERLAPPING, CANV_WITHTAG + }; + + if (newTag != NULL) { + uid = Tk_GetUid(Tcl_GetString(newTag)); + } else { + uid = NULL; + } + if (Tcl_GetIndexFromObj(interp, objv[first], optionStrings, + "search command", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + switch ((enum options) index) { + case CANV_ABOVE: { + Tk_PathItem *lastPtr = NULL; + + if (objc != first+2) { + Tcl_WrongNumArgs(interp, first+1, objv, "tagOrId"); + return TCL_ERROR; + } + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, + return TCL_ERROR) { + lastPtr = itemPtr; + } + + /* We constrain this to siblings. */ + if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) { + DoItem(interp, lastPtr->nextPtr, uid); + } + break; + } + case CANV_ALL: + if (objc != first+1) { + Tcl_WrongNumArgs(interp, first+1, objv, NULL); + return TCL_ERROR; + } + for (itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + DoItem(interp, itemPtr, uid); + } + break; + + case CANV_BELOW: + if (objc != first+2) { + Tcl_WrongNumArgs(interp, first+1, objv, "tagOrId"); + return TCL_ERROR; + } + FIRST_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, + return TCL_ERROR); + if (itemPtr != NULL) { + + /* We constrain this to siblings. */ + if (itemPtr->prevPtr != NULL) { + DoItem(interp, itemPtr->prevPtr, uid); + } + } + break; + case CANV_CLOSEST: { + double closestDist; + Tk_PathItem *startPtr, *closestPtr; + double coords[2], halo; + int x1, y1, x2, y2; + + if ((objc < first+3) || (objc > first+5)) { + Tcl_WrongNumArgs(interp, first+1, objv, "x y ?halo? ?start?"); + return TCL_ERROR; + } + if ((Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, objv[first+1], + &coords[0]) != TCL_OK) || (Tk_PathCanvasGetCoordFromObj(interp, + (Tk_PathCanvas) canvasPtr, objv[first+2], &coords[1]) != TCL_OK)) { + return TCL_ERROR; + } + if (objc > first+3) { + if (Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, objv[first+3], + &halo) != TCL_OK) { + return TCL_ERROR; + } + if (halo < 0.0) { + Tcl_AppendResult(interp, "can't have negative halo value \"", + Tcl_GetString(objv[3]), "\"", NULL); + return TCL_ERROR; + } + } else { + halo = 0.0; + } + + /* + * Find the item at which to start the search. + */ + + startPtr = canvasPtr->rootItemPtr; + if (objc == first+5) { + FIRST_CANVAS_ITEM_MATCHING(objv[first+4], searchPtrPtr, + return TCL_ERROR); + if (itemPtr != NULL) { + startPtr = itemPtr; + } + } + + /* + * The code below is optimized so that it can eliminate most items + * without having to call their item-specific functions. This is done + * by keeping a bounding box (x1, y1, x2, y2) that an item's bbox must + * overlap if the item is to have any chance of being closer than the + * closest so far. + */ + + itemPtr = startPtr; + while(itemPtr && (itemPtr->state == TK_PATHSTATE_HIDDEN || + (itemPtr->state == TK_PATHSTATE_NULL && + canvasPtr->canvas_state == TK_PATHSTATE_HIDDEN))) { + itemPtr = TkPathCanvasItemIteratorNext(itemPtr); + } + if (itemPtr == NULL) { + return TCL_OK; + } + closestDist = (*itemPtr->typePtr->pointProc)((Tk_PathCanvas) canvasPtr, + itemPtr, coords) - halo; + if (closestDist < 0.0) { + closestDist = 0.0; + } + while (1) { + double newDist; + + /* + * Update the bounding box using itemPtr, which is the new closest + * item. + */ + + x1 = (int) (coords[0] - closestDist - halo - 1); + y1 = (int) (coords[1] - closestDist - halo - 1); + x2 = (int) (coords[0] + closestDist + halo + 1); + y2 = (int) (coords[1] + closestDist + halo + 1); + closestPtr = itemPtr; + + /* + * Search for an item that beats the current closest one. Work + * circularly through the canvas's item list until getting back to + * the starting item. + */ + + while (1) { + itemPtr = TkPathCanvasItemIteratorNext(itemPtr); + if (itemPtr == NULL) { + itemPtr = canvasPtr->rootItemPtr; + } + if (itemPtr == startPtr) { + DoItem(interp, closestPtr, uid); + return TCL_OK; + } + if (itemPtr->state == TK_PATHSTATE_HIDDEN || + (itemPtr->state == TK_PATHSTATE_NULL && + canvasPtr->canvas_state == TK_PATHSTATE_HIDDEN)) { + continue; + } + if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1) + || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) { + continue; + } + newDist = (*itemPtr->typePtr->pointProc)((Tk_PathCanvas) canvasPtr, + itemPtr, coords) - halo; + if (newDist < 0.0) { + newDist = 0.0; + } + if (newDist <= closestDist) { + closestDist = newDist; + break; + } + } + } + break; + } + case CANV_ENCLOSED: + if (objc != first+5) { + Tcl_WrongNumArgs(interp, first+1, objv, "x1 y1 x2 y2"); + return TCL_ERROR; + } + return FindArea(interp, canvasPtr, objv+first+1, uid, 1); + case CANV_OVERLAPPING: + if (objc != first+5) { + Tcl_WrongNumArgs(interp, first+1, objv, "x1 y1 x2 y2"); + return TCL_ERROR; + } + return FindArea(interp, canvasPtr, objv+first+1, uid, 0); + case CANV_WITHTAG: + if (objc != first+2) { + Tcl_WrongNumArgs(interp, first+1, objv, "tagOrId"); + return TCL_ERROR; + } + FOR_EVERY_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, + return TCL_ERROR) { + DoItem(interp, itemPtr, uid); + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * FindArea -- + * + * This function implements area searches for the "find" and "addtag" + * options. + * + * Results: + * A standard Tcl return value. If newTag is NULL, then a list of ids + * from all the items overlapping or enclosed by the rectangle given by + * objc is returned in the interp's result. If newTag is NULL, then the + * normal the interp's result is an empty string. If an error occurs, + * then the interp's result will hold an error message. + * + * Side effects: + * If uid is non-NULL, then all the items overlapping or enclosed by the + * area in objv have that tag added to their lists of tags. + * + *-------------------------------------------------------------- + */ + +static int +FindArea( + Tcl_Interp *interp, /* Interpreter for error reporting and result + * storing. */ + TkPathCanvas *canvasPtr, /* Canvas whose items are to be searched. */ + Tcl_Obj *CONST *objv, /* Array of four arguments that give the + * coordinates of the rectangular area to + * search. */ + Tk_Uid uid, /* If non-NULL, gives new tag to set on all + * found items; if NULL, then ids of found + * items are returned in the interp's + * result. */ + int enclosed) /* 0 means overlapping or enclosed items are + * OK, 1 means only enclosed items are OK. */ +{ + double rect[4], tmp; + int x1, y1, x2, y2; + Tk_PathItem *itemPtr; + + if ((Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, objv[0], + &rect[0]) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, objv[1], + &rect[1]) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, objv[2], + &rect[2]) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, (Tk_PathCanvas) canvasPtr, objv[3], + &rect[3]) != TCL_OK)) { + return TCL_ERROR; + } + if (rect[0] > rect[2]) { + tmp = rect[0]; rect[0] = rect[2]; rect[2] = tmp; + } + if (rect[1] > rect[3]) { + tmp = rect[1]; rect[1] = rect[3]; rect[3] = tmp; + } + + /* + * Use an integer bounding box for a quick test, to avoid calling + * item-specific code except for items that are close. + */ + + x1 = (int) (rect[0]-1.0); + y1 = (int) (rect[1]-1.0); + x2 = (int) (rect[2]+1.0); + y2 = (int) (rect[3]+1.0); + for (itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + if (itemPtr->state == TK_PATHSTATE_HIDDEN || (itemPtr->state == TK_PATHSTATE_NULL && + canvasPtr->canvas_state == TK_PATHSTATE_HIDDEN)) { + continue; + } + if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1) + || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) { + continue; + } + if ((*itemPtr->typePtr->areaProc)((Tk_PathCanvas) canvasPtr, itemPtr, rect) + >= enclosed) { + DoItem(interp, itemPtr, uid); + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * RelinkItems -- + * + * Move one or more items to a different place in the display order for a + * canvas. + * Only items with same parent as prevPtr will be moved. Items matching + * tag but with different parent will be silently ignored. + * If we didn't do this we would break the tree hierarchy structure + * which would create a mess! + * + * Results: + * None. + * + * Side effects: + * The items identified by "tag" are moved so that they are all together + * in the display list and immediately after prevPtr. The order of the + * moved items relative to each other is not changed. + * + *-------------------------------------------------------------- + */ + +#ifdef USE_OLD_TAG_SEARCH +static void +RelinkItems( + TkPathCanvas *canvasPtr, /* Canvas to be modified. */ + Tcl_Obj *tag, /* Tag identifying items to be moved in the + * redisplay list. */ + Tk_PathItem *prevPtr) /* Reposition the items so that they go just + * after this item (NULL means put at + * beginning of list). */ +#else /* USE_OLD_TAG_SEARCH */ +static int +RelinkItems( + TkPathCanvas *canvasPtr, /* Canvas to be modified. */ + Tcl_Obj *tag, /* Tag identifying items to be moved in the + * redisplay list. */ + Tk_PathItem *prevPtr, /* Reposition the items so that they go just + * after this item (NULL means put at + * beginning of list). */ + TagSearch **searchPtrPtr) /* From CanvasWidgetCmd local vars */ +#endif /* USE_OLD_TAG_SEARCH */ +{ + Tk_PathItem *itemPtr; +#ifdef USE_OLD_TAG_SEARCH + TagSearch search; +#endif /* USE_OLD_TAG_SEARCH */ + Tk_PathItem *firstMovePtr, *lastMovePtr; + Tk_PathItem *parentPtr, *rootItemPtr; + int result; + + rootItemPtr = canvasPtr->rootItemPtr; + if (prevPtr == rootItemPtr) { +#ifdef USE_OLD_TAG_SEARCH + return; +#else /* USE_OLD_TAG_SEARCH */ + return TCL_OK; +#endif /* USE_OLD_TAG_SEARCH */ + } + + /* + * Keep track of parentPtr for the selection of items. + * prevPtr equal to NULL means use the root item as parent. + * This keeps compatiblity with old canvas. + */ + if (prevPtr != NULL) { + parentPtr = prevPtr->parentPtr; + } else { + parentPtr = rootItemPtr; + } + + /* + * Find all of the items to be moved and remove them from the list, making + * an auxiliary list running from firstMovePtr to lastMovePtr. Record + * their areas for redisplay. + */ + firstMovePtr = lastMovePtr = NULL; + FOR_EVERY_CANVAS_ITEM_MATCHING(tag, searchPtrPtr, return TCL_ERROR) { + if (itemPtr->parentPtr == NULL) { + continue; + } + if (itemPtr->parentPtr != parentPtr) { + continue; + } + if (itemPtr == prevPtr) { + /* + * Item after which insertion is to occur is being moved! Switch + * to insert after its predecessor. + */ + + prevPtr = prevPtr->prevPtr; + } + + /* + * Detach (splice out) item to be moved. + */ + if (itemPtr->parentPtr->firstChildPtr == itemPtr) { + itemPtr->parentPtr->firstChildPtr = itemPtr->nextPtr; + } + if (itemPtr->parentPtr->lastChildPtr == itemPtr) { + itemPtr->parentPtr->lastChildPtr = itemPtr->prevPtr; + } + if (itemPtr->prevPtr != NULL) { + itemPtr->prevPtr->nextPtr = itemPtr->nextPtr; + } + if (itemPtr->nextPtr != NULL) { + itemPtr->nextPtr->prevPtr = itemPtr->prevPtr; + } + + /* + * Place moved item as the last item of the + * moved linked list. + */ + if (firstMovePtr == NULL) { + itemPtr->prevPtr = NULL; + itemPtr->nextPtr = NULL; + firstMovePtr = itemPtr; + } else { + itemPtr->prevPtr = lastMovePtr; + lastMovePtr->nextPtr = itemPtr; + } + lastMovePtr = itemPtr; + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + canvasPtr->flags |= REPICK_NEEDED; + } + + if (firstMovePtr == NULL) { +#ifdef USE_OLD_TAG_SEARCH + return; +#else /* USE_OLD_TAG_SEARCH */ + return TCL_OK; +#endif /* USE_OLD_TAG_SEARCH */ + } + + /* + * Insert the list of to-be-moved items back into the canvas's at the + * desired position. + */ + firstMovePtr->prevPtr = prevPtr; + if (prevPtr != NULL) { + if (prevPtr->nextPtr != NULL) { + prevPtr->nextPtr->prevPtr = lastMovePtr; + } + lastMovePtr->nextPtr = prevPtr->nextPtr; + prevPtr->nextPtr = firstMovePtr; + } else { + if (parentPtr->firstChildPtr != NULL) { + parentPtr->firstChildPtr->prevPtr = lastMovePtr; + } + lastMovePtr->nextPtr = parentPtr->firstChildPtr; + parentPtr->firstChildPtr = firstMovePtr; + } + if (parentPtr->lastChildPtr == prevPtr) { + parentPtr->lastChildPtr = lastMovePtr; + } + +#ifndef USE_OLD_TAG_SEARCH + return TCL_OK; +#endif /* not USE_OLD_TAG_SEARCH */ +} + +/* + *-------------------------------------------------------------- + * + * CanvasBindProc -- + * + * This function is invoked by the Tk dispatcher to handle events + * associated with bindings on items. + * + * Results: + * None. + * + * Side effects: + * Depends on the command invoked as part of the binding (if there was + * any). + * + *-------------------------------------------------------------- + */ + +static void +CanvasBindProc( + ClientData clientData, /* Pointer to canvas structure. */ + XEvent *eventPtr) /* Pointer to X event that just happened. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) clientData; + + Tcl_Preserve((ClientData) canvasPtr); + + /* + * This code below keeps track of the current modifier state in + * canvasPtr>state. This information is used to defer repicks of the + * current item while buttons are down. + */ + + if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) { + int mask; + + switch (eventPtr->xbutton.button) { + case Button1: + mask = Button1Mask; + break; + case Button2: + mask = Button2Mask; + break; + case Button3: + mask = Button3Mask; + break; + case Button4: + mask = Button4Mask; + break; + case Button5: + mask = Button5Mask; + break; + default: + mask = 0; + break; + } + + /* + * For button press events, repick the current item using the button + * state before the event, then process the event. For button release + * events, first process the event, then repick the current item using + * the button state *after* the event (the button has logically gone + * up before we change the current item). + */ + + if (eventPtr->type == ButtonPress) { + /* + * On a button press, first repick the current item using the + * button state before the event, the process the event. + */ + + canvasPtr->state = eventPtr->xbutton.state; + PickCurrentItem(canvasPtr, eventPtr); + canvasPtr->state ^= mask; + CanvasDoEvent(canvasPtr, eventPtr); + } else { + /* + * Button release: first process the event, with the button still + * considered to be down. Then repick the current item under the + * assumption that the button is no longer down. + */ + + canvasPtr->state = eventPtr->xbutton.state; + CanvasDoEvent(canvasPtr, eventPtr); + eventPtr->xbutton.state ^= mask; + canvasPtr->state = eventPtr->xbutton.state; + PickCurrentItem(canvasPtr, eventPtr); + eventPtr->xbutton.state ^= mask; + } + goto done; + } else if ((eventPtr->type == EnterNotify) + || (eventPtr->type == LeaveNotify)) { + canvasPtr->state = eventPtr->xcrossing.state; + PickCurrentItem(canvasPtr, eventPtr); + goto done; + } else if (eventPtr->type == MotionNotify) { + canvasPtr->state = eventPtr->xmotion.state; + PickCurrentItem(canvasPtr, eventPtr); + } + CanvasDoEvent(canvasPtr, eventPtr); + + done: + Tcl_Release((ClientData) canvasPtr); +} + +/* + *-------------------------------------------------------------- + * + * PickCurrentItem -- + * + * Find the topmost item in a canvas that contains a given location and + * mark the the current item. If the current item has changed, generate a + * fake exit event on the old current item, a fake enter event on the new + * current item item and force a redraw of the two items. Canvas items + * that are hidden or disabled are ignored. + * + * Results: + * None. + * + * Side effects: + * The current item for canvasPtr may change. If it does, then the + * commands associated with item entry and exit could do just about + * anything. A binding script could delete the canvas, so callers should + * protect themselves with Tcl_Preserve and Tcl_Release. + * + *-------------------------------------------------------------- + */ + +static void +PickCurrentItem( + TkPathCanvas *canvasPtr, /* Canvas widget in which to select current + * item. */ + XEvent *eventPtr) /* Event describing location of mouse cursor. + * Must be EnterWindow, LeaveWindow, + * ButtonRelease, or MotionNotify. */ +{ + double coords[2]; + int buttonDown; + Tk_PathItem *prevItemPtr; +#ifndef USE_OLD_TAG_SEARCH + SearchUids *searchUids = GetStaticUids(); +#endif + + /* + * Check whether or not a button is down. If so, we'll log entry and exit + * into and out of the current item, but not entry into any other item. + * This implements a form of grabbing equivalent to what the X server does + * for windows. + */ + + buttonDown = canvasPtr->state + & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask); + if (!buttonDown) { + canvasPtr->flags &= ~LEFT_GRABBED_ITEM; + } + + /* + * Save information about this event in the canvas. The event in the + * canvas is used for two purposes: + * + * 1. Event bindings: if the current item changes, fake events are + * generated to allow item-enter and item-leave bindings to trigger. + * 2. Reselection: if the current item gets deleted, can use the saved + * event to find a new current item. + * + * Translate MotionNotify events into EnterNotify events, since that's + * what gets reported to item handlers. + */ + + if (eventPtr != &canvasPtr->pickEvent) { + if ((eventPtr->type == MotionNotify) + || (eventPtr->type == ButtonRelease)) { + canvasPtr->pickEvent.xcrossing.type = EnterNotify; + canvasPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial; + canvasPtr->pickEvent.xcrossing.send_event + = eventPtr->xmotion.send_event; + canvasPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display; + canvasPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window; + canvasPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root; + canvasPtr->pickEvent.xcrossing.subwindow = None; + canvasPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time; + canvasPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x; + canvasPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y; + canvasPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root; + canvasPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root; + canvasPtr->pickEvent.xcrossing.mode = NotifyNormal; + canvasPtr->pickEvent.xcrossing.detail = NotifyNonlinear; + canvasPtr->pickEvent.xcrossing.same_screen + = eventPtr->xmotion.same_screen; + canvasPtr->pickEvent.xcrossing.focus = False; + canvasPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state; + } else { + canvasPtr->pickEvent = *eventPtr; + } + } + + /* + * If this is a recursive call (there's already a partially completed call + * pending on the stack; it's in the middle of processing a Leave event + * handler for the old current item) then just return; the pending call + * will do everything that's needed. + */ + + if (canvasPtr->flags & REPICK_IN_PROGRESS) { + return; + } + + /* + * A LeaveNotify event automatically means that there's no current object, + * so the check for closest item can be skipped. + */ + + coords[0] = canvasPtr->pickEvent.xcrossing.x + canvasPtr->xOrigin; + coords[1] = canvasPtr->pickEvent.xcrossing.y + canvasPtr->yOrigin; + if (canvasPtr->pickEvent.type != LeaveNotify) { + canvasPtr->newCurrentPtr = CanvasFindClosest(canvasPtr, coords); + } else { + canvasPtr->newCurrentPtr = NULL; + } + + if ((canvasPtr->newCurrentPtr == canvasPtr->currentItemPtr) + && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) { + /* + * Nothing to do: the current item hasn't changed. + */ + + return; + } + + /* + * Simulate a LeaveNotify event on the previous current item and an + * EnterNotify event on the new current item. Remove the "current" tag + * from the previous current item and place it on the new current item. + */ + + if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr) + && (canvasPtr->currentItemPtr != NULL) + && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) { + XEvent event; + Tk_PathItem *itemPtr = canvasPtr->currentItemPtr; + Tk_PathTags *ptagsPtr; + int i; + + event = canvasPtr->pickEvent; + event.type = LeaveNotify; + + /* + * If the event's detail happens to be NotifyInferior the binding + * mechanism will discard the event. To be consistent, always use + * NotifyAncestor. + */ + + event.xcrossing.detail = NotifyAncestor; + canvasPtr->flags |= REPICK_IN_PROGRESS; + CanvasDoEvent(canvasPtr, &event); + canvasPtr->flags &= ~REPICK_IN_PROGRESS; + + /* + * The check below is needed because there could be an event handler + * for <LeaveNotify> that deletes the current item. + */ + + if ((itemPtr == canvasPtr->currentItemPtr) && !buttonDown && + (itemPtr->pathTagsPtr != NULL)) { + ptagsPtr = itemPtr->pathTagsPtr; + for (i = ptagsPtr->numTags-1; i >= 0; i--) { +#ifdef USE_OLD_TAG_SEARCH + if (ptagsPtr->tagPtr[i] == Tk_GetUid("current")) +#else /* USE_OLD_TAG_SEARCH */ + if (ptagsPtr->tagPtr[i] == searchUids->currentUid) +#endif /* USE_OLD_TAG_SEARCH */ + /* then */ { + ptagsPtr->tagPtr[i] = ptagsPtr->tagPtr[ptagsPtr->numTags-1]; + ptagsPtr->numTags--; + break; + } + } + } + + /* + * Note: during CanvasDoEvent above, it's possible that + * canvasPtr->newCurrentPtr got reset to NULL because the item was + * deleted. + */ + } + if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr) && buttonDown) { + canvasPtr->flags |= LEFT_GRABBED_ITEM; + return; + } + + /* + * Special note: it's possible that canvasPtr->newCurrentPtr == + * canvasPtr->currentItemPtr here. This can happen, for example, if + * LEFT_GRABBED_ITEM was set. + */ + + prevItemPtr = canvasPtr->currentItemPtr; + canvasPtr->flags &= ~LEFT_GRABBED_ITEM; + canvasPtr->currentItemPtr = canvasPtr->newCurrentPtr; + if (prevItemPtr != NULL && prevItemPtr != canvasPtr->currentItemPtr && + (prevItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT)) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, prevItemPtr); + (*prevItemPtr->typePtr->configProc)(canvasPtr->interp, + (Tk_PathCanvas) canvasPtr, prevItemPtr, 0, NULL, + TK_CONFIG_ARGV_ONLY); + } + if (canvasPtr->currentItemPtr != NULL) { + XEvent event; + +#ifdef USE_OLD_TAG_SEARCH + DoItem(NULL, canvasPtr->currentItemPtr, Tk_GetUid("current")); +#else /* USE_OLD_TAG_SEARCH */ + DoItem(NULL, canvasPtr->currentItemPtr, searchUids->currentUid); +#endif /* USE_OLD_TAG_SEA */ + if ((canvasPtr->currentItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT && + prevItemPtr != canvasPtr->currentItemPtr)) { + (*canvasPtr->currentItemPtr->typePtr->configProc)(canvasPtr->interp, + (Tk_PathCanvas) canvasPtr, canvasPtr->currentItemPtr, 0, NULL, + TK_CONFIG_ARGV_ONLY); + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, + canvasPtr->currentItemPtr); + } + event = canvasPtr->pickEvent; + event.type = EnterNotify; + event.xcrossing.detail = NotifyAncestor; + CanvasDoEvent(canvasPtr, &event); + } +} + +/* + *---------------------------------------------------------------------- + * + * CanvasFindClosest -- + * + * Given x and y coordinates, find the topmost canvas item that is + * "close" to the coordinates. Canvas items that are hidden or disabled + * are ignored. + * + * Results: + * The return value is a pointer to the topmost item that is close to + * (x,y), or NULL if no item is close. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tk_PathItem * +CanvasFindClosest( + TkPathCanvas *canvasPtr, /* Canvas widget to search. */ + double coords[2]) /* Desired x,y position in canvas, not screen, + * coordinates.) */ +{ + Tk_PathItem *itemPtr; + Tk_PathItem *bestPtr; + int x1, y1, x2, y2; + + x1 = (int) (coords[0] - canvasPtr->closeEnough); + y1 = (int) (coords[1] - canvasPtr->closeEnough); + x2 = (int) (coords[0] + canvasPtr->closeEnough); + y2 = (int) (coords[1] + canvasPtr->closeEnough); + + bestPtr = NULL; + for (itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + if (itemPtr->state == TK_PATHSTATE_HIDDEN || itemPtr->state==TK_PATHSTATE_DISABLED || + (itemPtr->state == TK_PATHSTATE_NULL && (canvasPtr->canvas_state == TK_PATHSTATE_HIDDEN || + canvasPtr->canvas_state == TK_PATHSTATE_DISABLED))) { + continue; + } + if ((itemPtr->x1 > x2) || (itemPtr->x2 < x1) + || (itemPtr->y1 > y2) || (itemPtr->y2 < y1)) { + continue; + } + if ((*itemPtr->typePtr->pointProc)((Tk_PathCanvas) canvasPtr, + itemPtr, coords) <= canvasPtr->closeEnough) { + bestPtr = itemPtr; + } + } + return bestPtr; +} + +/* + *-------------------------------------------------------------- + * + * CanvasDoEvent -- + * + * This function is called to invoke binding processing for a new event + * that is associated with the current item for a canvas. + * + * Results: + * None. + * + * Side effects: + * Depends on the bindings for the canvas. A binding script could delete + * the canvas, so callers should protect themselves with Tcl_Preserve and + * Tcl_Release. + * + *-------------------------------------------------------------- + */ + +static void +CanvasDoEvent( + TkPathCanvas *canvasPtr, /* Canvas widget in which event occurred. */ + XEvent *eventPtr) /* Real or simulated X event that is to be + * processed. */ +{ +#define NUM_STATIC 3 + ClientData staticObjects[NUM_STATIC]; + ClientData *objectPtr; + int numObjects, i; + int numTags; + Tk_PathItem *itemPtr; + Tk_PathTags *ptagsPtr; +#ifndef USE_OLD_TAG_SEARCH + TagSearchExpr *expr; + int numExprs; + SearchUids *searchUids = GetStaticUids(); +#endif /* not USE_OLD_TAG_SEARCH */ + + if (canvasPtr->bindingTable == NULL) { + return; + } + + itemPtr = canvasPtr->currentItemPtr; + if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) { + itemPtr = canvasPtr->textInfo.focusItemPtr; + } + if (itemPtr == NULL) { + return; + } + ptagsPtr = itemPtr->pathTagsPtr; + numTags = ItemGetNumTags(itemPtr); + +#ifdef USE_OLD_TAG_SEARCH + /* + * Set up an array with all the relevant objects for processing this + * event. The relevant objects are (a) the event's item, (b) the tags + * associated with the event's item, and (c) the tag "all". If there are a + * lot of tags then malloc an array to hold all of the objects. + */ + + numObjects = numTags + 2; + +#else /* USE_OLD_TAG_SEARCH */ + /* + * Set up an array with all the relevant objects for processing this + * event. The relevant objects are: + * (a) the event's item, + * (b) the tags associated with the event's item, + * (c) the expressions that are true for the event's item's tags, and + * (d) the tag "all". + * + * If there are a lot of tags then malloc an array to hold all of the + * objects. + */ + + /* + * Flag and count all expressions that match item's tags. + */ + + numExprs = 0; + expr = canvasPtr->bindTagExprs; + while (expr) { + expr->index = 0; + expr->match = TagSearchEvalExpr(expr, itemPtr); + if (expr->match) { + numExprs++; + } + expr = expr->next; + } + numObjects = numTags + numExprs + 2; + +#endif /* not USE_OLD_TAG_SEARCH */ + + if (numObjects <= NUM_STATIC) { + objectPtr = staticObjects; + } else { + objectPtr = (ClientData *) ckalloc((unsigned) + (numObjects * sizeof(ClientData))); + } +#ifdef USE_OLD_TAG_SEARCH + objectPtr[0] = (ClientData) Tk_GetUid("all"); +#else /* USE_OLD_TAG_SEARCH */ + objectPtr[0] = (ClientData) searchUids->allUid; +#endif /* USE_OLD_TAG_SEARCH */ + + if (ptagsPtr != NULL) { + for (i = ptagsPtr->numTags-1; i >= 0; i--) { + objectPtr[i+1] = (ClientData) ptagsPtr->tagPtr[i]; + } + } + objectPtr[numTags+1] = (ClientData) itemPtr; + +#ifndef USE_OLD_TAG_SEARCH + /* + * Copy uids of matching expressions into object array + */ + + i = numTags + 2; + expr = canvasPtr->bindTagExprs; + while (expr) { + if (expr->match) { + objectPtr[i++] = (int *) expr->uid; + } + expr = expr->next; + } +#endif /* not USE_OLD_TAG_SEARCH */ + + /* + * Invoke the binding system, then free up the object array if it was + * malloc-ed. + */ + + if (canvasPtr->tkwin != NULL) { + Tk_BindEvent(canvasPtr->bindingTable, eventPtr, canvasPtr->tkwin, + numObjects, objectPtr); + } + if (objectPtr != staticObjects) { + ckfree((char *) objectPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * CanvasBlinkProc -- + * + * This function is called as a timer handler to blink the insertion + * cursor off and on. + * + * Results: + * None. + * + * Side effects: + * The cursor gets turned on or off, redisplay gets invoked, and this + * function reschedules itself. + * + *---------------------------------------------------------------------- + */ + +static void +CanvasBlinkProc( + ClientData clientData) /* Pointer to record describing entry. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) clientData; + + if (!canvasPtr->textInfo.gotFocus || (canvasPtr->insertOffTime == 0)) { + return; + } + if (canvasPtr->textInfo.cursorOn) { + canvasPtr->textInfo.cursorOn = 0; + canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler( + canvasPtr->insertOffTime, CanvasBlinkProc, + (ClientData) canvasPtr); + } else { + canvasPtr->textInfo.cursorOn = 1; + canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler( + canvasPtr->insertOnTime, CanvasBlinkProc, + (ClientData) canvasPtr); + } + if (canvasPtr->textInfo.focusItemPtr != NULL) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, + canvasPtr->textInfo.focusItemPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * CanvasFocusProc -- + * + * This function is called whenever a canvas gets or loses the input + * focus. It's also called whenever the window is reconfigured while it + * has the focus. + * + * Results: + * None. + * + * Side effects: + * The cursor gets turned on or off. + * + *---------------------------------------------------------------------- + */ + +static void +CanvasFocusProc( + TkPathCanvas *canvasPtr, /* Canvas that just got or lost focus. */ + int gotFocus) /* 1 means window is getting focus, 0 means + * it's losing it. */ +{ + Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler); + if (gotFocus) { + canvasPtr->textInfo.gotFocus = 1; + canvasPtr->textInfo.cursorOn = 1; + if (canvasPtr->insertOffTime != 0) { + canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler( + canvasPtr->insertOffTime, CanvasBlinkProc, + (ClientData) canvasPtr); + } + } else { + canvasPtr->textInfo.gotFocus = 0; + canvasPtr->textInfo.cursorOn = 0; + canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL; + } + if (canvasPtr->textInfo.focusItemPtr != NULL) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, + canvasPtr->textInfo.focusItemPtr); + } + if (canvasPtr->highlightWidth > 0) { + canvasPtr->flags |= REDRAW_BORDERS; + if (!(canvasPtr->flags & REDRAW_PENDING)) { + Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr); + canvasPtr->flags |= REDRAW_PENDING; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * CanvasSelectTo -- + * + * Modify the selection by moving its un-anchored end. This could make + * the selection either larger or smaller. + * + * Results: + * None. + * + * Side effects: + * The selection changes. + * + *---------------------------------------------------------------------- + */ + +static void +CanvasSelectTo( + TkPathCanvas *canvasPtr, /* Information about widget. */ + Tk_PathItem *itemPtr, /* Item that is to hold selection. */ + int index) /* Index of element that is to become the + * "other" end of the selection. */ +{ + int oldFirst, oldLast; + Tk_PathItem *oldSelPtr; + + oldFirst = canvasPtr->textInfo.selectFirst; + oldLast = canvasPtr->textInfo.selectLast; + oldSelPtr = canvasPtr->textInfo.selItemPtr; + + /* + * Grab the selection if we don't own it already. + */ + + if (canvasPtr->textInfo.selItemPtr == NULL) { + Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection, + (ClientData) canvasPtr); + } else if (canvasPtr->textInfo.selItemPtr != itemPtr) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, + canvasPtr->textInfo.selItemPtr); + } + canvasPtr->textInfo.selItemPtr = itemPtr; + + if (canvasPtr->textInfo.anchorItemPtr != itemPtr) { + canvasPtr->textInfo.anchorItemPtr = itemPtr; + canvasPtr->textInfo.selectAnchor = index; + } + if (canvasPtr->textInfo.selectAnchor <= index) { + canvasPtr->textInfo.selectFirst = canvasPtr->textInfo.selectAnchor; + canvasPtr->textInfo.selectLast = index; + } else { + canvasPtr->textInfo.selectFirst = index; + canvasPtr->textInfo.selectLast = canvasPtr->textInfo.selectAnchor - 1; + } + if ((canvasPtr->textInfo.selectFirst != oldFirst) + || (canvasPtr->textInfo.selectLast != oldLast) + || (itemPtr != oldSelPtr)) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, itemPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * CanvasFetchSelection -- + * + * This function is invoked by Tk to return part or all of the selection, + * when the selection is in a canvas widget. This function always returns + * the selection as a STRING. + * + * 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 +CanvasFetchSelection( + ClientData clientData, /* Information about canvas 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. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) clientData; + + if (canvasPtr->textInfo.selItemPtr == NULL) { + return -1; + } + if (canvasPtr->textInfo.selItemPtr->typePtr->selectionProc == NULL) { + return -1; + } + return (*canvasPtr->textInfo.selItemPtr->typePtr->selectionProc)( + (Tk_PathCanvas) canvasPtr, canvasPtr->textInfo.selItemPtr, offset, + buffer, maxBytes); +} + +/* + *---------------------------------------------------------------------- + * + * CanvasLostSelection -- + * + * This function is called back by Tk when the selection is grabbed away + * from a canvas widget. + * + * Results: + * None. + * + * Side effects: + * The existing selection is unhighlighted, and the window is marked as + * not containing a selection. + * + *---------------------------------------------------------------------- + */ + +static void +CanvasLostSelection( + ClientData clientData) /* Information about entry widget. */ +{ + TkPathCanvas *canvasPtr = (TkPathCanvas *) clientData; + + if (canvasPtr->textInfo.selItemPtr != NULL) { + EventuallyRedrawItem((Tk_PathCanvas) canvasPtr, + canvasPtr->textInfo.selItemPtr); + } + canvasPtr->textInfo.selItemPtr = NULL; +} + +/* + *-------------------------------------------------------------- + * + * GridAlign -- + * + * Given a coordinate and a grid spacing, this function computes the + * location of the nearest grid line to the coordinate. + * + * Results: + * The return value is the location of the grid line nearest to coord. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static double +GridAlign( + double coord, /* Coordinate to grid-align. */ + double spacing) /* Spacing between grid lines. If <= 0 then no + * alignment is done. */ +{ + if (spacing <= 0.0) { + return coord; + } + if (coord < 0) { + return -((int) ((-coord)/spacing + 0.5)) * spacing; + } + return ((int) (coord/spacing + 0.5)) * spacing; +} + +/* + *---------------------------------------------------------------------- + * + * ScrollFractions -- + * + * Given the range that's visible in the window and the "100% range" for + * what's in the canvas, return a list of two doubles representing the + * scroll fractions. This function is used for both x and y scrolling. + * + * Results: + * A List Tcl_Obj with two real numbers (Double Tcl_Objs) containing the + * scroll fractions (between 0 and 1) corresponding to the other + * arguments. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tcl_Obj * +ScrollFractions( + int screen1, /* Lowest coordinate visible in the window. */ + int screen2, /* Highest coordinate visible in the window. */ + int object1, /* Lowest coordinate in the object. */ + int object2) /* Highest coordinate in the object. */ +{ + Tcl_Obj *buffer[2]; + double range, f1, f2; + + range = object2 - object1; + if (range <= 0) { + f1 = 0; + f2 = 1.0; + } else { + f1 = (screen1 - object1)/range; + if (f1 < 0) { + f1 = 0.0; + } + f2 = (screen2 - object1)/range; + if (f2 > 1.0) { + f2 = 1.0; + } + if (f2 < f1) { + f2 = f1; + } + } + buffer[0] = Tcl_NewDoubleObj(f1); + buffer[1] = Tcl_NewDoubleObj(f2); + return Tcl_NewListObj(2, buffer); +} + +/* + *-------------------------------------------------------------- + * + * CanvasUpdateScrollbars -- + * + * This function is invoked whenever a canvas has changed in a way that + * requires scrollbars to be redisplayed (e.g. the view in the canvas has + * changed). + * + * Results: + * None. + * + * Side effects: + * If there are scrollbars associated with the canvas, then their + * scrolling commands are invoked to cause them to redisplay. If errors + * occur, additional Tcl commands may be invoked to process the errors. + * + *-------------------------------------------------------------- + */ + +static void +CanvasUpdateScrollbars( + TkPathCanvas *canvasPtr) /* Information about canvas. */ +{ + int result; + Tcl_Interp *interp; + int xOrigin, yOrigin, inset, width, height; + int scrollX1, scrollX2, scrollY1, scrollY2; + char *xScrollCmd, *yScrollCmd; + + /* + * Save all the relevant values from the canvasPtr, because it might be + * deleted as part of either of the two calls to Tcl_VarEval below. + */ + + interp = canvasPtr->interp; + Tcl_Preserve((ClientData) interp); + xScrollCmd = canvasPtr->xScrollCmd; + if (xScrollCmd != NULL) { + Tcl_Preserve((ClientData) xScrollCmd); + } + yScrollCmd = canvasPtr->yScrollCmd; + if (yScrollCmd != NULL) { + Tcl_Preserve((ClientData) yScrollCmd); + } + xOrigin = canvasPtr->xOrigin; + yOrigin = canvasPtr->yOrigin; + inset = canvasPtr->inset; + width = Tk_Width(canvasPtr->tkwin); + height = Tk_Height(canvasPtr->tkwin); + scrollX1 = canvasPtr->scrollX1; + scrollX2 = canvasPtr->scrollX2; + scrollY1 = canvasPtr->scrollY1; + scrollY2 = canvasPtr->scrollY2; + canvasPtr->flags &= ~UPDATE_SCROLLBARS; + if (canvasPtr->xScrollCmd != NULL) { + Tcl_Obj *fractions = ScrollFractions(xOrigin + inset, + xOrigin + width - inset, scrollX1, scrollX2); + result = Tcl_VarEval(interp, xScrollCmd, " ", Tcl_GetString(fractions), + NULL); + Tcl_DecrRefCount(fractions); + if (result != TCL_OK) { + Tcl_BackgroundError(interp); + } + Tcl_ResetResult(interp); + Tcl_Release((ClientData) xScrollCmd); + } + + if (yScrollCmd != NULL) { + Tcl_Obj *fractions = ScrollFractions(yOrigin + inset, + yOrigin + height - inset, scrollY1, scrollY2); + result = Tcl_VarEval(interp, yScrollCmd, " ", Tcl_GetString(fractions), + NULL); + Tcl_DecrRefCount(fractions); + if (result != TCL_OK) { + Tcl_BackgroundError(interp); + } + Tcl_ResetResult(interp); + Tcl_Release((ClientData) yScrollCmd); + } + Tcl_Release((ClientData) interp); +} + +/* + *-------------------------------------------------------------- + * + * CanvasSetOrigin -- + * + * This function is invoked to change the mapping between canvas + * coordinates and screen coordinates in the canvas window. + * + * Results: + * None. + * + * Side effects: + * The canvas will be redisplayed to reflect the change in view. In + * addition, scrollbars will be updated if there are any. + * + *-------------------------------------------------------------- + */ + +static void +CanvasSetOrigin( + TkPathCanvas *canvasPtr, /* Information about canvas. */ + int xOrigin, /* New X origin for canvas (canvas x-coord + * corresponding to left edge of canvas + * window). */ + int yOrigin) /* New Y origin for canvas (canvas y-coord + * corresponding to top edge of canvas + * window). */ +{ + int left, right, top, bottom, delta; + + /* + * If scroll increments have been set, round the window origin to the + * nearest multiple of the increments. Remember, the origin is the place + * just inside the borders, not the upper left corner. + */ + + if (canvasPtr->xScrollIncrement > 0) { + if (xOrigin >= 0) { + xOrigin += canvasPtr->xScrollIncrement/2; + xOrigin -= (xOrigin + canvasPtr->inset) + % canvasPtr->xScrollIncrement; + } else { + xOrigin = (-xOrigin) + canvasPtr->xScrollIncrement/2; + xOrigin = -(xOrigin - (xOrigin - canvasPtr->inset) + % canvasPtr->xScrollIncrement); + } + } + if (canvasPtr->yScrollIncrement > 0) { + if (yOrigin >= 0) { + yOrigin += canvasPtr->yScrollIncrement/2; + yOrigin -= (yOrigin + canvasPtr->inset) + % canvasPtr->yScrollIncrement; + } else { + yOrigin = (-yOrigin) + canvasPtr->yScrollIncrement/2; + yOrigin = -(yOrigin - (yOrigin - canvasPtr->inset) + % canvasPtr->yScrollIncrement); + } + } + + /* + * Adjust the origin if necessary to keep as much as possible of the + * canvas in the view. The variables left, right, etc. keep track of how + * much extra space there is on each side of the view before it will stick + * out past the scroll region. If one side sticks out past the edge of + * the scroll region, adjust the view to bring that side back to the edge + * of the scrollregion (but don't move it so much that the other side + * sticks out now). If scroll increments are in effect, be sure to adjust + * only by full increments. + */ + + if ((canvasPtr->confine) && (canvasPtr->regionString != NULL)) { + left = xOrigin + canvasPtr->inset - canvasPtr->scrollX1; + right = canvasPtr->scrollX2 + - (xOrigin + Tk_Width(canvasPtr->tkwin) - canvasPtr->inset); + top = yOrigin + canvasPtr->inset - canvasPtr->scrollY1; + bottom = canvasPtr->scrollY2 + - (yOrigin + Tk_Height(canvasPtr->tkwin) - canvasPtr->inset); + if ((left < 0) && (right > 0)) { + delta = (right > -left) ? -left : right; + if (canvasPtr->xScrollIncrement > 0) { + delta -= delta % canvasPtr->xScrollIncrement; + } + xOrigin += delta; + } else if ((right < 0) && (left > 0)) { + delta = (left > -right) ? -right : left; + if (canvasPtr->xScrollIncrement > 0) { + delta -= delta % canvasPtr->xScrollIncrement; + } + xOrigin -= delta; + } + if ((top < 0) && (bottom > 0)) { + delta = (bottom > -top) ? -top : bottom; + if (canvasPtr->yScrollIncrement > 0) { + delta -= delta % canvasPtr->yScrollIncrement; + } + yOrigin += delta; + } else if ((bottom < 0) && (top > 0)) { + delta = (top > -bottom) ? -bottom : top; + if (canvasPtr->yScrollIncrement > 0) { + delta -= delta % canvasPtr->yScrollIncrement; + } + yOrigin -= delta; + } + } + + if ((xOrigin == canvasPtr->xOrigin) && (yOrigin == canvasPtr->yOrigin)) { + return; + } + + /* + * Tricky point: must redisplay not only everything that's visible in the + * window's final configuration, but also everything that was visible in + * the initial configuration. This is needed because some item types, like + * windows, need to know when they move off-screen so they can explicitly + * undisplay themselves. + */ + + Tk_PathCanvasEventuallyRedraw((Tk_PathCanvas) canvasPtr, + canvasPtr->xOrigin, canvasPtr->yOrigin, + canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), + canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); + canvasPtr->xOrigin = xOrigin; + canvasPtr->yOrigin = yOrigin; + canvasPtr->flags |= UPDATE_SCROLLBARS; + Tk_PathCanvasEventuallyRedraw((Tk_PathCanvas) canvasPtr, + canvasPtr->xOrigin, canvasPtr->yOrigin, + canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin), + canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)); +} + +/* + *---------------------------------------------------------------------- + * + * TkGetStringsFromObjs -- + * + * Results: + * Converts object list into string list. + * + * Side effects: + * Memory is allocated for the objv array, which must be freed using + * ckfree() when no longer needed. + * + *---------------------------------------------------------------------- + */ + +// @@@ TODO: this shouldn't be needed when fully objectified! + +/* ARGSUSED */ +static CONST char ** +TkGetStringsFromObjs( + int objc, + Tcl_Obj *CONST objv[]) +{ + register int i; + CONST char **argv; + if (objc <= 0) { + return NULL; + } + argv = (CONST char **) ckalloc((objc+1) * sizeof(char *)); + for (i = 0; i < objc; i++) { + argv[i] = Tcl_GetString(objv[i]); + } + argv[objc] = 0; + return argv; +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasPsColor -- + * + * This function is called by individual canvas items when they want to + * set a color value for output. Given information about an X color, this + * function will generate Postscript commands to set up an appropriate + * color in Postscript. + * + * Results: + * Returns a standard Tcl return value. If an error occurs then an error + * message will be left in interp->result. If no error occurs, then + * additional Postscript will be appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathCanvasPsColor( + Tcl_Interp *interp, /* Interpreter for returning Postscript or + * error message. */ + Tk_PathCanvas canvas, /* Information about canvas. */ + XColor *colorPtr) /* Information about color. */ +{ + return Tk_PostscriptColor(interp, ((TkPathCanvas *) canvas)->psInfo, + colorPtr); +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasPsFont -- + * + * This function is called by individual canvas items when they want to + * output text. Given information about an X font, this function will + * generate Postscript commands to set up an appropriate font in + * Postscript. + * + * Results: + * Returns a standard Tcl return value. If an error occurs then an error + * message will be left in interp->result. If no error occurs, then + * additional Postscript will be appended to the interp->result. + * + * Side effects: + * The Postscript font name is entered into psInfoPtr->fontTable if it + * wasn't already there. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathCanvasPsFont( + Tcl_Interp *interp, /* Interpreter for returning Postscript or + * error message. */ + Tk_PathCanvas canvas, /* Information about canvas. */ + Tk_Font tkfont) /* Information about font in which text is to + * be printed. */ +{ + return Tk_PostscriptFont(interp, ((TkPathCanvas *) canvas)->psInfo, tkfont); +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasPsBitmap -- + * + * This function is called to output the contents of a sub-region of a + * bitmap in proper image data format for Postscript (i.e. data between + * angle brackets, one bit per pixel). + * + * Results: + * Returns a standard Tcl return value. If an error occurs then an error + * message will be left in interp->result. If no error occurs, then + * additional Postscript will be appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathCanvasPsBitmap( + Tcl_Interp *interp, /* Interpreter for returning Postscript or + * error message. */ + Tk_PathCanvas canvas, /* Information about canvas. */ + Pixmap bitmap, /* Bitmap for which to generate Postscript. */ + int startX, int startY, /* Coordinates of upper-left corner of + * rectangular region to output. */ + int width, int height) /* Size of rectangular region. */ +{ + return Tk_PostscriptBitmap(interp, ((TkPathCanvas *) canvas)->tkwin, + ((TkPathCanvas *) canvas)->psInfo, bitmap, startX, startY, + width, height); +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasPsStipple -- + * + * This function is called by individual canvas items when they have + * created a path that they'd like to be filled with a stipple pattern. + * Given information about an X bitmap, this function will generate + * Postscript commands to fill the current clip region using a stipple + * pattern defined by the bitmap. + * + * Results: + * Returns a standard Tcl return value. If an error occurs then an error + * message will be left in interp->result. If no error occurs, then + * additional Postscript will be appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_PathCanvasPsStipple( + Tcl_Interp *interp, /* Interpreter for returning Postscript or + * error message. */ + Tk_PathCanvas canvas, /* Information about canvas. */ + Pixmap bitmap) /* Bitmap to use for stippling. */ +{ + return Tk_PostscriptStipple(interp, ((TkPathCanvas *) canvas)->tkwin, + ((TkPathCanvas *) canvas)->psInfo, bitmap); +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasPsY -- + * + * Given a y-coordinate in canvas coordinates, this function returns a + * y-coordinate to use for Postscript output. + * + * Results: + * Returns the Postscript coordinate that corresponds to "y". + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +double +Tk_PathCanvasPsY( + Tk_PathCanvas canvas, /* Token for canvas on whose behalf Postscript + * is being generated. */ + double y) /* Y-coordinate in canvas coords. */ +{ + return Tk_PostscriptY(y, ((TkPathCanvas *) canvas)->psInfo); +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathCanvasPsPath -- + * + * Given an array of points for a path, generate Postscript commands to + * create the path. + * + * Results: + * Postscript commands get appended to what's in interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +Tk_PathCanvasPsPath( + Tcl_Interp *interp, /* Put generated Postscript in this + * interpreter's result field. */ + Tk_PathCanvas canvas, /* Canvas on whose behalf Postscript is being + * generated. */ + double *coordPtr, /* Pointer to first in array of 2*numPoints + * coordinates giving points for path. */ + int numPoints) /* Number of points at *coordPtr. */ +{ + Tk_PostscriptPath(interp, ((TkPathCanvas *) canvas)->psInfo, + coordPtr, numPoints); +} + +/* + * PathCanvasGradientChanged: find all matching items with this gradient and redisplay. + * If gradient deleted we must also update items style. + */ + +void +PathCanvasGradientChanged(TkPathCanvas *canvasPtr, Tcl_Obj *gradientObj, int flags) +{ + Tk_PathItem *itemPtr; + + for (itemPtr = canvasPtr->rootItemPtr; itemPtr != NULL; + itemPtr = TkPathCanvasItemIteratorNext(itemPtr)) { + + // EventuallyRedrawItem((Tk_PathCanvas)canvasPtr, itemPtr); + + } +} +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/pd/tkpath/generic/tkpCanvas.h b/pd/tkpath/generic/tkpCanvas.h new file mode 100644 index 0000000000000000000000000000000000000000..2402e1c5fa7bd835c1e4ffbd5563bb29b496101a --- /dev/null +++ b/pd/tkpath/generic/tkpCanvas.h @@ -0,0 +1,405 @@ +/* + * tkpCanvas.h -- + * + * Declarations shared among all the files that implement canvas widgets. + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1995 Sun Microsystems, Inc. + * Copyright (c) 1998 by Scriptics Corporation. + * Copyright (c) 2008 Mats Bengtsson + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpCanvas.h,v 1.10 2008/07/23 07:08:39 matben Exp $ + */ + +#ifndef _TKPCANVAS +#define _TKPCANVAS + +#ifndef _TK +#include "tk.h" +#endif +#include "tkp.h" +#include "tkPath.h" + +#ifndef USE_OLD_TAG_SEARCH +typedef struct TagSearchExpr_s TagSearchExpr; + +struct TagSearchExpr_s { + TagSearchExpr *next; /* For linked lists of expressions - used in + * bindings. */ + Tk_Uid uid; /* The uid of the whole expression. */ + Tk_Uid *uids; /* Expresion compiled to an array of uids. */ + int allocated; /* Available space for array of uids. */ + int length; /* Length of expression. */ + int index; /* Current position in expression + * evaluation. */ + int match; /* This expression matches event's item's + * tags. */ +}; +#endif /* not USE_OLD_TAG_SEARCH */ + +/* + * The record below describes a canvas widget. It is made available to the + * item functions so they can access certain shared fields such as the overall + * displacement and scale factor for the canvas. + */ + +typedef struct TkPathCanvas { + Tk_Window tkwin; /* Window that embodies the canvas. NULL means + * that the window has been destroyed but the + * data structures haven't yet been cleaned + * up.*/ + Display *display; /* Display containing widget; needed, among + * other things, to release resources after + * tkwin has already gone away. */ + Tcl_Interp *interp; /* Interpreter associated with canvas. */ + Tcl_Command widgetCmd; /* Token for canvas's widget command. */ + Tk_OptionTable optionTable; /* Table that defines configuration options + * available for this widget. */ + Tk_PathItem *rootItemPtr; /* The root item with id 0, always there. */ + + /* + * Information used when displaying widget: + */ + + Tcl_Obj *borderWidthPtr; /* Value of -borderWidth option: specifies + * width of border in pixels. */ + int borderWidth; /* Width of 3-D border around window. * + * Integer value corresponding to + * borderWidthPtr. Always >= 0. */ + Tk_3DBorder bgBorder; /* Used for canvas background. */ + int relief; /* Indicates whether window as a whole is + * raised, sunken, or flat. */ + Tcl_Obj *highlightWidthPtr; /* Value of -highlightthickness option: + * specifies width in pixels of highlight to + * draw around widget when it has the focus. + * <= 0 means don't draw a highlight. */ + int highlightWidth; /* Integer value corresponding to + * highlightWidthPtr. Always >= 0. */ + XColor *highlightBgColorPtr; + /* Color for drawing traversal highlight area + * when highlight is off. */ + XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ + int inset; /* Total width of all borders, including + * traversal highlight and 3-D border. + * Indicates how much interior stuff must be + * offset from outside edges to leave room for + * borders. */ + GC pixmapGC; /* Used to copy bits from a pixmap to the + * screen and also to clear the pixmap. */ + int width, height; /* Dimensions to request for canvas window, + * specified in pixels. */ + int redrawX1, redrawY1; /* Upper left corner of area to redraw, in + * pixel coordinates. Border pixels are + * included. Only valid if REDRAW_PENDING flag + * is set. */ + int redrawX2, redrawY2; /* Lower right corner of area to redraw, in + * integer canvas coordinates. Border pixels + * will *not* be redrawn. */ + int confine; /* Non-zero means constrain view to keep as + * much of canvas visible as possible. */ + + /* + * Information used to manage the selection and insertion cursor: + */ + + Tk_PathCanvasTextInfo textInfo; /* Contains lots of fields; see tk.h for + * details. This structure is shared with the + * code that implements individual items. */ + 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. */ + Tcl_TimerToken insertBlinkHandler; + /* Timer handler used to blink cursor on and + * off. */ + + /* + * Transformation applied to canvas as a whole: to compute screen + * coordinates (X,Y) from canvas coordinates (x,y), do the following: + * + * X = x - xOrigin; + * Y = y - yOrigin; + */ + + int xOrigin, yOrigin; /* Canvas coordinates corresponding to + * upper-left corner of window, given in + * canvas pixel units. */ + int drawableXOrigin, drawableYOrigin; + /* During redisplay, these fields give the + * canvas coordinates corresponding to the + * upper-left corner of the drawable where + * items are actually being drawn (typically a + * pixmap smaller than the whole window). */ + + /* + * Information used for event bindings associated with items. + */ + + Tk_BindingTable bindingTable; + /* Table of all bindings currently defined for + * this canvas. NULL means that no bindings + * exist, so the table hasn't been created. + * Each "object" used for this table is either + * a Tk_Uid for a tag or the address of an + * item named by id. */ + Tk_PathItem *currentItemPtr; /* The item currently containing the mouse + * pointer, or NULL if none. */ + Tk_PathItem *newCurrentPtr; /* The item that is about to become the + * current one, or NULL. This field is used to + * detect deletions of the new current item + * pointer that occur during Leave processing + * of the previous current item. */ + double closeEnough; /* The mouse is assumed to be inside an item + * if it is this close to it. */ + XEvent pickEvent; /* The event upon which the current choice of + * currentItem is based. Must be saved so that + * if the currentItem is deleted, can pick + * another. */ + int state; /* Last known modifier state. Used to defer + * picking a new current object while buttons + * are down. */ + + /* + * Information used for managing scrollbars: + */ + + char *xScrollCmd; /* Command prefix for communicating with + * horizontal scrollbar. NULL means no + * horizontal scrollbar. Malloc'ed. */ + char *yScrollCmd; /* Command prefix for communicating with + * vertical scrollbar. NULL means no vertical + * scrollbar. Malloc'ed. */ + int scrollX1, scrollY1, scrollX2, scrollY2; + /* These four coordinates define the region + * that is the 100% area for scrolling (i.e. + * these numbers determine the size and + * location of the sliders on scrollbars). + * Units are pixels in canvas coords. */ + char *regionString; /* The option string from which scrollX1 etc. + * are derived. Malloc'ed. */ + int xScrollIncrement; /* If >0, defines a grid for horizontal + * scrolling. This is the size of the "unit", + * and the left edge of the screen will always + * lie on an even unit boundary. */ + int yScrollIncrement; /* If >0, defines a grid for horizontal + * scrolling. This is the size of the "unit", + * and the left edge of the screen will always + * lie on an even unit boundary. */ + + /* + * Information used for scanning: + */ + + int scanX; /* X-position at which scan started (e.g. + * button was pressed here). */ + int scanXOrigin; /* Value of xOrigin field when scan started. */ + int scanY; /* Y-position at which scan started (e.g. + * button was pressed here). */ + int scanYOrigin; /* Value of yOrigin field when scan started. */ + + /* + * Information used to speed up searches by remembering the last item + * created or found with an item id search. + */ + + Tk_PathItem *hotPtr; /* Pointer to "hot" item (one that's been + * recently used. NULL means there's no hot + * item. */ + Tk_PathItem *hotPrevPtr; /* Pointer to predecessor to hotPtr (NULL + * means item is first in list). This is only + * a hint and may not really be hotPtr's + * predecessor. */ + + /* + * Miscellaneous information: + */ + + Tk_Cursor cursor; /* Current cursor for window, or None. */ + char *takeFocus; /* Value of -takefocus option; not used in the + * C code, but used by keyboard traversal + * scripts. Malloc'ed, but may be NULL. */ + double pixelsPerMM; /* Scale factor between MM and pixels; used + * when converting coordinates. */ + int flags; /* Various flags; see below for + * definitions. */ + int nextId; /* Number to use as id for next item created + * in widget. */ + Tk_PostscriptInfo psInfo; /* Pointer to information used for generating + * Postscript for the canvas. NULL means no + * Postscript is currently being generated. */ + Tcl_HashTable idTable; /* Table of integer indices. */ +// @@@ TODO: as pointers instead??? + Tcl_HashTable styleTable; /* Table for styles. + * This defines the namespace for style names. */ + Tcl_HashTable gradientTable;/* Table for gradients. + * This defines the namespace for gradient names. */ + int styleUid; /* Running integer used to number style tokens. */ + int gradientUid; /* Running integer used to number gradient tokens. */ + int tagStyle; + + /* + * Additional information, added by the 'dash'-patch + */ + + void *reserved1; + Tk_PathState canvas_state; /* State of canvas. */ + void *reserved2; + void *reserved3; + Tk_TSOffset *tsoffsetPtr; +#ifndef USE_OLD_TAG_SEARCH + TagSearchExpr *bindTagExprs;/* Linked list of tag expressions used in + * bindings. */ +#endif +} TkPathCanvas; + +/* + * Flag bits for canvases: + * + * REDRAW_PENDING - 1 means a DoWhenIdle handler has already been + * created to redraw some or all of the canvas. + * REDRAW_BORDERS - 1 means that the borders need to be redrawn + * during the next redisplay operation. + * REPICK_NEEDED - 1 means DisplayCanvas should pick a new + * current item before redrawing the canvas. + * GOT_FOCUS - 1 means the focus is currently in this widget, + * so should draw the insertion cursor and + * traversal highlight. + * CURSOR_ON - 1 means the insertion cursor is in the "on" + * phase of its blink cycle. 0 means either we + * don't have the focus or the cursor is in the + * "off" phase of its cycle. + * UPDATE_SCROLLBARS - 1 means the scrollbars should get updated as + * part of the next display operation. + * LEFT_GRABBED_ITEM - 1 means that the mouse left the current item + * while a grab was in effect, so we didn't + * change canvasPtr->currentItemPtr. + * REPICK_IN_PROGRESS - 1 means PickCurrentItem is currently + * executing. If it should be called recursively, + * it should simply return immediately. + * BBOX_NOT_EMPTY - 1 means that the bounding box of the area that + * should be redrawn is not empty. + * CANVAS_DELETED - + */ + +#define REDRAW_PENDING (1 << 0) +#define REDRAW_BORDERS (1 << 1) +#define REPICK_NEEDED (1 << 2) +#define GOT_FOCUS (1 << 3) +#define CURSOR_ON (1 << 4) +#define UPDATE_SCROLLBARS (1 << 5) +#define LEFT_GRABBED_ITEM (1 << 6) +#define REPICK_IN_PROGRESS (1 << 7) +#define BBOX_NOT_EMPTY (1 << 8) +#define CANVAS_DELETED (1 << 9) + +/* + * Flag bits for canvas items (redraw_flags): + * + * FORCE_REDRAW - 1 means that the new coordinates of some item + * are not yet registered using + * Tk_PathCanvasEventuallyRedraw(). It should still + * be done by the general canvas code. + */ + +#define FORCE_REDRAW 8 + +/* + * This is an extended item record that is used for the new + * path based items to allow more generic code to be used for them + * since all of them (?) anyhow include a Tk_PathStyle record. + */ + +typedef struct Tk_PathItemEx { + Tk_PathItem header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + Tk_PathCanvas canvas; /* Canvas containing item. */ + Tk_PathStyle style; /* Contains most drawing info. */ + Tcl_Obj *styleObj; /* Object with style name. */ + TkPathStyleInst *styleInst; + /* The referenced style instance from styleObj. */ + + /* + *------------------------------------------------------------------ + * Starting here is additional type-specific stuff; see the declarations + * for individual types to see what is part of each type. The actual space + * below is determined by the "itemInfoSize" of the type's Tk_PathItemType + * record. + *------------------------------------------------------------------ + */ +} Tk_PathItemEx; + +/* + * Canvas-related functions that are shared among Tk modules but not exported + * to the outside world: + */ + +MODULE_SCOPE int TkCanvPostscriptCmd(TkPathCanvas *canvasPtr, + Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); +MODULE_SCOPE int TkPathCanvTranslatePath(TkPathCanvas *canvPtr, + int numVertex, double *coordPtr, int closed, + XPoint *outPtr); +MODULE_SCOPE Tk_PathTags * TkPathAllocTagsFromObj(Tcl_Interp *interp, Tcl_Obj *valuePtr); +MODULE_SCOPE int TkPathCanvasFindGroup(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tcl_Obj *parentObj, Tk_PathItem **parentPtrPtr); +MODULE_SCOPE void TkPathCanvasSetParent(Tk_PathItem *parentPtr, Tk_PathItem *itemPtr); +MODULE_SCOPE int TkPathCanvasGetDepth(Tk_PathItem *itemPtr); +MODULE_SCOPE Tk_PathStyle TkPathCanvasInheritStyle(Tk_PathItem *itemPtr, long flags); +MODULE_SCOPE TMatrix TkPathCanvasInheritTMatrix(Tk_PathItem *itemPtr); +MODULE_SCOPE void TkPathCanvasFreeInheritedStyle(Tk_PathStyle *stylePtr); +MODULE_SCOPE Tcl_HashTable *TkPathCanvasGradientTable(Tk_PathCanvas canvas); +MODULE_SCOPE Tcl_HashTable *TkPathCanvasStyleTable(Tk_PathCanvas canvas); +MODULE_SCOPE Tk_PathState TkPathCanvasState(Tk_PathCanvas canvas); +MODULE_SCOPE Tk_PathItem * TkPathCanvasCurrentItem(Tk_PathCanvas canvas); +MODULE_SCOPE void TkPathCanvasGroupBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + int *x1Ptr, int *y1Ptr, int *x2Ptr, int *y2Ptr); +MODULE_SCOPE void TkPathCanvasUpdateGroupBbox(Tk_PathCanvas canvas, Tk_PathItem *itemPtr); +MODULE_SCOPE void TkPathCanvasSetGroupDirtyBbox(Tk_PathItem *itemPtr); +MODULE_SCOPE Tk_PathItem * TkPathCanvasItemIteratorNext(Tk_PathItem *itemPtr); +MODULE_SCOPE Tk_PathItem * TkPathCanvasItemIteratorPrev(Tk_PathItem *itemPtr); +MODULE_SCOPE int TkPathCanvasItemExConfigure(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItemEx *itemExPtr, int mask); +MODULE_SCOPE void TkPathCanvasItemDetach(Tk_PathItem *itemPtr); + +MODULE_SCOPE void GroupItemConfigured(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int mask); +MODULE_SCOPE void CanvasTranslateGroup(Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, double deltaX, double deltaY); +MODULE_SCOPE void CanvasScaleGroup(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + double originX, double originY, double scaleX, double scaleY); +MODULE_SCOPE int CanvasGradientObjCmd(Tcl_Interp* interp, TkPathCanvas *canvasPtr, + int objc, Tcl_Obj* CONST objv[]); +MODULE_SCOPE int CanvasStyleObjCmd(Tcl_Interp* interp, TkPathCanvas *canvasPtr, + int objc, Tcl_Obj* CONST objv[]); + +MODULE_SCOPE void CanvasSetParentToRoot(Tk_PathItem *itemPtr); +MODULE_SCOPE void PathGradientChangedProc(ClientData clientData, int flags); +MODULE_SCOPE void PathStyleChangedProc(ClientData clientData, int flags); + +MODULE_SCOPE void CanvasGradientsFree(TkPathCanvas *canvasPtr); + +/* + * Standard item types provided by Tk: + */ + +MODULE_SCOPE Tk_PathItemType tkArcType, tkBitmapType, tkImageType, tkLineType; +MODULE_SCOPE Tk_PathItemType tkOvalType, tkPolygonType; +MODULE_SCOPE Tk_PathItemType tkRectangleType, tkTextType, tkWindowType; + +/* + * tkpath specific item types. + */ + +MODULE_SCOPE Tk_PathItemType tkPathType; +MODULE_SCOPE Tk_PathItemType tkPrectType; +MODULE_SCOPE Tk_PathItemType tkPlineType; +MODULE_SCOPE Tk_PathItemType tkPolylineType; +MODULE_SCOPE Tk_PathItemType tkPpolygonType; +MODULE_SCOPE Tk_PathItemType tkCircleType; +MODULE_SCOPE Tk_PathItemType tkEllipseType; +MODULE_SCOPE Tk_PathItemType tkPimageType; +MODULE_SCOPE Tk_PathItemType tkPtextType; +MODULE_SCOPE Tk_PathItemType tkGroupType; + +#endif /* _TKPCANVAS */ diff --git a/pd/tkpath/generic/tkpRectOval.c b/pd/tkpath/generic/tkpRectOval.c new file mode 100644 index 0000000000000000000000000000000000000000..f53923cc7dd556ef5f8abed88bd210ef37ce2217 --- /dev/null +++ b/pd/tkpath/generic/tkpRectOval.c @@ -0,0 +1,1456 @@ +/* + * tkpRectOval.c -- + * + * This file implements rectangle and oval items for canvas widgets. + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpRectOval.c,v 1.6 2008/07/22 09:41:35 matben Exp $ + */ + +#include <stdio.h> +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" + +/* + * The structure below defines the record for each rectangle/oval item. + */ + +typedef struct RectOvalItem { + Tk_PathItem header; /* Generic stuff that's the same for all + * types. MUST BE FIRST IN STRUCTURE. */ + Tk_PathOutline outline; /* Outline structure */ + double bbox[4]; /* Coordinates of bounding box for rectangle + * or oval (x1, y1, x2, y2). Item includes x1 + * and x2 but not y1 and y2. */ + Tk_TSOffset *tsoffsetPtr; + XColor *fillColor; /* Color for filling rectangle/oval. */ + XColor *activeFillColor; /* Color for filling rectangle/oval if state + * is active. */ + XColor *disabledFillColor; /* Color for filling rectangle/oval if state + * is disabled. */ + Pixmap fillStipple; /* Stipple bitmap for filling item. */ + Pixmap activeFillStipple; /* Stipple bitmap for filling item if state is + * active. */ + Pixmap disabledFillStipple; /* Stipple bitmap for filling item if state is + * disabled. */ + GC fillGC; /* Graphics context for filling item. */ +} RectOvalItem; + +/* + * Prototypes for functions defined in this file: + */ + +static void ComputeRectOvalBbox(Tk_PathCanvas canvas, + RectOvalItem *rectOvalPtr); +static int ConfigureRectOval(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, Tcl_Obj *CONST objv[], + int flags); +static int CreateRectOval(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, Tcl_Obj *CONST objv[]); +static void DeleteRectOval(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + Display *display); +static void DisplayRectOval(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + Display *display, Drawable dst, int x, int y, + int width, int height); +static int OvalToArea(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + double *areaPtr); +static double OvalToPoint(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + double *pointPtr); +static int RectOvalCoords(Tcl_Interp *interp, Tk_PathCanvas canvas, + Tk_PathItem *itemPtr, int objc, Tcl_Obj *CONST objv[]); +static int RectOvalToPostscript(Tcl_Interp *interp, + Tk_PathCanvas canvas, Tk_PathItem *itemPtr, int prepass); +static int RectToArea(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + double *areaPtr); +static double RectToPoint(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + double *pointPtr); +static void ScaleRectOval(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + double originX, double originY, + double scaleX, double scaleY); +static void TranslateRectOval(Tk_PathCanvas canvas, Tk_PathItem *itemPtr, + double deltaX, double deltaY); + +/* + * Information used for parsing option specs: + */ + +#define PATH_DEF_STATE "normal" + +static char *stateStrings[] = { + "active", "disabled", "normal", "hidden", NULL +}; + +static Tk_ObjCustomOption dashCO = { + "dash", + Tk_DashOptionSetProc, + Tk_DashOptionGetProc, + Tk_DashOptionRestoreProc, + Tk_DashOptionFreeProc, + (ClientData) NULL +}; + +static Tk_ObjCustomOption offsetCO = { + "offset", + TkPathOffsetOptionSetProc, + TkPathOffsetOptionGetProc, + TkPathOffsetOptionRestoreProc, + TkPathOffsetOptionFreeProc, + (ClientData) (TK_OFFSET_RELATIVE|TK_OFFSET_INDEX) +}; + +static Tk_ObjCustomOption pixelCO = { + "pixel", + Tk_PathPixelOptionSetProc, + Tk_PathPixelOptionGetProc, + Tk_PathPixelOptionRestoreProc, + NULL, + (ClientData) NULL +}; + +static Tk_ObjCustomOption tagsCO = { + "tags", + Tk_PathCanvasTagsOptionSetProc, + Tk_PathCanvasTagsOptionGetProc, + Tk_PathCanvasTagsOptionRestoreProc, + Tk_PathCanvasTagsOptionFreeProc, + (ClientData) NULL +}; + +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_CUSTOM, "-activedash", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, outline.activeDashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_COLOR, "-activefill", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, activeFillColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-activeoutline", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, outline.activeColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-activeoutlinestipple", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, outline.activeStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-activestipple", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, activeFillStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-activewidth", NULL, NULL, + "0.0", -1, Tk_Offset(RectOvalItem, outline.activeWidth), + 0, &pixelCO, 0}, + {TK_OPTION_CUSTOM, "-dash", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, outline.dashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_PIXELS, "-dashoffset", NULL, NULL, + "0", -1, Tk_Offset(RectOvalItem, outline.offset), + 0, 0, 0}, + {TK_OPTION_CUSTOM, "-disableddash", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, outline.disabledDashPtr), + TK_OPTION_NULL_OK, &dashCO, 0}, + {TK_OPTION_COLOR, "-disabledfill", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, disabledFillColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-disabledoutline", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, outline.disabledColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-disabledoutlinestipple", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, outline.disabledStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BITMAP, "-disabledstipple", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, disabledFillStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-disabledwidth", NULL, NULL, + "0.0", -1, Tk_Offset(RectOvalItem, outline.disabledWidth), + 0, &pixelCO, 0}, + {TK_OPTION_COLOR, "-fill", NULL, NULL, + "", -1, Tk_Offset(RectOvalItem, fillColor), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-offset", NULL, NULL, + "0,0", -1, Tk_Offset(RectOvalItem, tsoffsetPtr), + 0, &offsetCO, 0}, + {TK_OPTION_COLOR, "-outline", NULL, NULL, + "black", -1, Tk_Offset(RectOvalItem, outline.color), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-outlineoffset", NULL, NULL, + "0,0", -1, Tk_Offset(RectOvalItem, outline.tsoffsetPtr), + 0, &offsetCO, 0}, + {TK_OPTION_BITMAP, "-outlinestipple", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, outline.stipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING_TABLE, "-state", NULL, NULL, + PATH_DEF_STATE, -1, Tk_Offset(Tk_PathItem, state), + 0, (ClientData) stateStrings, 0}, + {TK_OPTION_BITMAP, "-stipple", NULL, NULL, + NULL, -1, Tk_Offset(RectOvalItem, fillStipple), + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_CUSTOM, "-tags", NULL, NULL, + NULL, -1, Tk_Offset(Tk_PathItem, pathTagsPtr), + TK_OPTION_NULL_OK, (ClientData) &tagsCO, 0}, + {TK_OPTION_CUSTOM, "-width", NULL, NULL, + "1.0", -1, Tk_Offset(RectOvalItem, outline.width), 0, &pixelCO, 0}, + {TK_OPTION_END, NULL, NULL, NULL, + NULL, 0, -1, 0, (ClientData) NULL, 0} +}; + +/* @@@ Not sure we need two option tables here */ +static Tk_OptionTable optionTableRect = NULL; +static Tk_OptionTable optionTableOval = NULL; + +/* + * The structures below defines the rectangle and oval item types by means of + * functions that can be invoked by generic item code. + */ + +Tk_PathItemType tkRectangleType = { + "rectangle", /* name */ + sizeof(RectOvalItem), /* itemSize */ + CreateRectOval, /* createProc */ + optionSpecs, /* optionSpecs */ + ConfigureRectOval, /* configureProc */ + RectOvalCoords, /* coordProc */ + DeleteRectOval, /* deleteProc */ + DisplayRectOval, /* displayProc */ + 0, /* flags */ + NULL, /* bboxProc */ + RectToPoint, /* pointProc */ + RectToArea, /* areaProc */ + RectOvalToPostscript, /* postscriptProc */ + ScaleRectOval, /* scaleProc */ + TranslateRectOval, /* translateProc */ + NULL, /* indexProc */ + NULL, /* icursorProc */ + NULL, /* selectionProc */ + NULL, /* insertProc */ + NULL, /* dTextProc */ + NULL, /* nextPtr */ +}; + +Tk_PathItemType tkOvalType = { + "oval", /* name */ + sizeof(RectOvalItem), /* itemSize */ + CreateRectOval, /* createProc */ + optionSpecs, /* configSpecs */ + ConfigureRectOval, /* configureProc */ + RectOvalCoords, /* coordProc */ + DeleteRectOval, /* deleteProc */ + DisplayRectOval, /* displayProc */ + 0, /* flags */ + NULL, /* bboxProc */ + OvalToPoint, /* pointProc */ + OvalToArea, /* areaProc */ + RectOvalToPostscript, /* postscriptProc */ + ScaleRectOval, /* scaleProc */ + TranslateRectOval, /* translateProc */ + NULL, /* indexProc */ + NULL, /* cursorProc */ + NULL, /* selectionProc */ + NULL, /* insertProc */ + NULL, /* dTextProc */ + NULL, /* nextPtr */ +}; + +/* + *-------------------------------------------------------------- + * + * CreateRectOval -- + * + * This function is invoked to create a new rectangle or oval 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 the interp's result; in this + * case itemPtr is left uninitialized, so it can be safely freed by the + * caller. + * + * Side effects: + * A new rectangle or oval item is created. + * + *-------------------------------------------------------------- + */ + +static int +CreateRectOval( + Tcl_Interp *interp, /* For error reporting. */ + Tk_PathCanvas canvas, /* Canvas to hold new item. */ + Tk_PathItem *itemPtr, /* Record to hold new item; header has been + * initialized by caller. */ + int objc, /* Number of arguments in objv. */ + Tcl_Obj *CONST objv[]) /* Arguments describing rectangle. */ +{ + RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; + Tk_OptionTable optionTable; + int i; + + if (objc == 0) { + Tcl_Panic("canvas did not pass any coords\n"); + } + + /* + * Carry out initialization that is needed in order to clean up after + * errors during the the remainder of this function. + */ + + Tk_PathCreateOutline(&(rectOvalPtr->outline)); + rectOvalPtr->tsoffsetPtr = NULL; + rectOvalPtr->fillColor = NULL; + rectOvalPtr->activeFillColor = NULL; + rectOvalPtr->disabledFillColor = NULL; + rectOvalPtr->fillStipple = None; + rectOvalPtr->activeFillStipple = None; + rectOvalPtr->disabledFillStipple = None; + rectOvalPtr->fillGC = None; + + /* @@@ Not sure we need two option tables here */ + if (rectOvalPtr->header.typePtr == &tkRectangleType) { + if (optionTableRect == NULL) { + optionTableRect = Tk_CreateOptionTable(interp, optionSpecs); + } + optionTable = optionTableRect; + } else { + if (optionTableOval == NULL) { + optionTableOval = Tk_CreateOptionTable(interp, optionSpecs); + } + optionTable = optionTableOval; + } + itemPtr->optionTable = optionTable; + if (Tk_InitOptions(interp, (char *) rectOvalPtr, optionTable, + Tk_PathCanvasTkwin(canvas)) != TCL_OK) { + goto error; + } + + /* + * Process the arguments to fill in the item record. + */ + + for (i = 1; i < objc; i++) { + char *arg = Tcl_GetString(objv[i]); + + if ((arg[0] == '-') && (arg[1] >= 'a') && (arg[1] <= 'z')) { + break; + } + } + if ((RectOvalCoords(interp, canvas, itemPtr, i, objv) != TCL_OK)) { + goto error; + } + if (ConfigureRectOval(interp, canvas, itemPtr, objc-i, objv+i, 0) + == TCL_OK) { + return TCL_OK; + } + + error: + DeleteRectOval(canvas, itemPtr, Tk_Display(Tk_PathCanvasTkwin(canvas))); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * RectOvalCoords -- + * + * This function is invoked to process the "coords" widget command on + * rectangles and ovals. See the user documentation for details on what + * it does. + * + * Results: + * Returns TCL_OK or TCL_ERROR, and sets the interp's result. + * + * Side effects: + * The coordinates for the given item may be changed. + * + *-------------------------------------------------------------- + */ + +static int +RectOvalCoords( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item whose coordinates are to be read or + * modified. */ + int objc, /* Number of coordinates supplied in objv. */ + Tcl_Obj *CONST objv[]) /* Array of coordinates: x1,y1,x2,y2,... */ +{ + RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; + + /* + * If no coordinates, return the current coordinates (i.e. bounding box). + */ + + if (objc == 0) { + Tcl_Obj *obj = Tcl_NewObj(); + + Tcl_ListObjAppendElement(NULL, obj, + Tcl_NewDoubleObj(rectOvalPtr->bbox[0])); + Tcl_ListObjAppendElement(NULL, obj, + Tcl_NewDoubleObj(rectOvalPtr->bbox[1])); + Tcl_ListObjAppendElement(NULL, obj, + Tcl_NewDoubleObj(rectOvalPtr->bbox[2])); + Tcl_ListObjAppendElement(NULL, obj, + Tcl_NewDoubleObj(rectOvalPtr->bbox[3])); + Tcl_SetObjResult(interp, obj); + return TCL_OK; + } + + /* + * If one "coordinate", treat as list of coordinates. + */ + + if (objc == 1) { + if (Tcl_ListObjGetElements(interp, objv[0], &objc, + (Tcl_Obj ***) &objv) != TCL_OK) { + return TCL_ERROR; + } + } + + /* + * Better have four coordinates now. Spit out an error message otherwise. + */ + + if (objc != 4) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 0 or 4, got %d", objc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + + /* + * Parse the coordinates and update our bounding box. + */ + + if ((Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[0], + &rectOvalPtr->bbox[0]) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[1], + &rectOvalPtr->bbox[1]) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[2], + &rectOvalPtr->bbox[2]) != TCL_OK) + || (Tk_PathCanvasGetCoordFromObj(interp, canvas, objv[3], + &rectOvalPtr->bbox[3]) != TCL_OK)) { + return TCL_ERROR; + } + ComputeRectOvalBbox(canvas, rectOvalPtr); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ConfigureRectOval -- + * + * This function is invoked to configure various aspects of a rectangle + * or oval item, such as its border and background colors. + * + * Results: + * A standard Tcl result code. If an error occurs, then an error message + * is left in the interp's result. + * + * Side effects: + * Configuration information, such as colors and stipple patterns, may be + * set for itemPtr. + * + *-------------------------------------------------------------- + */ + +static int +ConfigureRectOval( + Tcl_Interp *interp, /* Used for error reporting. */ + Tk_PathCanvas canvas, /* Canvas containing itemPtr. */ + Tk_PathItem *itemPtr, /* Rectangle item to reconfigure. */ + int objc, /* Number of elements in objv. */ + Tcl_Obj *CONST objv[], /* Arguments describing things to configure. */ + int flags) /* Flags to pass to Tk_ConfigureWidget. */ +{ + RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; + XGCValues gcValues; + GC newGC; + unsigned long mask; + Tk_Window tkwin; + Tk_TSOffset *tsoffset; + XColor *color; + Pixmap stipple; + Tk_PathState state; + Tk_OptionTable optionTable; + + if (rectOvalPtr->header.typePtr == &tkRectangleType) { + optionTable = optionTableRect; + } else { + optionTable = optionTableOval; + } + + tkwin = Tk_PathCanvasTkwin(canvas); + if (TCL_OK != Tk_SetOptions(interp, (char *) rectOvalPtr, optionTable, + objc, objv, tkwin, NULL, NULL)) { + return TCL_ERROR; + } + state = itemPtr->state; + + /* + * A few of the options require additional processing, such as graphics + * contexts. + */ + + if (rectOvalPtr->outline.activeWidth > rectOvalPtr->outline.width || + (rectOvalPtr->outline.activeDashPtr != NULL && + rectOvalPtr->outline.activeDashPtr->number != 0) || + rectOvalPtr->outline.activeColor != NULL || + rectOvalPtr->outline.activeStipple != None || + rectOvalPtr->activeFillColor != NULL || + rectOvalPtr->activeFillStipple != None) { + itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; + } else { + itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; + } + + tsoffset = rectOvalPtr->outline.tsoffsetPtr; + if (tsoffset != NULL) { + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) + ((rectOvalPtr->bbox[0]+rectOvalPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) + ((rectOvalPtr->bbox[1]+rectOvalPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[2] + 0.5); + } + } + + /* + * Configure the outline graphics context. If mask is non-zero, the gc has + * changed and must be reallocated, provided that the new settings specify + * a valid outline (non-zero width and non-NULL color) + */ + + mask = Tk_PathConfigOutlineGC(&gcValues, canvas, itemPtr, + &(rectOvalPtr->outline)); + if (mask && \ + rectOvalPtr->outline.width != 0 && \ + rectOvalPtr->outline.color != NULL) { + gcValues.cap_style = CapProjecting; + mask |= GCCapStyle; + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } else { + newGC = None; + } + if (rectOvalPtr->outline.gc != None) { + Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->outline.gc); + } + rectOvalPtr->outline.gc = newGC; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + if (state == TK_PATHSTATE_HIDDEN) { + ComputeRectOvalBbox(canvas, rectOvalPtr); + return TCL_OK; + } + + color = rectOvalPtr->fillColor; + stipple = rectOvalPtr->fillStipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectOvalPtr->activeFillColor!=NULL) { + color = rectOvalPtr->activeFillColor; + } + if (rectOvalPtr->activeFillStipple!=None) { + stipple = rectOvalPtr->activeFillStipple; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (rectOvalPtr->disabledFillColor!=NULL) { + color = rectOvalPtr->disabledFillColor; + } + if (rectOvalPtr->disabledFillStipple!=None) { + stipple = rectOvalPtr->disabledFillStipple; + } + } + + if (color == NULL) { + newGC = None; + } else { + gcValues.foreground = color->pixel; + if (stipple != None) { + gcValues.stipple = stipple; + gcValues.fill_style = FillStippled; + mask = GCForeground|GCStipple|GCFillStyle; + } else { + mask = GCForeground; + } +#ifdef MAC_OSX_TK + /* + * Mac OS X CG drawing needs access to the outline linewidth + * even for fills (as linewidth controls antialiasing). + */ + gcValues.line_width = rectOvalPtr->outline.gc != None ? + rectOvalPtr->outline.gc->line_width : 0; + mask |= GCLineWidth; +#endif + newGC = Tk_GetGC(tkwin, mask, &gcValues); + } + if (rectOvalPtr->fillGC != None) { + Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->fillGC); + } + rectOvalPtr->fillGC = newGC; + + tsoffset = rectOvalPtr->tsoffsetPtr; + if (tsoffset != NULL) { + flags = tsoffset->flags; + if (flags & TK_OFFSET_LEFT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[0] + 0.5); + } else if (flags & TK_OFFSET_CENTER) { + tsoffset->xoffset = (int) + ((rectOvalPtr->bbox[0]+rectOvalPtr->bbox[2]+1)/2); + } else if (flags & TK_OFFSET_RIGHT) { + tsoffset->xoffset = (int) (rectOvalPtr->bbox[2] + 0.5); + } + if (flags & TK_OFFSET_TOP) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[1] + 0.5); + } else if (flags & TK_OFFSET_MIDDLE) { + tsoffset->yoffset = (int) + ((rectOvalPtr->bbox[1]+rectOvalPtr->bbox[3]+1)/2); + } else if (flags & TK_OFFSET_BOTTOM) { + tsoffset->yoffset = (int) (rectOvalPtr->bbox[3] + 0.5); + } + } + + ComputeRectOvalBbox(canvas, rectOvalPtr); + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * DeleteRectOval -- + * + * This function is called to clean up the data structure associated with + * a rectangle or oval item. + * + * Results: + * None. + * + * Side effects: + * Resources associated with itemPtr are released. + * + *-------------------------------------------------------------- + */ + +static void +DeleteRectOval( + Tk_PathCanvas canvas, /* Info about overall widget. */ + Tk_PathItem *itemPtr, /* Item that is being deleted. */ + Display *display) /* Display containing window for canvas. */ +{ + RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; + Tk_OptionTable optionTable; + + if (rectOvalPtr->header.typePtr == &tkRectangleType) { + optionTable = optionTableRect; + } else { + optionTable = optionTableOval; + } + if (rectOvalPtr->fillGC != None) { + Tk_FreeGC(display, rectOvalPtr->fillGC); + } + Tk_FreeConfigOptions((char *) rectOvalPtr, optionTable, Tk_PathCanvasTkwin(canvas)); +} + +/* + *-------------------------------------------------------------- + * + * ComputeRectOvalBbox -- + * + * This function is invoked to compute the bounding box of all the pixels + * that may be drawn as part of a rectangle or oval. + * + * Results: + * None. + * + * Side effects: + * The fields x1, y1, x2, and y2 are updated in the header for itemPtr. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static void +ComputeRectOvalBbox( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + RectOvalItem *rectOvalPtr) /* Item whose bbox is to be recomputed. */ +{ + int bloat, tmp; + double dtmp, width; + Tk_PathState state = rectOvalPtr->header.state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = rectOvalPtr->outline.width; + if (state == TK_PATHSTATE_HIDDEN) { + rectOvalPtr->header.x1 = rectOvalPtr->header.y1 = + rectOvalPtr->header.x2 = rectOvalPtr->header.y2 = -1; + return; + } + if (((TkPathCanvas *)canvas)->currentItemPtr == (Tk_PathItem *)rectOvalPtr) { + if (rectOvalPtr->outline.activeWidth>width) { + width = rectOvalPtr->outline.activeWidth; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (rectOvalPtr->outline.disabledWidth>0) { + width = rectOvalPtr->outline.disabledWidth; + } + } + + /* + * Make sure that the first coordinates are the lowest ones. + */ + + if (rectOvalPtr->bbox[1] > rectOvalPtr->bbox[3]) { + double tmpY = rectOvalPtr->bbox[3]; + + rectOvalPtr->bbox[3] = rectOvalPtr->bbox[1]; + rectOvalPtr->bbox[1] = tmpY; + } + if (rectOvalPtr->bbox[0] > rectOvalPtr->bbox[2]) { + double tmpX = rectOvalPtr->bbox[2]; + + rectOvalPtr->bbox[2] = rectOvalPtr->bbox[0]; + rectOvalPtr->bbox[0] = tmpX; + } + + if (rectOvalPtr->outline.gc == None) { + /* + * The Win32 switch was added for 8.3 to solve a problem with ovals + * leaving traces on bottom and right of 1 pixel. This may not be the + * correct place to solve it, but it works. + */ + +#ifdef __WIN32__ + bloat = 1; +#else + bloat = 0; +#endif + } else { +#ifdef MAC_OSX_TK + /* + * Mac OS X CoreGraphics needs correct rounding here otherwise it will + * draw outside the bounding box. Probably correct on other platforms + * as well? + */ + + bloat = (int) (width+1.5)/2; +#else + bloat = (int) (width+1)/2; +#endif + } + + /* + * Special note: the rectangle is always drawn at least 1x1 in size, so + * round up the upper coordinates to be at least 1 unit greater than the + * lower ones. + */ + + tmp = (int) ((rectOvalPtr->bbox[0] >= 0) ? rectOvalPtr->bbox[0] + .5 + : rectOvalPtr->bbox[0] - .5); + rectOvalPtr->header.x1 = tmp - bloat; + tmp = (int) ((rectOvalPtr->bbox[1] >= 0) ? rectOvalPtr->bbox[1] + .5 + : rectOvalPtr->bbox[1] - .5); + rectOvalPtr->header.y1 = tmp - bloat; + dtmp = rectOvalPtr->bbox[2]; + if (dtmp < (rectOvalPtr->bbox[0] + 1)) { + dtmp = rectOvalPtr->bbox[0] + 1; + } + tmp = (int) ((dtmp >= 0) ? dtmp + .5 : dtmp - .5); + rectOvalPtr->header.x2 = tmp + bloat; + dtmp = rectOvalPtr->bbox[3]; + if (dtmp < (rectOvalPtr->bbox[1] + 1)) { + dtmp = rectOvalPtr->bbox[1] + 1; + } + tmp = (int) ((dtmp >= 0) ? dtmp + .5 : dtmp - .5); + rectOvalPtr->header.y2 = tmp + bloat; +} + +/* + *-------------------------------------------------------------- + * + * DisplayRectOval -- + * + * This function is invoked to draw a rectangle or oval item in a given + * drawable. + * + * Results: + * None. + * + * Side effects: + * ItemPtr is drawn in drawable using the transformation information in + * canvas. + * + *-------------------------------------------------------------- + */ + +static void +DisplayRectOval( + Tk_PathCanvas canvas, /* Canvas that contains item. */ + Tk_PathItem *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, int y, int width, int height) + /* Describes region of canvas that must be + * redisplayed (not used). */ +{ + RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; + short x1, y1, x2, y2; + Pixmap fillStipple; + Tk_PathState state = itemPtr->state; + + /* + * Compute the screen coordinates of the bounding box for the item. Make + * sure that the bbox is at least one pixel large, since some X servers + * will die if it isn't. + */ + + Tk_PathCanvasDrawableCoords(canvas, rectOvalPtr->bbox[0], rectOvalPtr->bbox[1], + &x1, &y1); + Tk_PathCanvasDrawableCoords(canvas, rectOvalPtr->bbox[2], rectOvalPtr->bbox[3], + &x2, &y2); + if (x2 <= x1) { + x2 = x1+1; + } + if (y2 <= y1) { + y2 = y1+1; + } + + /* + * Display filled part first (if wanted), then outline. 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 (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + fillStipple = rectOvalPtr->fillStipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == (Tk_PathItem *)rectOvalPtr) { + if (rectOvalPtr->activeFillStipple != None) { + fillStipple = rectOvalPtr->activeFillStipple; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (rectOvalPtr->disabledFillStipple != None) { + fillStipple = rectOvalPtr->disabledFillStipple; + } + } + + if (rectOvalPtr->fillGC != None) { + if (fillStipple != None) { + int w = 0, h = 0; + Tk_TSOffset tsoffset, *tsoffsetPtr; + + tsoffset.flags = 0; + tsoffset.xoffset = 0; + tsoffset.yoffset = 0; + tsoffsetPtr = rectOvalPtr->tsoffsetPtr; + if (tsoffsetPtr != NULL) { + int flags = tsoffsetPtr->flags; + + if (flags & (TK_OFFSET_CENTER|TK_OFFSET_MIDDLE)) { + Tk_SizeOfBitmap(display, fillStipple, &w, &h); + if (flags & TK_OFFSET_CENTER) { + w /= 2; + } else { + w = 0; + } + if (flags & TK_OFFSET_MIDDLE) { + h /= 2; + } else { + h = 0; + } + } + tsoffset = *tsoffsetPtr; + tsoffset.xoffset -= w; + tsoffset.yoffset -= h; + } + Tk_PathCanvasSetOffset(canvas, rectOvalPtr->fillGC, &tsoffset); + } + if (rectOvalPtr->header.typePtr == &tkRectangleType) { + XFillRectangle(display, drawable, rectOvalPtr->fillGC, + x1, y1, (unsigned int) (x2-x1), (unsigned int) (y2-y1)); + } else { + XFillArc(display, drawable, rectOvalPtr->fillGC, + x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), + 0, 360*64); + } + if (fillStipple != None) { + XSetTSOrigin(display, rectOvalPtr->fillGC, 0, 0); + } + } + + if (rectOvalPtr->outline.gc != None) { + Tk_PathChangeOutlineGC(canvas, itemPtr, &(rectOvalPtr->outline)); + if (rectOvalPtr->header.typePtr == &tkRectangleType) { + XDrawRectangle(display, drawable, rectOvalPtr->outline.gc, + x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1)); + } else { + XDrawArc(display, drawable, rectOvalPtr->outline.gc, + x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), 0, 360*64); + } + Tk_PathResetOutlineGC(canvas, itemPtr, &(rectOvalPtr->outline)); + } +} + +/* + *-------------------------------------------------------------- + * + * RectToPoint -- + * + * Computes the distance from a given point to a given rectangle, in + * canvas units. + * + * Results: + * The return value is 0 if the point whose x and y coordinates are + * coordPtr[0] and coordPtr[1] is inside the rectangle. If the point + * isn't inside the rectangle then the return value is the distance from + * the point to the rectangle. If itemPtr is filled, then anywhere in the + * interior is considered "inside"; if itemPtr isn't filled, then + * "inside" means only the area occupied by the outline. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static double +RectToPoint( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + double *pointPtr) /* Pointer to x and y coordinates. */ +{ + RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; + double xDiff, yDiff, x1, y1, x2, y2, inc, tmp; + double width; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = rectPtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectPtr->outline.activeWidth>width) { + width = rectPtr->outline.activeWidth; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (rectPtr->outline.disabledWidth>0) { + width = rectPtr->outline.disabledWidth; + } + } + + /* + * Generate a new larger rectangle that includes the border width, if + * there is one. + */ + + x1 = rectPtr->bbox[0]; + y1 = rectPtr->bbox[1]; + x2 = rectPtr->bbox[2]; + y2 = rectPtr->bbox[3]; + if (rectPtr->outline.gc != None) { + inc = width/2.0; + x1 -= inc; + y1 -= inc; + x2 += inc; + y2 += inc; + } + + /* + * If the point is inside the rectangle, handle specially: distance is 0 + * if rectangle is filled, otherwise compute distance to nearest edge of + * rectangle and subtract width of edge. + */ + + if ((pointPtr[0] >= x1) && (pointPtr[0] < x2) + && (pointPtr[1] >= y1) && (pointPtr[1] < y2)) { + if ((rectPtr->fillGC != None) || (rectPtr->outline.gc == None)) { + return 0.0; + } + xDiff = pointPtr[0] - x1; + tmp = x2 - pointPtr[0]; + if (tmp < xDiff) { + xDiff = tmp; + } + yDiff = pointPtr[1] - y1; + tmp = y2 - pointPtr[1]; + if (tmp < yDiff) { + yDiff = tmp; + } + if (yDiff < xDiff) { + xDiff = yDiff; + } + xDiff -= width; + if (xDiff < 0.0) { + return 0.0; + } + return xDiff; + } + + /* + * Point is outside rectangle. + */ + + if (pointPtr[0] < x1) { + xDiff = x1 - pointPtr[0]; + } else if (pointPtr[0] > x2) { + xDiff = pointPtr[0] - x2; + } else { + xDiff = 0; + } + + if (pointPtr[1] < y1) { + yDiff = y1 - pointPtr[1]; + } else if (pointPtr[1] > y2) { + yDiff = pointPtr[1] - y2; + } else { + yDiff = 0; + } + + return hypot(xDiff, yDiff); +} + +/* + *-------------------------------------------------------------- + * + * OvalToPoint -- + * + * Computes the distance from a given point to a given oval, in canvas + * units. + * + * Results: + * The return value is 0 if the point whose x and y coordinates are + * coordPtr[0] and coordPtr[1] is inside the oval. If the point isn't + * inside the oval then the return value is the distance from the point + * to the oval. If itemPtr is filled, then anywhere in the interior is + * considered "inside"; if itemPtr isn't filled, then "inside" means only + * the area occupied by the outline. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static double +OvalToPoint( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against point. */ + double *pointPtr) /* Pointer to x and y coordinates. */ +{ + RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; + double width; + int filled; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = (double) ovalPtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (ovalPtr->outline.activeWidth>width) { + width = (double) ovalPtr->outline.activeWidth; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (ovalPtr->outline.disabledWidth>0) { + width = (double) ovalPtr->outline.disabledWidth; + } + } + + + filled = ovalPtr->fillGC != None; + if (ovalPtr->outline.gc == None) { + width = 0.0; + filled = 1; + } + return TkOvalToPoint(ovalPtr->bbox, width, filled, pointPtr); +} + +/* + *-------------------------------------------------------------- + * + * RectToArea -- + * + * This function is called to determine whether an item lies entirely + * inside, entirely outside, or overlapping a given rectangle. + * + * Results: + * -1 is returned if the item is entirely outside the area given by + * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given + * area. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +RectToArea( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against rectangle. */ + double *areaPtr) /* Pointer to array of four coordinates (x1, + * y1, x2, y2) describing rectangular area. */ +{ + RectOvalItem *rectPtr = (RectOvalItem *) itemPtr; + double halfWidth; + double width; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = rectPtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectPtr->outline.activeWidth>width) { + width = rectPtr->outline.activeWidth; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (rectPtr->outline.disabledWidth>0) { + width = rectPtr->outline.disabledWidth; + } + } + + halfWidth = width/2.0; + if (rectPtr->outline.gc == None) { + halfWidth = 0.0; + } + + if ((areaPtr[2] <= (rectPtr->bbox[0] - halfWidth)) + || (areaPtr[0] >= (rectPtr->bbox[2] + halfWidth)) + || (areaPtr[3] <= (rectPtr->bbox[1] - halfWidth)) + || (areaPtr[1] >= (rectPtr->bbox[3] + halfWidth))) { + return -1; + } + if ((rectPtr->fillGC == None) && (rectPtr->outline.gc != None) + && (areaPtr[0] >= (rectPtr->bbox[0] + halfWidth)) + && (areaPtr[1] >= (rectPtr->bbox[1] + halfWidth)) + && (areaPtr[2] <= (rectPtr->bbox[2] - halfWidth)) + && (areaPtr[3] <= (rectPtr->bbox[3] - halfWidth))) { + return -1; + } + if ((areaPtr[0] <= (rectPtr->bbox[0] - halfWidth)) + && (areaPtr[1] <= (rectPtr->bbox[1] - halfWidth)) + && (areaPtr[2] >= (rectPtr->bbox[2] + halfWidth)) + && (areaPtr[3] >= (rectPtr->bbox[3] + halfWidth))) { + return 1; + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * OvalToArea -- + * + * This function 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 given by + * rectPtr, 0 if it overlaps, and 1 if it is entirely inside the given + * area. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +OvalToArea( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item to check against oval. */ + double *areaPtr) /* Pointer to array of four coordinates (x1, + * y1, x2, y2) describing rectangular area. */ +{ + RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr; + double oval[4], halfWidth; + int result; + double width; + Tk_PathState state = itemPtr->state; + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + + width = ovalPtr->outline.width; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (ovalPtr->outline.activeWidth>width) { + width = ovalPtr->outline.activeWidth; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (ovalPtr->outline.disabledWidth>0) { + width = ovalPtr->outline.disabledWidth; + } + } + + /* + * Expand the oval to include the width of the outline, if any. + */ + + halfWidth = width/2.0; + if (ovalPtr->outline.gc == None) { + halfWidth = 0.0; + } + oval[0] = ovalPtr->bbox[0] - halfWidth; + oval[1] = ovalPtr->bbox[1] - halfWidth; + oval[2] = ovalPtr->bbox[2] + halfWidth; + oval[3] = ovalPtr->bbox[3] + halfWidth; + + result = TkOvalToArea(oval, areaPtr); + + /* + * If the rectangle appears to overlap the oval and the oval isn't filled, + * do one more check to see if perhaps all four of the rectangle's corners + * are totally inside the oval's unfilled center, in which case we should + * return "outside". + */ + + if ((result == 0) && (ovalPtr->outline.gc != None) + && (ovalPtr->fillGC == None)) { + double centerX, centerY, height; + double xDelta1, yDelta1, xDelta2, yDelta2; + + centerX = (ovalPtr->bbox[0] + ovalPtr->bbox[2])/2.0; + centerY = (ovalPtr->bbox[1] + ovalPtr->bbox[3])/2.0; + width = (ovalPtr->bbox[2] - ovalPtr->bbox[0])/2.0 - halfWidth; + height = (ovalPtr->bbox[3] - ovalPtr->bbox[1])/2.0 - halfWidth; + xDelta1 = (areaPtr[0] - centerX)/width; + xDelta1 *= xDelta1; + yDelta1 = (areaPtr[1] - centerY)/height; + yDelta1 *= yDelta1; + xDelta2 = (areaPtr[2] - centerX)/width; + xDelta2 *= xDelta2; + yDelta2 = (areaPtr[3] - centerY)/height; + yDelta2 *= yDelta2; + if (((xDelta1 + yDelta1) < 1.0) + && ((xDelta1 + yDelta2) < 1.0) + && ((xDelta2 + yDelta1) < 1.0) + && ((xDelta2 + yDelta2) < 1.0)) { + return -1; + } + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * ScaleRectOval -- + * + * This function is invoked to rescale a rectangle or oval item. + * + * Results: + * None. + * + * Side effects: + * The rectangle or oval 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 +ScaleRectOval( + Tk_PathCanvas canvas, /* Canvas containing rectangle. */ + Tk_PathItem *itemPtr, /* Rectangle to be scaled. */ + double originX, double originY, + /* Origin about which to scale rect. */ + double scaleX, /* Amount to scale in X direction. */ + double scaleY) /* Amount to scale in Y direction. */ +{ + RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; + + rectOvalPtr->bbox[0] = originX + scaleX*(rectOvalPtr->bbox[0] - originX); + rectOvalPtr->bbox[1] = originY + scaleY*(rectOvalPtr->bbox[1] - originY); + rectOvalPtr->bbox[2] = originX + scaleX*(rectOvalPtr->bbox[2] - originX); + rectOvalPtr->bbox[3] = originY + scaleY*(rectOvalPtr->bbox[3] - originY); + ComputeRectOvalBbox(canvas, rectOvalPtr); +} + +/* + *-------------------------------------------------------------- + * + * TranslateRectOval -- + * + * This function is called to move a rectangle or oval by a given amount. + * + * Results: + * None. + * + * Side effects: + * The position of the rectangle or oval is offset by (xDelta, yDelta), + * and the bounding box is updated in the generic part of the item + * structure. + * + *-------------------------------------------------------------- + */ + +static void +TranslateRectOval( + Tk_PathCanvas canvas, /* Canvas containing item. */ + Tk_PathItem *itemPtr, /* Item that is being moved. */ + double deltaX, double deltaY) + /* Amount by which item is to be moved. */ +{ + RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; + + rectOvalPtr->bbox[0] += deltaX; + rectOvalPtr->bbox[1] += deltaY; + rectOvalPtr->bbox[2] += deltaX; + rectOvalPtr->bbox[3] += deltaY; + ComputeRectOvalBbox(canvas, rectOvalPtr); +} + +/* + *-------------------------------------------------------------- + * + * RectOvalToPostscript -- + * + * This function is called to generate Postscript for rectangle and oval + * items. + * + * Results: + * The return value is a standard Tcl result. If an error occurs in + * generating Postscript then an error message is left in the interp's + * result, replacing whatever used to be there. If no error occurs, then + * Postscript for the rectangle is appended to the result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +RectOvalToPostscript( + Tcl_Interp *interp, /* Interpreter for error reporting. */ + Tk_PathCanvas canvas, /* Information about overall canvas. */ + Tk_PathItem *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. */ +{ + char pathCmd[500]; + RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr; + double y1, y2; + XColor *color; + XColor *fillColor; + Pixmap fillStipple; + Tk_PathState state = itemPtr->state; + + y1 = Tk_PathCanvasPsY(canvas, rectOvalPtr->bbox[1]); + y2 = Tk_PathCanvasPsY(canvas, rectOvalPtr->bbox[3]); + + /* + * Generate a string that creates a path for the rectangle or oval. This + * is the only part of the function's code that is type-specific. + */ + + if (rectOvalPtr->header.typePtr == &tkRectangleType) { + sprintf(pathCmd, "%.15g %.15g moveto %.15g 0 rlineto 0 %.15g rlineto %.15g 0 rlineto closepath\n", + rectOvalPtr->bbox[0], y1, + rectOvalPtr->bbox[2]-rectOvalPtr->bbox[0], y2-y1, + rectOvalPtr->bbox[0]-rectOvalPtr->bbox[2]); + } else { + sprintf(pathCmd, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", + (rectOvalPtr->bbox[0] + rectOvalPtr->bbox[2])/2, (y1 + y2)/2, + (rectOvalPtr->bbox[2] - rectOvalPtr->bbox[0])/2, (y1 - y2)/2); + } + + if (state == TK_PATHSTATE_NULL) { + state = TkPathCanvasState(canvas); + } + color = rectOvalPtr->outline.color; + fillColor = rectOvalPtr->fillColor; + fillStipple = rectOvalPtr->fillStipple; + if (((TkPathCanvas *)canvas)->currentItemPtr == itemPtr) { + if (rectOvalPtr->outline.activeColor!=NULL) { + color = rectOvalPtr->outline.activeColor; + } + if (rectOvalPtr->activeFillColor!=NULL) { + fillColor = rectOvalPtr->activeFillColor; + } + if (rectOvalPtr->activeFillStipple!=None) { + fillStipple = rectOvalPtr->activeFillStipple; + } + } else if (state == TK_PATHSTATE_DISABLED) { + if (rectOvalPtr->outline.disabledColor!=NULL) { + color = rectOvalPtr->outline.disabledColor; + } + if (rectOvalPtr->disabledFillColor!=NULL) { + fillColor = rectOvalPtr->disabledFillColor; + } + if (rectOvalPtr->disabledFillStipple!=None) { + fillStipple = rectOvalPtr->disabledFillStipple; + } + } + + /* + * First draw the filled area of the rectangle. + */ + + if (fillColor != NULL) { + Tcl_AppendResult(interp, pathCmd, NULL); + if (Tk_PathCanvasPsColor(interp, canvas, fillColor) != TCL_OK) { + return TCL_ERROR; + } + if (fillStipple != None) { + Tcl_AppendResult(interp, "clip ", NULL); + if (Tk_PathCanvasPsStipple(interp, canvas, fillStipple) != TCL_OK) { + return TCL_ERROR; + } + if (color != NULL) { + Tcl_AppendResult(interp, "grestore gsave\n", NULL); + } + } else { + Tcl_AppendResult(interp, "fill\n", NULL); + } + } + + /* + * Now draw the outline, if there is one. + */ + + if (color != NULL) { + Tcl_AppendResult(interp, pathCmd, "0 setlinejoin 2 setlinecap\n", + NULL); + if (Tk_PathCanvasPsOutline(canvas, itemPtr, + &(rectOvalPtr->outline))!= TCL_OK) { + return TCL_ERROR; + } + } + return TCL_OK; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/pd/tkpath/generic/tkpTrig.c b/pd/tkpath/generic/tkpTrig.c new file mode 100644 index 0000000000000000000000000000000000000000..35d8369b2f8539b3553ba042da759d417bb17a9c --- /dev/null +++ b/pd/tkpath/generic/tkpTrig.c @@ -0,0 +1,736 @@ +/* + * tkpTrig.c -- + * + * This file contains a collection of trigonometry utility routines that + * are used by Tk and in particular by the canvas code. It also has + * miscellaneous geometry functions used by canvases. + * + * Copyright (c) 1992-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpTrig.c,v 1.2 2008/06/05 14:39:49 matben Exp $ + */ + +/* + * Copied here from tkTrig.c when they contain arguments + * specific for the canvas implementaion. + */ + +#include <stdio.h> +#include "tkInt.h" +#include "tkIntPath.h" +#include "tkpCanvas.h" + +#undef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#undef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#ifndef PI +# define PI 3.14159265358979323846 +#endif /* PI */ + + +/* + *-------------------------------------------------------------- + * + * TkPathIncludePoint -- + * + * Given a point and a generic canvas item header, expand the item's + * bounding box if needed to include the point. + * + * Results: + * None. + * + * Side effects: + * The boudn. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +void +TkPathIncludePoint( + register Tk_PathItem *itemPtr,/* Item whose bounding box is being + * calculated. */ + double *pointPtr) /* Address of two doubles giving x and y + * coordinates of point. */ +{ + int tmp; + + tmp = (int) (pointPtr[0] + 0.5); + if (tmp < itemPtr->x1) { + itemPtr->x1 = tmp; + } + if (tmp > itemPtr->x2) { + itemPtr->x2 = tmp; + } + tmp = (int) (pointPtr[1] + 0.5); + if (tmp < itemPtr->y1) { + itemPtr->y1 = tmp; + } + if (tmp > itemPtr->y2) { + itemPtr->y2 = tmp; + } +} + + +/* + *-------------------------------------------------------------- + * + * TkPathBezierScreenPoints -- + * + * Given four control points, create a larger set of XPoints for a Bezier + * curve based on the points. + * + * Results: + * The array at *xPointPtr gets filled in with numSteps XPoints + * corresponding to the Bezier spline defined by the four control points. + * Note: no output point is generated for the first input point, but an + * output point *is* generated for the last input point. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +TkPathBezierScreenPoints( + Tk_PathCanvas canvas, /* Canvas in which curve is to be drawn. */ + double control[], /* Array of coordinates for four control + * points: x0, y0, x1, y1, ... x3 y3. */ + int numSteps, /* Number of curve points to generate. */ + register XPoint *xPointPtr) /* Where to put new points. */ +{ + int i; + double u, u2, u3, t, t2, t3; + + for (i = 1; i <= numSteps; i++, xPointPtr++) { + t = ((double) i)/((double) numSteps); + t2 = t*t; + t3 = t2*t; + u = 1.0 - t; + u2 = u*u; + u3 = u2*u; + Tk_PathCanvasDrawableCoords(canvas, + (control[0]*u3 + 3.0 * (control[2]*t*u2 + control[4]*t2*u) + + control[6]*t3), + (control[1]*u3 + 3.0 * (control[3]*t*u2 + control[5]*t2*u) + + control[7]*t3), + &xPointPtr->x, &xPointPtr->y); + } +} + +/* + *-------------------------------------------------------------- + * + * TkPathBezierPoints -- + * + * Given four control points, create a larger set of points for a Bezier + * curve based on the points. + * + * Results: + * The array at *coordPtr gets filled in with 2*numSteps coordinates, + * which correspond to the Bezier spline defined by the four control + * points. Note: no output point is generated for the first input point, + * but an output point *is* generated for the last input point. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +TkPathBezierPoints( + double control[], /* Array of coordinates for four control + * points: x0, y0, x1, y1, ... x3 y3. */ + int numSteps, /* Number of curve points to generate. */ + register double *coordPtr) /* Where to put new points. */ +{ + int i; + double u, u2, u3, t, t2, t3; + + for (i = 1; i <= numSteps; i++, coordPtr += 2) { + t = ((double) i)/((double) numSteps); + t2 = t*t; + t3 = t2*t; + u = 1.0 - t; + u2 = u*u; + u3 = u2*u; + coordPtr[0] = control[0]*u3 + + 3.0 * (control[2]*t*u2 + control[4]*t2*u) + control[6]*t3; + coordPtr[1] = control[1]*u3 + + 3.0 * (control[3]*t*u2 + control[5]*t2*u) + control[7]*t3; + } +} + +/* + *-------------------------------------------------------------- + * + * TkPathMakeBezierCurve -- + * + * Given a set of points, create a new set of points that fit parabolic + * splines to the line segments connecting the original points. Produces + * output points in either of two forms. + * + * Note: the name of this function should *not* be taken to mean that it + * interprets the input points as directly defining Bezier curves. + * Rather, it internally computes a Bezier curve representation of each + * parabolic spline segment. (These Bezier curves are then flattened to + * produce the points filled into the output arrays.) + * + * Results: + * Either or both of the xPoints or dblPoints arrays are filled in. The + * return value is the number of points placed in the arrays. Note: if + * the first and last points are the same, then a closed curve is + * generated. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkPathMakeBezierCurve( + Tk_PathCanvas canvas, /* Canvas in which curve is to be drawn. */ + double *pointPtr, /* Array of input coordinates: x0, y0, x1, y1, + * etc.. */ + int numPoints, /* Number of points at pointPtr. */ + int numSteps, /* Number of steps to use for each spline + * segments (determines smoothness of + * curve). */ + XPoint xPoints[], /* Array of XPoints to fill in (e.g. for + * display). NULL means don't fill in any + * XPoints. */ + double dblPoints[]) /* Array of points to fill in as doubles, in + * the form x0, y0, x1, y1, .... NULL means + * don't fill in anything in this form. Caller + * must make sure that this array has enough + * space. */ +{ + int closed, outputPoints, i; + int numCoords = numPoints*2; + double control[8]; + + /* + * If the curve is a closed one then generate a special spline that spans + * the last points and the first ones. Otherwise just put the first point + * into the output. + */ + + if (!pointPtr) { + /* + * Of pointPtr == NULL, this function returns an upper limit of the + * array size to store the coordinates. This can be used to allocate + * storage, before the actual coordinates are calculated. + */ + + return 1 + numPoints * numSteps; + } + + outputPoints = 0; + if ((pointPtr[0] == pointPtr[numCoords-2]) + && (pointPtr[1] == pointPtr[numCoords-1])) { + closed = 1; + control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0]; + control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1]; + control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0]; + control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1]; + control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2]; + control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3]; + control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; + control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; + if (xPoints != NULL) { + Tk_PathCanvasDrawableCoords(canvas, control[0], control[1], + &xPoints->x, &xPoints->y); + TkPathBezierScreenPoints(canvas, control, numSteps, xPoints+1); + xPoints += numSteps+1; + } + if (dblPoints != NULL) { + dblPoints[0] = control[0]; + dblPoints[1] = control[1]; + TkPathBezierPoints(control, numSteps, dblPoints+2); + dblPoints += 2*(numSteps+1); + } + outputPoints += numSteps+1; + } else { + closed = 0; + if (xPoints != NULL) { + Tk_PathCanvasDrawableCoords(canvas, pointPtr[0], pointPtr[1], + &xPoints->x, &xPoints->y); + xPoints += 1; + } + if (dblPoints != NULL) { + dblPoints[0] = pointPtr[0]; + dblPoints[1] = pointPtr[1]; + dblPoints += 2; + } + outputPoints += 1; + } + + for (i = 2; i < numPoints; i++, pointPtr += 2) { + /* + * Set up the first two control points. This is done differently for + * the first spline of an open curve than for other cases. + */ + + if ((i == 2) && !closed) { + control[0] = pointPtr[0]; + control[1] = pointPtr[1]; + control[2] = 0.333*pointPtr[0] + 0.667*pointPtr[2]; + control[3] = 0.333*pointPtr[1] + 0.667*pointPtr[3]; + } else { + control[0] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; + control[1] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; + control[2] = 0.167*pointPtr[0] + 0.833*pointPtr[2]; + control[3] = 0.167*pointPtr[1] + 0.833*pointPtr[3]; + } + + /* + * Set up the last two control points. This is done differently for + * the last spline of an open curve than for other cases. + */ + + if ((i == (numPoints-1)) && !closed) { + control[4] = .667*pointPtr[2] + .333*pointPtr[4]; + control[5] = .667*pointPtr[3] + .333*pointPtr[5]; + control[6] = pointPtr[4]; + control[7] = pointPtr[5]; + } else { + control[4] = .833*pointPtr[2] + .167*pointPtr[4]; + control[5] = .833*pointPtr[3] + .167*pointPtr[5]; + control[6] = 0.5*pointPtr[2] + 0.5*pointPtr[4]; + control[7] = 0.5*pointPtr[3] + 0.5*pointPtr[5]; + } + + /* + * If the first two points coincide, or if the last two points + * coincide, then generate a single straight-line segment by + * outputting the last control point. + */ + + if (((pointPtr[0] == pointPtr[2]) && (pointPtr[1] == pointPtr[3])) + || ((pointPtr[2] == pointPtr[4]) + && (pointPtr[3] == pointPtr[5]))) { + if (xPoints != NULL) { + Tk_PathCanvasDrawableCoords(canvas, control[6], control[7], + &xPoints[0].x, &xPoints[0].y); + xPoints++; + } + if (dblPoints != NULL) { + dblPoints[0] = control[6]; + dblPoints[1] = control[7]; + dblPoints += 2; + } + outputPoints += 1; + continue; + } + + /* + * Generate a Bezier spline using the control points. + */ + + + if (xPoints != NULL) { + TkPathBezierScreenPoints(canvas, control, numSteps, xPoints); + xPoints += numSteps; + } + if (dblPoints != NULL) { + TkPathBezierPoints(control, numSteps, dblPoints); + dblPoints += 2*numSteps; + } + outputPoints += numSteps; + } + return outputPoints; +} + +/* + *-------------------------------------------------------------- + * + * TkPathMakeRawCurve -- + * + * Interpret the given set of points as the raw knots and control points + * defining a sequence of cubic Bezier curves. Create a new set of points + * that fit these Bezier curves. Output points are produced in either of + * two forms. + * + * Results: + * Either or both of the xPoints or dblPoints arrays are filled in. The + * return value is the number of points placed in the arrays. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkPathMakeRawCurve( + Tk_PathCanvas canvas, /* Canvas in which curve is to be drawn. */ + double *pointPtr, /* Array of input coordinates: x0, y0, x1, y1, + * etc.. */ + int numPoints, /* Number of points at pointPtr. */ + int numSteps, /* Number of steps to use for each curve + * segment (determines smoothness of + * curve). */ + XPoint xPoints[], /* Array of XPoints to fill in (e.g. for + * display). NULL means don't fill in any + * XPoints. */ + double dblPoints[]) /* Array of points to fill in as doubles, in + * the form x0, y0, x1, y1, .... NULL means + * don't fill in anything in this form. + * Caller must make sure that this array has + * enough space. */ +{ + int outputPoints, i; + int numSegments = (numPoints+1)/3; + double *segPtr; + + /* + * The input describes a curve with s Bezier curve segments if there are + * 3s+1, 3s, or 3s-1 input points. In the last two cases, 1 or 2 initial + * points from the first curve segment are reused as defining points also + * for the last curve segment. In the case of 3s input points, this will + * automatically close the curve. + */ + + if (!pointPtr) { + /* + * If pointPtr == NULL, this function returns an upper limit of the + * array size to store the coordinates. This can be used to allocate + * storage, before the actual coordinates are calculated. + */ + + return 1 + numSegments * numSteps; + } + + outputPoints = 0; + if (xPoints != NULL) { + Tk_PathCanvasDrawableCoords(canvas, pointPtr[0], pointPtr[1], + &xPoints->x, &xPoints->y); + xPoints += 1; + } + if (dblPoints != NULL) { + dblPoints[0] = pointPtr[0]; + dblPoints[1] = pointPtr[1]; + dblPoints += 2; + } + outputPoints += 1; + + /* + * The next loop handles all curve segments except one that overlaps the + * end of the list of coordinates. + */ + + for (i=numPoints,segPtr=pointPtr ; i>=4 ; i-=3,segPtr+=6) { + if (segPtr[0]==segPtr[2] && segPtr[1]==segPtr[3] && + segPtr[4]==segPtr[6] && segPtr[5]==segPtr[7]) { + /* + * The control points on this segment are equal to their + * neighbouring knots, so this segment is just a straight line. A + * single point is sufficient. + */ + + if (xPoints != NULL) { + Tk_PathCanvasDrawableCoords(canvas, segPtr[6], segPtr[7], + &xPoints->x, &xPoints->y); + xPoints += 1; + } + if (dblPoints != NULL) { + dblPoints[0] = segPtr[6]; + dblPoints[1] = segPtr[7]; + dblPoints += 2; + } + outputPoints += 1; + } else { + /* + * This is a generic Bezier curve segment. + */ + + if (xPoints != NULL) { + TkPathBezierScreenPoints(canvas, segPtr, numSteps, xPoints); + xPoints += numSteps; + } + if (dblPoints != NULL) { + TkPathBezierPoints(segPtr, numSteps, dblPoints); + dblPoints += 2*numSteps; + } + outputPoints += numSteps; + } + } + + /* + * If at this point i>1, then there is some point which has not yet been + * used. Make another curve segment. + */ + + if (i > 1) { + int j; + double control[8]; + + /* + * Copy the relevant coordinates to control[], so that it can be + * passed as a unit to e.g. TkPathBezierPoints. + */ + + for (j=0; j<2*i; j++) { + control[j] = segPtr[j]; + } + for (; j<8; j++) { + control[j] = pointPtr[j-2*i]; + } + + /* + * Then we just do the same things as above. + */ + + if (control[0]==control[2] && control[1]==control[3] && + control[4]==control[6] && control[5]==control[7]) { + /* + * The control points on this segment are equal to their + * neighbouring knots, so this segment is just a straight line. A + * single point is sufficient. + */ + + if (xPoints != NULL) { + Tk_PathCanvasDrawableCoords(canvas, control[6], control[7], + &xPoints->x, &xPoints->y); + xPoints += 1; + } + if (dblPoints != NULL) { + dblPoints[0] = control[6]; + dblPoints[1] = control[7]; + dblPoints += 2; + } + outputPoints += 1; + } else { + /* + * This is a generic Bezier curve segment. + */ + + if (xPoints != NULL) { + TkPathBezierScreenPoints(canvas, control, numSteps, xPoints); + xPoints += numSteps; + } + if (dblPoints != NULL) { + TkPathBezierPoints(control, numSteps, dblPoints); + dblPoints += 2*numSteps; + } + outputPoints += numSteps; + } + } + + return outputPoints; +} + +/* + *-------------------------------------------------------------- + * + * TkPathMakeBezierPostscript -- + * + * This function generates Postscript commands that create a path + * corresponding to a given Bezier curve. + * + * Results: + * None. Postscript commands to generate the path are appended to the + * interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +TkPathMakeBezierPostscript( + Tcl_Interp *interp, /* Interpreter in whose result the Postscript + * is to be stored. */ + Tk_PathCanvas canvas, /* Canvas widget for which the Postscript is + * being generated. */ + double *pointPtr, /* Array of input coordinates: x0, y0, x1, y1, + * etc.. */ + int numPoints) /* Number of points at pointPtr. */ +{ + int closed, i; + int numCoords = numPoints*2; + double control[8]; + char buffer[200]; + + /* + * If the curve is a closed one then generate a special spline that spans + * the last points and the first ones. Otherwise just put the first point + * into the path. + */ + + if ((pointPtr[0] == pointPtr[numCoords-2]) + && (pointPtr[1] == pointPtr[numCoords-1])) { + closed = 1; + control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0]; + control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1]; + control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0]; + control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1]; + control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2]; + control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3]; + control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; + control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; + sprintf(buffer, "%.15g %.15g moveto\n%.15g %.15g %.15g %.15g %.15g %.15g curveto\n", + control[0], Tk_PathCanvasPsY(canvas, control[1]), + control[2], Tk_PathCanvasPsY(canvas, control[3]), + control[4], Tk_PathCanvasPsY(canvas, control[5]), + control[6], Tk_PathCanvasPsY(canvas, control[7])); + } else { + closed = 0; + control[6] = pointPtr[0]; + control[7] = pointPtr[1]; + sprintf(buffer, "%.15g %.15g moveto\n", + control[6], Tk_PathCanvasPsY(canvas, control[7])); + } + Tcl_AppendResult(interp, buffer, NULL); + + /* + * Cycle through all the remaining points in the curve, generating a curve + * section for each vertex in the linear path. + */ + + for (i = numPoints-2, pointPtr += 2; i > 0; i--, pointPtr += 2) { + control[2] = 0.333*control[6] + 0.667*pointPtr[0]; + control[3] = 0.333*control[7] + 0.667*pointPtr[1]; + + /* + * Set up the last two control points. This is done differently for + * the last spline of an open curve than for other cases. + */ + + if ((i == 1) && !closed) { + control[6] = pointPtr[2]; + control[7] = pointPtr[3]; + } else { + control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2]; + control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3]; + } + control[4] = 0.333*control[6] + 0.667*pointPtr[0]; + control[5] = 0.333*control[7] + 0.667*pointPtr[1]; + + sprintf(buffer, "%.15g %.15g %.15g %.15g %.15g %.15g curveto\n", + control[2], Tk_PathCanvasPsY(canvas, control[3]), + control[4], Tk_PathCanvasPsY(canvas, control[5]), + control[6], Tk_PathCanvasPsY(canvas, control[7])); + Tcl_AppendResult(interp, buffer, NULL); + } +} + +/* + *-------------------------------------------------------------- + * + * TkPathMakeRawCurvePostscript -- + * + * This function interprets the input points as the raw knot and control + * points for a curve composed of Bezier curve segments, just like + * TkPathMakeRawCurve. It generates Postscript commands that create a path + * corresponding to this given curve. + * + * Results: + * None. Postscript commands to generate the path are appended to the + * interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +void +TkPathMakeRawCurvePostscript( + Tcl_Interp *interp, /* Interpreter in whose result the Postscript + * is to be stored. */ + Tk_PathCanvas canvas, /* Canvas widget for which the Postscript is + * being generated. */ + double *pointPtr, /* Array of input coordinates: x0, y0, x1, y1, + * etc.. */ + int numPoints) /* Number of points at pointPtr. */ +{ + int i; + double *segPtr; + char buffer[200]; + + /* + * Put the first point into the path. + */ + + sprintf(buffer, "%.15g %.15g moveto\n", + pointPtr[0], Tk_PathCanvasPsY(canvas, pointPtr[1])); + Tcl_AppendResult(interp, buffer, NULL); + + /* + * Loop through all the remaining points in the curve, generating a + * straight line or curve section for every three of them. + */ + + for (i=numPoints-1,segPtr=pointPtr ; i>=3 ; i-=3,segPtr+=6) { + if (segPtr[0]==segPtr[2] && segPtr[1]==segPtr[3] && + segPtr[4]==segPtr[6] && segPtr[5]==segPtr[7]) { + /* + * The control points on this segment are equal to their + * neighbouring knots, so this segment is just a straight line. + */ + + sprintf(buffer, "%.15g %.15g lineto\n", + segPtr[6], Tk_PathCanvasPsY(canvas, segPtr[7])); + } else { + /* + * This is a generic Bezier curve segment. + */ + + sprintf(buffer, "%.15g %.15g %.15g %.15g %.15g %.15g curveto\n", + segPtr[2], Tk_PathCanvasPsY(canvas, segPtr[3]), + segPtr[4], Tk_PathCanvasPsY(canvas, segPtr[5]), + segPtr[6], Tk_PathCanvasPsY(canvas, segPtr[7])); + } + Tcl_AppendResult(interp, buffer, NULL); + } + + /* + * If there are any points left that haven't been used, then build the + * last segment and generate Postscript in the same way for that. + */ + + if (i > 0) { + int j; + double control[8]; + + for (j=0; j<2*i+2; j++) { + control[j] = segPtr[j]; + } + for (; j<8; j++) { + control[j] = pointPtr[j-2*i-2]; + } + + if (control[0]==control[2] && control[1]==control[3] && + control[4]==control[6] && control[5]==control[7]) { + /* + * Straight line. + */ + + sprintf(buffer, "%.15g %.15g lineto\n", + control[6], Tk_PathCanvasPsY(canvas, control[7])); + } else { + /* + * Bezier curve segment. + */ + + sprintf(buffer, "%.15g %.15g %.15g %.15g %.15g %.15g curveto\n", + control[2], Tk_PathCanvasPsY(canvas, control[3]), + control[4], Tk_PathCanvasPsY(canvas, control[5]), + control[6], Tk_PathCanvasPsY(canvas, control[7])); + } + Tcl_AppendResult(interp, buffer, NULL); + } +} + + + \ No newline at end of file diff --git a/pd/tkpath/generic/tkpUtil.c b/pd/tkpath/generic/tkpUtil.c new file mode 100644 index 0000000000000000000000000000000000000000..bf0106458f5854de0854561e63286986e6f3d799 --- /dev/null +++ b/pd/tkpath/generic/tkpUtil.c @@ -0,0 +1,483 @@ +/* + * tkpUtil.c -- + * + * This file contains miscellaneous utility functions that are used by + * the rest of Tk, such as a function for drawing a focus highlight. + * + * Copyright (c) 1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkpUtil.c,v 1.7 2012/07/04 19:43:18 petasis Exp $ + */ + +#include "tkInt.h" +#include "tkIntPath.h" + +/* + * The structure below defines the implementation of the "statekey" Tcl + * object, used for quickly finding a mapping in a TkStateMap. + */ + +/* === EB - 30-apr-2010: commented out the CONST that made build fail with tcl/tk 8.5 */ +/* === George Petasis - 7 July 2012: The missing CONST fails with Tk 8.6... */ +#if (TK_MAJOR_VERSION >= 8) && (TK_MINOR_VERSION >= 6) +CONST +#endif +Tcl_ObjType tkStateKeyObjType = { + "statekey", /* name */ + NULL, /* freeIntRepProc */ + NULL, /* dupIntRepProc */ + NULL, /* updateStringProc */ + NULL /* setFromAnyProc */ +}; +/* === */ + +static int +GetOffset(Tcl_Interp *interp, ClientData clientData, + Tcl_Obj *offsetObj, Tk_Window tkwin, Tk_TSOffset *offsetPtr) +{ + char *value = Tcl_GetString(offsetObj); + Tk_TSOffset tsoffset; + const char *q, *p; + int result; + + if ((value == NULL) || (*value == 0)) { + tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_MIDDLE; + goto goodTSOffset; + } + tsoffset.flags = 0; + p = value; + + switch(value[0]) { + case '#': + if (PTR2INT(clientData) & TK_OFFSET_RELATIVE) { + tsoffset.flags = TK_OFFSET_RELATIVE; + p++; + break; + } + goto badTSOffset; + case 'e': + switch(value[1]) { + case '\0': + tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_MIDDLE; + goto goodTSOffset; + case 'n': + if (value[2]!='d' || value[3]!='\0') { + goto badTSOffset; + } + tsoffset.flags = INT_MAX; + goto goodTSOffset; + } + case 'w': + if (value[1] != '\0') {goto badTSOffset;} + tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_MIDDLE; + goto goodTSOffset; + case 'n': + if ((value[1] != '\0') && (value[2] != '\0')) { + goto badTSOffset; + } + switch(value[1]) { + case '\0': + tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_TOP; + goto goodTSOffset; + case 'w': + tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_TOP; + goto goodTSOffset; + case 'e': + tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_TOP; + goto goodTSOffset; + } + goto badTSOffset; + case 's': + if ((value[1] != '\0') && (value[2] != '\0')) { + goto badTSOffset; + } + switch(value[1]) { + case '\0': + tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_BOTTOM; + goto goodTSOffset; + case 'w': + tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_BOTTOM; + goto goodTSOffset; + case 'e': + tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_BOTTOM; + goto goodTSOffset; + } + goto badTSOffset; + case 'c': + if (strncmp(value, "center", strlen(value)) != 0) { + goto badTSOffset; + } + tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_MIDDLE; + goto goodTSOffset; + } + if ((q = strchr(p,',')) == NULL) { + if (PTR2INT(clientData) & TK_OFFSET_INDEX) { + if (Tcl_GetInt(interp, (char *) p, &tsoffset.flags) != TCL_OK) { + Tcl_ResetResult(interp); + goto badTSOffset; + } + tsoffset.flags |= TK_OFFSET_INDEX; + goto goodTSOffset; + } + goto badTSOffset; + } + *((char *) q) = 0; + result = Tk_GetPixels(interp, tkwin, (char *) p, &tsoffset.xoffset); + *((char *) q) = ','; + if (result != TCL_OK) { + return TCL_ERROR; + } + if (Tk_GetPixels(interp, tkwin, (char*)q+1, &tsoffset.yoffset) != TCL_OK) { + return TCL_ERROR; + } + +goodTSOffset: + /* + * Below is a hack to allow the stipple/tile offset to be stored in the + * internal tile structure. Most of the times, offsetPtr is a pointer to + * an already existing tile structure. However if this structure is not + * already created, we must do it with Tk_GetTile()!!!!; + */ + + memcpy(offsetPtr, &tsoffset, sizeof(Tk_TSOffset)); + return TCL_OK; + +badTSOffset: + Tcl_AppendResult(interp, "bad offset \"", value, + "\": expected \"x,y\"", NULL); + if (PTR2INT(clientData) & TK_OFFSET_RELATIVE) { + Tcl_AppendResult(interp, ", \"#x,y\"", NULL); + } + if (PTR2INT(clientData) & TK_OFFSET_INDEX) { + Tcl_AppendResult(interp, ", <index>", NULL); + } + Tcl_AppendResult(interp, ", n, ne, e, se, s, sw, w, nw, or center", NULL); + return TCL_ERROR; +} + +/* Return NULL on error and leave error message */ + +static Tk_TSOffset * +PathOffsetNew(Tcl_Interp *interp, ClientData clientData, Tk_Window tkwin, Tcl_Obj *offsetObj) +{ + Tk_TSOffset *offsetPtr; + + offsetPtr = (Tk_TSOffset *) ckalloc(sizeof(Tk_TSOffset)); + if (GetOffset(interp, clientData, offsetObj, tkwin, offsetPtr) != TCL_OK) { + ckfree((char *) offsetPtr); + return NULL;; + } + return offsetPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkPathOffsetOptionSetProc -- + * + * Converts the offset of a stipple or tile into the Tk_TSOffset + * structure. + * + *---------------------------------------------------------------------- + */ + +int TkPathOffsetOptionSetProc( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; /* Points to location in record where + * internal representation of value should + * be stored, or NULL. */ + Tcl_Obj *valuePtr; + Tk_TSOffset *newPtr = NULL; + + valuePtr = *value; + if (internalOffset >= 0) { + internalPtr = recordPtr + internalOffset; + } else { + internalPtr = NULL; + } + if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + newPtr = NULL; + } + if (internalPtr != NULL) { + if (valuePtr != NULL) { + newPtr = PathOffsetNew(interp, clientData, tkwin, valuePtr); + if (newPtr == NULL) { + return TCL_ERROR; + } + } + *((Tk_TSOffset **) oldInternalPtr) = *((Tk_TSOffset **) internalPtr); + *((Tk_TSOffset **) internalPtr) = newPtr; + } + return TCL_OK; +} + +Tcl_Obj * +TkPathOffsetOptionGetProc( + ClientData clientData, + Tk_Window tkwin, + char *recordPtr, /* Pointer to widget record. */ + int internalOffset) /* Offset within *recordPtr containing the + * value. */ +{ + Tk_TSOffset *offsetPtr; + char buffer[32], *p; + + offsetPtr = *((Tk_TSOffset **) (recordPtr + internalOffset)); + buffer[0] = '\0'; + if (offsetPtr->flags & TK_OFFSET_INDEX) { + if (offsetPtr->flags >= INT_MAX) { + strcat(buffer, "end"); + } else { + sprintf(buffer, "%d", offsetPtr->flags & ~TK_OFFSET_INDEX); + } + goto end; + } + if (offsetPtr->flags & TK_OFFSET_TOP) { + if (offsetPtr->flags & TK_OFFSET_LEFT) { + strcat(buffer, "nw"); + goto end; + } else if (offsetPtr->flags & TK_OFFSET_CENTER) { + strcat(buffer, "n"); + goto end; + } else if (offsetPtr->flags & TK_OFFSET_RIGHT) { + strcat(buffer, "ne"); + goto end; + } + } else if (offsetPtr->flags & TK_OFFSET_MIDDLE) { + if (offsetPtr->flags & TK_OFFSET_LEFT) { + strcat(buffer, "w"); + goto end; + } else if (offsetPtr->flags & TK_OFFSET_CENTER) { + strcat(buffer, "center"); + goto end; + } else if (offsetPtr->flags & TK_OFFSET_RIGHT) { + strcat(buffer, "e"); + goto end; + } + } else if (offsetPtr->flags & TK_OFFSET_BOTTOM) { + if (offsetPtr->flags & TK_OFFSET_LEFT) { + strcat(buffer, "sw"); + goto end; + } else if (offsetPtr->flags & TK_OFFSET_CENTER) { + strcat(buffer, "s"); + goto end; + } else if (offsetPtr->flags & TK_OFFSET_RIGHT) { + strcat(buffer, "se"); + goto end; + } + } + p = buffer; + if (offsetPtr->flags & TK_OFFSET_RELATIVE) { + strcat(buffer , "#"); + p++; + } + sprintf(p, "%d,%d", offsetPtr->xoffset, offsetPtr->yoffset); + +end: + return Tcl_NewStringObj(buffer, -1); +} + +void +TkPathOffsetOptionRestoreProc( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(Tk_TSOffset **)internalPtr = *(Tk_TSOffset **)oldInternalPtr; +} + +void +TkPathOffsetOptionFreeProc( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr) /* Pointer to storage for value. */ +{ + if (*((char **) internalPtr) != NULL) { + ckfree((char *) *((char **) internalPtr)); + } +} + +/* + *-------------------------------------------------------------- + * + * GetDoublePixels -- + * + * Given a string, returns the number of pixels corresponding + * to that string. + * + * Results: + * The return value is a standard Tcl return result. If + * TCL_OK is returned, then everything went well and the + * pixel distance is stored at *doublePtr; otherwise + * TCL_ERROR is returned and an error message is left in + * interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetDoublePixels( + Tcl_Interp *interp, /* Use this for error reporting. */ + Tk_Window tkwin, /* Window whose screen determines conversion + * from centimeters and other absolute + * units. */ + CONST char *string, /* String describing a number of pixels. */ + double *doublePtr) /* Place to store converted result. */ +{ + char *end; + double d; + + d = strtod((char *) string, &end); + if (end == string) { + error: + Tcl_AppendResult(interp, "bad screen distance \"", string, + "\"", (char *) NULL); + return TCL_ERROR; + } + while ((*end != '\0') && isspace(UCHAR(*end))) { + end++; + } + switch (*end) { + case 0: + break; + case 'c': + d *= 10*WidthOfScreen(Tk_Screen(tkwin)); + d /= WidthMMOfScreen(Tk_Screen(tkwin)); + end++; + break; + case 'i': + d *= 25.4*WidthOfScreen(Tk_Screen(tkwin)); + d /= WidthMMOfScreen(Tk_Screen(tkwin)); + end++; + break; + case 'm': + d *= WidthOfScreen(Tk_Screen(tkwin)); + d /= WidthMMOfScreen(Tk_Screen(tkwin)); + end++; + break; + case 'p': + d *= (25.4/72.0)*WidthOfScreen(Tk_Screen(tkwin)); + d /= WidthMMOfScreen(Tk_Screen(tkwin)); + end++; + break; + default: + goto error; + } + while ((*end != '\0') && isspace(UCHAR(*end))) { + end++; + } + if (*end != 0) { + goto error; + } + *doublePtr = d; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_PathPixelOptionSetProc -- + * + * As TK_OPTION_PIXELS but for double value instead of int. + * + * Results: + * The return value is a standard Tcl return result. If + * TCL_OK is returned, then everything went well and the + * pixel distance is stored at *doublePtr; otherwise + * TCL_ERROR is returned and an error message is left in + * interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int Tk_PathPixelOptionSetProc( + ClientData clientData, + Tcl_Interp *interp, /* Current interp; may be used for errors. */ + Tk_Window tkwin, /* Window for which option is being set. */ + Tcl_Obj **value, /* Pointer to the pointer to the value object. + * We use a pointer to the pointer because + * we may need to return a value (NULL). */ + char *recordPtr, /* Pointer to storage for the widget record. */ + int internalOffset, /* Offset within *recordPtr at which the + internal value is to be stored. */ + char *oldInternalPtr, /* Pointer to storage for the old value. */ + int flags) /* Flags for the option, set Tk_SetOptions. */ +{ + char *internalPtr; /* Points to location in record where + * internal representation of value should + * be stored, or NULL. */ + Tcl_Obj *valuePtr; + double newPixels; + int result; + + valuePtr = *value; + if (internalOffset >= 0) { + internalPtr = recordPtr + internalOffset; + } else { + internalPtr = NULL; + } + if ((flags & TK_OPTION_NULL_OK) && ObjectIsEmpty(valuePtr)) { + valuePtr = NULL; + newPixels = 0.0; + } + if (internalPtr != NULL) { + if (valuePtr != NULL) { + result = GetDoublePixels(interp, tkwin, Tcl_GetString(valuePtr), &newPixels); + if (result != TCL_OK) { + return TCL_ERROR; + } else if (newPixels < 0.0) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "bad screen distance \"", value, "\"", NULL); + return TCL_ERROR; + } + } + *((double *) oldInternalPtr) = *((double *) internalPtr); + *((double *) internalPtr) = newPixels; + } + return TCL_OK; +} + +Tcl_Obj * +Tk_PathPixelOptionGetProc( + ClientData clientData, + Tk_Window tkwin, + char *recordPtr, /* Pointer to widget record. */ + int internalOffset) /* Offset within *recordPtr containing the + * value. */ +{ + return Tcl_NewDoubleObj(*((double *) (recordPtr + internalOffset))); +} + +void +Tk_PathPixelOptionRestoreProc( + ClientData clientData, + Tk_Window tkwin, + char *internalPtr, /* Pointer to storage for value. */ + char *oldInternalPtr) /* Pointer to old value. */ +{ + *(double **)internalPtr = *(double **)oldInternalPtr; +} + diff --git a/pd/tkpath/library/tkpath.tcl b/pd/tkpath/library/tkpath.tcl new file mode 100644 index 0000000000000000000000000000000000000000..d0c7805013536c3db99ac1b1c6bd4a545d5cdd6d --- /dev/null +++ b/pd/tkpath/library/tkpath.tcl @@ -0,0 +1,166 @@ +# tkpath.tcl -- +# +# 03Sep06RT - fixes +# - "-return" in named gradient proc +# - braces all expressions +# - removed to [expr ... calls in side if {..} +# - recode polygon helper switch pattern in ::coords (bug fix same as v0.1) +# +# Various support procedures for the tkpath package. +# +# Copyright (c) 2005-2008 Mats Bengtsson +# +# $Id: tkpath.tcl,v 1.15 2008/06/04 14:08:21 matben Exp $ + +namespace eval ::tkp {} + + +# ::tkp::transform -- +# +# Helper for designing the -matrix option from simpler transformations. +# +# Arguments: +# cmd any of rotate, scale, skewx, skewy, or translate +# +# Results: +# a transformation matrix + +proc ::tkp::transform {cmd args} { + + set len [llength $args] + + switch -- $cmd { + rotate { + if {($len != 1) && ($len != 3)} { + return -code error "usage: transform rotate angle ?centerX centerY?" + } + set phi [lindex $args 0] + set cosPhi [expr {cos($phi)}] + set sinPhi [expr {sin($phi)}] + set msinPhi [expr {-1.0*$sinPhi}] + if {$len == 1} { + set matrix \ + [list [list $cosPhi $sinPhi] [list $msinPhi $cosPhi] {0 0}] + } elseif {$len == 3} { + set cx [lindex $args 1] + set cy [lindex $args 2] + set matrix [list \ + [list $cosPhi $sinPhi] \ + [list $msinPhi $cosPhi] \ + [list [expr {-$cx*$cosPhi + $cy*$sinPhi + $cx}] \ + [expr {-$cx*$sinPhi - $cy*$cosPhi + $cy}]]] + } + } + scale { + if {$len == 1} { + set sx [lindex $args 0] + set sy $sx + } elseif {$len == 2} { + set sx [lindex $args 0] + set sy [lindex $args 1] + } else { + return -code error "usage: transform scale s1 ?s2?" + } + set matrix [list [list $sx 0] [list 0 $sy] {0 0}] + } + skewx { + if {$len != 1} { + return -code error "usage: transform skewx angle" + } + set sinPhi [expr {sin([lindex $args 0])}] + set matrix [list {1 0} [list $sinPhi 1] {0 0}] + } + skewy { + if {$len != 1} { + return -code error "usage: transform skewy angle" + } + set sinPhi [expr {sin([lindex $args 0])}] + set matrix [list [list 1 $sinPhi] {0 1} {0 0}] + } + translate { + if {$len != 2} { + return -code error "usage: transform translate x y" + } + set matrix [list {1 0} {0 1} [lrange $args 0 1]] + } + default { + return -code error "unrecognized transform command: \"$cmd\"" + } + } + return $matrix +} + +proc ::tkp::mmult {m1 m2} { + seteach {{a1 b1} {c1 d1} {tx1 ty1}} $m1 + seteach {{a2 b2} {c2 d2} {tx2 ty2}} $m2 + return [list \ + [list [expr {$a1*$a2 + $c1*$b2}] [expr {$b1*$a2 + $d1*$b2}]] \ + [list [expr {$a1*$c2 + $c1*$d2}] [expr {$b1*$c2 + $d1*$d2}]] \ + [list [expr {$a1*$tx2 + $c1*$ty2 + $tx1}] \ + [expr {$b1*$tx2 + $d1*$ty2 + $ty1}]]] +} + +# Function : seteach +# ------------------------------ ------------------------------ ---- +# Returns : - +# Parameters : +# Description : set a list of variables +# Written : 01/10/2007, Arndt Roger Schneider +# roger.schneider@addcom.de +# +# Rewritten : 09/24/2007, Roger -- for tkpath::mmult +# License : Tcl-License +# ------------------------------ ------------------------------ ---- + +proc ::tkp::seteach {variables arglist} { + foreach i $variables j $arglist { + set lgi [llength $i] + if {1 < $lgi && [llength $j] == $lgi} { + uplevel [list seteach $i $j] + } else { + uplevel [list set $i $j] + } + } +} + +# ::tkp::gradientstopsstyle -- +# +# Utility function to create named example gradient definitions. +# +# Arguments: +# name the name of the gradient +# args +# +# Results: +# the stops list. + +proc ::tkp::gradientstopsstyle {name args} { + + switch -- $name { + rainbow { + set stops { + {0.00 "#ff0000"} + {0.15 "#ff7f00"} + {0.30 "#ffff00"} + {0.45 "#00ff00"} + {0.65 "#0000ff"} + {0.90 "#7f00ff"} + {1.00 "#7f007f"} + } + return $stops + } + default { + return -code error "the named gradient \"$name\" is unknown" + } + } +} + +proc ::tkp::ellipsepath {x y rx ry} { + return "M $x $y a $rx $ry 0 1 1 0 [expr {2*$ry}] a $rx $ry 0 1 1 0 [expr {-2*$ry}] Z" +} + +proc ::tkp::circlepath {x y r} { + return [ellipsepath $x $y $r $r] +} + + diff --git a/pd/tkpath/macosx/PBExportedSymbols b/pd/tkpath/macosx/PBExportedSymbols new file mode 100755 index 0000000000000000000000000000000000000000..3965c3d4c6023fae83176e4d47e666c7f0c346e1 --- /dev/null +++ b/pd/tkpath/macosx/PBExportedSymbols @@ -0,0 +1,4 @@ +_Tkpath_Init +_Tkpath_SafeInit +_Tkpath_Unload +_Tkpath_SafeUnload diff --git a/pd/tkpath/macosx/build/pkgIndex.tcl b/pd/tkpath/macosx/build/pkgIndex.tcl new file mode 100644 index 0000000000000000000000000000000000000000..8b40ea86ec8daf53172d16eaf465313517c9c005 --- /dev/null +++ b/pd/tkpath/macosx/build/pkgIndex.tcl @@ -0,0 +1 @@ +package ifneeded QuickTimeTcl 3.1 [list load [file join $dir QuickTimeTcl3.1.dylib]] diff --git a/pd/tkpath/macosx/build/tkpath0.1.dylib b/pd/tkpath/macosx/build/tkpath0.1.dylib new file mode 100755 index 0000000000000000000000000000000000000000..3247af9a8303ccc3d1a28adbb6e2b4bb78059a7b Binary files /dev/null and b/pd/tkpath/macosx/build/tkpath0.1.dylib differ diff --git a/pd/tkpath/macosx/build/tkpath0.2.2.dylib b/pd/tkpath/macosx/build/tkpath0.2.2.dylib new file mode 100755 index 0000000000000000000000000000000000000000..7bb85b566eaf0f967b359b75b57707189d3951a4 Binary files /dev/null and b/pd/tkpath/macosx/build/tkpath0.2.2.dylib differ diff --git a/pd/tkpath/macosx/build/tkpath0.2.4.dylib b/pd/tkpath/macosx/build/tkpath0.2.4.dylib new file mode 100755 index 0000000000000000000000000000000000000000..da40e58755f3ec4f9f7283ce6dd48a3472cbc208 Binary files /dev/null and b/pd/tkpath/macosx/build/tkpath0.2.4.dylib differ diff --git a/pd/tkpath/macosx/build/tkpath0.2.6.dylib b/pd/tkpath/macosx/build/tkpath0.2.6.dylib new file mode 100755 index 0000000000000000000000000000000000000000..3545ad957634e2e598de51621174f97e4db558c6 Binary files /dev/null and b/pd/tkpath/macosx/build/tkpath0.2.6.dylib differ diff --git a/pd/tkpath/macosx/build/tkpath0.2.8.dylib b/pd/tkpath/macosx/build/tkpath0.2.8.dylib new file mode 100755 index 0000000000000000000000000000000000000000..ba0bba5b4483de76f487044164fdab682325e3ba Binary files /dev/null and b/pd/tkpath/macosx/build/tkpath0.2.8.dylib differ diff --git a/pd/tkpath/macosx/build/tkpath0.2.dylib b/pd/tkpath/macosx/build/tkpath0.2.dylib new file mode 100755 index 0000000000000000000000000000000000000000..a68ec9c742b40ca99d010970a2cbb8f1e7846792 Binary files /dev/null and b/pd/tkpath/macosx/build/tkpath0.2.dylib differ diff --git a/pd/tkpath/macosx/build/tkpath0.3.0.dylib b/pd/tkpath/macosx/build/tkpath0.3.0.dylib new file mode 100755 index 0000000000000000000000000000000000000000..13207ab32253c99594e93002f40b6e40abd0b3ac Binary files /dev/null and b/pd/tkpath/macosx/build/tkpath0.3.0.dylib differ diff --git a/pd/tkpath/macosx/build/tkpath0.3.1.dylib b/pd/tkpath/macosx/build/tkpath0.3.1.dylib new file mode 100755 index 0000000000000000000000000000000000000000..0fe2deaaa18580bfee93cff2beda42a72af3e8e1 Binary files /dev/null and b/pd/tkpath/macosx/build/tkpath0.3.1.dylib differ diff --git a/pd/tkpath/macosx/build/tkpathtk0.2.dylib b/pd/tkpath/macosx/build/tkpathtk0.2.dylib new file mode 100755 index 0000000000000000000000000000000000000000..874f18d6344eb8ce58fd2ceab7dd6927f1e19107 Binary files /dev/null and b/pd/tkpath/macosx/build/tkpathtk0.2.dylib differ diff --git a/pd/tkpath/macosx/pkgIndex.tcl b/pd/tkpath/macosx/pkgIndex.tcl new file mode 100755 index 0000000000000000000000000000000000000000..8b40ea86ec8daf53172d16eaf465313517c9c005 --- /dev/null +++ b/pd/tkpath/macosx/pkgIndex.tcl @@ -0,0 +1 @@ +package ifneeded QuickTimeTcl 3.1 [list load [file join $dir QuickTimeTcl3.1.dylib]] diff --git a/pd/tkpath/macosx/tkMacOSXPath.c b/pd/tkpath/macosx/tkMacOSXPath.c new file mode 100644 index 0000000000000000000000000000000000000000..792f411cee29d48212de75cb7bedd8133a3a74aa --- /dev/null +++ b/pd/tkpath/macosx/tkMacOSXPath.c @@ -0,0 +1,1049 @@ +/* + * tkMacOSXPath.c -- + * + * This file implements path drawing API's using CoreGraphics on Mac OS X. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * $Id: tkMacOSXPath.c,v 1.62 2010/04/30 10:16:00 ebrunel Exp $ + * + */ + +/* This should go into configure.in but don't know how. */ +#ifdef USE_PANIC_ON_PHOTO_ALLOC_FAILURE +#undef USE_PANIC_ON_PHOTO_ALLOC_FAILURE +#endif + +#include "tkMacOSXInt.h" +#include "tkIntPath.h" + +/* Seems to work for both Endians. */ +#define BlueFloatFromXColorPtr(xc) (float) ((((xc)->pixel >> 0) & 0xFF)) / 255.0 +#define GreenFloatFromXColorPtr(xc) (float) ((((xc)->pixel >> 8) & 0xFF)) / 255.0 +#define RedFloatFromXColorPtr(xc) (float) ((((xc)->pixel >> 16) & 0xFF)) / 255.0 + +#ifndef FloatToFixed +#define FloatToFixed(a) ((Fixed)((float) (a) * fixed1)) +#endif + +extern int gAntiAlias; +extern int gSurfaceCopyPremultiplyAlpha; +extern int gDepixelize; + +/* For debugging. */ +extern Tcl_Interp *gInterp; + +const float kValidDomain[2] = {0, 1}; +const float kValidRange[8] = {0, 1, 0, 1, 0, 1, 0, 1}; + +/* + * This is used as a place holder for platform dependent stuff between each call. + */ +typedef struct TkPathContext_ { + CGContextRef c; + CGrafPtr port; /* QD graphics port, NULL for bitmaps. */ + char *data; /* bitmap data, NULL for windows. */ + int widthCode; /* Used to depixelize the strokes: + * 0: not integer width + * 1: odd integer width + * 2: even integer width */ +} TkPathContext_; + +typedef struct PathATSUIRecord { + ATSUStyle atsuStyle; + ATSUTextLayout atsuLayout; + UniChar *buffer; /* @@@ Not sure this needs to be cached! */ +} PathATSUIRecord; + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXGetClipRgn -- + * + * Get the clipping region needed to restrict drawing to the given + * drawable. + * + * Results: + * Clipping region. If non-NULL, CFRelease it when done. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +HIShapeRef +TkMacOSXGetClipRgn( + Drawable drawable) /* Drawable. */ +{ + MacDrawable *macDraw = (MacDrawable *) drawable; + HIShapeRef clipRgn = NULL; + CGRect r; + + if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) { + TkMacOSXUpdateClipRgn(macDraw->winPtr); +#ifdef TK_MAC_DEBUG_DRAWING + TkMacOSXDbgMsg("%s visRgn ", macDraw->winPtr->pathName); + TkMacOSXDebugFlashRegion(drawable, macDraw->visRgn); +#endif /* TK_MAC_DEBUG_DRAWING */ + } + + if (macDraw->flags & TK_CLIPPED_DRAW) { + r = CGRectOffset(macDraw->drawRect, macDraw->xOff, macDraw->yOff); + } + if (macDraw->visRgn) { + if (macDraw->flags & TK_CLIPPED_DRAW) { + HIShapeRef rgn = HIShapeCreateWithRect(&r); + + clipRgn = HIShapeCreateIntersection(macDraw->visRgn, rgn); + CFRelease(rgn); + } else { + clipRgn = HIShapeCreateCopy(macDraw->visRgn); + } + } else if (macDraw->flags & TK_CLIPPED_DRAW) { + clipRgn = HIShapeCreateWithRect(&r); + } +#ifdef TK_MAC_DEBUG_DRAWING + TkMacOSXDbgMsg("%s clipRgn ", macDraw->winPtr->pathName); + TkMacOSXDebugFlashRegion(drawable, clipRgn); +#endif /* TK_MAC_DEBUG_DRAWING */ + + return clipRgn; +} + +void +PathSetUpCGContext( + Drawable d, + CGContextRef *contextPtr) +{ + CGContextRef context; + CGrafPtr port; + Rect bounds; + MacDrawable *macDraw = (MacDrawable *) d; + + port = TkMacOSXGetDrawablePort(d); +#ifdef TKPATH_AQUA_USE_CACHED_CONTEXT + // Seems that the CG context is cached in MacDrawable but don't know how it works! + context = macDraw->context; +#else + OSStatus err; + err = QDBeginCGContext(port, &context); + if (err != noErr) { + Tcl_Panic("QDBeginCGContext(): context failed !"); + } + *contextPtr = context; + + /* http://developer.apple.com/qa/qa2001/qa1010.html */ + SyncCGContextOriginWithPort(context, port); +#endif + + HIShapeRef clipRgn; + clipRgn = TkMacOSXGetClipRgn(d); + + /* + * Core Graphics defines the origin to be the bottom left + * corner of the CGContext and the positive y-axis points up. + * Move the origin and flip the y-axis for all subsequent + * Core Graphics drawing operations. + */ + CGContextSaveGState(context); + GetPortBounds(port, &bounds); + CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0, + -1.0, 0.0, bounds.bottom - bounds.top)); + + HIShapeReplacePathInCGContext(clipRgn, context); + CGContextEOClip(context); + CFRelease(clipRgn); + + CGContextTranslateCTM(context, macDraw->xOff, macDraw->yOff); + + CGContextSetShouldAntialias(context, gAntiAlias); + CGContextSetInterpolationQuality(context, kCGInterpolationHigh); +} + +void +PathReleaseCGContext( + CGrafPtr destPort, + CGContextRef context) +{ + CGContextRestoreGState(context); +#ifndef TKPATH_AQUA_USE_CACHED_CONTEXT + if (destPort) { + QDEndCGContext(destPort, &context); + } +#endif +} + +CGColorSpaceRef GetTheColorSpaceRef(void) +{ + static CGColorSpaceRef deviceRGB = NULL; + if (deviceRGB == NULL) { + deviceRGB = CGColorSpaceCreateDeviceRGB(); + } + return deviceRGB; +} + +#if 0 // 10.3 +/* Cache some common colors to speed things up. */ +typedef struct LookupColor { + int from; + CGColorRef colorRef; +} LookupTable; +static LookupColor ColorTable[] = { + +}; +void +PreallocateColorRefs(void) +{ + +} +#endif + +static LookupTable LineCapStyleLookupTable[] = { + {CapNotLast, kCGLineCapButt}, + {CapButt, kCGLineCapButt}, + {CapRound, kCGLineCapRound}, + {CapProjecting, kCGLineCapSquare} +}; + +static LookupTable LineJoinStyleLookupTable[] = { + {JoinMiter, kCGLineJoinMiter}, + {JoinRound, kCGLineJoinRound}, + {JoinBevel, kCGLineJoinBevel} +}; + +void +PathSetCGContextStyle(CGContextRef c, Tk_PathStyle *style) +{ + Tk_PathDash *dashPtr; + int fill = 0, stroke = 0; + + /** Drawing attribute functions. **/ + + /* Set the line width in the current graphics state to `width'. */ + CGContextSetLineWidth(c, style->strokeWidth); + + /* Set the line cap in the current graphics state to `cap'. */ + CGContextSetLineCap(c, + TableLookup(LineCapStyleLookupTable, 4, style->capStyle)); + + /* Set the line join in the current graphics state to `join'. */ + CGContextSetLineJoin(c, + TableLookup(LineJoinStyleLookupTable, 3, style->joinStyle)); + + /* Set the miter limit in the current graphics state to `limit'. */ + CGContextSetMiterLimit(c, style->miterLimit); + + /* Set the line dash patttern in the current graphics state. */ + dashPtr = style->dashPtr; + if ((dashPtr != NULL) && (dashPtr->number != 0)) { + CGContextSetLineDash(c, 0.0, dashPtr->array, dashPtr->number); + } + + /* Set the current fill colorspace in the context `c' to `DeviceRGB' and + * set the components of the current fill color to `(red, green, blue, + * alpha)'. */ + if (GetColorFromPathColor(style->fill) != NULL) { + fill = 1; + CGContextSetRGBFillColor(c, + RedFloatFromXColorPtr(style->fill->color), + GreenFloatFromXColorPtr(style->fill->color), + BlueFloatFromXColorPtr(style->fill->color), + style->fillOpacity); + } + + /* Set the current stroke colorspace in the context `c' to `DeviceRGB' and + * set the components of the current stroke color to `(red, green, blue, + * alpha)'. */ + if (style->strokeColor != NULL) { + stroke = 1; + CGContextSetRGBStrokeColor(c, + RedFloatFromXColorPtr(style->strokeColor), + GreenFloatFromXColorPtr(style->strokeColor), + BlueFloatFromXColorPtr(style->strokeColor), + style->strokeOpacity); + } + if (stroke && fill) { + CGContextSetTextDrawingMode(c, kCGTextFillStroke); + } else if (stroke) { + CGContextSetTextDrawingMode(c, kCGTextStroke); + } else if (fill) { + CGContextSetTextDrawingMode(c, kCGTextFill); + } +} + +/* Various ATSUI support functions. */ + +static OSStatus +CreateATSUIStyle(const char *fontFamily, float fontSize, ATSUStyle *atsuStylePtr) +{ + OSStatus err = noErr; + ATSUStyle style; + ATSUFontID atsuFont; + Fixed atsuSize; + static const ATSUAttributeTag tags[] = { + kATSUFontTag, kATSUSizeTag, + kATSUQDBoldfaceTag, kATSUQDItalicTag, kATSUQDUnderlineTag // @@@ didn't help. + }; + static const ByteCount sizes[] = { + sizeof(ATSUFontID), sizeof(Fixed), + sizeof(Boolean), sizeof(Boolean), sizeof(Boolean) + }; + Boolean isBold = 0, isUnderline = 0, isItalic = 0; + const ATSUAttributeValuePtr values[] = { + &atsuFont, &atsuSize, + &isBold, &isItalic, &isUnderline + }; + + *atsuStylePtr = NULL; + style = NULL; + atsuFont = 0; + atsuSize = FloatToFixed(fontSize); + { + /* This is old QuickDraw code. */ + FMFontFamily iFontFamily; + FMFontStyle fbStyle; + Str255 str; + + str[0] = strlen(fontFamily); + strcpy(str+1, fontFamily); + iFontFamily = FMGetFontFamilyFromName(str); + err = FMGetFontFromFontFamilyInstance(iFontFamily, 0, &atsuFont, &fbStyle); + } +#if 0 // fonts come out with bold/italic? + { + err = ATSUFindFontFromName((Ptr) fontFamily, strlen(fontFamily), kFontFamilyName, + kFontNoPlatformCode, kFontNoScriptCode, kFontNoLanguageCode, &atsuFont); + } +#endif + if (err != noErr) { + return err; + } + err = ATSUCreateStyle(&style); + if (err != noErr) { + if (style) ATSUDisposeStyle(style); + return err; + } + err = ATSUSetAttributes(style, sizeof(tags)/sizeof(tags[0]), + tags, sizes, values); + if (err != noErr) { + if (style) ATSUDisposeStyle(style); + return err; + } + *atsuStylePtr = style; + return noErr; +} + +static OSStatus +CreateLayoutForString(UniChar *buffer, CFIndex length, ATSUStyle atsuStyle, ATSUTextLayout *layoutPtr) +{ + ATSUTextLayout layout = NULL; + OSStatus err = noErr; + + *layoutPtr = NULL; + err = ATSUCreateTextLayoutWithTextPtr(buffer, 0, + length, length, 1, (unsigned long *) &length, &atsuStyle, &layout); + if (err == noErr) { + *layoutPtr = layout; + } + ATSUSetTransientFontMatching(layout, true); + return err; +} + +/* === EB - 23-apr-2010: added function to register coordinate offsets; unneeded here (?) */ +void TkPathSetCoordOffsets(double dx, double dy) +{ +} +/* === */ + +TkPathContext +TkPathInit(Tk_Window tkwin, Drawable d) +{ + CGContextRef cgContext; + TkPathContext_ *context = (TkPathContext_ *) ckalloc(sizeof(TkPathContext_)); + + PathSetUpCGContext(d, &cgContext); + context->c = cgContext; + context->port = TkMacOSXGetDrawablePort(d); + context->data = NULL; + context->widthCode = 0; + return (TkPathContext) context; +} + +TkPathContext +TkPathInitSurface(int width, int height) +{ + CGContextRef cgContext; + TkPathContext_ *context = (TkPathContext_ *) ckalloc((unsigned) (sizeof(TkPathContext_))); + size_t bytesPerRow; + char *data; + + // Move up into own function + + bytesPerRow = 4*width; + /* Round up to nearest multiple of 16 */ + bytesPerRow = (bytesPerRow + (16-1)) & ~(16-1); + data = ckalloc(height*bytesPerRow); + + /* Make it RGBA with 32 bit depth. */ + cgContext = CGBitmapContextCreate(data, width, height, 8, bytesPerRow, + GetTheColorSpaceRef(), kCGImageAlphaPremultipliedLast); + if (cgContext == NULL) { + ckfree((char *) context); + return (TkPathContext) NULL; + } + CGContextClearRect(cgContext, CGRectMake(0, 0, width, height)); + CGContextTranslateCTM(cgContext, 0, height); + CGContextScaleCTM(cgContext, 1, -1); + context->c = cgContext; + context->port = NULL; + context->data = data; + return (TkPathContext) context; +} + +void +TkPathPushTMatrix(TkPathContext ctx, TMatrix *mPtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGAffineTransform transform; + + if (mPtr == NULL) { + return; + } + /* Return the transform [ a b c d tx ty ]. */ + transform = CGAffineTransformMake( + (float) mPtr->a, (float) mPtr->b, + (float) mPtr->c, (float) mPtr->d, + (float) mPtr->tx, (float) mPtr->ty); + CGContextConcatCTM(context->c, transform); +} + +void +TkPathSaveState(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGContextSaveGState(context->c); +} + +void +TkPathRestoreState(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGContextRestoreGState(context->c); +} + +void +TkPathBeginPath(TkPathContext ctx, Tk_PathStyle *stylePtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + int nint; + double width; + CGContextBeginPath(context->c); + PathSetCGContextStyle(context->c, stylePtr); + if (stylePtr->strokeColor == NULL) { + context->widthCode = 0; + } else { + width = stylePtr->strokeWidth; + nint = (int) (width + 0.5); + context->widthCode = fabs(width - nint) > 0.01 ? 0 : 2 - nint % 2; + } +} + +void +TkPathMoveTo(TkPathContext ctx, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + CGContextMoveToPoint(context->c, x, y); +} + +void +TkPathLineTo(TkPathContext ctx, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + CGContextAddLineToPoint(context->c, x, y); +} + +void +TkPathLinesTo(TkPathContext ctx, double *pts, int n) +{ + //TkPathContext_ *context = (TkPathContext_ *) ctx; + /* Add a set of lines to the context's path. */ + //CGContextAddLines(context->c, const CGPoint points[], size_t count); +} + +void +TkPathQuadBezier(TkPathContext ctx, double ctrlX, double ctrlY, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + CGContextAddQuadCurveToPoint(context->c, ctrlX, ctrlY, x, y); +} + +void +TkPathCurveTo(TkPathContext ctx, double ctrlX1, double ctrlY1, + double ctrlX2, double ctrlY2, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + CGContextAddCurveToPoint(context->c, ctrlX1, ctrlY1, ctrlX2, ctrlY2, x, y); +} + +void +TkPathArcTo(TkPathContext ctx, + double rx, double ry, + double phiDegrees, /* The rotation angle in degrees! */ + char largeArcFlag, char sweepFlag, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + // @@@ Should we try to use the native arc functions here? + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + TkPathArcToUsingBezier(ctx, rx, ry, phiDegrees, largeArcFlag, sweepFlag, x, y); +} + +void +TkPathRect(TkPathContext ctx, double x, double y, double width, double height) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGRect r; + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + r = CGRectMake(x, y, width, height); + CGContextAddRect(context->c, r); +} + +void +TkPathOval(TkPathContext ctx, double cx, double cy, double rx, double ry) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + +#if 0 // 10.4 + if (&CGContextAddEllipseInRect != NULL) { + CGRect r; + r = CGRectMake(cx-rx, cy-ry, 2*rx, 2*ry); + CGContextAddEllipseInRect(context->c, r); + } else { +#endif + if (rx == ry) { + CGContextMoveToPoint(context->c, cx+rx, cy); + CGContextAddArc(context->c, cx, cy, rx, 0.0, 2*M_PI, 1); + CGContextClosePath(context->c); + } else { + CGContextSaveGState(context->c); + CGContextTranslateCTM(context->c, cx, cy); + CGContextScaleCTM(context->c, rx, ry); + CGContextMoveToPoint(context->c, 1, 0); + CGContextAddArc(context->c, 0.0, 0.0, 1.0, 0.0, 2*M_PI, 1); + CGContextRestoreGState(context->c); + CGContextClosePath(context->c); + } +} + +void +TkPathImage(TkPathContext ctx, Tk_Image image, Tk_PhotoHandle photo, + double x, double y, double width, double height) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGImageRef cgImage; + CGDataProviderRef provider; + CGColorSpaceRef colorspace; + CGImageAlphaInfo alphaInfo; + size_t size; + Tk_PhotoImageBlock block; + + /* Return value? */ + Tk_PhotoGetImage(photo, &block); + size = block.pitch * block.height; + + /* + * The offset array contains the offsets from the address of a pixel to + * the addresses of the bytes containing the red, green, blue and alpha + * (transparency) components. These are normally 0, 1, 2 and 3. + * @@@ There are more cases to consider than these! + */ + if (block.offset[3] == 3) { + alphaInfo = kCGImageAlphaLast; + } else if (block.offset[3] == 0) { + alphaInfo = kCGImageAlphaFirst; + } else { + /* @@@ What to do here? */ + return; + } + provider = CGDataProviderCreateWithData(NULL, block.pixelPtr, size, NULL); + colorspace = CGColorSpaceCreateDeviceRGB(); + cgImage = CGImageCreate(block.width, block.height, + 8, /* bitsPerComponent */ + block.pixelSize*8, /* bitsPerPixel */ + block.pitch, /* bytesPerRow */ + colorspace, /* colorspace */ + alphaInfo, /* alphaInfo */ + provider, NULL, + 1, /* shouldInterpolate */ + kCGRenderingIntentDefault); + CGDataProviderRelease(provider); + CGColorSpaceRelease(colorspace); + if (width == 0.0) { + width = (double) block.width; + } + if (height == 0.0) { + height = (double) block.height; + } + + /* Flip back to an upright coordinate system since CGContextDrawImage expect this. */ + CGContextSaveGState(context->c); + CGContextTranslateCTM(context->c, x, y+height); + CGContextScaleCTM(context->c, 1, -1); + CGContextDrawImage(context->c, CGRectMake(0.0, 0.0, width, height), cgImage); + CGImageRelease(cgImage); + CGContextRestoreGState(context->c); +} + +void +TkPathClosePath(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGContextClosePath(context->c); +} + +// @@@ Problems: don't want Tcl_Interp, finding matching font not while processing options. +// Separate font style from layout??? + +int +TkPathTextConfig(Tcl_Interp *interp, Tk_PathTextStyle *textStylePtr, char *utf8, void **customPtr) +{ + PathATSUIRecord *recordPtr; + ATSUStyle atsuStyle = NULL; + ATSUTextLayout atsuLayout = NULL; + CFStringRef cf; + UniChar *buffer; + CFRange range; + CFIndex length; + OSStatus err; + + if (utf8 == NULL) { + return TCL_OK; + } + TkPathTextFree(textStylePtr, *customPtr); + + cf = CFStringCreateWithCString(NULL, utf8, kCFStringEncodingUTF8); + length = CFStringGetLength(cf); + if (length == 0) { + return TCL_OK; + } + range = CFRangeMake(0, length); + err = CreateATSUIStyle(textStylePtr->fontFamily, textStylePtr->fontSize, &atsuStyle); + if (err != noErr) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("font style couldn't be created", -1)); + return TCL_ERROR; + } + buffer = (UniChar *) ckalloc(length * sizeof(UniChar)); + CFStringGetCharacters(cf, range, buffer); + err = CreateLayoutForString(buffer, length, atsuStyle, &atsuLayout); + CFRelease(cf); + if (err != noErr) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("text layout couldn't be created", -1)); + ckfree((char *)buffer); + return TCL_ERROR; + } + recordPtr = (PathATSUIRecord *) ckalloc(sizeof(PathATSUIRecord)); + recordPtr->atsuStyle = atsuStyle; + recordPtr->atsuLayout = atsuLayout; + recordPtr->buffer = buffer; + *customPtr = (PathATSUIRecord *) recordPtr; + return TCL_OK; +} + +void +TkPathTextDraw(TkPathContext ctx, Tk_PathStyle *style, Tk_PathTextStyle *textStylePtr, + double x, double y, char *utf8, void *custom) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + PathATSUIRecord *recordPtr = (PathATSUIRecord *) custom; + ByteCount iSize = sizeof(CGContextRef); + ATSUAttributeTag iTag = kATSUCGContextTag; + ATSUAttributeValuePtr iValuePtr = &(context->c); + + ATSUSetLayoutControls(recordPtr->atsuLayout, 1, &iTag, &iSize, &iValuePtr); + CGContextSaveGState(context->c); + CGContextTranslateCTM(context->c, x, y); + CGContextScaleCTM(context->c, 1, -1); + ATSUDrawText(recordPtr->atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd, 0, 0); + CGContextRestoreGState(context->c); +} + +void +TkPathTextFree(Tk_PathTextStyle *textStylePtr, void *custom) +{ + PathATSUIRecord *recordPtr = (PathATSUIRecord *) custom; + if (recordPtr) { + if (recordPtr->atsuStyle) { + ATSUDisposeStyle(recordPtr->atsuStyle); + } + if (recordPtr->atsuLayout) { + ATSUDisposeTextLayout(recordPtr->atsuLayout); + } + if (recordPtr->buffer) { + ckfree((char *) recordPtr->buffer); + } + } +} + +PathRect +TkPathTextMeasureBbox(Tk_PathTextStyle *textStylePtr, char *utf8, void *custom) +{ + PathATSUIRecord *recordPtr = (PathATSUIRecord *) custom; + PathRect r; + + /* + * See Apple header ATSUnicodeDrawing.h for the difference + * between these two. Brief: ATSUMeasureTextImage considers + * the actual inked rect only. + */ +#if 0 + ATSTrapezoid b; + ItemCount numBounds; + + b.upperRight.x = b.upperLeft.x = 0; + ATSUGetGlyphBounds(recordPtr->atsuLayout, 0, 0, + kATSUFromTextBeginning, kATSUToTextEnd, + kATSUseFractionalOrigins, 1, &b, &numBounds); + r.x1 = MIN(Fix2X(b.upperLeft.x), Fix2X(b.lowerLeft.x)); + r.y1 = MIN(Fix2X(b.upperLeft.y), Fix2X(b.upperRight.y)); + r.x2 = MAX(Fix2X(b.upperRight.x), Fix2X(b.lowerRight.x)); + r.y2 = MAX(Fix2X(b.lowerLeft.y), Fix2X(b.lowerRight.y)); +#else + Rect rect; + + ATSUMeasureTextImage(recordPtr->atsuLayout, + kATSUFromTextBeginning, kATSUToTextEnd, 0, 0, &rect); + r.x1 = rect.left; + r.y1 = rect.top; + r.x2 = rect.right; + r.y2 = rect.bottom; +#endif + return r; +} + +void +TkPathSurfaceErase(TkPathContext ctx, double x, double y, double width, double height) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGContextClearRect(context->c, CGRectMake(x, y, width, height)); +} + +void +TkPathSurfaceToPhoto(Tcl_Interp *interp, TkPathContext ctx, Tk_PhotoHandle photo) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGContextRef c = context->c; + Tk_PhotoImageBlock block; + unsigned char *data; + unsigned char *pixel; + int width, height; + int bytesPerRow; + + width = CGBitmapContextGetWidth(c); + height = CGBitmapContextGetHeight(c); + data = CGBitmapContextGetData(c); + bytesPerRow = CGBitmapContextGetBytesPerRow(c); + + Tk_PhotoGetImage(photo, &block); + pixel = (unsigned char *) ckalloc(height*bytesPerRow); + if (gSurfaceCopyPremultiplyAlpha) { + PathCopyBitsPremultipliedAlphaRGBA(data, pixel, width, height, bytesPerRow); + } else { + memcpy(pixel, data, height*bytesPerRow); + } + block.pixelPtr = pixel; + block.width = width; + block.height = height; + block.pitch = bytesPerRow; + block.pixelSize = 4; + block.offset[0] = 0; + block.offset[1] = 1; + block.offset[2] = 2; + block.offset[3] = 3; + // Should change this to check for errors... + Tk_PhotoPutBlock(interp, photo, &block, 0, 0, width, height, TK_PHOTO_COMPOSITE_OVERLAY); +} + +void +TkPathClipToPath(TkPathContext ctx, int fillRule) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + + /* If you need to grow the clipping path after it’s shrunk, you must save the + * graphics state before you clip, then restore the graphics state to restore the current + * clipping path. */ + CGContextSaveGState(context->c); + if (fillRule == WindingRule) { + CGContextClip(context->c); + } else if (fillRule == EvenOddRule) { + CGContextEOClip(context->c); + } +} + +void +TkPathReleaseClipToPath(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGContextRestoreGState(context->c); +} + +void +TkPathStroke(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGContextStrokePath(context->c); +} + +void +TkPathFill(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (style->fillRule == WindingRule) { + CGContextFillPath(context->c); + } else if (style->fillRule == EvenOddRule) { + CGContextEOFillPath(context->c); + } +} + +void +TkPathFillAndStroke(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (style->fillRule == WindingRule) { + CGContextDrawPath(context->c, kCGPathFillStroke); + } else if (style->fillRule == EvenOddRule) { + CGContextDrawPath(context->c, kCGPathEOFillStroke); + } +} + +void +TkPathEndPath(TkPathContext ctx) +{ + //TkPathContext_ *context = (TkPathContext_ *) ctx; + /* Empty ??? */ +} + +void +TkPathFree(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; +#ifdef TKPATH_AQUA_USE_DRAWABLE_CONTEXT + +#else + PathReleaseCGContext(context->port, context->c); +#endif + if (context->data) { + ckfree(context->data); + } + ckfree((char *) ctx); +} + +int +TkPathDrawingDestroysPath(void) +{ + return 1; +} + +int +TkPathPixelAlign(void) +{ + return 0; +} + +/* TkPathGetCurrentPosition -- + * + * Returns the current pen position in untransformed coordinates! + */ + +int +TkPathGetCurrentPosition(TkPathContext ctx, PathPoint *ptPtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGPoint cgpt; + + cgpt = CGContextGetPathCurrentPoint(context->c); + ptPtr->x = cgpt.x; + ptPtr->y = cgpt.y; + return TCL_OK; +} + +int +TkPathBoundingBox(TkPathContext ctx, PathRect *rPtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGRect cgRect; + + /* This one is not very useful since it includes the control points. */ + cgRect = CGContextGetPathBoundingBox(context->c); + rPtr->x1 = cgRect.origin.x; + rPtr->y1 = cgRect.origin.y; + rPtr->x2 = cgRect.origin.x + cgRect.size.width; + rPtr->y2 = cgRect.origin.y + cgRect.size.height; + return TCL_OK; +} + +/* + * Using CGShading for fill gradients. + */ + +static void +ShadeEvaluate(void *info, const float *in, float *out) +{ + GradientStopArray *stopArrPtr = (GradientStopArray *) info; + GradientStop **stopPtrPtr = stopArrPtr->stops; + GradientStop *stop1 = NULL, *stop2 = NULL; + int nstops = stopArrPtr->nstops; + int i = 0; + float par = *in; + float f1, f2; + + /* Find the two stops for this point. Tricky! */ + while ((i < nstops) && ((*stopPtrPtr)->offset < par)) { + stopPtrPtr++, i++; + } + if (i == 0) { + /* First stop > 0. */ + stop1 = *stopPtrPtr; + stop2 = stop1; + } else if (i == nstops) { + /* We have stepped beyond the last stop; step back! */ + stop1 = *(stopPtrPtr - 1); + stop2 = stop1; + } else { + stop1 = *(stopPtrPtr - 1); + stop2 = *stopPtrPtr; + } + /* Interpolate between the two stops. + * "If two gradient stops have the same offset value, + * then the latter gradient stop controls the color value at the + * overlap point." + */ + if (fabs(stop2->offset - stop1->offset) < 1e-6) { + *out++ = RedFloatFromXColorPtr(stop2->color); + *out++ = GreenFloatFromXColorPtr(stop2->color); + *out++ = BlueFloatFromXColorPtr(stop2->color); + *out++ = stop2->opacity; + } else { + f1 = (stop2->offset - par)/(stop2->offset - stop1->offset); + f2 = (par - stop1->offset)/(stop2->offset - stop1->offset); + *out++ = f1 * RedFloatFromXColorPtr(stop1->color) + + f2 * RedFloatFromXColorPtr(stop2->color); + *out++ = f1 * GreenFloatFromXColorPtr(stop1->color) + + f2 * GreenFloatFromXColorPtr(stop2->color); + *out++ = f1 * BlueFloatFromXColorPtr(stop1->color) + + f2 * BlueFloatFromXColorPtr(stop2->color); + *out++ = f1 * stop1->opacity + f2 * stop2->opacity; + } +} + +static void +ShadeRelease(void *info) +{ + /* Not sure if anything to do here. */ +} + +void +TkPathPaintLinearGradient(TkPathContext ctx, PathRect *bbox, LinearGradientFill *fillPtr, int fillRule, TMatrix *mPtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGShadingRef shading; + CGPoint start, end; + CGColorSpaceRef colorSpaceRef; + CGFunctionRef function; + CGFunctionCallbacks callbacks; + PathRect *trans = fillPtr->transitionPtr; /* The transition line. */ + GradientStopArray *stopArrPtr = fillPtr->stopArrPtr; + + callbacks.version = 0; + callbacks.evaluate = ShadeEvaluate; + callbacks.releaseInfo = ShadeRelease; + colorSpaceRef = CGColorSpaceCreateDeviceRGB(); + + /* + * We need to do like this since this is how SVG defines gradient drawing + * in case the transition vector is in relative coordinates. + */ + CGContextSaveGState(context->c); + if (fillPtr->units == kPathGradientUnitsBoundingBox) { + CGContextTranslateCTM(context->c, bbox->x1, bbox->y1); + CGContextScaleCTM(context->c, bbox->x2 - bbox->x1, bbox->y2 - bbox->y1); + } + function = CGFunctionCreate((void *) stopArrPtr, 1, kValidDomain, 4, kValidRange, &callbacks); + start = CGPointMake(trans->x1, trans->y1); + end = CGPointMake(trans->x2, trans->y2); + shading = CGShadingCreateAxial(colorSpaceRef, start, end, function, 1, 1); + if (mPtr) { + /* @@@ I'm not completely sure of the order of transforms here! */ + TkPathPushTMatrix(ctx, mPtr); + } + CGContextDrawShading(context->c, shading); + CGContextRestoreGState(context->c); + CGShadingRelease(shading); + CGFunctionRelease(function); + CGColorSpaceRelease(colorSpaceRef); +} + +void +TkPathPaintRadialGradient(TkPathContext ctx, PathRect *bbox, RadialGradientFill *fillPtr, int fillRule, TMatrix *mPtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CGShadingRef shading; + CGPoint start, end; + CGColorSpaceRef colorSpaceRef; + CGFunctionRef function; + CGFunctionCallbacks callbacks; + RadialTransition *tPtr = fillPtr->radialPtr; + GradientStopArray *stopArrPtr = fillPtr->stopArrPtr; + + callbacks.version = 0; + callbacks.evaluate = ShadeEvaluate; + callbacks.releaseInfo = ShadeRelease; + colorSpaceRef = CGColorSpaceCreateDeviceRGB(); + + /* + * We need to do like this since this is how SVG defines gradient drawing + * in case the transition vector is in relative coordinates. + */ + if (fillPtr->units == kPathGradientUnitsBoundingBox) { + CGContextSaveGState(context->c); + CGContextTranslateCTM(context->c, bbox->x1, bbox->y1); + CGContextScaleCTM(context->c, bbox->x2 - bbox->x1, bbox->y2 - bbox->y1); + } + function = CGFunctionCreate((void *) stopArrPtr, 1, kValidDomain, 4, kValidRange, &callbacks); + start = CGPointMake(tPtr->focalX, tPtr->focalY); + end = CGPointMake(tPtr->centerX, tPtr->centerY); + shading = CGShadingCreateRadial(colorSpaceRef, start, 0.0, end, tPtr->radius, function, 1, 1); + if (mPtr) { + /* @@@ I'm not completely sure of the order of transforms here! */ + TkPathPushTMatrix(ctx, mPtr); + } + CGContextDrawShading(context->c, shading); + CGShadingRelease(shading); + CGFunctionRelease(function); + CGColorSpaceRelease(colorSpaceRef); + if (fillPtr->units == kPathGradientUnitsBoundingBox) { + CGContextRestoreGState(context->c); + } +} + diff --git a/pd/tkpath/macosx/tkpath.xcodeproj/project.pbxproj b/pd/tkpath/macosx/tkpath.xcodeproj/project.pbxproj new file mode 100755 index 0000000000000000000000000000000000000000..e2a86cd8d4ae29ea283e7e90ef185cd2ee7a73e2 --- /dev/null +++ b/pd/tkpath/macosx/tkpath.xcodeproj/project.pbxproj @@ -0,0 +1,580 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 496353F80D4CCE3C00A7B7DA /* tkCanvGroup.c in Sources */ = {isa = PBXBuildFile; fileRef = 496353F70D4CCE3C00A7B7DA /* tkCanvGroup.c */; }; + 4964DC250D4333A90050C442 /* tkpUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 4964DC240D4333A90050C442 /* tkpUtil.c */; }; + 4964E76E0D41D3730030426E /* tkpTrig.c in Sources */ = {isa = PBXBuildFile; fileRef = 4964E76D0D41D3730030426E /* tkpTrig.c */; }; + 496824A40DD5E65D000D7DA7 /* tkCanvGradient.c in Sources */ = {isa = PBXBuildFile; fileRef = 496824A30DD5E65D000D7DA7 /* tkCanvGradient.c */; }; + 496D9D750DE2B9BB002618BA /* tkCanvStyle.c in Sources */ = {isa = PBXBuildFile; fileRef = 496D9D740DE2B9BB002618BA /* tkCanvStyle.c */; }; + 49ECBBA40D3FA7C900A1FB4F /* tkp.h in Headers */ = {isa = PBXBuildFile; fileRef = 49ECBBA30D3FA7C900A1FB4F /* tkp.h */; }; + 49FA530A0D3CF52D00DE2BD2 /* tkIntPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AA1ECEA077FF7CC00A80065 /* tkIntPath.h */; }; + 49FA530B0D3CF52D00DE2BD2 /* tkPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AF2FEBB079410DB00AB783C /* tkPath.h */; }; + 49FA530C0D3CF52D00DE2BD2 /* tkCanvPathUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A66FCF40978E3400086B7B8 /* tkCanvPathUtil.h */; }; + 49FA530E0D3CF52D00DE2BD2 /* tkPathStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A96B2380B898CA800A80002 /* tkPathStyle.h */; }; + 49FA53100D3CF52D00DE2BD2 /* tkMacOSXPath.c in Sources */ = {isa = PBXBuildFile; fileRef = 9AA1ECE6077FF68100A80065 /* tkMacOSXPath.c */; }; + 49FA53110D3CF52D00DE2BD2 /* tkCanvPath.c in Sources */ = {isa = PBXBuildFile; fileRef = 9AA1ECE8077FF7BF00A80065 /* tkCanvPath.c */; }; + 49FA53120D3CF52D00DE2BD2 /* tkPathGradient.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A58E5420796814B00FBE143 /* tkPathGradient.c */; }; + 49FA53130D3CF52D00DE2BD2 /* tkPath.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A017ED6079FCCE100A80065 /* tkPath.c */; }; + 49FA53140D3CF52D00DE2BD2 /* path.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A56FF2807A234510091799F /* path.c */; }; + 49FA53150D3CF52D00DE2BD2 /* tkPathStyle.c in Sources */ = {isa = PBXBuildFile; fileRef = 9AA0B6C407DD8C9900A80065 /* tkPathStyle.c */; }; + 49FA53160D3CF52D00DE2BD2 /* tkPathUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A5BCDA007E2D8B400B6FA03 /* tkPathUtil.c */; }; + 49FA53180D3CF52D00DE2BD2 /* tkCanvPrect.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A66FCF20978D8050086B7B8 /* tkCanvPrect.c */; }; + 49FA53190D3CF52D00DE2BD2 /* tkCanvPathUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A5B17C7097BA957000B33B2 /* tkCanvPathUtil.c */; }; + 49FA531A0D3CF52D00DE2BD2 /* tkCanvPline.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A587F03098FA7870094E994 /* tkCanvPline.c */; }; + 49FA531B0D3CF52D00DE2BD2 /* tkCanvPimage.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A671A8F099DC683007AF773 /* tkCanvPimage.c */; }; + 49FA531C0D3CF52D00DE2BD2 /* tkCanvEllipse.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A6265BF09C474B3009A2B1E /* tkCanvEllipse.c */; }; + 49FA531D0D3CF52D00DE2BD2 /* tkCanvPpoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 9AB087D80A38001400A80065 /* tkCanvPpoly.c */; }; + 49FA531E0D3CF52D00DE2BD2 /* tkCanvPtext.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A5A2A920B45059700496554 /* tkCanvPtext.c */; }; + 49FA531F0D3CF52D00DE2BD2 /* tkPathSurface.c in Sources */ = {isa = PBXBuildFile; fileRef = 9AB6AB700B835DCD00A80002 /* tkPathSurface.c */; }; + 49FA53210D3CF52D00DE2BD2 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB77AAFE841565C02AAC07 /* Carbon.framework */; }; + 49FA53220D3CF52D00DE2BD2 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5564883038142E001A4FCC0 /* CoreServices.framework */; }; + 49FA53230D3CF52D00DE2BD2 /* libtclstub8.5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A57846A043C3778009A6529 /* libtclstub8.5.a */; }; + 49FA53240D3CF52D00DE2BD2 /* libtkstub8.5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A57846C043C37A8009A6529 /* libtkstub8.5.a */; }; + 49FA53410D3CF5DC00DE2BD2 /* tkpCanvArc.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA53350D3CF5DC00DE2BD2 /* tkpCanvArc.c */; }; + 49FA53420D3CF5DC00DE2BD2 /* tkpCanvas.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA53360D3CF5DC00DE2BD2 /* tkpCanvas.c */; }; + 49FA53430D3CF5DC00DE2BD2 /* tkpCanvas.h in Headers */ = {isa = PBXBuildFile; fileRef = 49FA53370D3CF5DC00DE2BD2 /* tkpCanvas.h */; }; + 49FA53440D3CF5DC00DE2BD2 /* tkpCanvBmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA53380D3CF5DC00DE2BD2 /* tkpCanvBmap.c */; }; + 49FA53450D3CF5DC00DE2BD2 /* tkpCanvImg.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA53390D3CF5DC00DE2BD2 /* tkpCanvImg.c */; }; + 49FA53460D3CF5DC00DE2BD2 /* tkpCanvLine.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA533A0D3CF5DC00DE2BD2 /* tkpCanvLine.c */; }; + 49FA53470D3CF5DC00DE2BD2 /* tkpCanvPoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA533B0D3CF5DC00DE2BD2 /* tkpCanvPoly.c */; }; + 49FA53480D3CF5DC00DE2BD2 /* tkpCanvPs.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA533C0D3CF5DC00DE2BD2 /* tkpCanvPs.c */; }; + 49FA53490D3CF5DC00DE2BD2 /* tkpCanvText.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA533D0D3CF5DC00DE2BD2 /* tkpCanvText.c */; }; + 49FA534A0D3CF5DC00DE2BD2 /* tkpCanvUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA533E0D3CF5DC00DE2BD2 /* tkpCanvUtil.c */; }; + 49FA534B0D3CF5DC00DE2BD2 /* tkpCanvWind.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA533F0D3CF5DC00DE2BD2 /* tkpCanvWind.c */; }; + 49FA534C0D3CF5DC00DE2BD2 /* tkpRectOval.c in Sources */ = {isa = PBXBuildFile; fileRef = 49FA53400D3CF5DC00DE2BD2 /* tkpRectOval.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 08FB77AAFE841565C02AAC07 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; }; + 496353F70D4CCE3C00A7B7DA /* tkCanvGroup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkCanvGroup.c; path = ../generic/tkCanvGroup.c; sourceTree = SOURCE_ROOT; }; + 4964DC240D4333A90050C442 /* tkpUtil.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkpUtil.c; path = ../generic/tkpUtil.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 4964E76D0D41D3730030426E /* tkpTrig.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkpTrig.c; path = ../generic/tkpTrig.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 496824A30DD5E65D000D7DA7 /* tkCanvGradient.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkCanvGradient.c; path = ../generic/tkCanvGradient.c; sourceTree = SOURCE_ROOT; }; + 496D9D740DE2B9BB002618BA /* tkCanvStyle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkCanvStyle.c; path = ../generic/tkCanvStyle.c; sourceTree = SOURCE_ROOT; }; + 49ECBBA30D3FA7C900A1FB4F /* tkp.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = tkp.h; path = ../generic/tkp.h; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 49FA532A0D3CF52D00DE2BD2 /* tkpath0.3.1.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = tkpath0.3.1.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + 49FA53350D3CF5DC00DE2BD2 /* tkpCanvArc.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkpCanvArc.c; path = ../generic/tkpCanvArc.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 49FA53360D3CF5DC00DE2BD2 /* tkpCanvas.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkpCanvas.c; path = ../generic/tkpCanvas.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 49FA53370D3CF5DC00DE2BD2 /* tkpCanvas.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = tkpCanvas.h; path = ../generic/tkpCanvas.h; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 49FA53380D3CF5DC00DE2BD2 /* tkpCanvBmap.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkpCanvBmap.c; path = ../generic/tkpCanvBmap.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 49FA53390D3CF5DC00DE2BD2 /* tkpCanvImg.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkpCanvImg.c; path = ../generic/tkpCanvImg.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 49FA533A0D3CF5DC00DE2BD2 /* tkpCanvLine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkpCanvLine.c; path = ../generic/tkpCanvLine.c; sourceTree = SOURCE_ROOT; }; + 49FA533B0D3CF5DC00DE2BD2 /* tkpCanvPoly.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkpCanvPoly.c; path = ../generic/tkpCanvPoly.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 49FA533C0D3CF5DC00DE2BD2 /* tkpCanvPs.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkpCanvPs.c; path = ../generic/tkpCanvPs.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 49FA533D0D3CF5DC00DE2BD2 /* tkpCanvText.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkpCanvText.c; path = ../generic/tkpCanvText.c; sourceTree = SOURCE_ROOT; }; + 49FA533E0D3CF5DC00DE2BD2 /* tkpCanvUtil.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkpCanvUtil.c; path = ../generic/tkpCanvUtil.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 49FA533F0D3CF5DC00DE2BD2 /* tkpCanvWind.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkpCanvWind.c; path = ../generic/tkpCanvWind.c; sourceTree = SOURCE_ROOT; }; + 49FA53400D3CF5DC00DE2BD2 /* tkpRectOval.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkpRectOval.c; path = ../generic/tkpRectOval.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 9A017ED6079FCCE100A80065 /* tkPath.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkPath.c; path = ../generic/tkPath.c; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 0; }; + 9A49B81F07A7AA2F00A80065 /* tkUnixCairoPath.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkUnixCairoPath.c; path = ../unix/tkUnixCairoPath.c; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 0; }; + 9A56FF2807A234510091799F /* path.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = path.c; path = ../generic/path.c; sourceTree = SOURCE_ROOT; }; + 9A578441043C3672009A6529 /* Tcl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Tcl.framework; path = /Library/Frameworks/Tcl.framework; sourceTree = "<absolute>"; }; + 9A578465043C369F009A6529 /* Tk.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Tk.framework; path = /Library/Frameworks/Tk.framework; sourceTree = "<absolute>"; }; + 9A57846A043C3778009A6529 /* libtclstub8.5.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtclstub8.5.a; path = /Library/Frameworks/Tcl.framework/libtclstub8.5.a; sourceTree = "<absolute>"; }; + 9A57846C043C37A8009A6529 /* libtkstub8.5.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtkstub8.5.a; path = /Library/Frameworks/Tk.framework/libtkstub8.5.a; sourceTree = "<absolute>"; }; + 9A587F03098FA7870094E994 /* tkCanvPline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkCanvPline.c; path = ../generic/tkCanvPline.c; sourceTree = SOURCE_ROOT; }; + 9A58E5420796814B00FBE143 /* tkPathGradient.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkPathGradient.c; path = ../generic/tkPathGradient.c; sourceTree = SOURCE_ROOT; }; + 9A5A2A920B45059700496554 /* tkCanvPtext.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = tkCanvPtext.c; path = ../generic/tkCanvPtext.c; sourceTree = SOURCE_ROOT; }; + 9A5B17C7097BA957000B33B2 /* tkCanvPathUtil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkCanvPathUtil.c; path = ../generic/tkCanvPathUtil.c; sourceTree = SOURCE_ROOT; }; + 9A5BCDA007E2D8B400B6FA03 /* tkPathUtil.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkPathUtil.c; path = ../generic/tkPathUtil.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 0; }; + 9A6265BF09C474B3009A2B1E /* tkCanvEllipse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkCanvEllipse.c; path = ../generic/tkCanvEllipse.c; sourceTree = SOURCE_ROOT; }; + 9A66FCF20978D8050086B7B8 /* tkCanvPrect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkCanvPrect.c; path = ../generic/tkCanvPrect.c; sourceTree = SOURCE_ROOT; }; + 9A66FCF40978E3400086B7B8 /* tkCanvPathUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tkCanvPathUtil.h; path = ../generic/tkCanvPathUtil.h; sourceTree = SOURCE_ROOT; }; + 9A671A8F099DC683007AF773 /* tkCanvPimage.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = tkCanvPimage.c; path = ../generic/tkCanvPimage.c; sourceTree = "<group>"; }; + 9A6C4D7407AD01B100A80065 /* tkWinGDIPlusPath.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 2; name = tkWinGDIPlusPath.cpp; path = ../win/tkWinGDIPlusPath.cpp; sourceTree = SOURCE_ROOT; }; + 9A8794BD07801B3900A80065 /* tkWinGDIPath.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = tkWinGDIPath.c; path = ../win/tkWinGDIPath.c; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 0; }; + 9A96B2380B898CA800A80002 /* tkPathStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tkPathStyle.h; path = ../generic/tkPathStyle.h; sourceTree = SOURCE_ROOT; }; + 9AA0B6C407DD8C9900A80065 /* tkPathStyle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkPathStyle.c; path = ../generic/tkPathStyle.c; sourceTree = SOURCE_ROOT; }; + 9AA1ECE6077FF68100A80065 /* tkMacOSXPath.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = tkMacOSXPath.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 0; }; + 9AA1ECE8077FF7BF00A80065 /* tkCanvPath.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = tkCanvPath.c; path = ../generic/tkCanvPath.c; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 0; }; + 9AA1ECEA077FF7CC00A80065 /* tkIntPath.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = tkIntPath.h; path = ../generic/tkIntPath.h; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; + 9AB087D80A38001400A80065 /* tkCanvPpoly.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = tkCanvPpoly.c; path = ../generic/tkCanvPpoly.c; sourceTree = SOURCE_ROOT; }; + 9AB6AB700B835DCD00A80002 /* tkPathSurface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tkPathSurface.c; path = ../generic/tkPathSurface.c; sourceTree = SOURCE_ROOT; }; + 9AF2FEBB079410DB00AB783C /* tkPath.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = tkPath.h; path = ../generic/tkPath.h; sourceTree = SOURCE_ROOT; }; + F5564883038142E001A4FCC0 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 49FA53200D3CF52D00DE2BD2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 49FA53210D3CF52D00DE2BD2 /* Carbon.framework in Frameworks */, + 49FA53220D3CF52D00DE2BD2 /* CoreServices.framework in Frameworks */, + 49FA53230D3CF52D00DE2BD2 /* libtclstub8.5.a in Frameworks */, + 49FA53240D3CF52D00DE2BD2 /* libtkstub8.5.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DDFF38A45A11DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + 49FA532A0D3CF52D00DE2BD2 /* tkpath0.3.1.dylib */, + ); + name = Products; + sourceTree = "<group>"; + }; + 0867D691FE84028FC02AAC07 /* MatsFramework */ = { + isa = PBXGroup; + children = ( + 9A8794B5078019DB00A80065 /* Source */, + 034768DDFF38A45A11DB9C8B /* Products */, + 089C1665FE841158C02AAC07 /* Resources */, + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, + ); + name = MatsFramework; + sourceTree = "<group>"; + }; + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 08FB77AAFE841565C02AAC07 /* Carbon.framework */, + F5564883038142E001A4FCC0 /* CoreServices.framework */, + 9A578441043C3672009A6529 /* Tcl.framework */, + 9A57846A043C3778009A6529 /* libtclstub8.5.a */, + 9A578465043C369F009A6529 /* Tk.framework */, + 9A57846C043C37A8009A6529 /* libtkstub8.5.a */, + ); + name = "External Frameworks and Libraries"; + sourceTree = "<group>"; + }; + 089C1665FE841158C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + ); + name = Resources; + sourceTree = "<group>"; + }; + 08FB77ACFE841707C02AAC07 /* generic */ = { + isa = PBXGroup; + children = ( + 49ECBBA30D3FA7C900A1FB4F /* tkp.h */, + 9A56FF2807A234510091799F /* path.c */, + 9AF2FEBB079410DB00AB783C /* tkPath.h */, + 9A017ED6079FCCE100A80065 /* tkPath.c */, + 49FA53360D3CF5DC00DE2BD2 /* tkpCanvas.c */, + 49FA53370D3CF5DC00DE2BD2 /* tkpCanvas.h */, + 49FA53350D3CF5DC00DE2BD2 /* tkpCanvArc.c */, + 49FA53380D3CF5DC00DE2BD2 /* tkpCanvBmap.c */, + 49FA53390D3CF5DC00DE2BD2 /* tkpCanvImg.c */, + 49FA533A0D3CF5DC00DE2BD2 /* tkpCanvLine.c */, + 49FA533B0D3CF5DC00DE2BD2 /* tkpCanvPoly.c */, + 49FA533C0D3CF5DC00DE2BD2 /* tkpCanvPs.c */, + 49FA533D0D3CF5DC00DE2BD2 /* tkpCanvText.c */, + 49FA533E0D3CF5DC00DE2BD2 /* tkpCanvUtil.c */, + 49FA533F0D3CF5DC00DE2BD2 /* tkpCanvWind.c */, + 49FA53400D3CF5DC00DE2BD2 /* tkpRectOval.c */, + 4964E76D0D41D3730030426E /* tkpTrig.c */, + 4964DC240D4333A90050C442 /* tkpUtil.c */, + 9AA1ECEA077FF7CC00A80065 /* tkIntPath.h */, + 9A66FCF40978E3400086B7B8 /* tkCanvPathUtil.h */, + 9A5B17C7097BA957000B33B2 /* tkCanvPathUtil.c */, + 9A6265BF09C474B3009A2B1E /* tkCanvEllipse.c */, + 496353F70D4CCE3C00A7B7DA /* tkCanvGroup.c */, + 9AA1ECE8077FF7BF00A80065 /* tkCanvPath.c */, + 9A66FCF20978D8050086B7B8 /* tkCanvPrect.c */, + 9A587F03098FA7870094E994 /* tkCanvPline.c */, + 9A671A8F099DC683007AF773 /* tkCanvPimage.c */, + 9AB087D80A38001400A80065 /* tkCanvPpoly.c */, + 9A5A2A920B45059700496554 /* tkCanvPtext.c */, + 496824A30DD5E65D000D7DA7 /* tkCanvGradient.c */, + 9A58E5420796814B00FBE143 /* tkPathGradient.c */, + 496D9D740DE2B9BB002618BA /* tkCanvStyle.c */, + 9A96B2380B898CA800A80002 /* tkPathStyle.h */, + 9AA0B6C407DD8C9900A80065 /* tkPathStyle.c */, + 9AB6AB700B835DCD00A80002 /* tkPathSurface.c */, + 9A5BCDA007E2D8B400B6FA03 /* tkPathUtil.c */, + ); + name = generic; + sourceTree = "<group>"; + }; + 9A8794B5078019DB00A80065 /* Source */ = { + isa = PBXGroup; + children = ( + 08FB77ACFE841707C02AAC07 /* generic */, + 9A8794B6078019FB00A80065 /* macosx */, + 9A8794B707801A0400A80065 /* unix */, + 9A8794BC07801A5D00A80065 /* windows */, + ); + name = Source; + sourceTree = "<group>"; + }; + 9A8794B6078019FB00A80065 /* macosx */ = { + isa = PBXGroup; + children = ( + 9AA1ECE6077FF68100A80065 /* tkMacOSXPath.c */, + ); + name = macosx; + sourceTree = "<group>"; + }; + 9A8794B707801A0400A80065 /* unix */ = { + isa = PBXGroup; + children = ( + 9A49B81F07A7AA2F00A80065 /* tkUnixCairoPath.c */, + ); + name = unix; + sourceTree = "<group>"; + }; + 9A8794BC07801A5D00A80065 /* windows */ = { + isa = PBXGroup; + children = ( + 9A8794BD07801B3900A80065 /* tkWinGDIPath.c */, + 9A6C4D7407AD01B100A80065 /* tkWinGDIPlusPath.cpp */, + ); + name = windows; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 49FA53090D3CF52D00DE2BD2 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 49FA530A0D3CF52D00DE2BD2 /* tkIntPath.h in Headers */, + 49FA530B0D3CF52D00DE2BD2 /* tkPath.h in Headers */, + 49FA530C0D3CF52D00DE2BD2 /* tkCanvPathUtil.h in Headers */, + 49FA530E0D3CF52D00DE2BD2 /* tkPathStyle.h in Headers */, + 49FA53430D3CF5DC00DE2BD2 /* tkpCanvas.h in Headers */, + 49ECBBA40D3FA7C900A1FB4F /* tkp.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 49FA53070D3CF52D00DE2BD2 /* tkp canvas dylib */ = { + isa = PBXNativeTarget; + buildConfigurationList = 49FA53260D3CF52D00DE2BD2 /* Build configuration list for PBXNativeTarget "tkp canvas dylib" */; + buildPhases = ( + 49FA53080D3CF52D00DE2BD2 /* ShellScript */, + 49FA53090D3CF52D00DE2BD2 /* Headers */, + 49FA530F0D3CF52D00DE2BD2 /* Sources */, + 49FA53200D3CF52D00DE2BD2 /* Frameworks */, + 49FA53250D3CF52D00DE2BD2 /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "tkp canvas dylib"; + productInstallPath = "/Library/Tcl/tkpath${DYLIB_COMPATIBILITY_VERSION}"; + productName = "MovableAlerts dylib"; + productReference = 49FA532A0D3CF52D00DE2BD2 /* tkpath0.3.1.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 49C087820D263BCC008B0A1B /* Build configuration list for PBXProject "tkpath" */; + compatibilityVersion = "Xcode 2.4"; + hasScannedForEncodings = 1; + mainGroup = 0867D691FE84028FC02AAC07 /* MatsFramework */; + productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; + projectDirPath = ""; + projectRoot = ..; + targets = ( + 49FA53070D3CF52D00DE2BD2 /* tkp canvas dylib */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXRezBuildPhase section */ + 49FA53250D3CF52D00DE2BD2 /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 49FA53080D3CF52D00DE2BD2 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = "# ensure we can overwrite a previous install\nif [ -d \"${INSTALL_ROOT}${INSTALL_PATH}\" ]; then\n chmod -RH u+w \"${INSTALL_ROOT}${INSTALL_PATH}\"\nfi"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 49FA530F0D3CF52D00DE2BD2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 49FA53100D3CF52D00DE2BD2 /* tkMacOSXPath.c in Sources */, + 49FA53110D3CF52D00DE2BD2 /* tkCanvPath.c in Sources */, + 49FA53120D3CF52D00DE2BD2 /* tkPathGradient.c in Sources */, + 49FA53130D3CF52D00DE2BD2 /* tkPath.c in Sources */, + 49FA53140D3CF52D00DE2BD2 /* path.c in Sources */, + 49FA53150D3CF52D00DE2BD2 /* tkPathStyle.c in Sources */, + 49FA53160D3CF52D00DE2BD2 /* tkPathUtil.c in Sources */, + 49FA53180D3CF52D00DE2BD2 /* tkCanvPrect.c in Sources */, + 49FA53190D3CF52D00DE2BD2 /* tkCanvPathUtil.c in Sources */, + 49FA531A0D3CF52D00DE2BD2 /* tkCanvPline.c in Sources */, + 49FA531B0D3CF52D00DE2BD2 /* tkCanvPimage.c in Sources */, + 49FA531C0D3CF52D00DE2BD2 /* tkCanvEllipse.c in Sources */, + 49FA531D0D3CF52D00DE2BD2 /* tkCanvPpoly.c in Sources */, + 49FA531E0D3CF52D00DE2BD2 /* tkCanvPtext.c in Sources */, + 49FA531F0D3CF52D00DE2BD2 /* tkPathSurface.c in Sources */, + 49FA53410D3CF5DC00DE2BD2 /* tkpCanvArc.c in Sources */, + 49FA53420D3CF5DC00DE2BD2 /* tkpCanvas.c in Sources */, + 49FA53440D3CF5DC00DE2BD2 /* tkpCanvBmap.c in Sources */, + 49FA53450D3CF5DC00DE2BD2 /* tkpCanvImg.c in Sources */, + 49FA53460D3CF5DC00DE2BD2 /* tkpCanvLine.c in Sources */, + 49FA53470D3CF5DC00DE2BD2 /* tkpCanvPoly.c in Sources */, + 49FA53480D3CF5DC00DE2BD2 /* tkpCanvPs.c in Sources */, + 49FA53490D3CF5DC00DE2BD2 /* tkpCanvText.c in Sources */, + 49FA534A0D3CF5DC00DE2BD2 /* tkpCanvUtil.c in Sources */, + 49FA534B0D3CF5DC00DE2BD2 /* tkpCanvWind.c in Sources */, + 49FA534C0D3CF5DC00DE2BD2 /* tkpRectOval.c in Sources */, + 4964E76E0D41D3730030426E /* tkpTrig.c in Sources */, + 4964DC250D4333A90050C442 /* tkpUtil.c in Sources */, + 496353F80D4CCE3C00A7B7DA /* tkCanvGroup.c in Sources */, + 496824A40DD5E65D000D7DA7 /* tkCanvGradient.c in Sources */, + 496D9D750DE2B9BB002618BA /* tkCanvStyle.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 49C087790D263BCB008B0A1B /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Development; + }; + 49C0877A0D263BCB008B0A1B /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Deployment; + }; + 49C0877B0D263BCB008B0A1B /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Default; + }; + 49FA53270D3CF52D00DE2BD2 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 0.3.1; + DYLIB_CURRENT_VERSION = 0.3.1; + EXPORTED_SYMBOLS_FILE = ./PBExportedSymbols; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + USE_TCL_STUBS, + "TARGET_OS_MAC=1", + "TARGET_API_MAC_CARBON=1", + USE_TK_STUBS, + MAC_OSX_TK, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + HEADER_SEARCH_PATHS = ( + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_2)", + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_3)", + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_4)", + ../../tk/generic, + ../../tk/macosx, + ); + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tcl.framework/Headers\\\""; + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tcl.framework/PrivateHeaders\\\""; + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_3 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tk.framework/Headers\\\""; + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_4 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tk.framework/PrivateHeaders\\\""; + INSTALL_PATH = "/Library/Tcl/tkpath${DYLIB_COMPATIBILITY_VERSION}"; + LIBRARY_SEARCH_PATHS = ( + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2)", + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3)", + ); + LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tcl.framework\\\""; + LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tk.framework\\\""; + LIBRARY_STYLE = DYNAMIC; + MACH_O_TYPE = mh_dylib; + MACOSX_DEPLOYMENT_TARGET = 10.3; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOL_FLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "tkpath${DYLIB_COMPATIBILITY_VERSION}"; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + ZERO_LINK = NO; + }; + name = Development; + }; + 49FA53280D3CF52D00DE2BD2 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + i386, + ppc, + ); + COPY_PHASE_STRIP = YES; + DYLIB_COMPATIBILITY_VERSION = 0.3.1; + DYLIB_CURRENT_VERSION = 0.3.1; + EXPORTED_SYMBOLS_FILE = ./PBExportedSymbols; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_OPTIMIZATION_LEVEL = s; + GCC_PREPROCESSOR_DEFINITIONS = ( + USE_TCL_STUBS, + "TARGET_OS_MAC=1", + "TARGET_API_MAC_CARBON=1", + USE_TK_STUBS, + MAC_OSX_TK, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + HEADER_SEARCH_PATHS = ( + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_2)", + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_3)", + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_4)", + ../../tk/generic, + ../../tk/macosx, + ); + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tcl.framework/Headers\\\""; + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tcl.framework/PrivateHeaders\\\""; + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_3 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tk.framework/Headers\\\""; + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_4 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tk.framework/PrivateHeaders\\\""; + INSTALL_PATH = "/Library/Tcl/tkpath${DYLIB_COMPATIBILITY_VERSION}"; + LIBRARY_SEARCH_PATHS = ( + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2)", + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3)", + ); + LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tcl.framework\\\""; + LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tk.framework\\\""; + LIBRARY_STYLE = DYNAMIC; + MACH_O_TYPE = mh_dylib; + MACOSX_DEPLOYMENT_TARGET = 10.3; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOL_FLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "tkpath${DYLIB_COMPATIBILITY_VERSION}"; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + ZERO_LINK = NO; + }; + name = Deployment; + }; + 49FA53290D3CF52D00DE2BD2 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + DYLIB_COMPATIBILITY_VERSION = 0.3.0; + DYLIB_CURRENT_VERSION = 0.3.0; + EXPORTED_SYMBOLS_FILE = ./PBExportedSymbols; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + USE_TCL_STUBS, + "TARGET_OS_MAC=1", + "TARGET_API_MAC_CARBON=1", + USE_TK_STUBS, + MAC_OSX_TK, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + HEADER_SEARCH_PATHS = ( + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_2)", + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_3)", + "$(HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_4)", + ../../tk/generic, + ../../tk/macosx, + ); + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tcl.framework/Headers\\\""; + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tcl.framework/PrivateHeaders\\\""; + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_3 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tk.framework/Headers\\\""; + HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_4 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tk.framework/PrivateHeaders\\\""; + INSTALL_PATH = "/Library/Tcl/tkpath${DYLIB_COMPATIBILITY_VERSION}"; + LIBRARY_SEARCH_PATHS = ( + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2)", + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3)", + ); + LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tcl.framework\\\""; + LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\\\"$(LOCAL_LIBRARY_DIR)/Frameworks/Tk.framework\\\""; + LIBRARY_STYLE = DYNAMIC; + MACH_O_TYPE = mh_dylib; + MACOSX_DEPLOYMENT_TARGET = 10.3; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOL_FLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "tkpath${DYLIB_COMPATIBILITY_VERSION}"; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + }; + name = Default; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 49C087820D263BCC008B0A1B /* Build configuration list for PBXProject "tkpath" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 49C087790D263BCB008B0A1B /* Development */, + 49C0877A0D263BCB008B0A1B /* Deployment */, + 49C0877B0D263BCB008B0A1B /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 49FA53260D3CF52D00DE2BD2 /* Build configuration list for PBXNativeTarget "tkp canvas dylib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 49FA53270D3CF52D00DE2BD2 /* Development */, + 49FA53280D3CF52D00DE2BD2 /* Deployment */, + 49FA53290D3CF52D00DE2BD2 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +} diff --git a/pd/tkpath/pkgIndex.tcl.in b/pd/tkpath/pkgIndex.tcl.in new file mode 100755 index 0000000000000000000000000000000000000000..b7d69202a4a8fb8826081ccf6778165445000044 --- /dev/null +++ b/pd/tkpath/pkgIndex.tcl.in @@ -0,0 +1,17 @@ +# @configure_input@ +# +namespace eval ::tkpath { + proc load_package {dir} { + load [file join $dir @PKG_LIB_FILE@] + # Allow optional redirect of library components. + # Only necessary for testing, but could be used elsewhere. + if {[info exists ::env(TKPATH_LIBRARY)]} { + set dir $::env(TKPATH_LIBRARY) + } + source $dir/tkpath.tcl + };# load_package +} + +package ifneeded tkpath @PACKAGE_VERSION@ [list ::tkpath::load_package $dir] + +#*EOF* diff --git a/pd/tkpath/tclconfig/install-sh b/pd/tkpath/tclconfig/install-sh new file mode 100755 index 0000000000000000000000000000000000000000..921da0fe11f33f11f0fc2e3a96de018578b75ae2 --- /dev/null +++ b/pd/tkpath/tclconfig/install-sh @@ -0,0 +1,528 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-04-20.01; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -S $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -S) stripcmd="$stripprog $2" + shift;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/pd/tkpath/tclconfig/tcl.m4 b/pd/tkpath/tclconfig/tcl.m4 new file mode 100644 index 0000000000000000000000000000000000000000..d79d72ac4975fba5449edc5bead7d94626979fc5 --- /dev/null +++ b/pd/tkpath/tclconfig/tcl.m4 @@ -0,0 +1,4171 @@ +# tcl.m4 -- +# +# This file provides a set of autoconf macros to help TEA-enable +# a Tcl extension. +# +# Copyright (c) 1999-2000 Ajuba Solutions. +# Copyright (c) 2002-2005 ActiveState Corporation. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +AC_PREREQ(2.57) + +dnl TEA extensions pass us the version of TEA they think they +dnl are compatible with (must be set in TEA_INIT below) +dnl TEA_VERSION="3.9" + +# Possible values for key variables defined: +# +# TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') +# TEA_PLATFORM - windows unix +# + +#------------------------------------------------------------------------ +# TEA_PATH_TCLCONFIG -- +# +# Locate the tclConfig.sh file and perform a sanity check on +# the Tcl compile flags +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-tcl=... +# +# Defines the following vars: +# TCL_BIN_DIR Full path to the directory containing +# the tclConfig.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_TCLCONFIG], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_INIT]) + # + # Ok, lets find the tcl configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tcl + # + + if test x"${no_tcl}" = x ; then + # we reset no_tcl in case something fails here + no_tcl=true + AC_ARG_WITH(tcl, + AC_HELP_STRING([--with-tcl], + [directory containing tcl configuration (tclConfig.sh)]), + with_tclconfig="${withval}") + AC_MSG_CHECKING([for Tcl configuration]) + AC_CACHE_VAL(ac_cv_c_tclconfig,[ + + # First check to see if --with-tcl was specified. + if test x"${with_tclconfig}" != x ; then + case "${with_tclconfig}" in + */tclConfig.sh ) + if test -f "${with_tclconfig}"; then + AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) + with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" + else + AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) + fi + fi + + # then check for a private Tcl installation + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ../tcl \ + `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tcl \ + `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tcl \ + `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + ; do + if test -f "$i/Tcl.framework/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" + break + fi + done + fi + + # TEA specific: on Windows, check in common installation locations + if test "${TEA_PLATFORM}" = "windows" \ + -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d C:/Tcl/lib 2>/dev/null` \ + `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + ]) + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) + else + no_tcl= + TCL_BIN_DIR="${ac_cv_c_tclconfig}" + AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_PATH_TKCONFIG -- +# +# Locate the tkConfig.sh file +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-tk=... +# +# Defines the following vars: +# TK_BIN_DIR Full path to the directory containing +# the tkConfig.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_TKCONFIG], [ + # + # Ok, lets find the tk configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tk + # + + if test x"${no_tk}" = x ; then + # we reset no_tk in case something fails here + no_tk=true + AC_ARG_WITH(tk, + AC_HELP_STRING([--with-tk], + [directory containing tk configuration (tkConfig.sh)]), + with_tkconfig="${withval}") + AC_MSG_CHECKING([for Tk configuration]) + AC_CACHE_VAL(ac_cv_c_tkconfig,[ + + # First check to see if --with-tkconfig was specified. + if test x"${with_tkconfig}" != x ; then + case "${with_tkconfig}" in + */tkConfig.sh ) + if test -f "${with_tkconfig}"; then + AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) + with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tkconfig}/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" + else + AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) + fi + fi + + # then check for a private Tk library + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ../tk \ + `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tk \ + `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tk \ + `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + ; do + if test -f "$i/Tk.framework/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # TEA specific: on Windows, check in common installation locations + if test "${TEA_PLATFORM}" = "windows" \ + -a x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d C:/Tcl/lib 2>/dev/null` \ + `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ${srcdir}/../tk \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test "${TEA_PLATFORM}" = "windows" \ + -a -f "$i/win/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/win; pwd)`" + break + fi + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + ]) + + if test x"${ac_cv_c_tkconfig}" = x ; then + TK_BIN_DIR="# no Tk configs found" + AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) + else + no_tk= + TK_BIN_DIR="${ac_cv_c_tkconfig}" + AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_TCLCONFIG -- +# +# Load the tclConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TCL_BIN_DIR +# +# Results: +# +# Subst the following vars: +# TCL_BIN_DIR +# TCL_SRC_DIR +# TCL_LIB_FILE +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LOAD_TCLCONFIG], [ + AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) + + if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then + AC_MSG_RESULT([loading]) + . "${TCL_BIN_DIR}/tclConfig.sh" + else + AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" + eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" + + # If the TCL_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TCL_LIB_SPEC will be set to the value + # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC + # instead of TCL_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" + TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" + TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tcl.framework installed in an arbitrary location. + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then + for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ + "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then + TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" + break + fi + done + fi + if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then + TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" + TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" + eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" + eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" + eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" + + AC_SUBST(TCL_VERSION) + AC_SUBST(TCL_PATCH_LEVEL) + AC_SUBST(TCL_BIN_DIR) + AC_SUBST(TCL_SRC_DIR) + + AC_SUBST(TCL_LIB_FILE) + AC_SUBST(TCL_LIB_FLAG) + AC_SUBST(TCL_LIB_SPEC) + + AC_SUBST(TCL_STUB_LIB_FILE) + AC_SUBST(TCL_STUB_LIB_FLAG) + AC_SUBST(TCL_STUB_LIB_SPEC) + + AC_MSG_CHECKING([platform]) + hold_cc=$CC; CC="$TCL_CC" + AC_TRY_COMPILE(,[ + #ifdef _WIN32 + #error win32 + #endif + ], TEA_PLATFORM="unix", + TEA_PLATFORM="windows" + ) + CC=$hold_cc + AC_MSG_RESULT($TEA_PLATFORM) + + # The BUILD_$pkg is to define the correct extern storage class + # handling when making this package + AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], + [Building extension source?]) + # Do this here as we have fully defined TEA_PLATFORM now + if test "${TEA_PLATFORM}" = "windows" ; then + EXEEXT=".exe" + CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" + fi + + # TEA specific: + AC_SUBST(CLEANFILES) + AC_SUBST(TCL_LIBS) + AC_SUBST(TCL_DEFS) + AC_SUBST(TCL_EXTRA_CFLAGS) + AC_SUBST(TCL_LD_FLAGS) + AC_SUBST(TCL_SHLIB_LD_LIBS) +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_TKCONFIG -- +# +# Load the tkConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TK_BIN_DIR +# +# Results: +# +# Sets the following vars that should be in tkConfig.sh: +# TK_BIN_DIR +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LOAD_TKCONFIG], [ + AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) + + if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then + AC_MSG_RESULT([loading]) + . "${TK_BIN_DIR}/tkConfig.sh" + else + AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) + fi + + # eval is required to do the TK_DBGX substitution + eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" + eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" + + # If the TK_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TK_LIB_SPEC will be set to the value + # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC + # instead of TK_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TK_BIN_DIR}/Makefile" ; then + TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" + TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" + TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tk.framework installed in an arbitrary location. + case ${TK_DEFS} in + *TK_FRAMEWORK*) + if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then + for i in "`cd "${TK_BIN_DIR}"; pwd`" \ + "`cd "${TK_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then + TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" + break + fi + done + fi + if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then + TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" + TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TK_DBGX substitution + eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" + eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" + eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" + eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" + + # TEA specific: Ensure windowingsystem is defined + if test "${TEA_PLATFORM}" = "unix" ; then + case ${TK_DEFS} in + *MAC_OSX_TK*) + AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) + TEA_WINDOWINGSYSTEM="aqua" + ;; + *) + TEA_WINDOWINGSYSTEM="x11" + ;; + esac + elif test "${TEA_PLATFORM}" = "windows" ; then + TEA_WINDOWINGSYSTEM="win32" + fi + + AC_SUBST(TK_VERSION) + AC_SUBST(TK_BIN_DIR) + AC_SUBST(TK_SRC_DIR) + + AC_SUBST(TK_LIB_FILE) + AC_SUBST(TK_LIB_FLAG) + AC_SUBST(TK_LIB_SPEC) + + AC_SUBST(TK_STUB_LIB_FILE) + AC_SUBST(TK_STUB_LIB_FLAG) + AC_SUBST(TK_STUB_LIB_SPEC) + + # TEA specific: + AC_SUBST(TK_LIBS) + AC_SUBST(TK_XINCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_PROG_TCLSH +# Determine the fully qualified path name of the tclsh executable +# in the Tcl build directory or the tclsh installed in a bin +# directory. This macro will correctly determine the name +# of the tclsh executable even if tclsh has not yet been +# built in the build directory. The tclsh found is always +# associated with a tclConfig.sh file. This tclsh should be used +# only for running extension test cases. It should never be +# or generation of files (like pkgIndex.tcl) at build time. +# +# Arguments +# none +# +# Results +# Subst's the following values: +# TCLSH_PROG +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PROG_TCLSH], [ + AC_MSG_CHECKING([for tclsh]) + if test -f "${TCL_BIN_DIR}/Makefile" ; then + # tclConfig.sh is in Tcl build directory + if test "${TEA_PLATFORM}" = "windows"; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" + else + TCLSH_PROG="${TCL_BIN_DIR}/tclsh" + fi + else + # tclConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" + else + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" + fi + list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${TCLSH_PROG}" ; then + REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" + fi + AC_MSG_RESULT([${TCLSH_PROG}]) + AC_SUBST(TCLSH_PROG) +]) + +#------------------------------------------------------------------------ +# TEA_PROG_WISH +# Determine the fully qualified path name of the wish executable +# in the Tk build directory or the wish installed in a bin +# directory. This macro will correctly determine the name +# of the wish executable even if wish has not yet been +# built in the build directory. The wish found is always +# associated with a tkConfig.sh file. This wish should be used +# only for running extension test cases. It should never be +# or generation of files (like pkgIndex.tcl) at build time. +# +# Arguments +# none +# +# Results +# Subst's the following values: +# WISH_PROG +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PROG_WISH], [ + AC_MSG_CHECKING([for wish]) + if test -f "${TK_BIN_DIR}/Makefile" ; then + # tkConfig.sh is in Tk build directory + if test "${TEA_PLATFORM}" = "windows"; then + WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" + else + WISH_PROG="${TK_BIN_DIR}/wish" + fi + else + # tkConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" + else + WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" + fi + list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TK_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${WISH_PROG}" ; then + REAL_TK_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" + fi + AC_MSG_RESULT([${WISH_PROG}]) + AC_SUBST(WISH_PROG) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_SHARED -- +# +# Allows the building of shared libraries +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-shared=yes|no +# +# Defines the following vars: +# STATIC_BUILD Used for building import/export libraries +# on Windows. +# +# Sets the following vars: +# SHARED_BUILD Value of 1 or 0 +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_SHARED], [ + AC_MSG_CHECKING([how to build libraries]) + AC_ARG_ENABLE(shared, + AC_HELP_STRING([--enable-shared], + [build and link with shared libraries (default: on)]), + [tcl_ok=$enableval], [tcl_ok=yes]) + + if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + tcl_ok=$enableval + else + tcl_ok=yes + fi + + if test "$tcl_ok" = "yes" ; then + AC_MSG_RESULT([shared]) + SHARED_BUILD=1 + else + AC_MSG_RESULT([static]) + SHARED_BUILD=0 + AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) + fi + AC_SUBST(SHARED_BUILD) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_THREADS -- +# +# Specify if thread support should be enabled. If "yes" is specified +# as an arg (optional), threads are enabled by default, "no" means +# threads are disabled. "yes" is the default. +# +# TCL_THREADS is checked so that if you are compiling an extension +# against a threaded core, your extension must be compiled threaded +# as well. +# +# Note that it is legal to have a thread enabled extension run in a +# threaded or non-threaded Tcl core, but a non-threaded extension may +# only run in a non-threaded Tcl core. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-threads +# +# Sets the following vars: +# THREADS_LIBS Thread library(s) +# +# Defines the following vars: +# TCL_THREADS +# _REENTRANT +# _THREAD_SAFE +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_THREADS], [ + AC_ARG_ENABLE(threads, + AC_HELP_STRING([--enable-threads], + [build with threads]), + [tcl_ok=$enableval], [tcl_ok=yes]) + + if test "${enable_threads+set}" = set; then + enableval="$enable_threads" + tcl_ok=$enableval + else + tcl_ok=yes + fi + + if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then + TCL_THREADS=1 + + if test "${TEA_PLATFORM}" != "windows" ; then + # We are always OK on Windows, so check what this platform wants: + + # USE_THREAD_ALLOC tells us to try the special thread-based + # allocator that significantly reduces lock contention + AC_DEFINE(USE_THREAD_ALLOC, 1, + [Do we want to use the threaded memory allocator?]) + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + if test "`uname -s`" = "SunOS" ; then + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + fi + AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) + AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) + if test "$tcl_ok" = "no"; then + # Check a little harder for __pthread_mutex_init in the same + # library, as some systems hide it there until pthread.h is + # defined. We could alternatively do an AC_TRY_COMPILE with + # pthread.h, but that will work with libpthread really doesn't + # exist, like AIX 4.2. [Bug: 4359] + AC_CHECK_LIB(pthread, __pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + fi + + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthread" + else + AC_CHECK_LIB(pthreads, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthreads" + else + AC_CHECK_LIB(c, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "no"; then + AC_CHECK_LIB(c_r, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -pthread" + else + TCL_THREADS=0 + AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) + fi + fi + fi + fi + fi + else + TCL_THREADS=0 + fi + # Do checking message here to not mess up interleaved configure output + AC_MSG_CHECKING([for building with threads]) + if test "${TCL_THREADS}" = 1; then + AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) + AC_MSG_RESULT([yes (default)]) + else + AC_MSG_RESULT([no]) + fi + # TCL_THREADS sanity checking. See if our request for building with + # threads is the same as the way Tcl was built. If not, warn the user. + case ${TCL_DEFS} in + *THREADS=1*) + if test "${TCL_THREADS}" = "0"; then + AC_MSG_WARN([ + Building ${PACKAGE_NAME} without threads enabled, but building against Tcl + that IS thread-enabled. It is recommended to use --enable-threads.]) + fi + ;; + *) + if test "${TCL_THREADS}" = "1"; then + AC_MSG_WARN([ + --enable-threads requested, but building against a Tcl that is NOT + thread-enabled. This is an OK configuration that will also run in + a thread-enabled core.]) + fi + ;; + esac + AC_SUBST(TCL_THREADS) +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_SYMBOLS -- +# +# Specify if debugging symbols should be used. +# Memory (TCL_MEM_DEBUG) debugging can also be enabled. +# +# Arguments: +# none +# +# TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives +# the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. +# Requires the following vars to be set in the Makefile: +# CFLAGS_DEFAULT +# LDFLAGS_DEFAULT +# +# Results: +# +# Adds the following arguments to configure: +# --enable-symbols +# +# Defines the following vars: +# CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true +# Sets to $(CFLAGS_OPTIMIZE) if false +# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true +# Sets to $(LDFLAGS_OPTIMIZE) if false +# DBGX Formerly used as debug library extension; +# always blank now. +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_SYMBOLS], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_CONFIG_CFLAGS]) + AC_MSG_CHECKING([for build with symbols]) + AC_ARG_ENABLE(symbols, + AC_HELP_STRING([--enable-symbols], + [build with debugging symbols (default: off)]), + [tcl_ok=$enableval], [tcl_ok=no]) + DBGX="" + if test "$tcl_ok" = "no"; then + CFLAGS_DEFAULT='${CFLAGS_OPTIMIZE}' + LDFLAGS_DEFAULT='${LDFLAGS_OPTIMIZE}' + AC_MSG_RESULT([no]) + else + CFLAGS_DEFAULT='${CFLAGS_DEBUG}' + LDFLAGS_DEFAULT='${LDFLAGS_DEBUG}' + if test "$tcl_ok" = "yes"; then + AC_MSG_RESULT([yes (standard debugging)]) + fi + fi + # TEA specific: + if test "${TEA_PLATFORM}" != "windows" ; then + LDFLAGS_DEFAULT="${LDFLAGS}" + fi + AC_SUBST(CFLAGS_DEFAULT) + AC_SUBST(LDFLAGS_DEFAULT) + AC_SUBST(TCL_DBGX) + + if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then + AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) + fi + + if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then + if test "$tcl_ok" = "all"; then + AC_MSG_RESULT([enabled symbols mem debugging]) + else + AC_MSG_RESULT([enabled $tcl_ok debugging]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_ENABLE_LANGINFO -- +# +# Allows use of modern nl_langinfo check for better l10n. +# This is only relevant for Unix. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-langinfo=yes|no (default is yes) +# +# Defines the following vars: +# HAVE_LANGINFO Triggers use of nl_langinfo if defined. +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_ENABLE_LANGINFO], [ + AC_ARG_ENABLE(langinfo, + AC_HELP_STRING([--enable-langinfo], + [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), + [langinfo_ok=$enableval], [langinfo_ok=yes]) + + HAVE_LANGINFO=0 + if test "$langinfo_ok" = "yes"; then + AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) + fi + AC_MSG_CHECKING([whether to use nl_langinfo]) + if test "$langinfo_ok" = "yes"; then + AC_CACHE_VAL(tcl_cv_langinfo_h, [ + AC_TRY_COMPILE([#include <langinfo.h>], [nl_langinfo(CODESET);], + [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) + AC_MSG_RESULT([$tcl_cv_langinfo_h]) + if test $tcl_cv_langinfo_h = yes; then + AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) + fi + else + AC_MSG_RESULT([$langinfo_ok]) + fi +]) + +#-------------------------------------------------------------------- +# TEA_CONFIG_SYSTEM +# +# Determine what the system is (some things cannot be easily checked +# on a feature-driven basis, alas). This can usually be done via the +# "uname" command. +# +# Arguments: +# none +# +# Results: +# Defines the following var: +# +# system - System/platform/version identification code. +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_CONFIG_SYSTEM], [ + AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ + # TEA specific: + if test "${TEA_PLATFORM}" = "windows" ; then + tcl_cv_sys_version=windows + else + tcl_cv_sys_version=`uname -s`-`uname -r` + if test "$?" -ne 0 ; then + AC_MSG_WARN([can't find uname command]) + tcl_cv_sys_version=unknown + else + if test "`uname -s`" = "AIX" ; then + tcl_cv_sys_version=AIX-`uname -v`.`uname -r` + fi + fi + fi + ]) + system=$tcl_cv_sys_version +]) + +#-------------------------------------------------------------------- +# TEA_CONFIG_CFLAGS +# +# Try to determine the proper flags to pass to the compiler +# for building shared libraries and other such nonsense. +# +# Arguments: +# none +# +# Results: +# +# Defines and substitutes the following vars: +# +# DL_OBJS, DL_LIBS - removed for TEA, only needed by core. +# LDFLAGS - Flags to pass to the compiler when linking object +# files into an executable application binary such +# as tclsh. +# LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", +# that tell the run-time dynamic linker where to look +# for shared libraries such as libtcl.so. Depends on +# the variable LIB_RUNTIME_DIR in the Makefile. Could +# be the same as CC_SEARCH_FLAGS if ${CC} is used to link. +# CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", +# that tell the run-time dynamic linker where to look +# for shared libraries such as libtcl.so. Depends on +# the variable LIB_RUNTIME_DIR in the Makefile. +# SHLIB_CFLAGS - Flags to pass to cc when compiling the components +# of a shared library (may request position-independent +# code, among other things). +# SHLIB_LD - Base command to use for combining object files +# into a shared library. +# SHLIB_LD_LIBS - Dependent libraries for the linker to scan when +# creating shared libraries. This symbol typically +# goes at the end of the "ld" commands that build +# shared libraries. The value of the symbol defaults to +# "${LIBS}" if all of the dependent libraries should +# be specified when creating a shared library. If +# dependent libraries should not be specified (as on +# SunOS 4.x, where they cause the link to fail, or in +# general if Tcl and Tk aren't themselves shared +# libraries), then this symbol has an empty string +# as its value. +# SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable +# extensions. An empty string means we don't know how +# to use shared libraries on this platform. +# LIB_SUFFIX - Specifies everything that comes after the "libfoo" +# in a static or shared library name, using the $VERSION variable +# to put the version in the right place. This is used +# by platforms that need non-standard library names. +# Examples: ${VERSION}.so.1.1 on NetBSD, since it needs +# to have a version after the .so, and ${VERSION}.a +# on AIX, since a shared library needs to have +# a .a extension whereas shared objects for loadable +# extensions have a .so extension. Defaults to +# ${VERSION}${SHLIB_SUFFIX}. +# CFLAGS_DEBUG - +# Flags used when running the compiler in debug mode +# CFLAGS_OPTIMIZE - +# Flags used when running the compiler in optimize mode +# CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_CONFIG_CFLAGS], [ + dnl TEA specific: Make sure we are initialized + AC_REQUIRE([TEA_INIT]) + + # Step 0.a: Enable 64 bit support? + + AC_MSG_CHECKING([if 64bit support is requested]) + AC_ARG_ENABLE(64bit, + AC_HELP_STRING([--enable-64bit], + [enable 64bit support (default: off)]), + [do64bit=$enableval], [do64bit=no]) + AC_MSG_RESULT([$do64bit]) + + # Step 0.b: Enable Solaris 64 bit VIS support? + + AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) + AC_ARG_ENABLE(64bit-vis, + AC_HELP_STRING([--enable-64bit-vis], + [enable 64bit Sparc VIS support (default: off)]), + [do64bitVIS=$enableval], [do64bitVIS=no]) + AC_MSG_RESULT([$do64bitVIS]) + # Force 64bit on with VIS + AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) + + # Step 0.c: Check if visibility support is available. Do this here so + # that platform specific alternatives can be used below if this fails. + + AC_CACHE_CHECK([if compiler supports visibility "hidden"], + tcl_cv_cc_visibility_hidden, [ + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" + AC_TRY_LINK([ + extern __attribute__((__visibility__("hidden"))) void f(void); + void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, + tcl_cv_cc_visibility_hidden=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ + AC_DEFINE(MODULE_SCOPE, + [extern __attribute__((__visibility__("hidden")))], + [Compiler support for module scope symbols]) + ]) + + # Step 0.d: Disable -rpath support? + + AC_MSG_CHECKING([if rpath support is requested]) + AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--disable-rpath], + [disable rpath support (default: on)]), + [doRpath=$enableval], [doRpath=yes]) + AC_MSG_RESULT([$doRpath]) + + # TEA specific: Cross-compiling options for Windows/CE builds? + + AS_IF([test "${TEA_PLATFORM}" = windows], [ + AC_MSG_CHECKING([if Windows/CE build is requested]) + AC_ARG_ENABLE(wince, + AC_HELP_STRING([--enable-wince], + [enable Win/CE support (where applicable)]), + [doWince=$enableval], [doWince=no]) + AC_MSG_RESULT([$doWince]) + ]) + + # Set the variable "system" to hold the name and version number + # for the system. + + TEA_CONFIG_SYSTEM + + # Require ranlib early so we can override it in special cases below. + + AC_REQUIRE([AC_PROG_RANLIB]) + + # Set configuration options based on system name and version. + # This is similar to Tcl's unix/tcl.m4 except that we've added a + # "windows" case and removed some core-only vars. + + do64bit_ok=no + # default to '{$LIBS}' and set to "" on per-platform necessary basis + SHLIB_LD_LIBS='${LIBS}' + # When ld needs options to work in 64-bit mode, put them in + # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] + # is disabled by the user. [Bug 1016796] + LDFLAGS_ARCH="" + UNSHARED_LIB_SUFFIX="" + # TEA specific: use PACKAGE_VERSION instead of VERSION + TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' + ECHO_VERSION='`echo ${PACKAGE_VERSION}`' + TCL_LIB_VERSIONS_OK=ok + CFLAGS_DEBUG=-g + AS_IF([test "$GCC" = yes], [ + CFLAGS_OPTIMIZE=-O2 + CFLAGS_WARNING="-Wall" + ], [ + CFLAGS_OPTIMIZE=-O + CFLAGS_WARNING="" + ]) + AC_CHECK_TOOL(AR, ar) + STLIB_LD='${AR} cr' + LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" + AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION="1.0"]) + case $system in + # TEA specific: + windows) + # This is a 2-stage check to make sure we have the 64-bit SDK + # We have to know where the SDK is installed. + # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs + # MACHINE is IX86 for LINK, but this is used by the manifest, + # which requires x86|amd64|ia64. + MACHINE="X86" + if test "$do64bit" != "no" ; then + if test "x${MSSDK}x" = "xx" ; then + MSSDK="C:/Progra~1/Microsoft Platform SDK" + fi + MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` + PATH64="" + case "$do64bit" in + amd64|x64|yes) + MACHINE="AMD64" ; # default to AMD64 64-bit build + PATH64="${MSSDK}/Bin/Win64/x86/AMD64" + ;; + ia64) + MACHINE="IA64" + PATH64="${MSSDK}/Bin/Win64" + ;; + esac + if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then + AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) + AC_MSG_WARN([Ensure latest Platform SDK is installed]) + do64bit="no" + else + AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) + do64bit_ok="yes" + fi + fi + + if test "$doWince" != "no" ; then + if test "$do64bit" != "no" ; then + AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) + fi + if test "$GCC" = "yes" ; then + AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) + fi + TEA_PATH_CELIB + # Set defaults for common evc4/PPC2003 setup + # Currently Tcl requires 300+, possibly 420+ for sockets + CEVERSION=420; # could be 211 300 301 400 420 ... + TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... + ARCH=ARM; # could be ARM MIPS X86EM ... + PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" + if test "$doWince" != "yes"; then + # If !yes then the user specified something + # Reset ARCH to allow user to skip specifying it + ARCH= + eval `echo $doWince | awk -F, '{ \ + if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ + if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ + if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ + if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ + if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ + }'` + if test "x${ARCH}" = "x" ; then + ARCH=$TARGETCPU; + fi + fi + OSVERSION=WCE$CEVERSION; + if test "x${WCEROOT}" = "x" ; then + WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" + if test ! -d "${WCEROOT}" ; then + WCEROOT="C:/Program Files/Microsoft eMbedded Tools" + fi + fi + if test "x${SDKROOT}" = "x" ; then + SDKROOT="C:/Program Files/Windows CE Tools" + if test ! -d "${SDKROOT}" ; then + SDKROOT="C:/Windows CE Tools" + fi + fi + WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` + SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` + if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ + -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then + AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) + doWince="no" + else + # We could PATH_NOSPACE these, but that's not important, + # as long as we quote them when used. + CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" + if test -d "${CEINCLUDE}/${TARGETCPU}" ; then + CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" + fi + CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" + fi + fi + + if test "$GCC" != "yes" ; then + if test "${SHARED_BUILD}" = "0" ; then + runtime=-MT + else + runtime=-MD + fi + + if test "$do64bit" != "no" ; then + # All this magic is necessary for the Win64 SDK RC1 - hobbs + CC="\"${PATH64}/cl.exe\"" + CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" + RC="\"${MSSDK}/bin/rc.exe\"" + lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" + LINKBIN="\"${PATH64}/link.exe\"" + CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" + CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" + # Avoid 'unresolved external symbol __security_cookie' + # errors, c.f. http://support.microsoft.com/?id=894573 + TEA_ADD_LIBS([bufferoverflowU.lib]) + elif test "$doWince" != "no" ; then + CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" + if test "${TARGETCPU}" = "X86"; then + CC="\"${CEBINROOT}/cl.exe\"" + else + CC="\"${CEBINROOT}/cl${ARCH}.exe\"" + fi + CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" + RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" + arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` + defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" + if test "${SHARED_BUILD}" = "1" ; then + # Static CE builds require static celib as well + defs="${defs} _DLL" + fi + for i in $defs ; do + AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) + done + AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) + AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) + CFLAGS_DEBUG="-nologo -Zi -Od" + CFLAGS_OPTIMIZE="-nologo -Ox" + lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` + lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" + LINKBIN="\"${CEBINROOT}/link.exe\"" + AC_SUBST(CELIB_DIR) + else + RC="rc" + lflags="-nologo" + LINKBIN="link" + CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" + CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" + fi + fi + + if test "$GCC" = "yes"; then + # mingw gcc mode + AC_CHECK_TOOL(RC, windres) + CFLAGS_DEBUG="-g" + CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" + SHLIB_LD='${CC} -shared' + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" + LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" + + AC_CACHE_CHECK(for cross-compile version of gcc, + ac_cv_cross, + AC_TRY_COMPILE([ + #ifdef __WIN32__ + #error cross-compiler + #endif + ], [], + ac_cv_cross=yes, + ac_cv_cross=no) + ) + + if test "$ac_cv_cross" = "yes"; then + case "$do64bit" in + amd64|x64|yes) + CC="x86_64-w64-mingw32-gcc" + LD="x86_64-w64-mingw32-ld" + AR="x86_64-w64-mingw32-ar" + RANLIB="x86_64-w64-mingw32-ranlib" + RC="x86_64-w64-mingw32-windres" + ;; + *) + CC="i686-w64-mingw32-gcc" + LD="i686-w64-mingw32-ld" + AR="i686-w64-mingw32-ar" + RANLIB="i686-w64-mingw32-ranlib" + RC="i686-w64-mingw32-windres" + ;; + esac + fi + + else + SHLIB_LD="${LINKBIN} -dll ${lflags}" + # link -lib only works when -lib is the first arg + STLIB_LD="${LINKBIN} -lib ${lflags}" + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' + PATHTYPE=-w + # For information on what debugtype is most useful, see: + # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp + # and also + # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx + # This essentially turns it all on. + LDFLAGS_DEBUG="-debug -debugtype:cv" + LDFLAGS_OPTIMIZE="-release" + if test "$doWince" != "no" ; then + LDFLAGS_CONSOLE="-link ${lflags}" + LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} + else + LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" + LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" + fi + fi + + SHLIB_SUFFIX=".dll" + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' + + TCL_LIB_VERSIONS_OK=nodots + ;; + AIX-*) + AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ + # AIX requires the _r compiler when gcc isn't being used + case "${CC}" in + *_r|*_r\ *) + # ok ... + ;; + *) + # Make sure only first arg gets _r + CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` + ;; + esac + AC_MSG_RESULT([Using $CC for compiling with threads]) + ]) + LIBS="$LIBS -lc" + SHLIB_CFLAGS="" + SHLIB_SUFFIX=".so" + + LD_LIBRARY_PATH_VAR="LIBPATH" + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = yes], [ + AS_IF([test "$GCC" = yes], [ + AC_MSG_WARN([64bit mode not supported with GCC on $system]) + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS -q64" + LDFLAGS_ARCH="-q64" + RANLIB="${RANLIB} -X64" + AR="${AR} -X64" + SHLIB_LD_FLAGS="-b64" + ]) + ]) + + AS_IF([test "`uname -m`" = ia64], [ + # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + AS_IF([test "$GCC" = yes], [ + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + ], [ + CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' + ]) + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + ], [ + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared -Wl,-bexpall' + ], [ + SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" + LDFLAGS="$LDFLAGS -brtl" + ]) + SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ]) + ;; + BeOS*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -nostart' + SHLIB_SUFFIX=".so" + + #----------------------------------------------------------- + # Check for inet_ntoa in -lbind, for BeOS (which also needs + # -lsocket, even if the network functions are in -lnet which + # is always linked to, for compatibility. + #----------------------------------------------------------- + AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) + ;; + BSD/OS-4.*) + SHLIB_CFLAGS="-export-dynamic -fPIC" + SHLIB_LD='${CC} -shared' + SHLIB_SUFFIX=".so" + LDFLAGS="$LDFLAGS -export-dynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + CYGWIN_*) + SHLIB_CFLAGS="" + SHLIB_LD='${CC} -shared' + SHLIB_SUFFIX=".dll" + EXEEXT=".exe" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + Haiku*) + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' + AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) + ;; + HP-UX-*.11.*) + # Use updated header definitions where possible + AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) + # TEA specific: Needed by Tcl, but not most extensions + #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) + #LIBS="$LIBS -lxnet" # Use the XOPEN network library + + AS_IF([test "`uname -m`" = ia64], [ + SHLIB_SUFFIX=".so" + # Use newer C++ library for C++ extensions + #if test "$GCC" != "yes" ; then + # CPPFLAGS="-AA" + #fi + ], [ + SHLIB_SUFFIX=".sl" + ]) + AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) + AS_IF([test "$tcl_ok" = yes], [ + LDFLAGS="$LDFLAGS -Wl,-E" + CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' + LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' + LD_LIBRARY_PATH_VAR="SHLIB_PATH" + ]) + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ], [ + CFLAGS="$CFLAGS -z" + # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc + #CFLAGS="$CFLAGS +DAportable" + SHLIB_CFLAGS="+z" + SHLIB_LD="ld -b" + ]) + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = "yes"], [ + AS_IF([test "$GCC" = yes], [ + case `${CC} -dumpmachine` in + hppa64*) + # 64-bit gcc in use. Fix flags for GNU ld. + do64bit_ok=yes + SHLIB_LD='${CC} -shared' + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ;; + *) + AC_MSG_WARN([64bit mode not supported with GCC on $system]) + ;; + esac + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS +DD64" + LDFLAGS_ARCH="+DD64" + ]) + ]) ;; + IRIX-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "$GCC" = yes], [ + CFLAGS="$CFLAGS -mabi=n32" + LDFLAGS="$LDFLAGS -mabi=n32" + ], [ + case $system in + IRIX-6.3) + # Use to build 6.2 compatible binaries on 6.3. + CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" + ;; + *) + CFLAGS="$CFLAGS -n32" + ;; + esac + LDFLAGS="$LDFLAGS -n32" + ]) + ;; + IRIX64-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + + # Check to enable 64-bit flags for compiler/linker + + AS_IF([test "$do64bit" = yes], [ + AS_IF([test "$GCC" = yes], [ + AC_MSG_WARN([64bit mode not supported by gcc]) + ], [ + do64bit_ok=yes + SHLIB_LD="ld -64 -shared -rdata_shared" + CFLAGS="$CFLAGS -64" + LDFLAGS_ARCH="-64" + ]) + ]) + ;; + Linux*) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + + # TEA specific: + CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" + + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) + AS_IF([test $do64bit = yes], [ + AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -m64" + AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_m64 = yes], [ + CFLAGS="$CFLAGS -m64" + do64bit_ok=yes + ]) + ]) + + # The combo of gcc + glibc has a bug related to inlining of + # functions like strtod(). The -fno-builtin flag should address + # this problem but it does not work. The -fno-inline flag is kind + # of overkill but it works. Disable inlining only when one of the + # files in compat/*.c is being linked in. + + AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) + + ;; + GNU*) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + + SHLIB_LD='${CC} -shared' + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) + ;; + Lynx*) + SHLIB_CFLAGS="-fPIC" + SHLIB_SUFFIX=".so" + CFLAGS_OPTIMIZE=-02 + SHLIB_LD='${CC} -shared' + LD_FLAGS="-Wl,--export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + ;; + OpenBSD-*) + arch=`arch -s` + case "$arch" in + m88k|vax) + SHLIB_SUFFIX="" + SHARED_LIB_SUFFIX="" + ;; + *) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}' + ;; + esac + case "$arch" in + m88k|vax) + CFLAGS_OPTIMIZE="-O1" + ;; + *) + CFLAGS_OPTIMIZE="-O2" + ;; + esac + AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ + AC_EGREP_CPP(yes, [ +#ifdef __ELF__ + yes +#endif + ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) + AS_IF([test $tcl_cv_ld_elf = yes], [ + LDFLAGS=-Wl,-export-dynamic + ], [LDFLAGS=""]) + AS_IF([test "${TCL_THREADS}" = "1"], [ + # On OpenBSD: Compile with -pthread + # Don't link with -lpthread + LIBS=`echo $LIBS | sed s/-lpthread//` + CFLAGS="$CFLAGS -pthread" + ]) + # OpenBSD doesn't do version numbers with dots. + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + TCL_LIB_VERSIONS_OK=nodots + ;; + NetBSD-*|FreeBSD-[[3-4]].*) + # FreeBSD 3.* and greater have ELF. + # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_SUFFIX=".so" + LDFLAGS="$LDFLAGS -export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "${TCL_THREADS}" = "1"], [ + # The -pthread needs to go in the CFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ]) + case $system in + FreeBSD-3.*) + # FreeBSD-3 doesn't handle version numbers with dots. + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' + TCL_LIB_VERSIONS_OK=nodots + ;; + esac + ;; + FreeBSD-*) + # This configuration from FreeBSD Ports. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="${CC} -shared" + TCL_SHLIB_LD_EXTRAS="-soname \$[@]" + SHLIB_SUFFIX=".so" + LDFLAGS="" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "${TCL_THREADS}" = "1"], [ + # The -pthread needs to go in the LDFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) + # Version numbers are dot-stripped by system policy. + TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .` + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' + TCL_LIB_VERSIONS_OK=nodots + ;; + Darwin-*) + CFLAGS_OPTIMIZE="-Os" + SHLIB_CFLAGS="-fno-common" + # To avoid discrepancies between what headers configure sees during + # preprocessing tests and compiling tests, move any -isysroot and + # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: + CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ + awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ + if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" + CFLAGS="`echo " ${CFLAGS}" | \ + awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ + if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" + AS_IF([test $do64bit = yes], [ + case `arch` in + ppc) + AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], + tcl_cv_cc_arch_ppc64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, + tcl_cv_cc_arch_ppc64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + do64bit_ok=yes + ]);; + i386) + AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], + tcl_cv_cc_arch_x86_64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -arch x86_64" + AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, + tcl_cv_cc_arch_x86_64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ + CFLAGS="$CFLAGS -arch x86_64" + do64bit_ok=yes + ]);; + *) + AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; + esac + ], [ + # Check for combined 32-bit and 64-bit fat build + AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ + && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ + fat_32_64=yes]) + ]) + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' + AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" + AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_single_module = yes], [ + SHLIB_LD="${SHLIB_LD} -Wl,-single_module" + ]) + # TEA specific: link shlib with current and compatiblity version flags + vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` + SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" + SHLIB_SUFFIX=".dylib" + # Don't use -prebind when building for Mac OS X 10.4 or later only: + AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ + "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ + LDFLAGS="$LDFLAGS -prebind"]) + LDFLAGS="$LDFLAGS -headerpad_max_install_names" + AC_CACHE_CHECK([if ld accepts -search_paths_first flag], + tcl_cv_ld_search_paths_first, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, + tcl_cv_ld_search_paths_first=no) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + ]) + AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ + AC_DEFINE(MODULE_SCOPE, [__private_extern__], + [Compiler support for module scope symbols]) + tcl_cv_cc_visibility_hidden=yes + ]) + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" + # TEA specific: for combined 32 & 64 bit fat builds of Tk + # extensions, verify that 64-bit build is possible. + AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ + AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ + AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' + done + CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" + LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" + AC_TRY_LINK([#include <X11/Xlib.h>], [XrmInitialize();], + tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done]) + ]) + AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ + AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' + done + CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" + LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" + AC_TRY_LINK([#include <tk.h>], [Tk_InitStubs(NULL, "", 0);], + tcl_cv_lib_tk_64=yes, tcl_cv_lib_tk_64=no) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done]) + ]) + # remove 64-bit arch flags from CFLAGS et al. if configuration + # does not support 64-bit. + AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ + AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' + done]) + ]) + ;; + OS/390-*) + CFLAGS_OPTIMIZE="" # Optimizer is buggy + AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h + [Should OS/390 do the right thing with sockets?]) + ;; + OSF1-V*) + # Digital OSF/1 + SHLIB_CFLAGS="" + AS_IF([test "$SHARED_BUILD" = 1], [ + SHLIB_LD='ld -shared -expect_unresolved "*"' + ], [ + SHLIB_LD='ld -non_shared -expect_unresolved "*"' + ]) + SHLIB_SUFFIX=".so" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ + CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) + # see pthread_intro(3) for pthread support on osf1, k.furukawa + AS_IF([test "${TCL_THREADS}" = 1], [ + CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" + CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" + LIBS=`echo $LIBS | sed s/-lpthreads//` + AS_IF([test "$GCC" = yes], [ + LIBS="$LIBS -lpthread -lmach -lexc" + ], [ + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ]) + ]) + ;; + QNX-6*) + # QNX RTP + # This may work for all QNX, but it was only reported for v6. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="ld -Bshareable -x" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SCO_SV-3.2*) + AS_IF([test "$GCC" = yes], [ + SHLIB_CFLAGS="-fPIC -melf" + LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" + ], [ + SHLIB_CFLAGS="-Kpic -belf" + LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" + ]) + SHLIB_LD="ld -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SunOS-5.[[0-6]]) + # Careful to not let 5.10+ fall into this case + + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + + SHLIB_CFLAGS="-KPIC" + SHLIB_SUFFIX=".so" + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ], [ + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ]) + ;; + SunOS-5*) + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + + SHLIB_CFLAGS="-KPIC" + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = yes], [ + arch=`isainfo` + AS_IF([test "$arch" = "sparcv9 sparc"], [ + AS_IF([test "$GCC" = yes], [ + AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ + AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS -m64 -mcpu=v9" + LDFLAGS="$LDFLAGS -m64 -mcpu=v9" + SHLIB_CFLAGS="-fPIC" + ]) + ], [ + do64bit_ok=yes + AS_IF([test "$do64bitVIS" = yes], [ + CFLAGS="$CFLAGS -xarch=v9a" + LDFLAGS_ARCH="-xarch=v9a" + ], [ + CFLAGS="$CFLAGS -xarch=v9" + LDFLAGS_ARCH="-xarch=v9" + ]) + # Solaris 64 uses this as well + #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" + ]) + ], [AS_IF([test "$arch" = "amd64 i386"], [ + AS_IF([test "$GCC" = yes], [ + case $system in + SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) + do64bit_ok=yes + CFLAGS="$CFLAGS -m64" + LDFLAGS="$LDFLAGS -m64";; + *) + AC_MSG_WARN([64bit mode not supported with GCC on $system]);; + esac + ], [ + do64bit_ok=yes + case $system in + SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) + CFLAGS="$CFLAGS -m64" + LDFLAGS="$LDFLAGS -m64";; + *) + CFLAGS="$CFLAGS -xarch=amd64" + LDFLAGS="$LDFLAGS -xarch=amd64";; + esac + ]) + ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) + ]) + + SHLIB_SUFFIX=".so" + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "$do64bit_ok" = yes], [ + AS_IF([test "$arch" = "sparcv9 sparc"], [ + # We need to specify -static-libgcc or we need to + # add the path to the sparv9 libgcc. + # JH: static-libgcc is necessary for core Tcl, but may + # not be necessary for extensions. + SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" + # for finding sparcv9 libgcc, get the regular libgcc + # path, remove so name and append 'sparcv9' + #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." + #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" + ], [AS_IF([test "$arch" = "amd64 i386"], [ + # JH: static-libgcc is necessary for core Tcl, but may + # not be necessary for extensions. + SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" + ])]) + ]) + ], [ + case $system in + SunOS-5.[[1-9]][[0-9]]*) + # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS + SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; + *) + SHLIB_LD='/usr/ccs/bin/ld -G -z text';; + esac + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + ]) + ;; + esac + + AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ + AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) + ]) + +dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so +dnl # until the end of configure, as configure's compile and link tests use +dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's +dnl # preprocessing tests use only CPPFLAGS. + AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) + + # Add in the arch flags late to ensure it wasn't removed. + # Not necessary in TEA, but this is aligned with core + LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" + + # If we're running gcc, then change the C flags for compiling shared + # libraries to the right flags for gcc, instead of those for the + # standard manufacturer compiler. + + AS_IF([test "$GCC" = yes], [ + case $system in + AIX-*) ;; + BSD/OS*) ;; + CYGWIN_*) ;; + IRIX*) ;; + NetBSD-*|FreeBSD-*|OpenBSD-*) ;; + Darwin-*) ;; + SCO_SV-3.2*) ;; + windows) ;; + *) SHLIB_CFLAGS="-fPIC" ;; + esac]) + + AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ + AC_DEFINE(MODULE_SCOPE, [extern], + [No Compiler support for module scope symbols]) + AC_DEFINE(NO_VIZ, [], [No visibility hidden passed to zlib?]) + ]) + + AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ + # TEA specific: use PACKAGE_VERSION instead of VERSION + SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) + AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ + # TEA specific: use PACKAGE_VERSION instead of VERSION + UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) + + AC_CACHE_CHECK(for SEH support in compiler, + tcl_cv_seh, + AC_TRY_RUN([ + #define WIN32_LEAN_AND_MEAN + #include <windows.h> + #undef WIN32_LEAN_AND_MEAN + + int main(int argc, char** argv) { + int a, b = 0; + __try { + a = 666 / b; + } + __except (EXCEPTION_EXECUTE_HANDLER) { + return 0; + } + return 1; + } + ], + tcl_cv_seh=yes, + tcl_cv_seh=no, + tcl_cv_seh=no) + ) + if test "$tcl_cv_seh" = "no" ; then + AC_DEFINE(HAVE_NO_SEH, 1, + [Defined when mingw does not support SEH]) + fi + + # + # Check to see if the excpt.h include file provided contains the + # definition for EXCEPTION_DISPOSITION; if not, which is the case + # with Cygwin's version as of 2002-04-10, define it to be int, + # sufficient for getting the current code to work. + # + AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files, + tcl_cv_eh_disposition, + AC_TRY_COMPILE([ +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# undef WIN32_LEAN_AND_MEAN + ],[ + EXCEPTION_DISPOSITION x; + ], + tcl_cv_eh_disposition=yes, + tcl_cv_eh_disposition=no) + ) + if test "$tcl_cv_eh_disposition" = "no" ; then + AC_DEFINE(EXCEPTION_DISPOSITION, int, + [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION]) + fi + + # Check to see if winnt.h defines CHAR, SHORT, and LONG + # even if VOID has already been #defined. The win32api + # used by mingw and cygwin is known to do this. + + AC_CACHE_CHECK(for winnt.h that ignores VOID define, + tcl_cv_winnt_ignore_void, + AC_TRY_COMPILE([ + #define VOID void + #define WIN32_LEAN_AND_MEAN + #include <windows.h> + #undef WIN32_LEAN_AND_MEAN + ], [ + CHAR c; + SHORT s; + LONG l; + ], + tcl_cv_winnt_ignore_void=yes, + tcl_cv_winnt_ignore_void=no) + ) + if test "$tcl_cv_winnt_ignore_void" = "yes" ; then + AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1, + [Defined when cygwin/mingw ignores VOID define in winnt.h]) + fi + + # See if the compiler supports casting to a union type. + # This is used to stop gcc from printing a compiler + # warning when initializing a union member. + + AC_CACHE_CHECK(for cast to union support, + tcl_cv_cast_to_union, + AC_TRY_COMPILE([], + [ + union foo { int i; double d; }; + union foo f = (union foo) (int) 0; + ], + tcl_cv_cast_to_union=yes, + tcl_cv_cast_to_union=no) + ) + if test "$tcl_cv_cast_to_union" = "yes"; then + AC_DEFINE(HAVE_CAST_TO_UNION, 1, + [Defined when compiler supports casting to union type.]) + fi + + AC_SUBST(CFLAGS_DEBUG) + AC_SUBST(CFLAGS_OPTIMIZE) + AC_SUBST(CFLAGS_WARNING) + + AC_SUBST(STLIB_LD) + AC_SUBST(SHLIB_LD) + + AC_SUBST(SHLIB_LD_LIBS) + AC_SUBST(SHLIB_CFLAGS) + + AC_SUBST(LD_LIBRARY_PATH_VAR) + + # These must be called after we do the basic CFLAGS checks and + # verify any possible 64-bit or similar switches are necessary + TEA_TCL_EARLY_FLAGS + TEA_TCL_64BIT_FLAGS +]) + +#-------------------------------------------------------------------- +# TEA_SERIAL_PORT +# +# Determine which interface to use to talk to the serial port. +# Note that #include lines must begin in leftmost column for +# some compilers to recognize them as preprocessor directives, +# and some build environments have stdin not pointing at a +# pseudo-terminal (usually /dev/null instead.) +# +# Arguments: +# none +# +# Results: +# +# Defines only one of the following vars: +# HAVE_SYS_MODEM_H +# USE_TERMIOS +# USE_TERMIO +# USE_SGTTY +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_SERIAL_PORT], [ + AC_CHECK_HEADERS(sys/modem.h) + AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ + AC_TRY_RUN([ +#include <termios.h> + +int main() { + struct termios t; + if (tcgetattr(0, &t) == 0) { + cfsetospeed(&t, 0); + t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include <termio.h> + +int main() { + struct termio t; + if (ioctl(0, TCGETA, &t) == 0) { + t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include <sgtty.h> + +int main() { + struct sgttyb t; + if (ioctl(0, TIOCGETP, &t) == 0) { + t.sg_ospeed = 0; + t.sg_flags |= ODDP | EVENP | RAW; + return 0; + } + return 1; +}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include <termios.h> +#include <errno.h> + +int main() { + struct termios t; + if (tcgetattr(0, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + cfsetospeed(&t, 0); + t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no; then + AC_TRY_RUN([ +#include <termio.h> +#include <errno.h> + +int main() { + struct termio t; + if (ioctl(0, TCGETA, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; + }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no; then + AC_TRY_RUN([ +#include <sgtty.h> +#include <errno.h> + +int main() { + struct sgttyb t; + if (ioctl(0, TIOCGETP, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + t.sg_ospeed = 0; + t.sg_flags |= ODDP | EVENP | RAW; + return 0; + } + return 1; +}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) + fi]) + case $tcl_cv_api_serial in + termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; + termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; + sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; + esac +]) + +#-------------------------------------------------------------------- +# TEA_MISSING_POSIX_HEADERS +# +# Supply substitutes for missing POSIX header files. Special +# notes: +# - stdlib.h doesn't define strtol, strtoul, or +# strtod in some versions of SunOS +# - some versions of string.h don't declare procedures such +# as strstr +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# NO_DIRENT_H +# NO_ERRNO_H +# NO_VALUES_H +# HAVE_LIMITS_H or NO_LIMITS_H +# NO_STDLIB_H +# NO_STRING_H +# NO_SYS_WAIT_H +# NO_DLFCN_H +# HAVE_SYS_PARAM_H +# +# HAVE_STRING_H ? +# +# tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and +# CHECK on limits.h +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [ + AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ + AC_TRY_LINK([#include <sys/types.h> +#include <dirent.h>], [ +#ifndef _POSIX_SOURCE +# ifdef __Lynx__ + /* + * Generate compilation error to make the test fail: Lynx headers + * are only valid if really in the POSIX environment. + */ + + missing_procedure(); +# endif +#endif +DIR *d; +struct dirent *entryPtr; +char *p; +d = opendir("foobar"); +entryPtr = readdir(d); +p = entryPtr->d_name; +closedir(d); +], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) + + if test $tcl_cv_dirent_h = no; then + AC_DEFINE(NO_DIRENT_H, 1, [Do we have <dirent.h>?]) + fi + + # TEA specific: + AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have <errno.h>?])]) + AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have <float.h>?])]) + AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have <values.h>?])]) + AC_CHECK_HEADER(limits.h, + [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have <limits.h>?])], + [AC_DEFINE(NO_LIMITS_H, 1, [Do we have <limits.h>?])]) + AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) + AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) + AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) + AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) + if test $tcl_ok = 0; then + AC_DEFINE(NO_STDLIB_H, 1, [Do we have <stdlib.h>?]) + fi + AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) + AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) + AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) + + # See also memmove check below for a place where NO_STRING_H can be + # set and why. + + if test $tcl_ok = 0; then + AC_DEFINE(NO_STRING_H, 1, [Do we have <string.h>?]) + fi + + AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have <sys/wait.h>?])]) + AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have <dlfcn.h>?])]) + + # OS/390 lacks sys/param.h (and doesn't need it, by chance). + AC_HAVE_HEADERS(sys/param.h) +]) + +#-------------------------------------------------------------------- +# TEA_PATH_X +# +# Locate the X11 header files and the X11 library archive. Try +# the ac_path_x macro first, but if it doesn't find the X stuff +# (e.g. because there's no xmkmf program) then check through +# a list of possible directories. Under some conditions the +# autoconf macro will return an include directory that contains +# no include files, so double-check its result just to be safe. +# +# This should be called after TEA_CONFIG_CFLAGS as setting the +# LIBS line can confuse some configure macro magic. +# +# Arguments: +# none +# +# Results: +# +# Sets the following vars: +# XINCLUDES +# XLIBSW +# PKG_LIBS (appends to) +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_PATH_X], [ + if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then + TEA_PATH_UNIX_X + fi +]) + +AC_DEFUN([TEA_PATH_UNIX_X], [ + AC_PATH_X + not_really_there="" + if test "$no_x" = ""; then + if test "$x_includes" = ""; then + AC_TRY_CPP([#include <X11/XIntrinsic.h>], , not_really_there="yes") + else + if test ! -r $x_includes/X11/Intrinsic.h; then + not_really_there="yes" + fi + fi + fi + if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then + AC_MSG_CHECKING([for X11 header files]) + found_xincludes="no" + AC_TRY_CPP([#include <X11/Intrinsic.h>], found_xincludes="yes", found_xincludes="no") + if test "$found_xincludes" = "no"; then + dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" + for i in $dirs ; do + if test -r $i/X11/Intrinsic.h; then + AC_MSG_RESULT([$i]) + XINCLUDES=" -I$i" + found_xincludes="yes" + break + fi + done + fi + else + if test "$x_includes" != ""; then + XINCLUDES="-I$x_includes" + found_xincludes="yes" + fi + fi + if test "$found_xincludes" = "no"; then + AC_MSG_RESULT([couldn't find any!]) + fi + + if test "$no_x" = yes; then + AC_MSG_CHECKING([for X11 libraries]) + XLIBSW=nope + dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" + for i in $dirs ; do + if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then + AC_MSG_RESULT([$i]) + XLIBSW="-L$i -lX11" + x_libraries="$i" + break + fi + done + else + if test "$x_libraries" = ""; then + XLIBSW=-lX11 + else + XLIBSW="-L$x_libraries -lX11" + fi + fi + if test "$XLIBSW" = nope ; then + AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) + fi + if test "$XLIBSW" = nope ; then + AC_MSG_RESULT([could not find any! Using -lX11.]) + XLIBSW=-lX11 + fi + # TEA specific: + if test x"${XLIBSW}" != x ; then + PKG_LIBS="${PKG_LIBS} ${XLIBSW}" + fi +]) + +#-------------------------------------------------------------------- +# TEA_BLOCKING_STYLE +# +# The statements below check for systems where POSIX-style +# non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. +# On these systems (mostly older ones), use the old BSD-style +# FIONBIO approach instead. +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# HAVE_SYS_IOCTL_H +# HAVE_SYS_FILIO_H +# USE_FIONBIO +# O_NONBLOCK +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_BLOCKING_STYLE], [ + AC_CHECK_HEADERS(sys/ioctl.h) + AC_CHECK_HEADERS(sys/filio.h) + TEA_CONFIG_SYSTEM + AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) + case $system in + OSF*) + AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) + AC_MSG_RESULT([FIONBIO]) + ;; + *) + AC_MSG_RESULT([O_NONBLOCK]) + ;; + esac +]) + +#-------------------------------------------------------------------- +# TEA_TIME_HANDLER +# +# Checks how the system deals with time.h, what time structures +# are used on the system, and what fields the structures have. +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# USE_DELTA_FOR_TZ +# HAVE_TM_GMTOFF +# HAVE_TM_TZADJ +# HAVE_TIMEZONE_VAR +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TIME_HANDLER], [ + AC_CHECK_HEADERS(sys/time.h) + AC_HEADER_TIME + AC_STRUCT_TIMEZONE + + AC_CHECK_FUNCS(gmtime_r localtime_r) + + AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ + AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_tzadj;], + tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) + if test $tcl_cv_member_tm_tzadj = yes ; then + AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) + fi + + AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ + AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_gmtoff;], + tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) + if test $tcl_cv_member_tm_gmtoff = yes ; then + AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) + fi + + # + # Its important to include time.h in this check, as some systems + # (like convex) have timezone functions, etc. + # + AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ + AC_TRY_COMPILE([#include <time.h>], + [extern long timezone; + timezone += 1; + exit (0);], + tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) + if test $tcl_cv_timezone_long = yes ; then + AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) + else + # + # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. + # + AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ + AC_TRY_COMPILE([#include <time.h>], + [extern time_t timezone; + timezone += 1; + exit (0);], + tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) + if test $tcl_cv_timezone_time = yes ; then + AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) + fi + fi +]) + +#-------------------------------------------------------------------- +# TEA_BUGGY_STRTOD +# +# Under Solaris 2.4, strtod returns the wrong value for the +# terminating character under some conditions. Check for this +# and if the problem exists use a substitute procedure +# "fixstrtod" (provided by Tcl) that corrects the error. +# Also, on Compaq's Tru64 Unix 5.0, +# strtod(" ") returns 0.0 instead of a failure to convert. +# +# Arguments: +# none +# +# Results: +# +# Might defines some of the following vars: +# strtod (=fixstrtod) +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_BUGGY_STRTOD], [ + AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) + if test "$tcl_strtod" = 1; then + AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ + AC_TRY_RUN([ + extern double strtod(); + int main() { + char *infString="Inf", *nanString="NaN", *spaceString=" "; + char *term; + double value; + value = strtod(infString, &term); + if ((term != infString) && (term[-1] == 0)) { + exit(1); + } + value = strtod(nanString, &term); + if ((term != nanString) && (term[-1] == 0)) { + exit(1); + } + value = strtod(spaceString, &term); + if (term == (spaceString+1)) { + exit(1); + } + exit(0); + }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, + tcl_cv_strtod_buggy=buggy)]) + if test "$tcl_cv_strtod_buggy" = buggy; then + AC_LIBOBJ([fixstrtod]) + USE_COMPAT=1 + AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) + fi + fi +]) + +#-------------------------------------------------------------------- +# TEA_TCL_LINK_LIBS +# +# Search for the libraries needed to link the Tcl shell. +# Things like the math library (-lm) and socket stuff (-lsocket vs. +# -lnsl) are dealt with here. +# +# Arguments: +# Requires the following vars to be set in the Makefile: +# DL_LIBS (not in TEA, only needed in core) +# LIBS +# MATH_LIBS +# +# Results: +# +# Subst's the following var: +# TCL_LIBS +# MATH_LIBS +# +# Might append to the following vars: +# LIBS +# +# Might define the following vars: +# HAVE_NET_ERRNO_H +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TCL_LINK_LIBS], [ + #-------------------------------------------------------------------- + # On a few very rare systems, all of the libm.a stuff is + # already in libc.a. Set compiler flags accordingly. + # Also, Linux requires the "ieee" library for math to work + # right (and it must appear before "-lm"). + #-------------------------------------------------------------------- + + AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") + AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) + + #-------------------------------------------------------------------- + # Interactive UNIX requires -linet instead of -lsocket, plus it + # needs net/errno.h to define the socket-related error codes. + #-------------------------------------------------------------------- + + AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) + AC_CHECK_HEADER(net/errno.h, [ + AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have <net/errno.h>?])]) + + #-------------------------------------------------------------------- + # Check for the existence of the -lsocket and -lnsl libraries. + # The order here is important, so that they end up in the right + # order in the command line generated by make. Here are some + # special considerations: + # 1. Use "connect" and "accept" to check for -lsocket, and + # "gethostbyname" to check for -lnsl. + # 2. Use each function name only once: can't redo a check because + # autoconf caches the results of the last check and won't redo it. + # 3. Use -lnsl and -lsocket only if they supply procedures that + # aren't already present in the normal libraries. This is because + # IRIX 5.2 has libraries, but they aren't needed and they're + # bogus: they goof up name resolution if used. + # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. + # To get around this problem, check for both libraries together + # if -lsocket doesn't work by itself. + #-------------------------------------------------------------------- + + tcl_checkBoth=0 + AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) + if test "$tcl_checkSocket" = 1; then + AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, + LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) + fi + if test "$tcl_checkBoth" = 1; then + tk_oldLibs=$LIBS + LIBS="$LIBS -lsocket -lnsl" + AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) + fi + AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, + [LIBS="$LIBS -lnsl"])]) + + # TEA specific: Don't perform the eval of the libraries here because + # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS + + TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' + AC_SUBST(TCL_LIBS) + AC_SUBST(MATH_LIBS) +]) + +#-------------------------------------------------------------------- +# TEA_TCL_EARLY_FLAGS +# +# Check for what flags are needed to be passed so the correct OS +# features are available. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# _ISOC99_SOURCE +# _LARGEFILE64_SOURCE +# _LARGEFILE_SOURCE64 +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TCL_EARLY_FLAG],[ + AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), + AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, + AC_TRY_COMPILE([[#define ]$1[ 1 +]$2], $3, + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) + if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then + AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) + tcl_flags="$tcl_flags $1" + fi +]) + +AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ + AC_MSG_CHECKING([for required early compiler flags]) + tcl_flags="" + TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include <stdlib.h>], + [char *p = (char *)strtoll; char *q = (char *)strtoull;]) + TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include <sys/stat.h>], + [struct stat64 buf; int i = stat64("/", &buf);]) + TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include <sys/stat.h>], + [char *p = (char *)open64;]) + if test "x${tcl_flags}" = "x" ; then + AC_MSG_RESULT([none]) + else + AC_MSG_RESULT([${tcl_flags}]) + fi +]) + +#-------------------------------------------------------------------- +# TEA_TCL_64BIT_FLAGS +# +# Check for what is defined in the way of 64-bit features. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# TCL_WIDE_INT_IS_LONG +# TCL_WIDE_INT_TYPE +# HAVE_STRUCT_DIRENT64 +# HAVE_STRUCT_STAT64 +# HAVE_TYPE_OFF64_T +# +#-------------------------------------------------------------------- + +AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ + AC_MSG_CHECKING([for 64-bit integer type]) + AC_CACHE_VAL(tcl_cv_type_64bit,[ + tcl_cv_type_64bit=none + # See if the compiler knows natively about __int64 + AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], + tcl_type_64bit=__int64, tcl_type_64bit="long long") + # See if we should use long anyway Note that we substitute in the + # type that is our current guess for a 64-bit type inside this check + # program, so it should be modified only carefully... + AC_TRY_COMPILE(,[switch (0) { + case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; + }],tcl_cv_type_64bit=${tcl_type_64bit})]) + if test "${tcl_cv_type_64bit}" = none ; then + AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) + AC_MSG_RESULT([using long]) + elif test "${tcl_cv_type_64bit}" = "__int64" \ + -a "${TEA_PLATFORM}" = "windows" ; then + # TEA specific: We actually want to use the default tcl.h checks in + # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* + AC_MSG_RESULT([using Tcl header defaults]) + else + AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, + [What type should be used to define wide integers?]) + AC_MSG_RESULT([${tcl_cv_type_64bit}]) + + # Now check for auxiliary declarations + AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ + AC_TRY_COMPILE([#include <sys/types.h> +#include <sys/dirent.h>],[struct dirent64 p;], + tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) + if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in <sys/types.h>?]) + fi + + AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ + AC_TRY_COMPILE([#include <sys/stat.h>],[struct stat64 p; +], + tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) + if test "x${tcl_cv_struct_stat64}" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in <sys/stat.h>?]) + fi + + AC_CHECK_FUNCS(open64 lseek64) + AC_MSG_CHECKING([for off64_t]) + AC_CACHE_VAL(tcl_cv_type_off64_t,[ + AC_TRY_COMPILE([#include <sys/types.h>],[off64_t offset; +], + tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) + dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the + dnl functions lseek64 and open64 are defined. + if test "x${tcl_cv_type_off64_t}" = "xyes" && \ + test "x${ac_cv_func_lseek64}" = "xyes" && \ + test "x${ac_cv_func_open64}" = "xyes" ; then + AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in <sys/types.h>?]) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi +]) + +## +## Here ends the standard Tcl configuration bits and starts the +## TEA specific functions +## + +#------------------------------------------------------------------------ +# TEA_INIT -- +# +# Init various Tcl Extension Architecture (TEA) variables. +# This should be the first called TEA_* macro. +# +# Arguments: +# none +# +# Results: +# +# Defines and substs the following vars: +# CYGPATH +# EXEEXT +# Defines only: +# TEA_VERSION +# TEA_INITED +# TEA_PLATFORM (windows or unix) +# +# "cygpath" is used on windows to generate native path names for include +# files. These variables should only be used with the compiler and linker +# since they generate native path names. +# +# EXEEXT +# Select the executable extension based on the host type. This +# is a lightweight replacement for AC_EXEEXT that doesn't require +# a compiler. +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_INIT], [ + # TEA extensions pass this us the version of TEA they think they + # are compatible with. + TEA_VERSION="3.9" + + AC_MSG_CHECKING([for correct TEA configuration]) + if test x"${PACKAGE_NAME}" = x ; then + AC_MSG_ERROR([ +The PACKAGE_NAME variable must be defined by your TEA configure.in]) + fi + if test x"$1" = x ; then + AC_MSG_ERROR([ +TEA version not specified.]) + elif test "$1" != "${TEA_VERSION}" ; then + AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) + else + AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) + fi + case "`uname -s`" in + *win32*|*WIN32*|*MINGW32_*) + AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo) + EXEEXT=".exe" + TEA_PLATFORM="windows" + ;; + *CYGWIN_*) + CYGPATH=echo + EXEEXT=".exe" + # TEA_PLATFORM is determined later in LOAD_TCLCONFIG + ;; + *) + CYGPATH=echo + # Maybe we are cross-compiling.... + case ${host_alias} in + *mingw32*) + EXEEXT=".exe" + TEA_PLATFORM="windows" + ;; + *) + EXEEXT="" + TEA_PLATFORM="unix" + ;; + esac + ;; + esac + + # Check if exec_prefix is set. If not use fall back to prefix. + # Note when adjusted, so that TEA_PREFIX can correct for this. + # This is needed for recursive configures, since autoconf propagates + # $prefix, but not $exec_prefix (doh!). + if test x$exec_prefix = xNONE ; then + exec_prefix_default=yes + exec_prefix=$prefix + fi + + AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) + + AC_SUBST(EXEEXT) + AC_SUBST(CYGPATH) + + # This package name must be replaced statically for AC_SUBST to work + AC_SUBST(PKG_LIB_FILE) + # Substitute STUB_LIB_FILE in case package creates a stub library too. + AC_SUBST(PKG_STUB_LIB_FILE) + + # We AC_SUBST these here to ensure they are subst'ed, + # in case the user doesn't call TEA_ADD_... + AC_SUBST(PKG_STUB_SOURCES) + AC_SUBST(PKG_STUB_OBJECTS) + AC_SUBST(PKG_TCL_SOURCES) + AC_SUBST(PKG_HEADERS) + AC_SUBST(PKG_INCLUDES) + AC_SUBST(PKG_LIBS) + AC_SUBST(PKG_CFLAGS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_SOURCES -- +# +# Specify one or more source files. Users should check for +# the right platform before adding to their list. +# It is not important to specify the directory, as long as it is +# in the generic, win or unix subdirectory of $(srcdir). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_SOURCES +# PKG_OBJECTS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_SOURCES], [ + vars="$@" + for i in $vars; do + case $i in + [\$]*) + # allow $-var names + PKG_SOURCES="$PKG_SOURCES $i" + PKG_OBJECTS="$PKG_OBJECTS $i" + ;; + *) + # check for existence - allows for generic/win/unix VPATH + # To add more dirs here (like 'src'), you have to update VPATH + # in Makefile.in as well + if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ + -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ + -a ! -f "${srcdir}/macosx/$i" \ + ; then + AC_MSG_ERROR([could not find source file '$i']) + fi + PKG_SOURCES="$PKG_SOURCES $i" + # this assumes it is in a VPATH dir + i=`basename $i` + # handle user calling this before or after TEA_SETUP_COMPILER + if test x"${OBJEXT}" != x ; then + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" + else + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" + fi + PKG_OBJECTS="$PKG_OBJECTS $j" + ;; + esac + done + AC_SUBST(PKG_SOURCES) + AC_SUBST(PKG_OBJECTS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_STUB_SOURCES -- +# +# Specify one or more source files. Users should check for +# the right platform before adding to their list. +# It is not important to specify the directory, as long as it is +# in the generic, win or unix subdirectory of $(srcdir). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_STUB_SOURCES +# PKG_STUB_OBJECTS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_STUB_SOURCES], [ + vars="$@" + for i in $vars; do + # check for existence - allows for generic/win/unix VPATH + if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ + -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ + -a ! -f "${srcdir}/macosx/$i" \ + ; then + AC_MSG_ERROR([could not find stub source file '$i']) + fi + PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" + # this assumes it is in a VPATH dir + i=`basename $i` + # handle user calling this before or after TEA_SETUP_COMPILER + if test x"${OBJEXT}" != x ; then + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" + else + j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" + fi + PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" + done + AC_SUBST(PKG_STUB_SOURCES) + AC_SUBST(PKG_STUB_OBJECTS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_TCL_SOURCES -- +# +# Specify one or more Tcl source files. These should be platform +# independent runtime files. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_TCL_SOURCES +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_TCL_SOURCES], [ + vars="$@" + for i in $vars; do + # check for existence, be strict because it is installed + if test ! -f "${srcdir}/$i" ; then + AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) + fi + PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" + done + AC_SUBST(PKG_TCL_SOURCES) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_HEADERS -- +# +# Specify one or more source headers. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_HEADERS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_HEADERS], [ + vars="$@" + for i in $vars; do + # check for existence, be strict because it is installed + if test ! -f "${srcdir}/$i" ; then + AC_MSG_ERROR([could not find header file '${srcdir}/$i']) + fi + PKG_HEADERS="$PKG_HEADERS $i" + done + AC_SUBST(PKG_HEADERS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_INCLUDES -- +# +# Specify one or more include dirs. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_INCLUDES +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_INCLUDES], [ + vars="$@" + for i in $vars; do + PKG_INCLUDES="$PKG_INCLUDES $i" + done + AC_SUBST(PKG_INCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_LIBS -- +# +# Specify one or more libraries. Users should check for +# the right platform before adding to their list. For Windows, +# libraries provided in "foo.lib" format will be converted to +# "-lfoo" when using GCC (mingw). +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_LIBS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_LIBS], [ + vars="$@" + for i in $vars; do + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then + # Convert foo.lib to -lfoo for GCC. No-op if not *.lib + i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` + fi + PKG_LIBS="$PKG_LIBS $i" + done + AC_SUBST(PKG_LIBS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_CFLAGS -- +# +# Specify one or more CFLAGS. Users should check for +# the right platform before adding to their list. +# +# Arguments: +# one or more file names +# +# Results: +# +# Defines and substs the following vars: +# PKG_CFLAGS +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_CFLAGS], [ + PKG_CFLAGS="$PKG_CFLAGS $@" + AC_SUBST(PKG_CFLAGS) +]) + +#------------------------------------------------------------------------ +# TEA_ADD_CLEANFILES -- +# +# Specify one or more CLEANFILES. +# +# Arguments: +# one or more file names to clean target +# +# Results: +# +# Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG +#------------------------------------------------------------------------ +AC_DEFUN([TEA_ADD_CLEANFILES], [ + CLEANFILES="$CLEANFILES $@" +]) + +#------------------------------------------------------------------------ +# TEA_PREFIX -- +# +# Handle the --prefix=... option by defaulting to what Tcl gave +# +# Arguments: +# none +# +# Results: +# +# If --prefix or --exec-prefix was not specified, $prefix and +# $exec_prefix will be set to the values given to Tcl when it was +# configured. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_PREFIX], [ + if test "${prefix}" = "NONE"; then + prefix_default=yes + if test x"${TCL_PREFIX}" != x; then + AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) + prefix=${TCL_PREFIX} + else + AC_MSG_NOTICE([--prefix defaulting to /usr/local]) + prefix=/usr/local + fi + fi + if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ + -o x"${exec_prefix_default}" = x"yes" ; then + if test x"${TCL_EXEC_PREFIX}" != x; then + AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) + exec_prefix=${TCL_EXEC_PREFIX} + else + AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) + exec_prefix=$prefix + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_SETUP_COMPILER_CC -- +# +# Do compiler checks the way we want. This is just a replacement +# for AC_PROG_CC in TEA configure.in files to make them cleaner. +# +# Arguments: +# none +# +# Results: +# +# Sets up CC var and other standard bits we need to make executables. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_SETUP_COMPILER_CC], [ + # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) + # in this macro, they need to go into TEA_SETUP_COMPILER instead. + + # If the user did not set CFLAGS, set it now to keep + # the AC_PROG_CC macro from adding "-g -O2". + if test "${CFLAGS+set}" != "set" ; then + CFLAGS="" + fi + + AC_PROG_CC + AC_PROG_CPP + + #-------------------------------------------------------------------- + # Checks to see if the make program sets the $MAKE variable. + #-------------------------------------------------------------------- + + AC_PROG_MAKE_SET + + #-------------------------------------------------------------------- + # Find ranlib + #-------------------------------------------------------------------- + + AC_CHECK_TOOL(RANLIB, ranlib) + + #-------------------------------------------------------------------- + # Determines the correct binary file extension (.o, .obj, .exe etc.) + #-------------------------------------------------------------------- + + AC_OBJEXT + AC_EXEEXT +]) + +#------------------------------------------------------------------------ +# TEA_SETUP_COMPILER -- +# +# Do compiler checks that use the compiler. This must go after +# TEA_SETUP_COMPILER_CC, which does the actual compiler check. +# +# Arguments: +# none +# +# Results: +# +# Sets up CC var and other standard bits we need to make executables. +#------------------------------------------------------------------------ +AC_DEFUN([TEA_SETUP_COMPILER], [ + # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. + AC_REQUIRE([TEA_SETUP_COMPILER_CC]) + + #------------------------------------------------------------------------ + # If we're using GCC, see if the compiler understands -pipe. If so, use it. + # It makes compiling go faster. (This is only a performance feature.) + #------------------------------------------------------------------------ + + if test -z "$no_pipe" -a -n "$GCC"; then + AC_CACHE_CHECK([if the compiler understands -pipe], + tcl_cv_cc_pipe, [ + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" + AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) + CFLAGS=$hold_cflags]) + if test $tcl_cv_cc_pipe = yes; then + CFLAGS="$CFLAGS -pipe" + fi + fi + + #-------------------------------------------------------------------- + # Common compiler flag setup + #-------------------------------------------------------------------- + + AC_C_BIGENDIAN + if test "${TEA_PLATFORM}" = "unix" ; then + TEA_TCL_LINK_LIBS + TEA_MISSING_POSIX_HEADERS + # Let the user call this, because if it triggers, they will + # need a compat/strtod.c that is correct. Users can also + # use Tcl_GetDouble(FromObj) instead. + #TEA_BUGGY_STRTOD + fi +]) + +#------------------------------------------------------------------------ +# TEA_MAKE_LIB -- +# +# Generate a line that can be used to build a shared/unshared library +# in a platform independent manner. +# +# Arguments: +# none +# +# Requires: +# +# Results: +# +# Defines the following vars: +# CFLAGS - Done late here to note disturb other AC macros +# MAKE_LIB - Command to execute to build the Tcl library; +# differs depending on whether or not Tcl is being +# compiled as a shared library. +# MAKE_SHARED_LIB Makefile rule for building a shared library +# MAKE_STATIC_LIB Makefile rule for building a static library +# MAKE_STUB_LIB Makefile rule for building a stub library +# VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL +# VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_MAKE_LIB], [ + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then + MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" + MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" + AC_EGREP_CPP([manifest needed], [ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +print("manifest needed") +#endif + ], [ + # Could do a CHECK_PROG for mt, but should always be with MSVC8+ + VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi" + VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi" + MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" + TEA_ADD_CLEANFILES([*.manifest]) + ]) + MAKE_STUB_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_STUB_OBJECTS)" + else + MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" + MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" + MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" + fi + + if test "${SHARED_BUILD}" = "1" ; then + MAKE_LIB="${MAKE_SHARED_LIB} " + else + MAKE_LIB="${MAKE_STATIC_LIB} " + fi + + #-------------------------------------------------------------------- + # Shared libraries and static libraries have different names. + # Use the double eval to make sure any variables in the suffix is + # substituted. (@@@ Might not be necessary anymore) + #-------------------------------------------------------------------- + + if test "${TEA_PLATFORM}" = "windows" ; then + if test "${SHARED_BUILD}" = "1" ; then + # We force the unresolved linking of symbols that are really in + # the private libraries of Tcl and Tk. + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" + if test x"${TK_BIN_DIR}" != x ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" + fi + eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + else + eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + fi + # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + if test "$GCC" = "yes"; then + PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} + fi + # These aren't needed on Windows (either MSVC or gcc) + RANLIB=: + RANLIB_STUB=: + else + RANLIB_STUB="${RANLIB}" + if test "${SHARED_BUILD}" = "1" ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" + if test x"${TK_BIN_DIR}" != x ; then + SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" + fi + eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + RANLIB=: + else + eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + fi + # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + fi + + # These are escaped so that only CFLAGS is picked up at configure time. + # The other values will be substituted at make time. + CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" + if test "${SHARED_BUILD}" = "1" ; then + CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" + fi + + AC_SUBST(MAKE_LIB) + AC_SUBST(MAKE_SHARED_LIB) + AC_SUBST(MAKE_STATIC_LIB) + AC_SUBST(MAKE_STUB_LIB) + AC_SUBST(RANLIB_STUB) + AC_SUBST(VC_MANIFEST_EMBED_DLL) + AC_SUBST(VC_MANIFEST_EMBED_EXE) +]) + +#------------------------------------------------------------------------ +# TEA_LIB_SPEC -- +# +# Compute the name of an existing object library located in libdir +# from the given base name and produce the appropriate linker flags. +# +# Arguments: +# basename The base name of the library without version +# numbers, extensions, or "lib" prefixes. +# extra_dir Extra directory in which to search for the +# library. This location is used first, then +# $prefix/$exec-prefix, then some defaults. +# +# Requires: +# TEA_INIT and TEA_PREFIX must be called first. +# +# Results: +# +# Defines the following vars: +# ${basename}_LIB_NAME The computed library name. +# ${basename}_LIB_SPEC The computed linker flags. +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LIB_SPEC], [ + AC_MSG_CHECKING([for $1 library]) + + # Look in exec-prefix for the library (defined by TEA_PREFIX). + + tea_lib_name_dir="${exec_prefix}/lib" + + # Or in a user-specified location. + + if test x"$2" != x ; then + tea_extra_lib_dir=$2 + else + tea_extra_lib_dir=NONE + fi + + for i in \ + `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ + `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ + `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do + if test -f "$i" ; then + tea_lib_name_dir=`dirname $i` + $1_LIB_NAME=`basename $i` + $1_LIB_PATH_NAME=$i + break + fi + done + + if test "${TEA_PLATFORM}" = "windows"; then + $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" + else + # Strip off the leading "lib" and trailing ".a" or ".so" + + tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` + $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" + fi + + if test "x${$1_LIB_NAME}" = x ; then + AC_MSG_ERROR([not found]) + else + AC_MSG_RESULT([${$1_LIB_SPEC}]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_PRIVATE_TCL_HEADERS -- +# +# Locate the private Tcl include files +# +# Arguments: +# +# Requires: +# TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has +# already been called. +# +# Results: +# +# Substs the following vars: +# TCL_TOP_DIR_NATIVE +# TCL_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ + # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} + AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) + AC_MSG_CHECKING([for Tcl private include files]) + + TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` + TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" + + # Check to see if tcl<Plat>Port.h isn't already with the public headers + # Don't look for tclInt.h because that resides with tcl.h in the core + # sources, but the <plat>Port headers are in a different directory + if test "${TEA_PLATFORM}" = "windows" -a \ + -f "${ac_cv_c_tclh}/tclWinPort.h"; then + result="private headers found with public headers" + elif test "${TEA_PLATFORM}" = "unix" -a \ + -f "${ac_cv_c_tclh}/tclUnixPort.h"; then + result="private headers found with public headers" + else + TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" + if test "${TEA_PLATFORM}" = "windows"; then + TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" + else + TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" + fi + # Overwrite the previous TCL_INCLUDES as this should capture both + # public and private headers in the same set. + # We want to ensure these are substituted so as not to require + # any *_NATIVE vars be defined in the Makefile + TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" + if test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use + # the framework's Headers and PrivateHeaders directories + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -d "${TCL_BIN_DIR}/Headers" -a \ + -d "${TCL_BIN_DIR}/PrivateHeaders"; then + TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" + else + TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" + fi + ;; + esac + result="Using ${TCL_INCLUDES}" + else + if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then + AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) + fi + result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" + fi + fi + + AC_SUBST(TCL_TOP_DIR_NATIVE) + + AC_SUBST(TCL_INCLUDES) + AC_MSG_RESULT([${result}]) +]) + +#------------------------------------------------------------------------ +# TEA_PUBLIC_TCL_HEADERS -- +# +# Locate the installed public Tcl header files +# +# Arguments: +# None. +# +# Requires: +# CYGPATH must be set +# +# Results: +# +# Adds a --with-tclinclude switch to configure. +# Result is cached. +# +# Substs the following vars: +# TCL_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ + AC_MSG_CHECKING([for Tcl public headers]) + + AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) + + AC_CACHE_VAL(ac_cv_c_tclh, [ + # Use the value from --with-tclinclude, if it was given + + if test x"${with_tclinclude}" != x ; then + if test -f "${with_tclinclude}/tcl.h" ; then + ac_cv_c_tclh=${with_tclinclude} + else + AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use + # the framework's Headers directory + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Look in the source dir only if Tcl is not installed, + # and in that situation, look there before installed locations. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" + fi + + # Check order: pkg --prefix location, Tcl's --prefix location, + # relative to directory of tclConfig.sh. + + eval "temp_includedir=${includedir}" + list="$list \ + `ls -d ${temp_includedir} 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then + list="$list /usr/local/include /usr/include" + if test x"${TCL_INCLUDE_SPEC}" != x ; then + d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="$list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in $list ; do + if test -f "$i/tcl.h" ; then + ac_cv_c_tclh=$i + break + fi + done + fi + ]) + + # Print a message based on how we determined the include path + + if test x"${ac_cv_c_tclh}" = x ; then + AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) + else + AC_MSG_RESULT([${ac_cv_c_tclh}]) + fi + + # Convert to a native path and substitute into the output files. + + INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` + + TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + AC_SUBST(TCL_INCLUDES) +]) + +#------------------------------------------------------------------------ +# TEA_PRIVATE_TK_HEADERS -- +# +# Locate the private Tk include files +# +# Arguments: +# +# Requires: +# TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has +# already been called. +# +# Results: +# +# Substs the following vars: +# TK_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ + # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} + AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) + AC_MSG_CHECKING([for Tk private include files]) + + TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` + TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" + + # Check to see if tk<Plat>Port.h isn't already with the public headers + # Don't look for tkInt.h because that resides with tk.h in the core + # sources, but the <plat>Port headers are in a different directory + if test "${TEA_PLATFORM}" = "windows" -a \ + -f "${ac_cv_c_tkh}/tkWinPort.h"; then + result="private headers found with public headers" + elif test "${TEA_PLATFORM}" = "unix" -a \ + -f "${ac_cv_c_tkh}/tkUnixPort.h"; then + result="private headers found with public headers" + else + TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" + TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" + if test "${TEA_PLATFORM}" = "windows"; then + TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" + else + TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" + fi + # Overwrite the previous TK_INCLUDES as this should capture both + # public and private headers in the same set. + # We want to ensure these are substituted so as not to require + # any *_NATIVE vars be defined in the Makefile + TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" + # Detect and add ttk subdir + if test -d "${TK_SRC_DIR}/generic/ttk"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" + fi + if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" + fi + if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then + TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" + fi + if test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use + # the framework's Headers and PrivateHeaders directories + case ${TK_DEFS} in + *TK_FRAMEWORK*) + if test -d "${TK_BIN_DIR}/Headers" -a \ + -d "${TK_BIN_DIR}/PrivateHeaders"; then + TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" + else + TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" + fi + ;; + esac + result="Using ${TK_INCLUDES}" + else + if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then + AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) + fi + result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" + fi + fi + + AC_SUBST(TK_TOP_DIR_NATIVE) + AC_SUBST(TK_XLIB_DIR_NATIVE) + + AC_SUBST(TK_INCLUDES) + AC_MSG_RESULT([${result}]) +]) + +#------------------------------------------------------------------------ +# TEA_PUBLIC_TK_HEADERS -- +# +# Locate the installed public Tk header files +# +# Arguments: +# None. +# +# Requires: +# CYGPATH must be set +# +# Results: +# +# Adds a --with-tkinclude switch to configure. +# Result is cached. +# +# Substs the following vars: +# TK_INCLUDES +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ + AC_MSG_CHECKING([for Tk public headers]) + + AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) + + AC_CACHE_VAL(ac_cv_c_tkh, [ + # Use the value from --with-tkinclude, if it was given + + if test x"${with_tkinclude}" != x ; then + if test -f "${with_tkinclude}/tk.h" ; then + ac_cv_c_tkh=${with_tkinclude} + else + AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) + fi + else + list="" + if test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use + # the framework's Headers directory. + case ${TK_DEFS} in + *TK_FRAMEWORK*) + list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" + ;; + esac + fi + + # Look in the source dir only if Tk is not installed, + # and in that situation, look there before installed locations. + if test -f "${TK_BIN_DIR}/Makefile" ; then + list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" + fi + + # Check order: pkg --prefix location, Tk's --prefix location, + # relative to directory of tkConfig.sh, Tcl's --prefix location, + # relative to directory of tclConfig.sh. + + eval "temp_includedir=${includedir}" + list="$list \ + `ls -d ${temp_includedir} 2>/dev/null` \ + `ls -d ${TK_PREFIX}/include 2>/dev/null` \ + `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" + if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then + list="$list /usr/local/include /usr/include" + if test x"${TK_INCLUDE_SPEC}" != x ; then + d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` + list="$list `ls -d ${d} 2>/dev/null`" + fi + fi + for i in $list ; do + if test -f "$i/tk.h" ; then + ac_cv_c_tkh=$i + break + fi + done + fi + ]) + + # Print a message based on how we determined the include path + + if test x"${ac_cv_c_tkh}" = x ; then + AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) + else + AC_MSG_RESULT([${ac_cv_c_tkh}]) + fi + + # Convert to a native path and substitute into the output files. + + INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` + + TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + + AC_SUBST(TK_INCLUDES) + + if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then + # On Windows and Aqua, we need the X compat headers + AC_MSG_CHECKING([for X11 header files]) + if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then + INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" + TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" + AC_SUBST(TK_XINCLUDES) + fi + AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_PATH_CONFIG -- +# +# Locate the ${1}Config.sh file and perform a sanity check on +# the ${1} compile flags. These are used by packages like +# [incr Tk] that load *Config.sh files from more than Tcl and Tk. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-$1=... +# +# Defines the following vars: +# $1_BIN_DIR Full path to the directory containing +# the $1Config.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_CONFIG], [ + # + # Ok, lets find the $1 configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-$1 + # + + if test x"${no_$1}" = x ; then + # we reset no_$1 in case something fails here + no_$1=true + AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) + AC_MSG_CHECKING([for $1 configuration]) + AC_CACHE_VAL(ac_cv_c_$1config,[ + + # First check to see if --with-$1 was specified. + if test x"${with_$1config}" != x ; then + case ${with_$1config} in + */$1Config.sh ) + if test -f ${with_$1config}; then + AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) + with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` + fi;; + esac + if test -f "${with_$1config}/$1Config.sh" ; then + ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` + else + AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) + fi + fi + + # then check for a private $1 installation + if test x"${ac_cv_c_$1config}" = x ; then + for i in \ + ../$1 \ + `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ../../$1 \ + `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ../../../$1 \ + `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ${srcdir}/../$1 \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ + ; do + if test -f "$i/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i; pwd)` + break + fi + if test -f "$i/unix/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i/unix; pwd)` + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_$1config}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + ; do + if test -f "$i/$1Config.sh" ; then + ac_cv_c_$1config=`(cd $i; pwd)` + break + fi + done + fi + ]) + + if test x"${ac_cv_c_$1config}" = x ; then + $1_BIN_DIR="# no $1 configs found" + AC_MSG_WARN([Cannot find $1 configuration definitions]) + exit 0 + else + no_$1= + $1_BIN_DIR=${ac_cv_c_$1config} + AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_CONFIG -- +# +# Load the $1Config.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# $1_BIN_DIR +# +# Results: +# +# Subst the following vars: +# $1_SRC_DIR +# $1_LIB_FILE +# $1_LIB_SPEC +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_LOAD_CONFIG], [ + AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) + + if test -f "${$1_BIN_DIR}/$1Config.sh" ; then + AC_MSG_RESULT([loading]) + . "${$1_BIN_DIR}/$1Config.sh" + else + AC_MSG_RESULT([file not found]) + fi + + # + # If the $1_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable $1_LIB_SPEC will be set to the value + # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC + # instead of $1_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + # + + if test -f "${$1_BIN_DIR}/Makefile" ; then + AC_MSG_WARN([Found Makefile - using build library specs for $1]) + $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} + $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} + $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} + $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} + $1_LIBRARY_PATH=${$1_LIBRARY_PATH} + fi + + AC_SUBST($1_VERSION) + AC_SUBST($1_BIN_DIR) + AC_SUBST($1_SRC_DIR) + + AC_SUBST($1_LIB_FILE) + AC_SUBST($1_LIB_SPEC) + + AC_SUBST($1_STUB_LIB_FILE) + AC_SUBST($1_STUB_LIB_SPEC) + AC_SUBST($1_STUB_LIB_PATH) + + # Allow the caller to prevent this auto-check by specifying any 2nd arg + AS_IF([test "x$2" = x], [ + # Check both upper and lower-case variants + # If a dev wanted non-stubs libs, this function could take an option + # to not use _STUB in the paths below + AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], + [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], + [TEA_LOAD_CONFIG_LIB($1_STUB)]) + ]) +]) + +#------------------------------------------------------------------------ +# TEA_LOAD_CONFIG_LIB -- +# +# Helper function to load correct library from another extension's +# ${PACKAGE}Config.sh. +# +# Results: +# Adds to LIBS the appropriate extension library +# +#------------------------------------------------------------------------ +AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ + AC_MSG_CHECKING([For $1 library for LIBS]) + # This simplifies the use of stub libraries by automatically adding + # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, + # but this is called before CONFIG_CFLAGS. More importantly, this adds + # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. + if test "x${$1_LIB_SPEC}" != "x" ; then + if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then + TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) + AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) + else + TEA_ADD_LIBS([${$1_LIB_SPEC}]) + AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) + fi + else + AC_MSG_RESULT([file not found]) + fi +]) + +#------------------------------------------------------------------------ +# TEA_EXPORT_CONFIG -- +# +# Define the data to insert into the ${PACKAGE}Config.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# $1 +# +# Results: +# Subst the following vars: +# +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_EXPORT_CONFIG], [ + #-------------------------------------------------------------------- + # These are for $1Config.sh + #-------------------------------------------------------------------- + + # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) + eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" + if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then + eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}${DBGX}" + eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}${DBGX}" + else + eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" + eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" + fi + $1_BUILD_LIB_SPEC="-L`pwd` ${$1_LIB_FLAG}" + $1_LIB_SPEC="-L${pkglibdir} ${$1_LIB_FLAG}" + $1_BUILD_STUB_LIB_SPEC="-L`pwd` [$]{$1_STUB_LIB_FLAG}" + $1_STUB_LIB_SPEC="-L${pkglibdir} [$]{$1_STUB_LIB_FLAG}" + $1_BUILD_STUB_LIB_PATH="`pwd`/[$]{PKG_STUB_LIB_FILE}" + $1_STUB_LIB_PATH="${pkglibdir}/[$]{PKG_STUB_LIB_FILE}" + + AC_SUBST($1_BUILD_LIB_SPEC) + AC_SUBST($1_LIB_SPEC) + AC_SUBST($1_BUILD_STUB_LIB_SPEC) + AC_SUBST($1_STUB_LIB_SPEC) + AC_SUBST($1_BUILD_STUB_LIB_PATH) + AC_SUBST($1_STUB_LIB_PATH) + + AC_SUBST(MAJOR_VERSION) + AC_SUBST(MINOR_VERSION) + AC_SUBST(PATCHLEVEL) +]) + + +#------------------------------------------------------------------------ +# TEA_PATH_CELIB -- +# +# Locate Keuchel's celib emulation layer for targeting Win/CE +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-celib=... +# +# Defines the following vars: +# CELIB_DIR Full path to the directory containing +# the include and platform lib files +#------------------------------------------------------------------------ + +AC_DEFUN([TEA_PATH_CELIB], [ + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-celib + + if test x"${no_celib}" = x ; then + # we reset no_celib in case something fails here + no_celib=true + AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) + AC_MSG_CHECKING([for Windows/CE celib directory]) + AC_CACHE_VAL(ac_cv_c_celibconfig,[ + # First check to see if --with-celibconfig was specified. + if test x"${with_celibconfig}" != x ; then + if test -d "${with_celibconfig}/inc" ; then + ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` + else + AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) + fi + fi + + # then check for a celib library + if test x"${ac_cv_c_celibconfig}" = x ; then + for i in \ + ../celib-palm-3.0 \ + ../celib \ + ../../celib-palm-3.0 \ + ../../celib \ + `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ + ${srcdir}/../celib-palm-3.0 \ + ${srcdir}/../celib \ + `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ + ; do + if test -d "$i/inc" ; then + ac_cv_c_celibconfig=`(cd $i; pwd)` + break + fi + done + fi + ]) + if test x"${ac_cv_c_celibconfig}" = x ; then + AC_MSG_ERROR([Cannot find celib support library directory]) + else + no_celib= + CELIB_DIR=${ac_cv_c_celibconfig} + CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` + AC_MSG_RESULT([found $CELIB_DIR]) + fi + fi +]) + + +# Local Variables: +# mode: autoconf +# End: diff --git a/pd/tkpath/tests/all.tcl b/pd/tkpath/tests/all.tcl new file mode 100644 index 0000000000000000000000000000000000000000..7e0ad21abc101a8ec2ceef4753fa3bf41d72ef68 --- /dev/null +++ b/pd/tkpath/tests/all.tcl @@ -0,0 +1,24 @@ +# all.tcl -- +# +# This file contains a top-level script to run all of the Tk +# tests. Execute it by invoking "source all.tcl" when running tktest +# in this directory. +# +# Copyright (c) 1998-1999 by Scriptics Corporation. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: all.tcl,v 1.1 2008/06/05 12:52:00 matben Exp $ + +# @@@ Anyone? + +package require Tcl 8.5 +package require tcltest 2.2 +package require Tk ;# This is the Tk test suite; fail early if no Tk! +tcltest::configure {*}$argv +tcltest::configure -testdir [file normalize [file dirname [info script]]] +tcltest::configure -loadfile \ + [file join [tcltest::testsDirectory] constraints.tcl] +tcltest::configure -singleproc 1 +tcltest::runAllTests diff --git a/pd/tkpath/tests/canvImg.test b/pd/tkpath/tests/canvImg.test new file mode 100644 index 0000000000000000000000000000000000000000..498b7b735d668a6fa3464f1549b4dd2ad965c067 --- /dev/null +++ b/pd/tkpath/tests/canvImg.test @@ -0,0 +1,393 @@ +# This file is a Tcl script to test out the procedures in tkCanvImg.c, +# which implement canvas "image" items. It is organized in the standard +# fashion for Tcl tests. +# +# Copyright (c) 1994 The Regents of the University of California. +# Copyright (c) 1994-1996 Sun Microsystems, Inc. +# Copyright (c) 1998-1999 by Scriptics Corporation. +# All rights reserved. +# +# RCS: @(#) $Id: canvImg.test,v 1.1 2008/05/21 13:55:57 matben Exp $ + +package require tcltest 2.1 +eval tcltest::configure $argv +tcltest::loadTestedCommands + +eval image delete [image names] +tkp::canvas .c +pack .c +update +if {[testConstraint testImageType]} { + image create test foo -variable x + image create test foo2 -variable y + foo2 changed 0 0 0 0 80 60 +} +test canvImg-1.1 {options for image items} { + .c delete all + .c create image 50 50 -anchor nw -tags i1 + .c itemconfigure i1 -anchor +} {-anchor {} {} center nw} +test canvImg-1.2 {options for image items} { + .c delete all + list [catch {.c create image 50 50 -anchor gorp -tags i1} msg] $msg +} {1 {bad anchor position "gorp": must be n, ne, e, se, s, sw, w, nw, or center}} +test canvImg-1.3 {options for image items} testImageType { + .c delete all + .c create image 50 50 -image foo -tags i1 + .c itemconfigure i1 -image +} {-image {} {} {} foo} +test canvImg-1.4 {options for image items} { + .c delete all + list [catch {.c create image 50 50 -image unknown -tags i1} msg] $msg +} {1 {image "unknown" doesn't exist}} +test canvImg-1.5 {options for image items} testImageType { + .c delete all + .c create image 50 50 -image foo -tags {i1 foo} + .c itemconfigure i1 -tags +} {-tags {} {} {} {i1 foo}} + +test canvImg-2.1 {CreateImage procedure} { + list [catch {.c create image 40} msg] $msg +} {1 {wrong # coordinates: expected 2, got 1}} +test canvImg-2.2 {CreateImage procedure} { + list [catch {.c create image 40 50 60} msg] $msg +} {1 {unknown option "60"}} +test canvImg-2.3 {CreateImage procedure} { + .c delete all + set i [.c create image 50 50] + list [lindex [.c itemconf $i -anchor] 4] \ + [lindex [.c itemconf $i -image] 4] \ + [lindex [.c itemconf $i -tags] 4] +} {center {} {}} +test canvImg-2.4 {CreateImage procedure} { + list [catch {.c create image xyz 40} msg] $msg +} {1 {bad screen distance "xyz"}} +test canvImg-2.5 {CreateImage procedure} { + list [catch {.c create image 50 qrs} msg] $msg +} {1 {bad screen distance "qrs"}} +test canvImg-2.6 {CreateImage procedure} testImageType { + list [catch {.c create image 50 50 -gorp foo} msg] $msg +} {1 {unknown option "-gorp"}} + +test canvImg-3.1 {ImageCoords procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags i1 + .c coords i1 +} {50.0 100.0} +test canvImg-3.2 {ImageCoords procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags i1 + list [catch {.c coords i1 dumb 100} msg] $msg +} {1 {bad screen distance "dumb"}} +test canvImg-3.3 {ImageCoords procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags i1 + list [catch {.c coords i1 250 dumb0} msg] $msg +} {1 {bad screen distance "dumb0"}} +test canvImg-3.4 {ImageCoords procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags i1 + list [catch {.c coords i1 250} msg] $msg +} {1 {wrong # coordinates: expected 2, got 1}} +test canvImg-3.5 {ImageCoords procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags i1 + list [catch {.c coords i1 250 300 400} msg] $msg +} {1 {wrong # coordinates: expected 0 or 2, got 3}} + +test canvImg-4.1 {ConfiugreImage procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags i1 + update + set x {} + .c itemconfigure i1 -image {} + update + list $x [.c bbox i1] +} {{{foo free}} {}} +test canvImg-4.2 {ConfiugreImage procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags i1 -anchor nw + update + set x {} + set y {} + .c itemconfigure i1 -image foo2 + update + list $x $y [.c bbox i1] +} {{{foo free}} {{foo2 get} {foo2 display 0 0 80 60 30 30}} {50 100 130 160}} +test canvImg-4.3 {ConfiugreImage procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags i1 -anchor nw + update + set x {} + set y {} + list [catch {.c itemconfigure i1 -image lousy} msg] $msg +} {1 {image "lousy" doesn't exist}} + +test canvImg-5.1 {DeleteImage procedure} testImageType { + image create test xyzzy -variable z + .c delete all + .c create image 50 100 -image xyzzy -tags i1 + update + set names [lsort [image names]] + image delete xyzzy + set z {} + set names2 [lsort [image names]] + .c delete i1 + update + list $names $names2 $z [lsort [image names]] +} {{foo foo2 xyzzy} {foo foo2} {} {foo foo2}} +test canvImg-5.2 {DeleteImage procedure (don't delete non-existent image)} { + .c delete all + .c create image 50 100 -tags i1 + update + .c delete i1 + update +} {} + +test canvImg-6.1 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 15.51 17.51 -image foo -tags i1 -anchor nw + .c bbox i1 +} {16 18 46 33} +test canvImg-6.2 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 15.49 17.49 -image foo -tags i1 -anchor nw + .c bbox i1 +} {15 17 45 32} +test canvImg-6.3 {ComputeImageBbox procedure} { + .c delete all + .c create image 20 30 -tags i1 -anchor nw + .c bbox i1 +} {} +test canvImg-6.4 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 20 30 -image foo -tags i1 -anchor nw + .c bbox i1 +} {20 30 50 45} +test canvImg-6.5 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 20 30 -image foo -tags i1 -anchor n + .c bbox i1 +} {5 30 35 45} +test canvImg-6.6 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 20 30 -image foo -tags i1 -anchor ne + .c bbox i1 +} {-10 30 20 45} +test canvImg-6.7 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 20 30 -image foo -tags i1 -anchor e + .c bbox i1 +} {-10 23 20 38} +test canvImg-6.8 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 20 30 -image foo -tags i1 -anchor se + .c bbox i1 +} {-10 15 20 30} +test canvImg-6.9 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 20 30 -image foo -tags i1 -anchor s + .c bbox i1 +} {5 15 35 30} +test canvImg-6.10 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 20 30 -image foo -tags i1 -anchor sw + .c bbox i1 +} {20 15 50 30} +test canvImg-6.11 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 20 30 -image foo -tags i1 -anchor w + .c bbox i1 +} {20 23 50 38} +test canvImg-6.12 {ComputeImageBbox procedure} testImageType { + .c delete all + .c create image 20 30 -image foo -tags i1 -anchor center + .c bbox i1 +} {5 23 35 38} + +# The following test is non-portable because of differences in +# coordinate rounding on some machines (does 0.5 round up?). + +test canvImg-7.1 {DisplayImage procedure} {nonPortable testImageType} { + .c delete all + .c create image 50 100 -image foo -tags i1 -anchor nw + update + set x {} + .c create rect 55 110 65 115 -width 1 -outline black -fill white + update + set x +} {{foo display 4 9 12 6 30 30}} +test canvImg-7.2 {DisplayImage procedure, no image} { + .c delete all + .c create image 50 100 -tags i1 + update + .c create rect 55 110 65 115 -width 1 -outline black -fill white + update +} {} + +.c delete all +if {[testConstraint testImageType]} { + .c create image 50 100 -image foo -tags image -anchor nw +} +.c create rect 10 10 20 20 -tags rect -fill black -width 0 -outline {} +foreach check { + {canvImg-8.1 {50 70 80 81} {70 90} rect} + {canvImg-8.2 {50 70 80 79} {70 90} image} + {canvImg-8.3 {99 70 110 81} {90 90} rect} + {canvImg-8.4 {101 70 110 79} {90 90} image} + {canvImg-8.5 {99 100 110 115} {90 110} rect} + {canvImg-8.6 {101 100 110 115} {90 110} image} + {canvImg-8.7 {99 134 110 145} {90 125} rect} + {canvImg-8.8 {101 136 110 145} {90 125} image} + {canvImg-8.9 {50 134 80 145} {70 125} rect} + {canvImg-8.10 {50 136 80 145} {70 125} image} + {canvImg-8.11 {20 134 31 145} {40 125} rect} + {canvImg-8.12 {20 136 29 145} {40 125} image} + {canvImg-8.13 {20 100 31 115} {40 110} rect} + {canvImg-8.14 {20 100 29 115} {40 110} image} + {canvImg-8.15 {20 70 31 80} {40 90} rect} + {canvImg-8.16 {20 70 29 79} {40 90} image} + {canvImg-8.17 {60 70 69 109} {70 110} image} + {canvImg-8.18 {60 70 71 111} {70 110} rect} +} { + lassign $check name rectCoords testPoint result + test $name {ImageToPoint procedure} testImageType { + .c coords rect {*}$rectCoords + .c gettags [.c find closest {*}$testPoint] + } $result +} + +.c delete all +if {[testConstraint testImageType]} { + .c create image 50 100 -image foo -tags image -anchor nw +} +test canvImg-8.19 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 60 0 70 99] +} {} +test canvImg-8.20 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 60 0 70 99.999] +} {} +test canvImg-8.21 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 60 0 70 101] +} {image} +test canvImg-8.22 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 81 105 120 115] +} {} +test canvImg-8.23 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 80.001 105 120 115] +} {} +test canvImg-8.24 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 79 105 120 115] +} {image} +test canvImg-8.25 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 60 116 70 150] +} {} +test canvImg-8.26 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 60 115.001 70 150] +} {} +test canvImg-8.27 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 60 114 70 150] +} {image} +test canvImg-8.28 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 0 105 49 115] +} {} +test canvImg-8.29 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 0 105 50 114.999] +} {} +test canvImg-8.30 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 0 105 51 115] +} {image} +test canvImg-8.31 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 0 0 49.999 99.999] +} {} +test canvImg-8.32 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 0 0 51 101] +} {image} +test canvImg-8.33 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 80 0 150 100] +} {} +test canvImg-8.34 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 79 0 150 101] +} {image} +test canvImg-8.35 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 80.001 115.001 150 180] +} {} +test canvImg-8.36 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 79 114 150 180] +} {image} +test canvImg-8.37 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 0 115 50 180] +} {} +test canvImg-8.38 {ImageToArea procedure} testImageType { + .c gettags [.c find overlapping 0 114 51 180] +} {image} +test canvImg-8.39 {ImageToArea procedure} testImageType { + .c gettags [.c find enclosed 0 0 200 200] +} {image} +test canvImg-8.40 {ImageToArea procedure} testImageType { + .c gettags [.c find enclosed 49.999 99.999 80.001 115.001] +} {image} +test canvImg-8.41 {ImageToArea procedure} testImageType { + .c gettags [.c find enclosed 51 100 80 115] +} {} +test canvImg-8.42 {ImageToArea procedure} testImageType { + .c gettags [.c find enclosed 50 101 80 115] +} {} +test canvImg-8.43 {ImageToArea procedure} testImageType { + .c gettags [.c find enclosed 50 100 79 115] +} {} +test canvImg-8.44 {ImageToArea procedure} testImageType { + .c gettags [.c find enclosed 50 100 80 114] +} {} + +test canvImg-9.1 {DisplayImage procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags image -anchor nw + .c scale image 25 0 2.0 1.5 + .c bbox image +} {75 150 105 165} + +test canvImg-10.1 {TranslateImage procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags image -anchor nw + update + set x {} + foo changed 2 4 6 8 30 15 + update + set x +} {{foo display 2 4 6 8 30 30}} + +test canvImg-11.1 {TranslateImage procedure} testImageType { + .c delete all + .c create image 50 100 -image foo -tags image -anchor nw + update + set x {} + foo changed 2 4 6 8 40 50 + update + set x +} {{foo display 0 0 40 50 30 30}} +test canvImg-11.2 {ImageChangedProc procedure} testImageType { + .c delete all + image create test foo -variable x + .c create image 50 100 -image foo -tags image -anchor center + update + set x {} + foo changed 0 0 0 0 40 50 + .c bbox image +} {30 75 70 125} +test canvImg-11.3 {ImageChangedProc procedure} testImageType { + .c delete all + image create test foo -variable x + foo changed 0 0 0 0 40 50 + .c create image 50 100 -image foo -tags image -anchor nw + .c create image 70 110 -image foo2 -anchor nw + update + set y {} + image create test foo -variable x + update + set y +} {{foo2 display 0 0 20 40 50 40}} + +# cleanup +cleanupTests +return diff --git a/pd/tkpath/tests/canvPs.test b/pd/tkpath/tests/canvPs.test new file mode 100644 index 0000000000000000000000000000000000000000..39949fd6f732994e1cd57e3020a0a6ae2bfba196 --- /dev/null +++ b/pd/tkpath/tests/canvPs.test @@ -0,0 +1,183 @@ +# This file is a Tcl script to test out procedures to write postscript +# for canvases to files and channels. It exercises the procedure +# TkCanvPostscriptCmd in generic/tkCanvPs.c +# +# Copyright (c) 1995 Sun Microsystems, Inc. +# Copyright (c) 1998-1999 by Scriptics Corporation. +# All rights reserved. +# +# RCS: @(#) $Id: canvPs.test,v 1.1 2008/05/21 13:55:58 matben Exp $ + +package require tcltest 2.1 +eval tcltest::configure $argv +tcltest::loadTestedCommands + +tkp::canvas .c -width 400 -height 300 -bd 2 -relief sunken +.c create rectangle 20 20 80 80 -fill red +pack .c +update + +test canvPs-1.1 {test writing to a file} -constraints { + unixOrPc +} -setup { + set foo [makeFile {} foo.ps] +} -body { + .c postscript -file $foo + file exists $foo +} -cleanup { + removeFile foo.ps +} -result 1 +test canvPs-1.2 {test writing to a file, idempotency} -constraints { + unixOrPc +} -setup { + set foo [makeFile {} foo.ps] + set bar [makeFile {} bar.ps] +} -body { + .c postscript -file $foo + .c postscript -file $bar + set status ok + if {[file size $bar] != [file size $foo]} { + set status broken + } + set status +} -cleanup { + removeFile foo.ps + removeFile bar.ps +} -result ok + +test canvPs-2.1 {test writing to a channel} -constraints { + unixOrPc +} -setup { + set foo [makeFile {} foo.ps] + file delete $foo +} -body { + set chan [open $foo w] + fconfigure $chan -translation lf + .c postscript -channel $chan + close $chan + file exists $foo +} -cleanup { + removeFile foo.ps +} -result 1 +test canvPs-2.2 {test writing to channel, idempotency} -constraints { + unixOrPc +} -setup { + set foo [makeFile {} foo.ps] + set bar [makeFile {} bar.ps] + file delete $foo + file delete $bar +} -body { + set c1 [open $foo w] + set c2 [open $bar w] + fconfigure $c1 -translation lf + fconfigure $c2 -translation lf + .c postscript -channel $c1 + .c postscript -channel $c2 + close $c1 + close $c2 + set status ok + if {[file size $bar] != [file size $foo]} { + set status broken + } + set status +} -cleanup { + removeFile foo.ps + removeFile bar.ps +} -result ok +test canvPs-2.3 {test writing to channel and file, same output} -constraints { + unix +} -setup { + set foo [makeFile {} foo.ps] + set bar [makeFile {} bar.ps] + file delete $foo + file delete $bar +} -body { + set c1 [open $foo w] + fconfigure $c1 -translation lf + .c postscript -channel $c1 + close $c1 + .c postscript -file $bar + set status ok + if {[file size $foo] != [file size $bar]} { + set status broken + } + set status +} -cleanup { + removeFile foo.ps + removeFile bar.ps +} -result ok +test canvPs-2.4 {test writing to channel and file, same output} -constraints { + win +} -setup { + set foo [makeFile {} foo.ps] + set bar [makeFile {} bar.ps] + file delete $foo + file delete $bar +} -body { + set c1 [open $foo w] + fconfigure $c1 -translation crlf + .c postscript -channel $c1 + close $c1 + .c postscript -file $bar + set status ok + if {[file size $foo] != [file size $bar]} { + set status broken + } + set status +} -cleanup { + removeFile foo.ps + removeFile bar.ps +} -result ok + +test canvPs-3.1 {test ps generation with an embedded window} -setup { + set bar [makeFile {} bar.ps] + file delete $bar +} -constraints { + notAqua +} -body { + destroy .c + pack [tkp::canvas .c -width 200 -height 200 -background white] + .c create rect 20 20 150 150 -tags rect0 -dash . -width 2 + .c create arc 0 50 200 200 -tags arc0 \ + -dash {4 4} -stipple question -outline red -fill green + + image create photo logo \ + -file [file join [file dirname [info script]] pwrdLogo150.gif] + .c create image 200 50 -image logo -anchor nw + + entry .c.e -background pink -foreground blue -width 14 + .c.e insert 0 "we gonna be postscripted" + .c create window 50 180 -anchor nw -window .c.e + update + .c postscript -file $bar + file exists $bar +} -cleanup { + removeFile bar.ps +} -result 1 +test canvPs-3.2 {test ps generation with an embedded window not mapped} -setup { + set bar [makeFile {} bar.ps] + file delete $bar +} -body { + destroy .c + pack [tkp::canvas .c -width 200 -height 200 -background white] + entry .c.e -background pink -foreground blue -width 14 + .c.e insert 0 "we gonna be postscripted" + .c create window 50 180 -anchor nw -window .c.e + .c postscript -file $bar + file exists $bar +} -cleanup { + removeFile bar.ps +} -result 1 + +test canvPs-4.1 {test ps generation with single-point uncolored poly, bug 734498} {} { + destroy .c + pack [tkp::canvas .c] + .c create poly 10 20 10 20 + catch {.c postscript} +} 0 + +# cleanup +unset -nocomplain foo bar +deleteWindows +cleanupTests +return diff --git a/pd/tkpath/tests/canvPsArc.tcl b/pd/tkpath/tests/canvPsArc.tcl new file mode 100644 index 0000000000000000000000000000000000000000..8dc0042ef14a55f45148c4914fcbedbcc2c20c6b --- /dev/null +++ b/pd/tkpath/tests/canvPsArc.tcl @@ -0,0 +1,45 @@ +# This file creates a screen to exercise Postscript generation +# for bitmaps in canvases. It is part of the Tk visual test suite, +# which is invoked via the "visual" script. +# +# RCS: @(#) $Id: canvPsArc.tcl,v 1.1 2008/05/21 13:55:58 matben Exp $ + +catch {destroy .t} +toplevel .t +wm title .t "Postscript Tests for Canvases" +wm iconname .t "Postscript" +wm geom .t +0+0 +wm minsize .t 1 1 + +set c .t.c + +message .t.m -text {This screen exercises the Postscript-generation abilities of Tk canvas widgets for arcs. Click on "Print" to print the canvas to your default printer. You can click on items in the canvas to delete them.} -width 6i +pack .t.m -side top -fill both + +frame .t.bot +pack .t.bot -side bottom -fill both +button .t.bot.quit -text Quit -command {destroy .t} +button .t.bot.print -text Print -command "lpr $c" +pack .t.bot.print .t.bot.quit -side left -pady 1m -expand 1 + +tkp::canvas $c -width 6i -height 6i -bd 2 -relief sunken +pack $c -expand yes -fill both -padx 2m -pady 2m + +$c create arc .5i .5i 2i 2i -style pieslice -start 20 -extent 90 \ + -fill black -outline {} +$c create arc 2.5i 0 4.5i 1i -style pieslice -start -45 -extent -135 \ + -fill {} -outline black -outlinestipple gray50 -width 3m +$c create arc 5.0i .5i 6.5i 2i -style pieslice -start 45 -extent 315 \ + -fill black -stipple gray25 -outline black -width 1m + +$c create arc -.5i 2.5i 2.0i 3.5i -style chord -start 90 -extent 270 \ + -fill black -outline {} +$c create arc 2.5i 2i 4i 6i -style chord -start 20 -extent 140 \ + -fill black -stipple gray50 -outline black -width 2m +$c create arc 4i 2.5i 8i 4.5i -style chord -start 60 -extent 60 \ + -fill {} -outline black + +$c create arc .5i 4.5i 2i 6i -style arc -start 135 -extent 315 -width 3m \ + -outline black -outlinestipple gray25 +$c create arc 3.5i 4.5i 5.5i 5.5i -style arc -start 45 -extent -90 -width 1m \ + -outline black diff --git a/pd/tkpath/tests/canvPsBmap.tcl b/pd/tkpath/tests/canvPsBmap.tcl new file mode 100644 index 0000000000000000000000000000000000000000..318f5cf3002c9f850d7dd33a1e229513a0571b44 --- /dev/null +++ b/pd/tkpath/tests/canvPsBmap.tcl @@ -0,0 +1,86 @@ +# This file creates a screen to exercise Postscript generation +# for bitmaps in canvases. It is part of the Tk visual test suite, +# which is invoked via the "visual" script. +# +# RCS: @(#) $Id: canvPsBmap.tcl,v 1.1 2008/05/21 13:56:02 matben Exp $ + +catch {destroy .t} +toplevel .t +wm title .t "Postscript Tests for Canvases" +wm iconname .t "Postscript" +wm geom .t +0+0 +wm minsize .t 1 1 + +set c .t.c + +message .t.m -text {This screen exercises the Postscript-generation abilities of Tk canvas widgets for bitmaps. Click on "Print" to print the canvas to your default printer. You can click on items in the canvas to delete them.} -width 6i +pack .t.m -side top -fill both + +frame .t.bot +pack .t.bot -side bottom -fill both +button .t.bot.quit -text Quit -command {destroy .t} +button .t.bot.print -text Print -command "lpr $c" +pack .t.bot.print .t.bot.quit -side left -pady 1m -expand 1 + +tkp::canvas $c -width 6i -height 6i -bd 2 -relief sunken +pack $c -expand yes -fill both -padx 2m -pady 2m + +set canvPsBmapImageDir [file join [file dirname [info script]] images] + +$c create bitmap 0.5i 0.5i \ + -bitmap @[file join $canvPsBmapImageDir flagdown.xbm] \ + -background {} -foreground black -anchor nw +$c create rect 0.47i 0.47i 0.53i 0.53i -fill {} -outline black + +$c create bitmap 3.0i 0.5i \ + -bitmap @[file join $canvPsBmapImageDir flagdown.xbm] \ + -background {} -foreground black -anchor n +$c create rect 2.97i 0.47i 3.03i 0.53i -fill {} -outline black + +$c create bitmap 5.5i 0.5i \ + -bitmap @[file join $canvPsBmapImageDir flagdown.xbm] \ + -background black -foreground white -anchor ne +$c create rect 5.47i 0.47i 5.53i 0.53i -fill {} -outline black + +$c create bitmap 0.5i 3.0i \ + -bitmap @[file join $canvPsBmapImageDir face.xbm] \ + -background {} -foreground black -anchor w +$c create rect 0.47i 2.97i 0.53i 3.03i -fill {} -outline black + +$c create bitmap 3.0i 3.0i \ + -bitmap @[file join $canvPsBmapImageDir face.xbm] \ + -background {} -foreground black -anchor center +$c create rect 2.97i 2.97i 3.03i 3.03i -fill {} -outline black + +$c create bitmap 5.5i 3.0i \ + -bitmap @[file join $canvPsBmapImageDir face.xbm] \ + -background blue -foreground black -anchor e +$c create rect 5.47i 2.97i 5.53i 3.03i -fill {} -outline black + +$c create bitmap 0.5i 5.5i \ + -bitmap @[file join $canvPsBmapImageDir flagup.xbm] \ + -background black -foreground white -anchor sw +$c create rect 0.47i 5.47i 0.53i 5.53i -fill {} -outline black + +$c create bitmap 3.0i 5.5i \ + -bitmap @[file join $canvPsBmapImageDir flagup.xbm] \ + -background green -foreground white -anchor s +$c create rect 2.97i 5.47i 3.03i 5.53i -fill {} -outline black + +$c create bitmap 5.5i 5.5i \ + -bitmap @[file join $canvPsBmapImageDir flagup.xbm] \ + -background {} -foreground black -anchor se +$c create rect 5.47i 5.47i 5.53i 5.53i -fill {} -outline black + + + + + + + + + + + + + diff --git a/pd/tkpath/tests/canvPsGrph.tcl b/pd/tkpath/tests/canvPsGrph.tcl new file mode 100644 index 0000000000000000000000000000000000000000..26a9e6d5661d8276004fdb95b1e8abe2c651d8cc --- /dev/null +++ b/pd/tkpath/tests/canvPsGrph.tcl @@ -0,0 +1,100 @@ +# This file creates a screen to exercise Postscript generation +# for some of the graphical objects in canvases. It is part of the Tk +# visual test suite, which is invoked via the "visual" script. +# +# RCS: @(#) $Id: canvPsGrph.tcl,v 1.1 2008/05/21 13:56:02 matben Exp $ + +catch {destroy .t} +toplevel .t +wm title .t "Postscript Tests for Canvases" +wm iconname .t "Postscript" +wm geom .t +0+0 +wm minsize .t 1 1 + +set c .t.mid.c + +message .t.m -text {This screen exercises the Postscript-generation abilities of Tk canvas widgets. Select what you want to display with the buttons below, then click on "Print" to print it to your default printer. You can click on items in the canvas to delete them.} -width 4i +pack .t.m -side top -fill both + +frame .t.top +pack .t.top -side top -fill both +set what rect +radiobutton .t.top.rect -text Rectangles -variable what -value rect \ + -command "mkObjs $c" -relief flat +radiobutton .t.top.oval -text Ovals -variable what -value oval \ + -command "mkObjs $c" -relief flat +radiobutton .t.top.poly -text Polygons -variable what -value poly \ + -command "mkObjs $c" -relief flat +radiobutton .t.top.line -text Lines -variable what -value line \ + -command "mkObjs $c" -relief flat +pack .t.top.rect .t.top.oval .t.top.poly .t.top.line \ + -side left -pady 2m -ipadx 2m -ipady 1m -expand 1 + +frame .t.bot +pack .t.bot -side bottom -fill both +button .t.bot.quit -text Quit -command {destroy .t} +button .t.bot.print -text Print -command "lpr $c" +pack .t.bot.print .t.bot.quit -side left -pady 1m -expand 1 + +frame .t.mid -relief sunken -bd 2 +pack .t.mid -side top -expand yes -fill both -padx 2m -pady 2m +tkp::canvas $c -width 400 -height 350 -bd 0 -relief sunken +pack $c -expand yes -fill both -padx 1 -pady 1 + +proc mkObjs c { + global what + $c delete all + if {$what == "rect"} { + $c create rect 0 0 400 350 -outline black + $c create rect 2 2 100 50 -fill black -stipple gray25 + $c create rect -20 180 80 320 -fill black -stipple gray50 -width .5c + $c create rect 200 -20 240 20 -fill black + $c create rect 380 200 420 240 -fill black + $c create rect 200 330 240 370 -fill black + } + + if {$what == "oval"} { + $c create oval 50 10 150 80 -fill black -stipple gray25 -outline {} + $c create oval 100 100 200 150 -outline {} -fill black -stipple gray50 + $c create oval 250 100 400 300 -width .5c + } + + if {$what == "poly"} { + $c create poly 100 200 200 50 300 200 -smooth yes -stipple gray25 \ + -outline black -width 4 + $c create poly 100 300 100 250 350 250 350 300 350 300 100 300 100 300 \ + -fill red -smooth yes + $c create poly 20 10 40 10 40 60 80 60 80 25 30 25 30 \ + 35 50 35 50 45 20 45 + $c create poly 300 20 300 120 380 80 320 100 -fill blue -outline black + $c create poly 20 200 100 220 90 100 40 250 \ + -fill {} -outline brown -width 3 + } + + if {$what == "line"} { + $c create line 20 20 120 20 -arrow both -width 5 + $c create line 20 80 150 80 20 200 150 200 -smooth yes + $c create line 150 20 150 150 250 150 -width .5c -smooth yes \ + -arrow both -arrowshape {.75c 1.0c .5c} -stipple gray25 + $c create line 50 340 100 250 150 340 -join round -cap round -width 10 + $c create line 200 340 250 250 300 340 -join bevel -cap project \ + -width 10 + $c create line 300 20 380 20 300 150 380 150 -join miter -cap butt \ + -width 10 -stipple gray25 + } +} + +mkObjs $c + + + + + + + + + + + + + diff --git a/pd/tkpath/tests/canvPsImg.tcl b/pd/tkpath/tests/canvPsImg.tcl new file mode 100644 index 0000000000000000000000000000000000000000..edbb673565896f394028de0d32f07bab3888b808 --- /dev/null +++ b/pd/tkpath/tests/canvPsImg.tcl @@ -0,0 +1,86 @@ +# This file creates a screen to exercise Postscript generation +# for images in canvases. It is part of the Tk visual test suite, +# which is invoked via the "visual" script. +# +# RCS: @(#) $Id: canvPsImg.tcl,v 1.1 2008/05/21 13:56:02 matben Exp $ + +# Build a test image in a canvas +proc BuildTestImage {} { + global BitmapImage PhotoImage visual level + catch {destroy .t.f} + frame .t.f -visual $visual -colormap new + pack .t.f -side top -after .t.top + bind .t.f <Enter> {wm colormapwindows .t {.t.f .t}} + bind .t.f <Leave> {wm colormapwindows .t {.t .t.f}} + tkp::canvas .t.f.c -width 550 -height 350 -borderwidth 2 -relief raised + pack .t.f.c + .t.f.c create rectangle 25 25 525 325 -fill {} -outline black + .t.f.c create image 50 50 -anchor nw -image $BitmapImage + .t.f.c create image 250 50 -anchor nw -image $PhotoImage +} + +# Put postscript in a file +proc FilePostscript { canvas } { + global level + $canvas postscript -file /tmp/test.ps -colormode $level +} + +# Send postscript output to printer +proc PrintPostcript { canvas } { + global level + $canvas postscript -file tmp.ps -colormode $level + exec lpr tmp.ps +} + +catch {destroy .t} +toplevel .t +wm title .t "Postscript Tests for Canvases: Images" +wm iconname .t "Postscript" + +message .t.m -text {This screen exercises the Postscript-generation abilities of Tk canvas widgets for images. Click the buttons below to select a Visual type for the canvas and colormode for the Postscript output. Then click "Print" to send the results to the default printer, or "Print to file" to put the Postscript output in a file called "/tmp/test.ps". You can also click on items in the canvas to delete them. +NOTE: Some Postscript printers may not be able to handle Postscript generated in color mode.} -width 6i +pack .t.m -side top -fill both + +frame .t.top +pack .t.top -side top +frame .t.top.l -relief raised -borderwidth 2 +frame .t.top.r -relief raised -borderwidth 2 +pack .t.top.l .t.top.r -side left -fill both -expand 1 + +label .t.visuals -text "Visuals" +pack .t.visuals -in .t.top.l + +set visual [lindex [winfo visualsavailable .] 0] +foreach v [winfo visualsavailable .] { + # The hack below is necessary for some systems, which have more than one + # visual of the same type... + if {![winfo exists .t.$v]} { + radiobutton .t.$v -text $v -variable visual -value $v \ + -command BuildTestImage + pack .t.$v -in .t.top.l -anchor w + } +} + +label .t.levels -text "Color Levels" +pack .t.levels -in .t.top.r +set level monochrome +foreach l { monochrome gray color } { + radiobutton .t.$l -text $l -variable level -value $l + pack .t.$l -in .t.top.r -anchor w +} + +set BitmapImage [image create bitmap \ + -file [file join [file dirname [info script]] face.xbm] \ + -background white -foreground black] +set PhotoImage [image create photo \ + -file [file join [file dirname [info script]] teapot.ppm]] + +BuildTestImage + +frame .t.bot +pack .t.bot -side top -fill x -expand 1 + +button .t.file -text "Print to File" -command { FilePostscript .t.f.c } +button .t.print -text "Print" -command { PrintPostscript .t.f.c } +button .t.quit -text "Quit" -command { destroy .t } +pack .t.file .t.print .t.quit -in .t.bot -side left -fill x -expand 1 diff --git a/pd/tkpath/tests/canvPsText.tcl b/pd/tkpath/tests/canvPsText.tcl new file mode 100644 index 0000000000000000000000000000000000000000..fd5ad3e7e5e9536f1cfca7398f6a44f480e78317 --- /dev/null +++ b/pd/tkpath/tests/canvPsText.tcl @@ -0,0 +1,96 @@ +# This file creates a screen to exercise Postscript generation +# for text in canvases. It is part of the Tk visual test suite, +# which is invoked via the "visual" script. +# +# RCS: @(#) $Id: canvPsText.tcl,v 1.1 2008/05/21 13:56:02 matben Exp $ + +catch {destroy .t} +toplevel .t +wm title .t "Postscript Tests for Canvases" +wm iconname .t "Postscript" +wm geom .t +0+0 +wm minsize .t 1 1 + +set c .t.c + +message .t.m -text {This screen exercises the Postscript-generation abilities of Tk canvas widgets for text. Click on "Print" to print the canvas to your default printer. The "Stipple" button can be used to turn stippling on and off for the text, but beware: many Postscript printers cannot handle stippled text. You can click on items in the canvas to delete them.} -width 6i +pack .t.m -side top -fill both + +set stipple {} +checkbutton .t.stipple -text Stippling -variable stipple -onvalue gray50 \ + -offvalue {} -command "setStipple $c" -relief flat +pack .t.stipple -side top -pady 2m -expand 1 -anchor w + +frame .t.bot +pack .t.bot -side bottom -fill both +button .t.bot.quit -text Quit -command {destroy .t} +button .t.bot.print -text Print -command "lpr $c" +pack .t.bot.print .t.bot.quit -side left -pady 1m -expand 1 + +tkp::canvas $c -width 6i -height 7i -bd 2 -relief sunken +pack $c -expand yes -fill both -padx 2m -pady 2m + +$c create rect 2.95i 0.45i 3.05i 0.55i -fill {} -outline black +$c create text 3.0i 0.5i -text "Center Courier Oblique 24" \ + -anchor center -tags text -font {Courier 24 italic} -stipple $stipple +$c create rect 2.95i 0.95i 3.05i 1.05i -fill {} -outline black +$c create text 3.0i 1.0i -text "Northwest Helvetica 24" \ + -anchor nw -tags text -font {Helvetica 24} -stipple $stipple +$c create rect 2.95i 1.45i 3.05i 1.55i -fill {} -outline black +$c create text 3.0i 1.5i -text "North Helvetica Oblique 12 " \ + -anchor n -tags text -font {Helvetica 12 italic} -stipple $stipple +$c create rect 2.95i 1.95i 3.05i 2.05i -fill {} -outline blue +$c create text 3.0i 2.0i -text "Northeast Helvetica Bold 24" \ + -anchor ne -tags text -font {Helvetica 24 bold} -stipple $stipple +$c create rect 2.95i 2.45i 3.05i 2.55i -fill {} -outline black +$c create text 3.0i 2.5i -text "East Helvetica Bold Oblique 18" \ + -anchor e -tags text -font {Helvetica 18 {bold italic}} -stipple $stipple +$c create rect 2.95i 2.95i 3.05i 3.05i -fill {} -outline black +$c create text 3.0i 3.0i -text "Southeast Times 10" \ + -anchor se -tags text -font {Times 10} -stipple $stipple +$c create rect 2.95i 3.45i 3.05i 3.55i -fill {} -outline black +$c create text 3.0i 3.5i -text "South Times Italic 24" \ + -anchor s -tags text -font {Times 24 italic} -stipple $stipple +$c create rect 2.95i 3.95i 3.05i 4.05i -fill {} -outline black +$c create text 3.0i 4.0i -text "Southwest Times Bold 18" \ + -anchor sw -tags text -font {Times 18 bold} -stipple $stipple +$c create rect 2.95i 4.45i 3.05i 4.55i -fill {} -outline black +$c create text 3.0i 4.5i -text "West Times Bold Italic 24"\ + -anchor w -tags text -font {Times 24 {bold italic}} -stipple $stipple + +$c create rect 0.95i 5.20i 1.05i 5.30i -fill {} -outline black +$c create text 1.0i 5.25i -width 1.9i -anchor c -justify left -tags text \ + -font {Times 18 bold} -stipple $stipple \ + -text "This is a sample text item to see how left justification works" +$c create rect 2.95i 5.20i 3.05i 5.30i -fill {} -outline black +$c create text 3.0i 5.25i -width 1.8i -anchor c -justify center -tags text \ + -font {Times 18 bold} -stipple $stipple \ + -text "This is a sample text item to see how center justification works" +$c create rect 4.95i 5.20i 5.05i 5.30i -fill {} -outline black +$c create text 5.0i 5.25i -width 1.8i -anchor c -justify right -tags text \ + -font {Times 18 bold} -stipple $stipple \ + -text "This is a sample text item to see how right justification works" + +$c create text 3.0i 6.0i -width 5.0i -anchor n -justify right -tags text \ + -text "This text is\nright justified\nwith a line length equal to\n\ + the size of the enclosing rectangle.\nMake sure it prints right\ + justified as well." +$c create rect 0.5i 6.0i 5.5i 6.9i -fill {} -outline black + +proc setStipple c { + global stipple + $c itemconfigure text -stipple $stipple +} + + + + + + + + + + + + + diff --git a/pd/tkpath/tests/canvRect.test b/pd/tkpath/tests/canvRect.test new file mode 100644 index 0000000000000000000000000000000000000000..f4e44ea54b4026608191bbded0babfd156fbe0f6 --- /dev/null +++ b/pd/tkpath/tests/canvRect.test @@ -0,0 +1,330 @@ +# This file is a Tcl script to test out the procedures in tkRectOval.c, +# which implement canvas "rectangle" and "oval" items. It is organized +# in the standard fashion for Tcl tests. +# +# Copyright (c) 1994-1996 Sun Microsystems, Inc. +# Copyright (c) 1998-1999 by Scriptics Corporation. +# All rights reserved. +# +# RCS: @(#) $Id: canvRect.test,v 1.1 2008/05/21 13:56:02 matben Exp $ + +package require tcltest 2.1 +eval tcltest::configure $argv +tcltest::loadTestedCommands + +tkp::canvas .c -width 400 -height 300 -bd 2 -relief sunken +pack .c +bind .c <1> { + puts "button down at (%x,%y)" +} +update + +set i 1 +.c create rectangle 20 20 80 80 -tag test +foreach test { + {-fill #ff0000 #ff0000 + non-existent {unknown color name "non-existent"}} + {-outline #123456 #123456 + bad_color {unknown color name "bad_color"}} + {-stipple gray50 gray50 + bogus {bitmap "bogus" not defined}} + {-tags {test a b c} {test a b c} + {} {}} + {-width 6.0 6.0 + abc {bad screen distance "abc"}} +} { + lassign $test name goodValue goodResult badValue badResult + test canvRect-1.$i "configuration options: good value for $name" { + .c itemconfigure test $name $goodValue + list [lindex [.c itemconfigure test $name] 4] [.c itemcget test $name] + } [list $goodResult $goodResult] + incr i + if {$badValue ne ""} { + test canvRect-1.$i "configuration options: bad value for $name" -body { + .c itemconfigure test $name $badValue + } -returnCodes error -result $badResult + } + incr i +} +test canvRect-1.$i {configuration options} { + .c itemconfigure test -tags {test xyz} + .c itemcget xyz -tags +} {test xyz} + +test canvRect-2.1 {CreateRectOval procedure} { + list [catch {.c create rect} msg] $msg +} {1 {wrong # args: should be ".c create rect coords ?arg arg ...?"}} +test canvRect-2.2 {CreateRectOval procedure} { + list [catch {.c create oval x y z} msg] $msg +} {1 {wrong # coordinates: expected 0 or 4, got 3}} +test canvRect-2.3 {CreateRectOval procedure} { + list [catch {.c create rectangle x 2 3 4} msg] $msg +} {1 {bad screen distance "x"}} +test canvRect-2.4 {CreateRectOval procedure} { + list [catch {.c create rectangle 1 y 3 4} msg] $msg +} {1 {bad screen distance "y"}} +test canvRect-2.5 {CreateRectOval procedure} { + list [catch {.c create rectangle 1 2 z 4} msg] $msg +} {1 {bad screen distance "z"}} +test canvRect-2.6 {CreateRectOval procedure} { + list [catch {.c create rectangle 1 2 3 q} msg] $msg +} {1 {bad screen distance "q"}} +test canvRect-2.7 {CreateRectOval procedure} { + .c create rectangle 1 2 3 4 -tags x + set result {} + foreach element [.c coords x] { + lappend result [format %.1f $element] + } + set result +} {1.0 2.0 3.0 4.0} +test canvRect-2.8 {CreateRectOval procedure} { + list [catch {.c create rectangle 1 2 3 4 -gorp foo} msg] $msg +} {1 {unknown option "-gorp"}} + +.c delete withtag all +.c create rectangle 10 20 30 40 -tags x +test canvRect-3.1 {RectOvalCoords procedure} { + set result {} + foreach element [.c coords x] { + lappend result [format %.1f $element] + } + set result +} {10.0 20.0 30.0 40.0} +test canvRect-3.2 {RectOvalCoords procedure} { + list [catch {.c coords x a 2 3 4} msg] $msg +} {1 {bad screen distance "a"}} +test canvRect-3.3 {RectOvalCoords procedure} { + list [catch {.c coords x 1 b 3 4} msg] $msg +} {1 {bad screen distance "b"}} +test canvRect-3.4 {RectOvalCoords procedure} { + list [catch {.c coords x 1 2 c 4} msg] $msg +} {1 {bad screen distance "c"}} +test canvRect-3.5 {RectOvalCoords procedure} { + list [catch {.c coords x 1 2 3 d} msg] $msg +} {1 {bad screen distance "d"}} +test canvRect-3.6 {RectOvalCoords procedure} {nonPortable} { + # Non-portable due to rounding differences. + .c coords x 10 25 15 40 + .c bbox x +} {9 24 16 41} +test canvRect-3.7 {RectOvalCoords procedure} { + list [catch {.c coords x 1 2 3 4 5} msg] $msg +} {1 {wrong # coordinates: expected 0 or 4, got 5}} + +.c delete withtag all +.c create rectangle 10 20 30 40 -tags x -width 1 +test canvRect-4.1 {ConfigureRectOval procedure} { + list [catch {.c itemconfigure x -width abc} msg] $msg \ + [.c itemcget x -width] +} {1 {bad screen distance "abc"} 1.0} +test canvRect-4.2 {ConfigureRectOval procedure} { + list [catch {.c itemconfigure x -width -5} msg] $msg +} {1 {bad screen distance "-5"}} +test canvRect-4.3 {ConfigureRectOval procedure} {nonPortable} { + # Non-portable due to rounding differences. + .c itemconfigure x -width 10 + .c bbox x +} {5 15 35 45} +# I can't come up with any good tests for DeleteRectOval. + +.c delete withtag all +.c create rectangle 10 20 30 40 -tags x -width 1 -outline {} +test canvRect-5.1 {ComputeRectOvalBbox procedure} {nonPortable} { + # Non-portable due to rounding differences: + .c coords x 20 15 10 5 + .c bbox x +} {10 5 20 15} +test canvRect-5.2 {ComputeRectOvalBbox procedure} {nonPortable} { + # Non-portable due to rounding differences: + .c coords x 10 20 30 10 + .c itemconfigure x -width 1 -outline red + .c bbox x +} {9 9 31 21} +test canvRect-5.3 {ComputeRectOvalBbox procedure} {nonPortable} { + # Non-portable due to rounding differences: + .c coords x 10 20 30 10 + .c itemconfigure x -width 2 -outline red + .c bbox x +} {9 9 31 21} +test canvRect-5.4 {ComputeRectOvalBbox procedure} {nonPortable} { + # Non-portable due to rounding differences: + .c coords x 10 20 30 10 + .c itemconfigure x -width 3 -outline red + .c bbox x +} {8 8 32 22} + +# I can't come up with any good tests for DisplayRectOval. + +.c delete withtag all +set x [.c create rectangle 10 20 30 35 -tags x -fill green] +set y [.c create rectangle 15 25 25 30 -tags y -fill red] +test canvRect-6.1 {RectToPoint procedure} { + .c itemconfigure y -outline {} + list [.c find closest 14.9 28] [.c find closest 15.1 28] \ + [.c find closest 24.9 28] [.c find closest 25.1 28] +} "$x $y $y $x" +test canvRect-6.2 {RectToPoint procedure} { + .c itemconfigure y -outline {} + list [.c find closest 20 24.9] [.c find closest 20 25.1] \ + [.c find closest 20 29.9] [.c find closest 20 30.1] +} "$x $y $y $x" +test canvRect-6.3 {RectToPoint procedure} { + .c itemconfigure y -width 1 -outline black + list [.c find closest 14.4 28] [.c find closest 14.6 28] \ + [.c find closest 25.4 28] [.c find closest 25.6 28] +} "$x $y $y $x" +test canvRect-6.4 {RectToPoint procedure} { + .c itemconfigure y -width 1 -outline black + list [.c find closest 20 24.4] [.c find closest 20 24.6] \ + [.c find closest 20 30.4] [.c find closest 20 30.6] +} "$x $y $y $x" +.c itemconfigure x -fill {} -outline black -width 3 +.c itemconfigure y -outline {} +test canvRect-6.5 {RectToPoint procedure} { + list [.c find closest 13.2 28] [.c find closest 13.3 28] \ + [.c find closest 26.7 28] [.c find closest 26.8 28] +} "$x $y $y $x" +test canvRect-6.6 {RectToPoint procedure} { + list [.c find closest 20 23.2] [.c find closest 20 23.3] \ + [.c find closest 20 31.7] [.c find closest 20 31.8] +} "$x $y $y $x" +.c delete withtag all +set x [.c create rectangle 10 20 30 40 -outline {} -fill black] +set y [.c create rectangle 40 40 50 50 -outline {} -fill black] +test canvRect-6.7 {RectToPoint procedure} { + list [.c find closest 35 35] [.c find closest 36 36] \ + [.c find closest 37 37] [.c find closest 38 38] +} "$x $y $y $y" + +.c delete withtag all +set x [.c create rectangle 10 20 30 35 -fill green -outline {}] +set y [.c create rectangle 40 45 60 70 -fill red -outline black -width 3] +set z [.c create rectangle 100 150 120 170 -fill {} -outline black -width 3] +test canvRect-7.1 {RectToArea procedure} { + list [.c find overlapping 20 50 38 60] \ + [.c find overlapping 20 50 39 60] \ + [.c find overlapping 20 50 70 60] \ + [.c find overlapping 61 50 70 60] \ + [.c find overlapping 62 50 70 60] +} "{} $y $y $y {}" +test canvRect-7.2 {RectToArea procedure} { + list [.c find overlapping 45 20 55 43] \ + [.c find overlapping 45 20 55 44] \ + [.c find overlapping 45 20 55 80] \ + [.c find overlapping 45 71 55 80] \ + [.c find overlapping 45 72 55 80] +} "{} $y $y $y {}" +test canvRect-7.3 {RectToArea procedure} { + list [.c find overlapping 5 25 9.9 30] [.c find overlapping 5 25 10.1 30] +} "{} $x" +test canvRect-7.4 {RectToArea procedure} { + list [.c find overlapping 102 152 118 168] \ + [.c find overlapping 101 152 118 168] \ + [.c find overlapping 102 151 118 168] \ + [.c find overlapping 102 152 119 168] \ + [.c find overlapping 102 152 118 169] +} "{} $z $z $z $z" +test canvRect-7.5 {RectToArea procedure} { + list [.c find enclosed 20 40 38 80] \ + [.c find enclosed 20 40 39 80] \ + [.c find enclosed 20 40 70 80] \ + [.c find enclosed 61 40 70 80] \ + [.c find enclosed 62 40 70 80] +} "{} {} $y {} {}" +test canvRect-7.6 {RectToArea procedure} { + list [.c find enclosed 20 20 65 43] \ + [.c find enclosed 20 20 65 44] \ + [.c find enclosed 20 20 65 80] \ + [.c find enclosed 20 71 65 80] \ + [.c find enclosed 20 72 65 80] +} "{} {} $y {} {}" + +.c delete withtag all +set x [.c create oval 50 100 200 150 -fill green -outline {}] +set y [.c create oval 50 100 200 150 -fill red -outline black -width 3] +set z [.c create oval 50 100 200 150 -fill {} -outline black -width 3] +test canvRect-8.1 {OvalToArea procedure} { + list [.c find overlapping 20 120 48 130] \ + [.c find overlapping 20 120 49 130] \ + [.c find overlapping 20 120 50.2 130] \ + [.c find overlapping 20 120 300 130] \ + [.c find overlapping 60 120 190 130] \ + [.c find overlapping 199.9 120 300 130] \ + [.c find overlapping 201 120 300 130] \ + [.c find overlapping 202 120 300 130] +} "{} {$y $z} {$x $y $z} {$x $y $z} {$x $y} {$x $y $z} {$y $z} {}" +test canvRect-8.2 {OvalToArea procedure} { + list [.c find overlapping 100 50 150 98] \ + [.c find overlapping 100 50 150 99] \ + [.c find overlapping 100 50 150 100.1] \ + [.c find overlapping 100 50 150 200] \ + [.c find overlapping 100 110 150 140] \ + [.c find overlapping 100 149.9 150 200] \ + [.c find overlapping 100 151 150 200] \ + [.c find overlapping 100 152 150 200] +} "{} {$y $z} {$x $y $z} {$x $y $z} {$x $y} {$x $y $z} {$y $z} {}" +test canvRect-8.3 {OvalToArea procedure} { + list [.c find overlapping 176 104 177 105] \ + [.c find overlapping 187 116 188 117] \ + [.c find overlapping 192 142 193 143] \ + [.c find overlapping 180 138 181 139] \ + [.c find overlapping 61 142 62 143] \ + [.c find overlapping 65 137 66 136] \ + [.c find overlapping 62 108 63 109] \ + [.c find overlapping 68 115 69 116] +} "{} {$x $y} {} {$x $y} {} {$x $y} {} {$x $y}" + +test canvRect-9.1 {ScaleRectOval procedure} { + .c delete withtag all + .c create rect 100 300 200 350 -tags x + .c scale x 50 100 2 4 + .c coords x +} {150.0 900.0 350.0 1100.0} + +test canvRect-10.1 {TranslateRectOval procedure} { + .c delete withtag all + .c create rect 100 300 200 350 -tags x + .c move x 100 -10 + .c coords x +} {200.0 290.0 300.0 340.0} + +# This test is non-portable because different color information +# will get generated on different displays (e.g. mono displays +# vs. color). +test canvRect-11.1 {RectOvalToPostscript procedure} {nonPortable macCrash} { + # Crashes on Mac because the XGetImage() call isn't implemented, causing a + # dereference of NULL. + + .c configure -bd 0 -highlightthickness 0 + .c delete withtag all + .c create rect 50 60 90 80 -fill black -stipple gray50 -outline {} + .c create oval 100 150 200 200 -fill {} -outline #ff0000 -width 5 + update + set x [.c postscript] + string range $x [string first "-200 -150 translate" $x] end +} {-200 -150 translate +0 300 moveto 400 300 lineto 400 0 lineto 0 0 lineto closepath clip newpath +gsave +50 240 moveto 40 0 rlineto 0 -20 rlineto -40 0 rlineto closepath +0.000 0.000 0.000 setrgbcolor AdjustColor +clip 16 16 <5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555 +aaaa> StippleFill +grestore +gsave +matrix currentmatrix +150 125 translate 50 25 scale 1 0 moveto 0 0 1 0 360 arc +setmatrix +5 setlinewidth 0 setlinejoin 2 setlinecap +1.000 0.000 0.000 setrgbcolor AdjustColor +stroke +grestore +restore showpage + +%%Trailer +end +%%EOF +} + +# cleanup +cleanupTests +return diff --git a/pd/tkpath/tests/canvText.test b/pd/tkpath/tests/canvText.test new file mode 100644 index 0000000000000000000000000000000000000000..fb00eec5f752ef9df03a088d8be74df738b613f7 --- /dev/null +++ b/pd/tkpath/tests/canvText.test @@ -0,0 +1,574 @@ +# This file is a Tcl script to test out the procedures in tkCanvText.c, +# which implement canvas "text" items. It is organized in the standard +# fashion for Tcl tests. +# +# Copyright (c) 1996-1997 Sun Microsystems, Inc. +# Copyright (c) 1998-1999 by Scriptics Corporation. +# All rights reserved. +# +# RCS: @(#) $Id: canvText.test,v 1.1 2008/05/21 13:56:02 matben Exp $ + +package require tcltest 2.1 +eval tcltest::configure $argv +tcltest::loadTestedCommands + +tkp::canvas .c -width 400 -height 300 -bd 2 -relief sunken +pack .c +update + +set i 1 +.c create text 20 20 -tag test + +set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" +set ay [font metrics $font -linespace] +set ax [font measure $font 0] + + +foreach test { + {-anchor nw nw xyz {bad anchor position "xyz": must be n, ne, e, se, s, sw, w, nw, or center}} + {-fill #ff0000 #ff0000 xyz {unknown color name "xyz"}} + {-fill {} {} {} {}} + {-font {Times 40} {Times 40} {} {font "" doesn't exist}} + {-justify left left xyz {bad justification "xyz": must be left, right, or center}} + {-stipple gray50 gray50 xyz {bitmap "xyz" not defined}} + {-tags {test a b c} {test a b c} {} {}} + {-text xyz xyz {} {}} + {-underline 0 0 xyz {expected integer but got "xyz"}} + {-width 6 6 xyz {bad screen distance "xyz"}} +} { + lassign $test name goodValue goodResult badValue badResult + test canvText-1.$i "configuration options: good value for $name" { + .c itemconfigure test $name $goodValue + list [lindex [.c itemconfigure test $name] 4] [.c itemcget test $name] + } [list $goodResult $goodResult] + incr i + if {$badValue ne ""} { + test canvText-1.$i "configuration options: bad value for $name" -body { + .c itemconfigure test $name $badValue + } -returnCodes error -result $badResult + } + incr i +} +test canvText-1.$i {configuration options} { + .c itemconfigure test -tags {test xyz} + .c itemcget xyz -tags +} {test xyz} + +.c delete test +.c create text 20 20 -tag test + +test canvText-2.1 {CreateText procedure: args} { + list [catch {.c create text} msg] $msg +} {1 {wrong # args: should be ".c create text coords ?arg arg ...?"}} +test canvText-2.2 {CreateText procedure: args} { + list [catch {.c create text xyz 0} msg] $msg +} {1 {bad screen distance "xyz"}} +test canvText-2.3 {CreateText procedure: args} { + list [catch {.c create text 0 xyz} msg] $msg +} {1 {bad screen distance "xyz"}} +test canvText-2.4 {CreateText procedure: args} { + list [catch {.c create text 0 0 -xyz xyz} msg] $msg +} {1 {unknown option "-xyz"}} +test canvText-2.5 {CreateText procedure} { + .c create text 0 0 -tags x + set x [.c coords x] + .c delete x + set x +} {0.0 0.0} + +focus -force .c +.c focus test +.c coords test 0 0 +update + +test canvText-3.1 {TextCoords procedure} { + .c coords test +} {0.0 0.0} +test canvText-3.2 {TextCoords procedure} { + list [catch {.c coords test xyz 0} msg] $msg +} {1 {bad screen distance "xyz"}} +test canvText-3.3 {TextCoords procedure} { + list [catch {.c coords test 0 xyz} msg] $msg +} {1 {bad screen distance "xyz"}} +test canvText-3.4 {TextCoords procedure} { + .c coords test 10 10 + set result {} + foreach element [.c coords test] { + lappend result [format %.1f $element] + } + set result +} {10.0 10.0} +test canvText-3.5 {TextCoords procedure} { + list [catch {.c coords test 10} msg] $msg +} {1 {wrong # coordinates: expected 2, got 1}} +test canvText-3.6 {TextCoords procedure} { + list [catch {.c coords test 10 10 10} msg] $msg +} {1 {wrong # coordinates: expected 0 or 2, got 3}} + +test canvText-4.1 {ConfigureText procedure} { + list [catch {.c itemconfig test -fill xyz} msg] $msg +} {1 {unknown color name "xyz"}} +test canvText-4.2 {ConfigureText procedure} { + .c itemconfig test -fill blue + .c itemcget test -fill +} {blue} +test canvText-4.3 {ConfigureText procedure: construct font gcs} { + .c itemconfig test -font "times 20" -fill black -stipple gray50 + list [.c itemcget test -font] [.c itemcget test -fill] [.c itemcget test -stipple] +} {{times 20} black gray50} +test canvText-4.4 {ConfigureText procedure: construct cursor gc} { + .c itemconfig test -text "abcdefg" + .c select from test 2 + .c select to test 4 + .c icursor test 3 + + # Both black -> cursor becomes white. + .c config -insertbackground black + .c config -selectbackground black + .c itemconfig test -just left + update + + # Both same color (and not black) -> cursor becomes black. + .c config -insertbackground red + .c config -selectbackground red + .c itemconfig test -just left + update +} {} +test canvText-4.5 {ConfigureText procedure: adjust selection} { + set x {} + .c itemconfig test -text "abcdefghi" + .c select from test 2 + .c select to test 6 + lappend x [selection get] + .c dchars test 1 end + lappend x [catch {selection get}] + .c insert test end "bcdefghi" + .c select from test 2 + .c select to test 6 + lappend x [selection get] + .c dchars test 4 end + lappend x [selection get] + .c insert test end "efghi" + .c select from test 6 + .c select to test 2 + lappend x [selection get] + .c dchars test 4 end + lappend x [selection get] +} {cdefg 1 cdefg cd cdef cd} +test canvText-4.6 {ConfigureText procedure: adjust cursor} { + .c itemconfig test -text "abcdefghi" + set x {} + .c icursor test 6 + .c dchars test 4 end + .c index test insert +} {4} + +test canvText-5.1 {ConfigureText procedure: adjust cursor} { + .c create text 10 10 -tag x -fill blue -font "times 40" -stipple gray50 -text "xyz" + .c delete x +} {} + +test canvText-6.1 {ComputeTextBbox procedure} {fonts nonPortable} { + .c itemconfig test -font $font -text 0 + .c coords test 0 0 + set x {} + lappend x [.c itemconfig test -anchor n; .c bbox test] + lappend x [.c itemconfig test -anchor nw; .c bbox test] + lappend x [.c itemconfig test -anchor w; .c bbox test] + lappend x [.c itemconfig test -anchor sw; .c bbox test] + lappend x [.c itemconfig test -anchor s; .c bbox test] + lappend x [.c itemconfig test -anchor se; .c bbox test] + lappend x [.c itemconfig test -anchor e; .c bbox test] + lappend x [.c itemconfig test -anchor ne; .c bbox test] + lappend x [.c itemconfig test -anchor center; .c bbox test] +} "{[expr -$ax/2-1] 0 [expr $ax/2+1] $ay}\ +{-1 0 [expr $ax+1] $ay}\ +{-1 [expr -$ay/2] [expr $ax+1] [expr $ay/2]}\ +{-1 -$ay [expr $ax+1] 0}\ +{[expr -$ax/2-1] -$ay [expr $ax/2+1] 0}\ +{[expr -$ax-1] -$ay 1 0}\ +{[expr -$ax-1] [expr -$ay/2] 1 [expr $ay/2]}\ +{[expr -$ax-1] 0 1 $ay}\ +{[expr -$ax/2-1] [expr -$ay/2] [expr $ax/2+1] [expr $ay/2]}" + +focus .c +.c focus test +.c itemconfig test -text "abcd\nefghi\njklmnopq" +test canvText-7.0 {DisplayText procedure: stippling} { + .c itemconfig test -stipple gray50 + update + .c itemconfig test -stipple {} + update +} {} +test canvText-7.2 {DisplayText procedure: draw selection} { + .c select from test 0 + .c select to test end + update + selection get +} "abcd\nefghi\njklmnopq" +test canvText-7.3 {DisplayText procedure: selection} { + .c select from test 0 + .c select to test end + update + selection get +} "abcd\nefghi\njklmnopq" +test canvText-7.4 {DisplayText procedure: one line selection} { + .c select from test 2 + .c select to test 3 + update +} {} +test canvText-7.5 {DisplayText procedure: multi-line selection} { + .c select from test 2 + .c select to test 12 + update +} {} +test canvText-7.6 {DisplayText procedure: draw cursor} { + .c icursor test 3 + update +} {} +test canvText-7.7 {DisplayText procedure: selected text different color} { + .c config -selectforeground blue + .c itemconfig test -anchor n + update +} {} +test canvText-7.8 {DisplayText procedure: not selected} { + .c select clear + update +} {} +test canvText-7.9 {DisplayText procedure: select end} { + catch {destroy .t} + toplevel .t + wm geometry .t +0+0 + tkp::canvas .t.c + pack .t.c + set id [.t.c create text 0 0 -text Dummy -anchor nw] + update + .t.c select from $id 0 + .t.c select to $id end + update + #catch {destroy .t} + update +} {} + +test canvText-8.1 {TextInsert procedure: 0 length insert} { + .c insert test end {} +} {} +test canvText-8.2 {TextInsert procedure: before beginning/after end} { + # Can't test this because GetTextIndex filters out those numbers. +} {} +test canvText-8.3 {TextInsert procedure: inserting in a selected item} { + .c itemconfig test -text "abcdefg" + .c select from test 2 + .c select to test 4 + .c insert test 1 "xyz" + .c itemcget test -text +} {axyzbcdefg} +test canvText-8.4 {TextInsert procedure: inserting before selection} { + .c itemconfig test -text "abcdefg" + .c select from test 2 + .c select to test 4 + .c insert test 1 "xyz" + list [.c index test sel.first] [.c index test sel.last] +} {5 7} +test canvText-8.5 {TextInsert procedure: inserting in selection} { + .c itemconfig test -text "abcdefg" + .c select from test 2 + .c select to test 4 + .c insert test 3 "xyz" + list [.c index test sel.first] [.c index test sel.last] +} {2 7} +test canvText-8.6 {TextInsert procedure: inserting after selection} { + .c itemconfig test -text "abcdefg" + .c select from test 2 + .c select to test 4 + .c insert test 5 "xyz" + list [.c index test sel.first] [.c index test sel.last] +} {2 4} +test canvText-8.7 {TextInsert procedure: inserting in unselected item} { + .c itemconfig test -text "abcdefg" + .c select clear + .c insert test 5 "xyz" + .c itemcget test -text +} {abcdexyzfg} +test canvText-8.8 {TextInsert procedure: inserting before cursor} { + .c itemconfig test -text "abcdefg" + .c icursor test 3 + .c insert test 2 "xyz" + .c index test insert +} {6} +test canvText-8.9 {TextInsert procedure: inserting after cursor} { + .c itemconfig test -text "abcdefg" + .c icursor test 3 + .c insert test 4 "xyz" + .c index test insert +} {3} + +test canvText-9.1 {TextInsert procedure: before beginning/after end} { + # Can't test this because GetTextIndex filters out those numbers. +} {} +test canvText-9.2 {TextInsert procedure: start > end} { + .c itemconfig test -text "abcdefg" + .c dchars test 4 2 + .c itemcget test -text +} {abcdefg} +test canvText-9.3 {TextInsert procedure: deleting from a selected item} { + .c itemconfig test -text "abcdefg" + .c select from test 2 + .c select to test 4 + .c dchars test 3 5 + .c itemcget test -text +} {abcg} +test canvText-9.4 {TextInsert procedure: deleting before start} { + .c itemconfig test -text "abcdefghijk" + .c select from test 4 + .c select to test 8 + .c dchars test 1 1 + list [.c index test sel.first] [.c index test sel.last] +} {3 7} +test canvText-9.5 {TextInsert procedure: keep start > first char deleted} { + .c itemconfig test -text "abcdefghijk" + .c select from test 4 + .c select to test 8 + .c dchars test 2 6 + list [.c index test sel.first] [.c index test sel.last] +} {2 3} +test canvText-9.6 {TextInsert procedure: deleting inside selection} { + .c itemconfig test -text "abcdefghijk" + .c select from test 4 + .c select to test 8 + .c dchars test 6 6 + list [.c index test sel.first] [.c index test sel.last] +} {4 7} +test canvText-9.7 {TextInsert procedure: keep end > first char deleted} { + .c itemconfig test -text "abcdefghijk" + .c select from test 4 + .c select to test 8 + .c dchars test 6 10 + list [.c index test sel.first] [.c index test sel.last] +} {4 5} +test canvText-9.8 {TextInsert procedure: selectFirst > selectLast: deselect} { + .c itemconfig test -text "abcdefghijk" + .c select from test 4 + .c select to test 8 + .c dchars test 3 10 + list [catch {.c index test sel.first} msg] $msg +} {1 {selection isn't in item}} +test canvText-9.9 {TextInsert procedure: selectFirst <= selectLast} { + .c itemconfig test -text "abcdefghijk" + .c select from test 4 + .c select to test 8 + .c dchars test 4 7 + list [.c index test sel.first] [.c index test sel.last] +} {4 4} +test canvText-9.10 {TextInsert procedure: move anchor} { + .c itemconfig test -text "abcdefghijk" + .c select from test 6 + .c select to test 8 + .c dchars test 2 4 + .c select to test 1 + list [.c index test sel.first] [.c index test sel.last] +} {1 2} +test canvText-9.11 {TextInsert procedure: keep anchor >= first} { + .c itemconfig test -text "abcdefghijk" + .c select from test 6 + .c select to test 8 + .c dchars test 5 7 + .c select to test 1 + list [.c index test sel.first] [.c index test sel.last] +} {1 4} +test canvText-9.12 {TextInsert procedure: anchor doesn't move} { + .c itemconfig test -text "abcdefghijk" + .c select from test 2 + .c select to test 5 + .c dchars test 6 8 + .c select to test 8 + list [.c index test sel.first] [.c index test sel.last] +} {2 8} +test canvText-9.13 {TextInsert procedure: move cursor} { + .c itemconfig test -text "abcdefghijk" + .c icursor test 6 + .c dchars test 2 4 + .c index test insert +} {3} +test canvText-9.14 {TextInsert procedure: keep cursor >= first} { + .c itemconfig test -text "abcdefghijk" + .c icursor test 6 + .c dchars test 2 10 + .c index test insert +} {2} +test canvText-9.15 {TextInsert procedure: cursor doesn't move} { + .c itemconfig test -text "abcdefghijk" + .c icursor test 5 + .c dchars test 7 9 + .c index test insert +} {5} + +test canvText-10.1 {TextToPoint procedure} { + .c coords test 0 0 + .c itemconfig test -text 0 -anchor center + .c index test @0,0 +} {0} + +test canvText-11.1 {TextToArea procedure} { + .c coords test 0 0 + .c itemconfig test -text 0 -anchor center + .c find overlapping 0 0 1 1 +} [.c find withtag test] +test canvText-11.2 {TextToArea procedure} { + .c coords test 0 0 + .c itemconfig test -text 0 -anchor center + .c find overlapping 1000 1000 1001 1001 +} {} + +test canvText-12.1 {ScaleText procedure} { + .c coords test 100 100 + .c scale all 50 50 2 2 + .c coords test +} {150.0 150.0} + +test canvText-13.1 {TranslateText procedure} { + .c coords test 100 100 + .c move all 10 10 + .c coords test +} {110.0 110.0} + +.c itemconfig test -text "abcdefghijklmno" -anchor nw +.c select from test 5 +.c select to test 8 +.c icursor test 12 +.c coords test 0 0 +test canvText-14.1 {GetTextIndex procedure} { + list [.c index test end] [.c index test insert] \ + [.c index test sel.first] [.c index test sel.last] \ + [.c index test @0,0] \ + [.c index test -1] [.c index test 10] [.c index test 100] +} {15 12 5 8 0 0 10 15} +test canvText-14.2 {GetTextIndex procedure: select error} { + .c select clear + list [catch {.c index test sel.first} msg] $msg +} {1 {selection isn't in item}} +test canvText-14.3 {GetTextIndex procedure: select error} { + .c select clear + list [catch {.c index test sel.last} msg] $msg +} {1 {selection isn't in item}} +test canvText-14.4 {GetTextIndex procedure: select error} { + .c select clear + list [catch {.c index test sel.} msg] $msg +} {1 {bad index "sel."}} +test canvText-14.5 {GetTextIndex procedure: bad int or unknown index} { + list [catch {.c index test xyz} msg] $msg +} {1 {bad index "xyz"}} + +test canvText-15.1 {SetTextCursor procedure} { + .c itemconfig -text "abcdefg" + .c icursor test 3 + .c index test insert +} {3} + +test canvText-16.1 {GetSelText procedure} { + .c itemconfig test -text "abcdefghijklmno" -anchor nw + .c select from test 5 + .c select to test 8 + selection get +} {fghi} + +set font {Courier 12 italic} +set ax [font measure $font 0] +set ay [font metrics $font -linespace] + +test canvText-17.1 {TextToPostscript procedure} { + .c delete all + .c config -height 300 -highlightthickness 0 -bd 0 + update + .c create text 100 100 -tags test + .c itemconfig test -font $font -text "00000000" -width [expr 3*$ax] + .c itemconfig test -anchor n -fill black + set x [.c postscript] + set x [string range $x [string first "/Courier-Oblique" $x] end] +} "/Courier-Oblique findfont [font actual $font -size] scalefont ISOEncode setfont +0.000 0.000 0.000 setrgbcolor AdjustColor +100 200 \[ +\[(000)\] +\[(000)\] +\[(00)\] +] $ay -0.5 0 0 false DrawText +grestore +restore showpage + +%%Trailer +end +%%EOF +" + +test canvText-18.1 {bug fix 2525, find enclosed on text with newlines} { + catch {destroy .c} + tkp::canvas .c + pack .c + .c delete all + .c create text 100 100 -text Hello\n -anchor nw + set bbox [.c bbox 1] + set x2 [lindex $bbox 2] + set y2 [lindex $bbox 3] + incr y2 + update + .c find enclosed 99 99 [expr $x2 + $i] [expr $y2 + 1] +} 1 + +test canvText-19.1 {patch 1006286, leading space caused wrap under Win32} { + catch {destroy .c} + set c [tkp::canvas .c -bg black -width 964] + pack $c + $c delete all + after 1000 "set done 1" ; vwait done + + set f {Arial 28 bold} + + set s1 { Yeah-ah-ah-ah-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-Yow} + set s2 { Yeah ah ah ah oh oh oh oh oh oh oh oh oh oh oh oh oh oh oh oh Yow} + + $c create text 21 18 \ + -font $f \ + -text $s1 \ + -fill white \ + -width 922 \ + -anchor nw \ + -tags tbox1 + eval {$c create rect} [$c bbox tbox1] -outline red + + $c create text 21 160 \ + -font $f \ + -text $s2 \ + -fill white \ + -width 922 \ + -anchor nw \ + -tags tbox2 + eval {$c create rect} [$c bbox tbox2] -outline red + + after 1000 "set done 1" ; vwait done + + set results [list] + + $c select from tbox2 4 + $c select to tbox2 8 + lappend results [selection get] + + $c select from tbox1 4 + $c select to tbox1 8 + lappend results [selection get] + + array set metrics [font metrics $f] + set x [expr {21 + [font measure $f " "] \ + + ([font measure {Arial 28 bold} "Y"] / 2)}] + set y1 [expr {18 + ($metrics(-linespace) / 2)}] + set y2 [expr {160 + ($metrics(-linespace) / 2)}] + + lappend results [$c index tbox1 @$x,$y1] + lappend results [$c index tbox2 @$x,$y2] + + set results +} {{Yeah } Yeah- 4 4} + + +# cleanup +cleanupTests +return diff --git a/pd/tkpath/tests/canvWind.test b/pd/tkpath/tests/canvWind.test new file mode 100644 index 0000000000000000000000000000000000000000..26ec7d4a414eeab2c0826703e57dce8136f65cdc --- /dev/null +++ b/pd/tkpath/tests/canvWind.test @@ -0,0 +1,131 @@ +# This file is a Tcl script to test out the procedures in tkCanvWind.c, +# which implement canvas "window" items. It is organized in the standard +# fashion for Tcl tests. +# +# Copyright (c) 1997 Sun Microsystems, Inc. +# Copyright (c) 1998-1999 by Scriptics Corporation. +# All rights reserved. +# +# RCS: @(#) $Id: canvWind.test,v 1.1 2008/05/21 13:56:02 matben Exp $ + +package require tcltest 2.1 +eval tcltest::configure $argv +tcltest::loadTestedCommands + +test canvWind-1.1 {DisplayWinItem, windows off-screen vertically} { + catch {destroy .t} + toplevel .t + tkp::canvas .t.c -scrollregion {0 0 1000 800} -width 250 -height 200 -bd 2 \ + -relief sunken -xscrollincrement 1 -yscrollincrement 1 \ + -highlightthickness 1 + pack .t.c -fill both -expand 1 -padx 20 -pady 20 + wm geometry .t +0+0 + set f .t.f + frame $f -width 80 -height 50 -bg red + .t.c create window 300 400 -window $f -anchor nw + .t.c xview moveto .3 + .t.c yview moveto .50 + update + set x [list [list [winfo ismapped $f] [winfo y $f]]] + .t.c yview scroll 52 units + update + lappend x [list [winfo ismapped $f] [winfo y $f]] + .t.c yview scroll 1 units + update + lappend x [list [winfo ismapped $f] [winfo y $f]] + .t.c yview scroll -255 units + update + lappend x [list [winfo ismapped $f] [winfo y $f]] + .t.c yview scroll -1 units + update + lappend x [list [winfo ismapped $f] [winfo y $f]] +} {{1 23} {1 -29} {0 -29} {1 225} {0 225}} +test canvWind-1.2 {DisplayWinItem, windows off-screen vertically} { + catch {destroy .t} + toplevel .t + tkp::canvas .t.c -scrollregion {0 0 1000 800} -width 250 -height 200 -bd 2 \ + -relief sunken -xscrollincrement 1 -yscrollincrement 1 \ + -highlightthickness 1 + pack .t.c -fill both -expand 1 -padx 20 -pady 20 + wm geometry .t +0+0 + set f .t.c.f + frame $f -width 80 -height 50 -bg red + .t.c create window 300 400 -window $f -anchor nw + .t.c xview moveto .3 + .t.c yview moveto .50 + update + set x [list [list [winfo ismapped $f] [winfo y $f]]] + .t.c yview scroll 52 units + update + lappend x [list [winfo ismapped $f] [winfo y $f]] + .t.c yview scroll 1 units + update + lappend x [list [winfo ismapped $f] [winfo y $f]] + .t.c yview scroll -255 units + update + lappend x [list [winfo ismapped $f] [winfo y $f]] + .t.c yview scroll -1 units + update + lappend x [list [winfo ismapped $f] [winfo y $f]] +} {{1 3} {1 -49} {0 -49} {1 205} {0 205}} +test canvWind-1.3 {DisplayWinItem, windows off-screen horizontally} { + catch {destroy .t} + toplevel .t + tkp::canvas .t.c -scrollregion {0 0 1000 800} -width 250 -height 200 -bd 2 \ + -relief sunken -xscrollincrement 1 -yscrollincrement 1 \ + -highlightthickness 1 + pack .t.c -fill both -expand 1 -padx 20 -pady 20 + wm geometry .t +0+0 + set f .t.f + frame $f -width 80 -height 50 -bg red + .t.c create window 300 400 -window $f -anchor nw + .t.c xview moveto .3 + .t.c yview moveto .50 + update + set x [list [list [winfo ismapped $f] [winfo x $f]]] + .t.c xview scroll 82 units + update + lappend x [list [winfo ismapped $f] [winfo x $f]] + .t.c xview scroll 1 units + update + lappend x [list [winfo ismapped $f] [winfo x $f]] + .t.c xview scroll -335 units + update + lappend x [list [winfo ismapped $f] [winfo x $f]] + .t.c xview scroll -1 units + update + lappend x [list [winfo ismapped $f] [winfo x $f]] +} {{1 23} {1 -59} {0 -59} {1 275} {0 275}} +test canvWind-1.4 {DisplayWinItem, windows off-screen horizontally} { + catch {destroy .t} + toplevel .t + tkp::canvas .t.c -scrollregion {0 0 1000 800} -width 250 -height 200 -bd 2 \ + -relief sunken -xscrollincrement 1 -yscrollincrement 1 \ + -highlightthickness 1 + pack .t.c -fill both -expand 1 -padx 20 -pady 20 + wm geometry .t +0+0 + set f .t.c.f + frame $f -width 80 -height 50 -bg red + .t.c create window 300 400 -window $f -anchor nw + .t.c xview moveto .3 + .t.c yview moveto .50 + update + set x [list [list [winfo ismapped $f] [winfo x $f]]] + .t.c xview scroll 82 units + update + lappend x [list [winfo ismapped $f] [winfo x $f]] + .t.c xview scroll 1 units + update + lappend x [list [winfo ismapped $f] [winfo x $f]] + .t.c xview scroll -335 units + update + lappend x [list [winfo ismapped $f] [winfo x $f]] + .t.c xview scroll -1 units + update + lappend x [list [winfo ismapped $f] [winfo x $f]] +} {{1 3} {1 -79} {0 -79} {1 255} {0 255}} +catch {destroy .t} + +# cleanup +cleanupTests +return diff --git a/pd/tkpath/tests/canvas.test b/pd/tkpath/tests/canvas.test new file mode 100644 index 0000000000000000000000000000000000000000..6479e135548d40810b86c46c4cd90a3fd657ee6f --- /dev/null +++ b/pd/tkpath/tests/canvas.test @@ -0,0 +1,529 @@ +# This file is a Tcl script to test out the procedures in tkCanvas.c, +# which implements generic code for canvases. It is organized in the +# standard fashion for Tcl tests. +# +# Copyright (c) 1995-1996 Sun Microsystems, Inc. +# Copyright (c) 1998-2000 Ajuba Solutions. +# All rights reserved. +# +# RCS: @(#) $Id: canvas.test,v 1.1 2008/05/21 13:56:02 matben Exp $ + +package require tcltest 2.1 +eval tcltest::configure $argv +tcltest::loadTestedCommands + +# XXX - This test file is woefully incomplete. At present, only a +# few of the features are tested. + +tkp::canvas .c +pack .c +update +set i 1 +foreach {testname testinfo} { + canvas-1.1 {-background #ff0000 #ff0000 + non-existent {unknown color name "non-existent"}} + canvas-1.2 {-bg #ff0000 #ff0000 + non-existent {unknown color name "non-existent"}} + canvas-1.3 {-bd 4 4 badValue {bad screen distance "badValue"}} + canvas-1.4 {-borderwidth 1.3 1 badValue {bad screen distance "badValue"}} + canvas-1.5 {-closeenough 24 24.0 + bogus {expected floating-point number but got "bogus"}} + canvas-1.6 {-confine true 1 silly {expected boolean value but got "silly"}} + canvas-1.7 {-cursor arrow arrow badValue {bad cursor spec "badValue"}} + canvas-1.8 {-height 2.1 2 x42 {bad screen distance "x42"}} + canvas-1.9 {-highlightbackground #112233 #112233 + ugly {unknown color name "ugly"}} + canvas-1.10 {-highlightcolor #110022 #110022 + bogus {unknown color name "bogus"}} + canvas-1.11 {-highlightthickness 18 18 + badValue {bad screen distance "badValue"}} + canvas-1.12 {-insertbackground #110022 #110022 + bogus {unknown color name "bogus"}} + canvas-1.13 {-insertborderwidth 1.3 1 2.6x {bad screen distance "2.6x"}} + canvas-1.14 {-insertofftime 100 100 3.2 {expected integer but got "3.2"}} + canvas-1.15 {-insertontime 100 100 3.2 {expected integer but got "3.2"}} + canvas-1.16 {-insertwidth 1.3 1 6x {bad screen distance "6x"}} + canvas-1.17 {-relief groove groove + 1.5 {bad relief type "1.5": must be flat, groove, raised, ridge, solid, or sunken}} + canvas-1.18 {-selectbackground #110022 #110022 + bogus {unknown color name "bogus"}} + canvas-1.19 {-selectborderwidth 1.3 1 + badValue {bad screen distance "badValue"}} + canvas-1.20 {-selectforeground #654321 #654321 + bogus {unknown color name "bogus"}} + canvas-1.21 {-takefocus "any string" "any string" {} {}} + canvas-1.22 {-width 402 402 xyz {bad screen distance "xyz"}} + canvas-1.23 {-xscrollcommand {Some command} {Some command} {} {}} + canvas-1.24 {-yscrollcommand {Another command} {Another command} {} {}} +} { + lassign $testinfo name goodValue goodResult badValue badResult + test $testname-good "configuration options: good value for $name" { + .c configure $name $goodValue + lindex [.c configure $name] 4 + } $goodResult + incr i + if {$badValue ne ""} { + test $testname-bad "configuration options: bad value for $name" -body { + .c configure $name $badValue + } -returnCodes error -result $badResult + } + .c configure $name [lindex [.c configure $name] 3] + incr i +} +test canvas-1.25 {configure throws error on bad option} { + set res [list [catch {.c configure -gorp foo}]] + .c create rect 10 10 100 100 + lappend res [catch {.c configure -gorp foo}] + set res +} [list 1 1] + +catch {destroy .c} +tkp::canvas .c -width 60 -height 40 -scrollregion {0 0 200 150} -bd 0 \ + -highlightthickness 0 +pack .c +update + +test canvas-2.1 {CanvasWidgetCmd, bind option} { + set i [.c create rect 10 10 100 100] + list [catch {.c bind $i <a>} msg] $msg +} {0 {}} +test canvas-2.2 {CanvasWidgetCmd, bind option} { + set i [.c create rect 10 10 100 100] + list [catch {.c bind $i <} msg] $msg +} {1 {no event type or button # or keysym}} +test canvas-2.3 {CanvasWidgetCmd, xview option} { + .c configure -xscrollincrement 40 -yscrollincrement 5 + .c xview moveto 0 + update + set x [list [.c xview]] + .c xview scroll 2 units + update + lappend x [.c xview] +} {{0.0 0.3} {0.4 0.7}} +test canvas-2.4 {CanvasWidgetCmd, xview option} {nonPortable} { + # This test gives slightly different results on platforms such + # as NetBSD. I don't know why... + .c configure -xscrollincrement 0 -yscrollincrement 5 + .c xview moveto 0.6 + update + set x [list [.c xview]] + .c xview scroll 2 units + update + lappend x [.c xview] +} {{0.6 0.9} {0.66 0.96}} + +catch {destroy .c} +tkp::canvas .c -width 60 -height 40 -scrollregion {0 0 200 80} \ + -borderwidth 0 -highlightthickness 0 +pack .c +update +test canvas-3.1 {CanvasWidgetCmd, yview option} { + .c configure -xscrollincrement 40 -yscrollincrement 5 + .c yview moveto 0 + update + set x [list [.c yview]] + .c yview scroll 3 units + update + lappend x [.c yview] +} {{0.0 0.5} {0.1875 0.6875}} +test canvas-3.2 {CanvasWidgetCmd, yview option} { + .c configure -xscrollincrement 40 -yscrollincrement 0 + .c yview moveto 0 + update + set x [list [.c yview]] + .c yview scroll 2 units + update + lappend x [.c yview] +} {{0.0 0.5} {0.1 0.6}} + +test canvas-4.1 {ButtonEventProc procedure} { + deleteWindows + tkp::canvas .c1 -bg #543210 + rename .c1 .c2 + set x {} + lappend x [winfo children .] + lappend x [.c2 cget -bg] + destroy .c1 + lappend x [info command .c*] [winfo children .] +} {.c1 #543210 {} {}} + +test canvas-5.1 {ButtonCmdDeletedProc procedure} { + deleteWindows + tkp::canvas .c1 + rename .c1 {} + list [info command .c*] [winfo children .] +} {{} {}} + +catch {destroy .c} +tkp::canvas .c -width 100 -height 50 -scrollregion {-200 -100 305 102} \ + -borderwidth 2 -highlightthickness 3 +pack .c +update +test canvas-6.1 {CanvasSetOrigin procedure} { + .c configure -xscrollincrement 0 -yscrollincrement 0 + .c xview moveto 0 + .c yview moveto 0 + update + list [.c canvasx 0] [.c canvasy 0] +} {-205.0 -105.0} +test canvas-6.2 {CanvasSetOrigin procedure} { + .c configure -xscrollincrement 20 -yscrollincrement 10 + set x "" + foreach i {.08 .10 .48 .50} { + .c xview moveto $i + update + lappend x [.c canvasx 0] + } + set x +} {-165.0 -145.0 35.0 55.0} +test canvas-6.3 {CanvasSetOrigin procedure} { + .c configure -xscrollincrement 20 -yscrollincrement 10 + set x "" + foreach i {.06 .08 .70 .72} { + .c yview moveto $i + update + lappend x [.c canvasy 0] + } + set x +} {-95.0 -85.0 35.0 45.0} +test canvas-6.4 {CanvasSetOrigin procedure} { + .c configure -xscrollincrement 20 -yscrollincrement 10 + .c xview moveto 1.0 + .c canvasx 0 +} {215.0} +test canvas-6.5 {CanvasSetOrigin procedure} { + .c configure -xscrollincrement 20 -yscrollincrement 10 + .c yview moveto 1.0 + .c canvasy 0 +} {55.0} + +deleteWindows + +set l [lsort [interp hidden]] +test canvas-7.1 {canvas widget vs hidden commands} -setup { + catch {destroy .c} +} -body { + tkp::canvas .c + interp hide {} .c + destroy .c + list [winfo children .] [lsort [interp hidden]] +} -result [list {} $l] + +test canvas-8.1 {canvas arc bbox} -setup { + catch {destroy .c} + tkp::canvas .c +} -body { + .c create arc -100 10 100 210 -start 10 -extent 50 -style arc -tags arc1 + set arcBox [.c bbox arc1] + .c create arc 100 10 300 210 -start 10 -extent 50 -style chord -tags arc2 + set coordBox [.c bbox arc2] + .c create arc 300 10 500 210 -start 10 -extent 50 -style pieslice -tags arc3 + set pieBox [.c bbox arc3] + list $arcBox $coordBox $pieBox +} -result {{48 21 100 94} {248 21 300 94} {398 21 500 112}} + +test canvas-9.1 {canvas id creation and deletion} -setup { + catch {destroy .c} + tkp::canvas .c +} -body { + # With Tk 8.0.4 the ids are now stored in a hash table. You + # can use this test as a performance test with older versions + # by changing the value of size. + set size 15 + + for {set i 0} {$i < $size} {incr i} { + set x [expr {-10 + 3*$i}] + for {set j 0; set y -10} {$j < 10} {incr j; incr y 3} { + .c create rect ${x}c ${y}c [expr $x+2]c [expr $y+2]c \ + -outline black -fill blue -tags rect + .c create text [expr $x+1]c [expr $y+1]c -text "$i,$j" \ + -anchor center -tags text + } + } + + # The actual bench mark - this code also exercises all the hash + # table changes. + + set time [lindex [time { + foreach id [.c find withtag all] { + .c lower $id + .c raise $id + .c find withtag $id + .c bind <Return> $id {} + .c delete $id + } + }] 0] + + set x "" +} -result {} +test canvas-10.1 {find items using tag expressions} -setup { + catch {destroy .c} + tkp::canvas .c +} -body { + .c create oval 20 20 40 40 -fill red -tag [list a b c d] + .c create oval 20 60 40 80 -fill yellow -tag [list b a] + .c create oval 20 100 40 120 -fill green -tag [list c b] + .c create oval 20 140 40 160 -fill blue -tag [list b] + .c create oval 20 180 40 200 -fill bisque -tag [list a d e] + .c create oval 20 220 40 240 -fill bisque -tag b + .c create oval 20 260 40 280 -fill bisque -tag [list d "tag with spaces"] + set res {} + lappend res [.c find withtag {!a}] + lappend res [.c find withtag {b&&c}] + lappend res [.c find withtag {b||c}] + lappend res [.c find withtag {a&&!b}] + lappend res [.c find withtag {!b&&!c}] + lappend res [.c find withtag {d&&a&&c&&b}] + lappend res [.c find withtag {b^a}] + lappend res [.c find withtag {(a&&!b)||(!a&&b)}] + lappend res [.c find withtag { ( a && ! b ) || ( ! a && b ) }] + lappend res [.c find withtag {a&&!(c||d)}] + lappend res [.c find withtag {d&&"tag with spaces"}] + lappend res [.c find withtag "tag with spaces"] +} -result {{3 4 6 7} {1 3} {1 2 3 4 6} 5 {5 7} 1 {3 4 5 6} {3 4 5 6} {3 4 5 6} 2 7 7} +test canvas-10.2 {check errors from tag expressions} -setup { + catch {destroy .c} + tkp::canvas .c + .c create oval 20 20 40 40 -fill red -tag [list a b c d] + .c create oval 20 260 40 280 -fill bisque -tag [list d "tag with spaces"] +} -body { + .c find withtag {&&c} +} -returnCodes error -result {Unexpected operator in tag search expression} +test canvas-10.3 {check errors from tag expressions} -setup { + catch {destroy .c} + tkp::canvas .c + .c create oval 20 20 40 40 -fill red -tag [list a b c d] + .c create oval 20 260 40 280 -fill bisque -tag [list d "tag with spaces"] +} -body { + .c find withtag {!!c} +} -returnCodes error -result {Too many '!' in tag search expression} +test canvas-10.4 {check errors from tag expressions} -setup { + catch {destroy .c} + tkp::canvas .c + .c create oval 20 20 40 40 -fill red -tag [list a b c d] + .c create oval 20 260 40 280 -fill bisque -tag [list d "tag with spaces"] +} -body { + .c find withtag {b||} +} -returnCodes error -result {Missing tag in tag search expression} +test canvas-10.5 {check errors from tag expressions} -setup { + catch {destroy .c} + tkp::canvas .c + .c create oval 20 20 40 40 -fill red -tag [list a b c d] + .c create oval 20 260 40 280 -fill bisque -tag [list d "tag with spaces"] +} -body { + .c find withtag {b&&(c||)} +} -returnCodes error -result {Unexpected operator in tag search expression} +test canvas-10.6 {check errors from tag expressions} -setup { + catch {destroy .c} + tkp::canvas .c + .c create oval 20 20 40 40 -fill red -tag [list a b c d] + .c create oval 20 260 40 280 -fill bisque -tag [list d "tag with spaces"] +} -body { + .c find withtag {d&&""} +} -returnCodes error -result {Null quoted tag string in tag search expression} +test canvas-10.7 {check errors from tag expressions} -setup { + catch {destroy .c} + tkp::canvas .c + .c create oval 20 20 40 40 -fill red -tag [list a b c d] + .c create oval 20 260 40 280 -fill bisque -tag [list d "tag with spaces"] +} -body { + .c find withtag "d&&\"tag with spaces" +} -returnCodes error -result {Missing endquote in tag search expression} +test canvas-10.8 {check errors from tag expressions} -setup { + catch {destroy .c} + tkp::canvas .c + .c create oval 20 20 40 40 -fill red -tag [list a b c d] + .c create oval 20 260 40 280 -fill bisque -tag [list d "tag with spaces"] +} -body { + .c find withtag {a&&"tag with spaces"z} +} -returnCodes error -result {Invalid boolean operator in tag search expression} +test canvas-10.9 {check errors from tag expressions} -setup { + catch {destroy .c} + tkp::canvas .c + .c create oval 20 20 40 40 -fill red -tag [list a b c d] + .c create oval 20 260 40 280 -fill bisque -tag [list d "tag with spaces"] +} -body { + .c find withtag {a&&b&c} +} -returnCodes error -result {Singleton '&' in tag search expression} +test canvas-10.10 {check errors from tag expressions} -setup { + catch {destroy .c} + tkp::canvas .c + .c create oval 20 20 40 40 -fill red -tag [list a b c d] + .c create oval 20 260 40 280 -fill bisque -tag [list d "tag with spaces"] +} -body { + .c find withtag {a||b|c} +} -returnCodes error -result {Singleton '|' in tag search expression} +test canvas-10.11 {backward compatility - strange tags that are not expressions} -setup { + catch {destroy .c} + tkp::canvas .c + .c create oval 20 20 40 40 -fill red -tag [list { strange tag(xxx&yyy|zzz) " && \" || ! ^ " }] +} -body { + .c find withtag { strange tag(xxx&yyy|zzz) " && \" || ! ^ " } +} -result 1 +test canvas-10.12 {multple events bound to same tag expr} -setup { + catch {destroy .c} + tkp::canvas .c +} -body { + .c bind {a && b} <Enter> {puts Enter} + .c bind {a && b} <Leave> {puts Leave} +} -result {} + +test canvas-11.1 {canvas poly fill check, bug 5783} -setup { + destroy .c + pack [tkp::canvas .c] +} -body { + # This would crash in 8.3.0 and 8.3.1 + .c create polygon 0 0 100 100 200 50 \ + -fill {} -stipple gray50 -outline black +} -result 1 +test canvas-11.2 {canvas poly overlap fill check, bug 226357} -setup { + destroy .c + pack [tkp::canvas .c] +} -body { + set result {} + .c create poly 30 30 90 90 30 90 90 30 + lappend result [.c find over 40 40 45 45]; # rect region inc. edge + lappend result [.c find over 60 40 60 40]; # top-center point + lappend result [.c find over 0 0 0 0]; # not on poly + lappend result [.c find over 60 60 60 60]; # center-point + lappend result [.c find over 45 50 45 50]; # outside poly + .c itemconfig 1 -fill "" -outline black + lappend result [.c find over 40 40 45 45]; # rect region inc. edge + lappend result [.c find over 60 40 60 40]; # top-center point + lappend result [.c find over 0 0 0 0]; # not on poly + lappend result [.c find over 60 60 60 60]; # center-point + lappend result [.c find over 45 50 45 50]; # outside poly + .c itemconfig 1 -width 8 + lappend result [.c find over 45 50 45 50]; # outside poly +} -result {1 1 {} 1 {} 1 1 {} 1 {} 1} + +test canvas-12.1 {canvas mm obj, patch SF-403327, 102471} -setup { + destroy .c + pack [tkp::canvas .c] +} -body { + set qx [expr {1.+1.}] + # qx has type double and no string representation + .c scale all $qx 0 1. 1. + # qx has now type MMRep and no string representation + list $qx [string length $qx] +} -result {2.0 3} +test canvas-12.2 {canvas mm obj, patch SF-403327, 102471} -setup { + destroy .c + pack [tkp::canvas .c] +} -body { + set val 10 + incr val + # qx has type double and no string representation + .c scale all $val 0 1 1 + # qx has now type MMRep and no string representation + incr val +} -result 12 + +proc kill_canvas {w} { + destroy $w + pack [tkp::canvas $w -height 200 -width 200] -fill both -expand yes + update idle + $w create rectangle 80 80 120 120 -fill blue -tags blue + # bind a button press to re-build the canvas + $w bind blue <ButtonRelease-1> [subst { + [lindex [info level 0] 0] $w + append ::x ok + } + ] +} + +test canvas-13.1 {canvas delete during event, SF bug-228024} { + kill_canvas .c + set ::x {} + # do this many times to improve chances of triggering the crash + for {set i 0} {$i < 30} {incr i} { + event generate .c <1> -x 100 -y 100 + event generate .c <ButtonRelease-1> -x 100 -y 100 + } + set ::x +} okokokokokokokokokokokokokokokokokokokokokokokokokokokokokok + +test canvas-14.1 {canvas scan SF bug 581560} -setup { + destroy .c + tkp::canvas .c +} -body { + .c scan +} -returnCodes error -result {wrong # args: should be ".c scan mark|dragto x y ?dragGain?"} +test canvas-14.2 {canvas scan} -setup { + destroy .c + tkp::canvas .c +} -body { + .c scan bogus +} -returnCodes error -result {wrong # args: should be ".c scan mark|dragto x y ?dragGain?"} +test canvas-14.3 {canvas scan} -setup { + destroy .c + tkp::canvas .c +} -body { + .c scan mark +} -returnCodes error -result {wrong # args: should be ".c scan mark|dragto x y ?dragGain?"} +test canvas-14.4 {canvas scan} -setup { + destroy .c + tkp::canvas .c +} -body { + .c scan mark 10 10 +} -result {} +test canvas-14.5 {canvas scan} -setup { + destroy .c + tkp::canvas .c +} -body { + .c scan mark 10 10 5 +} -returnCodes error -result {wrong # args: should be ".c scan mark x y"} +test canvas-14.6 {canvas scan} -setup { + destroy .c + tkp::canvas .c +} -body { + .c scan dragto 10 10 5 +} -result {} + +set i 0 +proc create {w type args} { + eval [list $w create $type] $args +} +foreach type {arc bitmap image line oval polygon rect text window} { + incr i + test canvas-15.$i "basic types check: $type requires coords" -setup { + destroy .c + tkp::canvas .c + } -body { + .c create $type + } -returnCodes error -result [format {wrong # args: should be ".c create %s coords ?arg arg ...?"} $type] + incr i + test canvas-15.$i "basic coords check: $type coords are paired" -setup { + destroy .c + tkp::canvas .c + } -match glob -body { + .c create $type 0 + } -returnCodes error -result "wrong # coordinates: expected*" +} + +test canvas-16.1 {arc coords check} -setup { + destroy .c + tkp::canvas .c +} -body { + set id [.c create arc {0 10 20 30} -start 33] + .c itemcget $id -start +} -result {33.0} + +test canvas-17.1 {default smooth method handling} -setup { + destroy .c + tkp::canvas .c +} -body { + set id [.c create line {0 0 1 1 2 2 3 3 4 4 5 5 6 6}] + set result [.c itemcget $id -smooth] + foreach smoother {yes 1 bezier raw r b} { + .c itemconfigure $id -smooth $smoother + lappend result [.c itemcget $id -smooth] + } + set result +} -result {0 true true true raw raw true} + +destroy .c + +# cleanup +cleanupTests +return diff --git a/pd/tkpath/tests/gradienttest04.test b/pd/tkpath/tests/gradienttest04.test new file mode 100644 index 0000000000000000000000000000000000000000..83d2be54cebd95c759a876571a87d29c5137c7ae --- /dev/null +++ b/pd/tkpath/tests/gradienttest04.test @@ -0,0 +1,103 @@ +#!/bin/sh +# start with WISH \ + exec wish "$0" ${1+"$@"} + + +# gradienttest04.test +# ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― +# Test for gradient spanning slave interps. +# Version tested tkpath 0.2.4 (patched) with tk8.4.11 OSX/X11 10.4 +# Negative test under Aqua 0.2.4 (unpatched) with tk8.4.11 +# +# Author : Arndt Roger Schneider +# Email : roger.schneider@addcom.de +# Copyright © 2008 Arndt Roger Schneider +# +# Modul : tkPathGradient.c +# Lines : 654 - 681 +# ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― +# +# +# /* +# fixme roger: 04/07/2008 +# +# Don't recreate the Gradient Tables for +# slave interps -- otherwise will void +# existing gradients in the main interp... +# +# THERE IS NO FREE FOR THESE HASH TABLES... +# +# +# */ +# +# if (NULL == gGradientHashPtr) { +# gGradientHashPtr = (Tcl_HashTable *) ckalloc( sizeof(Tcl_HashTable) ); +# Tcl_InitHashTable(gGradientHashPtr, TCL_STRING_KEYS); +# } +# +# if (NULL == gLinearGradientHashPtr) { +# gLinearGradientHashPtr = (Tcl_HashTable *) ckalloc( sizeof(Tcl_HashTable) ); +# Tcl_InitHashTable(gLinearGradientHashPtr, TCL_STRING_KEYS); +# } +# +# if (NULL == gRadialGradientHashPtr) { +# gRadialGradientHashPtr = (Tcl_HashTable *) ckalloc( sizeof(Tcl_HashTable) ); +# Tcl_InitHashTable(gRadialGradientHashPtr, TCL_STRING_KEYS); +# } +# ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― +# +# Date : Monday 07 April 20:39 +# License : Tcl-License (aka BSD) +# +# Description : Tkpath 0.2.4 uses global +# gradient tables which are deleted +# whenever a slave interp requires +# tkpath. +# +# ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― + +# The standard packages : Tk, Tcltest +package require Tk +package require tkpath + +if {[lsearch [namespace children] ::tcltest] == -1} { + package require tcltest + namespace import -force ::tcltest::* +} + +# Extend auto_path, that local packages can be used. +lappend auto_path [file dirname [info script]] + +# Load Local Packages ... +set masterg [tkpath::gradient create radial \ + -stops [list \ + {0 white 0.9} [list 1 red4 0.4]] \ + -radialtransition { + 0.477551020408 0.540983606557 + 1.00918367347 0.898979591837 + 0.139344262295}] + +test gradientslave-1.1 {Shared gradients inside slave} { + + interp create slavei + + slavei eval { + + package require Tk + package require tkpath + } + + tkpath::gradient names + +} $masterg + +test gradientslave-1.2 {Destroy slave} { + interp delete slavei +} {} + + + +# Local Variables: +# Coding: utf-8-unix +# Mode: Tcl +# End: diff --git a/pd/tkpath/tests/pline-move.test b/pd/tkpath/tests/pline-move.test new file mode 100644 index 0000000000000000000000000000000000000000..41cec825305133bfb04bd5e01778c2e57e14da83 --- /dev/null +++ b/pd/tkpath/tests/pline-move.test @@ -0,0 +1,72 @@ +#!/bin/sh +# Restart with WISH \ + exec wish "$0" ${1+"$@"} +# +# Copyright 2007-2008 Arndt Roger Schneider +# mail-to: roger.schneider@addcom.de +# +# License Tcl-License (aka BSD) +# +# Description: Tests for various pline functions. + +package require tkpath 0.3; # 0.2.4 cairo & aqua + # 0.3.0 strokedash under aqua +pack [tkp::canvas .c] + +if {[lsearch [namespace children] ::tcltest] == -1} { + package require tcltest + namespace import -force ::tcltest::* +} + + +# TestCase : move +# +# Description : Test for pline move operation. +# Written : 2007, Roger +# Ported : 07/23/2008, Roger -- tkpath 0.3 +# +test pline-1.1 {pline coords} { + tkp::seteach { + l t r b + } [.c coords [.c create pline 200 201 250 202]] + + return [list \ + [expr { round($l) }] \ + [expr { round($t) }] \ + [expr { round($r) }] \ + [expr { round($b) }]] + +} {200 201 250 202} + +test pline-1.2 {pline {coords after move}} { + set pline [.c create pline 200 201 250 202] + .c move $pline 20 20 + tkp::seteach { l t r b } [.c coords $pline] + return [list \ + [expr { round($l) }] \ + [expr { round($t) }] \ + [expr { round($r) }] \ + [expr { round($b) }]] + +} {220 221 270 222} + + +# TestCase : strokedash +# +# Parameters : . +# Description : Strokedash with tkpath 0.3.0 reports an +# floating point error under AQUA. +# Wish crashes after some time. +# Written : 07/23/2008, Roger +# +test pline-1.3 {pline {Strokedash as .}} { + set pline [.c create pline 200 201 250 202 \ + -strokedash .] + return {} +} {} + + +# Local Variables: +# Coding: utf-8-unix +# Mode: Tcl +# End: diff --git a/pd/tkpath/tests/polyline-coords.test b/pd/tkpath/tests/polyline-coords.test new file mode 100644 index 0000000000000000000000000000000000000000..13b0ffecab04f25e692592a6ae5be2ce750a1018 --- /dev/null +++ b/pd/tkpath/tests/polyline-coords.test @@ -0,0 +1,17 @@ +package require tkpath; # 0.2.4 cairo & aqua +pack [tkp::canvas .c] + +if {[lsearch [namespace children] ::tcltest] == -1} { + package require tcltest + namespace import -force ::tcltest::* +} + +test polyline-1.1 {polyline coords} { + .c coords [.c create polyline 12 20 34 5 90 56] +} {12.0 20.0 34.0 5.0 90.0 56.0} + +test polygon-1.1 {polygon coords} { + .c coords [.c create ppolygon 12 20 34 5 90 56 -fill red] +} {12.0 20.0 34.0 5.0 90.0 56.0} + + diff --git a/pd/tkpath/tests/test-pimage.tcl b/pd/tkpath/tests/test-pimage.tcl new file mode 100644 index 0000000000000000000000000000000000000000..40e1049f5475be64c06a3cb88acb6a5a20e3ad17 --- /dev/null +++ b/pd/tkpath/tests/test-pimage.tcl @@ -0,0 +1,85 @@ +#!/bin/sh +# start with WISH \ + exec wish "$0" ${1+"$@"} + + +# +# Testcase for pimage »move«. +# ---------------------------------------------------------------- +# Author : Arndt Roger Schneider +# Date : 09/22/2007 +# License: Tcl-License (aka BSD) +# +# Copyright © 2007 Arndt Roger Schneider +# ---------------------------------------------------------------- + +package require Tk +package require tkpath ; # version 0.2.4 + +if {[lsearch [namespace children] ::tcltest] == -1} { + package require tcltest + namespace import -force ::tcltest::* +} + + +# Extend auto_path, that local packages can be used. +lappend auto_path [file dirname [info script]] + +# Load Local Packages ... + + +# prepare the ui. +toplevel .t +pack [tkp::canvas .t.c] +image create photo _oval -data { +R0lGODlhIQAZAPcAMf//////////////9///9//39//39//39/f///f///f/ +9/f/9/f3//f3//f39/f39/f37/f37/fv9/fv9/fv7/fv7/fv7/fv3vfv3vfv +3u/39+/39+/v9+/v9+/v7+/v7+/v5+/v5+/v3u/v3u/v3u/v1u/v1u/vzu/v +zu/n7+/n7+/n7+/n5+/n5+/nve/nve/eve/eve/Wre/Wrefv7+fv7+fv5+fv +5+fn7+fn7+fn5+fn5+fn5+fWxufWxufWxufWvefWvefWvefOpefOpefGlOfG +lOfGlOe9jOe9jOe9jN7v997v997v797v79bW1tbW1tala9ala9ala87n787n +787n587n587Ozs7Ozs7Ozs7Oxs7Oxs7Gxs7Gxs6tjM6tjM6lY86lY8bn98bn +98bOzsbOzsbOxsbOxsbGzsbGzsbGzsbGxsbGxsbGvcbGvcbGvcale8ale73n +973n973n773n773Gxr3Gxr29vb29vb29vb2le72le72le72MUr2MUr2MUrW1 +tbW1tbW1rbW1rbWcjLWcjLWMY7WMY7WMY63e763e763e7621ta21ta1zKa1z +Ka1zKaW9zqW9zqW9zqWttaWttaWlpaWlpaWlpZzO55zO55ycnJycnJyUe5yU +e5yEa5yEa5yEa5TO55TO55S1xpS1xpSUlJSUlJRKAJRKAJQ5AJQ5AIS954S9 +54S93oS93oRjSoRjSoRjSoQpAIQpAHO11nO11nOt1nOt1nOt1nMAAHMAAGuE +nGuEnGuEnGOUxmOUxmOUxmMAAGMAAGMAAFpzjFpzjFpzjFo5AFo5AFo5AFKM +vVKMvVKMvUp7pUp7pUpje0pje0oAAEoAADlrlDlrlDlrlDkpADkpADkAKTkA +KTkAKTkAADkAACl7vSl7vSlrrSlrrSlrrSljjCljjCljjCkAACkAACkAAABj +pQBjpQBKlABKlABKlAA5cwA5cwA5WgA5WgAAawAAawAAawAAUgAAUgAAKQAA +KQAAKQAAAAAAAAAAAAAAACwAAAAAIQAZAAAI/wABAPCApaDBgwgTJvQgEACm +TnmwuLkzsSLFixYzUsyTp1MnAFg+AuDQUELDkygBmEzpoVPBPAAolJxpsqbK +mzhJCoyIBaaGmAJNMgTwc+BNCDiHMpQgkaIGmQyjCmRIwYOHJlaJImUIQSpP +mBygDuzK0I2sf2j/ybOkQUNUoQPv9MSS1aoHCQw1/PmXz5cjS1+U/YNXZ6AE +CmQBfPXQlUNXCBw8QPoHzTHJJhC+/LtXx7EHyx6+Rmbswa0HJP+aCrRrV4a3 +dXbJhn7J2q6IWu0gYK1tNcq/TbwX83bhChZv1heI5QpOmzcMdIuO22YFjjVW +jhytPvEgAquLbXWwdtTnLr6JCOra7Qonz90KNeNPIo/vLqIHsVt2t892k8fD +dvEeUKAKPLvNt1sYv/mX31dPUKDfdiIUQRkH5ZH3hTfgGGgVR3f0lx97iPxj +Cl0QNhHHP/RgUR59DCp4lYt8oHWMJZh8Qo2IVJA33nYc8acghA960MMn2aQl +zSRYPWFeE+b5J9x2QUKZnoI7cidlHnJh8mN6UroIpXlRXsVTJ1KGWSZ3VCq5 +5TFuSOARJhxhASd2HBFCpyV5uIFnndh18kVDIrwkKE9yzeUGFoVGdOhcTZgU +EAA7LA==} -gamma 1.0 + + +# The TestCase itself: +test pimage-1.1 {move 10 10} { + set id [.t.c create pimage 100 100 -image _oval] + .t.c move $id 10 10 + .t.c coords $id +} {{110.0 110.0}} + +test pimage-1.2 {coords 10 10} { + set id [.t.c create pimage 100 100 -image _oval] + .t.c coords $id 110.0 110.0 + .t.c coords $id +} {{110.0 110.0}} + +# Local Variables: +# Coding: utf-8-unix +# Mode: Tcl +# End: + + + \ No newline at end of file diff --git a/pd/tkpath/unix/libtkpath0.1.so b/pd/tkpath/unix/libtkpath0.1.so new file mode 100644 index 0000000000000000000000000000000000000000..961e3655df92bd113c4d0d134d9072039ab274a7 Binary files /dev/null and b/pd/tkpath/unix/libtkpath0.1.so differ diff --git a/pd/tkpath/unix/libtkpath0.2.2.so b/pd/tkpath/unix/libtkpath0.2.2.so new file mode 100755 index 0000000000000000000000000000000000000000..b2adfa551177738aa09f7371f20974afb383e25f Binary files /dev/null and b/pd/tkpath/unix/libtkpath0.2.2.so differ diff --git a/pd/tkpath/unix/libtkpath0.2.4.so b/pd/tkpath/unix/libtkpath0.2.4.so new file mode 100755 index 0000000000000000000000000000000000000000..d215314408cc86bf7deff93e15957110bf4ed4b1 Binary files /dev/null and b/pd/tkpath/unix/libtkpath0.2.4.so differ diff --git a/pd/tkpath/unix/libtkpath0.2.6.so b/pd/tkpath/unix/libtkpath0.2.6.so new file mode 100755 index 0000000000000000000000000000000000000000..a5649210487d252c67dd2e10523f4a44f6a8b065 Binary files /dev/null and b/pd/tkpath/unix/libtkpath0.2.6.so differ diff --git a/pd/tkpath/unix/libtkpath0.2.8.so b/pd/tkpath/unix/libtkpath0.2.8.so new file mode 100755 index 0000000000000000000000000000000000000000..230cea4c22755fb9b3073c50e832e0eeaed27201 Binary files /dev/null and b/pd/tkpath/unix/libtkpath0.2.8.so differ diff --git a/pd/tkpath/unix/libtkpath0.2.so b/pd/tkpath/unix/libtkpath0.2.so new file mode 100755 index 0000000000000000000000000000000000000000..af7ba2d7d13c56edd1f6e4aeae72029f9d0574c0 Binary files /dev/null and b/pd/tkpath/unix/libtkpath0.2.so differ diff --git a/pd/tkpath/unix/libtkpath0.3.0.so b/pd/tkpath/unix/libtkpath0.3.0.so new file mode 100755 index 0000000000000000000000000000000000000000..62b008759df36101f12cc27c4c48683171d3a09c Binary files /dev/null and b/pd/tkpath/unix/libtkpath0.3.0.so differ diff --git a/pd/tkpath/unix/libtkpath0.3.1.so b/pd/tkpath/unix/libtkpath0.3.1.so new file mode 100755 index 0000000000000000000000000000000000000000..e8e9d3b9cf51d92cb1a91e8986f792f43530f6f3 Binary files /dev/null and b/pd/tkpath/unix/libtkpath0.3.1.so differ diff --git a/pd/tkpath/unix/tkUnixCairoPath.c b/pd/tkpath/unix/tkUnixCairoPath.c new file mode 100644 index 0000000000000000000000000000000000000000..4202a3ec7c87d1abc78d5f63a597e24177130ebe --- /dev/null +++ b/pd/tkpath/unix/tkUnixCairoPath.c @@ -0,0 +1,771 @@ +/* + * tkUnixCairoPath.c -- + * + * This file implements path drawing API's using the Cairo rendering engine. + * + * TODO: implement text drawing using glyphs instead of the "toy" text API. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * $Id: tkUnixCairoPath.c,v 1.53 2010/04/30 10:16:00 ebrunel Exp $ + */ + +/* This should go into configure.in but don't know how. */ +#ifdef USE_PANIC_ON_PHOTO_ALLOC_FAILURE +#undef USE_PANIC_ON_PHOTO_ALLOC_FAILURE +#endif + +#include <cairo.h> +#include <cairo-xlib.h> +#include <tkUnixInt.h> +#include "tkIntPath.h" + +#define BlueDoubleFromXColorPtr(xc) (double) (((xc)->pixel & 0xFF)) / 255.0 +#define GreenDoubleFromXColorPtr(xc) (double) ((((xc)->pixel >> 8) & 0xFF)) / 255.0 +#define RedDoubleFromXColorPtr(xc) (double) ((((xc)->pixel >> 16) & 0xFF)) / 255.0 + +extern int gAntiAlias; +extern int gSurfaceCopyPremultiplyAlpha; +extern int gDepixelize; +extern Tcl_Interp *gInterp; + +int kPathSmallEndian = 1; /* Hardcoded. */ + +/* @@@ Need to use cairo_image_surface_create_for_data() here since prior to 1.2 + * there doesn't exist any cairo_image_surface_get_data() accessor. + */ +typedef struct PathSurfaceCairoRecord { + unsigned char* data; + cairo_format_t format; + int width; + int height; + int stride; /* the number of bytes between the start of rows in the buffer */ +} PathSurfaceCairoRecord; + +/* + * This is used as a place holder for platform dependent stuff between each call. + */ +typedef struct TkPathContext_ { + cairo_t* c; + cairo_surface_t* surface; + PathSurfaceCairoRecord* record; /* NULL except for memory surfaces. + * Skip when cairo 1.2 widely spread. */ + int widthCode; /* Used to depixelize the strokes: + * 0: not integer width + * 1: odd integer width + * 2: even integer width */ +} TkPathContext_; + + +void CairoSetFill(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + /* === EB - 28-apr-2010: Applied patch from Tim Edwards to handle color correctly on 64 bits architecture */ + cairo_set_source_rgba(context->c, + (double)(GetColorFromPathColor(style->fill)->red) / 0xFFFF, + (double)(GetColorFromPathColor(style->fill)->green) / 0xFFFF, + (double)(GetColorFromPathColor(style->fill)->blue) / 0xFFFF, + style->fillOpacity); + /* === */ + cairo_set_fill_rule(context->c, + (style->fillRule == WindingRule) ? CAIRO_FILL_RULE_WINDING : CAIRO_FILL_RULE_EVEN_ODD); +} + +/* === EB - 23-apr-2010: added function to register coordinate offsets */ +static int g_x_coord_offset = 0; +static int g_y_coord_offset = 0; + +void TkPathSetCoordOffsets(double dx, double dy) +{ + g_x_coord_offset = (dx > 0) ? (int)(dx + 0.5) : 0; + g_y_coord_offset = (dy > 0) ? (int)(dy + 0.5) : 0; +} +/* === */ + +TkPathContext TkPathInit(Tk_Window tkwin, Drawable d) +{ + cairo_t *c; + cairo_surface_t *surface; + TkPathContext_ *context = (TkPathContext_ *) ckalloc((unsigned) (sizeof(TkPathContext_))); + Window dummy; + int x, y; + unsigned int width, height, borderWidth, depth; + + /* Find size of Drawable */ + XGetGeometry(Tk_Display(tkwin), d, + &dummy, &x, &y, &width, &height, &borderWidth, &depth); + + surface = cairo_xlib_surface_create(Tk_Display(tkwin), d, Tk_Visual(tkwin), + width, height); + c = cairo_create(surface); + context->c = c; + context->surface = surface; + context->record = NULL; + context->widthCode = 0; + return (TkPathContext) context; +} + +TkPathContext TkPathInitSurface(int width, int height) +{ + cairo_t *c; + cairo_surface_t *surface; + unsigned char *data; + int stride; + + /* @@@ Need to use cairo_image_surface_create_for_data() here since prior to 1.2 + * there doesn't exist any cairo_image_surface_get_data() accessor. + */ + TkPathContext_ *context = (TkPathContext_ *) ckalloc((unsigned) (sizeof(TkPathContext_))); + PathSurfaceCairoRecord *record = (PathSurfaceCairoRecord *) ckalloc((unsigned) (sizeof(PathSurfaceCairoRecord))); + stride = 4*width; + /* Round up to nearest multiple of 16 */ + stride = (stride + (16-1)) & ~(16-1); + data = (unsigned char *) ckalloc(height*stride); + memset(data, '\0', height*stride); + surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, stride); + record->data = data; + record->format = CAIRO_FORMAT_ARGB32; + record->width = width; + record->height = height; + record->stride = stride; + c = cairo_create(surface); + context->c = c; + context->surface = surface; + context->record = record; + return (TkPathContext) context; +} + +void TkPathPushTMatrix(TkPathContext ctx, TMatrix *m) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + cairo_matrix_t matrix; + if (m == NULL) { + return; + } + cairo_matrix_init(&matrix, m->a, m->b, m->c, m->d, m->tx, m->ty); + cairo_transform(context->c, &matrix); +} + +void TkPathSaveState(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + cairo_save(context->c); +} + +void TkPathRestoreState(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + cairo_restore(context->c); +} + +void TkPathBeginPath(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + int nint; + double width; + cairo_new_path(context->c); + if (style->strokeColor == NULL) { + context->widthCode = 0; + } else { + width = style->strokeWidth; + nint = (int) (width + 0.5); + context->widthCode = fabs(width - nint) > 0.01 ? 0 : 2 - nint % 2; + } +} + +void TkPathMoveTo(TkPathContext ctx, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + cairo_move_to(context->c, x, y); +} + +void TkPathLineTo(TkPathContext ctx, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + cairo_line_to(context->c, x, y); +} + +void TkPathQuadBezier(TkPathContext ctx, double ctrlX, double ctrlY, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + double cx, cy; + double x31, y31, x32, y32; + + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + cairo_get_current_point(context->c, &cx, &cy); + + // conversion of quadratic bezier curve to cubic bezier curve: (mozilla/svg) + /* Unchecked! Must be an approximation! */ + x31 = cx + (ctrlX - cx) * 2 / 3; + y31 = cy + (ctrlY - cy) * 2 / 3; + x32 = ctrlX + (x - ctrlX) / 3; + y32 = ctrlY + (y - ctrlY) / 3; + + cairo_curve_to(context->c, x31, y31, x32, y32, x, y); +} + +void TkPathCurveTo(TkPathContext ctx, double x1, double y1, + double x2, double y2, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + cairo_curve_to(context->c, x1, y1, x2, y2, x, y); +} + +void TkPathArcTo(TkPathContext ctx, + double rx, double ry, + double phiDegrees, /* The rotation angle in degrees! */ + char largeArcFlag, char sweepFlag, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + TkPathArcToUsingBezier(ctx, rx, ry, phiDegrees, largeArcFlag, sweepFlag, x, y); +} + +void +TkPathRect(TkPathContext ctx, double x, double y, double width, double height) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (gDepixelize) { + x = PATH_DEPIXELIZE(context->widthCode, x); + y = PATH_DEPIXELIZE(context->widthCode, y); + } + cairo_rectangle(context->c, x, y, width, height); +} + +void +TkPathOval(TkPathContext ctx, double cx, double cy, double rx, double ry) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (rx == ry) { + cairo_move_to(context->c, cx+rx, cy); + cairo_arc(context->c, cx, cy, rx, 0.0, 2*M_PI); + cairo_close_path(context->c); + } else { + cairo_save(context->c); + cairo_translate(context->c, cx, cy); + cairo_scale(context->c, rx, ry); + cairo_move_to(context->c, 1.0, 0.0); + cairo_arc(context->c, 0.0, 0.0, 1.0, 0.0, 2*M_PI); + cairo_close_path(context->c); + cairo_restore(context->c); + } +} + +void +TkPathImage(TkPathContext ctx, Tk_Image image, Tk_PhotoHandle photo, + double x, double y, double width, double height) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + Tk_PhotoImageBlock block; + cairo_surface_t *surface; + cairo_format_t format; + unsigned char *data = NULL; + unsigned char *ptr = NULL; + unsigned char *srcPtr, *dstPtr; + int srcR, srcG, srcB, srcA; /* The source pixel offsets. */ + int dstR, dstG, dstB, dstA; /* The destination pixel offsets. */ + int size, pitch; + int iwidth, iheight; + int i, j; + + /* Return value? */ + Tk_PhotoGetImage(photo, &block); + size = block.pitch * block.height; + iwidth = block.width; + iheight = block.height; + pitch = block.pitch; + if (width == 0.0) { + width = (double) iwidth; + } + if (height == 0.0) { + height = (double) iheight; + } + + /* + * @format: the format of pixels in the buffer + * @width: the width of the image to be stored in the buffer + * @height: the eight of the image to be stored in the buffer + * @stride: the number of bytes between the start of rows + * in the buffer. Having this be specified separate from @width + * allows for padding at the end of rows, or for writing + * to a subportion of a larger image. + */ + + /** + * cairo_format_t + * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with + * alpha in the upper 8 bits, then red, then green, then blue. + * The 32-bit quantities are stored native-endian. Pre-multiplied + * alpha is used. (That is, 50% transparent red is 0x80800000, + * not 0x80ff0000.) + */ + if (block.pixelSize*8 == 32) { + format = CAIRO_FORMAT_ARGB32; + + /* The offset array contains the offsets from the address of a + * pixel to the addresses of the bytes containing the red, green, + * blue and alpha (transparency) components. + * + * We need to copy pixel data from the source using the photo offsets + * to cairos ARGB format which is in *native* endian order; Switch! + */ + srcR = block.offset[0]; + srcG = block.offset[1]; + srcB = block.offset[2]; + srcA = block.offset[3]; + dstR = 1; + dstG = 2; + dstB = 3; + dstA = 0; + if (kPathSmallEndian) { + dstR = 3-dstR, dstG = 3-dstG, dstB = 3-dstB, dstA = 3-dstA; + } + if ((srcR == dstR) && (srcG == dstG) && (srcB == dstB) && (srcA == dstA)) { + ptr = (unsigned char *) block.pixelPtr; + } else { + data = (unsigned char *) ckalloc(pitch*iheight); + ptr = data; + + for (i = 0; i < iheight; i++) { + srcPtr = block.pixelPtr + i*pitch; + dstPtr = ptr + i*pitch; + for (j = 0; j < iwidth; j++) { + *(dstPtr+dstR) = *(srcPtr+srcR); + *(dstPtr+dstG) = *(srcPtr+srcG); + *(dstPtr+dstB) = *(srcPtr+srcB); + *(dstPtr+dstA) = *(srcPtr+srcA); + srcPtr += 4; + dstPtr += 4; + } + } + } + } else if (block.pixelSize*8 == 24) { + /* Could do something about this? */ + return; + } else { + return; + } + surface = cairo_image_surface_create_for_data( + ptr, + format, + (int) width, (int) height, + pitch); /* stride */ + cairo_set_source_surface(context->c, surface, x, y); + cairo_paint(context->c); + cairo_surface_destroy(surface); + if (data) { + ckfree((char *)data); + } +} + +void TkPathClosePath(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + cairo_close_path(context->c); +} + +int +TkPathTextConfig(Tcl_Interp *interp, Tk_PathTextStyle *textStylePtr, char *utf8, void **customPtr) +{ + return TCL_OK; +} + +void +TkPathTextDraw(TkPathContext ctx, Tk_PathStyle *style, Tk_PathTextStyle *textStylePtr, + double x, double y, char *utf8, void *custom) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + + cairo_select_font_face(context->c, textStylePtr->fontFamily, + CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(context->c, textStylePtr->fontSize); + cairo_move_to(context->c, x, y); + if ((GetColorFromPathColor(style->fill) != NULL) && (style->strokeColor != NULL)) { + cairo_text_path(context->c, utf8); + TkPathFillAndStroke(ctx, style); + } else if (GetColorFromPathColor(style->fill) != NULL) { + + /* This is the normal way to draw text which is likely faster. */ + CairoSetFill(ctx, style); + cairo_show_text(context->c, utf8); + } else if (style->strokeColor != NULL) { + cairo_text_path(context->c, utf8); + TkPathStroke(ctx, style); + } +} + +void +TkPathTextFree(Tk_PathTextStyle *textStylePtr, void *custom) +{ + /* Empty. */ +} + +PathRect +TkPathTextMeasureBbox(Tk_PathTextStyle *textStylePtr, char *utf8, void *custom) +{ + cairo_t *c; + cairo_surface_t *surface; + cairo_text_extents_t extents; + PathRect r; + + /* @@@ Not very happy about this but it seems that there is no way to + * measure text without having a surface (drawable) in cairo. + */ + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10); + c = cairo_create(surface); + cairo_select_font_face(c, textStylePtr->fontFamily, + CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(c, textStylePtr->fontSize); + + cairo_text_extents(c, utf8, &extents); + r.x1 = 0.0; + r.y1 = extents.y_bearing; // will usually be negative. + r.x2 = extents.x_bearing + extents.width; + r.y2 = extents.y_bearing + extents.height; + cairo_destroy(c); + cairo_surface_destroy(surface); + return r; +} + +void +TkPathSurfaceErase(TkPathContext ctx, double dx, double dy, double dwidth, double dheight) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + unsigned char *data, *dst; + int i; + int x, y, width, height; + int xend, yend; + int stride; + int bwidth; + + /* Had to do it directly on the bits. Assuming CAIRO_FORMAT_ARGB32 + * cairos ARGB format is in *native* endian order; Switch! + * Be careful not to address the bitmap outside its limits. */ + data = context->record->data; + stride = context->record->stride; + x = (int) (dx + 0.5); + y = (int) (dy + 0.5); + width = (int) (dwidth + 0.5); + height = (int) (dheight + 0.5); + x = MAX(0, MIN(context->record->width, x)); + y = MAX(0, MIN(context->record->height, y)); + width = MAX(0, width); + height = MAX(0, height); + xend = MIN(x + width, context->record->width); + yend = MIN(y + height, context->record->height); + bwidth = 4*(xend - x); + + for (i = y; i < yend; i++) { + dst = data + i*stride + 4*x; + memset(dst, '\0', bwidth); + } +} + +void +TkPathSurfaceToPhoto(Tcl_Interp *interp, TkPathContext ctx, Tk_PhotoHandle photo) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + cairo_surface_t *surface = context->surface; + Tk_PhotoImageBlock block; + unsigned char *data; + unsigned char *pixel; + int width, height; + int stride; /* Bytes per row. */ + + width = cairo_image_surface_get_width(surface); + height = cairo_image_surface_get_height(surface); + data = context->record->data; + stride = context->record->stride; + + Tk_PhotoGetImage(photo, &block); + pixel = (unsigned char *) ckalloc(height*stride); + + if (gSurfaceCopyPremultiplyAlpha) { + if (kPathSmallEndian) { + PathCopyBitsPremultipliedAlphaBGRA(data, pixel, width, height, stride); + } else { + PathCopyBitsPremultipliedAlphaARGB(data, pixel, width, height, stride); + } + } else { + if (kPathSmallEndian) { + PathCopyBitsBGRA(data, pixel, width, height, stride); + } else { + PathCopyBitsARGB(data, pixel, width, height, stride); + } + } + block.pixelPtr = pixel; + block.width = width; + block.height = height; + block.pitch = stride; + block.pixelSize = 4; + block.offset[0] = 0; + block.offset[1] = 1; + block.offset[2] = 2; + block.offset[3] = 3; + Tk_PhotoPutBlock(interp, photo, &block, 0, 0, width, height, TK_PHOTO_COMPOSITE_OVERLAY); +} + +void TkPathClipToPath(TkPathContext ctx, int fillRule) +{ + /* Clipping to path is done by default. */ + /* Note: cairo_clip does not consume the current path */ + //cairo_clip(context->c); +} + +void TkPathReleaseClipToPath(TkPathContext ctx) +{ + //cairo_reset_clip(context->c); +} + +void TkPathStroke(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + Tk_PathDash *dashPtr; + + /* === EB - 28-apr-2010: Applied patch from Tim Edwards to handle color correctly on 64 bits architecture */ + cairo_set_source_rgba(context->c, + (double)(style->strokeColor->red) / 0xFFFF, + (double)(style->strokeColor->green) / 0xFFFF, + (double)(style->strokeColor->blue) / 0xFFFF, + style->strokeOpacity); + /* === */ + cairo_set_line_width(context->c, style->strokeWidth); + + switch (style->capStyle) { + case CapNotLast: + case CapButt: + cairo_set_line_cap(context->c, CAIRO_LINE_CAP_BUTT); + break; + case CapRound: + cairo_set_line_cap(context->c, CAIRO_LINE_CAP_ROUND); + break; + default: + cairo_set_line_cap(context->c, CAIRO_LINE_CAP_SQUARE); + break; + } + switch (style->joinStyle) { + case JoinMiter: + cairo_set_line_join(context->c, CAIRO_LINE_JOIN_MITER); + break; + case JoinRound: + cairo_set_line_join(context->c, CAIRO_LINE_JOIN_ROUND); + break; + default: + cairo_set_line_join(context->c, CAIRO_LINE_JOIN_BEVEL); + break; + } + cairo_set_miter_limit(context->c, style->miterLimit); + + dashPtr = style->dashPtr; + if ((dashPtr != NULL) && (dashPtr->number != 0)) { + int i; + double *dashes = (double *) ckalloc(dashPtr->number * sizeof(double)); + + for (i = 0; i < dashPtr->number; i++) { + dashes[i] = dashPtr->array[i]; + } + cairo_set_dash(context->c, dashes, dashPtr->number, style->offset); + } + + cairo_stroke(context->c); +} + +void TkPathFill(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CairoSetFill(ctx, style); + cairo_fill(context->c); +} + +void TkPathFillAndStroke(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + CairoSetFill(ctx, style); + cairo_fill_preserve(context->c); + TkPathStroke(ctx, style); +} + +void TkPathEndPath(TkPathContext ctx) +{ + /* Empty ??? */ +} + +void TkPathFree(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + cairo_destroy(context->c); + cairo_surface_destroy(context->surface); + if (context->record) { + ckfree((char *) context->record->data); + ckfree((char *) context->record); + } + ckfree((char *) context); +} + +int TkPathDrawingDestroysPath(void) +{ + return 1; +} + +int +TkPathPixelAlign(void) +{ + return 0; +} + +int TkPathGetCurrentPosition(TkPathContext ctx, PathPoint *pt) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + cairo_get_current_point(context->c, &(pt->x), &(pt->y)); + return TCL_OK; +} + +int TkPathBoundingBox(TkPathContext ctx, PathRect *rPtr) +{ + return TCL_ERROR; +} + +static int GetCairoExtend(int method) +{ + cairo_extend_t extend; + + switch (method) { + case kPathGradientMethodPad: + extend = CAIRO_EXTEND_NONE; + break; + case kPathGradientMethodRepeat: + extend = CAIRO_EXTEND_REPEAT; + break; + case kPathGradientMethodReflect: + extend = CAIRO_EXTEND_REFLECT; + break; + default: + extend = CAIRO_EXTEND_NONE; + break; + } + return extend; +} + +void TkPathPaintLinearGradient(TkPathContext ctx, PathRect *bbox, LinearGradientFill *fillPtr, int fillRule, TMatrix *mPtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + int i; + int nstops; + PathRect *tPtr; /* The transition line. */ + GradientStop *stop; + GradientStopArray *stopArrPtr; + cairo_pattern_t *pattern; + + stopArrPtr = fillPtr->stopArrPtr; + tPtr = fillPtr->transitionPtr; + nstops = stopArrPtr->nstops; + + /* + * The current path is consumed by filling. + * Need therfore to save the current context and restore after. + */ + cairo_save(context->c); + + pattern = cairo_pattern_create_linear(tPtr->x1, tPtr->y1, tPtr->x2, tPtr->y2); + + /* + * We need to do like this since this is how SVG defines gradient drawing + * in case the transition vector is in relative coordinates. + */ + if (fillPtr->units == kPathGradientUnitsBoundingBox) { + cairo_translate(context->c, bbox->x1, bbox->y1); + cairo_scale(context->c, bbox->x2 - bbox->x1, bbox->y2 - bbox->y1); + } + if (mPtr) { + cairo_matrix_t matrix; + cairo_matrix_init(&matrix, mPtr->a, mPtr->b, mPtr->c, mPtr->d, mPtr->tx, mPtr->ty); + cairo_pattern_set_matrix(pattern, &matrix); + } + + for (i = 0; i < nstops; i++) { + stop = stopArrPtr->stops[i]; + cairo_pattern_add_color_stop_rgba(pattern, stop->offset, + RedDoubleFromXColorPtr(stop->color), + GreenDoubleFromXColorPtr(stop->color), + BlueDoubleFromXColorPtr(stop->color), + stop->opacity); + } + cairo_set_source(context->c, pattern); + cairo_set_fill_rule(context->c, + (fillRule == WindingRule) ? CAIRO_FILL_RULE_WINDING : CAIRO_FILL_RULE_EVEN_ODD); + cairo_pattern_set_extend(pattern, GetCairoExtend(fillPtr->method)); + cairo_fill(context->c); + + cairo_pattern_destroy(pattern); + cairo_restore(context->c); +} + +void +TkPathPaintRadialGradient(TkPathContext ctx, PathRect *bbox, RadialGradientFill *fillPtr, int fillRule, TMatrix *mPtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + int i; + int nstops; + GradientStop *stop; + cairo_pattern_t *pattern; + GradientStopArray *stopArrPtr; + RadialTransition *tPtr; + + stopArrPtr = fillPtr->stopArrPtr; + nstops = stopArrPtr->nstops; + tPtr = fillPtr->radialPtr; + + /* + * The current path is consumed by filling. + * Need therfore to save the current context and restore after. + */ + cairo_save(context->c); + pattern = cairo_pattern_create_radial( + tPtr->focalX, tPtr->focalY, 0.0, + tPtr->centerX, tPtr->centerY, tPtr->radius); + + if (fillPtr->units == kPathGradientUnitsBoundingBox) { + cairo_translate(context->c, bbox->x1, bbox->y1); + cairo_scale(context->c, bbox->x2 - bbox->x1, bbox->y2 - bbox->y1); + } + if (mPtr) { + cairo_matrix_t matrix; + cairo_matrix_init(&matrix, mPtr->a, mPtr->b, mPtr->c, mPtr->d, mPtr->tx, mPtr->ty); + cairo_pattern_set_matrix(pattern, &matrix); + } + + for (i = 0; i < nstops; i++) { + stop = stopArrPtr->stops[i]; + cairo_pattern_add_color_stop_rgba(pattern, stop->offset, + RedDoubleFromXColorPtr(stop->color), + GreenDoubleFromXColorPtr(stop->color), + BlueDoubleFromXColorPtr(stop->color), + stop->opacity); + } + cairo_set_source(context->c, pattern); + cairo_set_fill_rule(context->c, + (fillRule == WindingRule) ? CAIRO_FILL_RULE_WINDING : CAIRO_FILL_RULE_EVEN_ODD); + cairo_pattern_set_extend(pattern, GetCairoExtend(fillPtr->method)); + cairo_fill(context->c); + + cairo_pattern_destroy(pattern); + cairo_restore(context->c); +} diff --git a/pd/tkpath/win/makefile.vc b/pd/tkpath/win/makefile.vc new file mode 100755 index 0000000000000000000000000000000000000000..f33cceea7c5b7f823ca21a849366096452cfb175 --- /dev/null +++ b/pd/tkpath/win/makefile.vc @@ -0,0 +1,491 @@ +# makefile.vc -- -*- Makefile -*- +# +# Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+) +# +# This makefile is based upon the Tcl 8.4 Makefile.vc and modified to +# make it suitable as a general package makefile. Look for the word EDIT +# which marks sections that may need modification. As a minumum you will +# need to change the PROJECT, DOTVERSION and DLLOBJS variables to values +# relevant to your package. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# Copyright (c) 1995-1996 Sun Microsystems, Inc. +# Copyright (c) 1998-2000 Ajuba Solutions. +# Copyright (c) 2001 ActiveState Corporation. +# Copyright (c) 2001-2002 David Gravereaux. +# Copyright (c) 2003-2006 Pat Thoyts +# +#------------------------------------------------------------------------- +# RCS: @(#)$Id: makefile.vc,v 1.3 2011/10/28 15:11:26 pspjuth Exp $ +#------------------------------------------------------------------------- + +# Check to see we are configured to build with MSVC (MSDEVDIR or MSVCDIR) +# or with the MS Platform SDK (MSSDK). Visual Studio .NET 2003 and 2005 define +# VCINSTALLDIR instead. +!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(MSSDK) && !defined(VCINSTALLDIR) +MSG = ^ +You need to run vcvars32.bat from Developer Studio or setenv.bat from the^ +Platform SDK first to setup the environment. Jump to this line to read^ +the build instructions. +!error $(MSG) +!endif + +#------------------------------------------------------------------------------ +# HOW TO USE this makefile: +# +# 1) It is now necessary to have %MSVCDir% set in the environment. This is +# used as a check to see if vcvars32.bat had been run prior to running +# nmake or during the installation of Microsoft Visual C++, MSVCDir had +# been set globally and the PATH adjusted. Either way is valid. +# +# You'll need to run vcvars32.bat contained in the MsDev's vc(98)/bin +# directory to setup the proper environment, if needed, for your current +# setup. This is a needed bootstrap requirement and allows the swapping of +# different environments to be easier. +# +# 2) To use the Platform SDK (not expressly needed), run setenv.bat after +# vcvars32.bat according to the instructions for it. This can also turn on +# the 64-bit compiler, if your SDK has it. +# +# 3) Targets are: +# all -- Builds everything. +# <project> -- Builds the project (eg: nmake sample) +# test -- Builds and runs the test suite. +# install -- Installs the built binaries and libraries to $(INSTALLDIR) +# in an appropriate subdirectory. +# clean/realclean/distclean -- varying levels of cleaning. +# +# 4) Macros usable on the commandline: +# INSTALLDIR=<path> +# Sets where to install Tcl from the built binaries. +# C:\Progra~1\Tcl is assumed when not specified. +# +# OPTS=static,msvcrt,staticpkg,threads,symbols,profile,loimpact,none +# Sets special options for the core. The default is for none. +# Any combination of the above may be used (comma separated). +# 'none' will over-ride everything to nothing. +# +# static = Builds a static library of the core instead of a +# dll. The shell will be static (and large), as well. +# msvcrt = Effects the static option only to switch it from +# using libcmt(d) as the C runtime [by default] to +# msvcrt(d). This is useful for static embedding +# support. +# staticpkg = Effects the static option only to switch +# tclshXX.exe to have the dde and reg extension linked +# inside it. +# nothreads = Turns off multithreading support (not recommended) +# thrdalloc = Use the thread allocator (shared global free pool). +# symbols = Adds symbols for step debugging. +# profile = Adds profiling hooks. Map file is assumed. +# loimpact = Adds a flag for how NT treats the heap to keep memory +# in use, low. This is said to impact alloc performance. +# +# STATS=memdbg,compdbg,none +# Sets optional memory and bytecode compiler debugging code added +# to the core. The default is for none. Any combination of the +# above may be used (comma separated). 'none' will over-ride +# everything to nothing. +# +# memdbg = Enables the debugging memory allocator. +# compdbg = Enables byte compilation logging. +# +# MACHINE=(IX86|IA64|ALPHA|AMD64) +# Set the machine type used for the compiler, linker, and +# resource compiler. This hook is needed to tell the tools +# when alternate platforms are requested. IX86 is the default +# when not specified. If the CPU environment variable has been +# set (ie: recent Platform SDK) then MACHINE is set from CPU. +# +# TMP_DIR=<path> +# OUT_DIR=<path> +# Hooks to allow the intermediate and output directories to be +# changed. $(OUT_DIR) is assumed to be +# $(BINROOT)\(Release|Debug) based on if symbols are requested. +# $(TMP_DIR) will de $(OUT_DIR)\<buildtype> by default. +# +# TESTPAT=<file> +# Reads the tests requested to be run from this file. +# +# CFG_ENCODING=encoding +# name of encoding for configuration information. Defaults +# to cp1252 +# +# 5) Examples: +# +# Basic syntax of calling nmake looks like this: +# nmake [-nologo] -f makefile.vc [target|macrodef [target|macrodef] [...]] +# +# Standard (no frills) +# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat +# Setting environment for using Microsoft Visual C++ tools. +# c:\tcl_src\win\>nmake -f makefile.vc all +# c:\tcl_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl +# +# Building for Win64 +# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat +# Setting environment for using Microsoft Visual C++ tools. +# c:\tcl_src\win\>c:\progra~1\platfo~1\setenv.bat /pre64 /RETAIL +# Targeting Windows pre64 RETAIL +# c:\tcl_src\win\>nmake -f makefile.vc MACHINE=IA64 +# +#------------------------------------------------------------------------------ +#============================================================================== +############################################################################### +#------------------------------------------------------------------------------ + +!if !exist("makefile.vc") +MSG = ^ +You must run this makefile only from the directory it is in.^ +Please `cd` to its location first. +!error $(MSG) +!endif + +#------------------------------------------------------------------------- +# Project specific information (EDIT) +# +# You should edit this with the name and version of your project. This +# information is used to generate the name of the package library and +# it's install location. +# +# For example, the sample extension is going to build sample04.dll and +# would install it into $(INSTALLDIR)\lib\sample04 +# +# You need to specify the object files that need to be linked into your +# binary here. +# +#------------------------------------------------------------------------- + +PROJECT = tkpath +!include "rules.vc" + +DOTVERSION = 0.3.2 +VERSION = $(DOTVERSION:.=) +STUBPREFIX = $(PROJECT)stub + +DLLOBJS = \ + $(TMP_DIR)\path.obj \ + $(TMP_DIR)\tkPath.obj \ + $(TMP_DIR)\tkpCanvas.obj \ + $(TMP_DIR)\tkpCanvArc.obj \ + $(TMP_DIR)\tkpCanvBmap.obj \ + $(TMP_DIR)\tkpCanvImg.obj \ + $(TMP_DIR)\tkpCanvLine.obj \ + $(TMP_DIR)\tkpCanvPoly.obj \ + $(TMP_DIR)\tkpCanvPs.obj \ + $(TMP_DIR)\tkpCanvText.obj \ + $(TMP_DIR)\tkpCanvUtil.obj \ + $(TMP_DIR)\tkpCanvWind.obj \ + $(TMP_DIR)\tkpRectOval.obj \ + $(TMP_DIR)\tkpTrig.obj \ + $(TMP_DIR)\tkpUtil.obj \ + $(TMP_DIR)\tkCanvPathUtil.obj \ + $(TMP_DIR)\tkCanvEllipse.obj \ + $(TMP_DIR)\tkCanvGroup.obj \ + $(TMP_DIR)\tkCanvPath.obj \ + $(TMP_DIR)\tkCanvPimage.obj \ + $(TMP_DIR)\tkCanvPline.obj \ + $(TMP_DIR)\tkCanvPpoly.obj \ + $(TMP_DIR)\tkCanvPrect.obj \ + $(TMP_DIR)\tkCanvPtext.obj \ + $(TMP_DIR)\tkCanvGradient.obj \ + $(TMP_DIR)\tkPathGradient.obj \ + $(TMP_DIR)\tkCanvStyle.obj \ + $(TMP_DIR)\tkPathStyle.obj \ + $(TMP_DIR)\tkPathSurface.obj \ + $(TMP_DIR)\tkPathUtil.obj \ + $(TMP_DIR)\tkWinGDIPlusPath.obj + +#------------------------------------------------------------------------- +# Target names and paths ( shouldn't need changing ) +#------------------------------------------------------------------------- + +BINROOT = . +ROOT = .. + +PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib +PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) +PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) + +PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib +PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) + +### Make sure we use backslash only. +PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) +LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) +BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) +DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) +SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) +INCLUDE_INSTALL_DIR = $(_TCLDIR)\include + +### The following paths CANNOT have spaces in them. +GENERICDIR = $(ROOT)\generic +WINDIR = $(ROOT)\win +LIBDIR = $(ROOT)\library +DOCDIR = $(ROOT)\doc +TOOLSDIR = $(ROOT)\tools +COMPATDIR = $(ROOT)\compat + +#--------------------------------------------------------------------- +# Compile flags +#--------------------------------------------------------------------- + +!if !$(DEBUG) +!if $(OPTIMIZING) +### This cranks the optimization level to maximize speed +cdebug = $(OPTIMIZATIONS) +!else +cdebug = +!endif +!else if "$(MACHINE)" == "IA64" +### Warnings are too many, can't support warnings into errors. +cdebug = -Z7 -Od $(DEBUGFLAGS) +!else +cdebug = -Z7 -WX $(DEBUGFLAGS) +!endif + +### Declarations common to all compiler options +cflags = -nologo -c $(COMPILERFLAGS) -D_CRT_SECURE_NO_WARNINGS -Fp$(TMP_DIR)^\ + +!if $(VCVER) > 7 +cflags =$(cflags) -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS +!endif + +!if $(MSVCRT) +!if $(DEBUG) +crt = -MDd +!else +crt = -MD +!endif +!else +!if $(DEBUG) +crt = -MTd +!else +crt = -MT +!endif +!endif + +INCLUDES = $(TCL_INCLUDES) $(TK_INCLUDES) \ + -I"$(TK_SRC_DIR)\generic" -I"$(TK_SRC_DIR)\win" \ + -I"$(WINDIR)" -I"$(GENERICDIR)" +BASE_CFLAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) +CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE +TCL_CFLAGS = -DUSE_TCL_STUBS -DUSE_TK_STUBS -DPACKAGE_VERSION="\"$(DOTVERSION)\"" \ + $(BASE_CFLAGS) $(OPTDEFINES) + +#--------------------------------------------------------------------- +# Link flags +#--------------------------------------------------------------------- + +!if $(DEBUG) +ldebug = -debug -debugtype:cv +!if $(MSVCRT) +ldebug = $(ldebug) -nodefaultlib:msvcrt +!endif +!else +ldebug = -release -opt:ref -opt:icf,3 +!endif + +### Declarations common to all linker options +lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) + +!if $(PROFILE) +lflags = $(lflags) -profile +!endif + +!if $(ALIGN98_HACK) && !$(STATIC_BUILD) +### Align sections for PE size savings. +lflags = $(lflags) -opt:nowin98 +!else if !$(ALIGN98_HACK) && $(STATIC_BUILD) +### Align sections for speed in loading by choosing the virtual page size. +lflags = $(lflags) -align:4096 +!endif + +!if $(LOIMPACT) +lflags = $(lflags) -ws:aggressive +!endif + +dlllflags = $(lflags) -dll +conlflags = $(lflags) -subsystem:console +guilflags = $(lflags) -subsystem:windows +baselibs = $(TCLSTUBLIB) $(TKSTUBLIB) Gdi32.lib gdiplus.lib + +# Avoid 'unresolved external symbol __security_cookie' errors. +# c.f. http://support.microsoft.com/?id=894573 +!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" +baselibs = $(baselibs) bufferoverflowU.lib +!endif + +#--------------------------------------------------------------------- +# TclTest flags +#--------------------------------------------------------------------- + +!IF "$(TESTPAT)" != "" +TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) +!ENDIF + +#--------------------------------------------------------------------- +# Project specific targets (EDIT) +#--------------------------------------------------------------------- + +all: setup $(PROJECT) +$(PROJECT): setup $(PRJLIB) +install: install-binaries install-libraries install-docs + +# Tests need to ensure we load the right dll file we +# have to handle the output differently on Win9x. +# +!if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE" +test: setup $(PROJECT) + set TCL_LIBRARY=$(ROOT)/library + $(TCLSH) << +load $(PRJLIB:\=/) +cd "$(ROOT)/tests" +set argv "$(TESTFLAGS)" +source all.tcl +<< +!else +test: setup $(PROJECT) + echo Please wait while the test results are collected + set TCL_LIBRARY=$(ROOT)/library + $(TCLSH) << >tests.log +load $(PRJLIB:\=/) +cd "$(ROOT)/tests" +set argv "$(TESTFLAGS)" +source all.tcl +<< + type tests.log | more +!endif + +setup: + @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) + @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) + +$(PRJLIB): $(DLLOBJS) +!if $(STATIC_BUILD) + $(lib32) -nologo -out:$@ @<< +$** +<< +!else + $(link32) $(dlllflags) -out:$@ $(baselibs) @<< +$** +<< + $(_VC_MANIFEST_EMBED_DLL) + -@del $*.exp +!endif + +$(PRJSTUBLIB): $(PRJSTUBOBJS) + $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) + +#--------------------------------------------------------------------- +# Implicit rules +#--------------------------------------------------------------------- + +{$(WINDIR)}.c{$(TMP_DIR)}.obj:: + $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< +$< +<< + +{$(WINDIR)}.cpp{$(TMP_DIR)}.obj:: + $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< +$< +<< + +{$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: + $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< +$< +<< + +{$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: + $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< +$< +<< + +{$(WINDIR)}.rc{$(TMP_DIR)}.res: + $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \ + -DCOMMAVERSION=$(DOTVERSION:.=,),0 \ + -DDOTVERSION=\"$(DOTVERSION)\" \ + -DVERSION=\"$(VERSION)$(SUFX)\" \ +!if $(DEBUG) + -d DEBUG \ +!endif +!if $(TCL_THREADS) + -d TCL_THREADS \ +!endif +!if $(STATIC_BUILD) + -d STATIC_BUILD \ +!endif + $< + +.SUFFIXES: +.SUFFIXES:.c .cpp .rc + +#--------------------------------------------------------------------- +# Installation. (EDIT) +# +# You may need to modify this section to reflect the final distribution +# of your files and possibly to generate documentation. +# +#--------------------------------------------------------------------- + +install-binaries: + @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)' + @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" + @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL + +### Automatic creation of pkgIndex +#install-libraries: +# @echo Installing library files to '$(SCRIPT_INSTALL_DIR)' +# @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" +# @echo cd "$(SCRIPT_INSTALL_DIR:\=/)" ; pkg_mkIndex . | $(TCLSH) + +### Manual creation of pkgIndex +### Normally the ifneeded command would be: +### package ifneeded $(PROJECT) $(DOTVERSION) \ +### [list load [file join $$dir $(PROJECT)$(VERSION).$(EXT)]] +### but this project has been named oddly. It has Sample_Init but provides +### the Tclsha1 package. +install-libraries: + @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' + @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" + @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' + @type << >"$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl" +# Hand-crafted pkgIndex.tcl +# +namespace eval ::tkpath { + proc load_package {dir} { + load [file join $$dir $(PROJECT)$(VERSION)$(SUFX).$(EXT)] + # Allow optional redirect of library components. + # Only necessary for testing, but could be used elsewhere. + if {[info exists ::env(TKPATH_LIBRARY)]} { + set dir $$::env(TKPATH_LIBRARY) + } + source $$dir/tkpath.tcl + };# load_package +} + +package ifneeded tkpath $(DOTVERSION) [list ::tkpath::load_package $$dir] + +#*EOF* +<< + +install-docs: + @echo Installing documentation files to '$(DOC_INSTALL_DIR)' + @if exist $(DOCDIR) $(CPY) $(DOCDIR)\*.n "$(DOC_INSTALL_DIR)" + +#--------------------------------------------------------------------- +# Clean up +#--------------------------------------------------------------------- + +clean: + @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) + @if exist $(WINDIR)\version.vc del $(WINDIR)\version.vc + +realclean: clean + @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) + +distclean: realclean + @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe + @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj diff --git a/pd/tkpath/win/nmakehlp.c b/pd/tkpath/win/nmakehlp.c new file mode 100755 index 0000000000000000000000000000000000000000..5db76bbc66ead3c642ec14b71d558658c9ea0fdd --- /dev/null +++ b/pd/tkpath/win/nmakehlp.c @@ -0,0 +1,508 @@ +/* ---------------------------------------------------------------------------- + * nmakehlp.c -- + * + * This is used to fix limitations within nmake and the environment. + * + * Copyright (c) 2002 by David Gravereaux. + * Copyright (c) 2003 by Patrick Thoyts + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * ---------------------------------------------------------------------------- + * RCS: @(#) $Id: nmakehlp.c,v 1.1 2007/01/24 10:48:16 ctasada Exp $ + * ---------------------------------------------------------------------------- + */ + +#define _CRT_SECURE_NO_DEPRECATE +#include <windows.h> +#include <shlwapi.h> +#pragma comment (lib, "user32.lib") +#pragma comment (lib, "kernel32.lib") +#pragma comment (lib, "shlwapi.lib") +#include <stdio.h> +#if defined(_M_IA64) || defined(_M_AMD64) +#pragma comment(lib, "bufferoverflowU") +#endif + +/* protos */ + +int CheckForCompilerFeature(const char *option); +int CheckForLinkerFeature(const char *option); +int IsIn(const char *string, const char *substring); +int GrepForDefine(const char *file, const char *string); +int GetVersionFromHeader(const char *tclh, const char *tkh); +DWORD WINAPI ReadFromPipe(LPVOID args); + +/* globals */ + +#define CHUNK 25 +#define STATICBUFFERSIZE 1000 +typedef struct { + HANDLE pipe; + char buffer[STATICBUFFERSIZE]; +} pipeinfo; + +pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; +pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; + +/* + * exitcodes: 0 == no, 1 == yes, 2 == error + */ + +int +main (int argc, char *argv[]) +{ + char msg[300]; + DWORD dwWritten; + int chars; + + /* + * Make sure children (cl.exe and link.exe) are kept quiet. + */ + + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); + + /* + * Make sure the compiler and linker aren't effected by the outside world. + */ + + SetEnvironmentVariable("CL", ""); + SetEnvironmentVariable("LINK", ""); + + if (argc > 1 && *argv[1] == '-') { + switch (*(argv[1]+1)) { + case 'c': + if (argc != 3) { + chars = wnsprintf(msg, sizeof(msg)-1, + "usage: %s -c <compiler option>\n" + "Tests for whether cl.exe supports an option\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return CheckForCompilerFeature(argv[2]); + case 'l': + if (argc != 3) { + chars = wnsprintf(msg, sizeof(msg) - 1, + "usage: %s -l <linker option>\n" + "Tests for whether link.exe supports an option\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return CheckForLinkerFeature(argv[2]); + case 'f': + if (argc == 2) { + chars = wnsprintf(msg, sizeof(msg) - 1, + "usage: %s -f <string> <substring>\n" + "Find a substring within another\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } else if (argc == 3) { + /* + * If the string is blank, there is no match. + */ + + return 0; + } else { + return IsIn(argv[2], argv[3]); + } + case 'v': + if (argc != 4) { + chars = wnsprintf(msg, sizeof(msg) - 1, + "usage: %s -v <tcl.h> <tk.h>\n" + "Search for versions from the tcl and tk headers.", + argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 0; + } + return GetVersionFromHeader(argv[2], argv[3]); + } + } + chars = wnsprintf(msg, sizeof(msg) - 1, + "usage: %s -c|-l|-f ...\n" + "This is a little helper app to equalize shell differences between WinNT and\n" + "Win9x and get nmake.exe to accomplish its job.\n", + argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + return 2; +} + +int +CheckForCompilerFeature( + const char *option) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES sa; + DWORD threadID, n; + char msg[300]; + BOOL ok; + HANDLE hProcess, h, pipeThreads[2]; + char cmdline[256]; + + hProcess = GetCurrentProcess(); + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = INVALID_HANDLE_VALUE; + + ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = FALSE; + + /* + * Create a non-inheritible pipe. + */ + + CreatePipe(&Out.pipe, &h, &sa, 0); + + /* + * Dupe the write side, make it inheritible, and close the original. + */ + + DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Same as above, but for the error side. + */ + + CreatePipe(&Err.pipe, &h, &sa, 0); + DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Base command line (use nmake environment) + */ + + n = GetEnvironmentVariable("CC", cmdline, 255); + cmdline[n] = 0; + if (n == 0) + lstrcpy(cmdline, "cl.exe"); + + strncat(cmdline, " -nologo -c -TC -Zs -X ", 255); + + /* + * Append our option for testing + */ + + lstrcat(cmdline, option); + + /* + * Filename to compile, which exists, but is nothing and empty. + */ + + lstrcat(cmdline, " .\\nul"); + + ok = CreateProcess( + NULL, /* Module name. */ + cmdline, /* Command line. */ + NULL, /* Process handle not inheritable. */ + NULL, /* Thread handle not inheritable. */ + TRUE, /* yes, inherit handles. */ + DETACHED_PROCESS, /* No console for you. */ + NULL, /* Use parent's environment block. */ + NULL, /* Use parent's starting directory. */ + &si, /* Pointer to STARTUPINFO structure. */ + &pi); /* Pointer to PROCESS_INFORMATION structure. */ + + if (!ok) { + DWORD err = GetLastError(); + int chars = wnsprintf(msg, sizeof(msg) - 1, + "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], + (300-chars), 0); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); + return 2; + } + + /* + * Close our references to the write handles that have now been inherited. + */ + + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + WaitForInputIdle(pi.hProcess, 5000); + CloseHandle(pi.hThread); + + /* + * Start the pipe reader threads. + */ + + pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); + pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); + + /* + * Block waiting for the process to end. + */ + + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + + /* + * Wait for our pipe to get done reading, should it be a little slow. + */ + + WaitForMultipleObjects(2, pipeThreads, TRUE, INFINITE); + CloseHandle(pipeThreads[0]); + CloseHandle(pipeThreads[1]); + +#ifdef _DEBUG + { + DWORD err = 0; + lstrcat(cmdline, "\n"); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), cmdline, + lstrlen(cmdline), &err, NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), Out.buffer, + lstrlen(Out.buffer), &err,NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), Err.buffer, + lstrlen(Err.buffer), &err,NULL); + } +#endif + + /* + * Look for the commandline warning code in both streams. + * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002. + */ + + return !(strstr(Out.buffer, "D4002") != NULL + || strstr(Err.buffer, "D4002") != NULL + || strstr(Out.buffer, "D9002") != NULL + || strstr(Err.buffer, "D9002") != NULL); +} + +int +CheckForLinkerFeature( + const char *option) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES sa; + DWORD threadID; + char msg[300]; + BOOL ok; + HANDLE hProcess, h, pipeThreads[2]; + char cmdline[100]; + + hProcess = GetCurrentProcess(); + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = INVALID_HANDLE_VALUE; + + ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + /* + * Create a non-inheritible pipe. + */ + + CreatePipe(&Out.pipe, &h, &sa, 0); + + /* + * Dupe the write side, make it inheritible, and close the original. + */ + + DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Same as above, but for the error side. + */ + + CreatePipe(&Err.pipe, &h, &sa, 0); + DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Base command line. + */ + + lstrcpy(cmdline, "link.exe -nologo "); + + /* + * Append our option for testing. + */ + + lstrcat(cmdline, option); + + ok = CreateProcess( + NULL, /* Module name. */ + cmdline, /* Command line. */ + NULL, /* Process handle not inheritable. */ + NULL, /* Thread handle not inheritable. */ + TRUE, /* yes, inherit handles. */ + DETACHED_PROCESS, /* No console for you. */ + NULL, /* Use parent's environment block. */ + NULL, /* Use parent's starting directory. */ + &si, /* Pointer to STARTUPINFO structure. */ + &pi); /* Pointer to PROCESS_INFORMATION structure. */ + + if (!ok) { + DWORD err = GetLastError(); + int chars = wnsprintf(msg, sizeof(msg) - 1, + "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], + (300-chars), 0); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); + return 2; + } + + /* + * Close our references to the write handles that have now been inherited. + */ + + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + WaitForInputIdle(pi.hProcess, 5000); + CloseHandle(pi.hThread); + + /* + * Start the pipe reader threads. + */ + + pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); + pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); + + /* + * Block waiting for the process to end. + */ + + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + + /* + * Wait for our pipe to get done reading, should it be a little slow. + */ + + WaitForMultipleObjects(2, pipeThreads, TRUE, 500); + CloseHandle(pipeThreads[0]); + CloseHandle(pipeThreads[1]); + + /* + * Look for the commandline warning code in the stderr stream. + */ + + return !(IsIn(Out.buffer, "LNK1117") || + IsIn(Err.buffer, "LNK1117") || + IsIn(Out.buffer, "LNK4044") || + IsIn(Err.buffer, "LNK4044")); +} + +#if 1 +DWORD WINAPI +ReadFromPipe( + LPVOID args) +{ + pipeinfo *pi = (pipeinfo *) args; + char *lastBuf = pi->buffer; + DWORD dwRead; + BOOL ok; + + again: + if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) { + CloseHandle(pi->pipe); + return (DWORD)-1; + } + ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L); + if (!ok || dwRead == 0) { + CloseHandle(pi->pipe); + return 0; + } + lastBuf += dwRead; + goto again; + + return 0; /* makes the compiler happy */ +} +#else +DWORD WINAPI +ReadFromPipe (LPVOID args) +{ + pipeinfo *pi = (pipeinfo *) args; + char *lastBuf = pi->buffer; + DWORD dwRead; + BOOL ok; + +again: + ok = ReadFile(pi->pipe, lastBuf, 25, &dwRead, 0L); + if (!ok || dwRead == 0) { + CloseHandle(pi->pipe); + return 0; + } + lastBuf += dwRead; + goto again; + + return 0; /* makes the compiler happy */ +} +#endif + +int +IsIn (const char *string, const char *substring) +{ + return (strstr(string, substring) != NULL); +} + +static double +ReadVersionFromHeader(const char *file, const char *macro) +{ + double d = 0.0; + CHAR szBuffer[100]; + LPSTR p; + DWORD cbBuffer = 100; + FILE *fp = fopen(file, "r"); + if (fp != NULL) { + while (fgets(szBuffer, cbBuffer, fp) != NULL) { + if ((p = strstr(szBuffer, macro)) != NULL) { + while (*p && !isdigit(*p)) ++p; + d = strtod(p, NULL); + break; + } + } + fclose(fp); + } + return d; +} + +int +GetVersionFromHeader(const char *tclh, const char *tkh) +{ + double dTcl = 0.0, dTk = 0.0; + + if (tclh != NULL) + dTcl = ReadVersionFromHeader(tclh, "TCL_VERSION"); + if (tkh != NULL) + dTk = ReadVersionFromHeader(tkh, "TK_VERSION"); + + if (dTcl > 0 || dTk > 0) { + FILE *ofp = fopen("version.vc", "w"); + if (dTcl > 0) + fprintf(ofp, "TCL_DOTVERSION\t= %0.1f\nTCL_VERSION\t= %u\n", + dTcl, (int)(dTcl * 10.0)); + if (dTk > 0) + fprintf(ofp, "TK_DOTVERSION\t= %0.1f\nTK_VERSION\t= %u\n", + dTk, (int)(dTk * 10.0)); + fclose(ofp); + return 0; + } + return 1; +} diff --git a/pd/tkpath/win/rules.vc b/pd/tkpath/win/rules.vc new file mode 100755 index 0000000000000000000000000000000000000000..2d43efe4e0ff0c12cba31f750d186a2e5effb42b --- /dev/null +++ b/pd/tkpath/win/rules.vc @@ -0,0 +1,564 @@ +#------------------------------------------------------------------------------ +# rules.vc -- +# +# Microsoft Visual C++ makefile include for decoding the commandline +# macros. This file does not need editing to build Tcl. +# +# This version is modified from the Tcl source version to support +# building extensions using nmake. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# Copyright (c) 2001-2002 David Gravereaux. +# Copyright (c) 2003-2006 Patrick Thoyts +# +#------------------------------------------------------------------------------ +# RCS: @(#) $Id: rules.vc,v 1.1 2007/01/24 10:48:16 ctasada Exp $ +#------------------------------------------------------------------------------ + +!ifndef _RULES_VC +_RULES_VC = 1 + +cc32 = $(CC) # built-in default. +link32 = link +lib32 = lib +rc32 = $(RC) # built-in default. + +!ifndef INSTALLDIR +### Assume the normal default. +_INSTALLDIR = C:\Program Files\Tcl +!else +### Fix the path separators. +_INSTALLDIR = $(INSTALLDIR:/=\) +!endif + +!ifndef MACHINE +!if "$(CPU)" == "" +MACHINE = IX86 +!else +MACHINE = $(CPU) +!endif +!endif + +!ifndef CFG_ENCODING +CFG_ENCODING = \"cp1252\" +!endif + +#---------------------------------------------------------- +# Set the proper copy method to avoid overwrite questions +# to the user when copying files and selecting the right +# "delete all" method. +#---------------------------------------------------------- + +!if "$(OS)" == "Windows_NT" +RMDIR = rmdir /S /Q +!if ![ver | find "4.0" > nul] +CPY = echo y | xcopy /i +!else +CPY = xcopy /i /y >NUL +!endif +!else +CPY = xcopy /i +RMDIR = deltree /Y +!endif +MKDIR = mkdir +COPY = copy /y >NUL + +!message =============================================================================== + +#---------------------------------------------------------- +# build the helper app we need to overcome nmake's limiting +# environment. +#---------------------------------------------------------- + +!if !exist(nmakehlp.exe) +!if [$(cc32) -nologo nmakehlp.c -link -subsystem:console > nul] +!endif +!endif + +#---------------------------------------------------------- +# Test for compiler features +#---------------------------------------------------------- + +### test for optimizations +!if [nmakehlp -c -Ot] +!message *** Compiler has 'Optimizations' +OPTIMIZING = 1 +!else +!message *** Compiler doesn't have 'Optimizations' +OPTIMIZING = 0 +!endif + +OPTIMIZATIONS = + +!if [nmakehlp -c -Ot] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Ot +!endif + +!if [nmakehlp -c -Oi] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Oi +!endif + +!if [nmakehlp -c -Op] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Op +!endif + +!if [nmakehlp -c -fp:strict] +OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:strict +!endif + +!if [nmakehlp -c -Gs] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Gs +!endif + +!if [nmakehlp -c -GS] +OPTIMIZATIONS = $(OPTIMIZATIONS) -GS +!endif + +!if [nmakehlp -c -GL] +OPTIMIZATIONS = $(OPTIMIZATIONS) -GL +!endif + +DEBUGFLAGS = + +!if [nmakehlp -c -RTC1] +DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 +!elseif [nmakehlp -c -GZ] +DEBUGFLAGS = $(DEBUGFLAGS) -GZ +!endif + +COMPILERFLAGS =-W3 + +!if [nmakehlp -c -YX] +COMPILERFLAGS = $(COMPILERFLAGS) -YX +!endif + +!if "$(MACHINE)" == "IX86" +### test for pentium errata +!if [nmakehlp -c -QI0f] +!message *** Compiler has 'Pentium 0x0f fix' +COMPILERFLAGS = $(COMPILERFLAGS) -QI0f +!else +!message *** Compiler doesn't have 'Pentium 0x0f fix' +!endif +!endif + +!if "$(MACHINE)" == "IA64" +### test for Itanium errata +!if [nmakehlp -c -QIA64_Bx] +!message *** Compiler has 'B-stepping errata workarounds' +COMPILERFLAGS = $(COMPILERFLAGS) -QIA64_Bx +!else +!message *** Compiler does not have 'B-stepping errata workarounds' +!endif +!endif + +!if "$(MACHINE)" == "IX86" +### test for -align:4096, when align:512 will do. +!if [nmakehlp -l -opt:nowin98] +!message *** Linker has 'Win98 alignment problem' +ALIGN98_HACK = 1 +!else +!message *** Linker doesn't have 'Win98 alignment problem' +ALIGN98_HACK = 0 +!endif +!else +ALIGN98_HACK = 0 +!endif + +LINKERFLAGS = + +!if [nmakehlp -l -ltcg] +LINKERFLAGS =-ltcg +!endif + +#---------------------------------------------------------- +# MSVC8 (ships with Visual Studio 2005) generates a manifest +# file that we should link into the binaries. This is how. +#---------------------------------------------------------- + +_VC_MANIFEST_EMBED_EXE= +_VC_MANIFEST_EMBED_DLL= +!if ![cl /Zs /Tc NUL 2>&1 | find "Version 12" > NUL] +VCVER=6 +!elseif ![cl /Zs /Tc NUL 2>&1 | find "Version 13" > NUL] +VCVER=7 +!elseif ![cl /Zs /Tc NUL 2>&1 | find "Version 14" > NUL] +VCVER=8 +_VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 +_VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 +!else +VCVER=0 +!endif + +#---------------------------------------------------------- +# Decode the options requested. +#---------------------------------------------------------- + +!if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"] +STATIC_BUILD = 0 +TCL_THREADS = 1 +DEBUG = 0 +PROFILE = 0 +MSVCRT = 0 +LOIMPACT = 0 +TCL_USE_STATIC_PACKAGES = 0 +USE_THREAD_ALLOC = 1 +USE_THREAD_STORAGE = 1 +UNCHECKED = 0 +!else +!if [nmakehlp -f $(OPTS) "static"] +!message *** Doing static +STATIC_BUILD = 1 +!else +STATIC_BUILD = 0 +!endif +!if [nmakehlp -f $(OPTS) "msvcrt"] +!message *** Doing msvcrt +MSVCRT = 1 +!else +MSVCRT = 0 +!endif +!if [nmakehlp -f $(OPTS) "staticpkg"] +!message *** Doing staticpkg +TCL_USE_STATIC_PACKAGES = 1 +!else +TCL_USE_STATIC_PACKAGES = 0 +!endif +!if [nmakehlp -f $(OPTS) "nothreads"] +!message *** Compile explicitly for non-threaded tcl +TCL_THREADS = 0 +!else +TCL_THREADS = 1 +!endif +!if [nmakehlp -f $(OPTS) "symbols"] +!message *** Doing symbols +DEBUG = 1 +!else +DEBUG = 0 +!endif +!if [nmakehlp -f $(OPTS) "profile"] +!message *** Doing profile +PROFILE = 1 +!else +PROFILE = 0 +!endif +!if [nmakehlp -f $(OPTS) "loimpact"] +!message *** Doing loimpact +LOIMPACT = 1 +!else +LOIMPACT = 0 +!endif +!if [nmakehlp -f $(OPTS) "thrdalloc"] +!message *** Doing thrdalloc +USE_THREAD_ALLOC = 1 +!else +USE_THREAD_ALLOC = 0 +!endif +!if [nmakehlp -f $(OPTS) "thrdstorage"] +!message *** Doing thrdstorage +USE_THREAD_STORAGE = 1 +!else +USE_THREAD_STORAGE = 0 +!endif +!if [nmakehlp -f $(OPTS) "unchecked"] +!message *** Doing unchecked +UNCHECKED = 1 +!else +UNCHECKED = 0 +!endif +!endif + + +!if !$(STATIC_BUILD) +# Make sure we don't build overly fat DLLs. +MSVCRT = 1 +# We shouldn't statically put the extensions inside the shell when dynamic. +TCL_USE_STATIC_PACKAGES = 0 +!endif + + +#---------------------------------------------------------- +# Figure-out how to name our intermediate and output directories. +# We wouldn't want different builds to use the same .obj files +# by accident. +#---------------------------------------------------------- + +#---------------------------------------- +# Naming convention: +# t = full thread support. +# s = static library (as opposed to an +# import library) +# g = linked to the debug enabled C +# run-time. +# x = special static build when it +# links to the dynamic C run-time. +#---------------------------------------- +SUFX = sgx + +!if $(DEBUG) +BUILDDIRTOP = Debug +DBGX = g +!else +BUILDDIRTOP = Release +DBGX = +SUFX = $(SUFX:g=) +!endif + +!if "$(MACHINE)" != "IX86" +BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE) +!endif +!if $(VCVER) > 6 +BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER) +!endif + +TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX + +!if !$(STATIC_BUILD) +TMP_DIRFULL = $(TMP_DIRFULL:Static=) +SUFX = $(SUFX:s=) +EXT = dll +!if $(MSVCRT) +TMP_DIRFULL = $(TMP_DIRFULL:X=) +SUFX = $(SUFX:x=) +!endif +!else +TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=) +EXT = lib +!if !$(MSVCRT) +TMP_DIRFULL = $(TMP_DIRFULL:X=) +SUFX = $(SUFX:x=) +!endif +!endif + +!if !$(TCL_THREADS) +TMP_DIRFULL = $(TMP_DIRFULL:Threaded=) +SUFX = $(SUFX:t=) +!endif + +!ifndef TMP_DIR +TMP_DIR = $(TMP_DIRFULL) +!ifndef OUT_DIR +OUT_DIR = .\$(BUILDDIRTOP) +!endif +!else +!ifndef OUT_DIR +OUT_DIR = $(TMP_DIR) +!endif +!endif + + +#---------------------------------------------------------- +# Decode the statistics requested. +#---------------------------------------------------------- + +!if "$(STATS)" == "" || [nmakehlp -f "$(STATS)" "none"] +TCL_MEM_DEBUG = 0 +TCL_COMPILE_DEBUG = 0 +!else +!if [nmakehlp -f $(STATS) "memdbg"] +!message *** Doing memdbg +TCL_MEM_DEBUG = 1 +!else +TCL_MEM_DEBUG = 0 +!endif +!if [nmakehlp -f $(STATS) "compdbg"] +!message *** Doing compdbg +TCL_COMPILE_DEBUG = 1 +!else +TCL_COMPILE_DEBUG = 0 +!endif +!endif + +#---------------------------------------------------------- +# Decode the checks requested. +#---------------------------------------------------------- + +!if "$(CHECKS)" == "" || [nmakehlp -f "$(CHECKS)" "none"] +TCL_NO_DEPRECATED = 0 +FULLWARNINGS = 0 +!else +!if [nmakehlp -f $(CHECKS) "nodep"] +!message *** Doing nodep check +TCL_NO_DEPRECATED = 1 +!else +TCL_NO_DEPRECATED = 0 +!endif +!if [nmakehlp -f $(CHECKS) "fullwarn"] +!message *** Doing full warnings check +FULLWARNINGS = 1 +!else +FULLWARNINGS = 0 +!endif +!endif + + +#---------------------------------------------------------- +# Set our defines now armed with our options. +#---------------------------------------------------------- + +OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) + +!if $(TCL_MEM_DEBUG) +OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG +!endif +!if $(TCL_COMPILE_DEBUG) +OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS +!endif +!if $(TCL_THREADS) +OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1 +!if $(USE_THREAD_ALLOC) +OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1 +!endif +!endif +!if $(STATIC_BUILD) +OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD +!endif + +!if $(DEBUG) +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DEBUG +!elseif $(OPTIMIZING) +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED +!endif +!if $(PROFILE) +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED +!endif +!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT +!endif + + +#---------------------------------------------------------- +# Get common info used when building extensions. +#---------------------------------------------------------- + +!if "$(PROJECT)" != "tcl" + +# If INSTALLDIR set to tcl root dir then reset to the lib dir. +!if exist("$(_INSTALLDIR)\include\tcl.h") +_INSTALLDIR=$(_INSTALLDIR)\lib +!endif + +!if !defined(TCLDIR) +!if exist("$(_INSTALLDIR)\..\include\tcl.h") +TCLINSTALL = 1 +_TCLDIR = $(_INSTALLDIR)\.. +_TCL_H = $(_INSTALLDIR)\..\include\tcl.h +TCLDIR = $(_INSTALLDIR)\.. +!else +MSG=^ +Failed to find tcl.h. Set the TCLDIR macro. +!error $(MSG) +!endif +!else +_TCLDIR = $(TCLDIR:/=\) +!if exist("$(_TCLDIR)\include\tcl.h") +TCLINSTALL = 1 +_TCL_H = $(_TCLDIR)\include\tcl.h +!elseif exist("$(_TCLDIR)\generic\tcl.h") +TCLINSTALL = 0 +_TCL_H = $(_TCLDIR)\generic\tcl.h +!else +MSG =^ +Failed to find tcl.h. The TCLDIR macro does not appear correct. +!error $(MSG) +!endif +!endif + +!if [nmakehlp -v "$(_TCL_H)" ""] == 0 +!include version.vc +!else +TCL_DOTVERSION = 8.5 +TCL_VERSION = $(TCL_DOTVERSION:.=) +!endif + +!if $(TCLINSTALL) +TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe" +TCLSTUBLIB = "$(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib" +TCLIMPLIB = "$(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib" +TCL_LIBRARY = $(_TCLDIR)\lib +TCL_INCLUDES = -I"$(_TCLDIR)\include" +!else +TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe" +TCLSTUBLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib" +TCLIMPLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib" +TCL_LIBRARY = $(_TCLDIR)\library +TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win" +!endif + +!endif + +#---------------------------------------------------------- +# Get Tk info for building extensions. +#---------------------------------------------------------- + +!if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk" + +!if !defined(TKDIR) +!if exist("$(_INSTALLDIR)\..\include\tk.h") +TKINSTALL = 1 +_TKDIR = $(_INSTALLDIR)\.. +_TK_H = $(_TKDIR)\include\tk.h +TKDIR = $(_TKDIR) +!elseif exist("$(_TCLDIR)\include\tk.h") +TKINSTALL = 1 +_TKDIR = $(_TCLDIR) +_TK_H = $(_TKDIR)\include\tk.h +TKDIR = $(_TKDIR) +!else +MSG =^ +Failed to find tk.h. Set the TKDIR macro. +!error $(MSG) +!endif +!else +_TKDIR = $(TKDIR:/=\) +!if exist("$(_TKDIR)\include\tk.h") +TKINSTALL = 1 +_TK_H = $(_TKDIR)\include\tk.h +!elseif exist("$(_TKDIR)\generic\tk.h") +TKINSTALL = 0 +_TK_H = $(_TKDIR)\generic\tk.h +!else +MSG =^ +Failed to find tk.h. The TKDIR macro does not appear correct. +!error $(MSG) +!endif +!endif + +!if [nmakehlp -v "$(_TCL_H)" "$(_TK_H)"] == 0 +!include version.vc +!else +TK_DOTVERSION = 8.5 +TK_VERSION = $(TK_DOTVERSION:.=) +!endif + +!if $(TKINSTALL) +WISH = "$(_TKDIR)\bin\wish$(TK_VERSION)$(SUFX).exe" +TKSTUBLIB = "$(_TKDIR)\lib\tkstub$(TK_VERSION).lib" +TKIMPLIB = "$(_TKDIR)\lib\tk$(TK_VERSION)$(SUFX).lib" +TK_INCLUDES = -I"$(_TKDIR)\include" +!else +WISH = "$(_TKDIR)\win\$(BUILDDIRTOP)\wish$(TCL_VERSION)$(SUFX).exe" +TKSTUBLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tkstub$(TCL_VERSION).lib" +TKIMPLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tk$(TCL_VERSION)$(SUFX).lib" +TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib" +!endif + +!endif + + + +#---------------------------------------------------------- +# Display stats being used. +#---------------------------------------------------------- + +!message *** Intermediate directory will be '$(TMP_DIR)' +!message *** Output directory will be '$(OUT_DIR)' +!message *** Suffix for binaries will be '$(SUFX)' +!message *** Optional defines are '$(OPTDEFINES)' +!message *** Compiler version $(VCVER), machine is $(MACHINE) +!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS)' +!message *** Link options '$(LINKERFLAGS)' + +!endif diff --git a/pd/tkpath/win/tkWinGDIPlusPath.cpp b/pd/tkpath/win/tkWinGDIPlusPath.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80a7049527f42d4ff5ce5670db17598d342c54fe --- /dev/null +++ b/pd/tkpath/win/tkWinGDIPlusPath.cpp @@ -0,0 +1,1103 @@ +/* + * tkWinGDIPlusPath.c -- + * + * This file implements path drawing API's on Windows using the GDI+ lib. + * + * Copyright (c) 2005-2008 Mats Bengtsson + * + * $Id: tkWinGDIPlusPath.cpp,v 1.58 2012/07/04 18:49:06 petasis Exp $ + */ + +/* This should go into configure.in but don't know how. */ +#ifdef USE_PANIC_ON_PHOTO_ALLOC_FAILURE +#undef USE_PANIC_ON_PHOTO_ALLOC_FAILURE +#endif + +#include <tkWinInt.h> +#include "tkPath.h" +#include "tkIntPath.h" + +#include <windows.h> + +// unknwn.h is needed to build with WIN32_LEAN_AND_MEAN +#include <unknwn.h> +#include <gdiplus.h> + +using namespace Gdiplus; + +extern Tcl_Interp *gInterp; +extern "C" int gAntiAlias; +extern "C" int gSurfaceCopyPremultiplyAlpha; + +#define MakeGDIPlusColor(xc, opacity) Color(BYTE(opacity*255), \ + BYTE(((xc)->pixel & 0xFF)), \ + BYTE(((xc)->pixel >> 8) & 0xFF), \ + BYTE(((xc)->pixel >> 16) & 0xFF)) + +static LookupTable LineCapStyleLookupTable[] = { + {CapNotLast, LineCapFlat}, + {CapButt, LineCapFlat}, + {CapRound, LineCapRound}, + {CapProjecting, LineCapSquare} +}; + +static LookupTable DashCapStyleLookupTable[] = { + {CapNotLast, DashCapFlat}, + {CapButt, DashCapFlat}, + {CapRound, DashCapRound}, + {CapProjecting, DashCapRound} +}; + +static LookupTable LineJoinStyleLookupTable[] = { + {JoinMiter, LineJoinMiter}, + {JoinRound, LineJoinRound}, + {JoinBevel, LineJoinBevel} +}; + +static int sGdiplusStarted; +static ULONG_PTR sGdiplusToken; +static GdiplusStartupOutput sGdiplusStartupOutput; + +static void InitGDIplus(void); + +static void PathExit(ClientData clientData); + +/* + * This class is a wrapper for path drawing using GDI+ + * It keeps storage for Graphics and GraphicsPath objects etc. + */ +class PathC { + + public: + PathC(HDC hdc); + ~PathC(void); + + void PushTMatrix(TMatrix *m); + void SaveState(); + void RestoreState(); + void BeginPath(Tk_PathStyle *style); + void MoveTo(float x, float y); + void LineTo(float x, float y); + void CurveTo(float x1, float y1, float x2, float y2, float x, float y); + void AddRectangle(float x, float y, float width, float height); + void AddEllipse(float cx, float cy, float rx, float ry); + void DrawImage(Tk_PhotoHandle photo, float x, float y, float width, float height); + void DrawString(Tk_PathStyle *style, Tk_PathTextStyle *textStylePtr, + float x, float y, char *utf8); + void CloseFigure(void); + void Stroke(Tk_PathStyle *style); + void Fill(Tk_PathStyle *style); + void FillAndStroke(Tk_PathStyle *style); + void GetCurrentPoint(PointF *pt); + void FillLinearGradient(PathRect *bbox, LinearGradientFill *fillPtr, int fillRule, TMatrix *mPtr); + void FillRadialGradient(PathRect *bbox, RadialGradientFill *fillPtr, int fillRule, TMatrix *mPtr); + + private: + HDC mMemHdc; + PointF mOrigin; + PointF mCurrentPoint; + Graphics *mGraphics; + GraphicsPath *mPath; + GraphicsContainer mContainerStack[10]; + int mCointainerTop; + + static Pen* PathCreatePen(Tk_PathStyle *style); + static SolidBrush* PathCreateBrush(Tk_PathStyle *style); +}; + +typedef struct PathSurfaceGDIpRecord { + HBITMAP bitmap; + void * data; + int width; + int height; + int bytesPerRow; /* the number of bytes between the start of rows in the buffer */ +} PathSurfaceGDIpRecord; + +/* + * This is used as a place holder for platform dependent stuff between each call. + */ +typedef struct TkPathContext_ { + PathC * c; + HDC memHdc; + PathSurfaceGDIpRecord * surface; /* NULL unless surface. */ +} TkPathContext_; + +void InitGDIplus(void) +{ + //Status status; + GdiplusStartupInput gdiplusStartupInput; + + GdiplusStartup(&sGdiplusToken, &gdiplusStartupInput, &sGdiplusStartupOutput); + /*status = GdiplusStartup(&sGdiplusToken, &gdiplusStartupInput, &sGdiplusStartupOutput); + if (status != Ok) { + return; + }*/ + Tcl_CreateExitHandler(PathExit, NULL); + sGdiplusStarted = 1; +} + +PathC::PathC(HDC hdc) +{ + if (!sGdiplusStarted) { + InitGDIplus(); + } + mMemHdc = hdc; + mGraphics = new Graphics(mMemHdc); + mPath = NULL; + mCointainerTop = 0; + if (gAntiAlias) { + mGraphics->SetSmoothingMode(SmoothingModeAntiAlias); + } + return; +} + +inline PathC::~PathC(void) +{ + if (mPath) { + delete mPath; + } + if (mGraphics) { + delete mGraphics; + } +} + +Pen* PathC::PathCreatePen(Tk_PathStyle *style) +{ + LineCap cap; + DashCap dashCap; + LineJoin lineJoin; + Pen *penPtr; + Tk_PathDash *dashPtr; + + penPtr = new Pen(MakeGDIPlusColor(style->strokeColor, style->strokeOpacity), (float) style->strokeWidth); + + cap = static_cast<LineCap>(TableLookup(LineCapStyleLookupTable, 4, style->capStyle)); + dashCap = static_cast<DashCap>(TableLookup(DashCapStyleLookupTable, 4, style->capStyle)); + penPtr->SetLineCap(cap, cap, dashCap); + + lineJoin = static_cast<LineJoin>(TableLookup(LineJoinStyleLookupTable, 3, style->joinStyle)); + penPtr->SetLineJoin(lineJoin); + + penPtr->SetMiterLimit((float) style->miterLimit); + + dashPtr = style->dashPtr; + if ((dashPtr != NULL) && (dashPtr->number != 0)) { + penPtr->SetDashPattern(dashPtr->array, dashPtr->number); + penPtr->SetDashOffset((float) style->offset); + } + return penPtr; +} + +inline SolidBrush* PathC::PathCreateBrush(Tk_PathStyle *style) +{ + SolidBrush *brushPtr; + brushPtr = new SolidBrush(MakeGDIPlusColor(GetColorFromPathColor(style->fill), style->fillOpacity)); + return brushPtr; +} + +inline void PathC::PushTMatrix(TMatrix *tm) +{ + Matrix m(float(tm->a), float(tm->b), float(tm->c), float(tm->d), float(tm->tx), float(tm->ty)); + mGraphics->MultiplyTransform(&m); +} + +inline void PathC::SaveState() +{ + if (mCointainerTop >= 9) { + Tcl_Panic("reached top of cointainer stack of GDI+"); + } + mContainerStack[mCointainerTop] = mGraphics->BeginContainer(); + mCointainerTop++; +} + +inline void PathC::RestoreState() +{ + mCointainerTop--; + mGraphics->EndContainer(mContainerStack[mCointainerTop]); +} + +inline void PathC::BeginPath(Tk_PathStyle *style) +{ + mPath = new GraphicsPath((style->fillRule == WindingRule) ? FillModeWinding : FillModeAlternate); +} + +inline void PathC::MoveTo(float x, float y) +{ + mPath->StartFigure(); + mOrigin.X = (float) x; + mOrigin.Y = (float) y; + mCurrentPoint.X = (float) x; + mCurrentPoint.Y = (float) y; +} + +inline void PathC::LineTo(float x, float y) +{ + mPath->AddLine(mCurrentPoint.X, mCurrentPoint.Y, x, y); + mCurrentPoint.X = x; + mCurrentPoint.Y = y; +} + +inline void PathC::CurveTo(float x1, float y1, float x2, float y2, float x, float y) +{ + mPath->AddBezier(mCurrentPoint.X, mCurrentPoint.Y, // startpoint + x1, y1, x2, y2, // controlpoints + x, y); // endpoint + mCurrentPoint.X = x; + mCurrentPoint.Y = y; +} + +inline void PathC::AddRectangle(float x, float y, float width, float height) +{ + RectF rect(x, y, width, height); + mPath->AddRectangle(rect); + // @@@ TODO: this depends + mCurrentPoint.X = x; + mCurrentPoint.Y = y; +} + +inline void PathC::AddEllipse(float cx, float cy, float rx, float ry) +{ + mPath->AddEllipse(cx-rx, cy-ry, 2*rx, 2*ry); + // @@@ TODO: this depends + mCurrentPoint.X = cx+rx; + mCurrentPoint.Y = cy; +} + +inline void PathC::DrawImage(Tk_PhotoHandle photo, float x, float y, float width, float height) +{ + Tk_PhotoImageBlock block; + PixelFormat format; + INT stride; + int iwidth, iheight; + int pitch; + int smallEndian = 1; /* Hardcoded. */ + unsigned char *data = NULL; + unsigned char *ptr = NULL; + unsigned char *srcPtr, *dstPtr; + int srcR, srcG, srcB, srcA; /* The source pixel offsets. */ + int dstR, dstG, dstB, dstA; /* The destination pixel offsets. */ + int i, j; + + Tk_PhotoGetImage(photo, &block); + iwidth = block.width; + iheight = block.height; + stride = block.pitch; + pitch = block.pitch; + if (width == 0.0) { + width = (float) iwidth; + } + if (height == 0.0) { + height = (float) iheight; + } + + if (block.pixelSize*8 == 32) { + format = PixelFormat32bppARGB; + + srcR = block.offset[0]; + srcG = block.offset[1]; + srcB = block.offset[2]; + srcA = block.offset[3]; + dstR = 1; + dstG = 2; + dstB = 3; + dstA = 0; + if (smallEndian) { + dstR = 3-dstR, dstG = 3-dstG, dstB = 3-dstB, dstA = 3-dstA; + } + if ((srcR == dstR) && (srcG == dstG) && (srcB == dstB) && (srcA == dstA)) { + ptr = (unsigned char *) block.pixelPtr; + } else { + data = (unsigned char *) ckalloc(pitch*iheight); + ptr = data; + + for (i = 0; i < iheight; i++) { + srcPtr = block.pixelPtr + i*pitch; + dstPtr = ptr + i*pitch; + for (j = 0; j < iwidth; j++) { + *(dstPtr+dstR) = *(srcPtr+srcR); + *(dstPtr+dstG) = *(srcPtr+srcG); + *(dstPtr+dstB) = *(srcPtr+srcB); + *(dstPtr+dstA) = *(srcPtr+srcA); + srcPtr += 4; + dstPtr += 4; + } + } + } + } else if (block.pixelSize*8 == 24) { + /* Could do something about this? */ + return; + } else { + return; + } + Bitmap bitmap(iwidth, iheight, stride, format, (BYTE *)ptr); + mGraphics->DrawImage(&bitmap, x, y, width, height); + if (data) { + ckfree((char *)data); + } +} + +inline void PathC::DrawString(Tk_PathStyle *style, Tk_PathTextStyle *textStylePtr, + float x, float y, char *utf8) +{ + Tcl_DString ds, dsFont; + Tcl_UniChar *uniPtr; + + Tcl_DStringInit(&dsFont); + FontFamily fontFamily((const WCHAR *)Tcl_UtfToUniCharDString(textStylePtr->fontFamily, -1, &dsFont)); + if (fontFamily.GetLastStatus() != Ok) { + fontFamily.GenericSansSerif(); + } + Gdiplus::Font font(&fontFamily, (float) textStylePtr->fontSize, FontStyleRegular, UnitPixel); + if (font.GetLastStatus() != Ok) { + // TODO + } + Tcl_DStringFree(&dsFont); + Tcl_DStringInit(&ds); + uniPtr = Tcl_UtfToUniCharDString(utf8, -1, &ds); + + /* The fourth argument is a PointF object that contains the + * coordinates of the upper-left corner of the string. + * See GDI+ docs and the FontFamily for translating between + * design units and pixels. + */ + float ascentPixels = font.GetSize() * + fontFamily.GetCellAscent(FontStyleRegular) / fontFamily.GetEmHeight(FontStyleRegular); + PointF point(x, y - ascentPixels); + if (gAntiAlias) { + mGraphics->SetTextRenderingHint(TextRenderingHintAntiAlias); + } + if (GetColorFromPathColor(style->fill) != NULL) { + SolidBrush *brush = PathCreateBrush(style); + mGraphics->DrawString((const WCHAR *)uniPtr, Tcl_UniCharLen(uniPtr), &font, point, brush); + delete brush; + } + if (style->strokeColor != NULL) { + Pen *pen = PathCreatePen(style); + mPath->AddString((const WCHAR *)uniPtr, Tcl_UniCharLen(uniPtr), + &fontFamily, FontStyleRegular, (float) textStylePtr->fontSize, point, NULL); + mGraphics->DrawPath(pen, mPath); + delete pen; + } + Tcl_DStringFree(&ds); +} + +inline void PathC::CloseFigure() +{ + mPath->CloseFigure(); + mCurrentPoint.X = mOrigin.X; + mCurrentPoint.Y = mOrigin.Y; +} + +inline void PathC::Stroke(Tk_PathStyle *style) +{ + Pen *pen = PathCreatePen(style); + mGraphics->DrawPath(pen, mPath); + delete pen; +} + +inline void PathC::Fill(Tk_PathStyle *style) +{ + SolidBrush *brush = PathCreateBrush(style); + mGraphics->FillPath(brush, mPath); + delete brush; +} + +inline void PathC::FillAndStroke(Tk_PathStyle *style) +{ + Pen *pen = PathCreatePen(style); + SolidBrush *brush = PathCreateBrush(style); + mGraphics->FillPath(brush, mPath); + mGraphics->DrawPath(pen, mPath); + delete pen; + delete brush; +} + +inline void PathC::GetCurrentPoint(PointF *pt) +{ + *pt = mCurrentPoint; +} + +void PathC::FillLinearGradient(PathRect *bbox, LinearGradientFill *fillPtr, int fillRule, TMatrix *mPtr) +{ + int i; + int nstops; + float x, y, width, height; + GradientStop *stop; + GradientStopArray *stopArrPtr; + PathRect *tPtr; + PointF p1, p2, pstart, pend; + + stopArrPtr = fillPtr->stopArrPtr; + nstops = stopArrPtr->nstops; + tPtr = fillPtr->transitionPtr; + + GraphicsContainer container = mGraphics->BeginContainer(); + /* + * We need to do like this since this is how SVG defines gradient drawing + * in case the transition vector is in relative coordinates. + */ + if (fillPtr->units == kPathGradientUnitsBoundingBox) { + x = float(bbox->x1); + y = float(bbox->y1); + width = float(bbox->x2 - bbox->x1); + height = float(bbox->y2 - bbox->y1); + p1.X = float(x + tPtr->x1*width); + p1.Y = float(y + tPtr->y1*height); + p2.X = float(x + tPtr->x2*width); + p2.Y = float(y + tPtr->y2*height); + } else { + p1.X = float(tPtr->x1); + p1.Y = float(tPtr->y1); + p2.X = float(tPtr->x2); + p2.Y = float(tPtr->y2); + } + stop = stopArrPtr->stops[0]; + Color col1(MakeGDIPlusColor(stop->color, stop->opacity)); + stop = stopArrPtr->stops[nstops-1]; + Color col2(MakeGDIPlusColor(stop->color, stop->opacity)); + if (fillPtr->method == kPathGradientMethodPad) { + /* + * GDI+ seems to miss a simple way to pad with constant colors. + * NB: This trick assumes no -matrix! + */ + float length = float(hypot(p1.X - p2.X, p1.Y - p2.Y)); + int singular = 0; + if (length < 1e-6) { + /* @@@ p1 and p2 essentially coincide. + * Not sure what is the standard fallback here since + * we get no direction. Pick the x direction and make + * essentially a two color painting. + */ + singular = 1; + } + /* We need to put up two extra points that are outside + * the bounding rectangle so that when used for gradient + * start and stop points it will cover the bbox. + */ + int npts = nstops + 2; + Color *col = new Color[npts]; + REAL *pos = new REAL[npts]; + + /* We do the painting within a rectangle which is normally + * the bounding box but if we do padding and have a gradient + * transform we pick a "large enough" rectangle. + */ + PointF corner[4]; + if (mPtr) { + corner[0].X = 0.0f; + corner[0].Y = 0.0f; + corner[1].X = 10000.0f; + corner[1].Y = 0.0f; + corner[2].X = 10000.0f; + corner[2].Y = 10000.0f; + corner[3].X = 0.0f; + corner[3].Y = 10000.0f; + } else { + corner[0].X = float(bbox->x1); + corner[0].Y = float(bbox->y1); + corner[1].X = float(bbox->x2); + corner[1].Y = float(bbox->y1); + corner[2].X = float(bbox->x2); + corner[2].Y = float(bbox->y2); + corner[3].X = float(bbox->x1); + corner[3].Y = float(bbox->y2); + } + /* The normalized transition vector as pn */ + PointF pn; + if (singular) { + pn.X = 1; + pn.Y = 0; + } else { + pn = p2 - p1; + pn.X /= length; + pn.Y /= length; + } + + /* To find the start point we need to find the minimum + * projection of the vector corner_i - p1 along pn. + * Only if this is negative we need to extend the start point from p1. + */ + PointF ptmp; + float min = 1e+6, max = -1e6; + float dist; + for (i = 0; i < 4; i++) { + ptmp = corner[i] - p1; + dist = ptmp.X*pn.X + ptmp.Y*pn.Y; + if (dist < min) { + min = dist; + } + } + if (min < 0) { + pstart.X = p1.X + min * pn.X; + pstart.Y = p1.Y + min * pn.Y; + } else { + pstart = p1; + min = 0; + } + + /* Do the same for the end point but use p2 instead of p1 and find max. */ + for (i = 0; i < 4; i++) { + ptmp = corner[i] - p2; + dist = ptmp.X*pn.X + ptmp.Y*pn.Y; + if (dist > max) { + max = dist; + } + } + if (max > 0) { + pend.X = p2.X + max * pn.X; + pend.Y = p2.Y + max * pn.Y; + } else { + pend = p2; + max = 0; + } + LinearGradientBrush brush(pstart, pend, col1, col2); + col[0] = col1; + col[npts-1] = col2; + pos[0] = 0.0; + pos[npts-1] = 1.0; + + /* Since we now have artificially extended the gradient transition + * we also need to rescale the (relative) stops values using + * this extended transition: + * |min| + offset * length + * new offset = ----------------------- + * |min| + length + |max| + */ + + float den = fabs(min) + length + fabs(max); + for (i = 0; i < nstops; i++) { + stop = stopArrPtr->stops[i]; + col[i+1] = MakeGDIPlusColor(stop->color, stop->opacity); + pos[i+1] = (fabs(min) + REAL(stop->offset) * length)/den; + } + if (mPtr) { + /* @@@ Not sure in which coord system we should do this. */ + Matrix m(float(mPtr->a), float(mPtr->b), float(mPtr->c), float(mPtr->d), float(mPtr->tx), float(mPtr->ty)); + brush.MultiplyTransform(&m); + } + brush.SetInterpolationColors(col, pos, npts); + mGraphics->FillPath(&brush, mPath); + delete [] col; + delete [] pos; + } else { + LinearGradientBrush brush(p1, p2, col1, col2); + if (fillPtr->method == kPathGradientMethodReflect) { + brush.SetWrapMode(WrapModeTileFlipXY); + } + if (mPtr) { + Matrix m(float(mPtr->a), float(mPtr->b), float(mPtr->c), float(mPtr->d), float(mPtr->tx), float(mPtr->ty)); + brush.MultiplyTransform(&m); + } + Color *col = new Color[nstops]; + REAL *pos = new REAL[nstops]; + for (i = 0; i < nstops; i++) { + stop = stopArrPtr->stops[i]; + col[i] = MakeGDIPlusColor(stop->color, stop->opacity); + pos[i] = REAL(stop->offset); + } + brush.SetInterpolationColors(col, pos, nstops); + mGraphics->FillPath(&brush, mPath); + delete [] col; + delete [] pos; + } + mGraphics->EndContainer(container); +} + +void PathC::FillRadialGradient( + PathRect *bbox, /* The items bounding box in untransformed coords. */ + RadialGradientFill *fillPtr, int fillRule, TMatrix *mPtr) +{ + int i; + int nstops; + float width, height; + GradientStop *stop; + GradientStopArray *stopArrPtr; + RadialTransition *tPtr; + PointF center, radius, focal; + + stopArrPtr = fillPtr->stopArrPtr; + nstops = stopArrPtr->nstops; + tPtr = fillPtr->radialPtr; + + /* + * We need to do like this since this is how SVG defines gradient drawing + * in case the transition vector is in relative coordinates. + */ + width = float(bbox->x2 - bbox->x1); + height = float(bbox->y2 - bbox->y1); + if (fillPtr->units == kPathGradientUnitsBoundingBox) { + center.X = float(bbox->x1 + width * tPtr->centerX); + center.Y = float(bbox->y1 + height * tPtr->centerY); + radius.X = float(width * tPtr->radius); + radius.Y = float(height * tPtr->radius); + focal.X = float(bbox->x1 + width * tPtr->focalX); + focal.Y = float(bbox->y1 + height * tPtr->focalY); + } else { + center.X = float(tPtr->centerX); + center.Y = float(tPtr->centerY); + radius.X = float(tPtr->radius); + radius.Y = float(tPtr->radius); + focal.X = float(tPtr->focalX); + focal.Y = float(tPtr->focalY); + } + GraphicsContainer container = mGraphics->BeginContainer(); + mGraphics->SetClip(mPath); + // @@@ Extend the transition instead like we did for liner gradients above. + stop = stopArrPtr->stops[nstops-1]; + SolidBrush solidBrush(MakeGDIPlusColor(stop->color, stop->opacity)); + mGraphics->FillPath(&solidBrush, mPath); + + /* This is a special trick to make a radial gradient pattern. + * Make an ellipse and use a PathGradientBrush. + */ + GraphicsPath path; + path.AddEllipse(center.X - radius.X, center.Y - radius.Y, 2*radius.X, 2*radius.Y); + PathGradientBrush brush(&path); + if (mPtr) { + Matrix m(float(mPtr->a), float(mPtr->b), float(mPtr->c), float(mPtr->d), float(mPtr->tx), float(mPtr->ty)); + brush.MultiplyTransform(&m); + } + stop = stopArrPtr->stops[0]; + brush.SetCenterColor(MakeGDIPlusColor(stop->color, stop->opacity)); + brush.SetCenterPoint(focal); + int count = 1; + stop = stopArrPtr->stops[nstops-1]; + Color color = MakeGDIPlusColor(stop->color, stop->opacity); + brush.SetSurroundColors(&color, &count); + + /* gdi+ counts them from the border and not from the center. */ + Color *col = new Color[nstops]; + REAL *pos = new REAL[nstops]; + for (i = nstops-1; i >= 0; i--) { + stop = stopArrPtr->stops[i]; + col[i] = MakeGDIPlusColor(stop->color, stop->opacity); + pos[i] = REAL(1.0 - stop->offset); + } + brush.SetInterpolationColors(col, pos, nstops); + mGraphics->FillPath(&brush, &path); + mGraphics->EndContainer(container); + delete [] col; + delete [] pos; +} + +/* + * Exit procedure for Tcl. + */ + +void PathExit(ClientData clientData) +{ + if (sGdiplusStarted) { + GdiplusShutdown(sGdiplusToken); + } +} + +/* === EB - 23-apr-2010: added function to register coordinate offsets; unneeded here (?) */ +void TkPathSetCoordOffsets(double dx, double dy) +{ +} +/* === */ + +/* + * Standard tkpath interface. + * More or less a wrapper for the class PathC. + * Is there a smarter way? + */ + +TkPathContext TkPathInit(Tk_Window tkwin, Drawable d) +{ + TkPathContext_ *context = reinterpret_cast<TkPathContext_ *> (ckalloc((unsigned) (sizeof(TkPathContext_)))); + TkWinDrawable *twdPtr = (TkWinDrawable *) d; + HDC memHdc; + //TkWinDrawable *twdPtr = reinterpret_cast<TkWinDrawable*>(d); + /* from tile + TkWinDCState dcState; + HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState); + ... + TkWinReleaseDrawableDC(d, hdc, &dcState); + */ + + /* This will only work for bitmaps; need something else! TkWinGetDrawableDC()? */ + memHdc = CreateCompatibleDC(NULL); + SelectObject(memHdc, twdPtr->bitmap.handle); + context->c = new PathC(memHdc); + context->memHdc = memHdc; + context->surface = NULL; + return (TkPathContext) context; +} + +TkPathContext TkPathInitSurface(int width, int height) +{ + TkPathContext_ *context = reinterpret_cast<TkPathContext_ *> (ckalloc((unsigned) (sizeof(TkPathContext_)))); + PathSurfaceGDIpRecord *surface = (PathSurfaceGDIpRecord *) ckalloc((unsigned) (sizeof(PathSurfaceGDIpRecord))); + HBITMAP hbm = NULL; + HDC memHdc = NULL; + BITMAPINFO *bmInfo = NULL; + void *data; + + memHdc = CreateCompatibleDC(NULL); + + /* We create off-screen surfaces as DIBs */ + bmInfo = (BITMAPINFO *) ckalloc(sizeof(BITMAPINFO)); + bmInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmInfo->bmiHeader.biWidth = width; + bmInfo->bmiHeader.biHeight = -(int) height; + bmInfo->bmiHeader.biPlanes = 1; + bmInfo->bmiHeader.biBitCount = 32; + bmInfo->bmiHeader.biCompression = BI_RGB; + bmInfo->bmiHeader.biSizeImage = 0; + bmInfo->bmiHeader.biXPelsPerMeter = + static_cast<LONG>(72. / 0.0254); /* unused here */ + bmInfo->bmiHeader.biYPelsPerMeter = + static_cast<LONG>(72. / 0.0254); /* unused here */ + bmInfo->bmiHeader.biClrUsed = 0; + bmInfo->bmiHeader.biClrImportant = 0; + + hbm = CreateDIBSection(memHdc, bmInfo, DIB_RGB_COLORS, &data, NULL, 0); + if (!hbm) { + Tcl_Panic("CreateDIBSection"); + } + SelectObject(memHdc, hbm); + + surface->bitmap = hbm; + surface->width = width; + surface->data = data; + surface->width = width; + surface->height = height; + /* Windows bitmaps are padded to 16-bit (word) boundaries */ + surface->bytesPerRow = 4*width; + + context->c = new PathC(memHdc); + context->memHdc = memHdc; + context->surface = surface; + if (bmInfo) { + ckfree((char *) bmInfo); + } + return (TkPathContext) context; +} + +void TkPathPushTMatrix(TkPathContext ctx, TMatrix *m) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + if (m == NULL) { + return; + } + context->c->PushTMatrix(m); +} + +void TkPathSaveState(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->SaveState(); +} + +void TkPathRestoreState(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->RestoreState(); +} + +void TkPathBeginPath(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->BeginPath(style); +} + +void TkPathMoveTo(TkPathContext ctx, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->MoveTo((float) x, (float) y); +} + +void TkPathLineTo(TkPathContext ctx, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->LineTo((float) x, (float) y); +} + +void TkPathLinesTo(TkPathContext ctx, double *pts, int n) +{ + /* @@@ TODO */ +} + +void TkPathQuadBezier(TkPathContext ctx, double ctrlX, double ctrlY, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + double x31, y31, x32, y32; + PointF cp; + + context->c->GetCurrentPoint(&cp); + // conversion of quadratic bezier curve to cubic bezier curve: (mozilla/svg) + /* Unchecked! Must be an approximation! */ + x31 = cp.X + (ctrlX - cp.X) * 2 / 3; + y31 = cp.Y + (ctrlY - cp.Y) * 2 / 3; + x32 = ctrlX + (x - ctrlX) / 3; + y32 = ctrlY + (y - ctrlY) / 3; + context->c->CurveTo((float) x31, (float) y31, (float) x32, (float) y32, (float) x, (float) y); +} + +void TkPathCurveTo(TkPathContext ctx, double ctrlX1, double ctrlY1, + double ctrlX2, double ctrlY2, double x, double y) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->CurveTo((float) ctrlX1, (float) ctrlY1, (float) ctrlX2, (float) ctrlY2, (float) x, (float) y); +} + + +void TkPathArcTo(TkPathContext ctx, + double rx, double ry, + double phiDegrees, /* The rotation angle in degrees! */ + char largeArcFlag, char sweepFlag, double x, double y) +{ + TkPathArcToUsingBezier(ctx, rx, ry, phiDegrees, largeArcFlag, sweepFlag, x, y); +} + +void +TkPathRect(TkPathContext ctx, double x, double y, double width, double height) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->AddRectangle((float) x, (float) y, (float) width, (float) height); +} + +void +TkPathOval(TkPathContext ctx, double cx, double cy, double rx, double ry) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->AddEllipse((float) cx, (float) cy, (float) rx, (float) ry); +} + +void +TkPathImage(TkPathContext ctx, Tk_Image image, Tk_PhotoHandle photo, + double x, double y, double width, double height) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->DrawImage(photo, (float) x, (float) y, (float) width, (float) height); +} + +void +TkPathClosePath(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->CloseFigure(); +} + +int +TkPathTextConfig(Tcl_Interp *interp, Tk_PathTextStyle *textStylePtr, char *utf8, void **customPtr) +{ + // @@@ We could think of having the FontFamily and Gdiplus::Font cached in custom. + return TCL_OK; +} + +void +TkPathTextDraw(TkPathContext ctx, Tk_PathStyle *style, Tk_PathTextStyle *textStylePtr, double x, double y, char *utf8, void *custom) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->DrawString(style, textStylePtr, (float) x, (float) y, utf8); +} + +void +TkPathTextFree(Tk_PathTextStyle *textStylePtr, void *custom) +{ + /* Empty. */ +} + +PathRect +TkPathTextMeasureBbox(Tk_PathTextStyle *textStylePtr, char *utf8, void *custom) +{ + HDC memHdc; + Tcl_DString ds, dsFont; + Tcl_UniChar *uniPtr = NULL; + PointF origin(0.0f, 0.0f); + RectF bounds; + PathRect r = {-1, -1, -1, -1}; + double ascent; + Graphics *graphics = NULL; + + if (!sGdiplusStarted) { + InitGDIplus(); + } + memHdc = CreateCompatibleDC(NULL); + /* @@@ I thought this was needed but seems not. + HBITMAP bm = CreateCompatibleBitmap(memHdc, 10, 10); + SelectObject(memHdc, bm); + */ + graphics = new Graphics(memHdc); + + Tcl_DStringInit(&dsFont); + FontFamily fontFamily((const WCHAR *)Tcl_UtfToUniCharDString(textStylePtr->fontFamily, -1, &dsFont)); + if (fontFamily.GetLastStatus() != Ok) { + fontFamily.GenericSansSerif(); + } + Gdiplus::Font font(&fontFamily, (float) textStylePtr->fontSize, FontStyleRegular, UnitPixel); + if (font.GetLastStatus() != Ok) { + // TODO + } + Tcl_DStringFree(&dsFont); + Tcl_DStringInit(&ds); + uniPtr = Tcl_UtfToUniCharDString(utf8, -1, &ds); + graphics->MeasureString((const WCHAR *)uniPtr, Tcl_UniCharLen(uniPtr), &font, origin, &bounds); + Tcl_DStringFree(&ds); + ascent = font.GetSize() * + fontFamily.GetCellAscent(FontStyleRegular) / fontFamily.GetEmHeight(FontStyleRegular); + r.x1 = 0.0; + r.y1 = -ascent; + r.x2 = bounds.Width; + r.y2 = bounds.Height - ascent; + delete graphics; + // DeleteObject(bm); + DeleteDC(memHdc); + return r; +} + +void +TkPathSurfaceErase(TkPathContext ctx, double dx, double dy, double dwidth, double dheight) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + PathSurfaceGDIpRecord *surface = context->surface; + unsigned char *data, *dst; + int i; + int x, y, width, height; + int xend, yend; + int bytesPerRow; + int bwidth; + + width = surface->width; + height = surface->height; + data = (unsigned char *)surface->data; + bytesPerRow = surface->bytesPerRow; + + x = (int) (dx + 0.5); + y = (int) (dy + 0.5); + width = (int) (dwidth + 0.5); + height = (int) (dheight + 0.5); + x = MAX(0, MIN(context->surface->width, x)); + y = MAX(0, MIN(context->surface->height, y)); + width = MAX(0, width); + height = MAX(0, height); + xend = MIN(x + width, context->surface->width); + yend = MIN(y + height, context->surface->height); + bwidth = 4*(xend - x); + + for (i = y; i < yend; i++) { + dst = data + i*bytesPerRow + 4*x; + memset(dst, '\0', bwidth); + } +} + +void +TkPathSurfaceToPhoto(Tcl_Interp *interp, TkPathContext ctx, Tk_PhotoHandle photo) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + PathSurfaceGDIpRecord *surface = context->surface; + Tk_PhotoImageBlock block; + unsigned char *data; + unsigned char *pixel; + int width, height; + int bytesPerRow; + + width = surface->width; + height = surface->height; + data = (unsigned char *)surface->data; + bytesPerRow = surface->bytesPerRow; + + Tk_PhotoGetImage(photo, &block); + pixel = (unsigned char *)ckalloc(height*bytesPerRow); + if (gSurfaceCopyPremultiplyAlpha) { + PathCopyBitsPremultipliedAlphaBGRA(data, pixel, width, height, bytesPerRow); + } else { + PathCopyBitsBGRA(data, pixel, width, height, bytesPerRow); + } + block.pixelPtr = pixel; + block.width = width; + block.height = height; + block.pitch = bytesPerRow; + block.pixelSize = 4; + block.offset[0] = 0; + block.offset[1] = 1; + block.offset[2] = 2; + block.offset[3] = 3; + Tk_PhotoPutBlock(interp, photo, &block, 0, 0, width, height, TK_PHOTO_COMPOSITE_OVERLAY); +} + +void +TkPathEndPath(TkPathContext ctx) +{ + // @@@ empty ? +} + +void +TkPathFree(TkPathContext ctx) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + DeleteDC(context->memHdc); + if (context->surface) { + DeleteObject(context->surface->bitmap); + ckfree((char *) context->surface); + } + delete context->c; + ckfree((char *) context); +} + +void TkPathClipToPath(TkPathContext ctx, int fillRule) +{ + /* empty */ +} + +void TkPathReleaseClipToPath(TkPathContext ctx) +{ + /* empty */ +} + +void TkPathStroke(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->Stroke(style); +} + +void TkPathFill(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->Fill(style); +} + +void TkPathFillAndStroke(TkPathContext ctx, Tk_PathStyle *style) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->FillAndStroke(style); +} + +int TkPathGetCurrentPosition(TkPathContext ctx, PathPoint *ptPtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + PointF pf; + context->c->GetCurrentPoint(&pf); + ptPtr->x = (double) pf.X; + ptPtr->y = (double) pf.Y; + return TCL_OK; +} + +int TkPathDrawingDestroysPath(void) +{ + return 0; +} +int +TkPathPixelAlign(void) +{ + return 1; +} + +/* @@@ INCOMPLETE! We need to consider any padding as well. */ + +void TkPathPaintLinearGradient(TkPathContext ctx, PathRect *bbox, LinearGradientFill *fillPtr, int fillRule, TMatrix *mPtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->FillLinearGradient(bbox, fillPtr, fillRule, mPtr); +} + +void +TkPathPaintRadialGradient(TkPathContext ctx, PathRect *bbox, RadialGradientFill *fillPtr, int fillRule, TMatrix *mPtr) +{ + TkPathContext_ *context = (TkPathContext_ *) ctx; + context->c->FillRadialGradient(bbox, fillPtr, fillRule, mPtr); +} + + diff --git a/pd/tkpath/win/tkpath/Debug/tkpath030.dll b/pd/tkpath/win/tkpath/Debug/tkpath030.dll new file mode 100755 index 0000000000000000000000000000000000000000..a0e9ac32a57d3b877178f3e8b5ac5b3e4d9f4dd2 Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpath030.dll differ diff --git a/pd/tkpath/win/tkpath/Debug/tkpath031.dll b/pd/tkpath/win/tkpath/Debug/tkpath031.dll new file mode 100755 index 0000000000000000000000000000000000000000..37cb65075d2ad558bf5cdef624078c57420a5d06 Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpath031.dll differ diff --git a/pd/tkpath/win/tkpath/Debug/tkpathgdi01.dll b/pd/tkpath/win/tkpath/Debug/tkpathgdi01.dll new file mode 100644 index 0000000000000000000000000000000000000000..d507acbe49c3dbca59fc925521e292d8c5a23f13 Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpathgdi01.dll differ diff --git a/pd/tkpath/win/tkpath/Debug/tkpathgdi02.dll b/pd/tkpath/win/tkpath/Debug/tkpathgdi02.dll new file mode 100755 index 0000000000000000000000000000000000000000..20f93d9f4d1ce97c9a13431fab630df8652f2bd2 Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpathgdi02.dll differ diff --git a/pd/tkpath/win/tkpath/Debug/tkpathgdi024.dll b/pd/tkpath/win/tkpath/Debug/tkpathgdi024.dll new file mode 100755 index 0000000000000000000000000000000000000000..851835b27494f2c1190f66de41ead75618328503 Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpathgdi024.dll differ diff --git a/pd/tkpath/win/tkpath/Debug/tkpathgdiplus01.dll b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus01.dll new file mode 100644 index 0000000000000000000000000000000000000000..837c11f29bf5528f0e69638e2a61dcb67edc0147 Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus01.dll differ diff --git a/pd/tkpath/win/tkpath/Debug/tkpathgdiplus02.dll b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus02.dll new file mode 100755 index 0000000000000000000000000000000000000000..8354a5a904cfc0728f8f939f0ea7b306820dfcb4 Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus02.dll differ diff --git a/pd/tkpath/win/tkpath/Debug/tkpathgdiplus022.dll b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus022.dll new file mode 100755 index 0000000000000000000000000000000000000000..93805ebae7cdce312883c410b750908cc2f0c823 Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus022.dll differ diff --git a/pd/tkpath/win/tkpath/Debug/tkpathgdiplus024.dll b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus024.dll new file mode 100755 index 0000000000000000000000000000000000000000..e77957e46d9e84a733a6555c4442424b771c9a92 Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus024.dll differ diff --git a/pd/tkpath/win/tkpath/Debug/tkpathgdiplus026.dll b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus026.dll new file mode 100755 index 0000000000000000000000000000000000000000..835ccf3ce0c47a7428bd95fa5f85dbcdbaf9196c Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus026.dll differ diff --git a/pd/tkpath/win/tkpath/Debug/tkpathgdiplus028.dll b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus028.dll new file mode 100755 index 0000000000000000000000000000000000000000..14044cc7d5d6d8e5fd243c9f392d0f1115e3121b Binary files /dev/null and b/pd/tkpath/win/tkpath/Debug/tkpathgdiplus028.dll differ diff --git a/pd/tkpath/win/tkpath/tkpathgdiplus.vcproj b/pd/tkpath/win/tkpath/tkpathgdiplus.vcproj new file mode 100644 index 0000000000000000000000000000000000000000..28024524de627329908ce1c2677065418963f7dc --- /dev/null +++ b/pd/tkpath/win/tkpath/tkpathgdiplus.vcproj @@ -0,0 +1,261 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="tkpathgdiplus" + ProjectGUID="{C60CE4AB-3D29-4CDC-9D1D-362B97B38535}" + RootNamespace="tkpath" + Keyword="Win32Proj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="2" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\generic;..\..\..\tcl\win;..\..\..\tcl\generic;..\..\..\tk\generic;..\..\..\tk\win;..\..\..\tk\xlib" + PreprocessorDefinitions="USE_TCL_STUBS;USE_TK_STUBS" + MinimalRebuild="TRUE" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="4"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="tclstub85.lib tkstub85.lib gdiplus.lib" + OutputFile="$(OutDir)/tkpath031.dll" + LinkIncremental="2" + AdditionalLibraryDirectories="C:\Tcl\lib" + GenerateDebugInformation="TRUE" + ProgramDatabaseFile="$(OutDir)/tkpath.pdb" + SubSystem="2" + ImportLibrary="$(OutDir)/tkpath.lib" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="2" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..\generic;..\..\..\tcl\win;..\..\..\tcl\generic;..\..\..\tk\generic;..\..\..\tk\win;..\..\..\tk\xlib" + PreprocessorDefinitions="USE_TCL_STUBS;USE_TK_STUBS" + RuntimeLibrary="0" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="tclstub85.lib tkstub85.lib gdiplus.lib" + OutputFile="$(OutDir)/tkpath031.dll" + LinkIncremental="1" + AdditionalLibraryDirectories="C:\Tcl\lib" + GenerateDebugInformation="TRUE" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + ImportLibrary="$(OutDir)/tkpath.lib" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> + <File + RelativePath="..\..\generic\path.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvEllipse.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvGradient.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvGroup.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvPath.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvPathUtil.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvPimage.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvPline.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvPpoly.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvPrect.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvPtext.c"> + </File> + <File + RelativePath="..\..\generic\tkCanvStyle.c"> + </File> + <File + RelativePath="..\..\generic\tkPath.c"> + </File> + <File + RelativePath="..\..\generic\tkPathGradient.c"> + </File> + <File + RelativePath="..\..\generic\tkPathStyle.c"> + </File> + <File + RelativePath="..\..\generic\tkPathSurface.c"> + </File> + <File + RelativePath="..\..\generic\tkPathUtil.c"> + </File> + <File + RelativePath="..\..\generic\tkpCanvArc.c"> + </File> + <File + RelativePath="..\..\generic\tkpCanvas.c"> + </File> + <File + RelativePath="..\..\generic\tkpCanvBmap.c"> + </File> + <File + RelativePath="..\..\generic\tkpCanvImg.c"> + </File> + <File + RelativePath="..\..\generic\tkpCanvLine.c"> + </File> + <File + RelativePath="..\..\generic\tkpCanvPoly.c"> + </File> + <File + RelativePath="..\..\generic\tkpCanvPs.c"> + </File> + <File + RelativePath="..\..\generic\tkpCanvText.c"> + </File> + <File + RelativePath="..\..\generic\tkpCanvUtil.c"> + </File> + <File + RelativePath="..\..\generic\tkpCanvWind.c"> + </File> + <File + RelativePath="..\..\generic\tkpRectOval.c"> + </File> + <File + RelativePath="..\..\generic\tkpTrig.c"> + </File> + <File + RelativePath="..\..\generic\tkpUtil.c"> + </File> + <File + RelativePath="..\tkWinGDIPlusPath.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)/$(InputName)1.obj"/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + <File + RelativePath="..\..\generic\tkCanvPathUtil.h"> + </File> + <File + RelativePath="..\..\generic\tkIntPath.h"> + </File> + <File + RelativePath="..\..\generic\tkp.h"> + </File> + <File + RelativePath="..\..\generic\tkPath.h"> + </File> + <File + RelativePath="..\..\generic\tkPathStyle.h"> + </File> + <File + RelativePath="..\..\generic\tkpCanvas.h"> + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/pd/tkpath/win/version.vc b/pd/tkpath/win/version.vc new file mode 100755 index 0000000000000000000000000000000000000000..5e0036de65ad360c1f643897328084b30d9d2635 --- /dev/null +++ b/pd/tkpath/win/version.vc @@ -0,0 +1,4 @@ +TCL_DOTVERSION = 8.5 +TCL_VERSION = 85 +TK_DOTVERSION = 8.5 +TK_VERSION = 85