arduino-0018-windows
This commit is contained in:
parent
157fd6f1a1
commit
f39fc49523
5182 changed files with 950586 additions and 0 deletions
|
@ -0,0 +1,82 @@
|
|||
# advice.tcl - Generic advice package.
|
||||
# Copyright (C) 1998 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# Please note that I adapted this from some code I wrote elsewhere,
|
||||
# for non-Cygnus reasons. Don't complain to me if you see something
|
||||
# like it somewhere else.
|
||||
|
||||
|
||||
# Internal state.
|
||||
defarray ADVICE_state
|
||||
|
||||
# This is a helper proc that does all the actual work.
|
||||
proc ADVICE_do {command argList} {
|
||||
global ADVICE_state
|
||||
|
||||
# Run before advice.
|
||||
if {[info exists ADVICE_state(before,$command)]} {
|
||||
foreach item $ADVICE_state(before,$command) {
|
||||
# We purposely let errors in advice go uncaught.
|
||||
uplevel $item $argList
|
||||
}
|
||||
}
|
||||
|
||||
# Run the command itself.
|
||||
set code [catch \
|
||||
[list uplevel \#0 $ADVICE_state(original,$command) $argList] \
|
||||
result]
|
||||
|
||||
# Run the after advice.
|
||||
if {[info exists ADVICE_state(after,$command)]} {
|
||||
foreach item $ADVICE_state(after,$command) {
|
||||
# We purposely let errors in advice go uncaught.
|
||||
uplevel $item [list $code $result] $argList
|
||||
}
|
||||
}
|
||||
|
||||
# Return just as the original command would.
|
||||
return -code $code $result
|
||||
}
|
||||
|
||||
# Put some advice on a proc or command.
|
||||
# WHEN says when to run the advice - `before' or `after' the
|
||||
# advisee is run.
|
||||
# WHAT is the name of the proc or command to advise.
|
||||
# ADVISOR is the advice. It is passed the arguments to the advisee
|
||||
# call as its arguments. In addition, `after' advisors are
|
||||
# passed the return code and return value of the proc as their
|
||||
# first and second arguments.
|
||||
proc advise {when what advisor} {
|
||||
global ADVICE_state
|
||||
|
||||
if {! [info exists ADVICE_state(original,$what)]} {
|
||||
set newName [gensym]
|
||||
rename $what $newName
|
||||
set ADVICE_state(original,$what) $newName
|
||||
|
||||
# Create a new proc which just runs our internal command with the
|
||||
# correct arguments.
|
||||
uplevel \#0 [list proc $what args \
|
||||
[format {ADVICE_do %s $args} $what]]
|
||||
}
|
||||
|
||||
lappend ADVICE_state($when,$what) $advisor
|
||||
}
|
||||
|
||||
# Remove some previously-set advice. Note that we could undo the
|
||||
# `rename' when the last advisor is removed. This adds complexity,
|
||||
# though, and there isn't much reason to.
|
||||
proc unadvise {when what advisor} {
|
||||
global ADVICE_state
|
||||
|
||||
if {[info exists ADVICE_state($when,$what)]} {
|
||||
set newList {}
|
||||
foreach item $ADVICE_state($when,$what) {
|
||||
if {[string compare $advisor $item]} {
|
||||
lappend newList $item
|
||||
}
|
||||
}
|
||||
set ADVICE_state($when,$what) $newList
|
||||
}
|
||||
}
|
|
@ -0,0 +1,538 @@
|
|||
# balloon.tcl - Balloon help.
|
||||
# Copyright (C) 1997, 1998, 2000 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# KNOWN BUGS:
|
||||
# * On Windows, various delays should be determined from system;
|
||||
# presently they are hard-coded.
|
||||
# * Likewise, balloon positioning on Windows is a hack.
|
||||
|
||||
itcl_class Balloon {
|
||||
# Name of associated global variable which should be set whenever
|
||||
# the help is shown.
|
||||
public variable {}
|
||||
|
||||
# Name of associated toplevel. Private variable.
|
||||
protected _top {}
|
||||
|
||||
# This is non-empty if there is an after script pending. Private
|
||||
# method.
|
||||
protected _after_id {}
|
||||
|
||||
# This is an array mapping window name to help text.
|
||||
protected _help_text
|
||||
|
||||
# This is an array mapping window name to notification proc.
|
||||
protected _notifiers
|
||||
|
||||
# This is set to the name of the parent widget whenever the mouse is
|
||||
# in a widget with balloon help.
|
||||
protected _active {}
|
||||
|
||||
# This is true when we're already calling a notification proc.
|
||||
# Private variable.
|
||||
protected _in_notifier 0
|
||||
|
||||
# This holds the parent of the most recently entered widget. It is
|
||||
# used to determine when the user is moving through a toolbar.
|
||||
# Private variable.
|
||||
protected _recent_parent {}
|
||||
|
||||
constructor {top} {
|
||||
global tcl_platform
|
||||
|
||||
set _top $top
|
||||
set class [$this info class]
|
||||
|
||||
# The standard widget-making trick.
|
||||
set hull [namespace tail $this]
|
||||
set old_name $this
|
||||
::rename $this $this-tmp-
|
||||
::toplevel $hull -class $class -borderwidth 1 -background black
|
||||
::rename $hull $old_name-win-
|
||||
::rename $this $old_name
|
||||
|
||||
# By default we are invisible. When we are visible, we are
|
||||
# borderless.
|
||||
wm withdraw [namespace tail $this]
|
||||
wm overrideredirect [namespace tail $this] 1
|
||||
|
||||
# Put some bindings on the toplevel. We don't use
|
||||
# bind_for_toplevel_only because *do* want these bindings to be
|
||||
# run when the event happens on some child.
|
||||
bind $_top <Enter> [list $this _enter %W]
|
||||
bind $_top <Leave> [list $this _leave]
|
||||
# Only run this one if we aren't already destroyed.
|
||||
bind $_top <Destroy> [format {
|
||||
if {[info commands %s] != ""} then {
|
||||
%s _subdestroy %%W
|
||||
}
|
||||
} $this $this]
|
||||
bind $_top <Unmap> [list $this _unmap %W]
|
||||
# Add more here as required.
|
||||
bind $_top <1> [format {
|
||||
%s _cancel
|
||||
%s _unshowballoon
|
||||
} $this $this]
|
||||
|
||||
if {$tcl_platform(platform) == "windows"} then {
|
||||
set bg SystemInfoBackground
|
||||
set fg SystemInfoText
|
||||
} else {
|
||||
# This color is called `LemonChiffon' by my X installation.
|
||||
set bg \#ffffffffcccc
|
||||
set fg black
|
||||
}
|
||||
|
||||
# Where we display stuff.
|
||||
label [namespace tail $this].label -background $bg -foreground $fg -font global/status \
|
||||
-anchor w -justify left
|
||||
pack [namespace tail $this].label -expand 1 -fill both
|
||||
|
||||
# Clean up when the label is destroyed. This has the hidden
|
||||
# assumption that the balloon widget is a child of the toplevel to
|
||||
# which it is connected.
|
||||
bind [namespace tail $this].label <Destroy> [list $this delete]
|
||||
}
|
||||
|
||||
destructor {
|
||||
catch {_cancel}
|
||||
catch {after cancel [list $this _unshowballoon]}
|
||||
catch {destroy $this}
|
||||
}
|
||||
|
||||
method configure {config} {}
|
||||
|
||||
# Register a notifier for a window.
|
||||
method notify {command window {tag {}}} {
|
||||
if {$tag == ""} then {
|
||||
set item $window
|
||||
} else {
|
||||
set item $window,$tag
|
||||
}
|
||||
|
||||
if {$command == ""} then {
|
||||
unset _notifiers($item)
|
||||
} else {
|
||||
set _notifiers($item) $command
|
||||
}
|
||||
}
|
||||
|
||||
# Register help for a window.
|
||||
method register {window text {tag {}}} {
|
||||
if {$tag == ""} then {
|
||||
set item $window
|
||||
} else {
|
||||
# Switching on the window class is bad. Do something better.
|
||||
set class [winfo class $window]
|
||||
|
||||
# Switching on window class is bad. Do something better.
|
||||
switch -- $class {
|
||||
Menu {
|
||||
# Menus require bindings that other items do not require.
|
||||
# So here we make sure the menu has the binding. We could
|
||||
# speed this up by keeping a special entry in the _help_text
|
||||
# array if we wanted. Note that we pass in the name of the
|
||||
# window as we know it. That lets us work even when we're
|
||||
# actually getting events for a clone window. This is less
|
||||
# than ideal, because it means we have to hijack the
|
||||
# MenuSelect binding, but we live with it. (The other
|
||||
# choice is to make a new bindtag per menu -- yuck.)
|
||||
# This is relatively nasty: we have to encode the window
|
||||
# name as passed to the _motion method; otherwise the
|
||||
# cloning munges it. Sigh.
|
||||
regsub -all -- \\. $window ! munge
|
||||
bind $window <<MenuSelect>> [list $this _motion %W $munge]
|
||||
}
|
||||
|
||||
Canvas {
|
||||
# If we need to add a binding for this tag, do so.
|
||||
if {! [info exists _help_text($window,$tag)]} then {
|
||||
$window bind $tag <Enter> +[list $this _enter $window $tag]
|
||||
$window bind $tag <Leave> +[list $this _leave]
|
||||
$window bind $tag <1> +[format {
|
||||
%s _cancel
|
||||
%s _unshowballoon
|
||||
} $this $this]
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
# If we need to add a binding for this tag, do so.
|
||||
if {! [info exists _help_text($window,$tag)]} then {
|
||||
$window tag bind $tag <Enter> +[list $this _enter $window $tag]
|
||||
$window tag bind $tag <Leave> +[list $this _leave]
|
||||
$window tag bind $tag <1> +[format {
|
||||
%s _cancel
|
||||
%s _unshowballoon
|
||||
} $this $this]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set item $window,$tag
|
||||
}
|
||||
|
||||
set _help_text($item) $text
|
||||
if {$_active == $item} then {
|
||||
_set_variable $item
|
||||
# If the label is already showing, then we re-show it. Why not
|
||||
# just set the -text on the label? Because if the label changes
|
||||
# size it might be offscreen, and we need to handle that.
|
||||
if {[wm state [namespace tail $this]] == "normal"} then {
|
||||
showballoon $window $tag
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Cancel any pending after handler. Private method.
|
||||
method _cancel {} {
|
||||
if {$_after_id != ""} then {
|
||||
after cancel $_after_id
|
||||
set _after_id {}
|
||||
}
|
||||
}
|
||||
|
||||
# This is run when the toplevel, or any child, is entered. Private
|
||||
# method.
|
||||
method _enter {W {tag {}}} {
|
||||
_cancel
|
||||
|
||||
# Don't bother for menus, since we know we use a different
|
||||
# mechanism for them.
|
||||
if {[winfo class $W] == "Menu"} then {
|
||||
return
|
||||
}
|
||||
|
||||
# If we just moved into the parent of the last child, then do
|
||||
# nothing. We want to keep the parent the same so the right thing
|
||||
# can happen if we move into a child of this same parent.
|
||||
set delay 1000
|
||||
if {$W != $_recent_parent} then {
|
||||
if {[winfo parent $W] == $_recent_parent} then {
|
||||
# As soon as possible.
|
||||
set delay idle
|
||||
} else {
|
||||
set _recent_parent ""
|
||||
}
|
||||
}
|
||||
|
||||
if {$tag == ""} then {
|
||||
set index $W
|
||||
} else {
|
||||
set index $W,$tag
|
||||
}
|
||||
set _active $index
|
||||
if {[info exists _help_text($index)]} then {
|
||||
# There is some help text. So arrange to display it when the
|
||||
# time is up. We arbitrarily set this to 1 second.
|
||||
set _after_id [after $delay [list $this showballoon $W $tag]]
|
||||
|
||||
# Set variable here; that way simply entering a window will
|
||||
# cause the text to appear.
|
||||
_set_variable $index
|
||||
}
|
||||
}
|
||||
|
||||
# This is run when the toplevel, or any child, is left. Private
|
||||
# method.
|
||||
method _leave {} {
|
||||
_cancel
|
||||
_unshowballoon
|
||||
_set_variable {}
|
||||
set _active {}
|
||||
}
|
||||
|
||||
# This is run to undisplay the balloon. Note that it does not
|
||||
# change the text stored in the variable. That is handled
|
||||
# elsewhere. Private method.
|
||||
method _unshowballoon {} {
|
||||
wm withdraw [namespace tail $this]
|
||||
}
|
||||
|
||||
# Set the variable, if it exists. Private method.
|
||||
method _set_variable {index} {
|
||||
# Run the notifier.
|
||||
if {$index == ""} then {
|
||||
set value ""
|
||||
} elseif {[info exists _notifiers($index)] && ! $_in_notifier} then {
|
||||
if {$variable != ""} {
|
||||
upvar $variable var
|
||||
set var $_help_text($index)
|
||||
}
|
||||
set _in_notifier 1
|
||||
uplevel \#0 $_notifiers($index)
|
||||
set _in_notifier 0
|
||||
# Get value afterwards to give notifier a chance to change it.
|
||||
if {$variable != ""} {
|
||||
upvar $variable var
|
||||
set _help_text($index) $var
|
||||
}
|
||||
set value $_help_text($index)
|
||||
} else {
|
||||
set value $_help_text($index)
|
||||
}
|
||||
|
||||
if {$variable != ""} then {
|
||||
upvar $variable var
|
||||
set var $value
|
||||
}
|
||||
}
|
||||
|
||||
# This is run to show the balloon. Private method.
|
||||
method showballoon {W tag {keep 0}} {
|
||||
global tcl_platform
|
||||
|
||||
if {$tag == ""} then {
|
||||
# An ordinary window. Position below the window, and right of
|
||||
# center.
|
||||
set _active $W
|
||||
set left [expr {[winfo rootx $W] + round ([winfo width $W] * .75)}]
|
||||
set ypos [expr {[winfo rooty $W] + [winfo height $W]}]
|
||||
set alt_ypos [winfo rooty $W]
|
||||
|
||||
# Balloon shown, so set parent info.
|
||||
set _recent_parent [winfo parent $W]
|
||||
} else {
|
||||
set _active $W,$tag
|
||||
# Switching on class name is bad. Do something better. Can't
|
||||
# just use the widget's bbox method, because the results differ
|
||||
# for Text and Canvas widgets. Bummer.
|
||||
switch -- [winfo class $W] {
|
||||
Menu {
|
||||
# Recognize but do nothing.
|
||||
}
|
||||
|
||||
Text {
|
||||
lassign [$W bbox $tag.first] x y width height
|
||||
set left [expr {[winfo rootx $W] + $x + round ($width * .75)}]
|
||||
set ypos [expr {[winfo rooty $W] + $y + $height}]
|
||||
set alt_ypos [expr {[winfo rooty $W] - $y}]
|
||||
}
|
||||
|
||||
Canvas {
|
||||
lassign [$W bbox $tag] x1 y1 x2 y2
|
||||
# Must subtract out coordinates of top-left corner of canvas
|
||||
# window; otherwise this will get the wrong position when
|
||||
# the canvas has been scrolled.
|
||||
set tlx [$W canvasx 0]
|
||||
set tly [$W canvasy 0]
|
||||
# Must round results because canvas coordinates are floats.
|
||||
set left [expr {round ([winfo rootx $W] + $x1 - $tlx
|
||||
+ ($x2 - $x1) * .75)}]
|
||||
set ypos [expr {round ([winfo rooty $W] + $y2 - $tly)}]
|
||||
set alt_ypos [expr {round ([winfo rooty $W] + $y1 - $tly)}]
|
||||
}
|
||||
|
||||
default {
|
||||
error "unrecognized window class for window \"$W\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set help $_help_text($_active)
|
||||
|
||||
# On Windows, the popup location is always determined by the
|
||||
# cursor. Actually, the rule seems to be somewhat more complex.
|
||||
# Unfortunately it doesn't seem to be written down anywhere.
|
||||
# Experiments show that the location is determined by the cursor
|
||||
# if the text is wider than the widget; and otherwise it is
|
||||
# centered under the widget. FIXME: we don't deal with those
|
||||
# cases.
|
||||
if {$tcl_platform(platform) == "windows"} then {
|
||||
# FIXME: for now this is turned off. It isn't enough to get the
|
||||
# cursor size; we actually have to find the bottommost "on"
|
||||
# pixel in the cursor and use that for the height. I don't know
|
||||
# how to do that.
|
||||
# lassign [ide_cursor size] dummy height
|
||||
# lassign [ide_cursor position] left ypos
|
||||
# incr ypos $height
|
||||
}
|
||||
|
||||
if {[info exists left] && $help != ""} then {
|
||||
[namespace tail $this].label configure -text $help
|
||||
set lw [winfo reqwidth [namespace tail $this].label]
|
||||
set sw [winfo screenwidth [namespace tail $this]]
|
||||
set bw [$this-win- cget -borderwidth]
|
||||
if {$left + $lw + 2 * $bw >= $sw} then {
|
||||
set left [expr {$sw - 2 * $bw - $lw}]
|
||||
}
|
||||
|
||||
set lh [winfo reqheight [namespace tail $this].label]
|
||||
if {$ypos + $lh >= [winfo screenheight [namespace tail $this]]} then {
|
||||
set ypos [expr {$alt_ypos - $lh}]
|
||||
}
|
||||
|
||||
wm positionfrom [namespace tail $this] user
|
||||
wm geometry [namespace tail $this] +${left}+${ypos}
|
||||
update
|
||||
wm deiconify [namespace tail $this]
|
||||
raise [namespace tail $this]
|
||||
|
||||
if {!$keep} {
|
||||
# After 6 seconds, close the window. The timer is reset every
|
||||
# time the window is shown.
|
||||
after cancel [list $this _unshowballoon]
|
||||
after 6000 [list $this _unshowballoon]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# This is run when a window or tag is destroyed. Private method.
|
||||
method _subdestroy {W {tag {}}} {
|
||||
if {$tag == ""} then {
|
||||
# A window. Remove the window and any associated tags. Note
|
||||
# that this is called for all Destroy events on descendents,
|
||||
# even for windows which were never registered. Hence the use
|
||||
# of catch.
|
||||
catch {unset _help_text($W)}
|
||||
foreach thing [array names _help_text($W,*)] {
|
||||
unset _help_text($thing)
|
||||
}
|
||||
} else {
|
||||
# Just a tag. This one can't be called by mistake, so this
|
||||
# shouldn't need to be caught.
|
||||
unset _help_text($W,$tag)
|
||||
}
|
||||
}
|
||||
|
||||
# This is run in response to a MenuSelect event on a menu.
|
||||
method _motion {window name} {
|
||||
# Decode window name.
|
||||
regsub -all -- ! $name . name
|
||||
|
||||
if {$variable == ""} then {
|
||||
# There's no point to doing anything.
|
||||
return
|
||||
}
|
||||
|
||||
set n [$window index active]
|
||||
if {$n == "none"} then {
|
||||
set index ""
|
||||
set _active {}
|
||||
} elseif {[info exists _help_text($name,$n)]} then {
|
||||
# Tag specified by index number.
|
||||
set index $name,$n
|
||||
set _active $name,$n
|
||||
} elseif {! [catch {$window entrycget $n -label} label]
|
||||
&& [info exists _help_text($name,$label)]} then {
|
||||
# Tag specified by index name.
|
||||
set index $name,$label
|
||||
set _active $name,$label
|
||||
} else {
|
||||
# No help for this item.
|
||||
set index ""
|
||||
set _active {}
|
||||
}
|
||||
|
||||
_set_variable $index
|
||||
}
|
||||
|
||||
# This is run when some widget unmaps. If the widget is the current
|
||||
# widget, then unmap the balloon help. Private method.
|
||||
method _unmap w {
|
||||
if {$w == $_active} then {
|
||||
_cancel
|
||||
_unshowballoon
|
||||
_set_variable {}
|
||||
set _active {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
################################################################
|
||||
|
||||
# Find (and possibly create) balloon widget associated with window.
|
||||
proc BALLOON_find_balloon {window} {
|
||||
# Find our associated toplevel. If it is a menu, then keep going.
|
||||
set top [winfo toplevel $window]
|
||||
while {[winfo class $top] == "Menu"} {
|
||||
set top [winfo toplevel [winfo parent $top]]
|
||||
}
|
||||
|
||||
if {$top == "."} {
|
||||
set bname .__balloon
|
||||
} else {
|
||||
set bname $top.__balloon
|
||||
}
|
||||
|
||||
# If the balloon help for this toplevel doesn't exist, then create
|
||||
# it. Yes, this relies on a magic name for the balloon help widget.
|
||||
if {! [winfo exists $bname]} then {
|
||||
Balloon $bname $top
|
||||
}
|
||||
return $bname
|
||||
}
|
||||
|
||||
# This implements "balloon register".
|
||||
proc BALLOON_command_register {window text {tag {}}} {
|
||||
set b [BALLOON_find_balloon $window]
|
||||
$b register $window $text $tag
|
||||
}
|
||||
|
||||
# This implements "balloon notify".
|
||||
proc BALLOON_command_notify {command window {tag {}}} {
|
||||
set b [BALLOON_find_balloon $window]
|
||||
$b notify $command $window $tag
|
||||
}
|
||||
|
||||
# This implements "balloon show".
|
||||
proc BALLOON_command_show {window {tag {}} {keep 0}} {
|
||||
set b [BALLOON_find_balloon $window]
|
||||
$b showballoon $window $tag $keep
|
||||
}
|
||||
|
||||
proc BALLOON_command_withdraw {window} {
|
||||
set b [BALLOON_find_balloon $window]
|
||||
$b _unmap $window
|
||||
}
|
||||
|
||||
# This implements "balloon variable".
|
||||
proc BALLOON_command_variable {window args} {
|
||||
if {[llength $args] == 0} then {
|
||||
# Fetch.
|
||||
set b [BALLOON_find_balloon $window]
|
||||
return [$b cget -variable]
|
||||
} else {
|
||||
# FIXME: no arg checking here.
|
||||
# Set.
|
||||
set b [BALLOON_find_balloon $window]
|
||||
$b configure -variable [lindex $args 0]
|
||||
}
|
||||
}
|
||||
|
||||
# The primary interface to balloon help.
|
||||
# Usage:
|
||||
# balloon notify COMMAND WINDOW ?TAG?
|
||||
# Run COMMAND just before the help text for WINDOW (and TAG, if
|
||||
# given) is displayed. If COMMAND is the empty string, then
|
||||
# notification is disabled for this window.
|
||||
# balloon register WINDOW TEXT ?TAG?
|
||||
# Associate TEXT as the balloon help for WINDOW.
|
||||
# If TAG is given, the use the appropriate tag for association.
|
||||
# For menu widgets, TAG is a menu index.
|
||||
# For canvas widgets, TAG is a tagOrId.
|
||||
# For text widgets, TAG is a text index. If you want to use
|
||||
# the text tag FOO, use `FOO.last'.
|
||||
# balloon show WINDOW ?TAG?
|
||||
# Immediately pop up the balloon for the given window and tag.
|
||||
# This should be used sparingly. For instance, you might need to
|
||||
# use it if the tag you're interested in does not track the mouse,
|
||||
# but instead is added just before show-time.
|
||||
# balloon variable WINDOW ?NAME?
|
||||
# If NAME specified, set balloon help variable associated
|
||||
# with window. This variable is set to the text whenever the
|
||||
# balloon help is on. If NAME is specified but empty,
|
||||
# no variable is set. If NAME not specified, then the
|
||||
# current variable name is returned.
|
||||
# balloon withdraw WINDOW
|
||||
# Withdraw the balloon window associated with WINDOW. This should
|
||||
# be used sparingly.
|
||||
proc balloon {key args} {
|
||||
if {[info commands BALLOON_command_$key] == "" } then {
|
||||
error "unrecognized key \"$key\""
|
||||
}
|
||||
|
||||
eval BALLOON_command_$key $args
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
# bbox.tcl - Function for handling button box.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# Pass this proc a frame whose children are all buttons. It will put
|
||||
# the children into the frame so that they look right on the current
|
||||
# platform. On Windows this means that they are all the same width
|
||||
# and have a uniform separation. (And currently on Unix it means this
|
||||
# same thing, though that might change.)
|
||||
proc standard_button_box {frame {horizontal 1}} {
|
||||
# This is half the separation we want between the buttons. This
|
||||
# number comes from the Windows UI "standards" manual.
|
||||
set half_gap 2
|
||||
|
||||
set width 0
|
||||
foreach button [winfo children $frame] {
|
||||
set bw [winfo reqwidth $button]
|
||||
if {$bw > $width} then {
|
||||
set width $bw
|
||||
}
|
||||
}
|
||||
|
||||
incr width $half_gap
|
||||
incr width $half_gap
|
||||
|
||||
if {$horizontal} then {
|
||||
set i 1
|
||||
} else {
|
||||
set i 0
|
||||
}
|
||||
foreach button [winfo children $frame] {
|
||||
if {$horizontal} then {
|
||||
# We set the size via the grid, and not -width on the button.
|
||||
# Why? Because in Tk -width has different units depending on the
|
||||
# contents of the button. And worse, the font units don't really
|
||||
# make sense when dealing with a proportional font.
|
||||
grid $button -row 0 -column $i -sticky ew \
|
||||
-padx $half_gap -pady $half_gap
|
||||
grid columnconfigure $frame $i -weight 0 -minsize $width
|
||||
} else {
|
||||
grid $button -column 0 -row $i -sticky new \
|
||||
-padx $half_gap -pady $half_gap
|
||||
grid rowconfigure $frame $i -weight 0
|
||||
}
|
||||
incr i
|
||||
}
|
||||
|
||||
if {$horizontal} then {
|
||||
# Make the empty column 0 suck up all the space.
|
||||
grid columnconfigure $frame 0 -weight 1
|
||||
} else {
|
||||
grid columnconfigure $frame 0 -minsize $width
|
||||
# Make the last row suck up all the space.
|
||||
incr i -1
|
||||
grid rowconfigure $frame $i -weight 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
# bgerror.tcl - Send bug report in response to uncaught Tcl error.
|
||||
# Copyright (C) 1997, 1998, 1999 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
proc bgerror err {
|
||||
global errorInfo errorCode
|
||||
|
||||
set info $errorInfo
|
||||
set code $errorCode
|
||||
|
||||
# log the error to the debug window or file
|
||||
dbug E $info
|
||||
dbug E $code
|
||||
|
||||
set command [list tk_dialog .bgerrorDialog [gettext "GDB Error"] \
|
||||
[format [gettext "Error: %s"] $err] \
|
||||
error 0 [gettext "OK"]]
|
||||
lappend command [gettext "Stack Trace"]
|
||||
|
||||
|
||||
set value [eval $command]
|
||||
if {$value == 0} {
|
||||
return
|
||||
}
|
||||
|
||||
set w .bgerrorTrace
|
||||
catch {destroy $w}
|
||||
toplevel $w -class ErrorTrace
|
||||
wm minsize $w 1 1
|
||||
wm title $w "Stack Trace for Error"
|
||||
wm iconname $w "Stack Trace"
|
||||
button $w.ok -text OK -command "destroy $w" -default active
|
||||
text $w.text -relief sunken -bd 2 -yscrollcommand "$w.scroll set" \
|
||||
-setgrid true -width 60 -height 20
|
||||
scrollbar $w.scroll -relief sunken -command "$w.text yview"
|
||||
pack $w.ok -side bottom -padx 3m -pady 2m
|
||||
pack $w.scroll -side right -fill y
|
||||
pack $w.text -side left -expand yes -fill both
|
||||
$w.text insert 0.0 "errorCode is $errorCode"
|
||||
$w.text insert 0.0 $info
|
||||
$w.text mark set insert 0.0
|
||||
|
||||
bind $w <Return> "destroy $w"
|
||||
bind $w.text <Return> "destroy $w; break"
|
||||
|
||||
# Center the window on the screen.
|
||||
|
||||
wm withdraw $w
|
||||
update idletasks
|
||||
set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
|
||||
- [winfo vrootx [winfo parent $w]]]
|
||||
set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
|
||||
- [winfo vrooty [winfo parent $w]]]
|
||||
wm geom $w +$x+$y
|
||||
wm deiconify $w
|
||||
|
||||
# Be sure to release any grabs that might be present on the
|
||||
# screen, since they could make it impossible for the user
|
||||
# to interact with the stack trace.
|
||||
|
||||
if {[grab current .] != ""} {
|
||||
grab release [grab current .]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
# bindings.tcl - Procs to handle bindings.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# Reorder the bindtags so that the tag appears before the widget.
|
||||
# Tries to preserve other relative orderings as much as possible. In
|
||||
# particular, nothing changes if the widget is already after the tag.
|
||||
proc bind_widget_after_tag {w tag} {
|
||||
set seen_tag 0
|
||||
set seen_widget 0
|
||||
set new_list {}
|
||||
foreach tag [bindtags $w] {
|
||||
if {$tag == $tag} then {
|
||||
lappend new_list $tag
|
||||
if {$seen_widget} then {
|
||||
lappend new_list $w
|
||||
}
|
||||
set seen_tag 1
|
||||
} elseif {$tag == $w} then {
|
||||
if {$seen_tag} then {
|
||||
lappend new_list $tag
|
||||
}
|
||||
set seen_widget 1
|
||||
} else {
|
||||
lappend new_list $tag
|
||||
}
|
||||
}
|
||||
|
||||
if {! $seen_widget} then {
|
||||
lappend new_list $w
|
||||
}
|
||||
|
||||
bindtags $w $new_list
|
||||
}
|
||||
|
||||
# Reorder the bindtags so that the class appears before the widget.
|
||||
# Tries to preserve other relative orderings as much as possible. In
|
||||
# particular, nothing changes if the widget is already after the
|
||||
# class.
|
||||
proc bind_widget_after_class {w} {
|
||||
bind_widget_after_tag $w [winfo class $w]
|
||||
}
|
||||
|
||||
# Make the specified binding for KEY and empty bindings for common
|
||||
# modifiers for KEY. This can be used to ensure that a binding won't
|
||||
# also be triggered by (eg) Alt-KEY. This proc also makes the binding
|
||||
# case-insensitive. KEY is either the name of a key, or a key with a
|
||||
# single modifier.
|
||||
proc bind_plain_key {w key binding} {
|
||||
set l [split $key -]
|
||||
if {[llength $l] == 1} then {
|
||||
set mod {}
|
||||
set part $key
|
||||
} else {
|
||||
set mod "[lindex $l 0]-"
|
||||
set part [lindex $l 1]
|
||||
}
|
||||
|
||||
set modifiers {Meta- Alt- Control-}
|
||||
|
||||
set part_list [list $part]
|
||||
# If we just have a single letter, then we can't look for
|
||||
# Shift-PART; we must use the uppercase equivalent.
|
||||
if {[string length $part] == 1} then {
|
||||
# This is nasty: if we bind Control-L, we won't see the events we
|
||||
# want. Instead we have to bind Shift-Control-L. Actually, we
|
||||
# must also bind Control-L so that we'll see the event if the Caps
|
||||
# Lock key is down.
|
||||
if {$mod != ""} then {
|
||||
lappend part_list "Shift-[string toupper $part]"
|
||||
}
|
||||
lappend part_list [string toupper $part]
|
||||
} else {
|
||||
lappend modifiers Shift-
|
||||
}
|
||||
|
||||
foreach part $part_list {
|
||||
# Bind the key itself (with modifier if required).
|
||||
bind $w <${mod}${part}> $binding
|
||||
|
||||
# Ignore any modifiers other than the one we like.
|
||||
foreach onemod $modifiers {
|
||||
if {$onemod != $mod} then {
|
||||
bind $w <${onemod}${part}> {;}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
# canvas.tcl - Handy canvas-related commands.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# Set scroll region on canvas.
|
||||
proc set_scroll_region {canvas} {
|
||||
set bbox [$canvas bbox all]
|
||||
if {[llength $bbox]} then {
|
||||
set sr [lreplace $bbox 0 1 0 0]
|
||||
} else {
|
||||
set sr {0 0 0 0}
|
||||
}
|
||||
|
||||
# Don't include borders in the scrollregion.
|
||||
set delta [expr {2 * ([$canvas cget -borderwidth]
|
||||
+ [$canvas cget -highlightthickness])}]
|
||||
|
||||
set ww [winfo width $canvas]
|
||||
if {[lindex $sr 2] < $ww} then {
|
||||
set sr [lreplace $sr 2 2 [expr {$ww - $delta}]]
|
||||
}
|
||||
|
||||
set wh [winfo height $canvas]
|
||||
if {[lindex $sr 3] < $wh} then {
|
||||
set sr [lreplace $sr 3 3 [expr {$wh - $delta}]]
|
||||
}
|
||||
|
||||
$canvas configure -scrollregion $sr
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
# center.tcl - Center a window on the screen or over another window
|
||||
# Copyright (C) 1997, 1998, 2001 Red Hat, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# Call this after the TOPLEVEL has been filled in, but before it has
|
||||
# been mapped. This proc will center the toplevel on the screen or
|
||||
# over another window.
|
||||
proc center_window {top args} {
|
||||
parse_args {{over ""}}
|
||||
|
||||
update idletasks
|
||||
if {$over != ""} {
|
||||
set cx [expr {int ([winfo rootx $over] + [winfo width $over] / 2)}]
|
||||
set cy [expr {int ([winfo rooty $over] + [winfo height $over] / 2)}]
|
||||
set x [expr {$cx - int ([winfo reqwidth $top] / 2)}]
|
||||
set y [expr {$cy - int ([winfo reqheight $top] / 2)}]
|
||||
} else {
|
||||
set x [expr {int (([winfo screenwidth $top] - [winfo reqwidth $top]) / 2)}]
|
||||
set y [expr {int (([winfo screenheight $top] - [winfo reqheight $top]) / 2)}]
|
||||
}
|
||||
wm geometry $top +${x}+${y}
|
||||
wm positionfrom $top user
|
||||
|
||||
# We run this update here because Tk updates toplevel geometry
|
||||
# (position) info in an idle handler on Windows, but doesn't force
|
||||
# the handler to run before mapping the window.
|
||||
update idletasks
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
# cframe.tcl - Frame controlled by checkbutton.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
itcl_class Checkframe {
|
||||
inherit Widgetframe
|
||||
|
||||
# The checkbutton text.
|
||||
public text {} {
|
||||
_set_option -text $text 0
|
||||
}
|
||||
|
||||
# This holds the last value of -variable. We use it to unset our
|
||||
# trace when the variable changes (or is deleted). Private
|
||||
# variable.
|
||||
protected _saved_variable {}
|
||||
|
||||
# The checkbutton variable.
|
||||
public variable {} {
|
||||
_var_changed
|
||||
}
|
||||
|
||||
# The checkbutton -onvalue.
|
||||
public onvalue 1 {
|
||||
_set_option -onvalue $onvalue
|
||||
}
|
||||
|
||||
# The checkbutton -offvalue.
|
||||
public offvalue 0 {
|
||||
_set_option -offvalue $offvalue
|
||||
}
|
||||
|
||||
# The checkbutton -command.
|
||||
public command {} {
|
||||
_set_option -command $command 0
|
||||
}
|
||||
|
||||
# This holds balloon help for the checkbutton.
|
||||
public help {} {
|
||||
if {[winfo exists [namespace tail $this].check]} then {
|
||||
balloon register [namespace tail $this].check $help
|
||||
}
|
||||
}
|
||||
|
||||
# This holds a list of all widgets which should be immune to
|
||||
# enabling/disabling. Private variable.
|
||||
protected _avoid {}
|
||||
|
||||
constructor {config} {
|
||||
checkbutton [namespace tail $this].check -text $text -variable $variable -padx 2 \
|
||||
-command $command -onvalue $onvalue -offvalue $offvalue
|
||||
balloon register [namespace tail $this].check $help
|
||||
_add [namespace tail $this].check
|
||||
}
|
||||
|
||||
# Exempt a child from state changes. Argument EXEMPT is true if the
|
||||
# child should be exempted, false if it should be re-enabled again.
|
||||
# Public method.
|
||||
method exempt {child {exempt 1}} {
|
||||
if {$exempt} then {
|
||||
if {[lsearch -exact $_avoid $child] == -1} then {
|
||||
lappend _avoid $child
|
||||
}
|
||||
} else {
|
||||
set _avoid [lremove $_avoid $child]
|
||||
_set_visibility $child
|
||||
}
|
||||
}
|
||||
|
||||
# This is run when the state of the frame's children should change.
|
||||
# Private method.
|
||||
method _set_visibility {{child {}}} {
|
||||
if {$variable == ""} then {
|
||||
# No variable means everything is ok. The behavior here is
|
||||
# arbitrary; this is a losing case.
|
||||
set state normal
|
||||
} else {
|
||||
upvar \#0 $variable the_var
|
||||
if {! [string compare $the_var $onvalue]} then {
|
||||
set state normal
|
||||
} else {
|
||||
set state disabled
|
||||
}
|
||||
}
|
||||
|
||||
if {$child != ""} then {
|
||||
$child configure -state $state
|
||||
} else {
|
||||
# FIXME: we force our logical children to be actual children of
|
||||
# the frame. Instead we should ask the geometry manager what's
|
||||
# going on.
|
||||
set avoid(_) {}
|
||||
unset avoid(_)
|
||||
foreach child $_avoid {
|
||||
set avoid($child) {}
|
||||
}
|
||||
foreach child [winfo children [namespace tail $this].iframe.frame] {
|
||||
if {! [info exists avoid($child)]} then {
|
||||
catch {$child configure -state $state}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# This is run to possibly update some option on the checkbutton.
|
||||
# Private method.
|
||||
method _set_option {option value {set_vis 1}} {
|
||||
if {[winfo exists [namespace tail $this].check]} then {
|
||||
[namespace tail $this].check configure $option $value
|
||||
if {$set_vis} then {
|
||||
_set_visibility
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# This is run when our associated variable changes. We use the
|
||||
# resulting information to set the state of our children. Private
|
||||
# method.
|
||||
method _trace {name1 name2 op} {
|
||||
if {$op == "u"} then {
|
||||
# The variable got deleted. So we stop looking at it.
|
||||
uplevel \#0 [list trace vdelete $_saved_variable uw [list $this _trace]]
|
||||
set _saved_variable {}
|
||||
set variable {}
|
||||
} else {
|
||||
# Got a write.
|
||||
_set_visibility
|
||||
}
|
||||
}
|
||||
|
||||
# This is run when the -variable changes. We remove our old trace
|
||||
# (if there was one) and add a new trace (if we need to). Private
|
||||
# method.
|
||||
method _var_changed {} {
|
||||
if {$_saved_variable != ""} then {
|
||||
# Remove the old trace.
|
||||
uplevel \#0 [list trace vdelete $_saved_variable uw [list $this _trace]]
|
||||
}
|
||||
set _saved_variable $variable
|
||||
|
||||
if {$variable != ""} then {
|
||||
# Set a new trace.
|
||||
uplevel \#0 [list trace variable $variable uw [list $this _trace]]
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,765 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
# NAME:
|
||||
# ::debug
|
||||
#
|
||||
# DESC:
|
||||
# This namespace implements general-purpose debugging functions
|
||||
# to display information as a program runs. In addition, it
|
||||
# includes profiling (derived from Sage 1.1) and tracing. For
|
||||
# output it can write to files, stdout, or use a debug output
|
||||
# window.
|
||||
#
|
||||
# NOTES:
|
||||
# Output of profiler is compatible with sageview.
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
package provide debug 1.0
|
||||
|
||||
namespace eval ::debug {
|
||||
namespace export debug dbug
|
||||
variable VERSION 1.1
|
||||
variable absolute
|
||||
variable stack ""
|
||||
variable outfile "trace.out"
|
||||
variable watch 0
|
||||
variable watchstart 0
|
||||
variable debugwin ""
|
||||
variable tracedVars
|
||||
variable logfile ""
|
||||
variable initialized 0
|
||||
variable stoptrace 0
|
||||
variable tracing 0
|
||||
variable profiling 0
|
||||
variable level 0
|
||||
|
||||
# here's where we'll store our collected profile data
|
||||
namespace eval data {
|
||||
variable entries
|
||||
}
|
||||
|
||||
proc logfile {file} {
|
||||
variable logfile
|
||||
if {$logfile != "" && $logfile != "stdout" && $logfile != "stderr"} {
|
||||
catch {close $logfile}
|
||||
}
|
||||
|
||||
if {$file == ""} {
|
||||
set logfile ""
|
||||
} elseif {$file == "stdout" || $file == "stderr"} {
|
||||
set logfile $file
|
||||
} else {
|
||||
set logfile [open $file w+]
|
||||
fconfigure $logfile -buffering line -blocking 0
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# NAME: debug::trace_var
|
||||
# SYNOPSIS: debug::trace_var {varName mode}
|
||||
# DESC: Sets up variable trace. When the trace is activated,
|
||||
# debugging messages will be displayed.
|
||||
# ARGS: varName - the variable name
|
||||
# mode - one of more of the following letters
|
||||
# r - read
|
||||
# w - write
|
||||
# u - unset
|
||||
# -----------------------------------------------------------------------------
|
||||
proc trace_var {varName mode} {
|
||||
variable tracedVars
|
||||
lappend tracedVars [list $varName $mode]
|
||||
uplevel \#0 trace variable $varName $mode ::debug::touched_by
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# NAME: debug::remove_trace
|
||||
# SYNOPSIS: debug::remove_trace {var mode}
|
||||
# DESC: Removes a trace set up with "trace_var".
|
||||
# ----------------------------------------------------------------------------
|
||||
proc remove_trace {var mode} {
|
||||
uplevel \#0 trace vdelete $var $mode ::debug::touched_by
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# NAME: debug::remove_all_traces
|
||||
# SYNOPSIS: debug::remove_all_traces
|
||||
# DESC: Removes all traces set up with "trace_var".
|
||||
# ----------------------------------------------------------------------------
|
||||
proc remove_all_traces {} {
|
||||
variable tracedVars
|
||||
if {[info exists tracedVars]} {
|
||||
foreach {elem} $tracedVars {
|
||||
eval remove_trace $elem
|
||||
}
|
||||
unset tracedVars
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# NAME: debug::touched_by
|
||||
# SYNOPSIS: debug::touched_by {v a m}
|
||||
# DESC: Trace function used by trace_var. Currently writes standard
|
||||
# debugging messages or priority "W".
|
||||
# ARGS: v - variable
|
||||
# a - array element or ""
|
||||
# m - mode
|
||||
# ----------------------------------------------------------------------------
|
||||
proc touched_by {v a m} {
|
||||
if {$a==""} {
|
||||
upvar $v foo
|
||||
dbug W "Variable $v touched in mode $m"
|
||||
} else {
|
||||
dbug W "Variable ${v}($a) touched in mode $m"
|
||||
upvar $v($a) foo
|
||||
}
|
||||
dbug W "New value: $foo"
|
||||
show_call_stack 2
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# NAME: debug::show_call_stack
|
||||
# SYNOPSIS: debug::show_call_stack {{start_decr 0}}
|
||||
# DESC: Function used by trace_var to print stack trace. Currently
|
||||
# writes standard debugging messages or priority "W".
|
||||
# ARGS: start_decr - how many levels to go up to start trace
|
||||
# ----------------------------------------------------------------------------
|
||||
proc show_call_stack {{start_decr 0}} {
|
||||
set depth [expr {[info level] - $start_decr}]
|
||||
if {$depth == 0} {
|
||||
dbug W "Called at global scope"
|
||||
} else {
|
||||
dbug W "Stack Trace follows:"
|
||||
for {set i $depth} {$i > 0} {incr i -1} {
|
||||
dbug W "Level $i: [info level $i]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# NAME: debug::createData
|
||||
# SYNOPSIS: createData { name }
|
||||
# DESC: Basically creates a data structure for storing profiling
|
||||
# information about a function.
|
||||
# ARGS: name - unique (full) function name
|
||||
# -----------------------------------------------------------------------------
|
||||
proc createData {name} {
|
||||
lappend data::entries $name
|
||||
|
||||
namespace eval data::$name {
|
||||
variable totaltimes 0
|
||||
variable activetime 0
|
||||
variable proccounts 0
|
||||
variable timers 0
|
||||
variable timerstart 0
|
||||
variable nest 0
|
||||
}
|
||||
}
|
||||
|
||||
proc debugwin {obj} {
|
||||
variable debugwin
|
||||
set debugwin $obj
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# NAME: debug::debug
|
||||
#
|
||||
# SYNOPSIS: debug { {msg ""} }
|
||||
#
|
||||
# DESC: Writes a message to the proper output. The priority of the
|
||||
# message is assumed to be "I" (informational). This function
|
||||
# is provided for compatibility with the previous debug function.
|
||||
# For higher priority messages, use dbug.
|
||||
#
|
||||
# ARGS: msg - Message to be displayed.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
proc debug {{msg ""}} {
|
||||
set cls [string trimleft [uplevel namespace current] :]
|
||||
if {$cls == ""} {
|
||||
set cls "global"
|
||||
}
|
||||
|
||||
set i [expr {[info level] - 1}]
|
||||
if {$i > 0} {
|
||||
set func [lindex [info level $i] 0]
|
||||
set i [string first "::" $func]
|
||||
if {$i != -1} {
|
||||
# itcl proc has class prepended to func
|
||||
# strip it off because we already have class in $cls
|
||||
set func [string range $func [expr {$i+2}] end]
|
||||
}
|
||||
} else {
|
||||
set func ""
|
||||
}
|
||||
|
||||
::debug::_putdebug I $cls $func $msg
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# NAME: debug::dbug
|
||||
#
|
||||
# SYNOPSIS: dbug { level msg }
|
||||
#
|
||||
# DESC: Writes a message to the proper output. Unlike debug, this
|
||||
# function take a priority level.
|
||||
#
|
||||
# ARGS: msg - Message to be displayed.
|
||||
# level - One of the following:
|
||||
# "I" - Informational only
|
||||
# "W" - Warning
|
||||
# "E" - Error
|
||||
# "X" - Fatal Error
|
||||
# -----------------------------------------------------------------------------
|
||||
proc dbug {level msg} {
|
||||
set cls [string trimleft [uplevel namespace current] :]
|
||||
if {$cls == ""} {
|
||||
set cls "global"
|
||||
}
|
||||
|
||||
set i [expr {[info level] - 1}]
|
||||
if {$i > 0} {
|
||||
set func [lindex [info level $i] 0]
|
||||
} else {
|
||||
set func ""
|
||||
}
|
||||
|
||||
::debug::_putdebug $level $cls $func $msg
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# NAME: debug::_putdebug
|
||||
#
|
||||
# SYNOPSIS: _putdebug { level cls func msg }
|
||||
#
|
||||
# DESC: Writes a message to the proper output. Will write to a debug
|
||||
# window if one is defined. Otherwise will write to stdout.
|
||||
#
|
||||
# ARGS: msg - Message to be displayed.
|
||||
# cls - name of calling itcl class or "global"
|
||||
# func - name of calling function
|
||||
# level - One of the following:
|
||||
# "I" - Informational only
|
||||
# "W" - Warning
|
||||
# "E" - Error
|
||||
# "X" - Fatal Error
|
||||
# -----------------------------------------------------------------------------
|
||||
proc _putdebug {lev cls func msg} {
|
||||
variable debugwin
|
||||
variable logfile
|
||||
if {$debugwin != ""} {
|
||||
$debugwin puts $lev $cls $func $msg
|
||||
}
|
||||
if {$logfile == "stdout"} {
|
||||
if {$func != ""} { append cls ::$func }
|
||||
puts $logfile "$lev: ($cls) $msg"
|
||||
} elseif {$logfile != ""} {
|
||||
puts $logfile [concat [list $lev] [list $cls] [list $func] [list $msg]]
|
||||
}
|
||||
}
|
||||
|
||||
proc _puttrace {enter lev func {ar ""}} {
|
||||
variable debugwin
|
||||
variable logfile
|
||||
variable stoptrace
|
||||
variable tracing
|
||||
|
||||
if {!$tracing} { return }
|
||||
|
||||
set func [string trimleft $func :]
|
||||
if {$func == "DebugWin::put_trace" || $func == "DebugWin::_buildwin"} {
|
||||
if {$enter} {
|
||||
incr stoptrace
|
||||
} else {
|
||||
incr stoptrace -1
|
||||
}
|
||||
}
|
||||
|
||||
if {$stoptrace == 0} {
|
||||
incr stoptrace
|
||||
# strip off leading function name
|
||||
set ar [lrange $ar 1 end]
|
||||
if {$debugwin != ""} {
|
||||
$debugwin put_trace $enter $lev $func $ar
|
||||
}
|
||||
|
||||
if {$logfile != ""} {
|
||||
puts $logfile [concat {T} [list $enter] [list $lev] [list $func] \
|
||||
[list $ar]]
|
||||
}
|
||||
incr stoptrace -1
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# NAME: debug::init
|
||||
# SYNOPSIS: init
|
||||
# DESC: Installs hooks in all procs and methods to enable profiling
|
||||
# and tracing.
|
||||
# NOTES: Installing these hooks slows loading of the program. Running
|
||||
# with the hooks installed will cause significant slowdown of
|
||||
# program execution.
|
||||
# -----------------------------------------------------------------------------
|
||||
proc init {} {
|
||||
variable VERSION
|
||||
variable absolute
|
||||
variable initialized
|
||||
|
||||
# create the arrays for the .global. level
|
||||
createData .global.
|
||||
|
||||
# start the absolute timer
|
||||
set absolute [clock clicks]
|
||||
|
||||
# rename waits, exit, and all the ways of declaring functions
|
||||
rename ::vwait ::original_vwait
|
||||
interp alias {} ::vwait {} [namespace current]::sagevwait
|
||||
createData .wait.
|
||||
|
||||
rename ::tkwait ::original_tkwait
|
||||
interp alias {} ::tkwait {} [namespace current]::sagetkwait
|
||||
|
||||
rename ::exit ::original_exit
|
||||
interp alias {} ::exit {} [namespace current]::sageexit
|
||||
|
||||
rename ::proc ::original_proc
|
||||
interp alias {} ::proc {} [namespace current]::sageproc
|
||||
|
||||
rename ::itcl::parser::method ::original_method
|
||||
interp alias {} ::itcl::parser::method {} [namespace current]::sagemethod
|
||||
|
||||
rename ::itcl::parser::proc ::original_itclproc
|
||||
interp alias {} ::itcl::parser::proc {} [namespace current]::sageitclproc
|
||||
|
||||
rename ::body ::original_itclbody
|
||||
interp alias {} ::body {} [namespace current]::sageitclbody
|
||||
|
||||
# redefine core procs
|
||||
# foreach p [uplevel \#0 info procs] {
|
||||
# set args ""
|
||||
# set default ""
|
||||
# # get the list of args (some could be defaulted)
|
||||
# foreach arg [info args $p] {
|
||||
# if { [info default $p $arg default] } {
|
||||
# lappend args [list $arg $default]
|
||||
# } else {
|
||||
# lappend args $arg
|
||||
# }
|
||||
# }
|
||||
# uplevel \#0 proc [list $p] [list $args] [list [info body $p]]
|
||||
#}
|
||||
|
||||
set initialized 1
|
||||
resetWatch 0
|
||||
procEntry .global.
|
||||
startWatch
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# NAME: ::debug::trace_start
|
||||
# SYNOPSIS: ::debug::trace_start
|
||||
# DESC: Starts logging of function trace information.
|
||||
# -----------------------------------------------------------------------------
|
||||
proc trace_start {} {
|
||||
variable tracing
|
||||
set tracing 1
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# NAME: ::debug::trace_stop
|
||||
# SYNOPSIS: ::debug::trace_stop
|
||||
# DESC: Stops logging of function trace information.
|
||||
# -----------------------------------------------------------------------------
|
||||
proc trace_stop {} {
|
||||
variable tracing
|
||||
set tracing 0
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# NAME: debug::sagetkwait
|
||||
# SYNOPSIS: sagetkwait {args}
|
||||
# DESC: A wrapper function around tkwait so we know how much time the
|
||||
# program is spending in the wait state.
|
||||
# ARGS: args - args to pass to tkwait
|
||||
# ----------------------------------------------------------------------------
|
||||
proc sagetkwait {args} {
|
||||
# simulate going into the .wait. proc
|
||||
stopWatch
|
||||
procEntry .wait.
|
||||
startWatch
|
||||
uplevel ::original_tkwait $args
|
||||
# simulate the exiting of this proc
|
||||
stopWatch
|
||||
procExit .wait.
|
||||
startWatch
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# NAME: debug::sagevwait
|
||||
# SYNOPSIS: sagevwait {args}
|
||||
# DESC: A wrapper function around vwait so we know how much time the
|
||||
# program is spending in the wait state.
|
||||
# ARGS: args - args to pass to vwait
|
||||
# ----------------------------------------------------------------------------
|
||||
proc sagevwait {args} {
|
||||
# simulate going into the .wait. proc
|
||||
stopWatch
|
||||
procEntry .wait.
|
||||
startWatch
|
||||
uplevel ::original_vwait $args
|
||||
# simulate the exiting of this proc
|
||||
stopWatch
|
||||
procExit .wait.
|
||||
startWatch
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# NAME: debug::sageexit
|
||||
# SYNOPSIS: sageexit {{value 0}}
|
||||
# DESC: A wrapper function around exit so we can turn off profiling
|
||||
# and tracing before exiting.
|
||||
# ARGS: value - value to pass to exit
|
||||
# -----------------------------------------------------------------------------
|
||||
proc sageexit {{value 0}} {
|
||||
variable program_name GDBtk
|
||||
variable program_args ""
|
||||
variable absolute
|
||||
|
||||
# stop the stopwatch
|
||||
stopWatch
|
||||
|
||||
set totaltime [getWatch]
|
||||
|
||||
# stop the absolute timer
|
||||
set stop [clock clicks]
|
||||
|
||||
# unwind the stack and turn off everyone's timers
|
||||
stackUnwind
|
||||
|
||||
# disengage the proc callbacks
|
||||
::original_proc procEntry {name} {}
|
||||
::original_proc procExit {name args} {}
|
||||
::original_proc methodEntry {name} {}
|
||||
::original_proc methodExit {name args} {}
|
||||
|
||||
set absolute [expr {$stop - $absolute}]
|
||||
|
||||
# get the sage overhead time
|
||||
set sagetime [expr {$absolute - $totaltime}]
|
||||
|
||||
# save the data
|
||||
variable outfile
|
||||
variable VERSION
|
||||
set f [open $outfile w]
|
||||
puts $f "set VERSION {$VERSION}"
|
||||
puts $f "set program_name {$program_name}"
|
||||
puts $f "set program_args {$program_args}"
|
||||
puts $f "set absolute $absolute"
|
||||
puts $f "set sagetime $sagetime"
|
||||
puts $f "set totaltime $totaltime"
|
||||
|
||||
foreach procname $data::entries {
|
||||
set totaltimes($procname) [set data::${procname}::totaltimes]
|
||||
set proccounts($procname) [set data::${procname}::proccounts]
|
||||
set timers($procname) [set data::${procname}::timers]
|
||||
}
|
||||
|
||||
puts $f "array set totaltimes {[array get totaltimes]}"
|
||||
puts $f "array set proccounts {[array get proccounts]}"
|
||||
puts $f "array set timers {[array get timers]}"
|
||||
close $f
|
||||
original_exit $value
|
||||
}
|
||||
|
||||
|
||||
proc sageproc {name args body} {
|
||||
# stop the watch
|
||||
stopWatch
|
||||
|
||||
# update the name to include the namespace if it doesn't have one already
|
||||
if {[string range $name 0 1] != "::"} {
|
||||
# get the namespace this proc is being defined in
|
||||
set ns [uplevel namespace current]
|
||||
if { $ns == "::" } {
|
||||
set ns ""
|
||||
}
|
||||
set name ${ns}::$name
|
||||
}
|
||||
|
||||
createData $name
|
||||
# create the callbacks for proc entry and exit
|
||||
set ns [namespace current]
|
||||
set extra "${ns}::stopWatch;"
|
||||
append extra "set __.__ {};trace variable __.__ u {${ns}::stopWatch;${ns}::procExit $name;${ns}::startWatch};"
|
||||
append extra "[namespace current]::procEntry $name;"
|
||||
append extra "[namespace current]::startWatch;"
|
||||
|
||||
set args [list $args]
|
||||
set body [list [concat $extra $body]]
|
||||
|
||||
startWatch
|
||||
|
||||
# define the proc with our extra stuff snuck in
|
||||
uplevel ::original_proc $name $args $body
|
||||
}
|
||||
|
||||
proc sageitclbody {name args body} {
|
||||
# stop the watch
|
||||
stopWatch
|
||||
|
||||
if {$name == "iwidgets::Scrolledwidget::_scrollWidget"} {
|
||||
# Hack. This causes too many problems for the scrolled debug window
|
||||
# so just don't include it in the profile functions.
|
||||
uplevel ::original_itclbody $name [list $args] [list $body]
|
||||
return
|
||||
}
|
||||
|
||||
set fullname $name
|
||||
# update the name to include the namespace if it doesn't have one already
|
||||
if {[string range $name 0 1] != "::"} {
|
||||
# get the namespace this proc is being defined in
|
||||
set ns [uplevel namespace current]
|
||||
if { $ns == "::" } {
|
||||
set ns ""
|
||||
}
|
||||
set fullname ${ns}::$name
|
||||
}
|
||||
|
||||
createData $fullname
|
||||
# create the callbacks for proc entry and exit
|
||||
set ns [namespace current]
|
||||
set extra "${ns}::stopWatch;"
|
||||
append extra "set __.__ {};trace variable __.__ u {${ns}::stopWatch;${ns}::procExit $fullname;${ns}::startWatch};"
|
||||
append extra "[namespace current]::procEntry $fullname;"
|
||||
append extra "[namespace current]::startWatch;"
|
||||
|
||||
set args [list $args]
|
||||
set body [list [concat $extra $body]]
|
||||
|
||||
startWatch
|
||||
|
||||
# define the proc with our extra stuff snuck in
|
||||
uplevel ::original_itclbody $name $args $body
|
||||
}
|
||||
|
||||
proc sageitclproc {name args} {
|
||||
# stop the watch
|
||||
stopWatch
|
||||
|
||||
set body [lindex $args 1]
|
||||
set args [lindex $args 0]
|
||||
|
||||
if {$body == ""} {
|
||||
set args [list $args]
|
||||
set args [concat $args $body]
|
||||
} else {
|
||||
# create the callbacks for proc entry and exit
|
||||
set ns [namespace current]
|
||||
set extra "${ns}::stopWatch;"
|
||||
append extra "set __.__ {};trace variable __.__ u {${ns}::stopWatch;${ns}::methodExit $name;${ns}::startWatch};"
|
||||
append extra "[namespace current]::methodEntry $name;"
|
||||
append extra "[namespace current]::startWatch;"
|
||||
|
||||
set args [list $args [concat $extra $body]]
|
||||
}
|
||||
|
||||
startWatch
|
||||
uplevel ::original_itclproc $name $args
|
||||
}
|
||||
|
||||
proc sagemethod {name args} {
|
||||
# stop the watch
|
||||
stopWatch
|
||||
|
||||
set body [lindex $args 1]
|
||||
set args [lindex $args 0]
|
||||
|
||||
if {[string index $body 0] == "@" || $body == ""} {
|
||||
set args [list $args]
|
||||
set args [concat $args $body]
|
||||
} else {
|
||||
# create the callbacks for proc entry and exit
|
||||
set ns [namespace current]
|
||||
set extra "${ns}::stopWatch;"
|
||||
append extra "set __.__ {};trace variable __.__ u {${ns}::stopWatch;${ns}::methodExit $name;${ns}::startWatch};"
|
||||
append extra "[namespace current]::methodEntry $name;"
|
||||
append extra "[namespace current]::startWatch;"
|
||||
|
||||
set args [list $args [concat $extra $body]]
|
||||
}
|
||||
|
||||
startWatch
|
||||
uplevel ::original_method $name $args
|
||||
}
|
||||
|
||||
proc push {v} {
|
||||
variable stack
|
||||
variable level
|
||||
lappend stack $v
|
||||
incr level
|
||||
}
|
||||
|
||||
proc pop {} {
|
||||
variable stack
|
||||
variable level
|
||||
set v [lindex $stack end]
|
||||
set stack [lreplace $stack end end]
|
||||
incr level -1
|
||||
return $v
|
||||
}
|
||||
|
||||
proc look {} {
|
||||
variable stack
|
||||
return [lindex $stack end]
|
||||
}
|
||||
|
||||
proc stackUnwind {} {
|
||||
# Now unwind all the stacked procs by calling procExit on each.
|
||||
# It is OK to use procExit on methods because the full name
|
||||
# was pushed on the stack
|
||||
while { [set procname [look]] != "" } {
|
||||
procExit $procname
|
||||
}
|
||||
}
|
||||
|
||||
# we need args because this is part of a trace callback
|
||||
proc startWatch {args} {
|
||||
variable watchstart
|
||||
set watchstart [clock clicks]
|
||||
}
|
||||
|
||||
proc resetWatch {value} {
|
||||
variable watch
|
||||
set watch $value
|
||||
}
|
||||
|
||||
proc stopWatch {} {
|
||||
variable watch
|
||||
variable watchstart
|
||||
set watch [expr {$watch + ([clock clicks] - $watchstart)}]
|
||||
return $watch
|
||||
}
|
||||
|
||||
proc getWatch {} {
|
||||
variable watch
|
||||
return $watch
|
||||
}
|
||||
|
||||
proc startTimer {v} {
|
||||
if { $v != "" } {
|
||||
set data::${v}::timerstart [getWatch]
|
||||
}
|
||||
}
|
||||
|
||||
proc stopTimer {v} {
|
||||
if { $v == "" } return
|
||||
set stop [getWatch]
|
||||
set data::${v}::timers [expr {[set data::${v}::timers] + ($stop - [set data::${v}::timerstart])}]
|
||||
}
|
||||
|
||||
proc procEntry {procname} {
|
||||
variable level
|
||||
_puttrace 1 $level $procname [uplevel info level [uplevel info level]]
|
||||
|
||||
set time [getWatch]
|
||||
|
||||
# stop the timer of the caller
|
||||
set caller [look]
|
||||
stopTimer $caller
|
||||
|
||||
incr data::${procname}::proccounts
|
||||
|
||||
if { [set data::${procname}::nest] == 0 } {
|
||||
set data::${procname}::activetime $time
|
||||
}
|
||||
incr data::${procname}::nest
|
||||
|
||||
# push this proc on the stack
|
||||
push $procname
|
||||
|
||||
# start the timer for this
|
||||
startTimer $procname
|
||||
}
|
||||
|
||||
proc methodEntry {procname} {
|
||||
variable level
|
||||
|
||||
set time [getWatch]
|
||||
|
||||
# stop the timer of the caller
|
||||
set caller [look]
|
||||
stopTimer $caller
|
||||
|
||||
# get the namespace this method is in
|
||||
set ns [uplevel namespace current]
|
||||
if { $ns == "::" } {
|
||||
set ns ""
|
||||
}
|
||||
set name ${ns}::$procname
|
||||
_puttrace 1 $level $name [uplevel info level [uplevel info level]]
|
||||
|
||||
if {![info exists data::${name}::proccounts]} {
|
||||
createData $name
|
||||
}
|
||||
|
||||
incr data::${name}::proccounts
|
||||
|
||||
if { [set data::${name}::nest] == 0 } {
|
||||
set data::${name}::activetime $time
|
||||
}
|
||||
incr data::${name}::nest
|
||||
|
||||
# push this proc on the stack
|
||||
push $name
|
||||
|
||||
# start the timer for this
|
||||
startTimer $name
|
||||
}
|
||||
|
||||
# we need the args because this is called from a vartrace handler
|
||||
proc procExit {procname args} {
|
||||
variable level
|
||||
|
||||
set time [getWatch]
|
||||
# stop the timer of the proc
|
||||
stopTimer [pop]
|
||||
|
||||
_puttrace 0 $level $procname
|
||||
|
||||
set r [incr data::${procname}::nest -1]
|
||||
if { $r == 0 } {
|
||||
set data::${procname}::totaltimes \
|
||||
[expr {[set data::${procname}::totaltimes] \
|
||||
+ ($time - [set data::${procname}::activetime])}]
|
||||
}
|
||||
|
||||
# now restart the timer of the caller
|
||||
startTimer [look]
|
||||
}
|
||||
|
||||
proc methodExit {procname args} {
|
||||
variable level
|
||||
|
||||
set time [getWatch]
|
||||
# stop the timer of the proc
|
||||
stopTimer [pop]
|
||||
|
||||
# get the namespace this method is in
|
||||
set ns [uplevel namespace current]
|
||||
if { $ns == "::" } {
|
||||
set ns ""
|
||||
}
|
||||
set procname ${ns}::$procname
|
||||
|
||||
_puttrace 0 $level $procname
|
||||
|
||||
set r [incr data::${procname}::nest -1]
|
||||
if { $r == 0 } {
|
||||
set data::${procname}::totaltimes \
|
||||
[expr {[set data::${procname}::totaltimes] \
|
||||
+ ($time - [set data::${procname}::activetime])}]
|
||||
}
|
||||
|
||||
# now restart the timer of the caller
|
||||
startTimer [look]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
# def.tcl - Definining commands.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# Define a global array.
|
||||
proc defarray {name {value {}}} {
|
||||
upvar \#0 $name ary
|
||||
|
||||
if {! [info exists ary]} then {
|
||||
set ary(_) {}
|
||||
unset ary(_)
|
||||
array set ary $value
|
||||
}
|
||||
}
|
||||
|
||||
# Define a global variable.
|
||||
proc defvar {name {value {}}} {
|
||||
upvar \#0 $name var
|
||||
if {! [info exists var]} then {
|
||||
set var $value
|
||||
}
|
||||
}
|
||||
|
||||
# Define a "constant". For now this is just a pretty way to declare a
|
||||
# global variable.
|
||||
proc defconst {name value} {
|
||||
upvar \#0 $name var
|
||||
set var $value
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
# font.tcl - Font handling.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
|
||||
# This function is called whenever a font preference changes. We use
|
||||
# this information to update the appropriate symbolic font.
|
||||
proc FONT_track_change {symbolic prefname value} {
|
||||
eval font configure [list $symbolic] $value
|
||||
}
|
||||
|
||||
# Primary interface to font handling.
|
||||
# define_font SYMBOLIC_NAME ARGS
|
||||
# Define a new font, named SYMBOLIC_NAME. ARGS is the default font
|
||||
# specification; it is a list of options such as those passed to `font
|
||||
# create'.
|
||||
proc define_font {symbolic args} {
|
||||
# We do a little trick with the names here, by inserting `font' in
|
||||
# the appropriate place in the name.
|
||||
set split [split $symbolic /]
|
||||
set name [join [linsert $split 1 font] /]
|
||||
|
||||
pref define $name $args
|
||||
eval font create [list $symbolic] [pref get $name]
|
||||
pref add_hook $name [list FONT_track_change $symbolic]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
# gensym.tcl - Generate new symbols.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# Internal counter used to provide new symbol names.
|
||||
defvar GENSYM_counter 0
|
||||
|
||||
# Return a new "symbol". This proc hopes that nobody else decides to
|
||||
# use its prefix.
|
||||
proc gensym {} {
|
||||
global GENSYM_counter
|
||||
return __gensym_symbol_[incr GENSYM_counter]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
# gettext.tcl - some stubs
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
proc gettext {str} {
|
||||
return $str
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
# hooks.tcl - Hook functions.
|
||||
# Copyright (C) 1997, 1999 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
proc add_hook {hook command} {
|
||||
upvar \#0 $hook var
|
||||
lappend var $command
|
||||
}
|
||||
|
||||
proc remove_hook {hook command} {
|
||||
upvar \#0 $hook var
|
||||
set var [lremove $var $command]
|
||||
}
|
||||
|
||||
proc define_hook {hook} {
|
||||
upvar \#0 $hook var
|
||||
|
||||
if {! [info exists var]} then {
|
||||
set var {}
|
||||
}
|
||||
}
|
||||
|
||||
proc run_hooks {hook args} {
|
||||
upvar \#0 $hook var
|
||||
set mssg_list {}
|
||||
foreach thunk $var {
|
||||
if {[catch {uplevel \#0 $thunk $args} mssg]} {
|
||||
set errStr "hook=$thunk args=\"$args\" $mssg\n"
|
||||
lappend mssg_list $errStr
|
||||
}
|
||||
}
|
||||
if {$mssg_list != ""} {
|
||||
error $mssg_list
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
#
|
||||
# internet.tcl - tcl interface to various internet functions
|
||||
#
|
||||
# Copyright (C) 1998 Cygnus Solutions
|
||||
#
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# send_mail - send email
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
proc send_mail {to subject body} {
|
||||
global tcl_platform
|
||||
|
||||
switch -- $tcl_platform(platform) {
|
||||
windows {
|
||||
ide_mapi simple-send $to $subject $body
|
||||
}
|
||||
unix {
|
||||
exec echo $body | mail -s $subject $to &
|
||||
}
|
||||
default {
|
||||
error "platform \"$tcl_platform(platform)\" not supported"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# open_url - open a URL in a browser
|
||||
# Netscape must be available for Unix.
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
proc open_url {url} {
|
||||
global tcl_platform
|
||||
switch -- $tcl_platform(platform) {
|
||||
windows {
|
||||
ide_shell_execute open $url
|
||||
# FIXME. can we detect errors?
|
||||
}
|
||||
unix {
|
||||
if {[catch "exec netscape -remote [list openURL($url,new-window)]" result]} {
|
||||
if {[string match {*not running on display*} $result]} {
|
||||
# Netscape is not running. Try to start it.
|
||||
if {[catch "exec netscape [list $url] &" result]} {
|
||||
tk_dialog .warn "Netscape Error" "$result" error 0 Ok
|
||||
return 0
|
||||
}
|
||||
} elseif {[string match {couldn't execute *} $result]} {
|
||||
tk_dialog .warn "Netscape Error" "Cannot locate \"netscape\" on your system.\nIt must be installed and in your path." error 0 Ok
|
||||
return 0
|
||||
} else {
|
||||
tk_dialog .warn "Netscape Error" "$result" error 0 Ok
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
default {
|
||||
error "platform \"$tcl_platform(platform)\" not supported"
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# lframe.tcl - Labelled frame widget.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
itcl_class Labelledframe {
|
||||
inherit Widgetframe
|
||||
|
||||
# The label text.
|
||||
public text {} {
|
||||
if {[winfo exists [namespace tail $this].label]} then {
|
||||
[namespace tail $this].label configure -text $text
|
||||
}
|
||||
}
|
||||
|
||||
constructor {config} {
|
||||
label [namespace tail $this].label -text $text -padx 2
|
||||
_add [namespace tail $this].label
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
# list.tcl - Some handy list procs.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
# FIXME: some are from TclX; we should probably just use the C
|
||||
# implementation that is in S-N.
|
||||
|
||||
proc lvarpush {listVar element {index 0}} {
|
||||
upvar $listVar var
|
||||
if {![info exists var]} then {
|
||||
lappend var $element
|
||||
} else {
|
||||
set var [linsert $var $index $element]
|
||||
}
|
||||
}
|
||||
|
||||
proc lvarpop {listVar {index 0}} {
|
||||
upvar $listVar var
|
||||
set result [lindex $var $index]
|
||||
# NOTE lreplace can fail if list is empty.
|
||||
if {! [catch {lreplace $var $index $index} new]} then {
|
||||
set var $new
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
proc lassign {list args} {
|
||||
set len [expr {[llength $args] - 1}]
|
||||
|
||||
# Special-case last element: if LIST is longer than ARGS, assign a
|
||||
# list of leftovers to the last variable.
|
||||
if {[llength $list] - 1 > $len} then {
|
||||
upvar [lindex $args $len] local
|
||||
set local [lrange $list $len end]
|
||||
incr len -1
|
||||
}
|
||||
|
||||
while {$len >= 0} {
|
||||
upvar [lindex $args $len] local
|
||||
set local [lindex $list $len]
|
||||
incr len -1
|
||||
}
|
||||
}
|
||||
|
||||
# Remove duplicates and sort list. ARGS are arguments to lsort, eg
|
||||
# --increasing.
|
||||
proc lrmdups {list args} {
|
||||
set slist [eval lsort $args [list $list]]
|
||||
set last [lvarpop slist]
|
||||
set result [list $last]
|
||||
foreach item $slist {
|
||||
if {$item != $last} then {
|
||||
set last $item
|
||||
lappend result $item
|
||||
}
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
proc lremove {list element} {
|
||||
set index [lsearch -exact $list $element]
|
||||
if {$index == -1} then {
|
||||
return $list
|
||||
}
|
||||
return [lreplace $list $index $index]
|
||||
}
|
||||
|
||||
# replace element with new element
|
||||
proc lrep {list element new} {
|
||||
set index [lsearch -exact $list $element]
|
||||
if {$index == -1} {
|
||||
return $list
|
||||
}
|
||||
return [lreplace $list $index $index $new]
|
||||
}
|
||||
|
||||
# FIXME: this isn't precisely like the C lvarcat. It is slower.
|
||||
proc lvarcat {listVar args} {
|
||||
upvar $listVar var
|
||||
if {[join $args] != ""} then {
|
||||
# Yuck!
|
||||
eval eval lappend var $args
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
# looknfeel.tcl - Standard look and feel decisions.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# Run this once just after Tk is initialized. It will do whatever
|
||||
# setup is required to make the application conform to our look and
|
||||
# feel.
|
||||
proc standard_look_and_feel {} {
|
||||
global tcl_platform
|
||||
|
||||
# FIXME: this is really gross: we know how tk_dialog chooses its
|
||||
# -wraplength, and we make it bigger. Instead we should make our
|
||||
# own dialog function.
|
||||
option add *Dialog.msg.wrapLength 0 startupFile
|
||||
|
||||
# We don't ever want tearoffs.
|
||||
option add *Menu.tearOff 0 startupFile
|
||||
|
||||
# The default font should be used by default.
|
||||
# The bold font is like the default font, but is bold; use it for
|
||||
# emphasis.
|
||||
# The fixed font is guaranteed not to be proportional.
|
||||
# The status font should be used in status bars and tooltips.
|
||||
if {$tcl_platform(platform) == "windows"} then {
|
||||
define_font global/default -family windows-message
|
||||
# FIXME: this isn't actually a bold font...
|
||||
define_font global/bold -family windows-caption
|
||||
define_font global/fixed -family fixedsys
|
||||
define_font global/status -family windows-status
|
||||
# FIXME: we'd like this font to update automatically as well. But
|
||||
# for now we can't.
|
||||
array set actual [font actual windows-message]
|
||||
set actual(-slant) italic
|
||||
eval define_font global/italic [array get actual]
|
||||
|
||||
# The menu font used to be set via the "windows-menu"
|
||||
# font family, however this seems to have been deprecated
|
||||
# for Tcl/Tk version 8.3, so we hard code it instead.
|
||||
define_font global/menu -family {MS Sans Serif} -size 8
|
||||
} else {
|
||||
set size 12
|
||||
define_font global/default -family courier -size $size
|
||||
define_font global/bold -family courier -size $size -weight bold
|
||||
define_font global/fixed -family courier -size $size
|
||||
define_font global/status -family helvetica -size [expr $size - 1]
|
||||
define_font global/italic -family courier -size $size -slant italic
|
||||
define_font global/menu -family helvetica -size $size
|
||||
}
|
||||
|
||||
# Make sure this font is actually used by default.
|
||||
option add *Font global/default
|
||||
option add *Menu.Font global/menu
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
# menu.tcl - Useful proc for dealing with menus.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# This proc computes the "desired width" of a menu. It can be used to
|
||||
# determine the minimum width for a toplevel whose -menu option is
|
||||
# set.
|
||||
proc compute_menu_width {menu} {
|
||||
set width 0
|
||||
set last [$menu index end]
|
||||
if {$last != "end"} then {
|
||||
# Start at borderwidth, but also preserve borderwidth on the
|
||||
# right.
|
||||
incr width [expr {2 * [$menu cget -borderwidth]}]
|
||||
|
||||
set deffont [$menu cget -font]
|
||||
set abw [expr {2 * [$menu cget -activeborderwidth]}]
|
||||
for {set i 0} {$i <= $last} {incr i} {
|
||||
if {[catch {$menu entrycget $i -font} font]} then {
|
||||
continue
|
||||
}
|
||||
if {$font == ""} then {
|
||||
set font $deffont
|
||||
}
|
||||
incr width [font measure $font [$menu entrycget $i -label]]
|
||||
incr width $abw
|
||||
# "10" was chosen by reading tkUnixMenu.c.
|
||||
incr width 10
|
||||
# This is arbitrary. Apparently I can't read tkUnixMenu.c well
|
||||
# enough to understand why the naive calculation above doesn't
|
||||
# work.
|
||||
incr width 2
|
||||
}
|
||||
# Another hack.
|
||||
incr width 2
|
||||
}
|
||||
|
||||
return $width
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
# mono.tcl - Dealing with monochrome.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# It is safe to run this any number of times, so it is ok to have it
|
||||
# here. Defined as true if the user wants monochrome display.
|
||||
pref define global/monochrome 0
|
||||
|
||||
# Return 1 if monochrome, 0 otherwise. This should be used to make
|
||||
# the application experience more friendly for colorblind users as
|
||||
# well as those stuck on mono displays.
|
||||
proc monochrome_p {} {
|
||||
return [expr {[pref get global/monochrome] || [winfo depth .] == 1}]
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
# multibox.tcl - Multi-column listbox.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# FIXME:
|
||||
# * Should support sashes so user can repartition widget sizes.
|
||||
# * Should support itemcget, itemconfigure.
|
||||
|
||||
itcl_class Multibox {
|
||||
# The selection mode.
|
||||
public selectmode browse {
|
||||
_apply_all configure [list -selectmode $selectmode]
|
||||
}
|
||||
|
||||
# The height.
|
||||
public height 10 {
|
||||
_apply_all configure [list -height $height]
|
||||
}
|
||||
|
||||
# This is a list of all the listbox widgets we've created. Private
|
||||
# variable.
|
||||
protected _listboxen {}
|
||||
|
||||
# Tricky: take the class bindings for the Listbox widget and turn
|
||||
# them into Multibox bindings that directly run our bindings. That
|
||||
# way any binding on any of our children will automatically work the
|
||||
# right way.
|
||||
# FIXME: this loses if any Listbox bindings are added later.
|
||||
# To really fix we need Uhler's change to support megawidgets.
|
||||
foreach seq [bind Listbox] {
|
||||
regsub -all -- %W [bind Listbox $seq] {[winfo parent %W]} sub
|
||||
bind Multibox $seq $sub
|
||||
}
|
||||
|
||||
constructor {config} {
|
||||
# The standard widget-making trick.
|
||||
set class [$this info class]
|
||||
set hull [namespace tail $this]
|
||||
set old_name $this
|
||||
::rename $this $this-tmp-
|
||||
::frame $hull -class $class -relief flat -borderwidth 0
|
||||
::rename $hull $old_name-win-
|
||||
::rename $this $old_name
|
||||
|
||||
scrollbar [namespace tail $this].vs -orient vertical
|
||||
bind [namespace tail $this].vs <Destroy> [list $this delete]
|
||||
|
||||
grid rowconfigure [namespace tail $this] 0 -weight 0
|
||||
grid rowconfigure [namespace tail $this] 1 -weight 1
|
||||
}
|
||||
|
||||
destructor {
|
||||
destroy $this
|
||||
}
|
||||
|
||||
#
|
||||
# Our interface.
|
||||
#
|
||||
|
||||
# Add a new column.
|
||||
method add {args} {
|
||||
# The first array set sets up the default values, and the second
|
||||
# overwrites with what the user wants.
|
||||
array set opts {-width 20 -fix 0 -title Zardoz}
|
||||
array set opts $args
|
||||
|
||||
set num [llength $_listboxen]
|
||||
listbox [namespace tail $this].box$num -exportselection 0 -height $height \
|
||||
-selectmode $selectmode -width $opts(-width)
|
||||
if {$num == 0} then {
|
||||
[namespace tail $this].box$num configure -yscrollcommand [list [namespace tail $this].vs set]
|
||||
[namespace tail $this].vs configure -command [list $this yview]
|
||||
}
|
||||
label [namespace tail $this].label$num -text $opts(-title) -anchor w
|
||||
|
||||
# No more class bindings.
|
||||
set tag_list [bindtags [namespace tail $this].box$num]
|
||||
set index [lsearch -exact $tag_list Listbox]
|
||||
bindtags [namespace tail $this].box$num [lreplace $tag_list $index $index Multibox]
|
||||
|
||||
grid [namespace tail $this].label$num -row 0 -column $num -sticky new
|
||||
grid [namespace tail $this].box$num -row 1 -column $num -sticky news
|
||||
if {$opts(-fix)} then {
|
||||
grid columnconfigure [namespace tail $this] $num -weight 0 \
|
||||
-minsize [winfo reqwidth [namespace tail $this].box$num]
|
||||
} else {
|
||||
grid columnconfigure [namespace tail $this] $num -weight 1
|
||||
}
|
||||
|
||||
lappend _listboxen [namespace tail $this].box$num
|
||||
|
||||
# Move the scrollbar over.
|
||||
incr num
|
||||
grid [namespace tail $this].vs -row 1 -column $num -sticky nsw
|
||||
grid columnconfigure [namespace tail $this] $num -weight 0
|
||||
}
|
||||
|
||||
method configure {config} {}
|
||||
|
||||
# FIXME: should handle automatically.
|
||||
method cget {option} {
|
||||
switch -- $option {
|
||||
-selectmode {
|
||||
return $selectmode
|
||||
}
|
||||
-height {
|
||||
return $height
|
||||
}
|
||||
|
||||
default {
|
||||
error "option $option not supported"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# FIXME: this isn't ideal. But we want to support adding bindings
|
||||
# at least. A "bind" method might be better.
|
||||
method get_boxes {} {
|
||||
return $_listboxen
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Methods that duplicate Listbox interface.
|
||||
#
|
||||
|
||||
method activate index {
|
||||
_apply_all activate [list $index]
|
||||
}
|
||||
|
||||
method bbox index {
|
||||
error "bbox method not supported"
|
||||
}
|
||||
|
||||
method curselection {} {
|
||||
return [_apply_first curselection {}]
|
||||
}
|
||||
|
||||
# FIXME: In itcl 1.5, can't have a method name "delete". Sigh.
|
||||
method delete_hack {args} {
|
||||
_apply_all delete $args
|
||||
}
|
||||
|
||||
# Return some contents. We return each item as a list of the
|
||||
# columns.
|
||||
method get {first {last {}}} {
|
||||
if {$last == ""} then {
|
||||
set r {}
|
||||
foreach l $_listboxen {
|
||||
lappend r [$l get $first]
|
||||
}
|
||||
return $r
|
||||
} else {
|
||||
# We do things this way so that we don't have to specially
|
||||
# handle the index "end".
|
||||
foreach box $_listboxen {
|
||||
set seen(var-$box) [$box get $first $last]
|
||||
}
|
||||
|
||||
# Tricky: we use the array indices as variable names and the
|
||||
# array values as values. This lets us "easily" construct the
|
||||
# result lists.
|
||||
set r {}
|
||||
eval foreach [array get seen] {{
|
||||
set elt {}
|
||||
foreach box $_listboxen {
|
||||
lappend elt [set var-$box]
|
||||
}
|
||||
lappend r $elt
|
||||
}}
|
||||
return $r
|
||||
}
|
||||
}
|
||||
|
||||
method index index {
|
||||
return [_apply_first index [list $index]]
|
||||
}
|
||||
|
||||
# Insert some items. Each new item is a list of items for all
|
||||
# columns.
|
||||
method insert {index args} {
|
||||
if {[llength $args]} then {
|
||||
set seen(_) {}
|
||||
unset seen(_)
|
||||
|
||||
foreach value $args {
|
||||
foreach columnvalue $value lname $_listboxen {
|
||||
lappend seen($lname) $columnvalue
|
||||
}
|
||||
}
|
||||
|
||||
foreach box $_listboxen {
|
||||
eval $box insert $index $seen($box)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
method nearest y {
|
||||
return [_apply_first nearest [list $y]]
|
||||
}
|
||||
|
||||
method scan {option args} {
|
||||
_apply_all scan $option $args
|
||||
}
|
||||
|
||||
method see index {
|
||||
_apply_all see [list $index]
|
||||
}
|
||||
|
||||
method selection {option args} {
|
||||
if {$option == "includes"} then {
|
||||
return [_apply_first selection [concat $option $args]]
|
||||
} else {
|
||||
return [_apply_all selection [concat $option $args]]
|
||||
}
|
||||
}
|
||||
|
||||
method size {} {
|
||||
return [_apply_first size {}]
|
||||
}
|
||||
|
||||
method xview args {
|
||||
error "xview method not supported"
|
||||
}
|
||||
|
||||
method yview args {
|
||||
if {! [llength $args]} then {
|
||||
return [_apply_first yview {}]
|
||||
} else {
|
||||
return [_apply_all yview $args]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Private methods.
|
||||
#
|
||||
|
||||
# This applies METHOD to every listbox.
|
||||
method _apply_all {method argList} {
|
||||
foreach l $_listboxen {
|
||||
eval $l $method $argList
|
||||
}
|
||||
}
|
||||
|
||||
# This applies METHOD to the first listbox, and returns the result.
|
||||
method _apply_first {method argList} {
|
||||
set l [lindex $_listboxen 0]
|
||||
return [eval $l $method $argList]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
#
|
||||
# Cygnus enhanced version of the iwidget Pane class
|
||||
# ----------------------------------------------------------------------
|
||||
# Implements a pane for a paned window widget. The pane is itself a
|
||||
# frame with a child site for other widgets. The pane class performs
|
||||
# basic option management.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
# AUTHOR: Mark L. Ulferts EMAIL: mulferts@austin.dsccc.com
|
||||
#
|
||||
# @(#) $Id: pane.tcl,v 1.2 1999/01/28 01:18:26 jingham Exp $
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1995 DSC Technologies Corporation
|
||||
# ======================================================================
|
||||
# Permission to use, copy, modify, distribute and license this software
|
||||
# and its documentation for any purpose, and without fee or written
|
||||
# agreement with DSC, is hereby granted, provided that the above copyright
|
||||
# notice appears in all copies and that both the copyright notice and
|
||||
# warranty disclaimer below appear in supporting documentation, and that
|
||||
# the names of DSC Technologies Corporation or DSC Communications
|
||||
# Corporation not be used in advertising or publicity pertaining to the
|
||||
# software without specific, written prior permission.
|
||||
#
|
||||
# DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
||||
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 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. IN NO EVENT SHALL
|
||||
# DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
||||
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
|
||||
# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
# SOFTWARE.
|
||||
# ======================================================================
|
||||
|
||||
#
|
||||
# Usual options.
|
||||
#
|
||||
itk::usual Pane {
|
||||
keep -background -cursor
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PANE
|
||||
# ------------------------------------------------------------------
|
||||
itcl::class cyg::Pane {
|
||||
inherit itk::Widget
|
||||
|
||||
constructor {args} {}
|
||||
|
||||
itk_option define -maximum maximum Maximum 0
|
||||
itk_option define -minimum minimum Minimum 10
|
||||
itk_option define -margin margin Margin 0
|
||||
itk_option define -resizable resizable Resizable 1
|
||||
|
||||
public method childSite {} {}
|
||||
}
|
||||
|
||||
#
|
||||
# Provide a lowercased access method for the Pane class.
|
||||
#
|
||||
proc ::cyg::pane {pathName args} {
|
||||
uplevel ::cyg::Pane $pathName $args
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# CONSTRUCTOR
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::Pane::constructor {args} {
|
||||
#
|
||||
# Create the pane childsite.
|
||||
#
|
||||
itk_component add childsite {
|
||||
frame $itk_interior.childsite
|
||||
} {
|
||||
keep -background -cursor
|
||||
}
|
||||
pack $itk_component(childsite) -fill both -expand yes
|
||||
|
||||
#
|
||||
# Set the itk_interior variable to be the childsite for derived
|
||||
# classes.
|
||||
#
|
||||
set itk_interior $itk_component(childsite)
|
||||
|
||||
eval itk_initialize $args
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# OPTIONS
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# OPTION: -minimum
|
||||
#
|
||||
# Specifies the minimum size that the pane may reach.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::configbody cyg::Pane::minimum {
|
||||
set pixels [winfo pixels $itk_component(hull) $itk_option(-minimum)]
|
||||
set $itk_option(-minimum) $pixels
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# OPTION: -maximum
|
||||
#
|
||||
# Specifies the maximum size that the pane may reach.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::configbody cyg::Pane::maximum {
|
||||
set pixels [winfo pixels $itk_component(hull) $itk_option(-maximum)]
|
||||
set $itk_option(-maximum) $pixels
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# OPTION: -margin
|
||||
#
|
||||
# Specifies the border distance between the pane and pane contents.
|
||||
# This is done by setting the borderwidth of the pane to the margin.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::configbody cyg::Pane::margin {
|
||||
set pixels [winfo pixels $itk_component(hull) $itk_option(-margin)]
|
||||
set itk_option(-margin) $pixels
|
||||
$itk_component(childsite) configure -borderwidth $itk_option(-margin)
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHODS
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHOD: childSite
|
||||
#
|
||||
# Return the pane child site path name.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::Pane::childSite {} {
|
||||
return $itk_component(childsite)
|
||||
}
|
|
@ -0,0 +1,875 @@
|
|||
#
|
||||
# Panedwindow
|
||||
# ----------------------------------------------------------------------
|
||||
# Implements a very general panedwindow which allows for mixing resizable
|
||||
# and non-resizable panes. It also allows limits to be set on individual
|
||||
# pane sizes, both minimum and maximum.
|
||||
#
|
||||
# The look of this widget is much like Window, instead of the Motif-like
|
||||
# iwidget panedwindow.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# Portions of this code are originally from the iwidget panedwindow which
|
||||
# is Copyright (c) 1995 DSC Technologies Corporation
|
||||
|
||||
itk::usual PanedWindow {
|
||||
keep -background -cursor
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PANEDWINDOW
|
||||
# ------------------------------------------------------------------
|
||||
itcl::class cyg::PanedWindow {
|
||||
inherit itk::Widget
|
||||
|
||||
constructor {args} {}
|
||||
|
||||
itk_option define -orient orient Orient horizontal
|
||||
itk_option define -sashwidth sashWidth SashWidth 10
|
||||
itk_option define -sashcolor sashColor SashColor gray
|
||||
|
||||
public {
|
||||
method index {index}
|
||||
method childsite {args}
|
||||
method add {tag args}
|
||||
method insert {index tag args}
|
||||
method delete {index}
|
||||
method hide {index}
|
||||
method replace {pane1 pane2}
|
||||
method show {index}
|
||||
method paneconfigure {index args}
|
||||
method reset {}
|
||||
}
|
||||
|
||||
private {
|
||||
method _eventHandler {width height}
|
||||
method _startDrag {num}
|
||||
method _endDrag {where num}
|
||||
method _configDrag {where num}
|
||||
method _handleDrag {where num}
|
||||
method _moveSash {where num {dir ""}}
|
||||
|
||||
method _resizeArray {}
|
||||
method _setActivePanes {}
|
||||
method _calcPos {where num {dir ""}}
|
||||
method _makeSashes {}
|
||||
method _placeSash {i}
|
||||
method _placePanes {{start 0} {end end} {forget 0}}
|
||||
|
||||
variable _initialized 0 ;# flag set when widget is first configured
|
||||
variable _sashes {} ;# List of sashes.
|
||||
|
||||
# Pane information
|
||||
variable _panes {} ;# List of panes.
|
||||
variable _activePanes {} ;# List of active panes.
|
||||
variable _where ;# Array of relative positions
|
||||
variable _ploc ;# Array of pixel positions
|
||||
variable _frac ;# Array of relative pane sizes
|
||||
variable _pixels ;# Array of sizes in pixels for non-resizable panes
|
||||
variable _max ;# Array of pane maximum locations
|
||||
variable _min ;# Array of pane minimum locations
|
||||
variable _pmin ;# Array of pane minimum size
|
||||
variable _pmax ;# Array of pane maximum size
|
||||
|
||||
variable _dimension 0 ;# width or height of window
|
||||
variable _dir "height" ;# resizable direction, "height" or "width"
|
||||
variable _rPixels
|
||||
|
||||
variable _sashloc ;# Array of dist of sash from above/left.
|
||||
|
||||
variable _minsashmoved ;# Lowest sash moved during dragging.
|
||||
variable _maxsashmoved ;# Highest sash moved during dragging.
|
||||
|
||||
variable _width 0 ;# hull's width.
|
||||
variable _height 0 ;# hull's height.
|
||||
variable _unique -1 ;# Unique number for pane names.
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Provide a lowercased access method for the PanedWindow class.
|
||||
#
|
||||
proc ::cyg::panedwindow {pathName args} {
|
||||
uplevel ::cyg::PanedWindow $pathName $args
|
||||
}
|
||||
|
||||
#
|
||||
# Use option database to override default resources of base classes.
|
||||
#
|
||||
option add *PanedWindow.width 10 widgetDefault
|
||||
option add *PanedWindow.height 10 widgetDefault
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# CONSTRUCTOR
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::constructor {args} {
|
||||
itk_option add hull.width hull.height
|
||||
|
||||
pack propagate $itk_component(hull) no
|
||||
|
||||
bind pw-config-$this <Configure> [code $this _eventHandler %w %h]
|
||||
bindtags $itk_component(hull) \
|
||||
[linsert [bindtags $itk_component(hull)] 0 pw-config-$this]
|
||||
|
||||
eval itk_initialize $args
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# OPTIONS
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# OPTION: -orient
|
||||
#
|
||||
# Specifies the orientation of the sashes. Once the paned window
|
||||
# has been mapped, set the sash bindings and place the panes.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::configbody cyg::PanedWindow::orient {
|
||||
#puts "orient $_initialized"
|
||||
if {$_initialized} {
|
||||
set orient $itk_option(-orient)
|
||||
if {$orient != "vertical" && $orient != "horizontal"} {
|
||||
error "bad orientation option \"$itk_option(-orient)\":\
|
||||
should be horizontal or vertical"
|
||||
}
|
||||
if {[string compare $orient "vertical"]} {
|
||||
set _dimension $_height
|
||||
set _dir "height"
|
||||
} else {
|
||||
set _dimension $_width
|
||||
set _dir "width"
|
||||
}
|
||||
_resizeArray
|
||||
_makeSashes
|
||||
_placePanes 0 end 1
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# OPTION: -sashwidth
|
||||
#
|
||||
# Specifies the width of the sash.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::configbody cyg::PanedWindow::sashwidth {
|
||||
set pixels [winfo pixels $itk_component(hull) $itk_option(-sashwidth)]
|
||||
set itk_option(-sashwidth) $pixels
|
||||
|
||||
if {$_initialized} {
|
||||
# FIXME
|
||||
for {set i 1} {$i < [llength $_panes]} {incr i} {
|
||||
$itk_component(sash$i) configure \
|
||||
-width $itk_option(-sashwidth) -height $itk_option(-sashwidth) \
|
||||
-borderwidth 2
|
||||
}
|
||||
for {set i 1} {$i < [llength $_panes]} {incr i} {
|
||||
_placeSash $i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# OPTION: -sashcolor
|
||||
#
|
||||
# Specifies the color of the sash.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::configbody cyg::PanedWindow::sashcolor {
|
||||
if {$_initialized} {
|
||||
for {set i 1} {$i < [llength $_panes]} {incr i} {
|
||||
$itk_component(sash$i) configure -background $itk_option(-sashcolor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHODS
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHOD: index index
|
||||
#
|
||||
# Searches the panes in the paned window for the one with the
|
||||
# requested tag, numerical index, or keyword "end". Returns the pane's
|
||||
# numerical index if found, otherwise error.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::index {index} {
|
||||
if {[llength $_panes] > 0} {
|
||||
if {[regexp {(^[0-9]+$)} $index]} {
|
||||
if {$index < [llength $_panes]} {
|
||||
return $index
|
||||
} else {
|
||||
error "PanedWindow index \"$index\" is out of range"
|
||||
}
|
||||
} elseif {$index == "end"} {
|
||||
return [expr [llength $_panes] - 1]
|
||||
} else {
|
||||
if {[set idx [lsearch $_panes $index]] != -1} {
|
||||
return $idx
|
||||
}
|
||||
error "bad PanedWindow index \"$index\": must be number, end,\
|
||||
or pattern"
|
||||
}
|
||||
} else {
|
||||
error "PanedWindow \"$itk_component(hull)\" has no panes"
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHOD: childsite ?index?
|
||||
#
|
||||
# Given an index return the specifc childsite path name. Invoked
|
||||
# without an index return a list of all the child site panes. The
|
||||
# list is ordered from the near side (left/top).
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::childsite {args} {
|
||||
#puts "childsite $args ($_initialized)"
|
||||
|
||||
if {[llength $args] == 0} {
|
||||
set children {}
|
||||
foreach pane $_panes {
|
||||
lappend children [$itk_component($pane) childSite]
|
||||
}
|
||||
return $children
|
||||
} else {
|
||||
set index [index [lindex $args 0]]
|
||||
return [$itk_component([lindex $_panes $index]) childSite]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHOD: add tag ?option value option value ...?
|
||||
#
|
||||
# Add a new pane to the paned window to the far (right/bottom) side.
|
||||
# The method takes additional options which are passed on to the
|
||||
# pane constructor. These include -margin, and -minimum. The path
|
||||
# of the pane is returned.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::add {tag args} {
|
||||
itk_component add $tag {
|
||||
eval cyg::Pane $itk_interior.pane[incr _unique] $args
|
||||
} {
|
||||
keep -background -cursor
|
||||
}
|
||||
|
||||
lappend _panes $tag
|
||||
lappend _activePanes $tag
|
||||
reset
|
||||
return $itk_component($tag)
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHOD: insert index tag ?option value option value ...?
|
||||
#
|
||||
# Insert the specified pane in the paned window just before the one
|
||||
# given by index. Any additional options which are passed on to the
|
||||
# pane constructor. These include -margin, -minimum. The path of
|
||||
# the pane is returned.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::insert {index tag args} {
|
||||
itk_component add $tag {
|
||||
eval cyg::Pane $itk_interior.pane[incr _unique] $args
|
||||
} {
|
||||
keep -background -cursor
|
||||
}
|
||||
|
||||
set index [index $index]
|
||||
set _panes [linsert $_panes $index $tag]
|
||||
lappend _activePanes $tag
|
||||
reset
|
||||
return $itk_component($tag)
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHOD: delete index
|
||||
#
|
||||
# Delete the specified pane.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::delete {index} {
|
||||
set index [index $index]
|
||||
set tag [lindex $_panes $index]
|
||||
|
||||
# remove the itk component
|
||||
destroy $itk_component($tag)
|
||||
# remove it from panes list
|
||||
set _panes [lreplace $_panes $index $index]
|
||||
|
||||
# remove its _frac value
|
||||
set ind [lsearch -exact $_activePanes $tag]
|
||||
if {$ind != -1 && [info exists _frac($ind)]} {
|
||||
unset _frac($ind)
|
||||
}
|
||||
|
||||
# this will reset _activePane and resize things
|
||||
reset
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHOD: hide index
|
||||
#
|
||||
# Remove the specified pane from the paned window.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::hide {index} {
|
||||
set index [index $index]
|
||||
set tag [lindex $_panes $index]
|
||||
|
||||
if {[set idx [lsearch -exact $_activePanes $tag]] != -1} {
|
||||
set _activePanes [lreplace $_activePanes $idx $idx]
|
||||
if {[info exists _frac($idx)]} {unset _frac($idx)}
|
||||
}
|
||||
|
||||
reset
|
||||
}
|
||||
|
||||
itcl::body cyg::PanedWindow::replace {pane1 pane2} {
|
||||
set ind1 [lsearch -exact $_activePanes $pane1]
|
||||
if {$ind1 == -1} {
|
||||
error "$pane1 is not an active pane name."
|
||||
}
|
||||
set ind2 [lsearch -exact $_panes $pane2]
|
||||
if {$ind2 == -1} {
|
||||
error "Pane $pane2 does not exist."
|
||||
}
|
||||
set _activePanes [lreplace $_activePanes $ind1 $ind1 $pane2]
|
||||
_placePanes 0 $ind1 1
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHOD: show index
|
||||
#
|
||||
# Display the specified pane in the paned window.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::show {index} {
|
||||
set index [index $index]
|
||||
set tag [lindex $_panes $index]
|
||||
|
||||
if {[lsearch -exact $_activePanes $tag] == -1} {
|
||||
lappend _activePanes $tag
|
||||
}
|
||||
|
||||
reset
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHOD: paneconfigure index ?option? ?value option value ...?
|
||||
#
|
||||
# Configure a specified pane. This method allows configuration of
|
||||
# panes from the PanedWindow level. The options may have any of the
|
||||
# values accepted by the add method.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::paneconfigure {index args} {
|
||||
set index [index $index]
|
||||
set tag [lindex $_panes $index]
|
||||
return [uplevel $itk_component($tag) configure $args]
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# METHOD: reset
|
||||
#
|
||||
# Redisplay the panes based on the default percentages of the panes.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::reset {} {
|
||||
if {$_initialized && [llength $_panes]} {
|
||||
#puts RESET
|
||||
_setActivePanes
|
||||
_resizeArray
|
||||
_makeSashes
|
||||
_placePanes 0 end 1
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PRIVATE METHOD: _setActivePanes
|
||||
#
|
||||
# Resets the active pane list.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_setActivePanes {} {
|
||||
set _prevActivePanes $_activePanes
|
||||
set _activePanes {}
|
||||
|
||||
foreach pane $_panes {
|
||||
if {[lsearch -exact $_prevActivePanes $pane] != -1} {
|
||||
lappend _activePanes $pane
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PROTECTED METHOD: _eventHandler
|
||||
#
|
||||
# Performs operations necessary following a configure event. This
|
||||
# includes placing the panes.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_eventHandler {width height} {
|
||||
#puts "Event $width $height"
|
||||
set _width $width
|
||||
set _height $height
|
||||
if {[string compare $itk_option(-orient) "vertical"]} {
|
||||
set _dimension $_height
|
||||
set _dir "height"
|
||||
} else {
|
||||
set _dimension $_width
|
||||
set _dir "width"
|
||||
}
|
||||
|
||||
if {$_initialized} {
|
||||
_resizeArray
|
||||
_placePanes
|
||||
} else {
|
||||
set _initialized 1
|
||||
reset
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PRIVATE METHOD: _resizeArray
|
||||
#
|
||||
# Recalculates the sizes and positions of all the panes.
|
||||
# This is only done at startup, when the window size changes, when
|
||||
# a new pane is added, or the orientation is changed.
|
||||
#
|
||||
# _frac($i) contains:
|
||||
# % of resizable space when pane$i is resizable
|
||||
# _pixels($i) contains
|
||||
# pixels when pane$i is not resizable
|
||||
#
|
||||
# _where($i) contains the relative position of the top of pane$i
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_resizeArray {} {
|
||||
set numpanes 0
|
||||
set _rPixels 0
|
||||
set totalFrac 0.0
|
||||
set numfreepanes 0
|
||||
|
||||
#puts "sresizeArray dim=$_dimension dir=$_dir"
|
||||
|
||||
# first pass. Count the number of resizable panes and
|
||||
# the pixels reserved for non-resizable panes.
|
||||
set i 0
|
||||
foreach p $_activePanes {
|
||||
set _resizable($i) [$itk_component($p) cget -resizable]
|
||||
if {$_resizable($i)} {
|
||||
# remember pane min and max
|
||||
set _pmin($i) [$itk_component($p) cget -minimum]
|
||||
set _pmax($i) [$itk_component($p) cget -maximum]
|
||||
|
||||
incr numpanes
|
||||
if {[info exists _frac($i)]} {
|
||||
# sum up all the percents
|
||||
set totalFrac [expr $totalFrac + $_frac($i)]
|
||||
} else {
|
||||
# number of new windows not yet sized
|
||||
incr numfreepanes
|
||||
}
|
||||
} else {
|
||||
set _pixels($i) [winfo req$_dir $itk_component($p)]
|
||||
set _pmin($i) $_pixels($i)
|
||||
set _pmax($i) $_pixels($i)
|
||||
incr _rPixels $_pixels($i)
|
||||
}
|
||||
incr i
|
||||
}
|
||||
set totalpanes $i
|
||||
|
||||
#puts "numpanes=$numpanes nfp=$numfreepanes _rPixels=$_rPixels totalFrac=$totalFrac"
|
||||
|
||||
if {$numfreepanes} {
|
||||
# set size for the new window(s) to average size
|
||||
if {$totalFrac > 0.0} {
|
||||
set freepanesize [expr $totalFrac / ($numpanes - $numfreepanes)]
|
||||
} else {
|
||||
set freepanesize [expr 1.0 / $numpanes.0]
|
||||
}
|
||||
for {set i 0} {$i < $totalpanes} {incr i} {
|
||||
if {$_resizable($i) && ![info exists _frac($i)]} {
|
||||
set _frac($i) $freepanesize
|
||||
set totalFrac [expr $totalFrac + $_frac($i)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set done 0
|
||||
|
||||
while {!$done} {
|
||||
# force to a reasonable value
|
||||
if {$totalFrac <= 0.0} { set totalFrac 1.0 }
|
||||
|
||||
# scale the _frac array
|
||||
if {$totalFrac > 1.01 || $totalFrac < 0.99} {
|
||||
set cor [expr 1.0 / $totalFrac]
|
||||
set totalFrac 0.0
|
||||
for {set i 0} {$i < $totalpanes} {incr i} {
|
||||
if {$_resizable($i)} {
|
||||
set _frac($i) [expr $_frac($i) * $cor]
|
||||
set totalFrac [expr $totalFrac + $_frac($i)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# bounds checking; look for panes that are too small or too large
|
||||
# if one is found, fix its size at the min or max and mark the
|
||||
# window non-resizable. Adjust percents and try again.
|
||||
set done 1
|
||||
for {set i 0} {$i < $totalpanes} {incr i} {
|
||||
if {$_resizable($i)} {
|
||||
set _pixels($i) [expr int($_frac($i) * ($_dimension - $_rPixels.0))]
|
||||
if {$_pixels($i) < $_pmin($i)} {
|
||||
set _resizable($i) 0
|
||||
set totalFrac [expr $totalFrac - $_frac($i)]
|
||||
set _pixels($i) $_pmin($i)
|
||||
incr _rPixels $_pixels($i)
|
||||
set done 0
|
||||
break
|
||||
} elseif {$_pmax($i) && $_pixels($i) > $_pmax($i)} {
|
||||
set _resizable($i) 0
|
||||
set totalFrac [expr $totalFrac - $_frac($i)]
|
||||
set _pixels($i) $_pmax($i)
|
||||
incr _rPixels $_pixels($i)
|
||||
set done 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Done adjusting. Now build pane position arrays. These are designed
|
||||
# to minimize calculations while resizing.
|
||||
# Note: position of sash $i = position of top of pane $i
|
||||
# _where($i): relative (0.0 - 1.0) position of sash $i
|
||||
# _ploc($i): position in pixels of sash $i
|
||||
# _max($i): maximum position in pixels of sash $i (0 = no max)
|
||||
set _where(0) 0.0
|
||||
set _ploc(0) 0
|
||||
set _max(0) 0
|
||||
set _min(0) 0
|
||||
|
||||
# calculate the percentage of resizable space
|
||||
set resizePerc [expr 1.0 - ($_rPixels.0 / $_dimension)]
|
||||
|
||||
# now set the pane positions
|
||||
for {set i 1; set n 0} {$i < $totalpanes} {incr i; incr n} {
|
||||
if {$_resizable($n)} {
|
||||
set _where($i) [expr $_where($n) + ($_frac($n) * $resizePerc)]
|
||||
} else {
|
||||
set _where($i) [expr $_where($n) + [expr $_pixels($n).0 / $_dimension]]
|
||||
}
|
||||
set _ploc($i) [expr $_ploc($n) + $_pixels($n)]
|
||||
set _max($i) [expr $_max($n) + $_pmax($n)]
|
||||
if {($_max($n) == 0 || $_pmax($n) == 0) && $n != 0} {
|
||||
set _max($i) 0
|
||||
}
|
||||
set _min($i) [expr $_min($n) + $_pmin($n)]
|
||||
#puts "where($i)=$_where($i)"
|
||||
#puts "ploc($i)=$_ploc($i)"
|
||||
#puts "min($i)=$_min($i)"
|
||||
#puts "pmin($i)=$_pmin($i)"
|
||||
#puts "pmax($i)=$_pmax($i)"
|
||||
#puts "pixels($i)=$_pixels($i)"
|
||||
}
|
||||
set _ploc($i) $_dimension
|
||||
set _where($i) 1.0
|
||||
|
||||
# finally, starting at the bottom,
|
||||
# check the _max and _min arrays
|
||||
set _max($totalpanes) $_dimension
|
||||
set _min($totalpanes) $_dimension
|
||||
#puts "_max($totalpanes) = $_max($totalpanes)"
|
||||
for {set i [expr $totalpanes - 1]} {$i > 0} {incr i -1} {
|
||||
set n [expr $i + 1]
|
||||
set m [expr $_max($n) - $_pmin($i)]
|
||||
if {$_max($i) > $m || !$_max($i)} { set _max($i) $m }
|
||||
if {$_pmax($i)} {
|
||||
set m [expr $_min($n) - $_pmax($i)]
|
||||
if {$_min($i) < $m} {set _min($i) $m }
|
||||
}
|
||||
#puts "$i $_max($i) $_min($i)"
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PROTECTED METHOD: _startDrag num
|
||||
#
|
||||
# Starts the sash drag and drop operation. At the start of the drag
|
||||
# operation all the information is known as for the upper and lower
|
||||
# limits for sash movement. The calculation is made at this time and
|
||||
# stored in protected variables for later access during the drag
|
||||
# handling routines.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_startDrag {num} {
|
||||
#puts "startDrag $num"
|
||||
|
||||
set _minsashmoved $num
|
||||
set _maxsashmoved $num
|
||||
|
||||
grab $itk_component(sash$num)
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PROTECTED METHOD: _endDrag where num
|
||||
#
|
||||
# Ends the sash drag and drop operation.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_endDrag {where num} {
|
||||
#puts "endDrag $where $num"
|
||||
|
||||
grab release $itk_component(sash$num)
|
||||
|
||||
# set new _frac values
|
||||
for {set i [expr $_minsashmoved-1]} {$i <= $_maxsashmoved} {incr i} {
|
||||
set _frac($i) \
|
||||
[expr ($_ploc([expr $i+1]).0 - $_ploc($i)) / ($_dimension - $_rPixels)]
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PROTECTED METHOD: _configDrag where num
|
||||
#
|
||||
# Configure action for sash.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_configDrag {where num} {
|
||||
set _sashloc($num) $where
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PROTECTED METHOD: _handleDrag where num
|
||||
#
|
||||
# Motion action for sash.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_handleDrag {where num} {
|
||||
#puts "handleDrag $where $num"
|
||||
_moveSash [expr $where + $_sashloc($num)] $num
|
||||
_placePanes [expr $_minsashmoved - 1] $_maxsashmoved
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PROTECTED METHOD: _moveSash where num
|
||||
#
|
||||
# Move the sash to the absolute pixel location
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_moveSash {where num {dir ""}} {
|
||||
#puts "moveSash $where $num"
|
||||
set _minsashmoved [expr ($_minsashmoved<$num)?$_minsashmoved:$num]
|
||||
set _maxsashmoved [expr ($_maxsashmoved>$num)?$_maxsashmoved:$num]
|
||||
_calcPos $where $num $dir
|
||||
}
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PRIVATE METHOD: _calcPos where num
|
||||
#
|
||||
# Determines the new position for the sash. Make sure the position does
|
||||
# not go past the minimum for the pane on each side of the sash.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_calcPos {where num {direction ""}} {
|
||||
set dir [expr $where - $_ploc($num)]
|
||||
#puts "calcPos $where $num $dir $direction"
|
||||
if {$dir == 0} { return }
|
||||
|
||||
# simplify expressions by computing these now
|
||||
set m [expr $num-1]
|
||||
set p [expr $num+1]
|
||||
|
||||
# we have squeezed the pane below us to the limit
|
||||
set lower1 [expr $_ploc($m) + $_pmin($m)]
|
||||
set lower2 0
|
||||
if {$_pmax($num)} {
|
||||
# we have stretched the pane above us to the limit
|
||||
set lower2 [expr $_ploc($p) - $_pmax($num)]
|
||||
}
|
||||
|
||||
set upper1 9999 ;# just a large number
|
||||
if {$_pmax($m)} {
|
||||
# we have stretched the pane above us to the limit
|
||||
set upper1 [expr $_ploc($m) + $_pmax($m)]
|
||||
}
|
||||
|
||||
# we have squeezed the pane below us to the limit
|
||||
set upper2 [expr $_ploc($p) - $_pmin($num)]
|
||||
|
||||
set done 0
|
||||
|
||||
#puts "lower1=$lower1 lower2=$lower2 _min($num)=$_min($num)"
|
||||
#puts "upper1=$upper1 upper2=$upper2 _max($num)=$_max($num)"
|
||||
if {$dir < 0 && $where > $_min($num)} {
|
||||
if {$where < $lower2 && $direction != "down"} {
|
||||
set done 1
|
||||
if {$p == [llength $_activePanes]} {
|
||||
set _ploc($num) $upper2
|
||||
} else {
|
||||
_moveSash [expr $where + $_pmax($num)] $p up
|
||||
set _ploc($num) [expr $_ploc($p) - $_pmax($num)]
|
||||
}
|
||||
}
|
||||
if {$where < $lower1 && $direction != "up"} {
|
||||
set done 1
|
||||
if {$num == 1} {
|
||||
set _ploc($num) $lower1
|
||||
} else {
|
||||
_moveSash [expr $where - $_pmin($m)] $m down
|
||||
set _ploc($num) [expr $_ploc($m) + $_pmin($m)]
|
||||
}
|
||||
}
|
||||
} elseif {$dir > 0 && ($_max($num) == 0 || $where < $_max($num))} {
|
||||
if {$where > $upper1 && $direction != "up"} {
|
||||
set done 1
|
||||
if {$num == 1} {
|
||||
set _ploc($num) $upper1
|
||||
} else {
|
||||
_moveSash [expr $where - $_pmax($m)] $m down
|
||||
set _ploc($num) [expr $_ploc($m) + $_pmax($m)]
|
||||
}
|
||||
}
|
||||
if {$where > $upper2 && $direction != "down"} {
|
||||
set done 1
|
||||
if {$p == [llength $_activePanes]} {
|
||||
set _ploc($num) $upper2
|
||||
} else {
|
||||
_moveSash [expr $where + $_pmin($num)] $p up
|
||||
set _ploc($num) [expr $_ploc($p) - $_pmin($num)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {!$done} {
|
||||
if {!($_max($num) > 0 && $where > $_max($num)) && $where >= $_min($num)} {
|
||||
set _ploc($num) $where
|
||||
}
|
||||
}
|
||||
set _where($num) [expr $_ploc($num).0 / $_dimension]
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PRIVATE METHOD: _makeSashes
|
||||
#
|
||||
# Removes any previous sashes and creates new ones.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_makeSashes {} {
|
||||
#
|
||||
# Remove any existing sashes.
|
||||
#
|
||||
foreach sash $_sashes {
|
||||
destroy $itk_component($sash)
|
||||
}
|
||||
|
||||
set _sashes {}
|
||||
set skipped_first 0
|
||||
#
|
||||
# Create necessary number of sashes
|
||||
#
|
||||
for {set id 0} {$id < [llength $_activePanes]} {incr id} {
|
||||
set p [lindex $_activePanes $id]
|
||||
if {[$itk_component($p) cget -resizable]} {
|
||||
if {$skipped_first == 0} {
|
||||
# create the first sash when we see the 2nd resizable pane
|
||||
incr skipped_first
|
||||
} else {
|
||||
# create sash
|
||||
|
||||
itk_component add sash$id {
|
||||
frame $itk_interior.sash$id -relief raised \
|
||||
-height $itk_option(-sashwidth) \
|
||||
-width $itk_option(-sashwidth) \
|
||||
-borderwidth 2
|
||||
} {
|
||||
keep -background
|
||||
}
|
||||
lappend _sashes sash$id
|
||||
|
||||
set com $itk_component(sash$id)
|
||||
$com configure -background $itk_option(-sashcolor)
|
||||
bind $com <Button-1> [code $this _startDrag $id]
|
||||
|
||||
switch $itk_option(-orient) {
|
||||
vertical {
|
||||
bind $com <B1-Motion> \
|
||||
[code $this _handleDrag %x $id]
|
||||
bind $com <B1-ButtonRelease-1> \
|
||||
[code $this _endDrag %x $id]
|
||||
bind $com <Configure> \
|
||||
[code $this _configDrag %x $id]
|
||||
# FIXME Windows should have a different cirsor
|
||||
$com configure -cursor sb_h_double_arrow
|
||||
}
|
||||
|
||||
horizontal {
|
||||
bind $com <B1-Motion> \
|
||||
[code $this _handleDrag %y $id]
|
||||
bind $com <B1-ButtonRelease-1> \
|
||||
[code $this _endDrag %y $id]
|
||||
bind $com <Configure> \
|
||||
[code $this _configDrag %y $id]
|
||||
# FIXME Windows should have a different cirsor
|
||||
$com configure -cursor sb_v_double_arrow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PRIVATE METHOD: _placeSash i
|
||||
#
|
||||
# Places the position of the sash
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_placeSash {i} {
|
||||
if {[string compare $itk_option(-orient) "vertical"]} {
|
||||
place $itk_component(sash$i) -in $itk_component(hull) \
|
||||
-x 0 -relwidth 1 -rely $_where($i) -anchor w \
|
||||
-height $itk_option(-sashwidth)
|
||||
} else {
|
||||
place $itk_component(sash$i) -in $itk_component(hull) \
|
||||
-y 0 -relheight 1 -relx $_where($i) -anchor n \
|
||||
-width $itk_option(-sashwidth)
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PRIVATE METHOD: _placePanes
|
||||
#
|
||||
# Resets the panes of the window following movement of the sash.
|
||||
# ------------------------------------------------------------------
|
||||
itcl::body cyg::PanedWindow::_placePanes {{start 0} {end end} {forget 0}} {
|
||||
#puts "placeplanes $start $end"
|
||||
|
||||
if {!$_initialized} {
|
||||
return
|
||||
}
|
||||
|
||||
if {$end=="end"} { set end [expr [llength $_activePanes] - 1] }
|
||||
set _updatePanes [lrange $_activePanes $start $end]
|
||||
|
||||
if {$forget} {
|
||||
if {$_updatePanes == $_activePanes} {
|
||||
set _forgetPanes $_panes
|
||||
} else {
|
||||
set _forgetPanes $_updatePanes
|
||||
}
|
||||
foreach pane $_forgetPanes {
|
||||
place forget $itk_component($pane)
|
||||
}
|
||||
}
|
||||
|
||||
if {[string compare $itk_option(-orient) "vertical"]} {
|
||||
set i $start
|
||||
foreach pane $_updatePanes {
|
||||
place $itk_component($pane) -in $itk_component(hull) \
|
||||
-x 0 -rely $_where($i) -relwidth 1 \
|
||||
-relheight [expr $_where([expr $i + 1]) - $_where($i)]
|
||||
incr i
|
||||
}
|
||||
} else {
|
||||
set i $start
|
||||
foreach pane $_updatePanes {
|
||||
place $itk_component($pane) -in $itk_component(hull) \
|
||||
-y 0 -relx $_where($i) -relheight 1 \
|
||||
-relwidth [expr $_where([expr $i + 1]) - $_where($i)]
|
||||
incr i
|
||||
}
|
||||
}
|
||||
|
||||
for {set i [expr $start+1]} {$i <= $end} {incr i} {
|
||||
if {[lsearch -exact $_sashes sash$i] != -1} {
|
||||
_placeSash $i
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
# parse_args.tcl -- procedure for pulling in arguments
|
||||
|
||||
# parse_args takes in a set of arguments with defaults and examines
|
||||
# the 'args' in the calling procedure to see what the arguments should
|
||||
# be set to. Sets variables in the calling frame to the right values.
|
||||
|
||||
proc parse_args { argset } {
|
||||
upvar args args
|
||||
|
||||
foreach argument $argset {
|
||||
if {[llength $argument] == 1} {
|
||||
# No default specified, so we assume that we should set
|
||||
# the value to 1 if the arg is present and 0 if it's not.
|
||||
# It is assumed that no value is given with the argument.
|
||||
set result [lsearch -exact $args "-$argument"]
|
||||
if {$result != -1} then {
|
||||
uplevel 1 [list set $argument 1]
|
||||
set args [lreplace $args $result $result]
|
||||
} else {
|
||||
uplevel 1 [list set $argument 0]
|
||||
}
|
||||
} elseif {[llength $argument] == 2} {
|
||||
# There are two items in the argument. The second is a
|
||||
# default value to use if the item is not present.
|
||||
# Otherwise, the variable is set to whatever is provided
|
||||
# after the item in the args.
|
||||
set arg [lindex $argument 0]
|
||||
set result [lsearch -exact $args "-[lindex $arg 0]"]
|
||||
if {$result != -1} then {
|
||||
uplevel 1 [list set $arg [lindex $args [expr $result+1]]]
|
||||
set args [lreplace $args $result [expr $result+1]]
|
||||
} else {
|
||||
uplevel 1 [list set $arg [lindex $argument 1]]
|
||||
}
|
||||
} else {
|
||||
error "Badly formatted argument \"$argument\" in argument set"
|
||||
}
|
||||
}
|
||||
|
||||
# The remaining args should be checked to see that they match the
|
||||
# number of items expected to be passed into the procedure...
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
# path.tcl - Path-handling helpers.
|
||||
# Copyright (C) 1998 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# This proc takes a possibly relative path and expands it to the
|
||||
# corresponding fully qualified path. Additionally, on Windows the
|
||||
# result is guaranteed to be in "long" form.
|
||||
proc canonical_path {path} {
|
||||
global tcl_platform
|
||||
|
||||
set r [file join [pwd] $path]
|
||||
if {$tcl_platform(platform) == "windows"} then {
|
||||
# This will fail if the file does not already exist.
|
||||
if {! [catch {file attributes $r -longname} long]} then {
|
||||
set r $long
|
||||
}
|
||||
}
|
||||
|
||||
return $r
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
# Tcl package index file, version 1.1
|
||||
# This file is generated by the "pkg_mkIndex" command
|
||||
# and sourced either when an application starts up or
|
||||
# by a "package unknown" script. It invokes the
|
||||
# "package ifneeded" command to set up package-related
|
||||
# information so that packages will be loaded automatically
|
||||
# in response to "package require" commands. When this
|
||||
# script is sourced, the variable $dir must contain the
|
||||
# full path name of this file's directory.
|
||||
|
||||
package ifneeded combobox 2.2.1 [list source [file join $dir combobox.tcl]]
|
||||
package ifneeded debug 1.0 [list source [file join $dir debug.tcl]]
|
|
@ -0,0 +1,38 @@
|
|||
# postghost.tcl - Ghost a menu item at post time.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
|
||||
# Helper proc.
|
||||
proc GHOST_helper {menu index predicate} {
|
||||
if {[eval $predicate]} then {
|
||||
set state normal
|
||||
} else {
|
||||
set state disabled
|
||||
}
|
||||
$menu entryconfigure $index -state $state
|
||||
}
|
||||
|
||||
# Add a -postcommand to a menu. This is careful not to stomp other
|
||||
# postcommands.
|
||||
proc add_post_command {menu callback} {
|
||||
set old [$menu cget -postcommand]
|
||||
# We use a "\n" and not a ";" to separate so that people can put
|
||||
# comments into their -postcommands without fear.
|
||||
$menu configure -postcommand "$old\n$callback"
|
||||
}
|
||||
|
||||
# Run this to make a menu item which ghosts or unghosts depending on a
|
||||
# predicate that is run at menu-post time. The NO_CACHE option
|
||||
# prevents the index from being looked up statically; this is useful
|
||||
# if you want to use an entry name as the index and you have a very
|
||||
# dynamic menu (ie one where the numeric index of a named item is not
|
||||
# constant over time). If PREDICATE returns 0 at post time, then the
|
||||
# item will be ghosted.
|
||||
proc ghosting_menu_item {menu index predicate {no_cache 0}} {
|
||||
if {! $no_cache} then {
|
||||
set index [$menu index $index]
|
||||
}
|
||||
|
||||
add_post_command $menu [list GHOST_helper $menu $index $predicate]
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
# prefs.tcl - Preference handling.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# KNOWN BUGS:
|
||||
# * When we move to the next tcl/itcl, rewrite to use namespaces and
|
||||
# possibly ensembles.
|
||||
|
||||
# Global state.
|
||||
defarray PREFS_state {
|
||||
inhibit-event 0
|
||||
initialized 0
|
||||
}
|
||||
|
||||
# This is called when a trace on some option fires. It makes sure the
|
||||
# relevant handlers get run.
|
||||
proc PREFS_run_handlers {name1 name2 op} {
|
||||
upvar $name1 state
|
||||
set option [lindex $name2 0]
|
||||
|
||||
global PREFS_state
|
||||
# Notify everybody else unless we've inhibited event generation.
|
||||
if {! $PREFS_state(inhibit-event) && $PREFS_state(ide_running)} then {
|
||||
ide_property set preference/$option $state([list $option value]) global
|
||||
}
|
||||
|
||||
# Run local handlers.
|
||||
run_hooks PREFS_state([list $option handler]) $option \
|
||||
$state([list $option value])
|
||||
}
|
||||
|
||||
# This is run when we see a property event. It updates our internal
|
||||
# state.
|
||||
proc PREFS_handle_property_event {exists property value} {
|
||||
global PREFS_state
|
||||
|
||||
# If it isn't a preference property, ignore it.
|
||||
if {! [string match preference/* $property]} then {
|
||||
return
|
||||
}
|
||||
# [string length preference/] == 11.
|
||||
set name [string range $property 11 end]
|
||||
|
||||
if {$exists} then {
|
||||
incr PREFS_state(inhibit-event)
|
||||
set PREFS_state([list $name value]) $value
|
||||
incr PREFS_state(inhibit-event) -1
|
||||
} elseif {$PREFS_state(ide_running)} then {
|
||||
# It doesn't make sense to remove a property that mirrors some
|
||||
# preference. So disallow by immediately redefining. Use
|
||||
# initialize and not set because several clients are likely to run
|
||||
# this at once.
|
||||
ide_property initialize preference/$name \
|
||||
$PREFS_state([list $name value]) global
|
||||
}
|
||||
}
|
||||
|
||||
# pref define NAME DEFAULT
|
||||
# Define a new option
|
||||
# NAME is the option name
|
||||
# DEFAULT is the default value of the option
|
||||
proc PREFS_cmd_define {name default} {
|
||||
global PREFS_state
|
||||
|
||||
# If the option has already been defined, do nothing.
|
||||
if {[info exists PREFS_state([list $name value])]} then {
|
||||
return
|
||||
}
|
||||
|
||||
if {$PREFS_state(ide_running)} then {
|
||||
# We only store the value in the database.
|
||||
ide_property initialize preference/$name $default global
|
||||
set default [ide_property get preference/$name]
|
||||
}
|
||||
|
||||
# We set our internal state no matter what. It is harmless if our
|
||||
# definition causes a property-set event.
|
||||
set PREFS_state([list $name value]) $default
|
||||
set PREFS_state([list $name handler]) {}
|
||||
|
||||
# Set up a variable trace so that the handlers can be run.
|
||||
trace variable PREFS_state([list $name value]) w PREFS_run_handlers
|
||||
}
|
||||
|
||||
# pref get NAME
|
||||
# Return value of option NAME
|
||||
proc PREFS_cmd_get {name} {
|
||||
global PREFS_state
|
||||
return $PREFS_state([list $name value])
|
||||
}
|
||||
|
||||
# pref getd NAME
|
||||
# Return value of option NAME
|
||||
# or define it if necessary and return ""
|
||||
proc PREFS_cmd_getd {name} {
|
||||
global PREFS_state
|
||||
PREFS_cmd_define $name ""
|
||||
return [pref get $name]
|
||||
}
|
||||
|
||||
# pref varname NAME
|
||||
# Return name of global variable that represents option NAME
|
||||
# This is suitable for (eg) a -variable option on a radiobutton
|
||||
proc PREFS_cmd_varname {name} {
|
||||
return PREFS_state([list $name value])
|
||||
}
|
||||
|
||||
# pref set NAME VALUE
|
||||
# Set the option NAME to VALUE
|
||||
proc PREFS_cmd_set {name value} {
|
||||
global PREFS_state
|
||||
|
||||
# For debugging purposes, make sure the preference has already been
|
||||
# defined.
|
||||
if {! [info exists PREFS_state([list $name value])]} then {
|
||||
error "attempt to set undefined preference $name"
|
||||
}
|
||||
|
||||
set PREFS_state([list $name value]) $value
|
||||
}
|
||||
|
||||
# pref setd NAME VALUE
|
||||
# Set the option NAME to VALUE
|
||||
# or define NAME and set the default to VALUE
|
||||
proc PREFS_cmd_setd {name value} {
|
||||
global PREFS_state
|
||||
|
||||
if {[info exists PREFS_state([list $name value])]} then {
|
||||
set PREFS_state([list $name value]) $value
|
||||
} else {
|
||||
PREFS_cmd_define $name $value
|
||||
}
|
||||
}
|
||||
|
||||
# pref add_hook NAME HOOK
|
||||
# Add a command to the hook that is run when the preference name NAME
|
||||
# changes. The command is run with the name of the changed option and
|
||||
# the new value as arguments.
|
||||
proc PREFS_cmd_add_hook {name hook} {
|
||||
add_hook PREFS_state([list $name handler]) $hook
|
||||
}
|
||||
|
||||
# pref remove_hook NAME HOOK
|
||||
# Remove a command from the per-preference hook.
|
||||
proc PREFS_cmd_remove_hook {name hook} {
|
||||
remove_hook PREFS_state([list $name handler]) $hook
|
||||
}
|
||||
|
||||
# pref init ?IDE_RUNNING?
|
||||
# Initialize the preference module. IDE_RUNNING is an optional
|
||||
# boolean argument. If 0, then the preference module will assume that
|
||||
# it is not connected to the IDE backplane. The default is based on
|
||||
# the global variable IDE_ENABLED.
|
||||
proc PREFS_cmd_init {{ide_running "unset"}} {
|
||||
global PREFS_state IDE_ENABLED
|
||||
|
||||
if {! $PREFS_state(initialized)} then {
|
||||
|
||||
if {$ide_running == "unset"} then {
|
||||
if {[info exists IDE_ENABLED]} then {
|
||||
set ide_running $IDE_ENABLED
|
||||
} else {
|
||||
set ide_running 0
|
||||
}
|
||||
}
|
||||
|
||||
set PREFS_state(initialized) 1
|
||||
set PREFS_state(ide_running) $ide_running
|
||||
if {$ide_running} then {
|
||||
property add_hook "" PREFS_handle_property_event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# pref list
|
||||
# Return a list of the names of all preferences defined by this
|
||||
# application.
|
||||
proc PREFS_cmd_list {} {
|
||||
global PREFS_state
|
||||
|
||||
set list {}
|
||||
foreach item [array names PREFS_state] {
|
||||
if {[lindex $item 1] == "value"} then {
|
||||
lappend list [lindex $item 0]
|
||||
}
|
||||
}
|
||||
|
||||
return $list
|
||||
}
|
||||
|
||||
# The primary interface to all preference subcommands.
|
||||
proc pref {dispatch args} {
|
||||
if {[info commands PREFS_cmd_$dispatch] == ""} then {
|
||||
error "unrecognized key \"$dispatch\""
|
||||
}
|
||||
|
||||
eval PREFS_cmd_$dispatch $args
|
||||
}
|
|
@ -0,0 +1,334 @@
|
|||
# print.tcl -- some procedures for dealing with printing. To print
|
||||
# PostScript on Windows, tkmswin.dll will need to be present.
|
||||
|
||||
proc send_printer { args } {
|
||||
global tcl_platform
|
||||
|
||||
parse_args {
|
||||
{printer {}}
|
||||
{outfile {}}
|
||||
{parent {}}
|
||||
ascii
|
||||
file
|
||||
}
|
||||
|
||||
if {[llength $args] == 0} {
|
||||
error "No filename or data provided."
|
||||
}
|
||||
|
||||
if {$ascii == 1} {
|
||||
if {$tcl_platform(platform) == "windows"} then {
|
||||
PRINT_windows_ascii -file $file -parent $parent [lindex $args 0]
|
||||
} else {
|
||||
send_printer_ascii -printer $printer -file $file \
|
||||
-outfile $outfile [lindex $args 0]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if {$outfile != ""} {
|
||||
if {$file} {
|
||||
file copy [lindex 0 $args] $outfile
|
||||
} else {
|
||||
set F [open $outfile w]
|
||||
puts $F [lindex 0 $args]
|
||||
close $F
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if {$tcl_platform(platform) == "windows"} then {
|
||||
load tkmswin.dll
|
||||
|
||||
set cmd {tkmswin print -postscript}
|
||||
if {$printer != ""} {
|
||||
lappend cmd -printer $printer
|
||||
}
|
||||
if {$file} {
|
||||
lappend cmd -file
|
||||
}
|
||||
lappend cmd [lindex $args 0]
|
||||
eval $cmd
|
||||
|
||||
} else {
|
||||
|
||||
# Unix box, assume lpr, but if it fails try lp.
|
||||
foreach prog {lpr lp} {
|
||||
set cmd [list exec $prog]
|
||||
if {$printer != ""} {
|
||||
if {$prog == "lpr"} {
|
||||
lappend cmd "-P$printer"
|
||||
} else {
|
||||
lappend cmd "-d$printer"
|
||||
}
|
||||
}
|
||||
if {$file} {
|
||||
lappend cmd "<"
|
||||
} else {
|
||||
lappend cmd "<<"
|
||||
}
|
||||
# tack on data or filename
|
||||
lappend cmd [lindex $args 0]
|
||||
|
||||
# attempt to run the command, and exit if successful
|
||||
if ![catch {eval $cmd} ret] {
|
||||
return
|
||||
}
|
||||
}
|
||||
error "Couldn't run either `lpr' or `lp' to print"
|
||||
}
|
||||
}
|
||||
|
||||
proc send_printer_ascii { args } {
|
||||
global tcl_platform
|
||||
|
||||
parse_args {
|
||||
{printer {}}
|
||||
{outfile {}}
|
||||
{file 0}
|
||||
{font Courier}
|
||||
{fontsize 10}
|
||||
{pageheight 11}
|
||||
{pagewidth 8.5}
|
||||
{margin .5}
|
||||
}
|
||||
if {[llength $args] == 0} {
|
||||
error "No filename or data provided."
|
||||
}
|
||||
|
||||
if {$tcl_platform(platform) == "windows"} then {
|
||||
PRINT_windows_ascii -file $file [lindex $args 0]
|
||||
return
|
||||
}
|
||||
|
||||
# convert the filename or data to ascii, and then send to the printer.
|
||||
|
||||
set inch 72
|
||||
set pageheight [expr $pageheight*$inch]
|
||||
set pagewidth [expr $pagewidth*$inch]
|
||||
set margin [expr $margin*$inch]
|
||||
|
||||
set output "%!PS-Adobe-1.0\n"
|
||||
append output "%%Creator: libgui ASCII-to-PS converter\n"
|
||||
append output "%%DocumentFonts: $font\n"
|
||||
append output "%%Pages: (atend)\n"
|
||||
append output "/$font findfont $fontsize scalefont setfont\n"
|
||||
append output "/M{moveto}def\n"
|
||||
append output "/S{show}def\n"
|
||||
|
||||
set pages 1
|
||||
set y [expr $pageheight-$margin-$fontsize]
|
||||
|
||||
if {$file == 1} {
|
||||
set G [open [lindex $args 0] r]
|
||||
set strlen [gets $G str]
|
||||
} else {
|
||||
# make sure that we end with a newline
|
||||
set args [lindex $args 0]
|
||||
append args "\n"
|
||||
|
||||
set strlen [string first "\n" $args]
|
||||
if {$strlen != -1} {
|
||||
set str [string range $args 0 [expr $strlen-1]]
|
||||
set args [string range $args [expr $strlen+1] end]
|
||||
}
|
||||
}
|
||||
while {$strlen != -1} {
|
||||
if {$y < $margin} {
|
||||
append output "showpage\n"
|
||||
incr pages
|
||||
set y [expr $pageheight-$margin-$fontsize]
|
||||
}
|
||||
regsub -all {[()\\]} $str {\\&} str
|
||||
append output "$margin $y M ($str) S\n"
|
||||
set y [expr $y-($fontsize+1)]
|
||||
|
||||
if {$file == 1} {
|
||||
set strlen [gets $G str]
|
||||
} else {
|
||||
set strlen [string first "\n" $args]
|
||||
if {$strlen != -1} {
|
||||
set str [string range $args 0 [expr $strlen-1]]
|
||||
set args [string range $args [expr $strlen+1] end]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
append output "showpage\n"
|
||||
append output "%%Pages: $pages\n"
|
||||
|
||||
if {$file == 1} {
|
||||
close $G
|
||||
}
|
||||
|
||||
send_printer -printer $printer -outfile $outfile $output
|
||||
}
|
||||
|
||||
# Print ASCII text on Windows.
|
||||
|
||||
proc PRINT_windows_ascii { args } {
|
||||
global tcl_platform errorInfo
|
||||
global PRINT_state
|
||||
|
||||
parse_args {
|
||||
{file 0}
|
||||
{parent {}}
|
||||
}
|
||||
if {[llength $args] == 0} {
|
||||
error "No filename or data provided."
|
||||
}
|
||||
|
||||
if {$tcl_platform(platform) != "windows"} then {
|
||||
error "Only works on Windows"
|
||||
}
|
||||
|
||||
# Copied from tk_dialog, except that it returns.
|
||||
catch {destroy .cancelprint}
|
||||
toplevel .cancelprint -class Dialog
|
||||
wm withdraw .cancelprint
|
||||
wm title .cancelprint [gettext "Printing"]
|
||||
frame .cancelprint.bot
|
||||
frame .cancelprint.top
|
||||
pack .cancelprint.bot -side bottom -fill both
|
||||
pack .cancelprint.top -side top -fill both -expand 1
|
||||
set PRINT_state(pageno) [format [gettext "Now printing page %d"] 0]
|
||||
label .cancelprint.msg -justify left -textvariable PRINT_state(pageno)
|
||||
pack .cancelprint.msg -in .cancelprint.top -side right -expand 1 \
|
||||
-fill both -padx 1i -pady 5
|
||||
button .cancelprint.button -text [gettext "Cancel"] \
|
||||
-command { ide_winprint abort } -default active
|
||||
grid .cancelprint.button -in .cancelprint.bot -column 0 -row 0 \
|
||||
-sticky ew -padx 10
|
||||
grid columnconfigure .cancelprint.bot 0
|
||||
|
||||
update idletasks
|
||||
set x [expr [winfo screenwidth .cancelprint]/2 \
|
||||
- [winfo reqwidth .cancelprint]/2 \
|
||||
- [winfo vrootx [winfo parent .cancelprint]]]
|
||||
set y [expr [winfo screenheight .cancelprint]/2 \
|
||||
- [winfo reqheight .cancelprint]/2 \
|
||||
- [winfo vrooty [winfo parent .cancelprint]]]
|
||||
wm geom .cancelprint +$x+$y
|
||||
update
|
||||
|
||||
# We're going to change the focus and the grab as soon as we start
|
||||
# printing, so remember them now.
|
||||
set oldFocus [focus]
|
||||
set oldGrab [grab current .cancelprint]
|
||||
if {$oldGrab != ""} then {
|
||||
set grabStatus [grab status $oldGrab]
|
||||
}
|
||||
|
||||
focus .cancelprint.button
|
||||
|
||||
set PRINT_state(start) 1
|
||||
set PRINT_state(file) $file
|
||||
if {$file == 1} then {
|
||||
set PRINT_state(fp) [open [lindex $args 0] r]
|
||||
} else {
|
||||
set PRINT_state(text) [lindex $args 0]
|
||||
}
|
||||
|
||||
set cmd [list ide_winprint print_text PRINT_query PRINT_text \
|
||||
-pageproc PRINT_page]
|
||||
if {$parent != {}} then {
|
||||
lappend cmd -parent $parent
|
||||
}
|
||||
|
||||
set code [catch $cmd errmsg]
|
||||
set errinfo $errorInfo
|
||||
|
||||
catch { focus $oldFocus }
|
||||
catch { destroy .cancelprint }
|
||||
if {$oldGrab != ""} then {
|
||||
if {$grabStatus == "global"} then {
|
||||
grab -global $oldGrab
|
||||
} else {
|
||||
grab $oldGrab
|
||||
}
|
||||
}
|
||||
|
||||
if {$code == 1} then {
|
||||
error $errmsg $errinfo
|
||||
}
|
||||
}
|
||||
|
||||
# The query procedure passed to ide_winprint print_text. This should
|
||||
# return one of "continue", "done", or "newpage".
|
||||
|
||||
proc PRINT_query { } {
|
||||
global PRINT_state
|
||||
|
||||
# Fetch the next line into PRINT_state(str).
|
||||
|
||||
if {$PRINT_state(file) == 1} then {
|
||||
set strlen [gets $PRINT_state(fp) PRINT_state(str)]
|
||||
} else {
|
||||
set strlen [string first "\n" $PRINT_state(text)]
|
||||
if {$strlen != -1} then {
|
||||
set PRINT_state(str) \
|
||||
[string range $PRINT_state(text) 0 [expr $strlen-1]]
|
||||
set PRINT_state(text) \
|
||||
[string range $PRINT_state(text) [expr $strlen+1] end]
|
||||
} else {
|
||||
if {$PRINT_state(text) != ""} then {
|
||||
set strlen 0
|
||||
set PRINT_state(str) $PRINT_state(text)
|
||||
set PRINT_state(text) ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {$strlen != -1} then {
|
||||
|
||||
# Expand tabs assuming tabstops every 8 spaces and a fixed
|
||||
# pitch font. Text written to other assumptions will have to
|
||||
# be handled by the caller.
|
||||
|
||||
set str $PRINT_state(str)
|
||||
while {[set i [string first "\t" $str]] >= 0} {
|
||||
set c [expr 8 - ($i % 8)]
|
||||
set spaces ""
|
||||
while {$c > 0} {
|
||||
set spaces "$spaces "
|
||||
incr c -1
|
||||
}
|
||||
set str "[string range $str 0 [expr $i - 1]]$spaces[string range $str [expr $i + 1] end]"
|
||||
}
|
||||
set PRINT_state(str) $str
|
||||
|
||||
return "continue"
|
||||
} else {
|
||||
return "done"
|
||||
}
|
||||
}
|
||||
|
||||
# The text procedure passed to ide_winprint print_text. This should
|
||||
# return the next line to print.
|
||||
|
||||
proc PRINT_text { } {
|
||||
global PRINT_state
|
||||
|
||||
return $PRINT_state(str)
|
||||
}
|
||||
|
||||
# This page procedure passed to ide_winprint print_text. This is
|
||||
# called at the start of each page.
|
||||
|
||||
proc PRINT_page { pageno } {
|
||||
global PRINT_state
|
||||
|
||||
set PRINT_state(pageno) [format [gettext "Now printing page %d"] $pageno]
|
||||
|
||||
if {$PRINT_state(start)} then {
|
||||
wm deiconify .cancelprint
|
||||
|
||||
grab .cancelprint
|
||||
focus .cancelprint.button
|
||||
|
||||
set PRINT_state(start) 0
|
||||
}
|
||||
|
||||
update
|
||||
return "continue"
|
||||
}
|
|
@ -0,0 +1,348 @@
|
|||
# sendpr.tcl - GUI to send-pr.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# FIXME:
|
||||
# * consider adding ability to set various options from outside,
|
||||
# eg via the configure method.
|
||||
# * Have explanatory text at the top
|
||||
# * if synopsis not set, don't allow PR to be sent
|
||||
# * at least one text field must have text in it before PR can be sent
|
||||
# * see other fixme comments in text.
|
||||
|
||||
# FIXME: shouldn't have global variable.
|
||||
defarray SENDPR_state
|
||||
|
||||
itcl_class Sendpr {
|
||||
inherit Ide_window
|
||||
|
||||
# This array holds information about this site. It is a private
|
||||
# common array. Once initialized it is never changed.
|
||||
common _site
|
||||
|
||||
# Initialize the _site array.
|
||||
global Paths tcl_platform
|
||||
|
||||
# On Windows, there is no `send-pr' program. For now, we just
|
||||
# hard-code things there to work in the most important case.
|
||||
if {$tcl_platform(platform) == "windows"} then {
|
||||
set _site(header) ""
|
||||
set _site(to) bugs@cygnus.com
|
||||
set _site(field,Submitter-Id) cygnus
|
||||
set _site(field,Originator) Nobody
|
||||
set _site(field,Release) "Internal"
|
||||
set _site(field,Organization) "Red Hat, Inc."
|
||||
set _site(field,Environment) ""
|
||||
foreach item {byteOrder machine os osVersion platform} {
|
||||
append _site(field,Environment) "$item = $tcl_platform($item)\n"
|
||||
}
|
||||
set _site(categories) foundry
|
||||
} else {
|
||||
set _site(sendpr) [file join $Paths(bindir) send-pr]
|
||||
# If it doesn't exist, try the user's path. This is a hack for
|
||||
# developers.
|
||||
if {! [file exists $_site(sendpr)]} then {
|
||||
set _site(sendpr) send-pr
|
||||
}
|
||||
|
||||
set _site(header) {}
|
||||
set outList [split [exec $_site(sendpr) -P] \n]
|
||||
set lastField {}
|
||||
foreach line $outList {
|
||||
if {[string match SEND-PR* $line]} then {
|
||||
# Nothing.
|
||||
} elseif {[regexp {^$} $line] || [regexp "^\[ \t\]" $line]} then {
|
||||
# Empty lines and lines starting with a blank are skipped.
|
||||
} elseif {$lastField == "" &&
|
||||
[regexp [format {^[^>]([^:]+):[ %s]+(.+)$} \t] \
|
||||
$line dummy field value]} then {
|
||||
# A non-empty mail header line. This can only occur when there
|
||||
# is no last field.
|
||||
if {[string tolower $field] == "to"} then {
|
||||
set _site(to) $value
|
||||
}
|
||||
} elseif {[regexp {^>([^:]*):(.*)$} $line dummy field value]} then {
|
||||
# Found a field. Set it.
|
||||
set lastField $field
|
||||
if {$value != "" && ![string match <*> [string trim $value]]} then {
|
||||
set _site(field,$lastField) $value
|
||||
}
|
||||
} elseif {$lastField == ""} then {
|
||||
# No last field.
|
||||
} else {
|
||||
# Stuff into last field.
|
||||
if {[info exists _site(field,$lastField)]} then {
|
||||
append _site(field,$lastField) \n
|
||||
}
|
||||
append _site(field,$lastField) $line
|
||||
}
|
||||
}
|
||||
# Now find the categories.
|
||||
regsub -all -- {[()\"]} [exec $_site(sendpr) -CL] \
|
||||
"" _site(categories)
|
||||
set _site(categories) [lrmdups [concat foundry $_site(categories)]]
|
||||
}
|
||||
|
||||
# Internationalize some text. We have to do this because of how
|
||||
# Tk's optionmenu works. Indices here are the names that GNATS
|
||||
# wants; this is important.
|
||||
set _site(sw-bug) [gettext "Software bug"]
|
||||
set _site(doc-bug) [gettext "Documentation bug"]
|
||||
set _site(change-request) [gettext "Change request"]
|
||||
set _site(support) [gettext "Support"]
|
||||
set _site(non-critical) [gettext "Non-critical"]
|
||||
set _site(serious) [gettext "Serious"]
|
||||
set _site(critical) [gettext "Critical"]
|
||||
set _site(low) [gettext "Low"]
|
||||
set _site(medium) [gettext "Medium"]
|
||||
set _site(high) [gettext "High"]
|
||||
|
||||
# Any text passed to constructor is saved and put into Description
|
||||
# section of output.
|
||||
constructor {{text ""}} {
|
||||
Ide_window::constructor [gettext "Report Bug"]
|
||||
} {
|
||||
global SENDPR_state
|
||||
|
||||
# The standard widget-making trick.
|
||||
set class [$this info class]
|
||||
set hull [namespace tail $this]
|
||||
set old_name $this
|
||||
::rename $this $this-tmp-
|
||||
# For now always make a toplevel. Number 7 comes from Windows
|
||||
::rename $hull $old_name-win-
|
||||
::rename $this $old_name
|
||||
::rename $this $this-win-
|
||||
::rename $this-tmp- $this
|
||||
|
||||
wm withdraw [namespace tail $this]
|
||||
###FIXME - this constructor callout will cause the parent constructor to be called twice
|
||||
|
||||
::set SENDPR_state($this,desc) $text
|
||||
|
||||
#
|
||||
# The Classification frame.
|
||||
#
|
||||
|
||||
Labelledframe [namespace tail $this].cframe -text [gettext "Classification"]
|
||||
set parent [[namespace tail $this].cframe get_frame]
|
||||
|
||||
tixComboBox $parent.category -dropdown 1 -editable 0 \
|
||||
-label [gettext "Category"] -variable SENDPR_state($this,category)
|
||||
foreach item $_site(categories) {
|
||||
$parent.category insert end $item
|
||||
}
|
||||
# FIXME: allow user of this class to set default category.
|
||||
::set SENDPR_state($this,category) foundry
|
||||
|
||||
::set SENDPR_state($this,secret) no
|
||||
checkbutton $parent.secret -text [gettext "Confidential"] \
|
||||
-variable SENDPR_state($this,secret) -onvalue yes -offvalue no \
|
||||
-anchor w
|
||||
|
||||
# FIXME: put labels on these?
|
||||
set m1 [_make_omenu $parent.class class 0 \
|
||||
sw-bug doc-bug change-request support]
|
||||
set m2 [_make_omenu $parent.severity severity 1 \
|
||||
non-critical serious critical]
|
||||
set m3 [_make_omenu $parent.priority priority 1 \
|
||||
low medium high]
|
||||
if {$m1 > $m2} then {
|
||||
set m2 $m1
|
||||
}
|
||||
if {$m2 > $m3} then {
|
||||
set m3 $m2
|
||||
}
|
||||
$parent.class configure -width $m3
|
||||
$parent.severity configure -width $m3
|
||||
$parent.priority configure -width $m3
|
||||
|
||||
grid $parent.category $parent.severity -sticky nw -padx 2
|
||||
grid $parent.secret $parent.class -sticky nw -padx 2
|
||||
grid x $parent.priority -sticky nw -padx 2
|
||||
|
||||
#
|
||||
# The text and entry frames.
|
||||
#
|
||||
|
||||
Labelledframe [namespace tail $this].synopsis -text [gettext "Synopsis"]
|
||||
set parent [[namespace tail $this].synopsis get_frame]
|
||||
entry $parent.synopsis -textvariable SENDPR_state($this,synopsis)
|
||||
pack $parent.synopsis -expand 1 -fill both
|
||||
|
||||
# Text fields. Each is wrapped in its own label frame.
|
||||
# We decided to eliminate all the frames but one; the others are
|
||||
# just confusing.
|
||||
::set SENDPR_state($this,repeat) [_make_text [namespace tail $this].desc \
|
||||
[gettext "Description"]]
|
||||
|
||||
# Some buttons.
|
||||
frame [namespace tail $this].buttons -borderwidth 0 -relief flat
|
||||
button [namespace tail $this].buttons.send -text [gettext "Send"] \
|
||||
-command [list $this _send]
|
||||
button [namespace tail $this].buttons.cancel -text [gettext "Cancel"] \
|
||||
-command [list destroy $this]
|
||||
button [namespace tail $this].buttons.help -text [gettext "Help"] -state disabled
|
||||
standard_button_box [namespace tail $this].buttons
|
||||
|
||||
# FIXME: we'd really like to have sashes between the text widgets.
|
||||
# iwidgets or tix will provide that for us.
|
||||
grid [namespace tail $this].cframe -sticky ew -padx 4 -pady 4
|
||||
grid [namespace tail $this].synopsis -sticky ew -padx 4 -pady 4
|
||||
grid [namespace tail $this].desc -sticky news -padx 4 -pady 4
|
||||
grid [namespace tail $this].buttons -sticky ew -padx 4
|
||||
|
||||
grid rowconfigure [namespace tail $this] 0 -weight 0
|
||||
grid rowconfigure [namespace tail $this] 1 -weight 0
|
||||
grid rowconfigure [namespace tail $this] 2 -weight 1
|
||||
grid rowconfigure [namespace tail $this] 3 -weight 1
|
||||
grid columnconfigure [namespace tail $this] 0 -weight 1
|
||||
|
||||
bind [namespace tail $this].buttons <Destroy> [list $this delete]
|
||||
|
||||
wm deiconify [namespace tail $this]
|
||||
}
|
||||
|
||||
destructor {
|
||||
global SENDPR_state
|
||||
foreach item [array names SENDPR_state $this,*] {
|
||||
::unset SENDPR_state($item)
|
||||
}
|
||||
catch {destroy $this}
|
||||
}
|
||||
|
||||
method configure {config} {}
|
||||
|
||||
# Create an optionmenu and fill it. Also, go through all the items
|
||||
# and find the one that makes the menubutton the widest. Return the
|
||||
# max width. Private method.
|
||||
method _make_omenu {name index def_index args} {
|
||||
global SENDPR_state
|
||||
|
||||
set max 0
|
||||
set values {}
|
||||
# FIXME: we can't actually examine which one makes the menubutton
|
||||
# widest. Why not? Because the menubutton's -width option is in
|
||||
# characters, but we can only look at the width in pixels.
|
||||
foreach item $args {
|
||||
lappend values $_site($item)
|
||||
if {[string length $_site($item)] > $max} then {
|
||||
set max [string length $_site($item)]
|
||||
}
|
||||
}
|
||||
|
||||
eval tk_optionMenu $name SENDPR_state($this,$index) $values
|
||||
|
||||
::set SENDPR_state($this,$index) $_site([lindex $args $def_index])
|
||||
|
||||
return $max
|
||||
}
|
||||
|
||||
# Create a labelled frame and put a text widget in it. Private
|
||||
# method.
|
||||
method _make_text {name text} {
|
||||
Labelledframe $name -text $text
|
||||
set parent [$name get_frame]
|
||||
text $parent.text -width 80 -height 15 -wrap word \
|
||||
-yscrollcommand [list $parent.vb set]
|
||||
scrollbar $parent.vb -orient vertical -command [list $parent.text yview]
|
||||
grid $parent.text -sticky news
|
||||
grid $parent.vb -row 0 -column 1 -sticky ns
|
||||
grid rowconfigure $parent 0 -weight 1
|
||||
grid columnconfigure $parent 0 -weight 1
|
||||
grid columnconfigure $parent 1 -weight 0
|
||||
return $parent.text
|
||||
}
|
||||
|
||||
# This takes a text string and finds the element of site which has
|
||||
# the same value. It returns the corresponding key. Private
|
||||
# method.
|
||||
method _invert {text values} {
|
||||
foreach item $values {
|
||||
if {$_site($item) == $text} then {
|
||||
return $item
|
||||
}
|
||||
}
|
||||
error "couldn't find \"$text\""
|
||||
}
|
||||
|
||||
# Send the PR. Private method.
|
||||
method _send {} {
|
||||
global SENDPR_state
|
||||
|
||||
set email {}
|
||||
|
||||
if {[info exists _site(field,Submitter-Id)]} then {
|
||||
set _site(field,Customer-Id) $_site(field,Submitter-Id)
|
||||
unset _site(field,Submitter-Id)
|
||||
}
|
||||
|
||||
foreach field {Customer-Id Originator Release} {
|
||||
append email ">$field: $_site(field,$field)\n"
|
||||
}
|
||||
foreach field {Organization Environment} {
|
||||
append email ">$field:\n$_site(field,$field)\n"
|
||||
}
|
||||
|
||||
append email ">Confidential: "
|
||||
if {$SENDPR_state($this,secret)} then {
|
||||
append email yes\n
|
||||
} else {
|
||||
append email no\n
|
||||
}
|
||||
|
||||
append email ">Synopsis: $SENDPR_state($this,synopsis)\n"
|
||||
|
||||
foreach field {Severity Priority Class} \
|
||||
values {{non-critical serious critical} {low medium high}
|
||||
{sw-bug doc-bug change-request support}} {
|
||||
set name [string tolower $field]
|
||||
set value [_invert $SENDPR_state($this,$name) $values]
|
||||
append email ">$field: $value\n"
|
||||
}
|
||||
|
||||
append email ">Category: $SENDPR_state($this,category)\n"
|
||||
|
||||
# Now big things.
|
||||
append email ">How-To-Repeat:\n"
|
||||
append email "[$SENDPR_state($this,repeat) get 1.0 end]\n"
|
||||
|
||||
# This isn't displayed to the user, but can be set by the caller.
|
||||
append email ">Description:\n$SENDPR_state($this,desc)\n"
|
||||
|
||||
send_mail $_site(to) $SENDPR_state($this,synopsis) $email
|
||||
|
||||
destroy $this
|
||||
}
|
||||
|
||||
# Override from Ide_window.
|
||||
method idew_save {} {
|
||||
global SENDPR_state
|
||||
|
||||
foreach name {category secret severity priority class synopsis} {
|
||||
set result($name) $SENDPR_state($this,$name)
|
||||
}
|
||||
# Stop just before `end'; otherwise we add a newline each time.
|
||||
set result(repeat) [$SENDPR_state($this,repeat) get 1.0 {end - 1c}]
|
||||
set result(desc) $SENDPR_state($this,desc)
|
||||
|
||||
return [list Sendpr :: _restore [array get result]]
|
||||
}
|
||||
|
||||
# This is used to restore a bug report window. Private proc.
|
||||
proc _restore {alist x y width height visibility} {
|
||||
global SENDPR_state
|
||||
|
||||
array set values $alist
|
||||
|
||||
set name .[gensym]
|
||||
Sendpr $name $values(desc)
|
||||
foreach name {category secret severity priority class synopsis} {
|
||||
::set $SENDPR_state($this,$name) $values($name)
|
||||
}
|
||||
$SENDPR_state($name,repeat) insert end $desc
|
||||
|
||||
$name idew_set_geometry $x $y $width $height
|
||||
$name idew_set_visibility $visibility
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
# 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(ADVICE_do) [list source [file join $dir advice.tcl]]
|
||||
set auto_index(advise) [list source [file join $dir advice.tcl]]
|
||||
set auto_index(unadvise) [list source [file join $dir advice.tcl]]
|
||||
set auto_index(Balloon) [list source [file join $dir balloon.tcl]]
|
||||
set auto_index(BALLOON_find_balloon) [list source [file join $dir balloon.tcl]]
|
||||
set auto_index(BALLOON_command_register) [list source [file join $dir balloon.tcl]]
|
||||
set auto_index(BALLOON_command_notify) [list source [file join $dir balloon.tcl]]
|
||||
set auto_index(BALLOON_command_show) [list source [file join $dir balloon.tcl]]
|
||||
set auto_index(BALLOON_command_withdraw) [list source [file join $dir balloon.tcl]]
|
||||
set auto_index(BALLOON_command_variable) [list source [file join $dir balloon.tcl]]
|
||||
set auto_index(balloon) [list source [file join $dir balloon.tcl]]
|
||||
set auto_index(standard_button_box) [list source [file join $dir bbox.tcl]]
|
||||
set auto_index(bgerror) [list source [file join $dir bgerror.tcl]]
|
||||
set auto_index(bind_widget_after_tag) [list source [file join $dir bindings.tcl]]
|
||||
set auto_index(bind_widget_after_class) [list source [file join $dir bindings.tcl]]
|
||||
set auto_index(bind_plain_key) [list source [file join $dir bindings.tcl]]
|
||||
set auto_index(set_scroll_region) [list source [file join $dir canvas.tcl]]
|
||||
set auto_index(center_window) [list source [file join $dir center.tcl]]
|
||||
set auto_index(Checkframe) [list source [file join $dir cframe.tcl]]
|
||||
set auto_index(::combobox::combobox) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::build) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::setBindings) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::handleEvent) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::destroyHandler) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::find) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::select) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::computeGeometry) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::doInternalWidgetCommand) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::widgetProc) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::configure) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::vTrace) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::setValue) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::getBoolean) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::combobox::widgetName) [list source [file join $dir combobox.tcl]]
|
||||
set auto_index(::debug::logfile) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::trace_var) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::remove_trace) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::remove_all_traces) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::touched_by) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::show_call_stack) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::createData) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::debugwin) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::debug) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::dbug) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::_putdebug) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::_puttrace) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::init) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::trace_start) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::trace_stop) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::sagetkwait) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::sagevwait) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::sageexit) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::sageproc) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::sageitclbody) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::sageitclproc) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::sagemethod) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::push) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::pop) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::look) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::stackUnwind) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::startWatch) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::resetWatch) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::stopWatch) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::getWatch) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::startTimer) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::stopTimer) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::procEntry) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::methodEntry) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::procExit) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(::debug::methodExit) [list source [file join $dir debug.tcl]]
|
||||
set auto_index(defarray) [list source [file join $dir def.tcl]]
|
||||
set auto_index(defvar) [list source [file join $dir def.tcl]]
|
||||
set auto_index(defconst) [list source [file join $dir def.tcl]]
|
||||
set auto_index(FONT_track_change) [list source [file join $dir font.tcl]]
|
||||
set auto_index(define_font) [list source [file join $dir font.tcl]]
|
||||
set auto_index(gensym) [list source [file join $dir gensym.tcl]]
|
||||
set auto_index(gettext) [list source [file join $dir gettext.tcl]]
|
||||
set auto_index(add_hook) [list source [file join $dir hooks.tcl]]
|
||||
set auto_index(remove_hook) [list source [file join $dir hooks.tcl]]
|
||||
set auto_index(define_hook) [list source [file join $dir hooks.tcl]]
|
||||
set auto_index(run_hooks) [list source [file join $dir hooks.tcl]]
|
||||
set auto_index(send_mail) [list source [file join $dir internet.tcl]]
|
||||
set auto_index(open_url) [list source [file join $dir internet.tcl]]
|
||||
set auto_index(Labelledframe) [list source [file join $dir lframe.tcl]]
|
||||
set auto_index(lvarpush) [list source [file join $dir list.tcl]]
|
||||
set auto_index(lvarpop) [list source [file join $dir list.tcl]]
|
||||
set auto_index(lassign) [list source [file join $dir list.tcl]]
|
||||
set auto_index(lrmdups) [list source [file join $dir list.tcl]]
|
||||
set auto_index(lremove) [list source [file join $dir list.tcl]]
|
||||
set auto_index(lrep) [list source [file join $dir list.tcl]]
|
||||
set auto_index(lvarcat) [list source [file join $dir list.tcl]]
|
||||
set auto_index(standard_look_and_feel) [list source [file join $dir looknfeel.tcl]]
|
||||
set auto_index(compute_menu_width) [list source [file join $dir menu.tcl]]
|
||||
set auto_index(monochrome_p) [list source [file join $dir mono.tcl]]
|
||||
set auto_index(Multibox) [list source [file join $dir multibox.tcl]]
|
||||
set auto_index(::cyg::Pane) [list source [file join $dir pane.tcl]]
|
||||
set auto_index(::cyg::pane) [list source [file join $dir pane.tcl]]
|
||||
set auto_index(::cyg::Pane::constructor) [list source [file join $dir pane.tcl]]
|
||||
set auto_index(::cyg::Pane::minimum) [list source [file join $dir pane.tcl]]
|
||||
set auto_index(::cyg::Pane::maximum) [list source [file join $dir pane.tcl]]
|
||||
set auto_index(::cyg::Pane::margin) [list source [file join $dir pane.tcl]]
|
||||
set auto_index(::cyg::Pane::childSite) [list source [file join $dir pane.tcl]]
|
||||
set auto_index(::cyg::PanedWindow) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::panedwindow) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::constructor) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::orient) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::sashwidth) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::sashcolor) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::index) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::childsite) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::add) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::insert) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::delete) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::hide) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::replace) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::show) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::paneconfigure) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::reset) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_setActivePanes) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_eventHandler) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_resizeArray) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_startDrag) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_endDrag) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_configDrag) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_handleDrag) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_moveSash) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_calcPos) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_makeSashes) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_placeSash) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(::cyg::PanedWindow::_placePanes) [list source [file join $dir panedwindow.tcl]]
|
||||
set auto_index(parse_args) [list source [file join $dir parse_args.tcl]]
|
||||
set auto_index(canonical_path) [list source [file join $dir path.tcl]]
|
||||
set auto_index(GHOST_helper) [list source [file join $dir postghost.tcl]]
|
||||
set auto_index(add_post_command) [list source [file join $dir postghost.tcl]]
|
||||
set auto_index(ghosting_menu_item) [list source [file join $dir postghost.tcl]]
|
||||
set auto_index(PREFS_run_handlers) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_handle_property_event) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_cmd_define) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_cmd_get) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_cmd_getd) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_cmd_varname) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_cmd_set) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_cmd_setd) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_cmd_add_hook) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_cmd_remove_hook) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_cmd_init) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(PREFS_cmd_list) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(pref) [list source [file join $dir prefs.tcl]]
|
||||
set auto_index(send_printer) [list source [file join $dir print.tcl]]
|
||||
set auto_index(send_printer_ascii) [list source [file join $dir print.tcl]]
|
||||
set auto_index(PRINT_windows_ascii) [list source [file join $dir print.tcl]]
|
||||
set auto_index(PRINT_query) [list source [file join $dir print.tcl]]
|
||||
set auto_index(PRINT_text) [list source [file join $dir print.tcl]]
|
||||
set auto_index(PRINT_page) [list source [file join $dir print.tcl]]
|
||||
set auto_index(Sendpr) [list source [file join $dir sendpr.tcl]]
|
||||
set auto_index(::Sendpr::_restore) [list source [file join $dir sendpr.tcl]]
|
||||
set auto_index(TOOLBAR_button_enter) [list source [file join $dir toolbar.tcl]]
|
||||
set auto_index(TOOLBAR_button_leave) [list source [file join $dir toolbar.tcl]]
|
||||
set auto_index(TOOLBAR_button_down) [list source [file join $dir toolbar.tcl]]
|
||||
set auto_index(TOOLBAR_button_up) [list source [file join $dir toolbar.tcl]]
|
||||
set auto_index(TOOLBAR_maybe_init) [list source [file join $dir toolbar.tcl]]
|
||||
set auto_index(TOOLBAR_command) [list source [file join $dir toolbar.tcl]]
|
||||
set auto_index(standard_toolbar) [list source [file join $dir toolbar.tcl]]
|
||||
set auto_index(bind_for_toplevel_only) [list source [file join $dir topbind.tcl]]
|
||||
set auto_index(extract_label_info) [list source [file join $dir ulset.tcl]]
|
||||
set auto_index(Validated_entry) [list source [file join $dir ventry.tcl]]
|
||||
set auto_index(Widgetframe) [list source [file join $dir wframe.tcl]]
|
||||
set auto_index(WINGRAB_disable) [list source [file join $dir wingrab.tcl]]
|
||||
set auto_index(WINGRAB_disable_except) [list source [file join $dir wingrab.tcl]]
|
||||
set auto_index(WINGRAB_enable) [list source [file join $dir wingrab.tcl]]
|
||||
set auto_index(WINGRAB_enable_all) [list source [file join $dir wingrab.tcl]]
|
||||
set auto_index(ide_grab_support) [list source [file join $dir wingrab.tcl]]
|
|
@ -0,0 +1,243 @@
|
|||
# toolbar.tcl - Handle layout for a toolbar.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# This holds global state for this module.
|
||||
defarray TOOLBAR_state {
|
||||
initialized 0
|
||||
button ""
|
||||
window ""
|
||||
relief flat
|
||||
last ""
|
||||
}
|
||||
|
||||
proc TOOLBAR_button_enter {w} {
|
||||
global TOOLBAR_state
|
||||
|
||||
#save older relief (it covers buttons that
|
||||
#interacte like checkbuttons)
|
||||
set TOOLBAR_state(relief) [$w cget -relief]
|
||||
|
||||
if {[$w cget -state] != "disabled"} then {
|
||||
|
||||
if {$TOOLBAR_state(button) == $w} then {
|
||||
set relief sunken
|
||||
} else {
|
||||
set relief raised
|
||||
}
|
||||
|
||||
$w configure \
|
||||
-state active \
|
||||
-relief $relief
|
||||
}
|
||||
|
||||
#store last action to synchronize operations
|
||||
set TOOLBAR_state(last) enter
|
||||
set TOOLBAR_state(window) $w
|
||||
}
|
||||
|
||||
proc TOOLBAR_button_leave {w} {
|
||||
global TOOLBAR_state
|
||||
if {[$w cget -state] != "disabled"} then {
|
||||
$w configure -state normal
|
||||
}
|
||||
|
||||
#restore original relief
|
||||
if {
|
||||
$TOOLBAR_state(window) == $w
|
||||
&& $TOOLBAR_state(last) == "enter"
|
||||
} then {
|
||||
$w configure -relief $TOOLBAR_state(relief)
|
||||
} else {
|
||||
$w configure -relief flat
|
||||
}
|
||||
|
||||
set TOOLBAR_state(window) ""
|
||||
#store last action to synch operations (enter->leave)
|
||||
set TOOLBAR_state(last) leave
|
||||
}
|
||||
|
||||
proc TOOLBAR_button_down {w} {
|
||||
global TOOLBAR_state
|
||||
if {[$w cget -state] != "disabled"} then {
|
||||
set TOOLBAR_state(button) $w
|
||||
$w configure -relief sunken
|
||||
}
|
||||
}
|
||||
|
||||
proc TOOLBAR_button_up {w} {
|
||||
global TOOLBAR_state
|
||||
if {$w == $TOOLBAR_state(button)} then {
|
||||
set TOOLBAR_state(button) ""
|
||||
|
||||
#restore original relief
|
||||
$w configure -relief $TOOLBAR_state(relief)
|
||||
|
||||
if {$TOOLBAR_state(window) == $w
|
||||
&& [$w cget -state] != "disabled"} then {
|
||||
|
||||
#SN does the toolbar bindings using "+" so that older
|
||||
#bindings don't disapear. So no need to invoke the command.
|
||||
#other applications should do the same so that we can delete
|
||||
#this hack
|
||||
global sn_options
|
||||
if {! [array exists sn_options]} {
|
||||
#invoke the binding
|
||||
uplevel \#0 [list $w invoke]
|
||||
}
|
||||
if {[winfo exists $w]} then {
|
||||
if {[$w cget -state] != "disabled"} then {
|
||||
$w configure -state normal
|
||||
}
|
||||
}
|
||||
# HOWEVER, if the pointer is still over the button, and it
|
||||
# is enabled, then raise it again.
|
||||
|
||||
if {[string compare [winfo containing \
|
||||
[winfo pointerx $w] \
|
||||
[winfo pointery $w]] $w] == 0} {
|
||||
$w configure -relief raised
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Set up toolbar bindings.
|
||||
proc TOOLBAR_maybe_init {} {
|
||||
global TOOLBAR_state
|
||||
if {! $TOOLBAR_state(initialized)} then {
|
||||
set TOOLBAR_state(initialized) 1
|
||||
|
||||
# We can't put our bindings onto the widget (and then use "break"
|
||||
# to avoid the class bindings) because that interacts poorly with
|
||||
# balloon help.
|
||||
bind ToolbarButton <Enter> [list TOOLBAR_button_enter %W]
|
||||
bind ToolbarButton <Leave> [list TOOLBAR_button_leave %W]
|
||||
bind ToolbarButton <1> [list TOOLBAR_button_down %W]
|
||||
bind ToolbarButton <ButtonRelease-1> [list TOOLBAR_button_up %W]
|
||||
}
|
||||
}
|
||||
|
||||
#Allows changing options of a toolbar button from the application
|
||||
#especially the relief value
|
||||
proc TOOLBAR_command {w args} {
|
||||
global TOOLBAR_state
|
||||
|
||||
set len [llength $args]
|
||||
for {set i 0} {$i < $len} {incr i} {
|
||||
set cmd [lindex $args $i]
|
||||
switch -- $cmd {
|
||||
"relief" -
|
||||
"-relief" {
|
||||
incr i
|
||||
set TOOLBAR_state(relief) [lindex $args $i]
|
||||
$w configure $cmd [lindex $args $i]
|
||||
}
|
||||
"window" -
|
||||
"-window" {
|
||||
incr i
|
||||
set TOOLBAR_state(window) [lindex $args $i]
|
||||
}
|
||||
default {
|
||||
#normal widget options
|
||||
incr i
|
||||
$w configure $cmd [lindex $args $i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Pass this proc a frame and some children of the frame. It will put
|
||||
# the children into the frame so that they look like a toolbar.
|
||||
# Children are added in the order they are listed. If a child's name
|
||||
# is "-", then the appropriate type of separator is entered instead.
|
||||
# If a child's name is "--" then all remaining children will be placed
|
||||
# on the right side of the window.
|
||||
#
|
||||
# For non-flat mode, each button must display an image, and this image
|
||||
# must have a twin. The primary (raised) image's name must end in
|
||||
# "u", and the depressed image's name must end in "d". Eg the edit
|
||||
# images should be called "editu" and "editd". There's no doubt that
|
||||
# this is a hack.
|
||||
#
|
||||
# If you want to add a button that doesn't have an image (or whose
|
||||
# image doesn't have a twin), you must wrap it in a frame.
|
||||
#
|
||||
# FIXME: someday, write a `toolbar button' widget that handles the
|
||||
# image mess invisibly.
|
||||
proc standard_toolbar {frame args} {
|
||||
global tcl_platform
|
||||
|
||||
# For now, there are two different layouts, depending on which kind
|
||||
# of icons we're using. This is just a test feature and will be
|
||||
# eliminated once we decide on an icon style.
|
||||
|
||||
TOOLBAR_maybe_init
|
||||
|
||||
# We reserve column 0 for some padding.
|
||||
set column 1
|
||||
if {$tcl_platform(platform) == "windows"} then {
|
||||
# See below to understand this.
|
||||
set row 1
|
||||
} else {
|
||||
set row 0
|
||||
}
|
||||
# This is set if we see "--" and thus the filling happens in the
|
||||
# center.
|
||||
set center_fill 0
|
||||
set sticky w
|
||||
foreach button $args {
|
||||
grid columnconfigure $frame $column -weight 0
|
||||
|
||||
if {$button == "-"} then {
|
||||
# A separator.
|
||||
set f [frame $frame.[gensym] -borderwidth 1 -width 2 -relief sunken]
|
||||
grid $f -row $row -column $column -sticky ns${sticky} -padx 4
|
||||
} elseif {$button == "--"} then {
|
||||
# Everything after this is put on the right. We do this by
|
||||
# adding a column that sucks up all the space.
|
||||
set center_fill 1
|
||||
set sticky e
|
||||
grid columnconfigure $frame $column -weight 1 -minsize 7
|
||||
} elseif {[winfo class $button] != "Button"} then {
|
||||
# Something other than a button. Just put it into the frame.
|
||||
grid $button -row $row -column $column -sticky $sticky -pady 2
|
||||
} else {
|
||||
# A button.
|
||||
# FIXME: does Windows allow focus traversal? For now we're
|
||||
# just turning it off.
|
||||
$button configure -takefocus 0 -highlightthickness 0 \
|
||||
-relief flat -borderwidth 1
|
||||
grid $button -row $row -column $column -sticky $sticky -pady 2
|
||||
|
||||
# Make sure the button acts the way we want, not the default Tk
|
||||
# way.
|
||||
set index [lsearch -exact [bindtags $button] Button]
|
||||
bindtags $button [lreplace [bindtags $button] $index $index \
|
||||
ToolbarButton]
|
||||
}
|
||||
|
||||
incr column
|
||||
}
|
||||
|
||||
# On Unix, it looks a little more natural to have a raised toolbar.
|
||||
# On Windows the toolbar is flat, but there is a horizontal
|
||||
# separator between the toolbar and the menubar. On both platforms
|
||||
# we provide some space to the left of the leftmost widget.
|
||||
grid columnconfigure $frame 0 -minsize 7 -weight 0
|
||||
|
||||
if {$tcl_platform(platform) == "windows"} then {
|
||||
$frame configure -borderwidth 0 -relief flat
|
||||
set name $frame.[gensym]
|
||||
frame $name -height 2 -borderwidth 1 -relief sunken
|
||||
grid $name -row 0 -column 0 -columnspan $column -pady 1 -sticky ew
|
||||
} else {
|
||||
$frame configure -borderwidth 2 -relief raised
|
||||
}
|
||||
|
||||
if {! $center_fill} then {
|
||||
# The rightmost column sucks up the extra space.
|
||||
incr column -1
|
||||
grid columnconfigure $frame $column -weight 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
# topbind.tcl - Put a binding on a toplevel.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# Put a binding on a toplevel. This needs a separate proc because by
|
||||
# default the toplevel's name is put into the bindtags list for all
|
||||
# its descendents. Eg Destroy bindings typically don't want to be run
|
||||
# more than once.
|
||||
#
|
||||
|
||||
# FIXME: should catch destroy operations and remove all bindings for
|
||||
# our tag.
|
||||
|
||||
# Make the binding. Return nothing.
|
||||
proc bind_for_toplevel_only {toplevel sequence script} {
|
||||
set tagList [bindtags $toplevel]
|
||||
set tag _DBind_$toplevel
|
||||
if {[lsearch -exact $tagList $tag] == -1} then {
|
||||
# Always put our new binding first in case the other bindings run
|
||||
# break.
|
||||
bindtags $toplevel [concat $tag $tagList]
|
||||
}
|
||||
|
||||
# Use "+" binding in case there are multiple calls to this. FIXME
|
||||
# should just use gensym.
|
||||
bind $tag $sequence +$script
|
||||
|
||||
return {}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
# ulset.tcl - Set labels based on info from gettext.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
# Extract underline and label info from a descriptor string. Any
|
||||
# underline in the descriptor is extracted, and the next character's
|
||||
# index is used as the -underline value. There can only be one _ in
|
||||
# the label.
|
||||
proc extract_label_info {option label} {
|
||||
set uList [split $label _]
|
||||
if {[llength $uList] > 2} then {
|
||||
error "too many underscores in label \"$label\""
|
||||
}
|
||||
|
||||
if {[llength $uList] == 1} then {
|
||||
set ul -1
|
||||
} else {
|
||||
set ul [string length [lindex $uList 0]]
|
||||
}
|
||||
|
||||
return [list $option [join $uList {}] -underline $ul]
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
# ventry.tcl - Entry with validation
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
itcl_class Validated_entry {
|
||||
# The validation command. It is passed the contents of the entry.
|
||||
# It should throw an error if there is a problem; the error text
|
||||
# will be displayed to the user.
|
||||
public command {}
|
||||
|
||||
constructor {config} {
|
||||
upvar \#0 $this state
|
||||
|
||||
# The standard widget-making trick.
|
||||
set class [$this info class]
|
||||
set hull [namespace tail $this]
|
||||
set old_name $this
|
||||
::rename $this $this-tmp-
|
||||
::frame $hull -class $class -borderwidth 0
|
||||
::rename $hull $old_name-win-
|
||||
::rename $this $old_name
|
||||
|
||||
::set ${this}(value) ""
|
||||
::entry [namespace tail $this].entry -textvariable ${this}(value)
|
||||
pack [namespace tail $this].entry -expand 1 -fill both
|
||||
|
||||
bind [namespace tail $this].entry <Map> [list $this _map]
|
||||
bind [namespace tail $this].entry <Unmap> [list $this _unmap]
|
||||
bind [namespace tail $this].entry <Destroy> [list $this delete]
|
||||
# We never want the focus on the frame.
|
||||
bind [namespace tail $this] <FocusIn> [list focus [namespace tail $this].entry]
|
||||
|
||||
# This window is used when the user enters a bad name for the new
|
||||
# executable. The color here is "plum3". We use a toplevel here
|
||||
# both to get a nice black border and because a frame would be
|
||||
# clipped by its parents.
|
||||
toplevel [namespace tail $this].badname -borderwidth 1 -background black -relief flat
|
||||
wm withdraw [namespace tail $this].badname
|
||||
wm overrideredirect [namespace tail $this].badname 1
|
||||
|
||||
::set state(message) ""
|
||||
|
||||
# FIXME: -textvariable didn't work; I suspect itcl.
|
||||
::label [namespace tail $this].badname.text -anchor w -justify left \
|
||||
-background \#cdd29687cdd2 ;# -textvariable ${this}(message)
|
||||
pack [namespace tail $this].badname.text -expand 1 -fill both
|
||||
|
||||
# Trace the entry contents.
|
||||
uplevel \#0 [list trace variable ${this}(value) w [list $this _trace]]
|
||||
}
|
||||
|
||||
destructor {
|
||||
upvar \#0 $this state
|
||||
catch {destroy $this}
|
||||
uplevel \#0 [list trace vdelete ${this}(value) w [list $this _trace]]
|
||||
unset state
|
||||
}
|
||||
|
||||
method configure {config} {}
|
||||
|
||||
# Return 1 if we're in the error state, 0 otherwise.
|
||||
method is_error {} {
|
||||
upvar \#0 $this state
|
||||
return [expr {$state(message) != ""}]
|
||||
}
|
||||
|
||||
# Return error text.
|
||||
method error_text {} {
|
||||
upvar \#0 $this state
|
||||
return $state(message)
|
||||
}
|
||||
|
||||
# Some methods to forward messages to the entry. Add more as
|
||||
# required.
|
||||
|
||||
# FIXME: itcl 1.5 won't let us have a `delete' method. Sigh.
|
||||
method delete_hack {args} {
|
||||
return [eval [namespace tail $this].entry delete $args]
|
||||
}
|
||||
|
||||
method get {} {
|
||||
return [[namespace tail $this].entry get]
|
||||
}
|
||||
|
||||
method insert {index string} {
|
||||
return [[namespace tail $this].entry insert $index $string]
|
||||
}
|
||||
|
||||
|
||||
# This is run to display the label. Private method.
|
||||
method _display {} {
|
||||
# FIXME: place above if it would go offscreen.
|
||||
set y [expr {[winfo rooty [namespace tail $this].entry] + [winfo height [namespace tail $this].entry] + 1}]
|
||||
set x [expr {round ([winfo rootx [namespace tail $this].entry]
|
||||
+ 0.12 * [winfo width [namespace tail $this].entry])}]
|
||||
wm positionfrom [namespace tail $this].badname user
|
||||
wm geometry [namespace tail $this].badname +$x+$y
|
||||
# Workaround for Tk 8.0b2 bug on NT.
|
||||
update
|
||||
wm deiconify [namespace tail $this].badname
|
||||
raise [namespace tail $this].badname
|
||||
}
|
||||
|
||||
# This is run when the entry widget is mapped. If we have an error,
|
||||
# map our error label. Private method.
|
||||
method _map {} {
|
||||
if {[is_error]} then {
|
||||
_display
|
||||
}
|
||||
}
|
||||
|
||||
# This is run when the entry widget is unmapped. Private method.
|
||||
method _unmap {} {
|
||||
wm withdraw [namespace tail $this].badname
|
||||
}
|
||||
|
||||
# This is called when the entry contents change. Private method.
|
||||
method _trace {args} {
|
||||
upvar \#0 $this state
|
||||
|
||||
if {$command != ""} then {
|
||||
set cmd $command
|
||||
lappend cmd $state(value)
|
||||
set cmd [list uplevel \#0 $cmd]
|
||||
}
|
||||
if {[info exists cmd] && [catch $cmd msg]} then {
|
||||
# FIXME: for some reason, the -textvariable on the label doesn't
|
||||
# work. I suspect itcl.
|
||||
set state(message) $msg
|
||||
[namespace tail $this].badname.text configure -text $msg
|
||||
_display
|
||||
} else {
|
||||
set state(message) ""
|
||||
wm withdraw [namespace tail $this].badname
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
# wframe.tcl - Frame with a widget on its border.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
|
||||
itcl_class Widgetframe {
|
||||
# Where to put the widget. For now, we don't support many anchors.
|
||||
# Augment as you like.
|
||||
public anchor nw {
|
||||
if {$anchor != "nw" && $anchor != "n"} then {
|
||||
error "anchors nw and n are the only ones supported"
|
||||
}
|
||||
_layout
|
||||
}
|
||||
|
||||
# The name of the widget to put on the frame. This is set by some
|
||||
# subclass calling the _add method. Private variable.
|
||||
protected _widget {}
|
||||
|
||||
constructor {config} {
|
||||
# The standard widget-making trick.
|
||||
set class [$this info class]
|
||||
set hull [namespace tail $this]
|
||||
set old_name $this
|
||||
::rename $this $this-tmp-
|
||||
::frame $hull -class $class -relief flat -borderwidth 0
|
||||
::rename $hull $old_name-win-
|
||||
::rename $this $old_name
|
||||
|
||||
frame [namespace tail $this].iframe -relief groove -borderwidth 2
|
||||
grid [namespace tail $this].iframe -row 1 -sticky news
|
||||
grid rowconfigure [namespace tail $this] 1 -weight 1
|
||||
grid columnconfigure [namespace tail $this] 0 -weight 1
|
||||
|
||||
# Make an internal frame so that user stuff isn't obscured. Note
|
||||
# that we can't use the placer, because it doesn't set the
|
||||
# geometry of the parent.
|
||||
frame [namespace tail $this].iframe.frame -borderwidth 4 -relief flat
|
||||
grid [namespace tail $this].iframe.frame -row 1 -sticky news
|
||||
grid rowconfigure [namespace tail $this].iframe 1 -weight 1
|
||||
grid columnconfigure [namespace tail $this].iframe 0 -weight 1
|
||||
|
||||
bind [namespace tail $this].iframe <Destroy> [list $this delete]
|
||||
}
|
||||
|
||||
destructor {
|
||||
catch {destroy $this}
|
||||
}
|
||||
|
||||
# Return name of internal frame.
|
||||
method get_frame {} {
|
||||
return [namespace tail $this].iframe.frame
|
||||
}
|
||||
|
||||
# Name a certain widget to be put on the frame. This should be
|
||||
# called by some subclass after making the widget. Protected
|
||||
# method.
|
||||
method _add {widget} {
|
||||
set _widget $widget
|
||||
set height [expr {int ([winfo reqheight $_widget] / 2)}]
|
||||
grid rowconfigure [namespace tail $this] 0 -minsize $height -weight 0
|
||||
grid rowconfigure [namespace tail $this].iframe 0 -minsize $height -weight 0
|
||||
_layout
|
||||
}
|
||||
|
||||
# Re-layout according to the anchor. Private method.
|
||||
method _layout {} {
|
||||
if {$_widget == "" || ! [winfo exists $_widget]} then {
|
||||
return
|
||||
}
|
||||
|
||||
switch -- $anchor {
|
||||
n {
|
||||
# Put the label over the border, in the center.
|
||||
place $_widget -in [namespace tail $this].iframe -relx 0.5 -rely 0 -y -2 \
|
||||
-anchor center
|
||||
}
|
||||
nw {
|
||||
# Put the label over the border, at the top left.
|
||||
place $_widget -in [namespace tail $this].iframe -relx 0 -x 6 -rely 0 -y -2 \
|
||||
-anchor w
|
||||
}
|
||||
default {
|
||||
error "unsupported anchor \"$anchor\""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
# wingrab.tcl -- grab support for Windows.
|
||||
# Copyright (C) 1997 Cygnus Solutions.
|
||||
# Written by Ian Lance Taylor <ian@cygnus.com>.
|
||||
|
||||
# Disable a list of windows.
|
||||
|
||||
proc WINGRAB_disable { args } {
|
||||
foreach w $args {
|
||||
ide_grab_support_disable [wm frame $w]
|
||||
}
|
||||
}
|
||||
|
||||
# Disable all top level windows, other than the argument, which are
|
||||
# children of `.'. Note that if you do this, and then destroy the
|
||||
# frame of the only enabled window, your application will lose the
|
||||
# input focus to some other application. Make sure that you reenable
|
||||
# the windows before calling wm transient or wm withdraw or destroy on
|
||||
# the only enabled window.
|
||||
|
||||
proc WINGRAB_disable_except { window } {
|
||||
foreach w [winfo children .] {
|
||||
if {$w != $window} then {
|
||||
ide_grab_support_disable [wm frame [winfo toplevel $w]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Enable a list of windows.
|
||||
|
||||
proc WINGRAB_enable { args } {
|
||||
foreach w $args {
|
||||
ide_grab_support_enable [wm frame $w]
|
||||
}
|
||||
}
|
||||
|
||||
# Enable all top level windows which are children of `.'.
|
||||
|
||||
proc WINGRAB_enable_all {} {
|
||||
foreach w [winfo children .] {
|
||||
ide_grab_support_enable [wm frame [winfo toplevel $w]]
|
||||
}
|
||||
}
|
||||
|
||||
# The basic routine. All commands are subcommands of this.
|
||||
|
||||
proc ide_grab_support {dispatch args} {
|
||||
global tcl_platform
|
||||
|
||||
if {[info commands WINGRAB_$dispatch] == ""} then {
|
||||
error "unrecognized key \"$dispatch\""
|
||||
}
|
||||
|
||||
# We only need to do stuff on Windows.
|
||||
if {$tcl_platform(platform) != "windows"} then {
|
||||
return
|
||||
}
|
||||
|
||||
eval WINGRAB_$dispatch $args
|
||||
}
|
Reference in a new issue