Tk Library Source Code

Check-in [87a5b58271]
Login

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

Overview
Comment:Tsw: Updated for version 1.1. See the ChangeLog for details.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 87a5b5827145db84024d69ce9731a3cafb59d10d83aee2b4cd7c6f3a35e277d6
User & Date: csaba 2025-05-17 16:33:07.426
Context
2025-05-21
18:16
Wcb: Updated for version 4.2. See the ChangeLog for details. check-in: 48048ea4d3 user: csaba tags: trunk
2025-05-17
16:33
Tsw: Updated for version 1.1. See the ChangeLog for details. check-in: 87a5b58271 user: csaba tags: trunk
12:53
Scrollutil: Made tclIndex file usable with Tcl/Tk 8.4, too. check-in: a1d3f90036 user: csaba tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to examples/tsw/EditingOpts.tcl.
41
42
43
44
45
46
47









48
49
50
51
52
53
54

#
# Create the images "checkedImg" and "uncheckedImg", as well as 16 images of
# names like "img#FF0000", displaying colors identified by names like "red"
#
source [file join $dir images.tcl]










#
# Improve the window's appearance by using a tile
# frame as a container for the other widgets
#
set f [ttk::frame .f]

#







>
>
>
>
>
>
>
>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

#
# Create the images "checkedImg" and "uncheckedImg", as well as 16 images of
# names like "img#FF0000", displaying colors identified by names like "red"
#
source [file join $dir images.tcl]

#
# Register the toggleswitch widget for interactive cell editing if supported
#
if {[catch {tablelist::addToggleswitch}] == 0} {	;# Tablelist 7.5+
    set editWin toggleswitch
} else {
    set editWin ttk::checkbutton
}

#
# Improve the window's appearance by using a tile
# frame as a container for the other widgets
#
set f [ttk::frame .f]

#
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
if {$isAwTheme && ![regexp {^(aw)?(arc|breeze.*)$} $currentTheme]} {
    $tbl configure -borderwidth 2
}
if {[$tbl cget -selectborderwidth] == 0} {
    $tbl configure -spacing 1
}
$tbl columnconfigure 0 -sortmode integer
$tbl columnconfigure 1 -name available -editable yes \
    -editwindow ttk::checkbutton -formatcommand emptyStr \
    -labelwindow ttk::checkbutton
$tbl columnconfigure 2 -name lineName  -editable yes -editwindow ttk::entry \
    -allowduplicates 0 -sortmode dictionary
$tbl columnconfigure 3 -name baudRate  -editable yes -editwindow ttk::combobox \
    -sortmode integer
$tbl columnconfigure 4 -name dataBits  -editable yes -editwindow ttk::spinbox
$tbl columnconfigure 5 -name parity    -editable yes -editwindow ttk::combobox
$tbl columnconfigure 6 -name stopBits  -editable yes -editwindow ttk::combobox







|
<
|







81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
if {$isAwTheme && ![regexp {^(aw)?(arc|breeze.*)$} $currentTheme]} {
    $tbl configure -borderwidth 2
}
if {[$tbl cget -selectborderwidth] == 0} {
    $tbl configure -spacing 1
}
$tbl columnconfigure 0 -sortmode integer
$tbl columnconfigure 1 -name available -editable yes -editwindow $editWin \

    -formatcommand emptyStr -labelwindow ttk::checkbutton
$tbl columnconfigure 2 -name lineName  -editable yes -editwindow ttk::entry \
    -allowduplicates 0 -sortmode dictionary
$tbl columnconfigure 3 -name baudRate  -editable yes -editwindow ttk::combobox \
    -sortmode integer
$tbl columnconfigure 4 -name dataBits  -editable yes -editwindow ttk::spinbox
$tbl columnconfigure 5 -name parity    -editable yes -editwindow ttk::combobox
$tbl columnconfigure 6 -name stopBits  -editable yes -editwindow ttk::combobox
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
	available {
	    #
	    # Update the image contained in the cell and the checkbutton
	    # embedded into the header label of the column "available"
	    #
	    set img [expr {$text ? "checkedImg" : "uncheckedImg"}]
	    $tbl cellconfigure $row,$col -image $img
	    after idle [list updateCkbtn $tbl $row $col]
	}

	baudRate {
	    #
	    # Check whether the baud rate is an integer in the range 50..921600
	    #
	    if {![regexp {^[0-9]+$} $text] || $text < 50 || $text > 921600} {







|







206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
	available {
	    #
	    # Update the image contained in the cell and the checkbutton
	    # embedded into the header label of the column "available"
	    #
	    set img [expr {$text ? "checkedImg" : "uncheckedImg"}]
	    $tbl cellconfigure $row,$col -image $img
	    after idle [list updateHdrCkbtn $tbl $col]
	}

	baudRate {
	    #
	    # Check whether the baud rate is an integer in the range 50..921600
	    #
	    if {![regexp {^[0-9]+$} $text] || $text < 50 || $text > 921600} {
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
	    $l configure -foreground red3
	}
	grid $l -row $row -column 0 -sticky w -padx 9p -pady {0 3p}

	set sw [tsw::toggleswitch $tf.sw$row]
	$sw switchstate $current	;# sets the switch state to $current
	$sw attrib default $default	;# saves $default as attribute value
	$sw configure -command [list applySwitchState $sw $l $tbl $opt]
	grid $sw -row $row -column 1 -sticky w -padx {0 9p} -pady {0 3p}

	incr row
    }

    grid configure $tf.l0 $tf.sw0 -pady {9p 3p}
    grid columnconfigure $tf 0 -weight 1







|







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
	    $l configure -foreground red3
	}
	grid $l -row $row -column 0 -sticky w -padx 9p -pady {0 3p}

	set sw [tsw::toggleswitch $tf.sw$row]
	$sw switchstate $current	;# sets the switch state to $current
	$sw attrib default $default	;# saves $default as attribute value
	$sw configure -command [list applySwitchState $sw $tbl $opt $l]
	grid $sw -row $row -column 1 -sticky w -padx {0 9p} -pady {0 3p}

	incr row
    }

    grid configure $tf.l0 $tf.sw0 -pady {9p 3p}
    grid columnconfigure $tf 0 -weight 1
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#------------------------------------------------------------------------------
# applySwitchState
#
# Sets the configuration option opt of the tablelist tbl and the foreground
# color of the ttk::label l according to the switch state of the toggleswitch
# widget sw.
#------------------------------------------------------------------------------
proc applySwitchState {sw l tbl opt} {
    set switchState [$sw switchstate]
    $tbl configure $opt $switchState

    set fgColor [expr {$switchState == [$sw attrib default] ? "" : "red3"}]
    $l configure -foreground $fgColor
}







|






304
305
306
307
308
309
310
311
312
313
314
315
316
317
#------------------------------------------------------------------------------
# applySwitchState
#
# Sets the configuration option opt of the tablelist tbl and the foreground
# color of the ttk::label l according to the switch state of the toggleswitch
# widget sw.
#------------------------------------------------------------------------------
proc applySwitchState {sw tbl opt l} {
    set switchState [$sw switchstate]
    $tbl configure $opt $switchState

    set fgColor [expr {$switchState == [$sw attrib default] ? "" : "red3"}]
    $l configure -foreground $fgColor
}
Changes to examples/tsw/serialParams.tcl.
1
2
3
4
5
6
7
8
9
10
11
#==============================================================================
# Populates a tablelist widget with the parameters of 16 serial lines,
# configures the checkbutton embedded into the header label of the column
# "available", and implements the procedures updateCkbtn and afterCopyCmd.
#
# Copyright (c) 2021-2025  Csaba Nemethi (E-mail: [email protected])
#==============================================================================

