source: trunk/gui/scripts/scroller.tcl @ 738

Last change on this file since 738 was 464, checked in by mmc, 18 years ago

Added popup options for the "download" button. Right now this works
only for <curve> objects. You can select between CSV and PDF output.
Will add other formats later.

Fixed a few "after cancel" errors that were happening when you switch
between inputs in the structure demo.

Fixed the colors and fonts for the new bug report window.

File size: 12.5 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: scroller - adds scrollbars to any standard Tk widget
3#
4#  This widget provides automatic scrollbars for any standard Tk
5#  widget.  The scrolled widget should be created as a child of this
6#  widget, and is connected by calling the "contents" method.  Calling
7#  contents with the keyword "frame" creates an internal frame that
8#  allows any collection of widgets to be scrolled.
9# ======================================================================
10#  AUTHOR:  Michael McLennan, Purdue University
11#  Copyright (c) 2004-2005  Purdue Research Foundation
12#
13#  See the file "license.terms" for information on usage and
14#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15# ======================================================================
16package require Itk
17
18option add *Scroller.xScrollMode off widgetDefault
19option add *Scroller.yScrollMode auto widgetDefault
20option add *Scroller.width 0 widgetDefault
21option add *Scroller.height 0 widgetDefault
22
23itcl::class Rappture::Scroller {
24    inherit itk::Widget
25
26    itk_option define -xscrollmode xScrollMode XScrollMode ""
27    itk_option define -yscrollmode yScrollMode YScrollMode ""
28    itk_option define -width width Width 0
29    itk_option define -height height Height 0
30
31    constructor {args} { # defined below }
32    destructor { # defined below }
33
34    public method contents {{frame "!@#query"}}
35
36    protected method _widget2sbar {which args}
37    protected method _fixsbar {which {state ""}}
38    protected method _fixframe {which}
39    protected method _fixsize {}
40    protected method _lock {option which}
41
42    private variable _dispatcher "" ;# dispatcher for !events
43    private variable _contents ""   ;# widget being controlled
44    private variable _frame ""      ;# for "contents frame" calls
45    private variable _lock          ;# for _lock on x/y scrollbar
46}
47                                                                               
48itk::usual Scroller {
49    keep -background -activebackground -activerelief
50    keep -cursor
51    keep -highlightcolor -highlightthickness
52    keep -troughcolor
53}
54
55# ----------------------------------------------------------------------
56# CONSTRUCTOR
57# ----------------------------------------------------------------------
58itcl::body Rappture::Scroller::constructor {args} {
59    array set _lock { x 0 y 0 }
60
61    Rappture::dispatcher _dispatcher
62
63    $_dispatcher register !fixframe-inner
64    $_dispatcher dispatch $this !fixframe-inner \
65        "[itcl::code $this _fixframe inner]; list"
66
67    $_dispatcher register !fixframe-outer
68    $_dispatcher dispatch $this !fixframe-outer \
69        "[itcl::code $this _fixframe outer]; list"
70
71    $_dispatcher register !fixsize
72    $_dispatcher dispatch $this !fixsize \
73        "[itcl::code $this _fixsize]; list"
74
75    itk_component add xsbar {
76        scrollbar $itk_interior.xsbar -orient horizontal
77    }
78    itk_component add ysbar {
79        scrollbar $itk_interior.ysbar -orient vertical
80    }
81
82    # we don't fix scrollbars when window is withdrawn, so
83    # fix them whenever a window pops up
84    bind $itk_component(hull) <Map> "
85        [itcl::code $this _fixsbar x]
86        [itcl::code $this _fixsbar y]
87    "
88
89    grid rowconfigure $itk_component(hull) 0 -weight 1
90    grid columnconfigure $itk_component(hull) 0 -weight 1
91
92    eval itk_initialize $args
93}
94
95# ----------------------------------------------------------------------
96# DESTRUCTOR
97# ----------------------------------------------------------------------
98itcl::body Rappture::Scroller::destructor {} {
99    after cancel [itcl::code $this _lock reset x]
100    after cancel [itcl::code $this _lock reset y]
101}
102
103# ----------------------------------------------------------------------
104# USAGE: contents ?<widget>|frame?
105#
106# Used to get/set the widget that is being scrolled.  With no args,
107# it returns the name of the widget currently connected to the
108# scrollbars.  Otherwise, the argument specifies a widget to be
109# controlled by the scrollbar.  If the argument is the keyword
110# "frame", then this method creates its own internal frame, which
111# can be packed with other widgets, and returns its name.
112# ----------------------------------------------------------------------
113itcl::body Rappture::Scroller::contents {{widget "!@#query"}} {
114    if {$widget == "!@#query"} {
115        return $_contents
116    }
117
118    #
119    # If the widget is "", then unhook any existing widget.
120    #
121    if {$widget == ""} {
122        if {$_contents != ""} {
123            $_contents configure -xscrollcommand "" -yscrollcommand ""
124            grid forget $_contents
125        }
126        $itk_component(xsbar) configure -command ""
127        $itk_component(ysbar) configure -command ""
128        set _contents ""
129
130        return ""
131    }
132
133    #
134    # For the "frame" keyword, create a canvas that can be scrolled
135    # and return it as the frame being scrolled.
136    #
137    if {$widget == "frame"} {
138        if {$_frame == ""} {
139            set _frame [canvas $itk_component(hull).ifr -highlightthickness 0]
140            frame $_frame.f
141            $_frame create window 0 0 -anchor nw -window $_frame.f -tags frame
142            bind $_frame.f <Configure> \
143                [itcl::code $_dispatcher event -idle !fixframe-inner]
144            bind $_frame <Configure> \
145                [itcl::code $_dispatcher event -idle !fixframe-outer]
146        }
147        set widget $_frame
148    }
149
150    #
151    # Plug the specified widget into the scrollbars for this widget.
152    #
153    contents ""
154    grid $widget -row 0 -column 0 -sticky nsew
155    $widget configure \
156        -xscrollcommand [itcl::code $this _widget2sbar x] \
157        -yscrollcommand [itcl::code $this _widget2sbar y]
158
159    $itk_component(xsbar) configure -command [list $widget xview]
160    $itk_component(ysbar) configure -command [list $widget yview]
161    set _contents $widget
162
163    if {$widget == $_frame} {
164        return $_frame.f
165    }
166    return $widget
167}
168
169# ----------------------------------------------------------------------
170# USAGE: _widget2sbar <which> ?args...?
171#
172# Used internally to handle communication from the widget to the
173# scrollbar.  If the scrollbars are in "auto" mode, this provides a
174# hook where we can fix their display.
175# ----------------------------------------------------------------------
176itcl::body Rappture::Scroller::_widget2sbar {which args} {
177    if {$itk_option(-xscrollmode) == "auto"} {
178        _fixsbar x
179    }
180    if {$itk_option(-yscrollmode) == "auto"} {
181        _fixsbar y
182    }
183    eval $itk_component(${which}sbar) set $args
184}
185
186# ----------------------------------------------------------------------
187# USAGE: _fixsbar <which> ?<state>?
188#
189# Used internally to show/hide the scrollbar in the <which> direction,
190# which is either "x" or "y".  If the scrollbar is "on", then it is
191# always displayed.  If "off", never displayed.  And if "auto", then
192# it is displayed if needed for the current view.
193# ----------------------------------------------------------------------
194itcl::body Rappture::Scroller::_fixsbar {which {state ""}} {
195    if {![winfo ismapped $itk_component(hull)]} {
196        #
197        # If we're not on yet screen, bail out!  This keeps bad
198        # numbers (from an empty or partially constructed widget)
199        # from prematurely influencing the scrollbar.
200        #
201        return
202    }
203
204    if {$state == ""} {
205        switch -- [string tolower $itk_option(-${which}scrollmode)] {
206            on - 1 - true - yes  { set state 1 }
207            off - 0 - false - no { set state 0 }
208            auto {
209                set state 0
210                if {$_contents != ""} {
211                    set lims [$_contents ${which}view]
212                    if {[lindex $lims 0] != 0 || [lindex $lims 1] != 1} {
213                        set state 1
214                    }
215                }
216            }
217            default {
218                set state 0
219            }
220        }
221    }
222
223    # show/hide the scrollbar depending on the desired state
224    switch -- $which {
225        x {
226            if {$state} {
227                if {![_lock active x]} {
228                    grid $itk_component(xsbar) -row 1 -column 0 -sticky ew
229                }
230            } else {
231                grid forget $itk_component(xsbar)
232                _lock set x
233            }
234        }
235        y {
236            if {$state} {
237                if {![_lock active y]} {
238                    grid $itk_component(ysbar) -row 0 -column 1 -sticky ns
239                }
240            } else {
241                grid forget $itk_component(ysbar)
242                _lock set y
243            }
244        }
245    }
246}
247
248# ----------------------------------------------------------------------
249# USAGE: _fixframe <which>
250#
251# Invoked automatically whenever the canvas representing the "frame"
252# keyword is resized.  Updates the scrolling limits for the canvas
253# to the new size.
254# ----------------------------------------------------------------------
255itcl::body Rappture::Scroller::_fixframe {which} {
256    switch -- $which {
257        inner {
258            $_frame configure -scrollregion [$_frame bbox all]
259            $_dispatcher event -idle !fixsize
260        }
261        outer {
262            $_frame itemconfigure frame -width [winfo width $_frame]
263            if {[winfo height $_frame] > [winfo reqheight $_frame.f]} {
264                $_frame itemconfigure frame -height [winfo height $_frame]
265            } else {
266                $_frame itemconfigure frame -height 0
267            }
268        }
269    }
270}
271
272# ----------------------------------------------------------------------
273# USAGE: _fixsize
274#
275# Used internally to update the size options for the widget
276# whenever the -width/-height options change.
277# ----------------------------------------------------------------------
278itcl::body Rappture::Scroller::_fixsize {} {
279    if {$itk_option(-width) == "0" && $itk_option(-height) == "0"} {
280        # for default size, let the frame being controlled set the size
281        grid propagate $itk_component(hull) yes
282        if {$_frame == "$itk_component(hull).ifr"} {
283            set w [winfo reqwidth $_frame.f]
284            set h [winfo reqheight $_frame.f]
285            $_frame configure -width $w -height $h
286        }
287    } else {
288        # for specific size, set the overall size of the widget
289        grid propagate $itk_component(hull) no
290        set w $itk_option(-width); if {$w == "0"} { set w 1i }
291        set h $itk_option(-height); if {$h == "0"} { set h 1i }
292        component hull configure -width $w -height $h
293    }
294}
295
296# ----------------------------------------------------------------------
297# USAGE: _lock set <which>
298# USAGE: _lock reset <which>
299# USAGE: _lock active <which>
300#
301# Used internally to lock out vibrations when the x-scrollbar pops
302# into view.  When the x-scrollbar pops up, it reduces the space
303# available for the widget.  For some widgets (e.g., text widget)
304# this changes the view.  A long line may fall off screen, and the
305# x-scrollbar will no longer be necessary.  If the x-scrollbar just
306# appeared, then its lock is active, signalling that it should stay
307# up.
308# ----------------------------------------------------------------------
309itcl::body Rappture::Scroller::_lock {option which} {
310    switch -- $option {
311        set {
312            set _lock($which) 1
313            after cancel [itcl::code $this _lock reset $which]
314            after 50 [itcl::code $this _lock reset $which]
315        }
316        reset {
317            set _lock($which) 0
318        }
319        active {
320            return $_lock($which)
321        }
322        default {
323            error "bad option \"$option\": should be set, reset, active"
324        }
325    }
326}
327
328# ----------------------------------------------------------------------
329# OPTION: -xscrollmode
330# ----------------------------------------------------------------------
331itcl::configbody Rappture::Scroller::xscrollmode {
332    _fixsbar x
333}
334
335# ----------------------------------------------------------------------
336# OPTION: -yscrollmode
337# ----------------------------------------------------------------------
338itcl::configbody Rappture::Scroller::yscrollmode {
339    _fixsbar y
340}
341
342# ----------------------------------------------------------------------
343# OPTION: -width
344# ----------------------------------------------------------------------
345itcl::configbody Rappture::Scroller::width {
346    # check for proper value
347    winfo pixels $itk_component(hull) $itk_option(-width)
348
349    $_dispatcher event -idle !fixsize
350}
351
352# ----------------------------------------------------------------------
353# OPTION: -height
354# ----------------------------------------------------------------------
355itcl::configbody Rappture::Scroller::height {
356    # check for proper value
357    winfo pixels $itk_component(hull) $itk_option(-height)
358
359    $_dispatcher event -idle !fixsize
360}
Note: See TracBrowser for help on using the repository browser.