source: trunk/gui/scripts/panes.tcl @ 785

Last change on this file since 785 was 785, checked in by mmc, 17 years ago

Added support for a <note> on the output side of an <image> object.
This was needed for app-nsopticsjr. We should experiement a little
more with this, design it properly, and apply the same idea to all
output items.

File size: 13.1 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: Panes - creates a series of adjustable panes
3#
4#  This is a simple paned window with an adjustable sash.
5#  the same quantity, but for various ranges of input values.
6#  It also manages the controls to select and visualize the data.
7# ======================================================================
8#  AUTHOR:  Michael McLennan, Purdue University
9#  Copyright (c) 2004-2005  Purdue Research Foundation
10#
11#  See the file "license.terms" for information on usage and
12#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13# ======================================================================
14package require Itk
15
16option add *Panes.width 3i widgetDefault
17option add *Panes.height 3i widgetDefault
18option add *Panes.sashRelief sunken widgetDefault
19option add *Panes.sashWidth 2 widgetDefault
20option add *Panes.sashPadding 4 widgetDefault
21option add *Panes.sashCursor sb_v_double_arrow
22
23itcl::class Rappture::Panes {
24    inherit itk::Widget
25
26    itk_option define -sashcursor sashCursor SashCursor ""
27    itk_option define -sashrelief sashRelief SashRelief ""
28    itk_option define -sashwidth sashWidth SashWidth 0
29    itk_option define -sashpadding sashPadding SashPadding 0
30
31    constructor {args} { # defined below }
32
33    public method insert {pos args}
34    public method pane {pos}
35    public method visibility {pos {newval ""}}
36    public method fraction {pos {newval ""}}
37    public method hilite {state sash}
38
39    protected method _grab {pane X Y}
40    protected method _drag {pane X Y}
41    protected method _drop {pane X Y}
42    protected method _fixLayout {args}
43    protected method _fixSashes {args}
44
45    private variable _dispatcher ""  ;# dispatcher for !events
46    private variable _panes ""       ;# list of pane frames
47    private variable _visibility ""  ;# list of visibilities for panes
48    private variable _counter 0      ;# counter for auto-generated names
49    private variable _frac 0.0       ;# list of fractions
50}
51
52itk::usual Panes {
53    keep -background -cursor
54}
55
56# ----------------------------------------------------------------------
57# CONSTRUCTOR
58# ----------------------------------------------------------------------
59itcl::body Rappture::Panes::constructor {args} {
60    itk_option add hull.width hull.height
61
62    # create a dispatcher for events
63    Rappture::dispatcher _dispatcher
64    $_dispatcher register !layout
65    $_dispatcher dispatch $this !layout [itcl::code $this _fixLayout]
66    $_dispatcher register !sashes
67    $_dispatcher dispatch $this !sashes [itcl::code $this _fixSashes]
68
69    # fix the layout whenever the window size changes
70    bind Panes <Configure> [itcl::code %W _fixLayout]
71
72    set pname "pane[incr _counter]"
73    itk_component add $pname {
74        frame $itk_interior.$pname
75    }
76
77    lappend _panes $pname
78    lappend _visibility 1
79    set _frac 0.5
80
81    eval itk_initialize $args
82
83    # make sure we fix up the layout at some point
84    $_dispatcher event -idle !layout
85}
86
87# ----------------------------------------------------------------------
88# USAGE: insert <pos> ?-fraction f?
89#
90# Adds a new page to this widget at the given position <pos>.
91# ----------------------------------------------------------------------
92itcl::body Rappture::Panes::insert {pos args} {
93    Rappture::getopts args params {
94        value -fraction 0.5
95    }
96    if {[llength $args] > 0} {
97        error "wrong # args: should be \"insert pos ?-fraction f?\""
98    }
99
100    set pname "pane[incr _counter]"
101    set sash "${pname}sash"
102    itk_component add $sash {
103        frame $itk_interior.$sash
104    } {
105        usual
106        rename -cursor -sashcursor sashCursor SashCursor
107    }
108    bind $itk_component($sash) <Enter> [itcl::code $this hilite on $sash]
109    bind $itk_component($sash) <Leave> [itcl::code $this hilite off $sash]
110
111    itk_component add ${sash}ridge {
112        frame $itk_component($sash).ridge
113    } {
114        usual
115        rename -cursor -sashcursor sashCursor SashCursor
116        rename -relief -sashrelief sashRelief SashRelief
117        ignore -borderwidth
118    }
119    pack $itk_component(${sash}ridge) -fill x
120
121    foreach comp [list $sash ${sash}ridge] {
122        bind $itk_component($comp) <ButtonPress-1> \
123            [itcl::code $this _grab $pname %X %Y]
124        bind $itk_component($comp) <B1-Motion> \
125            [itcl::code $this _drag $pname %X %Y]
126        bind $itk_component($comp) <ButtonRelease-1> \
127            [itcl::code $this _drop $pname %X %Y]
128    }
129
130
131    itk_component add $pname {
132        frame $itk_interior.$pname
133    }
134    set _panes [linsert $_panes $pos $pname]
135    set _visibility [linsert $_visibility $pos 1]
136    set _frac [linsert $_frac $pos $params(-fraction)]
137
138    # fix sash characteristics
139    $_dispatcher event -idle !sashes
140
141    # make sure we fix up the layout at some point
142    $_dispatcher event -idle !layout
143
144    return $itk_component($pname)
145}
146
147# ----------------------------------------------------------------------
148# USAGE: pane <pos>
149#
150# Returns the frame representing the pane at position <pos>.
151# ----------------------------------------------------------------------
152itcl::body Rappture::Panes::pane {pos} {
153    set pname [lindex $_panes $pos]
154    if {[info exists itk_component($pname)]} {
155        return $itk_component($pname)
156    }
157    return ""
158}
159
160# ----------------------------------------------------------------------
161# USAGE: visibility <pos> ?<newval>?
162#
163# Clients use this to get/set the visibility of the pane at position
164# <pos>.
165# ----------------------------------------------------------------------
166itcl::body Rappture::Panes::visibility {pos {newval ""}} {
167    if {"" == $newval} {
168        return [lindex $_visibility $pos]
169    }
170    if {![string is boolean $newval]} {
171        error "bad value \"$newval\": should be boolean"
172    }
173    if {$pos == "end" || ($pos >= 0 && $pos < [llength $_visibility])} {
174        set _visibility [lreplace $_visibility $pos $pos [expr {$newval}]]
175        $_dispatcher event -idle !layout
176    } else {
177        error "bad index \"$pos\": out of range"
178    }
179}
180
181# ----------------------------------------------------------------------
182# USAGE: fraction <pos> ?<newval>?
183#
184# Clients use this to get/set the fraction of real estate associated
185# with the pane at position <pos>.
186# ----------------------------------------------------------------------
187itcl::body Rappture::Panes::fraction {pos {newval ""}} {
188    if {"" == $newval} {
189        return [lindex $_frac $pos]
190    }
191    if {![string is double $newval]} {
192        error "bad value \"$newval\": should be fraction 0-1"
193    }
194    if {$pos == "end" || ($pos >= 0 && $pos < [llength $_frac])} {
195        set len [llength $_frac]
196        set _frac [lreplace $_frac $pos $pos xxx]
197        set total 0
198        foreach f $_frac {
199            if {"xxx" != $f} {
200                set total [expr {$total+$f}]
201            }
202        }
203        for {set i 0} {$i < $len} {incr i} {
204            set f [lindex $_frac $i]
205            if {"xxx" == $f} {
206                set f $newval
207            } else {
208                set f [expr {$f/$total - $newval/double($len-1)}]
209            }
210            set _frac [lreplace $_frac $i $i $f]
211        }
212        $_dispatcher event -idle !layout
213    } else {
214        error "bad index \"$pos\": out of range"
215    }
216}
217
218# ----------------------------------------------------------------------
219# USAGE: hilite <state> <sash>
220#
221# Invoked automatically whenever the user touches a sash.  Highlights
222# the sash by changing its size or relief.
223# ----------------------------------------------------------------------
224itcl::body Rappture::Panes::hilite {state sash} {
225    switch -- $itk_option(-sashrelief) {
226      sunken {
227        if {$state} {
228            $itk_component(${sash}ridge) configure -relief raised
229        } else {
230            $itk_component(${sash}ridge) configure -relief sunken
231        }
232      }
233      raised {
234        if {$state} {
235            $itk_component(${sash}ridge) configure -relief sunken
236        } else {
237            $itk_component(${sash}ridge) configure -relief raised
238        }
239      }
240      solid {
241        if {$state} {
242            $itk_component($sash) configure -background black
243        } else {
244            $itk_component($sash) configure \
245                -background $itk_option(-background)
246        }
247      }
248    }
249}
250
251# ----------------------------------------------------------------------
252# USAGE: _grab <pane> <X> <Y>
253#
254# Invoked automatically when the user clicks on a sash, to initiate
255# movement.
256# ----------------------------------------------------------------------
257itcl::body Rappture::Panes::_grab {pname X Y} {
258}
259
260# ----------------------------------------------------------------------
261# USAGE: _drag <pane> <X> <Y>
262#
263# Invoked automatically as the user drags a sash, to resize the panes.
264# ----------------------------------------------------------------------
265itcl::body Rappture::Panes::_drag {pname X Y} {
266    set realY [expr {$Y-[winfo rooty $itk_component(hull)]}]
267    set Ymax  [winfo height $itk_component(hull)]
268    set frac [expr double($realY)/$Ymax]
269    if {$frac < 0.05} {
270        set frac 0.05
271    }
272    if {$frac > 0.95} {
273        set frac 0.95
274    }
275    if {[llength $_frac] == 2} {
276        set _frac [list $frac [expr {1-$frac}]]
277    } else {
278        set i [expr {[lsearch $_panes $pname]-1}]
279        if {$i >= 0} {
280            set _frac [lreplace $_frac $i $i $frac]
281        }
282    }
283    _fixLayout
284
285    return $frac
286}
287
288# ----------------------------------------------------------------------
289# USAGE: _drop <pane> <X> <Y>
290#
291# Invoked automatically as the user drops a sash, to resize the panes.
292# ----------------------------------------------------------------------
293itcl::body Rappture::Panes::_drop {pname X Y} {
294    set frac [_drag $pname $X $Y]
295}
296
297# ----------------------------------------------------------------------
298# USAGE: _fixLayout ?<eventArgs>...?
299#
300# Used internally to update the layout of panes whenever a new pane
301# is added or a sash is moved.
302# ----------------------------------------------------------------------
303itcl::body Rappture::Panes::_fixLayout {args} {
304    set h [winfo height $itk_component(hull)]
305
306    set plist ""
307    set flist ""
308    foreach p $_panes f $_frac v $_visibility {
309        set sash ${p}sash
310        if {$v} {
311            # this pane is visible -- make room for it
312            lappend plist $p
313            lappend flist $f
314            if {[info exists itk_component($sash)]} {
315                set h [expr {$h - [winfo height $itk_component($sash)]}]
316            }
317        } else {
318            # this pane is not visible -- remove sash
319            if {[info exists itk_component($sash)]} {
320                place forget $itk_component($sash)
321            }
322            place forget $itk_component($p)
323        }
324    }
325
326    # normalize the fractions so they add up to 1
327    set total 0
328    foreach f $flist { set total [expr {$total+$f}] }
329    set newflist ""
330    foreach f $flist {
331        lappend newflist [expr {double($f)/$total}]
332    }
333    set flist $newflist
334
335    # lay out the various panes
336    set y 0
337    foreach p $plist f $flist {
338        set sash ${p}sash
339        if {[info exists itk_component($sash)]} {
340            set sh [winfo reqheight $itk_component($sash)]
341            place $itk_component($sash) -y $y -relx 0.5 -anchor n \
342                -relwidth 1.0 -height $sh
343            set y [expr {$y + $sh}]
344        }
345
346        set ph [expr {$h*$f}]
347        place $itk_component($p) -y $y -relx 0.5 -anchor n \
348            -relwidth 1.0 -height $ph
349        set y [expr {$y + $ph}]
350    }
351}
352
353# ----------------------------------------------------------------------
354# USAGE: _fixSashes
355#
356# Used internally to fix the appearance of sashes whenever a new
357# sash appears or the controlling configuration options change.
358# ----------------------------------------------------------------------
359itcl::body Rappture::Panes::_fixSashes {args} {
360    set ht [winfo pixels $itk_component(hull) $itk_option(-sashwidth)]
361    set bd [expr {$ht/2}]
362    foreach pane $_panes {
363        set sash "${pane}sashridge"
364        if {[info exists itk_component($sash)]} {
365            $itk_component($sash) configure -height $ht -borderwidth $bd
366            if {$itk_option(-sashrelief) == "solid"} {
367                $itk_component($sash) configure -background black
368            } else {
369                $itk_component($sash) configure \
370                    -background $itk_option(-background)
371            }
372            pack $itk_component($sash) -pady $itk_option(-sashpadding)
373        }
374    }
375}
376
377# ----------------------------------------------------------------------
378# CONFIGURATION OPTION: -sashrelief
379# ----------------------------------------------------------------------
380itcl::configbody Rappture::Panes::sashrelief {
381    $_dispatcher event -idle !sashes
382}
383
384# ----------------------------------------------------------------------
385# CONFIGURATION OPTION: -sashwidth
386# ----------------------------------------------------------------------
387itcl::configbody Rappture::Panes::sashwidth {
388    $_dispatcher event -idle !sashes
389}
390
391# ----------------------------------------------------------------------
392# CONFIGURATION OPTION: -sashpadding
393# ----------------------------------------------------------------------
394itcl::configbody Rappture::Panes::sashpadding {
395    $_dispatcher event -idle !sashes
396}
Note: See TracBrowser for help on using the repository browser.