added windows installer binary template builder
This commit is contained in:
parent
c22039105f
commit
decb78c6ab
|
|
@ -3,7 +3,7 @@
|
|||
- Windows 10
|
||||
- ActiveState TCL/TK 8.69 x64 (https://www.activestate.com/products/tcl/)
|
||||
- Gawk for Windows (Add directory of awk.exe to PATH)
|
||||
- NGSpice for Windows
|
||||
- NGSpice for Windows (Add directory of NGSpice to PATH, if it's not already done so)
|
||||
|
||||
2. Install Tree
|
||||
C:/Program Files/XSchem/bin - Binaries (executable file).
|
||||
|
|
|
|||
|
|
@ -0,0 +1,648 @@
|
|||
# auto.tcl --
|
||||
#
|
||||
# utility procs formerly in init.tcl dealing with auto execution of commands
|
||||
# and can be auto loaded themselves.
|
||||
#
|
||||
# Copyright (c) 1991-1993 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1998 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution of
|
||||
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
# auto_reset --
|
||||
#
|
||||
# Destroy all cached information for auto-loading and auto-execution, so that
|
||||
# the information gets recomputed the next time it's needed. Also delete any
|
||||
# commands that are listed in the auto-load index.
|
||||
#
|
||||
# Arguments:
|
||||
# None.
|
||||
|
||||
proc auto_reset {} {
|
||||
global auto_execs auto_index auto_path
|
||||
if {[array exists auto_index]} {
|
||||
foreach cmdName [array names auto_index] {
|
||||
set fqcn [namespace which $cmdName]
|
||||
if {$fqcn eq ""} {
|
||||
continue
|
||||
}
|
||||
rename $fqcn {}
|
||||
}
|
||||
}
|
||||
unset -nocomplain auto_execs auto_index ::tcl::auto_oldpath
|
||||
if {[catch {llength $auto_path}]} {
|
||||
set auto_path [list [info library]]
|
||||
} elseif {[info library] ni $auto_path} {
|
||||
lappend auto_path [info library]
|
||||
}
|
||||
}
|
||||
|
||||
# tcl_findLibrary --
|
||||
#
|
||||
# This is a utility for extensions that searches for a library directory
|
||||
# using a canonical searching algorithm. A side effect is to source the
|
||||
# initialization script and set a global library variable.
|
||||
#
|
||||
# Arguments:
|
||||
# basename Prefix of the directory name, (e.g., "tk")
|
||||
# version Version number of the package, (e.g., "8.0")
|
||||
# patch Patchlevel of the package, (e.g., "8.0.3")
|
||||
# initScript Initialization script to source (e.g., tk.tcl)
|
||||
# enVarName environment variable to honor (e.g., TK_LIBRARY)
|
||||
# varName Global variable to set when done (e.g., tk_library)
|
||||
|
||||
proc tcl_findLibrary {basename version patch initScript enVarName varName} {
|
||||
upvar #0 $varName the_library
|
||||
global auto_path env tcl_platform
|
||||
|
||||
set dirs {}
|
||||
set errors {}
|
||||
|
||||
# The C application may have hardwired a path, which we honor
|
||||
|
||||
if {[info exists the_library] && $the_library ne ""} {
|
||||
lappend dirs $the_library
|
||||
} else {
|
||||
# Do the canonical search
|
||||
|
||||
# 1. From an environment variable, if it exists. Placing this first
|
||||
# gives the end-user ultimate control to work-around any bugs, or
|
||||
# to customize.
|
||||
|
||||
if {[info exists env($enVarName)]} {
|
||||
lappend dirs $env($enVarName)
|
||||
}
|
||||
|
||||
# 2. In the package script directory registered within the
|
||||
# configuration of the package itself.
|
||||
|
||||
catch {
|
||||
lappend dirs [::${basename}::pkgconfig get scriptdir,runtime]
|
||||
}
|
||||
|
||||
# 3. Relative to auto_path directories. This checks relative to the
|
||||
# Tcl library as well as allowing loading of libraries added to the
|
||||
# auto_path that is not relative to the core library or binary paths.
|
||||
foreach d $auto_path {
|
||||
lappend dirs [file join $d $basename$version]
|
||||
if {$tcl_platform(platform) eq "unix"
|
||||
&& $tcl_platform(os) eq "Darwin"} {
|
||||
# 4. On MacOSX, check the Resources/Scripts subdir too
|
||||
lappend dirs [file join $d $basename$version Resources Scripts]
|
||||
}
|
||||
}
|
||||
|
||||
# 3. Various locations relative to the executable
|
||||
# ../lib/foo1.0 (From bin directory in install hierarchy)
|
||||
# ../../lib/foo1.0 (From bin/arch directory in install hierarchy)
|
||||
# ../library (From unix directory in build hierarchy)
|
||||
#
|
||||
# Remaining locations are out of date (when relevant, they ought to be
|
||||
# covered by the $::auto_path seach above) and disabled.
|
||||
#
|
||||
# ../../library (From unix/arch directory in build hierarchy)
|
||||
# ../../foo1.0.1/library
|
||||
# (From unix directory in parallel build hierarchy)
|
||||
# ../../../foo1.0.1/library
|
||||
# (From unix/arch directory in parallel build hierarchy)
|
||||
|
||||
set parentDir [file dirname [file dirname [info nameofexecutable]]]
|
||||
set grandParentDir [file dirname $parentDir]
|
||||
lappend dirs [file join $parentDir lib $basename$version]
|
||||
lappend dirs [file join $grandParentDir lib $basename$version]
|
||||
lappend dirs [file join $parentDir library]
|
||||
if {0} {
|
||||
lappend dirs [file join $grandParentDir library]
|
||||
lappend dirs [file join $grandParentDir $basename$patch library]
|
||||
lappend dirs [file join [file dirname $grandParentDir] \
|
||||
$basename$patch library]
|
||||
}
|
||||
}
|
||||
# uniquify $dirs in order
|
||||
array set seen {}
|
||||
foreach i $dirs {
|
||||
# Make sure $i is unique under normalization. Avoid repeated [source].
|
||||
if {[interp issafe]} {
|
||||
# Safe interps have no [file normalize].
|
||||
set norm $i
|
||||
} else {
|
||||
set norm [file normalize $i]
|
||||
}
|
||||
if {[info exists seen($norm)]} {
|
||||
continue
|
||||
}
|
||||
set seen($norm) {}
|
||||
|
||||
set the_library $i
|
||||
set file [file join $i $initScript]
|
||||
|
||||
# source everything when in a safe interpreter because we have a
|
||||
# source command, but no file exists command
|
||||
|
||||
if {[interp issafe] || [file exists $file]} {
|
||||
if {![catch {uplevel #0 [list source $file]} msg opts]} {
|
||||
return
|
||||
}
|
||||
append errors "$file: $msg\n"
|
||||
append errors [dict get $opts -errorinfo]\n
|
||||
}
|
||||
}
|
||||
unset -nocomplain the_library
|
||||
set msg "Can't find a usable $initScript in the following directories: \n"
|
||||
append msg " $dirs\n\n"
|
||||
append msg "$errors\n\n"
|
||||
append msg "This probably means that $basename wasn't installed properly.\n"
|
||||
error $msg
|
||||
}
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# auto_mkindex
|
||||
# ----------------------------------------------------------------------
|
||||
# The following procedures are used to generate the tclIndex file from Tcl
|
||||
# source files. They use a special safe interpreter to parse Tcl source
|
||||
# files, writing out index entries as "proc" commands are encountered. This
|
||||
# implementation won't work in a safe interpreter, since a safe interpreter
|
||||
# can't create the special parser and mess with its commands.
|
||||
|
||||
if {[interp issafe]} {
|
||||
return ;# Stop sourcing the file here
|
||||
}
|
||||
|
||||
# auto_mkindex --
|
||||
# Regenerate a tclIndex file from Tcl source files. Takes as argument the
|
||||
# name of the directory in which the tclIndex file is to be placed, followed
|
||||
# by any number of glob patterns to use in that directory to locate all of the
|
||||
# relevant files.
|
||||
#
|
||||
# Arguments:
|
||||
# dir - Name of the directory in which to create an index.
|
||||
|
||||
# args - Any number of additional arguments giving the names of files
|
||||
# within dir. If no additional are given auto_mkindex will look
|
||||
# for *.tcl.
|
||||
|
||||
proc auto_mkindex {dir args} {
|
||||
if {[interp issafe]} {
|
||||
error "can't generate index within safe interpreter"
|
||||
}
|
||||
|
||||
set oldDir [pwd]
|
||||
cd $dir
|
||||
|
||||
append index "# Tcl autoload index file, version 2.0\n"
|
||||
append index "# This file is generated by the \"auto_mkindex\" command\n"
|
||||
append index "# and sourced to set up indexing information for one or\n"
|
||||
append index "# more commands. Typically each line is a command that\n"
|
||||
append index "# sets an element in the auto_index array, where the\n"
|
||||
append index "# element name is the name of a command and the value is\n"
|
||||
append index "# a script that loads the command.\n\n"
|
||||
if {![llength $args]} {
|
||||
set args *.tcl
|
||||
}
|
||||
|
||||
auto_mkindex_parser::init
|
||||
foreach file [lsort [glob -- {*}$args]] {
|
||||
try {
|
||||
append index [auto_mkindex_parser::mkindex $file]
|
||||
} on error {msg opts} {
|
||||
cd $oldDir
|
||||
return -options $opts $msg
|
||||
}
|
||||
}
|
||||
auto_mkindex_parser::cleanup
|
||||
|
||||
set fid [open "tclIndex" w]
|
||||
puts -nonewline $fid $index
|
||||
close $fid
|
||||
cd $oldDir
|
||||
}
|
||||
|
||||
# Original version of auto_mkindex that just searches the source code for
|
||||
# "proc" at the beginning of the line.
|
||||
|
||||
proc auto_mkindex_old {dir args} {
|
||||
set oldDir [pwd]
|
||||
cd $dir
|
||||
set dir [pwd]
|
||||
append index "# Tcl autoload index file, version 2.0\n"
|
||||
append index "# This file is generated by the \"auto_mkindex\" command\n"
|
||||
append index "# and sourced to set up indexing information for one or\n"
|
||||
append index "# more commands. Typically each line is a command that\n"
|
||||
append index "# sets an element in the auto_index array, where the\n"
|
||||
append index "# element name is the name of a command and the value is\n"
|
||||
append index "# a script that loads the command.\n\n"
|
||||
if {![llength $args]} {
|
||||
set args *.tcl
|
||||
}
|
||||
foreach file [lsort [glob -- {*}$args]] {
|
||||
set f ""
|
||||
set error [catch {
|
||||
set f [open $file]
|
||||
fconfigure $f -eofchar \032
|
||||
while {[gets $f line] >= 0} {
|
||||
if {[regexp {^proc[ ]+([^ ]*)} $line match procName]} {
|
||||
set procName [lindex [auto_qualify $procName "::"] 0]
|
||||
append index "set [list auto_index($procName)]"
|
||||
append index " \[list source \[file join \$dir [list $file]\]\]\n"
|
||||
}
|
||||
}
|
||||
close $f
|
||||
} msg opts]
|
||||
if {$error} {
|
||||
catch {close $f}
|
||||
cd $oldDir
|
||||
return -options $opts $msg
|
||||
}
|
||||
}
|
||||
set f ""
|
||||
set error [catch {
|
||||
set f [open tclIndex w]
|
||||
puts -nonewline $f $index
|
||||
close $f
|
||||
cd $oldDir
|
||||
} msg opts]
|
||||
if {$error} {
|
||||
catch {close $f}
|
||||
cd $oldDir
|
||||
error $msg $info $code
|
||||
return -options $opts $msg
|
||||
}
|
||||
}
|
||||
|
||||
# Create a safe interpreter that can be used to parse Tcl source files
|
||||
# generate a tclIndex file for autoloading. This interp contains commands for
|
||||
# things that need index entries. Each time a command is executed, it writes
|
||||
# an entry out to the index file.
|
||||
|
||||
namespace eval auto_mkindex_parser {
|
||||
variable parser "" ;# parser used to build index
|
||||
variable index "" ;# maintains index as it is built
|
||||
variable scriptFile "" ;# name of file being processed
|
||||
variable contextStack "" ;# stack of namespace scopes
|
||||
variable imports "" ;# keeps track of all imported cmds
|
||||
variable initCommands ;# list of commands that create aliases
|
||||
if {![info exists initCommands]} {
|
||||
set initCommands [list]
|
||||
}
|
||||
|
||||
proc init {} {
|
||||
variable parser
|
||||
variable initCommands
|
||||
|
||||
if {![interp issafe]} {
|
||||
set parser [interp create -safe]
|
||||
$parser hide info
|
||||
$parser hide rename
|
||||
$parser hide proc
|
||||
$parser hide namespace
|
||||
$parser hide eval
|
||||
$parser hide puts
|
||||
foreach ns [$parser invokehidden namespace children ::] {
|
||||
# MUST NOT DELETE "::tcl" OR BAD THINGS HAPPEN!
|
||||
if {$ns eq "::tcl"} continue
|
||||
$parser invokehidden namespace delete $ns
|
||||
}
|
||||
foreach cmd [$parser invokehidden info commands ::*] {
|
||||
$parser invokehidden rename $cmd {}
|
||||
}
|
||||
$parser invokehidden proc unknown {args} {}
|
||||
|
||||
# We'll need access to the "namespace" command within the
|
||||
# interp. Put it back, but move it out of the way.
|
||||
|
||||
$parser expose namespace
|
||||
$parser invokehidden rename namespace _%@namespace
|
||||
$parser expose eval
|
||||
$parser invokehidden rename eval _%@eval
|
||||
|
||||
# Install all the registered psuedo-command implementations
|
||||
|
||||
foreach cmd $initCommands {
|
||||
eval $cmd
|
||||
}
|
||||
}
|
||||
}
|
||||
proc cleanup {} {
|
||||
variable parser
|
||||
interp delete $parser
|
||||
unset parser
|
||||
}
|
||||
}
|
||||
|
||||
# auto_mkindex_parser::mkindex --
|
||||
#
|
||||
# Used by the "auto_mkindex" command to create a "tclIndex" file for the given
|
||||
# Tcl source file. Executes the commands in the file, and handles things like
|
||||
# the "proc" command by adding an entry for the index file. Returns a string
|
||||
# that represents the index file.
|
||||
#
|
||||
# Arguments:
|
||||
# file Name of Tcl source file to be indexed.
|
||||
|
||||
proc auto_mkindex_parser::mkindex {file} {
|
||||
variable parser
|
||||
variable index
|
||||
variable scriptFile
|
||||
variable contextStack
|
||||
variable imports
|
||||
|
||||
set scriptFile $file
|
||||
|
||||
set fid [open $file]
|
||||
fconfigure $fid -eofchar \032
|
||||
set contents [read $fid]
|
||||
close $fid
|
||||
|
||||
# There is one problem with sourcing files into the safe interpreter:
|
||||
# references like "$x" will fail since code is not really being executed
|
||||
# and variables do not really exist. To avoid this, we replace all $ with
|
||||
# \0 (literally, the null char) later, when getting proc names we will
|
||||
# have to reverse this replacement, in case there were any $ in the proc
|
||||
# name. This will cause a problem if somebody actually tries to have a \0
|
||||
# in their proc name. Too bad for them.
|
||||
set contents [string map [list \$ \0] $contents]
|
||||
|
||||
set index ""
|
||||
set contextStack ""
|
||||
set imports ""
|
||||
|
||||
$parser eval $contents
|
||||
|
||||
foreach name $imports {
|
||||
catch {$parser eval [list _%@namespace forget $name]}
|
||||
}
|
||||
return $index
|
||||
}
|
||||
|
||||
# auto_mkindex_parser::hook command
|
||||
#
|
||||
# Registers a Tcl command to evaluate when initializing the child interpreter
|
||||
# used by the mkindex parser. The command is evaluated in the parent
|
||||
# interpreter, and can use the variable auto_mkindex_parser::parser to get to
|
||||
# the child
|
||||
|
||||
proc auto_mkindex_parser::hook {cmd} {
|
||||
variable initCommands
|
||||
|
||||
lappend initCommands $cmd
|
||||
}
|
||||
|
||||
# auto_mkindex_parser::slavehook command
|
||||
#
|
||||
# Registers a Tcl command to evaluate when initializing the child interpreter
|
||||
# used by the mkindex parser. The command is evaluated in the child
|
||||
# interpreter.
|
||||
|
||||
proc auto_mkindex_parser::slavehook {cmd} {
|
||||
variable initCommands
|
||||
|
||||
# The $parser variable is defined to be the name of the child interpreter
|
||||
# when this command is used later.
|
||||
|
||||
lappend initCommands "\$parser eval [list $cmd]"
|
||||
}
|
||||
|
||||
# auto_mkindex_parser::command --
|
||||
#
|
||||
# Registers a new command with the "auto_mkindex_parser" interpreter that
|
||||
# parses Tcl files. These commands are fake versions of things like the
|
||||
# "proc" command. When you execute them, they simply write out an entry to a
|
||||
# "tclIndex" file for auto-loading.
|
||||
#
|
||||
# This procedure allows extensions to register their own commands with the
|
||||
# auto_mkindex facility. For example, a package like [incr Tcl] might
|
||||
# register a "class" command so that class definitions could be added to a
|
||||
# "tclIndex" file for auto-loading.
|
||||
#
|
||||
# Arguments:
|
||||
# name Name of command recognized in Tcl files.
|
||||
# arglist Argument list for command.
|
||||
# body Implementation of command to handle indexing.
|
||||
|
||||
proc auto_mkindex_parser::command {name arglist body} {
|
||||
hook [list auto_mkindex_parser::commandInit $name $arglist $body]
|
||||
}
|
||||
|
||||
# auto_mkindex_parser::commandInit --
|
||||
#
|
||||
# This does the actual work set up by auto_mkindex_parser::command. This is
|
||||
# called when the interpreter used by the parser is created.
|
||||
#
|
||||
# Arguments:
|
||||
# name Name of command recognized in Tcl files.
|
||||
# arglist Argument list for command.
|
||||
# body Implementation of command to handle indexing.
|
||||
|
||||
proc auto_mkindex_parser::commandInit {name arglist body} {
|
||||
variable parser
|
||||
|
||||
set ns [namespace qualifiers $name]
|
||||
set tail [namespace tail $name]
|
||||
if {$ns eq ""} {
|
||||
set fakeName [namespace current]::_%@fake_$tail
|
||||
} else {
|
||||
set fakeName [namespace current]::[string map {:: _} _%@fake_$name]
|
||||
}
|
||||
proc $fakeName $arglist $body
|
||||
|
||||
# YUK! Tcl won't let us alias fully qualified command names, so we can't
|
||||
# handle names like "::itcl::class". Instead, we have to build procs with
|
||||
# the fully qualified names, and have the procs point to the aliases.
|
||||
|
||||
if {[string match *::* $name]} {
|
||||
set exportCmd [list _%@namespace export [namespace tail $name]]
|
||||
$parser eval [list _%@namespace eval $ns $exportCmd]
|
||||
|
||||
# The following proc definition does not work if you want to tolerate
|
||||
# space or something else diabolical in the procedure name, (i.e.,
|
||||
# space in $alias). The following does not work:
|
||||
# "_%@eval {$alias} \$args"
|
||||
# because $alias gets concat'ed to $args. The following does not work
|
||||
# because $cmd is somehow undefined
|
||||
# "set cmd {$alias} \; _%@eval {\$cmd} \$args"
|
||||
# A gold star to someone that can make test autoMkindex-3.3 work
|
||||
# properly
|
||||
|
||||
set alias [namespace tail $fakeName]
|
||||
$parser invokehidden proc $name {args} "_%@eval {$alias} \$args"
|
||||
$parser alias $alias $fakeName
|
||||
} else {
|
||||
$parser alias $name $fakeName
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
# auto_mkindex_parser::fullname --
|
||||
#
|
||||
# Used by commands like "proc" within the auto_mkindex parser. Returns the
|
||||
# qualified namespace name for the "name" argument. If the "name" does not
|
||||
# start with "::", elements are added from the current namespace stack to
|
||||
# produce a qualified name. Then, the name is examined to see whether or not
|
||||
# it should really be qualified. If the name has more than the leading "::",
|
||||
# it is returned as a fully qualified name. Otherwise, it is returned as a
|
||||
# simple name. That way, the Tcl autoloader will recognize it properly.
|
||||
#
|
||||
# Arguments:
|
||||
# name - Name that is being added to index.
|
||||
|
||||
proc auto_mkindex_parser::fullname {name} {
|
||||
variable contextStack
|
||||
|
||||
if {![string match ::* $name]} {
|
||||
foreach ns $contextStack {
|
||||
set name "${ns}::$name"
|
||||
if {[string match ::* $name]} {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {[namespace qualifiers $name] eq ""} {
|
||||
set name [namespace tail $name]
|
||||
} elseif {![string match ::* $name]} {
|
||||
set name "::$name"
|
||||
}
|
||||
|
||||
# Earlier, mkindex replaced all $'s with \0. Now, we have to reverse that
|
||||
# replacement.
|
||||
return [string map [list \0 \$] $name]
|
||||
}
|
||||
|
||||
# auto_mkindex_parser::indexEntry --
|
||||
#
|
||||
# Used by commands like "proc" within the auto_mkindex parser to add a
|
||||
# correctly-quoted entry to the index. This is shared code so it is done
|
||||
# *right*, in one place.
|
||||
#
|
||||
# Arguments:
|
||||
# name - Name that is being added to index.
|
||||
|
||||
proc auto_mkindex_parser::indexEntry {name} {
|
||||
variable index
|
||||
variable scriptFile
|
||||
|
||||
# We convert all metacharacters to their backslashed form, and pre-split
|
||||
# the file name that we know about (which will be a proper list, and so
|
||||
# correctly quoted).
|
||||
|
||||
set name [string range [list \}[fullname $name]] 2 end]
|
||||
set filenameParts [file split $scriptFile]
|
||||
|
||||
append index [format \
|
||||
{set auto_index(%s) [list source [file join $dir %s]]%s} \
|
||||
$name $filenameParts \n]
|
||||
return
|
||||
}
|
||||
|
||||
if {[llength $::auto_mkindex_parser::initCommands]} {
|
||||
return
|
||||
}
|
||||
|
||||
# Register all of the procedures for the auto_mkindex parser that will build
|
||||
# the "tclIndex" file.
|
||||
|
||||
# AUTO MKINDEX: proc name arglist body
|
||||
# Adds an entry to the auto index list for the given procedure name.
|
||||
|
||||
auto_mkindex_parser::command proc {name args} {
|
||||
indexEntry $name
|
||||
}
|
||||
|
||||
# Conditionally add support for Tcl byte code files. There are some tricky
|
||||
# details here. First, we need to get the tbcload library initialized in the
|
||||
# current interpreter. We cannot load tbcload into the child until we have
|
||||
# done so because it needs access to the tcl_patchLevel variable. Second,
|
||||
# because the package index file may defer loading the library until we invoke
|
||||
# a command, we need to explicitly invoke auto_load to force it to be loaded.
|
||||
# This should be a noop if the package has already been loaded
|
||||
|
||||
auto_mkindex_parser::hook {
|
||||
try {
|
||||
package require tbcload
|
||||
} on error {} {
|
||||
# OK, don't have it so do nothing
|
||||
} on ok {} {
|
||||
if {[namespace which -command tbcload::bcproc] eq ""} {
|
||||
auto_load tbcload::bcproc
|
||||
}
|
||||
load {} tbcload $auto_mkindex_parser::parser
|
||||
|
||||
# AUTO MKINDEX: tbcload::bcproc name arglist body
|
||||
# Adds an entry to the auto index list for the given pre-compiled
|
||||
# procedure name.
|
||||
|
||||
auto_mkindex_parser::commandInit tbcload::bcproc {name args} {
|
||||
indexEntry $name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# AUTO MKINDEX: namespace eval name command ?arg arg...?
|
||||
# Adds the namespace name onto the context stack and evaluates the associated
|
||||
# body of commands.
|
||||
#
|
||||
# AUTO MKINDEX: namespace import ?-force? pattern ?pattern...?
|
||||
# Performs the "import" action in the parser interpreter. This is important
|
||||
# for any commands contained in a namespace that affect the index. For
|
||||
# example, a script may say "itcl::class ...", or it may import "itcl::*" and
|
||||
# then say "class ...". This procedure does the import operation, but keeps
|
||||
# track of imported patterns so we can remove the imports later.
|
||||
|
||||
auto_mkindex_parser::command namespace {op args} {
|
||||
switch -- $op {
|
||||
eval {
|
||||
variable parser
|
||||
variable contextStack
|
||||
|
||||
set name [lindex $args 0]
|
||||
set args [lrange $args 1 end]
|
||||
|
||||
set contextStack [linsert $contextStack 0 $name]
|
||||
$parser eval [list _%@namespace eval $name] $args
|
||||
set contextStack [lrange $contextStack 1 end]
|
||||
}
|
||||
import {
|
||||
variable parser
|
||||
variable imports
|
||||
foreach pattern $args {
|
||||
if {$pattern ne "-force"} {
|
||||
lappend imports $pattern
|
||||
}
|
||||
}
|
||||
catch {$parser eval "_%@namespace import $args"}
|
||||
}
|
||||
ensemble {
|
||||
variable parser
|
||||
variable contextStack
|
||||
if {[lindex $args 0] eq "create"} {
|
||||
set name ::[join [lreverse $contextStack] ::]
|
||||
catch {
|
||||
set name [dict get [lrange $args 1 end] -command]
|
||||
if {![string match ::* $name]} {
|
||||
set name ::[join [lreverse $contextStack] ::]$name
|
||||
}
|
||||
regsub -all ::+ $name :: name
|
||||
}
|
||||
# create artifical proc to force an entry in the tclIndex
|
||||
$parser eval [list ::proc $name {} {}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# AUTO MKINDEX: oo::class create name ?definition?
|
||||
# Adds an entry to the auto index list for the given class name.
|
||||
auto_mkindex_parser::command oo::class {op name {body ""}} {
|
||||
if {$op eq "create"} {
|
||||
indexEntry $name
|
||||
}
|
||||
}
|
||||
auto_mkindex_parser::command class {op name {body ""}} {
|
||||
if {$op eq "create"} {
|
||||
indexEntry $name
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,335 @@
|
|||
# history.tcl --
|
||||
#
|
||||
# Implementation of the history command.
|
||||
#
|
||||
# Copyright (c) 1997 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution of
|
||||
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
# The tcl::history array holds the history list and some additional
|
||||
# bookkeeping variables.
|
||||
#
|
||||
# nextid the index used for the next history list item.
|
||||
# keep the max size of the history list
|
||||
# oldest the index of the oldest item in the history.
|
||||
|
||||
namespace eval ::tcl {
|
||||
variable history
|
||||
if {![info exists history]} {
|
||||
array set history {
|
||||
nextid 0
|
||||
keep 20
|
||||
oldest -20
|
||||
}
|
||||
}
|
||||
|
||||
namespace ensemble create -command ::tcl::history -map {
|
||||
add ::tcl::HistAdd
|
||||
change ::tcl::HistChange
|
||||
clear ::tcl::HistClear
|
||||
event ::tcl::HistEvent
|
||||
info ::tcl::HistInfo
|
||||
keep ::tcl::HistKeep
|
||||
nextid ::tcl::HistNextID
|
||||
redo ::tcl::HistRedo
|
||||
}
|
||||
}
|
||||
|
||||
# history --
|
||||
#
|
||||
# This is the main history command. See the man page for its interface.
|
||||
# This does some argument checking and calls the helper ensemble in the
|
||||
# tcl namespace.
|
||||
|
||||
proc ::history {args} {
|
||||
# If no command given, we're doing 'history info'. Can't be done with an
|
||||
# ensemble unknown handler, as those don't fire when no subcommand is
|
||||
# given at all.
|
||||
|
||||
if {![llength $args]} {
|
||||
set args info
|
||||
}
|
||||
|
||||
# Tricky stuff needed to make stack and errors come out right!
|
||||
tailcall apply {arglist {tailcall history {*}$arglist} ::tcl} $args
|
||||
}
|
||||
|
||||
# (unnamed) --
|
||||
#
|
||||
# Callback when [::history] is destroyed. Destroys the implementation.
|
||||
#
|
||||
# Parameters:
|
||||
# oldName what the command was called.
|
||||
# newName what the command is now called (an empty string).
|
||||
# op the operation (= delete).
|
||||
#
|
||||
# Results:
|
||||
# none
|
||||
#
|
||||
# Side Effects:
|
||||
# The implementation of the [::history] command ceases to exist.
|
||||
|
||||
trace add command ::history delete [list apply {{oldName newName op} {
|
||||
variable history
|
||||
unset -nocomplain history
|
||||
foreach c [info procs ::tcl::Hist*] {
|
||||
rename $c {}
|
||||
}
|
||||
rename ::tcl::history {}
|
||||
} ::tcl}]
|
||||
|
||||
# tcl::HistAdd --
|
||||
#
|
||||
# Add an item to the history, and optionally eval it at the global scope
|
||||
#
|
||||
# Parameters:
|
||||
# event the command to add
|
||||
# exec (optional) a substring of "exec" causes the command to
|
||||
# be evaled.
|
||||
# Results:
|
||||
# If executing, then the results of the command are returned
|
||||
#
|
||||
# Side Effects:
|
||||
# Adds to the history list
|
||||
|
||||
proc ::tcl::HistAdd {event {exec {}}} {
|
||||
variable history
|
||||
|
||||
if {
|
||||
[prefix longest {exec {}} $exec] eq ""
|
||||
&& [llength [info level 0]] == 3
|
||||
} then {
|
||||
return -code error "bad argument \"$exec\": should be \"exec\""
|
||||
}
|
||||
|
||||
# Do not add empty commands to the history
|
||||
if {[string trim $event] eq ""} {
|
||||
return ""
|
||||
}
|
||||
|
||||
# Maintain the history
|
||||
set history([incr history(nextid)]) $event
|
||||
unset -nocomplain history([incr history(oldest)])
|
||||
|
||||
# Only execute if 'exec' (or non-empty prefix of it) given
|
||||
if {$exec eq ""} {
|
||||
return ""
|
||||
}
|
||||
tailcall eval $event
|
||||
}
|
||||
|
||||
# tcl::HistKeep --
|
||||
#
|
||||
# Set or query the limit on the length of the history list
|
||||
#
|
||||
# Parameters:
|
||||
# limit (optional) the length of the history list
|
||||
#
|
||||
# Results:
|
||||
# If no limit is specified, the current limit is returned
|
||||
#
|
||||
# Side Effects:
|
||||
# Updates history(keep) if a limit is specified
|
||||
|
||||
proc ::tcl::HistKeep {{count {}}} {
|
||||
variable history
|
||||
if {[llength [info level 0]] == 1} {
|
||||
return $history(keep)
|
||||
}
|
||||
if {![string is integer -strict $count] || ($count < 0)} {
|
||||
return -code error "illegal keep count \"$count\""
|
||||
}
|
||||
set oldold $history(oldest)
|
||||
set history(oldest) [expr {$history(nextid) - $count}]
|
||||
for {} {$oldold <= $history(oldest)} {incr oldold} {
|
||||
unset -nocomplain history($oldold)
|
||||
}
|
||||
set history(keep) $count
|
||||
}
|
||||
|
||||
# tcl::HistClear --
|
||||
#
|
||||
# Erase the history list
|
||||
#
|
||||
# Parameters:
|
||||
# none
|
||||
#
|
||||
# Results:
|
||||
# none
|
||||
#
|
||||
# Side Effects:
|
||||
# Resets the history array, except for the keep limit
|
||||
|
||||
proc ::tcl::HistClear {} {
|
||||
variable history
|
||||
set keep $history(keep)
|
||||
unset history
|
||||
array set history [list \
|
||||
nextid 0 \
|
||||
keep $keep \
|
||||
oldest -$keep \
|
||||
]
|
||||
}
|
||||
|
||||
# tcl::HistInfo --
|
||||
#
|
||||
# Return a pretty-printed version of the history list
|
||||
#
|
||||
# Parameters:
|
||||
# num (optional) the length of the history list to return
|
||||
#
|
||||
# Results:
|
||||
# A formatted history list
|
||||
|
||||
proc ::tcl::HistInfo {{count {}}} {
|
||||
variable history
|
||||
if {[llength [info level 0]] == 1} {
|
||||
set count [expr {$history(keep) + 1}]
|
||||
} elseif {![string is integer -strict $count]} {
|
||||
return -code error "bad integer \"$count\""
|
||||
}
|
||||
set result {}
|
||||
set newline ""
|
||||
for {set i [expr {$history(nextid) - $count + 1}]} \
|
||||
{$i <= $history(nextid)} {incr i} {
|
||||
if {![info exists history($i)]} {
|
||||
continue
|
||||
}
|
||||
set cmd [string map [list \n \n\t] [string trimright $history($i) \ \n]]
|
||||
append result $newline[format "%6d %s" $i $cmd]
|
||||
set newline \n
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
# tcl::HistRedo --
|
||||
#
|
||||
# Fetch the previous or specified event, execute it, and then replace
|
||||
# the current history item with that event.
|
||||
#
|
||||
# Parameters:
|
||||
# event (optional) index of history item to redo. Defaults to -1,
|
||||
# which means the previous event.
|
||||
#
|
||||
# Results:
|
||||
# Those of the command being redone.
|
||||
#
|
||||
# Side Effects:
|
||||
# Replaces the current history list item with the one being redone.
|
||||
|
||||
proc ::tcl::HistRedo {{event -1}} {
|
||||
variable history
|
||||
|
||||
set i [HistIndex $event]
|
||||
if {$i == $history(nextid)} {
|
||||
return -code error "cannot redo the current event"
|
||||
}
|
||||
set cmd $history($i)
|
||||
HistChange $cmd 0
|
||||
tailcall eval $cmd
|
||||
}
|
||||
|
||||
# tcl::HistIndex --
|
||||
#
|
||||
# Map from an event specifier to an index in the history list.
|
||||
#
|
||||
# Parameters:
|
||||
# event index of history item to redo.
|
||||
# If this is a positive number, it is used directly.
|
||||
# If it is a negative number, then it counts back to a previous
|
||||
# event, where -1 is the most recent event.
|
||||
# A string can be matched, either by being the prefix of a
|
||||
# command or by matching a command with string match.
|
||||
#
|
||||
# Results:
|
||||
# The index into history, or an error if the index didn't match.
|
||||
|
||||
proc ::tcl::HistIndex {event} {
|
||||
variable history
|
||||
if {![string is integer -strict $event]} {
|
||||
for {set i [expr {$history(nextid)-1}]} {[info exists history($i)]} \
|
||||
{incr i -1} {
|
||||
if {[string match $event* $history($i)]} {
|
||||
return $i
|
||||
}
|
||||
if {[string match $event $history($i)]} {
|
||||
return $i
|
||||
}
|
||||
}
|
||||
return -code error "no event matches \"$event\""
|
||||
} elseif {$event <= 0} {
|
||||
set i [expr {$history(nextid) + $event}]
|
||||
} else {
|
||||
set i $event
|
||||
}
|
||||
if {$i <= $history(oldest)} {
|
||||
return -code error "event \"$event\" is too far in the past"
|
||||
}
|
||||
if {$i > $history(nextid)} {
|
||||
return -code error "event \"$event\" hasn't occured yet"
|
||||
}
|
||||
return $i
|
||||
}
|
||||
|
||||
# tcl::HistEvent --
|
||||
#
|
||||
# Map from an event specifier to the value in the history list.
|
||||
#
|
||||
# Parameters:
|
||||
# event index of history item to redo. See index for a description of
|
||||
# possible event patterns.
|
||||
#
|
||||
# Results:
|
||||
# The value from the history list.
|
||||
|
||||
proc ::tcl::HistEvent {{event -1}} {
|
||||
variable history
|
||||
set i [HistIndex $event]
|
||||
if {![info exists history($i)]} {
|
||||
return ""
|
||||
}
|
||||
return [string trimright $history($i) \ \n]
|
||||
}
|
||||
|
||||
# tcl::HistChange --
|
||||
#
|
||||
# Replace a value in the history list.
|
||||
#
|
||||
# Parameters:
|
||||
# newValue The new value to put into the history list.
|
||||
# event (optional) index of history item to redo. See index for a
|
||||
# description of possible event patterns. This defaults to 0,
|
||||
# which specifies the current event.
|
||||
#
|
||||
# Side Effects:
|
||||
# Changes the history list.
|
||||
|
||||
proc ::tcl::HistChange {newValue {event 0}} {
|
||||
variable history
|
||||
set i [HistIndex $event]
|
||||
set history($i) $newValue
|
||||
}
|
||||
|
||||
# tcl::HistNextID --
|
||||
#
|
||||
# Returns the number of the next history event.
|
||||
#
|
||||
# Parameters:
|
||||
# None.
|
||||
#
|
||||
# Side Effects:
|
||||
# None.
|
||||
|
||||
proc ::tcl::HistNextID {} {
|
||||
variable history
|
||||
return [expr {$history(nextid) + 1}]
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
# Local Variables:
|
||||
# mode: tcl
|
||||
# fill-column: 78
|
||||
# End:
|
||||
|
|
@ -0,0 +1,827 @@
|
|||
# init.tcl --
|
||||
#
|
||||
# Default system startup file for Tcl-based applications. Defines
|
||||
# "unknown" procedure and auto-load facilities.
|
||||
#
|
||||
# Copyright (c) 1991-1993 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1996 Sun Microsystems, Inc.
|
||||
# Copyright (c) 1998-1999 Scriptics Corporation.
|
||||
# Copyright (c) 2004 Kevin B. Kenny. All rights reserved.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
# This test intentionally written in pre-7.5 Tcl
|
||||
if {[info commands package] == ""} {
|
||||
error "version mismatch: library\nscripts expect Tcl version 7.5b1 or later but the loaded version is\nonly [info patchlevel]"
|
||||
}
|
||||
package require -exact Tcl 8.6.11
|
||||
|
||||
# Compute the auto path to use in this interpreter.
|
||||
# The values on the path come from several locations:
|
||||
#
|
||||
# The environment variable TCLLIBPATH
|
||||
#
|
||||
# tcl_library, which is the directory containing this init.tcl script.
|
||||
# [tclInit] (Tcl_Init()) searches around for the directory containing this
|
||||
# init.tcl and defines tcl_library to that location before sourcing it.
|
||||
#
|
||||
# The parent directory of tcl_library. Adding the parent
|
||||
# means that packages in peer directories will be found automatically.
|
||||
#
|
||||
# Also add the directory ../lib relative to the directory where the
|
||||
# executable is located. This is meant to find binary packages for the
|
||||
# same architecture as the current executable.
|
||||
#
|
||||
# tcl_pkgPath, which is set by the platform-specific initialization routines
|
||||
# On UNIX it is compiled in
|
||||
# On Windows, it is not used
|
||||
#
|
||||
# (Ticket 41c9857bdd) In a safe interpreter, this file does not set
|
||||
# ::auto_path (other than to {} if it is undefined). The caller, typically
|
||||
# a Safe Base command, is responsible for setting ::auto_path.
|
||||
|
||||
if {![info exists auto_path]} {
|
||||
if {[info exists env(TCLLIBPATH)] && (![interp issafe])} {
|
||||
set auto_path $env(TCLLIBPATH)
|
||||
} else {
|
||||
set auto_path ""
|
||||
}
|
||||
}
|
||||
namespace eval tcl {
|
||||
if {![interp issafe]} {
|
||||
variable Dir
|
||||
foreach Dir [list $::tcl_library [file dirname $::tcl_library]] {
|
||||
if {$Dir ni $::auto_path} {
|
||||
lappend ::auto_path $Dir
|
||||
}
|
||||
}
|
||||
set Dir [file join [file dirname [file dirname \
|
||||
[info nameofexecutable]]] lib]
|
||||
if {$Dir ni $::auto_path} {
|
||||
lappend ::auto_path $Dir
|
||||
}
|
||||
if {[info exists ::tcl_pkgPath]} { catch {
|
||||
foreach Dir $::tcl_pkgPath {
|
||||
if {$Dir ni $::auto_path} {
|
||||
lappend ::auto_path $Dir
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
variable Path [encoding dirs]
|
||||
set Dir [file join $::tcl_library encoding]
|
||||
if {$Dir ni $Path} {
|
||||
lappend Path $Dir
|
||||
encoding dirs $Path
|
||||
}
|
||||
unset Dir Path
|
||||
}
|
||||
|
||||
# TIP #255 min and max functions
|
||||
namespace eval mathfunc {
|
||||
proc min {args} {
|
||||
if {![llength $args]} {
|
||||
return -code error \
|
||||
"not enough arguments to math function \"min\""
|
||||
}
|
||||
set val Inf
|
||||
foreach arg $args {
|
||||
# This will handle forcing the numeric value without
|
||||
# ruining the internal type of a numeric object
|
||||
if {[catch {expr {double($arg)}} err]} {
|
||||
return -code error $err
|
||||
}
|
||||
if {$arg < $val} {set val $arg}
|
||||
}
|
||||
return $val
|
||||
}
|
||||
proc max {args} {
|
||||
if {![llength $args]} {
|
||||
return -code error \
|
||||
"not enough arguments to math function \"max\""
|
||||
}
|
||||
set val -Inf
|
||||
foreach arg $args {
|
||||
# This will handle forcing the numeric value without
|
||||
# ruining the internal type of a numeric object
|
||||
if {[catch {expr {double($arg)}} err]} {
|
||||
return -code error $err
|
||||
}
|
||||
if {$arg > $val} {set val $arg}
|
||||
}
|
||||
return $val
|
||||
}
|
||||
namespace export min max
|
||||
}
|
||||
}
|
||||
|
||||
# Windows specific end of initialization
|
||||
|
||||
if {(![interp issafe]) && ($tcl_platform(platform) eq "windows")} {
|
||||
namespace eval tcl {
|
||||
proc EnvTraceProc {lo n1 n2 op} {
|
||||
global env
|
||||
set x $env($n2)
|
||||
set env($lo) $x
|
||||
set env([string toupper $lo]) $x
|
||||
}
|
||||
proc InitWinEnv {} {
|
||||
global env tcl_platform
|
||||
foreach p [array names env] {
|
||||
set u [string toupper $p]
|
||||
if {$u ne $p} {
|
||||
switch -- $u {
|
||||
COMSPEC -
|
||||
PATH {
|
||||
set temp $env($p)
|
||||
unset env($p)
|
||||
set env($u) $temp
|
||||
trace add variable env($p) write \
|
||||
[namespace code [list EnvTraceProc $p]]
|
||||
trace add variable env($u) write \
|
||||
[namespace code [list EnvTraceProc $p]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if {![info exists env(COMSPEC)]} {
|
||||
set env(COMSPEC) cmd.exe
|
||||
}
|
||||
}
|
||||
InitWinEnv
|
||||
}
|
||||
}
|
||||
|
||||
# Setup the unknown package handler
|
||||
|
||||
|
||||
if {[interp issafe]} {
|
||||
package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
|
||||
} else {
|
||||
# Set up search for Tcl Modules (TIP #189).
|
||||
# and setup platform specific unknown package handlers
|
||||
if {$tcl_platform(os) eq "Darwin"
|
||||
&& $tcl_platform(platform) eq "unix"} {
|
||||
package unknown {::tcl::tm::UnknownHandler \
|
||||
{::tcl::MacOSXPkgUnknown ::tclPkgUnknown}}
|
||||
} else {
|
||||
package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
|
||||
}
|
||||
|
||||
# Set up the 'clock' ensemble
|
||||
|
||||
namespace eval ::tcl::clock [list variable TclLibDir $::tcl_library]
|
||||
|
||||
proc ::tcl::initClock {} {
|
||||
# Auto-loading stubs for 'clock.tcl'
|
||||
|
||||
foreach cmd {add format scan} {
|
||||
proc ::tcl::clock::$cmd args {
|
||||
variable TclLibDir
|
||||
source -encoding utf-8 [file join $TclLibDir clock.tcl]
|
||||
return [uplevel 1 [info level 0]]
|
||||
}
|
||||
}
|
||||
|
||||
rename ::tcl::initClock {}
|
||||
}
|
||||
::tcl::initClock
|
||||
}
|
||||
|
||||
# Conditionalize for presence of exec.
|
||||
|
||||
if {[namespace which -command exec] eq ""} {
|
||||
|
||||
# Some machines do not have exec. Also, on all
|
||||
# platforms, safe interpreters do not have exec.
|
||||
|
||||
set auto_noexec 1
|
||||
}
|
||||
|
||||
# Define a log command (which can be overwitten to log errors
|
||||
# differently, specially when stderr is not available)
|
||||
|
||||
if {[namespace which -command tclLog] eq ""} {
|
||||
proc tclLog {string} {
|
||||
catch {puts stderr $string}
|
||||
}
|
||||
}
|
||||
|
||||
# unknown --
|
||||
# This procedure is called when a Tcl command is invoked that doesn't
|
||||
# exist in the interpreter. It takes the following steps to make the
|
||||
# command available:
|
||||
#
|
||||
# 1. See if the autoload facility can locate the command in a
|
||||
# Tcl script file. If so, load it and execute it.
|
||||
# 2. If the command was invoked interactively at top-level:
|
||||
# (a) see if the command exists as an executable UNIX program.
|
||||
# If so, "exec" the command.
|
||||
# (b) see if the command requests csh-like history substitution
|
||||
# in one of the common forms !!, !<number>, or ^old^new. If
|
||||
# so, emulate csh's history substitution.
|
||||
# (c) see if the command is a unique abbreviation for another
|
||||
# command. If so, invoke the command.
|
||||
#
|
||||
# Arguments:
|
||||
# args - A list whose elements are the words of the original
|
||||
# command, including the command name.
|
||||
|
||||
proc unknown args {
|
||||
variable ::tcl::UnknownPending
|
||||
global auto_noexec auto_noload env tcl_interactive errorInfo errorCode
|
||||
|
||||
if {[info exists errorInfo]} {
|
||||
set savedErrorInfo $errorInfo
|
||||
}
|
||||
if {[info exists errorCode]} {
|
||||
set savedErrorCode $errorCode
|
||||
}
|
||||
|
||||
set name [lindex $args 0]
|
||||
if {![info exists auto_noload]} {
|
||||
#
|
||||
# Make sure we're not trying to load the same proc twice.
|
||||
#
|
||||
if {[info exists UnknownPending($name)]} {
|
||||
return -code error "self-referential recursion\
|
||||
in \"unknown\" for command \"$name\""
|
||||
}
|
||||
set UnknownPending($name) pending
|
||||
set ret [catch {
|
||||
auto_load $name [uplevel 1 {::namespace current}]
|
||||
} msg opts]
|
||||
unset UnknownPending($name)
|
||||
if {$ret != 0} {
|
||||
dict append opts -errorinfo "\n (autoloading \"$name\")"
|
||||
return -options $opts $msg
|
||||
}
|
||||
if {![array size UnknownPending]} {
|
||||
unset UnknownPending
|
||||
}
|
||||
if {$msg} {
|
||||
if {[info exists savedErrorCode]} {
|
||||
set ::errorCode $savedErrorCode
|
||||
} else {
|
||||
unset -nocomplain ::errorCode
|
||||
}
|
||||
if {[info exists savedErrorInfo]} {
|
||||
set errorInfo $savedErrorInfo
|
||||
} else {
|
||||
unset -nocomplain errorInfo
|
||||
}
|
||||
set code [catch {uplevel 1 $args} msg opts]
|
||||
if {$code == 1} {
|
||||
#
|
||||
# Compute stack trace contribution from the [uplevel].
|
||||
# Note the dependence on how Tcl_AddErrorInfo, etc.
|
||||
# construct the stack trace.
|
||||
#
|
||||
set errInfo [dict get $opts -errorinfo]
|
||||
set errCode [dict get $opts -errorcode]
|
||||
set cinfo $args
|
||||
if {[string bytelength $cinfo] > 150} {
|
||||
set cinfo [string range $cinfo 0 150]
|
||||
while {[string bytelength $cinfo] > 150} {
|
||||
set cinfo [string range $cinfo 0 end-1]
|
||||
}
|
||||
append cinfo ...
|
||||
}
|
||||
set tail "\n (\"uplevel\" body line 1)\n invoked\
|
||||
from within\n\"uplevel 1 \$args\""
|
||||
set expect "$msg\n while executing\n\"$cinfo\"$tail"
|
||||
if {$errInfo eq $expect} {
|
||||
#
|
||||
# The stack has only the eval from the expanded command
|
||||
# Do not generate any stack trace here.
|
||||
#
|
||||
dict unset opts -errorinfo
|
||||
dict incr opts -level
|
||||
return -options $opts $msg
|
||||
}
|
||||
#
|
||||
# Stack trace is nested, trim off just the contribution
|
||||
# from the extra "eval" of $args due to the "catch" above.
|
||||
#
|
||||
set last [string last $tail $errInfo]
|
||||
if {$last + [string length $tail] != [string length $errInfo]} {
|
||||
# Very likely cannot happen
|
||||
return -options $opts $msg
|
||||
}
|
||||
set errInfo [string range $errInfo 0 $last-1]
|
||||
set tail "\"$cinfo\""
|
||||
set last [string last $tail $errInfo]
|
||||
if {$last < 0 || $last + [string length $tail] != [string length $errInfo]} {
|
||||
return -code error -errorcode $errCode \
|
||||
-errorinfo $errInfo $msg
|
||||
}
|
||||
set errInfo [string range $errInfo 0 $last-1]
|
||||
set tail "\n invoked from within\n"
|
||||
set last [string last $tail $errInfo]
|
||||
if {$last + [string length $tail] == [string length $errInfo]} {
|
||||
return -code error -errorcode $errCode \
|
||||
-errorinfo [string range $errInfo 0 $last-1] $msg
|
||||
}
|
||||
set tail "\n while executing\n"
|
||||
set last [string last $tail $errInfo]
|
||||
if {$last + [string length $tail] == [string length $errInfo]} {
|
||||
return -code error -errorcode $errCode \
|
||||
-errorinfo [string range $errInfo 0 $last-1] $msg
|
||||
}
|
||||
return -options $opts $msg
|
||||
} else {
|
||||
dict incr opts -level
|
||||
return -options $opts $msg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {([info level] == 1) && ([info script] eq "")
|
||||
&& [info exists tcl_interactive] && $tcl_interactive} {
|
||||
if {![info exists auto_noexec]} {
|
||||
set new [auto_execok $name]
|
||||
if {$new ne ""} {
|
||||
set redir ""
|
||||
if {[namespace which -command console] eq ""} {
|
||||
set redir ">&@stdout <@stdin"
|
||||
}
|
||||
uplevel 1 [list ::catch \
|
||||
[concat exec $redir $new [lrange $args 1 end]] \
|
||||
::tcl::UnknownResult ::tcl::UnknownOptions]
|
||||
dict incr ::tcl::UnknownOptions -level
|
||||
return -options $::tcl::UnknownOptions $::tcl::UnknownResult
|
||||
}
|
||||
}
|
||||
if {$name eq "!!"} {
|
||||
set newcmd [history event]
|
||||
} elseif {[regexp {^!(.+)$} $name -> event]} {
|
||||
set newcmd [history event $event]
|
||||
} elseif {[regexp {^\^([^^]*)\^([^^]*)\^?$} $name -> old new]} {
|
||||
set newcmd [history event -1]
|
||||
catch {regsub -all -- $old $newcmd $new newcmd}
|
||||
}
|
||||
if {[info exists newcmd]} {
|
||||
tclLog $newcmd
|
||||
history change $newcmd 0
|
||||
uplevel 1 [list ::catch $newcmd \
|
||||
::tcl::UnknownResult ::tcl::UnknownOptions]
|
||||
dict incr ::tcl::UnknownOptions -level
|
||||
return -options $::tcl::UnknownOptions $::tcl::UnknownResult
|
||||
}
|
||||
|
||||
set ret [catch {set candidates [info commands $name*]} msg]
|
||||
if {$name eq "::"} {
|
||||
set name ""
|
||||
}
|
||||
if {$ret != 0} {
|
||||
dict append opts -errorinfo \
|
||||
"\n (expanding command prefix \"$name\" in unknown)"
|
||||
return -options $opts $msg
|
||||
}
|
||||
# Filter out bogus matches when $name contained
|
||||
# a glob-special char [Bug 946952]
|
||||
if {$name eq ""} {
|
||||
# Handle empty $name separately due to strangeness
|
||||
# in [string first] (See RFE 1243354)
|
||||
set cmds $candidates
|
||||
} else {
|
||||
set cmds [list]
|
||||
foreach x $candidates {
|
||||
if {[string first $name $x] == 0} {
|
||||
lappend cmds $x
|
||||
}
|
||||
}
|
||||
}
|
||||
if {[llength $cmds] == 1} {
|
||||
uplevel 1 [list ::catch [lreplace $args 0 0 [lindex $cmds 0]] \
|
||||
::tcl::UnknownResult ::tcl::UnknownOptions]
|
||||
dict incr ::tcl::UnknownOptions -level
|
||||
return -options $::tcl::UnknownOptions $::tcl::UnknownResult
|
||||
}
|
||||
if {[llength $cmds]} {
|
||||
return -code error "ambiguous command name \"$name\": [lsort $cmds]"
|
||||
}
|
||||
}
|
||||
return -code error -errorcode [list TCL LOOKUP COMMAND $name] \
|
||||
"invalid command name \"$name\""
|
||||
}
|
||||
|
||||
# auto_load --
|
||||
# Checks a collection of library directories to see if a procedure
|
||||
# is defined in one of them. If so, it sources the appropriate
|
||||
# library file to create the procedure. Returns 1 if it successfully
|
||||
# loaded the procedure, 0 otherwise.
|
||||
#
|
||||
# Arguments:
|
||||
# cmd - Name of the command to find and load.
|
||||
# namespace (optional) The namespace where the command is being used - must be
|
||||
# a canonical namespace as returned [namespace current]
|
||||
# for instance. If not given, namespace current is used.
|
||||
|
||||
proc auto_load {cmd {namespace {}}} {
|
||||
global auto_index auto_path
|
||||
|
||||
if {$namespace eq ""} {
|
||||
set namespace [uplevel 1 [list ::namespace current]]
|
||||
}
|
||||
set nameList [auto_qualify $cmd $namespace]
|
||||
# workaround non canonical auto_index entries that might be around
|
||||
# from older auto_mkindex versions
|
||||
lappend nameList $cmd
|
||||
foreach name $nameList {
|
||||
if {[info exists auto_index($name)]} {
|
||||
namespace eval :: $auto_index($name)
|
||||
# There's a couple of ways to look for a command of a given
|
||||
# name. One is to use
|
||||
# info commands $name
|
||||
# Unfortunately, if the name has glob-magic chars in it like *
|
||||
# or [], it may not match. For our purposes here, a better
|
||||
# route is to use
|
||||
# namespace which -command $name
|
||||
if {[namespace which -command $name] ne ""} {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if {![info exists auto_path]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
if {![auto_load_index]} {
|
||||
return 0
|
||||
}
|
||||
foreach name $nameList {
|
||||
if {[info exists auto_index($name)]} {
|
||||
namespace eval :: $auto_index($name)
|
||||
if {[namespace which -command $name] ne ""} {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
# auto_load_index --
|
||||
# Loads the contents of tclIndex files on the auto_path directory
|
||||
# list. This is usually invoked within auto_load to load the index
|
||||
# of available commands. Returns 1 if the index is loaded, and 0 if
|
||||
# the index is already loaded and up to date.
|
||||
#
|
||||
# Arguments:
|
||||
# None.
|
||||
|
||||
proc auto_load_index {} {
|
||||
variable ::tcl::auto_oldpath
|
||||
global auto_index auto_path
|
||||
|
||||
if {[info exists auto_oldpath] && ($auto_oldpath eq $auto_path)} {
|
||||
return 0
|
||||
}
|
||||
set auto_oldpath $auto_path
|
||||
|
||||
# Check if we are a safe interpreter. In that case, we support only
|
||||
# newer format tclIndex files.
|
||||
|
||||
set issafe [interp issafe]
|
||||
for {set i [expr {[llength $auto_path] - 1}]} {$i >= 0} {incr i -1} {
|
||||
set dir [lindex $auto_path $i]
|
||||
set f ""
|
||||
if {$issafe} {
|
||||
catch {source [file join $dir tclIndex]}
|
||||
} elseif {[catch {set f [open [file join $dir tclIndex]]}]} {
|
||||
continue
|
||||
} else {
|
||||
set error [catch {
|
||||
fconfigure $f -eofchar \032
|
||||
set id [gets $f]
|
||||
if {$id eq "# Tcl autoload index file, version 2.0"} {
|
||||
eval [read $f]
|
||||
} elseif {$id eq "# Tcl autoload index file: each line identifies a Tcl"} {
|
||||
while {[gets $f line] >= 0} {
|
||||
if {([string index $line 0] eq "#") \
|
||||
|| ([llength $line] != 2)} {
|
||||
continue
|
||||
}
|
||||
set name [lindex $line 0]
|
||||
set auto_index($name) \
|
||||
"source [file join $dir [lindex $line 1]]"
|
||||
}
|
||||
} else {
|
||||
error "[file join $dir tclIndex] isn't a proper Tcl index file"
|
||||
}
|
||||
} msg opts]
|
||||
if {$f ne ""} {
|
||||
close $f
|
||||
}
|
||||
if {$error} {
|
||||
return -options $opts $msg
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
# auto_qualify --
|
||||
#
|
||||
# Compute a fully qualified names list for use in the auto_index array.
|
||||
# For historical reasons, commands in the global namespace do not have leading
|
||||
# :: in the index key. The list has two elements when the command name is
|
||||
# relative (no leading ::) and the namespace is not the global one. Otherwise
|
||||
# only one name is returned (and searched in the auto_index).
|
||||
#
|
||||
# Arguments -
|
||||
# cmd The command name. Can be any name accepted for command
|
||||
# invocations (Like "foo::::bar").
|
||||
# namespace The namespace where the command is being used - must be
|
||||
# a canonical namespace as returned by [namespace current]
|
||||
# for instance.
|
||||
|
||||
proc auto_qualify {cmd namespace} {
|
||||
|
||||
# count separators and clean them up
|
||||
# (making sure that foo:::::bar will be treated as foo::bar)
|
||||
set n [regsub -all {::+} $cmd :: cmd]
|
||||
|
||||
# Ignore namespace if the name starts with ::
|
||||
# Handle special case of only leading ::
|
||||
|
||||
# Before each return case we give an example of which category it is
|
||||
# with the following form :
|
||||
# (inputCmd, inputNameSpace) -> output
|
||||
|
||||
if {[string match ::* $cmd]} {
|
||||
if {$n > 1} {
|
||||
# (::foo::bar , *) -> ::foo::bar
|
||||
return [list $cmd]
|
||||
} else {
|
||||
# (::global , *) -> global
|
||||
return [list [string range $cmd 2 end]]
|
||||
}
|
||||
}
|
||||
|
||||
# Potentially returning 2 elements to try :
|
||||
# (if the current namespace is not the global one)
|
||||
|
||||
if {$n == 0} {
|
||||
if {$namespace eq "::"} {
|
||||
# (nocolons , ::) -> nocolons
|
||||
return [list $cmd]
|
||||
} else {
|
||||
# (nocolons , ::sub) -> ::sub::nocolons nocolons
|
||||
return [list ${namespace}::$cmd $cmd]
|
||||
}
|
||||
} elseif {$namespace eq "::"} {
|
||||
# (foo::bar , ::) -> ::foo::bar
|
||||
return [list ::$cmd]
|
||||
} else {
|
||||
# (foo::bar , ::sub) -> ::sub::foo::bar ::foo::bar
|
||||
return [list ${namespace}::$cmd ::$cmd]
|
||||
}
|
||||
}
|
||||
|
||||
# auto_import --
|
||||
#
|
||||
# Invoked during "namespace import" to make see if the imported commands
|
||||
# reside in an autoloaded library. If so, the commands are loaded so
|
||||
# that they will be available for the import links. If not, then this
|
||||
# procedure does nothing.
|
||||
#
|
||||
# Arguments -
|
||||
# pattern The pattern of commands being imported (like "foo::*")
|
||||
# a canonical namespace as returned by [namespace current]
|
||||
|
||||
proc auto_import {pattern} {
|
||||
global auto_index
|
||||
|
||||
# If no namespace is specified, this will be an error case
|
||||
|
||||
if {![string match *::* $pattern]} {
|
||||
return
|
||||
}
|
||||
|
||||
set ns [uplevel 1 [list ::namespace current]]
|
||||
set patternList [auto_qualify $pattern $ns]
|
||||
|
||||
auto_load_index
|
||||
|
||||
foreach pattern $patternList {
|
||||
foreach name [array names auto_index $pattern] {
|
||||
if {([namespace which -command $name] eq "")
|
||||
&& ([namespace qualifiers $pattern] eq [namespace qualifiers $name])} {
|
||||
namespace eval :: $auto_index($name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# auto_execok --
|
||||
#
|
||||
# Returns string that indicates name of program to execute if
|
||||
# name corresponds to a shell builtin or an executable in the
|
||||
# Windows search path, or "" otherwise. Builds an associative
|
||||
# array auto_execs that caches information about previous checks,
|
||||
# for speed.
|
||||
#
|
||||
# Arguments:
|
||||
# name - Name of a command.
|
||||
|
||||
if {$tcl_platform(platform) eq "windows"} {
|
||||
# Windows version.
|
||||
#
|
||||
# Note that file executable doesn't work under Windows, so we have to
|
||||
# look for files with .exe, .com, or .bat extensions. Also, the path
|
||||
# may be in the Path or PATH environment variables, and path
|
||||
# components are separated with semicolons, not colons as under Unix.
|
||||
#
|
||||
proc auto_execok name {
|
||||
global auto_execs env tcl_platform
|
||||
|
||||
if {[info exists auto_execs($name)]} {
|
||||
return $auto_execs($name)
|
||||
}
|
||||
set auto_execs($name) ""
|
||||
|
||||
set shellBuiltins [list assoc cls copy date del dir echo erase ftype \
|
||||
md mkdir mklink move rd ren rename rmdir start time type ver vol]
|
||||
if {[info exists env(PATHEXT)]} {
|
||||
# Add an initial ; to have the {} extension check first.
|
||||
set execExtensions [split ";$env(PATHEXT)" ";"]
|
||||
} else {
|
||||
set execExtensions [list {} .com .exe .bat .cmd]
|
||||
}
|
||||
|
||||
if {[string tolower $name] in $shellBuiltins} {
|
||||
# When this is command.com for some reason on Win2K, Tcl won't
|
||||
# exec it unless the case is right, which this corrects. COMSPEC
|
||||
# may not point to a real file, so do the check.
|
||||
set cmd $env(COMSPEC)
|
||||
if {[file exists $cmd]} {
|
||||
set cmd [file attributes $cmd -shortname]
|
||||
}
|
||||
return [set auto_execs($name) [list $cmd /c $name]]
|
||||
}
|
||||
|
||||
if {[llength [file split $name]] != 1} {
|
||||
foreach ext $execExtensions {
|
||||
set file ${name}${ext}
|
||||
if {[file exists $file] && ![file isdirectory $file]} {
|
||||
return [set auto_execs($name) [list $file]]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
set path "[file dirname [info nameof]];.;"
|
||||
if {[info exists env(SystemRoot)]} {
|
||||
set windir $env(SystemRoot)
|
||||
} elseif {[info exists env(WINDIR)]} {
|
||||
set windir $env(WINDIR)
|
||||
}
|
||||
if {[info exists windir]} {
|
||||
if {$tcl_platform(os) eq "Windows NT"} {
|
||||
append path "$windir/system32;"
|
||||
}
|
||||
append path "$windir/system;$windir;"
|
||||
}
|
||||
|
||||
foreach var {PATH Path path} {
|
||||
if {[info exists env($var)]} {
|
||||
append path ";$env($var)"
|
||||
}
|
||||
}
|
||||
|
||||
foreach ext $execExtensions {
|
||||
unset -nocomplain checked
|
||||
foreach dir [split $path {;}] {
|
||||
# Skip already checked directories
|
||||
if {[info exists checked($dir)] || ($dir eq "")} {
|
||||
continue
|
||||
}
|
||||
set checked($dir) {}
|
||||
set file [file join $dir ${name}${ext}]
|
||||
if {[file exists $file] && ![file isdirectory $file]} {
|
||||
return [set auto_execs($name) [list $file]]
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
} else {
|
||||
# Unix version.
|
||||
#
|
||||
proc auto_execok name {
|
||||
global auto_execs env
|
||||
|
||||
if {[info exists auto_execs($name)]} {
|
||||
return $auto_execs($name)
|
||||
}
|
||||
set auto_execs($name) ""
|
||||
if {[llength [file split $name]] != 1} {
|
||||
if {[file executable $name] && ![file isdirectory $name]} {
|
||||
set auto_execs($name) [list $name]
|
||||
}
|
||||
return $auto_execs($name)
|
||||
}
|
||||
foreach dir [split $env(PATH) :] {
|
||||
if {$dir eq ""} {
|
||||
set dir .
|
||||
}
|
||||
set file [file join $dir $name]
|
||||
if {[file executable $file] && ![file isdirectory $file]} {
|
||||
set auto_execs($name) [list $file]
|
||||
return $auto_execs($name)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# ::tcl::CopyDirectory --
|
||||
#
|
||||
# This procedure is called by Tcl's core when attempts to call the
|
||||
# filesystem's copydirectory function fail. The semantics of the call
|
||||
# are that 'dest' does not yet exist, i.e. dest should become the exact
|
||||
# image of src. If dest does exist, we throw an error.
|
||||
#
|
||||
# Note that making changes to this procedure can change the results
|
||||
# of running Tcl's tests.
|
||||
#
|
||||
# Arguments:
|
||||
# action - "renaming" or "copying"
|
||||
# src - source directory
|
||||
# dest - destination directory
|
||||
proc tcl::CopyDirectory {action src dest} {
|
||||
set nsrc [file normalize $src]
|
||||
set ndest [file normalize $dest]
|
||||
|
||||
if {$action eq "renaming"} {
|
||||
# Can't rename volumes. We could give a more precise
|
||||
# error message here, but that would break the test suite.
|
||||
if {$nsrc in [file volumes]} {
|
||||
return -code error "error $action \"$src\" to\
|
||||
\"$dest\": trying to rename a volume or move a directory\
|
||||
into itself"
|
||||
}
|
||||
}
|
||||
if {[file exists $dest]} {
|
||||
if {$nsrc eq $ndest} {
|
||||
return -code error "error $action \"$src\" to\
|
||||
\"$dest\": trying to rename a volume or move a directory\
|
||||
into itself"
|
||||
}
|
||||
if {$action eq "copying"} {
|
||||
# We used to throw an error here, but, looking more closely
|
||||
# at the core copy code in tclFCmd.c, if the destination
|
||||
# exists, then we should only call this function if -force
|
||||
# is true, which means we just want to over-write. So,
|
||||
# the following code is now commented out.
|
||||
#
|
||||
# return -code error "error $action \"$src\" to\
|
||||
# \"$dest\": file already exists"
|
||||
} else {
|
||||
# Depending on the platform, and on the current
|
||||
# working directory, the directories '.', '..'
|
||||
# can be returned in various combinations. Anyway,
|
||||
# if any other file is returned, we must signal an error.
|
||||
set existing [glob -nocomplain -directory $dest * .*]
|
||||
lappend existing {*}[glob -nocomplain -directory $dest \
|
||||
-type hidden * .*]
|
||||
foreach s $existing {
|
||||
if {[file tail $s] ni {. ..}} {
|
||||
return -code error "error $action \"$src\" to\
|
||||
\"$dest\": file already exists"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if {[string first $nsrc $ndest] >= 0} {
|
||||
set srclen [expr {[llength [file split $nsrc]] - 1}]
|
||||
set ndest [lindex [file split $ndest] $srclen]
|
||||
if {$ndest eq [file tail $nsrc]} {
|
||||
return -code error "error $action \"$src\" to\
|
||||
\"$dest\": trying to rename a volume or move a directory\
|
||||
into itself"
|
||||
}
|
||||
}
|
||||
file mkdir $dest
|
||||
}
|
||||
# Have to be careful to capture both visible and hidden files.
|
||||
# We will also be more generous to the file system and not
|
||||
# assume the hidden and non-hidden lists are non-overlapping.
|
||||
#
|
||||
# On Unix 'hidden' files begin with '.'. On other platforms
|
||||
# or filesystems hidden files may have other interpretations.
|
||||
set filelist [concat [glob -nocomplain -directory $src *] \
|
||||
[glob -nocomplain -directory $src -types hidden *]]
|
||||
|
||||
foreach s [lsort -unique $filelist] {
|
||||
if {[file tail $s] ni {. ..}} {
|
||||
file copy -force -- $s [file join $dest [file tail $s]]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
This software is copyrighted by the Regents of the University of
|
||||
California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
|
||||
Corporation and other parties. The following terms apply to all files
|
||||
associated with the software unless explicitly disclaimed in
|
||||
individual files.
|
||||
|
||||
The authors 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 AUTHORS 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 AUTHORS HAVE BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
THE AUTHORS 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 AUTHORS AND DISTRIBUTORS HAVE
|
||||
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
||||
MODIFICATIONS.
|
||||
|
||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
||||
U.S. government, the Government shall have only "Restricted Rights"
|
||||
in the software and related documentation as defined in the Federal
|
||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
|
||||
are acquiring the software on behalf of the Department of Defense, the
|
||||
software shall be classified as "Commercial Computer Software" and the
|
||||
Government shall have only "Restricted Rights" as defined in Clause
|
||||
252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the
|
||||
authors grant the U.S. Government and others acting in its behalf
|
||||
permission to use and distribute the software in accordance with the
|
||||
terms specified in this license.
|
||||
|
|
@ -0,0 +1,751 @@
|
|||
# package.tcl --
|
||||
#
|
||||
# utility procs formerly in init.tcl which can be loaded on demand
|
||||
# for package management.
|
||||
#
|
||||
# Copyright (c) 1991-1993 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1998 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
namespace eval tcl::Pkg {}
|
||||
|
||||
# ::tcl::Pkg::CompareExtension --
|
||||
#
|
||||
# Used internally by pkg_mkIndex to compare the extension of a file to a given
|
||||
# extension. On Windows, it uses a case-insensitive comparison because the
|
||||
# file system can be file insensitive.
|
||||
#
|
||||
# Arguments:
|
||||
# fileName name of a file whose extension is compared
|
||||
# ext (optional) The extension to compare against; you must
|
||||
# provide the starting dot.
|
||||
# Defaults to [info sharedlibextension]
|
||||
#
|
||||
# Results:
|
||||
# Returns 1 if the extension matches, 0 otherwise
|
||||
|
||||
proc tcl::Pkg::CompareExtension {fileName {ext {}}} {
|
||||
global tcl_platform
|
||||
if {$ext eq ""} {set ext [info sharedlibextension]}
|
||||
if {$tcl_platform(platform) eq "windows"} {
|
||||
return [string equal -nocase [file extension $fileName] $ext]
|
||||
} else {
|
||||
# Some unices add trailing numbers after the .so, so
|
||||
# we could have something like '.so.1.2'.
|
||||
set root $fileName
|
||||
while {1} {
|
||||
set currExt [file extension $root]
|
||||
if {$currExt eq $ext} {
|
||||
return 1
|
||||
}
|
||||
|
||||
# The current extension does not match; if it is not a numeric
|
||||
# value, quit, as we are only looking to ignore version number
|
||||
# extensions. Otherwise we might return 1 in this case:
|
||||
# tcl::Pkg::CompareExtension foo.so.bar .so
|
||||
# which should not match.
|
||||
|
||||
if {![string is integer -strict [string range $currExt 1 end]]} {
|
||||
return 0
|
||||
}
|
||||
set root [file rootname $root]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# pkg_mkIndex --
|
||||
# This procedure creates a package index in a given directory. The package
|
||||
# index consists of a "pkgIndex.tcl" file whose contents are a Tcl script that
|
||||
# sets up package information with "package require" commands. The commands
|
||||
# describe all of the packages defined by the files given as arguments.
|
||||
#
|
||||
# Arguments:
|
||||
# -direct (optional) If this flag is present, the generated
|
||||
# code in pkgMkIndex.tcl will cause the package to be
|
||||
# loaded when "package require" is executed, rather
|
||||
# than lazily when the first reference to an exported
|
||||
# procedure in the package is made.
|
||||
# -verbose (optional) Verbose output; the name of each file that
|
||||
# was successfully rocessed is printed out. Additionally,
|
||||
# if processing of a file failed a message is printed.
|
||||
# -load pat (optional) Preload any packages whose names match
|
||||
# the pattern. Used to handle DLLs that depend on
|
||||
# other packages during their Init procedure.
|
||||
# dir - Name of the directory in which to create the index.
|
||||
# args - Any number of additional arguments, each giving
|
||||
# a glob pattern that matches the names of one or
|
||||
# more shared libraries or Tcl script files in
|
||||
# dir.
|
||||
|
||||
proc pkg_mkIndex {args} {
|
||||
set usage {"pkg_mkIndex ?-direct? ?-lazy? ?-load pattern? ?-verbose? ?--? dir ?pattern ...?"}
|
||||
|
||||
set argCount [llength $args]
|
||||
if {$argCount < 1} {
|
||||
return -code error "wrong # args: should be\n$usage"
|
||||
}
|
||||
|
||||
set more ""
|
||||
set direct 1
|
||||
set doVerbose 0
|
||||
set loadPat ""
|
||||
for {set idx 0} {$idx < $argCount} {incr idx} {
|
||||
set flag [lindex $args $idx]
|
||||
switch -glob -- $flag {
|
||||
-- {
|
||||
# done with the flags
|
||||
incr idx
|
||||
break
|
||||
}
|
||||
-verbose {
|
||||
set doVerbose 1
|
||||
}
|
||||
-lazy {
|
||||
set direct 0
|
||||
append more " -lazy"
|
||||
}
|
||||
-direct {
|
||||
append more " -direct"
|
||||
}
|
||||
-load {
|
||||
incr idx
|
||||
set loadPat [lindex $args $idx]
|
||||
append more " -load $loadPat"
|
||||
}
|
||||
-* {
|
||||
return -code error "unknown flag $flag: should be\n$usage"
|
||||
}
|
||||
default {
|
||||
# done with the flags
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set dir [lindex $args $idx]
|
||||
set patternList [lrange $args [expr {$idx + 1}] end]
|
||||
if {![llength $patternList]} {
|
||||
set patternList [list "*.tcl" "*[info sharedlibextension]"]
|
||||
}
|
||||
|
||||
try {
|
||||
set fileList [glob -directory $dir -tails -types {r f} -- \
|
||||
{*}$patternList]
|
||||
} on error {msg opt} {
|
||||
return -options $opt $msg
|
||||
}
|
||||
foreach file $fileList {
|
||||
# For each file, figure out what commands and packages it provides.
|
||||
# To do this, create a child interpreter, load the file into the
|
||||
# interpreter, and get a list of the new commands and packages that
|
||||
# are defined.
|
||||
|
||||
if {$file eq "pkgIndex.tcl"} {
|
||||
continue
|
||||
}
|
||||
|
||||
set c [interp create]
|
||||
|
||||
# Load into the child any packages currently loaded in the parent
|
||||
# interpreter that match the -load pattern.
|
||||
|
||||
if {$loadPat ne ""} {
|
||||
if {$doVerbose} {
|
||||
tclLog "currently loaded packages: '[info loaded]'"
|
||||
tclLog "trying to load all packages matching $loadPat"
|
||||
}
|
||||
if {![llength [info loaded]]} {
|
||||
tclLog "warning: no packages are currently loaded, nothing"
|
||||
tclLog "can possibly match '$loadPat'"
|
||||
}
|
||||
}
|
||||
foreach pkg [info loaded] {
|
||||
if {![string match -nocase $loadPat [lindex $pkg 1]]} {
|
||||
continue
|
||||
}
|
||||
if {$doVerbose} {
|
||||
tclLog "package [lindex $pkg 1] matches '$loadPat'"
|
||||
}
|
||||
try {
|
||||
load [lindex $pkg 0] [lindex $pkg 1] $c
|
||||
} on error err {
|
||||
if {$doVerbose} {
|
||||
tclLog "warning: load [lindex $pkg 0]\
|
||||
[lindex $pkg 1]\nfailed with: $err"
|
||||
}
|
||||
} on ok {} {
|
||||
if {$doVerbose} {
|
||||
tclLog "loaded [lindex $pkg 0] [lindex $pkg 1]"
|
||||
}
|
||||
}
|
||||
if {[lindex $pkg 1] eq "Tk"} {
|
||||
# Withdraw . if Tk was loaded, to avoid showing a window.
|
||||
$c eval [list wm withdraw .]
|
||||
}
|
||||
}
|
||||
|
||||
$c eval {
|
||||
# Stub out the package command so packages can require other
|
||||
# packages.
|
||||
|
||||
rename package __package_orig
|
||||
proc package {what args} {
|
||||
switch -- $what {
|
||||
require {
|
||||
return; # Ignore transitive requires
|
||||
}
|
||||
default {
|
||||
__package_orig $what {*}$args
|
||||
}
|
||||
}
|
||||
}
|
||||
proc tclPkgUnknown args {}
|
||||
package unknown tclPkgUnknown
|
||||
|
||||
# Stub out the unknown command so package can call into each other
|
||||
# during their initialilzation.
|
||||
|
||||
proc unknown {args} {}
|
||||
|
||||
# Stub out the auto_import mechanism
|
||||
|
||||
proc auto_import {args} {}
|
||||
|
||||
# reserve the ::tcl namespace for support procs and temporary
|
||||
# variables. This might make it awkward to generate a
|
||||
# pkgIndex.tcl file for the ::tcl namespace.
|
||||
|
||||
namespace eval ::tcl {
|
||||
variable dir ;# Current directory being processed
|
||||
variable file ;# Current file being processed
|
||||
variable direct ;# -direct flag value
|
||||
variable x ;# Loop variable
|
||||
variable debug ;# For debugging
|
||||
variable type ;# "load" or "source", for -direct
|
||||
variable namespaces ;# Existing namespaces (e.g., ::tcl)
|
||||
variable packages ;# Existing packages (e.g., Tcl)
|
||||
variable origCmds ;# Existing commands
|
||||
variable newCmds ;# Newly created commands
|
||||
variable newPkgs {} ;# Newly created packages
|
||||
}
|
||||
}
|
||||
|
||||
$c eval [list set ::tcl::dir $dir]
|
||||
$c eval [list set ::tcl::file $file]
|
||||
$c eval [list set ::tcl::direct $direct]
|
||||
|
||||
# Download needed procedures into the child because we've just deleted
|
||||
# the unknown procedure. This doesn't handle procedures with default
|
||||
# arguments.
|
||||
|
||||
foreach p {::tcl::Pkg::CompareExtension} {
|
||||
$c eval [list namespace eval [namespace qualifiers $p] {}]
|
||||
$c eval [list proc $p [info args $p] [info body $p]]
|
||||
}
|
||||
|
||||
try {
|
||||
$c eval {
|
||||
set ::tcl::debug "loading or sourcing"
|
||||
|
||||
# we need to track command defined by each package even in the
|
||||
# -direct case, because they are needed internally by the
|
||||
# "partial pkgIndex.tcl" step above.
|
||||
|
||||
proc ::tcl::GetAllNamespaces {{root ::}} {
|
||||
set list $root
|
||||
foreach ns [namespace children $root] {
|
||||
lappend list {*}[::tcl::GetAllNamespaces $ns]
|
||||
}
|
||||
return $list
|
||||
}
|
||||
|
||||
# init the list of existing namespaces, packages, commands
|
||||
|
||||
foreach ::tcl::x [::tcl::GetAllNamespaces] {
|
||||
set ::tcl::namespaces($::tcl::x) 1
|
||||
}
|
||||
foreach ::tcl::x [package names] {
|
||||
if {[package provide $::tcl::x] ne ""} {
|
||||
set ::tcl::packages($::tcl::x) 1
|
||||
}
|
||||
}
|
||||
set ::tcl::origCmds [info commands]
|
||||
|
||||
# Try to load the file if it has the shared library extension,
|
||||
# otherwise source it. It's important not to try to load
|
||||
# files that aren't shared libraries, because on some systems
|
||||
# (like SunOS) the loader will abort the whole application
|
||||
# when it gets an error.
|
||||
|
||||
if {[::tcl::Pkg::CompareExtension $::tcl::file [info sharedlibextension]]} {
|
||||
# The "file join ." command below is necessary. Without
|
||||
# it, if the file name has no \'s and we're on UNIX, the
|
||||
# load command will invoke the LD_LIBRARY_PATH search
|
||||
# mechanism, which could cause the wrong file to be used.
|
||||
|
||||
set ::tcl::debug loading
|
||||
load [file join $::tcl::dir $::tcl::file]
|
||||
set ::tcl::type load
|
||||
} else {
|
||||
set ::tcl::debug sourcing
|
||||
source [file join $::tcl::dir $::tcl::file]
|
||||
set ::tcl::type source
|
||||
}
|
||||
|
||||
# As a performance optimization, if we are creating direct
|
||||
# load packages, don't bother figuring out the set of commands
|
||||
# created by the new packages. We only need that list for
|
||||
# setting up the autoloading used in the non-direct case.
|
||||
if {!$::tcl::direct} {
|
||||
# See what new namespaces appeared, and import commands
|
||||
# from them. Only exported commands go into the index.
|
||||
|
||||
foreach ::tcl::x [::tcl::GetAllNamespaces] {
|
||||
if {![info exists ::tcl::namespaces($::tcl::x)]} {
|
||||
namespace import -force ${::tcl::x}::*
|
||||
}
|
||||
|
||||
# Figure out what commands appeared
|
||||
|
||||
foreach ::tcl::x [info commands] {
|
||||
set ::tcl::newCmds($::tcl::x) 1
|
||||
}
|
||||
foreach ::tcl::x $::tcl::origCmds {
|
||||
unset -nocomplain ::tcl::newCmds($::tcl::x)
|
||||
}
|
||||
foreach ::tcl::x [array names ::tcl::newCmds] {
|
||||
# determine which namespace a command comes from
|
||||
|
||||
set ::tcl::abs [namespace origin $::tcl::x]
|
||||
|
||||
# special case so that global names have no
|
||||
# leading ::, this is required by the unknown
|
||||
# command
|
||||
|
||||
set ::tcl::abs \
|
||||
[lindex [auto_qualify $::tcl::abs ::] 0]
|
||||
|
||||
if {$::tcl::x ne $::tcl::abs} {
|
||||
# Name changed during qualification
|
||||
|
||||
set ::tcl::newCmds($::tcl::abs) 1
|
||||
unset ::tcl::newCmds($::tcl::x)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Look through the packages that appeared, and if there is a
|
||||
# version provided, then record it
|
||||
|
||||
foreach ::tcl::x [package names] {
|
||||
if {[package provide $::tcl::x] ne ""
|
||||
&& ![info exists ::tcl::packages($::tcl::x)]} {
|
||||
lappend ::tcl::newPkgs \
|
||||
[list $::tcl::x [package provide $::tcl::x]]
|
||||
}
|
||||
}
|
||||
}
|
||||
} on error msg {
|
||||
set what [$c eval set ::tcl::debug]
|
||||
if {$doVerbose} {
|
||||
tclLog "warning: error while $what $file: $msg"
|
||||
}
|
||||
} on ok {} {
|
||||
set what [$c eval set ::tcl::debug]
|
||||
if {$doVerbose} {
|
||||
tclLog "successful $what of $file"
|
||||
}
|
||||
set type [$c eval set ::tcl::type]
|
||||
set cmds [lsort [$c eval array names ::tcl::newCmds]]
|
||||
set pkgs [$c eval set ::tcl::newPkgs]
|
||||
if {$doVerbose} {
|
||||
if {!$direct} {
|
||||
tclLog "commands provided were $cmds"
|
||||
}
|
||||
tclLog "packages provided were $pkgs"
|
||||
}
|
||||
if {[llength $pkgs] > 1} {
|
||||
tclLog "warning: \"$file\" provides more than one package ($pkgs)"
|
||||
}
|
||||
foreach pkg $pkgs {
|
||||
# cmds is empty/not used in the direct case
|
||||
lappend files($pkg) [list $file $type $cmds]
|
||||
}
|
||||
|
||||
if {$doVerbose} {
|
||||
tclLog "processed $file"
|
||||
}
|
||||
}
|
||||
interp delete $c
|
||||
}
|
||||
|
||||
append index "# Tcl package index file, version 1.1\n"
|
||||
append index "# This file is generated by the \"pkg_mkIndex$more\" command\n"
|
||||
append index "# and sourced either when an application starts up or\n"
|
||||
append index "# by a \"package unknown\" script. It invokes the\n"
|
||||
append index "# \"package ifneeded\" command to set up package-related\n"
|
||||
append index "# information so that packages will be loaded automatically\n"
|
||||
append index "# in response to \"package require\" commands. When this\n"
|
||||
append index "# script is sourced, the variable \$dir must contain the\n"
|
||||
append index "# full path name of this file's directory.\n"
|
||||
|
||||
foreach pkg [lsort [array names files]] {
|
||||
set cmd {}
|
||||
lassign $pkg name version
|
||||
lappend cmd ::tcl::Pkg::Create -name $name -version $version
|
||||
foreach spec [lsort -index 0 $files($pkg)] {
|
||||
foreach {file type procs} $spec {
|
||||
if {$direct} {
|
||||
set procs {}
|
||||
}
|
||||
lappend cmd "-$type" [list $file $procs]
|
||||
}
|
||||
}
|
||||
append index "\n[eval $cmd]"
|
||||
}
|
||||
|
||||
set f [open [file join $dir pkgIndex.tcl] w]
|
||||
puts $f $index
|
||||
close $f
|
||||
}
|
||||
|
||||
# tclPkgSetup --
|
||||
# This is a utility procedure use by pkgIndex.tcl files. It is invoked as
|
||||
# part of a "package ifneeded" script. It calls "package provide" to indicate
|
||||
# that a package is available, then sets entries in the auto_index array so
|
||||
# that the package's files will be auto-loaded when the commands are used.
|
||||
#
|
||||
# Arguments:
|
||||
# dir - Directory containing all the files for this package.
|
||||
# pkg - Name of the package (no version number).
|
||||
# version - Version number for the package, such as 2.1.3.
|
||||
# files - List of files that constitute the package. Each
|
||||
# element is a sub-list with three elements. The first
|
||||
# is the name of a file relative to $dir, the second is
|
||||
# "load" or "source", indicating whether the file is a
|
||||
# loadable binary or a script to source, and the third
|
||||
# is a list of commands defined by this file.
|
||||
|
||||
proc tclPkgSetup {dir pkg version files} {
|
||||
global auto_index
|
||||
|
||||
package provide $pkg $version
|
||||
foreach fileInfo $files {
|
||||
set f [lindex $fileInfo 0]
|
||||
set type [lindex $fileInfo 1]
|
||||
foreach cmd [lindex $fileInfo 2] {
|
||||
if {$type eq "load"} {
|
||||
set auto_index($cmd) [list load [file join $dir $f] $pkg]
|
||||
} else {
|
||||
set auto_index($cmd) [list source [file join $dir $f]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# tclPkgUnknown --
|
||||
# This procedure provides the default for the "package unknown" function. It
|
||||
# is invoked when a package that's needed can't be found. It scans the
|
||||
# auto_path directories and their immediate children looking for pkgIndex.tcl
|
||||
# files and sources any such files that are found to setup the package
|
||||
# database. As it searches, it will recognize changes to the auto_path and
|
||||
# scan any new directories.
|
||||
#
|
||||
# Arguments:
|
||||
# name - Name of desired package. Not used.
|
||||
# version - Version of desired package. Not used.
|
||||
# exact - Either "-exact" or omitted. Not used.
|
||||
|
||||
proc tclPkgUnknown {name args} {
|
||||
global auto_path env
|
||||
|
||||
if {![info exists auto_path]} {
|
||||
return
|
||||
}
|
||||
# Cache the auto_path, because it may change while we run through the
|
||||
# first set of pkgIndex.tcl files
|
||||
set old_path [set use_path $auto_path]
|
||||
while {[llength $use_path]} {
|
||||
set dir [lindex $use_path end]
|
||||
|
||||
# Make sure we only scan each directory one time.
|
||||
if {[info exists tclSeenPath($dir)]} {
|
||||
set use_path [lrange $use_path 0 end-1]
|
||||
continue
|
||||
}
|
||||
set tclSeenPath($dir) 1
|
||||
|
||||
# Get the pkgIndex.tcl files in subdirectories of auto_path directories.
|
||||
# - Safe Base interpreters have a restricted "glob" command that
|
||||
# works in this case.
|
||||
# - The "catch" was essential when there was no safe glob and every
|
||||
# call in a safe interp failed; it is retained only for corner
|
||||
# cases in which the eventual call to glob returns an error.
|
||||
catch {
|
||||
foreach file [glob -directory $dir -join -nocomplain \
|
||||
* pkgIndex.tcl] {
|
||||
set dir [file dirname $file]
|
||||
if {![info exists procdDirs($dir)]} {
|
||||
try {
|
||||
source $file
|
||||
} trap {POSIX EACCES} {} {
|
||||
# $file was not readable; silently ignore
|
||||
continue
|
||||
} on error msg {
|
||||
tclLog "error reading package index file $file: $msg"
|
||||
} on ok {} {
|
||||
set procdDirs($dir) 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
set dir [lindex $use_path end]
|
||||
if {![info exists procdDirs($dir)]} {
|
||||
set file [file join $dir pkgIndex.tcl]
|
||||
# safe interps usually don't have "file exists",
|
||||
if {([interp issafe] || [file exists $file])} {
|
||||
try {
|
||||
source $file
|
||||
} trap {POSIX EACCES} {} {
|
||||
# $file was not readable; silently ignore
|
||||
continue
|
||||
} on error msg {
|
||||
tclLog "error reading package index file $file: $msg"
|
||||
} on ok {} {
|
||||
set procdDirs($dir) 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set use_path [lrange $use_path 0 end-1]
|
||||
|
||||
# Check whether any of the index scripts we [source]d above set a new
|
||||
# value for $::auto_path. If so, then find any new directories on the
|
||||
# $::auto_path, and lappend them to the $use_path we are working from.
|
||||
# This gives index scripts the (arguably unwise) power to expand the
|
||||
# index script search path while the search is in progress.
|
||||
set index 0
|
||||
if {[llength $old_path] == [llength $auto_path]} {
|
||||
foreach dir $auto_path old $old_path {
|
||||
if {$dir ne $old} {
|
||||
# This entry in $::auto_path has changed.
|
||||
break
|
||||
}
|
||||
incr index
|
||||
}
|
||||
}
|
||||
|
||||
# $index now points to the first element of $auto_path that has
|
||||
# changed, or the beginning if $auto_path has changed length Scan the
|
||||
# new elements of $auto_path for directories to add to $use_path.
|
||||
# Don't add directories we've already seen, or ones already on the
|
||||
# $use_path.
|
||||
foreach dir [lrange $auto_path $index end] {
|
||||
if {![info exists tclSeenPath($dir)] && ($dir ni $use_path)} {
|
||||
lappend use_path $dir
|
||||
}
|
||||
}
|
||||
set old_path $auto_path
|
||||
}
|
||||
}
|
||||
|
||||
# tcl::MacOSXPkgUnknown --
|
||||
# This procedure extends the "package unknown" function for MacOSX. It scans
|
||||
# the Resources/Scripts directories of the immediate children of the auto_path
|
||||
# directories for pkgIndex files.
|
||||
#
|
||||
# Arguments:
|
||||
# original - original [package unknown] procedure
|
||||
# name - Name of desired package. Not used.
|
||||
# version - Version of desired package. Not used.
|
||||
# exact - Either "-exact" or omitted. Not used.
|
||||
|
||||
proc tcl::MacOSXPkgUnknown {original name args} {
|
||||
# First do the cross-platform default search
|
||||
uplevel 1 $original [linsert $args 0 $name]
|
||||
|
||||
# Now do MacOSX specific searching
|
||||
global auto_path
|
||||
|
||||
if {![info exists auto_path]} {
|
||||
return
|
||||
}
|
||||
# Cache the auto_path, because it may change while we run through the
|
||||
# first set of pkgIndex.tcl files
|
||||
set old_path [set use_path $auto_path]
|
||||
while {[llength $use_path]} {
|
||||
set dir [lindex $use_path end]
|
||||
|
||||
# Make sure we only scan each directory one time.
|
||||
if {[info exists tclSeenPath($dir)]} {
|
||||
set use_path [lrange $use_path 0 end-1]
|
||||
continue
|
||||
}
|
||||
set tclSeenPath($dir) 1
|
||||
|
||||
# get the pkgIndex files out of the subdirectories
|
||||
# Safe interpreters do not use tcl::MacOSXPkgUnknown - see init.tcl.
|
||||
foreach file [glob -directory $dir -join -nocomplain \
|
||||
* Resources Scripts pkgIndex.tcl] {
|
||||
set dir [file dirname $file]
|
||||
if {![info exists procdDirs($dir)]} {
|
||||
try {
|
||||
source $file
|
||||
} trap {POSIX EACCES} {} {
|
||||
# $file was not readable; silently ignore
|
||||
continue
|
||||
} on error msg {
|
||||
tclLog "error reading package index file $file: $msg"
|
||||
} on ok {} {
|
||||
set procdDirs($dir) 1
|
||||
}
|
||||
}
|
||||
}
|
||||
set use_path [lrange $use_path 0 end-1]
|
||||
|
||||
# Check whether any of the index scripts we [source]d above set a new
|
||||
# value for $::auto_path. If so, then find any new directories on the
|
||||
# $::auto_path, and lappend them to the $use_path we are working from.
|
||||
# This gives index scripts the (arguably unwise) power to expand the
|
||||
# index script search path while the search is in progress.
|
||||
set index 0
|
||||
if {[llength $old_path] == [llength $auto_path]} {
|
||||
foreach dir $auto_path old $old_path {
|
||||
if {$dir ne $old} {
|
||||
# This entry in $::auto_path has changed.
|
||||
break
|
||||
}
|
||||
incr index
|
||||
}
|
||||
}
|
||||
|
||||
# $index now points to the first element of $auto_path that has
|
||||
# changed, or the beginning if $auto_path has changed length Scan the
|
||||
# new elements of $auto_path for directories to add to $use_path.
|
||||
# Don't add directories we've already seen, or ones already on the
|
||||
# $use_path.
|
||||
foreach dir [lrange $auto_path $index end] {
|
||||
if {![info exists tclSeenPath($dir)] && ($dir ni $use_path)} {
|
||||
lappend use_path $dir
|
||||
}
|
||||
}
|
||||
set old_path $auto_path
|
||||
}
|
||||
}
|
||||
|
||||
# ::tcl::Pkg::Create --
|
||||
#
|
||||
# Given a package specification generate a "package ifneeded" statement
|
||||
# for the package, suitable for inclusion in a pkgIndex.tcl file.
|
||||
#
|
||||
# Arguments:
|
||||
# args arguments used by the Create function:
|
||||
# -name packageName
|
||||
# -version packageVersion
|
||||
# -load {filename ?{procs}?}
|
||||
# ...
|
||||
# -source {filename ?{procs}?}
|
||||
# ...
|
||||
#
|
||||
# Any number of -load and -source parameters may be
|
||||
# specified, so long as there is at least one -load or
|
||||
# -source parameter. If the procs component of a module
|
||||
# specifier is left off, that module will be set up for
|
||||
# direct loading; otherwise, it will be set up for lazy
|
||||
# loading. If both -source and -load are specified, the
|
||||
# -load'ed files will be loaded first, followed by the
|
||||
# -source'd files.
|
||||
#
|
||||
# Results:
|
||||
# An appropriate "package ifneeded" statement for the package.
|
||||
|
||||
proc ::tcl::Pkg::Create {args} {
|
||||
append err(usage) "[lindex [info level 0] 0] "
|
||||
append err(usage) "-name packageName -version packageVersion"
|
||||
append err(usage) "?-load {filename ?{procs}?}? ... "
|
||||
append err(usage) "?-source {filename ?{procs}?}? ..."
|
||||
|
||||
set err(wrongNumArgs) "wrong # args: should be \"$err(usage)\""
|
||||
set err(valueMissing) "value for \"%s\" missing: should be \"$err(usage)\""
|
||||
set err(unknownOpt) "unknown option \"%s\": should be \"$err(usage)\""
|
||||
set err(noLoadOrSource) "at least one of -load and -source must be given"
|
||||
|
||||
# process arguments
|
||||
set len [llength $args]
|
||||
if {$len < 6} {
|
||||
error $err(wrongNumArgs)
|
||||
}
|
||||
|
||||
# Initialize parameters
|
||||
array set opts {-name {} -version {} -source {} -load {}}
|
||||
|
||||
# process parameters
|
||||
for {set i 0} {$i < $len} {incr i} {
|
||||
set flag [lindex $args $i]
|
||||
incr i
|
||||
switch -glob -- $flag {
|
||||
"-name" -
|
||||
"-version" {
|
||||
if {$i >= $len} {
|
||||
error [format $err(valueMissing) $flag]
|
||||
}
|
||||
set opts($flag) [lindex $args $i]
|
||||
}
|
||||
"-source" -
|
||||
"-load" {
|
||||
if {$i >= $len} {
|
||||
error [format $err(valueMissing) $flag]
|
||||
}
|
||||
lappend opts($flag) [lindex $args $i]
|
||||
}
|
||||
default {
|
||||
error [format $err(unknownOpt) [lindex $args $i]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Validate the parameters
|
||||
if {![llength $opts(-name)]} {
|
||||
error [format $err(valueMissing) "-name"]
|
||||
}
|
||||
if {![llength $opts(-version)]} {
|
||||
error [format $err(valueMissing) "-version"]
|
||||
}
|
||||
|
||||
if {!([llength $opts(-source)] || [llength $opts(-load)])} {
|
||||
error $err(noLoadOrSource)
|
||||
}
|
||||
|
||||
# OK, now everything is good. Generate the package ifneeded statment.
|
||||
set cmdline "package ifneeded $opts(-name) $opts(-version) "
|
||||
|
||||
set cmdList {}
|
||||
set lazyFileList {}
|
||||
|
||||
# Handle -load and -source specs
|
||||
foreach key {load source} {
|
||||
foreach filespec $opts(-$key) {
|
||||
lassign $filespec filename proclist
|
||||
|
||||
if { [llength $proclist] == 0 } {
|
||||
set cmd "\[list $key \[file join \$dir [list $filename]\]\]"
|
||||
lappend cmdList $cmd
|
||||
} else {
|
||||
lappend lazyFileList [list $filename $key $proclist]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {[llength $lazyFileList]} {
|
||||
lappend cmdList "\[list tclPkgSetup \$dir $opts(-name)\
|
||||
$opts(-version) [list $lazyFileList]\]"
|
||||
}
|
||||
append cmdline [join $cmdList "\\n"]
|
||||
return $cmdline
|
||||
}
|
||||
|
||||
interp alias {} ::pkg::create {} ::tcl::Pkg::Create
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# parray:
|
||||
# Print the contents of a global array on stdout.
|
||||
#
|
||||
# Copyright (c) 1991-1993 The Regents of the University of California.
|
||||
# Copyright (c) 1994 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
proc parray {a {pattern *}} {
|
||||
upvar 1 $a array
|
||||
if {![array exists array]} {
|
||||
return -code error "\"$a\" isn't an array"
|
||||
}
|
||||
set maxl 0
|
||||
set names [lsort [array names array $pattern]]
|
||||
foreach name $names {
|
||||
if {[string length $name] > $maxl} {
|
||||
set maxl [string length $name]
|
||||
}
|
||||
}
|
||||
set maxl [expr {$maxl + [string length $a] + 2}]
|
||||
foreach name $names {
|
||||
set nameString [format %s(%s) $a $name]
|
||||
puts stdout [format "%-*s = %s" $maxl $nameString $array($name)]
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,78 @@
|
|||
# Tcl autoload index file, version 2.0
|
||||
# -*- tcl -*-
|
||||
# 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(auto_reset) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(tcl_findLibrary) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(auto_mkindex) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(auto_mkindex_old) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(::auto_mkindex_parser::init) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(::auto_mkindex_parser::cleanup) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(::auto_mkindex_parser::mkindex) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(::auto_mkindex_parser::hook) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(::auto_mkindex_parser::slavehook) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(::auto_mkindex_parser::command) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(::auto_mkindex_parser::commandInit) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(::auto_mkindex_parser::fullname) [list source [file join $dir auto.tcl]]
|
||||
set auto_index(history) [list source [file join $dir history.tcl]]
|
||||
set auto_index(::tcl::HistAdd) [list source [file join $dir history.tcl]]
|
||||
set auto_index(::tcl::HistKeep) [list source [file join $dir history.tcl]]
|
||||
set auto_index(::tcl::HistClear) [list source [file join $dir history.tcl]]
|
||||
set auto_index(::tcl::HistInfo) [list source [file join $dir history.tcl]]
|
||||
set auto_index(::tcl::HistRedo) [list source [file join $dir history.tcl]]
|
||||
set auto_index(::tcl::HistIndex) [list source [file join $dir history.tcl]]
|
||||
set auto_index(::tcl::HistEvent) [list source [file join $dir history.tcl]]
|
||||
set auto_index(::tcl::HistChange) [list source [file join $dir history.tcl]]
|
||||
set auto_index(pkg_mkIndex) [list source [file join $dir package.tcl]]
|
||||
set auto_index(tclPkgSetup) [list source [file join $dir package.tcl]]
|
||||
set auto_index(tclPkgUnknown) [list source [file join $dir package.tcl]]
|
||||
set auto_index(::tcl::MacOSXPkgUnknown) [list source [file join $dir package.tcl]]
|
||||
set auto_index(::pkg::create) [list source [file join $dir package.tcl]]
|
||||
set auto_index(parray) [list source [file join $dir parray.tcl]]
|
||||
set auto_index(::safe::InterpStatics) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::InterpNested) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::interpCreate) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::interpInit) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::CheckInterp) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::interpConfigure) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::InterpCreate) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::InterpSetConfig) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::interpFindInAccessPath) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::interpAddToAccessPath) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::InterpInit) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::AddSubDirs) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::interpDelete) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::setLogCmd) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::SyncAccessPath) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::PathToken) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::TranslatePath) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::Log) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::CheckFileName) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::AliasGlob) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::AliasSource) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::AliasLoad) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::FileInAccessPath) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::DirInAccessPath) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::Subset) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::AliasSubset) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(::safe::AliasEncoding) [list source [file join $dir safe.tcl]]
|
||||
set auto_index(tcl_wordBreakAfter) [list source [file join $dir word.tcl]]
|
||||
set auto_index(tcl_wordBreakBefore) [list source [file join $dir word.tcl]]
|
||||
set auto_index(tcl_endOfWord) [list source [file join $dir word.tcl]]
|
||||
set auto_index(tcl_startOfNextWord) [list source [file join $dir word.tcl]]
|
||||
set auto_index(tcl_startOfPreviousWord) [list source [file join $dir word.tcl]]
|
||||
set auto_index(::tcl::tm::add) [list source [file join $dir tm.tcl]]
|
||||
set auto_index(::tcl::tm::remove) [list source [file join $dir tm.tcl]]
|
||||
set auto_index(::tcl::tm::list) [list source [file join $dir tm.tcl]]
|
||||
set auto_index(::tcl::tm::Defaults) [list source [file join $dir tm.tcl]]
|
||||
set auto_index(::tcl::tm::UnknownHandler) [list source [file join $dir tm.tcl]]
|
||||
set auto_index(::tcl::tm::roots) [list source [file join $dir tm.tcl]]
|
||||
set auto_index(::tcl::tm::path) [list source [file join $dir tm.tcl]]
|
||||
if {[namespace exists ::tcl::unsupported]} {
|
||||
set auto_index(timerate) {namespace import ::tcl::unsupported::timerate}
|
||||
}
|
||||
|
|
@ -0,0 +1,380 @@
|
|||
# -*- tcl -*-
|
||||
#
|
||||
# Searching for Tcl Modules. Defines a procedure, declares it as the primary
|
||||
# command for finding packages, however also uses the former 'package unknown'
|
||||
# command as a fallback.
|
||||
#
|
||||
# Locates all possible packages in a directory via a less restricted glob. The
|
||||
# targeted directory is derived from the name of the requested package, i.e.
|
||||
# the TM scan will look only at directories which can contain the requested
|
||||
# package. It will register all packages it found in the directory so that
|
||||
# future requests have a higher chance of being fulfilled by the ifneeded
|
||||
# database without having to come to us again.
|
||||
#
|
||||
# We do not remember where we have been and simply rescan targeted directories
|
||||
# when invoked again. The reasoning is this:
|
||||
#
|
||||
# - The only way we get back to the same directory is if someone is trying to
|
||||
# [package require] something that wasn't there on the first scan.
|
||||
#
|
||||
# Either
|
||||
# 1) It is there now: If we rescan, you get it; if not you don't.
|
||||
#
|
||||
# This covers the possibility that the application asked for a package
|
||||
# late, and the package was actually added to the installation after the
|
||||
# application was started. It shoukld still be able to find it.
|
||||
#
|
||||
# 2) It still is not there: Either way, you don't get it, but the rescan
|
||||
# takes time. This is however an error case and we dont't care that much
|
||||
# about it
|
||||
#
|
||||
# 3) It was there the first time; but for some reason a "package forget" has
|
||||
# been run, and "package" doesn't know about it anymore.
|
||||
#
|
||||
# This can be an indication that the application wishes to reload some
|
||||
# functionality. And should work as well.
|
||||
#
|
||||
# Note that this also strikes a balance between doing a glob targeting a
|
||||
# single package, and thus most likely requiring multiple globs of the same
|
||||
# directory when the application is asking for many packages, and trying to
|
||||
# glob for _everything_ in all subdirectories when looking for a package,
|
||||
# which comes with a heavy startup cost.
|
||||
#
|
||||
# We scan for regular packages only if no satisfying module was found.
|
||||
|
||||
namespace eval ::tcl::tm {
|
||||
# Default paths. None yet.
|
||||
|
||||
variable paths {}
|
||||
|
||||
# The regex pattern a file name has to match to make it a Tcl Module.
|
||||
|
||||
set pkgpattern {^([_[:alpha:]][:_[:alnum:]]*)-([[:digit:]].*)[.]tm$}
|
||||
|
||||
# Export the public API
|
||||
|
||||
namespace export path
|
||||
namespace ensemble create -command path -subcommands {add remove list}
|
||||
}
|
||||
|
||||
# ::tcl::tm::path implementations --
|
||||
#
|
||||
# Public API to the module path. See specification.
|
||||
#
|
||||
# Arguments
|
||||
# cmd - The subcommand to execute
|
||||
# args - The paths to add/remove. Must not appear querying the
|
||||
# path with 'list'.
|
||||
#
|
||||
# Results
|
||||
# No result for subcommands 'add' and 'remove'. A list of paths for
|
||||
# 'list'.
|
||||
#
|
||||
# Sideeffects
|
||||
# The subcommands 'add' and 'remove' manipulate the list of paths to
|
||||
# search for Tcl Modules. The subcommand 'list' has no sideeffects.
|
||||
|
||||
proc ::tcl::tm::add {args} {
|
||||
# PART OF THE ::tcl::tm::path ENSEMBLE
|
||||
#
|
||||
# The path is added at the head to the list of module paths.
|
||||
#
|
||||
# The command enforces the restriction that no path may be an ancestor
|
||||
# directory of any other path on the list. If the new path violates this
|
||||
# restriction an error wil be raised.
|
||||
#
|
||||
# If the path is already present as is no error will be raised and no
|
||||
# action will be taken.
|
||||
|
||||
variable paths
|
||||
|
||||
# We use a copy of the path as source during validation, and extend it as
|
||||
# well. Because we not only have to detect if the new paths are bogus with
|
||||
# respect to the existing paths, but also between themselves. Otherwise we
|
||||
# can still add bogus paths, by specifying them in a single call. This
|
||||
# makes the use of the new paths simpler as well, a trivial assignment of
|
||||
# the collected paths to the official state var.
|
||||
|
||||
set newpaths $paths
|
||||
foreach p $args {
|
||||
if {$p in $newpaths} {
|
||||
# Ignore a path already on the list.
|
||||
continue
|
||||
}
|
||||
|
||||
# Search for paths which are subdirectories of the new one. If there
|
||||
# are any then the new path violates the restriction about ancestors.
|
||||
|
||||
set pos [lsearch -glob $newpaths ${p}/*]
|
||||
# Cannot use "in", we need the position for the message.
|
||||
if {$pos >= 0} {
|
||||
return -code error \
|
||||
"$p is ancestor of existing module path [lindex $newpaths $pos]."
|
||||
}
|
||||
|
||||
# Now look for existing paths which are ancestors of the new one. This
|
||||
# reverse question forces us to loop over the existing paths, as each
|
||||
# element is the pattern, not the new path :(
|
||||
|
||||
foreach ep $newpaths {
|
||||
if {[string match ${ep}/* $p]} {
|
||||
return -code error \
|
||||
"$p is subdirectory of existing module path $ep."
|
||||
}
|
||||
}
|
||||
|
||||
set newpaths [linsert $newpaths 0 $p]
|
||||
}
|
||||
|
||||
# The validation of the input is complete and successful, and everything
|
||||
# in newpaths is either an old path, or added. We can now extend the
|
||||
# official list of paths, a simple assignment is sufficient.
|
||||
|
||||
set paths $newpaths
|
||||
return
|
||||
}
|
||||
|
||||
proc ::tcl::tm::remove {args} {
|
||||
# PART OF THE ::tcl::tm::path ENSEMBLE
|
||||
#
|
||||
# Removes the path from the list of module paths. The command is silently
|
||||
# ignored if the path is not on the list.
|
||||
|
||||
variable paths
|
||||
|
||||
foreach p $args {
|
||||
set pos [lsearch -exact $paths $p]
|
||||
if {$pos >= 0} {
|
||||
set paths [lreplace $paths $pos $pos]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tcl::tm::list {} {
|
||||
# PART OF THE ::tcl::tm::path ENSEMBLE
|
||||
|
||||
variable paths
|
||||
return $paths
|
||||
}
|
||||
|
||||
# ::tcl::tm::UnknownHandler --
|
||||
#
|
||||
# Unknown handler for Tcl Modules, i.e. packages in module form.
|
||||
#
|
||||
# Arguments
|
||||
# original - Original [package unknown] procedure.
|
||||
# name - Name of desired package.
|
||||
# version - Version of desired package. Can be the
|
||||
# empty string.
|
||||
# exact - Either -exact or ommitted.
|
||||
#
|
||||
# Name, version, and exact are used to determine satisfaction. The
|
||||
# original is called iff no satisfaction was achieved. The name is also
|
||||
# used to compute the directory to target in the search.
|
||||
#
|
||||
# Results
|
||||
# None.
|
||||
#
|
||||
# Sideeffects
|
||||
# May populate the package ifneeded database with additional provide
|
||||
# scripts.
|
||||
|
||||
proc ::tcl::tm::UnknownHandler {original name args} {
|
||||
# Import the list of paths to search for packages in module form.
|
||||
# Import the pattern used to check package names in detail.
|
||||
|
||||
variable paths
|
||||
variable pkgpattern
|
||||
|
||||
# Without paths to search we can do nothing. (Except falling back to the
|
||||
# regular search).
|
||||
|
||||
if {[llength $paths]} {
|
||||
set pkgpath [string map {:: /} $name]
|
||||
set pkgroot [file dirname $pkgpath]
|
||||
if {$pkgroot eq "."} {
|
||||
set pkgroot ""
|
||||
}
|
||||
|
||||
# We don't remember a copy of the paths while looping. Tcl Modules are
|
||||
# unable to change the list while we are searching for them. This also
|
||||
# simplifies the loop, as we cannot get additional directories while
|
||||
# iterating over the list. A simple foreach is sufficient.
|
||||
|
||||
set satisfied 0
|
||||
foreach path $paths {
|
||||
if {![interp issafe] && ![file exists $path]} {
|
||||
continue
|
||||
}
|
||||
set currentsearchpath [file join $path $pkgroot]
|
||||
if {![interp issafe] && ![file exists $currentsearchpath]} {
|
||||
continue
|
||||
}
|
||||
set strip [llength [file split $path]]
|
||||
|
||||
# Get the module files out of the subdirectories.
|
||||
# - Safe Base interpreters have a restricted "glob" command that
|
||||
# works in this case.
|
||||
# - The "catch" was essential when there was no safe glob and every
|
||||
# call in a safe interp failed; it is retained only for corner
|
||||
# cases in which the eventual call to glob returns an error.
|
||||
|
||||
catch {
|
||||
# We always look for _all_ possible modules in the current
|
||||
# path, to get the max result out of the glob.
|
||||
|
||||
foreach file [glob -nocomplain -directory $currentsearchpath *.tm] {
|
||||
set pkgfilename [join [lrange [file split $file] $strip end] ::]
|
||||
|
||||
if {![regexp -- $pkgpattern $pkgfilename --> pkgname pkgversion]} {
|
||||
# Ignore everything not matching our pattern for
|
||||
# package names.
|
||||
continue
|
||||
}
|
||||
try {
|
||||
package vcompare $pkgversion 0
|
||||
} on error {} {
|
||||
# Ignore everything where the version part is not
|
||||
# acceptable to "package vcompare".
|
||||
continue
|
||||
}
|
||||
|
||||
if {([package ifneeded $pkgname $pkgversion] ne {})
|
||||
&& (![interp issafe])
|
||||
} {
|
||||
# There's already a provide script registered for
|
||||
# this version of this package. Since all units of
|
||||
# code claiming to be the same version of the same
|
||||
# package ought to be identical, just stick with
|
||||
# the one we already have.
|
||||
# This does not apply to Safe Base interpreters because
|
||||
# the token-to-directory mapping may have changed.
|
||||
continue
|
||||
}
|
||||
|
||||
# We have found a candidate, generate a "provide script"
|
||||
# for it, and remember it. Note that we are using ::list
|
||||
# to do this; locally [list] means something else without
|
||||
# the namespace specifier.
|
||||
|
||||
# NOTE. When making changes to the format of the provide
|
||||
# command generated below CHECK that the 'LOCATE'
|
||||
# procedure in core file 'platform/shell.tcl' still
|
||||
# understands it, or, if not, update its implementation
|
||||
# appropriately.
|
||||
#
|
||||
# Right now LOCATE's implementation assumes that the path
|
||||
# of the package file is the last element in the list.
|
||||
|
||||
package ifneeded $pkgname $pkgversion \
|
||||
"[::list package provide $pkgname $pkgversion];[::list source -encoding utf-8 $file]"
|
||||
|
||||
# We abort in this unknown handler only if we got a
|
||||
# satisfying candidate for the requested package.
|
||||
# Otherwise we still have to fallback to the regular
|
||||
# package search to complete the processing.
|
||||
|
||||
if {($pkgname eq $name)
|
||||
&& [package vsatisfies $pkgversion {*}$args]} {
|
||||
set satisfied 1
|
||||
|
||||
# We do not abort the loop, and keep adding provide
|
||||
# scripts for every candidate in the directory, just
|
||||
# remember to not fall back to the regular search
|
||||
# anymore.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {$satisfied} {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
# Fallback to previous command, if existing. See comment above about
|
||||
# ::list...
|
||||
|
||||
if {[llength $original]} {
|
||||
uplevel 1 $original [::linsert $args 0 $name]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tcl::tm::Defaults --
|
||||
#
|
||||
# Determines the default search paths.
|
||||
#
|
||||
# Arguments
|
||||
# None
|
||||
#
|
||||
# Results
|
||||
# None.
|
||||
#
|
||||
# Sideeffects
|
||||
# May add paths to the list of defaults.
|
||||
|
||||
proc ::tcl::tm::Defaults {} {
|
||||
global env tcl_platform
|
||||
|
||||
regexp {^(\d+)\.(\d+)} [package provide Tcl] - major minor
|
||||
set exe [file normalize [info nameofexecutable]]
|
||||
|
||||
# Note that we're using [::list], not [list] because [list] means
|
||||
# something other than [::list] in this namespace.
|
||||
roots [::list \
|
||||
[file dirname [info library]] \
|
||||
[file join [file dirname [file dirname $exe]] lib] \
|
||||
]
|
||||
|
||||
if {$tcl_platform(platform) eq "windows"} {
|
||||
set sep ";"
|
||||
} else {
|
||||
set sep ":"
|
||||
}
|
||||
for {set n $minor} {$n >= 0} {incr n -1} {
|
||||
foreach ev [::list \
|
||||
TCL${major}.${n}_TM_PATH \
|
||||
TCL${major}_${n}_TM_PATH \
|
||||
] {
|
||||
if {![info exists env($ev)]} continue
|
||||
foreach p [split $env($ev) $sep] {
|
||||
path add $p
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
# ::tcl::tm::roots --
|
||||
#
|
||||
# Public API to the module path. See specification.
|
||||
#
|
||||
# Arguments
|
||||
# paths - List of 'root' paths to derive search paths from.
|
||||
#
|
||||
# Results
|
||||
# No result.
|
||||
#
|
||||
# Sideeffects
|
||||
# Calls 'path add' to paths to the list of module search paths.
|
||||
|
||||
proc ::tcl::tm::roots {paths} {
|
||||
regexp {^(\d+)\.(\d+)} [package provide Tcl] - major minor
|
||||
foreach pa $paths {
|
||||
set p [file join $pa tcl$major]
|
||||
for {set n $minor} {$n >= 0} {incr n -1} {
|
||||
set px [file join $p ${major}.${n}]
|
||||
if {![interp issafe]} {set px [file normalize $px]}
|
||||
path add $px
|
||||
}
|
||||
set px [file join $p site-tcl]
|
||||
if {![interp issafe]} {set px [file normalize $px]}
|
||||
path add $px
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
# Initialization. Set up the default paths, then insert the new handler into
|
||||
# the chain.
|
||||
|
||||
if {![interp issafe]} {::tcl::tm::Defaults}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
# word.tcl --
|
||||
#
|
||||
# This file defines various procedures for computing word boundaries in
|
||||
# strings. This file is primarily needed so Tk text and entry widgets behave
|
||||
# properly for different platforms.
|
||||
#
|
||||
# Copyright (c) 1996 Sun Microsystems, Inc.
|
||||
# Copyright (c) 1998 Scritpics Corporation.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
|
||||
# The following variables are used to determine which characters are
|
||||
# interpreted as white space.
|
||||
|
||||
if {$::tcl_platform(platform) eq "windows"} {
|
||||
# Windows style - any but a unicode space char
|
||||
if {![info exists ::tcl_wordchars]} {
|
||||
set ::tcl_wordchars {\S}
|
||||
}
|
||||
if {![info exists ::tcl_nonwordchars]} {
|
||||
set ::tcl_nonwordchars {\s}
|
||||
}
|
||||
} else {
|
||||
# Motif style - any unicode word char (number, letter, or underscore)
|
||||
if {![info exists ::tcl_wordchars]} {
|
||||
set ::tcl_wordchars {\w}
|
||||
}
|
||||
if {![info exists ::tcl_nonwordchars]} {
|
||||
set ::tcl_nonwordchars {\W}
|
||||
}
|
||||
}
|
||||
|
||||
# Arrange for caches of the real matcher REs to be kept, which enables the REs
|
||||
# themselves to be cached for greater performance (and somewhat greater
|
||||
# clarity too).
|
||||
|
||||
namespace eval ::tcl {
|
||||
variable WordBreakRE
|
||||
array set WordBreakRE {}
|
||||
|
||||
proc UpdateWordBreakREs args {
|
||||
# Ignores the arguments
|
||||
global tcl_wordchars tcl_nonwordchars
|
||||
variable WordBreakRE
|
||||
|
||||
# To keep the RE strings short...
|
||||
set letter $tcl_wordchars
|
||||
set space $tcl_nonwordchars
|
||||
|
||||
set WordBreakRE(after) "$letter$space|$space$letter"
|
||||
set WordBreakRE(before) "^.*($letter$space|$space$letter)"
|
||||
set WordBreakRE(end) "$space*$letter+$space"
|
||||
set WordBreakRE(next) "$letter*$space+$letter"
|
||||
set WordBreakRE(previous) "$space*($letter+)$space*\$"
|
||||
}
|
||||
|
||||
# Initialize the cache
|
||||
UpdateWordBreakREs
|
||||
trace add variable ::tcl_wordchars write ::tcl::UpdateWordBreakREs
|
||||
trace add variable ::tcl_nonwordchars write ::tcl::UpdateWordBreakREs
|
||||
}
|
||||
|
||||
# tcl_wordBreakAfter --
|
||||
#
|
||||
# This procedure returns the index of the first word boundary after the
|
||||
# starting point in the given string, or -1 if there are no more boundaries in
|
||||
# the given string. The index returned refers to the first character of the
|
||||
# pair that comprises a boundary.
|
||||
#
|
||||
# Arguments:
|
||||
# str - String to search.
|
||||
# start - Index into string specifying starting point.
|
||||
|
||||
proc tcl_wordBreakAfter {str start} {
|
||||
variable ::tcl::WordBreakRE
|
||||
set result {-1 -1}
|
||||
regexp -indices -start $start -- $WordBreakRE(after) $str result
|
||||
return [lindex $result 1]
|
||||
}
|
||||
|
||||
# tcl_wordBreakBefore --
|
||||
#
|
||||
# This procedure returns the index of the first word boundary before the
|
||||
# starting point in the given string, or -1 if there are no more boundaries in
|
||||
# the given string. The index returned refers to the second character of the
|
||||
# pair that comprises a boundary.
|
||||
#
|
||||
# Arguments:
|
||||
# str - String to search.
|
||||
# start - Index into string specifying starting point.
|
||||
|
||||
proc tcl_wordBreakBefore {str start} {
|
||||
variable ::tcl::WordBreakRE
|
||||
set result {-1 -1}
|
||||
regexp -indices -- $WordBreakRE(before) [string range $str 0 $start] result
|
||||
return [lindex $result 1]
|
||||
}
|
||||
|
||||
# tcl_endOfWord --
|
||||
#
|
||||
# This procedure returns the index of the first end-of-word location after a
|
||||
# starting index in the given string. An end-of-word location is defined to be
|
||||
# the first whitespace character following the first non-whitespace character
|
||||
# after the starting point. Returns -1 if there are no more words after the
|
||||
# starting point.
|
||||
#
|
||||
# Arguments:
|
||||
# str - String to search.
|
||||
# start - Index into string specifying starting point.
|
||||
|
||||
proc tcl_endOfWord {str start} {
|
||||
variable ::tcl::WordBreakRE
|
||||
set result {-1 -1}
|
||||
regexp -indices -start $start -- $WordBreakRE(end) $str result
|
||||
return [lindex $result 1]
|
||||
}
|
||||
|
||||
# tcl_startOfNextWord --
|
||||
#
|
||||
# This procedure returns the index of the first start-of-word location after a
|
||||
# starting index in the given string. A start-of-word location is defined to
|
||||
# be a non-whitespace character following a whitespace character. Returns -1
|
||||
# if there are no more start-of-word locations after the starting point.
|
||||
#
|
||||
# Arguments:
|
||||
# str - String to search.
|
||||
# start - Index into string specifying starting point.
|
||||
|
||||
proc tcl_startOfNextWord {str start} {
|
||||
variable ::tcl::WordBreakRE
|
||||
set result {-1 -1}
|
||||
regexp -indices -start $start -- $WordBreakRE(next) $str result
|
||||
return [lindex $result 1]
|
||||
}
|
||||
|
||||
# tcl_startOfPreviousWord --
|
||||
#
|
||||
# This procedure returns the index of the first start-of-word location before
|
||||
# a starting index in the given string.
|
||||
#
|
||||
# Arguments:
|
||||
# str - String to search.
|
||||
# start - Index into string specifying starting point.
|
||||
|
||||
proc tcl_startOfPreviousWord {str start} {
|
||||
variable ::tcl::WordBreakRE
|
||||
set word {-1 -1}
|
||||
if {$start > 0} {
|
||||
regexp -indices -- $WordBreakRE(previous) [string range $str 0 $start-1] \
|
||||
result word
|
||||
}
|
||||
return [lindex $word 0]
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
# bgerror.tcl --
|
||||
#
|
||||
# Implementation of the bgerror procedure. It posts a dialog box with
|
||||
# the error message and gives the user a chance to see a more detailed
|
||||
# stack trace, and possible do something more interesting with that
|
||||
# trace (like save it to a log). This is adapted from work done by
|
||||
# Donal K. Fellows.
|
||||
#
|
||||
# Copyright (c) 1998-2000 by Ajuba Solutions.
|
||||
# Copyright (c) 2007 by ActiveState Software Inc.
|
||||
# Copyright (c) 2007 Daniel A. Steffen <das@users.sourceforge.net>
|
||||
# Copyright (c) 2009 Pat Thoyts <patthoyts@users.sourceforge.net>
|
||||
|
||||
namespace eval ::tk::dialog::error {
|
||||
namespace import -force ::tk::msgcat::*
|
||||
namespace export bgerror
|
||||
option add *ErrorDialog.function.text [mc "Save To Log"] \
|
||||
widgetDefault
|
||||
option add *ErrorDialog.function.command [namespace code SaveToLog]
|
||||
option add *ErrorDialog*Label.font TkCaptionFont widgetDefault
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
option add *ErrorDialog*background systemAlertBackgroundActive \
|
||||
widgetDefault
|
||||
option add *ErrorDialog*info.text.background \
|
||||
systemTextBackgroundColor widgetDefault
|
||||
option add *ErrorDialog*Button.highlightBackground \
|
||||
systemAlertBackgroundActive widgetDefault
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::dialog::error::Return {which code} {
|
||||
variable button
|
||||
|
||||
.bgerrorDialog.$which state {active selected focus}
|
||||
update idletasks
|
||||
after 100
|
||||
set button $code
|
||||
}
|
||||
|
||||
proc ::tk::dialog::error::Details {} {
|
||||
set w .bgerrorDialog
|
||||
set caption [option get $w.function text {}]
|
||||
set command [option get $w.function command {}]
|
||||
if {($caption eq "") || ($command eq "")} {
|
||||
grid forget $w.function
|
||||
}
|
||||
lappend command [$w.top.info.text get 1.0 end-1c]
|
||||
$w.function configure -text $caption -command $command
|
||||
grid $w.top.info - -sticky nsew -padx 3m -pady 3m
|
||||
}
|
||||
|
||||
proc ::tk::dialog::error::SaveToLog {text} {
|
||||
if {$::tcl_platform(platform) eq "windows"} {
|
||||
set allFiles *.*
|
||||
} else {
|
||||
set allFiles *
|
||||
}
|
||||
set types [list \
|
||||
[list [mc "Log Files"] .log] \
|
||||
[list [mc "Text Files"] .txt] \
|
||||
[list [mc "All Files"] $allFiles] \
|
||||
]
|
||||
set filename [tk_getSaveFile -title [mc "Select Log File"] \
|
||||
-filetypes $types -defaultextension .log -parent .bgerrorDialog]
|
||||
if {$filename ne {}} {
|
||||
set f [open $filename w]
|
||||
puts -nonewline $f $text
|
||||
close $f
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
proc ::tk::dialog::error::Destroy {w} {
|
||||
if {$w eq ".bgerrorDialog"} {
|
||||
variable button
|
||||
set button -1
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::dialog::error::DeleteByProtocol {} {
|
||||
variable button
|
||||
set button 1
|
||||
}
|
||||
|
||||
proc ::tk::dialog::error::ReturnInDetails w {
|
||||
bind $w <Return> {}; # Remove this binding
|
||||
$w invoke
|
||||
return -code break
|
||||
}
|
||||
|
||||
# ::tk::dialog::error::bgerror --
|
||||
#
|
||||
# This is the default version of bgerror.
|
||||
# It tries to execute tkerror, if that fails it posts a dialog box
|
||||
# containing the error message and gives the user a chance to ask
|
||||
# to see a stack trace.
|
||||
#
|
||||
# Arguments:
|
||||
# err - The error message.
|
||||
#
|
||||
proc ::tk::dialog::error::bgerror {err {flag 1}} {
|
||||
global errorInfo
|
||||
variable button
|
||||
|
||||
set info $errorInfo
|
||||
|
||||
set ret [catch {::tkerror $err} msg];
|
||||
if {$ret != 1} {return -code $ret $msg}
|
||||
|
||||
# The application's tkerror either failed or was not found
|
||||
# so we use the default dialog. But on Aqua we cannot display
|
||||
# the dialog if the background error occurs in an idle task
|
||||
# being processed inside of [NSView drawRect]. In that case
|
||||
# we post the dialog as an after task instead.
|
||||
set windowingsystem [tk windowingsystem]
|
||||
if {$windowingsystem eq "aqua"} {
|
||||
if $flag {
|
||||
set errorInfo $info
|
||||
after 500 [list bgerror "$err" 0]
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
set ok [mc OK]
|
||||
# Truncate the message if it is too wide (>maxLine characters) or
|
||||
# too tall (>4 lines). Truncation occurs at the first point at
|
||||
# which one of those conditions is met.
|
||||
set displayedErr ""
|
||||
set lines 0
|
||||
set maxLine 45
|
||||
foreach line [split $err \n] {
|
||||
if {[string length $line] > $maxLine} {
|
||||
append displayedErr "[string range $line 0 $maxLine-3]..."
|
||||
break
|
||||
}
|
||||
if {$lines > 4} {
|
||||
append displayedErr "..."
|
||||
break
|
||||
} else {
|
||||
append displayedErr "${line}\n"
|
||||
}
|
||||
incr lines
|
||||
}
|
||||
|
||||
set title [mc "Application Error"]
|
||||
set text [mc "Error: %1\$s" $displayedErr]
|
||||
set buttons [list ok $ok dismiss [mc "Skip Messages"] \
|
||||
function [mc "Details >>"]]
|
||||
|
||||
# 1. Create the top-level window and divide it into top
|
||||
# and bottom parts.
|
||||
|
||||
set dlg .bgerrorDialog
|
||||
set bg [ttk::style lookup . -background]
|
||||
destroy $dlg
|
||||
toplevel $dlg -class ErrorDialog -background $bg
|
||||
wm withdraw $dlg
|
||||
wm title $dlg $title
|
||||
wm iconname $dlg ErrorDialog
|
||||
wm protocol $dlg WM_DELETE_WINDOW [namespace code DeleteByProtocol]
|
||||
|
||||
if {$windowingsystem eq "aqua"} {
|
||||
::tk::unsupported::MacWindowStyle style $dlg moveableAlert {}
|
||||
} elseif {$windowingsystem eq "x11"} {
|
||||
wm attributes $dlg -type dialog
|
||||
}
|
||||
|
||||
ttk::frame $dlg.bot
|
||||
ttk::frame $dlg.top
|
||||
pack $dlg.bot -side bottom -fill both
|
||||
pack $dlg.top -side top -fill both -expand 1
|
||||
|
||||
set W [ttk::frame $dlg.top.info]
|
||||
text $W.text -setgrid true -height 10 -wrap char \
|
||||
-yscrollcommand [list $W.scroll set]
|
||||
if {$windowingsystem ne "aqua"} {
|
||||
$W.text configure -width 40
|
||||
}
|
||||
|
||||
ttk::scrollbar $W.scroll -command [list $W.text yview]
|
||||
pack $W.scroll -side right -fill y
|
||||
pack $W.text -side left -expand yes -fill both
|
||||
$W.text insert 0.0 "$err\n$info"
|
||||
$W.text mark set insert 0.0
|
||||
bind $W.text <Button-1> {focus %W}
|
||||
$W.text configure -state disabled
|
||||
|
||||
# 2. Fill the top part with bitmap and message
|
||||
|
||||
# Max-width of message is the width of the screen...
|
||||
set wrapwidth [winfo screenwidth $dlg]
|
||||
# ...minus the width of the icon, padding and a fudge factor for
|
||||
# the window manager decorations and aesthetics.
|
||||
set wrapwidth [expr {$wrapwidth-60-[winfo pixels $dlg 9m]}]
|
||||
ttk::label $dlg.msg -justify left -text $text -wraplength $wrapwidth
|
||||
ttk::label $dlg.bitmap -image ::tk::icons::error
|
||||
|
||||
grid $dlg.bitmap $dlg.msg -in $dlg.top -row 0 -padx 3m -pady 3m
|
||||
grid configure $dlg.bitmap -sticky ne
|
||||
grid configure $dlg.msg -sticky nsw -padx {0 3m}
|
||||
grid rowconfigure $dlg.top 1 -weight 1
|
||||
grid columnconfigure $dlg.top 1 -weight 1
|
||||
|
||||
# 3. Create a row of buttons at the bottom of the dialog.
|
||||
|
||||
set i 0
|
||||
foreach {name caption} $buttons {
|
||||
ttk::button $dlg.$name -text $caption -default normal \
|
||||
-command [namespace code [list set button $i]]
|
||||
grid $dlg.$name -in $dlg.bot -column $i -row 0 -sticky ew -padx 10
|
||||
grid columnconfigure $dlg.bot $i -weight 1
|
||||
# We boost the size of some Mac buttons for l&f
|
||||
if {$windowingsystem eq "aqua"} {
|
||||
if {($name eq "ok") || ($name eq "dismiss")} {
|
||||
grid columnconfigure $dlg.bot $i -minsize 90
|
||||
}
|
||||
grid configure $dlg.$name -pady 7
|
||||
}
|
||||
incr i
|
||||
}
|
||||
# The "OK" button is the default for this dialog.
|
||||
$dlg.ok configure -default active
|
||||
|
||||
bind $dlg <Return> [namespace code {Return ok 0}]
|
||||
bind $dlg <Escape> [namespace code {Return dismiss 1}]
|
||||
bind $dlg <Destroy> [namespace code {Destroy %W}]
|
||||
bind $dlg.function <Return> [namespace code {ReturnInDetails %W}]
|
||||
$dlg.function configure -command [namespace code Details]
|
||||
|
||||
# 6. Withdraw the window, then update all the geometry information
|
||||
# so we know how big it wants to be, then center the window in the
|
||||
# display (Motif style) and de-iconify it.
|
||||
|
||||
::tk::PlaceWindow $dlg
|
||||
|
||||
# 7. Set a grab and claim the focus too.
|
||||
|
||||
::tk::SetFocusGrab $dlg $dlg.ok
|
||||
|
||||
# 8. Ensure that we are topmost.
|
||||
|
||||
raise $dlg
|
||||
if {[tk windowingsystem] eq "win32"} {
|
||||
# Place it topmost if we aren't at the top of the stacking
|
||||
# order to ensure that it's seen
|
||||
if {[lindex [wm stackorder .] end] ne "$dlg"} {
|
||||
wm attributes $dlg -topmost 1
|
||||
}
|
||||
}
|
||||
|
||||
# 9. Wait for the user to respond, then restore the focus and
|
||||
# return the index of the selected button. Restore the focus
|
||||
# before deleting the window, since otherwise the window manager
|
||||
# may take the focus away so we can't redirect it. Finally,
|
||||
# restore any grab that was in effect.
|
||||
|
||||
vwait [namespace which -variable button]
|
||||
set copy $button; # Save a copy...
|
||||
|
||||
::tk::RestoreFocusGrab $dlg $dlg.ok destroy
|
||||
|
||||
if {$copy == 1} {
|
||||
return -code break
|
||||
}
|
||||
}
|
||||
|
||||
namespace eval :: {
|
||||
# Fool the indexer
|
||||
proc bgerror err {}
|
||||
rename bgerror {}
|
||||
namespace import ::tk::dialog::error::bgerror
|
||||
}
|
||||
|
|
@ -0,0 +1,782 @@
|
|||
# button.tcl --
|
||||
#
|
||||
# This file defines the default bindings for Tk label, button,
|
||||
# checkbutton, and radiobutton widgets and provides procedures
|
||||
# that help in implementing those bindings.
|
||||
#
|
||||
# Copyright (c) 1992-1994 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1996 Sun Microsystems, Inc.
|
||||
# Copyright (c) 2002 ActiveState Corporation.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The code below creates the default class bindings for buttons.
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
|
||||
bind Radiobutton <Enter> {
|
||||
tk::ButtonEnter %W
|
||||
}
|
||||
bind Radiobutton <1> {
|
||||
tk::ButtonDown %W
|
||||
}
|
||||
bind Radiobutton <ButtonRelease-1> {
|
||||
tk::ButtonUp %W
|
||||
}
|
||||
bind Checkbutton <Enter> {
|
||||
tk::ButtonEnter %W
|
||||
}
|
||||
bind Checkbutton <1> {
|
||||
tk::ButtonDown %W
|
||||
}
|
||||
bind Checkbutton <ButtonRelease-1> {
|
||||
tk::ButtonUp %W
|
||||
}
|
||||
bind Checkbutton <Leave> {
|
||||
tk::ButtonLeave %W
|
||||
}
|
||||
}
|
||||
if {"win32" eq [tk windowingsystem]} {
|
||||
bind Checkbutton <equal> {
|
||||
tk::CheckRadioInvoke %W select
|
||||
}
|
||||
bind Checkbutton <plus> {
|
||||
tk::CheckRadioInvoke %W select
|
||||
}
|
||||
bind Checkbutton <minus> {
|
||||
tk::CheckRadioInvoke %W deselect
|
||||
}
|
||||
bind Checkbutton <1> {
|
||||
tk::CheckRadioDown %W
|
||||
}
|
||||
bind Checkbutton <ButtonRelease-1> {
|
||||
tk::ButtonUp %W
|
||||
}
|
||||
bind Checkbutton <Enter> {
|
||||
tk::CheckRadioEnter %W
|
||||
}
|
||||
bind Checkbutton <Leave> {
|
||||
tk::ButtonLeave %W
|
||||
}
|
||||
|
||||
bind Radiobutton <1> {
|
||||
tk::CheckRadioDown %W
|
||||
}
|
||||
bind Radiobutton <ButtonRelease-1> {
|
||||
tk::ButtonUp %W
|
||||
}
|
||||
bind Radiobutton <Enter> {
|
||||
tk::CheckRadioEnter %W
|
||||
}
|
||||
}
|
||||
if {"x11" eq [tk windowingsystem]} {
|
||||
bind Checkbutton <Return> {
|
||||
if {!$tk_strictMotif} {
|
||||
tk::CheckInvoke %W
|
||||
}
|
||||
}
|
||||
bind Radiobutton <Return> {
|
||||
if {!$tk_strictMotif} {
|
||||
tk::CheckRadioInvoke %W
|
||||
}
|
||||
}
|
||||
bind Checkbutton <1> {
|
||||
tk::CheckInvoke %W
|
||||
}
|
||||
bind Radiobutton <1> {
|
||||
tk::CheckRadioInvoke %W
|
||||
}
|
||||
bind Checkbutton <Enter> {
|
||||
tk::CheckEnter %W
|
||||
}
|
||||
bind Radiobutton <Enter> {
|
||||
tk::ButtonEnter %W
|
||||
}
|
||||
bind Checkbutton <Leave> {
|
||||
tk::CheckLeave %W
|
||||
}
|
||||
}
|
||||
|
||||
bind Button <space> {
|
||||
tk::ButtonInvoke %W
|
||||
}
|
||||
bind Checkbutton <space> {
|
||||
tk::CheckRadioInvoke %W
|
||||
}
|
||||
bind Radiobutton <space> {
|
||||
tk::CheckRadioInvoke %W
|
||||
}
|
||||
bind Button <<Invoke>> {
|
||||
tk::ButtonInvoke %W
|
||||
}
|
||||
bind Checkbutton <<Invoke>> {
|
||||
tk::CheckRadioInvoke %W
|
||||
}
|
||||
bind Radiobutton <<Invoke>> {
|
||||
tk::CheckRadioInvoke %W
|
||||
}
|
||||
|
||||
bind Button <FocusIn> {}
|
||||
bind Button <Enter> {
|
||||
tk::ButtonEnter %W
|
||||
}
|
||||
bind Button <Leave> {
|
||||
tk::ButtonLeave %W
|
||||
}
|
||||
bind Button <1> {
|
||||
tk::ButtonDown %W
|
||||
}
|
||||
bind Button <ButtonRelease-1> {
|
||||
tk::ButtonUp %W
|
||||
}
|
||||
|
||||
bind Checkbutton <FocusIn> {}
|
||||
|
||||
bind Radiobutton <FocusIn> {}
|
||||
bind Radiobutton <Leave> {
|
||||
tk::ButtonLeave %W
|
||||
}
|
||||
|
||||
if {"win32" eq [tk windowingsystem]} {
|
||||
|
||||
#########################
|
||||
# Windows implementation
|
||||
#########################
|
||||
|
||||
# ::tk::ButtonEnter --
|
||||
# The procedure below is invoked when the mouse pointer enters a
|
||||
# button widget. It records the button we're in and changes the
|
||||
# state of the button to active unless the button is disabled.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonEnter w {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
|
||||
# If the mouse button is down, set the relief to sunken on entry.
|
||||
# Overwise, if there's an -overrelief value, set the relief to that.
|
||||
|
||||
set Priv($w,relief) [$w cget -relief]
|
||||
if {$Priv(buttonWindow) eq $w} {
|
||||
$w configure -relief sunken -state active
|
||||
set Priv($w,prelief) sunken
|
||||
} elseif {[set over [$w cget -overrelief]] ne ""} {
|
||||
$w configure -relief $over
|
||||
set Priv($w,prelief) $over
|
||||
}
|
||||
}
|
||||
set Priv(window) $w
|
||||
}
|
||||
|
||||
# ::tk::ButtonLeave --
|
||||
# The procedure below is invoked when the mouse pointer leaves a
|
||||
# button widget. It changes the state of the button back to inactive.
|
||||
# Restore any modified relief too.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonLeave w {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
$w configure -state normal
|
||||
}
|
||||
|
||||
# Restore the original button relief if it was changed by Tk.
|
||||
# That is signaled by the existence of Priv($w,prelief).
|
||||
|
||||
if {[info exists Priv($w,relief)]} {
|
||||
if {[info exists Priv($w,prelief)] && \
|
||||
$Priv($w,prelief) eq [$w cget -relief]} {
|
||||
$w configure -relief $Priv($w,relief)
|
||||
}
|
||||
unset -nocomplain Priv($w,relief) Priv($w,prelief)
|
||||
}
|
||||
|
||||
set Priv(window) ""
|
||||
}
|
||||
|
||||
# ::tk::ButtonDown --
|
||||
# The procedure below is invoked when the mouse button is pressed in
|
||||
# a button widget. It records the fact that the mouse is in the button,
|
||||
# saves the button's relief so it can be restored later, and changes
|
||||
# the relief to sunken.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonDown w {
|
||||
variable ::tk::Priv
|
||||
|
||||
# Only save the button's relief if it does not yet exist. If there
|
||||
# is an overrelief setting, Priv($w,relief) will already have been set,
|
||||
# and the current value of the -relief option will be incorrect.
|
||||
|
||||
if {![info exists Priv($w,relief)]} {
|
||||
set Priv($w,relief) [$w cget -relief]
|
||||
}
|
||||
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
set Priv(buttonWindow) $w
|
||||
$w configure -relief sunken -state active
|
||||
set Priv($w,prelief) sunken
|
||||
|
||||
# If this button has a repeatdelay set up, get it going with an after
|
||||
after cancel $Priv(afterId)
|
||||
set delay [$w cget -repeatdelay]
|
||||
set Priv(repeated) 0
|
||||
if {$delay > 0} {
|
||||
set Priv(afterId) [after $delay [list tk::ButtonAutoInvoke $w]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ButtonUp --
|
||||
# The procedure below is invoked when the mouse button is released
|
||||
# in a button widget. It restores the button's relief and invokes
|
||||
# the command as long as the mouse hasn't left the button.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonUp w {
|
||||
variable ::tk::Priv
|
||||
if {$Priv(buttonWindow) eq $w} {
|
||||
set Priv(buttonWindow) ""
|
||||
|
||||
# Restore the button's relief if it was cached.
|
||||
|
||||
if {[info exists Priv($w,relief)]} {
|
||||
if {[info exists Priv($w,prelief)] && \
|
||||
$Priv($w,prelief) eq [$w cget -relief]} {
|
||||
$w configure -relief $Priv($w,relief)
|
||||
}
|
||||
unset -nocomplain Priv($w,relief) Priv($w,prelief)
|
||||
}
|
||||
|
||||
# Clean up the after event from the auto-repeater
|
||||
after cancel $Priv(afterId)
|
||||
|
||||
if {$Priv(window) eq $w && [$w cget -state] ne "disabled"} {
|
||||
$w configure -state normal
|
||||
|
||||
# Only invoke the command if it wasn't already invoked by the
|
||||
# auto-repeater functionality
|
||||
if { $Priv(repeated) == 0 } {
|
||||
uplevel #0 [list $w invoke]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::CheckRadioEnter --
|
||||
# The procedure below is invoked when the mouse pointer enters a
|
||||
# checkbutton or radiobutton widget. It records the button we're in
|
||||
# and changes the state of the button to active unless the button is
|
||||
# disabled.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::CheckRadioEnter w {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
if {$Priv(buttonWindow) eq $w} {
|
||||
$w configure -state active
|
||||
}
|
||||
if {[set over [$w cget -overrelief]] ne ""} {
|
||||
set Priv($w,relief) [$w cget -relief]
|
||||
set Priv($w,prelief) $over
|
||||
$w configure -relief $over
|
||||
}
|
||||
}
|
||||
set Priv(window) $w
|
||||
}
|
||||
|
||||
# ::tk::CheckRadioDown --
|
||||
# The procedure below is invoked when the mouse button is pressed in
|
||||
# a button widget. It records the fact that the mouse is in the button,
|
||||
# saves the button's relief so it can be restored later, and changes
|
||||
# the relief to sunken.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::CheckRadioDown w {
|
||||
variable ::tk::Priv
|
||||
if {![info exists Priv($w,relief)]} {
|
||||
set Priv($w,relief) [$w cget -relief]
|
||||
}
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
set Priv(buttonWindow) $w
|
||||
set Priv(repeated) 0
|
||||
$w configure -state active
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if {"x11" eq [tk windowingsystem]} {
|
||||
|
||||
#####################
|
||||
# Unix implementation
|
||||
#####################
|
||||
|
||||
# ::tk::ButtonEnter --
|
||||
# The procedure below is invoked when the mouse pointer enters a
|
||||
# button widget. It records the button we're in and changes the
|
||||
# state of the button to active unless the button is disabled.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonEnter {w} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
# On unix the state is active just with mouse-over
|
||||
$w configure -state active
|
||||
|
||||
# If the mouse button is down, set the relief to sunken on entry.
|
||||
# Overwise, if there's an -overrelief value, set the relief to that.
|
||||
|
||||
set Priv($w,relief) [$w cget -relief]
|
||||
if {$Priv(buttonWindow) eq $w} {
|
||||
$w configure -relief sunken
|
||||
set Priv($w,prelief) sunken
|
||||
} elseif {[set over [$w cget -overrelief]] ne ""} {
|
||||
$w configure -relief $over
|
||||
set Priv($w,prelief) $over
|
||||
}
|
||||
}
|
||||
set Priv(window) $w
|
||||
}
|
||||
|
||||
# ::tk::ButtonLeave --
|
||||
# The procedure below is invoked when the mouse pointer leaves a
|
||||
# button widget. It changes the state of the button back to inactive.
|
||||
# Restore any modified relief too.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonLeave w {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
$w configure -state normal
|
||||
}
|
||||
|
||||
# Restore the original button relief if it was changed by Tk.
|
||||
# That is signaled by the existence of Priv($w,prelief).
|
||||
|
||||
if {[info exists Priv($w,relief)]} {
|
||||
if {[info exists Priv($w,prelief)] && \
|
||||
$Priv($w,prelief) eq [$w cget -relief]} {
|
||||
$w configure -relief $Priv($w,relief)
|
||||
}
|
||||
unset -nocomplain Priv($w,relief) Priv($w,prelief)
|
||||
}
|
||||
|
||||
set Priv(window) ""
|
||||
}
|
||||
|
||||
# ::tk::ButtonDown --
|
||||
# The procedure below is invoked when the mouse button is pressed in
|
||||
# a button widget. It records the fact that the mouse is in the button,
|
||||
# saves the button's relief so it can be restored later, and changes
|
||||
# the relief to sunken.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonDown w {
|
||||
variable ::tk::Priv
|
||||
|
||||
# Only save the button's relief if it does not yet exist. If there
|
||||
# is an overrelief setting, Priv($w,relief) will already have been set,
|
||||
# and the current value of the -relief option will be incorrect.
|
||||
|
||||
if {![info exists Priv($w,relief)]} {
|
||||
set Priv($w,relief) [$w cget -relief]
|
||||
}
|
||||
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
set Priv(buttonWindow) $w
|
||||
$w configure -relief sunken
|
||||
set Priv($w,prelief) sunken
|
||||
|
||||
# If this button has a repeatdelay set up, get it going with an after
|
||||
after cancel $Priv(afterId)
|
||||
set delay [$w cget -repeatdelay]
|
||||
set Priv(repeated) 0
|
||||
if {$delay > 0} {
|
||||
set Priv(afterId) [after $delay [list tk::ButtonAutoInvoke $w]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ButtonUp --
|
||||
# The procedure below is invoked when the mouse button is released
|
||||
# in a button widget. It restores the button's relief and invokes
|
||||
# the command as long as the mouse hasn't left the button.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonUp w {
|
||||
variable ::tk::Priv
|
||||
if {$w eq $Priv(buttonWindow)} {
|
||||
set Priv(buttonWindow) ""
|
||||
|
||||
# Restore the button's relief if it was cached.
|
||||
|
||||
if {[info exists Priv($w,relief)]} {
|
||||
if {[info exists Priv($w,prelief)] && \
|
||||
$Priv($w,prelief) eq [$w cget -relief]} {
|
||||
$w configure -relief $Priv($w,relief)
|
||||
}
|
||||
unset -nocomplain Priv($w,relief) Priv($w,prelief)
|
||||
}
|
||||
|
||||
# Clean up the after event from the auto-repeater
|
||||
after cancel $Priv(afterId)
|
||||
|
||||
if {$Priv(window) eq $w && [$w cget -state] ne "disabled"} {
|
||||
# Only invoke the command if it wasn't already invoked by the
|
||||
# auto-repeater functionality
|
||||
if { $Priv(repeated) == 0 } {
|
||||
uplevel #0 [list $w invoke]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
|
||||
####################
|
||||
# Mac implementation
|
||||
####################
|
||||
|
||||
# ::tk::ButtonEnter --
|
||||
# The procedure below is invoked when the mouse pointer enters a
|
||||
# button widget. It records the button we're in and changes the
|
||||
# state of the button to active unless the button is disabled.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonEnter {w} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
|
||||
# If there's an -overrelief value, set the relief to that.
|
||||
|
||||
if {$Priv(buttonWindow) eq $w} {
|
||||
$w configure -state active
|
||||
} elseif {[set over [$w cget -overrelief]] ne ""} {
|
||||
set Priv($w,relief) [$w cget -relief]
|
||||
set Priv($w,prelief) $over
|
||||
$w configure -relief $over
|
||||
}
|
||||
}
|
||||
set Priv(window) $w
|
||||
}
|
||||
|
||||
# ::tk::ButtonLeave --
|
||||
# The procedure below is invoked when the mouse pointer leaves a
|
||||
# button widget. It changes the state of the button back to
|
||||
# inactive. If we're leaving the button window with a mouse button
|
||||
# pressed (Priv(buttonWindow) == $w), restore the relief of the
|
||||
# button too.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonLeave w {
|
||||
variable ::tk::Priv
|
||||
if {$w eq $Priv(buttonWindow)} {
|
||||
$w configure -state normal
|
||||
}
|
||||
|
||||
# Restore the original button relief if it was changed by Tk.
|
||||
# That is signaled by the existence of Priv($w,prelief).
|
||||
|
||||
if {[info exists Priv($w,relief)]} {
|
||||
if {[info exists Priv($w,prelief)] && \
|
||||
$Priv($w,prelief) eq [$w cget -relief]} {
|
||||
$w configure -relief $Priv($w,relief)
|
||||
}
|
||||
unset -nocomplain Priv($w,relief) Priv($w,prelief)
|
||||
}
|
||||
|
||||
set Priv(window) ""
|
||||
}
|
||||
|
||||
# ::tk::ButtonDown --
|
||||
# The procedure below is invoked when the mouse button is pressed in
|
||||
# a button widget. It records the fact that the mouse is in the button,
|
||||
# saves the button's relief so it can be restored later, and changes
|
||||
# the relief to sunken.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonDown w {
|
||||
variable ::tk::Priv
|
||||
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
set Priv(buttonWindow) $w
|
||||
$w configure -state active
|
||||
|
||||
# If this button has a repeatdelay set up, get it going with an after
|
||||
after cancel $Priv(afterId)
|
||||
set Priv(repeated) 0
|
||||
if { ![catch {$w cget -repeatdelay} delay] } {
|
||||
if {$delay > 0} {
|
||||
set Priv(afterId) [after $delay [list tk::ButtonAutoInvoke $w]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ButtonUp --
|
||||
# The procedure below is invoked when the mouse button is released
|
||||
# in a button widget. It restores the button's relief and invokes
|
||||
# the command as long as the mouse hasn't left the button.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonUp w {
|
||||
variable ::tk::Priv
|
||||
if {$Priv(buttonWindow) eq $w} {
|
||||
set Priv(buttonWindow) ""
|
||||
$w configure -state normal
|
||||
|
||||
# Restore the button's relief if it was cached.
|
||||
|
||||
if {[info exists Priv($w,relief)]} {
|
||||
if {[info exists Priv($w,prelief)] && \
|
||||
$Priv($w,prelief) eq [$w cget -relief]} {
|
||||
$w configure -relief $Priv($w,relief)
|
||||
}
|
||||
unset -nocomplain Priv($w,relief) Priv($w,prelief)
|
||||
}
|
||||
|
||||
# Clean up the after event from the auto-repeater
|
||||
after cancel $Priv(afterId)
|
||||
|
||||
if {$Priv(window) eq $w && [$w cget -state] ne "disabled"} {
|
||||
# Only invoke the command if it wasn't already invoked by the
|
||||
# auto-repeater functionality
|
||||
if { $Priv(repeated) == 0 } {
|
||||
uplevel #0 [list $w invoke]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
##################
|
||||
# Shared routines
|
||||
##################
|
||||
|
||||
# ::tk::ButtonInvoke --
|
||||
# The procedure below is called when a button is invoked through
|
||||
# the keyboard. It simulate a press of the button via the mouse.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::ButtonInvoke w {
|
||||
if {[winfo exists $w] && [$w cget -state] ne "disabled"} {
|
||||
set oldRelief [$w cget -relief]
|
||||
set oldState [$w cget -state]
|
||||
$w configure -state active -relief sunken
|
||||
after 100 [list ::tk::ButtonInvokeEnd $w $oldState $oldRelief]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ButtonInvokeEnd --
|
||||
# The procedure below is called after a button is invoked through
|
||||
# the keyboard. It simulate a release of the button via the mouse.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
# oldState - Old state to be set back.
|
||||
# oldRelief - Old relief to be set back.
|
||||
|
||||
proc ::tk::ButtonInvokeEnd {w oldState oldRelief} {
|
||||
if {[winfo exists $w]} {
|
||||
$w configure -state $oldState -relief $oldRelief
|
||||
uplevel #0 [list $w invoke]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ButtonAutoInvoke --
|
||||
#
|
||||
# Invoke an auto-repeating button, and set it up to continue to repeat.
|
||||
#
|
||||
# Arguments:
|
||||
# w button to invoke.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
#
|
||||
# Side effects:
|
||||
# May create an after event to call ::tk::ButtonAutoInvoke.
|
||||
|
||||
proc ::tk::ButtonAutoInvoke {w} {
|
||||
variable ::tk::Priv
|
||||
after cancel $Priv(afterId)
|
||||
set delay [$w cget -repeatinterval]
|
||||
if {$Priv(window) eq $w} {
|
||||
incr Priv(repeated)
|
||||
uplevel #0 [list $w invoke]
|
||||
}
|
||||
if {$delay > 0} {
|
||||
set Priv(afterId) [after $delay [list tk::ButtonAutoInvoke $w]]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::CheckRadioInvoke --
|
||||
# The procedure below is invoked when the mouse button is pressed in
|
||||
# a checkbutton or radiobutton widget, or when the widget is invoked
|
||||
# through the keyboard. It invokes the widget if it
|
||||
# isn't disabled.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
# cmd - The subcommand to invoke (one of invoke, select, or deselect).
|
||||
|
||||
proc ::tk::CheckRadioInvoke {w {cmd invoke}} {
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
uplevel #0 [list $w $cmd]
|
||||
}
|
||||
}
|
||||
|
||||
# Special versions of the handlers for checkbuttons on Unix that do the magic
|
||||
# to make things work right when the checkbutton indicator is hidden;
|
||||
# radiobuttons don't need this complexity.
|
||||
|
||||
# ::tk::CheckInvoke --
|
||||
# The procedure below invokes the checkbutton, like ButtonInvoke, but handles
|
||||
# what to do when the checkbutton indicator is missing. Only used on Unix.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::CheckInvoke {w} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
# Additional logic to switch the "selected" colors around if necessary
|
||||
# (when we're indicator-less).
|
||||
|
||||
if {![$w cget -indicatoron] && [info exist Priv($w,selectcolor)]} {
|
||||
if {[$w cget -selectcolor] eq $Priv($w,aselectcolor)} {
|
||||
$w configure -selectcolor $Priv($w,selectcolor)
|
||||
} else {
|
||||
$w configure -selectcolor $Priv($w,aselectcolor)
|
||||
}
|
||||
}
|
||||
uplevel #0 [list $w invoke]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::CheckEnter --
|
||||
# The procedure below enters the checkbutton, like ButtonEnter, but handles
|
||||
# what to do when the checkbutton indicator is missing. Only used on Unix.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::CheckEnter {w} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
# On unix the state is active just with mouse-over
|
||||
$w configure -state active
|
||||
|
||||
# If the mouse button is down, set the relief to sunken on entry.
|
||||
# Overwise, if there's an -overrelief value, set the relief to that.
|
||||
|
||||
set Priv($w,relief) [$w cget -relief]
|
||||
if {$Priv(buttonWindow) eq $w} {
|
||||
$w configure -relief sunken
|
||||
set Priv($w,prelief) sunken
|
||||
} elseif {[set over [$w cget -overrelief]] ne ""} {
|
||||
$w configure -relief $over
|
||||
set Priv($w,prelief) $over
|
||||
}
|
||||
|
||||
# Compute what the "selected and active" color should be.
|
||||
|
||||
if {![$w cget -indicatoron] && [$w cget -selectcolor] ne ""} {
|
||||
set Priv($w,selectcolor) [$w cget -selectcolor]
|
||||
lassign [winfo rgb $w [$w cget -selectcolor]] r1 g1 b1
|
||||
lassign [winfo rgb $w [$w cget -activebackground]] r2 g2 b2
|
||||
set Priv($w,aselectcolor) \
|
||||
[format "#%04x%04x%04x" [expr {($r1+$r2)/2}] \
|
||||
[expr {($g1+$g2)/2}] [expr {($b1+$b2)/2}]]
|
||||
# use uplevel to work with other var resolvers
|
||||
if {[uplevel #0 [list set [$w cget -variable]]]
|
||||
eq [$w cget -onvalue]} {
|
||||
$w configure -selectcolor $Priv($w,aselectcolor)
|
||||
}
|
||||
}
|
||||
}
|
||||
set Priv(window) $w
|
||||
}
|
||||
|
||||
# ::tk::CheckLeave --
|
||||
# The procedure below leaves the checkbutton, like ButtonLeave, but handles
|
||||
# what to do when the checkbutton indicator is missing. Only used on Unix.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of the widget.
|
||||
|
||||
proc ::tk::CheckLeave {w} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -state] ne "disabled"} {
|
||||
$w configure -state normal
|
||||
}
|
||||
|
||||
# Restore the original button "selected" color; but only if the user
|
||||
# has not changed it in the meantime.
|
||||
|
||||
if {![$w cget -indicatoron] && [info exist Priv($w,selectcolor)]} {
|
||||
if {[$w cget -selectcolor] eq $Priv($w,selectcolor)
|
||||
|| ([info exist Priv($w,aselectcolor)] &&
|
||||
[$w cget -selectcolor] eq $Priv($w,aselectcolor))} {
|
||||
$w configure -selectcolor $Priv($w,selectcolor)
|
||||
}
|
||||
}
|
||||
unset -nocomplain Priv($w,selectcolor) Priv($w,aselectcolor)
|
||||
|
||||
# Restore the original button relief if it was changed by Tk. That is
|
||||
# signaled by the existence of Priv($w,prelief).
|
||||
|
||||
if {[info exists Priv($w,relief)]} {
|
||||
if {[info exists Priv($w,prelief)] && \
|
||||
$Priv($w,prelief) eq [$w cget -relief]} {
|
||||
$w configure -relief $Priv($w,relief)
|
||||
}
|
||||
unset -nocomplain Priv($w,relief) Priv($w,prelief)
|
||||
}
|
||||
|
||||
set Priv(window) ""
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
# Local Variables:
|
||||
# mode: tcl
|
||||
# fill-column: 78
|
||||
# End:
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
# choosedir.tcl --
|
||||
#
|
||||
# Choose directory dialog implementation for Unix/Mac.
|
||||
#
|
||||
# Copyright (c) 1998-2000 by Scriptics Corporation.
|
||||
# All rights reserved.
|
||||
|
||||
# Make sure the tk::dialog namespace, in which all dialogs should live, exists
|
||||
namespace eval ::tk::dialog {}
|
||||
namespace eval ::tk::dialog::file {}
|
||||
|
||||
# Make the chooseDir namespace inside the dialog namespace
|
||||
namespace eval ::tk::dialog::file::chooseDir {
|
||||
namespace import -force ::tk::msgcat::*
|
||||
}
|
||||
|
||||
# ::tk::dialog::file::chooseDir:: --
|
||||
#
|
||||
# Implements the TK directory selection dialog.
|
||||
#
|
||||
# Arguments:
|
||||
# args Options parsed by the procedure.
|
||||
#
|
||||
proc ::tk::dialog::file::chooseDir:: {args} {
|
||||
variable ::tk::Priv
|
||||
set dataName __tk_choosedir
|
||||
upvar ::tk::dialog::file::$dataName data
|
||||
Config $dataName $args
|
||||
|
||||
if {$data(-parent) eq "."} {
|
||||
set w .$dataName
|
||||
} else {
|
||||
set w $data(-parent).$dataName
|
||||
}
|
||||
|
||||
# (re)create the dialog box if necessary
|
||||
#
|
||||
if {![winfo exists $w]} {
|
||||
::tk::dialog::file::Create $w TkChooseDir
|
||||
} elseif {[winfo class $w] ne "TkChooseDir"} {
|
||||
destroy $w
|
||||
::tk::dialog::file::Create $w TkChooseDir
|
||||
} else {
|
||||
set data(dirMenuBtn) $w.contents.f1.menu
|
||||
set data(dirMenu) $w.contents.f1.menu.menu
|
||||
set data(upBtn) $w.contents.f1.up
|
||||
set data(icons) $w.contents.icons
|
||||
set data(ent) $w.contents.f2.ent
|
||||
set data(okBtn) $w.contents.f2.ok
|
||||
set data(cancelBtn) $w.contents.f2.cancel
|
||||
set data(hiddenBtn) $w.contents.f2.hidden
|
||||
}
|
||||
if {$::tk::dialog::file::showHiddenBtn} {
|
||||
$data(hiddenBtn) configure -state normal
|
||||
grid $data(hiddenBtn)
|
||||
} else {
|
||||
$data(hiddenBtn) configure -state disabled
|
||||
grid remove $data(hiddenBtn)
|
||||
}
|
||||
|
||||
# When using -mustexist, manage the OK button state for validity
|
||||
$data(okBtn) configure -state normal
|
||||
if {$data(-mustexist)} {
|
||||
$data(ent) configure -validate key \
|
||||
-validatecommand [list ::tk::dialog::file::chooseDir::IsOK? $w %P]
|
||||
} else {
|
||||
$data(ent) configure -validate none
|
||||
}
|
||||
|
||||
# Dialog boxes should be transient with respect to their parent,
|
||||
# so that they will always stay on top of their parent window. However,
|
||||
# some window managers will create the window as withdrawn if the parent
|
||||
# window is withdrawn or iconified. Combined with the grab we put on the
|
||||
# window, this can hang the entire application. Therefore we only make
|
||||
# the dialog transient if the parent is viewable.
|
||||
|
||||
if {[winfo viewable [winfo toplevel $data(-parent)]] } {
|
||||
wm transient $w $data(-parent)
|
||||
}
|
||||
|
||||
trace add variable data(selectPath) write \
|
||||
[list ::tk::dialog::file::SetPath $w]
|
||||
$data(dirMenuBtn) configure \
|
||||
-textvariable ::tk::dialog::file::${dataName}(selectPath)
|
||||
|
||||
set data(filter) "*"
|
||||
set data(previousEntryText) ""
|
||||
::tk::dialog::file::UpdateWhenIdle $w
|
||||
|
||||
# Withdraw the window, then update all the geometry information
|
||||
# so we know how big it wants to be, then center the window in the
|
||||
# display (Motif style) and de-iconify it.
|
||||
|
||||
::tk::PlaceWindow $w widget $data(-parent)
|
||||
wm title $w $data(-title)
|
||||
|
||||
# Set a grab and claim the focus too.
|
||||
|
||||
::tk::SetFocusGrab $w $data(ent)
|
||||
$data(ent) delete 0 end
|
||||
$data(ent) insert 0 $data(selectPath)
|
||||
$data(ent) selection range 0 end
|
||||
$data(ent) icursor end
|
||||
|
||||
# Wait for the user to respond, then restore the focus and
|
||||
# return the index of the selected button. Restore the focus
|
||||
# before deleting the window, since otherwise the window manager
|
||||
# may take the focus away so we can't redirect it. Finally,
|
||||
# restore any grab that was in effect.
|
||||
|
||||
vwait ::tk::Priv(selectFilePath)
|
||||
|
||||
::tk::RestoreFocusGrab $w $data(ent) withdraw
|
||||
|
||||
# Cleanup traces on selectPath variable
|
||||
#
|
||||
|
||||
foreach trace [trace info variable data(selectPath)] {
|
||||
trace remove variable data(selectPath) [lindex $trace 0] [lindex $trace 1]
|
||||
}
|
||||
$data(dirMenuBtn) configure -textvariable {}
|
||||
|
||||
# Return value to user
|
||||
#
|
||||
|
||||
return $Priv(selectFilePath)
|
||||
}
|
||||
|
||||
# ::tk::dialog::file::chooseDir::Config --
|
||||
#
|
||||
# Configures the Tk choosedir dialog according to the argument list
|
||||
#
|
||||
proc ::tk::dialog::file::chooseDir::Config {dataName argList} {
|
||||
upvar ::tk::dialog::file::$dataName data
|
||||
|
||||
# 0: Delete all variable that were set on data(selectPath) the
|
||||
# last time the file dialog is used. The traces may cause troubles
|
||||
# if the dialog is now used with a different -parent option.
|
||||
#
|
||||
foreach trace [trace info variable data(selectPath)] {
|
||||
trace remove variable data(selectPath) [lindex $trace 0] [lindex $trace 1]
|
||||
}
|
||||
|
||||
# 1: the configuration specs
|
||||
#
|
||||
set specs {
|
||||
{-mustexist "" "" 0}
|
||||
{-initialdir "" "" ""}
|
||||
{-parent "" "" "."}
|
||||
{-title "" "" ""}
|
||||
}
|
||||
|
||||
# 2: default values depending on the type of the dialog
|
||||
#
|
||||
if {![info exists data(selectPath)]} {
|
||||
# first time the dialog has been popped up
|
||||
set data(selectPath) [pwd]
|
||||
}
|
||||
|
||||
# 3: parse the arguments
|
||||
#
|
||||
tclParseConfigSpec ::tk::dialog::file::$dataName $specs "" $argList
|
||||
|
||||
if {$data(-title) eq ""} {
|
||||
set data(-title) "[mc "Choose Directory"]"
|
||||
}
|
||||
|
||||
# Stub out the -multiple value for the dialog; it doesn't make sense for
|
||||
# choose directory dialogs, but we have to have something there because we
|
||||
# share so much code with the file dialogs.
|
||||
set data(-multiple) 0
|
||||
|
||||
# 4: set the default directory and selection according to the -initial
|
||||
# settings
|
||||
#
|
||||
if {$data(-initialdir) ne ""} {
|
||||
# Ensure that initialdir is an absolute path name.
|
||||
if {[file isdirectory $data(-initialdir)]} {
|
||||
set old [pwd]
|
||||
cd $data(-initialdir)
|
||||
set data(selectPath) [pwd]
|
||||
cd $old
|
||||
} else {
|
||||
set data(selectPath) [pwd]
|
||||
}
|
||||
}
|
||||
|
||||
if {![winfo exists $data(-parent)]} {
|
||||
return -code error -errorcode [list TK LOOKUP WINDOW $data(-parent)] \
|
||||
"bad window path name \"$data(-parent)\""
|
||||
}
|
||||
}
|
||||
|
||||
# Gets called when user presses Return in the "Selection" entry or presses OK.
|
||||
#
|
||||
proc ::tk::dialog::file::chooseDir::OkCmd {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
# This is the brains behind selecting non-existant directories. Here's
|
||||
# the flowchart:
|
||||
# 1. If the icon list has a selection, join it with the current dir,
|
||||
# and return that value.
|
||||
# 1a. If the icon list does not have a selection ...
|
||||
# 2. If the entry is empty, do nothing.
|
||||
# 3. If the entry contains an invalid directory, then...
|
||||
# 3a. If the value is the same as last time through here, end dialog.
|
||||
# 3b. If the value is different than last time, save it and return.
|
||||
# 4. If entry contains a valid directory, then...
|
||||
# 4a. If the value is the same as the current directory, end dialog.
|
||||
# 4b. If the value is different from the current directory, change to
|
||||
# that directory.
|
||||
|
||||
set selection [$data(icons) selection get]
|
||||
if {[llength $selection] != 0} {
|
||||
set iconText [$data(icons) get [lindex $selection 0]]
|
||||
set iconText [file join $data(selectPath) $iconText]
|
||||
Done $w $iconText
|
||||
} else {
|
||||
set text [$data(ent) get]
|
||||
if {$text eq ""} {
|
||||
return
|
||||
}
|
||||
set text [file join {*}[file split [string trim $text]]]
|
||||
if {![file exists $text] || ![file isdirectory $text]} {
|
||||
# Entry contains an invalid directory. If it's the same as the
|
||||
# last time they came through here, reset the saved value and end
|
||||
# the dialog. Otherwise, save the value (so we can do this test
|
||||
# next time).
|
||||
if {$text eq $data(previousEntryText)} {
|
||||
set data(previousEntryText) ""
|
||||
Done $w $text
|
||||
} else {
|
||||
set data(previousEntryText) $text
|
||||
}
|
||||
} else {
|
||||
# Entry contains a valid directory. If it is the same as the
|
||||
# current directory, end the dialog. Otherwise, change to that
|
||||
# directory.
|
||||
if {$text eq $data(selectPath)} {
|
||||
Done $w $text
|
||||
} else {
|
||||
set data(selectPath) $text
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
# Change state of OK button to match -mustexist correctness of entry
|
||||
#
|
||||
proc ::tk::dialog::file::chooseDir::IsOK? {w text} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
set ok [file isdirectory $text]
|
||||
$data(okBtn) configure -state [expr {$ok ? "normal" : "disabled"}]
|
||||
|
||||
# always return 1
|
||||
return 1
|
||||
}
|
||||
|
||||
proc ::tk::dialog::file::chooseDir::DblClick {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
set selection [$data(icons) selection get]
|
||||
if {[llength $selection] != 0} {
|
||||
set filenameFragment [$data(icons) get [lindex $selection 0]]
|
||||
set file $data(selectPath)
|
||||
if {[file isdirectory $file]} {
|
||||
::tk::dialog::file::ListInvoke $w [list $filenameFragment]
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Gets called when user browses the IconList widget (dragging mouse, arrow
|
||||
# keys, etc)
|
||||
#
|
||||
proc ::tk::dialog::file::chooseDir::ListBrowse {w text} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
if {$text eq ""} {
|
||||
return
|
||||
}
|
||||
|
||||
set file [::tk::dialog::file::JoinFile $data(selectPath) $text]
|
||||
$data(ent) delete 0 end
|
||||
$data(ent) insert 0 $file
|
||||
}
|
||||
|
||||
# ::tk::dialog::file::chooseDir::Done --
|
||||
#
|
||||
# Gets called when user has input a valid filename. Pops up a
|
||||
# dialog box to confirm selection when necessary. Sets the
|
||||
# Priv(selectFilePath) variable, which will break the "vwait"
|
||||
# loop in tk_chooseDirectory and return the selected filename to the
|
||||
# script that calls tk_getOpenFile or tk_getSaveFile
|
||||
#
|
||||
proc ::tk::dialog::file::chooseDir::Done {w {selectFilePath ""}} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
variable ::tk::Priv
|
||||
|
||||
if {$selectFilePath eq ""} {
|
||||
set selectFilePath $data(selectPath)
|
||||
}
|
||||
if {$data(-mustexist) && ![file isdirectory $selectFilePath]} {
|
||||
return
|
||||
}
|
||||
set Priv(selectFilePath) $selectFilePath
|
||||
}
|
||||
|
|
@ -0,0 +1,695 @@
|
|||
# clrpick.tcl --
|
||||
#
|
||||
# Color selection dialog for platforms that do not support a
|
||||
# standard color selection dialog.
|
||||
#
|
||||
# Copyright (c) 1996 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
# ToDo:
|
||||
#
|
||||
# (1): Find out how many free colors are left in the colormap and
|
||||
# don't allocate too many colors.
|
||||
# (2): Implement HSV color selection.
|
||||
#
|
||||
|
||||
# Make sure namespaces exist
|
||||
namespace eval ::tk {}
|
||||
namespace eval ::tk::dialog {}
|
||||
namespace eval ::tk::dialog::color {
|
||||
namespace import ::tk::msgcat::*
|
||||
}
|
||||
|
||||
# ::tk::dialog::color:: --
|
||||
#
|
||||
# Create a color dialog and let the user choose a color. This function
|
||||
# should not be called directly. It is called by the tk_chooseColor
|
||||
# function when a native color selector widget does not exist
|
||||
#
|
||||
proc ::tk::dialog::color:: {args} {
|
||||
variable ::tk::Priv
|
||||
set dataName __tk__color
|
||||
upvar ::tk::dialog::color::$dataName data
|
||||
set w .$dataName
|
||||
|
||||
# The lines variables track the start and end indices of the line
|
||||
# elements in the colorbar canvases.
|
||||
set data(lines,red,start) 0
|
||||
set data(lines,red,last) -1
|
||||
set data(lines,green,start) 0
|
||||
set data(lines,green,last) -1
|
||||
set data(lines,blue,start) 0
|
||||
set data(lines,blue,last) -1
|
||||
|
||||
# This is the actual number of lines that are drawn in each color strip.
|
||||
# Note that the bars may be of any width.
|
||||
# However, NUM_COLORBARS must be a number that evenly divides 256.
|
||||
# Such as 256, 128, 64, etc.
|
||||
set data(NUM_COLORBARS) 16
|
||||
|
||||
# BARS_WIDTH is the number of pixels wide the color bar portion of the
|
||||
# canvas is. This number must be a multiple of NUM_COLORBARS
|
||||
set data(BARS_WIDTH) 160
|
||||
|
||||
# PLGN_WIDTH is the number of pixels wide of the triangular selection
|
||||
# polygon. This also results in the definition of the padding on the
|
||||
# left and right sides which is half of PLGN_WIDTH. Make this number even.
|
||||
set data(PLGN_HEIGHT) 10
|
||||
|
||||
# PLGN_HEIGHT is the height of the selection polygon and the height of the
|
||||
# selection rectangle at the bottom of the color bar. No restrictions.
|
||||
set data(PLGN_WIDTH) 10
|
||||
|
||||
Config $dataName $args
|
||||
InitValues $dataName
|
||||
|
||||
set sc [winfo screen $data(-parent)]
|
||||
set winExists [winfo exists $w]
|
||||
if {!$winExists || $sc ne [winfo screen $w]} {
|
||||
if {$winExists} {
|
||||
destroy $w
|
||||
}
|
||||
toplevel $w -class TkColorDialog -screen $sc
|
||||
if {[tk windowingsystem] eq "x11"} {wm attributes $w -type dialog}
|
||||
BuildDialog $w
|
||||
}
|
||||
|
||||
# Dialog boxes should be transient with respect to their parent,
|
||||
# so that they will always stay on top of their parent window. However,
|
||||
# some window managers will create the window as withdrawn if the parent
|
||||
# window is withdrawn or iconified. Combined with the grab we put on the
|
||||
# window, this can hang the entire application. Therefore we only make
|
||||
# the dialog transient if the parent is viewable.
|
||||
|
||||
if {[winfo viewable [winfo toplevel $data(-parent)]] } {
|
||||
wm transient $w $data(-parent)
|
||||
}
|
||||
|
||||
# 5. Withdraw the window, then update all the geometry information
|
||||
# so we know how big it wants to be, then center the window in the
|
||||
# display (Motif style) and de-iconify it.
|
||||
|
||||
::tk::PlaceWindow $w widget $data(-parent)
|
||||
wm title $w $data(-title)
|
||||
|
||||
# 6. Set a grab and claim the focus too.
|
||||
|
||||
::tk::SetFocusGrab $w $data(okBtn)
|
||||
|
||||
# 7. Wait for the user to respond, then restore the focus and
|
||||
# return the index of the selected button. Restore the focus
|
||||
# before deleting the window, since otherwise the window manager
|
||||
# may take the focus away so we can't redirect it. Finally,
|
||||
# restore any grab that was in effect.
|
||||
|
||||
vwait ::tk::Priv(selectColor)
|
||||
set result $Priv(selectColor)
|
||||
::tk::RestoreFocusGrab $w $data(okBtn)
|
||||
unset data
|
||||
|
||||
return $result
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::InitValues --
|
||||
#
|
||||
# Get called during initialization or when user resets NUM_COLORBARS
|
||||
#
|
||||
proc ::tk::dialog::color::InitValues {dataName} {
|
||||
upvar ::tk::dialog::color::$dataName data
|
||||
|
||||
# IntensityIncr is the difference in color intensity between a colorbar
|
||||
# and its neighbors.
|
||||
set data(intensityIncr) [expr {256 / $data(NUM_COLORBARS)}]
|
||||
|
||||
# ColorbarWidth is the width of each colorbar
|
||||
set data(colorbarWidth) [expr {$data(BARS_WIDTH) / $data(NUM_COLORBARS)}]
|
||||
|
||||
# Indent is the width of the space at the left and right side of the
|
||||
# colorbar. It is always half the selector polygon width, because the
|
||||
# polygon extends into the space.
|
||||
set data(indent) [expr {$data(PLGN_WIDTH) / 2}]
|
||||
|
||||
set data(colorPad) 2
|
||||
set data(selPad) [expr {$data(PLGN_WIDTH) / 2}]
|
||||
|
||||
#
|
||||
# minX is the x coordinate of the first colorbar
|
||||
#
|
||||
set data(minX) $data(indent)
|
||||
|
||||
#
|
||||
# maxX is the x coordinate of the last colorbar
|
||||
#
|
||||
set data(maxX) [expr {$data(BARS_WIDTH) + $data(indent)-1}]
|
||||
|
||||
#
|
||||
# canvasWidth is the width of the entire canvas, including the indents
|
||||
#
|
||||
set data(canvasWidth) [expr {$data(BARS_WIDTH) + $data(PLGN_WIDTH)}]
|
||||
|
||||
# Set the initial color, specified by -initialcolor, or the
|
||||
# color chosen by the user the last time.
|
||||
set data(selection) $data(-initialcolor)
|
||||
set data(finalColor) $data(-initialcolor)
|
||||
set rgb [winfo rgb . $data(selection)]
|
||||
|
||||
set data(red,intensity) [expr {[lindex $rgb 0]/0x100}]
|
||||
set data(green,intensity) [expr {[lindex $rgb 1]/0x100}]
|
||||
set data(blue,intensity) [expr {[lindex $rgb 2]/0x100}]
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::Config --
|
||||
#
|
||||
# Parses the command line arguments to tk_chooseColor
|
||||
#
|
||||
proc ::tk::dialog::color::Config {dataName argList} {
|
||||
variable ::tk::Priv
|
||||
upvar ::tk::dialog::color::$dataName data
|
||||
|
||||
# 1: the configuration specs
|
||||
#
|
||||
if {[info exists Priv(selectColor)] && $Priv(selectColor) ne ""} {
|
||||
set defaultColor $Priv(selectColor)
|
||||
} else {
|
||||
set defaultColor [. cget -background]
|
||||
}
|
||||
|
||||
set specs [list \
|
||||
[list -initialcolor "" "" $defaultColor] \
|
||||
[list -parent "" "" "."] \
|
||||
[list -title "" "" [mc "Color"]] \
|
||||
]
|
||||
|
||||
# 2: parse the arguments
|
||||
#
|
||||
tclParseConfigSpec ::tk::dialog::color::$dataName $specs "" $argList
|
||||
|
||||
if {$data(-title) eq ""} {
|
||||
set data(-title) " "
|
||||
}
|
||||
if {[catch {winfo rgb . $data(-initialcolor)} err]} {
|
||||
return -code error -errorcode [list TK LOOKUP COLOR $data(-initialcolor)] \
|
||||
$err
|
||||
}
|
||||
|
||||
if {![winfo exists $data(-parent)]} {
|
||||
return -code error -errorcode [list TK LOOKUP WINDOW $data(-parent)] \
|
||||
"bad window path name \"$data(-parent)\""
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::BuildDialog --
|
||||
#
|
||||
# Build the dialog.
|
||||
#
|
||||
proc ::tk::dialog::color::BuildDialog {w} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
# TopFrame contains the color strips and the color selection
|
||||
#
|
||||
set topFrame [frame $w.top -relief raised -bd 1]
|
||||
|
||||
# StripsFrame contains the colorstrips and the individual RGB entries
|
||||
set stripsFrame [frame $topFrame.colorStrip]
|
||||
|
||||
set maxWidth [::tk::mcmaxamp &Red &Green &Blue]
|
||||
set maxWidth [expr {$maxWidth<6 ? 6 : $maxWidth}]
|
||||
set colorList {
|
||||
red "&Red"
|
||||
green "&Green"
|
||||
blue "&Blue"
|
||||
}
|
||||
foreach {color l} $colorList {
|
||||
# each f frame contains an [R|G|B] entry and the equiv. color strip.
|
||||
set f [frame $stripsFrame.$color]
|
||||
|
||||
# The box frame contains the label and entry widget for an [R|G|B]
|
||||
set box [frame $f.box]
|
||||
|
||||
::tk::AmpWidget label $box.label -text "[mc $l]:" \
|
||||
-width $maxWidth -anchor ne
|
||||
bind $box.label <<AltUnderlined>> [list focus $box.entry]
|
||||
|
||||
entry $box.entry -textvariable \
|
||||
::tk::dialog::color::[winfo name $w]($color,intensity) \
|
||||
-width 4
|
||||
pack $box.label -side left -fill y -padx 2 -pady 3
|
||||
pack $box.entry -side left -anchor n -pady 0
|
||||
pack $box -side left -fill both
|
||||
|
||||
set height [expr {
|
||||
[winfo reqheight $box.entry] -
|
||||
2*([$box.entry cget -highlightthickness] + [$box.entry cget -bd])
|
||||
}]
|
||||
|
||||
canvas $f.color -height $height \
|
||||
-width $data(BARS_WIDTH) -relief sunken -bd 2
|
||||
canvas $f.sel -height $data(PLGN_HEIGHT) \
|
||||
-width $data(canvasWidth) -highlightthickness 0
|
||||
pack $f.color -expand yes -fill both
|
||||
pack $f.sel -expand yes -fill both
|
||||
|
||||
pack $f -side top -fill x -padx 0 -pady 2
|
||||
|
||||
set data($color,entry) $box.entry
|
||||
set data($color,col) $f.color
|
||||
set data($color,sel) $f.sel
|
||||
|
||||
bind $data($color,col) <Configure> \
|
||||
[list tk::dialog::color::DrawColorScale $w $color 1]
|
||||
bind $data($color,col) <Enter> \
|
||||
[list tk::dialog::color::EnterColorBar $w $color]
|
||||
bind $data($color,col) <Leave> \
|
||||
[list tk::dialog::color::LeaveColorBar $w $color]
|
||||
|
||||
bind $data($color,sel) <Enter> \
|
||||
[list tk::dialog::color::EnterColorBar $w $color]
|
||||
bind $data($color,sel) <Leave> \
|
||||
[list tk::dialog::color::LeaveColorBar $w $color]
|
||||
|
||||
bind $box.entry <Return> [list tk::dialog::color::HandleRGBEntry $w]
|
||||
}
|
||||
|
||||
pack $stripsFrame -side left -fill both -padx 4 -pady 10
|
||||
|
||||
# The selFrame contains a frame that demonstrates the currently
|
||||
# selected color
|
||||
#
|
||||
set selFrame [frame $topFrame.sel]
|
||||
set lab [::tk::AmpWidget label $selFrame.lab \
|
||||
-text [mc "&Selection:"] -anchor sw]
|
||||
set ent [entry $selFrame.ent \
|
||||
-textvariable ::tk::dialog::color::[winfo name $w](selection) \
|
||||
-width 16]
|
||||
set f1 [frame $selFrame.f1 -relief sunken -bd 2]
|
||||
set data(finalCanvas) [frame $f1.demo -bd 0 -width 100 -height 70]
|
||||
|
||||
pack $lab $ent -side top -fill x -padx 4 -pady 2
|
||||
pack $f1 -expand yes -anchor nw -fill both -padx 6 -pady 10
|
||||
pack $data(finalCanvas) -expand yes -fill both
|
||||
|
||||
bind $ent <Return> [list tk::dialog::color::HandleSelEntry $w]
|
||||
|
||||
pack $selFrame -side left -fill none -anchor nw
|
||||
pack $topFrame -side top -expand yes -fill both -anchor nw
|
||||
|
||||
# the botFrame frame contains the buttons
|
||||
#
|
||||
set botFrame [frame $w.bot -relief raised -bd 1]
|
||||
|
||||
::tk::AmpWidget button $botFrame.ok -text [mc "&OK"] \
|
||||
-command [list tk::dialog::color::OkCmd $w]
|
||||
::tk::AmpWidget button $botFrame.cancel -text [mc "&Cancel"] \
|
||||
-command [list tk::dialog::color::CancelCmd $w]
|
||||
|
||||
set data(okBtn) $botFrame.ok
|
||||
set data(cancelBtn) $botFrame.cancel
|
||||
|
||||
grid x $botFrame.ok x $botFrame.cancel x -sticky ew
|
||||
grid configure $botFrame.ok $botFrame.cancel -padx 10 -pady 10
|
||||
grid columnconfigure $botFrame {0 4} -weight 1 -uniform space
|
||||
grid columnconfigure $botFrame {1 3} -weight 1 -uniform button
|
||||
grid columnconfigure $botFrame 2 -weight 2 -uniform space
|
||||
pack $botFrame -side bottom -fill x
|
||||
|
||||
# Accelerator bindings
|
||||
bind $lab <<AltUnderlined>> [list focus $ent]
|
||||
bind $w <KeyPress-Escape> [list tk::ButtonInvoke $data(cancelBtn)]
|
||||
bind $w <Alt-Key> [list tk::AltKeyInDialog $w %A]
|
||||
|
||||
wm protocol $w WM_DELETE_WINDOW [list tk::dialog::color::CancelCmd $w]
|
||||
bind $lab <Destroy> [list tk::dialog::color::CancelCmd $w]
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::SetRGBValue --
|
||||
#
|
||||
# Sets the current selection of the dialog box
|
||||
#
|
||||
proc ::tk::dialog::color::SetRGBValue {w color} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
set data(red,intensity) [lindex $color 0]
|
||||
set data(green,intensity) [lindex $color 1]
|
||||
set data(blue,intensity) [lindex $color 2]
|
||||
|
||||
RedrawColorBars $w all
|
||||
|
||||
# Now compute the new x value of each colorbars pointer polygon
|
||||
foreach color {red green blue} {
|
||||
set x [RgbToX $w $data($color,intensity)]
|
||||
MoveSelector $w $data($color,sel) $color $x 0
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::XToRgb --
|
||||
#
|
||||
# Converts a screen coordinate to intensity
|
||||
#
|
||||
proc ::tk::dialog::color::XToRgb {w x} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
set x [expr {($x * $data(intensityIncr))/ $data(colorbarWidth)}]
|
||||
if {$x > 255} {
|
||||
set x 255
|
||||
}
|
||||
return $x
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::RgbToX
|
||||
#
|
||||
# Converts an intensity to screen coordinate.
|
||||
#
|
||||
proc ::tk::dialog::color::RgbToX {w color} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
return [expr {($color * $data(colorbarWidth)/ $data(intensityIncr))}]
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::DrawColorScale --
|
||||
#
|
||||
# Draw color scale is called whenever the size of one of the color
|
||||
# scale canvases is changed.
|
||||
#
|
||||
proc ::tk::dialog::color::DrawColorScale {w c {create 0}} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
# col: color bar canvas
|
||||
# sel: selector canvas
|
||||
set col $data($c,col)
|
||||
set sel $data($c,sel)
|
||||
|
||||
# First handle the case that we are creating everything for the first time.
|
||||
if {$create} {
|
||||
# First remove all the lines that already exist.
|
||||
if { $data(lines,$c,last) > $data(lines,$c,start)} {
|
||||
for {set i $data(lines,$c,start)} \
|
||||
{$i <= $data(lines,$c,last)} {incr i} {
|
||||
$sel delete $i
|
||||
}
|
||||
}
|
||||
# Delete the selector if it exists
|
||||
if {[info exists data($c,index)]} {
|
||||
$sel delete $data($c,index)
|
||||
}
|
||||
|
||||
# Draw the selection polygons
|
||||
CreateSelector $w $sel $c
|
||||
$sel bind $data($c,index) <Button-1> \
|
||||
[list tk::dialog::color::StartMove $w $sel $c %x $data(selPad) 1]
|
||||
$sel bind $data($c,index) <B1-Motion> \
|
||||
[list tk::dialog::color::MoveSelector $w $sel $c %x $data(selPad)]
|
||||
$sel bind $data($c,index) <ButtonRelease-1> \
|
||||
[list tk::dialog::color::ReleaseMouse $w $sel $c %x $data(selPad)]
|
||||
|
||||
set height [winfo height $col]
|
||||
# Create an invisible region under the colorstrip to catch mouse clicks
|
||||
# that aren't on the selector.
|
||||
set data($c,clickRegion) [$sel create rectangle 0 0 \
|
||||
$data(canvasWidth) $height -fill {} -outline {}]
|
||||
|
||||
bind $col <Button-1> \
|
||||
[list tk::dialog::color::StartMove $w $sel $c %x $data(colorPad)]
|
||||
bind $col <B1-Motion> \
|
||||
[list tk::dialog::color::MoveSelector $w $sel $c %x $data(colorPad)]
|
||||
bind $col <ButtonRelease-1> \
|
||||
[list tk::dialog::color::ReleaseMouse $w $sel $c %x $data(colorPad)]
|
||||
|
||||
$sel bind $data($c,clickRegion) <Button-1> \
|
||||
[list tk::dialog::color::StartMove $w $sel $c %x $data(selPad)]
|
||||
$sel bind $data($c,clickRegion) <B1-Motion> \
|
||||
[list tk::dialog::color::MoveSelector $w $sel $c %x $data(selPad)]
|
||||
$sel bind $data($c,clickRegion) <ButtonRelease-1> \
|
||||
[list tk::dialog::color::ReleaseMouse $w $sel $c %x $data(selPad)]
|
||||
} else {
|
||||
# l is the canvas index of the first colorbar.
|
||||
set l $data(lines,$c,start)
|
||||
}
|
||||
|
||||
# Draw the color bars.
|
||||
set highlightW [expr {[$col cget -highlightthickness] + [$col cget -bd]}]
|
||||
for {set i 0} { $i < $data(NUM_COLORBARS)} { incr i} {
|
||||
set intensity [expr {$i * $data(intensityIncr)}]
|
||||
set startx [expr {$i * $data(colorbarWidth) + $highlightW}]
|
||||
if {$c eq "red"} {
|
||||
set color [format "#%02x%02x%02x" \
|
||||
$intensity $data(green,intensity) $data(blue,intensity)]
|
||||
} elseif {$c eq "green"} {
|
||||
set color [format "#%02x%02x%02x" \
|
||||
$data(red,intensity) $intensity $data(blue,intensity)]
|
||||
} else {
|
||||
set color [format "#%02x%02x%02x" \
|
||||
$data(red,intensity) $data(green,intensity) $intensity]
|
||||
}
|
||||
|
||||
if {$create} {
|
||||
set index [$col create rect $startx $highlightW \
|
||||
[expr {$startx +$data(colorbarWidth)}] \
|
||||
[expr {[winfo height $col] + $highlightW}] \
|
||||
-fill $color -outline $color]
|
||||
} else {
|
||||
$col itemconfigure $l -fill $color -outline $color
|
||||
incr l
|
||||
}
|
||||
}
|
||||
$sel raise $data($c,index)
|
||||
|
||||
if {$create} {
|
||||
set data(lines,$c,last) $index
|
||||
set data(lines,$c,start) [expr {$index - $data(NUM_COLORBARS) + 1}]
|
||||
}
|
||||
|
||||
RedrawFinalColor $w
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::CreateSelector --
|
||||
#
|
||||
# Creates and draws the selector polygon at the position
|
||||
# $data($c,intensity).
|
||||
#
|
||||
proc ::tk::dialog::color::CreateSelector {w sel c } {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
set data($c,index) [$sel create polygon \
|
||||
0 $data(PLGN_HEIGHT) \
|
||||
$data(PLGN_WIDTH) $data(PLGN_HEIGHT) \
|
||||
$data(indent) 0]
|
||||
set data($c,x) [RgbToX $w $data($c,intensity)]
|
||||
$sel move $data($c,index) $data($c,x) 0
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::RedrawFinalColor
|
||||
#
|
||||
# Combines the intensities of the three colors into the final color
|
||||
#
|
||||
proc ::tk::dialog::color::RedrawFinalColor {w} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
set color [format "#%02x%02x%02x" $data(red,intensity) \
|
||||
$data(green,intensity) $data(blue,intensity)]
|
||||
|
||||
$data(finalCanvas) configure -bg $color
|
||||
set data(finalColor) $color
|
||||
set data(selection) $color
|
||||
set data(finalRGB) [list \
|
||||
$data(red,intensity) \
|
||||
$data(green,intensity) \
|
||||
$data(blue,intensity)]
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::RedrawColorBars --
|
||||
#
|
||||
# Only redraws the colors on the color strips that were not manipulated.
|
||||
# Params: color of colorstrip that changed. If color is not [red|green|blue]
|
||||
# Then all colorstrips will be updated
|
||||
#
|
||||
proc ::tk::dialog::color::RedrawColorBars {w colorChanged} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
switch $colorChanged {
|
||||
red {
|
||||
DrawColorScale $w green
|
||||
DrawColorScale $w blue
|
||||
}
|
||||
green {
|
||||
DrawColorScale $w red
|
||||
DrawColorScale $w blue
|
||||
}
|
||||
blue {
|
||||
DrawColorScale $w red
|
||||
DrawColorScale $w green
|
||||
}
|
||||
default {
|
||||
DrawColorScale $w red
|
||||
DrawColorScale $w green
|
||||
DrawColorScale $w blue
|
||||
}
|
||||
}
|
||||
RedrawFinalColor $w
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Event handlers
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# ::tk::dialog::color::StartMove --
|
||||
#
|
||||
# Handles a mousedown button event over the selector polygon.
|
||||
# Adds the bindings for moving the mouse while the button is
|
||||
# pressed. Sets the binding for the button-release event.
|
||||
#
|
||||
# Params: sel is the selector canvas window, color is the color of the strip.
|
||||
#
|
||||
proc ::tk::dialog::color::StartMove {w sel color x delta {dontMove 0}} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
if {!$dontMove} {
|
||||
MoveSelector $w $sel $color $x $delta
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::MoveSelector --
|
||||
#
|
||||
# Moves the polygon selector so that its middle point has the same
|
||||
# x value as the specified x. If x is outside the bounds [0,255],
|
||||
# the selector is set to the closest endpoint.
|
||||
#
|
||||
# Params: sel is the selector canvas, c is [red|green|blue]
|
||||
# x is a x-coordinate.
|
||||
#
|
||||
proc ::tk::dialog::color::MoveSelector {w sel color x delta} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
incr x -$delta
|
||||
|
||||
if { $x < 0 } {
|
||||
set x 0
|
||||
} elseif { $x > $data(BARS_WIDTH)} {
|
||||
set x $data(BARS_WIDTH)
|
||||
}
|
||||
set diff [expr {$x - $data($color,x)}]
|
||||
$sel move $data($color,index) $diff 0
|
||||
set data($color,x) [expr {$data($color,x) + $diff}]
|
||||
|
||||
# Return the x value that it was actually set at
|
||||
return $x
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::ReleaseMouse
|
||||
#
|
||||
# Removes mouse tracking bindings, updates the colorbars.
|
||||
#
|
||||
# Params: sel is the selector canvas, color is the color of the strip,
|
||||
# x is the x-coord of the mouse.
|
||||
#
|
||||
proc ::tk::dialog::color::ReleaseMouse {w sel color x delta} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
set x [MoveSelector $w $sel $color $x $delta]
|
||||
|
||||
# Determine exactly what color we are looking at.
|
||||
set data($color,intensity) [XToRgb $w $x]
|
||||
|
||||
RedrawColorBars $w $color
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::ResizeColorbars --
|
||||
#
|
||||
# Completely redraws the colorbars, including resizing the
|
||||
# colorstrips
|
||||
#
|
||||
proc ::tk::dialog::color::ResizeColorBars {w} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
if {
|
||||
($data(BARS_WIDTH) < $data(NUM_COLORBARS)) ||
|
||||
(($data(BARS_WIDTH) % $data(NUM_COLORBARS)) != 0)
|
||||
} then {
|
||||
set data(BARS_WIDTH) $data(NUM_COLORBARS)
|
||||
}
|
||||
InitValues [winfo name $w]
|
||||
foreach color {red green blue} {
|
||||
$data($color,col) configure -width $data(canvasWidth)
|
||||
DrawColorScale $w $color 1
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::HandleSelEntry --
|
||||
#
|
||||
# Handles the return keypress event in the "Selection:" entry
|
||||
#
|
||||
proc ::tk::dialog::color::HandleSelEntry {w} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
set text [string trim $data(selection)]
|
||||
# Check to make sure that the color is valid
|
||||
if {[catch {set color [winfo rgb . $text]} ]} {
|
||||
set data(selection) $data(finalColor)
|
||||
return
|
||||
}
|
||||
|
||||
set R [expr {[lindex $color 0]/0x100}]
|
||||
set G [expr {[lindex $color 1]/0x100}]
|
||||
set B [expr {[lindex $color 2]/0x100}]
|
||||
|
||||
SetRGBValue $w "$R $G $B"
|
||||
set data(selection) $text
|
||||
}
|
||||
|
||||
# ::tk::dialog::color::HandleRGBEntry --
|
||||
#
|
||||
# Handles the return keypress event in the R, G or B entry
|
||||
#
|
||||
proc ::tk::dialog::color::HandleRGBEntry {w} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
foreach c {red green blue} {
|
||||
if {[catch {
|
||||
set data($c,intensity) [expr {int($data($c,intensity))}]
|
||||
}]} {
|
||||
set data($c,intensity) 0
|
||||
}
|
||||
|
||||
if {$data($c,intensity) < 0} {
|
||||
set data($c,intensity) 0
|
||||
}
|
||||
if {$data($c,intensity) > 255} {
|
||||
set data($c,intensity) 255
|
||||
}
|
||||
}
|
||||
|
||||
SetRGBValue $w "$data(red,intensity) \
|
||||
$data(green,intensity) $data(blue,intensity)"
|
||||
}
|
||||
|
||||
# mouse cursor enters a color bar
|
||||
#
|
||||
proc ::tk::dialog::color::EnterColorBar {w color} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
$data($color,sel) itemconfigure $data($color,index) -fill red
|
||||
}
|
||||
|
||||
# mouse leaves enters a color bar
|
||||
#
|
||||
proc ::tk::dialog::color::LeaveColorBar {w color} {
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
$data($color,sel) itemconfigure $data($color,index) -fill black
|
||||
}
|
||||
|
||||
# user hits OK button
|
||||
#
|
||||
proc ::tk::dialog::color::OkCmd {w} {
|
||||
variable ::tk::Priv
|
||||
upvar ::tk::dialog::color::[winfo name $w] data
|
||||
|
||||
set Priv(selectColor) $data(finalColor)
|
||||
}
|
||||
|
||||
# user hits Cancel button or destroys window
|
||||
#
|
||||
proc ::tk::dialog::color::CancelCmd {w} {
|
||||
variable ::tk::Priv
|
||||
set Priv(selectColor) ""
|
||||
}
|
||||
|
|
@ -0,0 +1,322 @@
|
|||
# comdlg.tcl --
|
||||
#
|
||||
# Some functions needed for the common dialog boxes. Probably need to go
|
||||
# in a different file.
|
||||
#
|
||||
# Copyright (c) 1996 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
# tclParseConfigSpec --
|
||||
#
|
||||
# Parses a list of "-option value" pairs. If all options and
|
||||
# values are legal, the values are stored in
|
||||
# $data($option). Otherwise an error message is returned. When
|
||||
# an error happens, the data() array may have been partially
|
||||
# modified, but all the modified members of the data(0 array are
|
||||
# guaranteed to have valid values. This is different than
|
||||
# Tk_ConfigureWidget() which does not modify the value of a
|
||||
# widget record if any error occurs.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# w = widget record to modify. Must be the pathname of a widget.
|
||||
#
|
||||
# specs = {
|
||||
# {-commandlineswitch resourceName ResourceClass defaultValue verifier}
|
||||
# {....}
|
||||
# }
|
||||
#
|
||||
# flags = a list of flags. Currently supported flags are:
|
||||
# DONTSETDEFAULTS = skip default values setting
|
||||
#
|
||||
# argList = The list of "-option value" pairs.
|
||||
#
|
||||
proc tclParseConfigSpec {w specs flags argList} {
|
||||
upvar #0 $w data
|
||||
|
||||
# 1: Put the specs in associative arrays for faster access
|
||||
#
|
||||
foreach spec $specs {
|
||||
if {[llength $spec] < 4} {
|
||||
return -code error -errorcode {TK VALUE CONFIG_SPEC} \
|
||||
"\"spec\" should contain 5 or 4 elements"
|
||||
}
|
||||
set cmdsw [lindex $spec 0]
|
||||
set cmd($cmdsw) ""
|
||||
set rname($cmdsw) [lindex $spec 1]
|
||||
set rclass($cmdsw) [lindex $spec 2]
|
||||
set def($cmdsw) [lindex $spec 3]
|
||||
set verproc($cmdsw) [lindex $spec 4]
|
||||
}
|
||||
|
||||
if {[llength $argList] & 1} {
|
||||
set cmdsw [lindex $argList end]
|
||||
if {![info exists cmd($cmdsw)]} {
|
||||
return -code error -errorcode [list TK LOOKUP OPTION $cmdsw] \
|
||||
"bad option \"$cmdsw\": must be [tclListValidFlags cmd]"
|
||||
}
|
||||
return -code error -errorcode {TK VALUE_MISSING} \
|
||||
"value for \"$cmdsw\" missing"
|
||||
}
|
||||
|
||||
# 2: set the default values
|
||||
#
|
||||
if {"DONTSETDEFAULTS" ni $flags} {
|
||||
foreach cmdsw [array names cmd] {
|
||||
set data($cmdsw) $def($cmdsw)
|
||||
}
|
||||
}
|
||||
|
||||
# 3: parse the argument list
|
||||
#
|
||||
foreach {cmdsw value} $argList {
|
||||
if {![info exists cmd($cmdsw)]} {
|
||||
return -code error -errorcode [list TK LOOKUP OPTION $cmdsw] \
|
||||
"bad option \"$cmdsw\": must be [tclListValidFlags cmd]"
|
||||
}
|
||||
set data($cmdsw) $value
|
||||
}
|
||||
|
||||
# Done!
|
||||
}
|
||||
|
||||
proc tclListValidFlags {v} {
|
||||
upvar $v cmd
|
||||
|
||||
set len [llength [array names cmd]]
|
||||
set i 1
|
||||
set separator ""
|
||||
set errormsg ""
|
||||
foreach cmdsw [lsort [array names cmd]] {
|
||||
append errormsg "$separator$cmdsw"
|
||||
incr i
|
||||
if {$i == $len} {
|
||||
set separator ", or "
|
||||
} else {
|
||||
set separator ", "
|
||||
}
|
||||
}
|
||||
return $errormsg
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
#
|
||||
# Focus Group
|
||||
#
|
||||
# Focus groups are used to handle the user's focusing actions inside a
|
||||
# toplevel.
|
||||
#
|
||||
# One example of using focus groups is: when the user focuses on an
|
||||
# entry, the text in the entry is highlighted and the cursor is put to
|
||||
# the end of the text. When the user changes focus to another widget,
|
||||
# the text in the previously focused entry is validated.
|
||||
#
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
|
||||
# ::tk::FocusGroup_Create --
|
||||
#
|
||||
# Create a focus group. All the widgets in a focus group must be
|
||||
# within the same focus toplevel. Each toplevel can have only
|
||||
# one focus group, which is identified by the name of the
|
||||
# toplevel widget.
|
||||
#
|
||||
proc ::tk::FocusGroup_Create {t} {
|
||||
variable ::tk::Priv
|
||||
if {[winfo toplevel $t] ne $t} {
|
||||
return -code error -errorcode [list TK LOOKUP TOPLEVEL $t] \
|
||||
"$t is not a toplevel window"
|
||||
}
|
||||
if {![info exists Priv(fg,$t)]} {
|
||||
set Priv(fg,$t) 1
|
||||
set Priv(focus,$t) ""
|
||||
bind $t <FocusIn> [list tk::FocusGroup_In $t %W %d]
|
||||
bind $t <FocusOut> [list tk::FocusGroup_Out $t %W %d]
|
||||
bind $t <Destroy> [list tk::FocusGroup_Destroy $t %W]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::FocusGroup_BindIn --
|
||||
#
|
||||
# Add a widget into the "FocusIn" list of the focus group. The $cmd will be
|
||||
# called when the widget is focused on by the user.
|
||||
#
|
||||
proc ::tk::FocusGroup_BindIn {t w cmd} {
|
||||
variable FocusIn
|
||||
variable ::tk::Priv
|
||||
if {![info exists Priv(fg,$t)]} {
|
||||
return -code error -errorcode [list TK LOOKUP FOCUS_GROUP $t] \
|
||||
"focus group \"$t\" doesn't exist"
|
||||
}
|
||||
set FocusIn($t,$w) $cmd
|
||||
}
|
||||
|
||||
|
||||
# ::tk::FocusGroup_BindOut --
|
||||
#
|
||||
# Add a widget into the "FocusOut" list of the focus group. The
|
||||
# $cmd will be called when the widget loses the focus (User
|
||||
# types Tab or click on another widget).
|
||||
#
|
||||
proc ::tk::FocusGroup_BindOut {t w cmd} {
|
||||
variable FocusOut
|
||||
variable ::tk::Priv
|
||||
if {![info exists Priv(fg,$t)]} {
|
||||
return -code error -errorcode [list TK LOOKUP FOCUS_GROUP $t] \
|
||||
"focus group \"$t\" doesn't exist"
|
||||
}
|
||||
set FocusOut($t,$w) $cmd
|
||||
}
|
||||
|
||||
# ::tk::FocusGroup_Destroy --
|
||||
#
|
||||
# Cleans up when members of the focus group is deleted, or when the
|
||||
# toplevel itself gets deleted.
|
||||
#
|
||||
proc ::tk::FocusGroup_Destroy {t w} {
|
||||
variable FocusIn
|
||||
variable FocusOut
|
||||
variable ::tk::Priv
|
||||
|
||||
if {$t eq $w} {
|
||||
unset Priv(fg,$t)
|
||||
unset Priv(focus,$t)
|
||||
|
||||
foreach name [array names FocusIn $t,*] {
|
||||
unset FocusIn($name)
|
||||
}
|
||||
foreach name [array names FocusOut $t,*] {
|
||||
unset FocusOut($name)
|
||||
}
|
||||
} else {
|
||||
if {[info exists Priv(focus,$t)] && ($Priv(focus,$t) eq $w)} {
|
||||
set Priv(focus,$t) ""
|
||||
}
|
||||
unset -nocomplain FocusIn($t,$w) FocusOut($t,$w)
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::FocusGroup_In --
|
||||
#
|
||||
# Handles the <FocusIn> event. Calls the FocusIn command for the newly
|
||||
# focused widget in the focus group.
|
||||
#
|
||||
proc ::tk::FocusGroup_In {t w detail} {
|
||||
variable FocusIn
|
||||
variable ::tk::Priv
|
||||
|
||||
if {$detail ne "NotifyNonlinear" && $detail ne "NotifyNonlinearVirtual"} {
|
||||
# This is caused by mouse moving out&in of the window *or*
|
||||
# ordinary keypresses some window managers (ie: CDE [Bug: 2960]).
|
||||
return
|
||||
}
|
||||
if {![info exists FocusIn($t,$w)]} {
|
||||
set FocusIn($t,$w) ""
|
||||
return
|
||||
}
|
||||
if {![info exists Priv(focus,$t)]} {
|
||||
return
|
||||
}
|
||||
if {$Priv(focus,$t) eq $w} {
|
||||
# This is already in focus
|
||||
#
|
||||
return
|
||||
} else {
|
||||
set Priv(focus,$t) $w
|
||||
eval $FocusIn($t,$w)
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::FocusGroup_Out --
|
||||
#
|
||||
# Handles the <FocusOut> event. Checks if this is really a lose
|
||||
# focus event, not one generated by the mouse moving out of the
|
||||
# toplevel window. Calls the FocusOut command for the widget
|
||||
# who loses its focus.
|
||||
#
|
||||
proc ::tk::FocusGroup_Out {t w detail} {
|
||||
variable FocusOut
|
||||
variable ::tk::Priv
|
||||
|
||||
if {$detail ne "NotifyNonlinear" && $detail ne "NotifyNonlinearVirtual"} {
|
||||
# This is caused by mouse moving out of the window
|
||||
return
|
||||
}
|
||||
if {![info exists Priv(focus,$t)]} {
|
||||
return
|
||||
}
|
||||
if {![info exists FocusOut($t,$w)]} {
|
||||
return
|
||||
} else {
|
||||
eval $FocusOut($t,$w)
|
||||
set Priv(focus,$t) ""
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::FDGetFileTypes --
|
||||
#
|
||||
# Process the string given by the -filetypes option of the file
|
||||
# dialogs. Similar to the C function TkGetFileFilters() on the Mac
|
||||
# and Windows platform.
|
||||
#
|
||||
proc ::tk::FDGetFileTypes {string} {
|
||||
foreach t $string {
|
||||
if {[llength $t] < 2 || [llength $t] > 3} {
|
||||
return -code error -errorcode {TK VALUE FILE_TYPE} \
|
||||
"bad file type \"$t\", should be \"typeName {extension ?extensions ...?} ?{macType ?macTypes ...?}?\""
|
||||
}
|
||||
lappend fileTypes([lindex $t 0]) {*}[lindex $t 1]
|
||||
}
|
||||
|
||||
set types {}
|
||||
foreach t $string {
|
||||
set label [lindex $t 0]
|
||||
set exts {}
|
||||
|
||||
if {[info exists hasDoneType($label)]} {
|
||||
continue
|
||||
}
|
||||
|
||||
# Validate each macType. This is to agree with the
|
||||
# behaviour of TkGetFileFilters(). This list may be
|
||||
# empty.
|
||||
foreach macType [lindex $t 2] {
|
||||
if {[string length $macType] != 4} {
|
||||
return -code error -errorcode {TK VALUE MAC_TYPE} \
|
||||
"bad Macintosh file type \"$macType\""
|
||||
}
|
||||
}
|
||||
|
||||
set name "$label \("
|
||||
set sep ""
|
||||
set doAppend 1
|
||||
foreach ext $fileTypes($label) {
|
||||
if {$ext eq ""} {
|
||||
continue
|
||||
}
|
||||
regsub {^[.]} $ext "*." ext
|
||||
if {![info exists hasGotExt($label,$ext)]} {
|
||||
if {$doAppend} {
|
||||
if {[string length $sep] && [string length $name]>40} {
|
||||
set doAppend 0
|
||||
append name $sep...
|
||||
} else {
|
||||
append name $sep$ext
|
||||
}
|
||||
}
|
||||
lappend exts $ext
|
||||
set hasGotExt($label,$ext) 1
|
||||
}
|
||||
set sep ","
|
||||
}
|
||||
append name "\)"
|
||||
lappend types [list $name $exts]
|
||||
|
||||
set hasDoneType($label) 1
|
||||
}
|
||||
|
||||
return $types
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,175 @@
|
|||
# dialog.tcl --
|
||||
#
|
||||
# This file defines the procedure tk_dialog, which creates a dialog
|
||||
# box containing a bitmap, a message, and one or more buttons.
|
||||
#
|
||||
# Copyright (c) 1992-1993 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1997 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
#
|
||||
# ::tk_dialog:
|
||||
#
|
||||
# This procedure displays a dialog box, waits for a button in the dialog
|
||||
# to be invoked, then returns the index of the selected button. If the
|
||||
# dialog somehow gets destroyed, -1 is returned.
|
||||
#
|
||||
# Arguments:
|
||||
# w - Window to use for dialog top-level.
|
||||
# title - Title to display in dialog's decorative frame.
|
||||
# text - Message to display in dialog.
|
||||
# bitmap - Bitmap to display in dialog (empty string means none).
|
||||
# default - Index of button that is to display the default ring
|
||||
# (-1 means none).
|
||||
# args - One or more strings to display in buttons across the
|
||||
# bottom of the dialog box.
|
||||
|
||||
proc ::tk_dialog {w title text bitmap default args} {
|
||||
variable ::tk::Priv
|
||||
|
||||
# Check that $default was properly given
|
||||
if {[string is integer -strict $default]} {
|
||||
if {$default >= [llength $args]} {
|
||||
return -code error -errorcode {TK DIALOG BAD_DEFAULT} \
|
||||
"default button index greater than number of buttons\
|
||||
specified for tk_dialog"
|
||||
}
|
||||
} elseif {"" eq $default} {
|
||||
set default -1
|
||||
} else {
|
||||
set default [lsearch -exact $args $default]
|
||||
}
|
||||
|
||||
set windowingsystem [tk windowingsystem]
|
||||
|
||||
# 1. Create the top-level window and divide it into top
|
||||
# and bottom parts.
|
||||
|
||||
destroy $w
|
||||
toplevel $w -class Dialog
|
||||
wm title $w $title
|
||||
wm iconname $w Dialog
|
||||
wm protocol $w WM_DELETE_WINDOW { }
|
||||
|
||||
# Dialog boxes should be transient with respect to their parent,
|
||||
# so that they will always stay on top of their parent window. However,
|
||||
# some window managers will create the window as withdrawn if the parent
|
||||
# window is withdrawn or iconified. Combined with the grab we put on the
|
||||
# window, this can hang the entire application. Therefore we only make
|
||||
# the dialog transient if the parent is viewable.
|
||||
#
|
||||
if {[winfo viewable [winfo toplevel [winfo parent $w]]] } {
|
||||
wm transient $w [winfo toplevel [winfo parent $w]]
|
||||
}
|
||||
|
||||
if {$windowingsystem eq "aqua"} {
|
||||
::tk::unsupported::MacWindowStyle style $w moveableModal {}
|
||||
} elseif {$windowingsystem eq "x11"} {
|
||||
wm attributes $w -type dialog
|
||||
}
|
||||
|
||||
frame $w.bot
|
||||
frame $w.top
|
||||
if {$windowingsystem eq "x11"} {
|
||||
$w.bot configure -relief raised -bd 1
|
||||
$w.top configure -relief raised -bd 1
|
||||
}
|
||||
pack $w.bot -side bottom -fill both
|
||||
pack $w.top -side top -fill both -expand 1
|
||||
grid anchor $w.bot center
|
||||
|
||||
# 2. Fill the top part with bitmap and message (use the option
|
||||
# database for -wraplength and -font so that they can be
|
||||
# overridden by the caller).
|
||||
|
||||
option add *Dialog.msg.wrapLength 3i widgetDefault
|
||||
option add *Dialog.msg.font TkCaptionFont widgetDefault
|
||||
|
||||
label $w.msg -justify left -text $text
|
||||
pack $w.msg -in $w.top -side right -expand 1 -fill both -padx 3m -pady 3m
|
||||
if {$bitmap ne ""} {
|
||||
if {$windowingsystem eq "aqua" && $bitmap eq "error"} {
|
||||
set bitmap "stop"
|
||||
}
|
||||
label $w.bitmap -bitmap $bitmap
|
||||
pack $w.bitmap -in $w.top -side left -padx 3m -pady 3m
|
||||
}
|
||||
|
||||
# 3. Create a row of buttons at the bottom of the dialog.
|
||||
|
||||
set i 0
|
||||
foreach but $args {
|
||||
button $w.button$i -text $but -command [list set ::tk::Priv(button) $i]
|
||||
if {$i == $default} {
|
||||
$w.button$i configure -default active
|
||||
} else {
|
||||
$w.button$i configure -default normal
|
||||
}
|
||||
grid $w.button$i -in $w.bot -column $i -row 0 -sticky ew \
|
||||
-padx 10 -pady 4
|
||||
grid columnconfigure $w.bot $i
|
||||
# We boost the size of some Mac buttons for l&f
|
||||
if {$windowingsystem eq "aqua"} {
|
||||
set tmp [string tolower $but]
|
||||
if {$tmp eq "ok" || $tmp eq "cancel"} {
|
||||
grid columnconfigure $w.bot $i -minsize 90
|
||||
}
|
||||
grid configure $w.button$i -pady 7
|
||||
}
|
||||
incr i
|
||||
}
|
||||
|
||||
# 4. Create a binding for <Return> on the dialog if there is a
|
||||
# default button.
|
||||
# Convention also dictates that if the keyboard focus moves among the
|
||||
# the buttons that the <Return> binding affects the button with the focus.
|
||||
|
||||
if {$default >= 0} {
|
||||
bind $w <Return> [list $w.button$default invoke]
|
||||
}
|
||||
bind $w <<PrevWindow>> [list bind $w <Return> {[tk_focusPrev %W] invoke}]
|
||||
bind $w <<NextWindow>> [list bind $w <Return> {[tk_focusNext %W] invoke}]
|
||||
|
||||
# 5. Create a <Destroy> binding for the window that sets the
|
||||
# button variable to -1; this is needed in case something happens
|
||||
# that destroys the window, such as its parent window being destroyed.
|
||||
|
||||
bind $w <Destroy> {set ::tk::Priv(button) -1}
|
||||
|
||||
# 6. Withdraw the window, then update all the geometry information
|
||||
# so we know how big it wants to be, then center the window in the
|
||||
# display (Motif style) and de-iconify it.
|
||||
|
||||
::tk::PlaceWindow $w
|
||||
tkwait visibility $w
|
||||
|
||||
# 7. Set a grab and claim the focus too.
|
||||
|
||||
if {$default >= 0} {
|
||||
set focus $w.button$default
|
||||
} else {
|
||||
set focus $w
|
||||
}
|
||||
tk::SetFocusGrab $w $focus
|
||||
|
||||
# 8. Wait for the user to respond, then restore the focus and
|
||||
# return the index of the selected button. Restore the focus
|
||||
# before deleting the window, since otherwise the window manager
|
||||
# may take the focus away so we can't redirect it. Finally,
|
||||
# restore any grab that was in effect.
|
||||
|
||||
vwait ::tk::Priv(button)
|
||||
|
||||
catch {
|
||||
# It's possible that the window has already been destroyed,
|
||||
# hence this "catch". Delete the Destroy handler so that
|
||||
# Priv(button) doesn't get reset by it.
|
||||
|
||||
bind $w <Destroy> {}
|
||||
}
|
||||
tk::RestoreFocusGrab $w $focus
|
||||
return $Priv(button)
|
||||
}
|
||||
|
|
@ -0,0 +1,686 @@
|
|||
# entry.tcl --
|
||||
#
|
||||
# This file defines the default bindings for Tk entry widgets and provides
|
||||
# procedures that help in implementing those bindings.
|
||||
#
|
||||
# Copyright (c) 1992-1994 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1997 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Elements of tk::Priv that are used in this file:
|
||||
#
|
||||
# afterId - If non-null, it means that auto-scanning is underway
|
||||
# and it gives the "after" id for the next auto-scan
|
||||
# command to be executed.
|
||||
# mouseMoved - Non-zero means the mouse has moved a significant
|
||||
# amount since the button went down (so, for example,
|
||||
# start dragging out a selection).
|
||||
# pressX - X-coordinate at which the mouse button was pressed.
|
||||
# selectMode - The style of selection currently underway:
|
||||
# char, word, or line.
|
||||
# x, y - Last known mouse coordinates for scanning
|
||||
# and auto-scanning.
|
||||
# data - Used for Cut and Copy
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The code below creates the default class bindings for entries.
|
||||
#-------------------------------------------------------------------------
|
||||
bind Entry <<Cut>> {
|
||||
if {![catch {tk::EntryGetSelection %W} tk::Priv(data)]} {
|
||||
clipboard clear -displayof %W
|
||||
clipboard append -displayof %W $tk::Priv(data)
|
||||
%W delete sel.first sel.last
|
||||
unset tk::Priv(data)
|
||||
}
|
||||
}
|
||||
bind Entry <<Copy>> {
|
||||
if {![catch {tk::EntryGetSelection %W} tk::Priv(data)]} {
|
||||
clipboard clear -displayof %W
|
||||
clipboard append -displayof %W $tk::Priv(data)
|
||||
unset tk::Priv(data)
|
||||
}
|
||||
}
|
||||
bind Entry <<Paste>> {
|
||||
catch {
|
||||
if {[tk windowingsystem] ne "x11"} {
|
||||
catch {
|
||||
%W delete sel.first sel.last
|
||||
}
|
||||
}
|
||||
%W insert insert [::tk::GetSelection %W CLIPBOARD]
|
||||
tk::EntrySeeInsert %W
|
||||
}
|
||||
}
|
||||
bind Entry <<Clear>> {
|
||||
# ignore if there is no selection
|
||||
catch {%W delete sel.first sel.last}
|
||||
}
|
||||
bind Entry <<PasteSelection>> {
|
||||
if {$tk_strictMotif || ![info exists tk::Priv(mouseMoved)]
|
||||
|| !$tk::Priv(mouseMoved)} {
|
||||
tk::EntryPaste %W %x
|
||||
}
|
||||
}
|
||||
|
||||
bind Entry <<TraverseIn>> {
|
||||
%W selection range 0 end
|
||||
%W icursor end
|
||||
}
|
||||
|
||||
# Standard Motif bindings:
|
||||
|
||||
bind Entry <Button-1> {
|
||||
tk::EntryButton1 %W %x
|
||||
%W selection clear
|
||||
}
|
||||
bind Entry <B1-Motion> {
|
||||
set tk::Priv(x) %x
|
||||
tk::EntryMouseSelect %W %x
|
||||
}
|
||||
bind Entry <Double-Button-1> {
|
||||
set tk::Priv(selectMode) word
|
||||
tk::EntryMouseSelect %W %x
|
||||
catch {%W icursor sel.last}
|
||||
}
|
||||
bind Entry <Triple-Button-1> {
|
||||
set tk::Priv(selectMode) line
|
||||
tk::EntryMouseSelect %W %x
|
||||
catch {%W icursor sel.last}
|
||||
}
|
||||
bind Entry <Shift-Button-1> {
|
||||
set tk::Priv(selectMode) char
|
||||
%W selection adjust @%x
|
||||
}
|
||||
bind Entry <Double-Shift-Button-1> {
|
||||
set tk::Priv(selectMode) word
|
||||
tk::EntryMouseSelect %W %x
|
||||
}
|
||||
bind Entry <Triple-Shift-Button-1> {
|
||||
set tk::Priv(selectMode) line
|
||||
tk::EntryMouseSelect %W %x
|
||||
}
|
||||
bind Entry <B1-Leave> {
|
||||
set tk::Priv(x) %x
|
||||
tk::EntryAutoScan %W
|
||||
}
|
||||
bind Entry <B1-Enter> {
|
||||
tk::CancelRepeat
|
||||
}
|
||||
bind Entry <ButtonRelease-1> {
|
||||
tk::CancelRepeat
|
||||
}
|
||||
bind Entry <Control-Button-1> {
|
||||
%W icursor @%x
|
||||
}
|
||||
|
||||
bind Entry <<PrevChar>> {
|
||||
tk::EntrySetCursor %W [expr {[%W index insert]-1}]
|
||||
}
|
||||
bind Entry <<NextChar>> {
|
||||
tk::EntrySetCursor %W [expr {[%W index insert]+1}]
|
||||
}
|
||||
bind Entry <<SelectPrevChar>> {
|
||||
tk::EntryKeySelect %W [expr {[%W index insert]-1}]
|
||||
tk::EntrySeeInsert %W
|
||||
}
|
||||
bind Entry <<SelectNextChar>> {
|
||||
tk::EntryKeySelect %W [expr {[%W index insert]+1}]
|
||||
tk::EntrySeeInsert %W
|
||||
}
|
||||
bind Entry <<PrevWord>> {
|
||||
tk::EntrySetCursor %W [tk::EntryPreviousWord %W insert]
|
||||
}
|
||||
bind Entry <<NextWord>> {
|
||||
tk::EntrySetCursor %W [tk::EntryNextWord %W insert]
|
||||
}
|
||||
bind Entry <<SelectPrevWord>> {
|
||||
tk::EntryKeySelect %W [tk::EntryPreviousWord %W insert]
|
||||
tk::EntrySeeInsert %W
|
||||
}
|
||||
bind Entry <<SelectNextWord>> {
|
||||
tk::EntryKeySelect %W [tk::EntryNextWord %W insert]
|
||||
tk::EntrySeeInsert %W
|
||||
}
|
||||
bind Entry <<LineStart>> {
|
||||
tk::EntrySetCursor %W 0
|
||||
}
|
||||
bind Entry <<SelectLineStart>> {
|
||||
tk::EntryKeySelect %W 0
|
||||
tk::EntrySeeInsert %W
|
||||
}
|
||||
bind Entry <<LineEnd>> {
|
||||
tk::EntrySetCursor %W end
|
||||
}
|
||||
bind Entry <<SelectLineEnd>> {
|
||||
tk::EntryKeySelect %W end
|
||||
tk::EntrySeeInsert %W
|
||||
}
|
||||
|
||||
bind Entry <Delete> {
|
||||
if {[%W selection present]} {
|
||||
%W delete sel.first sel.last
|
||||
} else {
|
||||
%W delete insert
|
||||
}
|
||||
}
|
||||
bind Entry <BackSpace> {
|
||||
tk::EntryBackspace %W
|
||||
}
|
||||
|
||||
bind Entry <Control-space> {
|
||||
%W selection from insert
|
||||
}
|
||||
bind Entry <Select> {
|
||||
%W selection from insert
|
||||
}
|
||||
bind Entry <Control-Shift-space> {
|
||||
%W selection adjust insert
|
||||
}
|
||||
bind Entry <Shift-Select> {
|
||||
%W selection adjust insert
|
||||
}
|
||||
bind Entry <<SelectAll>> {
|
||||
%W selection range 0 end
|
||||
}
|
||||
bind Entry <<SelectNone>> {
|
||||
%W selection clear
|
||||
}
|
||||
bind Entry <Key> {
|
||||
tk::CancelRepeat
|
||||
tk::EntryInsert %W %A
|
||||
}
|
||||
|
||||
# Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
|
||||
# Otherwise, if a widget binding for one of these is defined, the
|
||||
# <Key> class binding will also fire and insert the character,
|
||||
# which is wrong. Ditto for Escape, Return, and Tab.
|
||||
|
||||
bind Entry <Alt-Key> {# nothing}
|
||||
bind Entry <Meta-Key> {# nothing}
|
||||
bind Entry <Control-Key> {# nothing}
|
||||
bind Entry <Escape> {# nothing}
|
||||
bind Entry <Return> {# nothing}
|
||||
bind Entry <KP_Enter> {# nothing}
|
||||
bind Entry <Tab> {# nothing}
|
||||
bind Entry <Prior> {# nothing}
|
||||
bind Entry <Next> {# nothing}
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
bind Entry <Command-Key> {# nothing}
|
||||
}
|
||||
# Tk-on-Cocoa generates characters for these two keys. [Bug 2971663]
|
||||
bind Entry <<NextLine>> {# nothing}
|
||||
bind Entry <<PrevLine>> {# nothing}
|
||||
|
||||
# On Windows, paste is done using Shift-Insert. Shift-Insert already
|
||||
# generates the <<Paste>> event, so we don't need to do anything here.
|
||||
if {[tk windowingsystem] ne "win32"} {
|
||||
bind Entry <Insert> {
|
||||
catch {tk::EntryInsert %W [::tk::GetSelection %W PRIMARY]}
|
||||
}
|
||||
}
|
||||
|
||||
# Additional emacs-like bindings:
|
||||
|
||||
bind Entry <Control-d> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W delete insert
|
||||
}
|
||||
}
|
||||
bind Entry <Control-h> {
|
||||
if {!$tk_strictMotif} {
|
||||
tk::EntryBackspace %W
|
||||
}
|
||||
}
|
||||
bind Entry <Control-k> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W delete insert end
|
||||
}
|
||||
}
|
||||
bind Entry <Control-t> {
|
||||
if {!$tk_strictMotif} {
|
||||
tk::EntryTranspose %W
|
||||
}
|
||||
}
|
||||
bind Entry <Meta-b> {
|
||||
if {!$tk_strictMotif} {
|
||||
tk::EntrySetCursor %W [tk::EntryPreviousWord %W insert]
|
||||
}
|
||||
}
|
||||
bind Entry <Meta-d> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W delete insert [tk::EntryNextWord %W insert]
|
||||
}
|
||||
}
|
||||
bind Entry <Meta-f> {
|
||||
if {!$tk_strictMotif} {
|
||||
tk::EntrySetCursor %W [tk::EntryNextWord %W insert]
|
||||
}
|
||||
}
|
||||
bind Entry <Meta-BackSpace> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W delete [tk::EntryPreviousWord %W insert] insert
|
||||
}
|
||||
}
|
||||
bind Entry <Meta-Delete> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W delete [tk::EntryPreviousWord %W insert] insert
|
||||
}
|
||||
}
|
||||
|
||||
# Bindings for IME text input and accents.
|
||||
|
||||
bind Entry <<TkStartIMEMarkedText>> {
|
||||
dict set ::tk::Priv(IMETextMark) "%W" [%W index insert]
|
||||
}
|
||||
bind Entry <<TkEndIMEMarkedText>> {
|
||||
if {[catch {dict get $::tk::Priv(IMETextMark) "%W"} mark]} {
|
||||
bell
|
||||
} else {
|
||||
%W selection range $mark insert
|
||||
}
|
||||
}
|
||||
bind Entry <<TkClearIMEMarkedText>> {
|
||||
%W delete [dict get $::tk::Priv(IMETextMark) "%W"] [%W index insert]
|
||||
}
|
||||
bind Entry <<TkAccentBackspace>> {
|
||||
tk::EntryBackspace %W
|
||||
}
|
||||
|
||||
# A few additional bindings of my own.
|
||||
|
||||
if {[tk windowingsystem] ne "aqua"} {
|
||||
bind Entry <Button-2> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntryScanMark %W %x
|
||||
}
|
||||
}
|
||||
bind Entry <B2-Motion> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntryScanDrag %W %x
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bind Entry <Button-3> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntryScanMark %W %x
|
||||
}
|
||||
}
|
||||
bind Entry <B3-Motion> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntryScanDrag %W %x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::EntryClosestGap --
|
||||
# Given x and y coordinates, this procedure finds the closest boundary
|
||||
# between characters to the given coordinates and returns the index
|
||||
# of the character just after the boundary.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window.
|
||||
# x - X-coordinate within the window.
|
||||
|
||||
proc ::tk::EntryClosestGap {w x} {
|
||||
set pos [$w index @$x]
|
||||
set bbox [$w bbox $pos]
|
||||
if {($x - [lindex $bbox 0]) < ([lindex $bbox 2]/2)} {
|
||||
return $pos
|
||||
}
|
||||
incr pos
|
||||
}
|
||||
|
||||
# ::tk::EntryButton1 --
|
||||
# This procedure is invoked to handle button-1 presses in entry
|
||||
# widgets. It moves the insertion cursor, sets the selection anchor,
|
||||
# and claims the input focus.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window in which the button was pressed.
|
||||
# x - The x-coordinate of the button press.
|
||||
|
||||
proc ::tk::EntryButton1 {w x} {
|
||||
variable ::tk::Priv
|
||||
|
||||
set Priv(selectMode) char
|
||||
set Priv(mouseMoved) 0
|
||||
set Priv(pressX) $x
|
||||
$w icursor [EntryClosestGap $w $x]
|
||||
$w selection from insert
|
||||
if {"disabled" ne [$w cget -state]} {
|
||||
focus $w
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::EntryMouseSelect --
|
||||
# This procedure is invoked when dragging out a selection with
|
||||
# the mouse. Depending on the selection mode (character, word,
|
||||
# line) it selects in different-sized units. This procedure
|
||||
# ignores mouse motions initially until the mouse has moved from
|
||||
# one character to another or until there have been multiple clicks.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window in which the button was pressed.
|
||||
# x - The x-coordinate of the mouse.
|
||||
|
||||
proc ::tk::EntryMouseSelect {w x} {
|
||||
variable ::tk::Priv
|
||||
|
||||
set cur [EntryClosestGap $w $x]
|
||||
set anchor [$w index anchor]
|
||||
if {($cur != $anchor) || (abs($Priv(pressX) - $x) >= 3)} {
|
||||
set Priv(mouseMoved) 1
|
||||
}
|
||||
switch $Priv(selectMode) {
|
||||
char {
|
||||
if {$Priv(mouseMoved)} {
|
||||
if {$cur < $anchor} {
|
||||
$w selection range $cur $anchor
|
||||
} elseif {$cur > $anchor} {
|
||||
$w selection range $anchor $cur
|
||||
} else {
|
||||
$w selection clear
|
||||
}
|
||||
}
|
||||
}
|
||||
word {
|
||||
if {$cur < $anchor} {
|
||||
set before [tcl_wordBreakBefore [$w get] $cur]
|
||||
set after [tcl_wordBreakAfter [$w get] $anchor-1]
|
||||
} elseif {$cur > $anchor} {
|
||||
set before [tcl_wordBreakBefore [$w get] $anchor]
|
||||
set after [tcl_wordBreakAfter [$w get] $cur-1]
|
||||
} else {
|
||||
if {[$w index @$Priv(pressX)] < $anchor} {
|
||||
incr anchor -1
|
||||
}
|
||||
set before [tcl_wordBreakBefore [$w get] $anchor]
|
||||
set after [tcl_wordBreakAfter [$w get] $anchor]
|
||||
}
|
||||
if {$before < 0} {
|
||||
set before 0
|
||||
}
|
||||
if {$after < 0} {
|
||||
set after end
|
||||
}
|
||||
$w selection range $before $after
|
||||
}
|
||||
line {
|
||||
$w selection range 0 end
|
||||
}
|
||||
}
|
||||
if {$Priv(mouseMoved)} {
|
||||
$w icursor $cur
|
||||
}
|
||||
update idletasks
|
||||
}
|
||||
|
||||
# ::tk::EntryPaste --
|
||||
# This procedure sets the insertion cursor to the current mouse position,
|
||||
# pastes the selection there, and sets the focus to the window.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window.
|
||||
# x - X position of the mouse.
|
||||
|
||||
proc ::tk::EntryPaste {w x} {
|
||||
$w icursor [EntryClosestGap $w $x]
|
||||
catch {$w insert insert [::tk::GetSelection $w PRIMARY]}
|
||||
if {"disabled" ne [$w cget -state]} {
|
||||
focus $w
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::EntryAutoScan --
|
||||
# This procedure is invoked when the mouse leaves an entry window
|
||||
# with button 1 down. It scrolls the window left or right,
|
||||
# depending on where the mouse is, and reschedules itself as an
|
||||
# "after" command so that the window continues to scroll until the
|
||||
# mouse moves back into the window or the mouse button is released.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window.
|
||||
|
||||
proc ::tk::EntryAutoScan {w} {
|
||||
variable ::tk::Priv
|
||||
set x $Priv(x)
|
||||
if {![winfo exists $w]} {
|
||||
return
|
||||
}
|
||||
if {$x >= [winfo width $w]} {
|
||||
$w xview scroll 2 units
|
||||
EntryMouseSelect $w $x
|
||||
} elseif {$x < 0} {
|
||||
$w xview scroll -2 units
|
||||
EntryMouseSelect $w $x
|
||||
}
|
||||
set Priv(afterId) [after 50 [list tk::EntryAutoScan $w]]
|
||||
}
|
||||
|
||||
# ::tk::EntryKeySelect --
|
||||
# This procedure is invoked when stroking out selections using the
|
||||
# keyboard. It moves the cursor to a new position, then extends
|
||||
# the selection to that position.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window.
|
||||
# new - A new position for the insertion cursor (the cursor hasn't
|
||||
# actually been moved to this position yet).
|
||||
|
||||
proc ::tk::EntryKeySelect {w new} {
|
||||
if {![$w selection present]} {
|
||||
$w selection from insert
|
||||
$w selection to $new
|
||||
} else {
|
||||
$w selection adjust $new
|
||||
}
|
||||
$w icursor $new
|
||||
}
|
||||
|
||||
# ::tk::EntryInsert --
|
||||
# Insert a string into an entry at the point of the insertion cursor.
|
||||
# If there is a selection in the entry, and it covers the point of the
|
||||
# insertion cursor, then delete the selection before inserting.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window in which to insert the string
|
||||
# s - The string to insert (usually just a single character)
|
||||
|
||||
proc ::tk::EntryInsert {w s} {
|
||||
if {$s eq ""} {
|
||||
return
|
||||
}
|
||||
catch {
|
||||
set insert [$w index insert]
|
||||
if {([$w index sel.first] <= $insert)
|
||||
&& ([$w index sel.last] >= $insert)} {
|
||||
$w delete sel.first sel.last
|
||||
}
|
||||
}
|
||||
$w insert insert $s
|
||||
EntrySeeInsert $w
|
||||
}
|
||||
|
||||
# ::tk::EntryBackspace --
|
||||
# Backspace over the character just before the insertion cursor.
|
||||
# If backspacing would move the cursor off the left edge of the
|
||||
# window, reposition the cursor at about the middle of the window.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window in which to backspace.
|
||||
|
||||
proc ::tk::EntryBackspace w {
|
||||
if {[$w selection present]} {
|
||||
$w delete sel.first sel.last
|
||||
} else {
|
||||
set x [$w index insert]
|
||||
if {$x > 0} {
|
||||
$w delete [expr {$x-1}]
|
||||
}
|
||||
if {[$w index @0] >= [$w index insert]} {
|
||||
set range [$w xview]
|
||||
set left [lindex $range 0]
|
||||
set right [lindex $range 1]
|
||||
$w xview moveto [expr {$left - ($right - $left)/2.0}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::EntrySeeInsert --
|
||||
# Make sure that the insertion cursor is visible in the entry window.
|
||||
# If not, adjust the view so that it is.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window.
|
||||
|
||||
proc ::tk::EntrySeeInsert w {
|
||||
set c [$w index insert]
|
||||
if {($c < [$w index @0]) || ($c > [$w index @[winfo width $w]])} {
|
||||
$w xview $c
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::EntrySetCursor -
|
||||
# Move the insertion cursor to a given position in an entry. Also
|
||||
# clears the selection, if there is one in the entry, and makes sure
|
||||
# that the insertion cursor is visible.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window.
|
||||
# pos - The desired new position for the cursor in the window.
|
||||
|
||||
proc ::tk::EntrySetCursor {w pos} {
|
||||
$w icursor $pos
|
||||
$w selection clear
|
||||
EntrySeeInsert $w
|
||||
}
|
||||
|
||||
# ::tk::EntryTranspose -
|
||||
# This procedure implements the "transpose" function for entry widgets.
|
||||
# It tranposes the characters on either side of the insertion cursor,
|
||||
# unless the cursor is at the end of the line. In this case it
|
||||
# transposes the two characters to the left of the cursor. In either
|
||||
# case, the cursor ends up to the right of the transposed characters.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window.
|
||||
|
||||
proc ::tk::EntryTranspose w {
|
||||
set i [$w index insert]
|
||||
if {$i < [$w index end]} {
|
||||
incr i
|
||||
}
|
||||
if {$i < 2} {
|
||||
return
|
||||
}
|
||||
set first [expr {$i-2}]
|
||||
set data [$w get]
|
||||
set new [string index $data $i-1][string index $data $first]
|
||||
$w delete $first $i
|
||||
$w insert insert $new
|
||||
EntrySeeInsert $w
|
||||
}
|
||||
|
||||
# ::tk::EntryNextWord --
|
||||
# Returns the index of the next word position after a given position in the
|
||||
# entry. The next word is platform dependent and may be either the next
|
||||
# end-of-word position or the next start-of-word position after the next
|
||||
# end-of-word position.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window in which the cursor is to move.
|
||||
# start - Position at which to start search.
|
||||
|
||||
if {[tk windowingsystem] eq "win32"} {
|
||||
proc ::tk::EntryNextWord {w start} {
|
||||
set pos [tcl_endOfWord [$w get] [$w index $start]]
|
||||
if {$pos >= 0} {
|
||||
set pos [tcl_startOfNextWord [$w get] $pos]
|
||||
}
|
||||
if {$pos < 0} {
|
||||
return end
|
||||
}
|
||||
return $pos
|
||||
}
|
||||
} else {
|
||||
proc ::tk::EntryNextWord {w start} {
|
||||
set pos [tcl_endOfWord [$w get] [$w index $start]]
|
||||
if {$pos < 0} {
|
||||
return end
|
||||
}
|
||||
return $pos
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::EntryPreviousWord --
|
||||
#
|
||||
# Returns the index of the previous word position before a given
|
||||
# position in the entry.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window in which the cursor is to move.
|
||||
# start - Position at which to start search.
|
||||
|
||||
proc ::tk::EntryPreviousWord {w start} {
|
||||
set pos [tcl_startOfPreviousWord [$w get] [$w index $start]]
|
||||
if {$pos < 0} {
|
||||
return 0
|
||||
}
|
||||
return $pos
|
||||
}
|
||||
|
||||
# ::tk::EntryScanMark --
|
||||
#
|
||||
# Marks the start of a possible scan drag operation
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window from which the text to get
|
||||
# x - x location on screen
|
||||
|
||||
proc ::tk::EntryScanMark {w x} {
|
||||
$w scan mark $x
|
||||
set ::tk::Priv(x) $x
|
||||
set ::tk::Priv(y) 0 ; # not used
|
||||
set ::tk::Priv(mouseMoved) 0
|
||||
}
|
||||
|
||||
# ::tk::EntryScanDrag --
|
||||
#
|
||||
# Marks the start of a possible scan drag operation
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window from which the text to get
|
||||
# x - x location on screen
|
||||
|
||||
proc ::tk::EntryScanDrag {w x} {
|
||||
# Make sure these exist, as some weird situations can trigger the
|
||||
# motion binding without the initial press. [Bug #220269]
|
||||
if {![info exists ::tk::Priv(x)]} {set ::tk::Priv(x) $x}
|
||||
# allow for a delta
|
||||
if {abs($x-$::tk::Priv(x)) > 2} {
|
||||
set ::tk::Priv(mouseMoved) 1
|
||||
}
|
||||
$w scan dragto $x
|
||||
}
|
||||
|
||||
# ::tk::EntryGetSelection --
|
||||
#
|
||||
# Returns the selected text of the entry with respect to the -show option.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window from which the text to get
|
||||
|
||||
proc ::tk::EntryGetSelection {w} {
|
||||
set entryString [string range [$w get] [$w index sel.first] \
|
||||
[$w index sel.last]-1]
|
||||
if {[$w cget -show] ne ""} {
|
||||
return [string repeat [string index [$w cget -show] 0] \
|
||||
[string length $entryString]]
|
||||
}
|
||||
return $entryString
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
# focus.tcl --
|
||||
#
|
||||
# This file defines several procedures for managing the input
|
||||
# focus.
|
||||
#
|
||||
# Copyright (c) 1994-1995 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
# ::tk_focusNext --
|
||||
# This procedure returns the name of the next window after "w" in
|
||||
# "focus order" (the window that should receive the focus next if
|
||||
# Tab is typed in w). "Next" is defined by a pre-order search
|
||||
# of a top-level and its non-top-level descendants, with the stacking
|
||||
# order determining the order of siblings. The "-takefocus" options
|
||||
# on windows determine whether or not they should be skipped.
|
||||
#
|
||||
# Arguments:
|
||||
# w - Name of a window.
|
||||
|
||||
proc ::tk_focusNext w {
|
||||
set cur $w
|
||||
while {1} {
|
||||
|
||||
# Descend to just before the first child of the current widget.
|
||||
|
||||
set parent $cur
|
||||
set children [winfo children $cur]
|
||||
set i -1
|
||||
|
||||
# Look for the next sibling that isn't a top-level.
|
||||
|
||||
while {1} {
|
||||
incr i
|
||||
if {$i < [llength $children]} {
|
||||
set cur [lindex $children $i]
|
||||
if {[winfo toplevel $cur] eq $cur} {
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# No more siblings, so go to the current widget's parent.
|
||||
# If it's a top-level, break out of the loop, otherwise
|
||||
# look for its next sibling.
|
||||
|
||||
set cur $parent
|
||||
if {[winfo toplevel $cur] eq $cur} {
|
||||
break
|
||||
}
|
||||
set parent [winfo parent $parent]
|
||||
set children [winfo children $parent]
|
||||
set i [lsearch -exact $children $cur]
|
||||
}
|
||||
if {$w eq $cur || [tk::FocusOK $cur]} {
|
||||
return $cur
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk_focusPrev --
|
||||
# This procedure returns the name of the previous window before "w" in
|
||||
# "focus order" (the window that should receive the focus next if
|
||||
# Shift-Tab is typed in w). "Next" is defined by a pre-order search
|
||||
# of a top-level and its non-top-level descendants, with the stacking
|
||||
# order determining the order of siblings. The "-takefocus" options
|
||||
# on windows determine whether or not they should be skipped.
|
||||
#
|
||||
# Arguments:
|
||||
# w - Name of a window.
|
||||
|
||||
proc ::tk_focusPrev w {
|
||||
set cur $w
|
||||
while {1} {
|
||||
|
||||
# Collect information about the current window's position
|
||||
# among its siblings. Also, if the window is a top-level,
|
||||
# then reposition to just after the last child of the window.
|
||||
|
||||
if {[winfo toplevel $cur] eq $cur} {
|
||||
set parent $cur
|
||||
set children [winfo children $cur]
|
||||
set i [llength $children]
|
||||
} else {
|
||||
set parent [winfo parent $cur]
|
||||
set children [winfo children $parent]
|
||||
set i [lsearch -exact $children $cur]
|
||||
}
|
||||
|
||||
# Go to the previous sibling, then descend to its last descendant
|
||||
# (highest in stacking order. While doing this, ignore top-levels
|
||||
# and their descendants. When we run out of descendants, go up
|
||||
# one level to the parent.
|
||||
|
||||
while {$i > 0} {
|
||||
incr i -1
|
||||
set cur [lindex $children $i]
|
||||
if {[winfo toplevel $cur] eq $cur} {
|
||||
continue
|
||||
}
|
||||
set parent $cur
|
||||
set children [winfo children $parent]
|
||||
set i [llength $children]
|
||||
}
|
||||
set cur $parent
|
||||
if {$w eq $cur || [tk::FocusOK $cur]} {
|
||||
return $cur
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::FocusOK --
|
||||
#
|
||||
# This procedure is invoked to decide whether or not to focus on
|
||||
# a given window. It returns 1 if it's OK to focus on the window,
|
||||
# 0 if it's not OK. The code first checks whether the window is
|
||||
# viewable. If not, then it never focuses on the window. Then it
|
||||
# checks the -takefocus option for the window and uses it if it's
|
||||
# set. If there's no -takefocus option, the procedure checks to
|
||||
# see if (a) the widget isn't disabled, and (b) it has some key
|
||||
# bindings. If all of these are true, then 1 is returned.
|
||||
#
|
||||
# Arguments:
|
||||
# w - Name of a window.
|
||||
|
||||
proc ::tk::FocusOK w {
|
||||
set code [catch {$w cget -takefocus} value]
|
||||
if {($code == 0) && ($value ne "")} {
|
||||
if {$value == 0} {
|
||||
return 0
|
||||
} elseif {$value == 1} {
|
||||
return [winfo viewable $w]
|
||||
} else {
|
||||
set value [uplevel #0 $value [list $w]]
|
||||
if {$value ne ""} {
|
||||
return $value
|
||||
}
|
||||
}
|
||||
}
|
||||
if {![winfo viewable $w]} {
|
||||
return 0
|
||||
}
|
||||
set code [catch {$w cget -state} value]
|
||||
if {($code == 0) && $value eq "disabled"} {
|
||||
return 0
|
||||
}
|
||||
regexp Key|Focus "[bind $w] [bind [winfo class $w]]"
|
||||
}
|
||||
|
||||
# ::tk_focusFollowsMouse --
|
||||
#
|
||||
# If this procedure is invoked, Tk will enter "focus-follows-mouse"
|
||||
# mode, where the focus is always on whatever window contains the
|
||||
# mouse. If this procedure isn't invoked, then the user typically
|
||||
# has to click on a window to give it the focus.
|
||||
#
|
||||
# Arguments:
|
||||
# None.
|
||||
|
||||
proc ::tk_focusFollowsMouse {} {
|
||||
set old [bind all <Enter>]
|
||||
set script {
|
||||
if {"%d" eq "NotifyAncestor" || "%d" eq "NotifyNonlinear" \
|
||||
|| "%d" eq "NotifyInferior"} {
|
||||
if {[tk::FocusOK %W]} {
|
||||
focus %W
|
||||
}
|
||||
}
|
||||
}
|
||||
if {$old ne ""} {
|
||||
bind all <Enter> "$old; $script"
|
||||
} else {
|
||||
bind all <Enter> $script
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,455 @@
|
|||
# fontchooser.tcl -
|
||||
#
|
||||
# A themeable Tk font selection dialog. See TIP #324.
|
||||
#
|
||||
# Copyright (C) 2008 Keith Vetter
|
||||
# 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.
|
||||
|
||||
namespace eval ::tk::fontchooser {
|
||||
variable S
|
||||
|
||||
set S(W) .__tk__fontchooser
|
||||
set S(fonts) [lsort -dictionary [font families]]
|
||||
set S(styles) [list \
|
||||
[::msgcat::mc "Regular"] \
|
||||
[::msgcat::mc "Italic"] \
|
||||
[::msgcat::mc "Bold"] \
|
||||
[::msgcat::mc "Bold Italic"] \
|
||||
]
|
||||
|
||||
set S(sizes) {8 9 10 11 12 14 16 18 20 22 24 26 28 36 48 72}
|
||||
set S(strike) 0
|
||||
set S(under) 0
|
||||
set S(first) 1
|
||||
set S(sampletext) [::msgcat::mc "AaBbYyZz01"]
|
||||
set S(-parent) .
|
||||
set S(-title) [::msgcat::mc "Font"]
|
||||
set S(-command) ""
|
||||
set S(-font) TkDefaultFont
|
||||
}
|
||||
|
||||
proc ::tk::fontchooser::Setup {} {
|
||||
variable S
|
||||
|
||||
# Canonical versions of font families, styles, etc. for easier searching
|
||||
set S(fonts,lcase) {}
|
||||
foreach font $S(fonts) {lappend S(fonts,lcase) [string tolower $font]}
|
||||
set S(styles,lcase) {}
|
||||
foreach style $S(styles) {lappend S(styles,lcase) [string tolower $style]}
|
||||
set S(sizes,lcase) $S(sizes)
|
||||
|
||||
::ttk::style layout FontchooserFrame {
|
||||
Entry.field -sticky news -border true -children {
|
||||
FontchooserFrame.padding -sticky news
|
||||
}
|
||||
}
|
||||
bind [winfo class .] <<ThemeChanged>> \
|
||||
[list +ttk::style layout FontchooserFrame \
|
||||
[ttk::style layout FontchooserFrame]]
|
||||
|
||||
namespace ensemble create -map {
|
||||
show ::tk::fontchooser::Show
|
||||
hide ::tk::fontchooser::Hide
|
||||
configure ::tk::fontchooser::Configure
|
||||
}
|
||||
}
|
||||
::tk::fontchooser::Setup
|
||||
|
||||
proc ::tk::fontchooser::Show {} {
|
||||
variable S
|
||||
if {![winfo exists $S(W)]} {
|
||||
Create
|
||||
wm transient $S(W) [winfo toplevel $S(-parent)]
|
||||
tk::PlaceWindow $S(W) widget $S(-parent)
|
||||
}
|
||||
set S(fonts) [lsort -dictionary [font families]]
|
||||
set S(fonts,lcase) {}
|
||||
foreach font $S(fonts) { lappend S(fonts,lcase) [string tolower $font]}
|
||||
wm deiconify $S(W)
|
||||
}
|
||||
|
||||
proc ::tk::fontchooser::Hide {} {
|
||||
variable S
|
||||
wm withdraw $S(W)
|
||||
}
|
||||
|
||||
proc ::tk::fontchooser::Configure {args} {
|
||||
variable S
|
||||
|
||||
set specs {
|
||||
{-parent "" "" . }
|
||||
{-title "" "" ""}
|
||||
{-font "" "" ""}
|
||||
{-command "" "" ""}
|
||||
}
|
||||
|
||||
if {[llength $args] == 0} {
|
||||
set result {}
|
||||
foreach spec $specs {
|
||||
foreach {name xx yy default} $spec break
|
||||
lappend result $name \
|
||||
[expr {[info exists S($name)] ? $S($name) : $default}]
|
||||
}
|
||||
lappend result -visible \
|
||||
[expr {[winfo exists $S(W)] && [winfo ismapped $S(W)]}]
|
||||
return $result
|
||||
}
|
||||
if {[llength $args] == 1} {
|
||||
set option [lindex $args 0]
|
||||
if {[string equal $option "-visible"]} {
|
||||
return [expr {[winfo exists $S(W)] && [winfo ismapped $S(W)]}]
|
||||
} elseif {[info exists S($option)]} {
|
||||
return $S($option)
|
||||
}
|
||||
return -code error -errorcode [list TK LOOKUP OPTION $option] \
|
||||
"bad option \"$option\": must be\
|
||||
-command, -font, -parent, -title or -visible"
|
||||
}
|
||||
|
||||
set cache [dict create -parent $S(-parent) -title $S(-title) \
|
||||
-font $S(-font) -command $S(-command)]
|
||||
set r [tclParseConfigSpec [namespace which -variable S] $specs DONTSETDEFAULTS $args]
|
||||
if {![winfo exists $S(-parent)]} {
|
||||
set code [list TK LOOKUP WINDOW $S(-parent)]
|
||||
set err "bad window path name \"$S(-parent)\""
|
||||
array set S $cache
|
||||
return -code error -errorcode $code $err
|
||||
}
|
||||
if {[string trim $S(-title)] eq ""} {
|
||||
set S(-title) [::msgcat::mc "Font"]
|
||||
}
|
||||
if {[winfo exists $S(W)] && ("-font" in $args)} {
|
||||
Init $S(-font)
|
||||
event generate $S(-parent) <<TkFontchooserFontChanged>>
|
||||
}
|
||||
return $r
|
||||
}
|
||||
|
||||
proc ::tk::fontchooser::Create {} {
|
||||
variable S
|
||||
set windowName __tk__fontchooser
|
||||
if {$S(-parent) eq "."} {
|
||||
set S(W) .$windowName
|
||||
} else {
|
||||
set S(W) $S(-parent).$windowName
|
||||
}
|
||||
|
||||
# Now build the dialog
|
||||
if {![winfo exists $S(W)]} {
|
||||
toplevel $S(W) -class TkFontDialog
|
||||
if {[package provide tcltest] ne {}} {set ::tk_dialog $S(W)}
|
||||
wm withdraw $S(W)
|
||||
wm title $S(W) $S(-title)
|
||||
wm transient $S(W) [winfo toplevel $S(-parent)]
|
||||
|
||||
set scaling [tk scaling]
|
||||
set sizeWidth [expr {int([string length [::msgcat::mc "&Size:"]] * $scaling)}]
|
||||
|
||||
set outer [::ttk::frame $S(W).outer -padding {10 10}]
|
||||
::tk::AmpWidget ::ttk::label $S(W).font -text [::msgcat::mc "&Font:"]
|
||||
::tk::AmpWidget ::ttk::label $S(W).style -text [::msgcat::mc "Font st&yle:"]
|
||||
::tk::AmpWidget ::ttk::label $S(W).size -text [::msgcat::mc "&Size:"] -width $sizeWidth
|
||||
ttk::entry $S(W).efont -width 18 \
|
||||
-textvariable [namespace which -variable S](font)
|
||||
ttk::entry $S(W).estyle -width 10 \
|
||||
-textvariable [namespace which -variable S](style)
|
||||
ttk::entry $S(W).esize -textvariable [namespace which -variable S](size) \
|
||||
-width 3 -validate key -validatecommand {string is double %P}
|
||||
|
||||
ttk_slistbox $S(W).lfonts -height 7 -exportselection 0 \
|
||||
-selectmode browse -activestyle none \
|
||||
-listvariable [namespace which -variable S](fonts)
|
||||
ttk_slistbox $S(W).lstyles -width 5 -height 7 -exportselection 0 \
|
||||
-selectmode browse -activestyle none \
|
||||
-listvariable [namespace which -variable S](styles)
|
||||
ttk_slistbox $S(W).lsizes -width 4 -height 7 -exportselection 0 \
|
||||
-selectmode browse -activestyle none \
|
||||
-listvariable [namespace which -variable S](sizes)
|
||||
|
||||
set WE $S(W).effects
|
||||
::ttk::labelframe $WE -text [::msgcat::mc "Effects"]
|
||||
::tk::AmpWidget ::ttk::checkbutton $WE.strike \
|
||||
-variable [namespace which -variable S](strike) \
|
||||
-text [::msgcat::mc "Stri&keout"] \
|
||||
-command [namespace code [list Click strike]]
|
||||
::tk::AmpWidget ::ttk::checkbutton $WE.under \
|
||||
-variable [namespace which -variable S](under) \
|
||||
-text [::msgcat::mc "&Underline"] \
|
||||
-command [namespace code [list Click under]]
|
||||
|
||||
set bbox [::ttk::frame $S(W).bbox]
|
||||
::ttk::button $S(W).ok -text [::msgcat::mc OK] -default active\
|
||||
-command [namespace code [list Done 1]]
|
||||
::ttk::button $S(W).cancel -text [::msgcat::mc Cancel] \
|
||||
-command [namespace code [list Done 0]]
|
||||
::tk::AmpWidget ::ttk::button $S(W).apply -text [::msgcat::mc "&Apply"] \
|
||||
-command [namespace code [list Apply]]
|
||||
wm protocol $S(W) WM_DELETE_WINDOW [namespace code [list Done 0]]
|
||||
|
||||
# Calculate minimum sizes
|
||||
ttk::scrollbar $S(W).tmpvs
|
||||
set scroll_width [winfo reqwidth $S(W).tmpvs]
|
||||
destroy $S(W).tmpvs
|
||||
set minsize(gap) 10
|
||||
set minsize(bbox) [winfo reqwidth $S(W).ok]
|
||||
set minsize(fonts) \
|
||||
[expr {[font measure TkDefaultFont "Helvetica"] + $scroll_width}]
|
||||
set minsize(styles) \
|
||||
[expr {[font measure TkDefaultFont "Bold Italic"] + $scroll_width}]
|
||||
set minsize(sizes) \
|
||||
[expr {[font measure TkDefaultFont "-99"] + $scroll_width}]
|
||||
set min [expr {$minsize(gap) * 4}]
|
||||
foreach {what width} [array get minsize] {incr min $width}
|
||||
wm minsize $S(W) $min 260
|
||||
|
||||
bind $S(W) <Return> [namespace code [list Done 1]]
|
||||
bind $S(W) <Escape> [namespace code [list Done 0]]
|
||||
bind $S(W) <Map> [namespace code [list Visibility %W 1]]
|
||||
bind $S(W) <Unmap> [namespace code [list Visibility %W 0]]
|
||||
bind $S(W) <Destroy> [namespace code [list Visibility %W 0]]
|
||||
bind $S(W).lfonts.list <<ListboxSelect>> [namespace code [list Click font]]
|
||||
bind $S(W).lstyles.list <<ListboxSelect>> [namespace code [list Click style]]
|
||||
bind $S(W).lsizes.list <<ListboxSelect>> [namespace code [list Click size]]
|
||||
bind $S(W) <Alt-Key> [list ::tk::AltKeyInDialog $S(W) %A]
|
||||
bind $S(W).font <<AltUnderlined>> [list ::focus $S(W).efont]
|
||||
bind $S(W).style <<AltUnderlined>> [list ::focus $S(W).estyle]
|
||||
bind $S(W).size <<AltUnderlined>> [list ::focus $S(W).esize]
|
||||
bind $S(W).apply <<AltUnderlined>> [namespace code [list Apply]]
|
||||
bind $WE.strike <<AltUnderlined>> [list $WE.strike invoke]
|
||||
bind $WE.under <<AltUnderlined>> [list $WE.under invoke]
|
||||
|
||||
set WS $S(W).sample
|
||||
::ttk::labelframe $WS -text [::msgcat::mc "Sample"]
|
||||
::ttk::label $WS.sample -relief sunken -anchor center \
|
||||
-textvariable [namespace which -variable S](sampletext)
|
||||
set S(sample) $WS.sample
|
||||
grid $WS.sample -sticky news -padx 6 -pady 4
|
||||
grid rowconfigure $WS 0 -weight 1
|
||||
grid columnconfigure $WS 0 -weight 1
|
||||
grid propagate $WS 0
|
||||
|
||||
grid $S(W).ok -in $bbox -sticky new -pady {0 2}
|
||||
grid $S(W).cancel -in $bbox -sticky new -pady 2
|
||||
if {$S(-command) ne ""} {
|
||||
grid $S(W).apply -in $bbox -sticky new -pady 2
|
||||
}
|
||||
grid columnconfigure $bbox 0 -weight 1
|
||||
|
||||
grid $WE.strike -sticky w -padx 10
|
||||
grid $WE.under -sticky w -padx 10 -pady {0 30}
|
||||
grid columnconfigure $WE 1 -weight 1
|
||||
|
||||
grid $S(W).font x $S(W).style x $S(W).size x -in $outer -sticky w
|
||||
grid $S(W).efont x $S(W).estyle x $S(W).esize x $bbox -in $outer -sticky ew
|
||||
grid $S(W).lfonts x $S(W).lstyles x $S(W).lsizes x ^ -in $outer -sticky news
|
||||
grid $WE x $WS - - x ^ -in $outer -sticky news -pady {15 30}
|
||||
grid configure $bbox -sticky n
|
||||
grid columnconfigure $outer {1 3 5} -minsize $minsize(gap)
|
||||
grid columnconfigure $outer {0 2 4} -weight 1
|
||||
grid columnconfigure $outer 0 -minsize $minsize(fonts)
|
||||
grid columnconfigure $outer 2 -minsize $minsize(styles)
|
||||
grid columnconfigure $outer 4 -minsize $minsize(sizes)
|
||||
grid columnconfigure $outer 6 -minsize $minsize(bbox)
|
||||
|
||||
grid $outer -sticky news
|
||||
grid rowconfigure $S(W) 0 -weight 1
|
||||
grid columnconfigure $S(W) 0 -weight 1
|
||||
|
||||
Init $S(-font)
|
||||
|
||||
trace add variable [namespace which -variable S](size) \
|
||||
write [namespace code [list Tracer]]
|
||||
trace add variable [namespace which -variable S](style) \
|
||||
write [namespace code [list Tracer]]
|
||||
trace add variable [namespace which -variable S](font) \
|
||||
write [namespace code [list Tracer]]
|
||||
} else {
|
||||
Init $S(-font)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
# ::tk::fontchooser::Done --
|
||||
#
|
||||
# Handles teardown of the dialog, calling -command if needed
|
||||
#
|
||||
# Arguments:
|
||||
# ok true if user pressed OK
|
||||
#
|
||||
proc ::tk::fontchooser::Done {ok} {
|
||||
variable S
|
||||
|
||||
if {! $ok} {
|
||||
set S(result) ""
|
||||
}
|
||||
trace vdelete S(size) w [namespace code [list Tracer]]
|
||||
trace vdelete S(style) w [namespace code [list Tracer]]
|
||||
trace vdelete S(font) w [namespace code [list Tracer]]
|
||||
destroy $S(W)
|
||||
if {$ok && $S(-command) ne ""} {
|
||||
uplevel #0 $S(-command) [list $S(result)]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::fontchooser::Apply --
|
||||
#
|
||||
# Call the -command procedure appending the current font
|
||||
# Errors are reported via the background error mechanism
|
||||
#
|
||||
proc ::tk::fontchooser::Apply {} {
|
||||
variable S
|
||||
if {$S(-command) ne ""} {
|
||||
if {[catch {uplevel #0 $S(-command) [list $S(result)]} err]} {
|
||||
::bgerror $err
|
||||
}
|
||||
}
|
||||
event generate $S(-parent) <<TkFontchooserFontChanged>>
|
||||
}
|
||||
|
||||
# ::tk::fontchooser::Init --
|
||||
#
|
||||
# Initializes dialog to a default font
|
||||
#
|
||||
# Arguments:
|
||||
# defaultFont font to use as the default
|
||||
#
|
||||
proc ::tk::fontchooser::Init {{defaultFont ""}} {
|
||||
variable S
|
||||
|
||||
if {$S(first) || $defaultFont ne ""} {
|
||||
if {$defaultFont eq ""} {
|
||||
set defaultFont [[entry .___e] cget -font]
|
||||
destroy .___e
|
||||
}
|
||||
array set F [font actual $defaultFont]
|
||||
set S(font) $F(-family)
|
||||
set S(size) $F(-size)
|
||||
set S(strike) $F(-overstrike)
|
||||
set S(under) $F(-underline)
|
||||
set S(style) [::msgcat::mc "Regular"]
|
||||
if {$F(-weight) eq "bold" && $F(-slant) eq "italic"} {
|
||||
set S(style) [::msgcat::mc "Bold Italic"]
|
||||
} elseif {$F(-weight) eq "bold"} {
|
||||
set S(style) [::msgcat::mc "Bold"]
|
||||
} elseif {$F(-slant) eq "italic"} {
|
||||
set S(style) [::msgcat::mc "Italic"]
|
||||
}
|
||||
|
||||
set S(first) 0
|
||||
}
|
||||
|
||||
Tracer a b c
|
||||
Update
|
||||
}
|
||||
|
||||
# ::tk::fontchooser::Click --
|
||||
#
|
||||
# Handles all button clicks, updating the appropriate widgets
|
||||
#
|
||||
# Arguments:
|
||||
# who which widget got pressed
|
||||
#
|
||||
proc ::tk::fontchooser::Click {who} {
|
||||
variable S
|
||||
|
||||
if {$who eq "font"} {
|
||||
set S(font) [$S(W).lfonts get [$S(W).lfonts curselection]]
|
||||
} elseif {$who eq "style"} {
|
||||
set S(style) [$S(W).lstyles get [$S(W).lstyles curselection]]
|
||||
} elseif {$who eq "size"} {
|
||||
set S(size) [$S(W).lsizes get [$S(W).lsizes curselection]]
|
||||
}
|
||||
Update
|
||||
}
|
||||
|
||||
# ::tk::fontchooser::Tracer --
|
||||
#
|
||||
# Handles traces on key variables, updating the appropriate widgets
|
||||
#
|
||||
# Arguments:
|
||||
# standard trace arguments (not used)
|
||||
#
|
||||
proc ::tk::fontchooser::Tracer {var1 var2 op} {
|
||||
variable S
|
||||
|
||||
set bad 0
|
||||
set nstate normal
|
||||
# Make selection in each listbox
|
||||
foreach var {font style size} {
|
||||
set value [string tolower $S($var)]
|
||||
$S(W).l${var}s selection clear 0 end
|
||||
set n [lsearch -exact $S(${var}s,lcase) $value]
|
||||
$S(W).l${var}s selection set $n
|
||||
if {$n >= 0} {
|
||||
set S($var) [lindex $S(${var}s) $n]
|
||||
$S(W).e$var icursor end
|
||||
$S(W).e$var selection clear
|
||||
} else { ;# No match, try prefix
|
||||
# Size is weird: valid numbers are legal but don't display
|
||||
# unless in the font size list
|
||||
set n [lsearch -glob $S(${var}s,lcase) "$value*"]
|
||||
set bad 1
|
||||
if {$var ne "size" || ! [string is double -strict $value]} {
|
||||
set nstate disabled
|
||||
}
|
||||
}
|
||||
$S(W).l${var}s see $n
|
||||
}
|
||||
if {!$bad} {Update}
|
||||
$S(W).ok configure -state $nstate
|
||||
}
|
||||
|
||||
# ::tk::fontchooser::Update --
|
||||
#
|
||||
# Shows a sample of the currently selected font
|
||||
#
|
||||
proc ::tk::fontchooser::Update {} {
|
||||
variable S
|
||||
|
||||
set S(result) [list $S(font) $S(size)]
|
||||
if {$S(style) eq [::msgcat::mc "Bold"]} {lappend S(result) bold}
|
||||
if {$S(style) eq [::msgcat::mc "Italic"]} {lappend S(result) italic}
|
||||
if {$S(style) eq [::msgcat::mc "Bold Italic"]} {lappend S(result) bold italic}
|
||||
if {$S(strike)} {lappend S(result) overstrike}
|
||||
if {$S(under)} {lappend S(result) underline}
|
||||
|
||||
$S(sample) configure -font $S(result)
|
||||
}
|
||||
|
||||
# ::tk::fontchooser::Visibility --
|
||||
#
|
||||
# Notify the parent when the dialog visibility changes
|
||||
#
|
||||
proc ::tk::fontchooser::Visibility {w visible} {
|
||||
variable S
|
||||
if {$w eq $S(W)} {
|
||||
event generate $S(-parent) <<TkFontchooserVisibility>>
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::fontchooser::ttk_listbox --
|
||||
#
|
||||
# Create a properly themed scrolled listbox.
|
||||
# This is exactly right on XP but may need adjusting on other platforms.
|
||||
#
|
||||
proc ::tk::fontchooser::ttk_slistbox {w args} {
|
||||
set f [ttk::frame $w -style FontchooserFrame -padding 2]
|
||||
if {[catch {
|
||||
listbox $f.list -relief flat -highlightthickness 0 -borderwidth 0 {*}$args
|
||||
ttk::scrollbar $f.vs -command [list $f.list yview]
|
||||
$f.list configure -yscrollcommand [list $f.vs set]
|
||||
grid $f.list $f.vs -sticky news
|
||||
grid rowconfigure $f 0 -weight 1
|
||||
grid columnconfigure $f 0 -weight 1
|
||||
interp hide {} $w
|
||||
interp alias {} $w {} $f.list
|
||||
} err opt]} {
|
||||
destroy $f
|
||||
return -options $opt $err
|
||||
}
|
||||
return $w
|
||||
}
|
||||
|
|
@ -0,0 +1,717 @@
|
|||
# iconlist.tcl
|
||||
#
|
||||
# Implements the icon-list megawidget used in the "Tk" standard file
|
||||
# selection dialog boxes.
|
||||
#
|
||||
# Copyright (c) 1994-1998 Sun Microsystems, Inc.
|
||||
# Copyright (c) 2009 Donal K. Fellows
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution of
|
||||
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
# API Summary:
|
||||
# tk::IconList <path> ?<option> <value>? ...
|
||||
# <path> add <imageName> <itemList>
|
||||
# <path> cget <option>
|
||||
# <path> configure ?<option>? ?<value>? ...
|
||||
# <path> deleteall
|
||||
# <path> destroy
|
||||
# <path> get <itemIndex>
|
||||
# <path> index <index>
|
||||
# <path> invoke
|
||||
# <path> see <index>
|
||||
# <path> selection anchor ?<int>?
|
||||
# <path> selection clear <first> ?<last>?
|
||||
# <path> selection get
|
||||
# <path> selection includes <item>
|
||||
# <path> selection set <first> ?<last>?
|
||||
|
||||
package require Tk
|
||||
|
||||
::tk::Megawidget create ::tk::IconList ::tk::FocusableWidget {
|
||||
variable w canvas sbar accel accelCB fill font index \
|
||||
itemList itemsPerColumn list maxIH maxIW maxTH maxTW noScroll \
|
||||
numItems oldX oldY options rect selected selection textList
|
||||
constructor args {
|
||||
next {*}$args
|
||||
set accelCB {}
|
||||
}
|
||||
destructor {
|
||||
my Reset
|
||||
next
|
||||
}
|
||||
|
||||
method GetSpecs {} {
|
||||
concat [next] {
|
||||
{-command "" "" ""}
|
||||
{-font "" "" "TkIconFont"}
|
||||
{-multiple "" "" "0"}
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
method index i {
|
||||
if {![info exist list]} {
|
||||
set list {}
|
||||
}
|
||||
switch -regexp -- $i {
|
||||
"^-?[0-9]+$" {
|
||||
if {$i < 0} {
|
||||
set i 0
|
||||
}
|
||||
if {$i >= [llength $list]} {
|
||||
set i [expr {[llength $list] - 1}]
|
||||
}
|
||||
return $i
|
||||
}
|
||||
"^anchor$" {
|
||||
return $index(anchor)
|
||||
}
|
||||
"^end$" {
|
||||
return [llength $list]
|
||||
}
|
||||
"@-?[0-9]+,-?[0-9]+" {
|
||||
scan $i "@%d,%d" x y
|
||||
set item [$canvas find closest \
|
||||
[$canvas canvasx $x] [$canvas canvasy $y]]
|
||||
return [lindex [$canvas itemcget $item -tags] 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
method selection {op args} {
|
||||
switch -exact -- $op {
|
||||
anchor {
|
||||
if {[llength $args] == 1} {
|
||||
set index(anchor) [$w index [lindex $args 0]]
|
||||
} else {
|
||||
return $index(anchor)
|
||||
}
|
||||
}
|
||||
clear {
|
||||
switch [llength $args] {
|
||||
2 {
|
||||
lassign $args first last
|
||||
}
|
||||
1 {
|
||||
set first [set last [lindex $args 0]]
|
||||
}
|
||||
default {
|
||||
return -code error -errorcode {TCL WRONGARGS} \
|
||||
"wrong # args: should be\
|
||||
\"[lrange [info level 0] 0 1] first ?last?\""
|
||||
}
|
||||
}
|
||||
|
||||
set first [$w index $first]
|
||||
set last [$w index $last]
|
||||
if {$first > $last} {
|
||||
set tmp $first
|
||||
set first $last
|
||||
set last $tmp
|
||||
}
|
||||
set ind 0
|
||||
foreach item $selection {
|
||||
if {$item >= $first} {
|
||||
set first $ind
|
||||
break
|
||||
}
|
||||
incr ind
|
||||
}
|
||||
set ind [expr {[llength $selection] - 1}]
|
||||
for {} {$ind >= 0} {incr ind -1} {
|
||||
set item [lindex $selection $ind]
|
||||
if {$item <= $last} {
|
||||
set last $ind
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if {$first > $last} {
|
||||
return
|
||||
}
|
||||
set selection [lreplace $selection $first $last]
|
||||
event generate $w <<ListboxSelect>>
|
||||
my DrawSelection
|
||||
}
|
||||
get {
|
||||
return $selection
|
||||
}
|
||||
includes {
|
||||
return [expr {[lindex $args 0] in $selection}]
|
||||
}
|
||||
set {
|
||||
switch [llength $args] {
|
||||
2 {
|
||||
lassign $args first last
|
||||
}
|
||||
1 {
|
||||
set first [set last [lindex $args 0]]
|
||||
}
|
||||
default {
|
||||
return -code error -errorcode {TCL WRONGARGS} \
|
||||
"wrong # args: should be\
|
||||
\"[lrange [info level 0] 0 1] first ?last?\""
|
||||
}
|
||||
}
|
||||
|
||||
set first [$w index $first]
|
||||
set last [$w index $last]
|
||||
if {$first > $last} {
|
||||
set tmp $first
|
||||
set first $last
|
||||
set last $tmp
|
||||
}
|
||||
|
||||
for {set i $first} {$i <= $last} {incr i} {
|
||||
lappend selection $i
|
||||
}
|
||||
set selection [lsort -integer -unique $selection]
|
||||
event generate $w <<ListboxSelect>>
|
||||
my DrawSelection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
method get item {
|
||||
set rTag [lindex $list $item 2]
|
||||
lassign $itemList($rTag) iTag tTag text serial
|
||||
return $text
|
||||
}
|
||||
|
||||
# Deletes all the items inside the canvas subwidget and reset the
|
||||
# iconList's state.
|
||||
#
|
||||
method deleteall {} {
|
||||
$canvas delete all
|
||||
unset -nocomplain selected rect list itemList
|
||||
set maxIW 1
|
||||
set maxIH 1
|
||||
set maxTW 1
|
||||
set maxTH 1
|
||||
set numItems 0
|
||||
set noScroll 1
|
||||
set selection {}
|
||||
set index(anchor) ""
|
||||
$sbar set 0.0 1.0
|
||||
$canvas xview moveto 0
|
||||
}
|
||||
|
||||
# Adds an icon into the IconList with the designated image and text
|
||||
#
|
||||
method add {image items} {
|
||||
foreach text $items {
|
||||
set iID item$numItems
|
||||
set iTag [$canvas create image 0 0 -image $image -anchor nw \
|
||||
-tags [list icon $numItems $iID]]
|
||||
set tTag [$canvas create text 0 0 -text $text -anchor nw \
|
||||
-font $options(-font) -fill $fill \
|
||||
-tags [list text $numItems $iID]]
|
||||
set rTag [$canvas create rect 0 0 0 0 -fill "" -outline "" \
|
||||
-tags [list rect $numItems $iID]]
|
||||
|
||||
lassign [$canvas bbox $iTag] x1 y1 x2 y2
|
||||
set iW [expr {$x2 - $x1}]
|
||||
set iH [expr {$y2 - $y1}]
|
||||
if {$maxIW < $iW} {
|
||||
set maxIW $iW
|
||||
}
|
||||
if {$maxIH < $iH} {
|
||||
set maxIH $iH
|
||||
}
|
||||
|
||||
lassign [$canvas bbox $tTag] x1 y1 x2 y2
|
||||
set tW [expr {$x2 - $x1}]
|
||||
set tH [expr {$y2 - $y1}]
|
||||
if {$maxTW < $tW} {
|
||||
set maxTW $tW
|
||||
}
|
||||
if {$maxTH < $tH} {
|
||||
set maxTH $tH
|
||||
}
|
||||
|
||||
lappend list [list $iTag $tTag $rTag $iW $iH $tW $tH $numItems]
|
||||
set itemList($rTag) [list $iTag $tTag $text $numItems]
|
||||
set textList($numItems) [string tolower $text]
|
||||
incr numItems
|
||||
}
|
||||
my WhenIdle Arrange
|
||||
return
|
||||
}
|
||||
|
||||
# Gets called when the user invokes the IconList (usually by
|
||||
# double-clicking or pressing the Return key).
|
||||
#
|
||||
method invoke {} {
|
||||
if {$options(-command) ne "" && [llength $selection]} {
|
||||
uplevel #0 $options(-command)
|
||||
}
|
||||
}
|
||||
|
||||
# If the item is not (completely) visible, scroll the canvas so that it
|
||||
# becomes visible.
|
||||
#
|
||||
method see rTag {
|
||||
if {$noScroll} {
|
||||
return
|
||||
}
|
||||
set sRegion [$canvas cget -scrollregion]
|
||||
if {$sRegion eq ""} {
|
||||
return
|
||||
}
|
||||
|
||||
if {$rTag < 0 || $rTag >= [llength $list]} {
|
||||
return
|
||||
}
|
||||
|
||||
set bbox [$canvas bbox item$rTag]
|
||||
set pad [expr {[$canvas cget -highlightthickness]+[$canvas cget -bd]}]
|
||||
|
||||
set x1 [lindex $bbox 0]
|
||||
set x2 [lindex $bbox 2]
|
||||
incr x1 [expr {$pad * -2}]
|
||||
incr x2 [expr {$pad * -1}]
|
||||
|
||||
set cW [expr {[winfo width $canvas] - $pad*2}]
|
||||
|
||||
set scrollW [expr {[lindex $sRegion 2]-[lindex $sRegion 0]+1}]
|
||||
set dispX [expr {int([lindex [$canvas xview] 0]*$scrollW)}]
|
||||
set oldDispX $dispX
|
||||
|
||||
# check if out of the right edge
|
||||
#
|
||||
if {($x2 - $dispX) >= $cW} {
|
||||
set dispX [expr {$x2 - $cW}]
|
||||
}
|
||||
# check if out of the left edge
|
||||
#
|
||||
if {($x1 - $dispX) < 0} {
|
||||
set dispX $x1
|
||||
}
|
||||
|
||||
if {$oldDispX ne $dispX} {
|
||||
set fraction [expr {double($dispX) / double($scrollW)}]
|
||||
$canvas xview moveto $fraction
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# Places the icons in a column-major arrangement.
|
||||
#
|
||||
method Arrange {} {
|
||||
if {![info exists list]} {
|
||||
if {[info exists canvas] && [winfo exists $canvas]} {
|
||||
set noScroll 1
|
||||
$sbar configure -command ""
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
set W [winfo width $canvas]
|
||||
set H [winfo height $canvas]
|
||||
set pad [expr {[$canvas cget -highlightthickness]+[$canvas cget -bd]}]
|
||||
if {$pad < 2} {
|
||||
set pad 2
|
||||
}
|
||||
|
||||
incr W [expr {$pad*-2}]
|
||||
incr H [expr {$pad*-2}]
|
||||
|
||||
set dx [expr {$maxIW + $maxTW + 8}]
|
||||
if {$maxTH > $maxIH} {
|
||||
set dy $maxTH
|
||||
} else {
|
||||
set dy $maxIH
|
||||
}
|
||||
incr dy 2
|
||||
set shift [expr {$maxIW + 4}]
|
||||
|
||||
set x [expr {$pad * 2}]
|
||||
set y [expr {$pad * 1}] ; # Why * 1 ?
|
||||
set usedColumn 0
|
||||
foreach sublist $list {
|
||||
set usedColumn 1
|
||||
lassign $sublist iTag tTag rTag iW iH tW tH
|
||||
|
||||
set i_dy [expr {($dy - $iH)/2}]
|
||||
set t_dy [expr {($dy - $tH)/2}]
|
||||
|
||||
$canvas coords $iTag $x [expr {$y + $i_dy}]
|
||||
$canvas coords $tTag [expr {$x + $shift}] [expr {$y + $t_dy}]
|
||||
$canvas coords $rTag $x $y [expr {$x+$dx}] [expr {$y+$dy}]
|
||||
|
||||
incr y $dy
|
||||
if {($y + $dy) > $H} {
|
||||
set y [expr {$pad * 1}] ; # *1 ?
|
||||
incr x $dx
|
||||
set usedColumn 0
|
||||
}
|
||||
}
|
||||
|
||||
if {$usedColumn} {
|
||||
set sW [expr {$x + $dx}]
|
||||
} else {
|
||||
set sW $x
|
||||
}
|
||||
|
||||
if {$sW < $W} {
|
||||
$canvas configure -scrollregion [list $pad $pad $sW $H]
|
||||
$sbar configure -command ""
|
||||
$canvas xview moveto 0
|
||||
set noScroll 1
|
||||
} else {
|
||||
$canvas configure -scrollregion [list $pad $pad $sW $H]
|
||||
$sbar configure -command [list $canvas xview]
|
||||
set noScroll 0
|
||||
}
|
||||
|
||||
set itemsPerColumn [expr {($H-$pad) / $dy}]
|
||||
if {$itemsPerColumn < 1} {
|
||||
set itemsPerColumn 1
|
||||
}
|
||||
|
||||
my DrawSelection
|
||||
}
|
||||
|
||||
method DrawSelection {} {
|
||||
$canvas delete selection
|
||||
$canvas itemconfigure selectionText -fill black
|
||||
$canvas dtag selectionText
|
||||
set cbg [ttk::style lookup TEntry -selectbackground focus]
|
||||
set cfg [ttk::style lookup TEntry -selectforeground focus]
|
||||
foreach item $selection {
|
||||
set rTag [lindex $list $item 2]
|
||||
foreach {iTag tTag text serial} $itemList($rTag) {
|
||||
break
|
||||
}
|
||||
|
||||
set bbox [$canvas bbox $tTag]
|
||||
$canvas create rect $bbox -fill $cbg -outline $cbg \
|
||||
-tags selection
|
||||
$canvas itemconfigure $tTag -fill $cfg -tags selectionText
|
||||
}
|
||||
$canvas lower selection
|
||||
return
|
||||
}
|
||||
|
||||
# Creates an IconList widget by assembling a canvas widget and a
|
||||
# scrollbar widget. Sets all the bindings necessary for the IconList's
|
||||
# operations.
|
||||
#
|
||||
method Create {} {
|
||||
variable hull
|
||||
set sbar [ttk::scrollbar $hull.sbar -orient horizontal -takefocus 0]
|
||||
catch {$sbar configure -highlightthickness 0}
|
||||
set canvas [canvas $hull.canvas -highlightthick 0 -takefocus 1 \
|
||||
-width 400 -height 120 -background white]
|
||||
pack $sbar -side bottom -fill x -padx 2 -pady {0 2}
|
||||
pack $canvas -expand yes -fill both -padx 2 -pady {2 0}
|
||||
|
||||
$sbar configure -command [list $canvas xview]
|
||||
$canvas configure -xscrollcommand [list $sbar set]
|
||||
|
||||
# Initializes the max icon/text width and height and other variables
|
||||
#
|
||||
set maxIW 1
|
||||
set maxIH 1
|
||||
set maxTW 1
|
||||
set maxTH 1
|
||||
set numItems 0
|
||||
set noScroll 1
|
||||
set selection {}
|
||||
set index(anchor) ""
|
||||
set fg [option get $canvas foreground Foreground]
|
||||
if {$fg eq ""} {
|
||||
set fill black
|
||||
} else {
|
||||
set fill $fg
|
||||
}
|
||||
|
||||
# Creates the event bindings.
|
||||
#
|
||||
bind $canvas <Configure> [namespace code {my WhenIdle Arrange}]
|
||||
|
||||
bind $canvas <1> [namespace code {my Btn1 %x %y}]
|
||||
bind $canvas <B1-Motion> [namespace code {my Motion1 %x %y}]
|
||||
bind $canvas <B1-Leave> [namespace code {my Leave1 %x %y}]
|
||||
bind $canvas <Control-1> [namespace code {my CtrlBtn1 %x %y}]
|
||||
bind $canvas <Shift-1> [namespace code {my ShiftBtn1 %x %y}]
|
||||
bind $canvas <B1-Enter> [list tk::CancelRepeat]
|
||||
bind $canvas <ButtonRelease-1> [list tk::CancelRepeat]
|
||||
bind $canvas <Double-ButtonRelease-1> \
|
||||
[namespace code {my Double1 %x %y}]
|
||||
|
||||
bind $canvas <Control-B1-Motion> {;}
|
||||
bind $canvas <Shift-B1-Motion> [namespace code {my ShiftMotion1 %x %y}]
|
||||
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
bind $canvas <Shift-MouseWheel> [namespace code {my MouseWheel [expr {40 * (%D)}]}]
|
||||
bind $canvas <Option-Shift-MouseWheel> [namespace code {my MouseWheel [expr {400 * (%D)}]}]
|
||||
} else {
|
||||
bind $canvas <Shift-MouseWheel> [namespace code {my MouseWheel %D}]
|
||||
}
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
bind $canvas <Shift-4> [namespace code {my MouseWheel 120}]
|
||||
bind $canvas <Shift-5> [namespace code {my MouseWheel -120}]
|
||||
}
|
||||
|
||||
bind $canvas <<PrevLine>> [namespace code {my UpDown -1}]
|
||||
bind $canvas <<NextLine>> [namespace code {my UpDown 1}]
|
||||
bind $canvas <<PrevChar>> [namespace code {my LeftRight -1}]
|
||||
bind $canvas <<NextChar>> [namespace code {my LeftRight 1}]
|
||||
bind $canvas <Return> [namespace code {my ReturnKey}]
|
||||
bind $canvas <KeyPress> [namespace code {my KeyPress %A}]
|
||||
bind $canvas <Control-KeyPress> ";"
|
||||
bind $canvas <Alt-KeyPress> ";"
|
||||
|
||||
bind $canvas <FocusIn> [namespace code {my FocusIn}]
|
||||
bind $canvas <FocusOut> [namespace code {my FocusOut}]
|
||||
|
||||
return $w
|
||||
}
|
||||
|
||||
# This procedure is invoked when the mouse leaves an entry window with
|
||||
# button 1 down. It scrolls the window up, down, left, or right,
|
||||
# depending on where the mouse left the window, and reschedules itself
|
||||
# as an "after" command so that the window continues to scroll until the
|
||||
# mouse moves back into the window or the mouse button is released.
|
||||
#
|
||||
method AutoScan {} {
|
||||
if {![winfo exists $w]} return
|
||||
set x $oldX
|
||||
set y $oldY
|
||||
if {$noScroll} {
|
||||
return
|
||||
}
|
||||
if {$x >= [winfo width $canvas]} {
|
||||
$canvas xview scroll 1 units
|
||||
} elseif {$x < 0} {
|
||||
$canvas xview scroll -1 units
|
||||
} elseif {$y >= [winfo height $canvas]} {
|
||||
# do nothing
|
||||
} elseif {$y < 0} {
|
||||
# do nothing
|
||||
} else {
|
||||
return
|
||||
}
|
||||
my Motion1 $x $y
|
||||
set ::tk::Priv(afterId) [after 50 [namespace code {my AutoScan}]]
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# Event handlers
|
||||
method MouseWheel {amount} {
|
||||
if {$noScroll || $::tk_strictMotif} {
|
||||
return
|
||||
}
|
||||
if {$amount > 0} {
|
||||
$canvas xview scroll [expr {(-119-$amount) / 120}] units
|
||||
} else {
|
||||
$canvas xview scroll [expr {-($amount / 120)}] units
|
||||
}
|
||||
}
|
||||
method Btn1 {x y} {
|
||||
focus $canvas
|
||||
set i [$w index @$x,$y]
|
||||
if {$i eq ""} {
|
||||
return
|
||||
}
|
||||
$w selection clear 0 end
|
||||
$w selection set $i
|
||||
$w selection anchor $i
|
||||
}
|
||||
method CtrlBtn1 {x y} {
|
||||
if {$options(-multiple)} {
|
||||
focus $canvas
|
||||
set i [$w index @$x,$y]
|
||||
if {$i eq ""} {
|
||||
return
|
||||
}
|
||||
if {[$w selection includes $i]} {
|
||||
$w selection clear $i
|
||||
} else {
|
||||
$w selection set $i
|
||||
$w selection anchor $i
|
||||
}
|
||||
}
|
||||
}
|
||||
method ShiftBtn1 {x y} {
|
||||
if {$options(-multiple)} {
|
||||
focus $canvas
|
||||
set i [$w index @$x,$y]
|
||||
if {$i eq ""} {
|
||||
return
|
||||
}
|
||||
if {[$w index anchor] eq ""} {
|
||||
$w selection anchor $i
|
||||
}
|
||||
$w selection clear 0 end
|
||||
$w selection set anchor $i
|
||||
}
|
||||
}
|
||||
|
||||
# Gets called on button-1 motions
|
||||
#
|
||||
method Motion1 {x y} {
|
||||
set oldX $x
|
||||
set oldY $y
|
||||
set i [$w index @$x,$y]
|
||||
if {$i eq ""} {
|
||||
return
|
||||
}
|
||||
$w selection clear 0 end
|
||||
$w selection set $i
|
||||
}
|
||||
method ShiftMotion1 {x y} {
|
||||
set oldX $x
|
||||
set oldY $y
|
||||
set i [$w index @$x,$y]
|
||||
if {$i eq ""} {
|
||||
return
|
||||
}
|
||||
$w selection clear 0 end
|
||||
$w selection set anchor $i
|
||||
}
|
||||
method Double1 {x y} {
|
||||
if {[llength $selection]} {
|
||||
$w invoke
|
||||
}
|
||||
}
|
||||
method ReturnKey {} {
|
||||
$w invoke
|
||||
}
|
||||
method Leave1 {x y} {
|
||||
set oldX $x
|
||||
set oldY $y
|
||||
my AutoScan
|
||||
}
|
||||
method FocusIn {} {
|
||||
$w state focus
|
||||
if {![info exists list]} {
|
||||
return
|
||||
}
|
||||
if {[llength $selection]} {
|
||||
my DrawSelection
|
||||
}
|
||||
}
|
||||
method FocusOut {} {
|
||||
$w state !focus
|
||||
$w selection clear 0 end
|
||||
}
|
||||
|
||||
# Moves the active element up or down by one element
|
||||
#
|
||||
# Arguments:
|
||||
# amount - +1 to move down one item, -1 to move back one item.
|
||||
#
|
||||
method UpDown amount {
|
||||
if {![info exists list]} {
|
||||
return
|
||||
}
|
||||
set curr [$w selection get]
|
||||
if {[llength $curr] == 0} {
|
||||
set i 0
|
||||
} else {
|
||||
set i [$w index anchor]
|
||||
if {$i eq ""} {
|
||||
return
|
||||
}
|
||||
incr i $amount
|
||||
}
|
||||
$w selection clear 0 end
|
||||
$w selection set $i
|
||||
$w selection anchor $i
|
||||
$w see $i
|
||||
}
|
||||
|
||||
# Moves the active element left or right by one column
|
||||
#
|
||||
# Arguments:
|
||||
# amount - +1 to move right one column, -1 to move left one
|
||||
# column
|
||||
#
|
||||
method LeftRight amount {
|
||||
if {![info exists list]} {
|
||||
return
|
||||
}
|
||||
set curr [$w selection get]
|
||||
if {[llength $curr] == 0} {
|
||||
set i 0
|
||||
} else {
|
||||
set i [$w index anchor]
|
||||
if {$i eq ""} {
|
||||
return
|
||||
}
|
||||
incr i [expr {$amount * $itemsPerColumn}]
|
||||
}
|
||||
$w selection clear 0 end
|
||||
$w selection set $i
|
||||
$w selection anchor $i
|
||||
$w see $i
|
||||
}
|
||||
|
||||
# Gets called when user enters an arbitrary key in the listbox.
|
||||
#
|
||||
method KeyPress key {
|
||||
append accel $key
|
||||
my Goto $accel
|
||||
after cancel $accelCB
|
||||
set accelCB [after 500 [namespace code {my Reset}]]
|
||||
}
|
||||
|
||||
method Goto text {
|
||||
if {![info exists list]} {
|
||||
return
|
||||
}
|
||||
if {$text eq "" || $numItems == 0} {
|
||||
return
|
||||
}
|
||||
|
||||
if {[llength [$w selection get]]} {
|
||||
set start [$w index anchor]
|
||||
} else {
|
||||
set start 0
|
||||
}
|
||||
set theIndex -1
|
||||
set less 0
|
||||
set len [string length $text]
|
||||
set len0 [expr {$len - 1}]
|
||||
set i $start
|
||||
|
||||
# Search forward until we find a filename whose prefix is a
|
||||
# case-insensitive match with $text
|
||||
while {1} {
|
||||
if {[string equal -nocase -length $len0 $textList($i) $text]} {
|
||||
set theIndex $i
|
||||
break
|
||||
}
|
||||
incr i
|
||||
if {$i == $numItems} {
|
||||
set i 0
|
||||
}
|
||||
if {$i == $start} {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if {$theIndex >= 0} {
|
||||
$w selection clear 0 end
|
||||
$w selection set $theIndex
|
||||
$w selection anchor $theIndex
|
||||
$w see $theIndex
|
||||
}
|
||||
}
|
||||
method Reset {} {
|
||||
unset -nocomplain accel
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
# Local Variables:
|
||||
# mode: tcl
|
||||
# fill-column: 78
|
||||
# End:
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
# icons.tcl --
|
||||
#
|
||||
# A set of stock icons for use in Tk dialogs. The icons used here
|
||||
# were provided by the Tango Desktop project which provides a
|
||||
# unified set of high quality icons licensed under the
|
||||
# Creative Commons Attribution Share-Alike license
|
||||
# (http://creativecommons.org/licenses/by-sa/3.0/)
|
||||
#
|
||||
# See http://tango.freedesktop.org/Tango_Desktop_Project
|
||||
#
|
||||
# Copyright (c) 2009 Pat Thoyts <patthoyts@users.sourceforge.net>
|
||||
|
||||
namespace eval ::tk::icons {}
|
||||
|
||||
image create photo ::tk::icons::warning -data {
|
||||
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAABSZJREFU
|
||||
WIXll1toVEcYgL+Zc87u2Yu7MYmrWRuTJuvdiMuqiJd4yYKXgMQKVkSjFR80kFIVJfWCWlvpg4h9
|
||||
8sXGWGof8iKNICYSo6JgkCBEJRG8ImYThNrNxmaTeM7pQ5IlJkabi0/9YZhhZv7///4z/8zPgf+7
|
||||
KCNRLgdlJijXwRyuDTlcxV9hbzv8nQmxMjg+XDtiOEplkG9PSfkztGmTgmFQd+FCVzwa3fYN/PHZ
|
||||
AcpBaReicW5xcbb64IEQqko8Lc26d/58cxS+/BY6hmJvyEfQBoUpwWCmW1FErKaGWHU13uRk4QkE
|
||||
UtxQNFR7QwIoB4eiKD9PWbVKbb10CZmaCqmpxCormRYO26QQx85B0mcD+AeK0xYvHqu1tNDx+DH6
|
||||
gQM4jh0j3tCA3tGBLyfHLuD7zwJwAcYqun44sHy51nr5MsqsWWj5+djCYdS5c4ldvUr24sU2qarf
|
||||
lUL6qAN0wqH0vDy7+fAhXZEI+v79CNmt7igpofPVK5SmJvyhkJBwYlQBSiHd7vUWZ86bp8WqqtCW
|
||||
LkVbuBAhBEIItGAQ2+rVxG7cICMY1KTDsekc5IwagIQTmStXis47dzBiMfR9+xCi+wb39s79+zFi
|
||||
MczGRjLmzTMlnBoVgLMwyzF+/Cb/lClq2/Xr2AoKUKdPxzAMWltbiUajmKaJkpGBY8sW3tbW4g8E
|
||||
VNXrXVEKK0YMoMKp7Px8K15Tg2VZOHbvBiASiRAMBgkGg0QiEYQQOIuLsRSFrnv3yJo/HxVOW594
|
||||
7D4KUAa57qysvNSUFOVtbS32rVuRfj9CCFwuV2Kfy+VCCIFMScFVVET7/fukJidLm883rQy+HhaA
|
||||
BUII8cvUNWt4W1WFcLvRd+5MnHl/AOjOB+eOHchx44jX1ZEdCqkSTpaDbcgA5+GrpNmzc9ymKdvr
|
||||
67Hv2oVMSko4cjgcKIqCoijoup64EdLpxLV3Lx1PnuCVUrgmTfK9hV1DAjgKqlSUk1PCYdl25QrS
|
||||
70cvLEw4SWS+04nT6XxvXgiBc8MGtKlTaa+rIysnR1Ok/OF38PxngAzY4VuwYKL99WvR8fQpjj17
|
||||
kLqeiL6393g8eDyeAWBSVfEcOkRXczOOaBRvVpZuDPJEDwD4DVyKrv+UlZurxSorUWfMQC8oGOBc
|
||||
CDHgC/Rdc4TD2BctIl5fT+bkyTahaXvOw8RPApiwd2Ju7hjZ2EhXSwvOkhKQcoADgIqKCioqKgYc
|
||||
QW9LOnIEIxZDbWpiXCCABT9+FKAUxtm83pKMUEiLVVejLVqEtmTJB50LIdi2bRuFPbnRd7232efM
|
||||
wbVuHR2PHjHR77dJXS8sg5mDAihweFJenmrevYvR1oazpGTQ6IQQaJqG7ClI/dd655IOHsSyLMSL
|
||||
F6QFAib9nugEQClk2Xy+orTsbK3t1i3sa9ei5eQMGr0QgvLyci5evDiocyEEtsxMPNu30/nsGRO8
|
||||
XlVzu8NlkNvrV+0T/fHMZcusrtu3MeNx9PXrobUVq8cYQrw3TrRub1h9+v573Bs3Ej1zBvP5c/zp
|
||||
6dbLhoaTwPy+ANKCfF92thq7dg2A6JYt/fNlxGK8eUNSerryHEJHQT8K8V4A5ztojty8OeaLzZul
|
||||
1DSwLCzDANPEMozusWFgmWZ33288YK3/nGlixuM0v3xpWfDX0Z4i1VupXEWwIgRnJfhGPfQ+YsLr
|
||||
+7DzNFwCuvqWyiRg7DSYoIBu9smPkYqEd4AwIN4ITUAL0A4Da7UC6ICdEfy2fUBMoAvo7GnWKNoe
|
||||
mfwLcAuinuFNL7QAAAAASUVORK5CYII=
|
||||
}
|
||||
|
||||
image create photo ::tk::icons::error -data {
|
||||
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAABiRJREFU
|
||||
WIXFl11sHFcVgL97Z/bX693sbtd2ipOqCU7sQKukFYUigQgv/a+hoZGoqipvfQKpAsEDD0hIvCHE
|
||||
j/pQ3sIDUdOiIqUyqXioEFSUhqit7cRJFJpEruxs1mt77Z3d2Z259/KwM5vZXTtOERJXOrozZ+6e
|
||||
852fuXcW/s9D3O3Cs1Bow1Nx234BKQ9qpYpK6yFLSseScsVoveApdUrAzNOw9j8DOAMTtmX9RsM3
|
||||
SqOjevcXDqUzu8dI5AvEc8O0axu4q6s4yzdZvnCxUSmXLWHMXzxjXpmGq/81wGmIZ6T8NXDi8w8d
|
||||
id//+GPS8j1YWQXHgVYbfA/sGCRiMDQExTzKtvn3zDv6k9m5FsacXNT6+y+D95kAZqCEEO/cMzIy
|
||||
9eBLLybjyodrN6DpDqw1/dfpFNw3TtuSfPz7P7irlZUL2pjHn4GVuwJ4G/JCiLl9U1OjB58/ZnP5
|
||||
Mqxv3NGpMWZAz64cHNzHlTf/5N9YuHzTMeaLx6HW78+K3pwGKynEu/snJycOHPuWzdw81BuDUQZO
|
||||
dfQ+MmvAuC1MdY3i178izUo15VZXj07DyTf6OGX0Jivlz0vFwgMTz3/bNnMXO0ZCo8b0iIk4C0WF
|
||||
zsP1TRc1e4l9x56N5YuFwxkpf9afgW4J/gi7M1IuHH3lezm5uAQbmwOpjc79ujArA2uMgWwGMz7K
|
||||
P377u/WW1pPTUB7IQFrKXx44NJWRbQ9d2+hGqbeRMEoTZEQFJdERfVgmvVFH+D57Jw9k4lL+YqAE
|
||||
pyGnjZm+95knLHVjcVvHA6WIPgtLE+hVH4i6vsS9T3zTVsY8NwPZHoAUPFUs5JVQCt1q9zqORKm3
|
||||
iLKrF6IjkfSHOiUlqu0hhCSXHdYePNYDEBPiu6MT+zOquo6JGNGhESkxUnYNmkCnLQtjWRgpMRG9
|
||||
CtZ3JdD7axsU9+3N2EK8EALYQcNMpvfuQTcaXUMIAa+/Hi0Xgs9weASjefx4p5mFQDdbpD63G/HR
|
||||
hakeAA2l+EgJU652iIMMyO2sRoYxBq1191oIgZQSITqooT0A7fnEirswUAp/LwG0MZlYIY9WqpPa
|
||||
IHU7Da01Sqluo4UQSil830dr3emVsBeMIZbLoI0Z7gGQQtTbjoOOxW/XewcApVQ38jsBNs6fx6tW
|
||||
O70Si+GWKwghNsM1NoCAW81KJTeUjKNbrR2N7uS4B7TRwJ+fR6TTxO4fxzUeAio9AMCl+tVrE0NH
|
||||
DmM2nU4DAu6JE53UGoNfLuNdv45xnO4OF/ZKz+4X2T179I6D5To0NupouNgD4Btzqjx/8WjpS0cy
|
||||
PU1Tr6MqFfylpc4bss1W26/rBwyfybECtcvXNrUxp3oAXJjZ2Kxb7cVP8P61gDGgWy2M624Z5d1E
|
||||
3wNkDDKdwMQkjtuygbMhgAQ4DjUhxFvL/5z15X1jeLUaynW7p1u484WiuL3V9m/NoV6F50Ogjx3Y
|
||||
Q/mDBV8a3piGzR4AAFfrHy4vlesmm0bks7edRQ6aAafcPoZVH2AUXOYzkI5TvbVa9+FHREYX4Bgs
|
||||
I8RrV9/9oJF4eBKTjO8YvdoCJgqujcGkEqQemmDxb7OOFOLV6FHcAwBQ1/onTtOd/fTvH3rJRx/A
|
||||
pBIDqd0q+p5sRaInnWDoywdZem+u7bbaH9W1/il9Y2Brfwt22TBfKOVHxr92JOacv4S/UuttuC06
|
||||
PKoHsEs5hg7vZ/m9eW+zWltuwoNbfRNuebacgXsEnE2lkof2Hn04ZRouzQvXUU5z29cwFGs4TWpy
|
||||
HJGK8+lfP256bnuuDU8+B9WtfG17uL0GsTF4VQrxYn60kBh55JDEbdG6uYq/7qDdFtpTELOQyQRW
|
||||
Lk1sLI+MW9w6d8Wv3Vrz2nDyJPzgDDS287MVgAAywBCQ+Q5MTsOPs/BIMpVQ2bFCKlnMYg+nsYeS
|
||||
eE6TVq1Be3WD9ZtrTc9tWetw7k341dtwBagDTmTeESAdAAxH5z0w9iQ8ehi+moWxBGRsiPvguVBf
|
||||
h8qH8P6f4dxSp9PrdN73cN6k859R3U0J0nS+28JMpIM5FUgCiNP5X2ECox7gAk06KQ8ldLzZ7/xO
|
||||
ANHnscBhCkgGjuOB3gb8CEAbaAWO3UA34DQ6/gPnmhBFs5mqXAAAAABJRU5ErkJggg==
|
||||
}
|
||||
|
||||
image create photo ::tk::icons::information -data {
|
||||
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBI
|
||||
WXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1gUdFDM4pWaDogAABwNJREFUWMPFlltsVNcVhv+199ln
|
||||
bh7PjAdfMGNDcA04EKMkJlIsBVJVbRqlEVUrqyW0QAtFTVWpjVpFfamUF6K+tCTKQyXn0jaiShOr
|
||||
bRqRoHJpEEoIEBucENuk2OViPB5f5j5zrvuc3YcMFQ8FPBFVj7S0paN91v+tf1/OAv7PD9UzeeCp
|
||||
p0KRCrYyHtymoPrgySYAANdyBBr2Peu1agP+NrR/v3nHAb6/52d7wfivWlet11NdvZG21laEwzo0
|
||||
RvA9F4uLi7h08bxxaWLUVp78xSsv/XrwjgAMDDyjRxPWUGOy5Uu9/VsjEA3I5KvIVQ240gHIh9CA
|
||||
5YkwelIJRATw94NvGpnpK0fL+eDA0NAzzq3ya7cDjCbsoWWr1j+y4f4vB/41Z8JTeaxqE7hndSNi
|
||||
EeELzn3LkapQdfzJTE5JV/GBb28LHz327lcnzp4ZAvB1AOpmAvyWtv/g6R9GW1c+uf6Bx0Kfzpjo
|
||||
TmnYtDaKtkTAj4aEFBqTnJPUOfciIeG3N4XVQtmyzl/JuY8/fH9wOjO/smvVmuy5s+8P1w2wa9dP
|
||||
46SLN3sf2ha7uiixaU0Qna06NA6PMXIZQRJBMiIXRBKABygv3hBQV+bK1dmcoR7d3Bc5c/pk/8YN
|
||||
fYOjo6es/6bDbgbAdLa9uXNj2PYF2pOEloQGAiRIuUTkME42J7IZweYES+NkckZWWNfseEPAKJtO
|
||||
oWxLu69/c5jpbPtNdW7qPwvsbO1cF8pVLKxs0+HD94gpl0AOQTlEsDkjizFmMk4WESyNM4NzMgOC
|
||||
VYI6q17OlIp9992ngek769+EvtfVEI3jWqaKgAgAIAlFLuOwGZHDiTnElGQgF4DvM1LKV7Bdz2NE
|
||||
xaCuhQpVm1Y0p5qhvNV1AyjlRTWhwVM2TMdzgkJzieAQyGGMbMZgfwZBEiBPA3xX+VSouAvBAFeM
|
||||
yDddD7rgpHw/WjcAMa0EZScZk5heqFrxiO4BzCGCzYgsBrI4I5sYcxlBKl/5WdOdd6S0gxoLEZEi
|
||||
Iq4AnzGq1r0HiPhYuZRFU1R3FgqWkS1aZQA2gWzOyGQcJudkaAwVR3qz8yXzvCXlzJoViaagrlWC
|
||||
jJnLm8Jarli2GNMm6wbwPPO31y6Ollc2N3pcI+fyYjW/8a5EKqQTz5WtdLHsTi1W7Im5vDlcMdxx
|
||||
wVk2Ys9/pTI3+WhAaIauM+MLbYnlH46MVKVyX6v7Hhg9e2ps3doN32ld0Rlrb1nmmK4stCdCSCUj
|
||||
Le1NwW6uXJ08m/t2OarBXh0ie0syHu0plKtTFGw8n4o33q1z1XngD7+X3C/uHBkZces7hoAi1946
|
||||
fPSvtpDlYFdLPDI8mR03HC87frXwFpgqLYuFuzrbkg8m49EeDsqDa+cizXcNpppia5ui+sYXnn+O
|
||||
29LbOTg4aHzun9GOPT/pDemhf3xzx25DicjkiqaAIs4zhumMRUJaPhzgJZ0LQ5C7gXjQL1kS0YD+
|
||||
o337nhWlYvHJV178zZ9vlZ/dDuDVl57/2HWt755894hINoYSmZx11TYKCUZKCs4cnQuDmGtfvDiR
|
||||
dD3n04aA6J4YHzeLhfLg7cSXBAAA5NPpufS1WFjwkFSelZ6ZLWfn0kliTDJdue8dO9qenp2d1DVR
|
||||
4cTarlyZJgV5dim5lwTw8sv7c1L6H89cm6FlDcHVhlOJffThsa9d+ud72y5+cnTn2PjJJ1avjOoE
|
||||
SnBiPadOfRDTGT5YSm5tqR2R7Zp7//L6gRPf27NjVaolqS9MCzh28W6mgDXdKxCNRb/oOlV18O3D
|
||||
1xzXGXpx8LnZO94Tbt/x+MFYouexh7dsQU/PWjRGI+BcAyMgm1vAO28fxvj4xOX5jL7u0KEX7Dvq
|
||||
AAC0Nucf2rLZhq8Y3njjT8gulOBKDw0NAQjNQT435eQWL3iHDk3YS81ZF0B6psI/GbuAXbu+gQf7
|
||||
H4ArPeQWC5jLZKCUhQvjWb2QD3bVk5PVM9nz5LML8waOH38fekBHIhFDqqMFXd0pnDhxGmMTU3Bd
|
||||
9/X/GQDntO/eezswMPBjaFwAABxH4sKFq+jt7cX6ni6EQuJbdeWsZ3J3d/PTmqaEYUyhXDZBTEOh
|
||||
WIIQwOi5jzA1eRnZXPFSPO7/bmbGlLfqhus5BVotRH9/x7rGxtBeIQJPACrMOYNSPpRiUIpnlTIO
|
||||
nzmT+eX8fLH8WZMKF4Csje7ncUAHEKhFcHq6ZE5OZoc7O3tlc3N33+7dP9c2bXoE09NlO52uHDhy
|
||||
ZOTVatUWte+otsTXg2pQSwagG6r/jwsAQul0erqjo+OesbGx1tHRUT+fz48dP378j57neQD8mtB1
|
||||
B1TtnV9zo64loJqoXhtFDUQHEGhvb2/2fZ9nMpliTcAFYNdC1sIBYN1sCeq5Ca9bqtWcu9Fe3FDl
|
||||
9Uqvu3HLjfhvTUo85WzjhogAAAAASUVORK5CYII=
|
||||
}
|
||||
|
||||
image create photo ::tk::icons::question -data {
|
||||
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAACG5JREFU
|
||||
WIXFl3twVdUVxn97n3Nubm7euZcghEdeBBICEQUFIgVECqIo1uJMp3WodqyjMzpjZ7TTh20cK31N
|
||||
/2jL2FYdKXaqRcbnDKGpoBFaAY1BHgHMgyRKQkJy87yv3Nyzd/84594k1RlppzPumTXn3Dl3r/Wd
|
||||
b31rrbPhS17iSv+4bl2t2ZFhrRGI7QKxRkMAyHEfjwgYEOgjNnpfcXjiSENDbeL/AqBoW22uGE/7
|
||||
MYL7yubN4MYVpVkrquaKqwJZ+LPTARgcjdIbHKOx+aI+9EH7WGvnZdA8q9PGf9b5eu3w/wygaPPO
|
||||
h6Uhntxcsyj9/q+vtMrnBa6Is7ZPgzzzyvGJ/YfPRpWWj3fWff93/xWAonW1Xu3z/nVx6cxNTz74
|
||||
1YzK4gIQjuN/nfyEEx9fIjgaYXAkhhAQyE3Hn5PBsvJZrF46l5I5+QB83NnP40+/FT7d1ltPOPrN
|
||||
zoba2BcCWLy91hMOp72/bX1VxU/u3+BJ91i0fhrkuTcaaTzbjTQkhpQIIZBSIBApL1prtNYsryhk
|
||||
xy1XUzonn1g8wVPPvh1/5dDpcz5f7LrmfbXxqfGM6eG1yCw+9uq2G6tW7nxoU5plGrzecJYnnnub
|
||||
SwMhTNPAmmKmYWCaBoYpMQyJaRhIQ3IpGOKt4+1k+dKoLJ7BjStKjb6hcN7JloFrhlsO7oUnPh9A
|
||||
8Rbvo6uuLrr3N4/ckm4Ykt/vPcqe/R9hGAamaWJZbnDL+W2axqRJA8NlxzAkAI3newhF4lxbMZs1
|
||||
y4rNM+19c0PZ++NDLQff+0wKCu/Y6c/UVsubv/12/ryZubxUf5Ln3vgQ0zKnvK1kadkMlpQUUFEU
|
||||
oCDPR25WOuPxBH2DYZpa+qg/3kEoGsdWCttWJGzF3ZuXcuf6Ci5eHmXrw7sHR4mXd7/2w+A0Bvyl
|
||||
N+265/bl19+8eqE8c6GPn+85jGkYWC4Ay3Luf/3AV1g038+MXB8+rwfDkKR5TPKyvCyan8+qqtmc
|
||||
au8nFrcdnQCn2vuoLptJSWEeE7bynDjdXTDUcvBNAAmweF1tpmXKu+65bYWh0Ty97zhSyGkUO0BM
|
||||
hBAI4RAXTyjiCYWUEukKMz/Ly/b1C7EsE49lYlkmhjTYvf8jNHD3lmsM0zTuWryuNhPABIj4vFvW
|
||||
Xl0s87PTOdXWS8snQTwec4ro3DSYBglbcfx8P+8199I7FMEQgg3L53N7TWkKXOV8Px7LJCFtXKx0
|
||||
dA9zrnOAyqIAa68tkQePtm4BXpaO9vWOm65b4EPAkY+6HDEZTt4NN/dJML946QSv/fMCA6PjpHks
|
||||
LI/F2a5BtNYpMUtJirGpLL7f3A3AxpXlPiHFjhQDaJZVlc0EoPWT4DQ1m8ZkKizTJDRuY1mmC04i
|
||||
pWDNksJUD9Bac7E/jGUZrmuN1qCU5sKlIQAqSwrQWi+bBCDwF+RnAk5fl27wqeYAkZM9wLWaxVex
|
||||
qnJmKritFO+e7sMyDdBOc1JKYxiSkdA4CMGM3Aw02j+VAfLcwTIWibuiEpNApJMSw208ydJcu3QW
|
||||
axZPCW7bHGjspmcwimkYTmAlMWzHTyTmDMiczLRU/ctkNxgajboPvUghppuUGFJMY6O6OJ/ViwIo
|
||||
pVBKYds2dR9e4uPuMbc7Tm9MUgqyM70AjITHUy1IAghNsH8oDEAgz4cQOIqWjkkpEC4rSYfXL/Sn
|
||||
giulONYyRFd/1GXKAZxkUrgvkp/tAAgORxAQnAQg5InmC5cBWDgv4NS5EAhAINzyIlVmUgiy040U
|
||||
9Uop2voiKYakEAiRvDp7EYKS2XkAnOvsR0h5IqUBrfWeQ8fb1t2xvtJXs3QuB462TfZokbxMGZxC
|
||||
8If6DtI8Fh6PhcdjojSpBuXin7Kc3csXzQLgrWOtEWWrPSkAvkis7kjTBTU8FqOypIAF8/x09Y6Q
|
||||
FGjyTdHJstLsWDsnNZIBXj7Wj1LKYSS5B412nRTNymHBnHxGQ+O8836r8kVidakUNDfUhhIJtfcv
|
||||
dU22AO69dRlCCNeZU8fJe6U0ylZYBlgGmNKx+ESCiYRNwlYoWzn/UxqtHOB3ra8AAX/7x0nbttXe
|
||||
5oba0GQVAPGE9dju1z4Y7u4fY9F8P9/YWOUEV06O7eTVnXBTBaiUIj4xwcSETSJhk7BtbNtOPdta
|
||||
U0ZpYS59wRB/2ndsOBa3HkvGTU3D0fb6aE7ZBt3RM1yzuabcqiwKEI5N0N495ChaSKcihJPRa0pz
|
||||
sbUmYTugPmgbJmErB4DLxETC5oYlhWxdXUrCVvxgV32krav/qa4Djx76D4kllxalt/7q9e2bqjf9
|
||||
9Lsb0oQQHGrsYO+hc0gp3emW/Bhxm5NbZlqD0g79CTcFt60u4YYlhWhg5/MN4y/WNdW3vfnoNhD6
|
||||
Mww46wlmV9/w6snzA1sHRqKBVUvnGQvm+qkuKyA4GqVvKOJAdrcn8zz14yNh2ywozOVbGyuoKg4w
|
||||
PmHzyxcOx1+sazqTlhbZ3H92vT29Pj5nzVn1SLqVH3ipunzOxqceutlX6n7lXrw8yqn2flq7hxgL
|
||||
TzAWiyOFICfTS44vjbLCXKqK/cwOOHOl49IwP9r192hT84V3e4+9cF90sC0IRL8QAOADsgvXfu9B
|
||||
b3bgkTs3LPN+52srzPlX5V7RUerTy6M8/0Zj4uUDH45Hg13PdB/9425gzLUhQH0RgDQgC8hKLyid
|
||||
7a/c9oCV4d9WVTpLbF5TmX5tRaGYkecjJ8MLAkZD4wyMRGg636PrDjfHzrT26NhYT33w1Kt/Hh/u
|
||||
6XUDh4BBIHwlDIBTohlANpBhWb6s7PKNK30FCzZa6dnVYORoIX2OExVF26Px8NCZSN/5d0bb3mlK
|
||||
JGIhHLpDwLAL4jPnxSs9nBqABXhddrw4XdRygSrABuKuxYBx9/6KDqlf2vo3PYe56vmkuwMAAAAA
|
||||
SUVORK5CYII=
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
This software is copyrighted by the Regents of the University of
|
||||
California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
|
||||
Corporation, Apple Inc. and other parties. The following terms apply to
|
||||
all files associated with the software unless explicitly disclaimed in
|
||||
individual files.
|
||||
|
||||
The authors 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 AUTHORS 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 AUTHORS HAVE BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
THE AUTHORS 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 AUTHORS AND DISTRIBUTORS HAVE
|
||||
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
||||
MODIFICATIONS.
|
||||
|
||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
||||
U.S. government, the Government shall have only "Restricted Rights"
|
||||
in the software and related documentation as defined in the Federal
|
||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
|
||||
are acquiring the software on behalf of the Department of Defense, the
|
||||
software shall be classified as "Commercial Computer Software" and the
|
||||
Government shall have only "Restricted Rights" as defined in Clause
|
||||
252.227-7013 (b) (3) of DFARs. Notwithstanding the foregoing, the
|
||||
authors grant the U.S. Government and others acting in its behalf
|
||||
permission to use and distribute the software in accordance with the
|
||||
terms specified in this license.
|
||||
|
|
@ -0,0 +1,560 @@
|
|||
# listbox.tcl --
|
||||
#
|
||||
# This file defines the default bindings for Tk listbox widgets
|
||||
# and provides procedures that help in implementing those bindings.
|
||||
#
|
||||
# Copyright (c) 1994 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1995 Sun Microsystems, Inc.
|
||||
# Copyright (c) 1998 by Scriptics Corporation.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# tk::Priv elements used in this file:
|
||||
#
|
||||
# afterId - Token returned by "after" for autoscanning.
|
||||
# listboxPrev - The last element to be selected or deselected
|
||||
# during a selection operation.
|
||||
# listboxSelection - All of the items that were selected before the
|
||||
# current selection operation (such as a mouse
|
||||
# drag) started; used to cancel an operation.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The code below creates the default class bindings for listboxes.
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
# Note: the check for existence of %W below is because this binding
|
||||
# is sometimes invoked after a window has been deleted (e.g. because
|
||||
# there is a double-click binding on the widget that deletes it). Users
|
||||
# can put "break"s in their bindings to avoid the error, but this check
|
||||
# makes that unnecessary.
|
||||
|
||||
bind Listbox <1> {
|
||||
if {[winfo exists %W]} {
|
||||
tk::ListboxBeginSelect %W [%W index @%x,%y] 1
|
||||
}
|
||||
}
|
||||
|
||||
# Ignore double clicks so that users can define their own behaviors.
|
||||
# Among other things, this prevents errors if the user deletes the
|
||||
# listbox on a double click.
|
||||
|
||||
bind Listbox <Double-1> {
|
||||
# Empty script
|
||||
}
|
||||
|
||||
bind Listbox <B1-Motion> {
|
||||
set tk::Priv(x) %x
|
||||
set tk::Priv(y) %y
|
||||
tk::ListboxMotion %W [%W index @%x,%y]
|
||||
}
|
||||
bind Listbox <ButtonRelease-1> {
|
||||
tk::CancelRepeat
|
||||
%W activate @%x,%y
|
||||
}
|
||||
bind Listbox <Shift-1> {
|
||||
tk::ListboxBeginExtend %W [%W index @%x,%y]
|
||||
}
|
||||
bind Listbox <Control-1> {
|
||||
tk::ListboxBeginToggle %W [%W index @%x,%y]
|
||||
}
|
||||
bind Listbox <B1-Leave> {
|
||||
set tk::Priv(x) %x
|
||||
set tk::Priv(y) %y
|
||||
tk::ListboxAutoScan %W
|
||||
}
|
||||
bind Listbox <B1-Enter> {
|
||||
tk::CancelRepeat
|
||||
}
|
||||
|
||||
bind Listbox <<PrevLine>> {
|
||||
tk::ListboxUpDown %W -1
|
||||
}
|
||||
bind Listbox <<SelectPrevLine>> {
|
||||
tk::ListboxExtendUpDown %W -1
|
||||
}
|
||||
bind Listbox <<NextLine>> {
|
||||
tk::ListboxUpDown %W 1
|
||||
}
|
||||
bind Listbox <<SelectNextLine>> {
|
||||
tk::ListboxExtendUpDown %W 1
|
||||
}
|
||||
bind Listbox <<PrevChar>> {
|
||||
%W xview scroll -1 units
|
||||
}
|
||||
bind Listbox <<PrevWord>> {
|
||||
%W xview scroll -1 pages
|
||||
}
|
||||
bind Listbox <<NextChar>> {
|
||||
%W xview scroll 1 units
|
||||
}
|
||||
bind Listbox <<NextWord>> {
|
||||
%W xview scroll 1 pages
|
||||
}
|
||||
bind Listbox <Prior> {
|
||||
%W yview scroll -1 pages
|
||||
%W activate @0,0
|
||||
}
|
||||
bind Listbox <Next> {
|
||||
%W yview scroll 1 pages
|
||||
%W activate @0,0
|
||||
}
|
||||
bind Listbox <Control-Prior> {
|
||||
%W xview scroll -1 pages
|
||||
}
|
||||
bind Listbox <Control-Next> {
|
||||
%W xview scroll 1 pages
|
||||
}
|
||||
bind Listbox <<LineStart>> {
|
||||
%W xview moveto 0
|
||||
}
|
||||
bind Listbox <<LineEnd>> {
|
||||
%W xview moveto 1
|
||||
}
|
||||
bind Listbox <Control-Home> {
|
||||
%W activate 0
|
||||
%W see 0
|
||||
%W selection clear 0 end
|
||||
%W selection set 0
|
||||
tk::FireListboxSelectEvent %W
|
||||
}
|
||||
bind Listbox <Control-Shift-Home> {
|
||||
tk::ListboxDataExtend %W 0
|
||||
}
|
||||
bind Listbox <Control-End> {
|
||||
%W activate end
|
||||
%W see end
|
||||
%W selection clear 0 end
|
||||
%W selection set end
|
||||
tk::FireListboxSelectEvent %W
|
||||
}
|
||||
bind Listbox <Control-Shift-End> {
|
||||
tk::ListboxDataExtend %W [%W index end]
|
||||
}
|
||||
bind Listbox <<Copy>> {
|
||||
if {[selection own -displayof %W] eq "%W"} {
|
||||
clipboard clear -displayof %W
|
||||
clipboard append -displayof %W [selection get -displayof %W]
|
||||
}
|
||||
}
|
||||
bind Listbox <space> {
|
||||
tk::ListboxBeginSelect %W [%W index active]
|
||||
}
|
||||
bind Listbox <<Invoke>> {
|
||||
tk::ListboxBeginSelect %W [%W index active]
|
||||
}
|
||||
bind Listbox <Select> {
|
||||
tk::ListboxBeginSelect %W [%W index active]
|
||||
}
|
||||
bind Listbox <Control-Shift-space> {
|
||||
tk::ListboxBeginExtend %W [%W index active]
|
||||
}
|
||||
bind Listbox <Shift-Select> {
|
||||
tk::ListboxBeginExtend %W [%W index active]
|
||||
}
|
||||
bind Listbox <Escape> {
|
||||
tk::ListboxCancel %W
|
||||
}
|
||||
bind Listbox <<SelectAll>> {
|
||||
tk::ListboxSelectAll %W
|
||||
}
|
||||
bind Listbox <<SelectNone>> {
|
||||
if {[%W cget -selectmode] ne "browse"} {
|
||||
%W selection clear 0 end
|
||||
tk::FireListboxSelectEvent %W
|
||||
}
|
||||
}
|
||||
|
||||
# Additional Tk bindings that aren't part of the Motif look and feel:
|
||||
|
||||
bind Listbox <2> {
|
||||
%W scan mark %x %y
|
||||
}
|
||||
bind Listbox <B2-Motion> {
|
||||
%W scan dragto %x %y
|
||||
}
|
||||
|
||||
# The MouseWheel will typically only fire on Windows and Mac OS X.
|
||||
# However, someone could use the "event generate" command to produce
|
||||
# one on other platforms.
|
||||
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
bind Listbox <MouseWheel> {
|
||||
%W yview scroll [expr {-(%D)}] units
|
||||
}
|
||||
bind Listbox <Option-MouseWheel> {
|
||||
%W yview scroll [expr {-10 * (%D)}] units
|
||||
}
|
||||
bind Listbox <Shift-MouseWheel> {
|
||||
%W xview scroll [expr {-(%D)}] units
|
||||
}
|
||||
bind Listbox <Shift-Option-MouseWheel> {
|
||||
%W xview scroll [expr {-10 * (%D)}] units
|
||||
}
|
||||
} else {
|
||||
bind Listbox <MouseWheel> {
|
||||
if {%D >= 0} {
|
||||
%W yview scroll [expr {-%D/30}] units
|
||||
} else {
|
||||
%W yview scroll [expr {(29-%D)/30}] units
|
||||
}
|
||||
}
|
||||
bind Listbox <Shift-MouseWheel> {
|
||||
if {%D >= 0} {
|
||||
%W xview scroll [expr {-%D/30}] units
|
||||
} else {
|
||||
%W xview scroll [expr {(29-%D)/30}] units
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
# Support for mousewheels on Linux/Unix commonly comes through mapping
|
||||
# the wheel to the extended buttons. If you have a mousewheel, find
|
||||
# Linux configuration info at:
|
||||
# http://linuxreviews.org/howtos/xfree/mouse/
|
||||
bind Listbox <4> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W yview scroll -5 units
|
||||
}
|
||||
}
|
||||
bind Listbox <Shift-4> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W xview scroll -5 units
|
||||
}
|
||||
}
|
||||
bind Listbox <5> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W yview scroll 5 units
|
||||
}
|
||||
}
|
||||
bind Listbox <Shift-5> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W xview scroll 5 units
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ListboxBeginSelect --
|
||||
#
|
||||
# This procedure is typically invoked on button-1 presses. It begins
|
||||
# the process of making a selection in the listbox. Its exact behavior
|
||||
# depends on the selection mode currently in effect for the listbox;
|
||||
# see the Motif documentation for details.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The listbox widget.
|
||||
# el - The element for the selection operation (typically the
|
||||
# one under the pointer). Must be in numerical form.
|
||||
|
||||
proc ::tk::ListboxBeginSelect {w el {focus 1}} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -selectmode] eq "multiple"} {
|
||||
if {[$w selection includes $el]} {
|
||||
$w selection clear $el
|
||||
} else {
|
||||
$w selection set $el
|
||||
}
|
||||
} else {
|
||||
$w selection clear 0 end
|
||||
$w selection set $el
|
||||
$w selection anchor $el
|
||||
set Priv(listboxSelection) {}
|
||||
set Priv(listboxPrev) $el
|
||||
}
|
||||
tk::FireListboxSelectEvent $w
|
||||
# check existence as ListboxSelect may destroy us
|
||||
if {$focus && [winfo exists $w] && [$w cget -state] eq "normal"} {
|
||||
focus $w
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ListboxMotion --
|
||||
#
|
||||
# This procedure is called to process mouse motion events while
|
||||
# button 1 is down. It may move or extend the selection, depending
|
||||
# on the listbox's selection mode.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The listbox widget.
|
||||
# el - The element under the pointer (must be a number).
|
||||
|
||||
proc ::tk::ListboxMotion {w el} {
|
||||
variable ::tk::Priv
|
||||
if {$el == $Priv(listboxPrev)} {
|
||||
return
|
||||
}
|
||||
set anchor [$w index anchor]
|
||||
switch [$w cget -selectmode] {
|
||||
browse {
|
||||
$w selection clear 0 end
|
||||
$w selection set $el
|
||||
set Priv(listboxPrev) $el
|
||||
tk::FireListboxSelectEvent $w
|
||||
}
|
||||
extended {
|
||||
set i $Priv(listboxPrev)
|
||||
if {$i eq ""} {
|
||||
set i $el
|
||||
$w selection set $el
|
||||
}
|
||||
if {[$w selection includes anchor]} {
|
||||
$w selection clear $i $el
|
||||
$w selection set anchor $el
|
||||
} else {
|
||||
$w selection clear $i $el
|
||||
$w selection clear anchor $el
|
||||
}
|
||||
if {![info exists Priv(listboxSelection)]} {
|
||||
set Priv(listboxSelection) [$w curselection]
|
||||
}
|
||||
while {($i < $el) && ($i < $anchor)} {
|
||||
if {$i in $Priv(listboxSelection)} {
|
||||
$w selection set $i
|
||||
}
|
||||
incr i
|
||||
}
|
||||
while {($i > $el) && ($i > $anchor)} {
|
||||
if {$i in $Priv(listboxSelection)} {
|
||||
$w selection set $i
|
||||
}
|
||||
incr i -1
|
||||
}
|
||||
set Priv(listboxPrev) $el
|
||||
tk::FireListboxSelectEvent $w
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ListboxBeginExtend --
|
||||
#
|
||||
# This procedure is typically invoked on shift-button-1 presses. It
|
||||
# begins the process of extending a selection in the listbox. Its
|
||||
# exact behavior depends on the selection mode currently in effect
|
||||
# for the listbox; see the Motif documentation for details.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The listbox widget.
|
||||
# el - The element for the selection operation (typically the
|
||||
# one under the pointer). Must be in numerical form.
|
||||
|
||||
proc ::tk::ListboxBeginExtend {w el} {
|
||||
if {[$w cget -selectmode] eq "extended"} {
|
||||
if {[$w selection includes anchor]} {
|
||||
ListboxMotion $w $el
|
||||
} else {
|
||||
# No selection yet; simulate the begin-select operation.
|
||||
ListboxBeginSelect $w $el
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ListboxBeginToggle --
|
||||
#
|
||||
# This procedure is typically invoked on control-button-1 presses. It
|
||||
# begins the process of toggling a selection in the listbox. Its
|
||||
# exact behavior depends on the selection mode currently in effect
|
||||
# for the listbox; see the Motif documentation for details.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The listbox widget.
|
||||
# el - The element for the selection operation (typically the
|
||||
# one under the pointer). Must be in numerical form.
|
||||
|
||||
proc ::tk::ListboxBeginToggle {w el} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -selectmode] eq "extended"} {
|
||||
set Priv(listboxSelection) [$w curselection]
|
||||
set Priv(listboxPrev) $el
|
||||
$w selection anchor $el
|
||||
if {[$w selection includes $el]} {
|
||||
$w selection clear $el
|
||||
} else {
|
||||
$w selection set $el
|
||||
}
|
||||
tk::FireListboxSelectEvent $w
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ListboxAutoScan --
|
||||
# This procedure is invoked when the mouse leaves an entry window
|
||||
# with button 1 down. It scrolls the window up, down, left, or
|
||||
# right, depending on where the mouse left the window, and reschedules
|
||||
# itself as an "after" command so that the window continues to scroll until
|
||||
# the mouse moves back into the window or the mouse button is released.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The entry window.
|
||||
|
||||
proc ::tk::ListboxAutoScan {w} {
|
||||
variable ::tk::Priv
|
||||
if {![winfo exists $w]} return
|
||||
set x $Priv(x)
|
||||
set y $Priv(y)
|
||||
if {$y >= [winfo height $w]} {
|
||||
$w yview scroll 1 units
|
||||
} elseif {$y < 0} {
|
||||
$w yview scroll -1 units
|
||||
} elseif {$x >= [winfo width $w]} {
|
||||
$w xview scroll 2 units
|
||||
} elseif {$x < 0} {
|
||||
$w xview scroll -2 units
|
||||
} else {
|
||||
return
|
||||
}
|
||||
ListboxMotion $w [$w index @$x,$y]
|
||||
set Priv(afterId) [after 50 [list tk::ListboxAutoScan $w]]
|
||||
}
|
||||
|
||||
# ::tk::ListboxUpDown --
|
||||
#
|
||||
# Moves the location cursor (active element) up or down by one element,
|
||||
# and changes the selection if we're in browse or extended selection
|
||||
# mode.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The listbox widget.
|
||||
# amount - +1 to move down one item, -1 to move back one item.
|
||||
|
||||
proc ::tk::ListboxUpDown {w amount} {
|
||||
variable ::tk::Priv
|
||||
$w activate [expr {[$w index active] + $amount}]
|
||||
$w see active
|
||||
switch [$w cget -selectmode] {
|
||||
browse {
|
||||
$w selection clear 0 end
|
||||
$w selection set active
|
||||
tk::FireListboxSelectEvent $w
|
||||
}
|
||||
extended {
|
||||
$w selection clear 0 end
|
||||
$w selection set active
|
||||
$w selection anchor active
|
||||
set Priv(listboxPrev) [$w index active]
|
||||
set Priv(listboxSelection) {}
|
||||
tk::FireListboxSelectEvent $w
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ListboxExtendUpDown --
|
||||
#
|
||||
# Does nothing unless we're in extended selection mode; in this
|
||||
# case it moves the location cursor (active element) up or down by
|
||||
# one element, and extends the selection to that point.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The listbox widget.
|
||||
# amount - +1 to move down one item, -1 to move back one item.
|
||||
|
||||
proc ::tk::ListboxExtendUpDown {w amount} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -selectmode] ne "extended"} {
|
||||
return
|
||||
}
|
||||
set active [$w index active]
|
||||
if {![info exists Priv(listboxSelection)]} {
|
||||
$w selection set $active
|
||||
set Priv(listboxSelection) [$w curselection]
|
||||
}
|
||||
$w activate [expr {$active + $amount}]
|
||||
$w see active
|
||||
ListboxMotion $w [$w index active]
|
||||
}
|
||||
|
||||
# ::tk::ListboxDataExtend
|
||||
#
|
||||
# This procedure is called for key-presses such as Shift-KEndData.
|
||||
# If the selection mode isn't multiple or extend then it does nothing.
|
||||
# Otherwise it moves the active element to el and, if we're in
|
||||
# extended mode, extends the selection to that point.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The listbox widget.
|
||||
# el - An integer element number.
|
||||
|
||||
proc ::tk::ListboxDataExtend {w el} {
|
||||
set mode [$w cget -selectmode]
|
||||
if {$mode eq "extended"} {
|
||||
$w activate $el
|
||||
$w see $el
|
||||
if {[$w selection includes anchor]} {
|
||||
ListboxMotion $w $el
|
||||
}
|
||||
} elseif {$mode eq "multiple"} {
|
||||
$w activate $el
|
||||
$w see $el
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ListboxCancel
|
||||
#
|
||||
# This procedure is invoked to cancel an extended selection in
|
||||
# progress. If there is an extended selection in progress, it
|
||||
# restores all of the items between the active one and the anchor
|
||||
# to their previous selection state.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The listbox widget.
|
||||
|
||||
proc ::tk::ListboxCancel w {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -selectmode] ne "extended"} {
|
||||
return
|
||||
}
|
||||
set first [$w index anchor]
|
||||
set last $Priv(listboxPrev)
|
||||
if {$last eq ""} {
|
||||
# Not actually doing any selection right now
|
||||
return
|
||||
}
|
||||
if {$first > $last} {
|
||||
set tmp $first
|
||||
set first $last
|
||||
set last $tmp
|
||||
}
|
||||
$w selection clear $first $last
|
||||
while {$first <= $last} {
|
||||
if {$first in $Priv(listboxSelection)} {
|
||||
$w selection set $first
|
||||
}
|
||||
incr first
|
||||
}
|
||||
tk::FireListboxSelectEvent $w
|
||||
}
|
||||
|
||||
# ::tk::ListboxSelectAll
|
||||
#
|
||||
# This procedure is invoked to handle the "select all" operation.
|
||||
# For single and browse mode, it just selects the active element.
|
||||
# Otherwise it selects everything in the widget.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The listbox widget.
|
||||
|
||||
proc ::tk::ListboxSelectAll w {
|
||||
set mode [$w cget -selectmode]
|
||||
if {$mode eq "single" || $mode eq "browse"} {
|
||||
$w selection clear 0 end
|
||||
$w selection set active
|
||||
} else {
|
||||
$w selection set 0 end
|
||||
}
|
||||
tk::FireListboxSelectEvent $w
|
||||
}
|
||||
|
||||
# ::tk::FireListboxSelectEvent
|
||||
#
|
||||
# Fire the <<ListboxSelect>> event if the listbox is not in disabled
|
||||
# state.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The listbox widget.
|
||||
|
||||
proc ::tk::FireListboxSelectEvent w {
|
||||
if {[$w cget -state] eq "normal"} {
|
||||
event generate $w <<ListboxSelect>>
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
# megawidget.tcl
|
||||
#
|
||||
# Basic megawidget support classes. Experimental for any use other than
|
||||
# the ::tk::IconList megawdget, which is itself only designed for use in
|
||||
# the Unix file dialogs.
|
||||
#
|
||||
# Copyright (c) 2009-2010 Donal K. Fellows
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution of
|
||||
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
package require Tk
|
||||
|
||||
::oo::class create ::tk::Megawidget {
|
||||
superclass ::oo::class
|
||||
method unknown {w args} {
|
||||
if {[string match .* $w]} {
|
||||
[self] create $w {*}$args
|
||||
return $w
|
||||
}
|
||||
next $w {*}$args
|
||||
}
|
||||
unexport new unknown
|
||||
self method create {name superclasses body} {
|
||||
next $name [list \
|
||||
superclass ::tk::MegawidgetClass {*}$superclasses]\;$body
|
||||
}
|
||||
}
|
||||
|
||||
::oo::class create ::tk::MegawidgetClass {
|
||||
variable w hull options IdleCallbacks
|
||||
constructor args {
|
||||
# Extract the "widget name" from the object name
|
||||
set w [namespace tail [self]]
|
||||
|
||||
# Configure things
|
||||
tclParseConfigSpec [my varname options] [my GetSpecs] "" $args
|
||||
|
||||
# Move the object out of the way of the hull widget
|
||||
rename [self] _tmp
|
||||
|
||||
# Make the hull widget(s)
|
||||
my CreateHull
|
||||
bind $hull <Destroy> [list [namespace which my] destroy]
|
||||
|
||||
# Rename things into their final places
|
||||
rename ::$w theWidget
|
||||
rename [self] ::$w
|
||||
|
||||
# Make the contents
|
||||
my Create
|
||||
}
|
||||
destructor {
|
||||
foreach {name cb} [array get IdleCallbacks] {
|
||||
after cancel $cb
|
||||
unset IdleCallbacks($name)
|
||||
}
|
||||
if {[winfo exists $w]} {
|
||||
bind $hull <Destroy> {}
|
||||
destroy $w
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################
|
||||
#
|
||||
# MegawidgetClass::configure --
|
||||
#
|
||||
# Implementation of 'configure' for megawidgets. Emulates the operation
|
||||
# of the standard Tk configure method fairly closely, which makes things
|
||||
# substantially more complex than they otherwise would be.
|
||||
#
|
||||
# This method assumes that the 'GetSpecs' method returns a description
|
||||
# of all the specifications of the options (i.e., as Tk returns except
|
||||
# with the actual values removed). It also assumes that the 'options'
|
||||
# array in the class holds all options; it is up to subclasses to set
|
||||
# traces on that array if they want to respond to configuration changes.
|
||||
#
|
||||
# TODO: allow unambiguous abbreviations.
|
||||
#
|
||||
method configure args {
|
||||
# Configure behaves differently depending on the number of arguments
|
||||
set argc [llength $args]
|
||||
if {$argc == 0} {
|
||||
return [lmap spec [my GetSpecs] {
|
||||
lappend spec $options([lindex $spec 0])
|
||||
}]
|
||||
} elseif {$argc == 1} {
|
||||
set opt [lindex $args 0]
|
||||
if {[info exists options($opt)]} {
|
||||
set spec [lsearch -inline -index 0 -exact [my GetSpecs] $opt]
|
||||
return [linsert $spec end $options($opt)]
|
||||
}
|
||||
} elseif {$argc == 2} {
|
||||
# Special case for where we're setting a single option. This
|
||||
# avoids some of the costly operations. We still do the [array
|
||||
# get] as this gives a sufficiently-consistent trace.
|
||||
set opt [lindex $args 0]
|
||||
if {[dict exists [array get options] $opt]} {
|
||||
# Actually set the new value of the option. Use a catch to
|
||||
# allow a megawidget user to throw an error from a write trace
|
||||
# on the options array to reject invalid values.
|
||||
try {
|
||||
array set options $args
|
||||
} on error {ret info} {
|
||||
# Rethrow the error to get a clean stack trace
|
||||
return -code error -errorcode [dict get $info -errorcode] $ret
|
||||
}
|
||||
return
|
||||
}
|
||||
} elseif {$argc % 2 == 0} {
|
||||
# Check that all specified options exist. Any unknown option will
|
||||
# cause the merged dictionary to be bigger than the options array
|
||||
set merge [dict merge [array get options] $args]
|
||||
if {[dict size $merge] == [array size options]} {
|
||||
# Actually set the new values of the options. Use a catch to
|
||||
# allow a megawidget user to throw an error from a write trace
|
||||
# on the options array to reject invalid values
|
||||
try {
|
||||
array set options $args
|
||||
} on error {ret info} {
|
||||
# Rethrow the error to get a clean stack trace
|
||||
return -code error -errorcode [dict get $info -errorcode] $ret
|
||||
}
|
||||
return
|
||||
}
|
||||
# Due to the order of the merge, the unknown options will be at
|
||||
# the end of the dict. This makes the first unknown option easy to
|
||||
# find.
|
||||
set opt [lindex [dict keys $merge] [array size options]]
|
||||
} else {
|
||||
set opt [lindex $args end]
|
||||
return -code error -errorcode [list TK VALUE_MISSING] \
|
||||
"value for \"$opt\" missing"
|
||||
}
|
||||
return -code error -errorcode [list TK LOOKUP OPTION $opt] \
|
||||
"bad option \"$opt\": must be [tclListValidFlags options]"
|
||||
}
|
||||
|
||||
####################################################################
|
||||
#
|
||||
# MegawidgetClass::cget --
|
||||
#
|
||||
# Implementation of 'cget' for megawidgets. Emulates the operation of
|
||||
# the standard Tk cget method fairly closely.
|
||||
#
|
||||
# This method assumes that the 'options' array in the class holds all
|
||||
# options; it is up to subclasses to set traces on that array if they
|
||||
# want to respond to configuration reads.
|
||||
#
|
||||
# TODO: allow unambiguous abbreviations.
|
||||
#
|
||||
method cget option {
|
||||
return $options($option)
|
||||
}
|
||||
|
||||
####################################################################
|
||||
#
|
||||
# MegawidgetClass::TraceOption --
|
||||
#
|
||||
# Sets up the tracing of an element of the options variable.
|
||||
#
|
||||
method TraceOption {option method args} {
|
||||
set callback [list my $method {*}$args]
|
||||
trace add variable options($option) write [namespace code $callback]
|
||||
}
|
||||
|
||||
####################################################################
|
||||
#
|
||||
# MegawidgetClass::GetSpecs --
|
||||
#
|
||||
# Return a list of descriptions of options supported by this
|
||||
# megawidget. Each option is described by the 4-tuple list, consisting
|
||||
# of the name of the option, the "option database" name, the "option
|
||||
# database" class-name, and the default value of the option. These are
|
||||
# the same values returned by calling the configure method of a widget,
|
||||
# except without the current values of the options.
|
||||
#
|
||||
method GetSpecs {} {
|
||||
return {
|
||||
{-takefocus takeFocus TakeFocus {}}
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################
|
||||
#
|
||||
# MegawidgetClass::CreateHull --
|
||||
#
|
||||
# Creates the real main widget of the megawidget. This is often a frame
|
||||
# or toplevel widget, but isn't always (lightweight megawidgets might
|
||||
# use a content widget directly).
|
||||
#
|
||||
# The name of the hull widget is given by the 'w' instance variable. The
|
||||
# name should be written into the 'hull' instance variable. The command
|
||||
# created by this method will be renamed.
|
||||
#
|
||||
method CreateHull {} {
|
||||
return -code error -errorcode {TCL OO ABSTRACT_METHOD} \
|
||||
"method must be overridden"
|
||||
}
|
||||
|
||||
####################################################################
|
||||
#
|
||||
# MegawidgetClass::Create --
|
||||
#
|
||||
# Creates the content of the megawidget. The name of the widget to
|
||||
# create the content in will be in the 'hull' instance variable.
|
||||
#
|
||||
method Create {} {
|
||||
return -code error -errorcode {TCL OO ABSTRACT_METHOD} \
|
||||
"method must be overridden"
|
||||
}
|
||||
|
||||
####################################################################
|
||||
#
|
||||
# MegawidgetClass::WhenIdle --
|
||||
#
|
||||
# Arrange for a method to be called on the current instance when Tk is
|
||||
# idle. Only one such method call per method will be queued; subsequent
|
||||
# queuing actions before the callback fires will be silently ignored.
|
||||
# The additional args will be passed to the callback, and the callbacks
|
||||
# will be properly cancelled if the widget is destroyed.
|
||||
#
|
||||
method WhenIdle {method args} {
|
||||
if {![info exists IdleCallbacks($method)]} {
|
||||
set IdleCallbacks($method) [after idle [list \
|
||||
[namespace which my] DoWhenIdle $method $args]]
|
||||
}
|
||||
}
|
||||
method DoWhenIdle {method arguments} {
|
||||
unset IdleCallbacks($method)
|
||||
tailcall my $method {*}$arguments
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################
|
||||
#
|
||||
# tk::SimpleWidget --
|
||||
#
|
||||
# Simple megawidget class that makes it easy create widgets that behave
|
||||
# like a ttk widget. It creates the hull as a ttk::frame and maps the
|
||||
# state manipulation methods of the overall megawidget to the equivalent
|
||||
# operations on the ttk::frame.
|
||||
#
|
||||
::tk::Megawidget create ::tk::SimpleWidget {} {
|
||||
variable w hull options
|
||||
method GetSpecs {} {
|
||||
return {
|
||||
{-cursor cursor Cursor {}}
|
||||
{-takefocus takeFocus TakeFocus {}}
|
||||
}
|
||||
}
|
||||
method CreateHull {} {
|
||||
set hull [::ttk::frame $w -cursor $options(-cursor)]
|
||||
my TraceOption -cursor UpdateCursorOption
|
||||
}
|
||||
method UpdateCursorOption args {
|
||||
$hull configure -cursor $options(-cursor)
|
||||
}
|
||||
# Not fixed names, so can't forward
|
||||
method state args {
|
||||
tailcall $hull state {*}$args
|
||||
}
|
||||
method instate args {
|
||||
tailcall $hull instate {*}$args
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################
|
||||
#
|
||||
# tk::FocusableWidget --
|
||||
#
|
||||
# Simple megawidget class that makes a ttk-like widget that has a focus
|
||||
# ring.
|
||||
#
|
||||
::tk::Megawidget create ::tk::FocusableWidget ::tk::SimpleWidget {
|
||||
variable w hull options
|
||||
method GetSpecs {} {
|
||||
return {
|
||||
{-cursor cursor Cursor {}}
|
||||
{-takefocus takeFocus TakeFocus ::ttk::takefocus}
|
||||
}
|
||||
}
|
||||
method CreateHull {} {
|
||||
ttk::frame $w
|
||||
set hull [ttk::entry $w.cHull -takefocus 0 -cursor $options(-cursor)]
|
||||
pack $hull -expand yes -fill both -ipadx 2 -ipady 2
|
||||
my TraceOption -cursor UpdateCursorOption
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
# Local Variables:
|
||||
# mode: tcl
|
||||
# fill-column: 78
|
||||
# End:
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,427 @@
|
|||
# msgbox.tcl --
|
||||
#
|
||||
# Implements messageboxes for platforms that do not have native
|
||||
# messagebox support.
|
||||
#
|
||||
# Copyright (c) 1994-1997 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
# Ensure existence of ::tk::dialog namespace
|
||||
#
|
||||
namespace eval ::tk::dialog {}
|
||||
|
||||
image create bitmap ::tk::dialog::b1 -foreground black \
|
||||
-data "#define b1_width 32\n#define b1_height 32
|
||||
static unsigned char q1_bits[] = {
|
||||
0x00, 0xf8, 0x1f, 0x00, 0x00, 0x07, 0xe0, 0x00, 0xc0, 0x00, 0x00, 0x03,
|
||||
0x20, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10,
|
||||
0x04, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40,
|
||||
0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
|
||||
0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80,
|
||||
0x01, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40,
|
||||
0x04, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x08,
|
||||
0x60, 0x00, 0x00, 0x04, 0x80, 0x03, 0x80, 0x03, 0x00, 0x0c, 0x78, 0x00,
|
||||
0x00, 0x30, 0x04, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x40, 0x04, 0x00,
|
||||
0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};"
|
||||
image create bitmap ::tk::dialog::b2 -foreground white \
|
||||
-data "#define b2_width 32\n#define b2_height 32
|
||||
static unsigned char b2_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x00,
|
||||
0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07, 0xf0, 0xff, 0xff, 0x0f,
|
||||
0xf8, 0xff, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
|
||||
0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
|
||||
0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
|
||||
0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
|
||||
0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x07,
|
||||
0x80, 0xff, 0xff, 0x03, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xf0, 0x07, 0x00,
|
||||
0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};"
|
||||
image create bitmap ::tk::dialog::q -foreground blue \
|
||||
-data "#define q_width 32\n#define q_height 32
|
||||
static unsigned char q_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
|
||||
0x00, 0x10, 0x0f, 0x00, 0x00, 0x18, 0x1e, 0x00, 0x00, 0x38, 0x1e, 0x00,
|
||||
0x00, 0x38, 0x1e, 0x00, 0x00, 0x10, 0x0f, 0x00, 0x00, 0x80, 0x07, 0x00,
|
||||
0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00,
|
||||
0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};"
|
||||
image create bitmap ::tk::dialog::i -foreground blue \
|
||||
-data "#define i_width 32\n#define i_height 32
|
||||
static unsigned char i_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf0, 0x03, 0x00,
|
||||
0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xf8, 0x03, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x03, 0x00,
|
||||
0x00, 0xe0, 0x03, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xe0, 0x03, 0x00,
|
||||
0x00, 0xe0, 0x03, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00,
|
||||
0x00, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};"
|
||||
image create bitmap ::tk::dialog::w1 -foreground black \
|
||||
-data "#define w1_width 32\n#define w1_height 32
|
||||
static unsigned char w1_bits[] = {
|
||||
0x00, 0x80, 0x01, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x20, 0x04, 0x00,
|
||||
0x00, 0x10, 0x04, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00,
|
||||
0x00, 0x08, 0x10, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x04, 0x20, 0x00,
|
||||
0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00,
|
||||
0x00, 0x01, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x01,
|
||||
0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x02,
|
||||
0x20, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x08,
|
||||
0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x10,
|
||||
0x04, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x40,
|
||||
0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x20,
|
||||
0xfc, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00};"
|
||||
image create bitmap ::tk::dialog::w2 -foreground yellow \
|
||||
-data "#define w2_width 32\n#define w2_height 32
|
||||
static unsigned char w2_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00,
|
||||
0x00, 0xe0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x07, 0x00,
|
||||
0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x00,
|
||||
0x00, 0xfc, 0x1f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x3f, 0x00,
|
||||
0x00, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00,
|
||||
0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x01, 0xc0, 0xff, 0xff, 0x01,
|
||||
0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07,
|
||||
0xf0, 0xff, 0xff, 0x07, 0xf0, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
|
||||
0xf8, 0xff, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0x3f,
|
||||
0xfe, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x1f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};"
|
||||
image create bitmap ::tk::dialog::w3 -foreground black \
|
||||
-data "#define w3_width 32\n#define w3_height 32
|
||||
static unsigned char w3_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
|
||||
0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
|
||||
0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
|
||||
0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00,
|
||||
0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};"
|
||||
|
||||
# ::tk::MessageBox --
|
||||
#
|
||||
# Pops up a messagebox with an application-supplied message with
|
||||
# an icon and a list of buttons. This procedure will be called
|
||||
# by tk_messageBox if the platform does not have native
|
||||
# messagebox support, or if the particular type of messagebox is
|
||||
# not supported natively.
|
||||
#
|
||||
# Color icons are used on Unix displays that have a color
|
||||
# depth of 4 or more and $tk_strictMotif is not on.
|
||||
#
|
||||
# This procedure is a private procedure shouldn't be called
|
||||
# directly. Call tk_messageBox instead.
|
||||
#
|
||||
# See the user documentation for details on what tk_messageBox does.
|
||||
#
|
||||
proc ::tk::MessageBox {args} {
|
||||
global tk_strictMotif
|
||||
variable ::tk::Priv
|
||||
|
||||
set w ::tk::PrivMsgBox
|
||||
upvar $w data
|
||||
|
||||
#
|
||||
# The default value of the title is space (" ") not the empty string
|
||||
# because for some window managers, a
|
||||
# wm title .foo ""
|
||||
# causes the window title to be "foo" instead of the empty string.
|
||||
#
|
||||
set specs {
|
||||
{-default "" "" ""}
|
||||
{-detail "" "" ""}
|
||||
{-icon "" "" "info"}
|
||||
{-message "" "" ""}
|
||||
{-parent "" "" .}
|
||||
{-title "" "" " "}
|
||||
{-type "" "" "ok"}
|
||||
}
|
||||
|
||||
tclParseConfigSpec $w $specs "" $args
|
||||
|
||||
if {$data(-icon) ni {info warning error question}} {
|
||||
return -code error -errorcode [list TK LOOKUP ICON $data(-icon)] \
|
||||
"bad -icon value \"$data(-icon)\": must be error, info, question, or warning"
|
||||
}
|
||||
set windowingsystem [tk windowingsystem]
|
||||
if {$windowingsystem eq "aqua"} {
|
||||
switch -- $data(-icon) {
|
||||
"error" {set data(-icon) "stop"}
|
||||
"warning" {set data(-icon) "caution"}
|
||||
"info" {set data(-icon) "note"}
|
||||
}
|
||||
}
|
||||
|
||||
if {![winfo exists $data(-parent)]} {
|
||||
return -code error -errorcode [list TK LOOKUP WINDOW $data(-parent)] \
|
||||
"bad window path name \"$data(-parent)\""
|
||||
}
|
||||
|
||||
switch -- $data(-type) {
|
||||
abortretryignore {
|
||||
set names [list abort retry ignore]
|
||||
set labels [list &Abort &Retry &Ignore]
|
||||
set cancel abort
|
||||
}
|
||||
ok {
|
||||
set names [list ok]
|
||||
set labels {&OK}
|
||||
set cancel ok
|
||||
}
|
||||
okcancel {
|
||||
set names [list ok cancel]
|
||||
set labels [list &OK &Cancel]
|
||||
set cancel cancel
|
||||
}
|
||||
retrycancel {
|
||||
set names [list retry cancel]
|
||||
set labels [list &Retry &Cancel]
|
||||
set cancel cancel
|
||||
}
|
||||
yesno {
|
||||
set names [list yes no]
|
||||
set labels [list &Yes &No]
|
||||
set cancel no
|
||||
}
|
||||
yesnocancel {
|
||||
set names [list yes no cancel]
|
||||
set labels [list &Yes &No &Cancel]
|
||||
set cancel cancel
|
||||
}
|
||||
default {
|
||||
return -code error -errorcode [list TK LOOKUP DLG_TYPE $data(-type)] \
|
||||
"bad -type value \"$data(-type)\": must be\
|
||||
abortretryignore, ok, okcancel, retrycancel,\
|
||||
yesno, or yesnocancel"
|
||||
}
|
||||
}
|
||||
|
||||
set buttons {}
|
||||
foreach name $names lab $labels {
|
||||
lappend buttons [list $name -text [mc $lab]]
|
||||
}
|
||||
|
||||
# If no default button was specified, the default default is the
|
||||
# first button (Bug: 2218).
|
||||
|
||||
if {$data(-default) eq ""} {
|
||||
set data(-default) [lindex [lindex $buttons 0] 0]
|
||||
}
|
||||
|
||||
set valid 0
|
||||
foreach btn $buttons {
|
||||
if {[lindex $btn 0] eq $data(-default)} {
|
||||
set valid 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if {!$valid} {
|
||||
return -code error -errorcode {TK MSGBOX DEFAULT} \
|
||||
"bad -default value \"$data(-default)\": must be\
|
||||
abort, retry, ignore, ok, cancel, no, or yes"
|
||||
}
|
||||
|
||||
# 2. Set the dialog to be a child window of $parent
|
||||
#
|
||||
#
|
||||
if {$data(-parent) ne "."} {
|
||||
set w $data(-parent).__tk__messagebox
|
||||
} else {
|
||||
set w .__tk__messagebox
|
||||
}
|
||||
|
||||
# There is only one background colour for the whole dialog
|
||||
set bg [ttk::style lookup . -background]
|
||||
|
||||
# 3. Create the top-level window and divide it into top
|
||||
# and bottom parts.
|
||||
|
||||
catch {destroy $w}
|
||||
toplevel $w -class Dialog -bg $bg
|
||||
wm title $w $data(-title)
|
||||
wm iconname $w Dialog
|
||||
wm protocol $w WM_DELETE_WINDOW [list $w.$cancel invoke]
|
||||
|
||||
# Message boxes should be transient with respect to their parent so that
|
||||
# they always stay on top of the parent window. But some window managers
|
||||
# will simply create the child window as withdrawn if the parent is not
|
||||
# viewable (because it is withdrawn or iconified). This is not good for
|
||||
# "grab"bed windows. So only make the message box transient if the parent
|
||||
# is viewable.
|
||||
#
|
||||
if {[winfo viewable [winfo toplevel $data(-parent)]] } {
|
||||
wm transient $w $data(-parent)
|
||||
}
|
||||
|
||||
if {$windowingsystem eq "aqua"} {
|
||||
::tk::unsupported::MacWindowStyle style $w moveableModal {}
|
||||
} elseif {$windowingsystem eq "x11"} {
|
||||
wm attributes $w -type dialog
|
||||
}
|
||||
|
||||
ttk::frame $w.bot
|
||||
grid anchor $w.bot center
|
||||
pack $w.bot -side bottom -fill both
|
||||
ttk::frame $w.top
|
||||
pack $w.top -side top -fill both -expand 1
|
||||
|
||||
# 4. Fill the top part with bitmap, message and detail (use the
|
||||
# option database for -wraplength and -font so that they can be
|
||||
# overridden by the caller).
|
||||
|
||||
option add *Dialog.msg.wrapLength 3i widgetDefault
|
||||
option add *Dialog.dtl.wrapLength 3i widgetDefault
|
||||
option add *Dialog.msg.font TkCaptionFont widgetDefault
|
||||
option add *Dialog.dtl.font TkDefaultFont widgetDefault
|
||||
|
||||
ttk::label $w.msg -anchor nw -justify left -text $data(-message)
|
||||
if {$data(-detail) ne ""} {
|
||||
ttk::label $w.dtl -anchor nw -justify left -text $data(-detail)
|
||||
}
|
||||
if {$data(-icon) ne ""} {
|
||||
if {([winfo depth $w] < 4) || $tk_strictMotif} {
|
||||
# ttk::label has no -bitmap option
|
||||
label $w.bitmap -bitmap $data(-icon) -background $bg
|
||||
} else {
|
||||
switch $data(-icon) {
|
||||
error {
|
||||
ttk::label $w.bitmap -image ::tk::icons::error
|
||||
}
|
||||
info {
|
||||
ttk::label $w.bitmap -image ::tk::icons::information
|
||||
}
|
||||
question {
|
||||
ttk::label $w.bitmap -image ::tk::icons::question
|
||||
}
|
||||
default {
|
||||
ttk::label $w.bitmap -image ::tk::icons::warning
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
grid $w.bitmap $w.msg -in $w.top -sticky news -padx 2m -pady 2m
|
||||
grid configure $w.bitmap -sticky nw
|
||||
grid columnconfigure $w.top 1 -weight 1
|
||||
if {$data(-detail) ne ""} {
|
||||
grid ^ $w.dtl -in $w.top -sticky news -padx 2m -pady {0 2m}
|
||||
grid rowconfigure $w.top 1 -weight 1
|
||||
} else {
|
||||
grid rowconfigure $w.top 0 -weight 1
|
||||
}
|
||||
|
||||
# 5. Create a row of buttons at the bottom of the dialog.
|
||||
|
||||
set i 0
|
||||
foreach but $buttons {
|
||||
set name [lindex $but 0]
|
||||
set opts [lrange $but 1 end]
|
||||
if {![llength $opts]} {
|
||||
# Capitalize the first letter of $name
|
||||
set capName [string toupper $name 0]
|
||||
set opts [list -text $capName]
|
||||
}
|
||||
|
||||
eval [list tk::AmpWidget ttk::button $w.$name] $opts \
|
||||
[list -command [list set tk::Priv(button) $name]]
|
||||
|
||||
if {$name eq $data(-default)} {
|
||||
$w.$name configure -default active
|
||||
} else {
|
||||
$w.$name configure -default normal
|
||||
}
|
||||
grid $w.$name -in $w.bot -row 0 -column $i -padx 3m -pady 2m -sticky ew
|
||||
grid columnconfigure $w.bot $i -uniform buttons
|
||||
# We boost the size of some Mac buttons for l&f
|
||||
if {$windowingsystem eq "aqua"} {
|
||||
set tmp [string tolower $name]
|
||||
if {$tmp eq "ok" || $tmp eq "cancel" || $tmp eq "yes" ||
|
||||
$tmp eq "no" || $tmp eq "abort" || $tmp eq "retry" ||
|
||||
$tmp eq "ignore"} {
|
||||
grid columnconfigure $w.bot $i -minsize 90
|
||||
}
|
||||
grid configure $w.$name -pady 7
|
||||
}
|
||||
incr i
|
||||
|
||||
# create the binding for the key accelerator, based on the underline
|
||||
#
|
||||
# set underIdx [$w.$name cget -under]
|
||||
# if {$underIdx >= 0} {
|
||||
# set key [string index [$w.$name cget -text] $underIdx]
|
||||
# bind $w <Alt-[string tolower $key]> [list $w.$name invoke]
|
||||
# bind $w <Alt-[string toupper $key]> [list $w.$name invoke]
|
||||
# }
|
||||
}
|
||||
bind $w <Alt-Key> [list ::tk::AltKeyInDialog $w %A]
|
||||
|
||||
if {$data(-default) ne ""} {
|
||||
bind $w <FocusIn> {
|
||||
if {[winfo class %W] in "Button TButton"} {
|
||||
%W configure -default active
|
||||
}
|
||||
}
|
||||
bind $w <FocusOut> {
|
||||
if {[winfo class %W] in "Button TButton"} {
|
||||
%W configure -default normal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 6. Create bindings for <Return>, <Escape> and <Destroy> on the dialog
|
||||
|
||||
bind $w <Return> {
|
||||
if {[winfo class %W] in "Button TButton"} {
|
||||
%W invoke
|
||||
}
|
||||
}
|
||||
|
||||
# Invoke the designated cancelling operation
|
||||
bind $w <Escape> [list $w.$cancel invoke]
|
||||
|
||||
# At <Destroy> the buttons have vanished, so must do this directly.
|
||||
bind $w.msg <Destroy> [list set tk::Priv(button) $cancel]
|
||||
|
||||
# 7. Withdraw the window, then update all the geometry information
|
||||
# so we know how big it wants to be, then center the window in the
|
||||
# display (Motif style) and de-iconify it.
|
||||
|
||||
::tk::PlaceWindow $w widget $data(-parent)
|
||||
|
||||
# 8. Set a grab and claim the focus too.
|
||||
|
||||
if {$data(-default) ne ""} {
|
||||
set focus $w.$data(-default)
|
||||
} else {
|
||||
set focus $w
|
||||
}
|
||||
::tk::SetFocusGrab $w $focus
|
||||
|
||||
# 9. Wait for the user to respond, then restore the focus and
|
||||
# return the index of the selected button. Restore the focus
|
||||
# before deleting the window, since otherwise the window manager
|
||||
# may take the focus away so we can't redirect it. Finally,
|
||||
# restore any grab that was in effect.
|
||||
|
||||
vwait ::tk::Priv(button)
|
||||
# Copy the result now so any <Destroy> that happens won't cause
|
||||
# trouble
|
||||
set result $Priv(button)
|
||||
|
||||
::tk::RestoreFocusGrab $w $focus
|
||||
|
||||
return $result
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
# obsolete.tcl --
|
||||
#
|
||||
# This file contains obsolete procedures that people really shouldn't
|
||||
# be using anymore, but which are kept around for backward compatibility.
|
||||
#
|
||||
# Copyright (c) 1994 The Regents of the University of California.
|
||||
# Copyright (c) 1994 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
# The procedures below are here strictly for backward compatibility with
|
||||
# Tk version 3.6 and earlier. The procedures are no longer needed, so
|
||||
# they are no-ops. You should not use these procedures anymore, since
|
||||
# they may be removed in some future release.
|
||||
|
||||
proc tk_menuBar args {}
|
||||
proc tk_bindForTraversal args {}
|
||||
|
||||
# ::tk::classic::restore --
|
||||
#
|
||||
# Restore the pre-8.5 (Tk classic) look as the widget defaults for classic
|
||||
# Tk widgets.
|
||||
#
|
||||
# The value following an 'option add' call is the new 8.5 value.
|
||||
#
|
||||
namespace eval ::tk::classic {
|
||||
# This may need to be adjusted for some window managers that are
|
||||
# more aggressive with their own Xdefaults (like KDE and CDE)
|
||||
variable prio "widgetDefault"
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore {args} {
|
||||
# Restore classic (8.4) look to classic Tk widgets
|
||||
variable prio
|
||||
|
||||
if {[llength $args]} {
|
||||
foreach what $args {
|
||||
::tk::classic::restore_$what
|
||||
}
|
||||
} else {
|
||||
foreach cmd [info procs restore_*] {
|
||||
$cmd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_font {args} {
|
||||
# Many widgets were adjusted from hard-coded defaults to using the
|
||||
# TIP#145 fonts defined in fonts.tcl (eg TkDefaultFont, TkFixedFont, ...)
|
||||
# For restoring compatibility, we only correct size and weighting changes,
|
||||
# as the fonts themselves remained mostly the same.
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
font configure TkDefaultFont -weight bold ; # normal
|
||||
font configure TkFixedFont -size -12 ; # -10
|
||||
}
|
||||
# Add these with prio 21 to override value in dialog/msgbox.tcl
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
option add *Dialog.msg.font system 21; # TkCaptionFont
|
||||
option add *Dialog.dtl.font system 21; # TkCaptionFont
|
||||
option add *ErrorDialog*Label.font system 21; # TkCaptionFont
|
||||
} else {
|
||||
option add *Dialog.msg.font {Times 12} 21; # TkCaptionFont
|
||||
option add *Dialog.dtl.font {Times 10} 21; # TkCaptionFont
|
||||
option add *ErrorDialog*Label.font {Times -18} 21; # TkCaptionFont
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_button {args} {
|
||||
variable prio
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
foreach cls {Button Radiobutton Checkbutton} {
|
||||
option add *$cls.borderWidth 2 $prio; # 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_entry {args} {
|
||||
variable prio
|
||||
# Entry and Spinbox share core defaults
|
||||
foreach cls {Entry Spinbox} {
|
||||
if {[tk windowingsystem] ne "aqua"} {
|
||||
option add *$cls.borderWidth 2 $prio; # 1
|
||||
}
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
option add *$cls.background "#d9d9d9" $prio; # "white"
|
||||
option add *$cls.selectBorderWidth 1 $prio; # 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_listbox {args} {
|
||||
variable prio
|
||||
if {[tk windowingsystem] ne "win32"} {
|
||||
option add *Listbox.background "#d9d9d9" $prio; # "white"
|
||||
option add *Listbox.activeStyle "underline" $prio; # "dotbox"
|
||||
}
|
||||
if {[tk windowingsystem] ne "aqua"} {
|
||||
option add *Listbox.borderWidth 2 $prio; # 1
|
||||
}
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
option add *Listbox.selectBorderWidth 1 $prio; # 0
|
||||
}
|
||||
# Remove focus into Listbox added for 8.5
|
||||
bind Listbox <1> {
|
||||
if {[winfo exists %W]} {
|
||||
tk::ListboxBeginSelect %W [%W index @%x,%y]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_menu {args} {
|
||||
variable prio
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
option add *Menu.activeBorderWidth 2 $prio; # 1
|
||||
option add *Menu.borderWidth 2 $prio; # 1
|
||||
option add *Menu.clickToFocus true $prio
|
||||
option add *Menu.useMotifHelp true $prio
|
||||
}
|
||||
if {[tk windowingsystem] ne "aqua"} {
|
||||
option add *Menu.font "TkDefaultFont" $prio; # "TkMenuFont"
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_menubutton {args} {
|
||||
variable prio
|
||||
option add *Menubutton.borderWidth 2 $prio; # 1
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_message {args} {
|
||||
variable prio
|
||||
option add *Message.borderWidth 2 $prio; # 1
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_panedwindow {args} {
|
||||
variable prio
|
||||
option add *Panedwindow.borderWidth 2 $prio; # 1
|
||||
option add *Panedwindow.sashWidth 2 $prio; # 3
|
||||
option add *Panedwindow.sashPad 2 $prio; # 0
|
||||
option add *Panedwindow.sashRelief raised $prio; # flat
|
||||
option add *Panedwindow.opaqueResize 0 $prio; # 1
|
||||
if {[tk windowingsystem] ne "win32"} {
|
||||
option add *Panedwindow.showHandle 1 $prio; # 0
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_scale {args} {
|
||||
variable prio
|
||||
option add *Scale.borderWidth 2 $prio; # 1
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
option add *Scale.troughColor "#c3c3c3" $prio; # "#b3b3b3"
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_scrollbar {args} {
|
||||
variable prio
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
option add *Scrollbar.borderWidth 2 $prio; # 1
|
||||
option add *Scrollbar.highlightThickness 1 $prio; # 0
|
||||
option add *Scrollbar.width 15 $prio; # 11
|
||||
option add *Scrollbar.troughColor "#c3c3c3" $prio; # "#b3b3b3"
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::classic::restore_text {args} {
|
||||
variable prio
|
||||
if {[tk windowingsystem] ne "aqua"} {
|
||||
option add *Text.borderWidth 2 $prio; # 1
|
||||
}
|
||||
if {[tk windowingsystem] eq "win32"} {
|
||||
option add *Text.font "TkDefaultFont" $prio; # "TkFixedFont"
|
||||
}
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
option add *Text.background "#d9d9d9" $prio; # white
|
||||
option add *Text.selectBorderWidth 1 $prio; # 0
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
# optMenu.tcl --
|
||||
#
|
||||
# This file defines the procedure tk_optionMenu, which creates
|
||||
# an option button and its associated menu.
|
||||
#
|
||||
# Copyright (c) 1994 The Regents of the University of California.
|
||||
# Copyright (c) 1994 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
# ::tk_optionMenu --
|
||||
# This procedure creates an option button named $w and an associated
|
||||
# menu. Together they provide the functionality of Motif option menus:
|
||||
# they can be used to select one of many values, and the current value
|
||||
# appears in the global variable varName, as well as in the text of
|
||||
# the option menubutton. The name of the menu is returned as the
|
||||
# procedure's result, so that the caller can use it to change configuration
|
||||
# options on the menu or otherwise manipulate it.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name to use for the menubutton.
|
||||
# varName - Global variable to hold the currently selected value.
|
||||
# firstValue - First of legal values for option (must be >= 1).
|
||||
# args - Any number of additional values.
|
||||
|
||||
proc ::tk_optionMenu {w varName firstValue args} {
|
||||
upvar #0 $varName var
|
||||
|
||||
if {![info exists var]} {
|
||||
set var $firstValue
|
||||
}
|
||||
menubutton $w -textvariable $varName -indicatoron 1 -menu $w.menu \
|
||||
-relief raised -highlightthickness 1 -anchor c \
|
||||
-direction flush
|
||||
menu $w.menu -tearoff 0
|
||||
$w.menu add radiobutton -label $firstValue -variable $varName
|
||||
foreach i $args {
|
||||
$w.menu add radiobutton -label $i -variable $varName
|
||||
}
|
||||
return $w.menu
|
||||
}
|
||||
|
|
@ -0,0 +1,244 @@
|
|||
# palette.tcl --
|
||||
#
|
||||
# This file contains procedures that change the color palette used
|
||||
# by Tk.
|
||||
#
|
||||
# Copyright (c) 1995-1997 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
# ::tk_setPalette --
|
||||
# Changes the default color scheme for a Tk application by setting
|
||||
# default colors in the option database and by modifying all of the
|
||||
# color options for existing widgets that have the default value.
|
||||
#
|
||||
# Arguments:
|
||||
# The arguments consist of either a single color name, which
|
||||
# will be used as the new background color (all other colors will
|
||||
# be computed from this) or an even number of values consisting of
|
||||
# option names and values. The name for an option is the one used
|
||||
# for the option database, such as activeForeground, not -activeforeground.
|
||||
|
||||
proc ::tk_setPalette {args} {
|
||||
if {[winfo depth .] == 1} {
|
||||
# Just return on monochrome displays, otherwise errors will occur
|
||||
return
|
||||
}
|
||||
|
||||
# Create an array that has the complete new palette. If some colors
|
||||
# aren't specified, compute them from other colors that are specified.
|
||||
|
||||
if {[llength $args] == 1} {
|
||||
set new(background) [lindex $args 0]
|
||||
} else {
|
||||
array set new $args
|
||||
}
|
||||
if {![info exists new(background)]} {
|
||||
return -code error -errorcode {TK SET_PALETTE BACKGROUND} \
|
||||
"must specify a background color"
|
||||
}
|
||||
set bg [winfo rgb . $new(background)]
|
||||
if {![info exists new(foreground)]} {
|
||||
# Note that the range of each value in the triple returned by
|
||||
# [winfo rgb] is 0-65535, and your eyes are more sensitive to
|
||||
# green than to red, and more to red than to blue.
|
||||
foreach {r g b} $bg {break}
|
||||
if {$r+1.5*$g+0.5*$b > 100000} {
|
||||
set new(foreground) black
|
||||
} else {
|
||||
set new(foreground) white
|
||||
}
|
||||
}
|
||||
lassign [winfo rgb . $new(foreground)] fg_r fg_g fg_b
|
||||
lassign $bg bg_r bg_g bg_b
|
||||
set darkerBg [format #%02x%02x%02x [expr {(9*$bg_r)/2560}] \
|
||||
[expr {(9*$bg_g)/2560}] [expr {(9*$bg_b)/2560}]]
|
||||
|
||||
foreach i {activeForeground insertBackground selectForeground \
|
||||
highlightColor} {
|
||||
if {![info exists new($i)]} {
|
||||
set new($i) $new(foreground)
|
||||
}
|
||||
}
|
||||
if {![info exists new(disabledForeground)]} {
|
||||
set new(disabledForeground) [format #%02x%02x%02x \
|
||||
[expr {(3*$bg_r + $fg_r)/1024}] \
|
||||
[expr {(3*$bg_g + $fg_g)/1024}] \
|
||||
[expr {(3*$bg_b + $fg_b)/1024}]]
|
||||
}
|
||||
if {![info exists new(highlightBackground)]} {
|
||||
set new(highlightBackground) $new(background)
|
||||
}
|
||||
if {![info exists new(activeBackground)]} {
|
||||
# Pick a default active background that islighter than the
|
||||
# normal background. To do this, round each color component
|
||||
# up by 15% or 1/3 of the way to full white, whichever is
|
||||
# greater.
|
||||
|
||||
foreach i {0 1 2} color $bg {
|
||||
set light($i) [expr {$color/256}]
|
||||
set inc1 [expr {($light($i)*15)/100}]
|
||||
set inc2 [expr {(255-$light($i))/3}]
|
||||
if {$inc1 > $inc2} {
|
||||
incr light($i) $inc1
|
||||
} else {
|
||||
incr light($i) $inc2
|
||||
}
|
||||
if {$light($i) > 255} {
|
||||
set light($i) 255
|
||||
}
|
||||
}
|
||||
set new(activeBackground) [format #%02x%02x%02x $light(0) \
|
||||
$light(1) $light(2)]
|
||||
}
|
||||
if {![info exists new(selectBackground)]} {
|
||||
set new(selectBackground) $darkerBg
|
||||
}
|
||||
if {![info exists new(troughColor)]} {
|
||||
set new(troughColor) $darkerBg
|
||||
}
|
||||
|
||||
# let's make one of each of the widgets so we know what the
|
||||
# defaults are currently for this platform.
|
||||
toplevel .___tk_set_palette
|
||||
wm withdraw .___tk_set_palette
|
||||
foreach q {
|
||||
button canvas checkbutton entry frame label labelframe
|
||||
listbox menubutton menu message radiobutton scale scrollbar
|
||||
spinbox text
|
||||
} {
|
||||
$q .___tk_set_palette.$q
|
||||
}
|
||||
|
||||
# Walk the widget hierarchy, recoloring all existing windows.
|
||||
# The option database must be set according to what we do here,
|
||||
# but it breaks things if we set things in the database while
|
||||
# we are changing colors...so, ::tk::RecolorTree now returns the
|
||||
# option database changes that need to be made, and they
|
||||
# need to be evalled here to take effect.
|
||||
# We have to walk the whole widget tree instead of just
|
||||
# relying on the widgets we've created above to do the work
|
||||
# because different extensions may provide other kinds
|
||||
# of widgets that we don't currently know about, so we'll
|
||||
# walk the whole hierarchy just in case.
|
||||
|
||||
eval [tk::RecolorTree . new]
|
||||
|
||||
destroy .___tk_set_palette
|
||||
|
||||
# Change the option database so that future windows will get the
|
||||
# same colors.
|
||||
|
||||
foreach option [array names new] {
|
||||
option add *$option $new($option) widgetDefault
|
||||
}
|
||||
|
||||
# Save the options in the variable ::tk::Palette, for use the
|
||||
# next time we change the options.
|
||||
|
||||
array set ::tk::Palette [array get new]
|
||||
}
|
||||
|
||||
# ::tk::RecolorTree --
|
||||
# This procedure changes the colors in a window and all of its
|
||||
# descendants, according to information provided by the colors
|
||||
# argument. This looks at the defaults provided by the option
|
||||
# database, if it exists, and if not, then it looks at the default
|
||||
# value of the widget itself.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The name of a window. This window and all its
|
||||
# descendants are recolored.
|
||||
# colors - The name of an array variable in the caller,
|
||||
# which contains color information. Each element
|
||||
# is named after a widget configuration option, and
|
||||
# each value is the value for that option.
|
||||
|
||||
proc ::tk::RecolorTree {w colors} {
|
||||
upvar $colors c
|
||||
set result {}
|
||||
set prototype .___tk_set_palette.[string tolower [winfo class $w]]
|
||||
if {![winfo exists $prototype]} {
|
||||
unset prototype
|
||||
}
|
||||
foreach dbOption [array names c] {
|
||||
set option -[string tolower $dbOption]
|
||||
set class [string replace $dbOption 0 0 [string toupper \
|
||||
[string index $dbOption 0]]]
|
||||
if {![catch {$w configure $option} value]} {
|
||||
# if the option database has a preference for this
|
||||
# dbOption, then use it, otherwise use the defaults
|
||||
# for the widget.
|
||||
set defaultcolor [option get $w $dbOption $class]
|
||||
if {$defaultcolor eq "" || \
|
||||
([info exists prototype] && \
|
||||
[$prototype cget $option] ne "$defaultcolor")} {
|
||||
set defaultcolor [lindex $value 3]
|
||||
}
|
||||
if {$defaultcolor ne ""} {
|
||||
set defaultcolor [winfo rgb . $defaultcolor]
|
||||
}
|
||||
set chosencolor [lindex $value 4]
|
||||
if {$chosencolor ne ""} {
|
||||
set chosencolor [winfo rgb . $chosencolor]
|
||||
}
|
||||
if {[string match $defaultcolor $chosencolor]} {
|
||||
# Change the option database so that future windows will get
|
||||
# the same colors.
|
||||
append result ";\noption add [list \
|
||||
*[winfo class $w].$dbOption $c($dbOption) 60]"
|
||||
$w configure $option $c($dbOption)
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach child [winfo children $w] {
|
||||
append result ";\n[::tk::RecolorTree $child c]"
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
# ::tk::Darken --
|
||||
# Given a color name, computes a new color value that darkens (or
|
||||
# brightens) the given color by a given percent.
|
||||
#
|
||||
# Arguments:
|
||||
# color - Name of starting color.
|
||||
# percent - Integer telling how much to brighten or darken as a
|
||||
# percent: 50 means darken by 50%, 110 means brighten
|
||||
# by 10%.
|
||||
|
||||
proc ::tk::Darken {color percent} {
|
||||
if {$percent < 0} {
|
||||
return #000000
|
||||
} elseif {$percent > 200} {
|
||||
return #ffffff
|
||||
} elseif {$percent <= 100} {
|
||||
lassign [winfo rgb . $color] r g b
|
||||
set r [expr {($r/256)*$percent/100}]
|
||||
set g [expr {($g/256)*$percent/100}]
|
||||
set b [expr {($b/256)*$percent/100}]
|
||||
} elseif {$percent > 100} {
|
||||
lassign [winfo rgb . $color] r g b
|
||||
set r [expr {255 - ((65535-$r)/256)*(200-$percent)/100}]
|
||||
set g [expr {255 - ((65535-$g)/256)*(200-$percent)/100}]
|
||||
set b [expr {255 - ((65535-$b)/256)*(200-$percent)/100}]
|
||||
}
|
||||
return [format #%02x%02x%02x $r $g $b]
|
||||
}
|
||||
|
||||
# ::tk_bisque --
|
||||
# Reset the Tk color palette to the old "bisque" colors.
|
||||
#
|
||||
# Arguments:
|
||||
# None.
|
||||
|
||||
proc ::tk_bisque {} {
|
||||
tk_setPalette activeBackground #e6ceb1 activeForeground black \
|
||||
background #ffe4c4 disabledForeground #b0b0b0 foreground black \
|
||||
highlightBackground #ffe4c4 highlightColor black \
|
||||
insertBackground black \
|
||||
selectBackground #e6ceb1 selectForeground black \
|
||||
troughColor #cdb79e
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
# panedwindow.tcl --
|
||||
#
|
||||
# This file defines the default bindings for Tk panedwindow widgets and
|
||||
# provides procedures that help in implementing those bindings.
|
||||
|
||||
bind Panedwindow <Button-1> { ::tk::panedwindow::MarkSash %W %x %y 1 }
|
||||
bind Panedwindow <Button-2> { ::tk::panedwindow::MarkSash %W %x %y 0 }
|
||||
|
||||
bind Panedwindow <B1-Motion> { ::tk::panedwindow::DragSash %W %x %y 1 }
|
||||
bind Panedwindow <B2-Motion> { ::tk::panedwindow::DragSash %W %x %y 0 }
|
||||
|
||||
bind Panedwindow <ButtonRelease-1> {::tk::panedwindow::ReleaseSash %W 1}
|
||||
bind Panedwindow <ButtonRelease-2> {::tk::panedwindow::ReleaseSash %W 0}
|
||||
|
||||
bind Panedwindow <Motion> { ::tk::panedwindow::Motion %W %x %y }
|
||||
|
||||
bind Panedwindow <Leave> { ::tk::panedwindow::Leave %W }
|
||||
|
||||
# Initialize namespace
|
||||
namespace eval ::tk::panedwindow {}
|
||||
|
||||
# ::tk::panedwindow::MarkSash --
|
||||
#
|
||||
# Handle marking the correct sash for possible dragging
|
||||
#
|
||||
# Arguments:
|
||||
# w the widget
|
||||
# x widget local x coord
|
||||
# y widget local y coord
|
||||
# proxy whether this should be a proxy sash
|
||||
# Results:
|
||||
# None
|
||||
#
|
||||
proc ::tk::panedwindow::MarkSash {w x y proxy} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -opaqueresize]} {
|
||||
set proxy 0
|
||||
}
|
||||
set what [$w identify $x $y]
|
||||
if { [llength $what] == 2 } {
|
||||
lassign $what index which
|
||||
if {!$::tk_strictMotif || $which eq "handle"} {
|
||||
if {!$proxy} {
|
||||
$w sash mark $index $x $y
|
||||
}
|
||||
set Priv(sash) $index
|
||||
lassign [$w sash coord $index] sx sy
|
||||
set Priv(dx) [expr {$sx-$x}]
|
||||
set Priv(dy) [expr {$sy-$y}]
|
||||
# Do this to init the proxy location
|
||||
DragSash $w $x $y $proxy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::panedwindow::DragSash --
|
||||
#
|
||||
# Handle dragging of the correct sash
|
||||
#
|
||||
# Arguments:
|
||||
# w the widget
|
||||
# x widget local x coord
|
||||
# y widget local y coord
|
||||
# proxy whether this should be a proxy sash
|
||||
# Results:
|
||||
# Moves sash
|
||||
#
|
||||
proc ::tk::panedwindow::DragSash {w x y proxy} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -opaqueresize]} {
|
||||
set proxy 0
|
||||
}
|
||||
if {[info exists Priv(sash)]} {
|
||||
if {$proxy} {
|
||||
$w proxy place [expr {$x+$Priv(dx)}] [expr {$y+$Priv(dy)}]
|
||||
} else {
|
||||
$w sash place $Priv(sash) \
|
||||
[expr {$x+$Priv(dx)}] [expr {$y+$Priv(dy)}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::panedwindow::ReleaseSash --
|
||||
#
|
||||
# Handle releasing of the sash
|
||||
#
|
||||
# Arguments:
|
||||
# w the widget
|
||||
# proxy whether this should be a proxy sash
|
||||
# Results:
|
||||
# Returns ...
|
||||
#
|
||||
proc ::tk::panedwindow::ReleaseSash {w proxy} {
|
||||
variable ::tk::Priv
|
||||
if {[$w cget -opaqueresize]} {
|
||||
set proxy 0
|
||||
}
|
||||
if {[info exists Priv(sash)]} {
|
||||
if {$proxy} {
|
||||
lassign [$w proxy coord] x y
|
||||
$w sash place $Priv(sash) $x $y
|
||||
$w proxy forget
|
||||
}
|
||||
unset Priv(sash) Priv(dx) Priv(dy)
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::panedwindow::Motion --
|
||||
#
|
||||
# Handle motion on the widget. This is used to change the cursor
|
||||
# when the user moves over the sash area.
|
||||
#
|
||||
# Arguments:
|
||||
# w the widget
|
||||
# x widget local x coord
|
||||
# y widget local y coord
|
||||
# Results:
|
||||
# May change the cursor. Sets up a timer to verify that we are still
|
||||
# over the widget.
|
||||
#
|
||||
proc ::tk::panedwindow::Motion {w x y} {
|
||||
variable ::tk::Priv
|
||||
set id [$w identify $x $y]
|
||||
if {([llength $id] == 2) && \
|
||||
(!$::tk_strictMotif || [lindex $id 1] eq "handle")} {
|
||||
if {![info exists Priv($w,panecursor)]} {
|
||||
set Priv($w,panecursor) [$w cget -cursor]
|
||||
if {[$w cget -sashcursor] ne ""} {
|
||||
$w configure -cursor [$w cget -sashcursor]
|
||||
} elseif {[$w cget -orient] eq "horizontal"} {
|
||||
$w configure -cursor sb_h_double_arrow
|
||||
} else {
|
||||
$w configure -cursor sb_v_double_arrow
|
||||
}
|
||||
if {[info exists Priv($w,pwAfterId)]} {
|
||||
after cancel $Priv($w,pwAfterId)
|
||||
}
|
||||
set Priv($w,pwAfterId) [after 150 \
|
||||
[list ::tk::panedwindow::Cursor $w]]
|
||||
}
|
||||
return
|
||||
}
|
||||
if {[info exists Priv($w,panecursor)]} {
|
||||
$w configure -cursor $Priv($w,panecursor)
|
||||
unset Priv($w,panecursor)
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::panedwindow::Cursor --
|
||||
#
|
||||
# Handles returning the normal cursor when we are no longer over the
|
||||
# sash area. This needs to be done this way, because the panedwindow
|
||||
# won't see Leave events when the mouse moves from the sash to a
|
||||
# paned child, although the child does receive an Enter event.
|
||||
#
|
||||
# Arguments:
|
||||
# w the widget
|
||||
# Results:
|
||||
# May restore the default cursor, or schedule a timer to do it.
|
||||
#
|
||||
proc ::tk::panedwindow::Cursor {w} {
|
||||
variable ::tk::Priv
|
||||
# Make sure to check window existence in case it is destroyed.
|
||||
if {[info exists Priv($w,panecursor)] && [winfo exists $w]} {
|
||||
if {[winfo containing [winfo pointerx $w] [winfo pointery $w]] eq $w} {
|
||||
set Priv($w,pwAfterId) [after 150 \
|
||||
[list ::tk::panedwindow::Cursor $w]]
|
||||
} else {
|
||||
$w configure -cursor $Priv($w,panecursor)
|
||||
unset Priv($w,panecursor)
|
||||
if {[info exists Priv($w,pwAfterId)]} {
|
||||
after cancel $Priv($w,pwAfterId)
|
||||
unset Priv($w,pwAfterId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::panedwindow::Leave --
|
||||
#
|
||||
# Return to default cursor when leaving the pw widget.
|
||||
#
|
||||
# Arguments:
|
||||
# w the widget
|
||||
# Results:
|
||||
# Restores the default cursor
|
||||
#
|
||||
proc ::tk::panedwindow::Leave {w} {
|
||||
variable ::tk::Priv
|
||||
if {[info exists Priv($w,panecursor)]} {
|
||||
$w configure -cursor $Priv($w,panecursor)
|
||||
unset Priv($w,panecursor)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
# safetk.tcl --
|
||||
#
|
||||
# Support procs to use Tk in safe interpreters.
|
||||
#
|
||||
# Copyright (c) 1997 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
|
||||
# see safetk.n for documentation
|
||||
|
||||
#
|
||||
#
|
||||
# Note: It is now ok to let untrusted code being executed
|
||||
# between the creation of the interp and the actual loading
|
||||
# of Tk in that interp because the C side Tk_Init will
|
||||
# now look up the parent interp and ask its safe::TkInit
|
||||
# for the actual parameters to use for it's initialization (if allowed),
|
||||
# not relying on the child state.
|
||||
#
|
||||
|
||||
# We use opt (optional arguments parsing)
|
||||
package require opt 0.4.1;
|
||||
|
||||
namespace eval ::safe {
|
||||
|
||||
# counter for safe toplevels
|
||||
variable tkSafeId 0
|
||||
}
|
||||
|
||||
#
|
||||
# tkInterpInit : prepare the child interpreter for tk loading
|
||||
# most of the real job is done by loadTk
|
||||
# returns the child name (tkInterpInit does)
|
||||
#
|
||||
proc ::safe::tkInterpInit {child argv} {
|
||||
global env tk_library
|
||||
|
||||
# We have to make sure that the tk_library variable is normalized.
|
||||
set tk_library [file normalize $tk_library]
|
||||
|
||||
# Clear Tk's access for that interp (path).
|
||||
allowTk $child $argv
|
||||
|
||||
# Ensure tk_library and subdirs (eg, ttk) are on the access path
|
||||
::interp eval $child [list set tk_library [::safe::interpAddToAccessPath $child $tk_library]]
|
||||
foreach subdir [::safe::AddSubDirs [list $tk_library]] {
|
||||
::safe::interpAddToAccessPath $child $subdir
|
||||
}
|
||||
return $child
|
||||
}
|
||||
|
||||
|
||||
# tkInterpLoadTk:
|
||||
# Do additional configuration as needed (calling tkInterpInit)
|
||||
# and actually load Tk into the child.
|
||||
#
|
||||
# Either contained in the specified windowId (-use) or
|
||||
# creating a decorated toplevel for it.
|
||||
|
||||
# empty definition for auto_mkIndex
|
||||
proc ::safe::loadTk {} {}
|
||||
|
||||
::tcl::OptProc ::safe::loadTk {
|
||||
{child -interp "name of the child interpreter"}
|
||||
{-use -windowId {} "window Id to use (new toplevel otherwise)"}
|
||||
{-display -displayName {} "display name to use (current one otherwise)"}
|
||||
} {
|
||||
set displayGiven [::tcl::OptProcArgGiven "-display"]
|
||||
if {!$displayGiven} {
|
||||
# Try to get the current display from "."
|
||||
# (which might not exist if the parent is tk-less)
|
||||
if {[catch {set display [winfo screen .]}]} {
|
||||
if {[info exists ::env(DISPLAY)]} {
|
||||
set display $::env(DISPLAY)
|
||||
} else {
|
||||
Log $child "no winfo screen . nor env(DISPLAY)" WARNING
|
||||
set display ":0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Get state for access to the cleanupHook.
|
||||
namespace upvar ::safe S$child state
|
||||
|
||||
if {![::tcl::OptProcArgGiven "-use"]} {
|
||||
# create a decorated toplevel
|
||||
lassign [tkTopLevel $child $display] w use
|
||||
|
||||
# set our delete hook (child arg is added by interpDelete)
|
||||
# to clean up both window related code and tkInit(child)
|
||||
set state(cleanupHook) [list tkDelete {} $w]
|
||||
} else {
|
||||
# set our delete hook (child arg is added by interpDelete)
|
||||
# to clean up tkInit(child)
|
||||
set state(cleanupHook) [list disallowTk]
|
||||
|
||||
# Let's be nice and also accept tk window names instead of ids
|
||||
if {[string match ".*" $use]} {
|
||||
set windowName $use
|
||||
set use [winfo id $windowName]
|
||||
set nDisplay [winfo screen $windowName]
|
||||
} else {
|
||||
# Check for a better -display value
|
||||
# (works only for multi screens on single host, but not
|
||||
# cross hosts, for that a tk window name would be better
|
||||
# but embeding is also usefull for non tk names)
|
||||
if {![catch {winfo pathname $use} name]} {
|
||||
set nDisplay [winfo screen $name]
|
||||
} else {
|
||||
# Can't have a better one
|
||||
set nDisplay $display
|
||||
}
|
||||
}
|
||||
if {$nDisplay ne $display} {
|
||||
if {$displayGiven} {
|
||||
return -code error -errorcode {TK DISPLAY SAFE} \
|
||||
"conflicting -display $display and -use $use -> $nDisplay"
|
||||
} else {
|
||||
set display $nDisplay
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Prepares the child for tk with those parameters
|
||||
tkInterpInit $child [list "-use" $use "-display" $display]
|
||||
|
||||
load {} Tk $child
|
||||
|
||||
return $child
|
||||
}
|
||||
|
||||
proc ::safe::TkInit {interpPath} {
|
||||
variable tkInit
|
||||
if {[info exists tkInit($interpPath)]} {
|
||||
set value $tkInit($interpPath)
|
||||
Log $interpPath "TkInit called, returning \"$value\"" NOTICE
|
||||
return $value
|
||||
} else {
|
||||
Log $interpPath "TkInit called for interp with clearance:\
|
||||
preventing Tk init" ERROR
|
||||
return -code error -errorcode {TK SAFE PERMISSION} "not allowed"
|
||||
}
|
||||
}
|
||||
|
||||
# safe::allowTk --
|
||||
#
|
||||
# Set tkInit(interpPath) to allow Tk to be initialized in
|
||||
# safe::TkInit.
|
||||
#
|
||||
# Arguments:
|
||||
# interpPath child interpreter handle
|
||||
# argv arguments passed to safe::TkInterpInit
|
||||
#
|
||||
# Results:
|
||||
# none.
|
||||
|
||||
proc ::safe::allowTk {interpPath argv} {
|
||||
variable tkInit
|
||||
set tkInit($interpPath) $argv
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
# safe::disallowTk --
|
||||
#
|
||||
# Unset tkInit(interpPath) to disallow Tk from getting initialized
|
||||
# in safe::TkInit.
|
||||
#
|
||||
# Arguments:
|
||||
# interpPath child interpreter handle
|
||||
#
|
||||
# Results:
|
||||
# none.
|
||||
|
||||
proc ::safe::disallowTk {interpPath} {
|
||||
variable tkInit
|
||||
# This can already be deleted by the DeleteHook of the interp
|
||||
if {[info exists tkInit($interpPath)]} {
|
||||
unset tkInit($interpPath)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
# safe::tkDelete --
|
||||
#
|
||||
# Clean up the window associated with the interp being deleted.
|
||||
#
|
||||
# Arguments:
|
||||
# interpPath child interpreter handle
|
||||
#
|
||||
# Results:
|
||||
# none.
|
||||
|
||||
proc ::safe::tkDelete {W window child} {
|
||||
|
||||
# we are going to be called for each widget... skip untill it's
|
||||
# top level
|
||||
|
||||
Log $child "Called tkDelete $W $window" NOTICE
|
||||
if {[::interp exists $child]} {
|
||||
if {[catch {::safe::interpDelete $child} msg]} {
|
||||
Log $child "Deletion error : $msg"
|
||||
}
|
||||
}
|
||||
if {[winfo exists $window]} {
|
||||
Log $child "Destroy toplevel $window" NOTICE
|
||||
destroy $window
|
||||
}
|
||||
|
||||
# clean up tkInit(child)
|
||||
disallowTk $child
|
||||
return
|
||||
}
|
||||
|
||||
proc ::safe::tkTopLevel {child display} {
|
||||
variable tkSafeId
|
||||
incr tkSafeId
|
||||
set w ".safe$tkSafeId"
|
||||
if {[catch {toplevel $w -screen $display -class SafeTk} msg]} {
|
||||
return -code error -errorcode {TK TOPLEVEL SAFE} \
|
||||
"Unable to create toplevel for \"$child\" ($msg)"
|
||||
}
|
||||
Log $child "New toplevel $w" NOTICE
|
||||
|
||||
set msg "Untrusted Tcl applet ($child)"
|
||||
wm title $w $msg
|
||||
|
||||
# Control frame (we must create a style for it)
|
||||
ttk::style layout TWarningFrame {WarningFrame.border -sticky nswe}
|
||||
ttk::style configure TWarningFrame -background red
|
||||
|
||||
set wc $w.fc
|
||||
ttk::frame $wc -relief ridge -borderwidth 4 -style TWarningFrame
|
||||
|
||||
# We will destroy the interp when the window is destroyed
|
||||
bindtags $wc [concat Safe$wc [bindtags $wc]]
|
||||
bind Safe$wc <Destroy> [list ::safe::tkDelete %W $w $child]
|
||||
|
||||
ttk::label $wc.l -text $msg -anchor w
|
||||
|
||||
# We want the button to be the last visible item
|
||||
# (so be packed first) and at the right and not resizing horizontally
|
||||
|
||||
# frame the button so it does not expand horizontally
|
||||
# but still have the default background instead of red one from the parent
|
||||
ttk::frame $wc.fb -borderwidth 0
|
||||
ttk::button $wc.fb.b -text "Delete" \
|
||||
-command [list ::safe::tkDelete $w $w $child]
|
||||
pack $wc.fb.b -side right -fill both
|
||||
pack $wc.fb -side right -fill both -expand 1
|
||||
pack $wc.l -side left -fill both -expand 1 -ipady 2
|
||||
pack $wc -side bottom -fill x
|
||||
|
||||
# Container frame
|
||||
frame $w.c -container 1
|
||||
pack $w.c -fill both -expand 1
|
||||
|
||||
# return both the toplevel window name and the id to use for embedding
|
||||
list $w [winfo id $w.c]
|
||||
}
|
||||
|
|
@ -0,0 +1,290 @@
|
|||
# scale.tcl --
|
||||
#
|
||||
# This file defines the default bindings for Tk scale widgets and provides
|
||||
# procedures that help in implementing the bindings.
|
||||
#
|
||||
# Copyright (c) 1994 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1995 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The code below creates the default class bindings for entries.
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
# Standard Motif bindings:
|
||||
|
||||
bind Scale <Enter> {
|
||||
if {$tk_strictMotif} {
|
||||
set tk::Priv(activeBg) [%W cget -activebackground]
|
||||
%W configure -activebackground [%W cget -background]
|
||||
}
|
||||
tk::ScaleActivate %W %x %y
|
||||
}
|
||||
bind Scale <Motion> {
|
||||
tk::ScaleActivate %W %x %y
|
||||
}
|
||||
bind Scale <Leave> {
|
||||
if {$tk_strictMotif} {
|
||||
%W configure -activebackground $tk::Priv(activeBg)
|
||||
}
|
||||
if {[%W cget -state] eq "active"} {
|
||||
%W configure -state normal
|
||||
}
|
||||
}
|
||||
bind Scale <1> {
|
||||
tk::ScaleButtonDown %W %x %y
|
||||
}
|
||||
bind Scale <B1-Motion> {
|
||||
tk::ScaleDrag %W %x %y
|
||||
}
|
||||
bind Scale <B1-Leave> { }
|
||||
bind Scale <B1-Enter> { }
|
||||
bind Scale <ButtonRelease-1> {
|
||||
tk::CancelRepeat
|
||||
tk::ScaleEndDrag %W
|
||||
tk::ScaleActivate %W %x %y
|
||||
}
|
||||
bind Scale <2> {
|
||||
tk::ScaleButton2Down %W %x %y
|
||||
}
|
||||
bind Scale <B2-Motion> {
|
||||
tk::ScaleDrag %W %x %y
|
||||
}
|
||||
bind Scale <B2-Leave> { }
|
||||
bind Scale <B2-Enter> { }
|
||||
bind Scale <ButtonRelease-2> {
|
||||
tk::CancelRepeat
|
||||
tk::ScaleEndDrag %W
|
||||
tk::ScaleActivate %W %x %y
|
||||
}
|
||||
if {[tk windowingsystem] eq "win32"} {
|
||||
# On Windows do the same with button 3, as that is the right mouse button
|
||||
bind Scale <3> [bind Scale <2>]
|
||||
bind Scale <B3-Motion> [bind Scale <B2-Motion>]
|
||||
bind Scale <B3-Leave> [bind Scale <B2-Leave>]
|
||||
bind Scale <B3-Enter> [bind Scale <B2-Enter>]
|
||||
bind Scale <ButtonRelease-3> [bind Scale <ButtonRelease-2>]
|
||||
}
|
||||
bind Scale <Control-1> {
|
||||
tk::ScaleControlPress %W %x %y
|
||||
}
|
||||
bind Scale <<PrevLine>> {
|
||||
tk::ScaleIncrement %W up little noRepeat
|
||||
}
|
||||
bind Scale <<NextLine>> {
|
||||
tk::ScaleIncrement %W down little noRepeat
|
||||
}
|
||||
bind Scale <<PrevChar>> {
|
||||
tk::ScaleIncrement %W up little noRepeat
|
||||
}
|
||||
bind Scale <<NextChar>> {
|
||||
tk::ScaleIncrement %W down little noRepeat
|
||||
}
|
||||
bind Scale <<PrevPara>> {
|
||||
tk::ScaleIncrement %W up big noRepeat
|
||||
}
|
||||
bind Scale <<NextPara>> {
|
||||
tk::ScaleIncrement %W down big noRepeat
|
||||
}
|
||||
bind Scale <<PrevWord>> {
|
||||
tk::ScaleIncrement %W up big noRepeat
|
||||
}
|
||||
bind Scale <<NextWord>> {
|
||||
tk::ScaleIncrement %W down big noRepeat
|
||||
}
|
||||
bind Scale <<LineStart>> {
|
||||
%W set [%W cget -from]
|
||||
}
|
||||
bind Scale <<LineEnd>> {
|
||||
%W set [%W cget -to]
|
||||
}
|
||||
|
||||
# ::tk::ScaleActivate --
|
||||
# This procedure is invoked to check a given x-y position in the
|
||||
# scale and activate the slider if the x-y position falls within
|
||||
# the slider.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scale widget.
|
||||
# x, y - Mouse coordinates.
|
||||
|
||||
proc ::tk::ScaleActivate {w x y} {
|
||||
if {[$w cget -state] eq "disabled"} {
|
||||
return
|
||||
}
|
||||
if {[$w identify $x $y] eq "slider"} {
|
||||
set state active
|
||||
} else {
|
||||
set state normal
|
||||
}
|
||||
if {[$w cget -state] ne $state} {
|
||||
$w configure -state $state
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScaleButtonDown --
|
||||
# This procedure is invoked when a button is pressed in a scale. It
|
||||
# takes different actions depending on where the button was pressed.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scale widget.
|
||||
# x, y - Mouse coordinates of button press.
|
||||
|
||||
proc ::tk::ScaleButtonDown {w x y} {
|
||||
variable ::tk::Priv
|
||||
set Priv(dragging) 0
|
||||
set el [$w identify $x $y]
|
||||
|
||||
# save the relief
|
||||
set Priv($w,relief) [$w cget -sliderrelief]
|
||||
|
||||
if {$el eq "trough1"} {
|
||||
ScaleIncrement $w up little initial
|
||||
} elseif {$el eq "trough2"} {
|
||||
ScaleIncrement $w down little initial
|
||||
} elseif {$el eq "slider"} {
|
||||
set Priv(dragging) 1
|
||||
set Priv(initValue) [$w get]
|
||||
set coords [$w coords]
|
||||
set Priv(deltaX) [expr {$x - [lindex $coords 0]}]
|
||||
set Priv(deltaY) [expr {$y - [lindex $coords 1]}]
|
||||
switch -exact -- $Priv($w,relief) {
|
||||
"raised" { $w configure -sliderrelief sunken }
|
||||
"ridge" { $w configure -sliderrelief groove }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScaleDrag --
|
||||
# This procedure is called when the mouse is dragged with
|
||||
# mouse button 1 down. If the drag started inside the slider
|
||||
# (i.e. the scale is active) then the scale's value is adjusted
|
||||
# to reflect the mouse's position.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scale widget.
|
||||
# x, y - Mouse coordinates.
|
||||
|
||||
proc ::tk::ScaleDrag {w x y} {
|
||||
variable ::tk::Priv
|
||||
if {!$Priv(dragging)} {
|
||||
return
|
||||
}
|
||||
$w set [$w get [expr {$x-$Priv(deltaX)}] [expr {$y-$Priv(deltaY)}]]
|
||||
}
|
||||
|
||||
# ::tk::ScaleEndDrag --
|
||||
# This procedure is called to end an interactive drag of the
|
||||
# slider. It just marks the drag as over.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scale widget.
|
||||
|
||||
proc ::tk::ScaleEndDrag {w} {
|
||||
variable ::tk::Priv
|
||||
set Priv(dragging) 0
|
||||
if {[info exists Priv($w,relief)]} {
|
||||
$w configure -sliderrelief $Priv($w,relief)
|
||||
unset Priv($w,relief)
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScaleIncrement --
|
||||
# This procedure is invoked to increment the value of a scale and
|
||||
# to set up auto-repeating of the action if that is desired. The
|
||||
# way the value is incremented depends on the "dir" and "big"
|
||||
# arguments.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scale widget.
|
||||
# dir - "up" means move value towards -from, "down" means
|
||||
# move towards -to.
|
||||
# big - Size of increments: "big" or "little".
|
||||
# repeat - Whether and how to auto-repeat the action: "noRepeat"
|
||||
# means don't auto-repeat, "initial" means this is the
|
||||
# first action in an auto-repeat sequence, and "again"
|
||||
# means this is the second repetition or later.
|
||||
|
||||
proc ::tk::ScaleIncrement {w dir big repeat} {
|
||||
variable ::tk::Priv
|
||||
if {![winfo exists $w]} return
|
||||
if {$big eq "big"} {
|
||||
set inc [$w cget -bigincrement]
|
||||
if {$inc == 0} {
|
||||
set inc [expr {abs([$w cget -to] - [$w cget -from])/10.0}]
|
||||
}
|
||||
if {$inc < [$w cget -resolution]} {
|
||||
set inc [$w cget -resolution]
|
||||
}
|
||||
} else {
|
||||
set inc [$w cget -resolution]
|
||||
}
|
||||
if {([$w cget -from] > [$w cget -to]) ^ ($dir eq "up")} {
|
||||
if {$inc > 0} {
|
||||
set inc [expr {-$inc}]
|
||||
}
|
||||
} else {
|
||||
if {$inc < 0} {
|
||||
set inc [expr {-$inc}]
|
||||
}
|
||||
}
|
||||
$w set [expr {[$w get] + $inc}]
|
||||
|
||||
if {$repeat eq "again"} {
|
||||
set Priv(afterId) [after [$w cget -repeatinterval] \
|
||||
[list tk::ScaleIncrement $w $dir $big again]]
|
||||
} elseif {$repeat eq "initial"} {
|
||||
set delay [$w cget -repeatdelay]
|
||||
if {$delay > 0} {
|
||||
set Priv(afterId) [after $delay \
|
||||
[list tk::ScaleIncrement $w $dir $big again]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScaleControlPress --
|
||||
# This procedure handles button presses that are made with the Control
|
||||
# key down. Depending on the mouse position, it adjusts the scale
|
||||
# value to one end of the range or the other.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scale widget.
|
||||
# x, y - Mouse coordinates where the button was pressed.
|
||||
|
||||
proc ::tk::ScaleControlPress {w x y} {
|
||||
set el [$w identify $x $y]
|
||||
if {$el eq "trough1"} {
|
||||
$w set [$w cget -from]
|
||||
} elseif {$el eq "trough2"} {
|
||||
$w set [$w cget -to]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScaleButton2Down
|
||||
# This procedure is invoked when button 2 is pressed over a scale.
|
||||
# It sets the value to correspond to the mouse position and starts
|
||||
# a slider drag.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# x, y - Mouse coordinates within the widget.
|
||||
|
||||
proc ::tk::ScaleButton2Down {w x y} {
|
||||
variable ::tk::Priv
|
||||
|
||||
if {[$w cget -state] eq "disabled"} {
|
||||
return
|
||||
}
|
||||
|
||||
$w configure -state active
|
||||
$w set [$w get $x $y]
|
||||
set Priv(dragging) 1
|
||||
set Priv(initValue) [$w get]
|
||||
set Priv($w,relief) [$w cget -sliderrelief]
|
||||
set coords "$x $y"
|
||||
set Priv(deltaX) 0
|
||||
set Priv(deltaY) 0
|
||||
}
|
||||
|
|
@ -0,0 +1,456 @@
|
|||
# scrlbar.tcl --
|
||||
#
|
||||
# This file defines the default bindings for Tk scrollbar widgets.
|
||||
# It also provides procedures that help in implementing the bindings.
|
||||
#
|
||||
# Copyright (c) 1994 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1996 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The code below creates the default class bindings for scrollbars.
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
# Standard Motif bindings:
|
||||
if {[tk windowingsystem] eq "x11" || [tk windowingsystem] eq "aqua"} {
|
||||
|
||||
bind Scrollbar <Enter> {
|
||||
if {$tk_strictMotif} {
|
||||
set tk::Priv(activeBg) [%W cget -activebackground]
|
||||
%W configure -activebackground [%W cget -background]
|
||||
}
|
||||
%W activate [%W identify %x %y]
|
||||
}
|
||||
bind Scrollbar <Motion> {
|
||||
%W activate [%W identify %x %y]
|
||||
}
|
||||
|
||||
# The "info exists" command in the following binding handles the
|
||||
# situation where a Leave event occurs for a scrollbar without the Enter
|
||||
# event. This seems to happen on some systems (such as Solaris 2.4) for
|
||||
# unknown reasons.
|
||||
|
||||
bind Scrollbar <Leave> {
|
||||
if {$tk_strictMotif && [info exists tk::Priv(activeBg)]} {
|
||||
%W configure -activebackground $tk::Priv(activeBg)
|
||||
}
|
||||
%W activate {}
|
||||
}
|
||||
bind Scrollbar <1> {
|
||||
tk::ScrollButtonDown %W %x %y
|
||||
}
|
||||
bind Scrollbar <B1-Motion> {
|
||||
tk::ScrollDrag %W %x %y
|
||||
}
|
||||
bind Scrollbar <B1-B2-Motion> {
|
||||
tk::ScrollDrag %W %x %y
|
||||
}
|
||||
bind Scrollbar <ButtonRelease-1> {
|
||||
tk::ScrollButtonUp %W %x %y
|
||||
}
|
||||
bind Scrollbar <B1-Leave> {
|
||||
# Prevents <Leave> binding from being invoked.
|
||||
}
|
||||
bind Scrollbar <B1-Enter> {
|
||||
# Prevents <Enter> binding from being invoked.
|
||||
}
|
||||
bind Scrollbar <2> {
|
||||
tk::ScrollButton2Down %W %x %y
|
||||
}
|
||||
bind Scrollbar <B1-2> {
|
||||
# Do nothing, since button 1 is already down.
|
||||
}
|
||||
bind Scrollbar <B2-1> {
|
||||
# Do nothing, since button 2 is already down.
|
||||
}
|
||||
bind Scrollbar <B2-Motion> {
|
||||
tk::ScrollDrag %W %x %y
|
||||
}
|
||||
bind Scrollbar <ButtonRelease-2> {
|
||||
tk::ScrollButtonUp %W %x %y
|
||||
}
|
||||
bind Scrollbar <B1-ButtonRelease-2> {
|
||||
# Do nothing: B1 release will handle it.
|
||||
}
|
||||
bind Scrollbar <B2-ButtonRelease-1> {
|
||||
# Do nothing: B2 release will handle it.
|
||||
}
|
||||
bind Scrollbar <B2-Leave> {
|
||||
# Prevents <Leave> binding from being invoked.
|
||||
}
|
||||
bind Scrollbar <B2-Enter> {
|
||||
# Prevents <Enter> binding from being invoked.
|
||||
}
|
||||
bind Scrollbar <Control-1> {
|
||||
tk::ScrollTopBottom %W %x %y
|
||||
}
|
||||
bind Scrollbar <Control-2> {
|
||||
tk::ScrollTopBottom %W %x %y
|
||||
}
|
||||
|
||||
bind Scrollbar <<PrevLine>> {
|
||||
tk::ScrollByUnits %W v -1
|
||||
}
|
||||
bind Scrollbar <<NextLine>> {
|
||||
tk::ScrollByUnits %W v 1
|
||||
}
|
||||
bind Scrollbar <<PrevPara>> {
|
||||
tk::ScrollByPages %W v -1
|
||||
}
|
||||
bind Scrollbar <<NextPara>> {
|
||||
tk::ScrollByPages %W v 1
|
||||
}
|
||||
bind Scrollbar <<PrevChar>> {
|
||||
tk::ScrollByUnits %W h -1
|
||||
}
|
||||
bind Scrollbar <<NextChar>> {
|
||||
tk::ScrollByUnits %W h 1
|
||||
}
|
||||
bind Scrollbar <<PrevWord>> {
|
||||
tk::ScrollByPages %W h -1
|
||||
}
|
||||
bind Scrollbar <<NextWord>> {
|
||||
tk::ScrollByPages %W h 1
|
||||
}
|
||||
bind Scrollbar <Prior> {
|
||||
tk::ScrollByPages %W hv -1
|
||||
}
|
||||
bind Scrollbar <Next> {
|
||||
tk::ScrollByPages %W hv 1
|
||||
}
|
||||
bind Scrollbar <<LineStart>> {
|
||||
tk::ScrollToPos %W 0
|
||||
}
|
||||
bind Scrollbar <<LineEnd>> {
|
||||
tk::ScrollToPos %W 1
|
||||
}
|
||||
}
|
||||
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
bind Scrollbar <MouseWheel> {
|
||||
tk::ScrollByUnits %W v [expr {-(%D)}]
|
||||
}
|
||||
bind Scrollbar <Option-MouseWheel> {
|
||||
tk::ScrollByUnits %W v [expr {-10 * (%D)}]
|
||||
}
|
||||
bind Scrollbar <Shift-MouseWheel> {
|
||||
tk::ScrollByUnits %W h [expr {-(%D)}]
|
||||
}
|
||||
bind Scrollbar <Shift-Option-MouseWheel> {
|
||||
tk::ScrollByUnits %W h [expr {-10 * (%D)}]
|
||||
}
|
||||
} else {
|
||||
bind Scrollbar <MouseWheel> {
|
||||
if {%D >= 0} {
|
||||
tk::ScrollByUnits %W v [expr {-%D/30}]
|
||||
} else {
|
||||
tk::ScrollByUnits %W v [expr {(29-%D)/30}]
|
||||
}
|
||||
}
|
||||
bind Scrollbar <Shift-MouseWheel> {
|
||||
if {%D >= 0} {
|
||||
tk::ScrollByUnits %W h [expr {-%D/30}]
|
||||
} else {
|
||||
tk::ScrollByUnits %W h [expr {(29-%D)/30}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {[tk windowingsystem] eq "x11"} {
|
||||
bind Scrollbar <4> {tk::ScrollByUnits %W v -5}
|
||||
bind Scrollbar <5> {tk::ScrollByUnits %W v 5}
|
||||
bind Scrollbar <Shift-4> {tk::ScrollByUnits %W h -5}
|
||||
bind Scrollbar <Shift-5> {tk::ScrollByUnits %W h 5}
|
||||
}
|
||||
|
||||
# tk::ScrollButtonDown --
|
||||
# This procedure is invoked when a button is pressed in a scrollbar.
|
||||
# It changes the way the scrollbar is displayed and takes actions
|
||||
# depending on where the mouse is.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# x, y - Mouse coordinates.
|
||||
|
||||
proc tk::ScrollButtonDown {w x y} {
|
||||
variable ::tk::Priv
|
||||
set Priv(relief) [$w cget -activerelief]
|
||||
$w configure -activerelief sunken
|
||||
set element [$w identify $x $y]
|
||||
if {$element eq "slider"} {
|
||||
ScrollStartDrag $w $x $y
|
||||
} else {
|
||||
ScrollSelect $w $element initial
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScrollButtonUp --
|
||||
# This procedure is invoked when a button is released in a scrollbar.
|
||||
# It cancels scans and auto-repeats that were in progress, and restores
|
||||
# the way the active element is displayed.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# x, y - Mouse coordinates.
|
||||
|
||||
proc ::tk::ScrollButtonUp {w x y} {
|
||||
variable ::tk::Priv
|
||||
tk::CancelRepeat
|
||||
if {[info exists Priv(relief)]} {
|
||||
# Avoid error due to spurious release events
|
||||
$w configure -activerelief $Priv(relief)
|
||||
ScrollEndDrag $w $x $y
|
||||
$w activate [$w identify $x $y]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScrollSelect --
|
||||
# This procedure is invoked when a button is pressed over the scrollbar.
|
||||
# It invokes one of several scrolling actions depending on where in
|
||||
# the scrollbar the button was pressed.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# element - The element of the scrollbar that was selected, such
|
||||
# as "arrow1" or "trough2". Shouldn't be "slider".
|
||||
# repeat - Whether and how to auto-repeat the action: "noRepeat"
|
||||
# means don't auto-repeat, "initial" means this is the
|
||||
# first action in an auto-repeat sequence, and "again"
|
||||
# means this is the second repetition or later.
|
||||
|
||||
proc ::tk::ScrollSelect {w element repeat} {
|
||||
variable ::tk::Priv
|
||||
if {![winfo exists $w]} return
|
||||
switch -- $element {
|
||||
"arrow1" {ScrollByUnits $w hv -1}
|
||||
"trough1" {ScrollByPages $w hv -1}
|
||||
"trough2" {ScrollByPages $w hv 1}
|
||||
"arrow2" {ScrollByUnits $w hv 1}
|
||||
default {return}
|
||||
}
|
||||
if {$repeat eq "again"} {
|
||||
set Priv(afterId) [after [$w cget -repeatinterval] \
|
||||
[list tk::ScrollSelect $w $element again]]
|
||||
} elseif {$repeat eq "initial"} {
|
||||
set delay [$w cget -repeatdelay]
|
||||
if {$delay > 0} {
|
||||
set Priv(afterId) [after $delay \
|
||||
[list tk::ScrollSelect $w $element again]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScrollStartDrag --
|
||||
# This procedure is called to initiate a drag of the slider. It just
|
||||
# remembers the starting position of the mouse and slider.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# x, y - The mouse position at the start of the drag operation.
|
||||
|
||||
proc ::tk::ScrollStartDrag {w x y} {
|
||||
variable ::tk::Priv
|
||||
|
||||
if {[$w cget -command] eq ""} {
|
||||
return
|
||||
}
|
||||
set Priv(pressX) $x
|
||||
set Priv(pressY) $y
|
||||
set Priv(initValues) [$w get]
|
||||
set iv0 [lindex $Priv(initValues) 0]
|
||||
if {[llength $Priv(initValues)] == 2} {
|
||||
set Priv(initPos) $iv0
|
||||
} elseif {$iv0 == 0} {
|
||||
set Priv(initPos) 0.0
|
||||
} else {
|
||||
set Priv(initPos) [expr {(double([lindex $Priv(initValues) 2])) \
|
||||
/ [lindex $Priv(initValues) 0]}]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScrollDrag --
|
||||
# This procedure is called for each mouse motion even when the slider
|
||||
# is being dragged. It notifies the associated widget if we're not
|
||||
# jump scrolling, and it just updates the scrollbar if we are jump
|
||||
# scrolling.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# x, y - The current mouse position.
|
||||
|
||||
proc ::tk::ScrollDrag {w x y} {
|
||||
variable ::tk::Priv
|
||||
|
||||
if {$Priv(initPos) eq ""} {
|
||||
return
|
||||
}
|
||||
set delta [$w delta [expr {$x - $Priv(pressX)}] [expr {$y - $Priv(pressY)}]]
|
||||
if {[$w cget -jump]} {
|
||||
if {[llength $Priv(initValues)] == 2} {
|
||||
$w set [expr {[lindex $Priv(initValues) 0] + $delta}] \
|
||||
[expr {[lindex $Priv(initValues) 1] + $delta}]
|
||||
} else {
|
||||
set delta [expr {round($delta * [lindex $Priv(initValues) 0])}]
|
||||
eval [list $w] set [lreplace $Priv(initValues) 2 3 \
|
||||
[expr {[lindex $Priv(initValues) 2] + $delta}] \
|
||||
[expr {[lindex $Priv(initValues) 3] + $delta}]]
|
||||
}
|
||||
} else {
|
||||
ScrollToPos $w [expr {$Priv(initPos) + $delta}]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScrollEndDrag --
|
||||
# This procedure is called to end an interactive drag of the slider.
|
||||
# It scrolls the window if we're in jump mode, otherwise it does nothing.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# x, y - The mouse position at the end of the drag operation.
|
||||
|
||||
proc ::tk::ScrollEndDrag {w x y} {
|
||||
variable ::tk::Priv
|
||||
|
||||
if {$Priv(initPos) eq ""} {
|
||||
return
|
||||
}
|
||||
if {[$w cget -jump]} {
|
||||
set delta [$w delta [expr {$x - $Priv(pressX)}] \
|
||||
[expr {$y - $Priv(pressY)}]]
|
||||
ScrollToPos $w [expr {$Priv(initPos) + $delta}]
|
||||
}
|
||||
set Priv(initPos) ""
|
||||
}
|
||||
|
||||
# ::tk::ScrollByUnits --
|
||||
# This procedure tells the scrollbar's associated widget to scroll up
|
||||
# or down by a given number of units. It notifies the associated widget
|
||||
# in different ways for old and new command syntaxes.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# orient - Which kinds of scrollbars this applies to: "h" for
|
||||
# horizontal, "v" for vertical, "hv" for both.
|
||||
# amount - How many units to scroll: typically 1 or -1.
|
||||
|
||||
proc ::tk::ScrollByUnits {w orient amount} {
|
||||
set cmd [$w cget -command]
|
||||
if {$cmd eq "" || ([string first \
|
||||
[string index [$w cget -orient] 0] $orient] < 0)} {
|
||||
return
|
||||
}
|
||||
set info [$w get]
|
||||
if {[llength $info] == 2} {
|
||||
uplevel #0 $cmd scroll $amount units
|
||||
} else {
|
||||
uplevel #0 $cmd [expr {[lindex $info 2] + $amount}]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScrollByPages --
|
||||
# This procedure tells the scrollbar's associated widget to scroll up
|
||||
# or down by a given number of screenfuls. It notifies the associated
|
||||
# widget in different ways for old and new command syntaxes.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# orient - Which kinds of scrollbars this applies to: "h" for
|
||||
# horizontal, "v" for vertical, "hv" for both.
|
||||
# amount - How many screens to scroll: typically 1 or -1.
|
||||
|
||||
proc ::tk::ScrollByPages {w orient amount} {
|
||||
set cmd [$w cget -command]
|
||||
if {$cmd eq "" || ([string first \
|
||||
[string index [$w cget -orient] 0] $orient] < 0)} {
|
||||
return
|
||||
}
|
||||
set info [$w get]
|
||||
if {[llength $info] == 2} {
|
||||
uplevel #0 $cmd scroll $amount pages
|
||||
} else {
|
||||
uplevel #0 $cmd [expr {[lindex $info 2] + $amount*([lindex $info 1] - 1)}]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScrollToPos --
|
||||
# This procedure tells the scrollbar's associated widget to scroll to
|
||||
# a particular location, given by a fraction between 0 and 1. It notifies
|
||||
# the associated widget in different ways for old and new command syntaxes.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# pos - A fraction between 0 and 1 indicating a desired position
|
||||
# in the document.
|
||||
|
||||
proc ::tk::ScrollToPos {w pos} {
|
||||
set cmd [$w cget -command]
|
||||
if {$cmd eq ""} {
|
||||
return
|
||||
}
|
||||
set info [$w get]
|
||||
if {[llength $info] == 2} {
|
||||
uplevel #0 $cmd moveto $pos
|
||||
} else {
|
||||
uplevel #0 $cmd [expr {round([lindex $info 0]*$pos)}]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScrollTopBottom
|
||||
# Scroll to the top or bottom of the document, depending on the mouse
|
||||
# position.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# x, y - Mouse coordinates within the widget.
|
||||
|
||||
proc ::tk::ScrollTopBottom {w x y} {
|
||||
variable ::tk::Priv
|
||||
set element [$w identify $x $y]
|
||||
if {[string match *1 $element]} {
|
||||
ScrollToPos $w 0
|
||||
} elseif {[string match *2 $element]} {
|
||||
ScrollToPos $w 1
|
||||
}
|
||||
|
||||
# Set Priv(relief), since it's needed by tk::ScrollButtonUp.
|
||||
|
||||
set Priv(relief) [$w cget -activerelief]
|
||||
}
|
||||
|
||||
# ::tk::ScrollButton2Down
|
||||
# This procedure is invoked when button 2 is pressed over a scrollbar.
|
||||
# If the button is over the trough or slider, it sets the scrollbar to
|
||||
# the mouse position and starts a slider drag. Otherwise it just
|
||||
# behaves the same as button 1.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The scrollbar widget.
|
||||
# x, y - Mouse coordinates within the widget.
|
||||
|
||||
proc ::tk::ScrollButton2Down {w x y} {
|
||||
variable ::tk::Priv
|
||||
if {![winfo exists $w]} {
|
||||
return
|
||||
}
|
||||
set element [$w identify $x $y]
|
||||
if {[string match {arrow[12]} $element]} {
|
||||
ScrollButtonDown $w $x $y
|
||||
return
|
||||
}
|
||||
ScrollToPos $w [$w fraction $x $y]
|
||||
set Priv(relief) [$w cget -activerelief]
|
||||
|
||||
# Need the "update idletasks" below so that the widget calls us
|
||||
# back to reset the actual scrollbar position before we start the
|
||||
# slider drag.
|
||||
|
||||
update idletasks
|
||||
if {[winfo exists $w]} {
|
||||
$w configure -activerelief sunken
|
||||
$w activate slider
|
||||
ScrollStartDrag $w $x $y
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,593 @@
|
|||
# spinbox.tcl --
|
||||
#
|
||||
# This file defines the default bindings for Tk spinbox widgets and provides
|
||||
# procedures that help in implementing those bindings. The spinbox builds
|
||||
# off the entry widget, so it can reuse Entry bindings and procedures.
|
||||
#
|
||||
# Copyright (c) 1992-1994 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1997 Sun Microsystems, Inc.
|
||||
# Copyright (c) 1999-2000 Jeffrey Hobbs
|
||||
# Copyright (c) 2000 Ajuba Solutions
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Elements of tk::Priv that are used in this file:
|
||||
#
|
||||
# afterId - If non-null, it means that auto-scanning is underway
|
||||
# and it gives the "after" id for the next auto-scan
|
||||
# command to be executed.
|
||||
# mouseMoved - Non-zero means the mouse has moved a significant
|
||||
# amount since the button went down (so, for example,
|
||||
# start dragging out a selection).
|
||||
# pressX - X-coordinate at which the mouse button was pressed.
|
||||
# selectMode - The style of selection currently underway:
|
||||
# char, word, or line.
|
||||
# x, y - Last known mouse coordinates for scanning
|
||||
# and auto-scanning.
|
||||
# data - Used for Cut and Copy
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
# Initialize namespace
|
||||
namespace eval ::tk::spinbox {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The code below creates the default class bindings for entries.
|
||||
#-------------------------------------------------------------------------
|
||||
bind Spinbox <<Cut>> {
|
||||
if {![catch {::tk::spinbox::GetSelection %W} tk::Priv(data)]} {
|
||||
clipboard clear -displayof %W
|
||||
clipboard append -displayof %W $tk::Priv(data)
|
||||
%W delete sel.first sel.last
|
||||
unset tk::Priv(data)
|
||||
}
|
||||
}
|
||||
bind Spinbox <<Copy>> {
|
||||
if {![catch {::tk::spinbox::GetSelection %W} tk::Priv(data)]} {
|
||||
clipboard clear -displayof %W
|
||||
clipboard append -displayof %W $tk::Priv(data)
|
||||
unset tk::Priv(data)
|
||||
}
|
||||
}
|
||||
bind Spinbox <<Paste>> {
|
||||
catch {
|
||||
if {[tk windowingsystem] ne "x11"} {
|
||||
catch {
|
||||
%W delete sel.first sel.last
|
||||
}
|
||||
}
|
||||
%W insert insert [::tk::GetSelection %W CLIPBOARD]
|
||||
::tk::EntrySeeInsert %W
|
||||
}
|
||||
}
|
||||
bind Spinbox <<Clear>> {
|
||||
%W delete sel.first sel.last
|
||||
}
|
||||
bind Spinbox <<PasteSelection>> {
|
||||
if {$tk_strictMotif || ![info exists tk::Priv(mouseMoved)]
|
||||
|| !$tk::Priv(mouseMoved)} {
|
||||
::tk::spinbox::Paste %W %x
|
||||
}
|
||||
}
|
||||
|
||||
bind Spinbox <<TraverseIn>> {
|
||||
%W selection range 0 end
|
||||
%W icursor end
|
||||
}
|
||||
|
||||
# Standard Motif bindings:
|
||||
|
||||
bind Spinbox <1> {
|
||||
::tk::spinbox::ButtonDown %W %x %y
|
||||
}
|
||||
bind Spinbox <B1-Motion> {
|
||||
::tk::spinbox::Motion %W %x %y
|
||||
}
|
||||
bind Spinbox <Double-1> {
|
||||
::tk::spinbox::ArrowPress %W %x %y
|
||||
set tk::Priv(selectMode) word
|
||||
::tk::spinbox::MouseSelect %W %x sel.first
|
||||
}
|
||||
bind Spinbox <Triple-1> {
|
||||
::tk::spinbox::ArrowPress %W %x %y
|
||||
set tk::Priv(selectMode) line
|
||||
::tk::spinbox::MouseSelect %W %x 0
|
||||
}
|
||||
bind Spinbox <Shift-1> {
|
||||
set tk::Priv(selectMode) char
|
||||
%W selection adjust @%x
|
||||
}
|
||||
bind Spinbox <Double-Shift-1> {
|
||||
set tk::Priv(selectMode) word
|
||||
::tk::spinbox::MouseSelect %W %x
|
||||
}
|
||||
bind Spinbox <Triple-Shift-1> {
|
||||
set tk::Priv(selectMode) line
|
||||
::tk::spinbox::MouseSelect %W %x
|
||||
}
|
||||
bind Spinbox <B1-Leave> {
|
||||
set tk::Priv(x) %x
|
||||
::tk::spinbox::AutoScan %W
|
||||
}
|
||||
bind Spinbox <B1-Enter> {
|
||||
tk::CancelRepeat
|
||||
}
|
||||
bind Spinbox <ButtonRelease-1> {
|
||||
::tk::spinbox::ButtonUp %W %x %y
|
||||
}
|
||||
bind Spinbox <Control-1> {
|
||||
%W icursor @%x
|
||||
}
|
||||
|
||||
bind Spinbox <<PrevLine>> {
|
||||
%W invoke buttonup
|
||||
}
|
||||
bind Spinbox <<NextLine>> {
|
||||
%W invoke buttondown
|
||||
}
|
||||
|
||||
bind Spinbox <<PrevChar>> {
|
||||
::tk::EntrySetCursor %W [expr {[%W index insert] - 1}]
|
||||
}
|
||||
bind Spinbox <<NextChar>> {
|
||||
::tk::EntrySetCursor %W [expr {[%W index insert] + 1}]
|
||||
}
|
||||
bind Spinbox <<SelectPrevChar>> {
|
||||
::tk::EntryKeySelect %W [expr {[%W index insert] - 1}]
|
||||
::tk::EntrySeeInsert %W
|
||||
}
|
||||
bind Spinbox <<SelectNextChar>> {
|
||||
::tk::EntryKeySelect %W [expr {[%W index insert] + 1}]
|
||||
::tk::EntrySeeInsert %W
|
||||
}
|
||||
bind Spinbox <<PrevWord>> {
|
||||
::tk::EntrySetCursor %W [::tk::EntryPreviousWord %W insert]
|
||||
}
|
||||
bind Spinbox <<NextWord>> {
|
||||
::tk::EntrySetCursor %W [::tk::EntryNextWord %W insert]
|
||||
}
|
||||
bind Spinbox <<SelectPrevWord>> {
|
||||
::tk::EntryKeySelect %W [::tk::EntryPreviousWord %W insert]
|
||||
::tk::EntrySeeInsert %W
|
||||
}
|
||||
bind Spinbox <<SelectNextWord>> {
|
||||
::tk::EntryKeySelect %W [::tk::EntryNextWord %W insert]
|
||||
::tk::EntrySeeInsert %W
|
||||
}
|
||||
bind Spinbox <<LineStart>> {
|
||||
::tk::EntrySetCursor %W 0
|
||||
}
|
||||
bind Spinbox <<SelectLineStart>> {
|
||||
::tk::EntryKeySelect %W 0
|
||||
::tk::EntrySeeInsert %W
|
||||
}
|
||||
bind Spinbox <<LineEnd>> {
|
||||
::tk::EntrySetCursor %W end
|
||||
}
|
||||
bind Spinbox <<SelectLineEnd>> {
|
||||
::tk::EntryKeySelect %W end
|
||||
::tk::EntrySeeInsert %W
|
||||
}
|
||||
|
||||
bind Spinbox <Delete> {
|
||||
if {[%W selection present]} {
|
||||
%W delete sel.first sel.last
|
||||
} else {
|
||||
%W delete insert
|
||||
}
|
||||
}
|
||||
bind Spinbox <BackSpace> {
|
||||
::tk::EntryBackspace %W
|
||||
}
|
||||
|
||||
bind Spinbox <Control-space> {
|
||||
%W selection from insert
|
||||
}
|
||||
bind Spinbox <Select> {
|
||||
%W selection from insert
|
||||
}
|
||||
bind Spinbox <Control-Shift-space> {
|
||||
%W selection adjust insert
|
||||
}
|
||||
bind Spinbox <Shift-Select> {
|
||||
%W selection adjust insert
|
||||
}
|
||||
bind Spinbox <<SelectAll>> {
|
||||
%W selection range 0 end
|
||||
}
|
||||
bind Spinbox <<SelectNone>> {
|
||||
%W selection clear
|
||||
}
|
||||
bind Spinbox <KeyPress> {
|
||||
::tk::EntryInsert %W %A
|
||||
}
|
||||
|
||||
# Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
|
||||
# Otherwise, if a widget binding for one of these is defined, the
|
||||
# <KeyPress> class binding will also fire and insert the character,
|
||||
# which is wrong. Ditto for Escape, Return, and Tab.
|
||||
|
||||
bind Spinbox <Alt-KeyPress> {# nothing}
|
||||
bind Spinbox <Meta-KeyPress> {# nothing}
|
||||
bind Spinbox <Control-KeyPress> {# nothing}
|
||||
bind Spinbox <Escape> {# nothing}
|
||||
bind Spinbox <Return> {# nothing}
|
||||
bind Spinbox <KP_Enter> {# nothing}
|
||||
bind Spinbox <Tab> {# nothing}
|
||||
bind Spinbox <Prior> {# nothing}
|
||||
bind Spinbox <Next> {# nothing}
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
bind Spinbox <Command-KeyPress> {# nothing}
|
||||
}
|
||||
|
||||
# On Windows, paste is done using Shift-Insert. Shift-Insert already
|
||||
# generates the <<Paste>> event, so we don't need to do anything here.
|
||||
if {[tk windowingsystem] ne "win32"} {
|
||||
bind Spinbox <Insert> {
|
||||
catch {::tk::EntryInsert %W [::tk::GetSelection %W PRIMARY]}
|
||||
}
|
||||
}
|
||||
|
||||
# Additional emacs-like bindings:
|
||||
|
||||
bind Spinbox <Control-d> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W delete insert
|
||||
}
|
||||
}
|
||||
bind Spinbox <Control-h> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntryBackspace %W
|
||||
}
|
||||
}
|
||||
bind Spinbox <Control-k> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W delete insert end
|
||||
}
|
||||
}
|
||||
bind Spinbox <Control-t> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntryTranspose %W
|
||||
}
|
||||
}
|
||||
bind Spinbox <Meta-b> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntrySetCursor %W [::tk::EntryPreviousWord %W insert]
|
||||
}
|
||||
}
|
||||
bind Spinbox <Meta-d> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W delete insert [::tk::EntryNextWord %W insert]
|
||||
}
|
||||
}
|
||||
bind Spinbox <Meta-f> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntrySetCursor %W [::tk::EntryNextWord %W insert]
|
||||
}
|
||||
}
|
||||
bind Spinbox <Meta-BackSpace> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W delete [::tk::EntryPreviousWord %W insert] insert
|
||||
}
|
||||
}
|
||||
bind Spinbox <Meta-Delete> {
|
||||
if {!$tk_strictMotif} {
|
||||
%W delete [::tk::EntryPreviousWord %W insert] insert
|
||||
}
|
||||
}
|
||||
|
||||
# A few additional bindings of my own.
|
||||
|
||||
if {[tk windowingsystem] ne "aqua"} {
|
||||
bind Spinbox <2> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntryScanMark %W %x
|
||||
}
|
||||
}
|
||||
bind Spinbox <B2-Motion> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntryScanDrag %W %x
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bind Spinbox <3> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntryScanMark %W %x
|
||||
}
|
||||
}
|
||||
bind Spinbox <B3-Motion> {
|
||||
if {!$tk_strictMotif} {
|
||||
::tk::EntryScanDrag %W %x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::spinbox::Invoke --
|
||||
# Invoke an element of the spinbox
|
||||
#
|
||||
# Arguments:
|
||||
# w - The spinbox window.
|
||||
# elem - Element to invoke
|
||||
|
||||
proc ::tk::spinbox::Invoke {w elem} {
|
||||
variable ::tk::Priv
|
||||
|
||||
if {![winfo exists $w]} {
|
||||
return
|
||||
}
|
||||
|
||||
if {![info exists Priv(outsideElement)]} {
|
||||
$w invoke $elem
|
||||
incr Priv(repeated)
|
||||
}
|
||||
set delay [$w cget -repeatinterval]
|
||||
if {$delay > 0} {
|
||||
set Priv(afterId) [after $delay \
|
||||
[list ::tk::spinbox::Invoke $w $elem]]
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::spinbox::ClosestGap --
|
||||
# Given x and y coordinates, this procedure finds the closest boundary
|
||||
# between characters to the given coordinates and returns the index
|
||||
# of the character just after the boundary.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The spinbox window.
|
||||
# x - X-coordinate within the window.
|
||||
|
||||
proc ::tk::spinbox::ClosestGap {w x} {
|
||||
set pos [$w index @$x]
|
||||
set bbox [$w bbox $pos]
|
||||
if {($x - [lindex $bbox 0]) < ([lindex $bbox 2]/2)} {
|
||||
return $pos
|
||||
}
|
||||
incr pos
|
||||
}
|
||||
|
||||
# ::tk::spinbox::ArrowPress --
|
||||
# This procedure is invoked to handle button-1 presses in buttonup
|
||||
# or buttondown elements of spinbox widgets.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The spinbox window in which the button was pressed.
|
||||
# x - The x-coordinate of the button press.
|
||||
# y - The y-coordinate of the button press.
|
||||
|
||||
proc ::tk::spinbox::ArrowPress {w x y} {
|
||||
variable ::tk::Priv
|
||||
|
||||
if {[$w cget -state] ne "disabled" && \
|
||||
[string match "button*" $Priv(element)]} {
|
||||
$w selection element $Priv(element)
|
||||
set Priv(repeated) 0
|
||||
set Priv(relief) [$w cget -$Priv(element)relief]
|
||||
catch {after cancel $Priv(afterId)}
|
||||
set delay [$w cget -repeatdelay]
|
||||
if {$delay > 0} {
|
||||
set Priv(afterId) [after $delay \
|
||||
[list ::tk::spinbox::Invoke $w $Priv(element)]]
|
||||
}
|
||||
if {[info exists Priv(outsideElement)]} {
|
||||
unset Priv(outsideElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::spinbox::ButtonDown --
|
||||
# This procedure is invoked to handle button-1 presses in spinbox
|
||||
# widgets. It moves the insertion cursor, sets the selection anchor,
|
||||
# and claims the input focus.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The spinbox window in which the button was pressed.
|
||||
# x - The x-coordinate of the button press.
|
||||
# y - The y-coordinate of the button press.
|
||||
|
||||
proc ::tk::spinbox::ButtonDown {w x y} {
|
||||
variable ::tk::Priv
|
||||
|
||||
# Get the element that was clicked in. If we are not directly over
|
||||
# the spinbox, default to entry. This is necessary for spinbox grabs.
|
||||
#
|
||||
set Priv(element) [$w identify $x $y]
|
||||
if {$Priv(element) eq ""} {
|
||||
set Priv(element) "entry"
|
||||
}
|
||||
|
||||
switch -exact $Priv(element) {
|
||||
"buttonup" - "buttondown" {
|
||||
::tk::spinbox::ArrowPress $w $x $y
|
||||
}
|
||||
"entry" {
|
||||
set Priv(selectMode) char
|
||||
set Priv(mouseMoved) 0
|
||||
set Priv(pressX) $x
|
||||
$w icursor [::tk::spinbox::ClosestGap $w $x]
|
||||
$w selection from insert
|
||||
if {"disabled" ne [$w cget -state]} {focus $w}
|
||||
$w selection clear
|
||||
}
|
||||
default {
|
||||
return -code error -errorcode {TK SPINBOX UNKNOWN_ELEMENT} \
|
||||
"unknown spinbox element \"$Priv(element)\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::spinbox::ButtonUp --
|
||||
# This procedure is invoked to handle button-1 releases in spinbox
|
||||
# widgets.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The spinbox window in which the button was pressed.
|
||||
# x - The x-coordinate of the button press.
|
||||
# y - The y-coordinate of the button press.
|
||||
|
||||
proc ::tk::spinbox::ButtonUp {w x y} {
|
||||
variable ::tk::Priv
|
||||
|
||||
::tk::CancelRepeat
|
||||
|
||||
# Priv(relief) may not exist if the ButtonUp is not paired with
|
||||
# a preceding ButtonDown
|
||||
if {[info exists Priv(element)] && [info exists Priv(relief)] && \
|
||||
[string match "button*" $Priv(element)]} {
|
||||
if {[info exists Priv(repeated)] && !$Priv(repeated)} {
|
||||
$w invoke $Priv(element)
|
||||
}
|
||||
$w configure -$Priv(element)relief $Priv(relief)
|
||||
$w selection element none
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::spinbox::MouseSelect --
|
||||
# This procedure is invoked when dragging out a selection with
|
||||
# the mouse. Depending on the selection mode (character, word,
|
||||
# line) it selects in different-sized units. This procedure
|
||||
# ignores mouse motions initially until the mouse has moved from
|
||||
# one character to another or until there have been multiple clicks.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The spinbox window in which the button was pressed.
|
||||
# x - The x-coordinate of the mouse.
|
||||
# cursor - optional place to set cursor.
|
||||
|
||||
proc ::tk::spinbox::MouseSelect {w x {cursor {}}} {
|
||||
variable ::tk::Priv
|
||||
|
||||
if {$Priv(element) ne "entry"} {
|
||||
# The ButtonUp command triggered by ButtonRelease-1 handles
|
||||
# invoking one of the spinbuttons.
|
||||
return
|
||||
}
|
||||
set cur [::tk::spinbox::ClosestGap $w $x]
|
||||
set anchor [$w index anchor]
|
||||
if {($cur ne $anchor) || (abs($Priv(pressX) - $x) >= 3)} {
|
||||
set Priv(mouseMoved) 1
|
||||
}
|
||||
switch $Priv(selectMode) {
|
||||
char {
|
||||
if {$Priv(mouseMoved)} {
|
||||
if {$cur < $anchor} {
|
||||
$w selection range $cur $anchor
|
||||
} elseif {$cur > $anchor} {
|
||||
$w selection range $anchor $cur
|
||||
} else {
|
||||
$w selection clear
|
||||
}
|
||||
}
|
||||
}
|
||||
word {
|
||||
if {$cur < [$w index anchor]} {
|
||||
set before [tcl_wordBreakBefore [$w get] $cur]
|
||||
set after [tcl_wordBreakAfter [$w get] $anchor-1]
|
||||
} else {
|
||||
set before [tcl_wordBreakBefore [$w get] $anchor]
|
||||
set after [tcl_wordBreakAfter [$w get] $cur-1]
|
||||
}
|
||||
if {$before < 0} {
|
||||
set before 0
|
||||
}
|
||||
if {$after < 0} {
|
||||
set after end
|
||||
}
|
||||
$w selection range $before $after
|
||||
}
|
||||
line {
|
||||
$w selection range 0 end
|
||||
}
|
||||
}
|
||||
if {$cursor ne {} && $cursor ne "ignore"} {
|
||||
catch {$w icursor $cursor}
|
||||
}
|
||||
update idletasks
|
||||
}
|
||||
|
||||
# ::tk::spinbox::Paste --
|
||||
# This procedure sets the insertion cursor to the current mouse position,
|
||||
# pastes the selection there, and sets the focus to the window.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The spinbox window.
|
||||
# x - X position of the mouse.
|
||||
|
||||
proc ::tk::spinbox::Paste {w x} {
|
||||
$w icursor [::tk::spinbox::ClosestGap $w $x]
|
||||
catch {$w insert insert [::tk::GetSelection $w PRIMARY]}
|
||||
if {"disabled" eq [$w cget -state]} {
|
||||
focus $w
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::spinbox::Motion --
|
||||
# This procedure is invoked when the mouse moves in a spinbox window
|
||||
# with button 1 down.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The spinbox window.
|
||||
# x - The x-coordinate of the mouse.
|
||||
# y - The y-coordinate of the mouse.
|
||||
|
||||
proc ::tk::spinbox::Motion {w x y} {
|
||||
variable ::tk::Priv
|
||||
|
||||
if {![info exists Priv(element)]} {
|
||||
set Priv(element) [$w identify $x $y]
|
||||
}
|
||||
|
||||
set Priv(x) $x
|
||||
if {"entry" eq $Priv(element)} {
|
||||
::tk::spinbox::MouseSelect $w $x ignore
|
||||
} elseif {[$w identify $x $y] ne $Priv(element)} {
|
||||
if {![info exists Priv(outsideElement)]} {
|
||||
# We've wandered out of the spin button
|
||||
# setting outside element will cause ::tk::spinbox::Invoke to
|
||||
# loop without doing anything
|
||||
set Priv(outsideElement) ""
|
||||
$w selection element none
|
||||
}
|
||||
} elseif {[info exists Priv(outsideElement)]} {
|
||||
unset Priv(outsideElement)
|
||||
$w selection element $Priv(element)
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::spinbox::AutoScan --
|
||||
# This procedure is invoked when the mouse leaves an spinbox window
|
||||
# with button 1 down. It scrolls the window left or right,
|
||||
# depending on where the mouse is, and reschedules itself as an
|
||||
# "after" command so that the window continues to scroll until the
|
||||
# mouse moves back into the window or the mouse button is released.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The spinbox window.
|
||||
|
||||
proc ::tk::spinbox::AutoScan {w} {
|
||||
variable ::tk::Priv
|
||||
|
||||
set x $Priv(x)
|
||||
if {$x >= [winfo width $w]} {
|
||||
$w xview scroll 2 units
|
||||
::tk::spinbox::MouseSelect $w $x ignore
|
||||
} elseif {$x < 0} {
|
||||
$w xview scroll -2 units
|
||||
::tk::spinbox::MouseSelect $w $x ignore
|
||||
}
|
||||
set Priv(afterId) [after 50 [list ::tk::spinbox::AutoScan $w]]
|
||||
}
|
||||
|
||||
# ::tk::spinbox::GetSelection --
|
||||
#
|
||||
# Returns the selected text of the spinbox. Differs from entry in that
|
||||
# a spinbox has no -show option to obscure contents.
|
||||
#
|
||||
# Arguments:
|
||||
# w - The spinbox window from which the text to get
|
||||
|
||||
proc ::tk::spinbox::GetSelection {w} {
|
||||
return [string range [$w get] [$w index sel.first] \
|
||||
[expr {[$w index sel.last] - 1}]]
|
||||
}
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
# 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(::tk::dialog::error::Return) [list source [file join $dir bgerror.tcl]]
|
||||
set auto_index(::tk::dialog::error::Details) [list source [file join $dir bgerror.tcl]]
|
||||
set auto_index(::tk::dialog::error::SaveToLog) [list source [file join $dir bgerror.tcl]]
|
||||
set auto_index(::tk::dialog::error::Destroy) [list source [file join $dir bgerror.tcl]]
|
||||
set auto_index(::tk::dialog::error::bgerror) [list source [file join $dir bgerror.tcl]]
|
||||
set auto_index(bgerror) [list source [file join $dir bgerror.tcl]]
|
||||
set auto_index(::tk::ButtonInvoke) [list source [file join $dir button.tcl]]
|
||||
set auto_index(::tk::ButtonAutoInvoke) [list source [file join $dir button.tcl]]
|
||||
set auto_index(::tk::CheckRadioInvoke) [list source [file join $dir button.tcl]]
|
||||
set auto_index(::tk::dialog::file::chooseDir::) [list source [file join $dir choosedir.tcl]]
|
||||
set auto_index(::tk::dialog::file::chooseDir::Config) [list source [file join $dir choosedir.tcl]]
|
||||
set auto_index(::tk::dialog::file::chooseDir::OkCmd) [list source [file join $dir choosedir.tcl]]
|
||||
set auto_index(::tk::dialog::file::chooseDir::DblClick) [list source [file join $dir choosedir.tcl]]
|
||||
set auto_index(::tk::dialog::file::chooseDir::ListBrowse) [list source [file join $dir choosedir.tcl]]
|
||||
set auto_index(::tk::dialog::file::chooseDir::Done) [list source [file join $dir choosedir.tcl]]
|
||||
set auto_index(::tk::dialog::color::) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::InitValues) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::Config) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::BuildDialog) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::SetRGBValue) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::XToRgb) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::RgbToX) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::DrawColorScale) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::CreateSelector) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::RedrawFinalColor) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::RedrawColorBars) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::StartMove) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::MoveSelector) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::ReleaseMouse) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::ResizeColorBars) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::HandleSelEntry) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::HandleRGBEntry) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::EnterColorBar) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::LeaveColorBar) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::OkCmd) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(::tk::dialog::color::CancelCmd) [list source [file join $dir clrpick.tcl]]
|
||||
set auto_index(tclParseConfigSpec) [list source [file join $dir comdlg.tcl]]
|
||||
set auto_index(tclListValidFlags) [list source [file join $dir comdlg.tcl]]
|
||||
set auto_index(::tk::FocusGroup_Create) [list source [file join $dir comdlg.tcl]]
|
||||
set auto_index(::tk::FocusGroup_BindIn) [list source [file join $dir comdlg.tcl]]
|
||||
set auto_index(::tk::FocusGroup_BindOut) [list source [file join $dir comdlg.tcl]]
|
||||
set auto_index(::tk::FocusGroup_Destroy) [list source [file join $dir comdlg.tcl]]
|
||||
set auto_index(::tk::FocusGroup_In) [list source [file join $dir comdlg.tcl]]
|
||||
set auto_index(::tk::FocusGroup_Out) [list source [file join $dir comdlg.tcl]]
|
||||
set auto_index(::tk::FDGetFileTypes) [list source [file join $dir comdlg.tcl]]
|
||||
set auto_index(::tk::ConsoleInit) [list source [file join $dir console.tcl]]
|
||||
set auto_index(::tk::ConsoleSource) [list source [file join $dir console.tcl]]
|
||||
set auto_index(::tk::ConsoleInvoke) [list source [file join $dir console.tcl]]
|
||||
set auto_index(::tk::ConsoleHistory) [list source [file join $dir console.tcl]]
|
||||
set auto_index(::tk::ConsolePrompt) [list source [file join $dir console.tcl]]
|
||||
set auto_index(::tk::ConsoleBind) [list source [file join $dir console.tcl]]
|
||||
set auto_index(::tk::ConsoleInsert) [list source [file join $dir console.tcl]]
|
||||
set auto_index(::tk::ConsoleOutput) [list source [file join $dir console.tcl]]
|
||||
set auto_index(::tk::ConsoleExit) [list source [file join $dir console.tcl]]
|
||||
set auto_index(::tk::ConsoleAbout) [list source [file join $dir console.tcl]]
|
||||
set auto_index(tk_dialog) [list source [file join $dir dialog.tcl]]
|
||||
set auto_index(::tk::EntryClosestGap) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntryButton1) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntryMouseSelect) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntryPaste) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntryAutoScan) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntryKeySelect) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntryInsert) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntryBackspace) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntrySeeInsert) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntrySetCursor) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntryTranspose) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntryPreviousWord) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(::tk::EntryGetSelection) [list source [file join $dir entry.tcl]]
|
||||
set auto_index(tk_focusNext) [list source [file join $dir focus.tcl]]
|
||||
set auto_index(tk_focusPrev) [list source [file join $dir focus.tcl]]
|
||||
set auto_index(::tk::FocusOK) [list source [file join $dir focus.tcl]]
|
||||
set auto_index(tk_focusFollowsMouse) [list source [file join $dir focus.tcl]]
|
||||
set auto_index(::tk::IconList) [list source [file join $dir iconlist.tcl]]
|
||||
set auto_index(::tk::ListboxBeginSelect) [list source [file join $dir listbox.tcl]]
|
||||
set auto_index(::tk::ListboxMotion) [list source [file join $dir listbox.tcl]]
|
||||
set auto_index(::tk::ListboxBeginExtend) [list source [file join $dir listbox.tcl]]
|
||||
set auto_index(::tk::ListboxBeginToggle) [list source [file join $dir listbox.tcl]]
|
||||
set auto_index(::tk::ListboxAutoScan) [list source [file join $dir listbox.tcl]]
|
||||
set auto_index(::tk::ListboxUpDown) [list source [file join $dir listbox.tcl]]
|
||||
set auto_index(::tk::ListboxExtendUpDown) [list source [file join $dir listbox.tcl]]
|
||||
set auto_index(::tk::ListboxDataExtend) [list source [file join $dir listbox.tcl]]
|
||||
set auto_index(::tk::ListboxCancel) [list source [file join $dir listbox.tcl]]
|
||||
set auto_index(::tk::ListboxSelectAll) [list source [file join $dir listbox.tcl]]
|
||||
set auto_index(::tk::Megawidget) [list source [file join $dir megawidget.tcl]]
|
||||
set auto_index(::tk::MbEnter) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MbLeave) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MbPost) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuUnpost) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MbMotion) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MbButtonUp) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuMotion) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuButtonDown) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuLeave) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuInvoke) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuEscape) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuUpArrow) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuDownArrow) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuLeftArrow) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuRightArrow) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuNextMenu) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuNextEntry) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuFind) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::TraverseToMenu) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::FirstMenu) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::TraverseWithinMenu) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuFirstEntry) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::MenuFindName) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::PostOverPoint) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::SaveGrabInfo) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::RestoreOldGrab) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(tk_menuSetFocus) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::GenerateMenuSelect) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(tk_popup) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(::tk::ensure_psenc_is_loaded) [list source [file join $dir mkpsenc.tcl]]
|
||||
set auto_index(::tk::MessageBox) [list source [file join $dir msgbox.tcl]]
|
||||
set auto_index(tk_menuBar) [list source [file join $dir obsolete.tcl]]
|
||||
set auto_index(tk_bindForTraversal) [list source [file join $dir obsolete.tcl]]
|
||||
set auto_index(::tk::classic::restore) [list source [file join $dir obsolete.tcl]]
|
||||
set auto_index(tk_optionMenu) [list source [file join $dir optMenu.tcl]]
|
||||
set auto_index(tk_setPalette) [list source [file join $dir palette.tcl]]
|
||||
set auto_index(::tk::RecolorTree) [list source [file join $dir palette.tcl]]
|
||||
set auto_index(::tk::Darken) [list source [file join $dir palette.tcl]]
|
||||
set auto_index(tk_bisque) [list source [file join $dir palette.tcl]]
|
||||
set auto_index(::safe::tkInterpInit) [list source [file join $dir safetk.tcl]]
|
||||
set auto_index(::safe::loadTk) [list source [file join $dir safetk.tcl]]
|
||||
set auto_index(::safe::TkInit) [list source [file join $dir safetk.tcl]]
|
||||
set auto_index(::safe::allowTk) [list source [file join $dir safetk.tcl]]
|
||||
set auto_index(::safe::disallowTk) [list source [file join $dir safetk.tcl]]
|
||||
set auto_index(::safe::tkDelete) [list source [file join $dir safetk.tcl]]
|
||||
set auto_index(::safe::tkTopLevel) [list source [file join $dir safetk.tcl]]
|
||||
set auto_index(::tk::ScaleActivate) [list source [file join $dir scale.tcl]]
|
||||
set auto_index(::tk::ScaleButtonDown) [list source [file join $dir scale.tcl]]
|
||||
set auto_index(::tk::ScaleDrag) [list source [file join $dir scale.tcl]]
|
||||
set auto_index(::tk::ScaleEndDrag) [list source [file join $dir scale.tcl]]
|
||||
set auto_index(::tk::ScaleIncrement) [list source [file join $dir scale.tcl]]
|
||||
set auto_index(::tk::ScaleControlPress) [list source [file join $dir scale.tcl]]
|
||||
set auto_index(::tk::ScaleButton2Down) [list source [file join $dir scale.tcl]]
|
||||
set auto_index(::tk::ScrollButtonDown) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::ScrollButtonUp) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::ScrollSelect) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::ScrollStartDrag) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::ScrollDrag) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::ScrollEndDrag) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::ScrollByUnits) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::ScrollByPages) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::ScrollToPos) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::ScrollTopBottom) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::ScrollButton2Down) [list source [file join $dir scrlbar.tcl]]
|
||||
set auto_index(::tk::spinbox::Invoke) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::ClosestGap) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::ButtonDown) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::ButtonUp) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::MouseSelect) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::Paste) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::Motion) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::AutoScan) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::KeySelect) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::Insert) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::Backspace) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::SeeInsert) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::SetCursor) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::Transpose) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::PreviousWord) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::spinbox::GetSelection) [list source [file join $dir spinbox.tcl]]
|
||||
set auto_index(::tk::TearOffMenu) [list source [file join $dir tearoff.tcl]]
|
||||
set auto_index(::tk::MenuDup) [list source [file join $dir tearoff.tcl]]
|
||||
set auto_index(::tk::TextClosestGap) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextButton1) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextSelectTo) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextKeyExtend) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextPaste) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextAutoScan) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextSetCursor) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextKeySelect) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextResetAnchor) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextInsert) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextUpDownLine) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextPrevPara) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextNextPara) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextScrollPages) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextTranspose) [list source [file join $dir text.tcl]]
|
||||
set auto_index(tk_textCopy) [list source [file join $dir text.tcl]]
|
||||
set auto_index(tk_textCut) [list source [file join $dir text.tcl]]
|
||||
set auto_index(tk_textPaste) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextNextPos) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::TextPrevPos) [list source [file join $dir text.tcl]]
|
||||
set auto_index(::tk::PlaceWindow) [list source [file join $dir tk.tcl]]
|
||||
set auto_index(::tk::SetFocusGrab) [list source [file join $dir tk.tcl]]
|
||||
set auto_index(::tk::RestoreFocusGrab) [list source [file join $dir tk.tcl]]
|
||||
set auto_index(::tk::ScreenChanged) [list source [file join $dir tk.tcl]]
|
||||
set auto_index(::tk::EventMotifBindings) [list source [file join $dir tk.tcl]]
|
||||
set auto_index(::tk::CancelRepeat) [list source [file join $dir tk.tcl]]
|
||||
set auto_index(::tk::TabToWindow) [list source [file join $dir tk.tcl]]
|
||||
set auto_index(::tk::dialog::file::) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::Config) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::Create) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::SetSelectMode) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::UpdateWhenIdle) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::Update) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::SetPathSilently) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::SetPath) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::SetFilter) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::ResolveFile) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::EntFocusIn) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::EntFocusOut) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::ActivateEnt) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::VerifyFileName) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::InvokeBtn) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::UpDirCmd) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::JoinFile) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::OkCmd) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::CancelCmd) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::ListBrowse) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::ListInvoke) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::dialog::file::Done) [list source [file join $dir tkfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_Create) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_FileTypes) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_SetFilter) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_Config) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_BuildUI) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_SetListMode) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_MakeSList) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_InterpFilter) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_Update) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_LoadFiles) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_BrowseDList) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_ActivateDList) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_BrowseFList) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_ActivateFList) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_ActivateFEnt) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_ActivateSEnt) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_OkCmd) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_FilterCmd) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::MotifFDialog_CancelCmd) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::ListBoxKeyAccel_Set) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::ListBoxKeyAccel_Unset) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::ListBoxKeyAccel_Key) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::ListBoxKeyAccel_Goto) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::ListBoxKeyAccel_Reset) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(tk_getFileType) [list source [file join $dir xmfbox.tcl]]
|
||||
set auto_index(::tk::unsupported::ExposePrivateCommand) [list source [file join $dir unsupported.tcl]]
|
||||
set auto_index(::tk::unsupported::ExposePrivateVariable) [list source [file join $dir unsupported.tcl]]
|
||||
set auto_index(::tk::fontchooser) [list source [file join $dir fontchooser.tcl]]
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
# tearoff.tcl --
|
||||
#
|
||||
# This file contains procedures that implement tear-off menus.
|
||||
#
|
||||
# Copyright (c) 1994 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1997 Sun Microsystems, Inc.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
#
|
||||
|
||||
# ::tk::TearoffMenu --
|
||||
# Given the name of a menu, this procedure creates a torn-off menu
|
||||
# that is identical to the given menu (including nested submenus).
|
||||
# The new torn-off menu exists as a toplevel window managed by the
|
||||
# window manager. The return value is the name of the new menu.
|
||||
# The window is created at the point specified by x and y
|
||||
#
|
||||
# Arguments:
|
||||
# w - The menu to be torn-off (duplicated).
|
||||
# x - x coordinate where window is created
|
||||
# y - y coordinate where window is created
|
||||
|
||||
proc ::tk::TearOffMenu {w {x 0} {y 0}} {
|
||||
# Find a unique name to use for the torn-off menu. Find the first
|
||||
# ancestor of w that is a toplevel but not a menu, and use this as
|
||||
# the parent of the new menu. This guarantees that the torn off
|
||||
# menu will be on the same screen as the original menu. By making
|
||||
# it a child of the ancestor, rather than a child of the menu, it
|
||||
# can continue to live even if the menu is deleted; it will go
|
||||
# away when the toplevel goes away.
|
||||
|
||||
if {$x == 0} {
|
||||
set x [winfo rootx $w]
|
||||
}
|
||||
if {$y == 0} {
|
||||
set y [winfo rooty $w]
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
# Shift by height of tearoff entry minus height of window titlebar
|
||||
catch {incr y [expr {[$w yposition 1] - 16}]}
|
||||
# Avoid the native menu bar which sits on top of everything.
|
||||
if {$y < 22} {set y 22}
|
||||
}
|
||||
}
|
||||
|
||||
set parent [winfo parent $w]
|
||||
while {[winfo toplevel $parent] ne $parent \
|
||||
|| [winfo class $parent] eq "Menu"} {
|
||||
set parent [winfo parent $parent]
|
||||
}
|
||||
if {$parent eq "."} {
|
||||
set parent ""
|
||||
}
|
||||
for {set i 1} 1 {incr i} {
|
||||
set menu $parent.tearoff$i
|
||||
if {![winfo exists $menu]} {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
$w clone $menu tearoff
|
||||
|
||||
# Pick a title for the new menu by looking at the parent of the
|
||||
# original: if the parent is a menu, then use the text of the active
|
||||
# entry. If it's a menubutton then use its text.
|
||||
|
||||
set parent [winfo parent $w]
|
||||
if {[$menu cget -title] ne ""} {
|
||||
wm title $menu [$menu cget -title]
|
||||
} else {
|
||||
switch -- [winfo class $parent] {
|
||||
Menubutton {
|
||||
wm title $menu [$parent cget -text]
|
||||
}
|
||||
Menu {
|
||||
wm title $menu [$parent entrycget active -label]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {[tk windowingsystem] eq "win32"} {
|
||||
# [Bug 3181181]: Find the toplevel window for the menu
|
||||
set parent [winfo toplevel $parent]
|
||||
while {[winfo class $parent] eq "Menu"} {
|
||||
set parent [winfo toplevel [winfo parent $parent]]
|
||||
}
|
||||
wm transient $menu [winfo toplevel $parent]
|
||||
wm attributes $menu -toolwindow 1
|
||||
}
|
||||
|
||||
$menu post $x $y
|
||||
|
||||
if {[winfo exists $menu] == 0} {
|
||||
return ""
|
||||
}
|
||||
|
||||
# Set tk::Priv(focus) on entry: otherwise the focus will get lost
|
||||
# after keyboard invocation of a sub-menu (it will stay on the
|
||||
# submenu).
|
||||
|
||||
bind $menu <Enter> {
|
||||
set tk::Priv(focus) %W
|
||||
}
|
||||
|
||||
# If there is a -tearoffcommand option for the menu, invoke it
|
||||
# now.
|
||||
|
||||
set cmd [$w cget -tearoffcommand]
|
||||
if {$cmd ne ""} {
|
||||
uplevel #0 $cmd [list $w $menu]
|
||||
}
|
||||
return $menu
|
||||
}
|
||||
|
||||
# ::tk::MenuDup --
|
||||
# Given a menu (hierarchy), create a duplicate menu (hierarchy)
|
||||
# in a given window.
|
||||
#
|
||||
# Arguments:
|
||||
# src - Source window. Must be a menu. It and its
|
||||
# menu descendants will be duplicated at dst.
|
||||
# dst - Name to use for topmost menu in duplicate
|
||||
# hierarchy.
|
||||
|
||||
proc ::tk::MenuDup {src dst type} {
|
||||
set cmd [list menu $dst -type $type]
|
||||
foreach option [$src configure] {
|
||||
if {[llength $option] == 2} {
|
||||
continue
|
||||
}
|
||||
if {[lindex $option 0] eq "-type"} {
|
||||
continue
|
||||
}
|
||||
lappend cmd [lindex $option 0] [lindex $option 4]
|
||||
}
|
||||
eval $cmd
|
||||
set last [$src index last]
|
||||
if {$last eq "none"} {
|
||||
return
|
||||
}
|
||||
for {set i [$src cget -tearoff]} {$i <= $last} {incr i} {
|
||||
set cmd [list $dst add [$src type $i]]
|
||||
foreach option [$src entryconfigure $i] {
|
||||
lappend cmd [lindex $option 0] [lindex $option 4]
|
||||
}
|
||||
eval $cmd
|
||||
}
|
||||
|
||||
# Duplicate the binding tags and bindings from the source menu.
|
||||
|
||||
set tags [bindtags $src]
|
||||
set srcLen [string length $src]
|
||||
|
||||
# Copy tags to x, replacing each substring of src with dst.
|
||||
|
||||
while {[set index [string first $src $tags]] >= 0} {
|
||||
if {$index > 0} {
|
||||
append x [string range $tags 0 $index-1]$dst
|
||||
}
|
||||
set tags [string range $tags $index+$srcLen end]
|
||||
}
|
||||
append x $tags
|
||||
|
||||
bindtags $dst $x
|
||||
|
||||
foreach event [bind $src] {
|
||||
unset x
|
||||
set script [bind $src $event]
|
||||
set eventLen [string length $event]
|
||||
|
||||
# Copy script to x, replacing each substring of event with dst.
|
||||
|
||||
while {[set index [string first $event $script]] >= 0} {
|
||||
if {$index > 0} {
|
||||
append x [string range $script 0 $index-1]
|
||||
}
|
||||
append x $dst
|
||||
set script [string range $script $index+$eventLen end]
|
||||
}
|
||||
append x $script
|
||||
|
||||
bind $dst $event $x
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,712 @@
|
|||
# tk.tcl --
|
||||
#
|
||||
# Initialization script normally executed in the interpreter for each Tk-based
|
||||
# application. Arranges class bindings for widgets.
|
||||
#
|
||||
# Copyright (c) 1992-1994 The Regents of the University of California.
|
||||
# Copyright (c) 1994-1996 Sun Microsystems, Inc.
|
||||
# Copyright (c) 1998-2000 Ajuba Solutions.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution of
|
||||
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
|
||||
# Verify that we have Tk binary and script components from the same release
|
||||
package require -exact Tk 8.6.11
|
||||
|
||||
# Create a ::tk namespace
|
||||
namespace eval ::tk {
|
||||
# Set up the msgcat commands
|
||||
namespace eval msgcat {
|
||||
namespace export mc mcmax
|
||||
if {[interp issafe] || [catch {package require msgcat}]} {
|
||||
# The msgcat package is not available. Supply our own
|
||||
# minimal replacement.
|
||||
proc mc {src args} {
|
||||
return [format $src {*}$args]
|
||||
}
|
||||
proc mcmax {args} {
|
||||
set max 0
|
||||
foreach string $args {
|
||||
set len [string length $string]
|
||||
if {$len>$max} {
|
||||
set max $len
|
||||
}
|
||||
}
|
||||
return $max
|
||||
}
|
||||
} else {
|
||||
# Get the commands from the msgcat package that Tk uses.
|
||||
namespace import ::msgcat::mc
|
||||
namespace import ::msgcat::mcmax
|
||||
::msgcat::mcload [file join $::tk_library msgs]
|
||||
}
|
||||
}
|
||||
namespace import ::tk::msgcat::*
|
||||
}
|
||||
# and a ::ttk namespace
|
||||
namespace eval ::ttk {
|
||||
if {$::tk_library ne ""} {
|
||||
# avoid file join to work in safe interps, but this is also x-plat ok
|
||||
variable library $::tk_library/ttk
|
||||
}
|
||||
}
|
||||
|
||||
# Add Ttk & Tk's directory to the end of the auto-load search path, if it
|
||||
# isn't already on the path:
|
||||
|
||||
if {[info exists ::auto_path] && ($::tk_library ne "")
|
||||
&& ($::tk_library ni $::auto_path)
|
||||
} then {
|
||||
lappend ::auto_path $::tk_library $::ttk::library
|
||||
}
|
||||
|
||||
# Turn off strict Motif look and feel as a default.
|
||||
|
||||
set ::tk_strictMotif 0
|
||||
|
||||
# Turn on useinputmethods (X Input Methods) by default.
|
||||
# We catch this because safe interpreters may not allow the call.
|
||||
|
||||
catch {tk useinputmethods 1}
|
||||
|
||||
# ::tk::PlaceWindow --
|
||||
# place a toplevel at a particular position
|
||||
# Arguments:
|
||||
# toplevel name of toplevel window
|
||||
# ?placement? pointer ?center? ; places $w centered on the pointer
|
||||
# widget widgetPath ; centers $w over widget_name
|
||||
# defaults to placing toplevel in the middle of the screen
|
||||
# ?anchor? center or widgetPath
|
||||
# Results:
|
||||
# Returns nothing
|
||||
#
|
||||
proc ::tk::PlaceWindow {w {place ""} {anchor ""}} {
|
||||
wm withdraw $w
|
||||
update idletasks
|
||||
set checkBounds 1
|
||||
if {$place eq ""} {
|
||||
set x [expr {([winfo screenwidth $w]-[winfo reqwidth $w])/2}]
|
||||
set y [expr {([winfo screenheight $w]-[winfo reqheight $w])/2}]
|
||||
set checkBounds 0
|
||||
} elseif {[string equal -length [string length $place] $place "pointer"]} {
|
||||
## place at POINTER (centered if $anchor == center)
|
||||
if {[string equal -length [string length $anchor] $anchor "center"]} {
|
||||
set x [expr {[winfo pointerx $w]-[winfo reqwidth $w]/2}]
|
||||
set y [expr {[winfo pointery $w]-[winfo reqheight $w]/2}]
|
||||
} else {
|
||||
set x [winfo pointerx $w]
|
||||
set y [winfo pointery $w]
|
||||
}
|
||||
} elseif {[string equal -length [string length $place] $place "widget"] && \
|
||||
[winfo exists $anchor] && [winfo ismapped $anchor]} {
|
||||
## center about WIDGET $anchor, widget must be mapped
|
||||
set x [expr {[winfo rootx $anchor] + \
|
||||
([winfo width $anchor]-[winfo reqwidth $w])/2}]
|
||||
set y [expr {[winfo rooty $anchor] + \
|
||||
([winfo height $anchor]-[winfo reqheight $w])/2}]
|
||||
} else {
|
||||
set x [expr {([winfo screenwidth $w]-[winfo reqwidth $w])/2}]
|
||||
set y [expr {([winfo screenheight $w]-[winfo reqheight $w])/2}]
|
||||
set checkBounds 0
|
||||
}
|
||||
if {$checkBounds} {
|
||||
if {$x < [winfo vrootx $w]} {
|
||||
set x [winfo vrootx $w]
|
||||
} elseif {$x > ([winfo vrootx $w]+[winfo vrootwidth $w]-[winfo reqwidth $w])} {
|
||||
set x [expr {[winfo vrootx $w]+[winfo vrootwidth $w]-[winfo reqwidth $w]}]
|
||||
}
|
||||
if {$y < [winfo vrooty $w]} {
|
||||
set y [winfo vrooty $w]
|
||||
} elseif {$y > ([winfo vrooty $w]+[winfo vrootheight $w]-[winfo reqheight $w])} {
|
||||
set y [expr {[winfo vrooty $w]+[winfo vrootheight $w]-[winfo reqheight $w]}]
|
||||
}
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
# Avoid the native menu bar which sits on top of everything.
|
||||
if {$y < 22} {
|
||||
set y 22
|
||||
}
|
||||
}
|
||||
}
|
||||
wm maxsize $w [winfo vrootwidth $w] [winfo vrootheight $w]
|
||||
wm geometry $w +$x+$y
|
||||
wm deiconify $w
|
||||
}
|
||||
|
||||
# ::tk::SetFocusGrab --
|
||||
# swap out current focus and grab temporarily (for dialogs)
|
||||
# Arguments:
|
||||
# grab new window to grab
|
||||
# focus window to give focus to
|
||||
# Results:
|
||||
# Returns nothing
|
||||
#
|
||||
proc ::tk::SetFocusGrab {grab {focus {}}} {
|
||||
set index "$grab,$focus"
|
||||
upvar ::tk::FocusGrab($index) data
|
||||
|
||||
lappend data [focus]
|
||||
set oldGrab [grab current $grab]
|
||||
lappend data $oldGrab
|
||||
if {[winfo exists $oldGrab]} {
|
||||
lappend data [grab status $oldGrab]
|
||||
}
|
||||
# The "grab" command will fail if another application
|
||||
# already holds the grab. So catch it.
|
||||
catch {grab $grab}
|
||||
if {[winfo exists $focus]} {
|
||||
focus $focus
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::RestoreFocusGrab --
|
||||
# restore old focus and grab (for dialogs)
|
||||
# Arguments:
|
||||
# grab window that had taken grab
|
||||
# focus window that had taken focus
|
||||
# destroy destroy|withdraw - how to handle the old grabbed window
|
||||
# Results:
|
||||
# Returns nothing
|
||||
#
|
||||
proc ::tk::RestoreFocusGrab {grab focus {destroy destroy}} {
|
||||
set index "$grab,$focus"
|
||||
if {[info exists ::tk::FocusGrab($index)]} {
|
||||
foreach {oldFocus oldGrab oldStatus} $::tk::FocusGrab($index) { break }
|
||||
unset ::tk::FocusGrab($index)
|
||||
} else {
|
||||
set oldGrab ""
|
||||
}
|
||||
|
||||
catch {focus $oldFocus}
|
||||
grab release $grab
|
||||
if {$destroy eq "withdraw"} {
|
||||
wm withdraw $grab
|
||||
} else {
|
||||
destroy $grab
|
||||
}
|
||||
if {[winfo exists $oldGrab] && [winfo ismapped $oldGrab]} {
|
||||
if {$oldStatus eq "global"} {
|
||||
grab -global $oldGrab
|
||||
} else {
|
||||
grab $oldGrab
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::GetSelection --
|
||||
# This tries to obtain the default selection. On Unix, we first try
|
||||
# and get a UTF8_STRING, a type supported by modern Unix apps for
|
||||
# passing Unicode data safely. We fall back on the default STRING
|
||||
# type otherwise. On Windows, only the STRING type is necessary.
|
||||
# Arguments:
|
||||
# w The widget for which the selection will be retrieved.
|
||||
# Important for the -displayof property.
|
||||
# sel The source of the selection (PRIMARY or CLIPBOARD)
|
||||
# Results:
|
||||
# Returns the selection, or an error if none could be found
|
||||
#
|
||||
if {[tk windowingsystem] ne "win32"} {
|
||||
proc ::tk::GetSelection {w {sel PRIMARY}} {
|
||||
if {[catch {
|
||||
selection get -displayof $w -selection $sel -type UTF8_STRING
|
||||
} txt] && [catch {
|
||||
selection get -displayof $w -selection $sel
|
||||
} txt]} then {
|
||||
return -code error -errorcode {TK SELECTION NONE} \
|
||||
"could not find default selection"
|
||||
} else {
|
||||
return $txt
|
||||
}
|
||||
}
|
||||
} else {
|
||||
proc ::tk::GetSelection {w {sel PRIMARY}} {
|
||||
if {[catch {
|
||||
selection get -displayof $w -selection $sel
|
||||
} txt]} then {
|
||||
return -code error -errorcode {TK SELECTION NONE} \
|
||||
"could not find default selection"
|
||||
} else {
|
||||
return $txt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::ScreenChanged --
|
||||
# This procedure is invoked by the binding mechanism whenever the
|
||||
# "current" screen is changing. The procedure does two things.
|
||||
# First, it uses "upvar" to make variable "::tk::Priv" point at an
|
||||
# array variable that holds state for the current display. Second,
|
||||
# it initializes the array if it didn't already exist.
|
||||
#
|
||||
# Arguments:
|
||||
# screen - The name of the new screen.
|
||||
|
||||
proc ::tk::ScreenChanged screen {
|
||||
# Extract the display name.
|
||||
set disp [string range $screen 0 [string last . $screen]-1]
|
||||
|
||||
# Ensure that namespace separators never occur in the display name (as
|
||||
# they cause problems in variable names). Double-colons exist in some VNC
|
||||
# display names. [Bug 2912473]
|
||||
set disp [string map {:: _doublecolon_} $disp]
|
||||
|
||||
uplevel #0 [list upvar #0 ::tk::Priv.$disp ::tk::Priv]
|
||||
variable ::tk::Priv
|
||||
|
||||
if {[info exists Priv]} {
|
||||
set Priv(screen) $screen
|
||||
return
|
||||
}
|
||||
array set Priv {
|
||||
activeMenu {}
|
||||
activeItem {}
|
||||
afterId {}
|
||||
buttons 0
|
||||
buttonWindow {}
|
||||
dragging 0
|
||||
focus {}
|
||||
grab {}
|
||||
initPos {}
|
||||
inMenubutton {}
|
||||
listboxPrev {}
|
||||
menuBar {}
|
||||
mouseMoved 0
|
||||
oldGrab {}
|
||||
popup {}
|
||||
postedMb {}
|
||||
pressX 0
|
||||
pressY 0
|
||||
prevPos 0
|
||||
selectMode char
|
||||
}
|
||||
set Priv(screen) $screen
|
||||
set Priv(tearoff) [string equal [tk windowingsystem] "x11"]
|
||||
set Priv(window) {}
|
||||
}
|
||||
|
||||
# Do initial setup for Priv, so that it is always bound to something
|
||||
# (otherwise, if someone references it, it may get set to a non-upvar-ed
|
||||
# value, which will cause trouble later).
|
||||
|
||||
tk::ScreenChanged [winfo screen .]
|
||||
|
||||
# ::tk::EventMotifBindings --
|
||||
# This procedure is invoked as a trace whenever ::tk_strictMotif is
|
||||
# changed. It is used to turn on or turn off the motif virtual
|
||||
# bindings.
|
||||
#
|
||||
# Arguments:
|
||||
# n1 - the name of the variable being changed ("::tk_strictMotif").
|
||||
|
||||
proc ::tk::EventMotifBindings {n1 dummy dummy} {
|
||||
upvar $n1 name
|
||||
|
||||
if {$name} {
|
||||
set op delete
|
||||
} else {
|
||||
set op add
|
||||
}
|
||||
|
||||
event $op <<Cut>> <Control-Key-w> <Control-Lock-Key-W> <Shift-Key-Delete>
|
||||
event $op <<Copy>> <Meta-Key-w> <Meta-Lock-Key-W> <Control-Key-Insert>
|
||||
event $op <<Paste>> <Control-Key-y> <Control-Lock-Key-Y> <Shift-Key-Insert>
|
||||
event $op <<PrevChar>> <Control-Key-b> <Control-Lock-Key-B>
|
||||
event $op <<NextChar>> <Control-Key-f> <Control-Lock-Key-F>
|
||||
event $op <<PrevLine>> <Control-Key-p> <Control-Lock-Key-P>
|
||||
event $op <<NextLine>> <Control-Key-n> <Control-Lock-Key-N>
|
||||
event $op <<LineStart>> <Control-Key-a> <Control-Lock-Key-A>
|
||||
event $op <<LineEnd>> <Control-Key-e> <Control-Lock-Key-E>
|
||||
event $op <<SelectPrevChar>> <Control-Key-B> <Control-Lock-Key-b>
|
||||
event $op <<SelectNextChar>> <Control-Key-F> <Control-Lock-Key-f>
|
||||
event $op <<SelectPrevLine>> <Control-Key-P> <Control-Lock-Key-p>
|
||||
event $op <<SelectNextLine>> <Control-Key-N> <Control-Lock-Key-n>
|
||||
event $op <<SelectLineStart>> <Control-Key-A> <Control-Lock-Key-a>
|
||||
event $op <<SelectLineEnd>> <Control-Key-E> <Control-Lock-Key-e>
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Define common dialogs on platforms where they are not implemented
|
||||
# using compiled code.
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
if {![llength [info commands tk_chooseColor]]} {
|
||||
proc ::tk_chooseColor {args} {
|
||||
return [::tk::dialog::color:: {*}$args]
|
||||
}
|
||||
}
|
||||
if {![llength [info commands tk_getOpenFile]]} {
|
||||
proc ::tk_getOpenFile {args} {
|
||||
if {$::tk_strictMotif} {
|
||||
return [::tk::MotifFDialog open {*}$args]
|
||||
} else {
|
||||
return [::tk::dialog::file:: open {*}$args]
|
||||
}
|
||||
}
|
||||
}
|
||||
if {![llength [info commands tk_getSaveFile]]} {
|
||||
proc ::tk_getSaveFile {args} {
|
||||
if {$::tk_strictMotif} {
|
||||
return [::tk::MotifFDialog save {*}$args]
|
||||
} else {
|
||||
return [::tk::dialog::file:: save {*}$args]
|
||||
}
|
||||
}
|
||||
}
|
||||
if {![llength [info commands tk_messageBox]]} {
|
||||
proc ::tk_messageBox {args} {
|
||||
return [::tk::MessageBox {*}$args]
|
||||
}
|
||||
}
|
||||
if {![llength [info command tk_chooseDirectory]]} {
|
||||
proc ::tk_chooseDirectory {args} {
|
||||
return [::tk::dialog::file::chooseDir:: {*}$args]
|
||||
}
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Define the set of common virtual events.
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
switch -exact -- [tk windowingsystem] {
|
||||
"x11" {
|
||||
event add <<Cut>> <Control-Key-x> <Key-F20> <Control-Lock-Key-X>
|
||||
event add <<Copy>> <Control-Key-c> <Key-F16> <Control-Lock-Key-C>
|
||||
event add <<Paste>> <Control-Key-v> <Key-F18> <Control-Lock-Key-V>
|
||||
event add <<PasteSelection>> <ButtonRelease-2>
|
||||
event add <<Undo>> <Control-Key-z> <Control-Lock-Key-Z>
|
||||
event add <<Redo>> <Control-Key-Z> <Control-Lock-Key-z>
|
||||
event add <<ContextMenu>> <Button-3>
|
||||
# On Darwin/Aqua, buttons from left to right are 1,3,2. On Darwin/X11 with recent
|
||||
# XQuartz as the X server, they are 1,2,3; other X servers may differ.
|
||||
|
||||
event add <<SelectAll>> <Control-Key-slash>
|
||||
event add <<SelectNone>> <Control-Key-backslash>
|
||||
event add <<NextChar>> <Right>
|
||||
event add <<SelectNextChar>> <Shift-Right>
|
||||
event add <<PrevChar>> <Left>
|
||||
event add <<SelectPrevChar>> <Shift-Left>
|
||||
event add <<NextWord>> <Control-Right>
|
||||
event add <<SelectNextWord>> <Control-Shift-Right>
|
||||
event add <<PrevWord>> <Control-Left>
|
||||
event add <<SelectPrevWord>> <Control-Shift-Left>
|
||||
event add <<LineStart>> <Home>
|
||||
event add <<SelectLineStart>> <Shift-Home>
|
||||
event add <<LineEnd>> <End>
|
||||
event add <<SelectLineEnd>> <Shift-End>
|
||||
event add <<PrevLine>> <Up>
|
||||
event add <<NextLine>> <Down>
|
||||
event add <<SelectPrevLine>> <Shift-Up>
|
||||
event add <<SelectNextLine>> <Shift-Down>
|
||||
event add <<PrevPara>> <Control-Up>
|
||||
event add <<NextPara>> <Control-Down>
|
||||
event add <<SelectPrevPara>> <Control-Shift-Up>
|
||||
event add <<SelectNextPara>> <Control-Shift-Down>
|
||||
event add <<ToggleSelection>> <Control-Button-1>
|
||||
|
||||
# Some OS's define a goofy (as in, not <Shift-Tab>) keysym that is
|
||||
# returned when the user presses <Shift-Tab>. In order for tab
|
||||
# traversal to work, we have to add these keysyms to the PrevWindow
|
||||
# event. We use catch just in case the keysym isn't recognized.
|
||||
|
||||
# This is needed for XFree86 systems
|
||||
catch { event add <<PrevWindow>> <ISO_Left_Tab> }
|
||||
# This seems to be correct on *some* HP systems.
|
||||
catch { event add <<PrevWindow>> <hpBackTab> }
|
||||
|
||||
trace add variable ::tk_strictMotif write ::tk::EventMotifBindings
|
||||
set ::tk_strictMotif $::tk_strictMotif
|
||||
# On unix, we want to always display entry/text selection,
|
||||
# regardless of which window has focus
|
||||
set ::tk::AlwaysShowSelection 1
|
||||
}
|
||||
"win32" {
|
||||
event add <<Cut>> <Control-Key-x> <Shift-Key-Delete> <Control-Lock-Key-X>
|
||||
event add <<Copy>> <Control-Key-c> <Control-Key-Insert> <Control-Lock-Key-C>
|
||||
event add <<Paste>> <Control-Key-v> <Shift-Key-Insert> <Control-Lock-Key-V>
|
||||
event add <<PasteSelection>> <ButtonRelease-2>
|
||||
event add <<Undo>> <Control-Key-z> <Control-Lock-Key-Z>
|
||||
event add <<Redo>> <Control-Key-y> <Control-Lock-Key-Y>
|
||||
event add <<ContextMenu>> <Button-3>
|
||||
|
||||
event add <<SelectAll>> <Control-Key-slash> <Control-Key-a> <Control-Lock-Key-A>
|
||||
event add <<SelectNone>> <Control-Key-backslash>
|
||||
event add <<NextChar>> <Right>
|
||||
event add <<SelectNextChar>> <Shift-Right>
|
||||
event add <<PrevChar>> <Left>
|
||||
event add <<SelectPrevChar>> <Shift-Left>
|
||||
event add <<NextWord>> <Control-Right>
|
||||
event add <<SelectNextWord>> <Control-Shift-Right>
|
||||
event add <<PrevWord>> <Control-Left>
|
||||
event add <<SelectPrevWord>> <Control-Shift-Left>
|
||||
event add <<LineStart>> <Home>
|
||||
event add <<SelectLineStart>> <Shift-Home>
|
||||
event add <<LineEnd>> <End>
|
||||
event add <<SelectLineEnd>> <Shift-End>
|
||||
event add <<PrevLine>> <Up>
|
||||
event add <<NextLine>> <Down>
|
||||
event add <<SelectPrevLine>> <Shift-Up>
|
||||
event add <<SelectNextLine>> <Shift-Down>
|
||||
event add <<PrevPara>> <Control-Up>
|
||||
event add <<NextPara>> <Control-Down>
|
||||
event add <<SelectPrevPara>> <Control-Shift-Up>
|
||||
event add <<SelectNextPara>> <Control-Shift-Down>
|
||||
event add <<ToggleSelection>> <Control-Button-1>
|
||||
}
|
||||
"aqua" {
|
||||
event add <<Cut>> <Command-Key-x> <Key-F2> <Command-Lock-Key-X>
|
||||
event add <<Copy>> <Command-Key-c> <Key-F3> <Command-Lock-Key-C>
|
||||
event add <<Paste>> <Command-Key-v> <Key-F4> <Command-Lock-Key-V>
|
||||
event add <<PasteSelection>> <ButtonRelease-3>
|
||||
event add <<Clear>> <Clear>
|
||||
event add <<ContextMenu>> <Button-2>
|
||||
|
||||
# Official bindings
|
||||
# See http://support.apple.com/kb/HT1343
|
||||
event add <<SelectAll>> <Command-Key-a>
|
||||
event add <<Undo>> <Command-Key-z> <Command-Lock-Key-Z>
|
||||
event add <<Redo>> <Shift-Command-Key-z> <Shift-Command-Lock-Key-z>
|
||||
event add <<NextChar>> <Right> <Control-Key-f> <Control-Lock-Key-F>
|
||||
event add <<SelectNextChar>> <Shift-Right> <Shift-Control-Key-F> <Shift-Control-Lock-Key-F>
|
||||
event add <<PrevChar>> <Left> <Control-Key-b> <Control-Lock-Key-B>
|
||||
event add <<SelectPrevChar>> <Shift-Left> <Shift-Control-Key-B> <Shift-Control-Lock-Key-B>
|
||||
event add <<NextWord>> <Option-Right>
|
||||
event add <<SelectNextWord>> <Shift-Option-Right>
|
||||
event add <<PrevWord>> <Option-Left>
|
||||
event add <<SelectPrevWord>> <Shift-Option-Left>
|
||||
event add <<LineStart>> <Home> <Command-Left> <Control-Key-a> <Control-Lock-Key-A>
|
||||
event add <<SelectLineStart>> <Shift-Home> <Shift-Command-Left> <Shift-Control-Key-A> <Shift-Control-Lock-Key-A>
|
||||
event add <<LineEnd>> <End> <Command-Right> <Control-Key-e> <Control-Lock-Key-E>
|
||||
event add <<SelectLineEnd>> <Shift-End> <Shift-Command-Right> <Shift-Control-Key-E> <Shift-Control-Lock-Key-E>
|
||||
event add <<PrevLine>> <Up> <Control-Key-p> <Control-Lock-Key-P>
|
||||
event add <<SelectPrevLine>> <Shift-Up> <Shift-Control-Key-P> <Shift-Control-Lock-Key-P>
|
||||
event add <<NextLine>> <Down> <Control-Key-n> <Control-Lock-Key-N>
|
||||
event add <<SelectNextLine>> <Shift-Down> <Shift-Control-Key-N> <Shift-Control-Lock-Key-N>
|
||||
# Not official, but logical extensions of above. Also derived from
|
||||
# bindings present in MS Word on OSX.
|
||||
event add <<PrevPara>> <Option-Up>
|
||||
event add <<NextPara>> <Option-Down>
|
||||
event add <<SelectPrevPara>> <Shift-Option-Up>
|
||||
event add <<SelectNextPara>> <Shift-Option-Down>
|
||||
event add <<ToggleSelection>> <Command-Button-1>
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Read in files that define all of the class bindings.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
if {$::tk_library ne ""} {
|
||||
proc ::tk::SourceLibFile {file} {
|
||||
namespace eval :: [list source -encoding utf-8 [file join $::tk_library $file.tcl]]
|
||||
}
|
||||
namespace eval ::tk {
|
||||
SourceLibFile icons
|
||||
SourceLibFile button
|
||||
SourceLibFile entry
|
||||
SourceLibFile listbox
|
||||
SourceLibFile menu
|
||||
SourceLibFile panedwindow
|
||||
SourceLibFile scale
|
||||
SourceLibFile scrlbar
|
||||
SourceLibFile spinbox
|
||||
SourceLibFile text
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Default bindings for keyboard traversal.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
event add <<PrevWindow>> <Shift-Tab>
|
||||
event add <<NextWindow>> <Tab>
|
||||
bind all <<NextWindow>> {tk::TabToWindow [tk_focusNext %W]}
|
||||
bind all <<PrevWindow>> {tk::TabToWindow [tk_focusPrev %W]}
|
||||
|
||||
# ::tk::CancelRepeat --
|
||||
# This procedure is invoked to cancel an auto-repeat action described
|
||||
# by ::tk::Priv(afterId). It's used by several widgets to auto-scroll
|
||||
# the widget when the mouse is dragged out of the widget with a
|
||||
# button pressed.
|
||||
#
|
||||
# Arguments:
|
||||
# None.
|
||||
|
||||
proc ::tk::CancelRepeat {} {
|
||||
variable ::tk::Priv
|
||||
after cancel $Priv(afterId)
|
||||
set Priv(afterId) {}
|
||||
}
|
||||
|
||||
# ::tk::TabToWindow --
|
||||
# This procedure moves the focus to the given widget.
|
||||
# It sends a <<TraverseOut>> virtual event to the previous focus window,
|
||||
# if any, before changing the focus, and a <<TraverseIn>> event
|
||||
# to the new focus window afterwards.
|
||||
#
|
||||
# Arguments:
|
||||
# w - Window to which focus should be set.
|
||||
|
||||
proc ::tk::TabToWindow {w} {
|
||||
set focus [focus]
|
||||
if {$focus ne ""} {
|
||||
event generate $focus <<TraverseOut>>
|
||||
}
|
||||
focus $w
|
||||
event generate $w <<TraverseIn>>
|
||||
}
|
||||
|
||||
# ::tk::UnderlineAmpersand --
|
||||
# This procedure takes some text with ampersand and returns text w/o
|
||||
# ampersand and position of the ampersand. Double ampersands are
|
||||
# converted to single ones. Position returned is -1 when there is no
|
||||
# ampersand.
|
||||
#
|
||||
proc ::tk::UnderlineAmpersand {text} {
|
||||
set s [string map {&& & & \ufeff} $text]
|
||||
set idx [string first \ufeff $s]
|
||||
return [list [string map {\ufeff {}} $s] $idx]
|
||||
}
|
||||
|
||||
# ::tk::SetAmpText --
|
||||
# Given widget path and text with "magic ampersands", sets -text and
|
||||
# -underline options for the widget
|
||||
#
|
||||
proc ::tk::SetAmpText {widget text} {
|
||||
lassign [UnderlineAmpersand $text] newtext under
|
||||
$widget configure -text $newtext -underline $under
|
||||
}
|
||||
|
||||
# ::tk::AmpWidget --
|
||||
# Creates new widget, turning -text option into -text and -underline
|
||||
# options, returned by ::tk::UnderlineAmpersand.
|
||||
#
|
||||
proc ::tk::AmpWidget {class path args} {
|
||||
set options {}
|
||||
foreach {opt val} $args {
|
||||
if {$opt eq "-text"} {
|
||||
lassign [UnderlineAmpersand $val] newtext under
|
||||
lappend options -text $newtext -underline $under
|
||||
} else {
|
||||
lappend options $opt $val
|
||||
}
|
||||
}
|
||||
set result [$class $path {*}$options]
|
||||
if {[string match "*button" $class]} {
|
||||
bind $path <<AltUnderlined>> [list $path invoke]
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
# ::tk::AmpMenuArgs --
|
||||
# Processes arguments for a menu entry, turning -label option into
|
||||
# -label and -underline options, returned by ::tk::UnderlineAmpersand.
|
||||
# The cmd argument is supposed to be either "add" or "entryconfigure"
|
||||
#
|
||||
proc ::tk::AmpMenuArgs {widget cmd type args} {
|
||||
set options {}
|
||||
foreach {opt val} $args {
|
||||
if {$opt eq "-label"} {
|
||||
lassign [UnderlineAmpersand $val] newlabel under
|
||||
lappend options -label $newlabel -underline $under
|
||||
} else {
|
||||
lappend options $opt $val
|
||||
}
|
||||
}
|
||||
$widget $cmd $type {*}$options
|
||||
}
|
||||
|
||||
# ::tk::FindAltKeyTarget --
|
||||
# Search recursively through the hierarchy of visible widgets to find
|
||||
# button or label which has $char as underlined character.
|
||||
#
|
||||
proc ::tk::FindAltKeyTarget {path char} {
|
||||
set class [winfo class $path]
|
||||
if {$class in {
|
||||
Button Checkbutton Label Radiobutton
|
||||
TButton TCheckbutton TLabel TRadiobutton
|
||||
} && [string equal -nocase $char \
|
||||
[string index [$path cget -text] [$path cget -underline]]]} {
|
||||
return $path
|
||||
}
|
||||
set subwins [concat [grid slaves $path] [pack slaves $path] \
|
||||
[place slaves $path]]
|
||||
if {$class eq "Canvas"} {
|
||||
foreach item [$path find all] {
|
||||
if {[$path type $item] eq "window"} {
|
||||
set w [$path itemcget $item -window]
|
||||
if {$w ne ""} {lappend subwins $w}
|
||||
}
|
||||
}
|
||||
} elseif {$class eq "Text"} {
|
||||
lappend subwins {*}[$path window names]
|
||||
}
|
||||
foreach child $subwins {
|
||||
set target [FindAltKeyTarget $child $char]
|
||||
if {$target ne ""} {
|
||||
return $target
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::AltKeyInDialog --
|
||||
# <Alt-Key> event handler for standard dialogs. Sends <<AltUnderlined>>
|
||||
# to button or label which has appropriate underlined character.
|
||||
#
|
||||
proc ::tk::AltKeyInDialog {path key} {
|
||||
set target [FindAltKeyTarget $path $key]
|
||||
if {$target ne ""} {
|
||||
event generate $target <<AltUnderlined>>
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::mcmaxamp --
|
||||
# Replacement for mcmax, used for texts with "magic ampersand" in it.
|
||||
#
|
||||
|
||||
proc ::tk::mcmaxamp {args} {
|
||||
set maxlen 0
|
||||
foreach arg $args {
|
||||
# Should we run [mc] in caller's namespace?
|
||||
lassign [UnderlineAmpersand [mc $arg]] msg
|
||||
set length [string length $msg]
|
||||
if {$length > $maxlen} {
|
||||
set maxlen $length
|
||||
}
|
||||
}
|
||||
return $maxlen
|
||||
}
|
||||
|
||||
# For now, turn off the custom mdef proc for the Mac:
|
||||
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
namespace eval ::tk::mac {
|
||||
set useCustomMDEF 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if {[tk windowingsystem] eq "aqua"} {
|
||||
#stub procedures to respond to "do script" Apple Events
|
||||
proc ::tk::mac::DoScriptFile {file} {
|
||||
uplevel #0 $file
|
||||
source -encoding utf-8 $file
|
||||
}
|
||||
proc ::tk::mac::DoScriptText {script} {
|
||||
uplevel #0 $script
|
||||
eval $script
|
||||
}
|
||||
}
|
||||
|
||||
# Create a dictionary to store the starting index of the IME marked
|
||||
# text in an Entry or Text widget.
|
||||
|
||||
set ::tk::Priv(IMETextMark) [dict create]
|
||||
|
||||
# Run the Ttk themed widget set initialization
|
||||
if {$::ttk::library ne ""} {
|
||||
uplevel \#0 [list source -encoding utf-8 $::ttk::library/ttk.tcl]
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# mode: tcl
|
||||
# fill-column: 78
|
||||
# End:
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,269 @@
|
|||
# unsupported.tcl --
|
||||
#
|
||||
# Commands provided by Tk without official support. Use them at your
|
||||
# own risk. They may change or go away without notice.
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Unsupported compatibility interface for folks accessing Tk's private
|
||||
# commands and variable against recommended usage.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
namespace eval ::tk::unsupported {
|
||||
|
||||
# Map from the old global names of Tk private commands to their
|
||||
# new namespace-encapsulated names.
|
||||
|
||||
variable PrivateCommands
|
||||
array set PrivateCommands {
|
||||
tkButtonAutoInvoke ::tk::ButtonAutoInvoke
|
||||
tkButtonDown ::tk::ButtonDown
|
||||
tkButtonEnter ::tk::ButtonEnter
|
||||
tkButtonInvoke ::tk::ButtonInvoke
|
||||
tkButtonLeave ::tk::ButtonLeave
|
||||
tkButtonUp ::tk::ButtonUp
|
||||
tkCancelRepeat ::tk::CancelRepeat
|
||||
tkCheckRadioDown ::tk::CheckRadioDown
|
||||
tkCheckRadioEnter ::tk::CheckRadioEnter
|
||||
tkCheckRadioInvoke ::tk::CheckRadioInvoke
|
||||
tkColorDialog ::tk::dialog::color::
|
||||
tkColorDialog_BuildDialog ::tk::dialog::color::BuildDialog
|
||||
tkColorDialog_CancelCmd ::tk::dialog::color::CancelCmd
|
||||
tkColorDialog_Config ::tk::dialog::color::Config
|
||||
tkColorDialog_CreateSelector ::tk::dialog::color::CreateSelector
|
||||
tkColorDialog_DrawColorScale ::tk::dialog::color::DrawColorScale
|
||||
tkColorDialog_EnterColorBar ::tk::dialog::color::EnterColorBar
|
||||
tkColorDialog_InitValues ::tk::dialog::color::InitValues
|
||||
tkColorDialog_HandleRGBEntry ::tk::dialog::color::HandleRGBEntry
|
||||
tkColorDialog_HandleSelEntry ::tk::dialog::color::HandleSelEntry
|
||||
tkColorDialog_LeaveColorBar ::tk::dialog::color::LeaveColorBar
|
||||
tkColorDialog_MoveSelector ::tk::dialog::color::MoveSelector
|
||||
tkColorDialog_OkCmd ::tk::dialog::color::OkCmd
|
||||
tkColorDialog_RedrawColorBars ::tk::dialog::color::RedrawColorBars
|
||||
tkColorDialog_RedrawFinalColor ::tk::dialog::color::RedrawFinalColor
|
||||
tkColorDialog_ReleaseMouse ::tk::dialog::color::ReleaseMouse
|
||||
tkColorDialog_ResizeColorBars ::tk::dialog::color::ResizeColorBars
|
||||
tkColorDialog_RgbToX ::tk::dialog::color::RgbToX
|
||||
tkColorDialog_SetRGBValue ::tk::dialog::color::SetRGBValue
|
||||
tkColorDialog_StartMove ::tk::dialog::color::StartMove
|
||||
tkColorDialog_XToRgb ::tk::dialog::color::XToRGB
|
||||
tkConsoleAbout ::tk::ConsoleAbout
|
||||
tkConsoleBind ::tk::ConsoleBind
|
||||
tkConsoleExit ::tk::ConsoleExit
|
||||
tkConsoleHistory ::tk::ConsoleHistory
|
||||
tkConsoleInit ::tk::ConsoleInit
|
||||
tkConsoleInsert ::tk::ConsoleInsert
|
||||
tkConsoleInvoke ::tk::ConsoleInvoke
|
||||
tkConsoleOutput ::tk::ConsoleOutput
|
||||
tkConsolePrompt ::tk::ConsolePrompt
|
||||
tkConsoleSource ::tk::ConsoleSource
|
||||
tkDarken ::tk::Darken
|
||||
tkEntryAutoScan ::tk::EntryAutoScan
|
||||
tkEntryBackspace ::tk::EntryBackspace
|
||||
tkEntryButton1 ::tk::EntryButton1
|
||||
tkEntryClosestGap ::tk::EntryClosestGap
|
||||
tkEntryGetSelection ::tk::EntryGetSelection
|
||||
tkEntryInsert ::tk::EntryInsert
|
||||
tkEntryKeySelect ::tk::EntryKeySelect
|
||||
tkEntryMouseSelect ::tk::EntryMouseSelect
|
||||
tkEntryNextWord ::tk::EntryNextWord
|
||||
tkEntryPaste ::tk::EntryPaste
|
||||
tkEntryPreviousWord ::tk::EntryPreviousWord
|
||||
tkEntrySeeInsert ::tk::EntrySeeInsert
|
||||
tkEntrySetCursor ::tk::EntrySetCursor
|
||||
tkEntryTranspose ::tk::EntryTranspose
|
||||
tkEventMotifBindings ::tk::EventMotifBindings
|
||||
tkFDGetFileTypes ::tk::FDGetFileTypes
|
||||
tkFirstMenu ::tk::FirstMenu
|
||||
tkFocusGroup_BindIn ::tk::FocusGroup_BindIn
|
||||
tkFocusGroup_BindOut ::tk::FocusGroup_BindOut
|
||||
tkFocusGroup_Create ::tk::FocusGroup_Create
|
||||
tkFocusGroup_Destroy ::tk::FocusGroup_Destroy
|
||||
tkFocusGroup_In ::tk::FocusGroup_In
|
||||
tkFocusGroup_Out ::tk::FocusGroup_Out
|
||||
tkFocusOK ::tk::FocusOK
|
||||
tkGenerateMenuSelect ::tk::GenerateMenuSelect
|
||||
tkIconList ::tk::IconList
|
||||
tkListbox ::tk::Listbox
|
||||
tkListboxAutoScan ::tk::ListboxAutoScan
|
||||
tkListboxBeginExtend ::tk::ListboxBeginExtend
|
||||
tkListboxBeginSelect ::tk::ListboxBeginSelect
|
||||
tkListboxBeginToggle ::tk::ListboxBeginToggle
|
||||
tkListboxCancel ::tk::ListboxCancel
|
||||
tkListboxDataExtend ::tk::ListboxDataExtend
|
||||
tkListboxExtendUpDown ::tk::ListboxExtendUpDown
|
||||
tkListboxKeyAccel_Goto ::tk::ListboxKeyAccel_Goto
|
||||
tkListboxKeyAccel_Key ::tk::ListboxKeyAccel_Key
|
||||
tkListboxKeyAccel_Reset ::tk::ListboxKeyAccel_Reset
|
||||
tkListboxKeyAccel_Set ::tk::ListboxKeyAccel_Set
|
||||
tkListboxKeyAccel_Unset ::tk::ListboxKeyAccel_Unxet
|
||||
tkListboxMotion ::tk::ListboxMotion
|
||||
tkListboxSelectAll ::tk::ListboxSelectAll
|
||||
tkListboxUpDown ::tk::ListboxUpDown
|
||||
tkListboxBeginToggle ::tk::ListboxBeginToggle
|
||||
tkMbButtonUp ::tk::MbButtonUp
|
||||
tkMbEnter ::tk::MbEnter
|
||||
tkMbLeave ::tk::MbLeave
|
||||
tkMbMotion ::tk::MbMotion
|
||||
tkMbPost ::tk::MbPost
|
||||
tkMenuButtonDown ::tk::MenuButtonDown
|
||||
tkMenuDownArrow ::tk::MenuDownArrow
|
||||
tkMenuDup ::tk::MenuDup
|
||||
tkMenuEscape ::tk::MenuEscape
|
||||
tkMenuFind ::tk::MenuFind
|
||||
tkMenuFindName ::tk::MenuFindName
|
||||
tkMenuFirstEntry ::tk::MenuFirstEntry
|
||||
tkMenuInvoke ::tk::MenuInvoke
|
||||
tkMenuLeave ::tk::MenuLeave
|
||||
tkMenuLeftArrow ::tk::MenuLeftArrow
|
||||
tkMenuMotion ::tk::MenuMotion
|
||||
tkMenuNextEntry ::tk::MenuNextEntry
|
||||
tkMenuNextMenu ::tk::MenuNextMenu
|
||||
tkMenuRightArrow ::tk::MenuRightArrow
|
||||
tkMenuUnpost ::tk::MenuUnpost
|
||||
tkMenuUpArrow ::tk::MenuUpArrow
|
||||
tkMessageBox ::tk::MessageBox
|
||||
tkMotifFDialog ::tk::MotifFDialog
|
||||
tkMotifFDialog_ActivateDList ::tk::MotifFDialog_ActivateDList
|
||||
tkMotifFDialog_ActivateFList ::tk::MotifFDialog_ActivateFList
|
||||
tkMotifFDialog_ActivateFEnt ::tk::MotifFDialog_ActivateFEnt
|
||||
tkMotifFDialog_ActivateSEnt ::tk::MotifFDialog_ActivateSEnt
|
||||
tkMotifFDialog ::tk::MotifFDialog
|
||||
tkMotifFDialog_BrowseDList ::tk::MotifFDialog_BrowseDList
|
||||
tkMotifFDialog_BrowseFList ::tk::MotifFDialog_BrowseFList
|
||||
tkMotifFDialog_BuildUI ::tk::MotifFDialog_BuildUI
|
||||
tkMotifFDialog_CancelCmd ::tk::MotifFDialog_CancelCmd
|
||||
tkMotifFDialog_Config ::tk::MotifFDialog_Config
|
||||
tkMotifFDialog_Create ::tk::MotifFDialog_Create
|
||||
tkMotifFDialog_FileTypes ::tk::MotifFDialog_FileTypes
|
||||
tkMotifFDialog_FilterCmd ::tk::MotifFDialog_FilterCmd
|
||||
tkMotifFDialog_InterpFilter ::tk::MotifFDialog_InterpFilter
|
||||
tkMotifFDialog_LoadFiles ::tk::MotifFDialog_LoadFiles
|
||||
tkMotifFDialog_MakeSList ::tk::MotifFDialog_MakeSList
|
||||
tkMotifFDialog_OkCmd ::tk::MotifFDialog_OkCmd
|
||||
tkMotifFDialog_SetFilter ::tk::MotifFDialog_SetFilter
|
||||
tkMotifFDialog_SetListMode ::tk::MotifFDialog_SetListMode
|
||||
tkMotifFDialog_Update ::tk::MotifFDialog_Update
|
||||
tkPostOverPoint ::tk::PostOverPoint
|
||||
tkRecolorTree ::tk::RecolorTree
|
||||
tkRestoreOldGrab ::tk::RestoreOldGrab
|
||||
tkSaveGrabInfo ::tk::SaveGrabInfo
|
||||
tkScaleActivate ::tk::ScaleActivate
|
||||
tkScaleButtonDown ::tk::ScaleButtonDown
|
||||
tkScaleButton2Down ::tk::ScaleButton2Down
|
||||
tkScaleControlPress ::tk::ScaleControlPress
|
||||
tkScaleDrag ::tk::ScaleDrag
|
||||
tkScaleEndDrag ::tk::ScaleEndDrag
|
||||
tkScaleIncrement ::tk::ScaleIncrement
|
||||
tkScreenChanged ::tk::ScreenChanged
|
||||
tkScrollButtonDown ::tk::ScrollButtonDown
|
||||
tkScrollButton2Down ::tk::ScrollButton2Down
|
||||
tkScrollButtonDrag ::tk::ScrollButtonDrag
|
||||
tkScrollButtonUp ::tk::ScrollButtonUp
|
||||
tkScrollByPages ::tk::ScrollByPages
|
||||
tkScrollByUnits ::tk::ScrollByUnits
|
||||
tkScrollEndDrag ::tk::ScrollEndDrag
|
||||
tkScrollSelect ::tk::ScrollSelect
|
||||
tkScrollStartDrag ::tk::ScrollStartDrag
|
||||
tkScrollTopBottom ::tk::ScrollTopBottom
|
||||
tkScrollToPos ::tk::ScrollToPos
|
||||
tkTabToWindow ::tk::TabToWindow
|
||||
tkTearOffMenu ::tk::TearOffMenu
|
||||
tkTextAutoScan ::tk::TextAutoScan
|
||||
tkTextButton1 ::tk::TextButton1
|
||||
tkTextClosestGap ::tk::TextClosestGap
|
||||
tkTextInsert ::tk::TextInsert
|
||||
tkTextKeyExtend ::tk::TextKeyExtend
|
||||
tkTextKeySelect ::tk::TextKeySelect
|
||||
tkTextNextPara ::tk::TextNextPara
|
||||
tkTextNextPos ::tk::TextNextPos
|
||||
tkTextNextWord ::tk::TextNextWord
|
||||
tkTextPaste ::tk::TextPaste
|
||||
tkTextPrevPara ::tk::TextPrevPara
|
||||
tkTextPrevPos ::tk::TextPrevPos
|
||||
tkTextPrevWord ::tk::TextPrevWord
|
||||
tkTextResetAnchor ::tk::TextResetAnchor
|
||||
tkTextScrollPages ::tk::TextScrollPages
|
||||
tkTextSelectTo ::tk::TextSelectTo
|
||||
tkTextSetCursor ::tk::TextSetCursor
|
||||
tkTextTranspose ::tk::TextTranspose
|
||||
tkTextUpDownLine ::tk::TextUpDownLine
|
||||
tkTraverseToMenu ::tk::TraverseToMenu
|
||||
tkTraverseWithinMenu ::tk::TraverseWithinMenu
|
||||
unsupported1 ::tk::unsupported::MacWindowStyle
|
||||
}
|
||||
|
||||
# Map from the old global names of Tk private variable to their
|
||||
# new namespace-encapsulated names.
|
||||
|
||||
variable PrivateVariables
|
||||
array set PrivateVariables {
|
||||
droped_to_start ::tk::mac::Droped_to_start
|
||||
histNum ::tk::HistNum
|
||||
stub_location ::tk::mac::Stub_location
|
||||
tkFocusIn ::tk::FocusIn
|
||||
tkFocusOut ::tk::FocusOut
|
||||
tkPalette ::tk::Palette
|
||||
tkPriv ::tk::Priv
|
||||
tkPrivMsgBox ::tk::PrivMsgBox
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::unsupported::ExposePrivateCommand --
|
||||
#
|
||||
# Expose one of Tk's private commands to be visible under its
|
||||
# old global name
|
||||
#
|
||||
# Arguments:
|
||||
# cmd Global name by which the command was once known,
|
||||
# or a glob-style pattern.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
#
|
||||
# Side effects:
|
||||
# The old command name in the global namespace is aliased to the
|
||||
# new private name.
|
||||
|
||||
proc ::tk::unsupported::ExposePrivateCommand {cmd} {
|
||||
variable PrivateCommands
|
||||
set cmds [array get PrivateCommands $cmd]
|
||||
if {[llength $cmds] == 0} {
|
||||
return -code error -errorcode {TK EXPOSE_PRIVATE_COMMAND} \
|
||||
"No compatibility support for \[$cmd]"
|
||||
}
|
||||
foreach {old new} $cmds {
|
||||
namespace eval :: [list interp alias {} $old {}] $new
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::unsupported::ExposePrivateVariable --
|
||||
#
|
||||
# Expose one of Tk's private variables to be visible under its
|
||||
# old global name
|
||||
#
|
||||
# Arguments:
|
||||
# var Global name by which the variable was once known,
|
||||
# or a glob-style pattern.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
#
|
||||
# Side effects:
|
||||
# The old variable name in the global namespace is aliased to the
|
||||
# new private name.
|
||||
|
||||
proc ::tk::unsupported::ExposePrivateVariable {var} {
|
||||
variable PrivateVariables
|
||||
set vars [array get PrivateVariables $var]
|
||||
if {[llength $vars] == 0} {
|
||||
return -code error -errorcode {TK EXPOSE_PRIVATE_VARIABLE} \
|
||||
"No compatibility support for \$$var"
|
||||
}
|
||||
namespace eval ::tk::mac {}
|
||||
foreach {old new} $vars {
|
||||
namespace eval :: [list upvar "#0" $new $old]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,989 @@
|
|||
# xmfbox.tcl --
|
||||
#
|
||||
# Implements the "Motif" style file selection dialog for the
|
||||
# Unix platform. This implementation is used only if the
|
||||
# "::tk_strictMotif" flag is set.
|
||||
#
|
||||
# Copyright (c) 1996 Sun Microsystems, Inc.
|
||||
# Copyright (c) 1998-2000 Scriptics Corporation
|
||||
#
|
||||
# See the file "license.terms" for information on usage and redistribution
|
||||
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
|
||||
namespace eval ::tk::dialog {}
|
||||
namespace eval ::tk::dialog::file {}
|
||||
|
||||
|
||||
# ::tk::MotifFDialog --
|
||||
#
|
||||
# Implements a file dialog similar to the standard Motif file
|
||||
# selection box.
|
||||
#
|
||||
# Arguments:
|
||||
# type "open" or "save"
|
||||
# args Options parsed by the procedure.
|
||||
#
|
||||
# Results:
|
||||
# When -multiple is set to 0, this returns the absolute pathname
|
||||
# of the selected file. (NOTE: This is not the same as a single
|
||||
# element list.)
|
||||
#
|
||||
# When -multiple is set to > 0, this returns a Tcl list of absolute
|
||||
# pathnames. The argument for -multiple is ignored, but for consistency
|
||||
# with Windows it defines the maximum amount of memory to allocate for
|
||||
# the returned filenames.
|
||||
|
||||
proc ::tk::MotifFDialog {type args} {
|
||||
variable ::tk::Priv
|
||||
set dataName __tk_filedialog
|
||||
upvar ::tk::dialog::file::$dataName data
|
||||
|
||||
set w [MotifFDialog_Create $dataName $type $args]
|
||||
|
||||
# Set a grab and claim the focus too.
|
||||
|
||||
::tk::SetFocusGrab $w $data(sEnt)
|
||||
$data(sEnt) selection range 0 end
|
||||
|
||||
# Wait for the user to respond, then restore the focus and
|
||||
# return the index of the selected button. Restore the focus
|
||||
# before deleting the window, since otherwise the window manager
|
||||
# may take the focus away so we can't redirect it. Finally,
|
||||
# restore any grab that was in effect.
|
||||
|
||||
vwait ::tk::Priv(selectFilePath)
|
||||
set result $Priv(selectFilePath)
|
||||
::tk::RestoreFocusGrab $w $data(sEnt) withdraw
|
||||
|
||||
return $result
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_Create --
|
||||
#
|
||||
# Creates the Motif file dialog (if it doesn't exist yet) and
|
||||
# initialize the internal data structure associated with the
|
||||
# dialog.
|
||||
#
|
||||
# This procedure is used by ::tk::MotifFDialog to create the
|
||||
# dialog. It's also used by the test suite to test the Motif
|
||||
# file dialog implementation. User code shouldn't call this
|
||||
# procedure directly.
|
||||
#
|
||||
# Arguments:
|
||||
# dataName Name of the global "data" array for the file dialog.
|
||||
# type "Save" or "Open"
|
||||
# argList Options parsed by the procedure.
|
||||
#
|
||||
# Results:
|
||||
# Pathname of the file dialog.
|
||||
|
||||
proc ::tk::MotifFDialog_Create {dataName type argList} {
|
||||
upvar ::tk::dialog::file::$dataName data
|
||||
|
||||
MotifFDialog_Config $dataName $type $argList
|
||||
|
||||
if {$data(-parent) eq "."} {
|
||||
set w .$dataName
|
||||
} else {
|
||||
set w $data(-parent).$dataName
|
||||
}
|
||||
|
||||
# (re)create the dialog box if necessary
|
||||
#
|
||||
if {![winfo exists $w]} {
|
||||
MotifFDialog_BuildUI $w
|
||||
} elseif {[winfo class $w] ne "TkMotifFDialog"} {
|
||||
destroy $w
|
||||
MotifFDialog_BuildUI $w
|
||||
} else {
|
||||
set data(fEnt) $w.top.f1.ent
|
||||
set data(dList) $w.top.f2.a.l
|
||||
set data(fList) $w.top.f2.b.l
|
||||
set data(sEnt) $w.top.f3.ent
|
||||
set data(okBtn) $w.bot.ok
|
||||
set data(filterBtn) $w.bot.filter
|
||||
set data(cancelBtn) $w.bot.cancel
|
||||
}
|
||||
MotifFDialog_SetListMode $w
|
||||
|
||||
# Dialog boxes should be transient with respect to their parent,
|
||||
# so that they will always stay on top of their parent window. However,
|
||||
# some window managers will create the window as withdrawn if the parent
|
||||
# window is withdrawn or iconified. Combined with the grab we put on the
|
||||
# window, this can hang the entire application. Therefore we only make
|
||||
# the dialog transient if the parent is viewable.
|
||||
|
||||
if {[winfo viewable [winfo toplevel $data(-parent)]] } {
|
||||
wm transient $w $data(-parent)
|
||||
}
|
||||
|
||||
MotifFDialog_FileTypes $w
|
||||
MotifFDialog_Update $w
|
||||
|
||||
# Withdraw the window, then update all the geometry information
|
||||
# so we know how big it wants to be, then center the window in the
|
||||
# display (Motif style) and de-iconify it.
|
||||
|
||||
::tk::PlaceWindow $w
|
||||
wm title $w $data(-title)
|
||||
|
||||
return $w
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_FileTypes --
|
||||
#
|
||||
# Checks the -filetypes option. If present this adds a list of radio-
|
||||
# buttons to pick the file types from.
|
||||
#
|
||||
# Arguments:
|
||||
# w Pathname of the tk_get*File dialogue.
|
||||
#
|
||||
# Results:
|
||||
# none
|
||||
|
||||
proc ::tk::MotifFDialog_FileTypes {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
set f $w.top.f3.types
|
||||
destroy $f
|
||||
|
||||
# No file types: use "*" as the filter and display no radio-buttons
|
||||
if {$data(-filetypes) eq ""} {
|
||||
set data(filter) *
|
||||
return
|
||||
}
|
||||
|
||||
# The filetypes radiobuttons
|
||||
# set data(fileType) $data(-defaulttype)
|
||||
# Default type to first entry
|
||||
set initialTypeName [lindex $data(origfiletypes) 0 0]
|
||||
if {$data(-typevariable) ne ""} {
|
||||
upvar #0 $data(-typevariable) typeVariable
|
||||
if {[info exists typeVariable]} {
|
||||
set initialTypeName $typeVariable
|
||||
}
|
||||
}
|
||||
set ix 0
|
||||
set data(fileType) 0
|
||||
foreach fltr $data(origfiletypes) {
|
||||
set fname [lindex $fltr 0]
|
||||
if {[string first $initialTypeName $fname] == 0} {
|
||||
set data(fileType) $ix
|
||||
break
|
||||
}
|
||||
incr ix
|
||||
}
|
||||
|
||||
MotifFDialog_SetFilter $w [lindex $data(-filetypes) $data(fileType)]
|
||||
|
||||
#don't produce radiobuttons for only one filetype
|
||||
if {[llength $data(-filetypes)] == 1} {
|
||||
return
|
||||
}
|
||||
|
||||
frame $f
|
||||
set cnt 0
|
||||
if {$data(-filetypes) ne {}} {
|
||||
foreach type $data(-filetypes) {
|
||||
set title [lindex $type 0]
|
||||
set filter [lindex $type 1]
|
||||
radiobutton $f.b$cnt \
|
||||
-text $title \
|
||||
-variable ::tk::dialog::file::[winfo name $w](fileType) \
|
||||
-value $cnt \
|
||||
-command [list tk::MotifFDialog_SetFilter $w $type]
|
||||
pack $f.b$cnt -side left
|
||||
incr cnt
|
||||
}
|
||||
}
|
||||
$f.b$data(fileType) invoke
|
||||
|
||||
pack $f -side bottom -fill both
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
# This proc gets called whenever data(filter) is set
|
||||
#
|
||||
proc ::tk::MotifFDialog_SetFilter {w type} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
variable ::tk::Priv
|
||||
|
||||
set data(filter) [lindex $type 1]
|
||||
set Priv(selectFileType) [lindex [lindex $type 0] 0]
|
||||
|
||||
MotifFDialog_Update $w
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_Config --
|
||||
#
|
||||
# Iterates over the optional arguments to determine the option
|
||||
# values for the Motif file dialog; gives default values to
|
||||
# unspecified options.
|
||||
#
|
||||
# Arguments:
|
||||
# dataName The name of the global variable in which
|
||||
# data for the file dialog is stored.
|
||||
# type "Save" or "Open"
|
||||
# argList Options parsed by the procedure.
|
||||
|
||||
proc ::tk::MotifFDialog_Config {dataName type argList} {
|
||||
upvar ::tk::dialog::file::$dataName data
|
||||
|
||||
set data(type) $type
|
||||
|
||||
# 1: the configuration specs
|
||||
#
|
||||
set specs {
|
||||
{-defaultextension "" "" ""}
|
||||
{-filetypes "" "" ""}
|
||||
{-initialdir "" "" ""}
|
||||
{-initialfile "" "" ""}
|
||||
{-parent "" "" "."}
|
||||
{-title "" "" ""}
|
||||
{-typevariable "" "" ""}
|
||||
}
|
||||
if {$type eq "open"} {
|
||||
lappend specs {-multiple "" "" "0"}
|
||||
}
|
||||
if {$type eq "save"} {
|
||||
lappend specs {-confirmoverwrite "" "" "1"}
|
||||
}
|
||||
|
||||
set data(-multiple) 0
|
||||
set data(-confirmoverwrite) 1
|
||||
# 2: default values depending on the type of the dialog
|
||||
#
|
||||
if {![info exists data(selectPath)]} {
|
||||
# first time the dialog has been popped up
|
||||
set data(selectPath) [pwd]
|
||||
set data(selectFile) ""
|
||||
}
|
||||
|
||||
# 3: parse the arguments
|
||||
#
|
||||
tclParseConfigSpec ::tk::dialog::file::$dataName $specs "" $argList
|
||||
|
||||
if {$data(-title) eq ""} {
|
||||
if {$type eq "open"} {
|
||||
if {$data(-multiple) != 0} {
|
||||
set data(-title) "[mc {Open Multiple Files}]"
|
||||
} else {
|
||||
set data(-title) [mc "Open"]
|
||||
}
|
||||
} else {
|
||||
set data(-title) [mc "Save As"]
|
||||
}
|
||||
}
|
||||
|
||||
# 4: set the default directory and selection according to the -initial
|
||||
# settings
|
||||
#
|
||||
if {$data(-initialdir) ne ""} {
|
||||
if {[file isdirectory $data(-initialdir)]} {
|
||||
set data(selectPath) [lindex [glob $data(-initialdir)] 0]
|
||||
} else {
|
||||
set data(selectPath) [pwd]
|
||||
}
|
||||
|
||||
# Convert the initialdir to an absolute path name.
|
||||
|
||||
set old [pwd]
|
||||
cd $data(selectPath)
|
||||
set data(selectPath) [pwd]
|
||||
cd $old
|
||||
}
|
||||
set data(selectFile) $data(-initialfile)
|
||||
|
||||
# 5. Parse the -filetypes option. It is not used by the motif
|
||||
# file dialog, but we check for validity of the value to make sure
|
||||
# the application code also runs fine with the TK file dialog.
|
||||
#
|
||||
set data(origfiletypes) $data(-filetypes)
|
||||
set data(-filetypes) [::tk::FDGetFileTypes $data(-filetypes)]
|
||||
|
||||
if {![info exists data(filter)]} {
|
||||
set data(filter) *
|
||||
}
|
||||
if {![winfo exists $data(-parent)]} {
|
||||
return -code error -errorcode [list TK LOOKUP WINDOW $data(-parent)] \
|
||||
"bad window path name \"$data(-parent)\""
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_BuildUI --
|
||||
#
|
||||
# Builds the UI components of the Motif file dialog.
|
||||
#
|
||||
# Arguments:
|
||||
# w Pathname of the dialog to build.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
|
||||
proc ::tk::MotifFDialog_BuildUI {w} {
|
||||
set dataName [lindex [split $w .] end]
|
||||
upvar ::tk::dialog::file::$dataName data
|
||||
|
||||
# Create the dialog toplevel and internal frames.
|
||||
#
|
||||
toplevel $w -class TkMotifFDialog
|
||||
set top [frame $w.top -relief raised -bd 1]
|
||||
set bot [frame $w.bot -relief raised -bd 1]
|
||||
|
||||
pack $w.bot -side bottom -fill x
|
||||
pack $w.top -side top -expand yes -fill both
|
||||
|
||||
set f1 [frame $top.f1]
|
||||
set f2 [frame $top.f2]
|
||||
set f3 [frame $top.f3]
|
||||
|
||||
pack $f1 -side top -fill x
|
||||
pack $f3 -side bottom -fill x
|
||||
pack $f2 -expand yes -fill both
|
||||
|
||||
set f2a [frame $f2.a]
|
||||
set f2b [frame $f2.b]
|
||||
|
||||
grid $f2a -row 0 -column 0 -rowspan 1 -columnspan 1 -padx 4 -pady 4 \
|
||||
-sticky news
|
||||
grid $f2b -row 0 -column 1 -rowspan 1 -columnspan 1 -padx 4 -pady 4 \
|
||||
-sticky news
|
||||
grid rowconfigure $f2 0 -minsize 0 -weight 1
|
||||
grid columnconfigure $f2 0 -minsize 0 -weight 1
|
||||
grid columnconfigure $f2 1 -minsize 150 -weight 2
|
||||
|
||||
# The Filter box
|
||||
#
|
||||
bind [::tk::AmpWidget label $f1.lab -text [mc "Fil&ter:"] -anchor w] \
|
||||
<<AltUnderlined>> [list focus $f1.ent]
|
||||
entry $f1.ent
|
||||
pack $f1.lab -side top -fill x -padx 6 -pady 4
|
||||
pack $f1.ent -side top -fill x -padx 4 -pady 0
|
||||
set data(fEnt) $f1.ent
|
||||
|
||||
# The file and directory lists
|
||||
#
|
||||
set data(dList) [MotifFDialog_MakeSList $w $f2a \
|
||||
[mc "&Directory:"] DList]
|
||||
set data(fList) [MotifFDialog_MakeSList $w $f2b \
|
||||
[mc "Fi&les:"] FList]
|
||||
|
||||
# The Selection box
|
||||
#
|
||||
bind [::tk::AmpWidget label $f3.lab -text [mc "&Selection:"] -anchor w] \
|
||||
<<AltUnderlined>> [list focus $f3.ent]
|
||||
entry $f3.ent
|
||||
pack $f3.lab -side top -fill x -padx 6 -pady 0
|
||||
pack $f3.ent -side top -fill x -padx 4 -pady 4
|
||||
set data(sEnt) $f3.ent
|
||||
|
||||
# The buttons
|
||||
#
|
||||
set maxWidth [::tk::mcmaxamp &OK &Filter &Cancel]
|
||||
set maxWidth [expr {$maxWidth<6?6:$maxWidth}]
|
||||
set data(okBtn) [::tk::AmpWidget button $bot.ok -text [mc "&OK"] \
|
||||
-width $maxWidth \
|
||||
-command [list tk::MotifFDialog_OkCmd $w]]
|
||||
set data(filterBtn) [::tk::AmpWidget button $bot.filter -text [mc "&Filter"] \
|
||||
-width $maxWidth \
|
||||
-command [list tk::MotifFDialog_FilterCmd $w]]
|
||||
set data(cancelBtn) [::tk::AmpWidget button $bot.cancel -text [mc "&Cancel"] \
|
||||
-width $maxWidth \
|
||||
-command [list tk::MotifFDialog_CancelCmd $w]]
|
||||
|
||||
pack $bot.ok $bot.filter $bot.cancel -padx 10 -pady 10 -expand yes \
|
||||
-side left
|
||||
|
||||
# Create the bindings:
|
||||
#
|
||||
bind $w <Alt-Key> [list ::tk::AltKeyInDialog $w %A]
|
||||
|
||||
bind $data(fEnt) <Return> [list tk::MotifFDialog_ActivateFEnt $w]
|
||||
bind $data(sEnt) <Return> [list tk::MotifFDialog_ActivateSEnt $w]
|
||||
bind $w <Escape> [list tk::MotifFDialog_CancelCmd $w]
|
||||
bind $w.bot <Destroy> {set ::tk::Priv(selectFilePath) {}}
|
||||
|
||||
wm protocol $w WM_DELETE_WINDOW [list tk::MotifFDialog_CancelCmd $w]
|
||||
}
|
||||
|
||||
proc ::tk::MotifFDialog_SetListMode {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
if {$data(-multiple) != 0} {
|
||||
set selectmode extended
|
||||
} else {
|
||||
set selectmode browse
|
||||
}
|
||||
set f $w.top.f2.b
|
||||
$f.l configure -selectmode $selectmode
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_MakeSList --
|
||||
#
|
||||
# Create a scrolled-listbox and set the keyboard accelerator
|
||||
# bindings so that the list selection follows what the user
|
||||
# types.
|
||||
#
|
||||
# Arguments:
|
||||
# w Pathname of the dialog box.
|
||||
# f Frame widget inside which to create the scrolled
|
||||
# listbox. This frame widget already exists.
|
||||
# label The string to display on top of the listbox.
|
||||
# under Sets the -under option of the label.
|
||||
# cmdPrefix Specifies procedures to call when the listbox is
|
||||
# browsed or activated.
|
||||
|
||||
proc ::tk::MotifFDialog_MakeSList {w f label cmdPrefix} {
|
||||
bind [::tk::AmpWidget label $f.lab -text $label -anchor w] \
|
||||
<<AltUnderlined>> [list focus $f.l]
|
||||
listbox $f.l -width 12 -height 5 -exportselection 0\
|
||||
-xscrollcommand [list $f.h set] -yscrollcommand [list $f.v set]
|
||||
scrollbar $f.v -orient vertical -takefocus 0 -command [list $f.l yview]
|
||||
scrollbar $f.h -orient horizontal -takefocus 0 -command [list $f.l xview]
|
||||
grid $f.lab -row 0 -column 0 -sticky news -rowspan 1 -columnspan 2 \
|
||||
-padx 2 -pady 2
|
||||
grid $f.l -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
|
||||
grid $f.v -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news
|
||||
grid $f.h -row 2 -column 0 -rowspan 1 -columnspan 1 -sticky news
|
||||
|
||||
grid rowconfigure $f 0 -weight 0 -minsize 0
|
||||
grid rowconfigure $f 1 -weight 1 -minsize 0
|
||||
grid columnconfigure $f 0 -weight 1 -minsize 0
|
||||
|
||||
# bindings for the listboxes
|
||||
#
|
||||
set list $f.l
|
||||
bind $list <<ListboxSelect>> [list tk::MotifFDialog_Browse$cmdPrefix $w]
|
||||
bind $list <Double-ButtonRelease-1> \
|
||||
[list tk::MotifFDialog_Activate$cmdPrefix $w]
|
||||
bind $list <Return> "tk::MotifFDialog_Browse$cmdPrefix [list $w]; \
|
||||
tk::MotifFDialog_Activate$cmdPrefix [list $w]"
|
||||
|
||||
bindtags $list [list Listbox $list [winfo toplevel $list] all]
|
||||
ListBoxKeyAccel_Set $list
|
||||
|
||||
return $f.l
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_InterpFilter --
|
||||
#
|
||||
# Interpret the string in the filter entry into two components:
|
||||
# the directory and the pattern. If the string is a relative
|
||||
# pathname, give a warning to the user and restore the pattern
|
||||
# to original.
|
||||
#
|
||||
# Arguments:
|
||||
# w pathname of the dialog box.
|
||||
#
|
||||
# Results:
|
||||
# A list of two elements. The first element is the directory
|
||||
# specified # by the filter. The second element is the filter
|
||||
# pattern itself.
|
||||
|
||||
proc ::tk::MotifFDialog_InterpFilter {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
set text [string trim [$data(fEnt) get]]
|
||||
|
||||
# Perform tilde substitution
|
||||
#
|
||||
set badTilde 0
|
||||
if {[string index $text 0] eq "~"} {
|
||||
set list [file split $text]
|
||||
set tilde [lindex $list 0]
|
||||
if {[catch {set tilde [glob $tilde]}]} {
|
||||
set badTilde 1
|
||||
} else {
|
||||
set text [eval file join [concat $tilde [lrange $list 1 end]]]
|
||||
}
|
||||
}
|
||||
|
||||
# If the string is a relative pathname, combine it
|
||||
# with the current selectPath.
|
||||
|
||||
set relative 0
|
||||
if {[file pathtype $text] eq "relative"} {
|
||||
set relative 1
|
||||
} elseif {$badTilde} {
|
||||
set relative 1
|
||||
}
|
||||
|
||||
if {$relative} {
|
||||
tk_messageBox -icon warning -type ok \
|
||||
-message "\"$text\" must be an absolute pathname"
|
||||
|
||||
$data(fEnt) delete 0 end
|
||||
$data(fEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
|
||||
$data(filter)]
|
||||
|
||||
return [list $data(selectPath) $data(filter)]
|
||||
}
|
||||
|
||||
set resolved [::tk::dialog::file::JoinFile [file dirname $text] [file tail $text]]
|
||||
|
||||
if {[file isdirectory $resolved]} {
|
||||
set dir $resolved
|
||||
set fil $data(filter)
|
||||
} else {
|
||||
set dir [file dirname $resolved]
|
||||
set fil [file tail $resolved]
|
||||
}
|
||||
|
||||
return [list $dir $fil]
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_Update
|
||||
#
|
||||
# Load the files and synchronize the "filter" and "selection" fields
|
||||
# boxes.
|
||||
#
|
||||
# Arguments:
|
||||
# w pathname of the dialog box.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
|
||||
proc ::tk::MotifFDialog_Update {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
$data(fEnt) delete 0 end
|
||||
$data(fEnt) insert 0 \
|
||||
[::tk::dialog::file::JoinFile $data(selectPath) $data(filter)]
|
||||
$data(sEnt) delete 0 end
|
||||
$data(sEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
|
||||
$data(selectFile)]
|
||||
|
||||
MotifFDialog_LoadFiles $w
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_LoadFiles --
|
||||
#
|
||||
# Loads the files and directories into the two listboxes according
|
||||
# to the filter setting.
|
||||
#
|
||||
# Arguments:
|
||||
# w pathname of the dialog box.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
|
||||
proc ::tk::MotifFDialog_LoadFiles {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
$data(dList) delete 0 end
|
||||
$data(fList) delete 0 end
|
||||
|
||||
set appPWD [pwd]
|
||||
if {[catch {cd $data(selectPath)}]} {
|
||||
cd $appPWD
|
||||
|
||||
$data(dList) insert end ".."
|
||||
return
|
||||
}
|
||||
|
||||
# Make the dir and file lists
|
||||
#
|
||||
# For speed we only have one glob, which reduces the file system
|
||||
# calls (good for slow NFS networks).
|
||||
#
|
||||
# We also do two smaller sorts (files + dirs) instead of one large sort,
|
||||
# which gives a small speed increase.
|
||||
#
|
||||
set top 0
|
||||
set dlist ""
|
||||
set flist ""
|
||||
foreach f [glob -nocomplain .* *] {
|
||||
if {[file isdir ./$f]} {
|
||||
lappend dlist $f
|
||||
} else {
|
||||
foreach pat $data(filter) {
|
||||
if {[string match $pat $f]} {
|
||||
if {[string match .* $f]} {
|
||||
incr top
|
||||
}
|
||||
lappend flist $f
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
eval [list $data(dList) insert end] [lsort -dictionary $dlist]
|
||||
eval [list $data(fList) insert end] [lsort -dictionary $flist]
|
||||
|
||||
# The user probably doesn't want to see the . files. We adjust the view
|
||||
# so that the listbox displays all the non-dot files
|
||||
$data(fList) yview $top
|
||||
|
||||
cd $appPWD
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_BrowseDList --
|
||||
#
|
||||
# This procedure is called when the directory list is browsed
|
||||
# (clicked-over) by the user.
|
||||
#
|
||||
# Arguments:
|
||||
# w The pathname of the dialog box.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
|
||||
proc ::tk::MotifFDialog_BrowseDList {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
focus $data(dList)
|
||||
if {[$data(dList) curselection] eq ""} {
|
||||
return
|
||||
}
|
||||
set subdir [$data(dList) get [$data(dList) curselection]]
|
||||
if {$subdir eq ""} {
|
||||
return
|
||||
}
|
||||
|
||||
$data(fList) selection clear 0 end
|
||||
|
||||
set list [MotifFDialog_InterpFilter $w]
|
||||
set data(filter) [lindex $list 1]
|
||||
|
||||
switch -- $subdir {
|
||||
. {
|
||||
set newSpec [::tk::dialog::file::JoinFile $data(selectPath) $data(filter)]
|
||||
}
|
||||
.. {
|
||||
set newSpec [::tk::dialog::file::JoinFile [file dirname $data(selectPath)] \
|
||||
$data(filter)]
|
||||
}
|
||||
default {
|
||||
set newSpec [::tk::dialog::file::JoinFile [::tk::dialog::file::JoinFile \
|
||||
$data(selectPath) $subdir] $data(filter)]
|
||||
}
|
||||
}
|
||||
|
||||
$data(fEnt) delete 0 end
|
||||
$data(fEnt) insert 0 $newSpec
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_ActivateDList --
|
||||
#
|
||||
# This procedure is called when the directory list is activated
|
||||
# (double-clicked) by the user.
|
||||
#
|
||||
# Arguments:
|
||||
# w The pathname of the dialog box.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
|
||||
proc ::tk::MotifFDialog_ActivateDList {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
if {[$data(dList) curselection] eq ""} {
|
||||
return
|
||||
}
|
||||
set subdir [$data(dList) get [$data(dList) curselection]]
|
||||
if {$subdir eq ""} {
|
||||
return
|
||||
}
|
||||
|
||||
$data(fList) selection clear 0 end
|
||||
|
||||
switch -- $subdir {
|
||||
. {
|
||||
set newDir $data(selectPath)
|
||||
}
|
||||
.. {
|
||||
set newDir [file dirname $data(selectPath)]
|
||||
}
|
||||
default {
|
||||
set newDir [::tk::dialog::file::JoinFile $data(selectPath) $subdir]
|
||||
}
|
||||
}
|
||||
|
||||
set data(selectPath) $newDir
|
||||
MotifFDialog_Update $w
|
||||
|
||||
if {$subdir ne ".."} {
|
||||
$data(dList) selection set 0
|
||||
$data(dList) activate 0
|
||||
} else {
|
||||
$data(dList) selection set 1
|
||||
$data(dList) activate 1
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_BrowseFList --
|
||||
#
|
||||
# This procedure is called when the file list is browsed
|
||||
# (clicked-over) by the user.
|
||||
#
|
||||
# Arguments:
|
||||
# w The pathname of the dialog box.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
|
||||
proc ::tk::MotifFDialog_BrowseFList {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
focus $data(fList)
|
||||
set data(selectFile) ""
|
||||
foreach item [$data(fList) curselection] {
|
||||
lappend data(selectFile) [$data(fList) get $item]
|
||||
}
|
||||
if {[llength $data(selectFile)] == 0} {
|
||||
return
|
||||
}
|
||||
|
||||
$data(dList) selection clear 0 end
|
||||
|
||||
$data(fEnt) delete 0 end
|
||||
$data(fEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
|
||||
$data(filter)]
|
||||
$data(fEnt) xview end
|
||||
|
||||
# if it's a multiple selection box, just put in the filenames
|
||||
# otherwise put in the full path as usual
|
||||
$data(sEnt) delete 0 end
|
||||
if {$data(-multiple) != 0} {
|
||||
$data(sEnt) insert 0 $data(selectFile)
|
||||
} else {
|
||||
$data(sEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
|
||||
[lindex $data(selectFile) 0]]
|
||||
}
|
||||
$data(sEnt) xview end
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_ActivateFList --
|
||||
#
|
||||
# This procedure is called when the file list is activated
|
||||
# (double-clicked) by the user.
|
||||
#
|
||||
# Arguments:
|
||||
# w The pathname of the dialog box.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
|
||||
proc ::tk::MotifFDialog_ActivateFList {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
if {[$data(fList) curselection] eq ""} {
|
||||
return
|
||||
}
|
||||
set data(selectFile) [$data(fList) get [$data(fList) curselection]]
|
||||
if {$data(selectFile) eq ""} {
|
||||
return
|
||||
} else {
|
||||
MotifFDialog_ActivateSEnt $w
|
||||
}
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_ActivateFEnt --
|
||||
#
|
||||
# This procedure is called when the user presses Return inside
|
||||
# the "filter" entry. It updates the dialog according to the
|
||||
# text inside the filter entry.
|
||||
#
|
||||
# Arguments:
|
||||
# w The pathname of the dialog box.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
|
||||
proc ::tk::MotifFDialog_ActivateFEnt {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
set list [MotifFDialog_InterpFilter $w]
|
||||
set data(selectPath) [lindex $list 0]
|
||||
set data(filter) [lindex $list 1]
|
||||
|
||||
MotifFDialog_Update $w
|
||||
}
|
||||
|
||||
# ::tk::MotifFDialog_ActivateSEnt --
|
||||
#
|
||||
# This procedure is called when the user presses Return inside
|
||||
# the "selection" entry. It sets the ::tk::Priv(selectFilePath)
|
||||
# variable so that the vwait loop in tk::MotifFDialog will be
|
||||
# terminated.
|
||||
#
|
||||
# Arguments:
|
||||
# w The pathname of the dialog box.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
|
||||
proc ::tk::MotifFDialog_ActivateSEnt {w} {
|
||||
variable ::tk::Priv
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
set selectFilePath [string trim [$data(sEnt) get]]
|
||||
|
||||
if {$selectFilePath eq ""} {
|
||||
MotifFDialog_FilterCmd $w
|
||||
return
|
||||
}
|
||||
|
||||
if {$data(-multiple) == 0} {
|
||||
set selectFilePath [list $selectFilePath]
|
||||
}
|
||||
|
||||
if {[file isdirectory [lindex $selectFilePath 0]]} {
|
||||
set data(selectPath) [lindex [glob $selectFilePath] 0]
|
||||
set data(selectFile) ""
|
||||
MotifFDialog_Update $w
|
||||
return
|
||||
}
|
||||
|
||||
set newFileList ""
|
||||
foreach item $selectFilePath {
|
||||
if {[file pathtype $item] ne "absolute"} {
|
||||
set item [file join $data(selectPath) $item]
|
||||
} elseif {![file exists [file dirname $item]]} {
|
||||
tk_messageBox -icon warning -type ok \
|
||||
-message [mc {Directory "%1$s" does not exist.} \
|
||||
[file dirname $item]]
|
||||
return
|
||||
}
|
||||
|
||||
if {![file exists $item]} {
|
||||
if {$data(type) eq "open"} {
|
||||
tk_messageBox -icon warning -type ok \
|
||||
-message [mc {File "%1$s" does not exist.} $item]
|
||||
return
|
||||
}
|
||||
} elseif {$data(type) eq "save" && $data(-confirmoverwrite)} {
|
||||
set message [format %s%s \
|
||||
[mc "File \"%1\$s\" already exists.\n\n" $selectFilePath] \
|
||||
[mc {Replace existing file?}]]
|
||||
set answer [tk_messageBox -icon warning -type yesno \
|
||||
-message $message]
|
||||
if {$answer eq "no"} {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
lappend newFileList $item
|
||||
}
|
||||
|
||||
# Return selected filter
|
||||
if {[info exists data(-typevariable)] && $data(-typevariable) ne ""
|
||||
&& [info exists data(-filetypes)] && $data(-filetypes) ne ""} {
|
||||
upvar #0 $data(-typevariable) typeVariable
|
||||
set typeVariable [lindex $data(origfiletypes) $data(fileType) 0]
|
||||
}
|
||||
|
||||
if {$data(-multiple) != 0} {
|
||||
set Priv(selectFilePath) $newFileList
|
||||
} else {
|
||||
set Priv(selectFilePath) [lindex $newFileList 0]
|
||||
}
|
||||
|
||||
# Set selectFile and selectPath to first item in list
|
||||
set Priv(selectFile) [file tail [lindex $newFileList 0]]
|
||||
set Priv(selectPath) [file dirname [lindex $newFileList 0]]
|
||||
}
|
||||
|
||||
|
||||
proc ::tk::MotifFDialog_OkCmd {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
MotifFDialog_ActivateSEnt $w
|
||||
}
|
||||
|
||||
proc ::tk::MotifFDialog_FilterCmd {w} {
|
||||
upvar ::tk::dialog::file::[winfo name $w] data
|
||||
|
||||
MotifFDialog_ActivateFEnt $w
|
||||
}
|
||||
|
||||
proc ::tk::MotifFDialog_CancelCmd {w} {
|
||||
variable ::tk::Priv
|
||||
|
||||
set Priv(selectFilePath) ""
|
||||
set Priv(selectFile) ""
|
||||
set Priv(selectPath) ""
|
||||
}
|
||||
|
||||
proc ::tk::ListBoxKeyAccel_Set {w} {
|
||||
bind Listbox <Any-KeyPress> ""
|
||||
bind $w <Destroy> [list tk::ListBoxKeyAccel_Unset $w]
|
||||
bind $w <Any-KeyPress> [list tk::ListBoxKeyAccel_Key $w %A]
|
||||
}
|
||||
|
||||
proc ::tk::ListBoxKeyAccel_Unset {w} {
|
||||
variable ::tk::Priv
|
||||
|
||||
catch {after cancel $Priv(lbAccel,$w,afterId)}
|
||||
unset -nocomplain Priv(lbAccel,$w) Priv(lbAccel,$w,afterId)
|
||||
}
|
||||
|
||||
# ::tk::ListBoxKeyAccel_Key--
|
||||
#
|
||||
# This procedure maintains a list of recently entered keystrokes
|
||||
# over a listbox widget. It arranges an idle event to move the
|
||||
# selection of the listbox to the entry that begins with the
|
||||
# keystrokes.
|
||||
#
|
||||
# Arguments:
|
||||
# w The pathname of the listbox.
|
||||
# key The key which the user just pressed.
|
||||
#
|
||||
# Results:
|
||||
# None.
|
||||
|
||||
proc ::tk::ListBoxKeyAccel_Key {w key} {
|
||||
variable ::tk::Priv
|
||||
|
||||
if { $key eq "" } {
|
||||
return
|
||||
}
|
||||
append Priv(lbAccel,$w) $key
|
||||
ListBoxKeyAccel_Goto $w $Priv(lbAccel,$w)
|
||||
catch {
|
||||
after cancel $Priv(lbAccel,$w,afterId)
|
||||
}
|
||||
set Priv(lbAccel,$w,afterId) [after 500 \
|
||||
[list tk::ListBoxKeyAccel_Reset $w]]
|
||||
}
|
||||
|
||||
proc ::tk::ListBoxKeyAccel_Goto {w string} {
|
||||
variable ::tk::Priv
|
||||
|
||||
set string [string tolower $string]
|
||||
set end [$w index end]
|
||||
set theIndex -1
|
||||
|
||||
for {set i 0} {$i < $end} {incr i} {
|
||||
set item [string tolower [$w get $i]]
|
||||
if {[string compare $string $item] >= 0} {
|
||||
set theIndex $i
|
||||
}
|
||||
if {[string compare $string $item] <= 0} {
|
||||
set theIndex $i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if {$theIndex >= 0} {
|
||||
$w selection clear 0 end
|
||||
$w selection set $theIndex $theIndex
|
||||
$w activate $theIndex
|
||||
$w see $theIndex
|
||||
event generate $w <<ListboxSelect>>
|
||||
}
|
||||
}
|
||||
|
||||
proc ::tk::ListBoxKeyAccel_Reset {w} {
|
||||
variable ::tk::Priv
|
||||
|
||||
unset -nocomplain Priv(lbAccel,$w)
|
||||
}
|
||||
|
||||
proc ::tk_getFileType {} {
|
||||
variable ::tk::Priv
|
||||
|
||||
return $Priv(selectFileType)
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
This software is copyrighted by the Regents of the University of
|
||||
California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
|
||||
Corporation and other parties. The following terms apply to all files
|
||||
associated with the software unless explicitly disclaimed in
|
||||
individual files.
|
||||
|
||||
The authors 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 AUTHORS 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 AUTHORS HAVE BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
THE AUTHORS 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 AUTHORS AND DISTRIBUTORS HAVE
|
||||
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
||||
MODIFICATIONS.
|
||||
|
||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
||||
U.S. government, the Government shall have only "Restricted Rights"
|
||||
in the software and related documentation as defined in the Federal
|
||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
|
||||
are acquiring the software on behalf of the Department of Defense, the
|
||||
software shall be classified as "Commercial Computer Software" and the
|
||||
Government shall have only "Restricted Rights" as defined in Clause
|
||||
252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the
|
||||
authors grant the U.S. Government and others acting in its behalf
|
||||
permission to use and distribute the software in accordance with the
|
||||
terms specified in this license.
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
This software is copyrighted by the Regents of the University of
|
||||
California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
|
||||
Corporation, Apple Inc. and other parties. The following terms apply to
|
||||
all files associated with the software unless explicitly disclaimed in
|
||||
individual files.
|
||||
|
||||
The authors 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 AUTHORS 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 AUTHORS HAVE BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
THE AUTHORS 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 AUTHORS AND DISTRIBUTORS HAVE
|
||||
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
||||
MODIFICATIONS.
|
||||
|
||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
||||
U.S. government, the Government shall have only "Restricted Rights"
|
||||
in the software and related documentation as defined in the Federal
|
||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
|
||||
are acquiring the software on behalf of the Department of Defense, the
|
||||
software shall be classified as "Commercial Computer Software" and the
|
||||
Government shall have only "Restricted Rights" as defined in Clause
|
||||
252.227-7013 (b) (3) of DFARs. Notwithstanding the foregoing, the
|
||||
authors grant the U.S. Government and others acting in its behalf
|
||||
permission to use and distribute the software in accordance with the
|
||||
terms specified in this license.
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
This software is copyrighted by the Regents of the University of
|
||||
California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
|
||||
Corporation, Apple Inc. and other parties. The following terms apply to
|
||||
all files associated with the software unless explicitly disclaimed in
|
||||
individual files.
|
||||
|
||||
The authors 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 AUTHORS 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 AUTHORS HAVE BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
THE AUTHORS 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 AUTHORS AND DISTRIBUTORS HAVE
|
||||
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
||||
MODIFICATIONS.
|
||||
|
||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
||||
U.S. government, the Government shall have only "Restricted Rights"
|
||||
in the software and related documentation as defined in the Federal
|
||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
|
||||
are acquiring the software on behalf of the Department of Defense, the
|
||||
software shall be classified as "Commercial Computer Software" and the
|
||||
Government shall have only "Restricted Rights" as defined in Clause
|
||||
252.227-7013 (b) (3) of DFARs. Notwithstanding the foregoing, the
|
||||
authors grant the U.S. Government and others acting in its behalf
|
||||
permission to use and distribute the software in accordance with the
|
||||
terms specified in this license.
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
xcopy binary_template xschem-%1-win64 /E/H/C/I
|
||||
cd xschem-%1-win64
|
||||
copy "C:\Program Files\Xschem\bin\Xschem.exe" bin
|
||||
copy "D:\Projects\XSchem\LICENSE" licenses
|
||||
mkdir doc
|
||||
cd doc
|
||||
xcopy "C:\Program Files\Xschem\doc" . /E/H/C/I
|
||||
cd ..
|
||||
mkdir share
|
||||
cd share
|
||||
xcopy "C:\Program Files\Xschem\share" . /E/H/C/I
|
||||
cd ..
|
||||
mkdir xschem_library
|
||||
cd xschem_library
|
||||
xcopy "C:\Program Files\Xschem\xschem_library" . /E/H/C/I
|
||||
cd ..
|
||||
cd ..
|
||||
tar.exe -a -c -f xschem-%1-win64.zip xschem-%1-win64
|
||||
rmdir /s /q xschem-%1-win64
|
||||
copy ..\XSchemWix\bin\Release\XSchem.msi .
|
||||
rename XSchem.msi XSchem-%1-64bit.msi
|
||||
|
|
@ -41,6 +41,7 @@ INSTRUCTIONS TO ADD XSCHEM TO VISUAL STUDIO 2019
|
|||
Optional:
|
||||
- Windows Ghostscript (to print)
|
||||
Update xschemrc to set variable to_pdf and to_png
|
||||
Add directory of gswin64.exe to PATH if installer didn't do it
|
||||
|
||||
2. Create new XSchemWin project on Visual Studio 2019
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product Id="*" Name="Xschem" Language="1033" Version="2.9.9.6" Manufacturer="Xschem" UpgradeCode="0deb9c17-cbbd-491c-be3e-24446b27ccd5">
|
||||
<Product Id="*" Name="Xschem" Language="1033" Version="2.9.9.7" Manufacturer="Xschem" UpgradeCode="0deb9c17-cbbd-491c-be3e-24446b27ccd5">
|
||||
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
|
||||
<WixVariable Id="WixUILicenseRtf"
|
||||
Value="License.rtf" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue