Tk Library Source Code

Check-in [bc89eb5c0f]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Scrollutil: A series of changes. See the ChangeLog for details.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: bc89eb5c0fcac7fffca34e199597cbcc52b1b0f6b2b358d5d4a342cbf71a2b64
User & Date: csaba 2025-06-07 17:09:06.480
Context
2025-06-09
11:23
Scrollutil, Tablelist: Minor corrections and improvements in the documentation. check-in: 3087430f43 user: csaba tags: trunk
2025-06-07
17:09
Scrollutil: A series of changes. See the ChangeLog for details. check-in: bc89eb5c0f user: csaba tags: trunk
15:49
Tablelist: Added the "-button2window" configuration option. check-in: 61bdb70e68 user: csaba tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to examples/scrollutil/BwScrollableFrmDemo2.tcl.
51
52
53
54
55
56
57

58







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
foreach w [list $txt $lb $tbl $tv] {
    bind $w <<TraverseIn>> [list seeScrollarea $sf %W]
}
proc seeScrollarea {sf w} { $sf see [scrollutil::getscrollarea $w] }

#
# Additional stuff related to the mouse wheel events:

#








#
# Create mouse wheel event bindings for the binding tag "all" and
# register the ScrollableFrame for scrolling by these bindings
#
scrollutil::createWheelEventBindings all
scrollutil::enableScrollingByWheel $sf

#
# Adapt the handling of the mouse wheel events for the text, listbox,
# ttk::combobox, ttk::spinbox, tablelist, and ttk::treeview widgets, as
# well as for the entry components of the mentry widget of type "Date"
#
set entryList [$me entries]
scrollutil::adaptWheelEventHandling $txt $lb $cb $sb $tbl $tv {*}$entryList

#
# For the entry components of the mentry widget
# set the "focus check window" to the mentry
#
scrollutil::setFocusCheckWindow {*}$entryList $me







>

>
>
>
>
>
>
>













<
|
|
<
<
<
<
<
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

80
81





foreach w [list $txt $lb $tbl $tv] {
    bind $w <<TraverseIn>> [list seeScrollarea $sf %W]
}
proc seeScrollarea {sf w} { $sf see [scrollutil::getscrollarea $w] }

#
# Additional stuff related to the mouse wheel events:
# ---------------------------------------------------
#

#
# For the entry components of the mentry widget
# set the "focus check window" to the mentry
#
set entryList [$me entries]
scrollutil::setFocusCheckWindow {*}$entryList $me

#
# Create mouse wheel event bindings for the binding tag "all" and
# register the ScrollableFrame for scrolling by these bindings
#
scrollutil::createWheelEventBindings all
scrollutil::enableScrollingByWheel $sf

#
# Adapt the handling of the mouse wheel events for the text, listbox,
# ttk::combobox, ttk::spinbox, tablelist, and ttk::treeview widgets, as
# well as for the entry components of the mentry widget of type "Date"
#

### scrollutil::adaptWheelEventHandling $txt $lb $cb $sb {*}$entryList $tbl $tv
scrollutil::prepareScrollingByWheel $sf





Changes to examples/scrollutil/ScrolledCanvas.tcl.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#
# Variables used in the scan-related binding scripts below:
#
set origCursor [$c cget -cursor]
set scanCursor \
    [expr {[tk windowingsystem] eq "aqua" ? "pointinghand" : "hand2"}]

bind $c <Button-1>  { %W scan mark %x %y; %W configure -cursor $scanCursor }
bind $c <B1-Motion> { %W scan dragto %x %y }
bind $c <ButtonRelease-1> { %W configure -cursor $origCursor }

#
# Create a ttk::scale widget for setting the number of box rows
#
set fRows [ttk::frame $f.fRows]
pack [ttk::label $fRows.l1 -text "Rows:"] -side left -padx {0 3p}
pack [ttk::label $fRows.l2 -textvariable rows] -side left -padx {0 3p}







|
|
|







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#
# Variables used in the scan-related binding scripts below:
#
set origCursor [$c cget -cursor]
set scanCursor \
    [expr {[tk windowingsystem] eq "aqua" ? "pointinghand" : "hand2"}]

bind $c <Button-2>  { %W scan mark %x %y; %W configure -cursor $scanCursor }
bind $c <B2-Motion> { %W scan dragto %x %y }
bind $c <ButtonRelease-2> { %W configure -cursor $origCursor }

#
# Create a ttk::scale widget for setting the number of box rows
#
set fRows [ttk::frame $f.fRows]
pack [ttk::label $fRows.l1 -text "Rows:"] -side left -padx {0 3p}
pack [ttk::label $fRows.l2 -textvariable rows] -side left -padx {0 3p}
Changes to examples/scrollutil/ScrolledFrmDemo2.tcl.
42
43
44
45
46
47
48

49







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#
set cf [$sf childsite]
$cf configure -background $bg
source [file join $dir ScrolledFrmContent.tcl]

#
# Additional stuff related to the mouse wheel events:

#








#
# Create mouse wheel event bindings for the binding tag "all"
# and register the scrolledframe for scrolling by these bindings
#
scrollutil::createWheelEventBindings all
scrollutil::enableScrollingByWheel $sf

#
# Adapt the handling of the mouse wheel events for the text, listbox,
# ttk::combobox, ttk::spinbox, tablelist, and ttk::treeview widgets, as
# well as for the entry components of the mentry widget of type "Date"
#
set entryList [$me entries]
scrollutil::adaptWheelEventHandling $txt $lb $cb $sb $tbl $tv {*}$entryList

#
# For the entry components of the mentry widget
# set the "focus check window" to the mentry
#
scrollutil::setFocusCheckWindow {*}$entryList $me







>

>
>
>
>
>
>
>













<
|
|
<
<
<
<
<
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

71
72





#
set cf [$sf childsite]
$cf configure -background $bg
source [file join $dir ScrolledFrmContent.tcl]

#
# Additional stuff related to the mouse wheel events:
# ---------------------------------------------------
#

#
# For the entry components of the mentry widget
# set the "focus check window" to the mentry
#
set entryList [$me entries]
scrollutil::setFocusCheckWindow {*}$entryList $me

#
# Create mouse wheel event bindings for the binding tag "all"
# and register the scrolledframe for scrolling by these bindings
#
scrollutil::createWheelEventBindings all
scrollutil::enableScrollingByWheel $sf

#
# Adapt the handling of the mouse wheel events for the text, listbox,
# ttk::combobox, ttk::spinbox, tablelist, and ttk::treeview widgets, as
# well as for the entry components of the mentry widget of type "Date"
#

### scrollutil::adaptWheelEventHandling $txt $lb $cb $sb {*}$entryList $tbl $tv
scrollutil::prepareScrollingByWheel $sf





Changes to examples/scrollutil/SuScrollableFrmContent.tcl.
370
371
372
373
374
375
376
377
378
379
380

381
382
383
384
385
386
387

		$w configure -values $values
		$w set [$tbl cget $opt]
		bind $w <<ComboboxSelected>> [list applyValue %W $tbl $opt]
		grid $w -row $row -column 1 -sticky w -padx 3p -pady {3p 0}

		#
		# Adapt the handling of the mouse wheel
		# events for the ttk::combobox widget
		#
		scrollutil::adaptWheelEventHandling $w

	    }

	    -autofinishediting -
	    -autoscan -
	    -customdragsource -
	    -displayondemand -
	    -editendonfocusout -







|
|


>







370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388

		$w configure -values $values
		$w set [$tbl cget $opt]
		bind $w <<ComboboxSelected>> [list applyValue %W $tbl $opt]
		grid $w -row $row -column 1 -sticky w -padx 3p -pady {3p 0}

		#
		# Adapt the handling of the mouse wheel and mouse
		# button 2 events for the ttk::combobox widget
		#
		scrollutil::adaptWheelEventHandling $w
		scrollutil::adaptBtn2EventHandling $w
	    }

	    -autofinishediting -
	    -autoscan -
	    -customdragsource -
	    -displayondemand -
	    -editendonfocusout -
435
436
437
438
439
440
441
442
443
444
445

446
447
448
449
450
451
452
453
454






455
456
457
458
459
460
461
		    {expr {[string length %P] <= 3 && [regexp {^[0-9]*$} %S]}}
		foreach event {<Return> <KP_Enter> <FocusOut>} {
		    bind $w $event [list applyValue %W $tbl $opt]
		}
		grid $w -row $row -column 1 -sticky w -padx 3p -pady {3p 0}

		#
		# Adapt the handling of the mouse wheel
		# events for the ttk::spinbox widget
		#
		scrollutil::adaptWheelEventHandling $w

	    }

	    default {
		ttk::entry $w -width 25
		$w insert 0 [$tbl cget $opt]
		foreach event {<Return> <KP_Enter> <FocusOut>} {
		    bind $w $event [list applyValue %W $tbl $opt]
		}
		grid $w -row $row -column 1 -sticky we -padx 3p -pady {3p 0}






	    }
	}

	#
	# Make the keyboard navigation more user-friendly
	#
	bind $w <<TraverseIn>> [list $sf see %W]







|
|


>









>
>
>
>
>
>







436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
		    {expr {[string length %P] <= 3 && [regexp {^[0-9]*$} %S]}}
		foreach event {<Return> <KP_Enter> <FocusOut>} {
		    bind $w $event [list applyValue %W $tbl $opt]
		}
		grid $w -row $row -column 1 -sticky w -padx 3p -pady {3p 0}

		#
		# Adapt the handling of the mouse wheel and mouse
		# button 2 events for the ttk::spinbox widget
		#
		scrollutil::adaptWheelEventHandling $w
		scrollutil::adaptBtn2EventHandling $w
	    }

	    default {
		ttk::entry $w -width 25
		$w insert 0 [$tbl cget $opt]
		foreach event {<Return> <KP_Enter> <FocusOut>} {
		    bind $w $event [list applyValue %W $tbl $opt]
		}
		grid $w -row $row -column 1 -sticky we -padx 3p -pady {3p 0}

		#
		# Adapt the handling of the mouse button
		# 2 events for the ttk::entry widget
		#
		scrollutil::adaptBtn2EventHandling $w
	    }
	}

	#
	# Make the keyboard navigation more user-friendly
	#
	bind $w <<TraverseIn>> [list $sf see %W]
Changes to examples/scrollutil/SuScrollableFrmDemo1.tcl.
75
76
77
78
79
80
81
82

83
84

85
86
87
88
89
90
91

    #
    # Make the keyboard navigation more user-friendly
    #
    bind $w <<TraverseIn>> [list $sf see %W]

    #
    # Adapt the handling of the mouse wheel events for the ttk::combobox widget

    #
    scrollutil::adaptWheelEventHandling $w


    set b [styleutil::createToolbutton $cf.b$row -text "Resolve" \
	   -command [list setCapital $w $country]]
    grid $b -row $row -column 2 -sticky w -padx 3p -pady $padY

    #
    # Make the keyboard navigation more user-friendly







|
>


>







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

    #
    # Make the keyboard navigation more user-friendly
    #
    bind $w <<TraverseIn>> [list $sf see %W]

    #
    # Adapt the handling of the mouse wheel and mouse
    # button 2 events for the ttk::combobox widget
    #
    scrollutil::adaptWheelEventHandling $w
    scrollutil::adaptBtn2EventHandling $w

    set b [styleutil::createToolbutton $cf.b$row -text "Resolve" \
	   -command [list setCapital $w $country]]
    grid $b -row $row -column 2 -sticky w -padx 3p -pady $padY

    #
    # Make the keyboard navigation more user-friendly
Changes to examples/scrollutil/SuScrollableFrmDemo2.tcl.
40
41
42
43
44
45
46

47







48
49
50
51
52
53
54
55
56
57
58
59
60

61
62







63
64
65
66

foreach w [list $txt $lb $tbl $tv] {
    bind $w <<TraverseIn>> [list seeScrollarea $sf %W]
}
proc seeScrollarea {sf w} { $sf see [scrollutil::getscrollarea $w] }

#
# Additional stuff related to the mouse wheel events:

#








#
# Create mouse wheel event bindings for the binding tag "all"
#
scrollutil::createWheelEventBindings all

#
# Adapt the handling of the mouse wheel events for the text, listbox,
# ttk::combobox, ttk::spinbox, tablelist, and ttk::treeview widgets, as
# well as for the entry components of the mentry widget of type "Date"
#
set entryList [$me entries]
scrollutil::adaptWheelEventHandling $txt $lb $cb $sb $tbl $tv {*}$entryList


#







# For the entry components of the mentry widget
# set the "focus check window" to the mentry
#
scrollutil::setFocusCheckWindow {*}$entryList $me








>

>
>
>
>
>
>
>











<
|
>


>
>
>
>
>
>
>
|
<

|
>
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74
75
76
77
78

79
80
81
foreach w [list $txt $lb $tbl $tv] {
    bind $w <<TraverseIn>> [list seeScrollarea $sf %W]
}
proc seeScrollarea {sf w} { $sf see [scrollutil::getscrollarea $w] }

#
# Additional stuff related to the mouse wheel events:
# ---------------------------------------------------
#

#
# For the entry components of the mentry widget
# set the "focus check window" to the mentry
#
set entryList [$me entries]
scrollutil::setFocusCheckWindow {*}$entryList $me

#
# Create mouse wheel event bindings for the binding tag "all"
#
scrollutil::createWheelEventBindings all

#
# Adapt the handling of the mouse wheel events for the text, listbox,
# ttk::combobox, ttk::spinbox, tablelist, and ttk::treeview widgets, as
# well as for the entry components of the mentry widget of type "Date"
#

### scrollutil::adaptWheelEventHandling $txt $lb $cb $sb {*}$entryList $tbl $tv
$sf preparescroll

#
# Additional stuff related to the mouse button 2 events:
# ------------------------------------------------------
#

#
# Adapt the handling of the mouse button 2 events for the text, listbox,
# ttk::combobox, ttk::spinbox, ttk::entry, and tablelist widgets, as
# well as for the entry components of the mentry widget of type "Date"

#
### scrollutil::adaptBtn2EventHandling $txt $lb $cb $sb $e {*}$entryList $tbl
$sf preparescan
Changes to modules/scrollutil/CHANGES.txt.
1
2
3




















4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
What is new in Scrollutil 2.6?
------------------------------





















1. The "scrollutil::addMouseWheelSupport" command now accepts also the
   path name of a (ttk::)menubutton widget or the class name
   "(T)Menubutton" as argument, in which case the binding scripts
   created by this command for the mouse wheel and <TouchpadScroll>
   events will activate the cyclically next or previous entry of the
   menu associated with the widget and invoke the action of that menu
   entry.

2. The "scrollutil::addMouseWheelSupport" command now accepts also the
   path name of a (ttk::)scale widget or the class name "(T)Scale" as
   argument, in which case the binding scripts created by this command
   for the mouse wheel and <TouchpadScroll> events will increment or
   decrement the widget's value and move the slider accordingly.

3. The demo script "ScrolledCanvas.tcl" now adds mouse wheel and
   <TouchpadScroll> event support not only to the canvas but also to two
   ttk::scale widgets.

4. Improved the documentation by extending the CSS stylesheet used in
   the HTML files.

What was new in Scrollutil 2.5?
-------------------------------

1. Improvements in the error handling for the scrollednotebook and
   plainnotebook widgets.



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

|
|
|
|
<

|

|
|
|

|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
What is new in Scrollutil 2.6?
------------------------------

1. The scanning in scrollableframe widgets is now supported with mouse
   button 2 rather than 1.  On Android this adds scan support via one-
   finger gestures (thanks to Christian Werner for his proposal).

2. Added the "scrollutil::adaptBtn2EventHandling" command, for user-
   friendly mouse button 2 event handling in scrollableframe widgets,
   which on Android means user-friendly support for scanning via one-
   finger gestures (thanks to Michael Nieren and Christian Werner for
   discussions on this subject).

3. Added the "preparescan" scrollableframe subcommand, designed to
   automate the invocations of scrollutil::adaptBtn2EventHandling".

4. Added the "scrollutil::prepareScrollingByWheel" command, designed to
   automate the invocations of "scrollutil::adaptWheelEventHandling" in
   scrollable widget containers.

5. Added the "preparescroll" scrollableframe subcommand, as a shortcut
   for the "scrollutil::prepareScrollingByWheel" command.

6. The "scrollutil::addMouseWheelSupport" command now accepts also the
   path name of a (ttk::)menubutton widget or the class name
   "(T)Menubutton" as argument, in which case the binding scripts for
   the mouse wheel and <TouchpadScroll> events will activate the
   cyclically next or previous entry of the menu associated with the
   widget and invoke the action of that menu entry.


7. The "scrollutil::addMouseWheelSupport" command now accepts also the
   path name of a (ttk::)scale widget or the class name "(T)Scale" as
   argument, in which case the binding scripts for the mouse wheel and
   <TouchpadScroll> events will increment or decrement the widget's
   value and move the slider accordingly.

8. The demo script "ScrolledCanvas.tcl" now adds mouse wheel and
   <TouchpadScroll> event support not only to the canvas but also to two
   ttk::scale widgets.

9. Improved the documentation by extending the CSS stylesheet used in
   the HTML files.

What was new in Scrollutil 2.5?
-------------------------------

1. Improvements in the error handling for the scrollednotebook and
   plainnotebook widgets.
Changes to modules/scrollutil/ChangeLog.





























1
2
3
4
5
6
7





























