source: trunk/gui/scripts/balloon.tcl @ 95

Last change on this file since 95 was 52, checked in by mmc, 19 years ago
  • Added a back door so we can debug Rappture applications running in the nanoHUB environment.
  • Added format and label controls to the axes of an XY plot.
  • Added a <molecule><about><emblems> directive, a boolean control indicating whether or not the molecule viewer should show the atom labels by default. If missing or "off", the labels are turned off. To turn labels on by default, this must be set to a boolean true value.
  • Fixed the packing bug that was causing tabbed notebooks to be the wrong size (size of last page, rather than max overall size).
  • Added -state option to comboboxes, so they can be disabled.
  • Added a grab stack, so that when a balloon dialog has the grab and a combobox steals it away, the balloon gets it back.
File size: 14.8 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: Balloon - toplevel popup window, like a cartoon balloon
3#
4#  This widget is used as a container for pop-up panels in Rappture.
5#  If shape extensions are supported, then the window is drawn as
6#  a cartoon balloon.  Otherwise, it is a raised panel, with a little
7#  line connecting it to the widget that brought it up.  When active,
8#  the panel has a global grab and focus, so the user must interact
9#  with it or dismiss it.
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2005
13#  Purdue Research Foundation, West Lafayette, IN
14# ======================================================================
15package require Itk
16
17namespace eval Rappture { # forward declaration }
18
19option add *Balloon.stemLength 16 widgetDefault
20
21itcl::class Rappture::Balloon {
22    inherit itk::Toplevel
23
24    itk_option define -stemlength stemLength StemLength 20
25    itk_option define -deactivatecommand deactivateCommand DeactivateCommand ""
26
27    constructor {args} { # defined below }
28
29    public method activate {where placement}
30    public method deactivate {}
31
32    protected method _createStems {}
33
34    protected variable _stems   ;# windows for cartoon balloon stems
35    protected variable _masks   ;# masks for cartoon balloon stems
36    protected variable _fills   ;# lines for cartoon balloon stems
37
38    public proc outside {widget x y}
39
40    bind RapptureBalloon <ButtonPress> \
41        {if {[Rappture::Balloon::outside %W %X %Y]} {%W deactivate}}
42}
43
44itk::usual Balloon {
45}
46
47# ----------------------------------------------------------------------
48# CONSTRUCTOR
49# ----------------------------------------------------------------------
50itcl::body Rappture::Balloon::constructor {args} {
51    wm overrideredirect $itk_component(hull) yes
52    wm withdraw $itk_component(hull)
53    component hull configure -borderwidth 1 -relief solid
54
55    itk_component add inner {
56        frame $itk_interior.inner -borderwidth 2 -relief raised
57    }
58    pack $itk_component(inner) -expand yes -fill both
59
60    # add bindings to release the grab
61    set btags [bindtags $itk_component(hull)]
62    bindtags $itk_component(hull) [linsert $btags 1 RapptureBalloon]
63
64    eval itk_initialize $args
65
66    _createStems
67}
68
69# ----------------------------------------------------------------------
70# USAGE: activate <where> <placement>
71#
72# Clients use this to pop up this balloon panel pointing to the
73# <where> location, which should be a widget name or @X,Y.  The
74# <placement> indicates whether the panel should be left, right,
75# above, or below the <where> coordinate.
76# ----------------------------------------------------------------------
77itcl::body Rappture::Balloon::activate {where placement} {
78    if {![info exists _stems($placement)]} {
79        error "bad placement \"$placement\": should be [join [lsort [array names _stems]] {, }]"
80    }
81    set s $_stems($placement)
82    set sw [image width $_fills($placement)]
83    set sh [image height $_fills($placement)]
84    set p $itk_component(hull)
85
86    if {[winfo exists $where]} {
87        set x [expr {[winfo rootx $where]+[winfo width $where]/2}]
88        set y [expr {[winfo rooty $where]+[winfo height $where]/2}]
89        switch -- $placement {
90            left { set x [expr {[winfo rootx $where]+5}] }
91            right { set x [expr {[winfo rootx $where]+[winfo width $where]-5}] }
92            above { set y [expr {[winfo rooty $where]+5}] }
93            below { set y [expr {[winfo rooty $where]+[winfo height $where]-5}] }
94        }
95    } elseif {[regexp {^@([0-9]+),([0-9]+)$} $where match x y]} {
96        # got x and y
97    } else {
98        error "bad location \"$where\": should be widget or @x,y"
99    }
100
101    # if the panel is already up, take it down
102    deactivate
103
104    switch -- $placement {
105        left {
106            set sx [expr {$x-$sw+3}]
107            set sy [expr {$y-$sh/2}]
108            set px [expr {$sx-[winfo reqwidth $p]+3}]
109            set py [expr {$y-[winfo reqheight $p]/2}]
110        }
111        right {
112            set sx $x
113            set sy [expr {$y-$sh/2}]
114            set px [expr {$x+$sw-3}]
115            set py [expr {$y-[winfo reqheight $p]/2}]
116        }
117        above {
118            set sx [expr {$x-$sw/2}]
119            set sy [expr {$y-$sh+3}]
120            set px [expr {$x-[winfo reqwidth $p]/2}]
121            set py [expr {$sy-[winfo reqheight $p]+3}]
122        }
123        below {
124            set sx [expr {$x-$sw/2}]
125            set sy $y
126            set px [expr {$x-[winfo reqwidth $p]/2}]
127            set py [expr {$y+$sh-3}]
128        }
129    }
130    if {[info exists _masks($placement)]} {
131        shape set $s -bound photo $_masks($placement)
132    }
133
134    wm geometry $p +$px+$py
135    wm deiconify $p
136    raise $p
137
138    wm geometry $s +$sx+$sy
139    wm deiconify $s
140    raise $s
141
142    # grab the mouse pointer
143    update
144    while {[catch {grab set -global $itk_component(hull)}]} {
145        after 100
146    }
147    focus $itk_component(hull)
148}
149
150# ----------------------------------------------------------------------
151# USAGE: deactivate
152#
153# Clients use this to take down the balloon panel if it is on screen.
154# ----------------------------------------------------------------------
155itcl::body Rappture::Balloon::deactivate {} {
156    if {[string length $itk_option(-deactivatecommand)] > 0} {
157        uplevel #0 $itk_option(-deactivatecommand)
158    }
159
160    grab release $itk_component(hull)
161
162    wm withdraw $itk_component(hull)
163    foreach dir {left right above below} {
164        wm withdraw $_stems($dir)
165    }
166}
167
168# ----------------------------------------------------------------------
169# USAGE: _createStems
170#
171# Used internally to create the stems that connect a balloon panel
172# to its anchor point, in all four possible directions:  left, right,
173# above, and below.
174# ----------------------------------------------------------------------
175itcl::body Rappture::Balloon::_createStems {} {
176    # destroy any existing stems
177    foreach dir [array names _stems] {
178        destroy $_stems($dir)
179        unset _stems($dir)
180    }
181    foreach dir [array names _masks] {
182        image delete $_masks($dir)
183        unset _masks($dir)
184    }
185    foreach dir [array names _fills] {
186        image delete $_fills($dir)
187        unset _fills($dir)
188    }
189
190    if {[catch {package require Shape}] == 0} {
191        #
192        # We have the Shape extension.  Use it to create nice
193        # looking (triangle-shaped) stems.
194        #
195        set s $itk_option(-stemlength)
196        foreach dir {left right above below} {
197            switch -- $dir {
198                left - right {
199                    set sw [expr {$s+2}]
200                    set sh $s
201                }
202                above - below {
203                    set sw $s
204                    set sh [expr {$s+2}]
205                }
206            }
207
208            set _stems($dir) [toplevel $itk_interior.s$dir -borderwidth 0]
209            label $_stems($dir).l \
210                -width $sw -height $sh -borderwidth 0
211            pack $_stems($dir).l -expand yes -fill both
212
213            wm withdraw $_stems($dir)
214            wm overrideredirect $_stems($dir) yes
215
216            #
217            # Draw the triangle part of the stem, with a black outline
218            # and light/dark highlights:
219            #
220            #     --------  ---       LEFT STEM
221            #    |..##    |  ^ 
222            #    |  ..##  |  |        . = light color
223            #    |    ..##|  | s      @ = dark color
224            #    |    @@##|  |        # = black
225            #    |  @@##  |  |
226            #    |@@##    |  v
227            #     --------  ---
228            #    |<------>|
229            #        s+2
230            #
231            set _masks($dir) [image create photo -width $sw -height $sh]
232            set _fills($dir) [image create photo -width $sw -height $sh]
233
234            set bg $itk_option(-background)
235            set light [Rappture::color::brightness $bg 0.4]
236            set dark [Rappture::color::brightness $bg -0.4]
237
238            $_fills($dir) put $bg -to 0 0 $sw $sh
239
240            switch -- $dir {
241              left {
242                set i 0
243                for {set j 0} {$j < $s/2} {incr j} {
244                    set ybtm [expr {$s-$j-1}]
245                    $_fills($dir) put $dark \
246                        -to $i [expr {$ybtm-1}] [expr {$i+2}] [expr {$ybtm+1}]
247                    $_fills($dir) put black \
248                        -to [expr {$i+2}] $ybtm [expr {$i+4}] [expr {$ybtm+1}]
249
250                    set ytop $j
251                    set ytoffs [expr {($j == $s/2-1) ? 1 : 2}]
252                    $_fills($dir) put $light \
253                        -to $i $ytop [expr {$i+2}] [expr {$ytop+$ytoffs}]
254                    $_fills($dir) put black \
255                        -to [expr {$i+2}] $ytop [expr {$i+4}] [expr {$ytop+1}]
256                    incr i 2
257                }
258                $_stems($dir).l configure -image $_fills($dir)
259
260                $_masks($dir) put black -to 0 0 $sw $sh
261                set i 0
262                for {set j 0} {$j < $s/2} {incr j} {
263                    for {set k [expr {$i+4}]} {$k < $s+2} {incr k} {
264                        $_masks($dir) transparency set $k $j yes
265                        $_masks($dir) transparency set $k [expr {$s-$j-1}] yes
266                    }
267                    incr i 2
268                }
269              }
270              right {
271                set i $sw
272                for {set j 0} {$j < $s/2} {incr j} {
273                    set ybtm [expr {$s-$j-1}]
274                    $_fills($dir) put $dark \
275                        -to [expr {$i-2}] [expr {$ybtm-1}] $i [expr {$ybtm+1}]
276                    $_fills($dir) put black \
277                        -to [expr {$i-4}] $ybtm [expr {$i-2}] [expr {$ybtm+1}]
278
279                    set ytop $j
280                    set ytoffs [expr {($j == $s/2-1) ? 1 : 2}]
281                    $_fills($dir) put $light \
282                        -to [expr {$i-2}] $ytop $i [expr {$ytop+$ytoffs}]
283                    $_fills($dir) put black \
284                        -to [expr {$i-4}] $ytop [expr {$i-2}] [expr {$ytop+1}]
285                    incr i -2
286                }
287                $_stems($dir).l configure -image $_fills($dir)
288
289                $_masks($dir) put black -to 0 0 $sw $sh
290                set i $sw
291                for {set j 0} {$j < $s/2} {incr j} {
292                    for {set k 0} {$k < $i-4} {incr k} {
293                        $_masks($dir) transparency set $k $j yes
294                        $_masks($dir) transparency set $k [expr {$s-$j-1}] yes
295                    }
296                    incr i -2
297                }
298              }
299              above {
300                set i 0
301                for {set j 0} {$j < $s/2} {incr j} {
302                    set xrhs [expr {$s-$j-1}]
303                    $_fills($dir) put $dark \
304                        -to [expr {$xrhs-1}] $i [expr {$xrhs+1}] [expr {$i+2}]
305                    $_fills($dir) put black \
306                        -to $xrhs [expr {$i+2}] [expr {$xrhs+1}] [expr {$i+4}]
307
308                    set xlhs $j
309                    set xloffs [expr {($j == $s/2-1) ? 1 : 2}]
310                    $_fills($dir) put $light \
311                        -to $xlhs $i [expr {$xlhs+$xloffs}] [expr {$i+2}]
312                    $_fills($dir) put black \
313                        -to $xlhs [expr {$i+2}] [expr {$xlhs+1}] [expr {$i+4}]
314                    incr i 2
315                }
316                $_stems($dir).l configure -image $_fills($dir)
317
318                $_masks($dir) put black -to 0 0 $sw $sh
319                set i 0
320                for {set j 0} {$j < $s/2} {incr j} {
321                    for {set k [expr {$i+4}]} {$k < $s+2} {incr k} {
322                        $_masks($dir) transparency set $j $k yes
323                        $_masks($dir) transparency set [expr {$s-$j-1}] $k yes
324                    }
325                    incr i 2
326                }
327              }
328              below {
329                set i $sh
330                for {set j 0} {$j < $s/2} {incr j} {
331                    set xrhs [expr {$s-$j-1}]
332                    $_fills($dir) put $dark \
333                        -to [expr {$xrhs-1}] [expr {$i-2}] [expr {$xrhs+1}] $i
334                    $_fills($dir) put black \
335                        -to $xrhs [expr {$i-4}] [expr {$xrhs+1}] [expr {$i-2}]
336
337                    set xlhs $j
338                    set xloffs [expr {($j == $s/2-1) ? 1 : 2}]
339                    $_fills($dir) put $light \
340                        -to $xlhs [expr {$i-2}] [expr {$xlhs+$xloffs}] $i
341                    $_fills($dir) put black \
342                        -to $xlhs [expr {$i-4}] [expr {$xlhs+1}] [expr {$i-2}]
343                    incr i -2
344                }
345                $_stems($dir).l configure -image $_fills($dir)
346
347                $_masks($dir) put black -to 0 0 $sw $sh
348                set i $sh
349                for {set j 0} {$j < $s/2} {incr j} {
350                    for {set k 0} {$k < $i-4} {incr k} {
351                        $_masks($dir) transparency set $j $k yes
352                        $_masks($dir) transparency set [expr {$s-$j-1}] $k yes
353                    }
354                    incr i -2
355                }
356              }
357            }
358        }
359    } else {
360        #
361        # No shape extension.  Do the best we can by creating a
362        # black line for all directions.
363        #
364        foreach {dir w h} [list \
365            left   $itk_option(-stemlength) 3 \
366            right  $itk_option(-stemlength) 3 \
367            above  3 $itk_option(-stemlength) \
368            below  3 $itk_option(-stemlength) \
369        ] {
370            set _stems($dir) [toplevel $itk_interior.s$dir \
371                -width $w -height $h \
372                -borderwidth 1 -relief solid -background black]
373            wm withdraw $_stems($dir)
374            wm overrideredirect $_stems($dir) yes
375
376            # create this for size, even though we don't really use it
377            set _fills($dir) [image create photo -width $w -height $h]
378        }
379    }
380}
381
382# ----------------------------------------------------------------------
383# USAGE: outside <widget> <x> <y>
384#
385# Used internally to see if the click point <x>,<y> is outside of
386# this widget.  If so, the widget usually releases is grab and
387# deactivates.
388# ----------------------------------------------------------------------
389itcl::body Rappture::Balloon::outside {widget x y} {
390    return [expr {$x < [winfo rootx $widget]
391             || $x > [winfo rootx $widget]+[winfo width $widget]
392             || $y < [winfo rooty $widget]
393             || $y > [winfo rooty $widget]+[winfo height $widget]}]
394}
395
396# ----------------------------------------------------------------------
397# CONFIGURATION OPTION: -stemlength
398#
399# Used internally to create the stems that connect a balloon panel
400# to its anchor point, in all four possible directions:  left, right,
401# above, and below.
402# ----------------------------------------------------------------------
403itcl::configbody Rappture::Balloon::stemlength {
404    if {$itk_option(-stemlength) % 2 != 0} {
405        error "stem length should be an even number of pixels"
406    }
407}
Note: See TracBrowser for help on using the repository browser.