Browse Source

punk8win.vfs add tklib08, punk::nav::fs fixes, add tar to bootsupport

master
Julian Noble 9 months ago
parent
commit
22e93659ed
  1. 186
      src/bootsupport/lib/tar/ChangeLog
  2. 5
      src/bootsupport/lib/tar/pkgIndex.tcl
  3. 202
      src/bootsupport/lib/tar/tar.man
  4. 83
      src/bootsupport/lib/tar/tar.pcx
  5. 550
      src/bootsupport/lib/tar/tar.tcl
  6. 139
      src/bootsupport/lib/tar/tar.test
  7. 149
      src/bootsupport/lib/tar/tests/support.tcl
  8. 33
      src/bootsupport/modules/punk/nav/fs-0.1.0.tm
  9. 33
      src/modules/punk/nav/fs-999999.0a1.0.tm
  10. 33
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm
  11. 33
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm
  12. 2
      src/runtime/mapvfs.config
  13. 212
      src/vfs/_vfscommon/modules/punk/du-0.1.0.tm
  14. 120
      src/vfs/_vfscommon/modules/punk/nav/fs-0.1.0.tm
  15. 2
      src/vfs/_vfscommon/modules/punk/winlnk-0.1.0.tm
  16. 238
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/autoscroll/autoscroll.tcl
  17. 13
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/autoscroll/pkgIndex.tcl
  18. 278
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_drag.tcl
  19. 383
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_ecircle.tcl
  20. 453
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_epoints.tcl
  21. 660
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_epolyline.tcl
  22. 400
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_equad.tcl
  23. 452
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_erectangle.tcl
  24. 278
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_gradient.tcl
  25. 106
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_highlight.tcl
  26. 392
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_mvg.tcl
  27. 111
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_snap.tcl
  28. 667
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_sqmap.tcl
  29. 70
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_tags.tcl
  30. 95
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_trlines.tcl
  31. 181
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_zoom.tcl
  32. 16
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/pkgIndex.tcl
  33. 777
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/chatwidget/chatwidget.tcl
  34. 1
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/chatwidget/pkgIndex.tcl
  35. 45
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/bindDown.tcl
  36. 17
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/controlwidget.tcl
  37. 127
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/led.tcl
  38. 23
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/pkgIndex.tcl
  39. 253
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/radioMatrix.tcl
  40. 455
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/rdial.tcl
  41. 389
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/tachometer.tcl
  42. 1458
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/vertical_meter.tcl
  43. 347
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/voltmeter.tcl
  44. 598
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/crosshair/crosshair.tcl
  45. 4
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/crosshair/pkgIndex.tcl
  46. 1113
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ctext/ctext.tcl
  47. 1
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ctext/pkgIndex.tcl
  48. 137
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/cursor/cursor.tcl
  49. 1
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/cursor/pkgIndex.tcl
  50. 456
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/datefield/datefield.tcl
  51. 1
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/datefield/pkgIndex.tcl
  52. 470
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/application.tcl
  53. 383
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/attributes.tcl
  54. 1279
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/basic.tcl
  55. 1120
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/core.tcl
  56. 62
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/diagram.tcl
  57. 254
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/direction.tcl
  58. 298
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/element.tcl
  59. 138
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/navigation.tcl
  60. 15
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/pkgIndex.tcl
  61. 184
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/point.tcl
  62. 13
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/getstring/pkgIndex.tcl
  63. 124
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/getstring/tk_getString.tcl
  64. 113
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/history/history.tcl
  65. 13
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/history/pkgIndex.tcl
  66. 1467
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ico/ico.tcl
  67. 1193
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ico/ico0.tcl
  68. 9
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ico/pkgIndex.tcl
  69. 975
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ipentry/ipentry.tcl
  70. 3
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ipentry/pkgIndex.tcl
  71. 74
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/ROOT.msg
  72. 108
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/cs.msg
  73. 104
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/da.msg
  74. 123
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/de.msg
  75. 114
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/en.msg
  76. 108
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/es.msg
  77. 2028
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/khim.tcl
  78. 11
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/pkgIndex.tcl
  79. 113
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/pl.msg
  80. 124
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/ru.msg
  81. 117
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/uk.msg
  82. 13
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/mentry.tcl
  83. 115
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/mentryCommon.tcl
  84. 24
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/mentry_tile.tcl
  85. 27
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/pkgIndex.tcl
  86. 863
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryDateTime.tcl
  87. 142
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryFixedPoint.tcl
  88. 244
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryIPAddr.tcl
  89. 282
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryIPv6Addr.tcl
  90. 675
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryThemes.tcl
  91. 2404
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryWidget.tcl
  92. 760
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mwutil/mwutil.tcl
  93. 7
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mwutil/pkgIndex.tcl
  94. 111
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/tclIndex
  95. 226
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/menubar/debug.tcl
  96. 1920
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/menubar/menubar.tcl
  97. 161
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/menubar/node.tcl
  98. 4
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/menubar/pkgIndex.tcl
  99. 1101
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/menubar/tree.tcl
  100. 105
      src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/notifywindow/notifywindow.tcl
  101. Some files were not shown because too many files have changed in this diff Show More

186
src/bootsupport/lib/tar/ChangeLog

@ -0,0 +1,186 @@
2013-11-22 Andreas Kupries <andreask@activestate.com>
* tar.man: Reviewed the work on the pyk-tar branch. Brought
* tar.tcl: new testsuite up to spec. Reviewed the skip fix,
* tar.test: modified it to reinstate the skip limit per round
* test-support.tcl: without getting the bug back. Bumped version
to 0.9. Thanks to PoorYorick for the initial work on the bug,
fix, and testsuite. This also fixes ticket [6b7aa0aecc].
2013-08-12 Andreas Kupries <andreask@activestate.com>
* tar.man (tar::untar, contents, stat, get): Extended the
* tar.tcl: procedures to detect and properly handle @LongName
* pkgIndex.tcl: header entries as generated by GNU tar. These
entries contain the file name for the next header entry as file
data, for files whose name is longer than the 100-char field of
the regular header. Version bumped to 0.8. This is a new
feature.
2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* Released and tagged Tcllib 1.15 ========================
*
2012-09-11 Andreas Kupries <andreask@activestate.com>
* tar.tcl (seekorskip): Fixed seekorskip which prevented its use
* pkgIndex.tcl: from a non-seekable channel, like stdin. The issue
was that the original attempt to seek before skipping not just
failed, but apparently still moved the read pointer in some way
which skipped over irreplacable input, breaking the next call of
readHeader. Using [tell] to check seekability does not break in
this manner. Bumped version to 0.7.1.
2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* Released and tagged Tcllib 1.14 ========================
*
2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* Released and tagged Tcllib 1.13 ========================
*
2011-01-20 Andreas Kupries <andreask@activestate.com>
* tar.tcl: [Bug 3162548]: Applied patch by Alexandre Ferrieux,
* tar.man: extending various tar commands to be able to use
* pkgIndex.tcl: the -chan option, and channels instead of files.
Version bumped to 0.7
2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* Released and tagged Tcllib 1.12 ========================
*
2009-12-03 Andreas Kupries <andreask@activestate.com>
* tar.man: [Patch 2840147]. Applied. New options -prefix and
* tar.tcl: -quick for tar::add. -prefix allows specifying a
* tar.pcx: prefix for filenames in the archive, and -quick 1
* pkgIndex.tcl: changes back to the seek-from-end algorithm for
finding the place where to add the new files. The new default
scans from start (robust). Bumped version to 0.6.
2009-05-12 Aaron Faupell <afaupell@users.sourceforge.net>
* tar.tcl: add support for reading pre-posix archives.
if a file isnt writable when extracting, try deleting
before giving up.
2008-12-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* Released and tagged Tcllib 1.11.1 ========================
*
2008-11-26 Aaron Faupell <afaupell@users.sourceforge.net>
* tar.man: add and clarify documentation
2008-10-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* Released and tagged Tcllib 1.11 ========================
*
2008-06-14 Andreas Kupries <andreas_kupries@users.sourceforge.net>
* tar.pcx: New file. Syntax definitions for the public commands of
the tar package.
2007-09-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* Released and tagged Tcllib 1.10 ========================
*
2007-03-21 Andreas Kupries <andreas_kupries@users.sourceforge.net>
* tar.man: Fixed all warnings due to use of now deprecated
commands. Added a section about how to give feedback.
2007-02-08 Aaron Faupell <afaupell@users.sourceforge.net>
* tar.tcl: bug fix in recursion algorithm that missed
some files in deep subdirs. incremented version
2007-01-08 Andreas Kupries <andreas_kupries@users.sourceforge.net>
* tar.tcl: Bumped version to 0.3, for the bugfix described
* tar.man: by the last entry.
* pkgIndex.tcl:
2006-12-20 Aaron Faupell <afaupell@users.sourceforge.net>
* tar.tcl: fix in parseOpts which affected -file and -glob
arguments to tar::untar
* tar.man: clarifications to add, create, and untar
2006-10-03 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* Released and tagged Tcllib 1.9 ========================
*
2006-29-06 Aaron Faupell <afaupell@users.sourceforge.net>
* tar.tcl: fixed bug in parseOpts
2005-11-08 Andreas Kupries <andreas_kupries@users.sourceforge.net>
* pkgIndex.tcl: Corrected buggy commit, synchronized version
* tar.man: numbers across all relevant files.
2005-11-08 Aaron Faupell <afaupell@users.sourceforge.net>
* tar.tcl: bumped version to 0.2 because of new feature
* tar.man: tar::remove
2005-11-07 Andreas Kupries <andreask@activestate.com>
* tar.man: Fixed error, incorrect placement of [call] markup
outside of list.
2005-11-04 Aaron Faupell <afaupell@users.sourceforge.net>
* tar.man: added tar::remove command and documentation for it
* tar.tcl:
2005-10-06 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* Released and tagged Tcllib 1.8 ========================
*
2005-09-30 Andreas Kupries <andreask@activestate.com>
* tar.tcl: qualified all [open] calls with :: to ensure usag of
the builtin. Apparently mitigates conflict between this package
and the vfs::tar module.
2004-10-05 Andreas Kupries <andreas_kupries@users.sourceforge.net>
*
* Released and tagged Tcllib 1.7 ========================
*
2004-10-02 Andreas Kupries <andreas_kupries@users.sourceforge.net>
* tar.man: Added keywords and title/module description to the
documentation.
2004-09-10 Aaron Faupell <afaupell@users.sourceforge.net>
* tar.tcl: Fixed typo bug in ::tar::add
* tar.man: Added info for ::tar::stat
2004-08-23 Andreas Kupries <andreask@activestate.com>
* tar.man: Fixed problems in the documentation.

5
src/bootsupport/lib/tar/pkgIndex.tcl

@ -0,0 +1,5 @@
if {![package vsatisfies [package provide Tcl] 8.5 9]} {
# PRAGMA: returnok
return
}
package ifneeded tar 0.12 [list source [file join $dir tar.tcl]]

202
src/bootsupport/lib/tar/tar.man

@ -0,0 +1,202 @@
[comment {-*- mode: tcl ; fill-column: 80 -*- doctools manpage}]
[vset PACKAGE_VERSION 0.12]
[manpage_begin tar n [vset PACKAGE_VERSION]]
[keywords archive]
[keywords {tape archive}]
[keywords tar]
[moddesc {Tar file handling}]
[titledesc {Tar file creation, extraction & manipulation}]
[category {File formats}]
[require Tcl "8.5 9"]
[require tar [opt [vset PACKAGE_VERSION]]]
[description]
[para] [strong Note]: Starting with version 0.8 the tar reader commands
(contents, stats, get, untar) support the GNU LongName extension (header type
'L') for large paths.
[para]
[section BEWARE]
For all commands, when using [option -chan] ...
[list_begin enumerated]
[enum] It is assumed that the channel was opened for reading, and configured for
binary input.
[enum] It is assumed that the channel position is at the beginning of a legal
tar file.
[enum] The commands will [emph modify] the channel position as they perform their
task.
[enum] The commands will [emph not] close the channel.
[enum] In other words, the commands leave the channel in a state very likely
unsuitable for use by further [cmd tar] commands. Still doing so will
very likely results in errors, bad data, etc. pp.
[enum] It is the responsibility of the user to seek the channel back to a
suitable position.
[enum] When using a channel transformation which is not generally seekable, for
example [cmd gunzip], then it is the responsibility of the user to (a)
unstack the transformation before seeking the channel back to a suitable
position, and (b) for restacking it after.
[list_end]
[section COMMANDS]
[list_begin definitions]
[call [cmd ::tar::contents] [arg tarball] [opt [option -chan]]]
Returns a list of the files contained in [arg tarball]. The order is not sorted and depends on the order
files were stored in the archive.
[para]
If the option [option -chan] is present [arg tarball] is interpreted as an open channel.
It is assumed that the channel was opened for reading, and configured for binary input.
The command will [emph not] close the channel.
[call [cmd ::tar::stat] [arg tarball] [opt file] [opt [option -chan]]]
Returns a nested dict containing information on the named [opt file] in [arg tarball],
or all files if none is specified. The top level are pairs of filename and info. The info is a dict with the keys
"[const mode] [const uid] [const gid] [const size] [const mtime] [const type] [const linkname] [const uname] [const gname]
[const devmajor] [const devminor]"
[example {
% ::tar::stat tarball.tar
foo.jpg {mode 0644 uid 1000 gid 0 size 7580 mtime 811903867 type file linkname {} uname user gname wheel devmajor 0 devminor 0}
}]
[para]
If the option [option -chan] is present [arg tarball] is interpreted as an open channel.
It is assumed that the channel was opened for reading, and configured for binary input.
The command will [emph not] close the channel.
[call [cmd ::tar::untar] [arg tarball] [arg args]]
Extracts [arg tarball]. [arg -file] and [arg -glob] limit the extraction
to files which exactly match or pattern match the given argument. No error is
thrown if no files match. Returns a list of filenames extracted and the file
size. The size will be null for non regular files. Leading path seperators are
stripped so paths will always be relative.
[list_begin options]
[opt_def -dir dirName]
Directory to extract to. Uses [cmd pwd] if none is specified
[opt_def -file fileName]
Only extract the file with this name. The name is matched against the complete path
stored in the archive including directories.
[opt_def -glob pattern]
Only extract files patching this glob style pattern. The pattern is matched against the complete path
stored in the archive.
[opt_def -nooverwrite]
Dont overwrite files that already exist
[opt_def -nomtime]
Leave the file modification time as the current time instead of setting it to the value in the archive.
[opt_def -noperms]
In Unix, leave the file permissions as the current umask instead of setting them to the values in the archive.
[opt_def -chan]
If this option is present [arg tarball] is interpreted as an open channel.
It is assumed that the channel was opened for reading, and configured for binary input.
The command will [emph not] close the channel.
[list_end]
[para]
[example {
% foreach {file size} [::tar::untar tarball.tar -glob *.jpg] {
puts "Extracted $file ($size bytes)"
}
}]
[call [cmd ::tar::get] [arg tarball] [arg fileName] [opt [option -chan]]]
Returns the contents of [arg fileName] from the [arg tarball].
[para][example {
% set readme [::tar::get tarball.tar doc/README] {
% puts $readme
}
}]
[para] If the option [option -chan] is present [arg tarball] is
interpreted as an open channel. It is assumed that the channel was
opened for reading, and configured for binary input. The command will
[emph not] close the channel.
[para] An error is thrown when [arg fileName] is not found in the tar
archive.
[call [cmd ::tar::create] [arg tarball] [arg files] [arg args]]
Creates a new tar file containing the [arg files]. [arg files] must be specified
as a single argument which is a proper list of filenames.
[list_begin options]
[opt_def -dereference]
Normally [cmd create] will store links as an actual link pointing at a file that may
or may not exist in the archive. Specifying this option will cause the actual file point to
by the link to be stored instead.
[opt_def -chan]
If this option is present [arg tarball] is interpreted as an open channel.
It is assumed that the channel was opened for writing, and configured for binary output.
The command will [emph not] close the channel.
[list_end]
[para]
[example {
% ::tar::create new.tar [glob -nocomplain file*]
% ::tar::contents new.tar
file1 file2 file3
}]
[call [cmd ::tar::add] [arg tarball] [arg files] [arg args]]
Appends [arg files] to the end of the existing [arg tarball]. [arg files] must be specified
as a single argument which is a proper list of filenames.
[list_begin options]
[opt_def -dereference]
Normally [cmd add] will store links as an actual link pointing at a file that may
or may not exist in the archive. Specifying this option will cause the actual file point to
by the link to be stored instead.
[opt_def -prefix string]
Normally [cmd add] will store files under exactly the name specified as
argument. Specifying a [opt -prefix] causes the [arg string] to be
prepended to every name.
[opt_def -quick]
The only sure way to find the position in the [arg tarball] where new
files can be added is to read it from start, but if [arg tarball] was
written with a "blocksize" of 1 (as this package does) then one can
alternatively find this position by seeking from the end. The
[opt -quick] option tells [cmd add] to do the latter.
[list_end]
[para]
[call [cmd ::tar::remove] [arg tarball] [arg files]]
Removes [arg files] from the [arg tarball]. No error will result if the file does not exist in the
tarball. Directory write permission and free disk space equivalent to at least the size of the tarball
will be needed.
[example {
% ::tar::remove new.tar {file2 file3}
% ::tar::contents new.tar
file3
}]
[list_end]
[vset CATEGORY tar]
[include ../common-text/feedback.inc]
[manpage_end]

83
src/bootsupport/lib/tar/tar.pcx

@ -0,0 +1,83 @@
# -*- tcl -*- tar.pcx
# Syntax of the commands provided by package tar.
#
# For use by TclDevKit's static syntax checker (v4.1+).
# See http://www.activestate.com/solutions/tcl/
# See http://aspn.activestate.com/ASPN/docs/Tcl_Dev_Kit/4.0/Checker.html#pcx_api
# for the specification of the format of the code in this file.
#
package require pcx
pcx::register tar
pcx::tcldep 0.4 needs tcl 8.2
pcx::tcldep 0.5 needs tcl 8.2
pcx::tcldep 0.6 needs tcl 8.2
namespace eval ::tar {}
#pcx::message FOO {... text ...} type
#pcx::scan <VERSION> <NAME> <RULE>
pcx::check 0.4 std ::tar::add \
{checkSimpleArgs 2 -1 {
checkFileName
{checkListValues 1 -1 checkFileName}
{checkSwitches 1 {
{-dereference checkBoolean}
} {}}
}}
pcx::check 0.6 std ::tar::add \
{checkSimpleArgs 2 -1 {
checkFileName
{checkListValues 1 -1 checkFileName}
{checkSwitches 1 {
{-dereference checkBoolean}
{-quick checkBoolean}
{-prefix checkWord}
} {}}
}}
pcx::check 0.4 std ::tar::contents \
{checkSimpleArgs 1 1 {
checkFileName
}}
pcx::check 0.4 std ::tar::create \
{checkSimpleArgs 2 -1 {
checkFileName
{checkListValues 1 -1 checkFileName}
{checkSwitches 1 {
{-chan checkChannelID}
{-dereference checkBoolean}
} {}}
}}
pcx::check 0.4 std ::tar::get \
{checkSimpleArgs 2 2 {
checkFileName
checkFileName
}}
pcx::check 0.4 std ::tar::remove \
{checkSimpleArgs 2 2 {
checkFileName
{checkListValues 1 -1 checkFileName}
}}
pcx::check 0.4 std ::tar::stat \
{checkSimpleArgs 1 2 {
checkFileName
checkFileName
}}
pcx::check 0.4 std ::tar::untar \
{checkSimpleArgs 1 -1 {
checkFileName
{checkSwitches 1 {
{-chan checkChannelID}
{-dir checkFileName}
{-file checkFileName}
{-glob checkPattern}
{-nomtime checkBoolean}
{-nooverwrite checkBoolean}
{-noperms checkBoolean}
} {}}
}}
# Initialization via pcx::init.
# Use a ::tar::init procedure for non-standard initialization.
pcx::complete

550
src/bootsupport/lib/tar/tar.tcl

@ -0,0 +1,550 @@
# tar.tcl --
#
# Creating, extracting, and listing posix tar archives
#
# Copyright (c) 2004 Aaron Faupell <afaupell@users.sourceforge.net>
# Copyright (c) 2013 Andreas Kupries <andreas_kupries@users.sourceforge.net>
# (GNU tar @LongLink support).
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: tar.tcl,v 1.17 2012/09/11 17:22:24 andreas_kupries Exp $
package require Tcl 8.5 9
package provide tar 0.12
namespace eval ::tar {}
proc ::tar::parseOpts {acc opts} {
array set flags $acc
foreach {x y} $acc {upvar $x $x}
set len [llength $opts]
set i 0
while {$i < $len} {
set name [string trimleft [lindex $opts $i] -]
if {![info exists flags($name)]} {
return -errorcode {TAR INVALID OPTION} \
-code error "unknown option \"$name\""
}
if {$flags($name) == 1} {
set $name [lindex $opts [expr {$i + 1}]]
incr i $flags($name)
} elseif {$flags($name) > 1} {
set $name [lrange $opts [expr {$i + 1}] [expr {$i + $flags($name)}]]
incr i $flags($name)
} else {
set $name 1
}
incr i
}
}
proc ::tar::pad {size} {
set pad [expr {512 - ($size % 512)}]
if {$pad == 512} {return 0}
return $pad
}
proc ::tar::seekorskip {ch off wh} {
if {[tell $ch] < 0} {
if {$wh!="current"} {
return -code error -errorcode [list TAR INVALID WHENCE $wh] \
"WHENCE=$wh not supported on non-seekable channel $ch"
}
skip $ch $off
return
}
seek $ch $off $wh
return
}
proc ::tar::skip {ch skipover} {
while {$skipover > 0} {
set requested $skipover
# Limit individual skips to 64K, as a compromise between speed
# of skipping (Number of read requests), and memory usage
# (Note how skipped block is read into memory!). While the
# read data is immediately discarded it still generates memory
# allocation traffic, gets copied, etc. Trying to skip the
# block in one go without the limit may cause us to run out of
# (virtual) memory, or just induce swapping, for nothing.
if {$requested > 65536} {
set requested 65536
}
set skipped [string length [read $ch $requested]]
# Stop in short read into the end of the file.
if {!$skipped && [eof $ch]} break
# Keep track of how much is (not) skipped yet.
incr skipover -$skipped
}
return
}
proc ::tar::readHeader {data} {
binary scan $data a100a8a8a8a12a12a8a1a100a6a2a32a32a8a8a155 \
name mode uid gid size mtime cksum type \
linkname magic version uname gname devmajor devminor prefix
foreach x {name type linkname} {
set $x [string trim [set $x] "\x00"]
}
foreach x {uid gid size mtime cksum} {
set $x [format %d 0[string trim [set $x] " \x00"]]
}
set mode [string trim $mode " \x00"]
if {$magic == "ustar "} {
# gnu tar
# not fully supported
foreach x {uname gname prefix} {
set $x [string trim [set $x] "\x00"]
}
foreach x {devmajor devminor} {
set $x [format %d 0[string trim [set $x] " \x00"]]
}
} elseif {$magic == "ustar\x00"} {
# posix tar
foreach x {uname gname prefix} {
set $x [string trim [set $x] "\x00"]
}
foreach x {devmajor devminor} {
set $x [format %d 0[string trim [set $x] " \x00"]]
}
} else {
# old style tar
foreach x {uname gname devmajor devminor prefix} { set $x {} }
if {$type == ""} {
if {[string match */ $name]} {
set type 5
} else {
set type 0
}
}
}
return [list name $name mode $mode uid $uid gid $gid size $size mtime $mtime \
cksum $cksum type $type linkname $linkname magic $magic \
version $version uname $uname gname $gname devmajor $devmajor \
devminor $devminor prefix $prefix]
}
proc ::tar::contents {file args} {
set chan 0
parseOpts {chan 0} $args
if {$chan} {
set fh $file
} else {
set fh [::open $file]
fconfigure $fh -encoding binary -translation lf -eofchar {}
}
set ret {}
while {![eof $fh]} {
array set header [readHeader [read $fh 512]]
HandleLongLink $fh header
if {$header(name) == ""} break
if {$header(prefix) != ""} {append header(prefix) /}
lappend ret $header(prefix)$header(name)
seekorskip $fh [expr {$header(size) + [pad $header(size)]}] current
}
if {!$chan} {
close $fh
}
return $ret
}
proc ::tar::stat {tar {file {}} args} {
set chan 0
parseOpts {chan 0} $args
if {$chan} {
set fh $tar
} else {
set fh [::open $tar]
fconfigure $fh -encoding binary -translation lf -eofchar {}
}
set ret {}
while {![eof $fh]} {
array set header [readHeader [read $fh 512]]
HandleLongLink $fh header
if {$header(name) == ""} break
if {$header(prefix) != ""} {append header(prefix) /}
seekorskip $fh [expr {$header(size) + [pad $header(size)]}] current
if {$file != "" && "$header(prefix)$header(name)" != $file} {continue}
set header(type) [string map {0 file 5 directory 3 characterSpecial 4 blockSpecial 6 fifo 2 link} $header(type)]
set header(mode) [string range $header(mode) 2 end]
lappend ret $header(prefix)$header(name) [list mode $header(mode) uid $header(uid) gid $header(gid) \
size $header(size) mtime $header(mtime) type $header(type) linkname $header(linkname) \
uname $header(uname) gname $header(gname) devmajor $header(devmajor) devminor $header(devminor)]
}
if {!$chan} {
close $fh
}
return $ret
}
proc ::tar::get {tar file args} {
set chan 0
parseOpts {chan 0} $args
if {$chan} {
set fh $tar
} else {
set fh [::open $tar]
fconfigure $fh -encoding binary -translation lf -eofchar {}
}
while {![eof $fh]} {
set data [read $fh 512]
array set header [readHeader $data]
HandleLongLink $fh header
if {$header(name) eq ""} break
if {$header(prefix) ne ""} {append header(prefix) /}
set name [string trimleft $header(prefix)$header(name) /]
if {$name eq $file} {
set file [read $fh $header(size)]
if {!$chan} {
close $fh
}
return $file
}
seekorskip $fh [expr {$header(size) + [pad $header(size)]}] current
}
if {!$chan} {
close $fh
}
return -code error -errorcode {TAR MISSING FILE} \
"Tar \"$tar\": File \"$file\" not found"
}
proc ::tar::untar {tar args} {
set nooverwrite 0
set data 0
set nomtime 0
set noperms 0
set chan 0
parseOpts {dir 1 file 1 glob 1 nooverwrite 0 nomtime 0 noperms 0 chan 0} $args
if {![info exists dir]} {set dir [pwd]}
set pattern *
if {[info exists file]} {
set pattern [string map {* \\* ? \\? \\ \\\\ \[ \\\[ \] \\\]} $file]
} elseif {[info exists glob]} {
set pattern $glob
}
set ret {}
if {$chan} {
set fh $tar
} else {
set fh [::open $tar]
fconfigure $fh -encoding binary -translation lf -eofchar {}
}
while {![eof $fh]} {
array set header [readHeader [read $fh 512]]
HandleLongLink $fh header
if {$header(name) == ""} break
if {$header(prefix) != ""} {append header(prefix) /}
set name [string trimleft $header(prefix)$header(name) /]
if {![string match $pattern $name] || ($nooverwrite && [file exists $name])} {
seekorskip $fh [expr {$header(size) + [pad $header(size)]}] current
continue
}
set name [file join $dir $name]
if {![file isdirectory [file dirname $name]]} {
file mkdir [file dirname $name]
lappend ret [file dirname $name] {}
}
if {[string match {[0346]} $header(type)]} {
if {[catch {::open $name w+} new]} {
# sometimes if we dont have write permission we can still delete
catch {file delete -force $name}
set new [::open $name w+]
}
fconfigure $new -encoding binary -translation lf -eofchar {}
fcopy $fh $new -size $header(size)
close $new
lappend ret $name $header(size)
} elseif {$header(type) == 5} {
file mkdir $name
lappend ret $name {}
} elseif {[string match {[12]} $header(type)] && $::tcl_platform(platform) == "unix"} {
catch {file delete $name}
if {![catch {file link [string map {1 -hard 2 -symbolic} $header(type)] $name $header(linkname)}]} {
lappend ret $name {}
}
}
seekorskip $fh [pad $header(size)] current
if {![file exists $name]} continue
if {$::tcl_platform(platform) == "unix"} {
if {!$noperms} {
catch {file attributes $name -permissions 0o[string range $header(mode) 2 end]}
}
catch {file attributes $name -owner $header(uid) -group $header(gid)}
catch {file attributes $name -owner $header(uname) -group $header(gname)}
}
if {!$nomtime} {
file mtime $name $header(mtime)
}
}
if {!$chan} {
close $fh
}
return $ret
}
##
# ::tar::statFile
#
# Returns stat info about a filesystem object, in the form of an info
# dictionary like that returned by ::tar::readHeader.
#
# The mode, uid, gid, mtime, and type entries are always present.
# The size and linkname entries are present if relevant for this type
# of object. The uname and gname entries are present if the OS supports
# them. No devmajor or devminor entry is present.
##
proc ::tar::statFile {name followlinks} {
if {$followlinks} {
file stat $name stat
} else {
file lstat $name stat
}
set ret {}
if {$::tcl_platform(platform) == "unix"} {
# Tcl 9 returns the permission as 0o octal number. Since this
# is written to the tar file and the file format expects "00"
# we have to rewrite.
lappend ret mode 1[string map {o 0} [file attributes $name -permissions]]
lappend ret uname [file attributes $name -owner]
lappend ret gname [file attributes $name -group]
if {$stat(type) == "link"} {
lappend ret linkname [file link $name]
}
} else {
lappend ret mode [lindex {100644 100755} [expr {$stat(type) == "directory"}]]
}
lappend ret uid $stat(uid) gid $stat(gid) mtime $stat(mtime) \
type $stat(type)
if {$stat(type) == "file"} {lappend ret size $stat(size)}
return $ret
}
##
# ::tar::formatHeader
#
# Opposite operation to ::tar::readHeader; takes a file name and info
# dictionary as arguments, returns a corresponding (POSIX-tar) header.
#
# The following dictionary entries must be present:
# mode
# type
#
# The following dictionary entries are used if present, otherwise
# the indicated default is used:
# uid 0
# gid 0
# size 0
# mtime [clock seconds]
# linkname {}
# uname {}
# gname {}
#
# All other dictionary entries, including devmajor and devminor, are
# presently ignored.
##
proc ::tar::formatHeader {name info} {
array set A {
linkname ""
uname ""
gname ""
size 0
gid 0
uid 0
}
set A(mtime) [clock seconds]
array set A $info
array set A {devmajor "" devminor ""}
set type [string map {file 0 directory 5 characterSpecial 3 \
blockSpecial 4 fifo 6 link 2 socket A} $A(type)]
set osize [format %o $A(size)]
set ogid [format %o $A(gid)]
set ouid [format %o $A(uid)]
set omtime [format %o $A(mtime)]
set name [string trimleft $name /]
if {[string length $name] > 255} {
return -code error -errorcode {TAR BAD PATH LENGTH} \
"path name over 255 chars"
} elseif {[string length $name] > 100} {
set common [string range $name end-99 154]
if {[set splitpoint [string first / $common]] == -1} {
return -code error -errorcode {TAR BAD PATH UNSPLITTABLE} \
"path name cannot be split into prefix and name"
}
set prefix [string range $name 0 end-100][string range $common 0 $splitpoint-1]
set name [string range $common $splitpoint+1 end][string range $name 155 end]
} else {
set prefix ""
}
set header [binary format a100A8A8A8A12A12A8a1a100A6a2a32a32a8a8a155a12 \
$name $A(mode)\x00 $ouid\x00 $ogid\x00\
$osize\x00 $omtime\x00 {} $type \
$A(linkname) ustar\x00 00 $A(uname) $A(gname)\
$A(devmajor) $A(devminor) $prefix {}]
binary scan $header c* tmp
set cksum 0
foreach x $tmp {incr cksum $x}
return [string replace $header 148 155 [binary format A8 [format %o $cksum]\x00]]
}
proc ::tar::recurseDirs {files followlinks} {
foreach x $files {
if {[file isdirectory $x] && ([file type $x] != "link" || $followlinks)} {
if {[set more [glob -dir $x -nocomplain *]] != ""} {
eval lappend files [recurseDirs $more $followlinks]
} else {
lappend files $x
}
}
}
return $files
}
proc ::tar::writefile {in out followlinks name} {
puts -nonewline $out [formatHeader $name [statFile $in $followlinks]]
set size 0
if {[file type $in] == "file" || ($followlinks && [file type $in] == "link")} {
set in [::open $in]
fconfigure $in -encoding binary -translation lf -eofchar {}
set size [fcopy $in $out]
close $in
}
puts -nonewline $out [string repeat \x00 [pad $size]]
}
proc ::tar::create {tar files args} {
set dereference 0
set chan 0
parseOpts {dereference 0 chan 0} $args
if {$chan} {
set fh $tar
} else {
set fh [::open $tar w+]
fconfigure $fh -encoding binary -translation lf -eofchar {}
}
foreach x [recurseDirs $files $dereference] {
writefile $x $fh $dereference $x
}
puts -nonewline $fh [string repeat \x00 1024]
if {!$chan} {
close $fh
}
return $tar
}
proc ::tar::add {tar files args} {
set dereference 0
set prefix ""
set quick 0
parseOpts {dereference 0 prefix 1 quick 0} $args
set fh [::open $tar r+]
fconfigure $fh -encoding binary -translation lf -eofchar {}
if {$quick} then {
seek $fh -1024 end
} else {
set data [read $fh 512]
while {[regexp {[^\0]} $data]} {
array set header [readHeader $data]
seek $fh [expr {$header(size) + [pad $header(size)]}] current
set data [read $fh 512]
}
seek $fh -512 current
}
foreach x [recurseDirs $files $dereference] {
writefile $x $fh $dereference $prefix$x
}
puts -nonewline $fh [string repeat \x00 1024]
close $fh
return $tar
}
proc ::tar::remove {tar files} {
set n 0
while {[file exists $tar$n.tmp]} {incr n}
set tfh [::open $tar$n.tmp w]
set fh [::open $tar r]
fconfigure $fh -encoding binary -translation lf -eofchar {}
fconfigure $tfh -encoding binary -translation lf -eofchar {}
while {![eof $fh]} {
array set header [readHeader [read $fh 512]]
if {$header(name) == ""} {
puts -nonewline $tfh [string repeat \x00 1024]
break
}
if {$header(prefix) != ""} {append header(prefix) /}
set name $header(prefix)$header(name)
set len [expr {$header(size) + [pad $header(size)]}]
if {[lsearch $files $name] > -1} {
seek $fh $len current
} else {
seek $fh -512 current
fcopy $fh $tfh -size [expr {$len + 512}]
}
}
close $fh
close $tfh
file rename -force $tar$n.tmp $tar
}
proc ::tar::HandleLongLink {fh hv} {
upvar 1 $hv header thelongname thelongname
# @LongName Part I.
if {$header(type) == "L"} {
# Size == Length of name. Read it, and pad to full 512
# size. After that is a regular header for the actual
# file, where we have to insert the name. This is handled
# by the next iteration and the part II below.
set thelongname [string trimright [read $fh $header(size)] \000]
seekorskip $fh [pad $header(size)] current
return -code continue
}
# Not supported yet: type 'K' for LongLink (long symbolic links).
# @LongName, part II, get data from previous entry, if defined.
if {[info exists thelongname]} {
set header(name) $thelongname
# Prevent leakage to further entries.
unset thelongname
}
return
}

139
src/bootsupport/lib/tar/tar.test

@ -0,0 +1,139 @@
# -*- tcl -*-
# These tests are in the public domain
# -------------------------------------------------------------------------
source [file join \
[file dirname [file dirname [file normalize [info script]]]] \
devtools testutilities.tcl]
testsNeedTcl 8.5 ; # Virt channel support!
testsNeedTcltest 1.0
# Check if we have TclOO available.
tcltest::testConstraint tcloo [expr {![catch {package require TclOO}]}]
support {
if {[tcltest::testConstraint tcloo]} {
use virtchannel_base/memchan.tcl tcl::chan::memchan
}
useLocalFile tests/support.tcl
}
testing {
useLocal tar.tcl tar
}
# -------------------------------------------------------------------------
test tar-stream {stream} -constraints tcloo -setup {
setup1
} -body {
string length [read $chan1]
} -cleanup {
cleanup1
} -result 128000
test tar-pad {pad} -body {
tar::pad 230
} -result {282}
test tar-skip {skip} -constraints tcloo -setup {
setup1
} -body {
tar::skip $chan1 10
lappend res [read $chan1 10]
tar::skip $chan1 72313
lappend res [read $chan1 10]
} -cleanup {
cleanup1
} -result {{6 7 8 9 10} {07 13908 1}}
test tar-seekorskip-backwards {seekorskip} -constraints tcl8.6plus -setup setup1 -body {
# The zlib push stuff is Tcl 8.6+. Properly restrict the test.
zlib push gzip $chan1
catch {tar::seekorskip $chan1 -10 start} cres
lappend res $cres
catch {tar::seekorskip $chan1 10 start} cres
lappend res $cres
catch {tar::seekorskip $chan1 -10 end} cres
lappend res $cres
catch {tar::seekorskip $chan1 10 end} cres
lappend res $cres
lappend res [read $chan1 10]
} -cleanup cleanup1 -match glob \
-result [list \
{WHENCE=start not supported*} \
{WHENCE=start not supported*} \
{WHENCE=end not supported*} \
{WHENCE=end not supported*} \
{1 2 3 4 5 } \
]
test tar-header {header} -body {
set file1 [dict get $filesys Dir1 File1]
dict set file1 path /Dir1/File1
set header [header_posix $file1]
set parsed [string trim [tar::readHeader $header]]
set golden "name /Dir1/File1 mode 755 uid 13103 gid 18103 size 100 mtime 5706756101 cksum 3676 type 0 linkname {} magic ustar\0 version 00 uname {} gname {} devmajor 0 devminor 0 prefix {}"
set len [string length $parsed]
foreach {key value} $golden {
if {[set value1 [dict get $parsed $key]] ne $value } {
lappend res [list $key $value $value1]
}
}
} -result {}
test tar-add {add} -constraints tcloo -setup {
setup1
} -body {
tar::create $chan1 [list $tmpdir/one/a $tmpdir/one/two/a $tmpdir/one/three/a] -chan
seek $chan1 0
lappend res {*}[tar::contents $chan1 -chan]
seek $chan1 0
lappend res [string trim [tar::get $chan1 $tmpdir/one/two/a -chan]]
} -cleanup {
cleanup1
} -result {tartest/one/a tartest/one/two/a tartest/one/three/a hello2}
test tar-bug-2840180 {Ticket 2840180} -setup {
setup2
} -body {
tar::create $chan1 [list $tmpdir/[large-path]/a] -chan
seek $chan1 0
# What the package sees.
lappend res {*}[tar::contents $chan1 -chan]
close $chan1
# What a regular tar package sees.
lappend res [exec 2> $tmpfile.err tar tvf $tmpfile]
join $res \n
} -cleanup {
cleanup2
} -match glob -result [join [list \
tartest/[large-path]/a \
"* tartest/[large-path]/a" \
] \n]
# -------------------------------------------------------------------------
test tar-tkt-9f4c0e3e95-1.0 {Ticket 9f4c0e3e95, A} -setup {
set tarfile [setup-tkt-9f4c0e3e95]
} -body {
string trim [tar::get $tarfile 02]
} -cleanup {
cleanup-tkt-9f4c0e3e95
unset tarfile
} -result {zero-two}
test tar-tkt-9f4c0e3e95-1.1 {Ticket 9f4c0e3e95, B, } -setup {
set tarfile [setup-tkt-9f4c0e3e95]
} -body {
tar::get $tarfile 0b10
} -cleanup {
cleanup-tkt-9f4c0e3e95
unset tarfile
} -returnCodes error -result {Tar "tartest/t.tar": File "0b10" not found}
# -------------------------------------------------------------------------
testsuiteCleanup

149
src/bootsupport/lib/tar/tests/support.tcl

@ -0,0 +1,149 @@
proc stream {{size 128000}} {
set chan [tcl::chan::memchan]
set line {}
while 1 {
incr i
set istring $i
set ilen [string length $istring]
if {$line ne {}} {
append line { }
incr size -1
}
append line $istring
incr size -$ilen
if {$size < 1} {
set line [string range $line 0 end-[expr {abs(1-$size)}]]
puts $chan $line
break
}
if {$i % 10 == 0} {
puts $chan $line
incr size -1 ;# for the [puts] newline
set line {}
}
}
seek $chan 0
return $chan
}
proc header_posix {tarball} {
dict with tarball {}
tar::formatHeader $path \
[dict create \
mode $mode \
type $type \
uid $uid \
gid $gid \
size $size \
mtime $mtime]
}
proc setup1 {} {
variable chan1
variable res {}
variable tmpdir tartest
tcltest::makeDirectory $tmpdir
foreach directory {
one
one/two
one/three
} {
tcltest::makeDirectory $tmpdir/$directory
set chan [open $tmpdir/$directory/a w]
puts $chan hello[incr i]
close $chan
}
set chan1 [stream]
}
proc large-path {} {
return aaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbaaaaa/bbbbtcllib/modules/tar
}
proc setup2 {} {
variable chan1
variable res {}
variable tmpdir tartest
variable tmpfile tarX
tcltest::makeDirectory $tmpdir
tcltest::makeFile {} $tmpfile
foreach directory [list [large-path]] {
tcltest::makeDirectory $tmpdir/$directory
set chan [open $tmpdir/$directory/a w]
puts $chan hello[incr i]
close $chan
}
set chan1 [open $tmpfile w+]
}
proc cleanup1 {} {
variable chan1
close $chan1
tcltest::removeDirectory tartest
return
}
proc cleanup2 {} {
variable chan1
variable tmpdir
variable tmpfile
catch { close $chan1 }
tcltest::removeDirectory $tmpdir
tcltest::removeFile $tmpfile
tcltest::removeFile $tmpfile.err
return
}
variable filesys {
Dir1 {
File1 {
type 0
mode 755
uid 13103
gid 18103
size 100
mtime 5706756101
}
}
Dir2 {
File1 {
type 0
mode 644
uid 15103
gid 19103
size 100
mtime 5706776103
}
}
}
proc setup-tkt-9f4c0e3e95 {} {
variable tmpdir tartest
tcltest::makeDirectory $tmpdir
tcltest::makeFile {zero-two} $tmpdir/02
tcltest::makeFile {number two} $tmpdir/2
set here [pwd]
cd $tmpdir
tar::create t.tar {2 02}
cd $here
return $tmpdir/t.tar
}
proc cleanup-tkt-9f4c0e3e95 {} {
variable tmpdir
tcltest::removeFile $tmpdir/2
tcltest::removeFile $tmpdir/02
tcltest::removeDirectory $tmpdir
return
}

33
src/bootsupport/modules/punk/nav/fs-0.1.0.tm

@ -378,7 +378,7 @@ tcl::namespace::eval punk::nav::fs {
}
}
}
set matchinfo [dirfiles_dict -searchbase $searchbase -tailglob $glob $location -with_sizes {f d l} -with_times {f d l}]
set matchinfo [dirfiles_dict -searchbase $searchbase -tailglob $glob -with_sizes {f d l} -with_times {f d l} $location]
#puts stderr "=--->$matchinfo"
@ -694,7 +694,7 @@ tcl::namespace::eval punk::nav::fs {
}
}
puts "--> -searchbase:$searchbase searchspec:$searchspec -tailglob:$tailglob location:$location"
set contents [dirfiles_dict -searchbase $searchbase -tailglob $tailglob -with_times {f d l} $location]
set contents [dirfiles_dict -searchbase $searchbase -tailglob $tailglob -with_times {f d l} -with_sizes {f d l} $location]
return [dirfiles_dict_as_lines -stripbase $opt_stripbase -formatsizes $opt_formatsizes $contents]
}
@ -1179,6 +1179,7 @@ tcl::namespace::eval punk::nav::fs {
set shortcutinfo [punk::winlnk::file_get_info $fname]
set target_type "file" ;#default/fallback
if {[dict exists $shortcutinfo link_target]} {
set is_valid_lnk 1
set tgt [dict get $shortcutinfo link_target]
if {[file exists $tgt]} {
#file type could return 'link' - we will use isfile/isdirectory
@ -1193,11 +1194,15 @@ tcl::namespace::eval punk::nav::fs {
#todo - see if punk::winlnk has info about the type at the time of linking
#for now - treat as file
}
} else {
#no link_target - probably an ordinary file - but there could have been some other error in reading the binary windows lnk format.
set is_valid_lnk 0
}
if {$is_valid_lnk} {
switch -- $target_type {
file {
set display [dict get $fdict display]
set display "$fshortcut_style$display (shortcut to $tgt)" ;#
set display "$fshortcut_style$display (shortcut $tgt)" ;#
dict set fdict display $display
lappend finfo_plus $fdict
}
@ -1208,6 +1213,28 @@ tcl::namespace::eval punk::nav::fs {
lappend dir_shortcuts $fname
}
}
} else {
#we were unable to get link_target - but we still need to check if it failed the header check (then assume not intended to be a windows shell lnk) or for some other reason.
if {[dict exists $shortcutinfo error]} {
if {[dict get $shortcutinfo error] ne "lnk_header_check_failed"} {
#Presumably there is a valid lnk header, but some unexpected error occurred - show it in the display for the file
#still style as a windows shell lnk - as to get here, the header check must have passed.
set display [dict get $fdict display]
set display "$fshortcut_style$display (shortcut error [dict get $shortcutinfo error])" ;#
dict set fdict display $display
lappend finfo_plus $fdict
} else {
#error of lnk_header_check_failed means it probably just isn't a windows shell link. Leave ordinary display for file.
lappend finfo_plus $fdict
}
} else {
#shouldn't ever happen. If no error, then there should have been a link_target
#report and move on
puts stderr "Unexpected error in result of parsing binary format for $fname"
lappend finfo_plus $fdict
}
}
#assert - we have either appended to finfo_plus (possibly with shortcut info/error if binary header was valid) - or appended to dirs (if it was a valid lnk and target was a dir)
}
#if we don't have punk::winlnk to read the .lnk - it will get no special highlighting and just appear as an ordinary file even if it points to a dir
} else {

33
src/modules/punk/nav/fs-999999.0a1.0.tm

@ -378,7 +378,7 @@ tcl::namespace::eval punk::nav::fs {
}
}
}
set matchinfo [dirfiles_dict -searchbase $searchbase -tailglob $glob $location -with_sizes {f d l} -with_times {f d l}]
set matchinfo [dirfiles_dict -searchbase $searchbase -tailglob $glob -with_sizes {f d l} -with_times {f d l} $location]
#puts stderr "=--->$matchinfo"
@ -694,7 +694,7 @@ tcl::namespace::eval punk::nav::fs {
}
}
puts "--> -searchbase:$searchbase searchspec:$searchspec -tailglob:$tailglob location:$location"
set contents [dirfiles_dict -searchbase $searchbase -tailglob $tailglob -with_times {f d l} $location]
set contents [dirfiles_dict -searchbase $searchbase -tailglob $tailglob -with_times {f d l} -with_sizes {f d l} $location]
return [dirfiles_dict_as_lines -stripbase $opt_stripbase -formatsizes $opt_formatsizes $contents]
}
@ -1179,6 +1179,7 @@ tcl::namespace::eval punk::nav::fs {
set shortcutinfo [punk::winlnk::file_get_info $fname]
set target_type "file" ;#default/fallback
if {[dict exists $shortcutinfo link_target]} {
set is_valid_lnk 1
set tgt [dict get $shortcutinfo link_target]
if {[file exists $tgt]} {
#file type could return 'link' - we will use isfile/isdirectory
@ -1193,11 +1194,15 @@ tcl::namespace::eval punk::nav::fs {
#todo - see if punk::winlnk has info about the type at the time of linking
#for now - treat as file
}
} else {
#no link_target - probably an ordinary file - but there could have been some other error in reading the binary windows lnk format.
set is_valid_lnk 0
}
if {$is_valid_lnk} {
switch -- $target_type {
file {
set display [dict get $fdict display]
set display "$fshortcut_style$display (shortcut to $tgt)" ;#
set display "$fshortcut_style$display (shortcut $tgt)" ;#
dict set fdict display $display
lappend finfo_plus $fdict
}
@ -1208,6 +1213,28 @@ tcl::namespace::eval punk::nav::fs {
lappend dir_shortcuts $fname
}
}
} else {
#we were unable to get link_target - but we still need to check if it failed the header check (then assume not intended to be a windows shell lnk) or for some other reason.
if {[dict exists $shortcutinfo error]} {
if {[dict get $shortcutinfo error] ne "lnk_header_check_failed"} {
#Presumably there is a valid lnk header, but some unexpected error occurred - show it in the display for the file
#still style as a windows shell lnk - as to get here, the header check must have passed.
set display [dict get $fdict display]
set display "$fshortcut_style$display (shortcut error [dict get $shortcutinfo error])" ;#
dict set fdict display $display
lappend finfo_plus $fdict
} else {
#error of lnk_header_check_failed means it probably just isn't a windows shell link. Leave ordinary display for file.
lappend finfo_plus $fdict
}
} else {
#shouldn't ever happen. If no error, then there should have been a link_target
#report and move on
puts stderr "Unexpected error in result of parsing binary format for $fname"
lappend finfo_plus $fdict
}
}
#assert - we have either appended to finfo_plus (possibly with shortcut info/error if binary header was valid) - or appended to dirs (if it was a valid lnk and target was a dir)
}
#if we don't have punk::winlnk to read the .lnk - it will get no special highlighting and just appear as an ordinary file even if it points to a dir
} else {

33
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm

@ -378,7 +378,7 @@ tcl::namespace::eval punk::nav::fs {
}
}
}
set matchinfo [dirfiles_dict -searchbase $searchbase -tailglob $glob $location -with_sizes {f d l} -with_times {f d l}]
set matchinfo [dirfiles_dict -searchbase $searchbase -tailglob $glob -with_sizes {f d l} -with_times {f d l} $location]
#puts stderr "=--->$matchinfo"
@ -694,7 +694,7 @@ tcl::namespace::eval punk::nav::fs {
}
}
puts "--> -searchbase:$searchbase searchspec:$searchspec -tailglob:$tailglob location:$location"
set contents [dirfiles_dict -searchbase $searchbase -tailglob $tailglob -with_times {f d l} $location]
set contents [dirfiles_dict -searchbase $searchbase -tailglob $tailglob -with_times {f d l} -with_sizes {f d l} $location]
return [dirfiles_dict_as_lines -stripbase $opt_stripbase -formatsizes $opt_formatsizes $contents]
}
@ -1179,6 +1179,7 @@ tcl::namespace::eval punk::nav::fs {
set shortcutinfo [punk::winlnk::file_get_info $fname]
set target_type "file" ;#default/fallback
if {[dict exists $shortcutinfo link_target]} {
set is_valid_lnk 1
set tgt [dict get $shortcutinfo link_target]
if {[file exists $tgt]} {
#file type could return 'link' - we will use isfile/isdirectory
@ -1193,11 +1194,15 @@ tcl::namespace::eval punk::nav::fs {
#todo - see if punk::winlnk has info about the type at the time of linking
#for now - treat as file
}
} else {
#no link_target - probably an ordinary file - but there could have been some other error in reading the binary windows lnk format.
set is_valid_lnk 0
}
if {$is_valid_lnk} {
switch -- $target_type {
file {
set display [dict get $fdict display]
set display "$fshortcut_style$display (shortcut to $tgt)" ;#
set display "$fshortcut_style$display (shortcut $tgt)" ;#
dict set fdict display $display
lappend finfo_plus $fdict
}
@ -1208,6 +1213,28 @@ tcl::namespace::eval punk::nav::fs {
lappend dir_shortcuts $fname
}
}
} else {
#we were unable to get link_target - but we still need to check if it failed the header check (then assume not intended to be a windows shell lnk) or for some other reason.
if {[dict exists $shortcutinfo error]} {
if {[dict get $shortcutinfo error] ne "lnk_header_check_failed"} {
#Presumably there is a valid lnk header, but some unexpected error occurred - show it in the display for the file
#still style as a windows shell lnk - as to get here, the header check must have passed.
set display [dict get $fdict display]
set display "$fshortcut_style$display (shortcut error [dict get $shortcutinfo error])" ;#
dict set fdict display $display
lappend finfo_plus $fdict
} else {
#error of lnk_header_check_failed means it probably just isn't a windows shell link. Leave ordinary display for file.
lappend finfo_plus $fdict
}
} else {
#shouldn't ever happen. If no error, then there should have been a link_target
#report and move on
puts stderr "Unexpected error in result of parsing binary format for $fname"
lappend finfo_plus $fdict
}
}
#assert - we have either appended to finfo_plus (possibly with shortcut info/error if binary header was valid) - or appended to dirs (if it was a valid lnk and target was a dir)
}
#if we don't have punk::winlnk to read the .lnk - it will get no special highlighting and just appear as an ordinary file even if it points to a dir
} else {

33
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm

@ -378,7 +378,7 @@ tcl::namespace::eval punk::nav::fs {
}
}
}
set matchinfo [dirfiles_dict -searchbase $searchbase -tailglob $glob $location -with_sizes {f d l} -with_times {f d l}]
set matchinfo [dirfiles_dict -searchbase $searchbase -tailglob $glob -with_sizes {f d l} -with_times {f d l} $location]
#puts stderr "=--->$matchinfo"
@ -694,7 +694,7 @@ tcl::namespace::eval punk::nav::fs {
}
}
puts "--> -searchbase:$searchbase searchspec:$searchspec -tailglob:$tailglob location:$location"
set contents [dirfiles_dict -searchbase $searchbase -tailglob $tailglob -with_times {f d l} $location]
set contents [dirfiles_dict -searchbase $searchbase -tailglob $tailglob -with_times {f d l} -with_sizes {f d l} $location]
return [dirfiles_dict_as_lines -stripbase $opt_stripbase -formatsizes $opt_formatsizes $contents]
}
@ -1179,6 +1179,7 @@ tcl::namespace::eval punk::nav::fs {
set shortcutinfo [punk::winlnk::file_get_info $fname]
set target_type "file" ;#default/fallback
if {[dict exists $shortcutinfo link_target]} {
set is_valid_lnk 1
set tgt [dict get $shortcutinfo link_target]
if {[file exists $tgt]} {
#file type could return 'link' - we will use isfile/isdirectory
@ -1193,11 +1194,15 @@ tcl::namespace::eval punk::nav::fs {
#todo - see if punk::winlnk has info about the type at the time of linking
#for now - treat as file
}
} else {
#no link_target - probably an ordinary file - but there could have been some other error in reading the binary windows lnk format.
set is_valid_lnk 0
}
if {$is_valid_lnk} {
switch -- $target_type {
file {
set display [dict get $fdict display]
set display "$fshortcut_style$display (shortcut to $tgt)" ;#
set display "$fshortcut_style$display (shortcut $tgt)" ;#
dict set fdict display $display
lappend finfo_plus $fdict
}
@ -1208,6 +1213,28 @@ tcl::namespace::eval punk::nav::fs {
lappend dir_shortcuts $fname
}
}
} else {
#we were unable to get link_target - but we still need to check if it failed the header check (then assume not intended to be a windows shell lnk) or for some other reason.
if {[dict exists $shortcutinfo error]} {
if {[dict get $shortcutinfo error] ne "lnk_header_check_failed"} {
#Presumably there is a valid lnk header, but some unexpected error occurred - show it in the display for the file
#still style as a windows shell lnk - as to get here, the header check must have passed.
set display [dict get $fdict display]
set display "$fshortcut_style$display (shortcut error [dict get $shortcutinfo error])" ;#
dict set fdict display $display
lappend finfo_plus $fdict
} else {
#error of lnk_header_check_failed means it probably just isn't a windows shell link. Leave ordinary display for file.
lappend finfo_plus $fdict
}
} else {
#shouldn't ever happen. If no error, then there should have been a link_target
#report and move on
puts stderr "Unexpected error in result of parsing binary format for $fname"
lappend finfo_plus $fdict
}
}
#assert - we have either appended to finfo_plus (possibly with shortcut info/error if binary header was valid) - or appended to dirs (if it was a valid lnk and target was a dir)
}
#if we don't have punk::winlnk to read the .lnk - it will get no special highlighting and just appear as an ordinary file even if it points to a dir
} else {

2
src/runtime/mapvfs.config

@ -33,7 +33,7 @@ tclkit87a5.exe {punk8win.vfs punk87}
##################################
#TCL9
tclsh90b2 {punk9win.vfs punk90b2 zip}
tclsh90b4_piperepl.exe {punk9win.vfs punk90b4 zip} {critcl.vfs critcl9 zip}
#tclsh90b4_piperepl.exe {punk9win.vfs punk90b4 zip} {critcl.vfs critcl9 zip}
##################################

212
src/vfs/_vfscommon/modules/punk/du-0.1.0.tm

@ -19,6 +19,7 @@
##e.g package require frobz
package require punk::mix::base
package require struct::set
package require punk::args
namespace eval punk::du {
@ -486,12 +487,105 @@ namespace eval punk::du {
return [lindex [lappend winfile_attributes $bitmask [twapi::decode_file_attributes $bitmask]] end]
}
}
proc attributes_twapi {path {detail basic}} {
try {
set iterator [twapi::find_file_open $path -detail $detail] ;# -detail full only adds data to the altname field
if {[twapi::find_file_next $iterator iteminfo]} {
variable win_reparse_tags
#implied prefix for all names IO_REPARSE_TAG_
#list of reparse tags: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/c8e77b37-3909-4fe6-a4ea-2b9d423b1ee4
set win_reparse_tags [dict create\
RESERVED_ZERO [list hex 0x00000000 obsolete 0 serverside 0 meaning "Reserved reparse tag value"]\
RESERVED_ONE [list hex 0x00000001 obsolete 0 serverside 0 meaning "Reserved reparse tag value"]\
RESERVED_TWO [list hex 0x00000002 obsolete 0 serverside 0 meaning "Reserved reparse tag value"]\
MOUNT_POINT [list hex 0xA0000003 obsolete 0 serverside 0 meaning "Used for mount point support"]\
HSM [list hex 0xC0000004 obsolete 1 serverside 0 meaning "Obsolete. Used by legacy Hierarchical Storage Manager Product"]\
DRIVE_EXTENDER [list hex 0x80000005 obsolete 0 serverside 0 meaning "Home server drive extender"]\
HSM2 [list hex 0xC0000006 obsolete 1 serverside 0 meaning "Obsolete. Used by legacy Hierarchical Storage Manager Product"]\
SIS [list hex 0x80000007 obsolete 0 serverside 1 meaning "Used by single-instance storage (SIS) filter driver."]\
WIM [list hex 0x80000008 obsolete 0 serverside 1 meaning "Used by the WIM Mount filter."]\
CSV [list hex 0x80000008 obsolete 1 serverside 1 meaning "Obsolete. Used by Clustered Shared Volumes (CSV) version 1 in Windows Server 2008 R2 operating system. "]\
DFS [list hex 0x8000000A obsolete 0 serverside 1 meaning "Used by the DFS filter. The DFS is described in the Distributed File System (DFS): Referral Protocol Specification \[MS-DFSC\]."]\
FILTER_MANAGER [list hex 0x8000000B obsolete 0 serverside 0 meaning "Used by filter manager test harness"]\
SYMLINK [list hex 0xA000000C obsolete 0 serverside 0 meaning "Used for symbolic link support."]\
IIS_CACHE [list hex 0xA0000010 obsolete 0 serverside 1 meaning "Used by Microsoft Internet Information Services (IIS) caching. "]\
DFSR [list hex 0x80000012 obsolete 0 serverside 1 meaning "Used by the DFS filter. The DFS is described in \[MS-DFSC\]. "]\
DEDUP [list hex 0x80000013 obsolete 0 serverside 1 meaning "Used by the Data Deduplication (Dedup) filter. "]\
APPXSTRM [list hex 0xC0000014 obsolete 0 serverside 0 meaning "Not used."]\
NFS [list hex 0x80000014 obsolete 0 serverside 1 meaning "Used by the Network File System (NFS) component. "]\
FILE_PLACEHOLDER [list hex 0x80000015 obsolete 1 serverside 1 meaning "Obsolete. Used by Windows Shell for legacy placeholder files in Windows 8.1. "]\
DFM [list hex 0x80000016 obsolete 0 serverside 1 meaning "Used by the Dynamic File filter. "]\
WOF [list hex 0x80000017 obsolete 0 serverside 1 meaning "Used by the Windows Overlay filter, for either WIMBoot or single-file compression."]\
WCI [list hex 0x80000018 obsolete 0 serverside 1 meaning "Used by the Windows Container Isolation filter. "]\
WCI_2 [list hex 0x90001018 obsolete 0 serverside 1 meaning "Used by the Windows Container Isolation filter. "]\
GLOBAL_REPARSE [list hex 0xA0000019 obsolete 0 serverside 1 meaning "Used by NPFS to indicate a named pipe symbolic link from a server silo into the host silo."]\
CLOUD [list hex 0x9000001A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_1 [list hex 0x9000101A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_2 [list hex 0x9000201A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_3 [list hex 0x9000301A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_4 [list hex 0x9000401A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_5 [list hex 0x9000501A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_6 [list hex 0x9000601A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_7 [list hex 0x9000701A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_8 [list hex 0x9000801A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_9 [list hex 0x9000901A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_A [list hex 0x9000A01A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_B [list hex 0x9000B01A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_C [list hex 0x9000C01A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_D [list hex 0x9000D01A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_E [list hex 0x9000E01A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
CLOUD_F [list hex 0x9000F01A obsolete 0 serverside 1 meaning "Used by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive."]\
APPEXECLINK [list hex 0x8000001B obsolete 0 serverside 1 meaning "Used by Universal Windows Platform (UWP) packages to encode information that allows the application to be launched by CreateProcess."]\
PROJFS [list hex 0x9000001C obsolete 0 serverside 1 meaning "Used by the Windows Projected File System filter, for files managed by a user mode provider such as VFS for Git."]\
LX_SYMLINK [list hex 0xA000001D obsolete 0 serverside 1 meaning "Used by the Windows Subsystem for Linux (WSL) to represent a UNIX symbolic link."]\
STORAGE_SYNC [list hex 0x8000001E obsolete 0 serverside 1 meaning "Used by the Azure File Sync (AFS) filter."]\
WCI_TOMBSTONE [list hex 0xA000001F obsolete 0 serverside 1 meaning "Used by the Windows Container Isolation filter."]\
UNHANDLED [list hex 0x80000020 obsolete 0 serverside 1 meaning "Used by the Windows Container Isolation filter."]\
ONEDRIVE [list hex 0x80000021 obsolete 0 serverside 0 meaning "Not used"]\
PROJFS_TOMBSTONE [list hex 0xA0000022 obsolete 0 serverside 1 meaning "Used by the Windows Projected File System filter, for files managed by a user mode provider such as VFS for Git."]\
AF_UNIX [list hex 0x80000023 obsolete 0 serverside 1 meaning "Used by the Windows Subsystem for Linux (WSL) to represent a UNIX domain socket."]\
LX_FIFO [list hex 0x80000024 obsolete 0 serverside 1 meaning "Used by the Windows Subsystem for Linux (WSL) to represent a UNIX FIFO (named pipe)."]\
LX_CHR [list hex 0x80000025 obsolete 0 serverside 1 meaning "Used by the Windows Subsystem for Linux (WSL) to represent a UNIX character special file."]\
LX_BLK [list hex 0x80000026 obsolete 0 serverside 1 meaning "Used by the Windows Subsystem for Linux (WSL) to represent a UNIX block special file."]\
WCI_LINK [list hex 0xA0000027 obsolete 0 serverside 1 meaning "Used by the Windows Container Isolation filter."]\
WCI_LINK_1 [list hex 0xA0001027 obsolete 0 serverside 1 meaning "Used by the Windows Container Isolation filter."]\
]
variable win_reparse_tags_by_int
dict for {k v} $win_reparse_tags {
set intkey [expr {[dict get $v hex]}]
set info [dict merge [dict create tag $k] $v] ;#put tag at front
dict set win_reparse_tags_by_int $intkey $info
}
#https://stackoverflow.com/questions/46383428/get-the-immediate-target-path-from-symlink-reparse-point
#need to call twapi::create_file with FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
#then twapi::device_ioctl (win32 DeviceIoControl)
#then parse buffer somehow (binary scan..)
#https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/b41f1cbf-10df-4a47-98d4-1c52a833d913
proc Get_attributes_from_iteminfo {args} {
variable win_reparse_tags_by_int
set argd [punk::args::get_dict {
-debug -default 0 -help "set 1 for raw data on -debugchannel (default stderr)"
-debugchannel -default stderr -help "channel to write debug output, or none to append to output"
*values -min 1 -max 1
iteminfo -help "iteminfo dict as set by 'twapi::find_file_next <iterator> iteminfo'"
} $args]
set opts [dict get $argd opts]
set iteminfo [dict get $argd values iteminfo]
set opt_debug [dict get $opts -debug]
set opt_debugchannel [dict get $opts -debugchannel]
#-longname is placeholder - caller needs to set
set result [dict create -archive 0 -hidden 0 -longname [dict get $iteminfo name] -readonly 0 -shortname {} -system 0]
if {$opt_debug} {
set dbg "iteminfo returned by find_file_open\n"
append dbg [pdict -channel none iteminfo]
if {$opt_debugchannel eq "none"} {
dict set result -debug $dbg
} else {
puts -nonewline $opt_debugchannel $dbg
}
}
set attrinfo [decode_win_attributes [dict get $iteminfo attrs]]
set result [dict create -archive 0 -hidden 0 -longname $path -readonly 0 -shortname {} -system 0]
if {"hidden" in $attrinfo} {
dict set result -hidden 1
}
@ -502,14 +596,48 @@ namespace eval punk::du {
dict set result -readonly 1
}
dict set result -shortname [dict get $iteminfo altname]
dict set result -rawflags $attrinfo
set extras [list]
#foreach prop {ctime atime mtime size} {
# lappend extras $prop [dict get $iteminfo $prop]
#}
#dict set result -extras $extras
dict set result -fileattributes $attrinfo
if {"reparse_point" in $attrinfo} {
#the twapi API splits this 32bit value for us
set low_word [dict get $iteminfo reserve0]
set high_word [dict get $iteminfo reserve1]
# 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
# 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
#+-+-+-+-+-----------------------+-------------------------------+
#|M|R|N|R| Reserved bits | Reparse tag value |
#+-+-+-+-+-----------------------+-------------------------------+
#todo - is_microsoft from first bit of high_word
set low_int [expr {$low_word}] ;#review - int vs string rep for dict key lookup? does it matter?
if {[dict exists $win_reparse_tags_by_int $low_int]} {
dict set result -reparseinfo [dict get $win_reparse_tags_by_int $low_int]
} else {
dict set result -reparseinfo [dict create tag "<UNKNOWN>" hex 0x[format %X $low_int] meaning "unknown reparse tag int:$low_int"]
}
}
dict set result -raw $iteminfo
return $result
}
proc attributes_twapi {args} {
set argd [punk::args::get_dict {
-debug -default 0 -help "set 1 for raw data on -debugchannel (default stderr)"
-debugchannel -default stderr -help "channel to write debug output, or none to append to output"
-detail -default basic -choices {basic full} -help "full returns also the altname/shortname field"
*values -min 1 -max 1
path -help "path to file or folder for which to retrieve attributes"
} $args]
set opts [dict get $argd opts]
set path [dict get $argd values path]
set opt_detail [dict get $opts -detail]
set opt_debug [dict get $opts -debug]
set opt_debugchannel [dict get $opts -debugchannel]
try {
set iterator [twapi::find_file_open $path -detail $opt_detail] ;# -detail full only adds data to the altname field
if {[twapi::find_file_next $iterator iteminfo]} {
set result [Get_attributes_from_iteminfo -debug $opt_debug -debugchannel $opt_debugchannel $iteminfo]
return $result
} else {
error "could not read attributes for $path"
}
@ -519,13 +647,14 @@ namespace eval punk::du {
}
#todo - review 'errors' key. We have errors relating to containing folder and args vs per child-item errors - additional key needed?
namespace export du_dirlisting_twapi du_dirlisting_generic du_dirlisting_unix du_dirlisting_undecided
namespace export attributes_twapi du_dirlisting_twapi du_dirlisting_generic du_dirlisting_unix du_dirlisting_undecided du_dirlisting_tclvfs
# get listing without using unix-tools (may not be installed on the windows system)
# this dirlisting is customised for du - so only retrieves dirs,files,filesizes (minimum work needed to perform du function)
# This also preserves path rep for elements in the dirs/folders keys etc - which can make a big difference in performance
proc du_dirlisting_twapi {folderpath args} {
set defaults [dict create\
-glob *\
-filedebug 0\
-with_sizes 1\
-with_times 1\
]
@ -534,6 +663,9 @@ namespace eval punk::du {
set opt_glob [dict get $opts -glob]
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_with_sizes [dict get $opts -with_sizes]
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_filedebug [dict get $opts -filedebug] ;#per file
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set ftypes [list f d l]
if {"$opt_with_sizes" in {0 1}} {
#don't use string is boolean - (f false vs f file!)
@ -705,6 +837,8 @@ namespace eval punk::du {
set alltimes [dict create]
set links [list]
set linkinfo [dict create]
set debuginfo [dict create]
set flaggedhidden [list]
set flaggedsystem [list]
set flaggedreadonly [list]
@ -717,25 +851,18 @@ namespace eval punk::du {
continue
}
set tail_altname [dict get $iteminfo altname] ;#altname of tail - not whole path
set attrinfo [decode_win_attributes [dict get $iteminfo attrs]]
#puts stderr "$iteminfo"
#puts stderr "$nm -> [dict get $iteminfo attrs] -> $attrinfo"
#set attrinfo [decode_win_attributes [dict get $iteminfo attrs]]
set ftype ""
#attributes applicable to any classification
set fullname [file_join_one $folderpath $nm]
if {"hidden" in $attrinfo} {
lappend flaggedhidden $fullname
}
if {"system" in $attrinfo} {
lappend flaggedsystem $fullname
}
if {"readonly" in $attrinfo} {
lappend flaggedreadonly $fullname
}
set attrdict [Get_attributes_from_iteminfo -debug $opt_filedebug -debugchannel none $iteminfo] ;#-debugchannel none puts -debug key in the resulting dict
set file_attributes [dict get $attrdict -fileattributes]
set linkdata [dict create]
# -----------------------------------------------------------
#main classification
if {"reparse_point" in $attrinfo} {
if {"reparse_point" in $file_attributes} {
#this concept doesn't correspond 1-to-1 with unix links
#https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-points
#review - and see which if any actually belong in the links key of our return
@ -758,17 +885,27 @@ namespace eval punk::du {
#Note also - a shortcut created in explorer with drag and drop to an existant folder is a different animal to a symlink (file with .lnk extension) even though it looks the same in explorer window.
#
#links are techically files too, whether they point to a file/dir or nothing.
lappend links $fullname
set ftype "l"
} elseif {"directory" in $attrinfo} {
dict set linkdata linktype reparse_point
dict set linkdata reparseinfo [dict get $attrdict -reparseinfo]
if {"directory" ni $file_attributes} {
dict set linkdata target_type file
}
}
if {"directory" in $file_attributes} {
if {$nm in {. ..}} {
continue
}
if {"reparse_point" ni $file_attributes} {
lappend dirs $fullname
set ftype "d"
} else {
#other mechanisms can't immediately classify a link as file vs directory - so we don't return this info in the main dirs/files collections
dict set linkdata target_type directory
}
}
if {"reparse_point" ni $file_attributes && "directory" ni $file_attributes} {
#review - is anything that isn't a reparse_point or a directory, some sort of 'file' in this context? What about the 'device' attribute? Can that occur in a directory listing of some sort?
lappend files $fullname
if {"f" in $sized_types} {
@ -776,6 +913,17 @@ namespace eval punk::du {
}
set ftype "f"
}
# -----------------------------------------------------------
if {[dict get $attrdict -hidden]} {
lappend flaggedhidden $fullname
}
if {[dict get $attrdict -system]} {
lappend flaggedsystem $fullname
}
if {[dict get $attrdict -readonly]} {
lappend flaggedreadonly $fullname
}
if {$ftype in $sized_types} {
dict set allsizes $fullname [dict create bytes [dict get $iteminfo size]]
}
@ -789,6 +937,12 @@ namespace eval punk::du {
m [twapi::large_system_time_to_secs_since_1970 [dict get $iteminfo mtime]]\
]
}
if {[dict size $linkdata]} {
dict set linkinfo $fullname $linkdata
}
if {[dict exists $attrdict -debug]} {
dict set debuginfo $fullname [dict get $attrdict -debug]
}
}
twapi::find_file_close $iterator
set vfsmounts [get_vfsmounts_in_folder $folderpath]
@ -799,7 +953,7 @@ namespace eval punk::du {
#also determine whether vfs. file system x is *much* faster than file attributes
#whether or not there is a corresponding file/dir add any applicable mountpoints for the containing folder
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes $filesizes sizes $allsizes times $alltimes flaggedhidden $flaggedhidden flaggedsystem $flaggedsystem flaggedreadonly $flaggedreadonly altname $altname opts $effective_opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links linkinfo $linkinfo files $files filesizes $filesizes sizes $allsizes times $alltimes flaggedhidden $flaggedhidden flaggedsystem $flaggedsystem flaggedreadonly $flaggedreadonly altname $altname opts $effective_opts debuginfo $debuginfo errors $errors]
}
proc get_vfsmounts_in_folder {folderpath} {
set vfsmounts [list]

120
src/vfs/_vfscommon/modules/punk/nav/fs-0.1.0.tm

@ -196,12 +196,12 @@ tcl::namespace::eval punk::nav::fs {
commandstack::basecall cd $VIRTUAL_CWD
}
}
set matchinfo [dirfiles_dict -searchbase $VIRTUAL_CWD]
set matchinfo [dirfiles_dict -searchbase $VIRTUAL_CWD -with_times {f d l} -with_sizes {f d l}]
} else {
if {[pwd] ne $VIRTUAL_CWD} {
commandstack::basecall cd $VIRTUAL_CWD
}
set matchinfo [dirfiles_dict -searchbase [pwd]]
set matchinfo [dirfiles_dict -searchbase [pwd] -with_times {f d l} -with_sizes {f d l}]
}
set dircount [llength [dict get $matchinfo dirs]]
set filecount [llength [dict get $matchinfo files]]
@ -378,7 +378,7 @@ tcl::namespace::eval punk::nav::fs {
}
}
}
set matchinfo [dirfiles_dict -searchbase $searchbase -tailglob $glob $location]
set matchinfo [dirfiles_dict -searchbase $searchbase -tailglob $glob -with_sizes {f d l} -with_times {f d l} $location]
#puts stderr "=--->$matchinfo"
@ -467,7 +467,7 @@ tcl::namespace::eval punk::nav::fs {
}
set normpath [file normalize $path]
cd $normpath
set matchinfo [dirfiles_dict -searchbase $normpath $normpath]
set matchinfo [dirfiles_dict -searchbase $normpath -with_sizes {f d l} -with_times {f d l} $normpath]
set dircount [llength [dict get $matchinfo dirs]]
set filecount [llength [dict get $matchinfo files]]
set location [file normalize [dict get $matchinfo location]]
@ -626,7 +626,7 @@ tcl::namespace::eval punk::nav::fs {
proc dirlist {{location ""}} {
set contents [dirfiles_dict $location]
set contents [dirfiles_dict -with_times {f d l} -with_sizes {f d l} $location]
return [dirfiles_dict_as_lines -stripbase 1 $contents]
}
@ -694,7 +694,7 @@ tcl::namespace::eval punk::nav::fs {
}
}
puts "--> -searchbase:$searchbase searchspec:$searchspec -tailglob:$tailglob location:$location"
set contents [dirfiles_dict -searchbase $searchbase -tailglob $tailglob $location]
set contents [dirfiles_dict -searchbase $searchbase -tailglob $tailglob -with_times {f d l} -with_sizes {f d l} $location]
return [dirfiles_dict_as_lines -stripbase $opt_stripbase -formatsizes $opt_formatsizes $contents]
}
@ -1038,17 +1038,20 @@ tcl::namespace::eval punk::nav::fs {
lappend vfsmounts {*}[dict get $contents vfsmounts]
}
set fkeys [dict create] ;#avoid some file normalize calls..
if {$opt_stripbase && $common_base ne ""} {
set filetails [list]
set dirtails [list]
foreach fileset [list dirs files links underlayfiles flaggedhidden flaggedreadonly flaggedsystem nonportable vfsmounts] {
set stripped [list]
foreach f [set $fileset] {
lappend stripped [strip_prefix_depth $f $common_base]
foreach fullname [set $fileset] {
set shortname [strip_prefix_depth $fullname $common_base]
dict set fkeys $shortname $fullname ;#cache so we can retrieve already normalised name without re-hitting filesystem
lappend stripped $shortname
}
set $fileset $stripped
}
#Note: we need to remember to use common_base to rebuild the key when we need to query the dict-based elements: sizes & times - because we didn't strip those keys.
#Note: without fkeys we would need to remember to use common_base to rebuild (and file normalize!) the key when we need to query the dict-based elements: sizes & times - because we didn't strip those keys.
}
# -- --- --- --- --- --- --- --- --- --- ---
@ -1060,6 +1063,23 @@ tcl::namespace::eval punk::nav::fs {
set dir_symlinks [list]
set dir_shortcuts [list] ;#windows shell links (.lnk) that have a target that is a directory
foreach s $links {
if {[dict exists $contents linkinfo $s target_type]} {
#some mechanisms such as twapi can provide the target_type info so we don't have to re-hit the filesystem.
set target_type [dict get $contents linkinfo $s target_type]
switch -- $target_type {
file {
lappend file_symlinks $s
}
directory {
lappend dir_symlinks $s
lappend dirs $s
}
default {
puts stderr "Warning - cannot determine link type for link $s (target_type value is:$target_type)"
}
}
} else {
#fallback if no target_type
if {[file isfile $s]} {
lappend file_symlinks $s
#will be appended in finfo_plus later
@ -1071,6 +1091,7 @@ tcl::namespace::eval punk::nav::fs {
puts stderr "Warning - cannot determine link type for link $s"
}
}
}
#we now have the issue that our symlinks aren't sorted within the dir/file categorisation - they currently will have to appear at beginning or end - TODO
# -- --- --- --- --- --- --- --- --- --- ---
@ -1083,28 +1104,66 @@ tcl::namespace::eval punk::nav::fs {
if {$opt_formatsizes} {
set filesizes [punk::lib::format_number $filesizes] ;#accepts a list and will process each
}
#col2 with subcolumns
#remove punk::pipedata dependency - allow use of punk::nav::fs without punk package
#set widest2a [punk::pipedata [list {*}$files ""] {lmap v $data {string length $v}} {tcl::mathfunc::max {*}$data}]
#widest2a.= concat $files [list ""] |> .=>2 lmap v {string length $v} |> .=>* tcl::mathfunc::max
#col2 (file info) with subcolumns
set widest2a [tcl::mathfunc::max {*}[lmap v [list {*}$files {*}$file_symlinks ""] {string length $v}]]
set c2a [string repeat " " [expr {$widest2a + 1}]]
#set widest2b [punk::pipedata [list {*}$filesizes ""] {lmap v $data {string length $v}} {tcl::mathfunc::max {*}$data}]
set widest2b [tcl::mathfunc::max {*}[lmap v [list {*}$filesizes ""] {string length $v}]]
set c2b [string repeat " " [expr {$widest2b + 1}]]
#c2c timestamp and short note - fixed width 19 for ts + <sp> + filetype note e.g "symlink" "shortcut" "binary" ?? combinations? allow 2 words 10 each for 21 + 1 for luck
# total 42
set c2c [string repeat " " 42]
set finfo [list]
foreach f $files s $filesizes {
if {[dict size $fkeys]} {
set key [dict get $fkeys $f]
} else {
#not stripped - they should match
set key $f
}
#note - the display entry isn't necessarily a valid tcl list e.g filename with unbalanced curly braces
#hence we need to keep the filename as well, properly protected as a list element
lappend finfo [list file $f display "[overtype::left $c2a $f] [overtype::right $c2b $s]"]
if {[dict exists $contents times $key m]} {
set mtime [dict get $contents times $key m]
set ts [tcl::clock::format $mtime -format "%Y-%m-%d %H:%M:%S"]
} else {
#set ts [string repeat { } 19]
set ts "$key vs [dict keys [dict get $contents times]]"
}
set note ""
lappend finfo [list file $f display "[overtype::left $c2a $f] [overtype::right $c2b $s] [overtype::left $c2c "$ts $note"]"]
}
set flink_style [punk::ansi::a+ undercurly underline undt-green] ;#curly green underline with fallback to normal underline
set dlink_style [punk::ansi::a+ undercurly underline undt-green]
#We use an underline so the visual styling of a link can coexist with fg/bg colors applied for other attributes such as hidden
foreach flink $file_symlinks {
lappend finfo [list file $flink display "$flink_style[overtype::left $c2a $flink] [overtype::right $c2b 0]"]
if {[dict size $fkeys]} {
set key [dict get $fkeys $flink]
} else {
set key $flink
}
if {[dict exists $contents times $key m]} {
set mtime [dict get $contents times $key m]
set ts [tcl::clock::format $mtime -format "%Y-%m-%d %H:%M:%S"]
} else {
set ts "[string repeat { } 19]"
}
set note "link" ;#default only
if {[dict exists $contents linkinfo $key linktype]} {
if {[dict get $contents linkinfo $key linktype] eq "reparse_point"} {
set note "reparse_point"
if {[dict exists $contents linkinfo $key reparseinfo tag]} {
append note " " [dict get $contents linkinfo $key reparseinfo tag]
}
} else {
append note "$key vs [dict keys [dict get $contents linkinfo]]"
}
}
lappend finfo [list file $flink display "$flink_style[overtype::left $c2a $flink] [overtype::right $c2b 0] [overtype::left $c2c "$ts $note"]"]
}
set fshortcut_style [punk::ansi::a+ underdotted underline undt-hotpink]
@ -1120,9 +1179,10 @@ tcl::namespace::eval punk::nav::fs {
set shortcutinfo [punk::winlnk::file_get_info $fname]
set target_type "file" ;#default/fallback
if {[dict exists $shortcutinfo link_target]} {
set is_valid_lnk 1
set tgt [dict get $shortcutinfo link_target]
if {[file exists $tgt]} {
#file type could return 'link' - we will use ifile/isdirectory
#file type could return 'link' - we will use isfile/isdirectory
if {[file isfile $tgt]} {
set target_type file
} elseif {[file isdirectory $tgt]} {
@ -1134,11 +1194,15 @@ tcl::namespace::eval punk::nav::fs {
#todo - see if punk::winlnk has info about the type at the time of linking
#for now - treat as file
}
} else {
#no link_target - probably an ordinary file - but there could have been some other error in reading the binary windows lnk format.
set is_valid_lnk 0
}
if {$is_valid_lnk} {
switch -- $target_type {
file {
set display [dict get $fdict display]
set display $fshortcut_style$display ;#
set display "$fshortcut_style$display (shortcut $tgt)" ;#
dict set fdict display $display
lappend finfo_plus $fdict
}
@ -1149,6 +1213,28 @@ tcl::namespace::eval punk::nav::fs {
lappend dir_shortcuts $fname
}
}
} else {
#we were unable to get link_target - but we still need to check if it failed the header check (then assume not intended to be a windows shell lnk) or for some other reason.
if {[dict exists $shortcutinfo error]} {
if {[dict get $shortcutinfo error] ne "lnk_header_check_failed"} {
#Presumably there is a valid lnk header, but some unexpected error occurred - show it in the display for the file
#still style as a windows shell lnk - as to get here, the header check must have passed.
set display [dict get $fdict display]
set display "$fshortcut_style$display (shortcut error [dict get $shortcutinfo error])" ;#
dict set fdict display $display
lappend finfo_plus $fdict
} else {
#error of lnk_header_check_failed means it probably just isn't a windows shell link. Leave ordinary display for file.
lappend finfo_plus $fdict
}
} else {
#shouldn't ever happen. If no error, then there should have been a link_target
#report and move on
puts stderr "Unexpected error in result of parsing binary format for $fname"
lappend finfo_plus $fdict
}
}
#assert - we have either appended to finfo_plus (possibly with shortcut info/error if binary header was valid) - or appended to dirs (if it was a valid lnk and target was a dir)
}
#if we don't have punk::winlnk to read the .lnk - it will get no special highlighting and just appear as an ordinary file even if it points to a dir
} else {

2
src/vfs/_vfscommon/modules/punk/winlnk-0.1.0.tm

@ -252,7 +252,7 @@ tcl::namespace::eval punk::winlnk {
#https://github.com/libyal/liblnk/blob/main/documentation/Windows%20Shortcut%20File%20(LNK)%20format.asciidoc
#offset 24 4 bytes
#File attribute flags

238
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/autoscroll/autoscroll.tcl

@ -0,0 +1,238 @@
# autoscroll.tcl --
#
# Package to create scroll bars that automatically appear when
# a window is too small to display its content.
#
# Copyright (c) 2003 Kevin B Kenny <kennykb@users.sourceforge.net>
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: autoscroll.tcl,v 1.8 2005/06/01 02:37:51 andreas_kupries Exp $
package require Tk
package provide autoscroll 1.1
namespace eval ::autoscroll {
namespace export autoscroll unautoscroll
bind Autoscroll <Destroy> [namespace code [list destroyed %W]]
bind Autoscroll <Map> [namespace code [list map %W]]
}
#----------------------------------------------------------------------
#
# ::autoscroll::autoscroll --
#
# Create a scroll bar that disappears when it is not needed, and
# reappears when it is.
#
# Parameters:
# w -- Path name of the scroll bar, which should already exist
#
# Results:
# None.
#
# Side effects:
# The widget command is renamed, so that the 'set' command can
# be intercepted and determine whether the widget should appear.
# In addition, the 'Autoscroll' bind tag is added to the widget,
# so that the <Destroy> event can be intercepted.
#
#----------------------------------------------------------------------
proc ::autoscroll::autoscroll { w } {
if { [info commands ::autoscroll::renamed$w] != "" } { return $w }
rename $w ::autoscroll::renamed$w
interp alias {} ::$w {} ::autoscroll::widgetCommand $w
bindtags $w [linsert [bindtags $w] 1 Autoscroll]
eval [list ::$w set] [renamed$w get]
return $w
}
#----------------------------------------------------------------------
#
# ::autoscroll::unautoscroll --
#
# Return a scrollbar to its normal static behavior by removing
# it from the control of this package.
#
# Parameters:
# w -- Path name of the scroll bar, which must have previously
# had ::autoscroll::autoscroll called on it.
#
# Results:
# None.
#
# Side effects:
# The widget command is renamed to its original name. The widget
# is mapped if it was not currently displayed. The widgets
# bindtags are returned to their original state. Internal memory
# is cleaned up.
#
#----------------------------------------------------------------------
proc ::autoscroll::unautoscroll { w } {
if { [info commands ::autoscroll::renamed$w] != "" } {
variable grid
rename ::$w {}
rename ::autoscroll::renamed$w ::$w
if { [set i [lsearch -exact [bindtags $w] Autoscroll]] > -1 } {
bindtags $w [lreplace [bindtags $w] $i $i]
}
if { [info exists grid($w)] } {
eval [join $grid($w) \;]
unset grid($w)
}
}
}
#----------------------------------------------------------------------
#
# ::autoscroll::widgetCommand --
#
# Widget command on an 'autoscroll' scrollbar
#
# Parameters:
# w -- Path name of the scroll bar
# command -- Widget command being executed
# args -- Arguments to the commane
#
# Results:
# Returns whatever the widget command returns
#
# Side effects:
# Has whatever side effects the widget command has. In
# addition, the 'set' widget command is handled specially,
# by gridding/packing the scroll bar according to whether
# it is required.
#
#------------------------------------------------------------
proc ::autoscroll::widgetCommand { w command args } {
variable grid
if { $command == "set" } {
foreach { min max } $args {}
if { $min <= 0 && $max >= 1 } {
switch -exact -- [winfo manager $w] {
grid {
lappend grid($w) "[list grid $w] [grid info $w]"
grid forget $w
}
pack {
foreach x [pack slaves [winfo parent $w]] {
lappend grid($w) "[list pack $x] [pack info $x]"
}
pack forget $w
}
}
} elseif { [info exists grid($w)] } {
eval [join $grid($w) \;]
unset grid($w)
}
}
return [eval [list renamed$w $command] $args]
}
#----------------------------------------------------------------------
#
# ::autoscroll::destroyed --
#
# Callback executed when an automatic scroll bar is destroyed.
#
# Parameters:
# w -- Path name of the scroll bar
#
# Results:
# None.
#
# Side effects:
# Cleans up internal memory.
#
#----------------------------------------------------------------------
proc ::autoscroll::destroyed { w } {
variable grid
catch { unset grid($w) }
rename ::$w {}
}
#----------------------------------------------------------------------
#
# ::autoscroll::map --
#
# Callback executed when an automatic scroll bar is mapped.
#
# Parameters:
# w -- Path name of the scroll bar.
#
# Results:
# None.
#
# Side effects:
# Geometry of the scroll bar's top-level window is constrained.
#
# This procedure keeps the top-level window associated with an
# automatic scroll bar from being resized automatically after the
# scroll bar is mapped. This effect avoids a potential endless loop
# in the case where the resize of the top-level window resizes the
# widget being scrolled, causing the scroll bar no longer to be needed.
#
#----------------------------------------------------------------------
proc ::autoscroll::map { w } {
wm geometry [winfo toplevel $w] [wm geometry [winfo toplevel $w]]
}
#----------------------------------------------------------------------
#
# ::autoscroll::wrap --
#
# Arrange for all new scrollbars to be automatically autoscrolled
#
# Parameters:
# None.
#
# Results:
# None.
#
# Side effects:
# ::scrollbar is overloaded to automatically autoscroll any new
# scrollbars.
#
#----------------------------------------------------------------------
proc ::autoscroll::wrap {} {
if {[info commands ::autoscroll::_scrollbar] != ""} {return}
rename ::scrollbar ::autoscroll::_scrollbar
proc ::scrollbar {w args} {
eval ::autoscroll::_scrollbar [list $w] $args
::autoscroll::autoscroll $w
return $w
}
}
#----------------------------------------------------------------------
#
# ::autoscroll::unwrap --
#
# Turns off automatic autoscrolling of new scrollbars. Does not
# effect existing scrollbars.
#
# Parameters:
# None.
#
# Results:
# None.
#
# Side effects:
# ::scrollbar is returned to its original state
#
#----------------------------------------------------------------------
proc ::autoscroll::unwrap {} {
if {[info commands ::autoscroll::_scrollbar] == ""} {return}
rename ::scrollbar {}
rename ::autoscroll::_scrollbar ::scrollbar
}

13
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/autoscroll/pkgIndex.tcl

@ -0,0 +1,13 @@
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script. It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands. When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.
if { ![package vsatisfies [package provide Tcl] 8.2] } { return }
package ifneeded autoscroll 1.1 [list source [file join $dir autoscroll.tcl]]

278
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_drag.tcl

@ -0,0 +1,278 @@
## -*- tcl -*-
# ### ### ### ######### ######### #########
# Canvas Behavior Module. Dragging items and groups of items.
# ### ### ### ######### ######### #########
## Requisites
package require Tcl 8.5-
package require Tk
# ### ### ### ######### ######### #########
## API
namespace eval ::canvas::drag {
namespace export \
item group on off
namespace ensemble create
}
proc ::canvas::drag::item {c tag args} {
# Set up dragging of single items identified by the <tag>
on $c $tag [namespace code Item1] {*}$args
return
}
proc ::canvas::drag::group {c tag cmdprefix args} {
# Set up dragging a group of items, with each group's drag
# handle(s) identified by <tag>, and the <cmdprefix> taking the
# handle item which triggered the drag and returning a tag which
# identifies the whole group to move.
on $c $tag [namespace code [list ItemGroup $cmdprefix]] {*}$args
return
}
proc ::canvas::drag::on {c tag cmdprefix args} {
# Setting up a general drag, with the drag handles identified by
# <tag> and <cmdprefix> providing start/move methods invoked to
# initialize and perform the drag. The cmdprefix is fully
# responsible for how the dragging of a particular handle is
# handled.
variable attached
# Process options (-event)
set events [dict get [Options {*}$args] event]
# Save the (canvas, tag) combination for use by 'off'.
set k [list $c $tag]
set attached($k) $events
# Install the bindings doing the drag
lassign $events trigger motion untrigger
$c bind $tag $trigger [namespace code [list Start $c $cmdprefix %x %y]]
$c bind $tag $motion [namespace code [list Move $c $cmdprefix %x %y]]
$c bind $tag $untrigger [namespace code [list Done $c $cmdprefix %x %y]]
return
}
proc ::canvas::drag::off {c tag} {
# Remove a drag identified by canvas and tag.
variable attached
# Find and remove the bindings for this particular canvas,tag
# combination.
set k [list $c $tag]
foreach event $attached($k) {
$c bind $tag $event {}
}
# Update our database
unset attached($k)
return
}
# ### ### ### ######### ######### #########
## Option processing.
proc ::canvas::drag::Options {args} {
# Button 3 is default for dragging.
set config [list event [Validate 3]]
foreach {option value} $args {
switch -exact -- $option {
-event {
dict set config event [Validate $value]
}
default {
return -code error "Unknown option \"$option\", expected -event"
}
}
}
return $config
}
# ### ### ### ######### ######### #########
## Event parsing and transformation
proc ::canvas::drag::Validate {event} {
# Assumes that events are specified in the forms
# <modifier>-<button> and <button>, where <modifier> is in the set
# {Control, Shift, Alt, ... } and <button> a number. Returns
# button-press and related motion event, or throws an error.
set xevent [split $event -]
if {[llength $xevent] > 2} {
return -code error "Bad event \"$event\""
} elseif {[llength $xevent] == 2} {
lassign $xevent modifier button
set trigger <${event}>
set motion <${modifier}-B${button}-Motion>
set untrigger <${modifier}-ButtonRelease-${button}>
} else {
lassign $xevent button
set modifier {}
set trigger <${button}>
set motion <B${button}-Motion>
set untrigger <ButtonRelease-${button}>
}
return [list $trigger $motion $untrigger]
}
# ### ### ### ######### ######### #########
## Drag execution.
proc ::canvas::drag::Start {c cmdprefix x y} {
# Start a drag operation.
variable attached
variable active
variable clientdata
variable lastx
variable lasty
# Clear drag state
unset -nocomplain active clientdata lastx lasty
# Get item under mouse, if any.
set item [$c find withtag current]
if {$item eq {}} return
# Initialize the drag state, run the command to initialize
# anything external to us. We remember the current location to
# enable the delta calculations in 'Move'.
set active $cmdprefix
set lastx [$c canvasx $x]
set lasty [$c canvasy $y]
set clientdata [{*}$active start $c $item]
return
}
proc ::canvas::drag::Move {c cmdprefix x y} {
# Check for active drag.
variable active
if {![info exists active]} return
# Import remainder of the drag state
variable clientdata
variable lastx
variable lasty
# Get current location and compute delta.
set x [$c canvasx $x]
set y [$c canvasy $y]
set dx [expr {$x - $lastx}]
set dy [expr {$y - $lasty}]
# Let the command process the movement as it sees fit.
# This may include updated client data.
set clientdata [{*}$active move $c $clientdata $dx $dy]
# Save the new location , for the next movement and delta.
set lastx $x
set lasty $y
return
}
proc ::canvas::drag::Done {c cmdprefix x y} {
# Check for active drag.
variable active
if {![info exists active]} return
# Import remainder of the drag state
variable clientdata
# Let the command process the end of the drag operation as it sees
# fit.
{*}$active done $c $clientdata
return
}
# ### ### ### ######### ######### #########
## Convenience. Dragging a single item.
# This is trivial. We remember the item to be dragged, and forward
# move requests directly to the canvas.
namespace eval ::canvas::drag::Item1 {
namespace export start move done
namespace ensemble create
}
proc ::canvas::drag::Item1::start {c item} {
return $item
}
proc ::canvas::drag::Item1::move {c item dx dy} {
$c move $item $dx $dy
return $item
}
proc ::canvas::drag::Item1::done {c item} {
return
}
# ### ### ### ######### ######### #########
## Convenience. Dragging an item group.
# Also mostly trivial. The move requests are still simply forwarded to
# the canvas, using the tag identifying the group. The main point is
# during start, using the external callback to transform the handle
# item into the group tag.
proc ::canvas::drag::ItemGroup {cmd method c args} {
return [ItemGroup::$method $cmd $c {*}$args]
}
namespace eval ::canvas::drag::ItemGroup {}
proc ::canvas::drag::ItemGroup::start {cmd c item} {
return [{*}$cmd start $c $item]
}
proc ::canvas::drag::ItemGroup::move {cmd c grouptag dx dy} {
$c move $grouptag $dx $dy
return $grouptag
}
proc ::canvas::drag::ItemGroup::done {cmd c grouptag} {
{*}$cmd done $c $grouptag
return
}
# ### ### ### ######### ######### #########
## State.
namespace eval ::canvas::drag {
# Database of canvas,tag combinations with active bindings
# (allowing their removal, see --> 'off'). Value are the
# events which have bindings.
variable attached
array set attached {}
# State of a drag in progress
variable active ; # command prefix to invoke for 'start' / 'move'.
variable clientdata ; # Result of invoking 'start', data for 'move'.
variable lastx ; # x coord of last position the drag was at.
variable lasty ; # y coord of last position the drag was at.
}
# ### ### ### ######### ######### #########
## Ready
package provide canvas::drag 0.1
return
# ### ### ### ######### ######### #########
## Scrap yard.

383
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_ecircle.tcl

@ -0,0 +1,383 @@
## -*- tcl -*-
# # ## ### ##### ######## ############# #####################
# Canvas Behavior Module. Editing 2 points describing an axis-aligned circle.
# Core interaction behaviour inherited from canvas::edit::points
# Configurable:
# - Tag used to mark/identify the points of this cloud.
# Default: CIRCLE
#
# - Callback used to create the item (group) representing the point.
# Default: <Inherited from the subordinate point cloud editor>
#
# - Callback used to report on circle editing activity.
# Default: NONE.
#
# - Callback used to report enter/leave events for the circle and its points.
# Default: NONE.
# # ## ### ##### ######## ############# #####################
## Requisites
package require Tcl 8.5-
package require Tk
package require snit
package require canvas::edit::points
namespace eval ::canvas::edit {
namespace export circle
namespace ensemble create
}
# # ## ### ##### ######## ############# #####################
## API
snit::type ::canvas::edit::circle {
# See canvas::edit::points
option -tag -default CIRCLE -readonly 1
option -create-cmd -default {} \
-configuremethod Chain \
-cgetmethod UnChain
# Callback reporting the circle after changes (add, remove, drag)
option -data-cmd -default {}
# Callback reporting when the circle or any of the points have the mouse over it
option -active-cmd -default {}
# See canvas::edit::points, also base config for circle
option -color -default SkyBlue2 -configuremethod Pass
option -hilit-color -default red -configuremethod Pass
# See canvas::edit::points
option -radius -default 3 -configuremethod Pass
option -kind -default oval -configuremethod Pass
# See canvas::edit::points, -add-remove also for click on circle
option -add-remove-point -default {} -readonly 1
option -drag-point -default 3 -readonly 1
# Additional circle configuration
# NOTE: __Cannot__ supercede -color/-hilit-color
option -circle-config -default {}
method Pass {o v} {
if {$v eq $options($o)} { return 0 }
set options($o) $v
if {$myeditor eq {}} { return 1 }
$myeditor configure $o $v
return 1
}
method Chain {o v} {
if {$v eq $options($o)} { return 0 }
set options($o) $v
if {$myeditor eq {}} { return 1 }
# Reconfigure the editor with our behaviour still in the chain
$myeditor configure -create-cmd [mymethod Deny $v]
return 1
}
method Unchain {o} {
# Hide the internal -create-cmd chaining from the user
return [$myeditor cget -create-cmd]
}
# # ## ### ##### ######## ############# #####################
constructor {c args} {
set mycanvas $c
set mystate {}
set myops base
$self configurelist $args
# Generate an internal point cloud editor, which will handle
# the basic tasks regarding the circles's vertices.
lappend cmd canvas::edit points ${selfns}::P $c
lappend cmd -tag $options(-tag)
lappend cmd -data-cmd [mymethod Point]
lappend cmd -active-cmd [mymethod PointActive]
# Pass point options/configuration to the subordinate editor
foreach o {
-create-cmd
-color
-hilit-color
-radius
-kind
-add-remove-point
-drag-point
} {
set c $options($o)
if {$c ne {}} { lappend cmd $o $c }
}
set myeditor [{*}$cmd]
$myeditor configure -create-cmd \
[mymethod Deny [$myeditor cget -create-cmd]]
$mycanvas bind [SegmentTag] <Enter> [mymethod Active circle]
$mycanvas bind [SegmentTag] <Leave> [mymethod Active {} ]
return
}
component myeditor
delegate method enable to myeditor
delegate method disable to myeditor
delegate method active to myeditor
method clear {} {
set myops shunt
$myeditor clear
set myops base
set mystate {}
set mycoords {}
$self Regenerate
Note
return
}
method set {center radius} {
$self clear
lassign $center x y
set edge [list [expr {$x + $radius} $y]]
$myeditor add {*}$center
$myeditor add {*}$edge
return
}
# # ## ### ##### ######## ############# #####################
## Actions bound to events, as reported by the point cloud editor.
method Deny {chain c x y} {
#puts deny/$myops/$mystate/
# Deny more points when we have the complete set.
if {$myops eq "complete"} return
# Continue to actual marker creation.
return [{*}$chain $c $x $y]
}
method PointActive {_ corner} {
if {$myops ne "complete"} return
if {$corner ne {}} { set corner [dict get $mystate $corner] }
$self Active $corner
return
}
method Active {kind} {
# puts /$kind/
if {![llength $options(-active-cmd)]} return
{*}$options(-active-cmd) $self $kind
return
}
method {Point add} {pe id x y} {
switch -exact -- $myops {
shunt {}
base {
Save $id center $x $y
set myops partial
return
}
partial {
Save $id edge $x $y
set myops complete
$self Regenerate
Note
}
complete {
return -code error "Should have been rejected by `Deny`"
}
}
}
method {Point remove} {pe id} {
switch -exact -- $myops {
shunt {}
base {
# no points known. nothing to do
return
}
partial {
# first point known, no second point. drop memory of first point
set mystate {}
set myops base
return
}
complete {
# removing even one point of the circle removes the entire circle!
# Disable point callbacks invoked due to this automatic task.
set myops shunt
# Find the corner removed by the user and drop it from the state.
# Then remove the remaining corners
set corner [dict get $mystate $id]
dict unset mystate $id
dict unset mystate $corner
foreach corner $ourcorners {
if {![dict exists $mystate $corner]} continue
$pe remove [dict get $mystate $corner]
}
# enter base state waiting for a new first point
set myops base
set mystate {}
set mycoords {}
$self Regenerate
Note
return
}
}
return
}
method {Point move start} {pe id} {
# Initialize local drag state.
set mydid $id
set corner [dict get $mystate $id]
set mydloc [dict get $mycoords $corner]
return
}
method {Point move delta} {pe id nx ny dx dy} {
# Track the movement.
set mydloc [list $nx $ny]
return
}
method {Point move done} {pe id} {
set corner [dict get $mystate $id]
Save $id $corner {*}$mydloc
$self Regenerate
Note
return 1
}
method Regenerate {} {
if {$mycircle ne {}} {
$mycanvas delete $mycircle
set mycircle {}
}
if {$myops ne "complete"} return
lassign [dict get $mycoords center] cx cy
lassign [dict get $mycoords edge ] ex ey
set radius [expr { hypot ($ex - $cx, $ey - $cy) }]
set w [expr {$cx - $radius}]
set n [expr {$cy - $radius}]
set e [expr {$cx + $radius}]
set s [expr {$cy + $radius}]
set mycircle [$mycanvas create oval $w $n $e $s \
-fill {} \
-width 2 \
{*}$options(-circle-config) \
-activeoutline $options(-hilit-color) \
-outline $options(-color)]
canvas::tag append $mycanvas $mycircle [SegmentTag]
$mycanvas lower $mycircle $options(-tag)
return
}
# # ## ### ##### ######## ############# #####################
## Corner management
proc Save {id corner x y} {
upvar 1 mystate mystate mycoords mycoords
dict set mycoords $corner [list $x $y]
dict set mystate $corner $id
dict set mystate $id $corner
return
}
proc SegmentTag {} {
upvar 1 options options
return $options(-tag)/Circle
}
#### Generate notification about changes to the point cloud.
proc Note {} {
upvar 1 options options self self myops myops mycoords mycoords
if {![llength $options(-data-cmd)]} return
switch -exact -- $myops {
shunt - base - partial {
set details {}
}
complete {
set center [dict get $mycoords center]
lassign $center cx cy
lassign [dict get $mycoords edge] ex ey
set radius [expr { hypot ($ex - $cx, $ey - $cy) }]
set details [list $center $radius]
}
}
return [{*}$options(-data-cmd) $self $details]
}
# debug support ...
proc X {p} { return [lindex [split $p /] 0] }
# # ## ### ##### ######## ############# #####################
## STATE
# - Saved handle of the canvas operated on.
# - Counter for the generation of point identifiers
# - List of the points managed by the object, conveying their
# order.
# - Canvas items for the actual circle
typevariable ourcorners {center edge}
variable mycanvas {} ;# The canvas we are working with.
variable myeditor {} ;# point editor instance managing the circle corners
variable mystate {} ;# dict, general state
variable myops {} ;# system state controlling callback processing
# states
# - base No points present, accept base point
# - shunt Ignore point editor callback, automatic task in progress
# - partial Single point known, wait for the second corner
# - complete Circle is complete, deny more points
variable mycoords {} ;# corner -> pair (x y)
variable mycircle {} ;# circle item
variable mydid ; # Drag state. id of the moving point.
variable mydloc ; # Drag state. Uncommitted location of the moving point.
# # ## ### ##### ######## ############# #####################
}
# # ## ### ##### ######## ############# #####################
## Ready
package provide canvas::edit::circle 0.1
return
# # ## ### ##### ######## ############# #####################
## Scrap yard.

453
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_epoints.tcl

@ -0,0 +1,453 @@
## -*- tcl -*-
# # ## ### ##### ######## ############# #####################
# Canvas Behavior Module. Editing a point cloud.
# - Create point - B1 (canvas global)
# - Remove point - B2 (linked to -tag, current item)
# - Drag/Move point - B3 (linked to -tag, current item)
# - Auto-highlight points, to show ability of drag/move.
# Configurable:
# - Tag used to mark/identify the points of this cloud.
# Default: POINT.
#
# - Callback used to create the item (group) representing the point.
# Default: Single blue circle of radius 3 with center at point location.
# Active color red.
#
# - Callback used to record editing activity (add, remove, move point)
# Default: Do nothing, accept all moves
#
# - Callback used to report enter/leave editing activity on the points
# Default: Do nothing.
# # ## ### ##### ######## ############# #####################
## Requisites
package require Tcl 8.5-
package require Tk
package require snit
package require canvas::drag
package require canvas::tag
namespace eval ::canvas::edit {
namespace export points
namespace ensemble create
}
# # ## ### ##### ######## ############# #####################
## API
snit::type ::canvas::edit::points {
# # ## ### ##### ######## ############# #####################
## Life cycle, and configuration
option -tag -default POINT -readonly 1 ;# Tag identifying our points
option -create-cmd -default {} ;# Callback invoked to create new points.
option -data-cmd -default {} ;# Callback for point edit operations
option -active-cmd -default {} ;# Callback to report point with mouse over it
# data-cmd signatures ...
# DC add (canvas group x y ) :: VOID
# DC remove (canvas group ) :: VOID
# DC move start (canvas group ) :: VOID
# DC move delta (canvas group x y dx dy) :: VOID
# DC move done (canvas group ) :: boolean
# Options to tweak the default marker style without having to go for full-custom callback
# Blue filled circle of radius 3, with a black border. See `DefaultCreate`.
option -color -default SkyBlue2
option -hilit-color -default red
option -radius -default 3
option -kind -default oval
# Event options ...
option -add-remove-point -default {} -readonly 1 ; # Event to add/remove a point
option -drag-point -default 3 -readonly 1 ; # Event to drag a point
constructor {c args} {
set options(-data-cmd) [mymethod DefaultData]
set options(-create-cmd) [mymethod DefaultCreate]
$self configurelist $args
set mycanvas $c
# TODO :: Connect this to the option processing to allow me to
# drop -readonly 1 from their definition. Note that this also
# requires code to re-tag all the items on the fly.
#$self Bindings Add {}
$mycanvas bind $options(-tag) <Enter> [mymethod Active 1 $mycanvas %x %y]
$mycanvas bind $options(-tag) <Leave> [mymethod Active 0 $mycanvas %x %y]
return
}
destructor {
if {![winfo exists $mycanvas]} return
$self Bindings Remove {}
return
}
# # ## ### ##### ######## ############# #####################
## API.
method disable {args} {
$self Bindings Remove $args
return
}
method enable {args} {
$self Bindings Add $args
return
}
method active {} {
return $myactive
}
method add {x y} {
# Create a point marker programmatically. This enables users
# to load an editor instance with existing point locations.
return [$self AddCore $mycanvas $x $y]
}
method remove {id} {
$self RemoveByTag $id
return
}
method move-to {id x y} {
$self MoveTo $id $x $y
return
}
method move-by {id dx dy} {
$self MoveBy $id $dx $dy
return
}
method current {} {
return [GetId $mycanvas [$mycanvas find withtag current]]
}
###### Destroy an existing point
method clear {} {
set grouptags {}
foreach item [$mycanvas find withtag $options(-tag)] {
lappend grouptags [GetId $mycanvas $item]
}
foreach grouptag [lsort -unique $grouptags] {
$mycanvas delete $grouptag
#puts "Remove|$x $y|$grouptag"
unset myloc($grouptag)
Note remove $grouptag
}
return
}
# # ## ### ##### ######## ############# #####################
## Manage the canvas bindings (point creation and removal, dragging).
method {Bindings Add} {parts} {
if {![llength $parts]} { lappend parts drag edit }
foreach part $parts {
switch -exact -- $part {
drag {
canvas::drag on $mycanvas $options(-tag) \
[mymethod Drag] \
-event $options(-drag-point)
}
edit {
if {$myactive} return
set myactive 1
# NOTES:
# 1. Is there a way to make 'Add' not canvas global ?
# 2. If not, is there a way to ensure that 'Add' is not triggered when a
# 'Remove' is done, even if the events for the 2 actions basically overlap
# (B1=Add, Shift-B1=Remove, for example) ?
#
# We know that Remove, as item binding, is run before the global Add.
if {$options(-add-remove-point) ne {}} {
set event <$options(-add-remove-point)>
$mycanvas bind $options(-tag) $event [mymethod Remove $mycanvas %x %y 1]
bind $mycanvas $event [mymethod Add $mycanvas %x %y 1]
} else {
$mycanvas bind $options(-tag) <2> [mymethod Remove $mycanvas %x %y 0]
bind $mycanvas <1> [mymethod Add $mycanvas %x %y 0]
}
}
}
}
return
}
method {Bindings Remove} {parts} {
if {![llength $parts]} { lappend parts drag edit }
foreach part $parts {
switch -exact -- $part {
drag {
canvas::drag off $mycanvas $options(-tag)
}
edit {
if {!$myactive} return
set myactive 0
if {$options(-add-remove-point) ne {}} {
set event <$options(-add-remove-point)>
$mycanvas bind $options(-tag) $event {}
bind $mycanvas $event {}
} else {
$mycanvas bind $options(-tag) <2> {}
bind $mycanvas <1> {}
}
}
}
}
return
}
# # ## ### ##### ######## ############# #####################
## The actions invoked by the bindings managed in the previous
## section.
###### Place new point
method Add {c x y skip} {
# x, y are relative to the viewport
if {$skip && $myskip} { set myskip 0 ; return }
$self CheckCanvas $c
# Translate into actual canvas coordinates
set x [$c canvasx $x]
set y [$c canvasy $y]
$self AddCore $c $x $y
}
method AddCore {c x y} {
# x, y are absolute canvas coordinates
set grouptag [NewId]
set items [{*}$options(-create-cmd) $c $x $y]
# No visual representation of the point, no point. Vetoed.
if {![llength $items]} return
Tag $c $items $grouptag
set myloc($grouptag) [list $x $y]
#puts "Add|$x $y|$items"
Note add $grouptag $x $y
return $grouptag
}
###### Destroy an existing point
method Remove {c x y skip} {
$self CheckCanvas $c
#puts "Remove|$x $y|[$c find withtag current]"
$self RemoveByTag [GetId $c [$c find withtag current]]
set myskip $skip
return
}
method RemoveByTag {grouptag} {
$mycanvas delete $grouptag
#puts "RemoveTag|$grouptag"
unset myloc($grouptag)
Note remove $grouptag
return
}
###### Move existing point programmatically, absolute or relative
method MoveTo {grouptag x y} {
set myloc($grouptag) [list $x $y]
$mycanvas moveto $grouptag $x $y
return
}
method MoveBy {grouptag dx dy} {
lassign $myloc($grouptag) x y
set x [expr {$x + $dx}]
set y [expr {$y + $dy}]
set myloc($grouptag) [list $x $y]
$mycanvas move $grouptag $dx $dy
return
}
###### Drag management. On start of a drag ... Identify the group of items to move.
method {Drag start} {c item} {
$self CheckCanvas $c
#puts "Drag Start|$item|"
set grouptag [GetId $c $item]
set mydbox [$c bbox $grouptag]
Note {move start} $grouptag
return $grouptag
}
###### Drag management. During a drag ... Move the grouped items.
method {Drag move} {c grouptag dx dy} {
$self CheckCanvas $c
#puts "Drag Move|$grouptag|$dx $dy|"
$c move $grouptag $dx $dy
lassign [Delta] px py dx dy
Note {move delta} $grouptag $px $py $dx $dy
return $grouptag
}
###### Drag management. After a drag ...
method {Drag done} {c grouptag} {
$self CheckCanvas $c
#puts "Drag Done|$grouptag|"
set ok [Note {move done} $grouptag]
lassign [Delta] px py dx dy
if {$ok} {
# Commit to new location.
set myloc($grouptag) [list $px $py]
} else {
# Vetoed. Undo the move.
set dx [expr {- $dx}]
set dy [expr {- $dy}]
$c move $grouptag $dx $dy
}
return
}
# # ## ### ##### ######## ############# #####################
## Class global commands for the actions in the previous section.
#### Generate notification about changes to the point cloud.
proc Note {cmd args} {
upvar 1 options options self self
if {![llength $options(-data-cmd)]} return
return [{*}$options(-data-cmd) {*}$cmd $self {*}$args]
}
#### Generate a unique tag for a new point.
#### The tag references editor instance and type
proc NewId {} {
upvar 1 mycounter mycounter self self type type
return P[incr mycounter]/$self/$type
}
#### Link both the unique tag for a point marker and the overall
#### tag identifying the markers managed by an editor to the
#### canvas items visually representing the marker.
proc Tag {c items grouptag} {
upvar 1 options options
foreach i $items {
canvas::tag append $c $i \
$grouptag \
$options(-tag)
}
return
}
#### Retrieve the tag of the point marker from any item which is
#### part of its visual representation.
proc GetId {c item} {
upvar 1 self self type type
return [lindex [canvas::tag match $c $item */$self/$type] 0]
}
#### Compute absolute location and full delta from current and
#### saved bounding boxes for the items of the point.
proc Delta {} {
upvar 1 grouptag grouptag c c
upvar 1 mydbox obox myloc($grouptag) p
set nbox [$c bbox $grouptag]
#puts |$myloc($grouptag)|$mydbox|$nbox|
lassign $p px py
lassign $obox ox oy _ _
lassign $nbox nx ny _ _
# Full delta based between old and current location.
set dx [expr {$nx - $ox}]
set dy [expr {$ny - $oy}]
# New absolute location based on the full delta.
set px [expr {$px + $dx}]
set py [expr {$py + $dy}]
return [list $px $py $dx $dy]
}
# # ## ### ##### ######## ############# #####################
## Instance state
variable myskip 0 ; # Remove/Add communication flag
variable mycanvas {} ; # Instance command of the canvas widget
# the editor works with.
variable mycounter 0 ; # Counter for NewId to generate
# identifiers for point markers.
variable mydbox {} ; # The bounding box of the items dragged
# around, to compute full deltas and
# absolute location during the drag.
variable myactive 0 ; # Flag, true when the editor bindings are
# set on the canvas, enabling editing.
variable myloc -array {} ; # Internal data base mapping from point
# id to point location, for the
# calculation of absolute coordinates
# during dragging.
method Active {on c x y} {
# puts "$on $c\t($x $y)"
if {![llength $options(-active-cmd)]} return
if {$on} { set on [$self current] } else { set on {} }
{*}$options(-active-cmd) $self $on
return
}
# # ## ### ##### ######## ############# #####################
## Default implementations for the configurable callbacks to
## create the edited points.
method DefaultCreate {c x y} {
$self CheckCanvas $c
# Create a circle marker in the default style
set r $options(-radius)
set w [expr {$x - $r}]
set n [expr {$y - $r}]
set e [expr {$x + $r}]
set s [expr {$y + $r}]
lappend items [$c create $options(-kind) $w $n $e $s \
-width 1 \
-outline black \
-activefill $options(-hilit-color) \
-fill $options(-color)]
return $items
}
method {DefaultData add} {c group x y} {}
method {DefaultData remove} {c group} {}
method {DefaultData move start} {c group} {}
method {DefaultData move delta} {c group x y dx dy} {}
method {DefaultData move done} {c group} { return yes } ;# accept always
method CheckCanvas {c} {
if {$c eq $mycanvas} return
return -code error "Canvas mismatch, ours is $mycanvas, called with $c"
}
# # ## ### ##### ######## ############# #####################
}
# # ## ### ##### ######## ############# #####################
## Ready
package provide canvas::edit::points 0.3
return
# # ## ### ##### ######## ############# #####################
## Scrap yard.

660
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_epolyline.tcl

@ -0,0 +1,660 @@
## -*- tcl -*-
# # ## ### ##### ######## ############# #####################
# Canvas Behavior Module. Editing a point cloud representing a poly-line. I.e.
# we have two designated points which are start and end of the line, and points
# have an order, with a line-segment drawn between each adjacent pair of points
# in this order.
# Default events
# - Inherited from canvas::edit::points
#
# Configurable:
# - Tag used to mark/identify the points of this cloud.
# Default: POLYLINE.
#
# The tag used for the line segment item is "(tag)/Segment".
#
# - Callback used to create the item (group) representing the point.
# Default: <Inherited from the subordinate point cloud editor>
#
# - Callback used to report on line editing activity.
# Default: NONE.
#
# - Callback used to report enter/leave editing activity on the points
# Default: Do nothing.
# # ## ### ##### ######## ############# #####################
# Notes:
#
# - New points are added per the following three rules (See NEW):
#
# 1. Points added on a specific segment split that segment, and can
# then be dragged to their final location.
#
# 2. Points not lying an a segment are attached to the nearest
# endpoint of the line
#
# 3. For a closed line which is not yet a line simply extend the
# line until we have 3 points and can close it as triangle.
#
# 4. For a closed line, i.e. loop, we do not have endpoints to
# attach to. For them rule 3 is disabled, and points can only be
# added as per rules 1 and 2.
#
# - Removal of a point P either removes the single line-segment it is
# part of (happens if P is the current start or end of the line), or
# replaces the two segments adjacent to P with a single segment
# joining the neighbours of P.
# # ## ### ##### ######## ############# #####################
## Requisites
package require Tcl 8.5
package require Tk
package require snit
package require canvas::edit::points
package require canvas::track::lines
namespace eval ::canvas::edit {
namespace export polyline
namespace ensemble create
}
# # ## ### ##### ######## ############# #####################
## API
snit::type ::canvas::edit::polyline {
# Major edit mode: line (open) / polygon (closed)
option -closed -type snit::boolean -default 0 -readonly 1
# Minor edit mode: Convex polygon (ignored for -closed 0)
option -convex -type snit::boolean -default 0 -readonly 1
# Callback reporting the line/polygon coordinates after changes (add, remove, drag)
option -data-cmd -default {}
# Callback reporting when the line/polygon or any of the points have the mouse over it
option -active-cmd -default {}
# See canvas::edit::points
option -tag -default POLYLINE -readonly 1
option -create-cmd -default {} \
-configuremethod Chain \
-cgetmethod UnChain
# See canvas::edit::points, also base config for line/polygon
option -color -default SkyBlue2 -configuremethod Pass
option -hilit-color -default red -configuremethod Pass
# See canvas::edit::points
option -radius -default 3 -configuremethod Pass
option -kind -default oval -configuremethod Pass
# See canvas::edit::points, -add-remove also for click on line/polygon
option -add-remove-point -default {} -readonly 1
option -drag-point -default 3 -readonly 1
# Additional line/polygon configuration
# NOTE: __Cannot__ supercede -color/-hilit-color
option -line-config -default {}
method Pass {o v} {
if {$v eq $options($o)} { return 0 }
set options($o) $v
if {$myeditor eq {}} { return 1 }
$myeditor configure $o $v
return 1
}
method Chain {o v} {
if {$v eq $options($o)} { return 0 }
set options($o) $v
if {$myeditor eq {}} { return 1 }
# Reconfigure the editor with our behaviour still in the chain
$myeditor configure -create-cmd [mymethod Deny $v]
return 1
}
method Unchain {o} {
# Hide the internal -create-cmd chaining from the user
return [$myeditor cget -create-cmd]
}
# # ## ### ##### ######## ############# #####################
constructor {c args} {
set mycanvas $c
$self configurelist $args
# Generate an internal point cloud editor, which will handle
# the basic tasks regarding the line's vertices.
lappend cmd canvas::edit points ${selfns}::P $c
lappend cmd -tag $options(-tag)
lappend cmd -data-cmd [mymethod Point]
lappend cmd -active-cmd [mymethod PointActive]
# Pass point options/configuration to the subordinate editor
foreach o {
-create-cmd
-color
-hilit-color
-radius
-kind
-add-remove-point
-drag-point
} {
set c $options($o)
if {$c ne {}} { lappend cmd $o $c }
}
set myeditor [{*}$cmd]
set mytracker [canvas::track lines ${selfns}::TRACK $mycanvas]
if {$options(-closed)} {
# Intercept point creation for early rejection of new points
# not placed on an existing segment of the loop.
$myeditor configure -create-cmd \
[mymethod DenyOutsideOfSegment [$myeditor cget -create-cmd]]
}
$mycanvas bind [SegmentTag] <Enter> [mymethod Active line]
$mycanvas bind [SegmentTag] <Leave> [mymethod Active {} ]
return
}
component mytracker
component myeditor
delegate method active to myeditor
method enable {args} {
Parts
$myeditor enable {*}$args
foreach part $args {
switch -exact $part {
drag {}
edit {
$mycanvas bind [SegmentTag] [Event] [mymethod FindSegment $mycanvas %x %y]
}
}
}
return
}
method disable {args} {
Parts
$myeditor disable {*}$args
foreach part $args {
switch -exact $part {
drag {}
edit {
$mycanvas bind [SegmentTag] [Event] {}
}
}
}
return
}
# This is not a straight-forward delegation. Because we have to
# remove than just the points of the line.
method clear {} {
# Drop points - Prevent slow incremental removal of line segments
set myrskip 1
$myeditor clear
set myrskip 0
set mypoints {}
# ... and the coordinates
array unset mycoords *
$self Regenerate
Note
return
}
# This is not a straight-forward delegation. Because we have to
# force 'appending the point' instead of using the heuristics.
method add {x y} {
set mydoappend 1
$myeditor add $x $y
set mydoappend 0
$self Regenerate
return
}
method set-line {points} {
# points :: list ((x0 y0) (x1 y1) ...)
$self clear
set mydoappend 1
foreach p $points {
$myeditor add {*}$p
}
set mydoappend 0
$self Regenerate
return
}
# # ## ### ##### ######## ############# #####################
## Actions bound to events, as reported by the point cloud editor.
method PointActive {_ point} {
if {$point ne {}} {
set point [lsearch -exact $mypoints $point]
# if {$point < 0} { set point {} }
}
$self Active $point
return
}
method Active {kind} {
# puts /$kind/
if {![llength $options(-active-cmd)]} return
{*}$options(-active-cmd) $self $kind
return
}
method FindSegment {c x y} {
# We know that we clicked on the line/polygon going through the known points.
# This means that (x,y) is on one of the segments of that line.
# Locate that segment.
# We look for the segment A-B where the direction of A-B best matches the direction of A-P,
# for the new point P.
set x [$c canvasx $x]
set y [$c canvasy $y]
# OPTIMIZE: keep last
if {$options(-closed)} {
set pas $mypoints
set pbs [lrange $mypoints 1 end]
lappend pbs [lindex $mypoints 0]
} else {
set pas [lrange $mypoints 0 end-1]
set pbs [lrange $mypoints 1 end]
}
set min Inf
set pos 0
foreach pa $pas pb $pbs {
incr pos ;# pos -- pb
lassign $mycoords($pa) xa ya
lassign $mycoords($pb) xb yb
# puts -nonewline \nB@$pos\t[X $pa]-[X $pb]
# vectors A-P and A-B
set dax [expr {$x - $xa}]
set day [expr {$y - $ya}]
set dbx [expr {$xb - $xa}]
set dby [expr {$yb - $ya}]
# normalized scalar product = cos (angle)
set mag [expr {hypot($dax,$day)}]
set sp [expr {(($dax*$dbx) + ($day*$dby))/($mag*hypot($dbx,$dby))}]
# puts -nonewline \t|$mag|\tcphi\t$sp
# -1 ==> vectors are anti collinear
# 0 ==> vectors are orthogonal
# 1 ==> vectors are collinear
# ignore directions which do not match to a minimum standard
if {$sp < 0.9} continue
# puts -nonewline \tGOOD
# ... and take the nearest of the remainder
if {$mag > $min} continue
# puts -nonewline \tREMEMBER
set min $mag
set mysplit [list $pa $pb]
}
#puts ""
if {[llength $mysplit]} return
# puts "/FAIL"
# With mysplit not set the system falls back to attaching to the nearest endpoint
# Or, for a polygon, denies the new point
return
}
method DenyOutsideOfSegment {chain c x y} {
# Accept all points during programmatic load
if {$mydoappend} {
return [{*}$chain $c $x $y]
}
# Interaction, Rule 4.
##
# We know here that we are working on a closed line/loop.
# Deny any attempts to add points not sitting on a segment of the line.
# Exception is when we have no loop at all yet (needs 3 points and segments).
set len [llength $mypoints]
if {$len >= 3} {
if {![llength $mysplit]} return ;# deny point not on segment
}
# Continue to actual marker creation.
return [{*}$chain $c $x $y]
}
method {Point add} {pe id x y} {
set mycoords($id) [list $x $y]
if {$mydoappend} {
set end [lindex $mypoints end]
lappend mypoints $id
if {[llength $mypoints] < 2} return
# Reject loading of closed non-convex line into convex editor
if {$options(-closed) && $options(-convex) && ![$self Convex]} {
return -code error "Polygon is not convex"
}
# Regenerate is handled by caller (enables deferal until complete line is loaded)
return
}
$self ExtendLine $id $x $y
$self Regenerate
Note
return
}
method {Point remove} {pe id} {
if {$myrskip} return
$self ShrinkLine $id
$self Regenerate
Note
return
}
method {Point move start} {pe id} {
set mydloc $mycoords($id)
set mydstart $mydloc
set len [llength $mypoints]
set pos [lsearch -exact $mypoints $id]
if {$pos < 0} return
set fix {}
set prev $pos ; incr prev -1
set next $pos ; incr next
if {$options(-closed) && ($prev < 0)} {
lappend fix $mycoords([lindex $mypoints end])
} elseif {$prev >= 0} {
lappend fix $mycoords([lindex $mypoints $prev])
}
if {$options(-closed) && ($next >= $len)} {
lappend fix $mycoords([lindex $mypoints 0])
} elseif {$next < $len} {
lappend fix $mycoords([lindex $mypoints $next])
}
$mytracker start $mydloc {*}$fix
return
}
method {Point move delta} {pe id nx ny dx dy} {
set mydloc [list $nx $ny]
$mytracker move $mydloc
return
}
method {Point move done} {pe id} {
$mytracker done
$self MoveVertex $id $mydloc
if {$options(-closed) && $options(-convex) && ![$self Convex]} {
# Undo the move when it makes the closed convex line non-convex.
$self MoveVertex $id $mydstart
return 0
}
$self Regenerate
Note
return 1
}
method MoveVertex {p new} {
# Move the reference location of the point, and ...
set mycoords($p) $new
return
}
method Convex {} {
# Anything up to a triangle is always considered convex.
if {[llength $mypoints] < 4} { return 1 }
foreach triple [Triples] {
lassign $triple a b c
# Corner a --> b --> c
# Convex if the turn is right-hand
set o [Cross [Delta $b $a] [Delta $c $b]]
if {$o < 0} { return 0 }
}
return 1
}
proc Cross {a b} {
lassign $a xa ya
lassign $b xb yb
return [expr {$xa*$yb - $ya*$xb}]
}
proc Delta {a b} {
lassign $a xa ya
lassign $b xb yb
return [list [expr {$xb - $xa}] [expr {$yb - $ya}]]
}
proc Triples {} {
upvar 1 mypoints mypoints mycoords mycoords
set plist $mypoints
lappend plist {*}[lrange $mypoints 0 1]
set plist [lmap p $plist { set mycoords($p) }]
set triples {}
foreach \
a [lrange $plist 0 end-2] \
b [lrange $plist 1 end-1] \
c [lrange $plist 2 end] {
lappend triples [list $a $b $c]
}
return $triples
}
# # ## ### ##### ######## ############# #####################
## Line management
method Regenerate {} {
if {$mytrack ne {}} {
$mycanvas delete $mytrack
set mytrack {}
}
set len [llength $mypoints]
if {$len < 2} return ;# line needs 2 points
set coordinates [concat {*}[lmap p $mypoints {
set mycoords($p)
}]]
if {$options(-closed) && ($len > 2)} {
set mytrack [$mycanvas create polygon {*}$coordinates \
-fill {} \
-width 2 \
{*}$options(-line-config) \
-activeoutline $options(-hilit-color) \
-outline $options(-color)]
} else {
set mytrack [$mycanvas create line {*}$coordinates \
-width 2 \
{*}$options(-line-config) \
-activefill $options(-hilit-color) \
-fill $options(-color)]
}
canvas::tag append $mycanvas $mytrack [SegmentTag]
$mycanvas lower $mytrack $options(-tag)
return
}
method ExtendLine {p x y} {
# Add point, with attached segments, drop superseded segments
set len [llength $mypoints]
switch -exact -- $len {
0 - 1 {
lappend mypoints $p
}
default {
# 2 or more points ... (NEW) ... Rules at top of file
##
# Rule 1.
if {[llength $mysplit]} {
lassign $mysplit pa pb
set mysplit {}
set pos [lsearch -exact $mypoints $pb]
set mypoints [linsert $mypoints $pos $p]
return
}
# Rule 4.
if {$options(-closed) && ($len >= 3)} {
return -code error \
"Failed to be rejected by DenyOutsideOfSegment"
}
# Rule 3. Extend at end and close
if {$options(-closed) && ($len == 2)} {
lappend mypoints $p
return
}
# Rule 2. Attach to the nearer of the two endpoints.
set first [lindex $mypoints 0]
set last [lindex $mypoints end]
if {[Distance $p $first] < [Distance $p $last]} {
set mypoints [linsert $mypoints 0 $p]
return
}
lappend mypoints $p
return
}
}
return
}
method ShrinkLine {p} {
set pos [lsearch -exact $mypoints $p]
if {$pos < 0} return
set mypoints [lreplace $mypoints $pos $pos]
unset mycoords($p)
return
}
proc Distance {pa pb} {
upvar 1 mycoords mycoords
lassign $mycoords($pa) xa ya
lassign $mycoords($pb) xb yb
return [expr {hypot($xa-$xb,$ya-$yb)}]
}
#### #### #### #### #### #### #### #### #### #### #### ####
proc SegmentTag {{suffix {}}} {
upvar 1 options options
if {$suffix ne {}} { set suffix ,$suffix }
return $options(-tag)/Segment$suffix
}
proc Parts {} {
upvar 1 args args
if {![llength $args]} { set args {edit} }
lappend args drag
set args [lsort -unique $args]
return
}
proc Event {} {
upvar 1 options options
if {$options(-add-remove-point) ne {}} {
return <$options(-add-remove-point)>
} else {
return <1>
}
}
#### Generate notification about changes to the point cloud.
proc Note {} {
upvar 1 options options
if {![llength $options(-data-cmd)]} return
upvar 1 mypoints mypoints mycoords mycoords self self
set coords {}
foreach p $mypoints {
lappend coords $mycoords($p)
}
return [{*}$options(-data-cmd) $self $coords]
}
# debug support ...
proc X {p} { return [lindex [split $p /] 0] }
proc XX {} { upvar 1 mypoints ps ; lmap p $ps { X $p } }
# # ## ### ##### ######## ############# #####################
## STATE
# - Saved handle of the canvas operated on.
# - List of the points managed by the object, conveying their
# order.
# - Canvas items for the line segments the poly line consists of.
variable mycanvas {} ;# canvas the editor is attached to
variable mytrack {} ;# line/polygon item for the entire track
# mypoints :: list (id...)
# mycoords :: array (id -> pixel)
# myline :: array (pair (a b) -> item)
variable mypoints {} ; # list of the ids for the line's points.
variable mysplit {} ; # Segment clicked on (pair (point-id-a point-id-b))
variable mycoords -array {} ; # Reference coordinates of the points. Keyed by point id.
variable mydloc {} ; # Drag state. Location of the moving vertex.
variable mydstart {} ; # Drag state. Original location of the moving vertex.
variable mydoappend 0 ; # Flag. When set new points are always
# appended at the end of the line.
variable myrskip 0 ; # Flag. Skip complex point removal when set.
#
# # ## ### ##### ######## ############# #####################
}
# # ## ### ##### ######## ############# #####################
## Ready
package provide canvas::edit::polyline 0.2
return
# # ## ### ##### ######## ############# #####################
## Scrap yard.

400
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_equad.tcl

@ -0,0 +1,400 @@
## -*- tcl -*-
# # ## ### ##### ######## ############# #####################
## TODO : Optimize the use of AddLine/DropAdjacent to reduce the amount
## TODO : of item churn.
# # ## ### ##### ######## ############# #####################
# Canvas Behavior Module. Editing 4 points/vertices describing a
# (convex) quadrilateral.
# - Create point - B1 (canvas global)
# - Remove point - B2 (linked to -tag, current item)
# - Drag/Move point - B3 (linked to -tag, current item)
# - Auto-highlight points, to show ability of drag/move.
# Configurable:
# - Tag used to mark/identify the points of this cloud.
# Default: QUADRILATERAL.
#
# - Callback used to create the item (group) representing the point.
# Default: <Inherited from the subordinate point cloud editor>
#
# - Callback used to (un)highlight the item (group) of a point.
# Default: <Inherited from the subordinate point cloud editor>
#
# - Callback used to report on quadrilateral editing activity.
# Default: NONE.
# # ## ### ##### ######## ############# #####################
## Requisites
package require Tcl 8.5-
package require Tk
package require snit
package require canvas::edit::points
package require canvas::track::lines
namespace eval ::canvas::edit {
namespace export quadrilateral
namespace ensemble create
}
# # ## ### ##### ######## ############# #####################
## API
snit::type ::canvas::edit::quadrilateral {
option -tag -default QUADRILATERAL -readonly 1
option -create-cmd -default {} -readonly 1
option -highlight-cmd -default {} -readonly 1
option -data-cmd -default {} -readonly 1
option -convex -type snit::boolean -default 0 -readonly 1
constructor {c args} {
set mycanvas $c
set myfreeref $ourrefs
# Generate an internal point cloud editor, which will handle
# the basic tasks regarding the quadrilaterals's vertices.
lappend cmd canvas::edit points ${selfns}::P $c
lappend cmd -tag [from args -tag QUADRILATERAL]
lappend cmd -data-cmd [mymethod Point]
lappend cmd -create-cmd [mymethod Create]
set c [from args -highlight-cmd {}]
if {$c ne {}} { lappend cmd -highlight-cmd $c }
set myeditor [{*}$cmd]
set mytracker [canvas::track lines ${selfns}::TRACK $mycanvas]
set c [from args -create-cmd [mymethod DefaultCreate]]
set options(-create-cmd) $c
$self configurelist $args
# TODO :: Connect this to the option processing to alow me to
# drop -readonly 1 from their definition. Note that this also
# requires code to re-tag all the items on the fly.
return
}
component mytracker
component myeditor
delegate method enable to myeditor
delegate method disable to myeditor
delegate method active to myeditor
delegate method clear to myeditor
delegate method add to myeditor
# # ## ### ##### ######## ############# #####################
## Actions bound to events, as reported by the point cloud editor.
method DefaultCreate {c x y} {
# No vetoing, just item creation. The vertices of the
# quadrilateral are uniquely colored and shaped, ensuring that
# we not only see the shape of the quad, but its exact
# orientation as well.
set items {}
set radius 5
switch -exact -- [lindex $myfreeref 0] {
0 {
# First vertex, top left.
# A circle centered on the chosen location, blue
# filled with black border.
set w [expr {$x - $radius}]
set n [expr {$y - $radius}]
set e [expr {$x + $radius}]
set s [expr {$y + $radius}]
lappend items [$c create oval $w $n $e $s \
-width 1 \
-outline black \
-fill SkyBlue2]
}
1 {
# Second vertex, clock-wise, top right
# A circle centered on the chosen location, green
# filled with black border.
set w [expr {$x - $radius}]
set n [expr {$y - $radius}]
set e [expr {$x + $radius}]
set s [expr {$y + $radius}]
lappend items [$c create oval $w $n $e $s \
-width 1 \
-outline black \
-fill Green]
}
2 {
# Third vertex, clock-wise, bottom right
# A square centered on the chosen location, blue
# filled with black border.
set w [expr {$x - $radius}]
set n [expr {$y - $radius}]
set e [expr {$x + $radius}]
set s [expr {$y + $radius}]
lappend items [$c create rect $w $n $e $s \
-width 1 \
-outline black \
-fill SkyBlue2]
}
3 {
# Fourth vertex, clock-wise, bottom left
# A square centered on the chosen location, green
# filled with black border.
set w [expr {$x - $radius}]
set n [expr {$y - $radius}]
set e [expr {$x + $radius}]
set s [expr {$y + $radius}]
lappend items [$c create rect $w $n $e $s \
-width 1 \
-outline black \
-fill Green]
}
}
return $items
}
method Create {c x y} {
if {![llength $myfreeref]} { return {} }
if {$options(-convex)} {
set next [lindex $myfreeref 0]
set mydactive 1
set mydvertex $next
set mydloc [list $x $y]
set convex [$self Convex]
set mydactive 0
if {!$convex} { return {} }
}
# XXX Might be useful to have our own standard create method.
# XXX To make the vertices of the quad visually unique
# XXX (color, shape).
return [{*}$options(-create-cmd) $c $x $y]
}
method {Point add} {pe id x y} {
set ref [lindex $myfreeref 0]
set myfreeref [lrange $myfreeref 1 end]
set myvertex($ref) [list $x $y]
set myvertex($id) $ref
$self AddLine [expr {($ref-1)%4}] $ref
$self AddLine $ref [expr {($ref+1)%4}]
# Report only when the quad has become complete.
if {[llength $myfreeref]} return
Note
return
}
method {Point remove} {pe id} {
set ref $myvertex($id)
unset myvertex($id) myvertex($ref)
lappend myfreeref $ref
$self DropAdjacent $ref
# Report only when the quad just lost a vertex
if {[llength $myfreeref] > 1} return
Note
return
}
method {Point move start} {pe id} {
# Initialize local drag state.
set ref $myvertex($id)
set mydactive 1
set mydid $id
set mydvertex $ref
set mydloc $myvertex($ref)
$mytracker start $mydloc {*}[$self Trackpoints]
return
}
method {Point move delta} {pe id nx ny dx dy} {
# Track the movement.
set mydloc [list $nx $ny]
$mytracker move $mydloc
return
}
method {Point move done} {pe id} {
# Accept any move if the quad is not restrained.
# Otherwise reject locations causing non-convexity.
$mytracker done
set ok [expr {!$options(-convex) || [$self Convex]}]
set mydactive 0
if {$ok} {
# Commit to the new location.
set myvertex($mydvertex) $mydloc
$self DropAdjacent $mydvertex
$self AddLine [expr {($mydvertex-1)%4}] $mydvertex
$self AddLine $mydvertex [expr {($mydvertex+1)%4}]
# Report only if the quad is complete.
if {![llength $myfreeref]} Note
}
return $ok
}
method Convex {} {
# An incomplete quad is at most a triangle, and always convex.
if {[llength $myfreeref] > 1} { return 1 }
foreach triple [$self Triples] {
lassign $triple a b c
# Corner a --> b --> c
# Convex if the turn is right-hand
set o [Cross [Delta $b $a] [Delta $c $b]]
if {$o < 0} { return 0 }
}
return 1
}
proc Cross {a b} {
lassign $a xa ya
lassign $b xb yb
return [expr {$xa*$yb - $ya*$xb}]
}
proc Delta {a b} {
lassign $a xa ya
lassign $b xb yb
return [list [expr {$xb - $xa}] [expr {$yb - $ya}]]
}
method Triples {} {
set plist [$self GetQuad 1]
set triples {}
foreach \
a [lrange $plist 0 end-2] \
b [lrange $plist 1 end-1] \
c [lrange $plist 2 end] {
lappend triples [list $a $b $c]
}
return $triples
}
method GetQuad {{extended 0}} {
set res {}
if {$extended} {
set idlist $ourerefs
} else {
set idlist $ourrefs
}
foreach ref $idlist {
if {$mydactive && ($ref == $mydvertex)} {
set p $mydloc
} else {
if {![info exists myvertex($ref)]} continue
set p $myvertex($ref)
}
lappend res $p
}
return $res
}
# # ## ### ##### ######## ############# #####################
## Line management
method Trackpoints {} {
set prev [expr {($mydvertex-1)%4}]
set next [expr {($mydvertex+1)%4}]
set res {}
if {[info exists myvertex($prev)]} {
lappend res $myvertex($prev)
}
if {[info exists myvertex($next)]} {
lappend res $myvertex($next)
}
return $res
}
method AddLine {aref bref} {
set key $aref$bref
if {[info exists myline($key)]} { error "present already" }
if {![info exists myvertex($aref)] ||
![info exists myvertex($bref)]
} return
set a $myvertex($aref)
set b $myvertex($bref)
# TODO :: Add a callback/create command prefix for the helper
# lines. At which point the 'line' may consist of multiple
# items.
set segment [$mycanvas create line {*}$a {*}$b -width 1 -fill black]
$mycanvas lower $segment $options(-tag)
set myline($key) $segment
# NOTE :: Should we tag the segment ?
return
}
method DropAdjacent {pref} {
foreach key [array names myline *${pref}*] {
set segment $myline($key)
$mycanvas delete $segment
unset myline($key)
}
return
}
#### Generate notification about changes to the point cloud.
proc Note {} {
upvar 1 options options myfreeref myfreeref myvertex myvertex self self
if {![llength $options(-data-cmd)]} return
if {[llength $myfreeref]} {
# Incomplete quad. Report as 'no quad'.
set coords {}
} else {
set coords [$self GetQuad]
}
return [{*}$options(-data-cmd) $self $coords]
}
# # ## ### ##### ######## ############# #####################
## STATE
# - Saved handle of the canvas operated on.
# - Counter for the generation of point identifiers
# - List of the points managed by the object, conveying their
# order.
# - Canvas items for the actual polyline
typevariable ourrefs {0 1 2 3}
typevariable ourerefs {0 1 2 3 0 1}
variable mycanvas {} ; # The canvas we are working with.
variable myfreeref ; # Vertex ids which are free to fill.
variable myvertex -array {} ; # Vertex information
# editor id -> vertex id
# vertex id -> vertex coordinates
variable myline -array {} ; # Canvas items for the quad helper lines connecting the points.
# Keyed by the pair if vertex ids connected by the line.
variable mydactive 0 ; # Drag state. Boolean flag. True when drag in progress.
variable mydid ; # Drag state. Editor point id of moving point.
variable mydvertex ; # Drag state. Vertex id of moving point.
variable mydloc ; # Drag state. Uncommitted location of the moving point.
variable mydcrosshair ; # Drag state. Crosshair / rubber band lines shown during dragging.
# # ## ### ##### ######## ############# #####################
}
# # ## ### ##### ######## ############# #####################
## Ready
package provide canvas::edit::quadrilateral 0.1
return
# # ## ### ##### ######## ############# #####################
## Scrap yard.

452
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_erectangle.tcl

@ -0,0 +1,452 @@
## -*- tcl -*-
# # ## ### ##### ######## ############# #####################
# Canvas Behavior Module. Editing 2-4 points/vertices describing an axis-aligned rectangle,
# i.e. bounding box.
# Core interaction behaviour inherited from canvas::edit::points
# Configurable:
# - Tag used to mark/identify the points of this cloud.
# Default: RECTANGLE
#
# - Callback used to create the item (group) representing the point.
# Default: <Inherited from the subordinate point cloud editor>
#
# - Callback used to report on rectangle editing activity.
# Default: NONE.
#
# - Callback used to report enter/leave events for the rectangle and its points.
# Default: NONE.
# # ## ### ##### ######## ############# #####################
## Requisites
package require Tcl 8.5-
package require Tk
package require snit
package require canvas::edit::points
namespace eval ::canvas::edit {
namespace export rectangle
namespace ensemble create
}
# # ## ### ##### ######## ############# #####################
## API
snit::type ::canvas::edit::rectangle {
# See canvas::edit::points
option -tag -default RECTANGLE -readonly 1
option -create-cmd -default {} \
-configuremethod Chain \
-cgetmethod UnChain
# Callback reporting the rectangle after changes (add, remove, drag)
option -data-cmd -default {}
# Callback reporting when the rectangle or any of the points have the mouse over it
option -active-cmd -default {}
# See canvas::edit::points, also base config for rectangle
option -color -default SkyBlue2 -configuremethod Pass
option -hilit-color -default red -configuremethod Pass
# See canvas::edit::points
option -radius -default 3 -configuremethod Pass
option -kind -default oval -configuremethod Pass
# See canvas::edit::points, -add-remove also for click on rectangle
option -add-remove-point -default {} -readonly 1
option -drag-point -default 3 -readonly 1
# Additional rectangle configuration
# NOTE: __Cannot__ supercede -color/-hilit-color
option -rect-config -default {}
method Pass {o v} {
if {$v eq $options($o)} { return 0 }
set options($o) $v
if {$myeditor eq {}} { return 1 }
$myeditor configure $o $v
return 1
}
method Chain {o v} {
if {$v eq $options($o)} { return 0 }
set options($o) $v
if {$myeditor eq {}} { return 1 }
# Reconfigure the editor with our behaviour still in the chain
$myeditor configure -create-cmd [mymethod Deny $v]
return 1
}
method Unchain {o} {
# Hide the internal -create-cmd chaining from the user
return [$myeditor cget -create-cmd]
}
# # ## ### ##### ######## ############# #####################
constructor {c args} {
set mycanvas $c
set mystate {}
set myops base
$self configurelist $args
# Generate an internal point cloud editor, which will handle
# the basic tasks regarding the rectangles's vertices.
lappend cmd canvas::edit points ${selfns}::P $c
lappend cmd -tag $options(-tag)
lappend cmd -data-cmd [mymethod Point]
lappend cmd -active-cmd [mymethod PointActive]
# Pass point options/configuration to the subordinate editor
foreach o {
-create-cmd
-color
-hilit-color
-radius
-kind
-add-remove-point
-drag-point
} {
set c $options($o)
if {$c ne {}} { lappend cmd $o $c }
}
set myeditor [{*}$cmd]
$myeditor configure -create-cmd \
[mymethod Deny [$myeditor cget -create-cmd]]
$mycanvas bind [SegmentTag] <Enter> [mymethod Active rect]
$mycanvas bind [SegmentTag] <Leave> [mymethod Active {} ]
return
}
component myeditor
delegate method enable to myeditor
delegate method disable to myeditor
delegate method active to myeditor
method clear {} {
set myops shunt
$myeditor clear
set myops base
set mystate {}
set mycoords {}
$self Regenerate
Note
return
}
method set {minx miny maxx maxy} {
$self clear
$self Complete $myeditor $minx $miny $maxx $maxy
return
}
# # ## ### ##### ######## ############# #####################
## Actions bound to events, as reported by the point cloud editor.
method Complete {pe minx miny maxx maxy} {
set myops shunt
# Corners
#
# tl *--* tr
# | |
# bl *--* br
# Create the proper corner points and remember their associations (id <-> corner)
Def $pe tl $minx $miny
Def $pe bl $minx $maxy
Def $pe tr $maxx $miny
Def $pe br $maxx $maxy
# enter completion, where the rectangle can be dragged (by its corners), and removed
set myops complete
$self Regenerate
Note
return
}
method Deny {chain c x y} {
#puts deny/$myops/$mystate/
# Deny more points when we have the complete set.
if {$myops eq "complete"} return
# Continue to actual marker creation.
return [{*}$chain $c $x $y]
}
method PointActive {_ corner} {
if {$myops ne "complete"} return
if {$corner ne {}} { set corner [dict get $mystate $corner] }
$self Active $corner
return
}
method Active {kind} {
# puts /$kind/
if {![llength $options(-active-cmd)]} return
{*}$options(-active-cmd) $self $kind
return
}
method {Point add} {pe id x y} {
switch -exact -- $myops {
shunt {}
base {
# Base point arrived, remember, now wait for second corner
set mystate [list $id $x $y]
set myops partial
return
}
partial {
# Second corner has arrived. Complete the rectangle.
# Disable point callbacks invoked due to this automatic task.
set myops shunt
# Get saved first corner
lassign $mystate id0 x0 y0
set mystate {}
# Compute all corners from it and the current, second, corner
set minx [expr { min ($x0, $x) }]
set miny [expr { min ($y0, $y) }]
set maxx [expr { max ($x0, $x) }]
set maxy [expr { max ($y0, $y) }]
# Drop old points (base, and current)
$pe remove $id
$pe remove $id0
# And generate the rectangle
$self Complete $pe $minx $miny $maxx $maxy
}
complete {
return -code error "Should have been rejected by `Deny`"
}
}
}
method {Point remove} {pe id} {
switch -exact -- $myops {
shunt {}
base {
# no points known. nothing to do
return
}
partial {
# first point known, no second point. drop memory of first point
set mystate {}
set myops base
return
}
complete {
# removing even one point of the rectangle removes the entire rectangle!
# Disable point callbacks invoked due to this automatic task.
set myops shunt
# Find the corner removed by the user and drop it from the state.
# Then remove the remaining corners
set corner [dict get $mystate $id]
dict unset mystate $id
dict unset mystate $corner
foreach corner $ourcorners {
if {![dict exists $mystate $corner]} continue
$pe remove [dict get $mystate $corner]
}
# enter base state waiting for a new first point
set myops base
set mystate {}
set mycoords {}
$self Regenerate
Note
return
}
}
return
}
method {Point move start} {pe id} {
# Initialize local drag state.
set mydid $id
set corner [dict get $mystate $id]
set mydloc [dict get $mycoords $corner]
return
}
method {Point move delta} {pe id nx ny dx dy} {
# Track the movement.
set mydloc [list $nx $ny]
return
}
method {Point move done} {pe id} {
set corner [dict get $mystate $id]
# Get the rectangle data from moving an opposite corner
lassign [dict get $mycoords [dict get {
tl br tr bl
bl tr br tl
} $corner]] x1 y1
lassign $mydloc x0 y0
# Update state of the moved point, for proper relative
# movement after the coming recalculation
Save $id $corner $x0 $y0
# Recompute all corner locations ...
set minx [expr { min ($x0, $x1) }]
set miny [expr { min ($y0, $y1) }]
set maxx [expr { max ($x0, $x1) }]
set maxy [expr { max ($y0, $y1) }]
# and move the points for the corners to the new locations
# One of the points, the current moved may not move again
Move $pe tl $minx $miny
Move $pe bl $minx $maxy
Move $pe tr $maxx $miny
Move $pe br $maxx $maxy
$self Regenerate
Note
return 1
}
method Regenerate {} {
if {$myrect ne {}} {
$mycanvas delete $myrect
set myrect {}
}
if {$myops ne "complete"} return
lassign [dict get $mycoords tl] minx miny
lassign [dict get $mycoords br] maxx maxy
set myrect [$mycanvas create rectangle $minx $miny $maxx $maxy \
-fill {} \
-width 2 \
{*}$options(-rect-config) \
-activeoutline $options(-hilit-color) \
-outline $options(-color)]
canvas::tag append $mycanvas $myrect [SegmentTag]
$mycanvas lower $myrect $options(-tag)
return
}
# # ## ### ##### ######## ############# #####################
## Corner management
proc Move {pe corner nx ny} {
upvar 1 mystate mystate mycoords mycoords
lassign [dict get $mycoords $corner] ox oy
set dx [expr {$nx - $ox}]
set dy [expr {$ny - $oy}]
set id [dict get $mystate $corner]
$pe move-by $id $dx $dy
Save $id $corner $nx $ny
return
}
proc Def {pe corner x y} {
upvar 1 mystate mystate mycoords mycoords
Save [$pe add $x $y] $corner $x $y
return
}
proc Save {id corner x y} {
upvar 1 mystate mystate mycoords mycoords
dict set mycoords $corner [list $x $y]
dict set mystate $corner $id
dict set mystate $id $corner
return
}
proc SegmentTag {} {
upvar 1 options options
return $options(-tag)/Rect
}
#### Generate notification about changes to the point cloud.
proc Note {} {
upvar 1 options options self self myops myops mycoords mycoords
if {![llength $options(-data-cmd)]} return
switch -exact -- $myops {
shunt - base - partial {
set coords {}
}
complete {
lassign [dict get $mycoords tl] minx miny
lassign [dict get $mycoords br] maxx maxy
set coords [list $minx $miny $maxx $maxy]
}
}
return [{*}$options(-data-cmd) $self $coords]
}
# debug support ...
proc X {p} { return [lindex [split $p /] 0] }
# # ## ### ##### ######## ############# #####################
## STATE
# - Saved handle of the canvas operated on.
# - Counter for the generation of point identifiers
# - List of the points managed by the object, conveying their
# order.
# - Canvas items for the actual rectangle
typevariable ourcorners {tl tr bl br}
variable mycanvas {} ;# The canvas we are working with.
variable myeditor {} ;# point editor instance managing the rectangle corners
variable mystate {} ;# dict, general state
variable myops {} ;# system state controlling callback processing
# states
# - base No points present, accept base point
# - shunt Ignore point editor callback, automatic task in progress
# - partial Single point known, wait for the second corner
# - complete Rectangle is complete, deny more points
variable mycoords {} ;# corner -> pair (x y)
variable myrect {} ;# rectangle item
variable mydid ; # Drag state. id of the moving point.
variable mydloc ; # Drag state. Uncommitted location of the moving point.
# # ## ### ##### ######## ############# #####################
}
# # ## ### ##### ######## ############# #####################
## Ready
package provide canvas::edit::rectangle 0.1
return
# # ## ### ##### ######## ############# #####################
## Scrap yard.

278
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_gradient.tcl

@ -0,0 +1,278 @@
# *- tcl -*-
# ### ### ### ######### ######### #########
# Copyright (c) 2013 Jarek Lewandowski (MaxJarek)
# Origin http://wiki.tcl.tk/6100
# Origin http://wiki.tcl.tk/37242
# Origin http://wiki.tcl.tk/9079
# OLL licensed (http://wiki.tcl.tk/10892)
# ### ### ### ######### ######### #########
## Requisites
package require Tcl 8.5-
package require Tk 8.5-
namespace eval ::canvas {}
# ### ### ### ######### ######### #########
## Implementation.
proc ::canvas::gradient {canvas args} {
gradient::DrawGradient $canvas {*}$args
bind $canvas <Configure> [list ::canvas::gradient::DrawGradient %W {*}$args]
return
}
# ### ### ### ######### ######### #########
## Helper commands. Internal.
namespace eval ::canvas::gradient {}
# ### ### ### ######### ######### #########
## Helper commands.
## Recreate the entire gradient from scratch, as a series of (nested)
## items each filled with a piece of it. This command is called on
## *every* change to the canvas's geometry.
## TODO: Force redraw only on changes to width and height, not
## position.
proc ::canvas::gradient::DrawGradient {canvas args} {
# Fill any holes in the user's specification with the defaults.
set args [dict merge {
-direction x
-color1 red
-color2 green
-type linear
} $args]
set color1 [dict get $args -color1]
set color2 [dict get $args -color2]
set direction [dict get $args -direction]
## Clear gradient. Destroys all canvas items the old gradient
## consisted of.
$canvas delete canvas::gradient
## Get current canvas width and height.
set canWidthPx [winfo width $canvas]
set canHeightPx [winfo height $canvas]
## No gradient if the canvas' area is too small
if {($canWidthPx < 10) ||
($canHeightPx < 10)} return
## Get the distance 'distPx' (in pixels) over which
## the 2 colors are to be gradiated.
switch -exact -- $direction {
x {
set distPx $canWidthPx
}
y {
set distPx $canHeightPx
}
r {
set halfWidthPx [expr {int($canWidthPx / 2)}]
set halfHeightPx [expr {int($canHeightPx / 2)}]
set distPx [expr {max($halfHeightPx,$halfWidthPx)}]
# Even with the radial gradient stopping at the farthest
# canvas border (see dist calculation above, max), we may
# have undefined pixels in the corners. The rectangle
# added below ensures that these have a defined color as
# well (the end color).
$canvas create rectangle 0 0 $canWidthPx $canHeightPx \
-tags canvas::gradient -fill $color2
}
d1 -
d2 {
# Hm. I wonder if that should be the length of the
# diagonal instead (hypot).
set distPx [expr {$canWidthPx + $canHeightPx}]
}
default {
return -code error "Invalid direction $direction"
}
}
## Translate whatever color specification came in into RGB triples
## we can then interpolate between.
if {[catch {
lassign [winfo rgb $canvas $color1] r1 g1 b1
lassign [winfo rgb $canvas $color2] r2 g2 b2
} err]} {
return -code error $err
}
## Calculate the data needed for the interpolation, i.e. color
## range and slope of the line (The ratio of RGB-color-ranges to
## distance 'across' the canvas).
set rRange [expr {$r2 - $r1 + 0.0}]
set gRange [expr {$g2 - $g1 + 0.0}]
set bRange [expr {$b2 - $b1 + 0.0}]
set rRatio [expr {$rRange / $distPx}]
set gRatio [expr {$gRange / $distPx}]
set bRatio [expr {$bRange / $distPx}]
## Increment 'across' the canvas, drawing colored lines, or ovals
## with canvas-'create line', 'create oval'. Computed jump to the
## actual drawing command.
Draw_$direction
## Lower the newly created gradient items into the background
$canvas lower canvas::gradient
return
}
# ### ### ### ######### ######### #########
## Draw helpers, one per direction.
proc ::canvas::gradient::Draw_d1 {} {
upvar 1 canvas canvas r1 r1 g1 g1 b1 b1 rRatio rRatio gRatio gRatio bRatio bRatio
upvar 1 canHeightPx canHeightPx canWidthPx canWidthPx
# Drawing for diagonal direction, left+top to bottom+right
# Two stages:
# - First along y-axis (canHeightPx), top to bottom,
# - Then along x-axis (canWidthPx), left to right.
# i 0 --> canHeight
for {set i 0} {$i <= $canHeightPx} {incr i} {
catch {
$canvas create line $i 0 0 $i \
-tags canvas::gradient -fill [GetNextColor $i]
}
}
# x canHeight --> canWidth + canHeight
# i 0 --> canWidth
for {
set x $canHeightPx
set i 0
} {$i <= $canWidthPx} {
incr i
incr x
} {
catch {
$canvas create line $i $canHeightPx $x 0 \
-tags canvas::gradient -fill [GetNextColor $x]
}
}
return
}
proc ::canvas::gradient::Draw_d2 {} {
upvar 1 canvas canvas r1 r1 g1 g1 b1 b1 rRatio rRatio gRatio gRatio bRatio bRatio
upvar 1 canHeightPx canHeightPx canWidthPx canWidthPx
# Drawing for diagonal direction, bottom+left to top+right
# Two stages:
# - First along y-axis (canHeightPx), bottom to top.
# - Then along x-axis (canWidthPx), left to right.
# x 0 --> canHeight
# i canHeight --> 0
for {
set x 0
set i $canHeightPx
} {$i >= 0} {
incr i -1
incr x
} {
catch {
$canvas create line $x $canHeightPx 0 $i \
-tags canvas::gradient -fill [GetNextColor $x]
}
}
# x canHeight --> canWidth + canHeight
# i 0 --> canWidth
for {
set x $canHeightPx
set i 0
} {$i <= $canWidthPx} {
incr i
incr x
} {
catch {
$canvas create line $i 0 $x $canHeightPx \
-tags canvas::gradient -fill [GetNextColor $x]
}
}
return
}
proc ::canvas::gradient::Draw_x {} {
upvar 1 canvas canvas r1 r1 g1 g1 b1 b1 rRatio rRatio gRatio gRatio bRatio bRatio
upvar 1 canHeightPx canHeightPx distPx distPx
for {set i $distPx} {$i >= 0} {incr i -1} {
catch {
$canvas create line $i 0 $i $canHeightPx \
-tags canvas::gradient -fill [GetNextColor $i]
}
}
return
}
proc ::canvas::gradient::Draw_y {} {
upvar 1 canvas canvas r1 r1 g1 g1 b1 b1 rRatio rRatio gRatio gRatio bRatio bRatio
upvar 1 canWidthPx canWidthPx distPx distPx
for {set i $distPx} {$i >= 0} {incr i -1} {
catch {
$canvas create line 0 $i $canWidthPx $i \
-tags canvas::gradient -fill [GetNextColor $i]
}
}
return
}
proc ::canvas::gradient::Draw_r {} {
upvar 1 canvas canvas r1 r1 g1 g1 b1 b1 rRatio rRatio gRatio gRatio bRatio bRatio
upvar 1 halfWidthPx halfWidthPx halfHeightPx halfHeightPx distPx distPx
for {set i $distPx} {$i >= 0} {incr i -1} {
set xx1 [expr {$halfWidthPx + $i}]
set xx2 [expr {$halfHeightPx + $i}]
set xx3 [expr {$halfWidthPx - $i}]
set xx4 [expr {$halfHeightPx - $i}]
catch {
$canvas create oval $xx1 $xx2 $xx3 $xx4 \
-outline {} -tags canvas::gradient -fill [GetNextColor $i]
}
}
return
}
# ### ### ### ######### ######### #########
## Helper command. Compute the color for step i of the gradient.
## Linear interpolation from the start color.
proc ::canvas::gradient::GetNextColor {i} {
upvar 1 r1 r1 g1 g1 b1 b1 rRatio rRatio gRatio gRatio bRatio bRatio
set nR [expr {int ($r1 + ($rRatio * $i))}]
set nG [expr {int ($g1 + ($gRatio * $i))}]
set nB [expr {int ($b1 + ($bRatio * $i))}]
return [format "#%04X%04X%04X" $nR $nG $nB]
}
# ### ### ### ######### ######### #########
## Ready
package provide canvas::gradient 0.2
return

106
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_highlight.tcl

@ -0,0 +1,106 @@
## -*- tcl -*-
# ### ### ### ######### ######### #########
# Canvas Behavior Module. Highlighting items and groups of items.
# ### ### ### ######### ######### #########
## Requisites
package require Tcl 8.5-
package require Tk
# ### ### ### ######### ######### #########
## API
namespace eval ::canvas::highlight {
namespace export \
on off
namespace ensemble create
}
proc ::canvas::highlight::on {c tagOrId cmdprefix} {
# Setting up a general highlight, with the items to highlight
# identified by <tagOrId> and <cmdprefix> providing the 'on' and 'off'
# methods invoked to (de)activate highlight. The cmdprefix is
# fully responsible for how the highlightging of a particular
# handle is handled.
# Install the bindings doing the highlight
$c bind $tagOrId <Any-Enter> [namespace code [list Highlight $c $cmdprefix %x %y]]
$c bind $tagOrId <Any-Leave> [namespace code [list Unhighlight $c $cmdprefix %x %y]]
return
}
proc ::canvas::highlight::off {c tagOrId} {
# Remove a highlight identified by canvas <c> and <tagOrId>.
# Find and remove the bindings for this particular combination of
# canvas and tagOrId.
$c bind $tagOrId <Any-Enter> {}
$c bind $tagOrId <Any-Leave> {}
return
}
# ### ### ### ######### ######### #########
## Highlight execution.
proc ::canvas::highlight::Highlight {c cmdprefix x y} {
# Check that highlight is not active
variable active
if {[info exists active]} return
# Start a highlight operation, import remainder of state
variable clientdata
# Get item under mouse, if any.
set item [$c find withtag current]
if {$item eq {}} return
# Initialize the highlight state, run the command to initialize
# anything external to us. We remember the current location to
# enable the delta calculations in 'Move'.
set active $cmdprefix
set clientdata [{*}$active on $c $item]
return
}
proc ::canvas::highlight::Unhighlight {c cmdprefix x y} {
# Check for active highlight.
variable active
if {![info exists active]} return
# Import remainder of the highlight state
variable clientdata
# Let the commnand process the movement as it sees fit.
# Must return a boolean. False vetos the unhighlight.
if {![{*}$active off $c $clientdata]} return
# Clear highlight state
unset -nocomplain active clientdata
return
}
# ### ### ### ######### ######### #########
## Convenience. Highlightging via ...
# ### ### ### ######### ######### #########
## State.
namespace eval ::canvas::highlight {
# State of a highlight in progress
variable active ; # command prefix to invoke for 'on' / 'off'.
variable clientdata ; # Result of invoking 'on', data for 'off'.
}
# ### ### ### ######### ######### #########
## Ready
package provide canvas::highlight 0.1
return
# ### ### ### ######### ######### #########
## Scrap yard.

392
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_mvg.tcl

@ -0,0 +1,392 @@
# *- tcl -*-
# ### ### ### ######### ######### #########
# Copyright (c) 2010 Wolf-Dieter Busch
# Origin http://wiki.tcl.tk/26859 [23-08-2010]
# OLL licensed (http://wiki.tcl.tk/10892).
# ### ### ### ######### ######### #########
## Requisites
package require Tcl 8.5-
package require Tk 8.5-
namespace eval ::canvas {}
# ### ### ### ######### ######### #########
## Implementation.
proc ::canvas::mvg {canvas} {
#raise [winfo toplevel $canvas]
#update
# Initialize drawing state... This array is keyed by the MVG
# commands for the attribute, not by the canvas options, and not
# by something third.
array set mode {
fill {}
stroke {}
stroke-width {}
stroke-linejoin {}
stroke-linecap {}
font {}
font-size {}
}
# Get the bounding box of all item, and compute the translation
# required to put the lower-left corner at the origin.
set dx 0
set dy 0
set box [$canvas bbox {*}[$canvas find all]]
lassign $box zx zy ex ey
if {$zx < 0} { set dx [expr {- $zx}] ; set ex [expr {$ex + $dx}] }
if {$zy < 0} { set dy [expr {- $zy}] ; set ey [expr {$ey + $dy}] }
set box [list 0 0 $ex $ey]
# Standard prelude...
mvg::Emit [list viewbox {*}$box]
mvg::EmitChanged stroke none
mvg::EmitChanged fill [mvg::Col2Hex $canvas]
mvg::Emit [list rectangle {*}$box]
# Introspect the canvas, i.e. convert each item to MVG
foreach item [$canvas find all] {
set type [$canvas type $item]
# Info to help debugging...
mvg::Emit "# $type ... [$canvas gettags $item]"
# Dump the item's attributes, as they are supported by it.
# Note how the code is not sliced by item type which then
# handles each of its attributes, but by attribute name, which
# then checks if the type of the current item supports it.
# Further note that the current attribute state is stored in
# the mode array and actually emitted if and only if it is
# different from the previously drawn state. This optimizes
# the number of commands needed to set the drawing state for a
# particular item.
# outline width
if {$type in {polygon oval arc rectangle line}} then {
mvg::EmitValue $item -width stroke-width
}
# fill, stroke
if {$type in {polygon oval arc rectangle}} {
mvg::EmitColor $item -fill fill
mvg::EmitColor $item -outline stroke
}
# joinstyle
if {$type in {polygon}} then {
mvg::EmitValue $item -joinstyle stroke-linejoin
}
# line color, capstyle
if {$type in {line}} then {
mvg::EmitChanged fill none
mvg::EmitColor $item -fill stroke
mvg::EmitCap $item -capstyle stroke-linecap
}
# text color, font, size
if {$type in {text}} then {
# Compute font-family, font-size
set font [$canvas itemcget $item -font]
if {$font in [font names]} {
set fontsize [font configure $font -size]
set fontfamily [font configure $font -family]
} else {
if {[llength $font] == 1} then {
set fontsize 12
} else {
set fontsize [lindex $font 1]
}
set fontfamily [lindex $font 0]
}
if {$fontsize < 0} {
set fontsize [expr {int(-$fontsize / [tk scaling])}]
}
mvg::EmitChanged stroke none
mvg::EmitColor $item -fill fill
mvg::EmitChanged font-size $fontsize
mvg::EmitChanged font $fontfamily
#
# Attention! In some cases ImageMagick assumes 72dpi where
# 90dpi is necessary. If that happens use the switch
# -density to force the correct dpi setting, like %
# convert -density 90 test.mvg test.png
#
# Attention! Make sure that ImageMagick has access to the
# used fonts. If it has not, an error msg will be shown,
# and then switches silently to the default font.
#
}
# After the attributes we can emit the command actually
# drawing the item, in the its place.
set line {}
set coords [mvg::Translate [$canvas coords $item]]
switch -exact -- $type {
line {
# start of path
lappend line path 'M
# smooth can be any boolean value, plus the name of a
# line smoothing method. Core supports only 'raw'.
# This however is extensible through packages.
switch -exact -- [mvg::Smooth $item] {
0 {
lappend line {*}[lrange $coords 0 1] L {*}[lrange $coords 2 end]
}
1 {
if {[$canvas itemcget $item -arrow] eq "none"} {
lappend line {*}[mvg::Spline2MVG $coords]
} else {
lappend line {*}[mvg::Spline2MVG $coords false]
}
}
2 {
lappend line {*}[lrange $coords 0 1] C {*}[lrange $coords 2 end]
}
}
append line '
mvg::Emit $line
}
polygon {
# start of path.
lappend line path 'M
switch -exact -- [mvg::Smooth $item] {
0 {
lassign $coords x0 y0
lassign [lrange $coords end-1 end] x1 y1
set x [expr {($x0+$x1)/2.0}]
set y [expr {($y0+$y1)/2.0}]
lappend line $x $y L {*}$coords $x $y Z
}
1 {
lassign $coords x0 y0
lassign [lrange $coords end-1 end] x1 y1
if {($x0 != $x1) || ($y0 != $y1)} {
lappend coords {*}[lrange $coords 0 1]
}
lappend line {*}[mvg::Spline2MVG $coords]
}
2 {
lappend line {*}[lrange $coords 0 1] C {*}[lrange $coords 2 end]
}
}
append line '
mvg::Emit $line
}
oval {
lassign $coords x0 y0 x1 y1
set xc [expr {($x0+$x1)/2.0}]
set yc [expr {($y0+$y1)/2.0}]
mvg::Emit [list ellipse $xc $yc [expr {$x1-$xc}] [expr {$y1-$yc}] 0 360]
}
arc {
lassign $coords x0 y0 x1 y1
set rx [expr {($x1-$x0)/2.0}]
set ry [expr {($y1-$y0)/2.0}]
set x [expr {($x0+$x1)/2.0}]
set y [expr {($y0+$y1)/2.0}]
set f [expr {acos(0)/90}]
set start [$canvas itemcget $item -start]
set startx [expr {cos($start*$f)*$rx+$x}]
set starty [expr {sin(-$start*$f)*$ry+$y}]
set angle [expr {$start+[$canvas itemcget $item -extent]}]
set endx [expr {cos($angle*$f)*$rx+$x}]
set endy [expr {sin(-$angle*$f)*$ry+$y}]
# start path
lappend line path 'M
# start point
lappend line $startx $starty
lappend line A
# radiusx, radiusy
lappend line $rx $ry
# angle -- always 0
lappend line 0
# "big" or "small"?
lappend line [expr {($angle-$start) > 180}]
# right side (always)
lappend line 0
# end point
lappend line $endx $endy
# close path
lappend line L $x $y Z
append line '
mvg::Emit $line
}
rectangle {
mvg::Emit [list rectangle {*}$coords]
}
text {
lassign [mvg::Translate [$canvas bbox $item]] x0 y0 x1 y1
mvg::Emit "text $x0 $y1 '[$canvas itemcget $item -text]'"
}
image - bitmap {
set img [$canvas itemcget $item -image]
set file [$img cget -file]
lassign [mvg::Translate [$canvas bbox $item]] x0 y0
mvg::Emit "image over $x0 $y0 0 0 '$file'"
}
default {
set line "# not yet done:"
append line " " [$canvas type $item]
append line " " [mvg::Translate [$canvas coords $item]]
append line " (" [$canvas gettags $item] ")"
mvg::Emit $line
}
}
}
# At last, return the fully assembled snapshot
return [join $result \n]
}
# ### ### ### ######### ######### #########
## Helper commands. Internal.
namespace eval ::canvas::mvg {}
proc ::canvas::mvg::Translate {coords} {
upvar 1 dx dx dy dy
set tmp {}
foreach {x y} $coords {
lappend tmp [expr {$x + $dx}] [expr {$y + $dy}]
}
return $tmp
}
proc ::canvas::mvg::Smooth {item} {
upvar 1 canvas canvas
# Force smooth to canonical values we can then switch on.
set smooth [$canvas itemcget $item -smooth]
if {[string is boolean $smooth]} {
if {$smooth} {
return 1
} else {
return 0
}
} else {
return 2
}
}
proc ::canvas::mvg::EmitValue {item option cmd} {
upvar 1 mode mode result result canvas canvas
EmitChanged $cmd \
[$canvas itemcget $item $option]
return
}
proc ::canvas::mvg::EmitColor {item option cmd} {
upvar 1 mode mode result result canvas canvas
EmitChanged $cmd \
[Col2Hex [$canvas itemcget $item $option]]
return
}
proc ::canvas::mvg::EmitCap {item option cmd} {
upvar 1 mode mode result result canvas canvas
EmitChanged $cmd \
[dict get {
butt butt
projecting square
round round
} [$canvas itemcget $item $option]]
return
}
proc ::canvas::mvg::EmitChanged {cmd value} {
upvar 1 mode mode result result
if {$mode($cmd) eq $value} return
set mode($cmd) $value
Emit [list $cmd $value]
return
}
proc ::canvas::mvg::Emit {command} {
upvar 1 result result
lappend result $command
return
}
proc ::canvas::mvg::Col2Hex {color} {
# This command or similar functionality we might have somewhere
# in tklib already ...
# Special handling of canvas widgets, use their background color.
if {[winfo exists $color] && [winfo class $color] eq "Canvas"} {
set color [$color cget -bg]
}
if {$color eq ""} {
return none
}
set result #
foreach x [winfo rgb . $color] {
append result [format %02x [expr {int($x / 256)}]]
}
return $result
}
proc ::canvas::mvg::Spline2MVG {coords {canBeClosed yes}} {
set closed [expr {$canBeClosed &&
[lindex $coords 0] == [lindex $coords end-1] &&
[lindex $coords 1] == [lindex $coords end]}]
if {$closed} {
lassign [lrange $coords end-3 end] x0 y0 x1 y1
set x [expr {($x0+$x1)/2.0}]
set y [expr {($y0+$y1)/2.0}]
lset coords end-1 $x
lset coords end $y
set coords [linsert $coords 0 $x $y]
}
if {[llength $coords] != 6} {
lappend tmp {*}[lrange $coords 0 1]
set co1 [lrange $coords 2 end-4]
set co2 [lrange $coords 4 end-2]
foreach {x1 y1} $co1 {x2 y2} $co2 {
lappend tmp $x1 $y1 [expr {($x1+$x2)/2.0}] [expr {($y1+$y2)/2.0}]
}
lappend tmp {*}[lrange $coords end-3 end]
set coords $tmp
}
return [lreplace $coords 2 1 Q]
}
# ### ### ### ######### ######### #########
## Ready
package provide canvas::mvg 1
return

111
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_snap.tcl

@ -0,0 +1,111 @@
# *- tcl -*-
# ### ### ### ######### ######### #########
# Copyright (c) 2004 George Petasis
# Origin http://wiki.tcl.tk/1404 [24-10-2004]
# BSD licensed.
# ### ### ### ######### ######### #########
## Requisites
package require Tcl 8.5-
package require Tk 8.5-
package require img::window
namespace eval ::canvas {}
# ### ### ### ######### ######### #########
## Implementation.
proc ::canvas::snap {canvas} {
# Ensure that the window is on top of everything else, so as not
# to get white ranges in the image, due to overlapped portions of
# the window with other windows...
raise [winfo toplevel $canvas]
update
# XXX: Undo the raise at the end ?!
set border [expr {[$canvas cget -borderwidth] +
[$canvas cget -highlightthickness]}]
set view_height [expr {[winfo height $canvas]-2*$border}]
set view_width [expr {[winfo width $canvas]-2*$border}]
lassign [$canvas bbox all] x1 y1 x2 y2
#foreach {x1 y1 x2 y2} [$canvas bbox all] break
set x1 [expr {int($x1-10)}]
set y1 [expr {int($y1-10)}]
set x2 [expr {int($x2+10)}]
set y2 [expr {int($y2+10)}]
set width [expr {$x2-$x1}]
set height [expr {$y2-$y1}]
set image [image create photo -height $height -width $width]
# Arrange the scrollregion of the canvas to get the whole window
# visible, so as to grab it into an image...
# Save the scrolling state, as this will be overidden in short order.
set scrollregion [$canvas cget -scrollregion]
set xscrollcommand [$canvas cget -xscrollcommand]
set yscrollcommand [$canvas cget -yscrollcommand]
$canvas configure -xscrollcommand {}
$canvas configure -yscrollcommand {}
set grabbed_x $x1
set grabbed_y $y1
set image_x 0
set image_y 0
while {$grabbed_y < $y2} {
while {$grabbed_x < $x2} {
set newregion [list \
$grabbed_x \
$grabbed_y \
[expr {$grabbed_x + $view_width}] \
[expr {$grabbed_y + $view_height}]]
$canvas configure -scrollregion $newregion
update
# Take a screenshot of the visible canvas part...
set tmp [image create photo -format window -data $canvas]
# Copy the screenshot to the target image...
$image copy $tmp -to $image_x $image_y -from $border $border
# And delete the temporary image (leak in original code)
image delete $tmp
incr grabbed_x $view_width
incr image_x $view_width
}
set grabbed_x $x1
set image_x 0
incr grabbed_y $view_height
incr image_y $view_height
}
# Restore the previous scrolling state of the canvas.
$canvas configure -scrollregion $scrollregion
$canvas configure -xscrollcommand $xscrollcommand
$canvas configure -yscrollcommand $yscrollcommand
# At last, return the fully assembled snapshot
return $image
}
# ### ### ### ######### ######### #########
## Ready
package provide canvas::snap 1.0.1
return

667
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_sqmap.tcl

@ -0,0 +1,667 @@
## -*- tcl -*-
# ### ### ### ######### ######### #########
# Known issue :: It is unspecified who is responsible for the images
# after they are used in the canvas. The canvas
# currently doesn't delete them. Meaning, this is
# likely leaking memory like mad when switching between
# sources, and dragging around.
# sqmap = square map.
# Ideas to work on ...
# -- Factor the low-level viewport tracking and viewport stabilization
# across scroll-region changes out into its own canvas class.
# -- Factor the grid layer handling into its own class. That is a
# requisite for the handling of multiple layers,
# -- Create a hexmap, i.e. hexagonal tiling. This can be done with
# images as well, with parts properly transparent and then
# positioned to overlap. Regarding coordinates this can be seen
# as a skewed cartesian system, so only 2 coordinates required
# -- Consider viewport stabilization for when the canvas is resized.
# ### ### ### ######### ######### #########
## Requisites
package require Tcl 8.4- ; # No {*}-expansion! :(
package require Tk
package require snit ; #
package require uevent::onidle ; # Some defered actions.
package require cache::async 0.3 ; # Internal tile cache.
# ### ### ### ######### ######### #########
##
snit::widgetadaptor canvas::sqmap {
# ### ### ### ######### ######### #########
## API
# All canvas options, except for -scrollregion are accepted by
# this widget(adaptor), and propagated to the embedded canvas. The
# region is always implicitly (0,0,w,h), with w and h computed
# from the number of grid rows, columns and the cell dimensions.
delegate option * to hull except -scrollregion
# All canvas methods are accepted and propagated to the embedded
# canvas. Some of them we intercept however, to either impose
# restrictions (*), or get information we need and not available
# otherwise (**).
# (*) The images used as background have to stay lower than all
# user-created items, to be that background. We cannot allow
# them to be raised, nor must others go below them.
# If we were extremely rigourous we would have to intercept
# all methods and filter out our internal tags and items ids,
# to make them completely invisible to the user. The last 5%
# needing 90% of the effort. *** Defered ***
# (**) Dragging changes the viewport, we do not see this without
# interception.
delegate method * to hull except {lower raise scan xview yview}
delegate method {scan mark} to hull as {scan mark}
# New options: Information about the grid, and where to get the
# images.
# rows = number of rows the grid consists of. <0 <=> unlimited
# columns = s.a., columns
# cell-width = width of a cell in the grid, in pixels
# cell-height = s.a., height
# cell-source = command prefix called to get the image for a cell in the grid.
option -grid-cell-width -default 0 -configuremethod O-ReconfigureNum -type {snit::integer -min 0}
option -grid-cell-height -default 0 -configuremethod O-ReconfigureNum -type {snit::integer -min 0}
option -grid-cell-command -default {} -configuremethod O-ReconfigureStr
option -scrollregion -default {} -configuremethod O-ReconfigureStr
# NOTE AK, maybe, for the future.
# rows/columns - we may wish to have min/max values, if any to represent
# - grid boundaries.
#option -grid-rows -default 0 -configuremethod O-ReconfigureNum
#option -grid-columns -default 0 -configuremethod O-ReconfigureNum
# NOTE !!! Use -grid-show-borders only for short-term debugging.
# NOTE !!! The items created when true are never deleted, i.e. leaking memory
option -grid-show-borders -default 0 -type snit::boolean
option -viewport-command -default {} -configuremethod O-vp-command
option -image-on-load -default {}
option -image-on-unset -default {}
constructor {args} {
installhull using canvas
install reconfigure using uevent::onidle ${selfns}::reconfigure \
[mymethod Reconfigure]
install redraw using uevent::onidle ${selfns}::redraw \
[mymethod Redraw]
install tilecache using cache::async ${selfns}::tilecache \
[mymethod Tile] -full-async-results 0
# Configuration means synchronous return of in-cache results.
# This is needed to get proper use and disposal of ->
# myfreeitems.
bind $win <Configure> [mymethod Configure]
$self configurelist $args
return
}
# ### ### ### ######### ######### #########
## API. Define/Remove images from grid cells. These are the main
## commands to control grid appearance. The -grid-cell-command should
## use these commands as well to provide its results to the
## widget.
method {image set} {at image} {
$tilecache set $at $image
# Nothing more is required for an invisible cell.
if {![info exists myvisible($at)]} return
# For empty cells we create proper items now.
set theitem $myvisible($at)
if {$theitem eq ""} {
set theitem [$self GetItem [GridToPixel $at]]
set myvisible($at) $theitem
}
# Show the chosen image
$hull itemconfigure $theitem -image $image
return
}
method {image unset} {at} {
# Show an image signaling that 'this tile is not valid/found' ...
if {$options(-image-on-unset) ne {}} {
$self image set $at $options(-image-on-unset)
return
}
$tilecache unset $at
# Nothing more is required for an invisible cell.
if {![info exists myvisible($at)]} return
# Nothing more is required for an empty cell.
set theitem $myvisible($at)
if {$theitem eq ""} return
# Mark the cell as empty and drop the associated item.
set myvisible($at) ""
$hull delete $theitem
return
}
# ### ### ### ######### ######### #########
## Force a full reload of all (visible) cells.
method flush {} {
$tilecache clear
set mypixelview {}
#puts REDRAW-RQ/flush
$redraw request
return
}
# ### ### ### ######### ######### #########
## Intercepting the methods changing the display order, to ensure
## that our grid is kept at the bottom. It is the background after
## all.
method raise {args} {
eval [linsert $args 0 $hull raise]
# Ensure that our cells stay at the bottom.
$hull lower $ourtag
return
}
method lower {args} {
eval [linsert $args 0 $hull lower]
# Ensure that our cells stay at the bottom.
$hull lower $ourtag
return
}
# ### ### ### ######### ######### #########
## Intercepting the dragto command to keep track of the
## viewport. See the scroll method interception below too.
# NOTE: 'scan mark' interception will be needed if we wish to
# allow items to float in place regardless of dragging (i.e. as UI
# elements, for example a zoom-scale).
method {scan dragto} {x y {gain 1}} {
# Regular handling of dragging ...
$hull scan dragto $x $y $gain
# ... then compute and record the changed viewport, and
# request a redraw to be done when the system has time for it
$self SetPixelView
return
}
# ### ### ### ######### ######### #########
## Intercepting the scroll methods to keep track of the viewport.
## The canvas has no way to report changes on its own. No
## callbacks, nothing. See the dragto interception above too.
method xview {args} {
# Regular handling of scrolling ...
set res [eval [linsert $args 0 $hull xview]]
# Keep track of the viewport in case of changes.
if {[llength $args]} { $self SetPixelView }
return $res
}
method yview {args} {
# Regular handling of scrolling ...
set res [eval [linsert $args 0 $hull yview]]
# Keep track of the viewport in case of changes.
if {[llength $args]} { $self SetPixelView }
return $res
}
# ### ### ### ######### ######### #########
## Intercept <Configure> events on the canvas. This changes the
## viewport. At the time the event happens the new viewport is not
## yet known, as this is done in a canvas-internal idle-handler. We
## simply trigger our redraw in our idle-handler, and force it to
## recompute the viewport.
method Configure {} {
set mypixelview {} ; # Force full recalculation.
#puts REDRAW-RQ/configure
$redraw request
return
}
# ### ### ### ######### ######### #########
method O-vp-command {o v} {
#puts $o=$v
if {$options($o) eq $v} return
set options($o) $v
set myhasvpcommand [expr {!![llength $v]}]
if {!$myhasvpcommand} return
# Callback changed and ok, request first call with current
# settings.
$self PixelViewExport
return
}
variable myhasvpcommand 0 ; # Track use of viewport-command callback
method PixelViewExport {} {
if {!$myhasvpcommand} return
if {![llength $mypixelview]} return
foreach {xl yt xr yb} $mypixelview break
uplevel \#0 [linsert $options(-viewport-command) end $xl $yt $xr $yb]
return
}
method SetPixelView {} {
set mypixelview [PV]
$self PixelViewExport
# Viewport changes imply redraws
#puts REDRAW-RQ/set-pixel-view
$redraw request
return
}
proc PV {} {
upvar 1 hull hull win win
return [list \
[$hull canvasx 0] \
[$hull canvasy 0] \
[$hull canvasx [winfo width $win]] \
[$hull canvasy [winfo height $win]]]
}
# ### ### ### ######### ######### #########
## Option processing. Any changes force a refresh of the grid
## information, and then a redraw.
method O-ReconfigureNum {o v} {
#puts $o=$v
if {$options($o) == $v} return
set options($o) $v
$reconfigure request
return
}
method O-ReconfigureStr {o v} {
#puts $o=$v
if {$options($o) eq $v} return
set options($o) $v
$reconfigure request
return
}
component reconfigure
method Reconfigure {} {
#puts /reconfigure
# The grid definition has changed, in parts, or all. We have
# to redraw the background, even if nothing else was changed.
# Here we commit all changed option values to the engine.
# This is the only place accessing the options array.
set oldsr $myscrollregion
set mygridwidth $options(-grid-cell-width)
set mygridheight $options(-grid-cell-height)
set mygridcmd $options(-grid-cell-command)
set myscrollregion $options(-scrollregion)
# Commit region change to the canvas itself
$hull configure -scrollregion $myscrollregion
# Flush the cache to force a reload of the entire visible
# area now, and of the invisible part later when scrolling.
$tilecache clear
# Now save and restore the view, keeping the center of the
# view as stable as possible across the transition. Note, the
# scrapyard at the end of this file contains the same
# calculations in long form, i.e. all steps written out. Here
# the various expressions are inlined and simplified.
foreach { sxl syt sxr syb} $oldsr break
if {[llength $oldsr] && (($sxr - $sxl) > 0) && (($syb - $syt) > 0)} {
# Old and new scroll regions.
foreach {nsxl nsyt nsxr nsyb} $myscrollregion break
#puts OSR=($oldsr)
#puts NSR=($myscrollregion)
# Get current pixel view, and limit it to the old
# scrollregion (as the canvas may show more than the
# scrollregion).
foreach {xl yt xr yb} $mypixelview break
if {$xl < $sxl} { set xl $sxl }
if {$xr > $sxr} { set xr $sxr }
if {$yt < $syt} { set yt $syt }
if {$yb > $syb} { set yb $syb }
# Determine the center of the pixel view, as fractions
# relative to old scroll origin.
set xcfrac [expr {double((($xr + $xl)/2) - $sxl) / ($sxr - $sxl)}]
set ycfrac [expr {double((($yt + $yb)/2) - $syt) / ($syb - $syt)}]
# The fractions for the topleft corner are the fractions
# of the center less the (fractional manhattan radii
# around the center, relative to the new region).
set nxlfrac [expr {$xcfrac - double(($xr - $xl)/2) / ($nsxr - $nsxl)}]
set nytfrac [expr {$ycfrac - double(($yb - $yt)/2) / ($nsyb - $nsyt)}]
# Limit the fractions to the scroll origin (>= 0).
if {$nxlfrac < 0} { set nxlfrac 0 }
if {$nytfrac < 0} { set nytfrac 0 }
# Adjust canvas view to keep the center as stable as
# possible across the transition. Note that this goes
# through our own xview/yview method, calls SetPixelView,
# and through that requests a redraw. No need to have the
# redraw done by this method.
#puts MOVETO\t$nxlfrac,$nytfrac
$self xview moveto $nxlfrac
$self yview moveto $nytfrac
# Note however that we still have to force the redraw to
# be fully done.
set mypixelview {}
} else {
# Nearly last, redraw full. This happens only because no
# view adjustments were done which would have forced it
# (see above), so in this cause we have to do it
# ourselves.
$self Redraw 1
}
#puts reconfigure/done
return
}
# ### ### ### ######### ######### #########
## Grid redraw. This is done after changes to the viewport,
## and when the system is idle.
component redraw
method Redraw {{forced 0}} {
#puts /redraw/$forced
# Compute viewport in tile coordinates and compare to last.
# This will tell us where to update and how, if any.
if {![llength $mypixelview]} {
# Undefined viewport, generate baseline, and force
# redraw. Scheduling another redraw is however not needed,
# so we are inlining only parts of SetPixelView.
set mypixelview [PV]
$self PixelViewExport
#puts \tforce-due-undefined-viewport
set forced 1
}
set gridview [PixelToGrid $mypixelview]
foreach {xl yt xr yb} $gridview break
foreach {ll lt lr lb} $myshowngridview break
#puts \tVP=($mypixelview)
#puts \tVG=($gridview)
#puts \tVL=($myshowngridview)
#puts \tF'=$forced
if {!$forced} {
# Viewport unchanged, nothing to do.
if {($xl == $ll) && ($xr == $lr) &&
($yt == $lt) && ($yb == $lb)} {
#puts \tunchanged,ignore
return
}
}
set myfreeitems {}
# NOTE. The code below is suboptimal. While already better
# than dropping and recreating all items, we could optimize by
# using the structure of the viewport (rectangles) to
# determine directly which grid cells became (in)visible, from
# the viewport boundary coordinates. This will however be also
# quite more complex, with all the possible cases of
# overlapping old and new views.
if {$forced} {
# Forced redraw, simply make all items available
# for the upcoming fill.
foreach at [array names myvisible] {
$self FreeCell $at
}
} elseif {[llength $myshowngridview]} {
# Scan through the grid cells of the view used at the last
# redraw, and check which of them have become
# invisible. Put these on the list of items we can reuse
# for the cells which just became visible and thus in need
# of items.
for {set r $lt} {$r <= $lb} {incr r} {
for {set c $ll} {$c <= $lr} {incr c} {
if {($r < $yt) || ($yb < $r) || ($c < $xl) || ($xr < $c)} {
# The grid cell dropped out of the viewport.
$self FreeCell [list $r $c]
#puts /drop/$idx
}
}
}
}
# Remember location for next redraw.
set myshowngridview $gridview
for {set r $yt} {$r <= $yb} {incr r} {
for {set c $xl} {$c <= $xr} {incr c} {
# Now scan through the cells of the new viewport.
# Ignore those which are still visible, and create the
# remainder.
set at [list $r $c]
if {[info exists myvisible($at)]} continue
#puts /make/$idx
set myvisible($at) "" ; # placeholder
# Show an image signaling that 'we are loading this tile' ...
if {$options(-image-on-load) ne {}} {
set theitem [$self GetItem [GridToPixel $at]]
set myvisible($at) $theitem
$hull itemconfigure $theitem \
-image $options(-image-on-load)
}
after 0 [list $tilecache get $at [mymethod image]]
# This cache access re-uses the items in myfreeitems
# as images already in the cache are delivered
# synchronously, going through 'image set' and
# GetItem. Only unknown cells will come later.
}
}
# Delete all items which were not reused.
# No, no need. Canvas image items without an image configured
# for display are effectively invisible, regardless of
# location. Keep them around for late coming provider results.
#$self DropFreeItems
#puts redraw/done
return
}
method FreeCell {at} {
# Ignore already invisible cells
if {![info exists myvisible($at)]} return
# Clear empty cells, nothing more
set theitem $myvisible($at)
unset myvisible($at)
if {$theitem eq ""} return
# Record re-usable item and clear the image it used. Note that
# this doesn't delete the image!
lappend myfreeitems $theitem
$hull itemconfigure $theitem -image {}
return
}
method {Tile get} {at donecmd} {
# Tile cache provider callback. The request is routed to the
# canvas's own tile provider. Responses go to the cache. The
# cache is set up that its responses go to the 'image ...'
# methods.
if {![llength $mygridcmd]} return
#puts \t\t\t\tGet($at)
uplevel #0 [linsert $mygridcmd end get $at $donecmd]
return
}
method GetItem {location} {
# location = pixel position, list (x y)
if {[llength $myfreeitems]} {
# Free items were found, reuse one of them.
set theitem [lindex $myfreeitems end]
set myfreeitems [lreplace $myfreeitems end end]
$hull coords $theitem $location
$hull itemconfigure $theitem -image {}
} else {
# Nothing available for reuse, create a new item.
if {$options(-grid-show-borders)} {
# Helper markers for debugging, showing cell borders
# and coordinates.
# NOTE !!! Use -grid-show-borders only for short-term debugging.
# NOTE !!! The items create here are never deleted, i.e. leaking memory
foreach {x y} $location break
set x [expr {int($x)}]
set y [expr {int($y)}]
set t "<[expr {$y/$mygridheight}],[expr {$x/$mygridwidth}]>"
incr x 2 ; incr y 2
set x1 $x ; incr x1 $mygridwidth ; incr x1 -2
set y1 $y ; incr y1 $mygridheight ; incr y1 -2
$hull create rectangle $x $y $x1 $y1 -outline red
incr x 4 ; incr y 4
set t [$hull create text $x $y -fill red -anchor nw -text $t]
$hull raise $t
}
set theitem [$hull create image $location -anchor nw -tags [list $ourtag]]
$hull lower $theitem
}
return $theitem
}
method DropFreeItems {} {
if {[llength $myfreeitems]} {
eval [linsert $myfreeitems 0 $hull delete]
set myfreeitems {}
}
return
}
# ### ### ### ######### ######### #########
proc PixelToGrid {pixelview} {
# Import grid definitions ...
upvar 1 mygridwidth gcw mygridheight gch
foreach {xl yt xr yb} $pixelview break
set coll [expr {int($xl / double($gcw))}]
set colr [expr {int($xr / double($gcw))}]
set rowt [expr {int($yt / double($gch))}]
set rowb [expr {int($yb / double($gch))}]
# NOTE AK: Maybe limit cell coordinates to boundaries, if
# NOTE AK: so requested.
return [list $coll $rowt $colr $rowb]
}
proc GridToPixel {at} {
# Import grid definitions ...
upvar 1 mygridwidth gcw mygridheight gch
foreach {r c} $at break
set y [expr {int($r * double($gch))}]
set x [expr {int($c * double($gcw))}]
return [list $x $y]
}
# ### ### ### ######### ######### #########
## State
# Active copies of various options. Their use prevents races in
# the redraw logic using new option values while other parts are
# not adapted to the changes. The 'Reconfigure' method is
# responsible for the atomic commit of external changes to the
# internal engine.
variable mygridwidth {} ; # Grid definition used by the engine.
variable mygridheight {} ; # s.a.
variable mygridcmd {} ; # s.a.
variable myscrollregion {} ; # s.a.
# All arrays using grid cells as keys, i.e. 'myvisible', use grid
# cell coordinates to reference grid cell, in the form
# tuple(row, col)
#
# This is the same form taken by the grid-cell-command command prefix and makes
# use of keys easier as it they are the same across the board.
# Cache for quick lookup of images and image misses we have seen
# before, to avoid async round-trips through the
# grid-cell-command, aka image provider.
component tilecache
# Tracking the viewport, i.e. the visible area of the canvas
# within the scrollregion.
variable mypixelview {} ; # Current viewport of the hull, in pixels.
variable myshowngridview {} ; # Viewport set by last Redraw, in grid cell coordinates
# Tracking the grid cells shown in the viewport and their canvas
# items.
variable myvisible -array {} ; # Visible grid cells, mapped to their canvas items.
# Transient list of items available for reassignment.
variable myfreeitems {}
# Tag used to mark all canvas items used for the grid cell display.
typevariable ourtag canvas::sqmap::cells
# ### ### ### ######### ######### #########
}
# ### ### ### ######### ######### #########
## Ready
package provide canvas::sqmap 0.3.1
return

70
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_tags.tcl

@ -0,0 +1,70 @@
## -*- tcl -*-
# ### ### ### ######### ######### #########
## Canvas Utilities. Operations on item tags.
# ### ### ### ######### ######### #########
## Requisites
package require Tcl 8.5-
package require Tk
namespace eval ::canvas::tag {
namespace export \
append prepend insert remove match
namespace ensemble create
}
# ### ### ### ######### ######### #########
## API
proc ::canvas::tag::append {c tagOrId args} {
insert $c $tagOrId end {*}$args
#$c addtag $newtag withtag $tagOrId
return
}
proc ::canvas::tag::prepend {c tagOrId args} {
insert $c $tagOrId 0 {*}$args
return
}
proc ::canvas::tag::insert {c tagOrId index args} {
foreach item [$c find withtag $tagOrId] {
$c itemconfigure $item -tags [linsert [$c gettags $item] $index {*}$args]
}
return
}
proc ::canvas::tag::remove {c tagOrId args} {
foreach item [$c find withtag $tagOrId] {
set tags [$c gettags $item]
foreach tagToRemove $args {
while {1} {
set pos [lsearch -exact $tags $tagToRemove]
if {$pos < 0} break
set tags [lreplace $tags $pos $pos]
}
}
$c itemconfigure $item -tags $tags
}
return
}
proc ::canvas::tag::match {c tagOrId pattern} {
set result {}
foreach item [$c find withtag $tagOrId] {
lappend result {*}[lsearch -inline -all -glob \
[$c gettags $item] $pattern]
}
return [lsort -unique $result]
}
# ### ### ### ######### ######### #########
## Ready
package provide canvas::tag 0.1
return
# ### ### ### ######### ######### #########
## Scrap yard.

95
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_trlines.tcl

@ -0,0 +1,95 @@
## -*- tcl -*-
# # ## ### ##### ######## ############# #####################
##
# Canvas Behavior Module. Managing semi-crosshair rubber bands when
# dragging. Tracers are lines from fixed points to current location
# Purely visual. Driven from the outside. No bindings of its own.
##
## TODO : Callback to customize the rubberband lines.
# # ## ### ##### ######## ############# #####################
## Requisites
package require Tcl 8.5-
package require Tk
package require snit
namespace eval ::canvas::track {
namespace export lines
namespace ensemble create
}
# # ## ### ##### ######## ############# #####################
## API
snit::type ::canvas::track::lines {
# # ## ### ##### ######## ############# #####################
## Lifecycle management
constructor {c} {
set mycanvas $c
return
}
destructor {
$self done
}
# # ## ### ##### ######## ############# #####################
## API.
method start {center args} {
if {![llength $args]} return
$self done
# args = list of pairs, each pair contains the x- and
# y-coordinates of a fixed point.
# center is current location.
set mycoords $args
set myitems {}
foreach p $mycoords {
lappend myitems [$mycanvas create line \
{*}$p {*}$center \
-width 0 -fill black -dash .]
}
return
}
method move {center} {
if {![llength $myitems]} return
foreach p $mycoords item $myitems {
$mycanvas coords $item {*}$p {*}$center
}
return
}
method done {} {
if {![llength $myitems]} return
$mycanvas delete {*}$myitems
set myitems {}
set mycoords {}
return
}
# # ## ### ##### ######## ############# #####################
## STATE
variable mycanvas {} ; # The canvas we are working with/on.
variable mycoords {} ; # List of fixed points for the rubberbands.
variable myitems {} ; # Liust of the canvas items representing the rubberbands.
##
# # ## ### ##### ######## ############# #####################
}
# # ## ### ##### ######## ############# #####################
## Ready
package provide canvas::track::lines 0.1
return
# # ## ### ##### ######## ############# #####################
## Scrap yard.

181
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/canvas_zoom.tcl

@ -0,0 +1,181 @@
## -*- tcl -*-
# ### ### ### ######### ######### #########
## A discrete zoom-control widget based on two buttons and label.
## The API is similar to a scale.
# ### ### ### ######### ######### #########
## Requisites
package require Tcl 8.4- ; # No {*}-expansion :(
package require Tk
package require snit ; #
package require uevent::onidle ; # Some defered actions.
# ### ### ### ######### ######### #########
##
snit::widget ::canvas::zoom {
# ### ### ### ######### ######### #########
## API
option -orient -default vertical -configuremethod O-orient \
-type {snit::enum -values {vertical horizontal}}
option -levels -default {0 10} -configuremethod O-levels \
-type {snit::listtype -minlen 1 -maxlen 2 -type snit::integer}
option -variable -default {} -configuremethod O-variable
option -command -default {} -configuremethod O-command
constructor {args} {
install reconfigure using uevent::onidle ${selfns}::reconfigure \
[mymethod Reconfigure]
set options(-variable) [myvar myzoomlevel] ;# Default value
$self configurelist $args
# Force redraw if it could not be triggered by options.
if {![llength $args]} {
$reconfigure request
}
return
}
# ### ### ### ######### ######### #########
## Option processing. Any changes force a refresh of the grid
## information, and then a redraw.
method O-orient {o v} {
if {$options($o) eq $v} return
set options($o) $v
$reconfigure request
return
}
method O-levels {o v} {
# When only a single value was specified, we use it as
# our maximum, and default the minimum to zero.
if {[llength $v] == 1} {
set v [linsert $v 0 0]
}
if {$options($o) == $v} return
set options($o) $v
$reconfigure request
return
}
method O-variable {o v} {
# The handling of an attached variable is very simple, without
# any of the trace management one would expect to be
# here. That is because we are using an unmapped aka hidden
# scale widget to do this for us, at the C level.
if {$options($o) == $v} return
set options($o) $v
$reconfigure request
return
}
method O-command {o v} {
if {$v eq $options(-command)} return
set options(-command) $v
return
}
# ### ### ### ######### ######### #########
component reconfigure
method Reconfigure {} {
# (Re)generate the user interface.
eval [linsert [winfo children $win] 0 destroy]
set side $options(-orient)
set var $options(-variable)
foreach {lo hi} $options(-levels) break
set vwidth [expr {max([string length $lo], [string length $hi])}]
set pre [expr {[info commands ::ttk::button] ne "" ? "::ttk" : "::tk"}]
${pre}::frame $win.z -relief solid -borderwidth 1
${pre}::button $win.z.plus -image ::canvas::zoom::plus -command [mymethod ZoomIn]
${pre}::label $win.z.val -textvariable $var -justify c -anchor c -width $vwidth
${pre}::button $win.z.minus -image ::canvas::zoom::minus -command [mymethod ZoomOut]
# Use an unmapped scale to keep var between lo and hi and
# avoid doing our own trace management
scale $win.z.sc -from $lo -to $hi -variable $var
pack $win.z -fill both -expand 1
if {$side eq "vertical"} {
pack $win.z.plus $win.z.val $win.z.minus -side top -fill x
} else {
pack $win.z.plus $win.z.val $win.z.minus -side left -fill y
}
return
}
# ### ### ### ######### ######### #########
## Events which act on the zoomlevel.
method ZoomIn {} {
upvar #0 $options(-variable) zoomlevel
foreach {lo hi} $options(-levels) break
if {$zoomlevel >= $hi} return
incr zoomlevel
$self Callback
return
}
method ZoomOut {} {
upvar #0 $options(-variable) zoomlevel
foreach {lo hi} $options(-levels) break
if {$zoomlevel <= $lo} return
incr zoomlevel -1
$self Callback
return
}
method Callback {} {
if {![llength $options(-command)]} return
upvar #0 $options(-variable) zoomlevel
uplevel #0 [linsert $options(-command) end $win $zoomlevel]
return
}
# ### ### ### ######### ######### #########
## State
variable myzoomlevel 0 ; # The variable to use if the user
# did not supply one to -variable.
# ### ### ### ######### ######### #########
}
# ### ### ### ######### ######### #########
## Images for the buttons
image create bitmap ::canvas::zoom::plus -data {
#define plus_width 8
#define plus_height 8
static char bullet_bits = {
0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18
}
}
image create bitmap ::canvas::zoom::minus -data {
#define minus_width 8
#define minus_height 8
static char bullet_bits = {
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00
}
}
# ### ### ### ######### ######### #########
## Ready
package provide canvas::zoom 0.2.1
return
# ### ### ### ######### ######### #########
## Scrap yard.

16
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/canvas/pkgIndex.tcl

@ -0,0 +1,16 @@
if {![package vsatisfies [package provide Tcl] 8.4]} {return}
package ifneeded canvas::sqmap 0.3.1 [list source [file join $dir canvas_sqmap.tcl]]
package ifneeded canvas::zoom 0.2.1 [list source [file join $dir canvas_zoom.tcl]]
if {![package vsatisfies [package provide Tcl] 8.5]} { return }
package ifneeded canvas::drag 0.1 [list source [file join $dir canvas_drag.tcl]]
package ifneeded canvas::edit::circle 0.1 [list source [file join $dir canvas_ecircle.tcl]]
package ifneeded canvas::edit::points 0.3 [list source [file join $dir canvas_epoints.tcl]]
package ifneeded canvas::edit::polyline 0.2 [list source [file join $dir canvas_epolyline.tcl]]
package ifneeded canvas::edit::quadrilateral 0.1 [list source [file join $dir canvas_equad.tcl]]
package ifneeded canvas::edit::rectangle 0.1 [list source [file join $dir canvas_erectangle.tcl]]
package ifneeded canvas::gradient 0.2 [list source [file join $dir canvas_gradient.tcl]]
package ifneeded canvas::highlight 0.1 [list source [file join $dir canvas_highlight.tcl]]
package ifneeded canvas::mvg 1 [list source [file join $dir canvas_mvg.tcl]]
package ifneeded canvas::snap 1.0.1 [list source [file join $dir canvas_snap.tcl]]
package ifneeded canvas::tag 0.1 [list source [file join $dir canvas_tags.tcl]]
package ifneeded canvas::track::lines 0.1 [list source [file join $dir canvas_trlines.tcl]]

777
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/chatwidget/chatwidget.tcl

@ -0,0 +1,777 @@
# chatwidget.tcl --
#
# This package provides a composite widget suitable for use in chat
# applications. A number of panes managed by panedwidgets are available
# for displaying user names, chat text and for entering new comments.
# The main display area makes use of text widget peers to enable a split
# view for history or searching.
#
# Copyright (C) 2007 Pat Thoyts <patthoyts@users.sourceforge.net>
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
package require Tcl 8.5-
package require Tk 8.5-
namespace eval chatwidget {
variable version 1.1.4
namespace export chatwidget
ttk::style layout ChatwidgetFrame {
Entry.field -sticky news -border 1 -children {
ChatwidgetFrame.padding -sticky news
}
}
if {[lsearch -exact [font names] ChatwidgetFont] == -1} {
eval [list font create ChatwidgetFont] [font configure TkTextFont]
eval [list font create ChatwidgetBoldFont] \
[font configure ChatwidgetFont] -weight bold
eval [list font create ChatwidgetItalicFont] \
[font configure ChatwidgetFont] -slant italic
eval [list font create ChatwidgetTopicFont] \
[font configure ChatwidgetFont] \
-size [expr {[font configure ChatwidgetFont -size] - 0}]
}
}
proc chatwidget::chatwidget {w args} {
Create $w
interp hide {} $w
interp alias {} $w {} [namespace origin WidgetProc] $w
return $w
}
proc chatwidget::WidgetProc {self cmd args} {
upvar #0 [namespace current]::$self state
switch -- $cmd {
hook {
if {[llength $args] < 2} {
return -code error "wrong \# args: should be\
\"\$widget hook add|remove|list hook_type ?script? ?priority?\""
}
return [uplevel 1 [list [namespace origin Hook] $self] $args]
}
cget {
return [uplevel 1 [list [namespace origin Cget] $self] $args]
}
configure {
return [uplevel 1 [list [namespace origin Configure] $self] $args]
}
insert {
return [uplevel 1 [list [namespace origin Insert] $self] $args]
}
message {
return [uplevel 1 [list [namespace origin Message] $self] $args]
}
name {
return [uplevel 1 [list [namespace origin Name] $self] $args]
}
topic {
return [uplevel 1 [list [namespace origin Topic] $self] $args]
}
names {
return [uplevel 1 [list [namespace origin Names] $self] $args]
}
entry {
return [uplevel 1 [list [namespace origin Entry] $self] $args]
}
peer {
return [uplevel 1 [list [namespace origin Peer] $self] $args]
}
chat -
default {
return [uplevel 1 [list [namespace origin Chat] $self] $args]
}
}
return
}
proc chatwidget::Chat {self args} {
upvar #0 [namespace current]::$self state
if {[llength $args] == 0} {
return $state(chat_widget)
}
return [uplevel 1 [list $state(chat_widget)] $args]
}
proc chatwidget::Cget {self args} {
upvar #0 [namespace current]::$self state
switch -exact -- [set what [lindex $args 0]] {
-chatstate { return $state(chatstate) }
-history { return $state(history) }
default {
return [uplevel 1 [list $state(chat_widget) cget] $args]
}
}
}
proc chatwidget::Configure {self args} {
upvar #0 [namespace current]::$self state
switch -exact -- [set option [lindex $args 0]] {
-chatstate {
if {[llength $args] > 1} { set state(chatstate) [Pop args 1] }
else { return $state(chatstate) }
}
-history {
if {[llength $args] > 1} { set state(history) [Pop args 1] }
else { return $state(history) }
}
-font {
if {[llength $args] > 1} {
set font [Pop args 1]
set family [font actual $font -family]
set size [font actual $font -size]
font configure ChatwidgetFont -family $family -size $size
font configure ChatwidgetBoldFont -family $family -size $size
font configure ChatwidgetItalicFont -family $family -size $size
} else { return [$state(chat_widget) cget -font] }
}
default {
return [uplevel 1 [list $state(chat_widget) configure] $args]
}
}
}
proc chatwidget::Peer {self args} {
upvar #0 [namespace current]::$self state
if {[llength $args] == 0} {
return $state(chat_peer_widget)
}
return [uplevel 1 [list $state(chat_peer_widget)] $args]
}
proc chatwidget::Topic {self cmd args} {
upvar #0 [namespace current]::$self state
switch -exact -- $cmd {
show { grid $self.topic -row 0 -column 0 -sticky new }
hide { grid forget $self.topic }
set {
set state(topic) [lindex $args 0]
$self.topic.text configure -state normal
$self.topic.text delete 1.0 end
$self.topic.text insert end $state(topic)
$self.topic.text configure -state disabled
bind $self.topic.text <Map> [list [namespace origin TopicUpdate] $self]
}
default {
return -code error "bad option \"$cmd\":\
must be show, hide or set"
}
}
}
# Set the topic widget to 2 lines with an optional scrollbar if the text
# will require more than a single line of display.
proc chatwidget::TopicUpdate {self} {
bind $self.topic.text <Map> {}
set lines [$self.topic.text count -displaylines 1.0 end]
if {$lines < 2} {
$self.topic.text configure -height 1
} else {
$self.topic.text configure -height 2
ttk::scrollbar $self.topic.vs -command [list $self.topic.text yview]
$self.topic.text configure -yscrollcommand \
[list [namespace origin scroll_set] $self.topic.vs $self 0]
grid $self.topic.vs -row 0 -column 2 -sticky new -pady {2 0} -padx 1
}
}
proc chatwidget::Names {self args} {
upvar #0 [namespace current]::$self state
set frame [winfo parent $state(names_widget)]
set pane [winfo parent $frame]
if {[llength $args] == 0} {
return $state(names_widget)
}
if {[llength $args] == 1 && [lindex $args 0] eq "hide"} {
if {$frame in [$pane panes]} {
$pane forget $frame
}
return
}
if {[llength $args] == 1 && [lindex $args 0] eq "show"} {
if {$frame ni [$pane panes]} {
$pane add $frame
}
return
}
return [uplevel 1 [list $state(names_widget)] $args]
}
proc chatwidget::Entry {self args} {
upvar #0 [namespace current]::$self state
if {[llength $args] == 0} {
return $state(entry_widget)
}
if {[llength $args] == 1 && [lindex $args 0] eq "text"} {
return [$state(entry_widget) get 1.0 end-1c]
}
return [uplevel 1 [list $state(entry_widget)] $args]
}
proc chatwidget::Message {self text args} {
upvar #0 [namespace current]::$self state
set chat $state(chat_widget)
set mark end
set type normal
set nick Unknown
set time [clock seconds]
set tags {}
while {[string match -* [set option [lindex $args 0]]]} {
switch -exact -- $option {
-nick { set nick [Pop args 1] }
-time { set time [Pop args 1] }
-type { set type [Pop args 1] }
-mark { set mark [Pop args 1] }
-tags { set tags [Pop args 1] }
default {
return -code error "unknown option \"$option\""
}
}
Pop args
}
if {[catch {Hook $self run message $text \
-mark $mark -type $type -nick $nick \
-time $time -tags $tags}] == 3} then {
return
}
if {$type ne "system"} { lappend tags NICK-$nick }
lappend tags TYPE-$type
$chat configure -state normal
set ts [clock format $time -format "\[%H:%M\]\t"]
$chat insert $mark $ts [concat BOOKMARK STAMP $tags]
if {$type eq "action"} {
$chat insert $mark " * $nick " [concat BOOKMARK NICK $tags]
lappend tags ACTION
} elseif {$type eq "system"} {
} else {
$chat insert $mark "$nick\t" [concat BOOKMARK NICK $tags]
}
if {$type ne "system"} { lappend tags MSG NICK-$nick }
#$chat insert $mark $text $tags
Insert $self $mark $text $tags
$chat insert $mark "\n" $tags
$chat configure -state disabled
if {$state(autoscroll)} {
$chat see $mark
}
return
}
proc chatwidget::Insert {self mark args} {
upvar #0 [namespace current]::$self state
if {![info exists state(urluid)]} {set state(urluid) 0}
set w $state(chat_widget)
set parts {}
foreach {s t} $args {
while {[regexp -indices {\m(https?://[^\s]+)} $s -> ndx]} {
foreach {fr bk} $ndx break
lappend parts [string range $s 0 [expr {$fr - 1}]] $t
lappend parts [string range $s $fr $bk] \
[linsert $t end URL URL-[incr state(urluid)]]
set s [string range $s [incr bk] end]
}
lappend parts $s $t
}
set ws [$w cget -state]
$w configure -state normal
eval [list $w insert $mark] $parts
$w configure -state $ws
}
# $w name add ericthered -group admin -color red
# state(names) {{pat -color red -group admin -thing wilf} {eric ....}}
proc chatwidget::Name {self cmd args} {
upvar #0 [namespace current]::$self state
switch -exact -- $cmd {
list {
switch -exact -- [lindex $args 0] {
-full {
return $state(names)
}
default {
set r {}
foreach item $state(names) { lappend r [lindex $item 0] }
return $r
}
}
}
add {
if {[llength $args] < 1 || ([llength $args] % 2) != 1} {
return -code error "wrong # args: should be\
\"add nick ?-group group ...?\""
}
set nick [lindex $args 0]
if {[set ndx [lsearch -exact -index 0 $state(names) $nick]] == -1} {
set fg [$state(chat_widget) cget -foreground]
array set opts [list -group {} -color $fg]
array set opts [lrange $args 1 end]
lappend state(names) [linsert [array get opts] 0 $nick]
} else {
array set opts [lrange [lindex $state(names) $ndx] 1 end]
array set opts [lrange $args 1 end]
lset state(names) $ndx [linsert [array get opts] 0 $nick]
}
UpdateNames $self
}
delete {
if {[llength $args] != 1} {
return -code error "wrong # args: should be \"delete nick\""
}
set nick [lindex $args 0]
if {[set ndx [lsearch -exact -index 0 $state(names) $nick]] != -1} {
set state(names) [lreplace $state(names) $ndx $ndx]
UpdateNames $self
}
}
get {
if {[llength $args] < 1} {
return -code error "wrong # args:\
should be \"get nick\" ?option?"
}
set result {}
set nick [lindex $args 0]
if {[set ndx [lsearch -exact -index 0 $state(names) $nick]] != -1} {
set result [lindex $state(names) $ndx]
if {[llength $args] > 1} {
if {[set ndx [lsearch $result [lindex $args 1]]] != -1} {
set result [lindex $result [incr ndx]]
} else {
set result {}
}
}
}
return $result
}
default {
return -code error "bad name option \"$cmd\":\
must be list, names, add or delete"
}
}
}
proc chatwidget::UpdateNames {self} {
upvar #0 [namespace current]::$self state
if {[info exists state(updatenames)]} {
after cancel $state(updatenames)
}
set state(updatenames) [after idle [list [namespace origin UpdateNamesExec] $self]]
}
proc chatwidget::UpdateNamesExec {self} {
upvar #0 [namespace current]::$self state
unset state(updatenames)
set names $state(names_widget)
set chat $state(chat_widget)
foreach tagname [lsearch -all -inline [$names tag names] NICK-*] {
$names tag delete $tagname
}
foreach tagname [lsearch -all -inline [$names tag names] GROUP-*] {
$names tag delete $tagname
}
$names configure -state normal
$names delete 1.0 end
array set groups {}
foreach item $state(names) {
set group {}
if {[set ndx [lsearch $item -group]] != -1} {
set group [lindex $item [incr ndx]]
}
lappend groups($group) [lindex $item 0]
}
foreach group [lsort [array names groups]] {
Hook $self run names_group $group
$names insert end "$group\n" [list SUBTITLE GROUP-$group]
foreach nick [lsort -dictionary $groups($group)] {
$names tag configure NICK-$nick
unset -nocomplain opts ; array set opts {}
if {[set ndx [lsearch -exact -index 0 $state(names) $nick]] != -1} {
array set opts [lrange [lindex $state(names) $ndx] 1 end]
if {[info exists opts(-color)]} {
$names tag configure NICK-$nick -foreground $opts(-color)
$chat tag configure NICK-$nick -foreground $opts(-color)
}
eval [linsert [lindex $state(names) $ndx] 0 \
Hook $self run names_nick]
}
$names insert end $nick\n [list NICK NICK-$nick GROUP-$group]
}
}
$names insert end "[llength $state(names)] nicks\n" [list SUBTITLE]
$names configure -state disabled
}
proc chatwidget::Pop {varname {nth 0}} {
upvar $varname args
set r [lindex $args $nth]
set args [lreplace $args $nth $nth]
return $r
}
proc chatwidget::Hook {self do type args} {
upvar #0 [namespace current]::$self state
set valid {message post names_group names_nick chatstate url}
if {[lsearch -exact $valid $type] == -1} {
return -code error "unknown hook type \"$type\":\
must be one of [join $valid ,]"
}
switch -exact -- $do {
add {
if {[llength $args] < 1 || [llength $args] > 2} {
return -code error "wrong # args: should be \"add hook cmd ?priority?\""
}
foreach {cmd pri} $args break
if {$pri eq {}} { set pri 50 }
lappend state(hook,$type) [list $cmd $pri]
set state(hook,$type) [lsort -real -index 1 [lsort -unique $state(hook,$type)]]
}
remove {
if {[llength $args] != 1} {
return -code error "wrong # args: should be \"remove hook cmd\""
}
if {![info exists state(hook,$type)]} { return }
for {set ndx 0} {$ndx < [llength $state(hook,$type)]} {incr ndx} {
set item [lindex $state(hook,$type) $ndx]
if {[lindex $item 0] eq [lindex $args 0]} {
set state(hook,$type) [lreplace $state(hook,$type) $ndx $ndx]
break
}
}
set state(hook,$type)
}
run {
if {![info exists state(hook,$type)]} { return }
set res ""
foreach item $state(hook,$type) {
foreach {cmd pri} $item break
set code [catch {eval $cmd $args} err]
if {$code} {
::bgerror "error running \"$type\" hook: $err"
break
} else {
lappend res $err
}
}
return $res
}
list {
if {[info exists state(hook,$type)]} {
return $state(hook,$type)
}
}
default {
return -code error "unknown hook action \"$do\":\
must be add, remove, list or run"
}
}
}
proc chatwidget::Grid {w {row 0} {column 0}} {
grid rowconfigure $w $row -weight 1
grid columnconfigure $w $column -weight 1
}
proc chatwidget::Create {self} {
upvar #0 [set State [namespace current]::$self] state
set state(history) {}
set state(current) 0
set state(autoscroll) 1
set state(names) {}
set state(chatstatetimer) {}
set state(chatstate) active
# NOTE: By using a non-ttk frame as the outermost part we are able
# to be [wm manage]d. The outermost frame should be invisible at all times.
set self [frame $self -class Chatwidget \
-borderwidth 0 -highlightthickness 0 -relief flat]
set outer [ttk::panedwindow $self.outer -orient vertical]
set inner [ttk::panedwindow $outer.inner -orient horizontal]
# Create a topic/subject header
set topic [ttk::frame $self.topic]
ttk::label $topic.label -anchor w -text Topic
text $topic.text -state disabled -font ChatwidgetTopicFont
$topic.text configure -state disabled -height 1 -wrap word
grid $topic.label $topic.text -sticky new -pady {2 0} -padx 1
Grid $topic 0 1
# Create the usernames scrolled text
set names [ttk::frame $inner.names -style ChatwidgetFrame]
text $names.text -borderwidth 0 -relief flat -font ChatwidgetFont
ttk::scrollbar $names.vs -command [list $names.text yview]
$names.text configure -width 10 -height 10 -state disabled \
-yscrollcommand [list [namespace origin scroll_set] $names.vs $inner 0]
bindtags $names.text [linsert [bindtags $names.text] 1 ChatwidgetNames]
grid $names.text $names.vs -sticky news -padx 1 -pady 1
Grid $names 0 0
set state(names_widget) $names.text
# Create the chat display
set chatf [ttk::frame $inner.chat -style ChatwidgetFrame]
set peers [ttk::panedwindow $chatf.peers -orient vertical]
set upper [ttk::frame $peers.upper]
set lower [ttk::frame $peers.lower]
set chat [text $lower.text -borderwidth 0 -relief flat -wrap word \
-state disabled -font ChatwidgetFont]
set chatvs [ttk::scrollbar $lower.vs -command [list $chat yview]]
$chat configure -height 10 -state disabled \
-yscrollcommand [list [namespace origin scroll_set] $chatvs $peers 1]
grid $chat $chatvs -sticky news
Grid $lower 0 0
set peer [$chat peer create $upper.text -borderwidth 0 -relief flat \
-wrap word -state disabled -font ChatwidgetFont]
set peervs [ttk::scrollbar $upper.vs -command [list $peer yview]]
$peer configure -height 0 \
-yscrollcommand [list [namespace origin scroll_set] $peervs $peers 0]
grid $peer $peervs -sticky news
Grid $upper 0 0
$peers add $upper
$peers add $lower -weight 1
grid $peers -sticky news -padx 1 -pady 1
Grid $chatf 0 0
bindtags $chat [linsert [bindtags $chat] 1 ChatwidgetText]
set state(chat_widget) $chat
set state(chat_peer_widget) $peer
# Create the entry widget
set entry [ttk::frame $outer.entry -style ChatwidgetFrame]
text $entry.text -borderwidth 0 -relief flat -font ChatwidgetFont
$entry.text configure -insertbackground [$entry.text cget -foreground]
ttk::scrollbar $entry.vs -command [list $entry.text yview]
$entry.text configure -height 1 \
-yscrollcommand [list [namespace origin scroll_set] $entry.vs $outer 0]
bindtags $entry.text [linsert [bindtags $entry.text] 1 ChatwidgetEntry]
grid $entry.text $entry.vs -sticky news -padx 1 -pady 1
Grid $entry 0 0
set state(entry_widget) $entry.text
bind ChatwidgetEntry <Return> "[namespace origin Post] \[[namespace origin Self] %W\]"
bind ChatwidgetEntry <KP_Enter> "[namespace origin Post] \[[namespace origin Self] %W\]"
bind ChatwidgetEntry <Shift-Return> "#"
bind ChatwidgetEntry <Control-Return> "#"
bind ChatwidgetEntry <Key-Up> "[namespace origin History] \[[namespace origin Self] %W\] prev"
bind ChatwidgetEntry <Key-Down> "[namespace origin History] \[[namespace origin Self] %W\] next"
bind ChatwidgetEntry <Key-Tab> "[namespace origin Nickcomplete] \[[namespace origin Self] %W\]"
bind ChatwidgetEntry <Key-Prior> "\[[namespace origin Self] %W\] chat yview scroll -1 pages"
bind ChatwidgetEntry <Key-Next> "\[[namespace origin Self] %W\] chat yview scroll 1 pages"
bind ChatwidgetEntry <Key> "+[namespace origin Chatstate] \[[namespace origin Self] %W\] composing"
bind ChatwidgetEntry <FocusIn> "+[namespace origin Chatstate] \[[namespace origin Self] %W\] active"
bind $self <Destroy> "+unset -nocomplain [namespace current]::%W"
bind $peer <Map> [list [namespace origin PaneMap] %W $peers 0]
bind $names.text <Map> [list [namespace origin PaneMap] %W $inner -90]
bind $entry.text <Map> [list [namespace origin PaneMap] %W $outer -28]
bind ChatwidgetText <<ThemeChanged>> {
ttk::style layout ChatwidgetFrame {
Entry.field -sticky news -border 1 -children {
ChatwidgetFrame.padding -sticky news
}
}
}
# Use inverted colors for the subtitles.
$names.text tag configure SUBTITLE -font ChatwidgetBoldFont \
-foreground [$names.text cget -background] \
-background [$names.text cget -foreground]
$chat tag configure NICK -font ChatwidgetBoldFont
$chat tag configure TYPE-system -font ChatwidgetItalicFont
$chat tag configure URL -underline 1
$inner add $chatf -weight 1
$inner add $names
$outer add $inner -weight 1
$outer add $entry
grid $outer -row 1 -column 0 -sticky news -padx 1 -pady 1
Grid $self 1 0
return $self
}
proc chatwidget::Self {widget} {
set class [winfo class [set w $widget]]
while {[winfo exists $w] && [winfo class $w] ne "Chatwidget"} {
set w [winfo parent $w]
}
if {![winfo exists $w]} {
return -code error "invalid window $widget"
}
return $w
}
# Set initial position of sash
proc chatwidget::PaneMap {w pane offset} {
bind $w <Map> {}
if {[llength [$pane panes]] > 1} {
if {$offset < 0} {
if {[$pane cget -orient] eq "horizontal"} {
set axis width
} else {
set axis height
}
#after idle [list $pane sashpos 0 [expr {[winfo $axis $pane] + $offset}]]
after idle [namespace code [list PaneMapImpl $pane $axis $offset]]
} else {
#after idle [list $pane sashpos 0 $offset]
after idle [namespace code [list PaneMapImpl $pane {} $offset]]
}
}
}
proc chatwidget::PaneMapImpl {pane axis offset} {
if {$axis eq {}} {
set size 0
} else {
set size [winfo $axis $pane]
}
set sashpos [expr {$size + $offset}]
#puts stderr "PaneMapImpl $pane $axis $offset : size:$size sashpos:$sashpos"
after 0 [list $pane sashpos 0 $sashpos]
}
# Handle auto-scroll smarts. This will cause the scrollbar to be removed if
# not required and to disable autoscroll for the text widget if we are not
# tracking the bottom line.
proc chatwidget::scroll_set {scrollbar pw set f1 f2} {
$scrollbar set $f1 $f2
if {($f1 == 0) && ($f2 == 1)} {
grid remove $scrollbar
} else {
if {[winfo manager $scrollbar] eq {}} {}
if {[llength [$pw panes]] > 1} {
set pos [$pw sashpos 0]
grid $scrollbar
after idle [list $pw sashpos 0 $pos]
} else {
grid $scrollbar
}
}
if {$set} {
upvar #0 [namespace current]::[Self $scrollbar] state
set state(autoscroll) [expr {(1.0 - $f2) < 1.0e-6 }]
}
}
proc chatwidget::Post {self} {
set msg [$self entry get 1.0 end-1c]
if {$msg eq ""} { return -code break "" }
if {[catch {Hook $self run post $msg}] != 3} {
$self entry delete 1.0 end
upvar #0 [namespace current]::$self state
set state(history) [lrange [lappend state(history) $msg] end-50 end]
set state(current) [llength $state(history)]
}
return -code break ""
}
proc chatwidget::History {self dir} {
upvar #0 [namespace current]::$self state
switch -exact -- $dir {
prev {
if {$state(current) == 0} { return }
if {$state(current) == [llength $state(history)]} {
set state(temp) [$self entry get 1.0 end-1c]
}
if {$state(current)} { incr state(current) -1 }
$self entry delete 1.0 end
$self entry insert 1.0 [lindex $state(history) $state(current)]
return
}
next {
if {$state(current) == [llength $state(history)]} { return }
if {[incr state(current)] == [llength $state(history)] && [info exists state(temp)]} {
set msg $state(temp)
} else {
set msg [lindex $state(history) $state(current)]
}
$self entry delete 1.0 end
$self entry insert 1.0 $msg
}
default {
return -code error "invalid direction \"$dir\":
must be either prev or next"
}
}
}
proc chatwidget::Nickcomplete {self} {
upvar #0 [namespace current]::$self state
if {[info exists state(nickcompletion)]} {
foreach {index matches after} $state(nickcompletion) break
after cancel $after
incr index
if {$index > [llength $matches]} { set index 0 }
set delta 2c
} else {
set delta 1c
set partial [$self entry get "insert - $delta wordstart" "insert - $delta wordend"]
set matches [lsearch -all -inline -glob -index 0 $state(names) $partial*]
set index 0
}
switch -exact -- [llength $matches] {
0 { bell ; return -code break ""}
1 { set match [lindex [lindex $matches 0] 0]}
default {
set match [lindex [lindex $matches $index] 0]
set state(nickcompletion) [list $index $matches \
[after 2000 [list [namespace origin NickcompleteCleanup] $self]]]
}
}
$self entry delete "insert - $delta wordstart" "insert - $delta wordend"
$self entry insert insert "$match "
return -code break ""
}
proc chatwidget::NickcompleteCleanup {self} {
upvar #0 [namespace current]::$self state
if {[info exists state(nickcompletion)]} {
unset state(nickcompletion)
}
}
# Update the widget chatstate (one of active, composing, paused, inactive, gone)
# These are from XEP-0085 but seem likey useful in many chat-type environments.
# Note: this state is _per-widget_. This is not the same as [tk inactive]
# active = got focus and recently active
# composing = typing
# paused = 5 secs non typing
# inactive = no activity for 30 seconds
# gone = no activity for 2 minutes or closed the window
proc chatwidget::Chatstate {self what} {
upvar #0 [namespace current]::$self state
if {![info exists state]} { return }
after cancel $state(chatstatetimer)
switch -exact -- $what {
composing - active {
set state(chatstatetimer) [after 5000 [namespace code [list Chatstate $self paused]]]
}
paused {
set state(chatstatetimer) [after 25000 [namespace code [list Chatstate $self inactive]]]
}
inactive {
set state(chatstatetimer) [after 120000 [namespace code [list Chatstate $self gone]]]
}
gone {}
}
set fire [expr {$state(chatstate) eq $what ? 0 : 1}]
set state(chatstate) $what
if {$fire} {
catch {Hook $self run chatstate $what}
event generate $self <<ChatwidgetChatstate>>
}
}
package provide chatwidget $chatwidget::version

1
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/chatwidget/pkgIndex.tcl

@ -0,0 +1 @@
package ifneeded chatwidget 1.1.4 [list source [file join $dir chatwidget.tcl]]

45
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/bindDown.tcl

@ -0,0 +1,45 @@
#
# This software is Copyright by the Board of Trustees of Michigan
# State University (c) Copyright 2005.
#
# You may use this software under the terms of the GNU public license
# (GPL) ir the Tcl BSD derived license The terms of these licenses
# are described at:
#
# GPL: http://www.gnu.org/licenses/gpl.txt
# Tcl: http://www.tcl.tk/softare/tcltk/license.html
# Start with the second paragraph under the Tcl/Tk License terms
# as ownership is solely by Board of Trustees at Michigan State University.
#
# Author:
# Ron Fox
# NSCL
# Michigan State University
# East Lansing, MI 48824-1321
#
#
# bindDown is a simple package that allows the user to attach
# bind tags to a hieararchy of widgets starting with the top of
# a widget tree. The most common use of this is in snit::widgets
# to allow a binding to be placed on the widget itself e.g:
# bindDown $win $win
#
# where the first item is the top of the widget tree, the second the
# bindtag to add to each widget in the subtree.
# This will allow bind $win <yada> yada to apply to the widget
# children.
#
#
package provide bindDown 1.0
proc bindDown {top tag} {
foreach widget [winfo children $top] {
set wtags [bindtags $widget]
lappend wtags $tag
bindtags $widget [lappend wtags $tag]
bindDown $widget $tag
}
}

17
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/controlwidget.tcl

@ -0,0 +1,17 @@
# controlwidget.tcl --
# Set up the requirements for the controlwidget module/package
# and source the individual files
#
package require Tk 8.5-
package require snit
package require bindDown
package require meter
package require led
package require rdial
package require tachometer
package require voltmeter
package require radioMatrix
package provide controlwidget 0.1

127
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/led.tcl

@ -0,0 +1,127 @@
#
# This software is Copyright by the Board of Trustees of Michigan
# State University (c) Copyright 2005.
#
# You may use this software under the terms of the GNU public license
# (GPL) ir the Tcl BSD derived license The terms of these licenses
# are described at:
#
# GPL: http://www.gnu.org/licenses/gpl.txt
# Tcl: http://www.tcl.tk/softare/tcltk/license.html
# Start with the second paragraph under the Tcl/Tk License terms
# as ownership is solely by Board of Trustees at Michigan State University.
#
# Author:
# Ron Fox
# NSCL
# Michigan State University
# East Lansing, MI 48824-1321
#
# Adjusted by Arjen Markus
#
#
# This package provides an LED
# widget. LED widgets are one color when on
# and another when off.
# Implementation is just a filled circle on a
# canvas.
# Options recognized:
# (all standard options for a frame).
# -size - Radius of the led.
# -on - Color of on state.
# -off - Color of off state.
# -variable - on color when variable is nonzero else off.
# Methods
# on - Turn led on.
# off - Turn led off.
#
# TODO:
# Add a label
#
package provide led 1.0
package require Tk
package require snit
package require bindDown
namespace eval controlwidget {
namespace export led
}
snit::widget controlwidget::led {
delegate option * to hull
option -size {17}
option -on green
option -off black
option -variable {}
constructor args {
$self configurelist $args
canvas $win.led -width $options(-size) -height $options(-size)
set border [expr [$win cget -borderwidth] + 2]
set end [expr $options(-size) - $border]
$win.led create oval $border $border $end $end -fill $options(-off)
grid $win.led -sticky nsew
bindDown $win $win
}
# Process the -variable configuration by killing off prior traces
# and setting an new trace:
#
onconfigure -variable name {
if {$options(-variable) ne ""} {
trace remove variable ::$options(-variable) write [mymethod varTrace]
}
trace add variable ::$name write [mymethod varTrace]
set options(-variable) $name
# set our initial state to the current value of the var:
# the after is because we could be constructing an need to give
# the widgets a chance to get built:
after 10 [list $self varTrace $name "" write]
}
# Trace for the led variable..
#
method varTrace {name index op} {
set name ::$name
set value [set $name]
if {[string is boolean -strict $value]} {
$self setstate $value
}
}
#
# Set the led on.
#
method on {} {
if {$options(-variable) ne ""} {
set ::$options(-variable) 1
} else {
$self setstate 1
}
}
# set the led off
#
method off {} {
if {$options(-variable) ne ""} {
set ::$options(-variable) 0
} else {
$self setstate 0
}
}
#
# Set the led state
#
method setstate {value} {
if {$value} {
$win.led itemconfigure 1 -fill $options(-on)
} else {
$win.led itemconfigure 1 -fill $options(-off)
}
}
}

23
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/pkgIndex.tcl

@ -0,0 +1,23 @@
# pkgIndex.tcl --
# Index script for controlwidget package
# Note:
# We could split this into several parts. Now it is presented
# as a single package.
#
if {![package vsatisfies [package provide Tcl] 8.5]} {
# PRAGMA: returnok
return
}
if {![package vsatisfies [package provide Tcl] 8.5-]} {
# PRAGMA: returnok
return
}
package ifneeded controlwidget 0.1 [list source [file join $dir controlwidget.tcl]]
package ifneeded meter 1.0 [list source [file join $dir vertical_meter.tcl]]
package ifneeded led 1.0 [list source [file join $dir led.tcl]]
package ifneeded rdial 0.7 [list source [file join $dir rdial.tcl]]
package ifneeded tachometer 0.1 [list source [file join $dir tachometer.tcl]]
package ifneeded voltmeter 0.1 [list source [file join $dir voltmeter.tcl]]
package ifneeded radioMatrix 1.0 [list source [file join $dir radioMatrix.tcl]]
package ifneeded bindDown 1.0 [list source [file join $dir bindDown.tcl]]

253
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/radioMatrix.tcl

@ -0,0 +1,253 @@
#
# This software is Copyright by the Board of Trustees of Michigan
# State University (c) Copyright 2005.
#
# You may use this software under the terms of the GNU public license
# (GPL) ir the Tcl BSD derived license The terms of these licenses
# are described at:
#
# GPL: http://www.gnu.org/licenses/gpl.txt
# Tcl: http://www.tcl.tk/softare/tcltk/license.html
# Start with the second paragraph under the Tcl/Tk License terms
# as ownership is solely by Board of Trustees at Michigan State University.
#
# Author:
# Ron Fox
# NSCL
# Michigan State University
# East Lansing, MI 48824-1321
#
# Provide a megawidget that is a matrix of radio buttons
# and a variable that is tracked. The idea is that this
# can be used to control a device that has an enumerable
# set of values.
#
# OPTIONS:
# -orient Determines the order in which the radio buttons are
# laid out:
# vertical - buttons run from top to bottom then left to right.
# horizontal - buttons run from left to right top to bottom.
# -columns Number of columns.
# -rows Number of rows.
# -values Contains a list of values. Each element of the list is either
# a single element, which represents the value of the button or
# is a pair of values that represent a name/value pair for the button.
# If -values is provided, only one of -rows/-columns can be provided.
# If -values is not provided, both -rows and -columns must be provided
# and the label name/value pairs are 1,2,3,4,5...
# -variable Variable to track in the widget.
# -command Script to run when a radio button is clicked.
#
# METHODS:
# get - Gets the current button value.
# set - Sets the current button value (-command is invoked if defined).
# NOTES:
# 1. See the constraints on the options described above.
# 2. If, on entry, the variable (either global or fully namespace qualified
# is set and matches a radio button value, that radio button is initially
# lit.
# 3. The geometric properties of the widget can only be established at
# construction time, and are therefore static.
package provide radioMatrix 1.0
package require Tk
package require snit
package require bindDown
namespace eval controlwidget {
namespace export radioMatrix
}
snit::widget ::controlwidget::radioMatrix {
delegate option -variable to label as -textvariable
delegate option * to hull
option -orient horizontal
option -rows {1}
option -columns {}
option -values [list]
option -command [list]
variable radioVariable; # for the radio button.
# Construct the widget.
constructor args {
# The buttons go in a frame just to make it easy to lay them out.:
set bf [frame $win.buttons]
install label using label $win.label
# Process the configuration.
$self configurelist $args
# Ensure that the option constraints are met.
$self errorIfConstraintsNotMet
# If the values have not been provided, then use the rows/columns
# to simluate them.
if {$options(-values) eq ""} {
set totalValues [expr $options(-columns) * $options(-rows)]
for {set i 0} {$i < $totalValues} {incr i} {
lappend options(-values) $i
}
}
# Top level layout decision based on orientation.
if {$options(-orient) eq "horizontal"} {
$self arrangeHorizontally
} elseif {$options(-orient) eq "vertical"} {
$self arrangeVertically
} else {
error "Invalid -orient value: $options(-orient)"
}
grid $bf
grid $win.label
# If the label has a text variable evaluate it to see
# if we can do a set with it:
set labelvar [$win.label cget -textvariable]
if {$labelvar ne ""} {
$self Set [set ::$labelvar]
}
bindDown $win $win
}
# Public methods:
method get {} {
return $radioVariable
}
method set value {
set radioVariable $value
}
# Private methods and procs.
# Ensure the constraints on the options are met.
method errorIfConstraintsNotMet {} {
if {$options(-values) eq "" &&
($options(-rows) eq "" || $options(-columns) eq "")} {
error "If -values is not supplied, but -rows and -coumns must be."
}
if {($options(-rows) ne "" && $options(-columns) ne "") &&
$options(-values) ne ""} {
error "If both -rows and -coumns were supplied, -values cannot be"
}
}
# Process radio button change.
#
method onChange {} {
set script $options(-command)
if {$script ne ""} {
eval $script
}
}
# Manage horizontal layout
method arrangeHorizontally {} {
#
# Either both rows and columns are defined, or
# one is defined and the other must be computed from the
# length of the values list (which by god was defined).
# If both are defined, values was computed from them.
set rows $options(-rows)
set cols $options(-columns)
# Only really need # of cols.
set len [llength $options(-values)]
if {$cols eq ""} {
set cols [expr ($len + $rows - 1)/$rows]
}
set index 0
set rowNum 0
while {$index < $len} {
for {set i 0} {$i < $cols} {incr i} {
if {$index >= $len} {
break
}
set item [lindex $options(-values) $index]
if {[llength $item] > 1} {
set label [lindex $item 0]
set value [lindex $item 1]
} else {
set value [lindex $item 0]
set label $value
}
radiobutton $win.buttons.cb$index \
-command [mymethod onChange] \
-variable ${selfns}::radioVariable \
-value $value -text $label
grid $win.buttons.cb$index -row $rowNum -column $i
incr index
}
incr rowNum
}
}
# manage vertical layout
method arrangeVertically {} {
#
# See arrangeHorizontally for the overall picture, just swap cols
# and rows.
set rows $options(-rows)
set cols $options(-columns)
set len [llength $options(-values)]
if {$rows eq ""} {
set rows [expr ($len + $cols -1)/$cols]
}
set index 0
set colNum 0
while {$index < $len} {
for {set i 0} {$i < $rows} {incr i} {
if {$index >= $len} {
break
}
set item [lindex $options(-values) $index]
if {[llength $item] > 1} {
set label [lindex $item 0]
set value [lindex $item 1]
} else {
set value [lindex $item 0]
set label $value
}
radiobutton $win.buttons.cb$index \
-command [mymethod onChange] \
-variable ${selfns}::radioVariable \
-value $value -text $label
grid $win.buttons.cb$index -row $i -column $colNum
incr index
}
incr colNum
}
}
}

455
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/rdial.tcl

@ -0,0 +1,455 @@
# rdial.tcl --
# Rotated dial widget, part of controlwidget package
#
# Contents: a "rotated" dial widget or thumbnail "roller" dial
# Date: Son May 23, 2010
#
# Abstract
# A mouse draggable "dial" widget from the side view - visible
# is the knurled area - Shift & Ctrl changes the sensitivity
#
# Copyright (c) Gerhard Reithofer, Tech-EDV 2010-05
#
# Adjusted for Tklib (snitified) by Arjen Markus
#
# The author hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose,
# provided that existing copyright notices are retained in all copies
# and that this notice is included verbatim in any distributions. No
# written agreement, license, or royalty fee is required for any of the
# authorized uses. Modifications to this software may be copyrighted by
# their authors and need not follow the licensing terms described here,
# provided that the new terms are clearly indicated on the first page of
# each file where they apply.
#
# IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHOR HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
# NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# AND THE AUTHOR AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
# MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
# Original syntax:
#
# Syntax:
# rdial::create w ?-width wid? ?-height hgt? ?-value floatval?
# ?-bg|-background bcol? ?-fg|-foreground fcol? ?-step step?
# ?-callback script? ?-scale "degrees"|"radians"|factor?
# ?-slow sfact? ?-fast ffact? ?-orient "horizontal"|"vertical"?
# ?-variable varname? ?-bindwheel step?
#
# History:
# 20100526: -scale option added
# 20100626: incorrect "rotation direction" in vertical mode repaired
# 20100704: added -variable option and methods get and set (AM)
# 20101020: bug {[info exists ...]<0} => {![info exists ...]} repaired
# 20101112: drag: set opt(-value) depending on scale - thank's Manfred R.
# 20101118: -variable option added
# 20170518: -bindwheel option added for scrollwheel input
# 20170523: boolean variable buttonwheel controls Button/Wheel binding.
# if false the <BindWheel> event is used (by default in Windows),
# the event <ButtonPress-4/5> if it is false (other systems).
#
# Todo:
# option -variable -- conflicts with -value
# methods get and set
#
package require Tk 8.5-
package require snit
namespace eval controlwidget {
namespace export rdial
}
# rdial --
# Rotated dial widget
#
snit::widget controlwidget::rdial {
#
# widget default values
#
option -bg -default "#dfdfdf" -configuremethod SetOption
option -background -default "#dfdfdf" -configuremethod SetOption
option -fg -default "black" -configuremethod SetOption
option -foreground -default "black" -configuremethod SetOption
option -callback -default ""
option -orient -default horizontal
option -width -default 80 -configuremethod SetOption
option -height -default 8 -configuremethod SetOption
option -step -default 10
option -value -default 0.0 -configuremethod SetOption
option -slow -default 0.1
option -fast -default 10
option -scale -default 1.0 -configuremethod SetOption
option -variable -default {} -configuremethod VariableName
option -bindwheel -default 2.0 -configuremethod SetOption
variable d2r
variable sfact
variable ssize
variable ovalue
variable sector 88
variable callback
variable buttonwheel 1
variable wheelfactor 15.0
constructor args {
# I did not find a platform independent method :-(
if {$::tcl_platform(platform) eq "windows"} {
set buttonwheel 0
}
#
# A few constants to reduce expr
#
set d2r [expr {atan(1.0)/45.0}]
set ssize [expr {sin($sector*$d2r)}]
#
# Now initialise the widget
#
$self configurelist $args
canvas $win.c \
-background $options(-background)
grid $win.c -sticky nsew
set wid $options(-width)
set hgt $options(-height)
set bgc $options(-background)
# canvas dimensions and bindings
if {$options(-orient) eq "horizontal"} {
$win.c configure -width $wid -height $hgt
# standard bindings
bind $win.c <ButtonPress-1> [list $self SetVar ovalue %x]
bind $win.c <B1-Motion> [list $self drag %W %x 0]
bind $win.c <ButtonRelease-1> [list $self drag %W %x 0]
# course movement
bind $win.c <Shift-ButtonPress-1> [list $self SetVar ovalue %x]
bind $win.c <Shift-B1-Motion> [list $self drag %W %x 1]
bind $win.c <Shift-ButtonRelease-1> [list $self drag %W %x 1]
# fine movement
bind $win.c <Control-ButtonPress-1> [list $self SetVar ovalue %x]
bind $win.c <Control-B1-Motion> [list $self drag %W %x -1]
bind $win.c <Control-ButtonRelease-1> [list $self drag %W %x -1]
} else {
$win.c configure -width $hgt -height $wid
# standard binding
bind $win.c <ButtonPress-1> [list $self SetVar ovalue %y]
bind $win.c <B1-Motion> [list $self drag %W %y 0]
bind $win.c <ButtonRelease-1> [list $self drag %W %y 0]
# course movement
bind $win.c <Shift-ButtonPress-1> [list $self SetVar ovalue %y]
bind $win.c <Shift-B1-Motion> [list $self drag %W %y 1]
bind $win.c <Shift-ButtonRelease-1> [list $self drag %W %y 1]
# fine movement
bind $win.c <Control-ButtonPress-1> [list $self SetVar ovalue %y]
bind $win.c <Control-B1-Motion> [list $self drag %W %y -1]
bind $win.c <Control-ButtonRelease-1> [list $self drag %W %y -1]
}
if {$options(-bindwheel) != 0} {
if {$buttonwheel} {
set up $options(-bindwheel)
set dn [expr {0.0 - $up}]
# standard binding
bind $win.c <ButtonPress-4> [list $self roll %W $up 0]
bind $win.c <ButtonPress-5> [list $self roll %W $dn 0]
# course movement
bind $win.c <Shift-ButtonPress-4> [list $self roll %W $up 1]
bind $win.c <Shift-ButtonPress-5> [list $self roll %W $dn 1]
# fine movement
bind $win.c <Control-ButtonPress-4> [list $self roll %W $up -1]
bind $win.c <Control-ButtonPress-5> [list $self roll %W $dn -1]
} else {
# it seem that Shift+Control doesn't work :-(
bind $win.c <MouseWheel> [list $self roll %W %D 0]
bind $win.c <Shift-MouseWheel> [list $self roll %W %D 1]
bind $win.c <Control-MouseWheel> [list $self roll %W %D -1]
}
}
if {$options(-variable) ne ""} {
if { [info exists ::$options(-variable)] } {
set options(-value) [set ::$options(-variable)]
} else {
set ::options(-variable) [expr {$options(-value)*$options(-scale)}]
}
trace add variable ::$options(-variable) write [mymethod variableChanged]
}
# draw insides
$self draw $win.c $options(-value)
}
#
# public methods --
#
method set {newValue} {
if { $options(-variable) != "" } {
set ::$options(-variable) $newValue ;#! This updates the dial too
} else {
set options(-value) $newValue
$self draw $win.c $options(-value)
}
}
method get {} {
return $options(-value)
}
#
# private methods --
#
# store some private variable
method SetVar {var value} {
set $var $value
}
# configure method - write only
method SetOption {option arg} {
switch -- $option {
"-bg" {set option "-background"}
"-fg" {set option "-foreground"}
"-scale" {
switch -glob -- $arg {
"d*" {set arg 1.0}
"r*" {set arg $d2r}
}
# numeric check
set arg [expr {$arg*1.0}]
}
"-value" {
set arg [expr {$arg/$options(-scale)}]
}
"-height" {
if { [winfo exists $win.c] } {
$win.c configure $option $arg
}
}
"-width" {
if { [winfo exists $win.c] } {
$win.c configure $option $arg
}
# sfact depends on width
set sfact [expr {$ssize*2/$arg}]
}
}
set options($option) $arg
if { [winfo exists $win.c] } {
$self draw $win.c $options(-value)
}
}
method VariableName {option name} {
# Could be still constructing in which case
# $win.c does not exist:
if {![winfo exists $win.c]} {
set options(-variable) $name
return;
}
# Remove any old traces
if {$options(-variable) ne ""} {
trace remove variable ::$options(-variable) write [mymethod variableChanged]
}
# Set new trace if appropriate and update value.
set options(-variable) $name
if {$options(-variable) ne ""} {
trace add variable ::$options(-variable) write [mymethod variableChanged]
$self draw $win.c [set ::$options(-variable)]
}
}
method variableChanged {name1 name2 op} {
set options(-value) [expr {[set ::$options(-variable)]/$options(-scale)}]
$self draw $win.c [set ::$options(-variable)]
if { $options(-callback) ne "" } {
{*}$options(-callback) [expr {$options(-value)*$options(-scale)}]
}
}
# cget method
proc GetOption {option} {
if { $option eq "-value" } {
return [expr {$options(-value)*$options(-scale)}]
} else {
return $options(-value)
}
}
# draw the thumb wheel view
method draw {w val} {
set stp $options(-step)
set wid $options(-width)
set hgt $options(-height)
set dfg $options(-foreground)
set dbg $options(-background)
$win.c delete all
if {$options(-orient) eq "horizontal"} {
# every value is mapped to the visible sector
set mod [expr {$val-$sector*int($val/$sector)}]
$win.c create rectangle 0 0 $wid $hgt -fill $dbg
# from normalized value to left end
for {set ri $mod} {$ri>=-$sector} {set ri [expr {$ri-$stp}]} {
set offs [expr {($ssize+sin($ri*$d2r))/$sfact}]
$win.c create line $offs 0 $offs $hgt -fill $dfg
}
# from normalized value to right end
for {set ri [expr {$mod+$stp}]} {$ri<=$sector} {set ri [expr {$ri+$stp}]} {
set offs [expr {($ssize+sin($ri*$d2r))/$sfact}]
$win.c create line $offs 0 $offs $hgt -fill $dfg
}
} else {
# every value is mapped to the visible sector
set mod [expr {$sector*int($val/$sector)-$val}]
$win.c create rectangle 0 0 $hgt $wid -fill $dbg
# from normalized value to upper end
for {set ri $mod} {$ri>=-$sector} {set ri [expr {$ri-$stp}]} {
set offs [expr {($ssize+sin($ri*$d2r))/$sfact}]
$win.c create line 0 $offs $hgt $offs -fill $dfg
}
# from normalized value to lower end
for {set ri [expr {$mod+$stp}]} {$ri<=$sector} {set ri [expr {$ri+$stp}]} {
set offs [expr {($ssize+sin($ri*$d2r))/$sfact}]
$win.c create line 0 $offs $hgt $offs -fill $dfg
}
}
# let's return the widget/canvas
set options(-value) $val
}
# update rdials after value change
method rdupdate {w diff} {
# calculate "new" calue
set options(-value) [expr {$options(-value)+$diff*$options(-scale)}]
# call callback if defined...
if {$options(-callback) ne ""} {
{*}$options(-callback) $options(-value)
}
# draw knob with new angle
$self draw $w $options(-value)
}
# change by mouse dragging
method drag {w coord mode} {
variable ovalue
# calculate new value
if {$options(-orient) eq "horizontal"} {
set diff [expr {$coord-$ovalue}]
} else {
set diff [expr {$ovalue-$coord}]
}
if {$mode<0} {
set diff [expr {$diff*$options(-slow)}]
} elseif {$mode>0} {
set diff [expr {$diff*$options(-fast)}]
}
$self rdupdate $w $diff
# store "old" value for diff
set ovalue $coord
}
# change by mouse wheel
method roll {w diff mode} {
if {! $buttonwheel} {
set diff [expr {$diff/$wheelfactor/$options(-bindwheel)}]
}
if {$mode<0} {
set diff [expr {$diff*$options(-slow)}]
} elseif {$mode>0} {
set diff [expr {$diff*$options(-fast)}]
}
$self rdupdate $w $diff
}
}
# Announce our presence
package provide rdial 0.7
#-------- test & demo ... disable it for package autoloading -> {0}
if {0} {
if {[info script] eq $argv0} {
array set disp_value {rs -30.0 rh 120.0 rv 10.0}
proc rndcol {} {
set col "#"
for {set i 0} {$i<3} {incr i} {
append col [format "%02x" [expr {int(rand()*230)+10}]]
}
return $col
}
proc set_rand_col {} {
.rs configure -fg [rndcol] -bg [rndcol]
}
proc show_value {which v} {
set val [.$which cget -value]
set ::disp_value($which) [format "%.1f" $val]
switch -- $which {
"rh" {
if {abs($val)<30} return
.rs configure -width [expr {abs($val)}]
}
"rv" {
if {abs($val)<5} return
.rs configure -height [expr {abs($val)}]
}
"rs" {
if {!(int($val)%10)} set_rand_col
}
}
}
set help "Use mouse button with Shift &"
append help "\nControl for dragging the dials"
append help "\nwith Mouswheel support"
label .lb -text $help
label .lv -textvariable disp_value(rv)
controlwidget::rdial .rv -callback {show_value rv} -value $disp_value(rv)\
-width 200 -step 5 -bg blue -fg white \
-variable score -bindwheel -10.0
label .lh -textvariable disp_value(rh)
controlwidget::rdial .rh -callback {show_value rh} -value $disp_value(rh)\
-width $disp_value(rh) -height 20 -fg blue -bg yellow -orient vertical
label .ls -textvariable disp_value(rs)
controlwidget::rdial .rs -callback {show_value rs} -value $disp_value(rs)\
-width $disp_value(rh) -height $disp_value(rv)
pack {*}[winfo children .]
wm minsize . 220 300
after 2000 {
set ::score 0.0
}
after 3000 {
set ::score 100.0
.rh set 3
}
}
}

389
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/tachometer.tcl

@ -0,0 +1,389 @@
# tachometer.tcl --
#
# Adapted by Arjen Markus (snitified), july 2010
#
# TODO:
# motion through the start and end - it can jump through the gap
# scaling (scale widget)
# deal with sizes of the widget (aspect ratio != 1)
#
#
# Part of: The TCL'ers Wiki
# Contents: a tachometer-like widget
# Date: Fri Jun 13, 2003
#
# Abstract
#
#
#
# Copyright (c) 2003 Marco Maggi
#
# The author hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose,
# provided that existing copyright notices are retained in all copies
# and that this notice is included verbatim in any distributions. No
# written agreement, license, or royalty fee is required for any of the
# authorized uses. Modifications to this software may be copyrighted by
# their authors and need not follow the licensing terms described here,
# provided that the new terms are clearly indicated on the first page of
# each file where they apply.
#
# IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHOR HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
# NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# AND THE AUTHOR AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
# MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
# $Id: tachometer.tcl,v 1.4 2010/09/10 17:16:29 andreas_kupries Exp $
#
package require Tk 8.5-
package require snit
package provide tachometer 0.1
namespace eval controlwidget {
namespace export tachometer
}
# tachometer --
# Tachometer-like widget
#
snit::widget controlwidget::tachometer {
#
# widget default values
#
option -borderwidth -default 1
option -title -default speed
option -labels -default {}
option -resolution -default 1
option -showvalue -default 1
option -variable -default {} -configuremethod VariableName
option -min -default 0.0
option -max -default 100.0
option -dangerlevel -default 90.0
option -dangercolor -default red
option -dangerwidth -default 3m
option -dialcolor -default white
option -pincolor -default red
option -indexid -default {}
option -background -default gray
option -width -default 50m
option -height -default 50m
option -foreground -default black
option -highlightthickness -default 0
option -relief -default raised
variable pi [expr {3.14159265359/180.0}]
variable xc
variable yc
variable motion
constructor args {
#
# Configure the widget
#
$self configurelist $args
canvas $win.c -background $options(-background) -width $options(-width) -height $options(-height) \
-relief $options(-relief) -borderwidth $options(-borderwidth)
grid $win.c -sticky news
if {$options(-variable) ne ""} {
trace add variable ::$options(-variable) write [mymethod tracer $options(-variable)]
}
#
# Draw the tachometer
#
set width [$win.c cget -width]
set height [$win.c cget -height]
set num [llength $options(-labels)]
set delta [expr {(360.0-40.0)/($num-1)}]
# display
set x1 [expr {$width/50.0*2.0}]
set y1 [expr {$width/50.0*2.0}]
set x2 [expr {$width/50.0*48.0}]
set y2 [expr {$width/50.0*48.0}]
$win.c create oval $x1 $y1 $x2 $y2 -fill $options(-dialcolor) -width 1 -outline lightgray
shadowcircle $win.c $x1 $y1 $x2 $y2 40 0.7m 135.0
# pin
set x1 [expr {$width/50.0*23.0}]
set y1 [expr {$width/50.0*23.0}]
set x2 [expr {$width/50.0*27.0}]
set y2 [expr {$width/50.0*27.0}]
$win.c create oval $x1 $y1 $x2 $y2 -width 1 -outline lightgray -fill $options(-pincolor)
shadowcircle $win.c $x1 $y1 $x2 $y2 40 0.7m -45.0
# danger marker
if { $options(-dangerlevel) != {} && $options(-dangerlevel) < $options(-max)} {
set deltadanger [expr {(360.0-40.0)*($options(-max)-$options(-dangerlevel))/(1.0*$options(-max)-$options(-min))}]
# Transform the thickness into a plain number (if given in mm for instance)
set id [$win.c create line 0 0 1 0]
$win.c move $id $options(-dangerwidth) 0
set coords [$win.c coords $id]
set thickness [expr {[lindex $coords 0]/2.0}]
$win.c delete $id
# Create the arc for the danger level
$win.c create arc \
[expr {$width/50.0*4.0+$thickness}] [expr {$width/50.0*4.0+$thickness}] \
[expr {$width/50.0*46.0-$thickness}] [expr {$width/50.0*46.0-$thickness}] \
-start -70 -extent $deltadanger -style arc \
-outline $options(-dangercolor) -fill $options(-dangercolor) -width $options(-dangerwidth)
}
# graduate line
set x1 [expr {$width/50.0*4.0}]
set y1 [expr {$width/50.0*4.0}]
set x2 [expr {$width/50.0*46.0}]
set y2 [expr {$width/50.0*46.0}]
$win.c create arc $x1 $y1 $x2 $y2 \
-start -70 -extent 320 -style arc \
-outline black -width 0.5m
set xc [expr {($x2+$x1)/2.0}]
set yc [expr {($y2+$y1)/2.0}]
set motion 0
bind $win.c <ButtonRelease> [list $self needleRelease %W]
bind $win.c <Motion> [list $self needleMotion %W %x %y]
set half [expr {$width/2.0}]
set l1 [expr {$half*0.85}]
set l2 [expr {$half*0.74}]
set l3 [expr {$half*0.62}]
set angle 110.0
for {set i 0} {$i < $num} {incr i} \
{
set a [expr {($angle+$delta*$i)*$pi}]
set x1 [expr {$half+$l1*cos($a)}]
set y1 [expr {$half+$l1*sin($a)}]
set x2 [expr {$half+$l2*cos($a)}]
set y2 [expr {$half+$l2*sin($a)}]
$win.c create line $x1 $y1 $x2 $y2 -fill black -width 0.5m
set x1 [expr {$half+$l3*cos($a)}]
set y1 [expr {$half+$l3*sin($a)}]
set label [lindex $options(-labels) $i]
if { [string length $label] } \
{
$win.c create text $x1 $y1 \
-anchor center -justify center -fill black \
-text $label -font { Helvetica 10 }
}
}
rivet $win.c 10 10
rivet $win.c [expr {$width-10}] 10
rivet $win.c 10 [expr {$height-10}]
rivet $win.c [expr {$width-10}] [expr {$height-10}]
set value 0
$self drawline $win $value
}
method destructor { widget } \
{
set varname [option get $widget varname {}]
trace remove variable $varname write \
[namespace code "tracer $widget $varname"]
}
#
# public methods --
#
method set {newValue} {
if { $options(-variable) != "" } {
set ::$options(-variable) $newValue ;#! This updates the dial too
} else {
set options(-value) $newValue
$self draw $win.c $options(-value)
}
}
method get {} {
return $options(-value)
}
#
# private methods --
#
method VariableName {option name} {
# Could be still constructing in which case
# $win.c does not exist:
if {![winfo exists $win.c]} {
set options(-variable) $name
return;
}
# Remove any old traces
if {$options(-variable) ne ""} {
trace remove variable ::$options(-variable) write [mymethod tracer $options(-variable)]
}
# Set new trace if appropriate and update value.
set options(-variable) $name
if {$options(-variable) ne ""} {
trace add variable ::$options(-variable) write [mymethod tracer $options(-variable)]
$self drawline $win.c [set ::$options(-variable)]
}
}
method tracer { varname args } \
{
set options(-value) [set ::$varname]
$self drawline $win [set ::$varname]
}
method drawline { widget value } \
{
set c $widget.c
set min $options(-min)
set max $options(-max)
set id $options(-indexid)
set v [expr { ($value <= ($max*1.02))? $value : ($max*1.02) }]
set angle [expr {((($v-$min)/($max-$min))*320.0+20.0)*$pi}]
set width [$c cget -width]
set half [expr {$width/2.0}]
set length [expr {$half*0.8}]
set xl [expr {$half-$length*sin($angle)}]
set yl [expr {$half+$length*cos($angle)}]
set xs [expr {$half+0.2*$length*sin($angle)}]
set ys [expr {$half-0.2*$length*cos($angle)}]
catch {$c delete $id}
set id [$c create line $xs $ys $xl $yl -fill $options(-pincolor) -width 0.6m]
$c bind $id <ButtonPress> [list $self needlePress %W]
set options(-indexid) $id
}
method needlePress {w} \
{
set motion 1
}
method needleRelease {w} \
{
set motion 0
}
method needleMotion {w x y} \
{
if {! $motion} { return }
if {$y == $yc && $x == $xc} { return }
#
# Compute the angle with the positive y-axis - easier to examine!
#
set angle [expr {atan2($xc - $x,$yc - $y) / $pi}]
if { $angle >= 160.0 } {
set angle 160.0
}
if { $angle < -160.0 } {
set angle -160.0
}
set ::$options(-variable) [expr {$options(-min) + ($options(-max)-$options(-min))*(160.0-$angle) / 320.0}]
}
proc rivet { c xc yc } \
{
set width 5
set bevel 0.5m
set angle -45.0
set ticks 7
shadowcircle $c \
[expr {$xc-$width}] [expr {$yc-$width}] [expr {$xc+$width}] [expr {$yc+$width}] \
$ticks $bevel $angle
}
proc shadowcircle { canvas x1 y1 x2 y2 ticks width orient } \
{
set angle $orient
set delta [expr {180.0/$ticks}]
for {set i 0} {$i <= $ticks} {incr i} \
{
set a [expr {($angle+$i*$delta)}]
set b [expr {($angle-$i*$delta)}]
set color [expr {40+$i*(200/$ticks)}]
set color [format "#%x%x%x" $color $color $color]
$canvas create arc $x1 $y1 $x2 $y2 -start $a -extent $delta \
-style arc -outline $color -width $width
$canvas create arc $x1 $y1 $x2 $y2 -start $b -extent $delta \
-style arc -outline $color -width $width
}
}
}
if {0} {
# main --
# Demonstration of the tachometer object
#
proc main { argc argv } \
{
global forever
wm withdraw .
wm title . "A tachometer-like widget"
wm geometry . +10+10
controlwidget::tachometer .t1 -variable ::value1 -labels { 0 10 20 30 40 50 60 70 80 90 100 } \
-pincolor green -dialcolor lightpink
scale .s1 -command "set ::value1" -variable ::value1
#
# Note: the labels are not used in the scaling of the values
#
controlwidget::tachometer .t2 -variable ::value2 -labels { 0 {} {} 5 {} {} 10 } -width 100m -height 100m \
-min 0 -max 10 -dangerlevel 3
scale .s2 -command "set ::value2" -variable ::value2 -from 0 -to 10
button .b -text Quit -command "set ::forever 1"
grid .t1 .s1 .t2 .s2 .b -padx 2 -pady 2
wm deiconify .
console show
vwait forever
#tachometer::destructor .t1
#tachometer::destructor .t2
exit 0
}
main $argc $argv
}
### end of file
# Local Variables:
# mode: tcl
# page-delimiter: "^#PAGE"
# End:

1458
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/vertical_meter.tcl

File diff suppressed because it is too large Load Diff

347
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/controlwidget/voltmeter.tcl

@ -0,0 +1,347 @@
# voltmeter.tcl --
#
# Adapted by Arjen Markus (snitified), july 2010
#
#
#
#
# Part of: The TCL'ers Wiki
# Contents: a voltmeter-like widget
# Date: Fri Jun 13, 2003
#
# Abstract
#
#
#
# Copyright (c) 2003 Marco Maggi
#
# The author hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose,
# provided that existing copyright notices are retained in all copies
# and that this notice is included verbatim in any distributions. No
# written agreement, license, or royalty fee is required for any of the
# authorized uses. Modifications to this software may be copyrighted by
# their authors and need not follow the licensing terms described here,
# provided that the new terms are clearly indicated on the first page of
# each file where they apply.
#
# IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHOR HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
# NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# AND THE AUTHOR AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
# MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
# $Id: voltmeter.tcl,v 1.3 2010/09/10 17:16:29 andreas_kupries Exp $
#
package require Tk 8.5-
package require snit
package provide voltmeter 0.1
namespace eval controlwidget {
namespace export voltmeter
}
# voltmeter --
# Voltmeter-like widget
#
snit::widget controlwidget::voltmeter {
#
# widget default values
#
option -borderwidth -default 1
option -background -default gray
option -dialcolor -default white
option -needlecolor -default black
option -scalecolor -default black
option -indexid -default {}
option -variable -default {} -configuremethod VariableName
option -min -default 0.0
option -max -default 100.0
option -labelcolor -default black
option -titlecolor -default black
option -labelfont -default {Helvetica 8}
option -titlefont -default {Helvetica 9}
option -labels -default {}
option -title -default {}
option -width -default 50m
option -height -default 25m
option -highlightthickness -default 0
option -relief -default raised
variable pi [expr {3.14159265359/180.0}]
variable motion
variable xc
variable yc
constructor args {
#
# Configure the widget
#
$self configurelist $args
canvas $win.c -background $options(-background) -width $options(-width) -height $options(-height) \
-relief $options(-relief) -borderwidth $options(-borderwidth)
grid $win.c -sticky news -padx 2m -pady 2m
if {$options(-variable) ne ""} {
trace add variable ::$options(-variable) write [mymethod tracer $options(-variable)]
}
set width [$win.c cget -width]
set height [$win.c cget -height]
set xcentre [expr {$width*0.5}]
set ycentre [expr {$width*1.4}]
set t 1.15
set t1 1.25
$win.c create arc \
[expr {$xcentre-$width*$t}] [expr {$ycentre-$width*$t}] \
[expr {$xcentre+$width*$t}] [expr {$ycentre+$width*$t}] \
-start 70.5 -extent 37 -style arc -outline lightgray \
-width [expr {$ycentre*0.245}]
$win.c create arc \
[expr {$xcentre-$width*$t}] [expr {$ycentre-$width*$t}] \
[expr {$xcentre+$width*$t}] [expr {$ycentre+$width*$t}] \
-start 71 -extent 36 -style arc -outline $options(-dialcolor) \
-width [expr {$ycentre*0.23}]
$win.c create arc \
[expr {$xcentre-$width*$t1}] [expr {$ycentre-$width*$t1}] \
[expr {$xcentre+$width*$t1}] [expr {$ycentre+$width*$t1}] \
-start 75 -extent 30 \
-fill black -outline $options(-scalecolor) -style arc -width 0.5m
set num [llength $options(-labels)]
set angle 255.0
set delta [expr {30.0/($num-1)}]
set l1 [expr {$width*$t1}]
set l2 [expr {$width*$t1*0.95}]
set l3 [expr {$width*$t1*0.92}]
for {set i 0} {$i < $num} {incr i} {
set a [expr {($angle+$delta*$i)*$pi}]
set x1 [expr {$xcentre+$l1*cos($a)}]
set y1 [expr {$ycentre+$l1*sin($a)}]
set x2 [expr {$xcentre+$l2*cos($a)}]
set y2 [expr {$ycentre+$l2*sin($a)}]
$win.c create line $x1 $y1 $x2 $y2 -fill $options(-scalecolor) -width 0.5m
set x1 [expr {$xcentre+$l3*cos($a)}]
set y1 [expr {$ycentre+$l3*sin($a)}]
set label [lindex $options(-labels) $i]
if { [string length $label] } {
$win.c create text $x1 $y1 \
-anchor center -justify center -fill $options(-labelcolor) \
-text $label -font $options(-labelfont)
}
}
set title $options(-title)
if { [string length $title] } {
$win.c create text $xcentre [expr {$ycentre-$width*1.05}] \
-anchor center -justify center -fill $options(-titlecolor) \
-text $title -font $options(-titlefont)
}
rivet $win.c 10 10
rivet $win.c [expr {$width-10}] 10
rivet $win.c 10 [expr {$height-10}]
rivet $win.c [expr {$width-10}] [expr {$height-10}]
set motion 0
set xc $xcentre
set yc $ycentre
bind $win.c <ButtonRelease> [list $self needleRelease %W]
bind $win.c <Motion> [list $self needleMotion %W %x %y]
set value 0
$self drawline $win $value
}
method destructor {} {
set varname ::$options(-variable)]
trace remove variable $varname write \
[namespace code "mymethod tracer $win $varname"]
}
#
# public methods --
#
method set {newValue} {
if { $options(-variable) != "" } {
set ::$options(-variable) $newValue ;#! This updates the dial too
} else {
set options(-value) $newValue
$self draw $win.c $options(-value)
}
}
method get {} {
return $options(-value)
}
#
# private methods --
#
method VariableName {option name} {
# Could be still constructing in which case
# $win.c does not exist:
if {![winfo exists $win.c]} {
set options(-variable) $name
return;
}
# Remove any old traces
if {$options(-variable) ne ""} {
trace remove variable ::$options(-variable) write [mymethod tracer $options(-variable)]
}
# Set new trace if appropriate and update value.
set options(-variable) $name
if {$options(-variable) ne ""} {
trace add variable ::$options(-variable) write [mymethod tracer $options(-variable)]
$self drawline $win.c [set ::$options(-variable)]
}
}
method tracer { varname args } \
{
set options(-value) [set ::$varname]
$self drawline $win [set ::$varname]
}
method drawline { widget value } {
set id $options(-indexid)
set min $options(-min)
set max $options(-max)
set c $widget.c
set v [expr { ($value <= ($max*1.05))? $value : ($max*1.05) }]
set angle [expr {((($v-$min)/(1.0*($max-$min)))*30.0+165.0)*$pi}]
set width [$c cget -width]
set xcentre [expr {$width/2.0}]
set ycentre [expr {$width*1.4}]
set l1 [expr {$ycentre*0.85}]
set l2 [expr {$ycentre*0.7}]
set xl [expr {$xcentre-$l1*sin($angle)}]
set yl [expr {$ycentre+$l1*cos($angle)}]
set xs [expr {$xcentre-$l2*sin($angle)}]
set ys [expr {$ycentre+$l2*cos($angle)}]
catch {$c delete $id}
set id [$c create line $xs $ys $xl $yl -fill $options(-needlecolor) -width 0.6m]
$c bind $id <ButtonPress> [list $self needlePress %W]
set options(-indexid) $id
}
method needlePress {w} \
{
set motion 1
}
method needleRelease {w} \
{
set motion 0
}
method needleMotion {w x y} \
{
if {! $motion} { return }
if {$y == $yc && $x == $xc} { return }
#
# Compute the angle with the positive y-axis - easier to examine!
#
set angle [expr {atan2($xc - $x,$yc - $y) / $pi}]
if { $angle >= 15.0 } {
set angle 15.0
}
if { $angle < -15.0 } {
set angle -15.0
}
set ::$options(-variable) [expr {$options(-min) + ($options(-max)-$options(-min))*(15.0-$angle) / 30.0}]
}
proc rivet { c xc yc } {
shadowcircle $c \
[expr {$xc-4}] [expr {$yc-4}] [expr {$xc+4}] [expr {$yc+4}] \
5 0.5m -45.0
}
proc shadowcircle { canvas x1 y1 x2 y2 ticks width orient } {
set radius [expr {($x2-$x1)/2.0}]
set angle $orient
set delta [expr {180.0/$ticks}]
for {set i 0} {$i <= $ticks} {incr i} {
set a [expr {($angle+$i*$delta)}]
set b [expr {($angle-$i*$delta)}]
set color [expr {40+$i*(200/$ticks)}]
set color [format "#%x%x%x" $color $color $color]
$canvas create arc $x1 $y1 $x2 $y2 -start $a -extent $delta \
-style arc -outline $color -width $width
$canvas create arc $x1 $y1 $x2 $y2 -start $b -extent $delta \
-style arc -outline $color -width $width
}
}
}
if {0} {
# main --
# Demonstration of the voltmeter object
#
proc main { argc argv } {
global forever
wm withdraw .
wm title . "A voltmeter-like widget"
wm geometry . +10+10
::controlwidget::voltmeter .t1 -variable value1 -labels { 0 50 100 } -title "Voltmeter (V)"
scale .s1 -command "set ::value1" -variable value1
::controlwidget::voltmeter .t2 -variable value2 -labels { 0 {} 2.5 {} 5 } \
-width 80m -height 40m -title "Ampere (mA)" -dialcolor lightgreen -scalecolor white \
-min 0 -max 5
scale .s2 -command "set ::value2" -variable value2
button .b -text Quit -command "set ::forever 1"
grid .t1 .s1 .t2 .s2 .b
wm deiconify .
vwait forever
.t1 destructor
.t2 destructor
exit 0
}
main $argc $argv
}
### end of file
# Local Variables:
# mode: tcl
# page-delimiter: "^#PAGE"
# End:

598
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/crosshair/crosshair.tcl

@ -0,0 +1,598 @@
# crosshair.tcl -
#
# Kevin's mouse-tracking crosshair in Tk's canvas widget.
#
# This package displays a mouse-tracking crosshair in the canvas widget.
#
# Copyright (c) 2003 by Kevin B. Kenny. All rights reserved.
# Redistribution permitted under the terms of the Tcl License.
#
# Copyright (c) 2008 Andreas Kupries. Added ability to provide the tracking
# information to external users.
#
# Copyright (c) 2013 Frank Gover, Andreas Kupries. Added ability to
# bound the crosshairs to an area of the canvas. Useful
# for plots.
# (Actual code inspired by Frank's, but modified and extended (multiple bboxes)).
# ### ### ### ######### ######### #########
## Requisites
package require Tcl 8.4-
package require Tk 8.4-
namespace eval ::crosshair {}
# ### ### ### ######### ######### #########
## API
#----------------------------------------------------------------------
#
# ::crosshair::crosshair --
#
# Displays a pair of cross-hairs in a canvas widget. The
# cross-hairs track the pointing device.
#
# Parameters:
# w - The path name of the canvas
# args - Remaining args are treated as options as for
# [$w create line]. Of particular interest are
# -fill and -dash.
#
# Results:
# None.
#
# Side effects:
# Adds the 'crosshair' bind tag to the widget so that
# crosshairs will be displayed on pointing device motion.
#
#----------------------------------------------------------------------
proc ::crosshair::crosshair { w args } {
variable config
set opts(args) $args
set opts(hidden) 0
bindtags $w [linsert [bindtags $w] 1 Crosshair]
set config($w) [array get opts]
return
}
#----------------------------------------------------------------------
#
# ::crosshair::off -
#
# Removes the crosshairs from a canvas widget
#
# Parameters:
# w - The canvas from which the crosshairs should be removed
#
# Results:
# None.
#
# Side effects:
# If the widget has crosshairs, they are removed. The 'Crosshair'
# bind tag is removed so that mouse motion will not restore them.
#
#----------------------------------------------------------------------
proc ::crosshair::off { w } {
variable config
if { ![info exists config($w)] } return
array set opts $config($w)
if { [winfo exists $w] } {
Hide $w
set bindtags [bindtags $w]
set pos [lsearch -exact $bindtags Crosshair]
if { $pos >= 0 } {
bindtags $w [lreplace $bindtags $pos $pos]
}
}
unset config($w)
return
}
#----------------------------------------------------------------------
#
# ::crosshair::configure --
#
# Changes the appearance of crosshairs in the canvas widget.
#
# Parameters:
# w - Path name of the widget
# args - Additional args are flags to [$w create line]. Interesting
# ones include -fill and -dash
#
# Results:
# Returns the crosshairs' current configuration settings.
#
#----------------------------------------------------------------------
proc ::crosshair::configure { w args } {
variable config
if { ![info exists config($w)] } {
return -code error "no crosshairs in $w"
}
array set opts $config($w)
if { [llength $args] > 0 } {
array set flags $opts(args)
array set flags $args
set opts(args) [array get flags]
# Immediately apply to a visible crosshair
if { [info exists opts(hhairl)] } {
eval [list $w itemconfig $opts(hhairl)] $args
eval [list $w itemconfig $opts(hhairr)] $args
eval [list $w itemconfig $opts(vhaird)] $args
eval [list $w itemconfig $opts(vhairu)] $args
}
set config($w) [array get opts]
}
return $opts(args)
}
#----------------------------------------------------------------------
#
# ::crosshair::bbox_add --
#
# Confines the crosshairs to a rectangular area in the canvas widget.
# Multiple calls add areas, each allowing the crosshairs.
#
# NOTE: Bounding boxes can overlap to the point of being identical.
#
# Parameters:
# w - Path name of the widget
# bbox - Area in the canvas. A list of 4 numbers in the form
# {bbox_llx bbox_lly bbox_urx bbox_ury}
# where:
# bbox-llx = Lower left X coordinate of the area
# bbox-lly = Lower left Y coordinate of the area
# bbox-urx = Upper right X coordinate of the area
# bbox-ury = Upper right Y coordinate of the area
#
# Result:
# A token identifying the bounding box, for future removal.
#
#----------------------------------------------------------------------
proc ::crosshair::bbox_add { w bbox } {
variable config
if { ![info exists config($w)] } {
return -code error "no crosshairs in $w"
}
array set opts $config($w)
if {[info exists opts(bbox)]} {
set len [llength $opts(bbox)]
} else {
set len 0
}
set token bbox$w/$len
lappend opts(bbox) $token
set config($w) [array get opts]
foreach {nllx nlly nurx nury} $bbox break
# Tcl 8.4 foreach-as-lassign hack
set rect [$w create rect \
$nllx $nlly $nurx $nury \
-tags $token -state hidden]
return $token
}
#----------------------------------------------------------------------
#
# ::crosshair::bbox_remove --
#
# Remove a bounding box for the crosshairs, identified by token.
# The crosshairs are confined to the remaining boxes, or not at
# all if no boxes remain.
#
# NOTE: Bounding boxes can overlap to the point of being identical.
#
# Parameters:
# token - The bbox token, identifying both canvas and bbox in it.
#
# Result:
# Nothing.
#
#----------------------------------------------------------------------
proc ::crosshair::bbox_remove { token } {
variable config
if {![regexp {^bbox([^/]+)/(\d+)$} -> w index]} {
return -code error "Expected a bbox token, got \"$token\""
}
if { ![info exists config($w)] } {
return -code error "no crosshairs in $w"
}
array set opts $config($w)
# Replace chosen box with nothing.
incr index -1
set newboxes [lreplace $opts(bbox) $index $index {}]
# Remove empty boxes from the end of the list.
while {[llength $newboxes] && ![llength [lindex $newboxes end]]} {
set newboxes [lreplace $newboxes end end]
}
if {![llength $newboxes]} {
# Nothing left, disable entirely
unset opts(bbox)
} else {
# Keep remainder.
set opts(bbox) $newboxes
}
set config($w) [array get opts]
#--- Delete Bbox
$w delete $token
return
}
#----------------------------------------------------------------------
#
# ::crosshair::track --
#
# (De)activates reporting of the cross-hair coordinates through
# a user-specified callback.
#
# Parameters:
# which - What to do (legal values: 'on', 'off').
# w - The path name of the canvas
# cmd - Only for which == 'on', the command prefix to
# use for execute.
#
# The cmd is called with 7 arguments: The widget, and the x- and
# y-coordinates of 3 points: Crosshair position, and the topleft
# and bottomright corners of the canvas viewport. All position
# data in pixels.
#
# Results:
# None.
#
# Side effects:
# See description.
#
#----------------------------------------------------------------------
proc ::crosshair::track { which w args } {
variable config
if { ![info exists config($w)] } {
return -code error "no crosshairs in $w"
}
if { ![info exists config($w)] } return
array set opts $config($w)
switch -exact -- $which {
on {
if {[llength $args] != 1} {
return -code error "wrong\#args: Expected 'on w cmdprefix'"
}
set opts(track) [lindex $args 0]
}
off {
if {[llength $args] != 0} {
return -code error "wrong\#args: Expected 'off w'"
}
catch { unset opts(track) }
}
}
set config($w) [array get opts]
return
}
# ### ### ### ######### ######### #########
## Internal commands.
#----------------------------------------------------------------------
#
# ::crosshair::Hide --
#
# Hides the crosshair temporarily
#
# Parameters:
# w - Canvas widget containing crosshairs
#
# Results:
# None.
#
# Side effects:
# If the canvas contains crosshairs, they are hidden.
#
# This procedure is invoked in response to the <Leave> event to
# hide the crosshair when the pointer is not in the window.
#
#----------------------------------------------------------------------
proc ::crosshair::Hide { w } {
variable config
if { ![info exists config($w)] } return
array set opts $config($w)
# Already hidden, do nothing
if { $opts(hidden) } return
set opts(hidden) 1
# Destroy the parts of a visible cross-hair
Kill $w opts
set config($w) [array get opts]
return
}
#----------------------------------------------------------------------
#
# ::crosshair::Unhide --
#
# Places a hidden crosshair back on display
#
# Parameters:
# w - Canvas widget containing crosshairs
# x - x co-ordinate relative to the window where the vertical
# crosshair should appear
# y - y co-ordinate relative to the window where the horizontal
# crosshair should appear.
#
# Results:
# None.
#
# Side effects:
# Crosshairs are put on display.
#
# This procedure is invoked in response to the <Enter> event to
# restore the crosshair to the display.
#
#----------------------------------------------------------------------
proc ::crosshair::Unhide { w x y } {
variable config
if { ![info exists config($w)] } return
array set opts $config($w)
# Already unhidden, do nothing
if { !$opts(hidden) } return
set opts(hidden) 0
# Store changes back.
set config($w) [array get opts]
# Recreate cross-hair. This takes the bounding boxes, if any, into
# account, i.e. if we are out of bounds nothing will appear.
Move $w $x $y
return
}
proc ::crosshair::GetBoundaries { w x y llxv llyv urxv uryv } {
upvar 1 $llxv llx $llyv lly $urxv urx $uryv ury
variable config
array set opts $config($w)
# Defaults
set llx [$w canvasx 0]
set lly [$w canvasy 0]
set urx [$w canvasx [winfo width $w]]
set ury [$w canvasy [winfo height $w]]
# (x) No boxes confining the crosshair.
if {![info exists opts(bbox)]} {
#puts ANY($x,$y)
return 1
}
# Determine active boundaries based on the boxes we are in (or not).
# NOTE: This is linear in the number of active boundaries on the
# canvas. If this is a really large number this will become
# slow. If that happens consider creation and maintenance of some
# fast data structure (R-tree, or similar) which can take
# advantage of overlap and nesting to quickly rule out large
# areas. Note that such a structure has its own price in time,
# memory, and code complexity.
set first 1
foreach token $opts(bbox) {
# Ignore removed boxes, not yet cleaned up. Note that we have
# at least one active box here to touch by the loop. If we had
# none the bbox_remove command ensured that (x) above
# triggered.
if {$token eq {}} continue
# Get the box data, then test for usability. Ignore all boxes
# we are outside of. They are not used for the boundary
# calculation.
set box [$w coords $token]
if {[Outside $box $x $y]} continue
# Unfold the box data and check if its boundaries are better
# (less restrictive) than we currently have, or if this is the
# first restriction.
foreach {nllx nlly nurx nury} $box break
if {$first || ($nllx < $llx)} { set llx $nllx }
if {$first || ($nlly > $lly)} { set lly $nlly }
if {$first || ($nurx > $urx)} { set urx $nurx }
if {$first || ($nury < $ury)} { set ury $nury }
set first 0
}
if {$first} {
# We have boxes limiting us (See both (x)), and we are outside
# of all of them. Time to hide the crosshairs.
#puts OUT($x,$y)
return 0
}
# We are inside of some box and have the proper boundaries of
# visibility.
#puts LIMIT($x,$y):$llx,$lly,$urx,$ury
return 1
}
proc ::crosshair::Outside { box x y } {
# Unfold box
foreach {llx lly urx ury} $box break
#puts \tTEST($x,$y):$llx,$lly,$urx,$ury:[expr {($x < $llx) || ($x > $urx) || ($y < $lly) || ($y > $ury)}]
# Test each edge. Note that the border lines are considered as
# "outside".
expr {($x <= $llx) ||
($x >= $urx) ||
($y <= $lly) ||
($y >= $ury)}
}
#----------------------------------------------------------------------
#
# ::crosshair::Move --
#
# Moves the crosshairs in a camvas
#
# Parameters:
# w - Canvas widget containing crosshairs
# x - x co-ordinate relative to the window where the vertical
# crosshair should appear
# y - y co-ordinate relative to the window where the horizontal
# crosshair should appear.
#
# Results:
# None.
#
# Side effects:
# Crosshairs move.
#
# This procedure is called in response to a <Motion> event in a canvas
# with crosshairs.
#
#----------------------------------------------------------------------
proc ::crosshair::Move { w x y } {
variable config
array set opts $config($w)
set x [$w canvasx $x]
set y [$w canvasy $y]
set opts(x) $x
set opts(y) $y
if {![GetBoundaries $w $x $y opts(x0) opts(y0) opts(x1) opts(y1)]} {
# We are out of bounds. Kill the crosshair, store changes, and
# return. This last disables the use of the tracking
# callback. The crosshairs track only inside the allowed
# boxes.
Kill $w opts
# Store changes back.
set config($w) [array get opts]
return
}
# Inside the boundaries, create or move.
Place $w opts
# Store changes back.
set config($w) [array get opts]
# And run the tracking callback, if active.
if {![info exists opts(track)]} return
uplevel \#0 [linsert $opts(track) end \
$w $opts(x) $opts(y) \
$opts(x0) $opts(y0) $opts(x1) $opts(y1)]
return
}
# ### ### ### ######### ######### #########
## Create, destroy, or modify the parts of a crosshair.
proc ::crosshair::Place {w ov} {
upvar 1 $ov opts
# +/-4 is the minimal possible distance which still prevents the
# canvas from choosing the crosshairs as 'current' object under
# the cursor.
set n 4
set x $opts(x)
set y $opts(y)
set x0 $opts(x0)
set y0 $opts(y0)
set x1 $opts(x1)
set y1 $opts(y1)
set ax [expr {$x-$n}]
set bx [expr {$x+$n}]
set ay [expr {$y-$n}]
set by [expr {$y+$n}]
if { [info exists opts(hhairl)] } {
# Modify a visible crosshair.
$w coords $opts(hhairl) $x0 $y $ax $y
$w coords $opts(hhairr) $bx $y $x1 $y
$w coords $opts(vhairu) $x $y0 $x $ay
$w coords $opts(vhaird) $x $by $x $y1
$w raise $opts(hhairl)
$w raise $opts(hhairr)
$w raise $opts(vhaird)
$w raise $opts(vhairu)
} else {
# Create a newly visible crosshair. After unhide and/or
# entering into one of the active bboxes, if any.
set opts(hhairl) [eval [list $w create line $x0 $y $ax $y] $opts(args)]
set opts(hhairr) [eval [list $w create line $bx $y $x1 $y] $opts(args)]
set opts(vhaird) [eval [list $w create line $x $y0 $x $ay] $opts(args)]
set opts(vhairu) [eval [list $w create line $x $by $x $y1] $opts(args)]
}
return
}
proc ::crosshair::Kill {w ov} {
upvar 1 $ov opts
if { ![info exists opts(hhairl)] } return
$w delete $opts(hhairl)
$w delete $opts(hhairr)
$w delete $opts(vhaird)
$w delete $opts(vhairu)
unset opts(hhairl)
unset opts(hhairr)
unset opts(vhairu)
unset opts(vhaird)
return
}
# ### ### ### ######### ######### #########
## State
namespace eval ::crosshair {
# Array holding information describing crosshairs in canvases
variable config
array set config {}
# Controller that positions crosshairs according to user actions
bind Crosshair <Destroy> "[namespace code off] %W"
bind Crosshair <Enter> "[namespace code Unhide] %W %x %y"
bind Crosshair <Leave> "[namespace code Hide] %W"
bind Crosshair <Motion> "[namespace code Move] %W %x %y"
}
# ### ### ### ######### ######### #########
## Ready
package provide crosshair 1.2.1

4
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/crosshair/pkgIndex.tcl

@ -0,0 +1,4 @@
if {![package vsatisfies [package provide Tcl] 8.4-]} {return}
package ifneeded crosshair 1.2.1 [list source [file join $dir crosshair.tcl]]

1113
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ctext/ctext.tcl

File diff suppressed because it is too large Load Diff

1
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ctext/pkgIndex.tcl

@ -0,0 +1 @@
package ifneeded ctext 3.3 [list source [file join $dir ctext.tcl]]

137
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/cursor/cursor.tcl

@ -0,0 +1,137 @@
# cursor.tcl --
#
# Tk cursor handling routines
#
# Copyright (c) 2001-2009 by Jeffrey Hobbs
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: cursor.tcl,v 1.4 2011/01/18 18:17:17 andreas_kupries Exp $
package require Tk 8.0
package provide cursor 0.3.1
namespace eval ::cursor {
namespace export propagate restore display
# Default to depthfirst (bottom up) restore to account for
# megawidgets that will self-propagate cursor changes down.
variable depthfirst 1
variable cursors [list \
X_cursor arrow based_arrow_down based_arrow_up boat bogosity \
bottom_left_corner bottom_right_corner bottom_side bottom_tee \
box_spiral center_ptr circle clock coffee_mug cross cross_reverse \
crosshair diamond_cross dot dotbox double_arrow draft_large \
draft_small draped_box exchange fleur gobbler gumby hand1 hand2 \
heart icon iron_cross left_ptr left_side left_tee leftbutton \
ll_angle lr_angle man middlebutton mouse pencil pirate plus \
question_arrow right_ptr right_side right_tee rightbutton \
rtl_logo sailboat sb_down_arrow sb_h_double_arrow sb_left_arrow \
sb_right_arrow sb_up_arrow sb_v_double_arrow shuttle sizing \
spider spraycan star target tcross top_left_arrow top_left_corner \
top_right_corner top_side top_tee trek ul_angle umbrella \
ur_angle watch xterm \
]
switch -exact $::tcl_platform(os) {
"windows" {
lappend cursors no starting size \
size_ne_sw size_ns size_nw_se size_we uparrow wait
}
"macintosh" {
lappend cursors text cross-hair
}
"unix" {
# no extra cursors
}
}
}
# ::cursor::propagate --
#
# Propagates a cursor to a widget and all descendants.
#
# Arguments:
# w Parent widget to set cursor on (includes children)
# cursor The cursor to use
#
# Results:
# Set the cursor of $w and all descendants to $cursor
proc ::cursor::propagate {w cursor} {
variable CURSOR
# Ignores {} cursors or widgets that don't have a -cursor option
if {![catch {set CURSOR($w) [$w cget -cursor]}] && $CURSOR($w) != ""} {
$w configure -cursor $cursor
} else {
catch {unset CURSOR($w)}
}
foreach child [winfo children $w] { propagate $child $cursor }
}
# ::cursor::restore --
#
# Restores original cursor of a widget and all descendants.
#
# Arguments:
# w Parent widget to restore cursor for (includes children)
# cursor The default cursor to use (if none was cached by propagate)
#
# Results:
# Restore the cursor of $w and all descendants
proc ::cursor::restore {w {cursor {}}} {
variable depthfirst
variable CURSOR
if {$depthfirst} {
foreach child [winfo children $w] { restore $child $cursor }
}
if {[info exists CURSOR($w)]} {
$w configure -cursor $CURSOR($w)
} else {
# Not all widgets have -cursor
catch {$w configure -cursor $cursor}
}
if {!$depthfirst} {
foreach child [winfo children $w] { restore $child $cursor }
}
}
# ::cursor::display --
#
# Show all known cursors for viewing
#
# Arguments:
# w Parent widget to use for dialog
#
# Results:
# Pops up a dialog
proc ::cursor::display {{root .}} {
variable cursors
if {$root == "."} {
set t .__cursorDisplay
} else {
set t $root.__cursorDisplay
}
destroy $t
toplevel $t
wm withdraw $t
label $t.lbl -text "Select a cursor:" -anchor w
listbox $t.lb -selectmode single -yscrollcommand [list $t.sy set]
scrollbar $t.sy -orient v -command [list $t.lb yview]
button $t.d -text Dismiss -command [list destroy $t]
pack $t.d -side bottom
pack $t.lbl -side top -fill x
pack $t.sy -side right -fill y
pack $t.lb -side right -fill both -expand 1
eval [list $t.lb insert end] $cursors
bind $t.lb <Button-1> { %W configure -cursor [%W get [%W nearest %y]] }
wm deiconify $t
}

1
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/cursor/pkgIndex.tcl

@ -0,0 +1 @@
package ifneeded cursor 0.3.1 [list source [file join $dir cursor.tcl]]

456
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/datefield/datefield.tcl

@ -0,0 +1,456 @@
##+##########################################################################
#
# datefield.tcl
#
# Implements a datefield entry widget ala Iwidget::datefield
# by Keith Vetter (keith@ebook.gemstar.com)
#
# Datefield creates an entry widget but with a special binding to KeyPress
# (based on Iwidget::datefield) to ensure that the current value is always
# a valid date. All normal entry commands and configurations still work.
#
# Usage:
# ::datefield::datefield .df -background yellow -textvariable myDate \
# -format "%Y-%m-%d"
# pack .df
#
# Bugs:
# o won't work if you programmatically put in an invalid date
# e.g. .df insert end "abc" will cause it to behave erratically
#
# Revisions:
# KPV Feb 07, 2002 - initial revision
# TW Mar 26, 2017 - support more keys and the mouse wheel
# - add option -format to support 3 date-styles:
# "%d.%m.%Y" (for German)
# "%m/%d/%Y" (for English, standard)
# "%Y-%m-%d" (for ISO)
#
##+##########################################################################
#############################################################################
package require Tk 8.0
package provide datefield 0.3
namespace eval ::datefield {
namespace export datefield
# Have the widget use tile/ttk should it be available.
variable entry entry
if {![catch {
package require tile
}]} {
set entry ttk::entry
}
proc datefield {w args} {
variable entry
variable Format
variable Separator
set i [lsearch $args "-form*"]
if {$i == -1} { # Default English
set Format($w) "%m/%d/%Y"
} else {
set Format($w) [lindex [lreplace $args $i $i] $i]
switch -- $Format($w) {
"%d.%m.%Y" { # German
}
"%m/%d/%Y" { # English
}
"%Y-%m-%d" { # ISO
}
default { # Error
error "ERROR: Unknown value for option -format on datefield $w $args"
}
}
set args [lreplace $args $i $i]
set args [lreplace $args $i $i]
}
set Separator($w) [string range $Format($w) 2 2]
eval $entry $w -width 10 -justify center $args
if {([$w get] eq "") \
|| [catch {clock scan [$w get] -format $Format($w)} base]} {
$w delete 0 end
$w insert end [clock format [clock seconds] -format $Format($w)]
}
$w icursor 0
bind $w <KeyPress> [list ::datefield::KeyPress $w %A %K %s]
bind $w <MouseWheel> [list ::datefield::MouseWheel $w %D]
bind $w <Button1-Motion> break
bind $w <Button2-Motion> break
bind $w <Double-Button> break
bind $w <Triple-Button> break
bind $w <2> break
return $w
}
proc Spin {w dir unit code} {
variable Format
set base [clock scan [$w get] -format $Format($w)]
set new [clock add $base $dir $unit]
set date [clock format $new -format $Format($w)]
set icursor [$w index insert]
$w delete 0 end
$w insert end $date
$w icursor $icursor
return $code
}
proc MouseWheel {w dir} {
$w selection clear
set Dir [expr {$dir / 120}]
return -code [Spin $w $Dir "day" continue]
}
# internal routine for all key presses in the datefield entry widget
proc KeyPress {w char sym state} {
variable Format
variable Separator
proc Move {w dir} {
variable Format
set icursor [$w index insert]
set icursor [expr {($icursor + 10 + $dir) % 10}]
if {$Format($w) ne "%Y-%m-%d"} { # English or German
if {($icursor == 2) || ($icursor == 5)} { # Don't land on a / or .
set icursor [expr {($icursor + 10 + $dir) % 10}]
}
} \
elseif {($icursor == 4) || ($icursor == 7)} { # ISO # Don't land on a -
set icursor [expr {($icursor + 10 + $dir) % 10}]
}
$w icursor $icursor
}
set icursor [$w index insert]
$w selection clear
# Handle some non-number characters first
switch -exact -- $sym {
"Down" {return -code [Spin $w -1 "day" continue]}
"End" {$w icursor 9; return -code break}
"minus" {return -code [Spin $w -1 "day" break]}
"Next" {return -code [Spin $w -1 "month" continue]}
"plus" {return -code [Spin $w 1 "day" break]}
"Prior" {return -code [Spin $w 1 "month" continue]}
"Up" {return -code [Spin $w 1 "day" continue]}
"BackSpace" -
"Delete" -
"Left" {Move $w -1; return -code break}
"Right" {Move $w 1; return -code break}
"Tab" {
if {$Format($w) ne "%Y-%m-%d"} { # English or German
if {($state & 5) == 0} { # ->|
if {$icursor < 3} { # from 1st to 2nd
$w icursor 3
} \
elseif {$icursor < 6} { # from 2nd to 10th-year
$w icursor 8
} else { # next widget
return -code continue
}
} \
elseif {$icursor > 4} { # |<-
$w icursor 3 ;# from year to 2nd
} \
elseif {$icursor > 1} { # from 2nd to 1st
$w icursor 0
} else { # previous widget
return -code continue
}
} \
elseif {($state & 5) == 0} { # ->| ISO
if {$icursor < 5} { # from year to month
$w icursor 5
} \
elseif {$icursor < 8} { # from month to day
$w icursor 8
} else { # next widget
return -code continue
}
} \
elseif {$icursor > 6} { # |<-
$w icursor 5 ;# from day to month
} \
elseif {$icursor > 2} { # from month to 10th-year
$w icursor 2
} else { # previous widget
return -code continue
}
return -code break
}
}
if {$char eq ""} { # remaining special keys
return -code continue
}
if {! [regexp -- {[0-9]} $char]} { # Unknown character
bell
return -code break
}
if {$icursor >= 10} { # Can't add beyond end
bell
return -code break
}
switch -- $Separator($w) {
"." { # German
foreach {day month year} [split [$w get] $Separator($w)] break
if {$icursor < 2} { # DAY SECTION
set endday [lastDay $month $year]
foreach {d1 d2} [split $day ""] break
set cursor 3 ;# Where to leave the cursor
if {$icursor == 0} { # 1st digit of day
if {($char < 3) \
|| (($char == 3) && ($month ne "02"))} {
set day "$char$d2"
if {$day eq "00"} {set day "01"}
if {$day > $endday} {set day $endday}
set cursor 1
} else {
set day "0$char"
}
} else { # 2nd digit of day
set day "$d1$char"
if {($day > $endday) || ($day eq "00")} {
bell
return -code break
}
}
$w delete 0 2
$w insert 0 $day
$w icursor $cursor
return -code break
}
if {$icursor < 5} { # MONTH SECTION
foreach {m1 m2} [split $month ""] break
set cursor 6 ;# Where to leave the cursor
if {$icursor == 3} { # 1st digit of month
if {$char < 2} {
set month "$char$m2"
set cursor 4
} else {
set month "0$char"
}
if {$month > 12} {set month "10"}
if {$month eq "00"} {set month "01"}
} else { # 2nd digit of month
set month "$m1$char"
if {$month > 12} {set month "0$char"}
if {$month eq "00"} {
bell
return -code break
}
}
$w delete 3 5
$w insert 3 $month
# Validate the day of the month
if {$day > [set endday [lastDay $month $year]]} {
$w delete 0 2
$w insert 0 $endday
}
$w icursor $cursor
return -code break
}
set y1 [string range $year 0 0]; # YEAR SECTION
if {$icursor < 7} { # 1st digit of year
if {($char ne "1") && ($char ne "2")} {
bell
return -code break
}
if {$char != $y1} { # Different century
set y 1999
if {$char eq "2"} {set y 2000}
$w delete 6 end
$w insert end $y
}
$w icursor 7
return -code break
}
$w delete $icursor
$w insert $icursor $char
if {[catch {clock scan [$w get] -format $Format($w)}] != 0} { # Validate the year
$w delete 6 end
$w insert end $year ;# Put back in the old year
$w icursor $icursor
bell
}
}
"/" { # English
foreach {month day year} [split [$w get] $Separator($w)] break
if {$icursor < 2} { # MONTH SECTION
foreach {m1 m2} [split $month ""] break
set cursor 3 ;# Where to leave the cursor
if {$icursor == 0} { # 1st digit of month
if {$char < 2} {
set month "$char$m2"
set cursor 1
} else {
set month "0$char"
}
if {$month > 12} {set month "10"}
if {$month eq "00"} {set month "01"}
} else { # 2nd digit of month
set month "$m1$char"
if {$month > 12} {set month "0$char"}
if {$month eq "00"} {
bell
return -code break
}
}
$w delete 0 2
$w insert 0 $month
# Validate the day of the month
if {$day > [set endday [lastDay $month $year]]} {
$w delete 3 5
$w insert 3 $endday
}
$w icursor $cursor
return -code break
}
if {$icursor < 5} { # DAY SECTION
set endday [lastDay $month $year]
foreach {d1 d2} [split $day ""] break
set cursor 6 ;# Where to leave the cursor
if {$icursor == 3} { # 1st digit of day
if {($char < 3) \
|| (($char == 3) && ($month ne "02"))} {
set day "$char$d2"
if {$day eq "00"} {set day "01"}
if {$day > $endday} {set day $endday}
set cursor 4
} else {
set day "0$char"
}
} else { # 2nd digit of day
set day "$d1$char"
if {($day > $endday) || ($day eq "00")} {
bell
return -code break
}
}
$w delete 3 5
$w insert 3 $day
$w icursor $cursor
return -code break
}
set y1 [string range $year 0 0]; # YEAR SECTION
if {$icursor < 7} { # 1st digit of year
if {($char ne "1") && ($char ne "2")} {
bell
return -code break
}
if {$char != $y1} { # Different century
set y 1999
if {$char eq "2"} {set y 2000}
$w delete 6 end
$w insert end $y
}
$w icursor 7
return -code break
}
$w delete $icursor
$w insert $icursor $char
if {[catch {clock scan [$w get] -format $Format($w)}] != 0} { # Validate the year
$w delete 6 end
$w insert end $year ;# Put back in the old year
$w icursor $icursor
bell
}
}
default { # ISO
foreach {year month day} [split [$w get] $Separator($w)] break
if {$icursor < 4} { # YEAR SECTION
set y1 [string range $year 0 0];
if {$icursor == 0} { # 1st digit of year
if {($char ne "1") && ($char ne "2")} {
bell
return -code break
}
if {$char != $y1} { # Different century
set y 1999
if {$char eq "2"} {set y 2000}
$w delete 0 4
$w insert 0 $y
}
$w icursor 1
return -code break
}
$w delete $icursor
$w insert $icursor $char
if {[catch {clock scan [$w get] -format $Format($w)}] != 0} { # Validate the year
$w delete 0 4
$w insert 0 $year ;# Put back in the old year
$w icursor $icursor
bell
}
if {$icursor == 3} { # last digit of year
$w icursor 5 ;# Don't land on a -
}
return -code break
}
if {$icursor < 7} { # MONTH SECTION
foreach {m1 m2} [split $month ""] break
set cursor 8 ;# Where to leave the cursor
if {$icursor == 5} { # 1st digit of month
if {$char < 2} {
set month "$char$m2"
set cursor 6
} else {
set month "0$char"
}
if {$month > 12} {set month "10"}
if {$month eq "00"} {set month "01"}
} else { # 2nd digit of month
set month "$m1$char"
if {$month > 12} {set month "0$char"}
if {$month eq "00"} {
bell
return -code break
}
}
$w delete 5 7
$w insert 5 $month
# Validate the day of the month
if {$day > [set endday [lastDay $month $year]]} {
$w delete 8 end
$w insert end $endday
}
$w icursor $cursor
return -code break
}
set endday [lastDay $month $year] ;# DAY SECTION
foreach {d1 d2} [split $day ""] break
set cursor 10 ;# Where to leave the cursor
if {$icursor == 8} { # 1st digit of day
if {($char < 3) \
|| (($char == 3) && ($month ne "02"))} {
set day "$char$d2"
if {$day eq "00"} {set day "01"}
if {$day > $endday} {set day $endday}
set cursor 9
} else {
set day "0$char"
}
} else { # 2nd digit of day
set day "$d1$char"
if {($day > $endday) || ($day eq "00")} {
bell
return -code break
}
}
$w delete 8 end
$w insert end $day
$w icursor $cursor
}
}
return -code break
}
# internal routine that returns the last valid day of a given month and year
proc lastDay {month year} {
return [clock format [clock scan "+1 month -1 day" \
-base [clock scan "$month/01/$year"]] -format %d]
}
}

1
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/datefield/pkgIndex.tcl

@ -0,0 +1 @@
package ifneeded datefield 0.3 [list source [file join $dir datefield.tcl]]

470
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/application.tcl

@ -0,0 +1,470 @@
## -*- tcl -*-
## (C) 2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
## BSD Licensed
# # ## ### ##### ######## ############# ######################
#
# application on top of the diagram drawing package.
#
## Use Cases
## (1) Reading a single diagram file and showing it on a canvas.
## (1a) Like (1), for multiple input files. This requires an additional
## selection step before the diagram is shown.
## (2) Convert one or more diagram files into raster images in various
## formats.
# # ## ### ##### ######## ############# #####################
## Command syntax
## (Ad 1) show picfile
## (Ad 1a) show picfile picfile...
## (Ad 2) convert -o output-file-or-dir format picfile
## convert -o output-dir format picfile picfile...
# # ## ### ##### ######## ############# #####################
## Requirements
package require Tcl 8.5
package require Tk 8.5
package require fileutil
wm withdraw . ; # Hide the main toplevel until we actually need it, if
# ever.
namespace eval ::diagram::application {}
# # ## ### ##### ######## ############# #####################
## Implementation
proc ::diagram::application {arguments} {
variable application::mode
application::ProcessCmdline $arguments
application::Run::$mode
return
}
proc ::diagram::application::showerror {text} {
global argv0
puts stderr "$argv0: $text"
exit 1
}
# # ## ### ##### ######## ############# #####################
## Internal data and status
namespace eval ::diagram::application {
# Path to where the output goes to. Depending on the chosen mode
# this information may be irrelevant, a file, or a directory.
# Specified through the option '-o' where suitable.
variable output ""
# Paths of the documents to convert. Always a list, even in the
# case of a single input file. Specified through the trailing
# arguments on the command line. The relative path of a file under
# 'input' also becomes its relative path under 'output'.
variable input ""
# The name of the format to convert the diagram documents
# into. Used as extension for the generated files as well when
# converting multiple files. Internally this is the name of the
# canvas::* or img::* package for the image format. The two cases
# are distinguished by the value of the boolean flag "snap". True
# indicates a raster format via img::*, false a canvas::* dump
# package ... FUTURE :: Should have a 'canvas::write::*' or
# somesuch family of packages which hide this type of difference
# from us.
variable format ""
variable snap 0
# Name of the found processing mode. Derived during processing all
# arguments on the command line. This value is used during the
# dispatch to the command implementing the mode, after processing
# the command line.
#
# Possible/Legal values: Meaning
# --------------------- -------
# --------------------- -------
variable mode ""
}
# # ## ### ##### ######## ############# #####################
##
proc ::diagram::application::ProcessCmdline {arguments} {
variable input {} ; # Set defaults.
variable output "" ; #
variable format "" ; #
variable mode "" ; #
# syntax: show file...
# convert -o output format file...
if {[llength $arguments] < 2} Usage
set arguments [lassign $arguments command]
switch -exact -- $command {
show {ProcessShow $arguments}
convert {ProcessConvert $arguments}
default Usage
}
set mode $command
return
}
proc ::diagram::application::ProcessShow {arguments} {
if {[llength $arguments] < 1} Usage
variable input {}
variable trusted 0
# Basic option processing and validation.
while {[llength $arguments]} {
set opt [lindex $arguments 0]
if {![string match "-*" $opt]} break
switch -exact -- $opt {
-t {
if {[llength $arguments] < 1} Usage
set arguments [lassign $arguments _opt_]
set trusted 1
}
default Usage
}
}
set input $arguments
CheckInput
return
}
proc ::diagram::application::ProcessConvert {arguments} {
variable output ""
variable input {}
variable format ""
variable trusted 0
if {[llength $arguments] < 4} Usage
# Basic option processing and validation.
while {[llength $arguments]} {
set opt [lindex $arguments 0]
if {![string match "-*" $opt]} break
switch -exact -- $opt {
-o {
if {[llength $arguments] < 2} Usage
set arguments [lassign $arguments _opt_ output]
}
-t {
if {[llength $arguments] < 1} Usage
set arguments [lassign $arguments _opt_]
set trusted 1
}
default Usage
}
}
# Format and at least one file are expected.
if {[llength $arguments] < 2} Usage
set input [lassign $arguments format]
ValidateFormat
CheckInput
CheckOutput
return
}
# # ## ### ##### ######## ############# #####################
proc ::diagram::application::Usage {} {
showerror "wrong#args, expected: show file...|convert -o outputpath format file..."
# not reached ...
}
# # ## ### ##### ######## ############# #####################
## Various complex checks on the arguments
proc ::diagram::application::ValidateFormat {} {
variable format
variable snap
if {![catch {
package require canvas::snap
package require img::$format
set snap 1
} msgA]} return
if {![catch {
package require canvas::$format
} msgB]} return
showerror "Unable to handle format \"$format\", because of: $msgA and $msgB"
return
}
proc ::diagram::application::CheckInput {} {
variable input
foreach f $input {
if {![file exists $f]} {
showerror "Unable to find picture \"$f\""
} elseif {![file readable $f]} {
showerror "picture \"$f\" not readable (permission denied)"
}
}
if {[llength $input] < 1} {
showerror "No picture(s) specified"
}
return
}
proc ::diagram::application::CheckOutput {} {
variable input
variable output
if {$output eq ""} {
showerror "No output path specified"
}
set base [file dirname $output]
if {$base eq ""} {set base [pwd]}
# Multiple inputs: Output must either exist as directory, or
# output base writable so that we can create the directory.
# Single input: As above except existence as file.
if {![file exists $output]} {
if {![file exists $base]} {
showerror "Output base path \"$base\" not found"
}
if {![file writable $base]} {
showerror "Output base path \"$base\" not writable (permission denied)"
}
} else {
if {![file writable $output]} {
showerror "Output path \"$output\" not writable (permission denied)"
}
if {[llength $input] > 1} {
if {![file isdirectory $output]} {
showerror "Output path \"$output\" not a directory"
}
} else {
if {![file isfile $output]} {
showerror "Output path \"$output\" not a file"
}
}
}
return
}
# # ## ### ##### ######## ############# #####################
##
namespace eval ::diagram::application::Run::GUI {}
proc ::diagram::application::Run::show {} {
variable ::diagram::application::input
GUI::Show
if {[llength $input] == 1} {
after 100 {
.l selection clear 0 end
.l selection set 0
event generate .l <<ListboxSelect>>
}
}
vwait __forever__
return
}
proc ::diagram::application::Run::convert {} {
variable ::diagram::application::input
variable ::diagram::application::output
set dip [MakeInterpreter]
GUI::Convert
PrepareOutput
if {[llength $input] > 1} {
foreach f $input {
Convert $dip $f [GetDestination $f]
}
} else {
set f [lindex $input 0]
if {[file exists $output] && [file isdirectory $output]} {
Convert $dip $f [GetExtension $output/[file tail $input]]
} else {
Convert $dip $f $output
}
}
interp delete $dip
GUI::Close
return
}
proc ::diagram::application::Run::Convert {dip src dst} {
variable ::diagram::application::format
variable ::diagram::application::snap
puts ${src}...
set pic [fileutil::cat $src]
if {[catch {
$dip eval [list D draw $pic]
} msg]} {
puts "FAIL $msg : $src"
} elseif {$snap} {
set DIA [canvas::snap .c]
$DIA write $dst -format $format
image delete $DIA
} else {
# Direct canvas dump ...
fileutil::writeFile $dst [canvas::$format .c]
}
# Wipe controller state, no information transfer between pictures.
$dip eval {D reset}
return
}
proc ::diagram::application::Run::GUI::Show {} {
package require widget::scrolledwindow
#package require crosshair
set dip [::diagram::application::Run::MakeInterpreter]
ttk::notebook .n
button .e -text Exit -command ::exit
widget::scrolledwindow .sl -borderwidth 1 -relief sunken
widget::scrolledwindow .sc -borderwidth 1 -relief sunken
widget::scrolledwindow .st -borderwidth 1 -relief sunken
listbox .l -width 40 -selectmode single -listvariable ::diagram::application::input
canvas .c -width 800 -height 600 -scrollregion {-4000 -4000 4000 4000}
text .t -font {Arial 20}
.sl setwidget .l
.sc setwidget .c
.st setwidget .t
pack .e -fill none -expand 0 -side bottom -anchor e
#panedwindow .p -orient vertical
#.p add .sl .sc
#.p paneconfigure .sl -width 100
pack .sl -fill both -expand 1 -padx 4 -pady 4 -side left
pack .n -fill both -expand 1 -padx 4 -pady 4 -side right
.n add .sc -state normal -sticky swen -text Diagram
.n add .st -state normal -sticky swen -text Code
bind .l <<ListboxSelect>> [list ::diagram::application::Run::GUI::ShowPicture $dip]
# Panning via mouse
bind .c <ButtonPress-2> {%W scan mark %x %y}
bind .c <B2-Motion> {%W scan dragto %x %y}
# Cross hairs ...
#.c configure -cursor tcross
#crosshair::crosshair .c -width 0 -fill \#999999 -dash {.}
#crosshair::track on .c TRACK
wm deiconify .
return
}
proc ::diagram::application::Run::GUI::ShowPicture {dip} {
set selection [.l curselection]
if {![llength $selection]} return
$dip eval {catch {D destroy}}
$dip eval {diagram D .c}
set pic [fileutil::cat [.l get $selection]]
.t delete 0.1 end
.t insert 0.1 $pic
after 0 [list $dip eval [list D draw $pic]]
return
}
proc ::diagram::application::Run::GUI::Convert {} {
canvas .c -width 800 -height 600 -scrollregion {0 0 1200 1000}
grid .c -row 0 -column 0 -sticky swen
grid rowconfigure . 0 -weight 1
grid columnconfigure . 0 -weight 1
wm attributes . -fullscreen 1
wm deiconify .
tkwait visibility .
return
}
proc ::diagram::application::Run::GUI::Close {} {
wm withdraw .
destroy .
return
}
proc ::diagram::application::Run::PrepareOutput {} {
variable ::diagram::application::input
variable ::diagram::application::output
if {[llength $input] > 1} {
file mkdir [file dirname $output]
}
return
}
proc ::diagram::application::Run::GetDestination {f} {
variable ::diagram::application::output
if {[file pathtype $f] ne "relative"} {
return set f [file join $output {*}[lrange [file split $f] 1 end]]
} else {
set f $output/$f
}
file mkdir [file dirname $f]
return [GetExtension $f]
}
proc ::diagram::application::Run::GetExtension {f} {
variable ::diagram::application::format
return [file rootname $f].$format
}
proc ::diagram::application::Run::MakeInterpreter {} {
variable ::diagram::application::trusted
set sec [expr {[lindex [time {
if {$trusted} {
puts {Creating trusted environment, please wait...}
set dip [interp create]
$dip eval [list set auto_path $::auto_path]
} else {
puts {Creating safe environment, please wait...}
set dip [::safe::interpCreate]
}
interp alias $dip .c {} .c ; # Import of canvas
interp alias $dip tk {} tk ; # enable tk scaling
$dip eval {package require diagram}
$dip eval {diagram D .c}
}] 0]/double(1e6)}]
puts "... completed in $sec seconds."
after 100
return $dip
}
# # ## ### ##### ######## ############# #####################
package provide diagram::application 1.2
return

383
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/attributes.tcl

@ -0,0 +1,383 @@
## -*- tcl -*-
## (C) 2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
## BSD Licensed
# # ## ### ##### ######## ############# ######################
#
# diagram attribute database, basic data plus extensibility features.
##
# # ## ### ##### ######## ############# ######################
## Requisites
package require Tcl 8.5 ; # Want the nice things it brings (dicts, {*}, etc.)
package require snit ; # Object framework.
package require struct::queue ; # Word storage when processing attribute arguments.
# # ## ### ##### ######## ############# ######################
## Implementation
snit::type ::diagram::attribute {
# # ## ### ##### ######## ############# ######################
## Public API :: Attribute extensibility
method new {name args} {
array set spec $args
if {![info exists spec(key)]} { set spec(key) $name }
set key $spec(key)
set getvalue [GetFunction spec]
set ovalidate [ValidateFunction spec] ; # snit validation type, or API compatible.
set otransform [TransformFunction spec] ; # o* <=> optional function.
set merger [MergeFunction spec $key]
set odefault [DefaultFunction spec $key]
set myattrp($name) [ProcessingFunction $getvalue $ovalidate $otransform $merger]
if {![llength $odefault]} return
set myattrd($key) $odefault
{*}$odefault init
return
}
method {unknown =} {unknowncmd} {
set myunknown [list $unknowncmd]
return
}
method {unknown +} {unknowncmd} {
lappend myunknown $unknowncmd
return
}
# # ## ### ##### ######## ############# ######################
## Public API :: attribute processing, integrated loading of requested defaults.
method attributes {shape words required} {
return [$self defaults [$self process $shape $words] $required]
}
method process {shape words} {
if {![llength $words]} {
return {}
}
set attributes [ReadySame $shape]
{*}$wq clear
{*}$wq put {*}$words
while {[{*}$wq size]} {
set aname [{*}$wq get]
set shape [dict get $attributes /shape]
if {[{*}$wq size]} {
#puts A|do|$aname|/$shape|\t\t(([{*}$wq peek [{*}$wq size]]))
} else {
#puts A|do|$aname|/$shape|\t\t(())
}
# Check for a shape-specific attribute first, then try the
# name as is.
if {[info exists myattrp(${shape}::$aname)]} {
{*}$myattrp(${shape}::$aname) $wq attributes
continue
} elseif {[info exists myattrp($aname)]} {
{*}$myattrp($aname) $wq attributes
continue
}
#puts A|unknown|$aname|
# Hooks for unknown names, for dynamic extension.
{*}$wq unget $aname
set ok 0
foreach hook $myunknown {
#puts A|unknown/$shape|\t\t(([{*}$wq peek [{*}$wq size]]))
if {[{*}$hook $shape $wq]} {
#puts A|unknown|taken|$hook
set ok 1
break
}
}
if {$ok} continue
BadAttribute $shape $wq
}
#puts A|done|$attributes|
SaveSame $attributes
return $attributes
}
method defaults {attributes required} {
# Note: All default hooks are run, even if the key is already
# specified. This gives the hook the opportunity to not only
# fill in defaults, but to compute and store derived
# information (from multiple other attributes) as well. An
# example using this ability are the Waypoint and ArcLocation
# handlers which essentially precompute large parts of their
# elements' geometry.
foreach key $required {
#if {[dict exists $attributes $key]} continue
if {![info exists myattrd($key)]} {
#return -code error "Unable to determine a default for \"$key\""
continue
}
{*}$myattrd($key) fill attributes
}
return $attributes
}
method set {attributes} {
dict for {key value} $attributes {
if {![info exists myattrd($key)]} continue
{*}$myattrd($key) set $key $value
}
return
}
# # ## ### ##### ######## ############# ######################
## Public API :: Instance construction
constructor {core} {
# Core attributes (shape redefinition, history access (same))
set mycore $core
#set myunknown [myproc BadAttribute]
$self new /shape merge [mymethod Merge/shape]
$self new same get [mymethod GetSame] merge [mymethod MergeSame]
install wq using struct::queue ${selfns}::WQ
# Queue Tracer
if {0} {set wq [list ::apply [list {args} {
puts $args
uplevel 1 $args
}] $wq]}
return
}
# # ## ### ##### ######## ############# ######################
##
proc ReadySame {shape} {
upvar 1 mycurrentsame mycurrentsame mysame mysame
set mycurrentsame {}
catch {
set mycurrentsame $mysame($shape)
}
return [list /shape $shape]
}
proc SaveSame {attributes} {
upvar 1 mysame mysame
set shape [dict get $attributes /shape]
set mysame($shape) $attributes
return
}
# # ## ### ##### ######## ############# ######################
proc BadAttribute {shape words} {
return -code error "Expected attribute, got \"[{*}$words peek]\""
}
# # ## ### ##### ######## ############# ######################
method GetSame {words_dummy} {
return $mycurrentsame
}
method MergeSame {key samedict attributes} {
# key == "same"
return [dict merge $attributes $samedict]
}
method Merge/shape {key newshape attributes} {
# key == "/shape"
ReadySame $newshape
dict set attributes /shape $newshape
return $attributes
}
# # ## ### ##### ######## ############# ######################
method Get {words} {
return [{*}$words get]
}
# # ## ### ##### ######## ############# ######################
method Set {key value attributes} {
#puts AM.=|$key||$value|\t|$attributes|
dict set attributes $key $value
#puts AM:=|$attributes|
return $attributes
}
method Lappend {key value attributes} {
#puts AM++|$key||$value|\t|$attributes|
dict lappend attributes $key $value
#puts AM:=|$attributes|
return $attributes
}
# # ## ### ##### ######## ############# ######################
method Linked {key varname defaultvalue cmd args} {
#puts "Linked ($key $varname $defaultvalue) $cmd $args"
$self Linked_ $cmd $key $varname $defaultvalue {*}$args
}
method {Linked_ init} {key varname defaultvalue} {
$mycore state set $varname $defaultvalue
return
}
method {Linked_ set} {key varname defaultvalue _key newvalue} {
$mycore state set $varname $newvalue
return
}
method {Linked_ fill} {key varname defaultvalue av} {
upvar 2 $av attributes ; # Bypass the 'Linked' dispatcher.
#puts LINK|$key|$varname|-|$attributes|-|[$mycore state get $varname]|
if {[dict exists $attributes $key]} return
dict set attributes $key [$mycore state get $varname]
return
}
# # ## ### ##### ######## ############# ######################
## Helper commands processing an attribute specification into a set of anonymous functions
proc GetFunction {sv} {
upvar 1 $sv spec selfns selfns
if {[info exists spec(get)]} { return $spec(get) }
return [mymethod Get]
}
proc ValidateFunction {sv} {
upvar 1 $sv spec
if {[info exists spec(type)]} {
set f $spec(type)
if {[llength $f] > 1} {
# The specification is type + arguments. Create a
# proper object by inserting a name into the command and then running it.
set f [eval [linsert $f 1 AttrType%AUTO%]]
}
return [list {*}$f validate]
}
return {}
}
proc TransformFunction {sv} {
upvar 1 $sv spec
if {[info exists spec(transform)]} { return $spec(transform) }
return {}
}
proc MergeFunction {sv key} {
upvar 1 $sv spec selfns selfns
if {[info exists spec(merge)]} { return [list {*}$spec(merge) $key] }
if {![info exists spec(aggregate)]} {
set spec(aggregate) 0
}
if {$spec(aggregate)} {
return [mymethod Lappend $key]
} else {
return [mymethod Set $key]
}
}
proc DefaultFunction {sv key} {
upvar 1 $sv spec selfns selfns
if {[info exists spec(default)]} { return $spec(default) }
if {[info exists spec(linked)]} {
#lassign $spec(linked) varname defaultvalue
return [mymethod Linked $key {*}$spec(linked)]
}
return {}
}
proc ProcessingFunction {get validate transform merge} {
# partial functions.
# validate, transform - optional
# get, merge - required
# Types
# get : wordvar -> value
# transform : value -> value
# validate : value -> value
# merge : value -> dict -> dict
if {[llength $validate] && [llength $transform]} {
return [list ::apply [list {get validate transform merge words av} {
upvar 1 $av attributes
set value [{*}$get $words]
set value [{*}$transform $value]
set value [{*}$validate $value]
set attributes [{*}$merge $value $attributes]
}] $get $validate $transform $merge]
} elseif {[llength $validate]} {
return [list ::apply [list {get validate merge words av} {
upvar 1 $av attributes
set value [{*}$get $words]
set value [{*}$validate $value]
set attributes [{*}$merge $value $attributes]
}] $get $validate $merge]
} elseif {[llength $transform]} {
return [list ::apply [list {get transform merge words av} {
upvar 1 $av attributes
set value [{*}$get $words]
set value [{*}$transform $value]
set attributes [{*}$merge $value $attributes]
}] $get $transform $merge]
} else {
return [list ::apply [list {get merge words av} {
upvar 1 $av attributes
set value [{*}$get $words]
set attributes [{*}$merge $value $attributes]
}] $get $merge]
}
}
# # ## ### ##### ######## ############# ######################
## Instance data. Maps from attribute names and dictionary keys to
## relevant functions for processing input and defaults.
variable mycore {}
variable myunknown {}
variable myattrp -array {} ; # attribute command -> processing function
variable myattrd -array {} ; # attribute key -> default management function
# History stack, one level deep, keyed by shape name.
variable mysame -array {}
variable mycurrentsame {}
component wq ; # Storage for the words we are processing as attributes.
##
# # ## ### ##### ######## ############# ######################
}
# # ## ### ##### ######## ############# ######################
## Ready
package provide diagram::attribute 1

1279
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/basic.tcl

File diff suppressed because it is too large Load Diff

1120
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/core.tcl

File diff suppressed because it is too large Load Diff

62
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/diagram.tcl

@ -0,0 +1,62 @@
## -*- tcl -*-
## (C) 2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
## BSD Licensed
# # ## ### ##### ######## ############# ######################
#
# diagram drawing package.
#
##
# # ## ### ##### ######## ############# ######################
## Requisites
package require Tcl 8.5 ; # Want the nice things it brings
# (dicts, {*}, etc.)
package require diagram::core ; # Core drawing management
package require diagram::basic ; # Basic shapes.
package require snit ; # Object framework.
# # ## ### ##### ######## ############# ######################
## Implementation
snit::type ::diagram {
# # ## ### ##### ######## ############# ######################
## Public API :: Instance construction, and method routing
constructor {canvas args} {
install core using diagram::core ${selfns}::CORE $canvas
install basic using diagram::basic ${selfns}::BASIC $core
set mybaseline [$core snap]
if {![llength $args]} return
$core draw {*}$args
return
}
method reset {} {
$core drop
$core restore $mybaseline
return
}
delegate method * to core
# # ## ### ##### ######## ############# ######################
## Instance data, just two components,
component core ; # Fundamental drawing engine and management
component basic ; # Fundamental shapes we can draw
variable mybaseline
##
# # ## ### ##### ######## ############# ######################
}
# # ## ### ##### ######## ############# ######################
## Ready
package provide diagram 1

254
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/direction.tcl

@ -0,0 +1,254 @@
## -*- tcl -*-
## (C) 2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
## BSD Licensed
# # ## ### ##### ######## ############# ######################
#
# Database of named directions, for use in the diagram controller.
#
# Directions are identified by name and each has a set of attributes,
# each identified by name, with associated value. The attributes are
# not typed.
#
# Standard attributes are 'angle' and 'oppposite', the first providing
# the angle of the direction, in degrees (0-360, 0 == right/east, 90
# == up/north), and the second naming the complentary direction going
# into the opposite direction (+/- 180 degrees).
#
# The eight directions (octants) of the compass rose are predefined,
# standard.
#
# Beyond the directions the system also manages 'aliases',
# i.e. alternate/secondary names for the primary directions.
#
# All names are handled case-insensitive!
#
##
# # ## ### ##### ######## ############# ######################
## Requisites
package require Tcl 8.5 ; # Want the nice things it brings (dicts, {*}, etc.)
package require snit ; # Object framework.
# # ## ### ##### ######## ############# ######################
## Implementation
snit::type ::diagram::direction {
# # ## ### ##### ######## ############# ######################
## Public API :: Extending the database
method {new direction} {name args} {
set thename [string tolower $name]
# Argument validation.
if {[info exists myinfo($thename)] ||
[info exists myalias($thename)]} {
return -code error "direction already known"
} elseif {[llength $args] % 2 == 1} {
return -code error "Expected a dictionary, got \"$args\""
} elseif {![dict exists $args angle]} {
return -code error "Standard attribute 'angle' is missing"
} elseif {![dict exists $args opposite]} {
return -code error "Standard attribute 'opposite' is missing"
}
# Note: Can't check the value of opposite, a direction, for
# existence, because then we are unable to define the pairs.
# Should either check the angle, or auto-reduce to the proper
# interval.
set myinfo($thename) $args
return
}
method {new alias} {name primary} {
set thename [string tolower $name]
set theprimary [string tolower $primary]
# Argument validation.
if {[info exists myalias($thename)]} {
return -code error "alias already known"
} elseif {![info exists myalias($theprimary)] &&
![info exists myinfo($theprimary)]} {
return -code error "existing direction expected, not known"
}
# (*a) Resolve alias to alias in favor of the underlying
# primary => Short lookup, no iteration required.
if {[info exists myalias($theprimary)]} {
set theprimary $myalias($theprimary)
}
# And remember the mapping.
set mydb($thename) $theprimary
return
}
# # ## ### ##### ######## ############# ######################
## Public API :: Validate directions, either as explict angle, or named.
## and return it normalized (angle reduced to
## interval, primary name of any alias).
method validate {direction} {
if {[Norm $direction angle]} { return $angle }
set d $direction
# Only one alias lookup necessary, see (*a) in 'new alias'.
if {[info exists myalias($d)]} { set d $myalias($d) }
if {[info exists myinfo($d)]} { return $d }
return -code error "Expected direction, got \"$direction\""
}
method is {d} {
if {[Norm $d angle]} { return 1 }
# Only one alias lookup necessary, see (*a) in 'new alias'.
if {[info exists myalias($d)]} { set d $myalias($d) }
return [info exists myinfo($d)]
}
method isStrict {d} {
# Only one alias lookup necessary, see (*a) in 'new alias'.
if {[info exists myalias($d)]} { set d $myalias($d) }
return [info exists myinfo($d)]
}
method map {corners c} {
if {[dict exists $corners $c]} {
return $c
} elseif {[$self is $c]} {
set new [$self validate $c]
if {$new ne $c} {
return $new
}
}
# Find nearest corner by angle.
set angle [$self get $c angle]
set delta Inf
set min {}
foreach d [dict keys $corners] {
if {![$self isStrict $d]} continue
if {[catch {
set da [$self get $d angle]
}]} continue
set dda [expr {abs($da - $angle)}]
if {$dda >= $delta} continue
set delta $dda
set min $d
}
if {$min ne $c} {
return $min
}
return $c
}
# # ## ### ##### ######## ############# ######################
## Public API :: Retrieve directional attributes (all, or
## specific). Accepts angles as well, and uses
## nearest named direction.
method get {direction {detail {}}} {
if {[Norm $direction angle]} {
set d [$self FindByAngle $angle]
} elseif {[info exists myalias($direction)]} {
set d $myalias($direction)
} else {
set d $direction
}
if {[info exists myinfo($d)]} {
if {[llength [info level 0]] == 7} {
return [dict get $myinfo($d) $detail]
} else {
return $myinfo($d)
}
}
return -code error "Expected direction, got \"$direction\""
}
# # ## ### ##### ######## ############# ######################
proc Norm {angle varname} {
if {![string is double -strict $angle]} { return 0 }
while {$angle < 0} { set angle [expr {$angle + 360}] }
while {$angle > 360} { set angle [expr {$angle - 360}] }
upvar 1 $varname normalized
set normalized $angle
return 1
}
method FindByAngle {angle} {
# Find nearest named angle.
set name {}
set delta 720
foreach k [array names myinfo] {
if {![dict exists $myinfo($k) angle]} continue
set a [dict get $myinfo($k) angle]
if {$a eq {}} continue
set d [expr {abs($a-$angle)}]
if {$d < $delta} {
set delta $d
set name $k
}
}
return $name
}
# # ## ### ##### ######## ############# ######################
## Instance data, database tables as arrays, keyed by direction
## and alias names.
# Standard directions, the eight sections of the compass rose,
# with angles and opposite, complementary direction.
#
# 135 90 45
# nw n ne
# \|/
# 180 w -*- e 0
# /|\.
# sw s se
# 225 270 315
variable myinfo -array {
east {angle 0 opposite west }
northeast {angle 45 opposite southwest}
north {angle 90 opposite south }
northwest {angle 135 opposite southeast}
west {angle 180 opposite east }
southwest {angle 225 opposite northeast}
south {angle 270 opposite north }
southeast {angle 315 opposite northwest}
center {}
}
# Predefined aliases for the standard directions
# Cardinal and intermediate directions.
# Names and appropriate unicode symbols.
variable myalias -array {
c center
w west left west \u2190 west
s south down south \u2191 north
e east right east \u2192 east
n north up north \u2193 south
t north top north r east
b south bottom south l west
bot south
nw northwest up-left northwest \u2196 northwest
ne northeast up-right northeast \u2197 northeast
se southeast down-right southeast \u2198 southeast
sw southwest down-left southwest \u2199 southwest
upleft northwest leftup northwest
upright northeast rightup northeast
downright southeast rightdown southeast
downleft southwest leftdown southwest
}
##
# # ## ### ##### ######## ############# ######################
}
# # ## ### ##### ######## ############# ######################
## Ready
package provide diagram::direction 1

298
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/element.tcl

@ -0,0 +1,298 @@
## -*- tcl -*-
## (C) 2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
## BSD Licensed
# # ## ### ##### ######## ############# ######################
#
# Database of the created/drawn elements, with their canvas items,
# corners (named points), and sub-elements.
#
##
# # ## ### ##### ######## ############# ######################
## Requisites
package require Tcl 8.5 ; # Want the nice things it
# brings (dicts, {*}, etc.)
package require snit ; # Object framework.
package require math::geometry 1.1.2 ; # Vector math (points, line
# (segments), poly-lines).
package require diagram::point
# # ## ### ##### ######## ############# ######################
## Implementation
snit::type ::diagram::element {
# # ## ### ##### ######## ############# ######################
typemethod validate {id} {
if {[$type is $id]} {return $id}
return -code error "Expected element id, got \"$id\""
}
typemethod is {id} {
return [expr {[llength $id] == 2 &&
[lindex $id 0] eq "element" &&
[string is integer -strict [lindex $id 1]] &&
([lindex $id 1] >= 1)}]
}
# # ## ### ##### ######## ############# ######################
method shape {shape} {
set myshape($shape) .
return
}
method isShape {shape} {
return [info exists myshape($shape)]
}
# # ## ### ##### ######## ############# ######################
## Public API :: Extending the database
method new {shape corners items subelements} {
# Generate key
set id [NewIdentifier]
# Save the element information.
set myelement($id) [dict create \
shape $shape \
corners $corners \
items $items \
elements $subelements]
lappend myhistory() $id
lappend myhistory($shape) $id
return $id
}
method drop {} {
set mycounter 0
array unset myelement *
array unset myhistory *
set myhistory() {}
return
}
method {history get} {} {
return [array get myhistory]
}
method {history set} {history} {
array unset myhistory *
array set myhistory $history
return
}
method {history find} {shape offset} {
# 1, 2,...: Offset from the beginning of history, forward.
# -1,-2,...: Offset from the end history, backward.
if {$offset < 0} {
set offset [expr {[llength $myhistory($shape)] + $offset}]
} else {
incr offset -1
}
#parray myhistory
#puts E|hf|$shape|$offset|
return [lindex $myhistory($shape) $offset]
}
# # ## ### ##### ######## ############# ######################
## Public API :: Query database.
method elements {} {
return $myhistory()
}
method corner {id corner} {
#puts MAP($corner)=|[MapCorner $id $corner]|
set corners [dict get $myelement($id) corners]
return [dict get $corners [$dir map $corners $corner]]
}
method corners {id} {
return [dict get $myelement($id) corners]
}
method names {id {pattern *}} {
return [dict keys [dict get $myelement($id) corners] $pattern]
}
method items {args} {
set items {}
foreach id $args {
lappend items {*}[dict get $myelement($id) items]
lappend items {*}[$self items {*}[dict get $myelement($id) elements]]
}
# Elements with sub-elements elements can cause canvas items
# to appear multiple times. Reduce this to only one
# appearance. Otherwise items may be processed multiple times
# later.
return [lsort -uniq $items]
}
method bbox {args} {
# We compute the bounding box from the corners we have for the
# specified elements. This makes the assumption that the
# convex hull of the element's corners is a good approximation
# of the areas they cover.
#
# (1) We cannot fall back to canvas items, as the items may
# cover a much smaller area than the system believes. This
# notably happens for text elements. In essence a user-
# declared WxH would be ignored by looking at the canvas.
#
# (2) We have to look at all corners because the simple NW/SE
# diagonal may underestimate the box. This happens for circles
# where these anchors are near the circle boundary and thus
# describe the in-scribed box, instead of the outer bounds.
# Note that corners may contain other information than
# points. This is why the corner values are type tagged,
# allowing us to ignore the non-point corners.
set polyline {}
foreach id $args {
foreach v [dict values [dict get $myelement($id) corners]] {
lassign $v cmd detail
if {$cmd ne "point"} continue
lappend polyline [geo::x $detail] [geo::y $detail]
}
}
return [geo::bbox $polyline]
}
# # ## ### ##### ######## ############# ######################
## Public API :: Move elements to a point.
method relocate {id destination corner canvas} {
#puts \trelocate($id).$corner\ @$destination
# Move the id'entified element such that the corner's point is
# at the destination.
# Retrieve element data.
array set el $myelement($id)
# Find current location of the specified corner.
set origin [diagram::point unbox [$self corner $id $corner]]
#puts \t$corner=$origin
# Determine the movement vector which brings the corner into
# coincidence with the destination.
set delta [geo::- $destination $origin]
#puts \tdelta=$delta
# And perform the movement.
$self Move $id $delta $canvas
return
}
method move {delta corners} {
set newcorners {}
foreach {key location} $corners {
#puts PLACE|$key|$location|$delta|
if {[llength $location] == 2} {
lassign $location cmd detail
if {$cmd eq "point"} {
#puts \tSHIFT
lappend newcorners $key \
[list $cmd [geo::+ $detail $delta]]
} else {
lappend newcorners $key $location
}
} else {
lappend newcorners $key $location
}
}
return $newcorners
}
method Move {id delta canvas} {
# Retrieve element data.
array set el $myelement($id)
# Move the primary items on the canvas.
foreach item $el(items) {
$canvas move $item {*}$delta
}
# Recursively move child elements
foreach sid $el(elements) {
$self Move $sid $delta $canvas
}
# And modify the corners appropriately
set newcorners [$self move $delta $el(corners)]
dict set myelement($id) corners $newcorners
return
}
# # ## ### ##### ######## ############# ######################
constructor {thedir} {
set dir $thedir
return
}
# # ## ### ##### ######## ############# ######################
proc NewIdentifier {} {
upvar 1 mycounter mycounter
return [list element [incr mycounter]]
}
# # ## ### ##### ######## ############# ######################
## Instance data, database tables as arrays, keyed by direction
## and alias names.
component dir ; # Database of named directions.
# Used to check for and resolve
# corner aliases.
variable mycounter 0 ; # Counter for the generation of
# element identifiers. See
# 'NewIdentifier' for the user.
variable myelement -array {} ; # Database of drawn elements. Maps
# from element identifiers to a
# dictionary holding the pertinent
# information (type, canvas items,
# sub elements, and corners (aka
# attributes).
variable myhistory -array {
{} {}
} ; # History database. Keyed by
# element type, they are mapped to
# lists of element identifiers
# naming the elements in order of
# creation. The empty key has the
# history without regard to type.
variable myshape -array {} ; # Database of element shapes.
##
# # ## ### ##### ######## ############# ######################
}
namespace eval ::diagram::element::geo {
namespace import ::math::geometry::*
}
# # ## ### ##### ######## ############# ######################
## Ready
package provide diagram::element 1

138
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/navigation.tcl

@ -0,0 +1,138 @@
## -*- tcl -*-
## (C) 2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
## BSD Licensed
# # ## ### ##### ######## ############# ######################
#
# Auto-layout management
#
##
# # ## ### ##### ######## ############# ######################
## Requisites
package require Tcl 8.5 ; # Want the nice things it
# brings (dicts, {*}, etc.)
package require snit ; # Object framework.
package require struct::stack
package require diagram::point
# # ## ### ##### ######## ############# ######################
## Implementation
snit::type ::diagram::navigation {
# # ## ### ##### ######## ############# ######################
## Public API :: Modify the state
method reset {} {
set mylocation {0 0}
set mydirection east
set mycorner west
set mycorners {}
$mystack clear
return
}
method turn {direction {commit 0}} {
#puts T|$direction|$commit
set mydirection [$mydirections validate $direction]
set mycorner [$mydirections get $mydirection opposite]
#puts O|$mycorner
if {$commit && [dict exists $mycorners $mydirection]} {
set mylocation \
[diagram::point unbox \
[diagram::point absolute \
[dict get $mycorners $mydirection]]]
}
return
}
method move {newcorners} {
#puts M|$newcorners
if {[dict exists $newcorners end]} {
set mycorners {}
set at [dict get $newcorners end]
} else {
# Note: We map mydirection to the corners to handle the
# possibility of directions which are not on the compass
# rose. Such are mapped to the nearest compass or other
# direction which is supported by the element we have
# moved to.
set mycorners $newcorners
set at [dict get $newcorners \
[$mydirections map $newcorners $mydirection]]
}
set mylocation \
[diagram::point unbox [diagram::point absolute $at]]
return
}
# # ## ### ##### ######## ############# ######################
## Public API :: State nesting
method save {} {
$mystack push [list \
$mylocation \
$mydirection \
$mycorner \
$mycorners]
return
}
method restore {} {
lassign [$mystack pop] \
mylocation \
mydirection \
mycorner \
mycorners
return
}
# # ## ### ##### ######## ############# ######################
## Public API :: Querying
method at {} {
# TODO :: gap processing goes here -- maybe not required, given 'chop'.
return $mylocation
}
method corner {} {
return $mycorner
}
method direction {} {
return $mydirection
}
# # ## ### ##### ######## ############# ######################
## Public API ::
constructor {directions} {
install mystack using struct::stack ${selfns}::STACK
set mydirections $directions
return
}
# # ## ### ##### ######## ############# ######################
## Instance data,
component mystack
component mydirections
variable mylocation {0 0} ; # attribute 'at' default
variable mydirection east ; # current layout direction.
variable mycorner west ; # attribute 'with' default
# (opposite of direction').
variable mycorners {} ; # The corners we can turn to.
##
# # ## ### ##### ######## ############# ######################
}
# # ## ### ##### ######## ############# ######################
## Ready
package provide diagram::navigation 1

15
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/pkgIndex.tcl

@ -0,0 +1,15 @@
if {![package vsatisfies [package provide Tcl] 8.5]} {
# PRAGMA: returnok
return
}
package ifneeded diagram::navigation 1 [list source [file join $dir navigation.tcl]]
package ifneeded diagram::direction 1 [list source [file join $dir direction.tcl]]
package ifneeded diagram::element 1 [list source [file join $dir element.tcl]]
package ifneeded diagram::attribute 1 [list source [file join $dir attributes.tcl]]
package ifneeded diagram::point 1 [list source [file join $dir point.tcl]]
package ifneeded diagram::core 1 [list source [file join $dir core.tcl]]
package ifneeded diagram::basic 1.0.1 [list source [file join $dir basic.tcl]]
package ifneeded diagram 1 [list source [file join $dir diagram.tcl]]
package ifneeded diagram::application 1.2 [list source [file join $dir application.tcl]]

184
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/diagrams/point.tcl

@ -0,0 +1,184 @@
## -*- tcl -*-
## (C) 2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
## BSD Licensed
# # ## ### ##### ######## ############# ######################
#
# diagram points.
#
# Type validation and implementation of the various operations on
# points and lines. The low-level commands for this come from
# math::geometry. The operations here additionally (un)box from/to
# tagged values. They also handle operations mixing polar and
# cartesian specifications.
#
##
# # ## ### ##### ######## ############# ######################
## Requisites
package require Tcl 8.5 ; # Want the nice things it
# brings (dicts, {*}, etc.)
package require math::geometry 1.1.2 ; # Vector math (points, line
# (segments), poly-lines).
namespace eval ::diagram::point {
namespace export is isa validate absolute at delta by unbox + - | resolve
namespace ensemble create
}
# # ## ### ##### ######## ############# ######################
## Implementation
# # ## ### ##### ######## ############# ######################
## Public API :: validation
proc ::diagram::point::validate {value} {
if {[is $value]} {return $value}
return -code error "Expected diagram::point, got \"$value\""
}
proc ::diagram::point::absolute {value} {
if {[isa $value]} {return $value}
return -code error "Expected absolute diagram::point, got \"$value\""
}
proc ::diagram::point::is {value} {
return [expr {([llength $value] == 2) &&
([lindex $value 0] in {point + by})}]
}
proc ::diagram::point::isa {value} {
# note overlap with constructor 'at'.
return [expr {([llength $value] == 2) ||
([lindex $value 0] eq "point")}]
}
# # ## ### ##### ######## ############# ######################
## Public API :: Constructors
# Absolute location
proc ::diagram::point::at {x y} {
return [list point [list $x $y]]
}
# Relative location, cartesian
proc ::diagram::point::delta {dx dy} {
return [list + [list $dx $dy]]
}
# Relative location, polar
proc ::diagram::point::by {distance angle} {
return [list by [list $distance $angle]]
}
# # ## ### ##### ######## ############# ######################
proc ::diagram::point::unbox {p} {
return [lindex $p 1]
}
# # ## ### ##### ######## ############# ######################
## Public API :: Point arithmetic
proc ::diagram::point::+ {a b} {
set a [2cartesian [validate $a]]
set b [2cartesian [validate $b]]
# Unboxing
lassign $a atag adetail
lassign $b btag bdetail
# Calculation and result type determination
set result [geo::+ $adetail $bdetail]
set rtype [expr {(($atag eq "point") || ($btag eq "point"))
? "at"
: "delta"}]
return [$rtype {*}$result]
}
proc ::diagram::point::- {a b} {
set a [2cartesian [validate $a]]
set b [2cartesian [validate $b]]
# Unboxing
lassign $a atag adetail
lassign $b btag bdetail
# Calculation and result type determination
set result [geo::- $adetail $bdetail]
set rtype [expr {(($atag eq "point") || ($btag eq "point"))
? "at"
: "delta"}]
return [$rtype {*}$result]
}
proc ::diagram::point::| {a b} {
set a [2cartesian [absolute $a]]
set b [2cartesian [absolute $b]]
# Unboxing
lassign $a atag adetail ; lassign $adetail ax ay
lassign $b btag bdetail ; lassign $bdetail bx by
# Calculation of the projection.
return [at $ax $by]
}
# # ## ### ##### ######## ############# ######################
proc ::diagram::point::resolve {base p} {
#puts P|resolve|$base|$p|
# The base is an untagged point, p is a tagged point or delta.
lassign $p tag detail
# A point is returned unchanged.
if {$tag eq "point"} { return [unbox $p] }
# A delta is normalized, then added to the base.
#puts R|$base|$p|
#puts R|[2cartesian $p]|
#puts R|[unbox [2cartesian $p]]|
return [geo::+ $base [unbox [2cartesian $p]]]
}
# # ## ### ##### ######## ############# ######################
# Normalize point/delta information to cartesian
# coordinates. Input and output are both tagged, and points not
# using a polar representation are not modified.
proc ::diagram::point::2cartesian {p} {
lassign $p tag details
if {$tag ne "by"} { return $p }
return [delta {*}[polar2cartesian $details]]
}
# Conversion of a delta from polar to cartesian coordinates,
# operating on untagged data.
proc ::diagram::point::polar2cartesian {polar} {
lassign $polar distance angle
return [geo::s* $distance [geo::direction $angle]]
}
##
# # ## ### ##### ######## ############# ######################
# # ## ### ##### ######## ############# ######################
## Ready
namespace eval ::diagram::point::geo {
namespace import ::math::geometry::*
}
package provide diagram::point 1

13
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/getstring/pkgIndex.tcl

@ -0,0 +1,13 @@
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script. It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands. When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.
if { ![package vsatisfies [package provide Tcl] 8.4] } { return }
package ifneeded getstring 0.1 [list source [file join $dir tk_getString.tcl]]

124
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/getstring/tk_getString.tcl

@ -0,0 +1,124 @@
# tk_getString.tcl --
#
# A dialog which prompts for a string input
#
# Copyright (c) 2005 Aaron Faupell <afaupell@users.sourceforge.net>
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: tk_getString.tcl,v 1.11 2005/04/13 01:29:22 andreas_kupries Exp $
package require Tk
package provide getstring 0.1
namespace eval ::getstring {
namespace export tk_getString
}
if {[tk windowingsystem] == "win32"} {
option add *TkSDialog*Button.width -8 widgetDefault
option add *TkSDialog*Button.padX 1m widgetDefault
} else {
option add *TkSDialog.borderWidth 1 widgetDefault
option add *TkSDialog*Button.width 5 widgetDefault
}
option add *TkSDialog*Entry.width 20 widgetDefault
proc ::getstring::tk_getString {w var text args} {
array set options {
-allowempty 0
-entryoptions {}
-title "Enter Information"
}
parseOpts options {{-allowempty boolean} {-entryoptions {}} {-geometry {}} \
{-title {}}} $args
variable ::getstring::result
upvar $var result
catch {destroy $w}
set focus [focus]
set grab [grab current .]
toplevel $w -relief raised -class TkSDialog
wm title $w $options(-title)
wm iconname $w $options(-title)
wm protocol $w WM_DELETE_WINDOW {set ::getstring::result 0}
wm transient $w [winfo toplevel [winfo parent $w]]
wm resizable $w 1 0
eval [list entry $w.entry] $options(-entryoptions)
button $w.ok -text OK -default active -command {set ::getstring::result 1}
button $w.cancel -text Cancel -command {set ::getstring::result 0}
label $w.label -text $text
grid $w.label -columnspan 2 -sticky ew -padx 5 -pady 3
grid $w.entry -columnspan 2 -sticky ew -padx 5 -pady 3
grid $w.ok $w.cancel -padx 4 -pady 7
grid rowconfigure $w 2 -weight 1
grid columnconfigure $w {0 1} -uniform 1 -weight 1
bind $w <Return> [list $w.ok invoke]
bind $w <Escape> [list $w.cancel invoke]
bind $w <Destroy> {set ::getstring::result 0}
if {!$options(-allowempty)} {
bind $w.entry <KeyPress> [list after idle [list ::getstring::getStringEnable $w]]
$w.ok configure -state disabled
}
wm withdraw $w
update idletasks
focus -force $w.entry
if {[info exists options(-geometry)]} {
wm geometry $w $options(-geometry)
} elseif {[winfo parent $w] == "."} {
set x [expr {[winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 - [winfo vrootx $w]}]
set y [expr {[winfo screenheight $w]/2 - [winfo reqheight $w]/2 - [winfo vrooty $w]}]
wm geom $w +$x+$y
} else {
set t [winfo toplevel [winfo parent $w]]
set x [expr {[winfo width $t]/2 - [winfo reqwidth $w]/2 - [winfo vrootx $w]}]
set y [expr {[winfo height $t]/2 - [winfo reqheight $w]/2 - [winfo vrooty $w]}]
wm geom $w +$x+$y
}
wm deiconify $w
grab $w
tkwait variable ::getstring::result
set result [$w.entry get]
bind $w <Destroy> {}
grab release $w
destroy $w
focus -force $focus
if {$grab != ""} {grab $grab}
update idletasks
return $::getstring::result
}
proc ::getstring::parseOpts {var opts input} {
upvar $var output
for {set i 0} {$i < [llength $input]} {incr i} {
for {set a 0} {$a < [llength $opts]} {incr a} {
if {[lindex $opts $a 0] == [lindex $input $i]} { break }
}
if {$a == [llength $opts]} { error "unknown option [lindex $input $i]" }
set opt [lindex $opts $a]
if {[llength $opt] > 1} {
foreach {opt type} $opt {break}
if {[incr i] >= [llength $input]} { error "$opt requires an argument" }
if {$type != "" && ![string is $type -strict [lindex $input $i]]} { error "$opt requires argument of type $type" }
set output($opt) [lindex $input $i]
} else {
set output($opt) {}
}
}
}
proc ::getstring::getStringEnable {w} {
if {![winfo exists $w.entry]} { return }
if {[$w.entry get] != ""} {
$w.ok configure -state normal
} else {
$w.ok configure -state disabled
}
}

113
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/history/history.tcl

@ -0,0 +1,113 @@
# history.tcl --
#
# Provides a history mechanism for entry widgets
#
# Copyright (c) 2005 Aaron Faupell <afaupell@users.sourceforge.net>
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: history.tcl,v 1.4 2005/08/25 03:36:58 andreas_kupries Exp $
package require Tk
package provide history 0.1
namespace eval history {
bind History <Up> {::history::up %W}
bind History <Down> {::history::down %W}
}
proc ::history::init {w {len 30}} {
variable history
variable prefs
set bt [bindtags $w]
if {[lsearch $bt History] > -1} { error "$w already has a history" }
if {[set i [lsearch $bt $w]] < 0} { error "cant find $w in bindtags" }
bindtags $w [linsert $bt [expr {$i + 1}] History]
array set history [list $w,list {} $w,cur -1]
set prefs(maxlen,$w) $len
return $w
}
proc ::history::remove {w} {
variable history
variable prefs
set bt [bindtags $w]
if {[set i [lsearch $bt History]] < 0} { error "$w has no history" }
bindtags $w [lreplace $bt $i $i]
unset prefs(maxlen,$w) history($w,list) history($w,cur)
}
proc ::history::add {w line} {
variable history
variable prefs
if {$history($w,cur) > -1 && [lindex $history($w,list) $history($w,cur)] == $line} {
set history($w,list) [lreplace $history($w,list) $history($w,cur) $history($w,cur)]
}
set history($w,list) [linsert $history($w,list) 0 $line]
set history($w,list) [lrange $history($w,list) 0 $prefs(maxlen,$w)]
set history($w,cur) -1
}
proc ::history::up {w} {
variable history
if {[lindex $history($w,list) [expr {$history($w,cur) + 1}]] != ""} {
if {$history($w,cur) == -1} {
set history($w,tmp) [$w get]
}
$w delete 0 end
incr history($w,cur)
$w insert end [lindex $history($w,list) $history($w,cur)]
} else {
alert $w
}
}
proc ::history::down {w} {
variable history
if {$history($w,cur) != -1} {
$w delete 0 end
if {$history($w,cur) == 0} {
$w insert end $history($w,tmp)
set history($w,cur) -1
} else {
incr history($w,cur) -1
$w insert end [lindex $history($w,list) $history($w,cur)]
}
} else {
alert $w
}
}
proc ::history::get {w} {
variable history
return $history($w,list)
}
proc ::history::clear {w} {
variable history
set history($w,cur) -1
set history($w,list) {}
unset -nocomplain history($w,tmp)
}
proc ::history::configure {w option {value {}}} {
variable history
variable prefs
switch -exact -- $option {
length {
if {$value == ""} { return $prefs(maxlen,$w) }
if {![string is integer -strict $value]} { error "length must be an integer" }
set prefs(maxlen,$w) $value
}
alert {
if {$value == ""} { return [info body ::history::alert] }
proc ::history::alert w $value
}
default {
error "unknown option $option"
}
}
}
proc ::history::alert {w} {bell}

13
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/history/pkgIndex.tcl

@ -0,0 +1,13 @@
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script. It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands. When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.
if { ![package vsatisfies [package provide Tcl] 8.4] } { return }
package ifneeded history 0.1 [list source [file join $dir history.tcl]]

1467
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ico/ico.tcl

File diff suppressed because it is too large Load Diff

1193
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ico/ico0.tcl

File diff suppressed because it is too large Load Diff

9
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ico/pkgIndex.tcl

@ -0,0 +1,9 @@
# pkgIndex.tcl --
#
# Copyright (c) 2003 ActiveState Corporation.
# All rights reserved.
#
# RCS: @(#) $Id: pkgIndex.tcl,v 1.11 2011/10/05 00:10:46 hobbs Exp $
package ifneeded ico 0.3.2 [list source [file join $dir ico0.tcl]]
package ifneeded ico 1.1 [list source [file join $dir ico.tcl]]

975
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ipentry/ipentry.tcl

@ -0,0 +1,975 @@
# ipentry.tcl --
#
# An entry widget for IP addresses.
#
# Copyright (c) 2003-2008 Aaron Faupell <afaupell@users.sourceforge.net>
# Copyright (c) 2008 Pat Thoyts <patthoyts@users.sourceforge.net>
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: ipentry.tcl,v 1.19 2009/01/21 07:10:03 afaupell Exp $
package require Tk
package provide ipentry 0.3
namespace eval ::ipentry {
namespace export ipentry ipentry6
# copy all the bindings from Entry class to our own IPEntrybindtag class
foreach x [bind Entry] {
bind IPEntrybindtag $x [bind Entry $x]
}
# then replace certain keys we are interested in with our own
bind IPEntrybindtag <KeyPress> {::ipentry::keypress %W %K}
bind IPEntrybindtag <BackSpace> {::ipentry::backspace %W}
bind IPEntrybindtag <period> {::ipentry::dot %W}
bind IPEntrybindtag <Key-Right> {::ipentry::arrow %W %K}
bind IPEntrybindtag <Key-Left> {::ipentry::arrow %W %K}
bind IPEntrybindtag <FocusIn> {::ipentry::FocusIn %W}
bind IPEntrybindtag <FocusOut> {::ipentry::FocusOut %W}
bind IPEntrybindtag <<Paste>> {::ipentry::Paste %W CLIPBOARD}
bind IPEntrybindtag <<PasteSelection>> {::ipentry::Paste %W PRIMARY}
# copy all the bindings from IPEntrybindtag
foreach x [bind IPEntrybindtag] {
bind IPEntrybindtag6 $x [bind IPEntrybindtag $x]
}
# and replace certain keys with ip6 bindings
bind IPEntrybindtag6 <KeyPress> {::ipentry::keypress %W %K 6}
bind IPEntrybindtag6 <colon> {::ipentry::dot %W}
bind IPEntrybindtag6 <period> {}
#if {[package vsatisfies [package provide Tk] 8.5]} {
# ttk::style layout IPEntryFrame {
# Entry.field -sticky news -border 1 -children {
# IPEntryFrame.padding -sticky news
# }
# }
# bind [winfo class .] <<ThemeChanged>> \
# [list +ttk::style layout IPEntryFrame \
# [ttk::style layout IPEntryFrame]]
# }
}
# ipentry --
#
# main entry point - construct a new ipentry widget
#
# ARGS:
# w path name of widget to create
#
# see ::ipentry::configure for args
#
# RETURNS:
# the widget path name
#
proc ::ipentry::ipentry {w args} {
upvar #0 [namespace current]::widget_$w state
#set state(themed) [package vsatisfies [package provide Tk] 8.5]
set state(themed) 0
foreach {name val} $args {
if {$name eq "-themed"} {
set state(themed) $val
}
}
if {$state(themed)} {
ttk::frame $w -style IPEntryFrame -class IPEntry -takefocus 0
} else {
frame $w -relief sunken -class IPEntry;#-padx 5
}
foreach x {0 1 2 3} y {d1 d2 d3 d4} {
#if {$state(themed)} {
# ttk::entry $w.$x -width 3 -justify center
# ttk::label $w.$y -text .
#}
entry $w.$x -borderwidth 0 -width 3 -highlightthickness 0 \
-justify center -takefocus 0
label $w.$y -borderwidth 0 -font [$w.$x cget -font] -width 1 -text . \
-justify center -cursor [$w.$x cget -cursor] \
-background [$w.$x cget -background] \
-disabledforeground [$w.$x cget -disabledforeground]
pack $w.$x $w.$y -side left
bindtags $w.$x [list $w.$x IPEntrybindtag . all]
bind $w.$y <Button-1> {::ipentry::dotclick %W %x}
}
destroy $w.d4
$w.0 configure -takefocus 1
if {$state(themed)} {
pack configure $w.0 -padx {1 0} -pady 1
pack configure $w.3 -padx {0 1} -pady 1 -fill x -expand 1
$w.3 configure -justify left
} else {
$w configure -borderwidth [lindex [$w.0 configure -bd] 3]
#-background [$w.0 cget -bg]
}
rename ::$w ::ipentry::_$w
# redirect the widget name command to the widgetCommand dispatcher
interp alias {} ::$w {} ::ipentry::widgetCommand $w
bind $w <Destroy> [list ::ipentry::destroyWidget $w]
if {[llength $args] > 0} {
eval [list $w configure] $args
}
return $w
}
# ipentry --
#
# main entry point - construct a new ipentry6 widget
#
# ARGS:
# w path name of widget to create
#
# see ::ipentry::configure for args
#
# RETURNS:
# the widget path name
#
proc ::ipentry::ipentry6 {w args} {
upvar #0 [namespace current]::widget_$w state
#set state(themed) [package vsatisfies [package provide Tk] 8.5]
set state(themed) 0
foreach {name val} $args {
if {$name eq "-themed"} {
set state(themed) $val
}
}
if {$state(themed)} {
ttk::frame $w -style IPEntryFrame -class IPEntry -takefocus 0
} else {
frame $w -relief sunken -class IPEntry;#-padx 5
}
foreach x {0 1 2 3 4 5 6 7} y {d1 d2 d3 d4 d5 d6 d7 d8} {
entry $w.$x -borderwidth 0 -width 4 -highlightthickness 0 \
-justify center -takefocus 0
label $w.$y -borderwidth 0 -font [$w.$x cget -font] -width 1 -text : \
-justify center -cursor [$w.$x cget -cursor] \
-background [$w.$x cget -background] \
-disabledforeground [$w.$x cget -disabledforeground]
pack $w.$x $w.$y -side left
bindtags $w.$x [list $w.$x IPEntrybindtag6 . all]
bind $w.$y <Button-1> {::ipentry::dotclick %W %x}
}
destroy $w.d8
$w.0 configure -takefocus 1
if {$state(themed)} {
pack configure $w.0 -padx {1 0} -pady 1
pack configure $w.7 -padx {0 1} -pady 1 -fill x -expand 1
$w.7 configure -justify left
} else {
$w configure -borderwidth [lindex [$w.0 configure -bd] 3]
#-background [$w.0 cget -bg]
}
rename ::$w ::ipentry::_$w
# redirect the widget name command to the widgetCommand dispatcher
interp alias {} ::$w {} ::ipentry::widgetCommand6 $w
bind $w <Destroy> [list ::ipentry::destroyWidget $w]
if {[llength $args] > 0} {
eval [list $w configure] $args
}
return $w
}
# keypress --
#
# called every time a key is pressed in an ipentry widget
# used by both ipentry and ipentry6
#
# ARGS:
# w window argument (%W) from the event binding
# key the keysym (%K) from the event
# type empty string or "6" depending on the type of ipentry
#
# RETURNS:
# nothing
#
proc ::ipentry::keypress {w key {type {}}} {
if {![validate$type $w $key]} { return }
# sel.first and sel.last throw an error if the selection isnt in $w
catch {
set insert [$w index insert]
# if a key is pressed while there is a selection then delete the
# selected chars
if {([$w index sel.first] <= $insert) && ([$w index sel.last] >= $insert)} {
$w delete sel.first sel.last
}
}
$w insert insert $key
::ipentry::updateTextvar $w
}
# backspace --
#
# called when the Backspace key is pressed in an ipentry widget
# used by both ipentry and ipentry6
#
# try to act like a normal backspace except if the cursor is at index 0
# of one entry we need to move to the end of the preceding entry
#
# ARGS:
# w window argument (%W) from the event binding
#
# RETURNS:
# nothing
#
proc ::ipentry::backspace {w} {
if {[$w selection present]} {
$w delete sel.first sel.last
} else {
if {[$w index insert] == 0} {
set w [skip $w prev]
}
$w delete [expr {[$w index insert] - 1}]
}
::ipentry::updateTextvar $w
}
# dot --
#
# called when the dot (Period) key is pressed in an ipentry widget
# used by both ipentry and ipentry6
#
# treat the current entry as done and move to the next entry field
#
# ARGS:
# w window argument (%W) from the event binding
#
# RETURNS:
# nothing
#
proc ::ipentry::dot {w} {
if {[string length [$w get]] > 0} {
skip $w next 1
}
::ipentry::updateTextvar $w
}
# FocusIn --
#
# called when the focus enters any of the child widgets of an ipentry
# used by both ipentry and ipentry6
#
# clear the selection of all child widgets other than the one with focus
#
# ARGS:
# w window argument (%W) from the event binding
#
# RETURNS:
# nothing
#
proc ::ipentry::FocusIn {w} {
set p [winfo parent $w]
foreach x {0 1 2 3 4 5 6 7} {
if {![winfo exists $p.$x]} { break }
if {"$p.$x" != $w} {
$p.$x selection clear
}
}
}
# FocusOut --
#
# called when the focus leaves any of the child widgets of an ipentry
# used by both ipentry and ipentry6
#
# dont allow a 0 in the first quad
#
# ARGS:
# w window argument (%W) from the event binding
#
# RETURNS:
# nothing
#
proc ::ipentry::FocusOut {w} {
set s [$w get]
if {[string match {*.0} $w] && $s != "" && $s < 1} {
$w delete 0 end
$w insert end 1
::ipentry::updateTextvar $w
}
# trim off leading zeros
if {[string length $s] > 1} {
set n [string trimleft $s 0]
if {$n eq ""} { set n 0 }
if {![string equal $n $s]} {
$w delete 0 end
$w insert end $n
}
}
}
# Paste --
#
# called from the <<Paste>> virtual event
# used by ipentry only
#
# clear the selection of all child widgets other than the one with focus
#
# ARGS:
# w window argument (%W) from the event binding
# sel one of CLIPBOARD or PRIMARY
#
# RETURNS:
# nothing
#
proc ::ipentry::Paste {w sel} {
if {[catch {::tk::GetSelection $w $sel} paste]} { return }
$w delete 0 end
foreach char [split $paste {}] {
# ignore everything except dots and digits
if {![string match {[0123456789.]} $char]} { continue }
if {$char != "."} {
$w insert end $char
}
# if value is over 255 truncate it
if {[$w get] > 255} {
$w delete 0 end
$w insert 0 255
}
# if char is a . then get the index of the current entry
# and update $w to point to the next entry
if {$char == "."} {
set n [string index $w end]
if { $n >= 3 } { return }
set w [string trimright $w "0123"][expr {$n + 1}]
$w delete 0 end
continue
}
}
::ipentry::updateTextvar $w
}
# Paste6 --
#
# called from the <<Paste>> virtual event
# used by both ipentry6 only
#
# clear the selection of all child widgets other than the one with focus
#
# ARGS:
# w window argument (%W) from the event binding
# sel one of CLIPBOARD or PRIMARY
#
# RETURNS:
# nothing
#
proc ::ipentry::Paste6 {w sel} {
if {[catch {::tk::GetSelection $w $sel} paste]} { return }
$w delete 0 end
foreach char [split $paste {}] {
# ignore everything except colons and hex digits
if {![string match {[0123456789abcdefABCDEF:]} $char]} { continue }
if {$char != ":"} {
$w insert end $char
}
# if char is a : then get the index of the current entry
# and update $w to point to the next entry
if {$char == ":"} {
set n [string index $w end]
if { $n >= 7 } { return }
set w [string trimright $w "01234567"][expr {$n + 1}]
$w delete 0 end
continue
}
}
::ipentry::updateTextvar $w
}
# dotclick --
#
# called when mouse button 1 is clicked on any of the label widgets
# used by both ipentry and ipentry6
#
# decide which side of the dot was clicked and put the focus and cursor
# in the correct entry
#
# ARGS:
# w window argument (%W) from the event binding
#
# RETURNS:
# nothing
#
proc ::ipentry::dotclick {w x} {
if {$x > ([winfo width $w] / 2)} {
set w [winfo parent $w].[string index $w end]
focus $w
$w icursor 0
} else {
set w [winfo parent $w].[expr {[string index $w end] - 1}]
focus $w
$w icursor end
}
}
# arrow --
#
# called when the left or right arrow keys are pressed in an ipentry
# used by both ipentry and ipentry6
#
# ARGS:
# w window argument (%W) from the event binding
# key one of Left or Right
#
# RETURNS:
# nothing
#
proc ::ipentry::arrow {w key} {
set i [$w index insert]
set l [string length [$w get]]
# move the icursor +1 or -1 position
$w icursor [expr $i [string map {Right + Left -} $key] 1]
$w selection clear
# if we are moving right and the cursor is at the end, or the entry is empty
if {$key == "Right" && ($i == $l || $l == 0)} {
skip $w next
} elseif {$key == "Left" && $i == 0} {
skip $w prev
}
}
# validate --
#
# called by keypress to validate the input
# used by ipentry only
#
# ARGS:
# w window argument (%W) from the event binding
# key the key pressed
#
# RETURNS:
# a boolean indicating if the key is valid or not
#
proc ::ipentry::validate {w key} {
if {![string match {[0123456789]} $key]} { return 0 }
set curval [$w get]
set insert [$w index insert]
# dont allow more than a single 0 to be entered
if {$curval == "0" && $key == "0"} { return 0 }
if {[string length $curval] == 2} {
set curval [join [linsert [split $curval {}] $insert $key] {}]
if {$curval > 255} {
$w delete 0 end
$w insert 0 255
$w selection range 0 end
::ipentry::updateTextvar $w
return 0
} elseif {$insert == 2} {
skip $w next 1
}
return 1
}
if {[string length $curval] >= 3 && ![$w selection present]} {
if {$insert == 3} { skip $w next 1 }
return 0
}
return 1
}
# validate6 --
#
# called by keypress to validate the input
# used by ipentry6 only
#
# ARGS:
# w window argument (%W) from the event binding
# key the key pressed
#
# RETURNS:
# a boolean indicating if the key is valid or not
#
proc ::ipentry::validate6 {w key} {
if {![string is xdigit $key]} { return 0 }
set curval 0x[$w get]
set insert [$w index insert]
# dont allow more than a single 0 to be entered
if {$curval == "0" && $key == "0"} { return 0 }
if {[string length $curval] == 5} {
set curval [join [linsert [split $curval {}] $insert $key] {}]
if {$insert == 3} {
skip $w next 1
}
return 1
}
if {[string length $curval] >= 6 && ![$w selection present]} {
if {$insert == 4} { skip $w next 1 }
return 0
}
return 1
}
# skip --
#
# move the cursor to the previous or next entry widget
# used by both ipentry and ipentry6
#
# ARGS:
# w name of the current entry widget
# dir direction to move, one of next or prev
# sel boolean indicating whether to select the digits in the next entry
#
# RETURNS:
# the name of the widget with focus
#
proc ::ipentry::skip {w dir {sel 0}} {
set n [string index $w end]
if {$dir == "next"} {
set next [string trimright $w "012345678"][expr {$n + 1}]
if { ![winfo exists $next] } { return $w }
focus $next
if {$sel} {
$next icursor 0
$next selection range 0 end
}
return $next
} else {
if { $n <= 0 } { return $w }
set prev [string trimright $w "012345678"][expr {$n - 1}]
focus $prev
$prev icursor end
return $prev
}
}
# _foreach --
#
# utility for the widget configure command
#
# perform a command on every subwidget of an ipentry frame
#
# ARGS:
# w name of the ipentry frame
# cmd command to perform
# type one of empty, "entry", or "dot"
#
# RETURNS:
# nothing
#
proc ::ipentry::_foreach {w cmd {type {}}} {
if {$type == "" || $type == "entry"} {
foreach x {0 1 2 3 4 5 6 7} {
if {![winfo exists $w.$x]} { break }
eval [list $w.$x] $cmd
}
}
if {$type == "" || $type == "dot"} {
foreach x {d1 d2 d3 d4 d5 d6 d7} {
if {![winfo exists $w.$x]} { break }
eval [list $w.$x] $cmd
}
}
}
# cget --
#
# handle the widgetName cget subcommand
# used by both ipentry and ipentry6
#
# ARGS:
# w name of the ipentry widget
# cmd name of a configuration option
#
# RETURNS:
# the value of the requested option
#
proc ::ipentry::cget {w cmd} {
upvar #0 [namespace current]::widget_$w state
switch -exact -- $cmd {
-bd -
-borderwidth -
-relief {
# for bd and relief return the value from the container frame
if {!$state(themed)} {
return [::ipentry::_$w cget $cmd]
}
}
-textvariable {
if {[info exists ::ipentry::textvars($w)]} {
return $::ipentry::textvars($w)
}
return {}
}
-themed { return $state(themed) }
-takefocus { return 0 }
default {
# for all other commands return the value from the first entry
return [$w.0 cget $cmd]
}
}
}
# configure --
#
# handle the widgetName configure subcommand
# used by both ipentry and ipentry6
#
# ARGS:
# w name of the ipentry widget
# args name/value pairs of configuration options
#
# RETURNS:
# nothing
#
proc ::ipentry::configure {w args} {
upvar #0 [namespace current]::widget_$w Priv
while {[set cmd [lindex $args 0]] != ""} {
switch -exact -- $cmd {
-state {
set state [lindex $args 1]
if {$state == "disabled"} {
_foreach $w [list configure -state disabled]
if {[set dbg [$w.0 cget -disabledbackground]] == ""} {
set dbg [$w.0 cget -bg]
}
_foreach $w [list configure -bg $dbg] dot
if {$Priv(themed)} {
::ipentry::_$w state disabled
} else {
::ipentry::_$w configure -background $dbg
}
} elseif {$state == "normal"} {
_foreach $w [list configure -state normal]
_foreach $w [list configure -bg [$w.0 cget -bg]] dot
if {$Priv(themed)} {
::ipentry::_$w state {!readonly !disabled}
} else {
::ipentry::_$w configure -background [$w.0 cget -bg]
}
} elseif {$state == "readonly"} {
_foreach $w [list configure -state readonly] entry
if {[set robg [$w.0 cget -readonlybackground]] == ""} {
set robg [$w.0 cget -bg]
}
_foreach $w [list configure -bg $robg] dot
if {$Priv(themed)} {
::ipentry::_$w state !readonly
} else {
::ipentry::_$w configure -background $robg
}
}
set args [lrange $args 2 end]
}
-bg - -background {
set bg [lindex $args 1]
_foreach $w [list configure -background $bg]
if {!$Priv(themed)} {
::ipentry::_$w configure -background $bg
}
set args [lrange $args 2 end]
}
-disabledforeground {
_foreach $w [list configure -disabledforeground [lindex $args 1]]
set args [lrange $args 2 end]
}
-font -
-fg - -foreground {
_foreach $w [list configure $cmd [lindex $args 1]]
set args [lrange $args 2 end]
}
-bd - -borderwidth -
-relief -
-highlightcolor -
-highlightbackground -
-highlightthickness {
_$w configure $cmd [lindex $args 1]
set args [lrange $args 2 end]
}
-readonlybackground -
-disabledbackground -
-selectforeground -
-selectbackground -
-selectborderwidth -
-insertbackground {
_foreach $w [list configure $cmd [lindex $args 1]] entry
set args [lrange $args 2 end]
}
-themed {
# ignored - only used in widget creation
}
-textvariable {
set name [lindex $args 1]
upvar #0 $name var
#if {![string match ::* $name]} { set name ::$name }
if {[info exists ::ipentry::textvars($w)]} {
set trace [trace info variable var]
trace remove variable var [lindex $trace 0 0] [lindex $trace 0 1]
}
set ::ipentry::textvars($w) $name
if {![info exists var]} { set var "" }
::ipentry::traceFired $w $name {} write
if {[winfo exists $w.4]} {
trace add variable var {write unset} [list ::ipentry::traceFired6 $w]
} else {
trace add variable var {write unset} [list ::ipentry::traceFired $w]
}
set args [lrange $args 2 end]
}
default {
error "unknown option \"[lindex $args 0]\""
}
}
}
}
# destroyWidget --
#
# bound to the <Destroy> event
# used by both ipentry and ipentry6
#
# ARGS:
# w name of the ipentry widget
#
# RETURNS:
# nothing
#
proc ::ipentry::destroyWidget {w} {
upvar #0 [namespace current]::widget_$w state
if {[info exists ::ipentry::textvars($w)]} {
upvar #0 $::ipentry::textvars($w) var
set trace [trace info variable var]
trace remove variable var [lindex $trace 0 0] [lindex $trace 0 1]
}
rename $w {}
unset state
}
# traceFired --
#
# called by the variable trace on the ipentry textvariable
# used by ipentry only
#
# ARGS:
# w name of the ipentry widget
# varname name of the variable being traced
# key array index of the variable
# op operation performed on the variable, read/write/unset
#
# RETURNS:
# nothing
#
proc ::ipentry::traceFired {w name key op} {
upvar #0 $name var
if {[info level] > 1} {
set caller [lindex [info level -1] 0]
if {$caller == "::ipentry::updateTextvar" || $caller == "::ipentry::traceFired"} { return }
}
if {$op == "write"} {
_insert $w [split $var .]
set val [string trim [join [$w get] .] .]
# allow a dot at the end, but only if we have less than 3 already
if {[string index $var end] == "." && [regexp -all {\.+} $var] <= 3} { append val . }
if {$val eq $var} return
after 0 [list set $name $val]
set var $val
} elseif {$op == "unset"} {
::ipentry::updateTextvar $w.0
trace add variable var {write unset} [list ipentry::traceFired $w]
}
}
# traceFired6 --
#
# called by the variable trace on the ipentry textvariable
# used by ipentry6 only
#
# ARGS:
# w name of the ipentry widget
# varname name of the variable being traced
# key array index of the variable
# op operation performed on the variable, read/write/unset
#
# RETURNS:
# nothing
#
proc ::ipentry::traceFired6 {w name key op} {
upvar #0 $name var
if {[info level] > 1} {
set caller [lindex [info level -1] 0]
if {$caller == "::ipentry::updateTextvar" || $caller == "::ipentry::traceFired6"} { return }
}
if {$op == "write"} {
_insert6 $w [split $var :]
set val [string trim [join [$w get] :] :]
# allow a dot at the end, but only if we have less than 3 already
if {[string index $var end] == ":" && [regexp -all {\:+} $var] <= 7} { append val : }
if {$val eq $var} return
after 0 [list set $name $val]
set var $val
} elseif {$op == "unset"} {
::ipentry::updateTextvar $w.0
trace add variable var {write unset} [list ipentry::traceFired6 $w]
}
}
# updateTextvar --
#
# called by all procs which change the value of the ipentry
# used by both ipentry and ipentry6
#
# update the textvariable if it exists with the new value
#
# ARGS:
# w name of the ipentry widget
#
# RETURNS:
# nothing
#
proc ::ipentry::updateTextvar {w} {
set p [winfo parent $w]
if {![info exists ::ipentry::textvars($p)]} { return }
set c [$p.d1 cget -text]
set val [string trim [join [$p get] $c] $c]
upvar #0 $::ipentry::textvars($p) var
if {[info exists var] && $var == $val} { return }
set var $val
}
# _insert --
#
# called by the variable trace on the ipentry textvariable and widget insert cmd
# used by ipentry only
#
# ARGS:
# w name of an ipentry widget
# val a list of 4 values to be inserted into the ipentry
#
# RETURNS:
# nothing
#
proc ::ipentry::_insert {w val} {
foreach x {0 1 2 3} {
set n [lindex $val $x]
if {$n != ""} {
if {![string is integer -strict $n]} {
#error "cannot insert non-numeric arguments"
return
}
if {$n > 255} { set n 255 }
if {$n <= 0} { set n 0 }
if {$x == 0 && $n < 1} { set n 1 }
}
$w.$x delete 0 end
$w.$x insert 0 $n
}
}
# _insert6 --
#
# called by the variable trace on the ipentry textvariable and widget insert cmd
# used by both ipentry6 only
#
# ARGS:
# w name of an ipentry widget
# val a list of 8 values to be inserted into the ipentry
#
# RETURNS:
# nothing
#
proc ::ipentry::_insert6 {w val} {
foreach x {0 1 2 3 4 5 6 7} {
set n [lindex $val $x]
if {![string is xdigit $n]} {
#error "cannot insert non-hex arguments"
return
}
if {$n != "" } {
if "$x == 0 && 0x$n < 1" { set n 1 }
if "0x$n > 0xffff" { set n ffff }
}
$w.$x delete 0 end
$w.$x insert 0 $n
}
}
# widgetCommand --
#
# handle the widgetName command
# used by ipentry, with some commands passed through from widgetCommand6
#
# ARGS:
# w name of the ipentry widget
# cmd the subcommand
# args arguments to the subcommand
#
# RETURNS:
# the results of the invoked subcommand
#
proc ::ipentry::widgetCommand {w cmd args} {
upvar #0 [namespace current]::widget_$w state
switch -exact -- $cmd {
get {
# return the 4 entry values as a list
foreach x {0 1 2 3 4 5 6 7} {
if {![winfo exists $w.$x]} { break }
set s [$w.$x get]
if {[string length $s] > 1} {
set s [string trimleft $s 0]
if {$s == ""} { set s 0 }
}
lappend r $s
}
return $r
}
insert {
_insert $w [join $args]
::ipentry::updateTextvar $w.3
}
icursor {
if {![string match $w.* [focus]]} { return }
set i [lindex $args 0]
if {![string is integer -strict $i]} { error "argument must be an integer" }
set s [expr {$i / 4}]
focus $w.$s
$w.$s icursor [expr {$i % 4}]
}
complete {
foreach x {0 1 2 3 4 5 6 7} {
if {![winfo exists $w.$x]} { break }
if {[$w.$x get] == ""} { return 0 }
}
return 1
}
configure {
eval [list ::ipentry::configure $w] $args
}
cget {
return [::ipentry::cget $w [lindex $args 0]]
}
default {
error "bad option \"$cmd\": must be get, insert, complete, cget, or configure"
}
}
}
# widgetCommand6 --
#
# handle the widgetName command for ipentry6 widgets
# most subcommands are passed through to widgetCommand by the default case
#
# ARGS:
# w name of the ipentry widget
# cmd the subcommand
# args arguments to the subcommand
#
# RETURNS:
# the results of the invoked subcommand
#
proc ::ipentry::widgetCommand6 {w cmd args} {
upvar #0 [namespace current]::widget_$w state
switch -exact -- $cmd {
insert {
_insert6 $w [join $args]
::ipentry::updateTextvar $w.7
}
icursor {
if {![string match $w.* [focus]]} { return }
set i [lindex $args 0]
if {![string is integer -strict $i]} { error "argument must be am integer" }
set s [expr {$i / 8}]
focus $w.$s
$w.$s icursor [expr {$i % 8}]
}
default {
return [eval [list ::ipentry::widgetCommand $w $cmd] $args]
}
}
}

3
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/ipentry/pkgIndex.tcl

@ -0,0 +1,3 @@
if { ![package vsatisfies [package provide Tcl] 8.4] } { return }
package ifneeded ipentry 0.3 [list source [file join $dir ipentry.tcl]]

74
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/ROOT.msg

@ -0,0 +1,74 @@
# ROOT.msg --
#
# Default English-language messages for KHIM
#
# Copyright (c) 2006 by Kevin B. Kenny. All rights reserved.
#
# Refer to the file "license.terms" for the terms and conditions of
# use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES.
#
# $Id: ROOT.msg,v 1.2 2006/09/05 18:52:22 kennykb Exp $
# $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/ROOT.msg,v $
#
#----------------------------------------------------------------------
# Make sure that help text is available in the root locale.
namespace eval ::khim {
# If you edit this file, also edit the corresponding text in en.msg,
# which is provided for 8.4 compatibility.
::msgcat::mcset {} HELPTEXT {
Kevin's Hacky Input Method (KHIM)
KHIM allows you to input international characters from a
keyboard that doesn't support them. It works independently of
any input method that the operating system may supply; it is
intended for when you don't have control over your keyboard
mapping and still need to input text in other languages.
To use KHIM, bring up the KHIM Controls (the way this is done
depends on your application) and enable KHIM by checking "Use
KHIM". You also need to choose a key on your keyboard that is
seldom used, and designate it as the "Compose" key by pressing
the button labelled, "Compose key:" then striking the key you
wish to designate. Generally speaking, this key should not be
the key designated as "Compose" on the keyboard; that key will
continue to invoke whatever input method the local operating
system supplies.
Once KHIM is enabled, you can enter international characters
in any widget that is configured to use KHIM by pressing the
Compose key followed by a two-character sequence. The listbox
in the KHIM controls shows the available sequences. In
addition, if you strike the Compose key twice, you get a
dialog that allows you to input arbitrary symbols from a
Unicode character map. In the map, you can navigate among the
characters using either the cursor keys or the mouse, and you
can select the current character for insertion by
double-clicking it, pressing the space bar, or pressing the
Enter (or Return) key.
To define a new sequence for use with the Compose key, bring
up the KHIM controls, enter the two characters in the
"Input key sequence" entry and the desired character to insert
into the "Character" entry, and press "Change". (You may copy
and paste the character from another application, or use the
"Unicode..." button (or press the Compose key twice) to select
the character from a map of all available Unicode code
points.) To remove a sequence, select it in the listbox and
press "Delete".
}
::msgcat::mcset {} {SELECT COMPOSE KEY} [string map [list \n\t \n] {
Please press the
key that you want
to use as the
"Compose" key.
}]
}

108
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/cs.msg

@ -0,0 +1,108 @@
# cs.msg --
#
# Czech-language messages for KHIM
#
# Copyright (c) 2005 by Kevin B. Kenny. All rights reserved.
# Translation by Michal Mestan <mestan@dix.cz>
#
# Refer to the file "license.terms" for the terms and conditions of
# use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES.
#
# $Id: cs.msg,v 1.1 2006/12/06 17:28:12 kennykb Exp $
# $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/cs.msg,v $
#
#----------------------------------------------------------------------
namespace eval ::khim {
::msgcat::mcset cs HELPTEXT {
Kevin's Hacky Input Method (KHIM)
KHIM vám umožňuje zadávat mezinárodní znaky včetně těch,
které na vaší klávesnici nejspou. Pracuje nezávisle na
požité vstupní metodě kterou váš operační systém může
poskytovat. Je hlavně určen pro případy, kdy nemáte možnost
měnit mapování klávesnice a přesto potřebujete zapsat
cizojazyčný text.
K nastavení KHIM slouží "Ovládací panel KHIM" (jeho vyvolání
je závaislé na konkrétní aplikaci), zde povolte KHIM zaškrtnutím
políčka "Používat KHIM". Mužete si zde též vybrat klávesu na
vaší klávesnici, kterou bude KHIM používat jako "mrtvá"
stisknutím talčítka "Mrtvá klávesa" a poté stisktnutím
patřičné klávesy. Obecně lze říci, nemůže to být jakákoliv
"mrtvá" klávasa vaší klávesové mapy, jelikož při stisknutí
je volána vstupní metoda operačního systému.
Když je KHIM povolen, můžete vkládat mezinárodní znaky
v jakémkoliv přípravku, který je nastaven tak, aby používal
KHIM stiknutním "mrtvé" klávesy následované posloupností
dvou znaků. Seznam v "Ovládacím panelu KHIM" zobrazuje
dostupné posloupnosti. Pokud stisknete "mrtvou" klávesu
dvakrát, zobrazí se vám dialog, ve kterém můžete vybrat
žádaný symbol z unokódové mapy. V mapě se můžete pohybovat
kursorovými klávesami, dvojklikem myší, mezerníkem či klávesou
enter vybraný znak vložíte do textu.
Chcete-li další znaky vkládat pomocí mrtvé klávesy, otevřete
"Ovládací panel KHIM" vložte dva znaky do pole "Posloupnost
kláves" a požadovaný znak, který chcete vložit do pole
"Vkládaný znak" a stisknětě talčítko "Změnit" (vkládaný
znak můžete nakopírovat z jiné aplikace nebo poučít talčítko
"Unikód..." (nebo stisknout dvakrát "mrtvou" klávesu) a vybrat
znak z unikódové mapy). K odstranění klávesové posloupnosti
slouží tlačítko "Smazat".
}
::msgcat::mcset cs {SELECT COMPOSE KEY} [string map [list \n\t \n] {
Stiskněte klávesu
kterou chcete používat
jako "mrtvou" klávesu.
}]
::msgcat::mcset cs {Apply} "Použít"
::msgcat::mcset cs {Cancel} "Zrušit"
::msgcat::mcset cs {Change} "Změnit"
::msgcat::mcset cs {Character} "Znak"
::msgcat::mcset cs {Compose Key} "Mrtvá klávesa"
::msgcat::mcset cs {Compose key:} "Mrtvá klávesa:"
::msgcat::mcset cs {Composed sequence must be two characters long} \
"Vkládaný znak je vždy šložen z posloupnosti zdvou nzaků"
::msgcat::mcset cs {Delete} "Smazat"
::msgcat::mcset cs {Help...} "Nápověda..."
::msgcat::mcset cs {Input key sequence} "Zadajete posloupnost kláves"
::msgcat::mcset cs {Insert Character} "Vkládaný znak"
::msgcat::mcset cs {Invalid sequence} "Chybná posloupnost"
::msgcat::mcset cs {Key sequences} "Posloupnosti kláves"
::msgcat::mcset cs {KHIM Controls} "Ovládací panel KHIM"
::msgcat::mcset cs {OK} {OK}
::msgcat::mcset cs {Select code page:} "Výběr kódové stránky:"
::msgcat::mcset cs {Unicode...} "Unikód..."
::msgcat::mcset cs {Use KHIM} "Používat KHIM"
}
# Local Variables:
# mode: tcl
# End:

104
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/da.msg

@ -0,0 +1,104 @@
# da.msg --
#
# Danish-language messages for KHIM
#
# Copyright (c) 2005 by Kevin B. Kenny. All rights reserved.
# Translation by Torsten Berg
#
# Refer to the file "license.terms" for the terms and conditions of
# use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES.
#
# $Id: da.msg,v 1.1 2006/09/05 13:48:49 kennykb Exp $
# $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/da.msg,v $
#
#----------------------------------------------------------------------
namespace eval ::khim {
::msgcat::mcset da {Apply} {Anvend}
::msgcat::mcset da {Cancel} {Annuller}
::msgcat::mcset da {Change} {Ændre}
::msgcat::mcset da {Character} {Tegn}
::msgcat::mcset da {Compose Key} {Compose taste}
::msgcat::mcset da {Compose key:} {Compose taste:}
::msgcat::mcset da {Composed sequence must be two characters long} \
{Compose tegnfølgen skal bestå af to tegn}
::msgcat::mcset da {Delete} {Slet}
::msgcat::mcset da {Help...} {Hjælp...}
::msgcat::mcset da HELPTEXT {
Kevin's Hacky Input Method (KHIM)
KHIM gør det muligt at indtaste internationale tegn med et tastatur
som ikke understøtter disse. Dette fungerer uafhængigt af en
bestående indtast metode som styresystemet måtte understøtte.
Det er tænkt til at hjælpe, hvis du ikke har kontrol over tilordningen
på dit tastatur og dog har brug for at indtaste tekst i andre sprog.
For at benytte KHIM, vis kontrolpanelet (hvordan det gøres, afhænger af
dit program) og aktiver KHIM ved at afkrydse "Benyt KHIM". Du skal vælge
en taste der kun sjældent benyttes på dit tastatur og fastlægge denne som
"Compose" taste for at sætte tegn sammen med. Tryk dertil på knappen
markeret med "Compose taste:" og tryk derefter på den taste du ønsker at
fastlægge. Generellt skulle det ikke være den taste som normalt benyttes
til at konstruere tegn med; denne taste vil fortsat opråbe din lokale
systems indtast metode.
Når KHIM er aktiveret kan du indtaste internationale tegn i enhver
kontrol der er konfigureret til at bruge KHIM ved at trykke på den valgte
"Compose" taste fulgt af to bestemte tegn. Rullelisten til venstre
på KHIM kontrolpanelet viser de tegnfølger der står til rådighed. Hvis
du trykker "Compose" tasten to gange kommer der et vindue frem hvor
du kan vælge vilkårlige symboler fra en unicode tabel. Du kan navigere
rundt i selve tabellen ved enten at benytte markøren eller markørtasterne.
Du kan udvælge det markerede tegn ved at doppelt-klikke på symbolet eller
ved at trykke på mellemrums-, enter- eller returtasten.
Ny tegnfølger kan defineres ved at indtaste en følge af to tegn i feltet
markeret med "Indtast tegnfølge" og det ønskede symbol i feltet markeret
med "Tegn" og derefter trykke på "Ændre". Du kan også kopiere og indsætte
et symbol fra et andet program eller benytte "Unicode..." knappen
(eller trykke "Compose" tasten to gange) for at hente et symbol fra
tabellen med alle unicode koder. Tryk på "Slet" knappen for at fjerne
en tegnfølge.
}
::msgcat::mcset da {Input key sequence} {Indtast tegnfølge}
::msgcat::mcset da {Insert Character} {Indtast et tegn}
::msgcat::mcset da {Invalid sequence} {Ugyldig tegnfølge}
::msgcat::mcset da {Key sequences} {Tegnfølger}
::msgcat::mcset da {KHIM Controls} {KHIM kontrolpanel}
::msgcat::mcset da {OK} {O.k.}
::msgcat::mcset da {Select code page:} {Vælg kode side:}
::msgcat::mcset da {SELECT COMPOSE KEY} [string map [list \n\t \n] {
Tryk på den taske
du ønsker at bruge
som "Compose" taste.
}]
::msgcat::mcset da {Unicode...} {Unicode...}
::msgcat::mcset da {Use KHIM} {Benyt KHIM}
}
# Local Variables:
# mode: tcl
# End:

123
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/de.msg

@ -0,0 +1,123 @@
# de.msg --
#
# German-language messages for KHIM
#
# Copyright (c) 2006 by Andreas Kupries. All rights reserved.
#
# Refer to the file "license.terms" for the terms and conditions of
# use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES.
#
# $Id: de.msg,v 1.2 2006/09/07 13:18:13 kennykb Exp $
# $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/de.msg,v $
#
#----------------------------------------------------------------------
namespace eval ::khim {
::msgcat::mcset de HELPTEXT {
Kevin's Hacky Input Method (KHIM)
KHIM ermöglicht die Eingabe von internationalen Zeichen
mittels einer Tastatur, welches diese nicht direkt
unterstützt. Es ist unabhängig von allen Eingabemethoden,
welche vom Betriebssystem bereitgestellt werden (könnten),
und für den Fall gedacht, wenn der Anwender keine Kontrolle
über die Tastatur hat und dennoch Text in anderen Sprachen
eingeben muß.
Um KHIM zu benutzen, ist es notwendig, den KHIM Steuer-Dialog zu
öffnen (dies ist abhängig von der Anwendung) und dann KHIM
durch 'ticken' der 'Benutze KHIM'-Checkbox zu aktivieren. Es
ist weiterhin notwendig, eine Taste als die Kombinier-Taste zu
wählen. Die gewählte Taste sollte im Normalgebrauch selten
genutzt werden. Die Auswahl selbst besteht aus zwei Schritten.
Zuerst muß der Knopf "Kombinier-Taste:" gedrückt werden,
dann die gewünschte Taste.
Allgemein gesprochen, wenn die benutzte Tastatur eine Taste
"Compose" besitzt, dann sollte diese _nicht_ als die
Kombinier-Taste für KHIM gewählt werden. Dies stellt sicher,
das diese Taste weiterhin vom Betriebssystem genutzt werden
kann, um dessen eventuelle Eingabemethoden zu aktivieren.
Sobald KHIM aktiviert wurde, können in jedem Widget, welches
für die Benutzung von KHIM konfiguriert wurde, internationale
Zeichen eingegeben werden. Dies geschieht durch Drücken der
gewählten Kombinier-Taste, gefolgt von zwei weiteren Zeichen,
welche das gewünschte Zeichen identifizieren. Der KHIM
Steuer-Dialog stellt eine Liste der bekannten Zeichenfolgen
zur Verfügung. Zusätzlich ist es möglich einen Dialog zu
öffnen, welcher die Auswahl beliebiger Zeichen in einer Tabelle
erlaubt. Dies geschieht durch zweimaliges Drücken der
Kombinier-Taste. Navigation in der Tabelle geschieht mit der
Maus oder den Kursor-Tasten. Das einzufügende Zeichen kann
mit Doppel-Klick gewählt werden, durch Drücken der
Leer-Taste, oder durch Drücken der Enter- (oder Return-)Taste.
Es ist auch möglich, die Liste der direkt anwählbären Zeichen
zu erweitern. Dies geschieht im KHIM Steuer-Dialog durch Eingabe
der zwei Zeichen für den Kode im Eingabefeld
"Eingabezeichenfolge", des gewünschten Zeichens im Feld
"Zeichen", gefolgt vom Drücken des Knopfes "Ändern".
(Bezüglich der Herkunft des gewünschten Zeichens: Es kann aus
einer anderen Anwendung kopiert werden, oder man benutze den Knopf
"Unicode..." (oder drücke die Kombinier-Taste zweimal), um es
aus der Tabelle aller Zeichen auszuwählen.)
Eine Zeichenfolge wird gelöscht durch Auswahl der Folge in
der Liste aller Zeichenfolgen, gefolgt von der
Lösch/Entferne-Taste.
}
::msgcat::mcset de {SELECT COMPOSE KEY} [string map [list \n\t \n] {
Bitte drücken Sie
die Taste, welche Sie
als Kombinier-Taste
verwenden wollen.
}]
::msgcat::mcset de {Apply} {Anwenden}
::msgcat::mcset de {Cancel} {Abbrechen}
::msgcat::mcset de {Change} {Ändern}
::msgcat::mcset de {Character} {Zeichen}
::msgcat::mcset de {Compose Key} {Kombinier-Taste}
::msgcat::mcset de {Compose key:} {Kombinier-Taste:}
::msgcat::mcset de {Composed sequence must be two characters long} \
{Die Eingabezeichenfolge muß aus zwei Zeichen bestehen}
::msgcat::mcset de {Delete} {Löschen}
::msgcat::mcset de {Help...} {Hilfe...}
::msgcat::mcset de {Input key sequence} {Eingabezeichenfolge}
::msgcat::mcset de {Insert Character} {Zeichen einfügen}
::msgcat::mcset de {Invalid sequence} {Ungültige Zeichenfolge}
::msgcat::mcset de {Key sequences} {Zeichenfolgen}
::msgcat::mcset de {KHIM Controls} {KHIM Steuerung}
::msgcat::mcset de {OK} {OK}
::msgcat::mcset de {Select code page:} {Wähle Code-Seite:}
::msgcat::mcset de {Unicode...} {Unicode...}
::msgcat::mcset de {Use KHIM} {Benutze KHIM}
}
# Local Variables:
# mode: tcl
# End:

114
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/en.msg

@ -0,0 +1,114 @@
# en.msg --
#
# English-language messages for KHIM
#
# Copyright (c) 2005 by Kevin B. Kenny. All rights reserved.
#
# Refer to the file "license.terms" for the terms and conditions of
# use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES.
#
# $Id: en.msg,v 1.3 2007/06/08 19:24:31 kennykb Exp $
# $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/en.msg,v $
#
#----------------------------------------------------------------------
namespace eval ::khim {
# If you edit HELPTEXT or {SELECT COMPOSE KEY}, also edit the corresponding
# messages in ROOT.msg
::msgcat::mcset en HELPTEXT {
Kevin's Hacky Input Method (KHIM)
KHIM allows you to input international characters from a
keyboard that doesn't support them. It works independently of
any input method that the operating system may supply; it is
intended for when you don't have control over your keyboard
mapping and still need to input text in other languages.
To use KHIM, bring up the KHIM Controls (the way this is done
depends on your application) and enable KHIM by checking "Use
KHIM". You also need to choose a key on your keyboard that is
seldom used, and designate it as the "Compose" key by pressing
the button labelled, "Compose key:" then striking the key you
wish to designate. Generally speaking, this key should not be
the key designated as "Compose" on the keyboard; that key will
continue to invoke whatever input method the local operating
system supplies.
Once KHIM is enabled, you can enter international characters
in any widget that is configured to use KHIM by pressing the
Compose key followed by a two-character sequence. The listbox
in the KHIM controls shows the available sequences. In
addition, if you strike the Compose key twice, you get a
dialog that allows you to input arbitrary symbols from a
Unicode character map. In the map, you can navigate among the
characters using either the cursor keys or the mouse, and you
can select the current character for insertion by
double-clicking it, pressing the space bar, or pressing the
Enter (or Return) key.
To define a new sequence for use with the Compose key, bring
up the KHIM controls, enter the two characters in the
"Input key sequence" entry and the desired character to insert
into the "Character" entry, and press "Change". (You may copy
and paste the character from another application, or use the
"Unicode..." button (or press the Compose key twice) to select
the character from a map of all available Unicode code
points.) To remove a sequence, select it in the listbox and
press "Delete".
}
::msgcat::mcset en {SELECT COMPOSE KEY} [string map [list \n\t \n] {
Please press the
key that you want
to use as the
"Compose" key.
}]
::msgcat::mcset en {Apply} {Apply}
::msgcat::mcset en {Cancel} {Cancel}
::msgcat::mcset en {Change} {Change}
::msgcat::mcset en {Character} {Character}
::msgcat::mcset en {Compose Key} {Compose Key}
::msgcat::mcset en {Compose key:} {Compose key:}
::msgcat::mcset en {Composed sequence must be two characters long} \
{Composed sequence must be two characters long}
::msgcat::mcset en {Delete} {Delete}
::msgcat::mcset en {KHIM Help} {KHIM Help}
::msgcat::mcset en {Help...} {Help...}
::msgcat::mcset en {Input key sequence} {Input key sequence}
::msgcat::mcset en {Insert Character} {Insert Character}
::msgcat::mcset en {Invalid sequence} {Invalid sequence}
::msgcat::mcset en {Key sequences} {Key sequences}
::msgcat::mcset en {KHIM Controls} {KHIM Controls}
::msgcat::mcset en {OK} {OK}
::msgcat::mcset en {Select code page:} {Select code page:}
::msgcat::mcset en {Unicode...} {Unicode...}
::msgcat::mcset en {Use KHIM} {Use KHIM}
}
# Local Variables:
# mode: tcl
# End:

108
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/es.msg

@ -0,0 +1,108 @@
# es.msg --
#
# Spanish-language messages for KHIM
#
# Copyright (c) 2008 by Emiliano Gavilán.
# Proofreading and corrections by Miguel Sofer.
#
# Refer to the file "license.terms" for the terms and conditions of
# use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES.
#
# $Id: es.msg,v 1.3 2008/05/30 02:00:19 kennykb Exp $
# $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/es.msg,v $
#
#----------------------------------------------------------------------
namespace eval ::khim {
::msgcat::mcset es HELPTEXT {
Kevin's Hacky Input Method (KHIM)
KHIM permite ingresar caracteres internacionales desde un teclado
que no soporta esta funcionalidad. Funciona independientemente de
cualquier método de entrada que su sistema operativo pueda proveer;
su finalidad es permitirle ingresar caracteres en otros lenguajes,
aun cuando no tenga control del mapeo de su teclado.
Para usar KHIM, seleccione el diálogo de control de KHIM
(la forma de lograr esto depende de su aplicación) y habilite
el uso de KHIM seleccionando "Usar KHIM". También necesitará
seleccionar una tecla que sea raramente usada y designarla como
tecla "Componer" presionando el botón con la leyenda "Tecla Componer:"
y luego la tecla que quiere asignar a esta función. Ésta tecla no
debe ser la tecla designada como la tecla de composición de su
teclado; dicha tecla seguirá invocando cualquier método de entrada
que su sistema operativo provea.
Una vez que KHIM esté habilitado, podrá ingresar caracteres
internacionales en cualquier widget que este configurado para
usar KHIM presionando la tecla designada como Componer seguida
de una secuencia de dos teclas. La lista en el control de KHIM
muestra todas las secuencias disponibles. Además, si presiona
la tecla "Componer" dos veces, se mostrará un diálogo que le
permitirá ingresar cualquier carácter arbitrario desde un mapa
de caracteres Unicode. Dicho mapa puede navegarse utilizando
el ratón o las teclas de dirección, y se puede seleccionar el
carácter deseado con un doble click, la barra espaciadora o la
tecla Return (Enter).
Para definir una nueva secuencia para utilizar con la tecla
"Componer", seleccione el control de KHIM, ingrese dos teclas en
secuencia en la entrada "Secuencia de teclas", el carácter deseado
en la entrada "Carácter", y luego presione la tecla "Cambiar".
(Usted puede copiar y pegar dicho carácter desde otra aplicación,
o presionar el botón "Unicode..." (o presione la tecla "Componer"
dos veces) para seleccionar el carácter desde el mapa de los
caracteres Unicode disponibles). Para borrar una secuencia,
selecciónela de la lista y presione "Borrar".
}
::msgcat::mcset es {SELECT COMPOSE KEY} [string map [list \n\t \n] {
Por favor presione
la tecla que desee
usar como tecla
"Componer".
}]
::msgcat::mcset es {Apply} {Aplicar}
::msgcat::mcset es {Cancel} {Cancelar}
::msgcat::mcset es {Change} {Cambiar}
::msgcat::mcset es {Character} {Carácter}
::msgcat::mcset es {Compose Key} {Tecla Componer}
::msgcat::mcset es {Compose key:} {Tecla Componer:}
::msgcat::mcset es {Composed sequence must be two characters long} \
{La secuencia de composición debe ser de dos teclas}
::msgcat::mcset es {Delete} {Borrar}
::msgcat::mcset es {KHIM Help} {Ayuda de KHIM}
::msgcat::mcset es {Help...} {Ayuda...}
::msgcat::mcset es {Input key sequence} {Secuencia de teclas de entrada}
::msgcat::mcset es {Insert Character} {Insertar carácter}
::msgcat::mcset es {Invalid sequence} {Secuencia inválida}
::msgcat::mcset es {Key sequences} {Secuencias de teclas}
::msgcat::mcset es {KHIM Controls} {Controles de KHIM}
::msgcat::mcset es {OK} {Aceptar}
::msgcat::mcset es {Select code page:} {Seleccionar página de código:}
::msgcat::mcset es {Unicode...} {Unicode...}
::msgcat::mcset es {Use KHIM} {Usar KHIM}
}

2028
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/khim.tcl

File diff suppressed because it is too large Load Diff

11
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/pkgIndex.tcl

@ -0,0 +1,11 @@
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script. It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands. When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.
package ifneeded khim 1.0.1 [list source [file join $dir khim.tcl]]

113
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/pl.msg

@ -0,0 +1,113 @@
# pl.msg --
#
# Polish-language messages for KHIM
# Contributed by Irek Chmielowiec <irek.ch (at) gmail.com>
# Copyright (c) 2005 by Kevin B. Kenny. All rights reserved.
#
# Refer to the file "license.terms" for the terms and conditions of
# use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES.
#
#----------------------------------------------------------------------
namespace eval ::khim {
# If you edit HELPTEXT or {SELECT COMPOSE KEY}, also edit the corresponding
# messages in ROOT.msg
::msgcat::mcset pl HELPTEXT {
Kevin's Hacky Input Method (KHIM)
KHIM pozwala na wprowadzanie znaków narodowych i symboli z
klawiatury która tego nie obsługuje. Działa niezależnie od
metody wprowadzania znaków jaką może oferować system operacyjny;
jest przewidziany do sytuacji kiedy nie ma się kontroli nad
odwzorowaniem klawiszy a istnieje potrzeba wprowadzania tekstu w
różnych językach.
Aby móc używać KHIM, uruchom okno Ustawień KHIM (sposób jego
uruchomienia zależy od używanej aplikacji) i włącz KHIM
zaznaczając opcję "Włącz KHIM". Należy także wybrać klawisz
który jest rzadko używany i przypisać mu funkcję klawisza
"sterującego" naciskając przycisk "Klawisz sterujący:",
a następnie naciskając klawisz któremu chcemy tę funkcję
przypisać. Mówiąc ogólnie, nie powinien to być klawisz
ustawiony jako sterujący dla używanego układu klawiatury (np.
Alt); klawisz ten będzie działał niezależnie od metody
wprowadzania znaków oferowanej przez lokalny system operacyjny.
Kiedy KHIM jest już uruchomiony, można wprowadzać znaki narodowe
i symbole w każdym elemencie interfejsu użytkownika, który
został ustawiony do korzystania z KHIM, naciskając klawisz
sterujący razem z sekwencją dwóch znaków. Lista wyboru w
ustawieniach KHIM pokazuje dostępne kombinacje. Dodatkowo, po
dwukrotnym naciśnięciu klawisza sterującego pojawi się okno
pozwalające na bezpośrednie wstawienie wybranego znaku z tablicy
symboli Unicode. W oknie tablicy można nawigować pomiędzy
znakami używając klawiszy kursorów lub za pomocą myszy a wybór
znaku następuje przez dwukrotne kliknięcie, naciśnięcie spacji
lub naciśnięcie klawisza Enter (Return).
Aby zdefiniować nową sekwencję do użycia z klawiszem sterującym
należy uruchomić ustawienia KHIM, wprowadzić dwa znaki w polu
"Sekwencja znaków" i znak jaki chcemy uzyskać w polu "Wynik"
oraz nacisnąć przycisk "Zmień". (Można także skopiować i
wkleić znak z innej aplikacji lub użyć przycisku "Tablica
Unicode..." (także przez dwukrotne naciśnięcie klawisza
sterującego) do wyboru znaku z tablicy wszystkich dostępnych
kodów Unicode.) Aby usunąć sekwencję znaków, należy wybrać ją z
listy i nacisnąć "Usuń".
}
::msgcat::mcset pl {SELECT COMPOSE KEY} [string map [list \n\t \n] {
Proszę nacisnąć klawisz
który ma być używany
jako sterujący.
}]
::msgcat::mcset pl {Apply} {Zastosuj}
::msgcat::mcset pl {Cancel} {Anuluj}
::msgcat::mcset pl {Change} {Zmień}
::msgcat::mcset pl {Character} {Wynik}
::msgcat::mcset pl {Compose Key} {Klawisz sterujący}
::msgcat::mcset pl {Compose key:} {Klawisz sterujący:}
::msgcat::mcset pl {Composed sequence must be two characters long} \
{Sekwecja znaków musi być dwuelementowa}
::msgcat::mcset pl {Delete} {Usuń}
::msgcat::mcset pl {KHIM Help} {Pomoc KHIM}
::msgcat::mcset pl {Help...} {Pomoc...}
::msgcat::mcset pl {Input key sequence} {Sekwencja znaków}
::msgcat::mcset pl {Insert Character} {Wstaw znak}
::msgcat::mcset pl {Invalid sequence} {Nieprawidłowa sekwencja}
::msgcat::mcset pl {Key sequences} {Sekwencje znaków}
::msgcat::mcset pl {KHIM Controls} {Ustawienia KHIM}
::msgcat::mcset pl {OK} {OK}
::msgcat::mcset pl {Select code page:} {Wybierz kodowanie:}
::msgcat::mcset pl {Unicode...} {Tablica Unicode...}
::msgcat::mcset pl {Use KHIM} {Włącz KHIM}
}
# vim:ft=tcl:ts=8:sw=4:sts=4:noet
# Local Variables:
# mode: tcl
# End:

124
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/ru.msg

@ -0,0 +1,124 @@
# ru.msg --
#
# Russian-language messages for KHIM
#
# Contributed by Konstantin Khomoutov <flatworm@users.sourceforge.net>.
# Proof-read and edited by Serge Yudin <talking_zero@mail.ru>.
#
# Copyright (c) 2005 by Kevin B. Kenny. All rights reserved.
#
# Refer to the file "license.terms" for the terms and conditions of
# use and redistribution of this file, and a DISCLAIMER OF ALL WARRANTEES.
#
# $Id: ru.msg,v 1.1 2007/06/08 19:24:31 kennykb Exp $
# $Source: /home/rkeene/tmp/cvs2fossil/tcllib/tklib/modules/khim/ru.msg,v $
#
#----------------------------------------------------------------------
namespace eval ::khim {
# If you edit HELPTEXT or {SELECT COMPOSE KEY}, also edit the corresponding
# messages in ROOT.msg
::msgcat::mcset ru HELPTEXT {
Kevin's Hacky Input Method (KHIM) --
Нетривиальный Метод Кевина для Ввода Символов
KHIM делает возможным ввод символов национальных алфавитов
с клавиатуры, которая не позволяют этого делать. Он работает
независимо от любых способов ввода, которые поддерживает ОС;
его задача -- позволить осуществлять ввод таких символов,
которые невозможно ввести с текущими настройками ОС данного
компьютера, а менять их нет возможности или желания.
Для того, чтобы использовать KHIM, следует вызвать диалог
"Настройки KHIM" (как это сделать, зависит от приложения,
использующего KHIM) и разрешить работу KHIM, включив переключатель
"Использовать KHIM". Также Вам понадобится выбрать редко
используемую клавишу на Вашей клавиатуре и назначить её
"клавишей композиции". Для этого нужно нажать кнопку, подписанную
"Клавиша композиции:", в диалоге настроек KHIM и затем нажать
выбранную клавишу на клавиатуре. Имейте в виду, что если на Вашей
клавиатуре есть клавиша, называемая "Compose", то её не следует
выбирать в качестве клавиши композиции для KHIM -- пусть она
продолжает вызывать тот метод ввода,
который назначен ей операционной системой.
После того как KHIM активирован, Вы можете вставлять символы
национальных алфавитов в любое поле ввода, настроенное на
использование KHIM, таким образом: нажать и отпустить клавишу
композиции, затем ввести два символа -- "входную последовательность".
В диалоге настроек KHIM есть окно со списком доступных
последовательностей. Кроме того, двойное нажатие клавиши
композиции вызывает окно диалога, позволяющее выбрать произвольный
символ Unicode. Выбор нужного символа в этом диалоге
осуществляется мышью либо клавишами управления курсором,
а вставка выбранного символа -- двойным щелчком левой кнопки
мыши на нём, либо нажатием клавиши Пробел или Ввод.
Чтобы создать новую входную последовательность для использования
совместно с клавишей композиции окройте диалог настроек KHIM,
введите два символа в поле "Входная последовательность" и
соответствующий ей символ в поле "Символ", затем нажмите
кнопку "Изменить". (Вы можете копировать и вставлять целевой
символ из другого приложения. Также можно воспользоваться
встроенным в KHIM диалогом выбора символов Unicode, нажав
кнопку "Unicode..." или дважды нажав клавишу композиции.)
Для удаления входной последовательности выберите её в списке
и дажмите "Удалить".
}
::msgcat::mcset ru {SELECT COMPOSE KEY} [string map [list \n\t \n] {
Нажмите клавишу,
которую вы хотите
использовать в качестве
"Клавиши композиции"
}]
::msgcat::mcset ru {Apply} {Применить}
::msgcat::mcset ru {Cancel} {Отменить}
::msgcat::mcset ru {Change} {Изменить}
::msgcat::mcset ru {Character} {Символ}
::msgcat::mcset ru {Compose Key} {Клавиша композиции}
::msgcat::mcset ru {Compose key:} {Клавиша композиции:}
::msgcat::mcset ru {Composed sequence must be two characters long} \
{Входная последовательность должна состоять из двух символов}
::msgcat::mcset ru {Delete} {Удалить}
::msgcat::mcset ru {KHIM Help} {Справка по KHIM}
::msgcat::mcset ru {Help...} {Справка...}
::msgcat::mcset ru {Input key sequence} {Входная последовательность}
::msgcat::mcset ru {Insert Character} {Выберите символ}
::msgcat::mcset ru {Invalid sequence} {Неправильная комбинация}
::msgcat::mcset ru {Key sequences} {Комбинации клавиш}
::msgcat::mcset ru {KHIM Controls} {Настройки KHIM}
::msgcat::mcset ru {OK} {OK}
::msgcat::mcset ru {Select code page:} {Выберите страницу кодов:}
::msgcat::mcset ru {Unicode...} {Unicode...}
::msgcat::mcset ru {Use KHIM} {Использовать KHIM}
}
# vim:ft=tcl:ts=8:sw=4:sts=4:noet
# Local Variables:
# mode: tcl
# End:

117
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/khim/uk.msg

@ -0,0 +1,117 @@
# uk.msg --
#
# Ukrainian-language messages for KHIM
#
# Contributed by Fixer jabber:<uzver@jabber.kiev.ua>, email:<artem_brz@mail.ru>.
#
# Copyright (c) 2005 by Kevin B. Kenny. All rights reserved.
#
#----------------------------------------------------------------------
namespace eval ::khim {
# If you edit HELPTEXT or {SELECT COMPOSE KEY}, also edit the corresponding
# messages in ROOT.msg
::msgcat::mcset uk HELPTEXT {
Kevin's Hacky Input Method (KHIM) --
Нетривіальний Метод Кевіна для Введення Символів
KHIM дає можливість вводити символи національних алфавітів
з клавіатури, яка не дозволяє цього робити. Він працює
незалежно від інших способів вводу, котрі підтримує ОС;
його завдання -- дати змогу здійснювати введення таких символів,
котрі неможливо ввести з теперішніми налаштуваннями ОС даного
компьютера, а поміняти їх немає ні можливості, ні бажання.
Для того, щоб користуватися KHIM, треба відкрити діалог
"Налаштування KHIM" (як це зробити, залежить від програми,
яка використовує KHIM) і дозволити роботу KHIM, увімкнувши перемикач
"Використовувати KHIM". Також Вам необхідно обрати рідко
використовувану клавішу на Вашій клавіатурі і призначити її
"клавішою композиції". Для цього потрібно натиснути кнопку, підписану як
"Клавіша композиції:", у діалозі налаштувань KHIM, а потім натиснути
обрану клавішу на клавіатурі. Майте на увазі, що якшо на Вашій
клавіатурі є клавіша, що зветься "Compose", то її не треба
обирати в якості клавіши композиції для KHIM -- хай вона
продовжує викликати той метод вводу,
котрий призначений їй операційною системою.
Після того як KHIM активувався, Ви можете вставляти символи
національних алфавітів в будь-яке поле для вводу, налаштоване на
використання KHIM, таким чином: натиснути і відпустити клавішу
композиції, а потім ввести два символи -- "вхідну послідовність".
У діалозі налаштувань KHIM є вікно з переліком доступних
послідовностей. Крім того, подвійне натискання клавіші
композиції викликає вікно діалогу, що дозволяє обрати довільний
символ Unicode. Вибір потрібного символу в цьому діалозі
здійснюється мишою чи клавішами управління курсором,
а вставляння обраного симолу -- подвійним клацанням лівої кнопки
миші на ньому, або натисканням клавіши Пробіл чи Ввід.
Щоб створити нову вхідну послідовність для використання
сумісно з клавішою композиції відкрийте діалог налаштувань KHIM,
введіть два символи в поле "Вхідна послідовність" і
відповідний їй символ у полі "Символ", а потім натисніть
клавішу "Змінити". (Ви можете копіювати і вставляти цільовий
символ з іншої програми. Також можна скористатися
вбудованим у KHIM діалогом вибору символів Unicode, натиснувши
кнопку "Unicode...", або подвійно клацнувши клавішу композиції.)
Для видалення вхідної послідовності оберіть її у переліку
і натисніть "Видалити."
}
::msgcat::mcset uk {SELECT COMPOSE KEY} [string map [list \n\t \n] {
Натисніть клавішу,
котру ви бажаєте
використовувати в якості
"Клавіші композиції"
}]
::msgcat::mcset uk {Apply} {Прийняти}
::msgcat::mcset uk {Cancel} {Відмінити}
::msgcat::mcset uk {Change} {Змінити}
::msgcat::mcset uk {Character} {Символ}
::msgcat::mcset uk {Compose Key} {Клавіша композиції}
::msgcat::mcset uk {Compose key:} {Клавіша композиції:}
::msgcat::mcset uk {Composed sequence must be two characters long} \
{Вхідна послідовність повинна складатися з двох символів}
::msgcat::mcset uk {Delete} {Видалити}
::msgcat::mcset uk {KHIM Help} {Допомога по KHIM}
::msgcat::mcset uk {Help...} {Допомога...}
::msgcat::mcset uk {Input key sequence} {Вхідна послідовність}
::msgcat::mcset uk {Insert Character} {Оберіть символ}
::msgcat::mcset uk {Invalid sequence} {Неправильна комбінація}
::msgcat::mcset uk {Key sequences} {Комбінації клавіш}
::msgcat::mcset uk {KHIM Controls} {Налаштування KHIM}
::msgcat::mcset uk {OK} {OK}
::msgcat::mcset uk {Select code page:} {Оберіть кодову сторінку:}
::msgcat::mcset uk {Unicode...} {Unicode...}
::msgcat::mcset uk {Use KHIM} {Використовувати KHIM}
}
# vim:ft=tcl:ts=8:sw=4:sts=4:noet
# Local Variables:
# mode: tcl
# End:

13
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/mentry.tcl

@ -0,0 +1,13 @@
#==============================================================================
# Main Mentry package module.
#
# Copyright (c) 1999-2023 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
package require -exact mentry::common 3.18
package provide mentry $::mentry::version
package provide Mentry $::mentry::version
::mentry::useTile 0
::mentry::createBindings

115
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/mentryCommon.tcl

@ -0,0 +1,115 @@
#==============================================================================
# Main Mentry and Mentry_tile package module.
#
# Copyright (c) 1999-2023 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
if {[catch {package require Wcb 3.1} result1] != 0 &&
[catch {package require wcb 3.1} result2] != 0} {
error "$result1; $result2"
}
namespace eval ::mentry {
#
# Public variables:
#
variable version 3.18
variable library
if {$::tcl_version >= 8.4} {
set library [file dirname [file normalize [info script]]]
} else {
set library [file dirname [info script]] ;# no "file normalize" yet
}
#
# Creates a new multi-entry widget:
#
namespace export mentry
#
# Implement multi-entry widgets for date and time:
#
namespace export dateMentry timeMentry dateTimeMentry \
putClockVal getClockVal
#
# Implement a multi-entry widget for real numbers in fixed-point format:
#
namespace export fixedPointMentry putReal getReal
#
# Implement a multi-entry widget for IP addresses:
#
namespace export ipAddrMentry putIPAddr getIPAddr
#
# Implement a multi-entry widget for IPv6 addresses:
#
namespace export ipv6AddrMentry putIPv6Addr getIPv6Addr
}
package provide mentry::common $::mentry::version
if {$::tcl_version >= 8.4} {
interp alias {} ::mentry::addVarTrace {} trace add variable
} else {
proc ::mentry::addVarTrace {name ops cmd} {
set ops2 ""
foreach op $ops { append ops2 [string index $op 0] }
trace variable $name $ops2 $cmd
}
}
#
# The following procedure, invoked in "mentry.tcl" and
# "mentry_tile.tcl", sets the variable ::mentry::usingTile
# to the given value and sets a trace on this variable.
#
proc ::mentry::useTile {bool} {
variable usingTile $bool
addVarTrace usingTile {write unset} [list ::mentry::restoreUsingTile $bool]
}
#
# The following trace procedure is executed whenever the variable
# ::mentry::usingTile is written or unset. It restores the variable to its
# original value, given by the first argument.
#
proc ::mentry::restoreUsingTile {origVal varName index op} {
variable usingTile $origVal
switch -glob $op {
w* {
return -code error "it is not supported to use both Mentry and\
Mentry_tile in the same application"
}
u* {
addVarTrace usingTile {write unset} \
[list ::mentry::restoreUsingTile $origVal]
}
}
}
proc ::mentry::createTkAliases {} {
foreach cmd {frame entry label} {
if {[llength [info commands ::tk::$cmd]] == 0} {
interp alias {} ::tk::$cmd {} ::$cmd
}
}
}
::mentry::createTkAliases
#
# Everything else needed is lazily loaded on demand, via the dispatcher
# set up in the subdirectory "scripts" (see the file "tclIndex").
#
lappend auto_path [file join $::mentry::library scripts]
#
# Load the package mwutil from the directory "scripts/mwutil". Take
# into account that it is also included in Scrollutil and Tablelist.
#
if {[catch {package present mwutil} version] == 0 &&
[package vcompare $version 2.20] < 0} {
package forget mwutil
}
package require mwutil 2.20

24
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/mentry_tile.tcl

@ -0,0 +1,24 @@
#==============================================================================
# Main Mentry_tile package module.
#
# Copyright (c) 1999-2023 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
package require Tk 8.4
if {$::tk_version < 8.5 || [regexp {^8\.5a[1-5]$} $::tk_patchLevel]} {
package require tile 0.6
}
package require -exact mentry::common 3.18
package provide mentry_tile $::mentry::version
package provide Mentry_tile $::mentry::version
::mentry::useTile 1
::mentry::createBindings
namespace eval ::mentry {
#
# Commands related to tile themes:
#
namespace export getThemes getCurrentTheme setTheme setThemeDefaults
}

27
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/pkgIndex.tcl

@ -0,0 +1,27 @@
#==============================================================================
# Mentry and Mentry_tile package index file.
#
# Copyright (c) 1999-2023 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
#
# Regular packages:
#
package ifneeded mentry 3.18 \
[list source [file join $dir mentry.tcl]]
package ifneeded mentry_tile 3.18 \
[list source [file join $dir mentry_tile.tcl]]
#
# Aliases:
#
package ifneeded Mentry 3.18 \
[list package require -exact mentry 3.18]
package ifneeded Mentry_tile 3.18 \
[list package require -exact mentry_tile 3.18]
#
# Code common to all packages:
#
package ifneeded mentry::common 3.18 \
[list source [file join $dir mentryCommon.tcl]]

863
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryDateTime.tcl

@ -0,0 +1,863 @@
#==============================================================================
# Contains the implementation of multi-entry widgets for date and time.
#
# Copyright (c) 1999-2023 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
#
# Namespace initialization
# ========================
#
namespace eval mentry {
#
# Min. and max. values of date/time components
#
variable dateTimeMins
variable dateTimeMaxs
array set dateTimeMins {d 1 m 1 y 0 Y 0 H 0 I 1 M 0 S 0}
array set dateTimeMaxs {d 31 m 12 y 99 Y 9999 H 23 I 12 M 59 S 59}
#
# Define some bindings for the binding
# tags MentryDateTime and MentryMeridian
#
bind MentryDateTime <Up> { mentry::incrDateTimeComp %W 1 }
bind MentryDateTime <Down> { mentry::incrDateTimeComp %W -1 }
bind MentryDateTime <Prior> { mentry::incrDateTimeComp %W 10 }
bind MentryDateTime <Next> { mentry::incrDateTimeComp %W -10 }
bind MentryMeridian <Up> { mentry::setMeridian %W "P" }
bind MentryMeridian <Down> { mentry::setMeridian %W "A" }
bind MentryMeridian <Prior> { mentry::setMeridian %W "P" }
bind MentryMeridian <Next> { mentry::setMeridian %W "A" }
variable winSys
variable uniformWheelSupport
if {$uniformWheelSupport} {
bind MentryDateTime <MouseWheel> {
mentry::incrDateTimeComp %W \
[expr {%D > 0 ? (%D + 119) / 120 : %D / 120}]
}
bind MentryDateTime <Option-MouseWheel> {
mentry::incrDateTimeComp %W \
[expr {%D > 0 ? (%D + 11) / 12 : %D / 12}]
}
} elseif {[string compare $winSys "classic"] == 0 ||
[string compare $winSys "aqua"] == 0} {
catch {
bind MentryDateTime <MouseWheel> {
mentry::incrDateTimeComp %W %D
}
bind MentryDateTime <Option-MouseWheel> {
mentry::incrDateTimeComp %W [expr {10 * %D}]
}
}
} else {
catch {
bind MentryDateTime <MouseWheel> {
mentry::incrDateTimeComp %W \
[expr {%D > 0 ? (%D + 119) / 120 : %D / 120}]
}
}
if {[string compare $winSys "x11"] == 0} {
bind MentryDateTime <Button-4> {
if {!$tk_strictMotif} {
mentry::incrDateTimeComp %W 1
}
}
bind MentryDateTime <Button-5> {
if {!$tk_strictMotif} {
mentry::incrDateTimeComp %W -1
}
}
bind MentryMeridian <Button-4> {
if {!$tk_strictMotif} {
mentry::setMeridian %W "P"
}
}
bind MentryMeridian <Button-5> {
if {!$tk_strictMotif} {
mentry::setMeridian %W "A"
}
}
}
}
catch {
bind MentryMeridian <MouseWheel> {
mentry::setMeridian %W [expr {(%D < 0) ? "A" : "P"}]
}
}
}
#
# Multi-entry widgets for date & time
# ===================================
#
#------------------------------------------------------------------------------
# mentry::dateMentry
#
# Creates a new mentry widget win that allows to display and edit a date
# according to the argument fmt, which must be a string of length 3, consisting
# of the letters d for the day (01 - 31), m for the month (01 - 12), and y or Y
# for the year without century (00 - 99) or with century (e.g., 1999), in an
# arbitrary order. sep specifies the text to be displayed in the labels
# separating the entry children of the mentry widget. Sets the type attribute
# of the widget to Date, saves the value of fmt in its format attribute, and
# returns the name of the newly created widget.
#------------------------------------------------------------------------------
proc mentry::dateMentry {win fmt sep args} {
#
# Parse the fmt argument
#
if {![regexp {^([dmyY])([dmyY])([dmyY])$} $fmt dummy \
fields(0) fields(1) fields(2)]} {
return -code error \
"bad format \"$fmt\": must be a string of length 3,\
consisting of the letters d, m, and y or Y"
}
#
# Check whether all the three date components are represented in fmt
#
for {set n 0} {$n < 3} {incr n} {
set lfields($n) [string tolower $fields($n)]
}
if {[string compare $lfields(0) $lfields(1)] == 0 ||
[string compare $lfields(0) $lfields(2)] == 0 ||
[string compare $lfields(1) $lfields(2)] == 0} {
return -code error \
"bad format \"$fmt\": must have unique components for the\
day, month, and year"
}
#
# Create the widget, set its type to Date, and save the format string
#
eval [list mentry $win] $args
array set widths {d 2 m 2 y 2 Y 4}
::$win configure -body [list $widths($fields(0)) $sep $widths($fields(1)) \
$sep $widths($fields(2))]
::$win attrib type Date format $fmt
#
# In each entry child allow only unsigned integers of the corresp.
# max. values, and insert the binding tag MentryDateTime in the
# list of binding tags of the entry, just after its path name
#
variable dateTimeMaxs
for {set n 0} {$n < 3} {incr n} {
set w [::$win entrypath $n]
wcb::cbappend $w before insert \
"wcb::checkEntryForUInt $dateTimeMaxs($fields($n))"
::$win adjustentry $n "0123456789"
bindtags $w [linsert [bindtags $w] 1 MentryDateTime]
}
return $win
}
#------------------------------------------------------------------------------
# mentry::timeMentry
#
# Creates a new mentry widget win that allows to display and edit a time
# according to the argument fmt, which must be a string of length 2 or 3,
# consisting of the following field descriptor characters of the clock format
# command: H or I, followed by M, and optionally the letter S. An H as first
# character specifies the time format %H:%M or %H:%M:%S, while the letter I
# stands for %I:%M %p or %I:%M:%S %p. sep specifies the text to be displayed
# in the labels separating the entry children of the mentry widget. Sets the
# type attribute of the widget to Time, saves the value of fmt in its format
# attribute, and returns the name of the newly created widget.
#------------------------------------------------------------------------------
proc mentry::timeMentry {win fmt sep args} {
#
# Parse the fmt argument
#
if {![regexp {^(H|I)(M)(S?)$} $fmt dummy fields(0) fields(1) fields(2)]} {
return -code error \
"bad format \"$fmt\": must be a string of length 2 or 3\
starting with H or I, followed by M and optionally by S"
}
#
# Create the widget, set its type to Time, and save the format
# string. If the AM/PM indicator is needed, devide it into
# an entry (containing A or P) and a label (displaying M)
#
eval [list mentry $win] $args
set len [string length $fmt]
set body [list 2 $sep 2]
if {$len == 3} {
lappend body $sep 2
}
if {[string compare $fields(0) "I"] == 0} {
lappend body " " 1 M
}
::$win configure -body $body
::$win attrib type Time format $fmt
#
# In each of the first len entry children allow only unsigned integers
# of the corresp. max. values, and insert the binding tag MentryDateTime
# in the list of binding tags of the entry, just after its path name
#
variable dateTimeMaxs
for {set n 0} {$n < $len} {incr n} {
set w [::$win entrypath $n]
wcb::cbappend $w before insert \
"wcb::checkEntryForUInt $dateTimeMaxs($fields($n))"
::$win adjustentry $n "0123456789"
bindtags $w [linsert [bindtags $w] 1 MentryDateTime]
}
#
# In the entry child containing the first character of the AM/PM
# indicator (if present) install automatic uppercase conversion,
# allow only the characters A and P, insert the binding tag
# MentryMeridian in the list of binding tags of the entry, just
# after its path name, and make the entry right-justified
#
if {[string compare $fields(0) "I"] == 0} {
set w [::$win entrypath $len]
wcb::cbappend $w before insert \
wcb::convStrToUpper {wcb::checkStrForRegExp {^[AP]$}}
::$win adjustentry $len "AP"
bindtags $w [linsert [bindtags $w] 1 MentryMeridian]
$w configure -justify right
}
return $win
}
#------------------------------------------------------------------------------
# mentry::dateTimeMentry
#
# Creates a new mentry widget win that allows to display and edit a date & time
# according to the argument fmt, which must be a string of length 5 or 6, with
# the first 3 characters consisting of the letters d for the day (01 - 31), m
# for the month (01 - 12), and y or Y for the year without century (00 - 99) or
# with century (e.g., 1999), in an arbitrary order, followed by 2 or 3 field
# descriptor characters of the clock format command, which must be: H or I,
# then M, and optionally the letter S. An H specifies the time format %H:%M or
# %H:%M:%S, while the letter I stands for %I:%M %p or %I:%M:%S %p. dateSep and
# timeSep specify the texts to be displayed in the labels separating the entry
# children of the mentry widget in the date and time parts, respectively (which
# in turn are separated from each other by a space character). Sets the type
# attribute of the widget to DateTime, saves the value of fmt in its format
# attribute, and returns the name of the newly created widget.
#------------------------------------------------------------------------------
proc mentry::dateTimeMentry {win fmt dateSep timeSep args} {
#
# Parse the fmt argument
#
if {![regexp {^([dmyY])([dmyY])([dmyY])(H|I)(M)(S?)$} $fmt dummy \
fields(0) fields(1) fields(2) fields(3) fields(4) fields(5)]} {
return -code error \
"bad format \"$fmt\": must be a string of length 5 or 6,\
with the first 3 characters consisting of the letters d, m,\
and y or Y, followed by H or I, then M, and optionally by S"
}
#
# Check whether all the three date components are represented in fmt
#
for {set n 0} {$n < 3} {incr n} {
set lfields($n) [string tolower $fields($n)]
}
if {[string compare $lfields(0) $lfields(1)] == 0 ||
[string compare $lfields(0) $lfields(2)] == 0 ||
[string compare $lfields(1) $lfields(2)] == 0} {
return -code error \
"bad format \"$fmt\": must have unique components for the\
day, month, and year"
}
#
# Create the widget, set its type to DateTime, and save the
# format string. If the AM/PM indicator is needed, devide it
# into an entry (containing A or P) and a label (displaying M)
#
eval [list mentry $win] $args
array set widths {d 2 m 2 y 2 Y 4}
set len [string length $fmt]
set body [list $widths($fields(0)) $dateSep $widths($fields(1)) $dateSep \
$widths($fields(2)) " " 2 $timeSep 2]
if {$len == 6} {
lappend body $timeSep 2
}
if {[string compare $fields(3) "I"] == 0} {
lappend body " " 1 M
}
::$win configure -body $body
::$win attrib type DateTime format $fmt
#
# In each of the first len entry children allow only unsigned integers
# of the corresp. max. values, and insert the binding tag MentryDateTime
# in the list of binding tags of the entry, just after its path name
#
variable dateTimeMaxs
for {set n 0} {$n < $len} {incr n} {
set w [::$win entrypath $n]
wcb::cbappend $w before insert \
"wcb::checkEntryForUInt $dateTimeMaxs($fields($n))"
::$win adjustentry $n "0123456789"
bindtags $w [linsert [bindtags $w] 1 MentryDateTime]
}
#
# In the entry child containing the first character of the AM/PM
# indicator (if present) install automatic uppercase conversion,
# allow only the characters A and P, insert the binding tag
# MentryMeridian in the list of binding tags of the entry, just
# after its path name, and make the entry right-justified
#
if {[string compare $fields(3) "I"] == 0} {
set w [::$win entrypath $len]
wcb::cbappend $w before insert \
wcb::convStrToUpper {wcb::checkStrForRegExp {^[AP]$}}
::$win adjustentry $len "AP"
bindtags $w [linsert [bindtags $w] 1 MentryMeridian]
$w configure -justify right
}
return $win
}
#------------------------------------------------------------------------------
# mentry::putClockVal
#
# Outputs the date, time, or date & time corresponding to the integer clockVal
# to the mentry widget win of type Date, Time, or DateTime. The keyword args
# stands for ?-gmt boolean?, like in the clock format command.
#------------------------------------------------------------------------------
proc mentry::putClockVal {clockVal win args} {
#
# Check whether clockVal is an integer number
#
if {[catch {format "%d" $clockVal} res] != 0} {
return -code error $res
}
set type [checkIfDateOrTimeMentry $win]
set usage "putClockVal clockValue pathName ?-gmt boolean?"
#
# Check the number of optional arguments
#
set count [llength $args]
if {$count != 0 && $count != 2} {
mwutil::wrongNumArgs $usage
}
#
# Parse the command line
#
set useGMT 0
foreach {opt val} $args {
if {[string compare $opt "-gmt"] == 0} {
#
# Get the boolean value specified by val
#
if {[catch {expr {$val ? 1 : 0}} useGMT] != 0} {
return -code error $useGMT
}
} else {
mwutil::wrongNumArgs $usage
}
}
set fmt [::$win attrib format]
#
# For each entry child of win, format clockVal according
# to the corresponding field descriptor character contained
# in fmt and to useGMT, and output the result to the entry
#
set len [string length $fmt]
for {set n 0} {$n < $len} {incr n} {
set field [string index $fmt $n]
::$win put $n [clock format $clockVal -format %$field -gmt $useGMT]
}
switch $type {
Date { return "" }
Time { set idx 0 }
DateTime { set idx 3 }
}
#
# In the entry child containing the first character of
# the AM/PM indicator (if present), display the first
# character of the corresponding time component
#
if {[string compare [string index $fmt $idx] "I"] == 0} {
if {[clock format $clockVal -format "%H"] < 12} {
::$win put $len A
} else {
::$win put $len P
}
}
}
#------------------------------------------------------------------------------
# mentry::getClockVal
#
# Returns the clock value corresponding to the date, time, or date & time
# contained in the mentry widget win of type Date, Time, or DateTime. The
# keyword args stands for ?-base clockValue? ?-gmt boolean?, like in the clock
# scan command.
#------------------------------------------------------------------------------
proc mentry::getClockVal {win args} {
set type [checkIfDateOrTimeMentry $win]
set usage "getClockVal pathName ?-base clockValue? ?-gmt boolean?"
#
# Check the number of optional arguments
#
set count [llength $args]
if {$count > 4} {
mwutil::wrongNumArgs $usage
}
#
# Parse the command line
#
set base [clock seconds]
set useGMT 0
foreach {opt val} $args {
if {$count == 1} {
mwutil::wrongNumArgs $usage
}
if {[string compare $opt "-base"] == 0} {
#
# Check whether val is an integer number
#
if {[catch {format "%d" $val} res] != 0} {
return -code error $res
}
set base $val
} elseif {[string compare $opt "-gmt"] == 0} {
#
# Get the boolean value specified by val
#
if {[catch {expr {$val ? 1 : 0}} useGMT] != 0} {
return -code error $useGMT
}
} else {
mwutil::wrongNumArgs $usage
}
incr count -2
}
switch $type {
Date { return [getClockValFromDateMentry $win $base $useGMT] }
Time { return [getClockValFromTimeMentry $win $base $useGMT] }
DateTime { return [getClockValFromDateTimeMentry $win $base $useGMT] }
}
}
#
# Private procedures implementing the mentry widgets for date & time
# ==================================================================
#
#------------------------------------------------------------------------------
# mentry::checkIfDateOrTimeMentry
#
# Generates an error if win is not a mentry widget of type Date, Time, or
# DateTime.
#------------------------------------------------------------------------------
proc mentry::checkIfDateOrTimeMentry win {
if {![winfo exists $win]} {
return -code error "bad window path name \"$win\""
}
set type [::$win attrib type]
if {[string compare [winfo class $win] "Mentry"] != 0 ||
[string compare $type "Date"] != 0 &&
[string compare $type "Time"] != 0 &&
[string compare $type "DateTime"] != 0} {
return -code error \
"window \"$win\" is not a mentry widget\
for date or time, or date & time"
}
return $type
}
#------------------------------------------------------------------------------
# mentry::getClockValFromDateMentry
#
# Returns the clock value corresponding to the date contained in the mentry
# widget win of type Date.
#------------------------------------------------------------------------------
proc mentry::getClockValFromDateMentry {win base useGMT} {
#
# Scan the contents of the entry children; generate an error if
# any of them is empty or the value of the day or month is zero
#
set fmt [::$win attrib format]
variable dateTimeMins
for {set n 0} {$n < 3} {incr n} {
set w [::$win entrypath $n]
set str [$w get]
if {[string length $str] == 0} {
focus $w
return -code error EMPTY
}
scan $str "%d" vals($n)
set field [string index $fmt $n]
if {$vals($n) < $dateTimeMins($field)} {
tabToEntry $w
return -code error BAD
}
set idxs($field) $n
}
#
# Get the year, month, and day displayed in the widget
#
if {[info exists idxs(y)]} {
set yearIdx $idxs(y)
set year $vals($yearIdx)
set yearStr [format "%02d" $year]
set format %m/%d/%y
} else {
set yearIdx $idxs(Y)
set year $vals($yearIdx)
set yearStr [format "%04d" $year]
set format %m/%d/%Y
}
set month $vals($idxs(m))
set day $vals($idxs(d))
#
# Check whether they represent a valid date
#
set dayList {0 31 28 31 30 31 30 31 31 30 31 30 31}
if {($year % 4 == 0 && $year % 100 != 0) || $year % 400 == 0} {
set dayList [lreplace $dayList 2 2 29]
}
if {$day > [lindex $dayList $month]} {
set w [::$win entrypath 0]
focus $w
$w icursor 0
return -code error BAD_DATE
}
#
# Now we have a valid date: try to convert it to an integer clock
# value; generate an error if this fails (because of the year)
#
set cmd [list clock scan $month/$day/$yearStr -base $base -gmt $useGMT]
if {$::tcl_version >= 8.5} {
lappend cmd -format $format
}
if {[catch {eval $cmd} res] == 0} {
return $res
} else {
tabToEntry [::$win entrypath $yearIdx]
return -code error BAD_YEAR
}
}
#------------------------------------------------------------------------------
# mentry::getClockValFromTimeMentry
#
# Returns the clock value corresponding to the time contained in the mentry
# widget win of type Time.
#------------------------------------------------------------------------------
proc mentry::getClockValFromTimeMentry {win base useGMT} {
#
# Scan the contents of the numeric entry children;
# generate an error if the first or second one is empty
# or the value of the hour in 12-hour format is zero
#
set fmt [::$win attrib format]
set len [string length $fmt]
set meridianFlag [expr {[string compare [string index $fmt 0] "I"] == 0}]
for {set n 0} {$n < $len} {incr n} {
set w [::$win entrypath $n]
set str [$w get]
if {[string length $str] == 0} {
if {$n == 2} {
set str 00
::$win put $n 00
} else {
focus $w
return -code error EMPTY
}
}
if {$n == 0 && $meridianFlag} {
scan $str "%d" val
if {$val < 1} {
tabToEntry $w
return -code error BAD
}
}
if {$n > 0} {
append timeStr :
}
append timeStr $str
}
#
# Generate an error if the entry that should
# contain an A or P (if present) is empty
#
if {$meridianFlag} {
set w [::$win entrypath $len]
set str [$w get]
if {[string length $str] == 0} {
focus $w
return -code error EMPTY
}
append timeStr " ${str}M"
if {$len == 2} {
set format "%I:%M %p"
} else {
set format "%I:%M:%S %p"
}
} else {
if {$len == 2} {
set format "%H:%M"
} else {
set format "%H:%M:%S"
}
}
#
# Convert the time string built from the contents
# of the widget to an integer clock value
#
if {$::tcl_version >= 8.5} {
return [clock scan $timeStr -base $base -gmt $useGMT -format $format]
} else {
return [clock scan $timeStr -base $base -gmt $useGMT]
}
}
#------------------------------------------------------------------------------
# mentry::getClockValFromDateTimeMentry
#
# Returns the clock value corresponding to the date & time contained in the
# mentry widget win of type DateTime.
#------------------------------------------------------------------------------
proc mentry::getClockValFromDateTimeMentry {win base useGMT} {
set fmt [::$win attrib format]
#
# Scan the contents of the first 3 entry children; generate an error
# if any of them is empty or the value of the day or month is zero
#
variable dateTimeMins
for {set n 0} {$n < 3} {incr n} {
set w [::$win entrypath $n]
set str [$w get]
if {[string length $str] == 0} {
focus $w
return -code error EMPTY
}
scan $str "%d" vals($n)
set field [string index $fmt $n]
if {$vals($n) < $dateTimeMins($field)} {
tabToEntry $w
return -code error BAD
}
set idxs($field) $n
}
#
# Get the year, month, and day displayed in the widget
#
if {[info exists idxs(y)]} {
set yearIdx $idxs(y)
set year $vals($yearIdx)
set yearStr [format "%02d" $year]
set format "%m/%d/%y "
} else {
set yearIdx $idxs(Y)
set year $vals($yearIdx)
set yearStr [format "%04d" $year]
set format "%m/%d/%Y "
}
set month $vals($idxs(m))
set day $vals($idxs(d))
#
# Check whether they represent a valid date
#
set dayList {0 31 28 31 30 31 30 31 31 30 31 30 31}
if {($year % 4 == 0 && $year % 100 != 0) || $year % 400 == 0} {
set dayList [lreplace $dayList 2 2 29]
}
if {$day > [lindex $dayList $month]} {
set w [::$win entrypath 0]
focus $w
$w icursor 0
return -code error BAD_DATE
}
set dateTimeStr "$month/$day/$yearStr "
#
# Scan the contents of the remaining numeric entry children;
# generate an error if the first or second one is empty
# or the value of the hour in 12-hour format is zero
#
set len [string length $fmt]
set meridianFlag [expr {[string compare [string index $fmt 3] "I"] == 0}]
for {set n 3} {$n < $len} {incr n} {
set w [::$win entrypath $n]
set str [$w get]
if {[string length $str] == 0} {
if {$n == 5} {
set str 00
::$win put $n 00
} else {
focus $w
return -code error EMPTY
}
}
if {$n == 3 && $meridianFlag} {
scan $str "%d" val
if {$val < 1} {
tabToEntry $w
return -code error BAD
}
}
if {$n > 3} {
append dateTimeStr :
}
append dateTimeStr $str
}
#
# Generate an error if the entry that should
# contain an A or P (if present) is empty
#
if {$meridianFlag} {
set w [::$win entrypath $len]
set str [$w get]
if {[string length $str] == 0} {
focus $w
return -code error EMPTY
}
append dateTimeStr " ${str}M"
if {$len == 5} {
append format "%I:%M %p"
} else {
append format "%I:%M:%S %p"
}
} else {
if {$len == 5} {
append format "%H:%M"
} else {
append format "%H:%M:%S"
}
}
#
# Now we have a valid date & time: try to convert it to an integer
# clock value; generate an error if this fails (because of the year)
#
set cmd [list clock scan $dateTimeStr -base $base -gmt $useGMT]
if {$::tcl_version >= 8.5} {
lappend cmd -format $format
}
if {[catch {eval $cmd} res] == 0} {
return $res
} else {
tabToEntry [::$win entrypath $yearIdx]
return -code error BAD_YEAR
}
}
#
# Private procedures used in bindings related to mentry widgets for date & time
# =============================================================================
#
#------------------------------------------------------------------------------
# mentry::incrDateTimeComp
#
# This procedure handles <Up>, <Down>, <Prior>, and <Next> events in the entry
# child w of a mentry widget for date, time, or date & time. It increments the
# entry's value by the specified amount if allowed.
#------------------------------------------------------------------------------
proc mentry::incrDateTimeComp {w amount} {
parseChildPath $w win n
set field [string index [::$win attrib format] $n]
set str [$w get]
if {[string length $str] == 0} {
#
# Insert the entry's min. value
#
variable dateTimeMins
set str [format "%0[::$win entrylimit $n]d" $dateTimeMins($field)]
_$w insert end $str
_$w icursor 0
} else {
#
# Increment the entry's value by the given amount if allowed
#
scan $str "%d" val
if {$amount > 0} {
variable dateTimeMaxs
if {$val < $dateTimeMaxs($field)} {
incr val $amount
if {$val > $dateTimeMaxs($field)} {
set val $dateTimeMaxs($field)
}
} else {
return ""
}
} else {
variable dateTimeMins
if {$val > $dateTimeMins($field)} {
incr val $amount
if {$val < $dateTimeMins($field)} {
set val $dateTimeMins($field)
}
} else {
return ""
}
}
set str [format "%0[::$win entrylimit $n]d" $val]
set oldPos [$w index insert]
_$w delete 0 end
_$w insert end $str
_$w icursor $oldPos
}
}
#------------------------------------------------------------------------------
# mentry::setMeridian
#
# This procedure handles <Up>, <Down>, <Prior>, and <Next> events in the entry
# child w of a mentry widget for time or date & time displaying the first
# character of the AM/PM indicator. It sets the entry's text to the specified
# value.
#------------------------------------------------------------------------------
proc mentry::setMeridian {w str} {
if {[string length [$w get]] == 0} {
#
# Insert an "A"
#
_$w insert end A
_$w icursor 0
} else {
#
# Replace the entry's text with the given value
#
set oldPos [$w index insert]
_$w delete 0 end
_$w insert end $str
_$w icursor $oldPos
}
}

142
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryFixedPoint.tcl

@ -0,0 +1,142 @@
#==============================================================================
# Contains the implementation of a multi-entry widget for real numbers in
# fixed-point format.
#
# Copyright (c) 1999-2023 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
#
# Public procedures
# =================
#
#------------------------------------------------------------------------------
# mentry::fixedPointMentry
#
# Creates a new mentry widget win that allows to display and edit real numbers
# in fixed-point format, with cnt1 characters before and cnt2 digits after the
# decimal point. Sets the type attribute of the widget to FixedPoint and
# returns the name of the newly created widget.
#------------------------------------------------------------------------------
proc mentry::fixedPointMentry {win cnt1 cnt2 args} {
#
# Check the arguments
#
if {[catch {format "%d" $cnt1}] != 0 || $cnt1 <= 0} {
return -code error "expected positive integer but got \"$cnt1\""
}
if {[catch {format "%d" $cnt2}] != 0 || $cnt2 <= 0} {
return -code error "expected positive integer but got \"$cnt2\""
}
#
# Change the default separator if the first optional argument is -comma
#
set sep .
if {[string compare [lindex $args 0] "-comma"] == 0} {
set sep ,
set args [lrange $args 1 end]
}
#
# Create the widget and set its type to FixedPoint
#
eval [list mentry $win] $args
::$win configure -body [list $cnt1 $sep $cnt2]
::$win attrib type FixedPoint
#
# Allow only integer input in the first entry
#
set w [::$win entrypath 0]
wcb::cbappend $w before insert wcb::checkEntryForInt
::$win adjustentry 0 "0123456789" "+-"
$w configure -justify right
#
# Allow only decimal digits in the second entry
#
set w [::$win entrypath 1]
wcb::cbappend $w before insert wcb::checkStrForNum
::$win adjustentry 1 "0123456789"
$w configure -justify left
return $win
}
#------------------------------------------------------------------------------
# mentry::putReal
#
# Outputs the number num to the mentry widget win of type FixedPoint.
#------------------------------------------------------------------------------
proc mentry::putReal {num win} {
checkIfFixedPointMentry $win
#
# Get the expected number of digits after the decimal point
# from the value of the -body configuration option of
# the mentry win and format the number num accordingly
#
set body [::$win cget -body]
if {[catch {format "%.*f" [lindex $body 2] $num} str] != 0} {
return -code error $str
}
#
# Check whether the result of the format command fits into the widget
#
set lst [split $str .]
if {[string length [lindex $lst 0]] > [lindex $body 0]} {
return -code error \
"the string \"$str\" does not fit into the mentry widget\
\"$win\""
}
eval [list ::$win put 0] $lst
}
#------------------------------------------------------------------------------
# mentry::getReal
#
# Returns the number contained in the mentry widget win of type FixedPoint.
#------------------------------------------------------------------------------
proc mentry::getReal win {
checkIfFixedPointMentry $win
#
# Generate an error if the widget is empty
#
if {[::$win isempty]} {
focus [::$win entrypath 0]
return -code error EMPTY
}
#
# Scan the contents of the widget
#
::$win getarray strs
scan $strs(0).$strs(1) "%f" val
return $val
}
#
# Private procedure
# =================
#
#------------------------------------------------------------------------------
# mentry::checkIfFixedPointMentry
#
# Generates an error if win is not a mentry widget of type FixedPoint.
#------------------------------------------------------------------------------
proc mentry::checkIfFixedPointMentry win {
if {![winfo exists $win]} {
return -code error "bad window path name \"$win\""
}
if {[string compare [winfo class $win] "Mentry"] != 0 ||
[string compare [::$win attrib type] "FixedPoint"] != 0} {
return -code error \
"window \"$win\" is not a mentry widget for fixed-point numbers"
}
}

244
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryIPAddr.tcl

@ -0,0 +1,244 @@
#==============================================================================
# Contains the implementation of a multi-entry widget for IP addresses.
#
# Copyright (c) 1999-2023 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
#
# Namespace initialization
# ========================
#
namespace eval mentry {
#
# Define some bindings for the binding tag MentryIPAddr
#
bind MentryIPAddr <Up> { mentry::incrIPAddrComp %W 1 }
bind MentryIPAddr <Down> { mentry::incrIPAddrComp %W -1 }
bind MentryIPAddr <Prior> { mentry::incrIPAddrComp %W 10 }
bind MentryIPAddr <Next> { mentry::incrIPAddrComp %W -10 }
bind MentryIPAddr <<Paste>> { mentry::pasteIPAddr %W }
variable winSys
variable uniformWheelSupport
if {$uniformWheelSupport} {
bind MentryIPAddr <MouseWheel> {
mentry::incrIPAddrComp %W \
[expr {%D > 0 ? (%D + 119) / 120 : %D / 120}]
}
bind MentryIPAddr <Option-MouseWheel> {
mentry::incrIPAddrComp %W \
[expr {%D > 0 ? (%D + 11) / 12 : %D / 12}]
}
} elseif {[string compare $winSys "classic"] == 0 ||
[string compare $winSys "aqua"] == 0} {
catch {
bind MentryIPAddr <MouseWheel> {
mentry::incrIPAddrComp %W %D
}
bind MentryIPAddr <Option-MouseWheel> {
mentry::incrIPAddrComp %W [expr {10 * %D}]
}
}
} else {
catch {
bind MentryIPAddr <MouseWheel> {
mentry::incrIPAddrComp %W \
[expr {%D > 0 ? (%D + 119) / 120 : %D / 120}]
}
}
if {[string compare $winSys "x11"] == 0} {
bind MentryIPAddr <Button-4> {
if {!$tk_strictMotif} {
mentry::incrIPAddrComp %W 1
}
}
bind MentryIPAddr <Button-5> {
if {!$tk_strictMotif} {
mentry::incrIPAddrComp %W -1
}
}
}
}
}
#
# Public procedures
# =================
#
#------------------------------------------------------------------------------
# mentry::ipAddrMentry
#
# Creates a new mentry widget win that allows to display and edit IP addresses.
# Sets the type attribute of the widget to IPAddr and returns the name of the
# newly created widget.
#------------------------------------------------------------------------------
proc mentry::ipAddrMentry {win args} {
#
# Create the widget and set its type to IPAddr
#
eval [list mentry $win] $args
::$win configure -body {3 . 3 . 3 . 3}
::$win attrib type IPAddr
#
# In each entry component allow only unsigned integers of max.
# value 255, and insert the binding tag MentryIPAddr in the
# list of binding tags of the entry, just after its path name
#
for {set n 0} {$n < 4} {incr n} {
set w [::$win entrypath $n]
wcb::cbappend $w before insert "wcb::checkEntryForUInt 255"
::$win adjustentry $n "0123456789"
bindtags $w [linsert [bindtags $w] 1 MentryIPAddr]
}
return $win
}
#------------------------------------------------------------------------------
# mentry::putIPAddr
#
# Outputs the IP address addr to the mentry widget win of type IPAddr.
#------------------------------------------------------------------------------
proc mentry::putIPAddr {addr win} {
set errorMsg "expected an IP address but got \"$addr\""
#
# Check the syntax of addr
#
set lst [split $addr .]
if {[llength $lst] != 4} {
return -code error $errorMsg
}
#
# Try to convert the four components of addr to decimal
# strings and check whether they are in the range 0 - 255
#
for {set n 0} {$n < 4} {incr n} {
set val [lindex $lst $n]
if {[catch {format "%d" $val} str$n] != 0 || $val < 0 || $val > 255} {
return -code error $errorMsg
}
}
checkIfIPAddrMentry $win
::$win put 0 $str0 $str1 $str2 $str3
}
#------------------------------------------------------------------------------
# mentry::getIPAddr
#
# Returns the IP address contained in the mentry widget win of type IPAddr.
#------------------------------------------------------------------------------
proc mentry::getIPAddr win {
checkIfIPAddrMentry $win
#
# Scan the contents of the entry components;
# generate an error if any of them is empty
#
for {set n 0} {$n < 4} {incr n} {
set w [::$win entrypath $n]
set str [$w get]
if {[string length $str] == 0} {
focus $w
return -code error EMPTY
}
scan $str "%d" val$n
}
return $val0.$val1.$val2.$val3
}
#
# Private procedures
# ==================
#
#------------------------------------------------------------------------------
# mentry::checkIfIPAddrMentry
#
# Generates an error if win is not a mentry widget of type IPAddr.
#------------------------------------------------------------------------------
proc mentry::checkIfIPAddrMentry win {
if {![winfo exists $win]} {
return -code error "bad window path name \"$win\""
}
if {[string compare [winfo class $win] "Mentry"] != 0 ||
[string compare [::$win attrib type] "IPAddr"] != 0} {
return -code error \
"window \"$win\" is not a mentry widget for IP addresses"
}
}
#------------------------------------------------------------------------------
# mentry::incrIPAddrComp
#
# This procedure handles <Up>, <Down>, <Prior>, and <Next> events in the entry
# component w of a mentry widget for IP addresses. It increments the entry's
# value by the specified amount if allowed.
#------------------------------------------------------------------------------
proc mentry::incrIPAddrComp {w amount} {
set str [$w get]
if {[string length $str] == 0} {
#
# Insert a "0"
#
_$w insert end 0
_$w icursor 0
} else {
#
# Increment the entry's value by the given amount if allowed
#
scan $str "%d" val
if {$amount > 0} {
if {$val < 255} {
incr val $amount
if {$val > 255} {
set val 255
}
} else {
return ""
}
} else {
if {$val > 0} {
incr val $amount
if {$val < 0} {
set val 0
}
} else {
return ""
}
}
set str [format "%d" $val]
set oldPos [$w index insert]
_$w delete 0 end
_$w insert end $str
_$w icursor $oldPos
}
}
#------------------------------------------------------------------------------
# mentry::pasteIPAddr
#
# This procedure handles <<Paste>> events in the entry component w of a mentry
# widget for IP addresses by pasting the current contents of the clipboard into
# the mentry if it is a valid IP address.
#------------------------------------------------------------------------------
proc mentry::pasteIPAddr w {
if {[llength [info procs ::tk::GetSelection]] == 1} {
set res [catch {::tk::GetSelection $w CLIPBOARD} addr]
} else { ;# for Tk versions prior to 8.3
set res [catch {selection get -displayof $w -selection CLIPBOARD} addr]
}
if {$res == 0} {
parseChildPath $w win n
catch { putIPAddr $addr $win }
}
return -code break ""
}

282
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryIPv6Addr.tcl

@ -0,0 +1,282 @@
#==============================================================================
# Contains the implementation of a multi-entry widget for IPv6 addresses.
#
# Copyright (c) 2009-2023 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
#
# Namespace initialization
# ========================
#
namespace eval mentry {
#
# Define some bindings for the binding tag MentryIPv6Addr
#
bind MentryIPv6Addr <Up> { mentry::incrIPv6AddrComp %W 1 }
bind MentryIPv6Addr <Down> { mentry::incrIPv6AddrComp %W -1 }
bind MentryIPv6Addr <Prior> { mentry::incrIPv6AddrComp %W 10 }
bind MentryIPv6Addr <Next> { mentry::incrIPv6AddrComp %W -10 }
bind MentryIPv6Addr <<Paste>> { mentry::pasteIPv6Addr %W }
variable winSys
variable uniformWheelSupport
if {$uniformWheelSupport} {
bind MentryIPv6Addr <MouseWheel> {
mentry::incrIPv6AddrComp %W \
[expr {%D > 0 ? (%D + 119) / 120 : %D / 120}]
}
bind MentryIPv6Addr <Option-MouseWheel> {
mentry::incrIPv6AddrComp %W \
[expr {%D > 0 ? (%D + 11) / 12 : %D / 12}]
}
} elseif {[string compare $winSys "classic"] == 0 ||
[string compare $winSys "aqua"] == 0} {
catch {
bind MentryIPv6Addr <MouseWheel> {
mentry::incrIPv6AddrComp %W %D
}
bind MentryIPv6Addr <Option-MouseWheel> {
mentry::incrIPv6AddrComp %W [expr {10 * %D}]
}
}
} else {
catch {
bind MentryIPv6Addr <MouseWheel> {
mentry::incrIPv6AddrComp %W \
[expr {%D > 0 ? (%D + 11) / 12 : %D / 12}]
}
}
if {[string compare $winSys "x11"] == 0} {
bind MentryIPv6Addr <Button-4> {
if {!$tk_strictMotif} {
mentry::incrIPv6AddrComp %W 1
}
}
bind MentryIPv6Addr <Button-5> {
if {!$tk_strictMotif} {
mentry::incrIPv6AddrComp %W -1
}
}
}
}
}
#
# Public procedures
# =================
#
#------------------------------------------------------------------------------
# mentry::ipv6AddrMentry
#
# Creates a new mentry widget win that allows to display and edit IPv6
# addresses. Sets the type attribute of the widget to IPv6Addr and returns the
# name of the newly created widget.
#------------------------------------------------------------------------------
proc mentry::ipv6AddrMentry {win args} {
#
# Create the widget and set its type to IPv6Addr
#
eval [list mentry $win] $args
::$win configure -body {4 : 4 : 4 : 4 : 4 : 4 : 4 : 4}
::$win attrib type IPv6Addr
#
# In each entry component allow only hexadecimal digits, and
# insert the binding tag MentryIPv6Addr in the list of
# binding tags of the entry, just after its path name
#
for {set n 0} {$n < 8} {incr n} {
set w [::$win entrypath $n]
wcb::cbappend $w before insert wcb::convStrToLower \
{wcb::checkStrForRegExp {^[0-9a-fA-F]*$}}
::$win adjustentry $n "0123456789abcdefABCDEF"
bindtags $w [linsert [bindtags $w] 1 MentryIPv6Addr]
}
return $win
}
#------------------------------------------------------------------------------
# mentry::putIPv6Addr
#
# Outputs the IPv6 address addr to the mentry widget win of type IPv6Addr.
#------------------------------------------------------------------------------
proc mentry::putIPv6Addr {addr win} {
set errorMsg "expected an IPv6 address but got \"$addr\""
#
# Check the syntax of addr
#
if {[string match "*::*::*" $addr] || [string match "*:::*" $addr] ||
[regexp {^:[^:]} $addr] || [regexp {[^:]:$} $addr]} {
return -code error $errorMsg
}
#
# Split addr on colons; make sure that a starting or
# trailing "::" will give rise to a single empty string
#
if {[string compare $addr "::"] == 0} {
set lst [list ""]
} elseif {[regexp {^::(.+)} $addr dummy var]} {
set lst [list ""]
eval lappend lst [split $var ":"]
} elseif {[regexp {(.+)::$} $addr dummy var]} {
set lst [split $var ":"]
lappend lst ""
} else {
set lst [split $addr ":"]
}
#
# Replace the unique empty element of the list
# (if any) with an appropriate number of zeros
#
set emptyIdx [lsearch -exact $lst ""]
set lstLen [llength $lst]
if {$emptyIdx < 0} {
if {$lstLen != 8} {
return -code error $errorMsg
}
} else {
if {$lstLen > 8} {
return -code error $errorMsg
}
set count [expr {9 - $lstLen}]
for {set n 0} {$n < $count} {incr n} {
lappend lst2 0
}
set lst [eval lreplace {$lst} $emptyIdx $emptyIdx $lst2]
}
#
# Try to convert the 8 elements of the list to hexadecimal
# strings and check whether they are in the range 0 - 65535
#
for {set n 0} {$n < 8} {incr n} {
set val 0x[lindex $lst $n]
if {[catch {format "%x" $val} str$n] != 0 | $val > 65535} {
return -code error $errorMsg
}
}
checkIfIPv6AddrMentry $win
::$win put 0 $str0 $str1 $str2 $str3 $str4 $str5 $str6 $str7
}
#------------------------------------------------------------------------------
# mentry::getIPv6Addr
#
# Returns the IPv6 address contained in the mentry widget win of type IPv6Addr.
#------------------------------------------------------------------------------
proc mentry::getIPv6Addr win {
checkIfIPv6AddrMentry $win
#
# Generate an error if any entry component is empty
#
for {set n 0} {$n < 8} {incr n} {
if {[::$win isempty $n]} {
focus [::$win entrypath $n]
return -code error EMPTY
}
}
::$win getarray strs
return [format "%x:%x:%x:%x:%x:%x:%x:%x" \
0x$strs(0) 0x$strs(1) 0x$strs(2) 0x$strs(3) \
0x$strs(4) 0x$strs(5) 0x$strs(6) 0x$strs(7)]
}
#
# Private procedures
# ==================
#
#------------------------------------------------------------------------------
# mentry::checkIfIPv6AddrMentry
#
# Generates an error if win is not a mentry widget of type IPv6Addr.
#------------------------------------------------------------------------------
proc mentry::checkIfIPv6AddrMentry win {
if {![winfo exists $win]} {
return -code error "bad window path name \"$win\""
}
if {[string compare [winfo class $win] "Mentry"] != 0 ||
[string compare [::$win attrib type] "IPv6Addr"] != 0} {
return -code error \
"window \"$win\" is not a mentry widget for IPv6 addresses"
}
}
#------------------------------------------------------------------------------
# mentry::incrIPv6AddrComp
#
# This procedure handles <Up>, <Down>, <Prior>, and <Next> events in the entry
# component w of a mentry widget for IPv6 addresses. It increments the entry's
# value by the specified amount if allowed.
#------------------------------------------------------------------------------
proc mentry::incrIPv6AddrComp {w amount} {
set str [$w get]
if {[string length $str] == 0} {
#
# Insert a "0"
#
_$w insert end 0
_$w icursor 0
} else {
#
# Increment the entry's value by the given amount if allowed
#
scan $str "%x" val
if {$amount > 0} {
if {$val < 65535} {
incr val $amount
if {$val > 65535} {
set val 65535
}
} else {
return ""
}
} else {
if {$val > 0} {
incr val $amount
if {$val < 0} {
set val 0
}
} else {
return ""
}
}
set str [format "%x" $val]
set oldPos [$w index insert]
_$w delete 0 end
_$w insert end $str
_$w icursor $oldPos
}
}
#------------------------------------------------------------------------------
# mentry::pasteIPv6Addr
#
# This procedure handles <<Paste>> events in the entry component w of a mentry
# widget for IPv6 addresses by pasting the current contents of the clipboard
# into the mentry if it is a valid IPv6 address.
#------------------------------------------------------------------------------
proc mentry::pasteIPv6Addr w {
if {[llength [info procs ::tk::GetSelection]] == 1} {
set res [catch {::tk::GetSelection $w CLIPBOARD} addr]
} else { ;# for Tk versions prior to 8.3
set res [catch {selection get -displayof $w -selection CLIPBOARD} addr]
}
if {$res == 0} {
parseChildPath $w win n
catch { putIPv6Addr $addr $win }
}
return -code break ""
}

675
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryThemes.tcl

@ -0,0 +1,675 @@
#==============================================================================
# Contains procedures that populate the array themeDefaults with theme-specific
# values of some mentry configuration options.
#
# Structure of the module:
# - Public procedure related to tile themes
# - Private procedures related to tile themes
# - Private procedures related to global KDE configuration options
#
# Copyright (c) 2006-2023 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
#
# Public procedure related to tile themes
# =======================================
#
#------------------------------------------------------------------------------
# mentry::setThemeDefaults
#
# Populates the array themeDefaults with theme-specific default values of some
# mentry configuration options and updates the array configSpecs.
#------------------------------------------------------------------------------
proc mentry::setThemeDefaults {} {
#
# For several themes, some of the following most frequent
# values will be overridden by theme-specific ones:
#
variable themeDefaults
array set themeDefaults [list \
-background white \
-disabledbackground "" \
-foreground black \
-foreground,background black \
-font TkTextFont \
]
if {[info exists themeDefaults(-readonlybackground)]} {
unset themeDefaults(-readonlybackground)
}
set currentTheme [::mwutil::currentTheme]
variable isAwTheme \
[llength [info commands ::ttk::theme::${currentTheme}::setTextColors]]
if {$isAwTheme} {
awTheme $currentTheme
} elseif {[catch {${currentTheme}Theme}] != 0} {
#
# Fall back to the "default" theme (which is the root of all
# themes) and then override the options set by the current one
#
defaultTheme
array set themeDefaults [styleConfig .]
if {[set bg [styleConfig TEntry -fieldbackground]] eq ""} {
set bg [styleConfig . -fieldbackground]
}
if {$bg ne ""} {
set themeDefaults(-background) $bg
}
if {[set fg [styleConfig TEntry -foreground]] eq ""} {
set fg [styleConfig . -foreground]
}
if {$fg ne ""} {
set themeDefaults(-foreground) $fg
}
set themeDefaults(-foreground,background) $themeDefaults(-foreground)
set disabledBg ""
array set arr [style map TEntry -fieldbackground]
if {[info exists arr(disabled)]} {
set disabledBg $arr(disabled)
} else {
array set arr [style map . -fieldbackground]
if {[info exists arr(disabled)]} {
set disabledBg $arr(disabled)
}
}
set themeDefaults(-disabledbackground) $disabledBg ;# may be ""
set disabledFg ""
unset arr
array set arr [style map TEntry -foreground]
if {[info exists arr(disabled)]} {
set disabledFg $arr(disabled)
} else {
array set arr [style map . -foreground]
if {[info exists arr(disabled)]} {
set disabledFg $arr(disabled)
}
}
if {$disabledFg ne ""} {
set themeDefaults(-disabledforeground) $disabledFg
}
set themeDefaults(-borderwidth) 2 ;# just a guess
set themeDefaults(-labelpady) {2 2} ;# just a guess
}
if {![info exists themeDefaults(-readonlybackground)]} {
set themeDefaults(-readonlybackground) \
$themeDefaults(-disabledbackground)
}
variable configSpecs
foreach opt {-background -foreground -font} {
if {[llength $configSpecs($opt)] < 4} {
lappend configSpecs($opt) $themeDefaults($opt)
} else {
lset configSpecs($opt) 3 $themeDefaults($opt)
}
}
}
#
# Private procedures related to tile themes
# =========================================
#
#------------------------------------------------------------------------------
# mentry::awTheme
#------------------------------------------------------------------------------
proc mentry::awTheme theme {
switch $theme {
awarc - arc -
awbreeze - breeze -
awbreezedark { set bdWidth 3; set labelPadY {3 3} }
awblack - black -
awclearlooks - clearlooks -
awdark -
awlight -
awtemplate -
awwinxpblue - winxpblue -
default { set bdWidth 2; set labelPadY {2 2} }
}
variable themeDefaults
array set themeDefaults [list \
-background [styleConfig . -fieldbackground] \
-disabledbackground [lindex [style map TEntry -fieldbackground] 1] \
-foreground [styleConfig TEntry -foreground] \
-foreground,background [styleConfig TEntry -foreground] \
-disabledforeground [lindex [style map TEntry -foreground] 1] \
-selectbackground [styleConfig . -selectbackground] \
-selectforeground [styleConfig . -selectforeground] \
-selectborderwidth [styleConfig . -selectborderwidth] \
-borderwidth $bdWidth \
-labelpady $labelPadY \
]
}
#------------------------------------------------------------------------------
# mentry::altTheme
#------------------------------------------------------------------------------
proc mentry::altTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledbackground #d9d9d9 \
-disabledforeground #a3a3a3 \
-selectbackground #4a6984 \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::aquaTheme
#------------------------------------------------------------------------------
proc mentry::aquaTheme {} {
variable newAquaSupport
variable themeDefaults
if {$newAquaSupport} {
variable extendedAquaSupport
if {[tk::unsupported::MacWindowStyle isdark .]} {
set background [expr {$extendedAquaSupport ? "#3a3a3a" : "#4b4b4b"}]
} else {
set background #ffffff
}
if {$extendedAquaSupport} {
scan $::tcl_platform(osVersion) "%d" majorOSVersion
set labelPadY [expr {$majorOSVersion >= 18 ? {4 7} : {4 5}}]
} else {
set labelPadY {4 7}
}
array set themeDefaults [list \
-background $background \
-foreground systemTextColor \
-foreground,background systemTextColor \
-disabledforeground systemDisabledControlTextColor \
-selectbackground systemSelectedTextBackgroundColor \
-selectforeground systemSelectedTextColor \
-selectborderwidth 0 \
-borderwidth 4 \
-labelpady $labelPadY \
]
} else {
array set themeDefaults [list \
-background systemWindowBody \
-foreground systemModelessDialogActiveText \
-foreground,background systemModelessDialogInactiveText \
-disabledforeground systemModelessDialogInactiveText \
-selectbackground systemHighlight \
-selectforeground systemModelessDialogActiveText \
-selectborderwidth 0 \
-borderwidth 4 \
-labelpady {4 4} \
]
}
}
#------------------------------------------------------------------------------
# mentry::AquativoTheme
#------------------------------------------------------------------------------
proc mentry::AquativoTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledforeground black \
-selectbackground #000000 \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::aquativoTheme
#------------------------------------------------------------------------------
proc mentry::aquativoTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledforeground #565248 \
-selectbackground #000000 \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::ArcTheme
#------------------------------------------------------------------------------
proc mentry::ArcTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledbackground #fbfcfc \
-foreground #5c616c \
-foreground,background #5c616c \
-disabledforeground #a9acb2 \
-selectbackground #5294e2 \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 3 \
-labelpady {3 3} \
]
}
#------------------------------------------------------------------------------
# mentry::blueTheme
#------------------------------------------------------------------------------
proc mentry::blueTheme {} {
variable themeDefaults
array set themeDefaults [list \
-background #e6f3ff \
-disabledforeground #666666 \
-selectbackground #ffff33 \
-selectforeground #000000 \
-selectborderwidth 1 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::clamTheme
#------------------------------------------------------------------------------
proc mentry::clamTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledforeground #999999 \
-selectbackground #4a6984 \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::classicTheme
#------------------------------------------------------------------------------
proc mentry::classicTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledbackground #d9d9d9 \
-disabledforeground #a3a3a3 \
-selectbackground #c3c3c3 \
-selectforeground #000000 \
-selectborderwidth 1 \
-borderwidth 3 \
-labelpady {3 3} \
]
}
#------------------------------------------------------------------------------
# mentry::clearlooksTheme
#------------------------------------------------------------------------------
proc mentry::clearlooksTheme {} {
variable themeDefaults
array set themeDefaults [list \
-readonlybackground #efebe7 \
-disabledforeground #b5b3ac \
-selectbackground #7c99ad \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::defaultTheme
#------------------------------------------------------------------------------
proc mentry::defaultTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledbackground #d9d9d9 \
-disabledforeground #a3a3a3 \
-selectbackground #4a6984 \
-selectforeground #ffffff \
-selectborderwidth 1 \
-borderwidth 1 \
-labelpady {1 1} \
]
}
#------------------------------------------------------------------------------
# mentry::keramikTheme
#------------------------------------------------------------------------------
proc mentry::keramikTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledforeground #aaaaaa \
-selectbackground #0a5f89 \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::keramik_altTheme
#------------------------------------------------------------------------------
proc mentry::keramik_altTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledforeground #aaaaaa \
-selectbackground #0a5f89 \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::krocTheme
#------------------------------------------------------------------------------
proc mentry::krocTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledforeground #b2b2b2 \
-selectbackground #000000 \
-selectforeground #ffffff \
-selectborderwidth 1 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::plastikTheme
#------------------------------------------------------------------------------
proc mentry::plastikTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledforeground #aaaaaa \
-selectbackground #657a9e \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::srivTheme
#------------------------------------------------------------------------------
proc mentry::srivTheme {} {
variable themeDefaults
array set themeDefaults [list \
-background #e6f3ff \
-disabledforeground #666666 \
-selectbackground #ffff33 \
-selectforeground #000000 \
-selectborderwidth 1 \
-borderwidth 1 \
-labelpady {1 1} \
]
}
#------------------------------------------------------------------------------
# mentry::srivlgTheme
#------------------------------------------------------------------------------
proc mentry::srivlgTheme {} {
variable themeDefaults
array set themeDefaults [list \
-background #e6f3ff \
-disabledforeground #666666 \
-selectbackground #ffff33 \
-selectforeground #000000 \
-selectborderwidth 1 \
-borderwidth 3 \
-labelpady {3 3} \
]
}
#------------------------------------------------------------------------------
# mentry::stepTheme
#------------------------------------------------------------------------------
proc mentry::stepTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledforeground #808080 \
-selectbackground #fdcd00 \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::tileqtTheme
#------------------------------------------------------------------------------
proc mentry::tileqtTheme {} {
set mentryBg [tileqt_currentThemeColour -base]
set mentryDisBg [tileqt_currentThemeColour -disabled -base]
set mentryFg [tileqt_currentThemeColour -text]
set mentryDisFg [tileqt_currentThemeColour -disabled -text]
set selectBg [tileqt_currentThemeColour -highlight]
set selectFg [tileqt_currentThemeColour -highlightedText]
variable themeDefaults
array set themeDefaults [list \
-background $mentryBg \
-disabledbackground $mentryDisBg \
-foreground $mentryFg \
-foreground,background $mentryFg \
-disabledforeground $mentryDisFg \
-selectbackground $selectBg \
-selectforeground $selectFg \
-selectborderwidth 0 \
-borderwidth 3 \
-labelpady {3 3} \
]
}
#------------------------------------------------------------------------------
# mentry::vistaTheme
#------------------------------------------------------------------------------
proc mentry::vistaTheme {} {
variable themeDefaults
array set themeDefaults [list \
-background SystemWindow \
-disabledbackground SystemButtonFace \
-foreground SystemWindowText \
-foreground,background SystemWindowText \
-disabledforeground SystemDisabledText \
-selectbackground SystemHighlight \
-selectforeground SystemHighlightText \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::winnativeTheme
#------------------------------------------------------------------------------
proc mentry::winnativeTheme {} {
variable themeDefaults
array set themeDefaults [list \
-background SystemWindow \
-disabledbackground SystemButtonFace \
-foreground SystemWindowText \
-foreground,background SystemWindowText \
-disabledforeground SystemDisabledText \
-selectbackground SystemHighlight \
-selectforeground SystemHighlightText \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::winxpblueTheme
#------------------------------------------------------------------------------
proc mentry::winxpblueTheme {} {
variable themeDefaults
array set themeDefaults [list \
-disabledforeground #565248 \
-selectbackground #4a6984 \
-selectforeground #ffffff \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 2} \
]
}
#------------------------------------------------------------------------------
# mentry::xpnativeTheme
#------------------------------------------------------------------------------
proc mentry::xpnativeTheme {} {
variable themeDefaults
array set themeDefaults [list \
-background SystemWindow \
-disabledbackground SystemButtonFace \
-foreground SystemWindowText \
-foreground,background SystemWindowText \
-disabledforeground SystemDisabledText \
-selectbackground SystemHighlight \
-selectforeground SystemHighlightText \
-selectborderwidth 0 \
-borderwidth 2 \
-labelpady {2 4} \
]
}
#
# Private procedures related to global KDE configuration options
# ==============================================================
#
#------------------------------------------------------------------------------
# mentry::getKdeConfigVal
#
# Returns the value of the global KDE configuration option identified by the
# given group (section) and key.
#------------------------------------------------------------------------------
proc mentry::getKdeConfigVal {group key} {
variable kdeDirList
if {![info exists kdeDirList]} {
makeKdeDirList
}
#
# Search for the entry corresponding to the given group and key in
# the file "share/config/kdeglobals" within the KDE directories
#
foreach dir $kdeDirList {
set fileName [file join $dir "share/config/kdeglobals"]
if {[set val [readKdeConfigVal $fileName $group $key]] ne ""} {
return $val
}
}
return ""
}
#------------------------------------------------------------------------------
# mentry::makeKdeDirList
#
# Builds the list of the directories to be considered when searching for global
# KDE configuration options.
#------------------------------------------------------------------------------
proc mentry::makeKdeDirList {} {
variable kdeDirList {}
if {[info exists ::env(KDE_SESSION_VERSION)]} {
set ver $::env(KDE_SESSION_VERSION)
} else {
set ver ""
}
if {[info exists ::env(USER)] && $::env(USER) eq "root"} {
set name "KDEROOTHOME"
} else {
set name "KDEHOME"
}
if {[info exists ::env($name)] && $::env($name) ne ""} {
set localKdeDir [file normalize $::env($name)]
} elseif {[info exists ::env(HOME)] && $::env(HOME) ne ""} {
set localKdeDir [file normalize [file join $::env(HOME) ".kde$ver"]]
}
if {[info exists localKdeDir] && $localKdeDir ne "-"} {
lappend kdeDirList $localKdeDir
}
if {[info exists ::env(KDEDIRS)] && $::env(KDEDIRS) ne ""} {
foreach dir [split $::env(KDEDIRS) ":"] {
if {$dir ne ""} {
lappend kdeDirList $dir
}
}
} elseif {[info exists ::env(KDEDIR)] && $::env(KDEDIR) ne ""} {
lappend kdeDirList $::env(KDEDIR)
}
set prefix [exec kde$ver-config --expandvars --prefix]
lappend kdeDirList $prefix
set execPrefix [exec kde$ver-config --expandvars --exec-prefix]
if {$execPrefix ne $prefix} {
lappend kdeDirList $execPrefix
}
}
#------------------------------------------------------------------------------
# mentry::readKdeConfigVal
#
# Reads the value of the global KDE configuration option identified by the
# given group (section) and key from the specified file. Note that the
# procedure performs a case-sensitive search and only works as expected for
# "simple" group and key names.
#------------------------------------------------------------------------------
proc mentry::readKdeConfigVal {fileName group key} {
if {[catch {open $fileName r} chan] != 0} {
return ""
}
#
# Search for the specified group
#
set groupFound 0
while {[gets $chan line] >= 0} {
set line [string trim $line]
if {$line eq "\[$group\]"} {
set groupFound 1
break
}
}
if {!$groupFound} {
close $chan
return ""
}
#
# Search for the specified key within the group
#
set pattern "^$key\\s*=\\s*(.+)$"
set keyFound 0
while {[gets $chan line] >= 0} {
set line [string trim $line]
if {[string range $line 0 0] eq "\["} {
break
}
if {[regexp $pattern $line dummy val]} {
set keyFound 1
break
}
}
close $chan
return [expr {$keyFound ? $val : ""}]
}

2404
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mentryWidget.tcl

File diff suppressed because it is too large Load Diff

760
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mwutil/mwutil.tcl

@ -0,0 +1,760 @@
#==============================================================================
# Contains utility procedures for mega-widgets.
#
# Structure of the module:
# - Namespace initialization
# - Public utility procedures
#
# Copyright (c) 2000-2023 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
package require Tk 8
#
# Namespace initialization
# ========================
#
namespace eval mwutil {
#
# Public variables:
#
variable version 2.20
variable library
if {$::tcl_version >= 8.4} {
set library [file dirname [file normalize [info script]]]
} else {
set library [file dirname [info script]] ;# no "file normalize" yet
}
#
# Public procedures:
#
namespace export wrongNumArgs getAncestorByClass convEventFields \
defineKeyNav processTraversal focusNext focusPrev \
configureWidget fullConfigOpt fullOpt enumOpts \
configureSubCmd attribSubCmd hasattribSubCmd \
unsetattribSubCmd getScrollInfo getScrollInfo2 \
isScrollable scrollByUnits genMouseWheelEvent \
containsPointer hasFocus windowingSystem currentTheme \
normalizeColor parsePadding
#
# Make modified versions of the procedures tk_focusNext and
# tk_focusPrev, to be invoked in the processTraversal command
#
proc makeFocusProcs {} {
#
# Enforce the evaluation of the Tk library file "focus.tcl"
#
tk_focusNext .
#
# Build the procedures focusNext and focusPrev
#
foreach dir {Next Prev} {
set procBody [info body tk_focus$dir]
regsub -all {winfo children} $procBody {getChildren $class} procBody
proc focus$dir {w class} $procBody
}
}
makeFocusProcs
#
# Invoked in the procedures focusNext and focusPrev defined above:
#
proc getChildren {class w} {
if {[string compare [winfo class $w] $class] == 0} {
return {}
} else {
return [winfo children $w]
}
}
}
package provide mwutil $mwutil::version
#
# Public utility procedures
# =========================
#
#------------------------------------------------------------------------------
# mwutil::wrongNumArgs
#
# Generates a "wrong # args" error message.
#------------------------------------------------------------------------------
proc mwutil::wrongNumArgs args {
set optList {}
foreach arg $args {
lappend optList \"$arg\"
}
return -code error "wrong # args: should be [enumOpts $optList]"
}
#------------------------------------------------------------------------------
# mwutil::getAncestorByClass
#
# Gets the path name of the widget of the specified class from the path name w
# of one of its descendants. It is assumed that all of the ancestors of w
# exist (but w itself needn't exist).
#------------------------------------------------------------------------------
proc mwutil::getAncestorByClass {w class} {
if {[regexp {^\.[^.]+$} $w]} {
return [expr {[string compare [winfo class .] $class] == 0 ? "." : ""}]
} elseif {[regexp {^(\..+)\.[^.]+$} $w dummy win]} {
while {[winfo exists $win]} {
if {[string compare [winfo class $win] $class] == 0} {
return $win
} else {
set win [winfo parent $win]
}
}
return ""
} else {
return ""
}
}
#------------------------------------------------------------------------------
# mwutil::convEventFields
#
# Gets the path name of the widget of the specified class and the x and y
# coordinates relative to the latter from the path name w of one of its
# descendants and from the x and y coordinates relative to the latter.
#------------------------------------------------------------------------------
proc mwutil::convEventFields {w x y class} {
set win [getAncestorByClass $w $class]
set _x [expr {$x + [winfo rootx $w] - [winfo rootx $win]}]
set _y [expr {$y + [winfo rooty $w] - [winfo rooty $win]}]
return [list $win $_x $_y]
}
#------------------------------------------------------------------------------
# mwutil::defineKeyNav
#
# For a given mega-widget class, the procedure defines the binding tag
# ${class}KeyNav as a partial replacement for "all", by substituting the
# scripts bound to the events <Tab>, <Shift-Tab>, and <<PrevWindow>> with new
# ones which propagate these events to the mega-widget of the given class
# containing the widget to which the event was reported. (The event
# <Shift-Tab> was replaced with <<PrevWindow>> in Tk 8.3.0.) This tag is
# designed to be inserted before "all" in the list of binding tags of a
# descendant of a mega-widget of the specified class.
#------------------------------------------------------------------------------
proc mwutil::defineKeyNav class {
foreach event {<Tab> <Shift-Tab> <<PrevWindow>>} {
bind ${class}KeyNav $event \
[list mwutil::processTraversal %W $class $event]
}
bind Entry <<TraverseIn>> { %W selection range 0 end; %W icursor end }
bind Spinbox <<TraverseIn>> { %W selection range 0 end; %W icursor end }
}
#------------------------------------------------------------------------------
# mwutil::processTraversal
#
# Processes the given traversal event for the mega-widget of the specified
# class containing the widget w if that mega-widget is not the only widget
# receiving the focus during keyboard traversal within its toplevel widget.
#------------------------------------------------------------------------------
proc mwutil::processTraversal {w class event} {
set win [getAncestorByClass $w $class]
if {[string compare $event "<Tab>"] == 0} {
set target [focusNext $win $class]
} else {
set target [focusPrev $win $class]
}
if {[string compare $target $win] != 0} {
set focusWin [focus -displayof $win]
if {[string length $focusWin] != 0} {
event generate $focusWin <<TraverseOut>>
}
focus $target
event generate $target <<TraverseIn>>
}
return -code break ""
}
#------------------------------------------------------------------------------
# mwutil::configureWidget
#
# Configures the widget win by processing the command-line arguments specified
# in optValPairs and, if the value of initialize is true, also those database
# options that don't match any command-line arguments.
#------------------------------------------------------------------------------
proc mwutil::configureWidget {win configSpecsName configCmd cgetCmd \
optValPairs initialize} {
upvar $configSpecsName configSpecs
#
# Process the command-line arguments
#
set cmdLineOpts {}
set savedOptValPairs {}
set failed 0
set count [llength $optValPairs]
foreach {opt val} $optValPairs {
if {[catch {fullConfigOpt $opt configSpecs} result] != 0} {
set failed 1
break
}
if {$count == 1} {
set result "value for \"$opt\" missing"
set failed 1
break
}
set opt $result
lappend cmdLineOpts $opt
lappend savedOptValPairs $opt [eval $cgetCmd [list $win $opt]]
if {[catch {eval $configCmd [list $win $opt $val]} result] != 0} {
set failed 1
break
}
incr count -2
}
if {$failed} {
#
# Restore the saved values
#
foreach {opt val} $savedOptValPairs {
eval $configCmd [list $win $opt $val]
}
return -code error $result
}
if {$initialize} {
#
# Process those configuration options that were not
# given as command-line arguments; use the corresponding
# values from the option database if available
#
foreach opt [lsort [array names configSpecs]] {
if {[llength $configSpecs($opt)] == 1 ||
[lsearch -exact $cmdLineOpts $opt] >= 0} {
continue
}
set dbName [lindex $configSpecs($opt) 0]
set dbClass [lindex $configSpecs($opt) 1]
set dbValue [option get $win $dbName $dbClass]
if {[string length $dbValue] == 0} {
set default [lindex $configSpecs($opt) 3]
eval $configCmd [list $win $opt $default]
} else {
if {[catch {
eval $configCmd [list $win $opt $dbValue]
} result] != 0} {
return -code error $result
}
}
}
}
return ""
}
#------------------------------------------------------------------------------
# mwutil::fullConfigOpt
#
# Returns the full configuration option corresponding to the possibly
# abbreviated option opt.
#------------------------------------------------------------------------------
proc mwutil::fullConfigOpt {opt configSpecsName} {
upvar $configSpecsName configSpecs
if {[info exists configSpecs($opt)]} {
if {[llength $configSpecs($opt)] == 1} {
return $configSpecs($opt)
} else {
return $opt
}
}
set optList [lsort [array names configSpecs]]
set count 0
foreach elem $optList {
if {[string first $opt $elem] == 0} {
incr count
if {$count == 1} {
set option $elem
} else {
break
}
}
}
if {$count == 1} {
if {[llength $configSpecs($option)] == 1} {
return $configSpecs($option)
} else {
return $option
}
} elseif {$count == 0} {
### return -code error "unknown option \"$opt\""
return -code error \
"bad option \"$opt\": must be [enumOpts $optList]"
} else {
### return -code error "unknown option \"$opt\""
return -code error \
"ambiguous option \"$opt\": must be [enumOpts $optList]"
}
}
#------------------------------------------------------------------------------
# mwutil::fullOpt
#
# Returns the full option corresponding to the possibly abbreviated option opt.
#------------------------------------------------------------------------------
proc mwutil::fullOpt {kind opt optList} {
if {[lsearch -exact $optList $opt] >= 0} {
return $opt
}
set count 0
foreach elem $optList {
if {[string first $opt $elem] == 0} {
incr count
if {$count == 1} {
set option $elem
} else {
break
}
}
}
if {$count == 1} {
return $option
} elseif {$count == 0} {
return -code error \
"bad $kind \"$opt\": must be [enumOpts $optList]"
} else {
return -code error \
"ambiguous $kind \"$opt\": must be [enumOpts $optList]"
}
}
#------------------------------------------------------------------------------
# mwutil::enumOpts
#
# Returns a string consisting of the elements of the given list, separated by
# commas and spaces.
#------------------------------------------------------------------------------
proc mwutil::enumOpts optList {
set optCount [llength $optList]
set n 1
foreach opt $optList {
if {$n == 1} {
set str $opt
} elseif {$n < $optCount} {
append str ", $opt"
} else {
if {$optCount > 2} {
append str ","
}
append str " or $opt"
}
incr n
}
return $str
}
#------------------------------------------------------------------------------
# mwutil::configureSubCmd
#
# This procedure is invoked to process configuration subcommands.
#------------------------------------------------------------------------------
proc mwutil::configureSubCmd {win configSpecsName configCmd cgetCmd argList} {
upvar $configSpecsName configSpecs
set argCount [llength $argList]
if {$argCount > 1} {
#
# Set the specified configuration options to the given values
#
return [configureWidget $win configSpecs $configCmd $cgetCmd $argList 0]
} elseif {$argCount == 1} {
#
# Return the description of the specified configuration option
#
set opt [fullConfigOpt [lindex $argList 0] configSpecs]
set dbName [lindex $configSpecs($opt) 0]
set dbClass [lindex $configSpecs($opt) 1]
set default [lindex $configSpecs($opt) 3]
return [list $opt $dbName $dbClass $default \
[eval $cgetCmd [list $win $opt]]]
} else {
#
# Return a list describing all available configuration options
#
foreach opt [lsort [array names configSpecs]] {
if {[llength $configSpecs($opt)] == 1} {
set alias $configSpecs($opt)
if {$::tk_version >= 8.1} {
lappend result [list $opt $alias]
} else {
set dbName [lindex $configSpecs($alias) 0]
lappend result [list $opt $dbName]
}
} else {
set dbName [lindex $configSpecs($opt) 0]
set dbClass [lindex $configSpecs($opt) 1]
set default [lindex $configSpecs($opt) 3]
lappend result [list $opt $dbName $dbClass $default \
[eval $cgetCmd [list $win $opt]]]
}
}
return $result
}
}
#------------------------------------------------------------------------------
# mwutil::attribSubCmd
#
# This procedure is invoked to process *attrib subcommands.
#------------------------------------------------------------------------------
proc mwutil::attribSubCmd {win prefix argList} {
set classNs [string tolower [winfo class $win]]
upvar ::${classNs}::ns${win}::attribs attribs
set argCount [llength $argList]
if {$argCount > 1} {
#
# Set the specified attributes to the given values
#
if {$argCount % 2 != 0} {
return -code error "value for \"[lindex $argList end]\" missing"
}
foreach {attr val} $argList {
set attribs($prefix-$attr) $val
}
return ""
} elseif {$argCount == 1} {
#
# Return the value of the specified attribute
#
set attr [lindex $argList 0]
set name $prefix-$attr
if {[info exists attribs($name)]} {
return $attribs($name)
} else {
return ""
}
} else {
#
# Return the current list of attribute names and values
#
set len [string length "$prefix-"]
set result {}
foreach name [lsort [array names attribs "$prefix-*"]] {
set attr [string range $name $len end]
lappend result [list $attr $attribs($name)]
}
return $result
}
}
#------------------------------------------------------------------------------
# mwutil::hasattribSubCmd
#
# This procedure is invoked to process has*attrib subcommands.
#------------------------------------------------------------------------------
proc mwutil::hasattribSubCmd {win prefix attr} {
set classNs [string tolower [winfo class $win]]
upvar ::${classNs}::ns${win}::attribs attribs
return [info exists attribs($prefix-$attr)]
}
#------------------------------------------------------------------------------
# mwutil::unsetattribSubCmd
#
# This procedure is invoked to process unset*attrib subcommands.
#------------------------------------------------------------------------------
proc mwutil::unsetattribSubCmd {win prefix attr} {
set classNs [string tolower [winfo class $win]]
upvar ::${classNs}::ns${win}::attribs attribs
set name $prefix-$attr
if {[info exists attribs($name)]} {
unset attribs($name)
}
return ""
}
#------------------------------------------------------------------------------
# mwutil::getScrollInfo
#
# Parses a list of arguments of the form "moveto <fraction>" or "scroll
# <number> units|pages" and returns the corresponding list consisting of two or
# three properly formatted elements.
#------------------------------------------------------------------------------
proc mwutil::getScrollInfo argList {
set argCount [llength $argList]
set opt [lindex $argList 0]
if {[string first $opt "moveto"] == 0} {
if {$argCount != 2} {
wrongNumArgs "moveto fraction"
}
set fraction [lindex $argList 1]
format "%f" $fraction ;# floating-point number check with error message
return [list moveto $fraction]
} elseif {[string first $opt "scroll"] == 0} {
if {$argCount != 3} {
wrongNumArgs "scroll number units|pages"
}
set number [lindex $argList 1]
format "%f" $number ;# floating-point number check with error message
set number [expr {int($number > 0 ? ceil($number) : floor($number))}]
set what [lindex $argList 2]
if {[string first $what "units"] == 0} {
return [list scroll $number units]
} elseif {[string first $what "pages"] == 0} {
return [list scroll $number pages]
} else {
return -code error "bad argument \"$what\": must be units or pages"
}
} else {
return -code error "unknown option \"$opt\": must be moveto or scroll"
}
}
#------------------------------------------------------------------------------
# mwutil::getScrollInfo2
#
# Parses a list of arguments of the form "moveto <fraction>" or "scroll
# <number> units|pages" and returns the corresponding list consisting of two or
# three properly formatted elements.
#------------------------------------------------------------------------------
proc mwutil::getScrollInfo2 {cmd argList} {
set argCount [llength $argList]
set opt [lindex $argList 0]
if {[string first $opt "moveto"] == 0} {
if {$argCount != 2} {
wrongNumArgs "$cmd moveto fraction"
}
set fraction [lindex $argList 1]
format "%f" $fraction ;# floating-point number check with error message
return [list moveto $fraction]
} elseif {[string first $opt "scroll"] == 0} {
if {$argCount != 3} {
wrongNumArgs "$cmd scroll number units|pages"
}
set number [lindex $argList 1]
format "%f" $number ;# floating-point number check with error message
set number [expr {int($number > 0 ? ceil($number) : floor($number))}]
set what [lindex $argList 2]
if {[string first $what "units"] == 0} {
return [list scroll $number units]
} elseif {[string first $what "pages"] == 0} {
return [list scroll $number pages]
} else {
return -code error "bad argument \"$what\": must be units or pages"
}
} else {
return -code error "unknown option \"$opt\": must be moveto or scroll"
}
}
#------------------------------------------------------------------------------
# mwutil::isScrollable
#
# Returns a boolean value indicating whether the widget w is scrollable along a
# given axis (x or y).
#------------------------------------------------------------------------------
proc mwutil::isScrollable {w axis} {
set viewCmd ${axis}view
return [expr {
[catch {$w cget -${axis}scrollcommand}] == 0 &&
[catch {$w $viewCmd} view] == 0 &&
[catch {$w $viewCmd moveto [lindex $view 0]}] == 0 &&
[catch {$w $viewCmd scroll 0 units}] == 0 &&
[catch {$w $viewCmd scroll 0 pages}] == 0
}]
}
#------------------------------------------------------------------------------
# mwutil::scrollByUnits
#
# Scrolls the widget w along a given axis (x or y) by units. The number of
# units is obtained by converting the fraction built from the last two
# arguments to an integer, rounded away from 0.
#------------------------------------------------------------------------------
proc mwutil::scrollByUnits {w axis delta divisor} {
set number [expr {$delta/$divisor}]
set number [expr {int($number > 0 ? ceil($number) : floor($number))}]
$w ${axis}view scroll $number units
}
#------------------------------------------------------------------------------
# mwutil::genMouseWheelEvent
#
# Generates a mouse wheel event with the given root coordinates and delta on
# the widget w.
#------------------------------------------------------------------------------
proc mwutil::genMouseWheelEvent {w event rootX rootY delta} {
set needsFocus [expr {($::tk_version < 8.6 ||
[package vcompare $::tk_patchLevel "8.6b2"] < 0) &&
[string compare $::tcl_platform(platform) "windows"] == 0}]
if {$needsFocus} {
set focusWin [focus -displayof $w]
focus $w
}
event generate $w $event -rootx $rootX -rooty $rootY -delta $delta
if {$needsFocus} {
focus $focusWin
}
}
#------------------------------------------------------------------------------
# mwutil::containsPointer
#
# Returns a boolean value indicating whether the widget w contains the mouse
# pointer.
#------------------------------------------------------------------------------
proc mwutil::containsPointer w {
if {![winfo viewable $w]} {
return 0
}
foreach {ptrX ptrY} [winfo pointerxy $w] {}
set wX [winfo rootx $w]
set wY [winfo rooty $w]
return [expr {
$ptrX >= $wX && $ptrX < $wX + [winfo width $w] &&
$ptrY >= $wY && $ptrY < $wY + [winfo height $w]
}]
}
#------------------------------------------------------------------------------
# mwutil::hasFocus
#
# Returns a boolean value indicating whether the focus window is (a descendant
# of) the widget w and has the same toplevel.
#------------------------------------------------------------------------------
proc mwutil::hasFocus w {
set focusWin [focus -displayof $w]
if {[string length $focusWin] == 0} {
return 0
}
return [expr {
([string compare $w "."] == 0 || [string first $w. $focusWin.] == 0) &&
[string compare [winfo toplevel $w] [winfo toplevel $focusWin]] == 0
}]
}
#------------------------------------------------------------------------------
# mwutil::windowingSystem
#
# Returns the windowing system ("x11", "win32", "classic", or "aqua").
#------------------------------------------------------------------------------
proc mwutil::windowingSystem {} {
if {[catch {tk windowingsystem} winSys] != 0} {
switch $::tcl_platform(platform) {
unix { set winSys x11 }
windows { set winSys win32 }
macintosh { set winSys classic }
}
}
return $winSys
}
#------------------------------------------------------------------------------
# mwutil::currentTheme
#
# Returns the current tile theme.
#------------------------------------------------------------------------------
proc mwutil::currentTheme {} {
if {[catch {ttk::style theme use} result] == 0} {
return $result
} elseif {[info exists ::ttk::currentTheme]} {
return $::ttk::currentTheme
} elseif {[info exists ::tile::currentTheme]} {
return $::tile::currentTheme
} else {
return ""
}
}
#------------------------------------------------------------------------------
# mwutil::normalizeColor
#
# Returns the representation of a given color in the form "#RRGGBB".
#------------------------------------------------------------------------------
proc mwutil::normalizeColor color {
foreach {r g b} [winfo rgb . $color] {}
return [format "#%02x%02x%02x" \
[expr {$r >> 8}] [expr {$g >> 8}] [expr {$b >> 8}]]
}
#------------------------------------------------------------------------------
# mwutil::parsePadding
#
# Returns the 4-elements list of pixels corresponding to a given padding
# specification.
#------------------------------------------------------------------------------
proc mwutil::parsePadding {w padding} {
switch [llength $padding] {
0 {
set l 0; set t 0; set r 0; set b 0
}
1 {
set l [winfo pixels $w $padding]
set t $l; set r $l; set b $l
}
2 {
foreach {l t} $padding {}
set l [winfo pixels $w $l]
set t [winfo pixels $w $t]
set r $l; set b $t
}
3 {
foreach {l t r} $padding {}
set l [winfo pixels $w $l]
set t [winfo pixels $w $t]
set r [winfo pixels $w $r]
set b $t
}
4 {
foreach {l t r b} $padding {}
set l [winfo pixels $w $l]
set t [winfo pixels $w $t]
set r [winfo pixels $w $r]
set b [winfo pixels $w $b]
}
default {
return -code error "wrong # elements in padding spec \"$padding\""
}
}
set result [list $l $t $r $b]
foreach pad $result {
if {$pad < 0} {
return -code error "bad pad value \"$pad\""
}
}
return $result
}

7
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/mwutil/pkgIndex.tcl

@ -0,0 +1,7 @@
#==============================================================================
# mwutil package index file.
#
# Copyright (c) 2020-2022 Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================
package ifneeded mwutil 2.20 [list source [file join $dir mwutil.tcl]]

111
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/mentry/scripts/tclIndex

@ -0,0 +1,111 @@
# Tcl autoload index file, version 2.0
# This file is generated by the "auto_mkindex" command
# and sourced to set up indexing information for one or
# more commands. Typically each line is a command that
# sets an element in the auto_index array, where the
# element name is the name of a command and the value is
# a script that loads the command.
set auto_index(::mentry::dateMentry) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::timeMentry) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::dateTimeMentry) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::putClockVal) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::getClockVal) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::checkIfDateOrTimeMentry) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::getClockValFromDateMentry) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::getClockValFromTimeMentry) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::getClockValFromDateTimeMentry) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::incrDateTimeComp) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::setMeridian) [list source [file join $dir mentryDateTime.tcl]]
set auto_index(::mentry::fixedPointMentry) [list source [file join $dir mentryFixedPoint.tcl]]
set auto_index(::mentry::putReal) [list source [file join $dir mentryFixedPoint.tcl]]
set auto_index(::mentry::getReal) [list source [file join $dir mentryFixedPoint.tcl]]
set auto_index(::mentry::checkIfFixedPointMentry) [list source [file join $dir mentryFixedPoint.tcl]]
set auto_index(::mentry::ipAddrMentry) [list source [file join $dir mentryIPAddr.tcl]]
set auto_index(::mentry::putIPAddr) [list source [file join $dir mentryIPAddr.tcl]]
set auto_index(::mentry::getIPAddr) [list source [file join $dir mentryIPAddr.tcl]]
set auto_index(::mentry::checkIfIPAddrMentry) [list source [file join $dir mentryIPAddr.tcl]]
set auto_index(::mentry::incrIPAddrComp) [list source [file join $dir mentryIPAddr.tcl]]
set auto_index(::mentry::pasteIPAddr) [list source [file join $dir mentryIPAddr.tcl]]
set auto_index(::mentry::ipv6AddrMentry) [list source [file join $dir mentryIPv6Addr.tcl]]
set auto_index(::mentry::putIPv6Addr) [list source [file join $dir mentryIPv6Addr.tcl]]
set auto_index(::mentry::getIPv6Addr) [list source [file join $dir mentryIPv6Addr.tcl]]
set auto_index(::mentry::checkIfIPv6AddrMentry) [list source [file join $dir mentryIPv6Addr.tcl]]
set auto_index(::mentry::incrIPv6AddrComp) [list source [file join $dir mentryIPv6Addr.tcl]]
set auto_index(::mentry::pasteIPv6Addr) [list source [file join $dir mentryIPv6Addr.tcl]]
set auto_index(::mentry::setThemeDefaults) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::awTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::altTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::aquaTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::AquativoTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::aquativoTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::ArcTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::blueTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::clamTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::classicTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::clearlooksTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::defaultTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::keramikTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::keramik_altTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::krocTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::plastikTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::srivTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::srivlgTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::stepTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::tileqtTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::vistaTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::winnativeTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::winxpblueTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::xpnativeTheme) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::getKdeConfigVal) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::makeKdeDirList) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::readKdeConfigVal) [list source [file join $dir mentryThemes.tcl]]
set auto_index(::mentry::createTileAliases) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::extendConfigSpecs) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::createBindings) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::mentry) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::doConfig) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::doCget) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::createChildren) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::mentryWidgetCmd) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::adjustentrySubCmd) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::putSubCmd) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::setentryextrawidthSubCmd) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::setentryfontSubCmd) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::setentrywidthSubCmd) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::childIndex) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::condTabToNext) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::condGoToNeighbor) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::updateLabelForegrounds) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::updateFonts) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::handleThemeChangedEvent) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::updateConfigSpecs) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::handleAppearanceEvent) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::updateAppearance) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::tabToPrev) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::tabToNext) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::goToHome) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::goToEnd) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::selectToHome) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::selectToEnd) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::backSpace) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::delToLeft) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::procLabelChars) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::labelButton1) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::parseChildPath) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::framePath) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::entryPath) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::labelPath) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::entries) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::labels) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::prevNormal) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::nextNormal) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::firstNormal) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::lastNormal) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::adjustChildren) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::tabToEntry) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::entrySetCursor) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::entryViewCursor) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::configEntry) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::reqEntryWidth) [list source [file join $dir mentryWidget.tcl]]
set auto_index(::mentry::geomParams) [list source [file join $dir mentryWidget.tcl]]

226
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/menubar/debug.tcl

@ -0,0 +1,226 @@
# debug.tcl --
#
# Package that add debugging procedures to the global namespace
# and to the menubar::Tree class.
#
# Copyright (c) 2009 Tom Krehbiel <tomk@users.sourceforge.net>
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: debug.tcl,v 1.5 2010/01/06 20:55:54 tomk Exp $
package require TclOO
package require menubar
package provide menubar::debug 0.5
# The ::oo namespace contains Tcloo commands that must be preceeded by 'my'.
# as the default namespace for callback commands
# --
#
# Generic debugging method for TclOO object instance.
#
oo::define ::oo::object method debug {{pat *}} {
set res [list class [info object class [self]]]
foreach i [info object vars [self] $pat] {
variable $i
lappend res $i [set $i]
}
set res
}
# -- pdict
#
# A pretty printer for dict object, similar to parray.
#
# Usage:
#
# pdict <dict> [d [i [p [s]]]]
#
# Where:
# d - dict to be printed
# i - indent level
# p - prefix string for one level of indent
# s - seperator string between key and value
#
# Examples:
# % set d [dict create a {1 i 2 j 3 k} b {x y z} c {i m j {q w e r} k o}]
# % a {1 i 2 j 3 k} b {x y z} c {i m j {q w e r} k o}
# % pdict $d
# a ->
# 1 -> 'i'
# 2 -> 'j'
# 3 -> 'k'
# b -> 'x y z'
# c ->
# i -> 'm'
# j ->
# q -> 'w'
# e -> 'r'
# k -> 'o'
#
proc ::pdict { d {i 0} {p " "} {s " -> "} } {
if { [catch {dict keys ${d}}] } {
error "error: pdict - argument is not a dict"
}
set result ""
set prefix [string repeat ${p} ${i}]
set max 0
foreach key [dict keys ${d}] {
if { [string length ${key}] > ${max} } {
set max [string length ${key}]
}
}
dict for {key val} ${d} {
append result "${prefix}[format "%-${max}s" ${key}]${s}"
if { [catch {dict keys ${val}}] } {
append result "'${val}'\n"
} else {
append result "\n"
append result "[pdict ${val} [expr ${i}+1] ${p} ${s}]\n"
}
}
return ${result}
}
# ------------------------------------------------------------
#
# Add debugging methods to ::menubar::tree class
#
# ------------------------------------------------------------
# -- ptree
# debugging utility
oo::define ::menubar::tree method ptree { {name ""} } {
variable root
if { ${name} eq "" } {
my DumpSubtree ${root}
} else {
if { [my exists ${name}] ne "" } {
error "node (${name}) - not found"
}
my DumpSubtree ${name}
}
}
# -- pnodes
# debugging utility
oo::define ::menubar::tree method pnodes { } {
variable nodes
foreach name [lsort -dictionary [dict keys ${nodes}]] {
set node [dict get ${nodes} ${name}]
set pnode [${node} parent]
set children [my children ${name}]
puts [format "(%-12s) %-12s %s -> %s" ${pnode} ${node} ${name} [join ${children} {, }]]
}
}
# -- pkeys
# debugging utility
oo::define ::menubar::tree method pkeys { args } {
if { [llength ${args}] == 0 } {
set args [my nodes]
} else {
set notfound [my exists {*}${args}]
if { ${notfound} ne "" } {
error "node (${notfound}) - not found"
}
}
foreach name ${args} {
set node [my Name2Node ${name}]
puts "node(${name})"
set width 0
foreach key [${node} attr.keys] {
set len [string length ${key}]
if { ${len} > ${width} } { set width ${len} }
}
foreach {key val} [${node} attrs.filter] {
puts " [format "%-${width}s" ${key}]: '${val}'"
}
}
}
# -- pstream
# debugging utility
oo::define ::menubar::tree method pstream { stream } {
lassign ${stream} name attrs children
my Pstream ${name} ${attrs} ${children} 0
}
# ------------------------------------------------------------
#
# Add debugging methods to ::menubar class
#
# ------------------------------------------------------------
oo::define ::menubar method debug { {type tree} } {
variable mtree
variable installs
variable notebookVals
set result ""
if { ${type} eq "tree" } {
lappend result "##### tag tree #####"
lappend result "menubar"
lappend result {*}[my children menubar]
} elseif { ${type} eq "nodes" } {
lappend result "##### tag defs #####"
foreach node [lsort -dictionary [${mtree} nodes]] {
lappend result ${node}
foreach {attr val} [${mtree} key.getall ${node} +*] {
lappend result " ${attr}: ${val}"
}
foreach {opt val} [${mtree} key.getall ${node} -*] {
lappend result " ${opt}: ${val}"
}
}
} elseif { ${type} eq "installs" } {
lappend result "##### installs #####"
lappend result [pdict ${installs}]
} elseif { ${type} eq "notebook" } {
lappend result "##### notebookVals #####"
lappend result [pdict ${notebookVals}]
}
return ${result}
}
oo::define ::menubar method children { node {indent 1} } {
variable mtree
set result ""
foreach _node [${mtree} children ${node}] {
lappend result [string repeat " " ${indent}]${_node}
set more [my children ${_node} [expr ${indent}+1]]
if { [string trim ${more}] ne "" } {
lappend result {*}${more}
}
}
return ${result}
}
oo::define ::menubar method debug_node { node } {
variable mtree
lappend result "==== node: ${node}"
foreach {attr val} [${mtree} key.getall ${node} +*] {
lappend result " ${attr}: ${val}"
}
foreach {opt val} [${mtree} key.getall ${node} -*] {
lappend result " ${opt}: ${val}"
}
return ${result}
}
oo::define ::menubar method print { type } {
variable mtree
switch -exact ${type} {
"tree" {
${mtree} ptree
}
"nodes" {
${mtree} pnodes
}
"keys" {
${mtree} pkeys
}
default {
}}
}

1920
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/menubar/menubar.tcl

File diff suppressed because it is too large Load Diff

161
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/menubar/node.tcl

@ -0,0 +1,161 @@
# node.tcl --
#
# Package that defines the menubar::Node class. This class is a
# privite class used by the menubar::Tree class.
#
# Copyright (c) 2009 Tom Krehbiel <tomk@users.sourceforge.net>
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: node.tcl,v 1.4 2010/01/06 20:55:54 tomk Exp $
package require TclOO
package provide menubar::node 0.5
# --------------------------------------------------
#
# manubar::Node class - used by menubar::Tree class
#
# --------------------------------------------------
# --
# parent - contains the parent node instance
# children - contains list of child node instances
# attrs - a dictionary of attribute/value pairs
oo::class create ::menubar::node {
# --
# create a named node
constructor { pnode } {
variable parent
variable children
variable attrs
set parent ${pnode}
set children {}
set attrs [dict create]
}
# --
# If 'pnode' isn't blank, set the node's parent to its
# value; return the current parent.
method parent { {pnode ""} } {
variable parent
if { ${pnode} ne "" } {
set parent ${pnode}
}
return ${parent}
}
# --
# If 'clist' is empty then return the current childern list else
# set the node's children to 'clist' and return the current childern list.
# If the option '-force' is found then set the node's children even
# if 'clist' is blank.
method children { {clist ""} args } {
variable children
if { [llength ${clist}] != 0 || "-force" in ${args} } {
set children ${clist}
}
return ${children}
}
# --
# Insert a list of node instances ('args') into the
# child list at location 'index'.
method insert { index args } {
variable children
set children [linsert ${children} ${index} {*}${args}]
return
}
# --
# If 'kdict' isn't blank set the node attributes to its
# value; return the current value of attributes.
method attrs { {kdict ""} {force ""} } {
variable attrs
if { ${kdict} ne "" || ${force} eq "-force" } {
set attrs ${kdict}
}
return ${attrs}
}
# --
# Return the node's attributes as a dict of key/value pairs. If
# globpat exists, only keys that match the glob pattern will be
# returned.
method attrs.filter { {globpat ""} } {
variable attrs
if { ${globpat} eq "" } {
return ${attrs}
} else {
return [dict filter ${attrs} key ${globpat}]
}
}
# --
# Return the node's attribute keys as a list. If globpat exists,
# only return keys that match the glob pattern.
method attr.keys { {globpat ""} } {
variable attrs
if { ${globpat} eq "" } {
return [dict keys ${attrs}]
} else {
return [dict keys ${attrs} ${globpat}]
}
}
# --
# Set the value of the attribute 'key' to 'value'. If 'key
# doesn't exist add it to the node.
method attr.set { key value } {
variable attrs
dict set attrs ${key} ${value}
return ${value}
}
# --
#
method attr.unset { key } {
variable attrs
dict unset attrs ${key}
return
}
# --
# Return true of attribute 'key' exists for node else return false.
method attr.exists { key } {
variable attrs
return [dict exist ${attrs} ${key}]
}
# --
# Return the value of the attribute 'key' for node.
method attr.get { key } {
variable attrs
if { [dict exist ${attrs} ${key}] } {
return [dict get ${attrs} ${key}]
}
error "attribute '${key}' - not found"
}
# --
# Do a string append of 'value' to the value of attribute 'key' for
# node. Return the resulting string value.
method attr.append { key value } {
variable attrs
dict append attrs ${key} ${value}
return
}
# --
# Do a list append of 'value' to the value of attribute 'key' for
# node. Return the resulting list value.
method attr.lappend { key value } {
variable attrs
dict lappend attrs ${key} ${value}
return
}
}

4
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/menubar/pkgIndex.tcl

@ -0,0 +1,4 @@
package ifneeded menubar::node 0.5 [list source [file join $dir node.tcl]]
package ifneeded menubar::tree 0.5 [list source [file join $dir tree.tcl]]
package ifneeded menubar 0.5 [list source [file join $dir menubar.tcl]]
package ifneeded menubar::debug 0.5 [list source [file join $dir debug.tcl]]

1101
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/menubar/tree.tcl

File diff suppressed because it is too large Load Diff

105
src/vfs/punk8win.vfs/lib_tcl8/tklib0.8/notifywindow/notifywindow.tcl

@ -0,0 +1,105 @@
#notifywindow.tcl: provides routines for posting a Growl-style "notification window" in the upper right corner of the screen, fading in and out in an unobtrusive fashion
#(c) 2015-2019 Kevin Walzer/WordTech Communications LLC. License: standard Tcl license, http://www.tcl.tk/software/tcltk/license.html
package provide notifywindow 1.0
namespace eval notifywindow {
#Main procedure for window
proc notifywindow {msg img} {
set w [toplevel ._notify]
if {[tk windowingsystem] eq "aqua"} {
::tk::unsupported::MacWindowStyle style $w utility {hud
closeBox resizable}
wm title $w "Alert"
}
if {[tk windowingsystem] eq "win32"} {
wm attributes $w -toolwindow true
wm title $w "Alert"
}
if {[lsearch [image names] $img] > -1} {
label $w.l -bg gray30 -fg white -image $img
pack $w.l -fill both -expand yes -side left
}
message $w.message -aspect 150 -bg gray30 -fg white -aspect 150 -text $msg -width 280
pack $w.message -side right -fill both -expand yes
if {[tk windowingsystem] eq "x11"} {
wm overrideredirect $w true
}
wm attributes $w -alpha 0.0
puts [winfo reqwidth $w]
set xpos [expr [winfo screenwidth $w] - 325]
wm geometry $w +$xpos+30
notifywindow::fade_in $w
after 3000 notifywindow::fade_out $w
}
#Fade and destroy window
proc fade_out {w} {
catch {
set prev_degree [wm attributes $w -alpha]
set new_degree [expr $prev_degree - 0.05]
set current_degree [wm attributes $w -alpha $new_degree]
if {$new_degree > 0.0 && $new_degree != $prev_degree} {
after 10 [list notifywindow::fade_out $w]
} else {
destroy $w
}
}
}
#Fade the window into view
proc fade_in {w} {
catch {
raise $w
wm attributes $w -topmost 1
set prev_degree [wm attributes $w -alpha]
set new_degree [expr $prev_degree + 0.05]
set current_degree [wm attributes $w -alpha $new_degree]
focus -force $w
if {$new_degree < 0.9 && $new_degree != $prev_degree} {
after 10 [list notifywindow::fade_in $w]
} else {
return
}
}
}
#The obligatory demo
proc demo {} {
image create photo flag -data {
R0lGODlhFAAUAPcAAAAAAIAAAACAAICAAAAAgIAAgACAgMDAwMDcwKbK8P/w1Pjisd/UjtHJ
a8O4SL2qJcWqAK+SAJN6AGJiAEpKADIyAP/j1P/Hsf+rjv+Pa/9zSP9XJf9VANxJALk9AJYx
AHMlAFAZAP/U1P+xsf+Ojv9ra/9ISP8lJf4AANwAALkAAJYAAHMAAFAAAP/U4/+xx/+Oq/9r
j/9Ic/8lV/8AVdwASbkAPZYAMXMAJVAAGf/U8P+x4v+O1P9rxv9IuP8lqv8AqtwAkrkAepYA
YnMASlAAMv/U//+x//+O//9r//9I//8l//4A/twA3LkAuZYAlnMAc1AAUPDU/+Kx/9SO/8Zr
/7hI/6ol/6oA/5IA3HoAuWIAlkoAczIAUOPU/8ex/6uO/49r/3NI/1cl/1UA/0kA3D0AuTEA
liUAcxkAUNTU/7Gx/46O/2tr/0hI/yUl/wAA/gAA3AAAuQAAlgAAcwAAUNTj/7HH/46r/2uP
/0hz/yVX/wBV/wBJ3AA9uQAxlgAlcwAZUNTw/7Hi/47U/2vG/0i4/yWq/wCq/wCS3AB6uQBi
lgBKcwAyUNT//7H//47//2v//0j//yX//wD+/gDc3AC5uQCWlgBzcwBQUNT/8LH/4o7/1Gv/
xkj/uCX/qgD/qgDckgC5egCWYgBzSgBQMtT/47H/x47/q2v/j0j/cyX/VwD/VQDcSQC5PQCW
MQBzJQBQGdT/1LH/sY7/jmv/a0j/SCX/JQD+AADcAAC5AACWAABzAABQAOP/1Mf/sav/jo//
a3P/SFf/JVX/AEncAD25ADGWACVzABlQAPD/1OL/sdT/jsb/a7j/SKr/Jar/AJLcAHq5AGKW
AEpzADJQAP//1P//sf//jv//a///SP//Jf7+ANzcALm5AJaWAHNzAFBQAPLy8ubm5tra2s7O
zsLCwra2tqqqqp6enpKSkoaGhnp6em5ubmJiYlZWVkpKSj4+PjIyMiYmJhoaGg4ODv/78KCg
pICAgP8AAAD/AP//AAAA//8A/wD//////yH5BAEAAAEALAAAAAAUABQAAAiZAAMIHEhQoLqD
CAsqFAigIQB3Dd0tNKjOXSxXrmABWBABgLqCByECuAir5EYJHimKvOgqFqxXrzZ2lBhgJUaY
LV/GOpkSIqybOF3ClPlQIEShMF/lfLVzAcqPRhsKXRqTY1GCFaUy1ckTKkiRGhtapTkxa82u
ExUSJZs2qtOUbQ2ujTsQ4luvbdXNpRtA712+UeEC7ou3YEAAADt=
}
notifywindow::notifywindow "Man page for Message\n\nSpecifies a non-negative integer value indicating desired aspect ratio for the text. The aspect ratio is specified as 100*width/height. 100 means the text should be as wide as it is tall, 200 means the text should be twice as wide as it is tall, 50 means the text should be twice as tall as it is wide, and so on. Used to choose line length for text if -width option is not specified. Defaults to 150." flag
}
namespace export *
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save