#
# Populate the tablelist widget
#



|







1
2
3
4
5
6
7
8
9
10
11
#==============================================================================
# Populates a tablelist widget with the parameters of 16 serial lines,
# configures the checkbutton embedded into the header label of the column
# "available", and implements the procedures updateHdrCkbtn and afterCopyCmd.
#
# Copyright (c) 2021-2025  Csaba Nemethi (E-mail: [email protected])
#==============================================================================

#
# Populate the tablelist widget
#
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
set varName [$ckbtn cget -variable]
unset $varName

#
# Selects/deselects the checkbutton embedded into the header label
# of the specified column or sets it into the tri-state mode.
#
proc updateCkbtn {tbl row col} {
    set lst [$tbl getcolumns $col]
    set ckbtn [$tbl labelwindowpath $col]
    upvar #0 [$ckbtn cget -variable] var

    if {[lsearch -exact $lst 1] < 0} {			;# all 0
	set var 0					;# deselect
    } elseif {[lsearch -exact $lst 0] < 0} {		;# all 1







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
set varName [$ckbtn cget -variable]
unset $varName

#
# Selects/deselects the checkbutton embedded into the header label
# of the specified column or sets it into the tri-state mode.
#
proc updateHdrCkbtn {tbl col} {
    set lst [$tbl getcolumns $col]
    set ckbtn [$tbl labelwindowpath $col]
    upvar #0 [$ckbtn cget -variable] var

    if {[lsearch -exact $lst 1] < 0} {			;# all 0
	set var 0					;# deselect
    } elseif {[lsearch -exact $lst 0] < 0} {		;# all 1
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
	    # the checkbutton embedded into the column's header label
	    #
	    for {set row 0} {$row < 16} {incr row} {
		set text [$tbl cellcget $row,$col -text]
		set img [expr {$text ? "checkedImg" : "uncheckedImg"}]
		$tbl cellconfigure $row,$col -image $img
	    }
	    updateCkbtn $tbl 0 $col
	}

	color {
	    #
	    # Update the images contained in the column's cells
	    #
	    for {set row 0} {$row < 16} {incr row} {
		set text [$tbl cellcget $row,$col -text]
		$tbl cellconfigure $row,$col -image img$::colors($text)
	    }
	}
    }
}







|













73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
	    # the checkbutton embedded into the column's header label
	    #
	    for {set row 0} {$row < 16} {incr row} {
		set text [$tbl cellcget $row,$col -text]
		set img [expr {$text ? "checkedImg" : "uncheckedImg"}]
		$tbl cellconfigure $row,$col -image $img
	    }
	    updateHdrCkbtn $tbl $col
	}

	color {
	    #
	    # Update the images contained in the column's cells
	    #
	    for {set row 0} {$row < 16} {incr row} {
		set text [$tbl cellcget $row,$col -text]
		$tbl cellconfigure $row,$col -image img$::colors($text)
	    }
	}
    }
}
Changes to modules/tsw/CHANGES.txt.
1
2


















3
4
5
6
What is new in Tsw 1.0?
-----------------------



















This is the first release.  Thanks to Nicolas Bats for his early
testing and proposing the support for the "-variable" toggleswitch
option.
|

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




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
What is new in Tsw 1.1?
-----------------------

1. For compatibility with the (ttk::)checkbutton, toggling the widget's
   switch state by changing the value of the variable specified by the
   "-variable" option will no longer cause the script specified by the
   "-command" option to get executed.

2. For further compatibility with the (ttk::)checkbutton, invoking the
   "switchstate" subcommand with the optional argument now has no effect
   if the widget's "disabled" state flag is set.

3. Several further improvements in the code and the demo script
   "EditingOpts.tcl".

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

What was new in Tsw 1.0?
------------------------

This is the first release.  Thanks to Nicolas Bats for his early
testing and proposing the support for the "-variable" toggleswitch
option.
Changes to modules/tsw/COPYRIGHT.txt.
1
2
3
4
5
6
7
8
Toggle switch widget package Tsw 1.0
Copyright (c) 2025  Csaba Nemethi (E-mail: [email protected])

This library is free software; you can use, modify, and redistribute it
for any purpose, provided that existing copyright notices are retained
in all copies and that this notice is included verbatim in any
distributions.

|







1
2
3
4
5
6
7
8
Toggle switch widget package Tsw 1.1
Copyright (c) 2025  Csaba Nemethi (E-mail: [email protected])

This library is free software; you can use, modify, and redistribute it
for any purpose, provided that existing copyright notices are retained
in all copies and that this notice is included verbatim in any
distributions.

Changes to modules/tsw/ChangeLog.

























1
2
3
4
5
6
7

























2025-03-24  Csaba Nemethi <[email protected]>

	* Released Tsw 1.0.

