2 ## Balloon Help Routines
5 ## Initiated: 28 October 1996
8 ##------------------------------------------------------------------------
13 ## Implements a balloon help system
16 ## balloonhelp <option> ?arg?
19 ## Stops the specified widgets (defaults to all) from showing balloon
23 ## Query or set the delay. The delay is in milliseconds and must
24 ## be at least 50. Returns the delay.
27 ## Disables all balloon help.
30 ## Enables balloon help for defined widgets.
32 ## <widget> ?-index index? ?message?
33 ## If -index is specified, then <widget> is assumed to be a menu
34 ## and the index represents what index into the menu (either the
35 ## numerical index or the label) to associate the balloon help
36 ## message with. If message is {}, then the balloon help for that
37 ## widget is removed. The widget must exist prior to calling
38 ## balloonhelp. The current balloon help message for <widget> is
41 ## RETURNS: varies (see methods above)
44 ## The global array BalloonHelp is used. Procs begin with BalloonHelp.
45 ## The overrideredirected toplevel is named $BalloonHelp(TOPLEVEL).
48 ## balloonhelp .button "A Button"
49 ## balloonhelp .menu -index "Load" "Loads a file"
51 ##------------------------------------------------------------------------
53 ## An alternative to binding to all would be to bind to BalloonHelp
54 ## and add that to the bindtags of each widget registered.
56 ## The extra :hide call in <Enter> is necessary to catch moving to
57 ## child widgets where the <Leave> event won't be generated
60 set BalloonHelp(LAST) -1
61 if {$BalloonHelp(enabled) && [info exists BalloonHelp(%W)]} {
62 set BalloonHelp(AFTERID) [after $BalloonHelp(DELAY) \
63 [list BalloonHelp:show %W $BalloonHelp(%W)]]
66 bind BalloonsMenu <Any-Motion> {
67 if {$BalloonHelp(enabled)} {
68 set cur [%W index active]
69 if {$cur == $BalloonHelp(LAST)} return
70 set BalloonHelp(LAST) $cur
72 if {[info exists BalloonHelp(%W,$cur)] || \
73 (![catch {%W entrycget $cur -label} cur] && \
74 [info exists BalloonHelp(%W,$cur)])} {
75 set BalloonHelp(AFTERID) [after $BalloonHelp(DELAY) \
76 [list BalloonHelp:show %W $BalloonHelp(%W,$cur) $cur]]
80 bind all <Leave> { BalloonHelp:hide }
81 bind Balloons <Any-KeyPress> { BalloonHelp:hide }
82 bind Balloons <Any-Button> { BalloonHelp:hide }
83 array set BalloonHelp {
88 TOPLEVEL .__balloonhelp__
91 proc balloonhelp {w args} {
95 if {[llength $args]==0} { set args .* }
96 BalloonHelp:clear $args
99 if {[llength $args]} {
100 if {![regexp {^[0-9]+$} $args] || $args<50} {
101 return -code error "BalloonHelp delay must be an\
102 integer greater than 50 (delay is in millisecs)"
104 return [set BalloonHelp(DELAY) $args]
106 return $BalloonHelp(DELAY)
110 set BalloonHelp(enabled) 0
114 set BalloonHelp(enabled) 1
117 if {[llength $args]} {
118 set i [uplevel BalloonHelp:register $w $args]
120 set b $BalloonHelp(TOPLEVEL)
121 if {![winfo exists $b]} {
123 wm overrideredirect $b 1
124 wm positionfrom $b program
126 pack [label $b.l -highlightthickness 0 -relief raised -bd 1 \
129 if {[info exists BalloonHelp($i)]} { return $BalloonHelp($i) }
134 ;proc BalloonHelp:register {w args} {
136 set key [lindex $args 0]
137 while {[string match -* $key]} {
140 if {[catch {$w entrycget 1 -label}]} {
141 return -code error "widget \"$w\" does not seem to be a\
142 menu, which is required for the -index switch"
144 set index [lindex $args 1]
145 set args [lreplace $args 0 1]
148 return -code error "unknown option \"$key\": should be -index"
151 set key [lindex $args 0]
153 if {[llength $args] != 1} {
154 return -code error "wrong \# args: should be \"balloonhelp widget\
155 ?-index index? message\""
157 if {[string match {} $key]} {
160 if {![winfo exists $w]} {
161 return -code error "bad window path name \"$w\""
163 if {[info exists index]} {
164 set BalloonHelp($w,$index) $key
165 bindtags $w [linsert [bindtags $w] end BalloonsMenu]
168 set BalloonHelp($w) $key
169 bindtags $w [linsert [bindtags $w] end Balloons]
175 ;proc BalloonHelp:clear {{pattern .*}} {
177 foreach w [array names BalloonHelp $pattern] {
178 unset BalloonHelp($w)
179 if {[winfo exists $w]} {
180 set tags [bindtags $w]
181 if {[set i [lsearch $tags Balloons]] != -1} {
182 bindtags $w [lreplace $tags $i $i]
184 ## We don't remove BalloonsMenu because there
185 ## might be other indices that use it
190 ;proc BalloonHelp:show {w msg {i {}}} {
191 if {![winfo exists $w] || [string compare \
192 $w [eval winfo containing [winfo pointerxy $w]]]} return
195 set b $BalloonHelp(TOPLEVEL)
196 $b.l configure -text $msg
198 if {[string compare {} $i]} {
199 set y [expr [winfo rooty $w]+[$w yposition $i]+25]
200 if {($y+[winfo reqheight $b])>[winfo screenheight $w]} {
201 set y [expr [winfo rooty $w]+[$w yposition $i]-\
202 [winfo reqheight $b]-5]
205 set y [expr [winfo rooty $w]+[winfo height $w]+5]
206 if {($y+[winfo reqheight $b])>[winfo screenheight $w]} {
207 set y [expr [winfo rooty $w]-[winfo reqheight $b]-5]
210 set x [expr [winfo rootx $w]+([winfo width $w]-[winfo reqwidth $b])/2]
213 } elseif {($x+[winfo reqwidth $b])>[winfo screenwidth $w]} {
214 set x [expr [winfo screenwidth $w]-[winfo reqwidth $b]]
216 wm geometry $b +$x+$y
221 ;proc BalloonHelp:hide {args} {
223 after cancel $BalloonHelp(AFTERID)
224 catch {wm withdraw $BalloonHelp(TOPLEVEL)}