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

Last change on this file since 1140 was 1140, checked in by gah, 16 years ago

small fixes to xylegend

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