2025-03-10  Csaba Nemethi <[email protected]>

	* Added tsw to tklib.
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
2025-05-17  Csaba Nemethi <[email protected]>

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

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

	* scripts/toggleswitch.tcl: Toggling the widget's switch state by
	  changing the value of the variable specified by the "-variable"
	  option will no longer cause the script specified by the "-command"
	  option to get executed; invoking the "switchstate" subcommand with
	  the optional argument now has no effect if the widget's "disabled"
	  state flag is set; several further improvements.

	* scripts/utils/*.tcl: Extended the mwutil package.

	* doc/SerialLineConfig.png: Updated screenshot.

	* doc/stylesheet.css: Extended the CSS stylesheet.

	* ../../examples/tsw/EditingOpts.tcl:  Improvements in the demo script
	* ../../examples/tsw/serialParams.tcl: "EditingOpts.tcl".

2025-03-24  Csaba Nemethi <[email protected]>

	* Released Tsw 1.0.

2025-03-10  Csaba Nemethi <[email protected]>

	* Added tsw to tklib.
Changes to modules/tsw/README.txt.
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
How to Get It?
--------------

Tsw is available for free download from the Web page

    https://www.nemethi.de

The distribution file is "tsw1.0.tar.gz" for UNIX and "tsw1_0.zip" for
Windows.  These files contain the same information, except for the
additional carriage return character preceding the linefeed at the end
of each line in the text files for Windows.

Tsw is also included in tklib, which has the address

    https://core.tcl.tk/tklib

How to Install It?
------------------

Install the package as a subdirectory of one of the directories given
by the "auto_path" variable.  For example, you can install it as a
subdirectory of the "lib" directory within your Tcl/Tk installation (at
the same level as the tk8.X or tk9.X subdirectory).

To install Tsw on UNIX, "cd" to the desired directory and unpack the
distribution file "tsw1.0.tar.gz":

    gunzip -c tsw1.0.tar.gz | tar -xf -

On most UNIX systems this can be replaced with

    tar -zxf tsw1.0.tar.gz

Both commands will create a directory named "tsw1.0", with the
subdirectories "demos", "doc", and "scripts".

On Windows, use WinZip or some other program capable of unpacking the
distribution file "tsw1_0.zip" into the directory "tsw1.0", with the
subdirectories "demos", "doc", and "scripts".

How to Use It?
--------------

To be able to access the commands and variables of the Tsw package, your
scripts must contain one of the lines







|

















|

|



|

|



|







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
How to Get It?
--------------

Tsw is available for free download from the Web page

    https://www.nemethi.de

The distribution file is "tsw1.1.tar.gz" for UNIX and "tsw1_1.zip" for
Windows.  These files contain the same information, except for the
additional carriage return character preceding the linefeed at the end
of each line in the text files for Windows.

Tsw is also included in tklib, which has the address

    https://core.tcl.tk/tklib

How to Install It?
------------------

Install the package as a subdirectory of one of the directories given
by the "auto_path" variable.  For example, you can install it as a
subdirectory of the "lib" directory within your Tcl/Tk installation (at
the same level as the tk8.X or tk9.X subdirectory).

To install Tsw on UNIX, "cd" to the desired directory and unpack the
distribution file "tsw1.1.tar.gz":

    gunzip -c tsw1.1.tar.gz | tar -xf -

On most UNIX systems this can be replaced with

    tar -zxf tsw1.1.tar.gz

Both commands will create a directory named "tsw1.1", with the
subdirectories "demos", "doc", and "scripts".

On Windows, use WinZip or some other program capable of unpacking the
distribution file "tsw1_1.zip" into the directory "tsw1.1", with the
subdirectories "demos", "doc", and "scripts".

How to Use It?
--------------

To be able to access the commands and variables of the Tsw package, your
scripts must contain one of the lines
Changes to modules/tsw/doc/SerialLineConfig.png.

cannot compute difference between binary files

Changes to modules/tsw/doc/index.html.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html>
<head>
  <title>The Toggle Switch Widget Package Tsw 1.0</title>

  <meta name="Author" content="Csaba Nemethi">
  <meta name="Keywords" content="toggleswitch, widget">

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

<body>
  <div>
    <h1>The Toggle Switch Widget Package Tsw 1.0</h1>

    <h3>by</h3>

    <h2>Csaba Nemethi</h2>

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



|









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html>
<head>
  <title>The Toggle Switch Widget Package Tsw 1.1</title>

  <meta name="Author" content="Csaba Nemethi">
  <meta name="Keywords" content="toggleswitch, widget">

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

<body>
  <div>
    <h1>The Toggle Switch Widget Package Tsw 1.1</h1>

    <h3>by</h3>

    <h2>Csaba Nemethi</h2>

    <address>
      <a href="mailto:[email protected]">[email protected]</a>
Changes to modules/tsw/doc/stylesheet.css.
1
2










3
4
5
6
7
8
9
10
11
12

13
14
15

16
17
18
19
20
/* generic class defining a top margin whose height equals the font size */
.tm {margin-top: 1em}











/* background, border, border-radius, and padding for the <pre> tag */
pre {
  background: #F7F7F7;
  border: silver solid 1px;
  border-radius: 4px;
  padding: 4px;
}

/* background for the <body> tag */

