1# -----------------------------------------------------------------------------
2#  scrollw.tcl
3#  This file is part of Unifix BWidget Toolkit
4#  $Id: scrollw.tcl,v 1.14 2009/09/06 21:40:13 oberdorfer Exp $
5# -----------------------------------------------------------------------------
6#  Index of commands:
7#     - ScrolledWindow::create
8#     - ScrolledWindow::getframe
9#     - ScrolledWindow::setwidget
10#     - ScrolledWindow::configure
11#     - ScrolledWindow::cget
12#     - ScrolledWindow::_set_hscroll
13#     - ScrolledWindow::_set_vscroll
14#     - ScrolledWindow::_setData
15#     - ScrolledWindow::_realize
16#     - ScrolledWindow::_themechanged
17# -----------------------------------------------------------------------------
18
19namespace eval ScrolledWindow {
20    Widget::define ScrolledWindow scrollw
21
22    Widget::declare ScrolledWindow {
23        {-background  Color      "SystemWindowFrame" 0}
24	{-scrollbar   Enum	 both 0 {none both vertical horizontal}}
25	{-auto	      Enum	 both 0 {none both vertical horizontal}}
26	{-sides	      Enum	 se   0 {ne en nw wn se es sw ws}}
27	{-size	      Int	 0    1 "%d >= 0"}
28	{-ipad	      Int	 1    1 "%d >= 0"}
29	{-managed     Boolean	 1    1}
30	{-relief      TkResource flat 0 frame}
31	{-borderwidth TkResource 0    0 frame}
32	{-bg	      Synonym	 -background}
33	{-bd	      Synonym	 -borderwidth}
34    }
35
36    Widget::addmap ScrolledWindow "" :cmd {-relief {} -borderwidth {}}
37
38    if {[lsearch [bindtags .] ScrolledWindowThemeChanged] < 0} {
39        bindtags . [linsert [bindtags .] 1 ScrolledWindowThemeChanged]
40    }
41}
42
43
44# -----------------------------------------------------------------------------
45#  Command ScrolledWindow::create
46# -----------------------------------------------------------------------------
47proc ScrolledWindow::create { path args } {
48    Widget::init ScrolledWindow $path $args
49
50    Widget::getVariable $path data
51
52    set bg     [Widget::cget $path -background]
53    set sbsize [Widget::cget $path -size]
54    set sw     [eval [list frame $path \
55			  -relief flat -borderwidth 0 -background $bg \
56			  -highlightthickness 0 -takefocus 0] \
57		     [Widget::subcget $path :cmd]]
58
59    if { [BWidget::using ttk] &&
60        ![string equal [tk windowingsystem] "aqua"]} {
61
62        ttk::scrollbar $path.vscroll -orient vertical
63        ttk::scrollbar $path.hscroll -orient horizontal
64
65    } else {
66
67        scrollbar $path.hscroll \
68	    -highlightthickness 0 -takefocus 0 \
69	    -orient	 horiz	\
70	    -relief	 sunken	\
71	    -bg	 $bg
72        scrollbar $path.vscroll \
73	    -highlightthickness 0 -takefocus 0 \
74	    -orient	 vert	\
75	    -relief	 sunken	\
76	    -bg	 $bg
77    }
78
79    set data(realized) 0
80
81    _setData $path \
82	    [Widget::cget $path -scrollbar] \
83	    [Widget::cget $path -auto] \
84	    [Widget::cget $path -sides]
85
86    if {[Widget::cget $path -managed]} {
87	set data(hsb,packed) $data(hsb,present)
88	set data(vsb,packed) $data(vsb,present)
89    } else {
90	set data(hsb,packed) 0
91	set data(vsb,packed) 0
92    }
93
94    if { ![BWidget::using ttk] } {
95        if {$sbsize} {
96	    $path.vscroll configure -width $sbsize
97	    $path.hscroll configure -width $sbsize
98        }
99    }
100    set data(ipad) [Widget::cget $path -ipad]
101
102    if {$data(hsb,packed)} {
103	grid $path.hscroll -column 1 -row $data(hsb,row) \
104		-sticky ew -ipady $data(ipad)
105    }
106    if {$data(vsb,packed)} {
107	grid $path.vscroll -column $data(vsb,column) -row 1 \
108		-sticky ns -ipadx $data(ipad)
109    }
110
111    grid columnconfigure $path 1 -weight 1
112    grid rowconfigure	 $path 1 -weight 1
113
114    bind $path <Configure> [list ScrolledWindow::_realize $path]
115    bind $path <Destroy>   [list ScrolledWindow::_destroy $path]
116
117    bind ScrolledWindowThemeChanged <<ThemeChanged>> \
118	   "+ [namespace current]::_themechanged $path"
119
120    return [Widget::create ScrolledWindow $path]
121}
122
123
124# -----------------------------------------------------------------------------
125#  Command ScrolledWindow::getframe
126# -----------------------------------------------------------------------------
127proc ScrolledWindow::getframe { path } {
128    return $path
129}
130
131
132# -----------------------------------------------------------------------------
133#  Command ScrolledWindow::setwidget
134# -----------------------------------------------------------------------------
135proc ScrolledWindow::setwidget { path widget } {
136    Widget::getVariable $path data
137
138    if {[info exists data(widget)] && [winfo exists $data(widget)]
139	&& ![string equal $data(widget) $widget]} {
140	grid remove $data(widget)
141	$data(widget) configure -xscrollcommand "" -yscrollcommand ""
142    }
143    set data(widget) $widget
144    grid $widget -in $path -row 1 -column 1 -sticky news
145
146    $path.hscroll configure -command [list $widget xview]
147    $path.vscroll configure -command [list $widget yview]
148    $widget configure \
149	    -xscrollcommand [list ScrolledWindow::_set_hscroll $path] \
150	    -yscrollcommand [list ScrolledWindow::_set_vscroll $path]
151}
152
153
154# -----------------------------------------------------------------------------
155#  Command ScrolledWindow::configure
156# -----------------------------------------------------------------------------
157proc ScrolledWindow::configure { path args } {
158    Widget::getVariable $path data
159
160    set res [Widget::configure $path $args]
161    if { [Widget::hasChanged $path -background bg] } {
162	$path:cmd configure -background $bg
163	catch { $path.hscroll configure -background $bg }
164	catch { $path.vscroll configure -background $bg }
165    }
166
167    if {[Widget::hasChanged $path -scrollbar scrollbar] | \
168	    [Widget::hasChanged $path -auto	 auto]	| \
169	    [Widget::hasChanged $path -sides	 sides]} {
170	_setData $path $scrollbar $auto $sides
171	foreach {vmin vmax} [$path.hscroll get] { break }
172	set data(hsb,packed) [expr {$data(hsb,present) && \
173		(!$data(hsb,auto) || ($vmin != 0 || $vmax != 1))}]
174	foreach {vmin vmax} [$path.vscroll get] { break }
175	set data(vsb,packed) [expr {$data(vsb,present) && \
176		(!$data(vsb,auto) || ($vmin != 0 || $vmax != 1))}]
177
178	set data(ipad) [Widget::cget $path -ipad]
179
180	if {$data(hsb,packed)} {
181	    grid $path.hscroll -column 1 -row $data(hsb,row) \
182		-sticky ew -ipady $data(ipad)
183	} else {
184	    if {![info exists data(hlock)]} {
185		set data(hsb,packed) 0
186		grid remove $path.hscroll
187	    }
188	}
189	if {$data(vsb,packed)} {
190	    grid $path.vscroll -column $data(vsb,column) -row 1 \
191		-sticky ns -ipadx $data(ipad)
192	} else {
193	    if {![info exists data(hlock)]} {
194		set data(vsb,packed) 0
195		grid remove $path.vscroll
196	    }
197	}
198    }
199    return $res
200}
201
202
203# -----------------------------------------------------------------------------
204#  Command ScrolledWindow::cget
205# -----------------------------------------------------------------------------
206proc ScrolledWindow::cget { path option } {
207    return [Widget::cget $path $option]
208}
209
210
211# -----------------------------------------------------------------------------
212#  Command ScrolledWindow::_set_hscroll
213# -----------------------------------------------------------------------------
214proc ScrolledWindow::_set_hscroll { path vmin vmax } {
215    Widget::getVariable $path data
216
217    if {$data(realized) && $data(hsb,present)} {
218	if {$data(hsb,auto) && ![info exists data(hlock)]} {
219	    if {$data(hsb,packed) && $vmin == 0 && $vmax == 1} {
220		set data(hsb,packed) 0
221		grid remove $path.hscroll
222		set data(hlock) 1
223		update idletasks
224		unset data(hlock)
225	    } elseif {!$data(hsb,packed) && ($vmin != 0 || $vmax != 1)} {
226		set data(hsb,packed) 1
227		grid $path.hscroll -column 1 -row $data(hsb,row) \
228			-sticky ew -ipady $data(ipad)
229		set data(hlock) 1
230		update idletasks
231		unset data(hlock)
232	    }
233	}
234	$path.hscroll set $vmin $vmax
235    }
236}
237
238
239# -----------------------------------------------------------------------------
240#  Command ScrolledWindow::_set_vscroll
241# -----------------------------------------------------------------------------
242proc ScrolledWindow::_set_vscroll { path vmin vmax } {
243    Widget::getVariable $path data
244
245    if {$data(realized) && $data(vsb,present)} {
246	if {$data(vsb,auto) && ![info exists data(vlock)]} {
247	    if {$data(vsb,packed) && $vmin == 0 && $vmax == 1} {
248		set data(vsb,packed) 0
249		grid remove $path.vscroll
250		set data(vlock) 1
251		update idletasks
252		unset data(vlock)
253	    } elseif {!$data(vsb,packed) && ($vmin != 0 || $vmax != 1) } {
254		set data(vsb,packed) 1
255		grid $path.vscroll -column $data(vsb,column) -row 1 \
256			-sticky ns -ipadx $data(ipad)
257		set data(vlock) 1
258		update idletasks
259		unset data(vlock)
260	    }
261	}
262	$path.vscroll set $vmin $vmax
263    }
264}
265
266
267proc ScrolledWindow::_setData {path scrollbar auto sides} {
268    Widget::getVariable $path data
269
270    set sb    [lsearch {none horizontal vertical both} $scrollbar]
271    set auto  [lsearch {none horizontal vertical both} $auto]
272
273    set data(hsb,present)  [expr {($sb & 1) != 0}]
274    set data(hsb,auto)	   [expr {($auto & 1) != 0}]
275    set data(hsb,row)	   [expr {[string match *n* $sides] ? 0 : 2}]
276
277    set data(vsb,present)  [expr {($sb & 2) != 0}]
278    set data(vsb,auto)	   [expr {($auto & 2) != 0}]
279    set data(vsb,column)   [expr {[string match *w* $sides] ? 0 : 2}]
280}
281
282
283# -----------------------------------------------------------------------------
284#  Command ScrolledWindow::_realize
285# -----------------------------------------------------------------------------
286proc ScrolledWindow::_realize { path } {
287    Widget::getVariable $path data
288
289    bind $path <Configure> {}
290    set data(realized) 1
291}
292
293
294# -----------------------------------------------------------------------------
295#  Command ScrolledWindow::_destroy
296# -----------------------------------------------------------------------------
297proc ScrolledWindow::_destroy { path } {
298    Widget::destroy $path
299}
300
301# ----------------------------------------------------------------------------
302#  Command ScrolledWindow::_themechanged
303# ----------------------------------------------------------------------------
304proc ScrolledWindow::_themechanged { path } {
305
306    if { ![winfo exists $path] } { return }
307    BWidget::set_themedefaults
308    $path configure -background $BWidget::colors(SystemWindowFrame)
309}
310