2025-05-16  Csaba Nemethi <[email protected]>

	* *.tcl:         Bumped the version number to 2.6.
	* COPYRIGHT.txt:
	* README.txt:

	* CHANGES.txt: Updated to reflect the changes.
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2025-06-07  Csaba Nemethi <[email protected]>

	* README.txt:  Updated to reflect the changes.
	* CHANGES.txt:
	* doc/*.html:

	* scripts/scrollableframe.tcl: The scanning is now supported with mouse
	  button 2 rather than 1; added the
	  "scrollutil::adaptBtn2EventHandling" command; added the "preparescan"
	  and "preparescroll" scrollableframe subcommands.

	* scripts/wheelEvent.tcl: Added the
	  "scrollutil::prepareScrollingByWheel" command.

	* scripts/tclIndex: Newly generated.

	* doc/ScrollableFrmDemo2.png: Updated screenshots.
	* doc/TablelistConfig.png:
	* doc/TablelistConfig2.png:

	* ../../examples/scrollutil/ScrolledCanvas.tcl: Scanning now with
	  mouse button 2 rather than 1.

	* ../../examples/scrollutil/BwScrollableFrmDemo2.tcl:   Updated to
	* ../../examples/scrollutil/ScrolledFrmDemo2.tcl:       use the new
	* ../../examples/scrollutil/SuScrollableFrmContent.tcl: commands.
	* ../../examples/scrollutil/SuScrollableFrmDemo1.tcl:
	* ../../examples/scrollutil/SuScrollableFrmDemo2.tcl:

2025-05-16  Csaba Nemethi <[email protected]>

	* *.tcl:         Bumped the version number to 2.6.
	* COPYRIGHT.txt:
	* README.txt:

	* CHANGES.txt: Updated to reflect the changes.
Changes to modules/scrollutil/README.txt.
21
22
23
24
25
26
27


28
29
30
31
32
33
34
  - the command "scrollutil::addMouseWheelSupport", which creates mouse
    wheel event bindings for a given binding tag;
  - commands for user-friendly mouse wheel event handling in scrollable
    widget containers like scrollutil::scrollableframe, BWidget
    ScrollableFrame, and iwidgets::scrolledframe.  These commands
    require Tcl/Tk versions 8.4 or higher on X11 and Mac OS X and Tk
    8.6b2 or later on Windows;


  - demo scripts illustrating the use of the Scrollutil package in
    connection with various scrollable widgets and the above-mentioned
    scrollable widget containers;
  - demo scripts illustrating the use of the scrollednotebook,
    plainnotebook, and pagesman widgets;
  - a tutorial in HTML format;
  - reference pages in HTML format.







>
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  - the command "scrollutil::addMouseWheelSupport", which creates mouse
    wheel event bindings for a given binding tag;
  - commands for user-friendly mouse wheel event handling in scrollable
    widget containers like scrollutil::scrollableframe, BWidget
    ScrollableFrame, and iwidgets::scrolledframe.  These commands
    require Tcl/Tk versions 8.4 or higher on X11 and Mac OS X and Tk
    8.6b2 or later on Windows;
  - commands for user-friendly mouse button 2 event handling in
    scrollutil::scrollableframe widgets;
  - demo scripts illustrating the use of the Scrollutil package in
    connection with various scrollable widgets and the above-mentioned
    scrollable widget containers;
  - demo scripts illustrating the use of the scrollednotebook,
    plainnotebook, and pagesman widgets;
  - a tutorial in HTML format;
  - reference pages in HTML format.
Changes to modules/scrollutil/doc/ScrollableFrmDemo2.png.

cannot compute difference between binary files

Changes to modules/scrollutil/doc/TablelistConfig.png.

cannot compute difference between binary files

Changes to modules/scrollutil/doc/TablelistConfig2.png.

cannot compute difference between binary files

Changes to modules/scrollutil/doc/index.html.
32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
  <p><a href="scrollarea.html">The <code>scrollutil::scrollarea</code> and
  <code>scrollutil::getscrollarea</code> Commands</a></p>

  <p><a href="scrollsync.html">The <code>scrollutil::scrollsync</code> and
  <code>scrollutil::getscrollsync</code> Commands</a></p>

  <p><a href="scrollableframe.html">The
  <code>scrollutil::scrollableframe</code> Command</a></p>


  <p><a href="scrollednotebook.html">The
  <code>scrollutil::scrollednotebook</code> Command and the
  <code>closetab</code> Style Element</a></p>

  <p><a href="plainnotebook.html">The <code>scrollutil::plainnotebook</code>
  Command</a></p>







|
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  <p><a href="scrollarea.html">The <code>scrollutil::scrollarea</code> and
  <code>scrollutil::getscrollarea</code> Commands</a></p>

  <p><a href="scrollsync.html">The <code>scrollutil::scrollsync</code> and
  <code>scrollutil::getscrollsync</code> Commands</a></p>

  <p><a href="scrollableframe.html">The
  <code>scrollutil::scrollableframe</code> and
  <code>scrollutil::adaptBtn2EventHandling</code> Commands</a></p>

  <p><a href="scrollednotebook.html">The
  <code>scrollutil::scrollednotebook</code> Command and the
  <code>closetab</code> Style Element</a></p>

  <p><a href="plainnotebook.html">The <code>scrollutil::plainnotebook</code>
  Command</a></p>
Changes to modules/scrollutil/doc/scrollableframe.html.
1
2
3
4

5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34





35
36
37
38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
<!DOCTYPE html>
<html>
<head>
  <title>The scrollutil::scrollableframe Command</title>


  <meta name="Author" content="Csaba Nemethi">
  <meta name="Keywords" content="scrollableframe, widget, frame, scrollable">

  <link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>

<body>
  <div>
    <h1>The <code><b>scrollutil::scrollableframe</b></code> Command</h1>


    <h2>For Scrollutil Version 2.6</h2>

    <h3>by</h3>

    <h2>Csaba Nemethi</h2>

    <address>
      <a href="mailto:[email protected]">[email protected]</a>
    </address>
  </div>

  <hr>

  <h2 id="contents">Contents</h2>

  <ul>
    <li><a href="#quick_ref">Quick Reference</a></li>



    <li><a href="#detailed_ref">Detailed Reference</a></li>






    <li><a href="#comparison">Comparison with BWidget ScrollableFrame and
    iwidgets::scrolledframe</a></li>
  </ul>

  <div>
    <p><a href="index.html">Start page</a></p>
  </div>

  <hr>


  <h2 id="quick_ref">Quick Reference</h2>

  <dl>
    <dt><a href="#name">NAME</a></dt>

    <dd><code>scrollutil::scrollableframe</code> &ndash; Create and manipulate
    scrollableframe widgets</dd>




|
>









|
>

















|
>
>

|
>
>
>
>
>











>
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!DOCTYPE html>
<html>
<head>
  <title>The scrollutil::scrollableframe and scrollutil::adaptBtn2EventHandling
  Commands</title>

  <meta name="Author" content="Csaba Nemethi">
  <meta name="Keywords" content="scrollableframe, widget, frame, scrollable">

  <link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>

<body>
  <div>
    <h1>The <code><b>scrollutil::scrollableframe</b></code> and<br>
    <code><b>scrollutil::adaptBtn2EventHandling</b></code> Commands</h1>

    <h2>For Scrollutil Version 2.6</h2>

    <h3>by</h3>

    <h2>Csaba Nemethi</h2>

    <address>
      <a href="mailto:[email protected]">[email protected]</a>
    </address>
  </div>

  <hr>

  <h2 id="contents">Contents</h2>

  <ul>
    <li><a href="#quick_ref">The
    <code><b>scrollutil::scrollableframe</b></code> Command &ndash; Quick
    Reference</a></li>

    <li><a href="#detailed_ref">The
    <code><b>scrollutil::scrollableframe</b></code> Command &ndash; Detailed
    Reference</a></li>

    <li><a href="#adapt">The
    <code><b>scrollutil::adaptBtn2EventHandling</b></code> Command</a></li>

    <li><a href="#comparison">Comparison with BWidget ScrollableFrame and
    iwidgets::scrolledframe</a></li>
  </ul>

  <div>
    <p><a href="index.html">Start page</a></p>
  </div>

  <hr>

  <h2 id="quick_ref">The <code><b>scrollutil::scrollableframe</b></code>
  Command &ndash; Quick Reference</h2>

  <dl>
    <dt><a href="#name">NAME</a></dt>

    <dd><code>scrollutil::scrollableframe</code> &ndash; Create and manipulate
    scrollableframe widgets</dd>

122
123
124
125
126
127
128






129
130
131
132
133
134
135

    <dd><code><i>pathName</i> <b><a href=
    "#contentframe">contentframe</a></b></code></dd>

    <dd><code><i>pathName</i> <b><a href="#hasattrib">hasattrib</a></b>
    <i>name</i></code></dd>







    <dd>
      <code><i>pathName</i> <b><a href="#scan">scan</a></b> <i>option
      args</i></code>

      <dl>
        <dd><code><i>pathName</i> <b>scan mark</b> <i>x y</i></code></dd>








>
>
>
>
>
>







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

    <dd><code><i>pathName</i> <b><a href=
    "#contentframe">contentframe</a></b></code></dd>

    <dd><code><i>pathName</i> <b><a href="#hasattrib">hasattrib</a></b>
    <i>name</i></code></dd>

    <dd><code><i>pathName</i> <b><a href=
    "#preparescan">preparescan</a></b></code></dd>

    <dd><code><i>pathName</i> <b><a href=
    "#preparescroll">preparescroll</a></b></code></dd>

    <dd>
      <code><i>pathName</i> <b><a href="#scan">scan</a></b> <i>option
      args</i></code>

      <dl>
        <dd><code><i>pathName</i> <b>scan mark</b> <i>x y</i></code></dd>

192
193
194
195
196
197
198

199
200
201
202
203
204
205
206
  <div>
    <p><a href="#contents">Contents</a>&nbsp;&nbsp;&nbsp;&nbsp; <a href=
    "index.html">Start page</a></p>
  </div>

  <hr>


  <h2 id="detailed_ref">Detailed Reference</h2>

  <dl>
    <dt id="name"><b>NAME</b></dt>

    <dd><code>scrollutil::scrollableframe</code> &ndash; Create and manipulate
    scrollableframe widgets</dd>








>
|







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  <div>
    <p><a href="#contents">Contents</a>&nbsp;&nbsp;&nbsp;&nbsp; <a href=
    "index.html">Start page</a></p>
  </div>

  <hr>

  <h2 id="detailed_ref">The <code><b>scrollutil::scrollableframe</b></code>
  Command &ndash; Detailed Reference</h2>

  <dl>
    <dt id="name"><b>NAME</b></dt>

    <dd><code>scrollutil::scrollableframe</code> &ndash; Create and manipulate
    scrollableframe widgets</dd>

717
718
719
720
721
722
723

































724
725
726
727
728
729
730
        <dd>Returns the path name of the widget's content frame.</dd>

        <dt class="tm" id="hasattrib"><code><i>pathName</i> <b>hasattrib</b>
        <i>name</i></code></dt>

        <dd>Returns <code>1</code> if the attribute <code><i>name</i></code>
        exists and <code>0</code> otherwise.</dd>


































        <dt class="tm" id="scan"><code><i>pathName</i> <b>scan</b> <i>option
        args</i></code></dt>

        <dd>This command is used to implement scanning on scrollableframe
        widgets.&nbsp; It has two forms, depending on
        <code><i>option</i></code>:</dd>







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
        <dd>Returns the path name of the widget's content frame.</dd>

        <dt class="tm" id="hasattrib"><code><i>pathName</i> <b>hasattrib</b>
        <i>name</i></code></dt>

        <dd>Returns <code>1</code> if the attribute <code><i>name</i></code>
        exists and <code>0</code> otherwise.</dd>

        <dt class="tm" id="preparescan"><code><i>pathName</i>
        <b>preparescan</b></code></dt>

        <dd>Prepares the scrollableframe for scanning, by passing its
        descendants located in the same toplevel and having bindings for mouse
        button 2 events to the <code><b><a href=
        "#adapt">scrollutil::adaptBtn2EventHandling</a></b></code>
        command.</dd>

        <dd class="tm"><b>REMARK:</b>&nbsp; If the scrollableframe has many
        descendants then it is much safer to invoke this subcommand than to
        manually pass a lot of widgets to
        <code><b>scrollutil::adaptBtn2EventHandling</b></code>, because
        deciding which descendants to process can become tedious and
        error-prone.</dd>

        <dt class="tm" id="preparescroll"><code><i>pathName</i>
        <b>preparescroll</b></code></dt>

        <dd>Prepares the scrollableframe for scrolling with the mouse wheel and
        touchpad, by passing its descendants located in the same toplevel and
        having bindings for mouse wheel or
        <code><b>&lt;TouchpadScroll&gt;</b></code> events to the
        <code><b><a href=
        "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></b></code>
        command.</dd>

        <dd class="tm"><b>REMARK:</b>&nbsp; Invoking this subcommand is just a
        shortcut for passing <code><i>pathName</i></code> to the
        <code><b><a href=
        "wheelEvent.html#prepare">scrollutil::prepareScrollingByWheel</a></b></code>
        command.</dd>

        <dt class="tm" id="scan"><code><i>pathName</i> <b>scan</b> <i>option
        args</i></code></dt>

        <dd>This command is used to implement scanning on scrollableframe
        widgets.&nbsp; It has two forms, depending on
        <code><i>option</i></code>:</dd>
748
749
750
751
752
753
754


755
756
757
758
759
760
761
762
763
764
765
            <dd>This command computes the difference between its
            <code><i>x</i></code> and <code><i>y</i></code> arguments (which
            are typically mouse coordinates) and the <code><i>x</i></code> and
            <code><i>y</i></code> arguments to the last&nbsp; <code><b>scan</b>
            <b>mark</b></code>&nbsp; command for the widget.&nbsp; It then
            adjusts the view by <code><i>gain</i></code> times the difference
            in coordinates, where <code><i>gain</i></code> defaults to


            <code>10</code>.&nbsp; This command is typically associated with
            mouse motion events in the widget, to produce the effect of
            dragging the content frame at high speed through the window.&nbsp;
            The return value is an empty string.</dd>
          </dl>
        </dd>

        <dt class="tm" id="see"><code><i>pathName</i> <b>see</b> <i>widget</i>
        ?<i>corner</i>?</code></dt>

        <dd>This command adjusts the view in the scrollableframe's window so







>
>
|
|
|
|







798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
            <dd>This command computes the difference between its
            <code><i>x</i></code> and <code><i>y</i></code> arguments (which
            are typically mouse coordinates) and the <code><i>x</i></code> and
            <code><i>y</i></code> arguments to the last&nbsp; <code><b>scan</b>
            <b>mark</b></code>&nbsp; command for the widget.&nbsp; It then
            adjusts the view by <code><i>gain</i></code> times the difference
            in coordinates, where <code><i>gain</i></code> defaults to
            <code>10</code>, except on Android, where the default is
            <code>2</code>, being that this value suits better the emulation of
            mouse button 2 events with one-finger gestures.&nbsp; This command
            is typically associated with mouse motion events in the widget, to
            produce the effect of dragging the content frame at high speed
            through the window.&nbsp; The return value is an empty string.</dd>
          </dl>
        </dd>

        <dt class="tm" id="see"><code><i>pathName</i> <b>see</b> <i>widget</i>
        ?<i>corner</i>?</code></dt>

        <dd>This command adjusts the view in the scrollableframe's window so
960
961
962
963
964
965
966
967
968
969






970






971
972
973
974
975






































































































































976
977
978
979
980
981
982
          </dl>
        </dd>
      </dl>
    </dd>

    <dt class="tm" id="bindings"><b>BINDINGS</b></dt>

    <dd>Mouse button 1 may be used for scanning.&nbsp; If it is pressed and
    dragged over the scrollableframe window, the content frame drags at high
    speed in the direction the mouse moves.&nbsp; For the duration of the scan






    the cursor is set to one having the shape of a pointing hand.</dd>







    <dt class="tm" id="keywords"><b>KEYWORDS</b></dt>

    <dd>scrollableframe, widget, frame, scrollable</dd>
  </dl>







































































































































  <div>
    <p><a href="#contents">Contents</a>&nbsp;&nbsp;&nbsp;&nbsp; <a href=
    "index.html">Start page</a></p>
  </div>

  <hr>







|
|
|
>
>
>
>
>
>
|
>
>
>
>
>
>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
          </dl>
        </dd>
      </dl>
    </dd>

    <dt class="tm" id="bindings"><b>BINDINGS</b></dt>

    <dd>Mouse button 2 may be used for scanning.&nbsp; If it is pressed and
    dragged over a free area of the scrollableframe window, the content frame
    drags at high speed in the direction the mouse moves.&nbsp; The same
    happens if a descendant was clicked that either has no bindings for mouse
    button 2 events, or was passed to the <code><b><a href=
    "#adapt">scrollutil::adaptBtn2EventHandling</a></b></code> command, and the
    focus is outside the window&nbsp; <code>[<b><a href=
    "wheelEvent.html#focusCkWin">focusCheckWindow</a></b>
    <i>descendant</i>]</code>.</dd>

    <dd class="tm"><b>REMARK:</b>&nbsp; On Android, the support for scanning
    with mouse button 2 implies scan support via one-finger gestures, because
    fast wipes with one finger are translated by AndroWish to
    <code><b>&lt;Button-2&gt;</b></code>,
    <code><b>&lt;B2-Motion&gt;</b></code>, and
    <code><b>&lt;ButtonRelease-2&gt;</b></code> events.</dd>

    <dt class="tm" id="keywords"><b>KEYWORDS</b></dt>

    <dd>scrollableframe, widget, frame, scrollable</dd>
  </dl>

  <div>
    <p><a href="#contents">Contents</a>&nbsp;&nbsp;&nbsp;&nbsp; <a href=
    "index.html">Start page</a></p>
  </div>

  <hr>

  <h2 id="adapt">The <code><b>scrollutil::adaptBtn2EventHandling</b></code>
  Command</h2>

  <dl>
    <dt><b>NAME</b></dt>

    <dd><code>scrollutil::adaptBtn2EventHandling</code> &ndash; Adapt mouse
    button 2 event handling</dd>

    <dt class="tm"><b>SYNOPSIS</b></dt>

    <dd>
      <pre>
<b>scrollutil::adaptBtn2EventHandling</b> ?<i>widget</i> <i>widget</i> ...?
</pre>
    </dd>

    <dt><b>DESCRIPTION</b></dt>

    <dd>For each <code><i>widget</i></code> argument, the command performs the
    following actions:</dd>

    <dd class="tm">
      <ul>
        <li>
          If <code><i>widget</i></code> is the path name of a <a href=
          "https://www.nemethi.de/tablelist/">tablelist</a> widget then it sets
          the latter's <code><b>-button2window</b></code> option to the path
          name of the containing toplevel window, provided that the Tablelist
          version is 7.6 or later (for earlier Tablelist versions the command
          silently ignores any tablelist widget passed to it as
          argument).&nbsp; As a result, a <code><b>&lt;Button-2&gt;</b></code>,
          <code><b>&lt;B2-Motion&gt;</b></code>, or
          <code><b>&lt;ButtonRelease-2&gt;</b></code> event sent to the
          tablelist's body or edit window (more precisely, a mouse button 2
          event sent to any component of the tablelist having the binding tag
          <code><b>TablelistBody</b></code> or
          <code><b>TablelistEdit</b></code>) will be handled as follows:

          <ul class="tm">
            <li>If the focus is inside the tablelist widget then the event will
            will trigger a scanning of the content of the tablelist or its edit
            window and no further processing of the event will take place.</li>

            <li class="tm">If the focus is outside the tablelist widget then no
            scanning within the tablelist's body or edit window will
            happen.&nbsp; Instead, the event will be redirected to the
            containing toplevel window via&nbsp; <code><b>event
            generate</b></code>.&nbsp; This in turn will trigger a scanning of
            the content of the (innermost) scrollableframe that is an ancestor
            of <code><i>widget</i></code> and has the same toplevel (if there
            is such a scrollableframe widget).</li>
          </ul>
        </li>

        <li class="tm">
          Otherwise it locates the (first) binding tag that has mouse button 2
          event bindings and is different from both the path name of the
          containing toplevel window and <code><b>all</b></code>.&nbsp; If the
          search for this tag was successful then the command modifies the
          widget's list of binding tags by prepending the tag
          <code><b>Btn2EventRedir</b></code> and appending the tag
          <code><b>Btn2EventBreak</b></code> to this binding tag.&nbsp; As a
          result, a <code><b>&lt;Button-2&gt;</b></code>,
          <code><b>&lt;B2-Motion&gt;</b></code>, or
          <code><b>&lt;ButtonRelease-2&gt;</b></code> event sent to this widget
          will be handled as follows:

          <ul class="tm">
            <li>If the focus is on or inside the window&nbsp;
            <code>[<b><a href=
            "wheelEvent.html#focusCkWin">focusCheckWindow</a></b>
            <i>widget</i>]</code>&nbsp; then the event will be handled by the
            binding script associated with this tag and no further processing
            of the event will take place.</li>

            <li class="tm">If the focus is outside the window&nbsp;
            <code>[<b>focusCheckWindow</b> <i>widget</i>]</code>&nbsp; then the
            event will be redirected to the containing toplevel window
            via&nbsp; <code><b>event generate</b></code>&nbsp; rather than
            being handled by the binding script associated with the
            above-mentioned tag.&nbsp; This in turn will trigger a scanning of
            the content of the (innermost) scrollableframe that is an ancestor
            of <code><i>widget</i></code> and has the same toplevel (if there
            is such a scrollableframe widget).</li>
          </ul>
        </li>
      </ul>
    </dd>

    <dd class="tm"><b>REMARK 1:</b>&nbsp; This command is designed to be
    invoked for widgets that have mouse button 2 event bindings and are
    descendants of a scrollableframe.&nbsp; The Tk and tile widgets
    having class bindings for mouse button 2 events area: Tk core entry,
    ttk::entry, ttk::combobox, listbox, panedwindow, Tk core scale, ttk::scale,
    Tk core spinbox, ttk::spinbox, Tk core scrollbar, ttk::scrollbar, and
    text.&nbsp; Examples of widgets with binding tags other than their class
    names that have mouse button 2 event bindings are ctext and tablelist
    widgets.&nbsp; (In case of a ctext widget <code><i>w</i></code>, the
    binding tags mentioned in the description above refer to the widget's main
    text widget child <code><i>w</i>.t</code> rather than to the widget
    itself.)</dd>

    <dd class="tm"><b>REMARK 2:</b>&nbsp; As mentioned above, Tk core scrollbar
    and ttk::scrollbar widgets have class bindings for mouse button 2 events,
    hence this command should be invoked for them in case they are descendants
    of a scrollableframe widget.&nbsp; Since this task can become tedious,
    Scrollutil makes sure that if you pass a widget to this command and that
    widget is embedded into a <a href="scrollarea.html">scrollarea</a> via the
    latter's <code><b><a href=
    "scrollarea.html#setwidget">setwidget</a></b></code> subcommand, then this
    command will automatically be invoked for the scrollbars of that
    scrollarea, too.</dd>

    <dd class="tm"><b>REMARK 3:</b>&nbsp; When handling a mouse button 2 event
    sent to a Tk core or tile scrollbar whose path name was passed to this
    command, if the focus is on or inside the associated widget then the event
    will be processed by the scrollbar rather than being redirected to the
    containing toplevel, just as if the focus were on the scrollbar
    itself.</dd>

    <dt class="tm"><b>KEYWORDS</b></dt>

    <dd>mouse button 2 event, binding, event handling, scanning,
    scrollableframe, focus</dd>
  </dl>

  <div>
    <p><a href="#contents">Contents</a>&nbsp;&nbsp;&nbsp;&nbsp; <a href=
    "index.html">Start page</a></p>
  </div>

  <hr>
1170
1171
1172
1173
1174
1175
1176












1177
1178
1179
1180
1181
1182
1183

    <tr>
      <td><code><b>hasattrib</b></code></td>
      <td bgcolor="#e0e0e0"></td>
      <td bgcolor="#e0e0e0"></td>
    </tr>













    <tr>
      <td><code><b>scan</b></code>&nbsp; (with mouse event bindings)</td>
      <td bgcolor="#e0e0e0"></td>
      <td bgcolor="#e0e0e0"></td>
    </tr>

    <tr>







>
>
>
>
>
>
>
>
>
>
>
>







1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393

    <tr>
      <td><code><b>hasattrib</b></code></td>
      <td bgcolor="#e0e0e0"></td>
      <td bgcolor="#e0e0e0"></td>
    </tr>

    <tr>
      <td><code><b>preparescan</b></code></td>
      <td bgcolor="#e0e0e0"></td>
      <td bgcolor="#e0e0e0"></td>
    </tr>

    <tr>
      <td><code><b>preparescroll</b></code></td>
      <td bgcolor="#e0e0e0"></td>
      <td bgcolor="#e0e0e0"></td>
    </tr>

    <tr>
      <td><code><b>scan</b></code>&nbsp; (with mouse event bindings)</td>
      <td bgcolor="#e0e0e0"></td>
      <td bgcolor="#e0e0e0"></td>
    </tr>

    <tr>
Changes to modules/scrollutil/doc/scrollednotebook.html.
577
578
579
580
581
582
583
584


585
586
587
588
589
590
591

        <dt class="tm" id="snb_closetabstate"><code><i>pathName</i>
        <b>closetabstate</b> <i>tabId</i>
        ?<b>normal</b>|<b>disabled</b>?</code></dt>

        <dd>Sets or queries the state of the <code><b><a href=
        "#closetab">closetab</a></b></code> element of the tab specified by
        <code><i>tabId</i></code>.&nbsp; Invoking this subcommand is just a


        shortcut for passing <code><i>pathName</i></code>,
        <code><i>tabId</i></code>, and the optional argument (if present) to
        the <code><b><a href=
        "#closetabstate">scrollutil::closetabstate</a></b></code> command.</dd>

        <dt class="tm" id="configure"><code><i>pathName</i> <b>configure</b>
        ?<i>option</i> ?<i>value</i> <i>option</i> <i>value</i>







|
>
>







577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593

        <dt class="tm" id="snb_closetabstate"><code><i>pathName</i>
        <b>closetabstate</b> <i>tabId</i>
        ?<b>normal</b>|<b>disabled</b>?</code></dt>

        <dd>Sets or queries the state of the <code><b><a href=
        "#closetab">closetab</a></b></code> element of the tab specified by
        <code><i>tabId</i></code>.</dd>

	<dd class="tm"><b>REMARK:</b>&nbsp; Invoking this subcommand is just a
        shortcut for passing <code><i>pathName</i></code>,
        <code><i>tabId</i></code>, and the optional argument (if present) to
        the <code><b><a href=
        "#closetabstate">scrollutil::closetabstate</a></b></code> command.</dd>

        <dt class="tm" id="configure"><code><i>pathName</i> <b>configure</b>
        ?<i>option</i> ?<i>value</i> <i>option</i> <i>value</i>
Changes to modules/scrollutil/doc/scrollutil.html.
119
120
121
122
123
124
125



126
127
128
129
130
131
132
    which creates mouse wheel event bindings for a given binding tag;</li>

    <li>commands for <i>user-friendly</i> mouse wheel event handling in
    <b>scrollable widget containers</b> like scrollutil::scrollableframe,
    BWidget ScrollableFrame, and iwidgets::scrolledframe.&nbsp; These commands
    require Tcl/Tk versions 8.4 or higher on X11 and Mac OS X/11+ and Tk 8.6b2
    or later on Windows;</li>




    <li>demo scripts illustrating the use of the Scrollutil package in
    connection with various scrollable widgets and the above-mentioned
    scrollable widget containers;</li>

    <li>demo scripts illustrating the use of the scrollednotebook,
    plainnotebook, and pagesman widgets;</li>







>
>
>







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
    which creates mouse wheel event bindings for a given binding tag;</li>

    <li>commands for <i>user-friendly</i> mouse wheel event handling in
    <b>scrollable widget containers</b> like scrollutil::scrollableframe,
    BWidget ScrollableFrame, and iwidgets::scrolledframe.&nbsp; These commands
    require Tcl/Tk versions 8.4 or higher on X11 and Mac OS X/11+ and Tk 8.6b2
    or later on Windows;</li>

    <li>commands for <i>user-friendly</i> mouse button 2 event handling in
    scrollutil::scrollableframe widgets;</li>

    <li>demo scripts illustrating the use of the Scrollutil package in
    connection with various scrollable widgets and the above-mentioned
    scrollable widget containers;</li>

    <li>demo scripts illustrating the use of the scrollednotebook,
    plainnotebook, and pagesman widgets;</li>
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
    registered scrollable widget container that is an ascendant of the widget
    under the pointer and is contained in the latter's toplevel.</li>

    <li class="tm">Invoke the <code><a href=
    "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
    command for those widgets contained in registered scrollable widget
    containers that have mouse wheel or <code>&lt;TouchpadScroll&gt;</code>
    event (class) bindings.&nbsp; This step eliminates the annoying and often
    dangerous double-handling effect, by modifying the mouse wheel and
    <code>&lt;TouchpadScroll&gt;</code> event handling as follows:&nbsp; If the
    focus is on the widget under the pointer then the above-mentioned events
    will be handled by the (class bindings of the) widget only, otherwise by
    the bindings created with the
    <code>scrollutil::createWheelEventBindings</code> command.&nbsp; Without
    this step the mouse wheel and <code>&lt;TouchpadScroll&gt;</code> events
    would scroll both the listbox, text, ttk::treeview, or tablelist widget
    under the pointer <i>and</i> the widget container to whose descendants the
    latter belongs, or they would select the next/previous value in the
    ttk::combobox or ttk::spinbox under the pointer <i>in addition to</i>
    scrolling the widget container.&nbsp; Note that this command accepts as
    optional argument the <code>-ignorefocus</code> switch, which specifies
    that the above-mentioned events are to be handled by the widget under the
    pointer (only), ragardless of whether that widget has the focus or
    not.</li>

    <li class="tm">For some widgets it can be desirable to make the focus check
    within this modified event handling less restrictive.&nbsp; For example, if
    the widget under the pointer is an entry component of a <a href=
    "https://www.nemethi.de/mentry/">mentry</a> of type <code>"Date"</code>,
    <code>"Time"</code>, <code>"DateTime"</code>, <code>"IPAddr"</code>, or
    <code>"IPv6Addr"</code> and the focus is on any of its siblings, then the







|
<




|
<
<
<
<
<
<
|
|
|
|







267
268
269
270
271
272
273
274

275
276
277
278
279






280
281
282
283
284
285
286
287
288
289
290
    registered scrollable widget container that is an ascendant of the widget
    under the pointer and is contained in the latter's toplevel.</li>

    <li class="tm">Invoke the <code><a href=
    "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
    command for those widgets contained in registered scrollable widget
    containers that have mouse wheel or <code>&lt;TouchpadScroll&gt;</code>
    event (class) bindings.&nbsp; This step modifies the mouse wheel and

    <code>&lt;TouchpadScroll&gt;</code> event handling as follows:&nbsp; If the
    focus is on the widget under the pointer then the above-mentioned events
    will be handled by the (class bindings of the) widget only, otherwise by
    the bindings created with the
    <code>scrollutil::createWheelEventBindings</code> command.&nbsp; Note that






    this command accepts as optional argument the <code>-ignorefocus</code>
    switch, which specifies that the above-mentioned events are to be handled
    by the widget under the pointer (only), ragardless of whether that widget
    has the focus or not.</li>

    <li class="tm">For some widgets it can be desirable to make the focus check
    within this modified event handling less restrictive.&nbsp; For example, if
    the widget under the pointer is an entry component of a <a href=
    "https://www.nemethi.de/mentry/">mentry</a> of type <code>"Date"</code>,
    <code>"Time"</code>, <code>"DateTime"</code>, <code>"IPAddr"</code>, or
    <code>"IPv6Addr"</code> and the focus is on any of its siblings, then the
304
305
306
307
308
309
310



















311
312
313
314
315
316
317
  with the aid of the Scrollutil package was also tested to work with the
  <code>scrolledframe::scrolledframe</code> command of the Scrolledframe
  package by Maurice Bredelet (ulis) and its optimized and enhanced version
  contributed by Keith Nash, as well as with the <code>sframe</code> command
  implemented by Paul Walton.&nbsp; For details on these commands (which
  provide further implementations of scrollable widget containers) see the
  above-mentioned wiki page.</p>




















  <h3 id="ov_get">How to Get It?</h3>

  <p>Scrollutil is available for free download from the Web page</p>

  <blockquote>
    <address>







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  with the aid of the Scrollutil package was also tested to work with the
  <code>scrolledframe::scrolledframe</code> command of the Scrolledframe
  package by Maurice Bredelet (ulis) and its optimized and enhanced version
  contributed by Keith Nash, as well as with the <code>sframe</code> command
  implemented by Paul Walton.&nbsp; For details on these commands (which
  provide further implementations of scrollable widget containers) see the
  above-mentioned wiki page.</p>

  <p><b>The comands related to mouse button 2 event handling</b> are restricted
  to the scrollutil::scrollableframe widget, which provides scan support via
  the&nbsp; <code>scan mark</code>&nbsp; and&nbsp; <code>scan
  dragto</code>&nbsp; commands.&nbsp; The mouse button 2 event bindings for the
  binding tag <code>"all"</code>, created automatically by Scrollutil, handle
  the <code>&lt;Button-2&gt;</code>, <code>&lt;B2-Motion&gt;</code>, and
  <code>&lt;ButtonRelease-2&gt;</code> events by scanning the content of the
  (innermost) scrollableframe widget that is an ascendant of the clicked widget
  and is contained in the latter's toplevel.&nbsp; By invoking the
  <code><a href=
  "scrollableframe.html#adapt">scrollutil::adaptBtn2EventHandling</a></code>
  command for the widgets that are contained in a scrollableframe  and have
  mouse button 2 (class) bindings, the handling of these events will be
  modified as follows:&nbsp; If the focus is on the clicked widget then the
  events will be handled by the (class bindings of the) widget only, otherwise
  by the bindings created for the <code>"all"</code> tag.&nbsp; This comes in
  handy especially on Android, where it provides user-friendly scan support for
  scrollableframe widgets via one-finger gestures.</p>

  <h3 id="ov_get">How to Get It?</h3>

  <p>Scrollutil is available for free download from the Web page</p>

  <blockquote>
    <address>
1410
1411
1412
1413
1414
1415
1416
1417

1418
1419

1420
1421
1422
1423
1424
1425
1426

    <span class="cmt">#
    # Make the keyboard navigation more user-friendly
    #</span>
    bind $w &lt;&lt;TraverseIn&gt;&gt; [list <span class="red">$sf see %W</span>]

    <span class="cmt">#
    # Adapt the handling of the mouse wheel events for the ttk::combobox widget

    #</span>
    <span class="red">scrollutil::adaptWheelEventHandling $w</span>


    . . .

    incr row
}

. . .







|
>

|
>







1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443

    <span class="cmt">#
    # Make the keyboard navigation more user-friendly
    #</span>
    bind $w &lt;&lt;TraverseIn&gt;&gt; [list <span class="red">$sf see %W</span>]

    <span class="cmt">#
    # Adapt the handling of the mouse wheel and mouse
    # button 2 events for the ttk::combobox widget
    #</span>
    <span class="red">scrollutil::adaptWheelEventHandling $w
    scrollutil::adaptBtn2EventHandling $w</span>

    . . .

    incr row
}

. . .
1435
1436
1437
1438
1439
1440
1441
1442





1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
  <code><a href=
  "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
  command for every ttk::combobox widget, which is needed for a user-friendly
  event handling, being that this widget has built-in bindings for the mouse
  wheel and <code>&lt;TouchpadScroll&gt;</code> events.&nbsp; Due to this
  command, these events over one of the ttk::combobox widgets will only select
  the next/previous capital city if the widget has the focus, otherwise they
  will scroll the scrollableframe.</p>






  <p>With this script you can also test the scanning in the
  scrollableframe:&nbsp; If you press mouse button 1 over a free space of the
  scrollableframe window then the cursor will take on the shape of a pointing
  hand, and by draggging the mouse, the content frame will drag at high speed
  through the window, in the direction the mouse moves.</p>

  <h3 id="ex_BwScrollableFrameDemo1">A Script Using a BWidget ScrollableFrame
  Widget</h3>

  <p>The script <code>BwScrollableFrmDemo1.tcl</code> in the <code>demos</code>
  directory creates a BWidget ScrollableFrame embedded into a <a href=
  "scrollarea.html">scrollarea</a> widget, creates mouse wheel and







|
>
>
>
>
>

<
<
|
|
|







1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465


1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
  <code><a href=
  "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
  command for every ttk::combobox widget, which is needed for a user-friendly
  event handling, being that this widget has built-in bindings for the mouse
  wheel and <code>&lt;TouchpadScroll&gt;</code> events.&nbsp; Due to this
  command, these events over one of the ttk::combobox widgets will only select
  the next/previous capital city if the widget has the focus, otherwise they
  will scroll the scrollableframe.&nbsp; For every ttk::combobox widget, we
  also invoke the <code><a href=
  "scrollableframe.html#adapt">scrollutil::adaptBtn2EventHandling</a></code>
  command, thus making sure that the mouse button 2 events sent to the widget
  will only be handled by the widget itself if it has the focus, otherwise they
  will result in scanning the scrollableframe's content.</p>



  <p>During the scan with mouse button 2, the cursor will take on the shape of
  a pointing hand, and by draggging the mouse, the content frame will drag at
  high speed through the window, in the direction the mouse moves.</p>

  <h3 id="ex_BwScrollableFrameDemo1">A Script Using a BWidget ScrollableFrame
  Widget</h3>

  <p>The script <code>BwScrollableFrmDemo1.tcl</code> in the <code>demos</code>
  directory creates a BWidget ScrollableFrame embedded into a <a href=
  "scrollarea.html">scrollarea</a> widget, creates mouse wheel and
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
<span class="cmt">#
# Get the content frame and populate it
#</span>

set cf [$sf childsite]
. . .

<i>&lt;exactly as in the two previous examples, except the stuff related to keyboard navigation&gt;</i>

. . .
</pre>
  </blockquote>

  <p>The code related to keyboard navigation is not present in this example,
  because the iwidgets::scrolledframe widget doesn't provide a <code>see</code>







|







1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
<span class="cmt">#
# Get the content frame and populate it
#</span>

set cf [$sf childsite]
. . .

<i>&lt;exactly as in the previous example, except the stuff related to keyboard navigation&gt;</i>

. . .
</pre>
  </blockquote>

  <p>The code related to keyboard navigation is not present in this example,
  because the iwidgets::scrolledframe widget doesn't provide a <code>see</code>
1637
1638
1639
1640
1641
1642
1643
1644


1645
1646
1647
1648
1649
1650
1651

    <li>a scrolled ttk::treeview widget <code>$tv</code> within a
    scrollarea.</li>
  </ul>

  <p>With the exception of ttk::label, ttk::entry, and ttk::separator, all
  these widgets have bult-in mouse wheel and
  <code>&lt;TouchpadScroll&gt;</code> event bindings.</p>



  <blockquote>
    <img src="ScrollableFrmDemo2.png" alt="ScrollableFrmDemo2" width="684"
    height="577">
  </blockquote>

  <p>Here is the relevant code:</p>







|
>
>







1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673

    <li>a scrolled ttk::treeview widget <code>$tv</code> within a
    scrollarea.</li>
  </ul>

  <p>With the exception of ttk::label, ttk::entry, and ttk::separator, all
  these widgets have bult-in mouse wheel and
  <code>&lt;TouchpadScroll&gt;</code> event bindings.&nbsp; And with the
  exception of ttk::label, ttk::separator, and ttk::treeview, all these
  widgets have bult-in mouse button 2 event bindings.</p>

  <blockquote>
    <img src="ScrollableFrmDemo2.png" alt="ScrollableFrmDemo2" width="684"
    height="577">
  </blockquote>

  <p>Here is the relevant code:</p>
1706
1707
1708
1709
1710
1711
1712







1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725

1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737


1738
1739

1740











1741


1742


1743
1744
1745
1746
1747
1748
1749
1750

  <p>Here is the additional stuff related to the mouse wheel and
  <code>&lt;TouchpadScroll&gt;</code> events, using the Scrollutil commands
  described in the <a href="#ov_what">What Is Scrollutil?</a> section:</p>

  <blockquote>
    <pre>







<span class="cmt">#
# Create mouse wheel event bindings for the binding tag "all"
#</span>
<span class="red">scrollutil::createWheelEventBindings all</span>

<span class="cmt">#
# Adapt the handling of the mouse wheel events for the text, listbox,
# ttk::combobox, ttk::spinbox, tablelist, and ttk::treeview widgets, as
# well as for the entry components of the mentry widget of type "Date"
#</span>
set entryList [$me entries]
<span class="red">scrollutil::adaptWheelEventHandling $txt $lb $cb $sb $tbl $tv {*}$entryList</span>


<span class="cmt">#
# For the entry components of the mentry widget
# set the "focus check window" to the mentry
#</span>
<span class="red">scrollutil::setFocusCheckWindow {*}$entryList $me</span>
</pre>
  </blockquote>

  <p>Notice that we have passed, among others, the tablelist widget to the
  <code><a href=
  "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
  command.&nbsp; This will only work for Tablelist versions 6.4 and later,


  because the command handles tablelist widgets by setting their
  <code>-xmousewheelwindow</code> and <code>-ymousewheelwindow</code> options

  to the path name of the containing toplevel window, and these options were











  introduced in Tablelist version 6.4.&nbsp; (For earlier Tablelist versions


  the command silently ignores any tablelist widget passed to it as


  argument.)</p>

  <p>As already mentioned, in the file <code>SuScrollableFrmContent.tcl</code>
  the scrolled text, listbox, tablelist, and ttk::treeview widgets are created
  within <a href="scrollarea.html">scrollarea</a> widgets:</p>

  <blockquote>
    <pre>







>
>
>
>
>
>
>









<
<
<
|
>
|
<
<
<
<



<
|

|
>
>
|
|
>
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
>
>
|







1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750



1751
1752
1753




1754
1755
1756

1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790

  <p>Here is the additional stuff related to the mouse wheel and
  <code>&lt;TouchpadScroll&gt;</code> events, using the Scrollutil commands
  described in the <a href="#ov_what">What Is Scrollutil?</a> section:</p>

  <blockquote>
    <pre>
<span class="cmt">#
# For the entry components of the mentry widget
# set the "focus check window" to the mentry
#</span>
set entryList [$me entries]
<span class="red">scrollutil::setFocusCheckWindow {*}$entryList $me</span>

<span class="cmt">#
# Create mouse wheel event bindings for the binding tag "all"
#</span>
<span class="red">scrollutil::createWheelEventBindings all</span>

<span class="cmt">#
# Adapt the handling of the mouse wheel events for the text, listbox,
# ttk::combobox, ttk::spinbox, tablelist, and ttk::treeview widgets, as
# well as for the entry components of the mentry widget of type "Date"



#
### scrollutil::adaptWheelEventHandling $txt $lb $cb $sb {*}$entryList $tbl $tv</span>
<span class="red">$sf preparescroll</span>




</pre>
  </blockquote>


  <p>Notice that the invocation of the <code><a href=
  "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
  command is commented out and replaced with the much simpler and safer
  invocation of the <code><a href=
  "scrollableframe.html#preparescroll">preparescroll</a></code> scrollableframe
  subcommand.</p>

  <p>We also have additional stuff related to the mouse button 2 events:</p>

  <blockquote>
    <pre>
<span class="cmt">#
# Adapt the handling of the mouse wheel events for the text, listbox,
# ttk::combobox, ttk::spinbox, tablelist, and ttk::treeview widgets, as
# well as for the entry components of the mentry widget of type "Date"
#
### scrollutil::adaptWheelEventHandling $txt $lb $cb $sb {*}$entryList $tbl $tv</span>
<span class="red">$sf preparescan</span>
</pre>
  </blockquote>

  <p>Again, the invocation of the <code><a href=
  "scrollableframe.html#adapt">scrollutil::adaptBtn2EventHandling</a></code>
  command is commented out and replaced with the much simpler and safer
  invocation of the <code><a href=
  "scrollableframe.html#preparescan">preparescan</a></code> scrollableframe
  subcommand.</p>

  <p>As already mentioned, in the file <code>SuScrollableFrmContent.tcl</code>
  the scrolled text, listbox, tablelist, and ttk::treeview widgets are created
  within <a href="scrollarea.html">scrollarea</a> widgets:</p>

  <blockquote>
    <pre>
1824
1825
1826
1827
1828
1829
1830
1831





1832
1833
1834
1835
1836
1837
1838
  checkbuttons.&nbsp; The procedure handles the
  <code>&lt;&lt;TraverseIn&gt;&gt;</code> virtual event sent to one of these
  widgets with the aid of the scrollableframe's <code><a href=
  "scrollableframe.html#see">see</a></code> subcommand.&nbsp; Whenever a
  ttk::combobox or ttk::spinbox is created, the <code><a href=
  "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
  command is invoked for it, being that these widgets have built-in bindings
  for the mouse wheel and <code>&lt;TouchpadScroll&gt;</code> events.</p>






  <p>The widgets populating the content frame are managed using
  <code>grid</code>.&nbsp; In case of the ttk::entry widgets we invoke
  <code>grid</code> with&nbsp; <code>-sticky we</code>.&nbsp; Due to this and
  the&nbsp; <code>-fitcontentwidth yes</code>&nbsp; scrollableframe setting,
  the ttk::entry widgets will stretch or shrink whenever the width of the
  scrollableframe changes as a result of resizing the toplevel window.</p>







|
>
>
>
>
>







1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
  checkbuttons.&nbsp; The procedure handles the
  <code>&lt;&lt;TraverseIn&gt;&gt;</code> virtual event sent to one of these
  widgets with the aid of the scrollableframe's <code><a href=
  "scrollableframe.html#see">see</a></code> subcommand.&nbsp; Whenever a
  ttk::combobox or ttk::spinbox is created, the <code><a href=
  "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
  command is invoked for it, being that these widgets have built-in bindings
  for the mouse wheel and <code>&lt;TouchpadScroll&gt;</code> events.&nbsp;
  Similarly, we pass the ttk::combobox, ttk::spinbox, and ttk::entry widgets
  to the <code><a href=
  "scrollableframe.html#adapt">scrollutil::adaptBtn2EventHandling</a></code>
  command, because these widgets have built-in bindings for the mouse button 2
  events.</p>

  <p>The widgets populating the content frame are managed using
  <code>grid</code>.&nbsp; In case of the ttk::entry widgets we invoke
  <code>grid</code> with&nbsp; <code>-sticky we</code>.&nbsp; Due to this and
  the&nbsp; <code>-fitcontentwidth yes</code>&nbsp; scrollableframe setting,
  the ttk::entry widgets will stretch or shrink whenever the width of the
  scrollableframe changes as a result of resizing the toplevel window.</p>
1908
1909
1910
1911
1912
1913
1914
1915


1916
1917
1918


1919
1920
1921
1922
1923
1924
1925
1926






1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943

1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
</pre>
  </blockquote>

  <p>The additional stuff related to the mouse wheel and
  <code>&lt;TouchpadScroll&gt;</code> events contains the same Scrollutil
  command invocations as the one in the previous example, except that in
  addition it registers the ScrollableFrame for scrolling with the mouse wheel
  and touchpad:</p>



  <blockquote>
    <pre>


<span class="cmt">#
# Create mouse wheel event bindings for the binding tag "all" and
# register the ScrollableFrame for scrolling by these bindings
#</span>
<span class="red">scrollutil::createWheelEventBindings all
scrollutil::enableScrollingByWheel $sf</span>

. . .






</pre>
  </blockquote>

  <p>The file <code>BwScrollableFrmContent.tcl</code> contains also the
  implementation of the procedure <code>configTablelist</code>, associated with
  the "Configure Tablelist Widget" button as the value of its
  <code>-command</code> option.&nbsp; This procedure opens a toplevel window
  that contains a BWidget ScrollableFrame created with the&nbsp;
  <code>-constrainedwidth yes</code>&nbsp; setting within a <a href=
  "scrollarea.html">scrollarea</a> widget and invokes the <code><a href=
  "wheelEvent.html#enable">scrollutil::enableScrollingByWheel</a></code>
  command for this ScrollableFrame, thus registering the latter for scrolling
  by the already created mouse wheel and <code>&lt;TouchpadScroll&gt;</code>
  event bindings for the binding tag <code>"all"</code>.&nbsp; After that it
  populates the content frame of the ScrollableFrame with ttk::label,
  ttk::combobox, ttk::spinbox, ttk::entry, and ttk::checkbutton widgets used to
  display and edit the configuration options of the tablelist widget.&nbsp; The

  procedure handles the <code>&lt;&lt;TraverseIn&gt;&gt;</code> virtual event
  sent to one of these widgets with the aid of the ScrollableFrame's
  <code>see</code> subcommand.&nbsp; Whenever a ttk::combobox or ttk::spinbox
  is created, the <code><a href=
  "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
  command is invoked for it, being that these widgets have built-in bindings
  for the mouse wheel and <code>&lt;TouchpadScroll&gt;</code>
  events.</p>

  <p>Again, all this is nearly identical to what we did in the previous
  example.</p>

  <h3 id="ex_ScrolledFrameDemo2">A Script Using Two iwidgets::scrolledframe
  Widgets</h3>








|
>
>



>
>







|
>
>
>
>
>
>















|
|
>
|
|
|
|


|
<







1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006

2007
2008
2009
2010
2011
2012
2013
</pre>
  </blockquote>

  <p>The additional stuff related to the mouse wheel and
  <code>&lt;TouchpadScroll&gt;</code> events contains the same Scrollutil
  command invocations as the one in the previous example, except that in
  addition it registers the ScrollableFrame for scrolling with the mouse wheel
  and touchpad, and invokes the <code><a href=
  "wheelEvent.html#prepare">scrollutil::prepareScrollingByWheel</a></code>
  command:</p>

  <blockquote>
    <pre>
. . .

<span class="cmt">#
# Create mouse wheel event bindings for the binding tag "all" and
# register the ScrollableFrame for scrolling by these bindings
#</span>
<span class="red">scrollutil::createWheelEventBindings all
scrollutil::enableScrollingByWheel $sf</span>

<span class="cmt">#
# Adapt the handling of the mouse wheel events for the text, listbox,
# ttk::combobox, ttk::spinbox, tablelist, and ttk::treeview widgets, as
# well as for the entry components of the mentry widget of type "Date"
#
### scrollutil::adaptWheelEventHandling $txt $lb $cb $sb {*}$entryList $tbl $tv</span>
<span class="red">scrollutil::prepareScrollingByWheel $sf</span>
</pre>
  </blockquote>

  <p>The file <code>BwScrollableFrmContent.tcl</code> contains also the
  implementation of the procedure <code>configTablelist</code>, associated with
  the "Configure Tablelist Widget" button as the value of its
  <code>-command</code> option.&nbsp; This procedure opens a toplevel window
  that contains a BWidget ScrollableFrame created with the&nbsp;
  <code>-constrainedwidth yes</code>&nbsp; setting within a <a href=
  "scrollarea.html">scrollarea</a> widget and invokes the <code><a href=
  "wheelEvent.html#enable">scrollutil::enableScrollingByWheel</a></code>
  command for this ScrollableFrame, thus registering the latter for scrolling
  by the already created mouse wheel and <code>&lt;TouchpadScroll&gt;</code>
  event bindings for the binding tag <code>"all"</code>.&nbsp; After that it
  populates the content frame of the ScrollableFrame with ttk::label,
  ttk::combobox, ttk::spinbox, ttk::entry, and ttk::checkbutton or
  tsw::toggleswitch widgets used to display and edit the configuration options
  of the tablelist widget.&nbsp; The procedure handles the
  <code>&lt;&lt;TraverseIn&gt;&gt;</code> virtual event sent to one of these
  widgets with the aid of the ScrollableFrame's <code>see</code>
  subcommand.&nbsp; Whenever a ttk::combobox or ttk::spinbox is created, the
  <code><a href=
  "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
  command is invoked for it, being that these widgets have built-in bindings
  for the mouse wheel and <code>&lt;TouchpadScroll&gt;</code> events.</p>


  <p>Again, all this is nearly identical to what we did in the previous
  example.</p>

  <h3 id="ex_ScrolledFrameDemo2">A Script Using Two iwidgets::scrolledframe
  Widgets</h3>

2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
  invokes the <code><a href=
  "wheelEvent.html#enable">scrollutil::enableScrollingByWheel</a></code>
  command for this scrolledframe, thus registering the latter for scrolling by
  the already created mouse wheel and
  <code>&lt;TouchpadScroll&gt;</code> event bindings for the binding tag
  <code>"all"</code>.&nbsp; After that it populates the content frame of the
  scrolledframe with ttk::label, ttk::combobox, ttk::spinbox, ttk::entry, and
  ttk::checkbutton widgets used to display and edit the configuration options
  of the tablelist widget.&nbsp; Whenever a ttk::combobox or ttk::spinbox is
  created, the <code><a href=
  "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
  command is invoked for it, being that these widgets have built-in bindings
  for the mouse wheel and <code>&lt;TouchpadScroll&gt;</code>
  events.</p>

  <p>Again, all this is nearly identical to what we did in the two previous
  examples.</p>







|
|
|







2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
  invokes the <code><a href=
  "wheelEvent.html#enable">scrollutil::enableScrollingByWheel</a></code>
  command for this scrolledframe, thus registering the latter for scrolling by
  the already created mouse wheel and
  <code>&lt;TouchpadScroll&gt;</code> event bindings for the binding tag
  <code>"all"</code>.&nbsp; After that it populates the content frame of the
  scrolledframe with ttk::label, ttk::combobox, ttk::spinbox, ttk::entry, and
  ttk::checkbutton or tsw::toggleswitch widgets used to display and edit the
  configuration options of the tablelist widget.&nbsp; Whenever a
  ttk::combobox or ttk::spinbox is created, the <code><a href=
  "wheelEvent.html#adapt">scrollutil::adaptWheelEventHandling</a></code>
  command is invoked for it, being that these widgets have built-in bindings
  for the mouse wheel and <code>&lt;TouchpadScroll&gt;</code>
  events.</p>

  <p>Again, all this is nearly identical to what we did in the two previous
  examples.</p>
Changes to modules/scrollutil/doc/wheelEvent.html.
43
44
45
46
47
48
49



50
51
52
53
54
55
56

    <li><a href="#disable">The
    <code><b>scrollutil::disableScrollingByWheel</b></code> Command</a></li>

    <li><a href="#adapt">The
    <code><b>scrollutil::adaptWheelEventHandling</b></code> Command</a></li>




    <li><a href="#setFocusCkWin">The
    <code><b>scrollutil::setFocusCheckWindow</b></code> Command</a></li>

    <li><a href="#focusCkWin">The
    <code><b>scrollutil::focusCheckWindow</b></code> Command</a></li>
  </ul>








>
>
>







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

    <li><a href="#disable">The
    <code><b>scrollutil::disableScrollingByWheel</b></code> Command</a></li>

    <li><a href="#adapt">The
    <code><b>scrollutil::adaptWheelEventHandling</b></code> Command</a></li>

    <li><a href="#prepare">The
    <code><b>scrollutil::prepareScrollingByWheel</b></code> Command</a></li>

    <li><a href="#setFocusCkWin">The
    <code><b>scrollutil::setFocusCheckWindow</b></code> Command</a></li>

    <li><a href="#focusCkWin">The
    <code><b>scrollutil::focusCheckWindow</b></code> Command</a></li>
  </ul>

519
520
521
522
523
524
525
526



















527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
















































589
590
591
592
593
594
595
    <code>"Date"</code>, <code>"Time"</code>, <code>"DateTime"</code>,
    <code>"IPAddr"</code>, and <code>"IPv6Addr"</code> (for Mentry versions 3.2
    and above).&nbsp; (In case of a ctext widget <code><i>w</i></code>, the
    binding tags mentioned in the description above refer to the widget's main
    text widget child <code><i>w</i>.t</code> rather than to the widget
    itself.)</dd>

    <dd class="tm"><b>REMARK 2:</b>&nbsp; The mouse wheel event class bindings



















    for the Tk core scrollbar on Windows and X11 were added in Tk 8.6.&nbsp;
    Prior to this Tk version there were such bindings only for the windowing
    system <code><b>aqua</b></code> on the Macintosh.&nbsp; Scrollutil
    eliminates this discrepancy by automatically creating the
    <code><b>Scrollbar</b></code> class bindings for mouse wheel events on
    Windows and X11.&nbsp; Note also that in Tk versions prior to 8.7a4 the
    ttk::scrollbar widget had no <i>built-in</i> class bindings for mouse wheel
    events, but Scrollutil automatically creates the missing bindings by
    copying the mouse wheel event bindings of the widget class
    <code><b>Scrollbar</b></code> to the binding tag
    <code><b>TScrollbar</b></code>.</dd>

    <dd class="tm"><b>REMARK 3:</b>&nbsp; As mentioned above, Tk core scrollbar
    and ttk::scrollbar widgets have class bindings for mouse wheel and
    <code><b>&lt;TouchpadScroll&gt;</b></code> events, hence this command
    should be invoked for them in case they are descendants of a scrollable
    widget container.&nbsp; Since this task can become tedious, Scrollutil
    makes sure that if you pass a widget to this command and that widget is
    embedded into a <a href="scrollarea.html">scrollarea</a> via the latter's
    <code><b><a href="scrollarea.html#setwidget">setwidget</a></b></code>
    subcommand, then this command will automatically be invoked for the
    scrollbars of that scrollarea, too.</dd>

    <dd class="tm"><b>REMARK 4:</b>&nbsp; Without the
    <code><b>-ignorefocus</b></code> option, when handling a mouse wheel or
    <code><b>&lt;TouchpadScroll&gt;</b></code> event sent to a Tk core or tile
    scrollbar whose path name was passed to this command, if the focus is on or
    inside the associated widget then the event will be processed by the
    scrollbar rather than being redirected to the containing toplevel, just as
    if the focus were on the scrollbar itself.</dd>

    <dd class="tm"><b>REMARK 5:</b>&nbsp; The mouse wheel event class bindings
    for the ttk::notebook widget were added in Tk 8.7a4, but Scrollutil
    automatically creates them for all Tk versions starting with 8.4.&nbsp;
    These bindings implement the navigation between the tabs of a ttk::notebook
    or <a href="scrollednotebook.html">scrollutil::scrollednotebook</a> widget
    via the mouse wheel.</dd>

    <dd class="tm"><b>REMARK 6:</b>&nbsp; Invoking this command for widgets
    that have mouse wheel or <code><b>&lt;TouchpadScroll&gt;</b></code> event
    bindings and are descendants of a scrollable widget container is essential
    for a user-friendly mouse wheel and
    <code><b>&lt;TouchpadScroll&gt;</b></code> event handling in scrollable
    widget containers.&nbsp; Without this step the mouse wheel and
    <code><b>&lt;TouchpadScroll&gt;</b></code> events would scroll both the
    listbox, text, ttk::treeview, or tablelist widget under the pointer
    <i>and</i> the widget container to whose descendants the latter belongs, or
    they would select the next/previous value in the ttk::combobox or
    ttk::spinbox under the pointer <i>in addition to</i> scrolling the widget
    container.</dd>

    <dd class="tm"><b>REMARK 7:</b>&nbsp; The recommended invocation of this
    command is without the <code><b>-ignorefocus</b></code> option, because it
    significantly reduces the probability that the user will inadvertently
    scroll a window within a widget container containing many scrollable
    widgets.</dd>

    <dt class="tm"><b>KEYWORDS</b></dt>

    <dd>mouse wheel event, binding, event handling, scrolling, scrollable
    widget container, focus</dd>
  </dl>

















































  <div>
    <p><a href="#contents">Contents</a>&nbsp;&nbsp;&nbsp;&nbsp; <a href=
    "index.html">Start page</a></p>
  </div>

  <hr>







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>












<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







|
<
<
<
<
<
<
<
<
<
<
<
<
<










>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560



















561
562
563
564
565
566
567
568













569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
    <code>"Date"</code>, <code>"Time"</code>, <code>"DateTime"</code>,
    <code>"IPAddr"</code>, and <code>"IPv6Addr"</code> (for Mentry versions 3.2
    and above).&nbsp; (In case of a ctext widget <code><i>w</i></code>, the
    binding tags mentioned in the description above refer to the widget's main
    text widget child <code><i>w</i>.t</code> rather than to the widget
    itself.)</dd>

    <dd class="tm"><b>REMARK 2:</b>&nbsp; As mentioned above, Tk core scrollbar
    and ttk::scrollbar widgets have class bindings for mouse wheel and
    <code><b>&lt;TouchpadScroll&gt;</b></code> events, hence this command
    should be invoked for them in case they are descendants of a scrollable
    widget container.&nbsp; Since this task can become tedious, Scrollutil
    makes sure that if you pass a widget to this command and that widget is
    embedded into a <a href="scrollarea.html">scrollarea</a> via the latter's
    <code><b><a href="scrollarea.html#setwidget">setwidget</a></b></code>
    subcommand, then this command will automatically be invoked for the
    scrollbars of that scrollarea, too.</dd>

    <dd class="tm"><b>REMARK 3:</b>&nbsp; When handling a mouse wheel or
    <code><b>&lt;TouchpadScroll&gt;</b></code> event sent to a Tk core or tile
    scrollbar whose path name was passed to this command without the
    <code><b>-ignorefocus</b></code> option, if the focus is on or inside the
    associated widget then the event will be processed by the scrollbar rather
    than being redirected to the containing toplevel, just as if the focus were
    on the scrollbar itself.</dd>

    <dd class="tm"><b>REMARK 4:</b>&nbsp; The mouse wheel event class bindings
    for the Tk core scrollbar on Windows and X11 were added in Tk 8.6.&nbsp;
    Prior to this Tk version there were such bindings only for the windowing
    system <code><b>aqua</b></code> on the Macintosh.&nbsp; Scrollutil
    eliminates this discrepancy by automatically creating the
    <code><b>Scrollbar</b></code> class bindings for mouse wheel events on
    Windows and X11.&nbsp; Note also that in Tk versions prior to 8.7a4 the
    ttk::scrollbar widget had no <i>built-in</i> class bindings for mouse wheel
    events, but Scrollutil automatically creates the missing bindings by
    copying the mouse wheel event bindings of the widget class
    <code><b>Scrollbar</b></code> to the binding tag
    <code><b>TScrollbar</b></code>.</dd>




















    <dd class="tm"><b>REMARK 5:</b>&nbsp; The mouse wheel event class bindings
    for the ttk::notebook widget were added in Tk 8.7a4, but Scrollutil
    automatically creates them for all Tk versions starting with 8.4.&nbsp;
    These bindings implement the navigation between the tabs of a ttk::notebook
    or <a href="scrollednotebook.html">scrollutil::scrollednotebook</a> widget
    via the mouse wheel.</dd>

    <dd class="tm"><b>REMARK 6:</b>&nbsp; The recommended invocation of this













    command is without the <code><b>-ignorefocus</b></code> option, because it
    significantly reduces the probability that the user will inadvertently
    scroll a window within a widget container containing many scrollable
    widgets.</dd>

    <dt class="tm"><b>KEYWORDS</b></dt>

    <dd>mouse wheel event, binding, event handling, scrolling, scrollable
    widget container, focus</dd>
  </dl>

  <div>
    <p><a href="#contents">Contents</a>&nbsp;&nbsp;&nbsp;&nbsp; <a href=
    "index.html">Start page</a></p>
  </div>

  <hr>

  <h2 id="prepare">The <code><b>scrollutil::prepareScrollingByWheel</b></code>
  Command</h2>

  <dl>
    <dt><b>NAME</b></dt>

    <dd><code>scrollutil::prepareScrollingByWheel</code> &ndash; Prepare
    scrollable widget containers for scrolling by the mouse wheel</dd>

    <dt class="tm"><b>SYNOPSIS</b></dt>

    <dd>
      <pre>
<b>scrollutil::prepareScrollingByWheel</b> ?<b>-ignorefocus</b>? ?<i>scrollableWidgetContainer</i> <i>scrollableWidgetContainer</i> ...?
</pre>
    </dd>

    <dt><b>REQUIRED TK VERSION</b></dt>

    <dd>8.4 or higher on X11 and Mac OS X/11+; 8.6b2 or later on Windows.</dd>

    <dt class="tm"><b>DESCRIPTION</b></dt>

    <dd>For each scrollable widget container specified as argument, this
    command prepares the scrolling with the mouse wheel and touchpad, by
    passing its descendants located in the same toplevel and having bindings
    for mouse wheel or <code><b>&lt;TouchpadScroll&gt;</b></code> events to
    <code><b><a href=
    "#adapt">scrollutil::adaptWheelEventHandling</a></b></code>.</dd>

    <dd class="tm"><b>REMARK:</b>&nbsp; If a scrollable widget container has
    many descendants then it is much safer to invoke this command than to
    manually pass a lot of widgets to
    <code><b>scrollutil::adaptWheelEventHandling</b></code>, because deciding
    which descendants to process can become tedious and error-prone.</dd>

    <dt class="tm"><b>KEYWORDS</b></dt>

    <dd>mouse wheel event, binding, scrollable widget container</dd>
  </dl>

  <div>
    <p><a href="#contents">Contents</a>&nbsp;&nbsp;&nbsp;&nbsp; <a href=
    "index.html">Start page</a></p>
  </div>

  <hr>
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623

624
625
626
627
628
629
630
631
632
633
634
635

636
637
638
639
640
641
642
643
644
645
646
      <pre>
<b>scrollutil::setFocusCheckWindow</b> <i>widget</i> ?<i>widget</i> ...? <i>otherWidget</i>
</pre>
    </dd>

    <dt><b>REQUIRED TK VERSION</b></dt>

    <dd>8.4 or higher on X11 and Mac OS X/11+; 8.6b2 or later on Windows.</dd>

    <dt class="tm"><b>DESCRIPTION</b></dt>

    <dd>For each <code><i>widget</i></code> argument, the command sets the
    associated "focus check window" to <code><i>otherWidget</i></code>.&nbsp;
    This is the window to be used in the binding scripts for the tag
    <code><b><a href="#adapt">WheeleventRedir</a></b></code> instead of the

    widget when checking whether the focus is on/inside or outside that
    window.&nbsp; For each <code><i>widget</i></code> argument,
    <code><i>otherWidget</i></code> must be an ancestor of or identical to
    <code><i>widget</i></code>.</dd>

    <dd class="tm"><b>REMARK 1:</b>&nbsp; When a widget whose path name was
    passed to this command as one of its <code><i>widget</i></code> arguments
    gets destroyed, the association between the widget and its "focus check
    window" is automatically removed.</dd>

    <dd class="tm"><b>REMARK 2:</b>&nbsp; This command comes in handy if for
    some widgets you want to make the focus check within the binding scripts

    for the tag <code><b>WheeleventRedir</b></code> less restrictive.&nbsp; For
    example, if the widget under the pointer is an entry component of a
    <a href="https://www.nemethi.de/mentry/">mentry</a> <code><i>me</i></code>
    of type <code>"Date"</code>, <code>"Time"</code>, <code>"DateTime"</code>,
    <code>"IPAddr"</code>, or <code>"IPv6Addr"</code> and the focus is on any
    of its siblings, then the mouse wheel and
    <code><b>&lt;TouchpadScroll&gt;</b></code> events sent to this entry should
    be handled by the entry widget itself rather than scrolling the widget
    container that is an ascendant of the mentry.&nbsp; You can achieve this by
    invoking</dd>








|





|
|
>
|
|










>
|
|
|
|







647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
      <pre>
<b>scrollutil::setFocusCheckWindow</b> <i>widget</i> ?<i>widget</i> ...? <i>otherWidget</i>
</pre>
    </dd>

    <dt><b>REQUIRED TK VERSION</b></dt>

    <dd>8.4 or higher.</dd>

    <dt class="tm"><b>DESCRIPTION</b></dt>

    <dd>For each <code><i>widget</i></code> argument, the command sets the
    associated "focus check window" to <code><i>otherWidget</i></code>.&nbsp;
    This is the window to be used in the binding scripts for the tags
    <code><b><a href="#adapt">WheeleventRedir</a></b></code> and
    <code><b><a href="scrollableframe.html#adapt">Btn2EventRedir</a></b></code>
    instead of the widget when checking whether the focus is on/inside or
    outside that window.&nbsp; For each <code><i>widget</i></code> argument,
    <code><i>otherWidget</i></code> must be an ancestor of or identical to
    <code><i>widget</i></code>.</dd>

    <dd class="tm"><b>REMARK 1:</b>&nbsp; When a widget whose path name was
    passed to this command as one of its <code><i>widget</i></code> arguments
    gets destroyed, the association between the widget and its "focus check
    window" is automatically removed.</dd>

    <dd class="tm"><b>REMARK 2:</b>&nbsp; This command comes in handy if for
    some widgets you want to make the focus check within the binding scripts
    for the tags <code><b>WheeleventRedir</b></code> and
    <code><b>Btn2EventRedir</b></code> less restrictive.&nbsp; For example, if
    the widget under the pointer is an entry component of a <a href=
    "https://www.nemethi.de/mentry/">mentry</a> <code><i>me</i></code> of type
    <code>"Date"</code>, <code>"Time"</code>, <code>"DateTime"</code>,
    <code>"IPAddr"</code>, or <code>"IPv6Addr"</code> and the focus is on any
    of its siblings, then the mouse wheel and
    <code><b>&lt;TouchpadScroll&gt;</b></code> events sent to this entry should
    be handled by the entry widget itself rather than scrolling the widget
    container that is an ascendant of the mentry.&nbsp; You can achieve this by
    invoking</dd>

729
730
731
732
733
734
735
736
737
738
739
740
741
742
743

744
745
746
747
748
749
750
751
752
      <pre>
<b>scrollutil::focusCheckWindow</b> <i>widget</i>
</pre>
    </dd>

    <dt><b>REQUIRED TK VERSION</b></dt>

    <dd>8.4 or higher on X11 and Mac OS X/11+; 8.6b2 or later on Windows.</dd>

    <dt class="tm"><b>DESCRIPTION</b></dt>

    <dd>Returns the path name of the "focus check window" associated with the
    <code><i>widget</i></code> argument.&nbsp; This is the window that is used
    in the binding scripts for the tag <code><b><a href=
    "#adapt">WheeleventRedir</a></b></code> instead of the widget when checking

    whether the focus is on/inside or outside that window.&nbsp; If the command
    <code><b><a href=
    "#setFocusCkWin">scrollutil::setFocusCheckWindow</a></b></code> was not
    invoked for <code><i>widget</i></code> then the return value is
    <code><i>widget</i></code> itself.</dd>

    <dt class="tm"><b>KEYWORDS</b></dt>

    <dd>binding, focus, "focus check window"</dd>







|





|
|
>
|
|







769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
      <pre>
<b>scrollutil::focusCheckWindow</b> <i>widget</i>
</pre>
    </dd>

    <dt><b>REQUIRED TK VERSION</b></dt>

    <dd>8.4 or higher.</dd>

    <dt class="tm"><b>DESCRIPTION</b></dt>

    <dd>Returns the path name of the "focus check window" associated with the
    <code><i>widget</i></code> argument.&nbsp; This is the window that is used
    in the binding scripts for the tags <code><b><a href=
    "#adapt">WheeleventRedir</a></b></code> and
    <code><b><a href="scrollableframe.html#adapt">Btn2EventRedir</a></b></code>
    instead of the widget when checking whether the focus is on/inside or
    outside that window.&nbsp; If the command <code><b><a href=
    "#setFocusCkWin">scrollutil::setFocusCheckWindow</a></b></code> was not
    invoked for <code><i>widget</i></code> then the return value is
    <code><i>widget</i></code> itself.</dd>

    <dt class="tm"><b>KEYWORDS</b></dt>

    <dd>binding, focus, "focus check window"</dd>
Changes to modules/scrollutil/scripts/scrollableframe.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#==============================================================================
# Contains the implementation of the scrollableframe widget.
#
# Structure of the module:
#   - Namespace initialization
#   - Private procedure creating the default bindings
#   - Public procedure creating a new scrollableframe widget
#   - Private configuration procedures
#   - Private procedures implementing the scrollableframe widget command
#   - Private procedures used in bindings
#
# Copyright (c) 2019-2025  Csaba Nemethi (E-mail: [email protected])
#==============================================================================







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#==============================================================================
# Contains the implementation of the scrollableframe widget.
#
# Structure of the module:
#   - Namespace initialization
#   - Private procedure creating the default bindings
#   - Public procedures
#   - Private configuration procedures
#   - Private procedures implementing the scrollableframe widget command
#   - Private procedures used in bindings
#
# Copyright (c) 2019-2025  Csaba Nemethi (E-mail: [email protected])
#==============================================================================

99
100
101
102
103
104
105
106
107

108
109
110
111
112
113
114
115
116
117
118
119
120







121
122
123
124
125
126
127
128
129
130
131
132

133
134
135
136
137
138
139
140
141
142
143
144
145
146

147
148
149
150
151

152

153
154
155

156
157
158

159
160
161
162




163
164
165
166
167
168
169
170
171
172
173
174
    variable configOpts [lsort [array names configSpecs]]

    #
    # Use lists to facilitate the handling
    # of various options and corner values
    #
    variable cmdOpts	[list attrib autofillx autofilly autosize cget \
			 configure contentframe hasattrib scan see seerect \
			 unsetattrib xview yview]

    variable scanOpts	[list mark dragto]
    variable dimensions	[list w h wh]
    variable corners	[list nw ne sw se]

    #
    # Variables used in scan-related binding scripts:
    #
    variable btn1Pressed 0
    variable scanCursor
    switch [tk windowingsystem] {
	aqua	{ set scanCursor pointinghand }
	default	{ set scanCursor hand2 }
    }







}

#
# Private procedure creating the default bindings
# ===============================================
#

#------------------------------------------------------------------------------
# scrollutil::sf::createBindings
#
# Creates the default bindings for the binding tags Scrollableframe,
# ScrollableframeMf, and ScrollableframeCf.

#------------------------------------------------------------------------------
proc scrollutil::sf::createBindings {} {
    bind Scrollableframe <KeyPress> continue
    bind Scrollableframe <<TraverseIn>> {
	set scrollutil::ns%W::data(traversedIn) 1
    }
    bind Scrollableframe <FocusIn> { scrollutil::sf::onFocusIn %W %d }
    bind Scrollableframe <Map> {
	scrollutil::sf::updateHorizPlaceOpts %W
	scrollutil::sf::updateVertPlaceOpts  %W
    }
    bind Scrollableframe <Destroy> {
	namespace delete scrollutil::ns%W
	catch {rename %W ""}

    }

    foreach class {ScrollableframeMf ScrollableframeCf} isCf {0 1} {
	bind $class <Configure> \
	    [list scrollutil::sf::on${class}Configure %W %w %h]

	bind $class <Button-1> \

	    [list scrollutil::sf::onButton1  %W %x %y $isCf]
	bind $class <B1-Motion> \
	    [list scrollutil::sf::onB1Motion %W %x %y $isCf]

	bind $class <ButtonRelease-1> \
	    [list scrollutil::sf::onButtonRelease1 %W $isCf]
    }


    bind ScrollableframeCf <<NoManagedChild>> {
	scrollutil::sf::onNoManagedChild %W
    }




}

#
# Public procedure creating a new scrollableframe widget
# ======================================================
#

#------------------------------------------------------------------------------
# scrollutil::scrollableframe
#
# Creates a new scrollableframe widget whose name is specified as the first
# command-line argument, and configures it according to the options and their







|
|
>





|

<





>
>
>
>
>
>
>











|
>











|
|
|
>





>
|
>
|
|
|
>
|
<
|
>

|
<

>
>
>
>



|
|







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

169
170
171
172

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
    variable configOpts [lsort [array names configSpecs]]

    #
    # Use lists to facilitate the handling
    # of various options and corner values
    #
    variable cmdOpts	[list attrib autofillx autofilly autosize cget \
			 configure contentframe hasattrib preparescan \
			 preparescroll scan see seerect unsetattrib xview \
			 yview]
    variable scanOpts	[list mark dragto]
    variable dimensions	[list w h wh]
    variable corners	[list nw ne sw se]

    #
    # Variable used in scan-related binding scripts:
    #

    variable scanCursor
    switch [tk windowingsystem] {
	aqua	{ set scanCursor pointinghand }
	default	{ set scanCursor hand2 }
    }

    #
    # The list of all scrollableframe widgets
    #
    variable sfList {}

    variable onAndroid [expr {[info exists ::tk::android] && $::tk::android}]
}

#
# Private procedure creating the default bindings
# ===============================================
#

#------------------------------------------------------------------------------
# scrollutil::sf::createBindings
#
# Creates the default bindings for the binding tags Scrollableframe,
# ScrollableframeMf, ScrollableframeCf, Btn2EventRedir, Btn2EventBreak, and
# all.
#------------------------------------------------------------------------------
proc scrollutil::sf::createBindings {} {
    bind Scrollableframe <KeyPress> continue
    bind Scrollableframe <<TraverseIn>> {
	set scrollutil::ns%W::data(traversedIn) 1
    }
    bind Scrollableframe <FocusIn> { scrollutil::sf::onFocusIn %W %d }
    bind Scrollableframe <Map> {
	scrollutil::sf::updateHorizPlaceOpts %W
	scrollutil::sf::updateVertPlaceOpts  %W
    }
    bind Scrollableframe <Destroy> { scrollutil::sf::onDestroy %W }

    bind ScrollableframeCf <<NoManagedChild>> {
	scrollutil::sf::onNoManagedChild %W
    }

    foreach class {ScrollableframeMf ScrollableframeCf} isCf {0 1} {
	bind $class <Configure> \
	    [list scrollutil::sf::on${class}Configure %W %w %h]
    }

    ##nagelfar ignore
    foreach event {<Button-2> <B2-Motion> <ButtonRelease-2>} {
	bind Btn2EventRedir $event [format {
	    if {![scrollutil::hasFocus %%W]} {
		event generate [winfo toplevel %%W] %s -rootx %%X -rooty %%Y
		break

	    }
	} $event]

	bind Btn2EventBreak $event { break }

    }

    bind all <Button-2>		{+ scrollutil::sf::onButton2  %W %X %Y }
    bind all <B2-Motion>	{+ scrollutil::sf::onB2Motion %W %X %Y }
    bind all <ButtonRelease-2>	{+ scrollutil::sf::onButtonRelease2 %W }
}

#
# Public procedures
# =================
#

#------------------------------------------------------------------------------
# scrollutil::scrollableframe
#
# Creates a new scrollableframe widget whose name is specified as the first
# command-line argument, and configures it according to the options and their
278
279
280
281
282
283
284






285
286
287
288
289
290
291
292
293
294
295
296
297
298











































































299
300
301
302
303
304
305
    #
    # Move the original widget command into the namespace sf within the current
    # one and create an alias of the original name for a new widget procedure
    #
    rename ::$win sf::$win
    interp alias {} ::$win {} scrollutil::sf::scrollableframeWidgetCmd $win







    #
    # Register the scrollableframe widget for scrolling by the mouse wheel
    #
    if {$::tcl_platform(platform) eq "windows"} {
	if {$::tk_version >= 8.6 &&
	    [package vcompare $::tk_patchLevel "8.6b2"] >= 0} {
	    enableScrollingByWheel $win
	}
    } else {
	enableScrollingByWheel $win
    }

    return $win
}












































































#
# Private configuration procedures
# ================================
#

#------------------------------------------------------------------------------







>
>
>
>
>
>














>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
    #
    # Move the original widget command into the namespace sf within the current
    # one and create an alias of the original name for a new widget procedure
    #
    rename ::$win sf::$win
    interp alias {} ::$win {} scrollutil::sf::scrollableframeWidgetCmd $win

    #
    # Add the scrollableframe widget to the list of all scrollableframe widgets
    #
    lappend sf::sfList $win
    set sf::sfList [lsort -command comparePaths $sf::sfList]

    #
    # Register the scrollableframe widget for scrolling by the mouse wheel
    #
    if {$::tcl_platform(platform) eq "windows"} {
	if {$::tk_version >= 8.6 &&
	    [package vcompare $::tk_patchLevel "8.6b2"] >= 0} {
	    enableScrollingByWheel $win
	}
    } else {
	enableScrollingByWheel $win
    }

    return $win
}

#------------------------------------------------------------------------------
# scrollutil::adaptBtn2EventHandling
#
# Usage: scrollutil::adaptBtn2EventHandling ?widget widget ...?
#
# For each widget argument, the command performs the following actions:
#
#   * If $widget is a tablelist then it sets the latter's -button2window option
#     to the path name of the containing toplevel window (for Tablelist
#     versions 7.6 and later).
#
#   * Otherwise it locates the (first) binding tag that has mouse button 2
#     event bindings and is different from both the path name of the containing
#     toplevel window and "all".  If the search for this tag was successful
#     then the command modifies the widget's list of binding tags by prepending
#     the tag "Btn2EventRedir" and appending the tag "Btn2EventBreak" to this
#     binding tag.  As a result, a <Button-2>, <B2-Motion>, or
#     <ButtonRelease-2> event sent to this widget will be handled as follows:
#
#       - If the focus is on or inside the window [focusCheckWindow $widget]
#         then the event will be handled by the binding script associated with
#         this tag and no further processing of the event will take place.
#
#       - If the focus is outside the window [focusCheckWindow $widget] then
#         the event will be redirected to the containing toplevel window via
#         event generate rather than being handled by the binding script
#         associated with the above-mentioned tag.
#------------------------------------------------------------------------------
proc scrollutil::adaptBtn2EventHandling args {
    foreach w $args {
	if {![winfo exists $w]} {
	    return -code error "bad window path name \"$w\""
	}

	set class [winfo class $w]
	set wTop [winfo toplevel $w]
	if {$class eq "Tablelist"} {
	    if {[package vcompare $::tablelist::version "7.6"] >= 0} {
		$w configure -button2window $wTop
	    }
	} else {
	    set w2 [expr {$class eq "Ctext" ? "$w.t" : $w}]
	    set tagList [bindtags $w2]
	    foreach tag {Btn2EventRedir Btn2EventBreak} {
		if {[set idx [lsearch -exact $tagList $tag]] >= 0} {
		    set tagList [lreplace $tagList $idx $idx]
		}
	    }

	    set idx 0
	    foreach tag $tagList {
		if {$tag eq $wTop || $tag eq "all" ||
		    [bind $tag <Button-2>] eq "" ||
		    [bind $tag <B2-Motion>] eq ""} {
		    incr idx
		    continue
		}

		bindtags $w2 [lreplace $tagList $idx $idx \
			      Btn2EventRedir $tag Btn2EventBreak]
		break
	    }
	}

	#
	# If $w is embedded into a scrollarea then invoke this
	# procedure for the scrollbars of that scrollarea, too
	#
	if {[set sa [getscrollarea $w]] ne "" && ([info level] == 1 ||
	    [lindex [info level -1] 0] ne "preparescanSubCmd")} {
	    adaptBtn2EventHandling $sa.hsb $sa.vsb
	}
    }
}

#
# Private configuration procedures
# ================================
#

#------------------------------------------------------------------------------
493
494
495
496
497
498
499










500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
	    if {$argCount != 2} {
		mwutil::wrongNumArgs "$win $cmd name"
	    }

	    return [::scrollutil::${cmd}SubCmd $win "widget" [lindex $args 1]]
	}











	scan	{ return [scanSubCmd    $win $argList] }

	see	{ return [seeSubCmd     $win $argList] }

	seerect	{ return [seerectSubCmd $win $argList] }

	xview	{ return [xviewSubCmd   $win $argList] }

	yview	{ return [yviewSubCmd   $win $argList] }
    }
}

#------------------------------------------------------------------------------
# scrollutil::sf::autofillxSubCmd
#
# Processes the scrollableframe autofillx subcommmand.







>
>
>
>
>
>
>
>
>
>
|

|

|

|

|







589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
	    if {$argCount != 2} {
		mwutil::wrongNumArgs "$win $cmd name"
	    }

	    return [::scrollutil::${cmd}SubCmd $win "widget" [lindex $args 1]]
	}

	preparescan { return [preparescanSubCmd $win $argList] }

	preparescroll {
	    if {$argCount != 1} {
		mwutil::wrongNumArgs "$win $cmd"
	    }

	    return [::scrollutil::prepareScrollingByWheel $win]
	}

	scan	{ return [scanSubCmd	$win $argList] }

	see	{ return [seeSubCmd	$win $argList] }

	seerect	{ return [seerectSubCmd	$win $argList] }

	xview	{ return [xviewSubCmd	$win $argList] }

	yview	{ return [yviewSubCmd	$win $argList] }
    }
}

#------------------------------------------------------------------------------
# scrollutil::sf::autofillxSubCmd
#
# Processes the scrollableframe autofillx subcommmand.
611
612
613
614
615
616
617




































618
619
620
621
622
623
624
	}

	after 100 [list scrollutil::sf::doAutosize $win $dimList]
    }

    return ""
}





































#------------------------------------------------------------------------------
# scrollutil::sf::scanSubCmd
#
# Processes the scrollableframe scan subcommmand.
#------------------------------------------------------------------------------
proc scrollutil::sf::scanSubCmd {win argList} {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
	}

	after 100 [list scrollutil::sf::doAutosize $win $dimList]
    }

    return ""
}

#------------------------------------------------------------------------------
# scrollutil::sf::preparescanSubCmd
#
# Processes the scrollableframe preparescan subcommmand.
#------------------------------------------------------------------------------
proc scrollutil::sf::preparescanSubCmd {win argList} {
    if {[llength $argList] != 0} {
	mwutil::wrongNumArgs "$win preparescan"
    }

    set widgetList {}
    upvar ::scrollutil::ns${win}::data data
    set winTop [winfo toplevel $win]

    #
    # Level-order traversal
    #
    set lst1 [winfo children $data(cf)]
    while {[llength $lst1] != 0} {
	set lst2 {}
	foreach w $lst1 {
	    if {[winfo toplevel $w] eq $winTop &&
		([winfo class $w] eq "Tablelist" || [hasBtn2Bindings $w])} {
		lappend widgetList $w
	    }
	    foreach child [winfo children $w] {
		lappend lst2 $child
	    }
	}
	set lst1 $lst2
    }

    eval scrollutil::adaptBtn2EventHandling $widgetList
    return ""
}

#------------------------------------------------------------------------------
# scrollutil::sf::scanSubCmd
#
# Processes the scrollableframe scan subcommmand.
#------------------------------------------------------------------------------
proc scrollutil::sf::scanSubCmd {win argList} {
642
643
644
645
646
647
648

649
650
651
652
653
654
655
656

	set data(scanX) $x
	set data(scanY) $y
	set data(scanXOffset) $data(xOffset)
	set data(scanYOffset) $data(yOffset)
    } else {
	if {$argCount == 3} {

	    set gain 10
	} elseif {$argCount == 4} {
	    ##nagelfar ignore
	    set gain [format "%d" [lindex $argList 3]]
	} else {
	    mwutil::wrongNumArgs "$win scan dragto x y ?gain?"
	}








>
|







784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799

	set data(scanX) $x
	set data(scanY) $y
	set data(scanXOffset) $data(xOffset)
	set data(scanYOffset) $data(yOffset)
    } else {
	if {$argCount == 3} {
	    variable onAndroid
	    set gain [expr {$onAndroid ? 2 : 10}]
	} elseif {$argCount == 4} {
	    ##nagelfar ignore
	    set gain [format "%d" [lindex $argList 3]]
	} else {
	    mwutil::wrongNumArgs "$win scan dragto x y ?gain?"
	}

988
989
990
991
992
993
994


















995
996
997
998
999
1000
1001
    }

    upvar ::scrollutil::ns${win}::data data
    foreach dim $dimList {
	doConfig $win -$dim [winfo req$dim $data(cf)]
    }
}



















#------------------------------------------------------------------------------
# scrollutil::sf::roundUp
#------------------------------------------------------------------------------
proc scrollutil::sf::roundUp {pixelsName scrlIncr} {
    upvar $pixelsName pixels
    if {$pixels < 0} {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
    }

    upvar ::scrollutil::ns${win}::data data
    foreach dim $dimList {
	doConfig $win -$dim [winfo req$dim $data(cf)]
    }
}

#------------------------------------------------------------------------------
# scrollutil::sf::hasBtn2Bindings
#------------------------------------------------------------------------------
proc scrollutil::sf::hasBtn2Bindings w {
    set wTop [winfo toplevel $w]
    foreach tag [bindtags $w] {
	if {$tag eq $wTop || $tag eq "all"} {
	    continue
	}

	if {[bind $tag <Button-2>] ne "" && [bind $tag <B2-Motion>] ne ""} {
	    return 1
	}
    }

    return 0
}

#------------------------------------------------------------------------------
# scrollutil::sf::roundUp
#------------------------------------------------------------------------------
proc scrollutil::sf::roundUp {pixelsName scrlIncr} {
    upvar $pixelsName pixels
    if {$pixels < 0} {
1092
1093
1094
1095
1096
1097
1098






























1099
1100
1101
1102
1103
1104
1105
	} else {
	    focus $data(cf)
	}
    }

    set data(traversedIn) 0
}































#------------------------------------------------------------------------------
# scrollutil::sf::onScrollableframeMfConfigure
#------------------------------------------------------------------------------
proc scrollutil::sf::onScrollableframeMfConfigure {mf mfWidth mfHeight} {
    set win [winfo parent $mf]
    upvar ::scrollutil::ns${win}::data data







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
	} else {
	    focus $data(cf)
	}
    }

    set data(traversedIn) 0
}

#------------------------------------------------------------------------------
# scrollutil::sf::onDestroy
#------------------------------------------------------------------------------
proc scrollutil::sf::onDestroy win {
    variable sfList
    set idx [lsearch -exact $sfList $win]
    set sfList [lreplace $sfList $idx $idx]

    namespace delete ::scrollutil::ns$win
    catch {rename ::$win ""}
}

#------------------------------------------------------------------------------
# scrollutil::sf::onNoManagedChild
#------------------------------------------------------------------------------
proc scrollutil::sf::onNoManagedChild cf {
    set win [winfo parent [winfo parent $cf]]
    upvar ::scrollutil::ns${win}::data data

    if {!$data(-fitcontentwidth) && $data(-contentwidth) <= 0} {
	$cf configure -width 1
	$cf configure -width $data(-contentwidth)
    }

    if {!$data(-fitcontentheight) && $data(-contentheight) <= 0} {
	$cf configure -height 1
	$cf configure -height $data(-contentheight)
    }
}

#------------------------------------------------------------------------------
# scrollutil::sf::onScrollableframeMfConfigure
#------------------------------------------------------------------------------
proc scrollutil::sf::onScrollableframeMfConfigure {mf mfWidth mfHeight} {
    set win [winfo parent $mf]
    upvar ::scrollutil::ns${win}::data data
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178






1179
1180
1181
1182
1183
1184

1185

1186



1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219

1220


1221
1222
1223





1224
1225
1226

1227





1228
1229
1230
1231
1232
1233


1234
1235
1236
1237
1238




1239
1240
1241
1242
1243

1244
    if {$cfHeight != $data(cfHeight)} {
	set data(cfHeight) $cfHeight
	yviewSubCmd $win {scroll 0 units}
    }
}

#------------------------------------------------------------------------------
# scrollutil::sf::onButton1
#------------------------------------------------------------------------------
proc scrollutil::sf::onButton1 {w x y isCf} {
    if {$isCf} {
	set win [winfo parent [winfo parent $w]]
	upvar ::scrollutil::ns${win}::data data
	incr x -$data(xOffset)
	incr y -$data(yOffset)
    } else {
	set win [winfo parent $w]
    }







    ::$win scan mark $x $y

    variable btn1Pressed 1
    variable origCursor [::$win cget -cursor]
    variable scanCursor
    ::$win configure -cursor $scanCursor

}





#------------------------------------------------------------------------------
# scrollutil::sf::onB1Motion
#------------------------------------------------------------------------------
proc scrollutil::sf::onB1Motion {w x y isCf} {
    variable btn1Pressed
    if {!$btn1Pressed} {
	return ""
    }

    if {$isCf} {
	set win [winfo parent [winfo parent $w]]
	upvar ::scrollutil::ns${win}::data data
	incr x -$data(xOffset)
	incr y -$data(yOffset)
    } else {
	set win [winfo parent $w]
    }

    ::$win scan dragto $x $y
}

#------------------------------------------------------------------------------
# scrollutil::sf::onButtonRelease1
#------------------------------------------------------------------------------
proc scrollutil::sf::onButtonRelease1 {w isCf} {
    variable btn1Pressed
    if {!$btn1Pressed} {
	return ""
    }

    set btn1Pressed 0

    if {$isCf} {

	set win [winfo parent [winfo parent $w]]


    } else {
	set win [winfo parent $w]
    }





    variable origCursor
    ::$win configure -cursor $origCursor
}







#------------------------------------------------------------------------------
# scrollutil::sf::onNoManagedChild
#------------------------------------------------------------------------------
proc scrollutil::sf::onNoManagedChild cf {
    set win [winfo parent [winfo parent $cf]]
    upvar ::scrollutil::ns${win}::data data



    if {!$data(-fitcontentwidth) && $data(-contentwidth) <= 0} {
	$cf configure -width 1
	$cf configure -width $data(-contentwidth)
    }





    if {!$data(-fitcontentheight) && $data(-contentheight) <= 0} {
	$cf configure -height 1
	$cf configure -height $data(-contentheight)
    }

}







|

|
|
<
<
|
<
<
<


>
>
>
>
>
>
|

<
|
|
|
>
|
>
|
>
>
>

|

|
<
|



|
<
|
|
<
|
|
<
|
|
|
<
<
<
<
<
<
<
|
|
|
<
|
|
>
|
>
>
|
|

>
>
>
>
>
|
|
<
>

>
>
>
>
>

|

|
<
<
>
>
|
<
<
<
|
>
>
>
>
|
<
<
<
|
>

1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361


1362



1363
1364
1365
1366
1367
1368
1369
1370
1371
1372

1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386

1387
1388
1389
1390
1391

1392
1393

1394
1395

1396
1397
1398







1399
1400
1401

1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417

1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428


1429
1430
1431



1432
1433
1434
1435
1436
1437



1438
1439
1440
    if {$cfHeight != $data(cfHeight)} {
	set data(cfHeight) $cfHeight
	yviewSubCmd $win {scroll 0 units}
    }
}

#------------------------------------------------------------------------------
# scrollutil::sf::onButton2
#------------------------------------------------------------------------------
proc scrollutil::sf::onButton2 {w rootX rootY} {
    if {[hasBtn2Bindings $w]} {


	return ""



    }

    variable sfList
    variable btn2Win [winfo containing -displayof $w $rootX $rootY]
    foreach win $sfList {
	if {[mayScan $win $btn2Win]} {
	    set x [expr {$rootX - [winfo x $win]}]
	    set y [expr {$rootY - [winfo y $win]}]
	    ::$win scan mark $x $y


	    variable origCursor [::$win cget -cursor]
	    variable scanCursor
	    ::$win configure -cursor $scanCursor
	    catch {$btn2Win configure -cursor $scanCursor}

	    return ""
	}
    }
}

#------------------------------------------------------------------------------
# scrollutil::sf::onB2Motion
#------------------------------------------------------------------------------
proc scrollutil::sf::onB2Motion {w rootX rootY} {

    if {[hasBtn2Bindings $w]} {
	return ""
    }

    variable sfList

    variable btn2Win
    foreach win $sfList {

	if {[mayScan $win $btn2Win]} {
	    set x [expr {$rootX - [winfo x $win]}]

	    set y [expr {$rootY - [winfo y $win]}]
	    ::$win scan dragto $x $y








	    return ""
	}
    }

}

#------------------------------------------------------------------------------
# scrollutil::sf::onButtonRelease2
#------------------------------------------------------------------------------
proc scrollutil::sf::onButtonRelease2 w {
    if {[hasBtn2Bindings $w]} {
	return ""
    }

    variable sfList
    variable btn2Win
    foreach win $sfList {
	if {[mayScan $win $btn2Win]} {
	    variable origCursor
	    ::$win configure -cursor $origCursor

	    catch {$btn2Win configure -cursor $origCursor}

	    return ""
	}
    }
}

#------------------------------------------------------------------------------
# scrollutil::sf::mayScan
#------------------------------------------------------------------------------
proc scrollutil::sf::mayScan {sf w} {


    if {[string first $sf. $w.] != 0} {    ;# $w is not (a descendant of) $sf
	return 0
    }




    set sfTop [winfo toplevel $sf]
    set wTop [winfo toplevel $w]
    if {$sfTop ne $wTop} {		;# $sf and $w have different toplevels
	return 0
    }




    return 1
}
Changes to modules/scrollutil/scripts/tclIndex.
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86

87
88
89
90
91
92

93
94
95
96
97


98
99
100
101
102
103
104
105
106
107
108
109
110
set auto_index(::scrollutil::pnb::tabToWidget) [list source [file join $dir plainnotebook.tcl]]
set auto_index(::scrollutil::pnb::tabToPnb) [list source [file join $dir plainnotebook.tcl]]
set auto_index(::scrollutil::pnb::mfToPnb) [list source [file join $dir plainnotebook.tcl]]
set auto_index(::scrollutil::pnb::destroyed) [list source [file join $dir plainnotebook.tcl]]
set auto_index(::scrollutil::sf::extendConfigSpecs) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::createBindings) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::scrollableframe) [list source [file join $dir scrollableframe.tcl]]

set auto_index(::scrollutil::sf::doConfig) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::doCget) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::updateHorizPlaceOpts) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::updateVertPlaceOpts) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::scrollableframeWidgetCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::autofillxSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::autofillySubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::autosizeSubCmd) [list source [file join $dir scrollableframe.tcl]]

set auto_index(::scrollutil::sf::scanSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::seeSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::seerectSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::xviewSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::yviewSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::doAutosize) [list source [file join $dir scrollableframe.tcl]]

set auto_index(::scrollutil::sf::roundUp) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::roundDn) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::roundUpOrDn) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::applyOffset) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onFocusIn) [list source [file join $dir scrollableframe.tcl]]


set auto_index(::scrollutil::sf::onScrollableframeMfConfigure) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onScrollableframeCfConfigure) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onButton1) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onB1Motion) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onButtonRelease1) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onNoManagedChild) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::restoreScalingpct) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::sa::extendConfigSpecs) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::sa::createBindings) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::scrollarea) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::getscrollarea) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::sa::doConfig) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::sa::doCget) [list source [file join $dir scrollarea.tcl]]







>








>






>





>
>


|
|
|
|







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
set auto_index(::scrollutil::pnb::tabToWidget) [list source [file join $dir plainnotebook.tcl]]
set auto_index(::scrollutil::pnb::tabToPnb) [list source [file join $dir plainnotebook.tcl]]
set auto_index(::scrollutil::pnb::mfToPnb) [list source [file join $dir plainnotebook.tcl]]
set auto_index(::scrollutil::pnb::destroyed) [list source [file join $dir plainnotebook.tcl]]
set auto_index(::scrollutil::sf::extendConfigSpecs) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::createBindings) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::scrollableframe) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::adaptBtn2EventHandling) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::doConfig) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::doCget) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::updateHorizPlaceOpts) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::updateVertPlaceOpts) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::scrollableframeWidgetCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::autofillxSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::autofillySubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::autosizeSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::preparescanSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::scanSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::seeSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::seerectSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::xviewSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::yviewSubCmd) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::doAutosize) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::hasBtn2Bindings) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::roundUp) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::roundDn) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::roundUpOrDn) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::applyOffset) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onFocusIn) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onDestroy) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onNoManagedChild) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onScrollableframeMfConfigure) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onScrollableframeCfConfigure) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onButton2) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onB2Motion) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::onButtonRelease2) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::sf::mayScan) [list source [file join $dir scrollableframe.tcl]]
set auto_index(::scrollutil::restoreScalingpct) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::sa::extendConfigSpecs) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::sa::createBindings) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::scrollarea) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::getscrollarea) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::sa::doConfig) [list source [file join $dir scrollarea.tcl]]
set auto_index(::scrollutil::sa::doCget) [list source [file join $dir scrollarea.tcl]]
200
201
202
203
204
205
206

207
208
209
210
211
212
213
214
215
216
217
218
219
220

221
222
set auto_index(::scrollutil::ss::unlockView) [list source [file join $dir scrollsync.tcl]]
set auto_index(::scrollutil::createBindings) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::addMouseWheelSupport) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::createWheelEventBindings) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::enableScrollingByWheel) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::disableScrollingByWheel) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::adaptWheelEventHandling) [list source [file join $dir wheelEvent.tcl]]

set auto_index(::scrollutil::setFocusCheckWindow) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::focusCheckWindow) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::bindMouseWheel) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::scrollByUnits) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::hasFocus) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::isCompatible) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::cycleMenuEntry1) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::cycleMenuEntry2) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::scaleIncrement1) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::ttkScaleIncrement1) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::scaleIncrement2) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::ttkScaleIncrement2) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::comparePaths) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::scrollByUnits) [list source [file join $dir wheelEvent.tcl]]

set auto_index(::scrollutil::mayScroll) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::onScrlWidgetContDestroy) [list source [file join $dir wheelEvent.tcl]]







>



|










>


205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
set auto_index(::scrollutil::ss::unlockView) [list source [file join $dir scrollsync.tcl]]
set auto_index(::scrollutil::createBindings) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::addMouseWheelSupport) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::createWheelEventBindings) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::enableScrollingByWheel) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::disableScrollingByWheel) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::adaptWheelEventHandling) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::prepareScrollingByWheel) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::setFocusCheckWindow) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::focusCheckWindow) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::bindMouseWheel) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::condScrollByUnits) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::hasFocus) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::isCompatible) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::cycleMenuEntry1) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::cycleMenuEntry2) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::scaleIncrement1) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::ttkScaleIncrement1) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::scaleIncrement2) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::ttkScaleIncrement2) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::comparePaths) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::scrollByUnits) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::hasWheelBindings) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::mayScroll) [list source [file join $dir wheelEvent.tcl]]
set auto_index(::scrollutil::onScrlWidgetContDestroy) [list source [file join $dir wheelEvent.tcl]]
Changes to modules/scrollutil/scripts/wheelEvent.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#==============================================================================
# Contains procedures related to mouse wheel event handling in scrollable
# widgets and scrollable widget containers like scrollutil::scrollableframe,
# BWidget ScrollableFrame, and iwidgets::scrolledframe.  Tested also with the
# scrolledframe::scrolledframe command of the Scrolledframe package by Maurice
# Bredelet (ulis) and its optimized and enhanced version contributed by Keith
# Nash, as well as with the sframe command implemented by Paul Walton (see
# https://wiki.tcl-lang.org/page/A+scrolled+frame).
#
# Structure of the module:
#   - Namespace initialization
#   - Private procedure creating mouse wheel event and <Destroy> bindings
#   - Public procedures
#   - Private procedures
#
# Copyright (c) 2019-2025  Csaba Nemethi (E-mail: [email protected])
#==============================================================================

#











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#==============================================================================
# Contains procedures related to mouse wheel event handling in scrollable
# widgets and scrollable widget containers like scrollutil::scrollableframe,
# BWidget ScrollableFrame, and iwidgets::scrolledframe.  Tested also with the
# scrolledframe::scrolledframe command of the Scrolledframe package by Maurice
# Bredelet (ulis) and its optimized and enhanced version contributed by Keith
# Nash, as well as with the sframe command implemented by Paul Walton (see
# https://wiki.tcl-lang.org/page/A+scrolled+frame).
#
# Structure of the module:
#   - Namespace initialization
#   - Private procedure creating mouse wheel and <Destroy> event bindings
#   - Public procedures
#   - Private procedures
#
# Copyright (c) 2019-2025  Csaba Nemethi (E-mail: [email protected])
#==============================================================================

#
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
	[package vcompare $::tk_patchLevel "8.7a4"] >= 0}]

    variable touchpadScrollSupport [expr {
	[llength [info commands ::tk::PreciseScrollDeltas]] != 0}]
}

#
# Private procedure creating mouse wheel event and <Destroy> bindings
# ===================================================================
#

#------------------------------------------------------------------------------
# scrollutil::createBindings
#
# Creates mouse wheel event bindings for the binding tags Scrollbar,
# TScrollbar, WheeleventRedir, and WheeleventBreak, as well as <Destroy>
# bindings for the binding tags ScrlWidgetCont and WheeleventWidget.
#------------------------------------------------------------------------------
proc scrollutil::createBindings {} {
    variable winSys
    variable uniformWheelSupport

    #
    # On the windowing systems win32 and x11 there are no built-in mouse wheel
    # event bindings for the binding tag Scrollbar if the Tk version is earlier
    # than 8.6 -- create them here.  In addition, implement the behavior
    # specified by TIP 563 (i.e., the mouse wheel should scroll a horizontal or
    # vertical scrollbar regardless of whether the "Shift" key is down or not)
    #
    bind Scrollbar <Enter> {+
	if {![info exists tk::Priv(xEvents)]} {
	    set scrollutil::xWheelEvents 0; set scrollutil::yWheelEvents 0
	}
    }
    if {$uniformWheelSupport} {
	bind Scrollbar <MouseWheel> {
	    scrollutil::scrollByUnits %W vh %D -40.0
	}
	bind Scrollbar <Option-MouseWheel> {
	    scrollutil::scrollByUnits %W vh %D -12.0
	}
	bind Scrollbar <Shift-MouseWheel> {
	    scrollutil::scrollByUnits %W hv %D -40.0
	}
	bind Scrollbar <Shift-Option-MouseWheel> {
	    scrollutil::scrollByUnits %W hv %D -12.0
	}
    } else {
	if {$winSys eq "aqua"} {
	    bind Scrollbar <MouseWheel> {
		scrollutil::scrollByUnits %W vh [expr {-(%D)}]
	    }
	    bind Scrollbar <Option-MouseWheel> {
		scrollutil::scrollByUnits %W vh [expr {-10 * (%D)}]
	    }
	    bind Scrollbar <Shift-MouseWheel> {
		scrollutil::scrollByUnits %W hv [expr {-(%D)}]
	    }
	    bind Scrollbar <Shift-Option-MouseWheel> {
		scrollutil::scrollByUnits %W hv [expr {-10 * (%D)}]
	    }
	} else {
	    bind Scrollbar <MouseWheel> {
		scrollutil::scrollByUnits %W vh \
		    [expr {%D >= 0 ? (-%D) / 30 : (-(%D) + 29) / 30}]
	    }
	    bind Scrollbar <Shift-MouseWheel> {
		scrollutil::scrollByUnits %W hv \
		    [expr {%D >= 0 ? (-%D) / 30 : (-(%D) + 29) / 30}]
	    }

	    if {$winSys eq "x11"} {
		bind Scrollbar <Button-4> {
		    scrollutil::scrollByUnits %W vh -5
		}
		bind Scrollbar <Button-5> {
		    scrollutil::scrollByUnits %W vh  5
		}
		bind Scrollbar <Shift-Button-4> {
		    scrollutil::scrollByUnits %W hv -5
		}
		bind Scrollbar <Shift-Button-5> {
		    scrollutil::scrollByUnits %W hv  5
		}

		if {$::tk_patchLevel eq "8.7a3"} {
		    bind Scrollbar <Button-6> {
			scrollutil::scrollByUnits %W hv -5
		    }
		    bind Scrollbar <Button-7> {
			scrollutil::scrollByUnits %W hv  5
		    }
		}
	    }
	}
    }

    set eventList [list <MouseWheel> <Shift-MouseWheel>]







|







|




















|


|


|


|




|


|


|


|



|



|





|


|


|


|




|


|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
	[package vcompare $::tk_patchLevel "8.7a4"] >= 0}]

    variable touchpadScrollSupport [expr {
	[llength [info commands ::tk::PreciseScrollDeltas]] != 0}]
}

#
# Private procedure creating mouse wheel and <Destroy> event bindings
# ===================================================================
#

#------------------------------------------------------------------------------
# scrollutil::createBindings
#
# Creates mouse wheel event bindings for the binding tags Scrollbar,
# TScrollbar, WheeleventRedir, and WheeleventBreak, as well as <Destroy> event
# bindings for the binding tags ScrlWidgetCont and WheeleventWidget.
#------------------------------------------------------------------------------
proc scrollutil::createBindings {} {
    variable winSys
    variable uniformWheelSupport

    #
    # On the windowing systems win32 and x11 there are no built-in mouse wheel
    # event bindings for the binding tag Scrollbar if the Tk version is earlier
    # than 8.6 -- create them here.  In addition, implement the behavior
    # specified by TIP 563 (i.e., the mouse wheel should scroll a horizontal or
    # vertical scrollbar regardless of whether the "Shift" key is down or not)
    #
    bind Scrollbar <Enter> {+
	if {![info exists tk::Priv(xEvents)]} {
	    set scrollutil::xWheelEvents 0; set scrollutil::yWheelEvents 0
	}
    }
    if {$uniformWheelSupport} {
	bind Scrollbar <MouseWheel> {
	    scrollutil::condScrollByUnits %W vh %D -40.0
	}
	bind Scrollbar <Option-MouseWheel> {
	    scrollutil::condScrollByUnits %W vh %D -12.0
	}
	bind Scrollbar <Shift-MouseWheel> {
	    scrollutil::condScrollByUnits %W hv %D -40.0
	}
	bind Scrollbar <Shift-Option-MouseWheel> {
	    scrollutil::condScrollByUnits %W hv %D -12.0
	}
    } else {
	if {$winSys eq "aqua"} {
	    bind Scrollbar <MouseWheel> {
		scrollutil::condScrollByUnits %W vh [expr {-(%D)}]
	    }
	    bind Scrollbar <Option-MouseWheel> {
		scrollutil::condScrollByUnits %W vh [expr {-10 * (%D)}]
	    }
	    bind Scrollbar <Shift-MouseWheel> {
		scrollutil::condScrollByUnits %W hv [expr {-(%D)}]
	    }
	    bind Scrollbar <Shift-Option-MouseWheel> {
		scrollutil::condScrollByUnits %W hv [expr {-10 * (%D)}]
	    }
	} else {
	    bind Scrollbar <MouseWheel> {
		scrollutil::condScrollByUnits %W vh \
		    [expr {%D >= 0 ? (-%D) / 30 : (-(%D) + 29) / 30}]
	    }
	    bind Scrollbar <Shift-MouseWheel> {
		scrollutil::condScrollByUnits %W hv \
		    [expr {%D >= 0 ? (-%D) / 30 : (-(%D) + 29) / 30}]
	    }

	    if {$winSys eq "x11"} {
		bind Scrollbar <Button-4> {
		    scrollutil::condScrollByUnits %W vh -5
		}
		bind Scrollbar <Button-5> {
		    scrollutil::condScrollByUnits %W vh  5
		}
		bind Scrollbar <Shift-Button-4> {
		    scrollutil::condScrollByUnits %W hv -5
		}
		bind Scrollbar <Shift-Button-5> {
		    scrollutil::condScrollByUnits %W hv  5
		}

		if {$::tk_patchLevel eq "8.7a3"} {
		    bind Scrollbar <Button-6> {
			scrollutil::condScrollByUnits %W hv -5
		    }
		    bind Scrollbar <Button-7> {
			scrollutil::condScrollByUnits %W hv  5
		    }
		}
	    }
	}
    }

    set eventList [list <MouseWheel> <Shift-MouseWheel>]
735
736
737
738
739
740
741

742





743
744
745
746
747
748


749
750

751
752
753
754
755
756
757
758
759
760
761
762

763
764
765
766
767
768
769
770
771

772
773
774
775
776
777
778
779




































































780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
	    set tagList [bindtags $w2]
	    foreach tag {WheeleventRedir WheeleventBreak} {
		if {[set idx [lsearch -exact $tagList $tag]] >= 0} {
		    set tagList [lreplace $tagList $idx $idx]
		}
	    }


	    foreach tag $tagList {





		if {$winSys eq "x11" && !$uniformWheelSupport} {
		    set hasWheelBindings [expr {[bind $tag <Button-4>] ne ""}]
		} else {
		    set hasWheelBindings [expr {
			[bind $tag <MouseWheel>] ne "" ||
			[bind $tag <TouchpadScroll>] ne ""}]


		}
		if {$tag eq $wTop || $tag eq "all" || !$hasWheelBindings} {

		    continue
		}

		set idx [lsearch -exact $tagList $tag]
		if {$ignoreFocus} {
		    bindtags $w2 [lreplace $tagList $idx $idx \
				  $tag WheeleventBreak]
		} else {
		    bindtags $w2 [lreplace $tagList $idx $idx \
				  WheeleventRedir $tag WheeleventBreak]
		}
		break

	    }
	}

	#
	# If $w is embedded into a scrollarea then invoke this
	# procedure for the scrollbars of that scrollarea, too
	#
	set sa [getscrollarea $w]
	if {$sa ne ""} {

	    if {$ignoreFocus} {
		adaptWheelEventHandling -ignorefocus $sa.hsb $sa.vsb
	    } else {
		adaptWheelEventHandling $sa.hsb $sa.vsb
	    }
	}
    }
}





































































#------------------------------------------------------------------------------
# scrollutil::setFocusCheckWindow
#
# Usage: scrollutil::setFocusCheckWindow widget ?widget ...? otherWidget
#
# For each widget argument, the command sets the associated "focus check
# window" to otherWidget.  This is the window to be used instead of the widget
# when checking whether the focus is on/inside or outside that window.  It must
# be an ancestor of or identical to widget.
#------------------------------------------------------------------------------
proc scrollutil::setFocusCheckWindow args {
    variable winSys
    if {$winSys eq "win32"} {
	package require Tk 8.6b2-
    }

    set argCount [llength $args]
    if {$argCount < 2} {
	return -code error "wrong # args: should be\
	    \"scrollutil::setFocusCheckWindow widget ?widget ...? otherWidget\""
    }

    foreach w $args {







>

>
>
>
>
>
|
<
<



>
>

|
>



<








>







|
|
>








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>












<
<
<
<
<







735
736
737
738
739
740
741
742
743
744
745
746
747
748
749


750
751
752
753
754
755
756
757
758
759
760

761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867





868
869
870
871
872
873
874
	    set tagList [bindtags $w2]
	    foreach tag {WheeleventRedir WheeleventBreak} {
		if {[set idx [lsearch -exact $tagList $tag]] >= 0} {
		    set tagList [lreplace $tagList $idx $idx]
		}
	    }

	    set idx 0
	    foreach tag $tagList {
		if {$tag eq $wTop || $tag eq "all"} {
		    incr idx
		    continue
		}

		if {$winSys ne "x11" || $uniformWheelSupport} {


		    set hasWheelBindings [expr {
			[bind $tag <MouseWheel>] ne "" ||
			[bind $tag <TouchpadScroll>] ne ""}]
		} else {
		    set hasWheelBindings [expr {[bind $tag <Button-4>] ne ""}]
		}
		if {!$hasWheelBindings} {
		    incr idx
		    continue
		}


		if {$ignoreFocus} {
		    bindtags $w2 [lreplace $tagList $idx $idx \
				  $tag WheeleventBreak]
		} else {
		    bindtags $w2 [lreplace $tagList $idx $idx \
				  WheeleventRedir $tag WheeleventBreak]
		}
		break

	    }
	}

	#
	# If $w is embedded into a scrollarea then invoke this
	# procedure for the scrollbars of that scrollarea, too
	#
	if {[set sa [getscrollarea $w]] ne "" && ([info level] == 1 ||
	    [lindex [info level -1] 0] ne
	    "scrollutil::prepareScrollingByWheel")} {
	    if {$ignoreFocus} {
		adaptWheelEventHandling -ignorefocus $sa.hsb $sa.vsb
	    } else {
		adaptWheelEventHandling $sa.hsb $sa.vsb
	    }
	}
    }
}

#------------------------------------------------------------------------------
# scrollutil::prepareScrollingByWheel
#
# Usage: scrollutil::prepareScrollingByWheel ?-ignorefocus?
#	 ?scrlWidgetCont scrlWidgetCont ...?
#
# For each scrollable widget container specified as argument, this command
# passes its descendants located in the same toplevel and having bindings for
# mouse wheel or <TouchpadScroll> events to scrollutil::adaptWheelEventHandling.
#------------------------------------------------------------------------------
proc scrollutil::prepareScrollingByWheel args {
    variable winSys
    if {$winSys eq "win32"} {
	package require Tk 8.6b2-
    }

    set ignoreFocus 0
    set arg0 [lindex $args 0]
    if {[string length $arg0] > 1 && [string first $arg0 "-ignorefocus"] == 0} {
	set ignoreFocus 1
	set args [lrange $args 1 end]
    }

    foreach swc $args {
	if {![winfo exists $swc]} {
	    return -code error "bad window path name \"$swc\""
	}

	if {[catch {$swc xview scroll 0 units}] != 0} {
	    return -code error \
		"widget $swc fails to support horizontal scrolling by units"
	}

	if {[catch {$swc yview scroll 0 units}] != 0} {
	    return -code error \
		"widget $swc fails to support vertical scrolling by units"
	}

	set widgetList {}
	set swcTop [winfo toplevel $swc]

	#
	# Level-order traversal
	#
	set lst1 [winfo children $swc]
	while {[llength $lst1] != 0} {
	    set lst2 {}
	    foreach w $lst1 {
		if {[winfo toplevel $w] eq $swcTop &&
		    ([winfo class $w] eq "Tablelist" ||
		     [hasWheelBindings $w])} {
		    lappend widgetList $w
		}
		foreach child [winfo children $w] {
		    lappend lst2 $child
		}
	    }
	    set lst1 $lst2
	}

	if {$ignoreFocus} {
	    eval adaptWheelEventHandling -ignorefocus $widgetList
	} else {
	    eval adaptWheelEventHandling $widgetList
	}
    }
}

#------------------------------------------------------------------------------
# scrollutil::setFocusCheckWindow
#
# Usage: scrollutil::setFocusCheckWindow widget ?widget ...? otherWidget
#
# For each widget argument, the command sets the associated "focus check
# window" to otherWidget.  This is the window to be used instead of the widget
# when checking whether the focus is on/inside or outside that window.  It must
# be an ancestor of or identical to widget.
#------------------------------------------------------------------------------
proc scrollutil::setFocusCheckWindow args {





    set argCount [llength $args]
    if {$argCount < 2} {
	return -code error "wrong # args: should be\
	    \"scrollutil::setFocusCheckWindow widget ?widget ...? otherWidget\""
    }

    foreach w $args {
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
#
# Returns the "focus check window" associated with widget.  This is the window
# that is used instead of the widget when checking whether the focus is
# on/inside or outside that window.  If the command setFocusCheckWindow was not
# invoked for widget then the return value is widget itself.
#------------------------------------------------------------------------------
proc scrollutil::focusCheckWindow w {
    variable winSys
    if {$winSys eq "win32"} {
	package require Tk 8.6b2-
    }

    if {![winfo exists $w]} {
	return -code error "bad window path name \"$w\""
    }

    variable focusCheckWinArr
    return [expr {[info exists focusCheckWinArr($w)] ?
		  $focusCheckWinArr($w) : $w}]







<
<
<
<
<







909
910
911
912
913
914
915





916
917
918
919
920
921
922
#
# Returns the "focus check window" associated with widget.  This is the window
# that is used instead of the widget when checking whether the focus is
# on/inside or outside that window.  If the command setFocusCheckWindow was not
# invoked for widget then the return value is widget itself.
#------------------------------------------------------------------------------
proc scrollutil::focusCheckWindow w {





    if {![winfo exists $w]} {
	return -code error "bad window path name \"$w\""
    }

    variable focusCheckWinArr
    return [expr {[info exists focusCheckWinArr($w)] ?
		  $focusCheckWinArr($w) : $w}]
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946

#
# Private procedures
# ==================
#

#------------------------------------------------------------------------------
# scrollutil::scrollByUnits
#------------------------------------------------------------------------------
proc scrollutil::scrollByUnits {w orient amount {divisor 1.0}} {
    if {![info exists ::tk::Priv(xEvents)]} {
	#
	# Count both the <MouseWheel> and <Shift-MouseWheel>
	# events, and ignore the non-dominant ones
	#
	variable xWheelEvents
	variable yWheelEvents







|

|







996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012

#
# Private procedures
# ==================
#

#------------------------------------------------------------------------------
# scrollutil::condScrollByUnits
#------------------------------------------------------------------------------
proc scrollutil::condScrollByUnits {w orient amount {divisor 1.0}} {
    if {![info exists ::tk::Priv(xEvents)]} {
	#
	# Count both the <MouseWheel> and <Shift-MouseWheel>
	# events, and ignore the non-dominant ones
	#
	variable xWheelEvents
	variable yWheelEvents
994
995
996
997
998
999
1000



1001
1002
1003
1004
1005
1006
1007
    if {[string match "*Scrollbar" [winfo class $w]] &&
	[string match {<Shift-*>} $event]} {
	return 1
    } else {
	set tagList [bindtags $w]
	set idx [lsearch -exact $tagList "WheeleventRedir"]
	set tag [lindex $tagList [incr idx]]



	return [expr {[bind $tag $event] ne ""}]
    }
}

#------------------------------------------------------------------------------
# scrollutil::cycleMenuEntry1
#------------------------------------------------------------------------------







>
>
>







1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
    if {[string match "*Scrollbar" [winfo class $w]] &&
	[string match {<Shift-*>} $event]} {
	return 1
    } else {
	set tagList [bindtags $w]
	set idx [lsearch -exact $tagList "WheeleventRedir"]
	set tag [lindex $tagList [incr idx]]
	if {$tag eq "Btn2EventRedir"} {
	    set tag [lindex $tagList [incr idx]]
	}
	return [expr {[bind $tag $event] ne ""}]
    }
}

#------------------------------------------------------------------------------
# scrollutil::cycleMenuEntry1
#------------------------------------------------------------------------------
1129
1130
1131
1132
1133
1134
1135




1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147




























1148
1149
1150
1151
1152
1153
1154
    }
}

#------------------------------------------------------------------------------
# scrollutil::scrollByUnits
#------------------------------------------------------------------------------
proc scrollutil::scrollByUnits {w rootX rootY axis delta divisor} {




    set w [winfo containing -displayof $w $rootX $rootY]
    variable scrlWidgetContList
    foreach swc $scrlWidgetContList {
	if {[mayScroll $swc $w]} {
	    set number [expr {$delta/$divisor}]
	    set number \
		[expr {int($number > 0 ? ceil($number) : floor($number))}]
	    $swc ${axis}view scroll $number units
	    return -code break ""
	}
    }
}





























#------------------------------------------------------------------------------
# scrollutil::mayScroll
#------------------------------------------------------------------------------
proc scrollutil::mayScroll {swc w} {
    if {[string first $swc. $w.] != 0} {    ;# $w is not (a descendant of) $swc
	return 0







>
>
>
>












>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
    }
}

#------------------------------------------------------------------------------
# scrollutil::scrollByUnits
#------------------------------------------------------------------------------
proc scrollutil::scrollByUnits {w rootX rootY axis delta divisor} {
    if {[hasWheelBindings $w]} {
	return ""
    }

    set w [winfo containing -displayof $w $rootX $rootY]
    variable scrlWidgetContList
    foreach swc $scrlWidgetContList {
	if {[mayScroll $swc $w]} {
	    set number [expr {$delta/$divisor}]
	    set number \
		[expr {int($number > 0 ? ceil($number) : floor($number))}]
	    $swc ${axis}view scroll $number units
	    return -code break ""
	}
    }
}

#------------------------------------------------------------------------------
# scrollutil::hasWheelBindings
#------------------------------------------------------------------------------
proc scrollutil::hasWheelBindings w {
    variable winSys
    variable uniformWheelSupport

    set wTop [winfo toplevel $w]
    foreach tag [bindtags $w] {
	if {$tag eq $wTop || $tag eq "all"} {
	    continue
	}

	if {$winSys ne "x11" || $uniformWheelSupport} {
	    if {[bind $tag <MouseWheel>] ne "" ||
		[bind $tag <TouchpadScroll>] ne ""} {
		return 1
	    }
	} else {
	    if {[bind $tag <Button-4>] ne ""} {
		return 1
	    }
	}
    }

    return 0
}

#------------------------------------------------------------------------------
# scrollutil::mayScroll
#------------------------------------------------------------------------------
proc scrollutil::mayScroll {swc w} {
    if {[string first $swc. $w.] != 0} {    ;# $w is not (a descendant of) $swc
	return 0
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
    if {[winfo class $swc] eq "Scrolledframe" &&
	[llength [info commands ::iwidgets::scrolledframe]] != 0 &&
	($w eq [$swc component horizsb] || $w eq [$swc component vertsb])} {
	return 0
    }

    #
    # Don't scroll the window $swc if the toplevel window of any
    # combobox widget contained in it is currently popped down
    #
    set toplevelList [wm stackorder $swcTop]
    if {[llength $toplevelList] == 1} {
	return 1
    } else {
	foreach top $toplevelList {







|







1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
    if {[winfo class $swc] eq "Scrolledframe" &&
	[llength [info commands ::iwidgets::scrolledframe]] != 0 &&
	($w eq [$swc component horizsb] || $w eq [$swc component vertsb])} {
	return 0
    }

    #
    # Don't scroll the widget $swc if the toplevel window of any
    # combobox widget contained in it is currently popped down
    #
    set toplevelList [wm stackorder $swcTop]
    if {[llength $toplevelList] == 1} {
	return 1
    } else {
	foreach top $toplevelList {