body {background: #FFFFFF}

/* text-align for the <div> tag */

div {text-align: center}

/* color for the <span> tag */
span.red {color: #E00000}
span.cmt {color: #36648b}


>
>
>
>
>
>
>
>
>
>









|
>
|
|
<
>
|
|
<
<
<
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



/* generic class defining a top margin whose height equals the font size */
.tm {margin-top: 1em}

/* text-align for the <div> tag */
div {text-align: center}

/* background for the <body> tag */
body {background: #FFFFFF}

/* color for the <span> tag */
span.red {color: #E00000}
span.cmt {color: #36648b}

/* background, border, border-radius, and padding for the <pre> tag */
pre {
  background: #F7F7F7;
  border: silver solid 1px;
  border-radius: 4px;
  padding: 4px;
}

/* background, border, border-radius, and padding for the <code> tag */
code {
  background: #F7F7F7;
  border: #F0F0F0 solid 1px;

  border-radius: 3px;
  padding: 2px;
}



Changes to modules/tsw/doc/toggleswitch.html.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  <link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
    
<body>
  <div>
    <h1>The <code><b>tsw::toggleswitch</b></code> Command</h1>

    <h2>For Tsw Version 1.0</h2>

    <h3>by</h3>
    
    <h2>Csaba Nemethi</h2>

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







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  <link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
    
<body>
  <div>
    <h1>The <code><b>tsw::toggleswitch</b></code> Command</h1>

    <h2>For Tsw Version 1.1</h2>

    <h3>by</h3>
    
    <h2>Csaba Nemethi</h2>

    <address>
      <a href="mailto:[email protected]">[email protected]</a>
235
236
237
238
239
240
241
242


243
244
245
246
247
248
249
          <td>Database Class:</td>
          <td><code><b>&nbsp;Command</b></code></td>
        </tr>
      </table>

      <blockquote>
        <p>Specifies a Tcl script to be evaluated at global scope whenever the
        switch state of the widget is toggled (programmatically or


        interactively).&nbsp; The default is an empty string.</p>
      </blockquote>
    </dd>

    <dd id="offvalue">
      <table border="0" cellpadding="0" cellspacing="0">
        <tr>







|
>
>







235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
          <td>Database Class:</td>
          <td><code><b>&nbsp;Command</b></code></td>
        </tr>
      </table>

      <blockquote>
        <p>Specifies a Tcl script to be evaluated at global scope whenever the
        switch state of the widget is toggled (programmatically, by invoking
        the <code><b><a href="#switchstate">switchstate</a></b></code> or
        <code><b><a href="#toggle">toggle</a></b></code> subcommand, or
        interactively).&nbsp; The default is an empty string.</p>
      </blockquote>
    </dd>

    <dd id="offvalue">
      <table border="0" cellpadding="0" cellspacing="0">
        <tr>
384
385
386
387
388
389
390





391
392
393
394
395
396
397

      <blockquote>
        <p>The name of a global variable whose value is linked to the
        toggleswitch.&nbsp; The widget's switch state changes to on when this
        variable is set to the value specified by the <code><b><a href=
        "#onvalue">-onvalue</a></b></code> option and to off otherwise.&nbsp;
        Defaults to the widget's pathname if not specified.</p>





      </blockquote>
    </dd>

    <dt class="tm" id="widget_command"><b>WIDGET COMMAND</b></dt>

    <dd>
      The <code><b>tsw::toggleswitch</b></code> command creates a new Tcl







>
>
>
>
>







386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404

      <blockquote>
        <p>The name of a global variable whose value is linked to the
        toggleswitch.&nbsp; The widget's switch state changes to on when this
        variable is set to the value specified by the <code><b><a href=
        "#onvalue">-onvalue</a></b></code> option and to off otherwise.&nbsp;
        Defaults to the widget's pathname if not specified.</p>

	<p>Note that for compatibility with the (ttk::)checkbutton, toggling
	the widget's switch state by changing the value of this variable will
	<i>not</i> cause the script specified by the <code><b><a href=
	"#command">-command</a></b></code> option to get executed.</p>
      </blockquote>
    </dd>

    <dt class="tm" id="widget_command"><b>WIDGET COMMAND</b></dt>

    <dd>
      The <code><b>tsw::toggleswitch</b></code> command creates a new Tcl
492
493
494
495
496
497
498
499


500
501

502
503
504

505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
        <dt class="tm" id="switchstate"><code><i>pathName</i>
        <b>switchstate</b> ?<i>boolean</i>?</code></dt>

        <dd>Modifies or inquires the widget's switch state.&nbsp; If the
        optional argument is present then it must be a boolean (a numeric
        value, where 0 is false and anything else is true, or a string such as
        <code><b>true</b>/<b>yes</b>/<b>on</b></code> or
        <code><b>false</b>/<b>no</b>/<b>off</b></code>).&nbsp; If it is true


        then the command sets the <code><b>selected</b></code> flag of the
        underlying ttk::scale widget, moves the slider to the end of the

        trough, and sets the associated <a href="#variable">variable</a> to the
        value specified by the <code><b><a href=
        "#onvalue">-onvalue</a></b></code> option; otherwise it clears the

        <code><b>selected</b></code> flag, moves the slider to the beginning of
        the trough, and sets the associated variable to the value specified by
        the <code><b><a href="#offvalue">-offvalue</a></b></code> option.&nbsp;
        If the argument's value causes the widget's switch state to get toggled
        and the script specified as the value of the <code><b><a href=
        "#command">-command</a></b></code> option is a nonempty string then the
        subcommand evaluates that script at global scope and returns its
        result; otherwise the return value is an empty string.&nbsp; If the
        optional argument is not present then the command returns the widget's
        current switch state as <code>0</code> or <code>1</code>.&nbsp; When a
        toggleswitch widget is created, its switch state is initialized with
        <code>0</code>.</dd>

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

        <dd>
          This convenience subcommand toggles the widget's switch state.&nbsp;
          It is logically equivalent to:







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







499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
        <dt class="tm" id="switchstate"><code><i>pathName</i>
        <b>switchstate</b> ?<i>boolean</i>?</code></dt>

        <dd>Modifies or inquires the widget's switch state.&nbsp; If the
        optional argument is present then it must be a boolean (a numeric
        value, where 0 is false and anything else is true, or a string such as
        <code><b>true</b>/<b>yes</b>/<b>on</b></code> or
        <code><b>false</b>/<b>no</b>/<b>off</b></code>).&nbsp; If the widget's
        <code><b>disabled</b></code> state flag is set then the command returns
        an empty string immediately after checking the argument.&nbsp;
        Otherwise, if the argument is true then the command sets the widget's
        switch state to on by setting the underlying ttk::scale widget's
        <code><b>selected</b></code> flag, moving the slider to the end of the
        trough, and setting the associated <a href="#variable">variable</a> to
        the value specified by the <code><b><a href=
        "#onvalue">-onvalue</a></b></code> option; if the argument is false
        then the command sets the widget's switch state to off by clearing the
        <code><b>selected</b></code> flag, moving the slider to the beginning
        of the trough, and setting the associated variable to the value
        specified by the <code><b><a href="#offvalue">-offvalue</a></b></code>
        option.&nbsp; If the argument's value causes the widget's switch state
        to get toggled and the script specified as the value of the
        <code><b><a href="#command">-command</a></b></code> option is a
        nonempty string then the command evaluates that script at global scope
        and returns its result; otherwise the return value is an empty
        string.&nbsp; If the optional argument is not present then the command
        returns the widget's current switch state as <code>0</code> (off) or
        <code>1</code> (on).&nbsp; When a toggleswitch widget is created, its
        switch state is initialized with <code>0</code>.</dd>

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

        <dd>
          This convenience subcommand toggles the widget's switch state.&nbsp;
          It is logically equivalent to:
Changes to modules/tsw/doc/tsw.html.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  <link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>

<body>
  <div>
    <h1>Tsw Programmer's Guide</h1>

    <h2>For Tsw Version 1.0</h2>
    
    <h3>by</h3>
    
    <h2>Csaba Nemethi</h2>

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







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  <link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>

<body>
  <div>
    <h1>Tsw Programmer's Guide</h1>

    <h2>For Tsw Version 1.1</h2>
    
    <h3>by</h3>
    
    <h2>Csaba Nemethi</h2>

    <address>
      <a href="mailto:[email protected]">[email protected]</a>
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

  <blockquote>
    <address>
      <a href="https://www.nemethi.de">https://www.nemethi.de</a>
    </address>
  </blockquote>

  <p>The distribution file is <code>tsw1.0.tar.gz</code> for UNIX and
  <code>tsw1_0.zip</code> for Windows.&nbsp; These files contain the same
  information, except for the additional carriage return character preceding
  the linefeed at the end of each line in the text files for Windows.</p>

  <p>Tsw is also included in tklib, which has the address</p>

  <blockquote>
    <address>
      <a href="https://core.tcl.tk/tklib">https://core.tcl.tk/tklib</a>
    </address>
  </blockquote>

  <h3 id="ov_install">How to Install It?</h3>

  <p>Install the package as a subdirectory of one of the directories given by
  the <code>auto_path</code> variable.&nbsp; For example, you can install it as
  a subdirectory of the <code>lib</code> directory within your Tcl/Tk
  installation (at the same level as the <code>tk8.X</code> or
  <code>tk9.X</code> subdirectory).</p>

  <p>To install Tsw <i>on UNIX</i>, <code>cd</code> to the desired directory
  and unpack the distribution file <code>tsw1.0.tar.gz</code>:</p>
  
  <blockquote>
    <pre>
gunzip -c tsw1.0.tar.gz | tar -xf -
</pre>
  </blockquote>

  <p>On most UNIX systems this can be replaced with</p>

  <blockquote>
    <pre>
tar -zxf tsw1.0.tar.gz
</pre>
  </blockquote>

  <p>Both commands will create a directory named <code>tsw1.0</code>, with the
  subdirectories <code>demos</code>, <code>doc</code>, and
  <code>scripts</code>.</p>

  <p><i>On Windows</i>, use WinZip or some other program capable of unpacking
  the distribution file <code>tsw1_0.zip</code> into the directory
  <code>tsw1.0</code>, with the subdirectories <code>demos</code>,
  <code>doc</code>, and <code>scripts</code>.</p>

  <p>Notice that in tklib the Tsw <code>demos</code> directory is replaced with
  the subdirectory <code>tsw</code> of the <code>examples</code>
  directory.&nbsp; Please take this into account when reading the <a href=
  "#examples">examples</a> below.</p>








|
|




















|



|







|



|




|
|







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

  <blockquote>
    <address>
      <a href="https://www.nemethi.de">https://www.nemethi.de</a>
    </address>
  </blockquote>

  <p>The distribution file is <code>tsw1.1.tar.gz</code> for UNIX and
  <code>tsw1_1.zip</code> for Windows.&nbsp; These files contain the same
  information, except for the additional carriage return character preceding
  the linefeed at the end of each line in the text files for Windows.</p>

  <p>Tsw is also included in tklib, which has the address</p>

  <blockquote>
    <address>
      <a href="https://core.tcl.tk/tklib">https://core.tcl.tk/tklib</a>
    </address>
  </blockquote>

  <h3 id="ov_install">How to Install It?</h3>

  <p>Install the package as a subdirectory of one of the directories given by
  the <code>auto_path</code> variable.&nbsp; For example, you can install it as
  a subdirectory of the <code>lib</code> directory within your Tcl/Tk
  installation (at the same level as the <code>tk8.X</code> or
  <code>tk9.X</code> subdirectory).</p>

  <p>To install Tsw <i>on UNIX</i>, <code>cd</code> to the desired directory
  and unpack the distribution file <code>tsw1.1.tar.gz</code>:</p>
  
  <blockquote>
    <pre>
gunzip -c tsw1.1.tar.gz | tar -xf -
</pre>
  </blockquote>

  <p>On most UNIX systems this can be replaced with</p>

  <blockquote>
    <pre>
tar -zxf tsw1.1.tar.gz
</pre>
  </blockquote>

  <p>Both commands will create a directory named <code>tsw1.1</code>, with the
  subdirectories <code>demos</code>, <code>doc</code>, and
  <code>scripts</code>.</p>

  <p><i>On Windows</i>, use WinZip or some other program capable of unpacking
  the distribution file <code>tsw1_1.zip</code> into the directory
  <code>tsw1.1</code>, with the subdirectories <code>demos</code>,
  <code>doc</code>, and <code>scripts</code>.</p>

  <p>Notice that in tklib the Tsw <code>demos</code> directory is replaced with
  the subdirectory <code>tsw</code> of the <code>examples</code>
  directory.&nbsp; Please take this into account when reading the <a href=
  "#examples">examples</a> below.</p>

283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
</pre>
  </blockquote>

  <p>We create the toggleswitch widgets by invoking the <code><a href=
  "toggleswitch.html#synopsis">tsw::toggleswitch</a></code> command.&nbsp; For
  the first three toggleswitch widgets we also set the <code><a href=
  "toggleswitch.html#size">-size</a></code> option to <code>1</code>,
  <code>2</code>, and <code>3</code>, respectively.&nbsp; With the exception of
  the themes <code>vista</code>, <code>winnative</code>, and
  <code>xpnative</code>, this results in widgets of different physical
  sizes.&nbsp; For the last toggleswitch we don't explicitly set this option,
  hence it will have its default value <code>2</code>.&nbsp; As seen in the
  screenshots, in the case of the <code>aqua</code> theme the colors used when
  drawing the toggleswitch widgets also depend on the system appearance (light
  mode or dark mode) and the accent color.</p>

  <p>For two of the four toggleswitch widgets we change the switch state from
  the initial value <code>0</code> (off) to <code>1</code> (on) by invoking the
  <code><a href="toggleswitch.html#switchstate">switchstate</a></code>
  subcommand of the associated Tcl command.&nbsp; In addition, for the last
  toggleswitch we set the <code><a href=
  "toggleswitch.html#command">-command</a></code> option to a script that will
  be executed whenever the widget's switch state gets toggled.&nbsp; This
  script invokes the procedure <code>toggleWidgetsState</code> implemented as
  follows:</p>







|
<
<
|
|
|
|
|


|







283
284
285
286
287
288
289
290


291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
</pre>
  </blockquote>

  <p>We create the toggleswitch widgets by invoking the <code><a href=
  "toggleswitch.html#synopsis">tsw::toggleswitch</a></code> command.&nbsp; For
  the first three toggleswitch widgets we also set the <code><a href=
  "toggleswitch.html#size">-size</a></code> option to <code>1</code>,
  <code>2</code>, and <code>3</code>, respectively.&nbsp; For the last


  toggleswitch we don't explicitly set this option, hence it will have its
  default value <code>2</code>.&nbsp; As seen in the screenshots, in the case
  of the <code>aqua</code> theme the colors used when drawing the toggleswitch
  widgets also depend on the system appearance (light mode or dark mode) and
  the accent color.</p>

  <p>For two of the four toggleswitch widgets we change the switch state from
  the default value <code>0</code> (off) to <code>1</code> (on) by invoking the
  <code><a href="toggleswitch.html#switchstate">switchstate</a></code>
  subcommand of the associated Tcl command.&nbsp; In addition, for the last
  toggleswitch we set the <code><a href=
  "toggleswitch.html#command">-command</a></code> option to a script that will
  be executed whenever the widget's switch state gets toggled.&nbsp; This
  script invokes the procedure <code>toggleWidgetsState</code> implemented as
  follows:</p>
339
340
341
342
343
344
345
346
347
348

349
350
351
352
353
354
355
356
357
358
359
360
361
  <p>The rest of the code is not Tsw-specific and for this reason is not shown
  here.</p>

  <h3 id="ex_EditingOpts">Tablelist Editing Options</h3>

  <p>The script <code>EditingOpts.tcl</code> in the <code>demos</code>
  directory is a slightly adapted version of the Tablelist demo script
  <code>tileWidgets.tcl</code>, which demonstrates the interactive tablelist
  cell editing with the aid of various Ttk widgets.&nbsp; The additional
  functionality in this version is implemented in the procedures

  <code>configEditing</code> and <code>applySwitchState</code>.&nbsp; The first
  one, triggered by the "Configure Editing" button, opens a toplevel window
  containing <a href="toggleswitch.html">toggleswitch</a> widgets for
  configuring the editing-related tablelist options having boolean values,
  proposed over the years by Tablelist users.&nbsp; This is a comfortable way
  to test the effect of setting/clearing these boolean options.</p>

  <blockquote>
    <table border="0" cellspacing="0" cellpadding="0">
      <tr valign="top">
        <td><img src="SerialLineConfig.png" alt="Serial Line Configuration"
        width="686" height="503"></td>
        <td><img src="EditingOpts.png" alt="Editing Options" width="285"







|
|
|
>
|
|
|
|
|
|







337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  <p>The rest of the code is not Tsw-specific and for this reason is not shown
  here.</p>

  <h3 id="ex_EditingOpts">Tablelist Editing Options</h3>

  <p>The script <code>EditingOpts.tcl</code> in the <code>demos</code>
  directory is a slightly adapted version of the Tablelist demo script
  <code>tileWidgets2.tcl</code>, which demonstrates the interactive tablelist
  cell editing with the aid of various Ttk widgets and the toggleswitch
  widget.&nbsp; The additional functionality in this version is implemented in
  the procedures <code>configEditing</code> and
  <code>applySwitchState</code>.&nbsp; The first one, triggered by the
  "Configure Editing" button, opens a toplevel window containing <a href=
  "toggleswitch.html">toggleswitch</a> widgets for configuring the
  editing-related tablelist options having boolean values, proposed over the
  years by Tablelist users.&nbsp; This is a comfortable way to test the effect
  of setting/clearing these boolean options.</p>

  <blockquote>
    <table border="0" cellspacing="0" cellpadding="0">
      <tr valign="top">
        <td><img src="SerialLineConfig.png" alt="Serial Line Configuration"
        width="686" height="503"></td>
        <td><img src="EditingOpts.png" alt="Editing Options" width="285"
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
            $l configure -foreground red3
        }
        grid $l -row $row -column 0 -sticky w -padx 9p -pady {0 3p}

        <span class="red">set sw [tsw::toggleswitch $tf.sw$row]
        $sw switchstate $current</span>        ;<span class="cmt"># sets the switch state to $current</span>
        <span class="red">$sw attrib default $default</span>     ;<span class="cmt"># saves $default as attribute value</span>
        <span class="red">$sw configure -command [list applySwitchState $sw $l $tbl $opt]</span>
        grid $sw -row $row -column 1 -sticky w -padx {0 9p} -pady {0 3p}

        incr row
    }

    . . .
}







|







415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
            $l configure -foreground red3
        }
        grid $l -row $row -column 0 -sticky w -padx 9p -pady {0 3p}

        <span class="red">set sw [tsw::toggleswitch $tf.sw$row]
        $sw switchstate $current</span>        ;<span class="cmt"># sets the switch state to $current</span>
        <span class="red">$sw attrib default $default</span>     ;<span class="cmt"># saves $default as attribute value</span>
        <span class="red">$sw configure -command [list applySwitchState $sw $tbl $opt $l]</span>
        grid $sw -row $row -column 1 -sticky w -padx {0 9p} -pady {0 3p}

        incr row
    }

    . . .
}
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
<span class="cmt">#------------------------------------------------------------------------------
# applySwitchState
#
# Sets the configuration option opt of the tablelist tbl and the foreground
# color of the ttk::label l according to the switch state of the toggleswitch
# widget sw.
#------------------------------------------------------------------------------</span>
proc applySwitchState {sw l tbl opt} {
    <span class="red">set switchState [$sw switchstate]</span>
    $tbl configure $opt $switchState

    <span class="red">set fgColor [expr {$switchState == [$sw attrib default] ? "" : "red3"}]</span>
    $l configure -foreground $fgColor
}
</pre>







|







453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
<span class="cmt">#------------------------------------------------------------------------------
# applySwitchState
#
# Sets the configuration option opt of the tablelist tbl and the foreground
# color of the ttk::label l according to the switch state of the toggleswitch
# widget sw.
#------------------------------------------------------------------------------</span>
proc applySwitchState {sw tbl opt l} {
    <span class="red">set switchState [$sw switchstate]</span>
    $tbl configure $opt $switchState

    <span class="red">set fgColor [expr {$switchState == [$sw attrib default] ? "" : "red3"}]</span>
    $l configure -foreground $fgColor
}
</pre>
Changes to modules/tsw/pkgIndex.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#==============================================================================
# Tsw package index file.
#   
# Copyright (c) 2025  Csaba Nemethi (E-mail: [email protected])
#==============================================================================

#
# Regular package:
# 
package ifneeded tsw 1.0 [list source [file join $dir tsw.tcl]]

#
# Alias:
#   
package ifneeded Tsw 1.0 { package require -exact tsw 1.0 }









|




|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#==============================================================================
# Tsw package index file.
#   
# Copyright (c) 2025  Csaba Nemethi (E-mail: [email protected])
#==============================================================================

#
# Regular package:
# 
package ifneeded tsw 1.1 [list source [file join $dir tsw.tcl]]

#
# Alias:
#   
package ifneeded Tsw 1.1 { package require -exact tsw 1.1 }
Changes to modules/tsw/scripts/toggleswitch.tcl.
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    proc condMakeLayouts {} {
	variable theme
	set themeMod $theme
	set mod ""

	if {$theme == "default"} {
	    set fg [ttk::style lookup . -foreground]
	    if {[mwutil::normalizeColor $fg] eq "#ffffff"} {
		set themeMod default-dark
		set mod "Dark"
	    }
	}

	variable elemInfoArr
	if {[info exists elemInfoArr($themeMod)]} {







|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    proc condMakeLayouts {} {
	variable theme
	set themeMod $theme
	set mod ""

	if {$theme == "default"} {
	    set fg [ttk::style lookup . -foreground]
	    if {[mwutil::isColorLight $fg]} {
		set themeMod default-dark
		set mod "Dark"
	    }
	}

	variable elemInfoArr
	if {[info exists elemInfoArr($themeMod)]} {
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
		foreach n {1 2 3} {
		    ttk::style element create Switch$n.trough from vista
		    ttk::style element create Switch$n.slider from vista
		}
	    }
	    default {
		set fg [ttk::style lookup . -foreground]
		if {[mwutil::normalizeColor $fg] eq "#ffffff" ||
		    [string match -nocase *dark* $theme]} {
		    set createCmd createElements_default-dark
		    set mod "Dark"
		} else {
		    set createCmd createElements_default
		}
		ttk::style theme settings default { $createCmd }







|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
		foreach n {1 2 3} {
		    ttk::style element create Switch$n.trough from vista
		    ttk::style element create Switch$n.slider from vista
		}
	    }
	    default {
		set fg [ttk::style lookup . -foreground]
		if {[mwutil::isColorLight $fg] ||
		    [string match -nocase *dark* $theme]} {
		    set createCmd createElements_default-dark
		    set mod "Dark"
		} else {
		    set createCmd createElements_default
		}
		ttk::style theme settings default { $createCmd }
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
    # Create a namespace within the current one to hold the data of the widget
    #
    namespace eval ns$win {
	#
	# The following array holds various data for this widget
	#
	variable data
	array set data {
	    moving 0
	    moved  0
	}

	#
	# The following array is used to hold arbitrary
	# attributes and their values for this widget
	#
	variable attribs
    }







|
<
<
<







242
243
244
245
246
247
248
249



250
251
252
253
254
255
256
    # Create a namespace within the current one to hold the data of the widget
    #
    namespace eval ns$win {
	#
	# The following array holds various data for this widget
	#
	variable data
	set data(moveState) idle		;# other values: moving, moved




	#
	# The following array is used to hold arbitrary
	# attributes and their values for this widget
	#
	variable attribs
    }
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
    set scl $win.scl
    upvar ::tsw::ns${win}::data data
    switch $op {
	write {
	    #
	    # Synchronize the widget's switch state with the variable's value
	    #
	    set oldSelState [$scl instate selected]
	    set newSelState [expr {$var eq $data(-onvalue) ? 1 : 0}]
	    if {$newSelState} {
		$scl state selected
		$scl set [$scl cget -to]
	    } else {
		$scl state !selected
		$scl set 0
	    }

	    if {$newSelState != $oldSelState && $data(-command) ne ""} {
		uplevel #0 $data(-command)
	    }
	}

	unset {
	    #
	    # Recreate the variable $varName by setting it according to
	    # the widget's switch state, and set the trace on it again
	    #







|
|
<




|

|
<
<
<







454
455
456
457
458
459
460
461
462

463
464
465
466
467
468
469



470
471
472
473
474
475
476
    set scl $win.scl
    upvar ::tsw::ns${win}::data data
    switch $op {
	write {
	    #
	    # Synchronize the widget's switch state with the variable's value
	    #
	    set stateSpec [$scl state !disabled]	;# needed for $scl set
	    if {$var eq $data(-onvalue)} {

		$scl state selected
		$scl set [$scl cget -to]
	    } else {
		$scl state !selected
		$scl set [$scl cget -from]
	    }
	    $scl state $stateSpec



	}

	unset {
	    #
	    # Recreate the variable $varName by setting it according to
	    # the widget's switch state, and set the trace on it again
	    #
599
600
601
602
603
604
605



606
607
608
609
610
611
612
613
614
615
616
617
618
		return [$scl instate selected]
	    } else {
		#
		# Update the widget's switch state
		#
		set oldSelState [$scl instate selected]
		set newSelState [expr {[lindex $args 1] ? 1 : 0}]



		if {$newSelState} {
		    $scl state selected
		    $scl set [$scl cget -to]
		} else {
		    $scl state !selected
		    $scl set 0
		}

		upvar ::tsw::ns${win}::data data
		if {$data(-variable) ne ""} {
		    #
		    # Update the associated variable
		    #







>
>
>





|







592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
		return [$scl instate selected]
	    } else {
		#
		# Update the widget's switch state
		#
		set oldSelState [$scl instate selected]
		set newSelState [expr {[lindex $args 1] ? 1 : 0}]
		$scl instate disabled {
		    return ""
		}
		if {$newSelState} {
		    $scl state selected
		    $scl set [$scl cget -to]
		} else {
		    $scl state !selected
		    $scl set [$scl cget -from]
		}

		upvar ::tsw::ns${win}::data data
		if {$data(-variable) ne ""} {
		    #
		    # Update the associated variable
		    #
667
668
669
670
671
672
673

674


675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
proc tsw::onThemeChanged w {
    variable theme [ttk::style theme use]

    if {$w eq "."} {
	condMakeLayouts
    } else {
	set scl $w.scl

	$scl set [expr {[$scl instate selected] ? [$scl cget -to] : 0}]


    }
}

#------------------------------------------------------------------------------
# tsw::onButton1
#------------------------------------------------------------------------------
proc tsw::onButton1 {w x y} {
    $w instate disabled {
	return ""
    }

    $w state pressed

    variable stateArr
    array set stateArr [list  dragging 0  startX $x  prevX $x \
			prevElem [$w identify element $x $y]]

    upvar ::tsw::ns[winfo parent $w]::data data
    set data(moving) 0
    set data(moved) 0
}

#------------------------------------------------------------------------------
# tsw::onB1Motion
#------------------------------------------------------------------------------
proc tsw::onB1Motion {w x y} {
    if {[$w instate disabled] || [$w instate !pressed]} {
	return ""
    }

    variable theme
    variable stateArr

    if {$theme eq "aqua"} {
	upvar ::tsw::ns[winfo parent $w]::data data
	if {$data(moving)} {
	    return ""
	}

	set curElem [$w identify element $x $y]
	if {[string match "*.slider" $stateArr(prevElem)] &&
	    [string match "*.trough" $curElem]} {
	    startToggling $w







>
|
>
>


















<
|















|







663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691

692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
proc tsw::onThemeChanged w {
    variable theme [ttk::style theme use]

    if {$w eq "."} {
	condMakeLayouts
    } else {
	set scl $w.scl
	set stateSpec [$scl state !disabled]		;# needed for $scl set
	$scl set [expr {[$scl instate selected] ?
			[$scl cget -to] : [$scl cget -from]}]
	$scl state $stateSpec
    }
}

#------------------------------------------------------------------------------
# tsw::onButton1
#------------------------------------------------------------------------------
proc tsw::onButton1 {w x y} {
    $w instate disabled {
	return ""
    }

    $w state pressed

    variable stateArr
    array set stateArr [list  dragging 0  startX $x  prevX $x \
			prevElem [$w identify element $x $y]]

    upvar ::tsw::ns[winfo parent $w]::data data

    set data(moveState) idle
}

#------------------------------------------------------------------------------
# tsw::onB1Motion
#------------------------------------------------------------------------------
proc tsw::onB1Motion {w x y} {
    if {[$w instate disabled] || [$w instate !pressed]} {
	return ""
    }

    variable theme
    variable stateArr

    if {$theme eq "aqua"} {
	upvar ::tsw::ns[winfo parent $w]::data data
	if {$data(moveState) eq "moving"} {
	    return ""
	}

	set curElem [$w identify element $x $y]
	if {[string match "*.slider" $stateArr(prevElem)] &&
	    [string match "*.trough" $curElem]} {
	    startToggling $w
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766

    if {$stateArr(dragging)} {
	::$win switchstate [expr {[$w get] > [$w cget -to]/2}]
    } elseif {[$w instate hover]} {
	variable theme
	if {$theme eq "aqua"} {
	    upvar ::tsw::ns${win}::data data
	    if {!$data(moving) && !$data(moved)} {
		startToggling $w
	    }
	} else {
	    ::$win toggle
	}
    }








|







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

    if {$stateArr(dragging)} {
	::$win switchstate [expr {[$w get] > [$w cget -to]/2}]
    } elseif {[$w instate hover]} {
	variable theme
	if {$theme eq "aqua"} {
	    upvar ::tsw::ns${win}::data data
	    if {$data(moveState) eq "idle"} {
		startToggling $w
	    }
	} else {
	    ::$win toggle
	}
    }

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
    after 200 [list tsw::toggleSwitchState $w]
}

#------------------------------------------------------------------------------
# tsw::startToggling
#------------------------------------------------------------------------------
proc tsw::startToggling w {
    if {[$w get] == 0} {
	startMovingRight $w
    } else {
	startMovingLeft $w
    }
}

#------------------------------------------------------------------------------
# tsw::startMovingLeft
#------------------------------------------------------------------------------
proc tsw::startMovingLeft w {
    if {[$w get] == 0} {
	return ""
    }

    upvar ::tsw::ns[winfo parent $w]::data data
    set data(moving) 1
    $w state !selected		;# will be undone before invoking switchstate
    moveLeft $w [$w cget -to]
}

#------------------------------------------------------------------------------
# tsw::moveLeft
#------------------------------------------------------------------------------
proc tsw::moveLeft {w val} {
    if {![winfo exists $w] || [winfo class $w] ne "TswScale"} {
	return ""
    }

    set val [expr {$val - 1}]
    $w set $val

    if {$val > 0} {
	after 10 [list tsw::moveLeft $w $val]
    } else {
	$w state selected	;# restores the original selected state flag
	set win [winfo parent $w]
	::$win switchstate 0

	upvar ::tsw::ns${win}::data data
	set data(moving) 0
	set data(moved) 1
    }
}

#------------------------------------------------------------------------------
# tsw::startMovingRight
#------------------------------------------------------------------------------
proc tsw::startMovingRight w {
    if {[$w get] == [$w cget -to]} {
	return ""
    }

    upvar ::tsw::ns[winfo parent $w]::data data
    set data(moving) 1
    $w state selected		;# will be undone before invoking switchstate
    moveRight $w 0
}

#------------------------------------------------------------------------------
# tsw::moveRight
#------------------------------------------------------------------------------
proc tsw::moveRight {w val} {
    if {![winfo exists $w] || [winfo class $w] ne "TswScale"} {







|
|

|







|




|















|







<
|












|

|







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
    after 200 [list tsw::toggleSwitchState $w]
}

#------------------------------------------------------------------------------
# tsw::startToggling
#------------------------------------------------------------------------------
proc tsw::startToggling w {
    if {[$w get] == [$w cget -to]} {
	startMovingLeft $w
    } else {
	startMovingRight $w
    }
}

#------------------------------------------------------------------------------
# tsw::startMovingLeft
#------------------------------------------------------------------------------
proc tsw::startMovingLeft w {
    if {[$w get] == [$w cget -from]} {
	return ""
    }

    upvar ::tsw::ns[winfo parent $w]::data data
    set data(moveState) moving
    $w state !selected		;# will be undone before invoking switchstate
    moveLeft $w [$w cget -to]
}

#------------------------------------------------------------------------------
# tsw::moveLeft
#------------------------------------------------------------------------------
proc tsw::moveLeft {w val} {
    if {![winfo exists $w] || [winfo class $w] ne "TswScale"} {
	return ""
    }

    set val [expr {$val - 1}]
    $w set $val

    if {$val > [$w cget -from]} {
	after 10 [list tsw::moveLeft $w $val]
    } else {
	$w state selected	;# restores the original selected state flag
	set win [winfo parent $w]
	::$win switchstate 0

	upvar ::tsw::ns${win}::data data

	set data(moveState) moved
    }
}

#------------------------------------------------------------------------------
# tsw::startMovingRight
#------------------------------------------------------------------------------
proc tsw::startMovingRight w {
    if {[$w get] == [$w cget -to]} {
	return ""
    }

    upvar ::tsw::ns[winfo parent $w]::data data
    set data(moveState) moving
    $w state selected		;# will be undone before invoking switchstate
    moveRight $w [$w cget -from]
}

#------------------------------------------------------------------------------
# tsw::moveRight
#------------------------------------------------------------------------------
proc tsw::moveRight {w val} {
    if {![winfo exists $w] || [winfo class $w] ne "TswScale"} {
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
	after 10 [list tsw::moveRight $w $val]
    } else {
	$w state !selected	;# restores the original !selected state flag
	set win [winfo parent $w]
	::$win switchstate 1

	upvar ::tsw::ns${win}::data data
	set data(moving) 0
	set data(moved) 1
    }
}

#------------------------------------------------------------------------------
# tsw::toggleSwitchState
#------------------------------------------------------------------------------
proc tsw::toggleSwitchState w {







<
|







855
856
857
858
859
860
861

862
863
864
865
866
867
868
869
	after 10 [list tsw::moveRight $w $val]
    } else {
	$w state !selected	;# restores the original !selected state flag
	set win [winfo parent $w]
	::$win switchstate 1

	upvar ::tsw::ns${win}::data data

	set data(moveState) moved
    }
}

#------------------------------------------------------------------------------
# tsw::toggleSwitchState
#------------------------------------------------------------------------------
proc tsw::toggleSwitchState w {
Changes to modules/tsw/scripts/utils/mwutil.tcl.
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
# ========================
#

namespace eval mwutil {
    #
    # Public variables:
    #
    variable version	2.24
    variable library	[file dirname [file normalize [info script]]]

    #
    # Public procedures:
    #
    namespace export	wrongNumArgs getAncestorByClass convEventFields \
			defineKeyNav processTraversal focusNext focusPrev \
			configureWidget fullConfigOpt fullOpt enumOpts \
			configureSubCmd attribSubCmdEx attribSubCmd \
			hasattribSubCmdEx hasattribSubCmd unsetattribSubCmdEx \
			unsetattribSubCmd getScrollInfo getScrollInfo2 \
			isScrollable scrollByUnits genMouseWheelEvent \
			containsPointer hasFocus windowingSystem currentTheme \
			normalizeColor parsePadding

    #
    # Make modified versions of the procedures tk_focusNext and
    # tk_focusPrev, to be invoked in the processTraversal command
    #
    proc makeFocusProcs {} {
	#







|













|







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
# ========================
#

namespace eval mwutil {
    #
    # Public variables:
    #
    variable version	2.25
    variable library	[file dirname [file normalize [info script]]]

    #
    # Public procedures:
    #
    namespace export	wrongNumArgs getAncestorByClass convEventFields \
			defineKeyNav processTraversal focusNext focusPrev \
			configureWidget fullConfigOpt fullOpt enumOpts \
			configureSubCmd attribSubCmdEx attribSubCmd \
			hasattribSubCmdEx hasattribSubCmd unsetattribSubCmdEx \
			unsetattribSubCmd getScrollInfo getScrollInfo2 \
			isScrollable scrollByUnits genMouseWheelEvent \
			containsPointer hasFocus windowingSystem currentTheme \
			isColorLight normalizeColor parsePadding

    #
    # Make modified versions of the procedures tk_focusNext and
    # tk_focusPrev, to be invoked in the processTraversal command
    #
    proc makeFocusProcs {} {
	#
703
704
705
706
707
708
709













710
711
712
713
714
715
716
	return $::ttk::currentTheme
    } elseif {[info exists ::tile::currentTheme]} {
	return $::tile::currentTheme
    } else {
	return ""
    }
}














#------------------------------------------------------------------------------
# mwutil::normalizeColor
#
# Returns the representation of a given color in the form "#RRGGBB".
#------------------------------------------------------------------------------
proc mwutil::normalizeColor color {







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







703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
	return $::ttk::currentTheme
    } elseif {[info exists ::tile::currentTheme]} {
	return $::tile::currentTheme
    } else {
	return ""
    }
}

#------------------------------------------------------------------------------
# mwutil::isColorLight
#
# A quick & dirty method to check whether a given color can be classified as
# light.  Inspired by article "Support Dark and Light themes in Win32 apps"
# (see https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/ui/
# apply-windows-themes).
#------------------------------------------------------------------------------
proc mwutil::isColorLight color {
    foreach {r g b} [winfo rgb . $color] {}
    return [expr {5 * ($g >> 8) + 2 * ($r >> 8) + ($b >> 8) > 8 * 128}]
}

#------------------------------------------------------------------------------
# mwutil::normalizeColor
#
# Returns the representation of a given color in the form "#RRGGBB".
#------------------------------------------------------------------------------
proc mwutil::normalizeColor color {
Changes to modules/tsw/scripts/utils/pkgIndex.tcl.
1
2
3
4
5
6
7
8
#==============================================================================
# mwutil package index file.
#
# Copyright (c) 2025  Csaba Nemethi (E-mail: [email protected])
#==============================================================================

package ifneeded mwutil    2.24 [list source [file join $dir mwutil.tcl]]
package ifneeded scaleutil 1.15 [list source [file join $dir scaleutil.tcl]]






|

1
2
3
4
5
6
7
8
#==============================================================================
# mwutil package index file.
#
# Copyright (c) 2025  Csaba Nemethi (E-mail: [email protected])
#==============================================================================

package ifneeded mwutil    2.25 [list source [file join $dir mwutil.tcl]]
package ifneeded scaleutil 1.15 [list source [file join $dir scaleutil.tcl]]
Changes to modules/tsw/tsw.tcl.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    if {$::tk_version == 8.6} {
	package require tksvg
    }

    #
    # Public variables:
    #
    variable version    1.0
    variable library    [file dirname [file normalize [info script]]]

    #
    # Creates a new toggleswitch widget:
    #
    namespace export	toggleswitch
}







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    if {$::tk_version == 8.6} {
	package require tksvg
    }

    #
    # Public variables:
    #
    variable version    1.1
    variable library    [file dirname [file normalize [info script]]]

    #
    # Creates a new toggleswitch widget:
    #
    namespace export	toggleswitch
}
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# Load the packages mwutil and (conditionally) scaleutil from
# the directory "scripts/utils".  Take into account that mwutil
# is also included in Mentry, Scrollutil, and Tablelist, and
# scaleutil is also included in Scrollutil and Tablelist.
#
proc tsw::loadUtils {} {
    if {[catch {package present mwutil} version] == 0 &&
        [package vcompare $version 2.24] < 0} {
        package forget mwutil
    }
    package require mwutil 2.24[-]

    if {[info exists ::tk::svgFmt]} {			;# Tk 8.7b1/9 or later
	return ""
    }

    if {[catch {package present scaleutil} version] == 0 &&
	[package vcompare $version 1.15] < 0} {







|


|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# Load the packages mwutil and (conditionally) scaleutil from
# the directory "scripts/utils".  Take into account that mwutil
# is also included in Mentry, Scrollutil, and Tablelist, and
# scaleutil is also included in Scrollutil and Tablelist.
#
proc tsw::loadUtils {} {
    if {[catch {package present mwutil} version] == 0 &&
        [package vcompare $version 2.25] < 0} {
        package forget mwutil
    }
    package require mwutil 2.25[-]

    if {[info exists ::tk::svgFmt]} {			;# Tk 8.7b1/9 or later
	return ""
    }

    if {[catch {package present scaleutil} version] == 0 &&
	[package vcompare $version 1.15] < 0} {