Tk Source Code

Artifact [0d60a65f]
Login

Artifact 0d60a65fbc38c94e781c21166107c22d683cee1e5725c92c175cec8c634b31fb:

Attachment "checkButtonScaled.tcl" to ticket [5d991b82] added by bll 2018-01-26 18:34:33.
#!/usr/bin/tclsh
#
#  Written by Brad Lanam 2016-4-26
#  This code is in the public domain
#
#  This package should be required _after_ tk scaling is set.
#
#  Check Buttons:
#  Substitute checkButtonScaled instead of ttk::checkbutton
#
#     checkButtonScaled .cb -variable var1
#
#  To change the background color (if you have a non-standard background):
#     checkButtonScaled::changeColor <background-color>
#
#  2018-1-22 version 1.20
#    Remove bad code on trace unset.
#  2018-1-5 version 1.19
#    Fixed character scaling
#  2018-1-5 version 1.18
#    Attempt to fix scaling issues.
#  2017-8-19 version 1.17
#    Reworked to scale by the size of the font.
#  2016-8-16 version 1.16
#    Removed propagateBinds routine; no longer needed.  Binds on the
#      main container are executed for all contained widgets.
#    Fixed focus state reporting.
#  2016-7-5 version 1.15
#    Fix propagateBinds check for window existence.
#  2016-7-4 version 1.14
#    Change spacer to be a frame.
#    Better handle mac os x's crazy amount of extra label padding.
#  2016-7-2 version 1.13
#    Focus fixes.
#    Highlight fixes.
#    Fixed space bar toggle.
#  2016-6-14 version 1.12
#    Keep disabled background the same color as the background color.
#    Disabled background colors probably looks better when the
#    checkbutton has a label.
#  2016-6-9 version 1.11
#    Fixed trace on configure of same variable name.
#  2016-6-3 version 1.10
#    improved efficiency
#    added changeColor proc
#    force theme change if it hasn't been done yet.
#  2016-5-16 version 1.9
#    clean up default variables in global namespace
#  2016-5-15 version 1.8
#    fixed problems with traces
#    fixed cleanup of variables on destroy.
#  2016-5-11 version 1.7
#    fixed scaling
#    indicator character is scaled better.
#  2016-5-10 version 1.6
#    propagateBinds routine
#    process -style option
#    -font
#    fix for configure of -variable
#  2016-5-10 version 1.5
#    fix typo.
#    bug fix for destroy
#  2016-5-9 Draft 5 (version 1.4)
#    passes checkbutton.test
#       - except for recreating a variable after unsetting it
#         since that can't be traced, don't know how that would work.
#    passes ttk.test
#  2016-5-9 Draft 4 (version 1.3)
#    accidental upload
#  2016-5-9 Draft 3 (version 1.2)
#    fixed padding/border values to be in points
#  2016-5-8 Draft 2 (version 1.1)
#    checkboxes now size correctly
#    adjusted sizing and padding for all checkboxes
#    -textvariable is working
#  2016-5-5 Draft 1 (version 1.0)
#

package require Tk

proc checkButtonScaled { nm args } {
  return [::checkButtonScaled::checkButtonScaled $nm {*}$args]
}

namespace eval ::checkButtonScaled {
  variable vars
  # vars(theme.current)                 - the current theme setting

  proc _lighten { col {count 1} } {
    scan $col "#%2x%2x%2x" r g b
    set adj 1.10
    for {set i 0} {$i < $count} {incr i} {
      set r [expr {min(round(double($r)*$adj),255)}]
      set g [expr {min(round(double($g)*$adj),255)}]
      set b [expr {min(round(double($b)*$adj),255)}]
    }
    return [format {#%02x%02x%02x} $r $g $b]
  }

  proc _darken { col {count 1} } {
    scan $col "#%2x%2x%2x" r g b
    set adj 0.80
    for {set i 0} {$i < $count} {incr i} {
      set r [expr {max(round(double($r)*$adj),0)}]
      set g [expr {max(round(double($g)*$adj),0)}]
      set b [expr {max(round(double($b)*$adj),0)}]
    }
    return [format {#%02x%02x%02x} $r $g $b]
  }

  proc _init { } {
    variable vars

    set vars(theme.current) {}

    # unicode:
    #  X mark
    #    00d7 multiplication sign
    #    2715 multiplication x
    #    2716 heavy multiplication sign (doesn't look good in bold)
    #    2a09 n-ary times operator
    #    2a2f vector/cross product
    #  checkmark:
    #    2713 checkmark (dingbats)
    #    2714 heavy checkmark (dingbats)
    #
    # bg - background                           ** required
    # the background usually doesn't change
    # bg.disabled - background disabled
    # bg.pressed - background pressed
    # bg.active - background active
    # foreground is the color of the text
    # sometimes the foreground disabled color is changed
    # fg - foreground                           ** required
    # fg.disabled - background disabled
    # fg.pressed - background pressed
    # fg.active - background active
    # indicatorcolor - indicator                ** required (background)
    # indicatorcolor.disabled
    # indicatorcolor.pressed
    # indicatorcolor.active
    # selectcolor - indicator color when selected
    # selectcolor.disabled
    # selectcolor.pressed
    # selectcolor.active
    # the character foreground will default to the foreground color
    # checkchar - checkbutton character
    # charfg - checkbutton character foreground normal
    # charfg.disabled
    # charfg.pressed
    # charfg.active
    # bordercolor - border background normal
    # bordercolor.disabled
    # bordercolor.pressed
    # bordercolor.active

    # -border {bg|other}
    #
    # STATUS:
    #   alt
    #     2016-5-5: border color is listed as 414141,
    #       but that seemed too dark.
    #   aqua:
    #     2016-5-9: There does not appear to be any way to get the
    #       windows's current disabled state, so the 'background' state
    #       cannot be used.
    #   aquativo
    #     2016-5-5: the border color does not change on selection, but
    #       I put in the dark blue border for 'active'
    #   xpnative
    #     2016-5-5: no unicode character display.  Substituted an 'x'.
    #
    set vars(theme.dict) [dict create \
        Alt             [list  \
                            -bg #d9d9d9 \
                            -bg.active #ececec \
                            -fg #000000 \
                            -fg.disabled #a3a3a3 \
                            -border bg \
                            -bordercolor [_darken #d9d9d9] \
                            -bordercolor.disabled [_darken #d9d9d9] \
                            -bordercolor.active [_darken #d9d9d9] \
                            -indicatorcolor #ffffff \
                            -indicatorcolor.disabled #d9d9d9 \
                            -indicatordiameter 7p \
                            -borderwidth 2 \
                            -checkchar \u2714 \
                            -charfg.disabled #a3a3a3 \
                            -padding 2 \
                            ] \
        Aqua            [list  \
                            -bg #ececec \
                            -bg.active #ececec \
                            -fg #000000 \
                            -fg.disabled #000000 \
                            -border bg \
                            -indicatorcolor #ffffff \
                            -indicatorcolor.active #ffffff \
                            -indicatorcolor.disabled #f6f6f6 \
                            -indicatordiameter 9.5p \
                            -selectcolor #3b99fc \
                            -selectcolor.active #3b99fc \
                            -selectcolor.pressed #3b99fc \
                            -selectcolor.disabled #f6f6f6 \
                            -selectcolor.background #f6f6f6 \
                            -checkchar \u2714 \
                            -charfg #ffffff \
                            -charfg.active #ffffff \
                            -charfg.pressed #ffffff \
                            -charfg.disabled #979797 \
                            ] \
        Aquablue        [list  \
                            -bg #f6f4f2 \
                            -bg.active #f6f4f2 \
                            -bg.pressed #f6f4f2 \
                            -fg #000000 \
                            -fg.disabled #9e928a \
                            -border other \
                            -bordercolor #ae9e8e \
                            -bordercolor.active #ae9e8e \
                            -bordercolor.pressed #ae9e8e \
                            -bordercolor.disabled #ae9e8e \
                            -indicatorcolor #ffffff \
                            -indicatorcolor.disabled #ffffff \
                            -indicatordiameter 9p \
                            -selectcolor.disabled #ffffff \
                            -checkchar \u2714 \
                            -charfg.disabled #b5b2ad \
                            -relief flat \
                            ] \
        Aquativo        [list  \
                            -bg #fafafa \
                            -bg.disabled #fafafa \
                            -bg.active #c1d2ee \
                            -bg.pressed #bab5ab \
                            -fg #000000 \
                            -fg.disabled #565248 \
                            -border other \
                            -bordercolor #bab5ab \
                            -bordercolor.active #1c5180 \
                            -bordercolor.disabled #bab5ab \
                            -indicatorcolor #e8e8e8 \
                            -indicatorcolor.active #e8e8e8 \
                            -indicatorcolor.pressed #e8e8e8 \
                            -indicatorcolor.disabled #e8e8e8 \
                            -indicatordiameter 9.5p \
                            -selectcolor #3f97e2 \
                            -selectcolor.active #3f97e2 \
                            -selectcolor.disabled #3f97e2 \
                            -checkchar \u2715 \
                            -charfg #000000 \
                            -relief flat \
                            -padding 0 \
                            ] \
        Arc             [list  \
                            -bg #f5f6f7 \
                            -bg.active #fbfcfc \
                            -bg.disabled #f5f6f7 \
                            -fg #000000 \
                            -fg.disabled #a9acb2 \
                            -border other \
                            -bordercolor #cfd6e6 \
                            -bordercolor.active #cfd6e6 \
                            -bordercolor.pressed #cfd6e6 \
                            -bordercolor.disabled #cfd6e6 \
                            -indicatorcolor #ffffff \
                            -indicatorcolor.disabled #ffffff \
                            -indicatordiameter 10.5p \
                            -selectcolor #5294e2 \
                            -selectcolor.active #5294e2 \
                            -selectcolor.pressed #5294e2 \
                            -selectcolor.disabled #ffffff \
                            -checkchar \u2714 \
                            -charfg #ffffff \
                            -charfg.active #ffffff \
                            -charfg.pressed #ffffff \
                            -charfg.disabled #ffffff \
                            -relief flat \
                            -padding 2 \
                            ] \
        Black           [list  \
                            -bg #424242 \
                            -bg.active #626262 \
                            -fg #ffffff \
                            -fg.disabled #a9a9a9 \
                            -border other \
                            -bordercolor #626262 \
                            -bordercolor.active #626262 \
                            -bordercolor.disabled #626262 \
                            -indicatorcolor #ffffff \
                            -indicatorcolor.disabled #ffffff \
                            -checkchar \u2715 \
                            -charfg #000000 \
                            -charfg.active #000000 \
                            -charfg.pressed #000000 \
                            -charfg.disabled #000000 \
                            -padding 0 \
                            ] \
        Blue            [list  \
                            -bg #6699cc \
                            -bg.active #6699cc \
                            -bg.pressed #6699cc \
                            -fg #000000 \
                            -fg.disabled #666666 \
                            -indicatorcolor #a1c0df \
                            -indicatorcolor.active #a1c0df \
                            -indicatorcolor.disabled #a1c0df \
                            -indicatordiameter 12p \
                            -relief flat \
                            -border other \
                            -bordercolor #2d2d66 \
                            -bordercolor.active #ffffff \
                            -bordercolor.disabled #2d2d66 \
                            -bordercolor.pressed #ffffff \
                            -checkchar \u00d7 \
                            -charfg.active #000000 \
                            -charfg.pressed #000000 \
                            -charfg.disabled #a1c0df \
                            -padding 0 \
                            ] \
        Blueelegance    [list  \
                            -bg #d8d8d8 \
                            -bg.active #d8d8d8 \
                            -fg #000000 \
                            -fg.active #000000 \
                            -fg.disabled #747474 \
                            -border other \
                            -bordercolor #000000 \
                            -bordercolor.active #000000 \
                            -bordercolor.pressed #000000 \
                            -bordercolor.disabled #000000 \
                            -indicatorcolor #627799 \
                            -indicatorcolor.disabled #627799 \
                            -checkchar \u2715 \
                            -charfg #ffffff \
                            -charfg.active #ffffff \
                            -charfg.disabled #ffffff \
                            -relief flat \
                            -padding 0 \
                            ] \
        Clam            [list  \
                            -bg #dcdad5 \
                            -fg #000000 \
                            -fg.disabled #999999 \
                            -border bg \
                            -indicatorcolor #ffffff \
                            -indicatorcolor.disabled #dcdad5 \
                            -checkchar \u2715 \
                            -charfg.disabled #000000 \
                            ] \
        Classic         [list  \
                            -bg #d9d9d9 \
                            -bg.active #ececec \
                            -fg #000000 \
                            -fg.disabled #a3a3a3 \
                            -border bg \
                            -indicatorcolor #d9d9d9 \
                            -indicatorcolor.active #d9d9d9 \
                            -indicatorcolor.disabled #d9d9d9 \
                            -indicatordiameter 6.5p \
                            -selectcolor #b03060 \
                            -selectcolor.active #b03060 \
                            -selectcolor.disabled #b03060 \
                            -selectrelief sunken \
                            -relief raised \
                            -borderwidth 2 \
                            -checkchar {} \
                            -padding 3 \
                            ] \
        Clearlooks      [list  \
                            -bg #efebe7 \
                            -bg.active #f5f3f0 \
                            -fg #000000 \
                            -fg.disabled #b5b3ac \
                            -border other \
                            -bordercolor #ae9e8e \
                            -bordercolor.active #ae9e8e \
                            -bordercolor.pressed #ae9e8e \
                            -bordercolor.disabled #ae9e8e \
                            -indicatorcolor #ffffff \
                            -indicatorcolor.disabled #ffffff \
                            -indicatordiameter 9p \
                            -selectcolor.disabled #ffffff \
                            -checkchar \u2714 \
                            -charfg.disabled #b5b2ad \
                            -relief flat \
                            ] \
        Default         [list  \
                            -bg #d9d9d9 \
                            -bg.active #ececec \
                            -fg #000000 \
                            -fg.disabled #a3a3a3 \
                            -indicatorcolor #ffffff \
                            -border bg \
                            -indicatorcolor.disabled #ffffff \
                            -indicatordiameter 7p \
                            -selectcolor #4a6984 \
                            -selectcolor.active #4a6984 \
                            -selectcolor.disabled #4a6984 \
                            -checkchar {} \
                            -padding 0 \
                            ] \
        Keramik         [list  \
                            -bg #cccccc \
                            -bg.active #cccccc \
                            -fg #000000 \
                            -fg.disabled #aaaaaa \
                            -border bg \
                            -indicatorcolor #ffffff \
                            -indicatordiameter 7p \
                            -checkchar \u00d7 \
                            -charfg.active #000000 \
                            -relief ridge \
                            -borderwidth 4 \
                            -padding 0 \
                            ] \
        Keramik_alt     [list  \
                            -bg #cccccc \
                            -bg.active #cccccc \
                            -fg #000000 \
                            -fg.disabled #aaaaaa \
                            -border bg \
                            -indicatorcolor #ffffff \
                            -indicatordiameter 7p \
                            -checkchar \u00d7 \
                            -charfg.active #000000 \
                            -relief ridge \
                            -borderwidth 4 \
                            -padding 0 \
                            ] \
        Kroc            [list  \
                            -bg #fcb64f \
                            -bg.active #694418 \
                            -fg #000000 \
                            -fg.active #ffffff \
                            -fg.disabled #b2b2b2 \
                            -border bg \
                            -indicatorcolor #fcb64f \
                            -indicatorcolor.disabled #fcb64f \
                            -checkchar \u2714 \
                            -charfg #694418 \
                            -charfg.active #694418 \
                            -charfg.disabled #694418 \
                            -indicatordiameter 13p \
                            -activerelief raised \
                            -padding 0 \
                            ] \
        Plastik         [list  \
                            -bg #efefef \
                            -bg.active #efefef \
                            -fg #000000 \
                            -fg.disabled #aaaaaa \
                            -border bg \
                            -indicatorcolor #f2f2f2 \
                            -indicatorcolor.active #657a9e \
                            -indicatorcolor.disabled #f2f2f2 \
                            -indicatordiameter 10p \
                            -bordercolor #8c8d90 \
                            -bordercolor.disabled #8c8d90 \
                            -checkchar \u2716 \
                            -charfg.active #000000 \
                            -charfg.disabled #000000 \
                            -relief flat \
                            -padding 0 \
                            ] \
        Radiance        [list  \
                            -bg #f6f4f2 \
                            -bg.active #f6f3f0 \
                            -fg #000000 \
                            -fg.disabled #9e928a \
                            -indicatorcolor #ffffff \
                            -indicatorcolor.disabled #e6e1dc \
                            -indicatordiameter 10p \
                            -border other \
                            -bordercolor #ae9e8e \
                            -bordercolor.active #ae9e83 \
                            -bordercolor.disabled #ae9e83 \
                            -selectcolor #f27c4d \
                            -selectcolor.active #f27c4d \
                            -checkchar \u2714 \
                            -charfg #79432d \
                            -charfg.active #79432d \
                            -charfg.disabled #ae9e8e \
                            -relief flat \
                            -padding 0 \
                            ] \
        Vista           [list  \
                            -bg #f0f0f0 \
                            -bg.active #f0f0f0 \
                            -bg.pressed #f0f0f0 \
                            -fg #000000 \
                            -fg.disabled #6d6d6d \
                            -border other \
                            -bordercolor #8f8f8f \
                            -bordercolor.active #8f8f8f \
                            -bordercolor.pressed #8f8f8f \
                            -bordercolor.disabled #8f8f8f \
                            -indicatorcolor #d0d4d9 \
                            -indicatorcolor.active #a8c8e1 \
                            -indicatorcolor.pressed #7ea6c6 \
                            -indicatorcolor.disabled #f0f0f0 \
                            -checkchar \u2713 \
                            -charfg #4b6097 \
                            -charfg.active #4b6097 \
                            -charfg.pressed #4b6097 \
                            -charfg.disabled #d5d5d5 \
                            -relief flat \
                            ] \
        Waldorf         [list  \
                            -bg #d1d1d1 \
                            -fg #000000 \
                            -fg.disabled #595959 \
                            -indicatorcolor #ffffff \
                            -indicatorcolor.disabled #dbdbdb \
                            -indicatordiameter 8p \
                            -selectcolor #a7a7a7 \
                            -selectcolor.active #a7a7a7 \
                            -selectcolor.disabled #dbdbdb \
                            -border other \
                            -bordercolor #8a8a8a \
                            -bordercolor.disabled #8a8a8a \
                            -bordercolor.active #8a8a8a \
                            -checkchar \u2714 \
                            -charfg #ffffff \
                            -charfg.active #ffffff \
                            -charfg.disabled #8a8a8a \
                            -relief flat \
                            ] \
        Winnative       [list  \
                            -bg #f0f0f0 \
                            -bg.active #f0f0f0 \
                            -bg.pressed #f0f0f0 \
                            -fg #000000 \
                            -fg.disabled #6d6d6d \
                            -border other \
                            -borderwidth 2 \
                            -bordercolor #f0f0f0 \
                            -bordercolor.active #f0f0f0 \
                            -bordercolor.pressed #f0f0f0 \
                            -bordercolor.disabled #f0f0f0 \
                            -indicatorcolor #ffffff \
                            -indicatorcolor.active #ffffff \
                            -indicatorcolor.pressed #ffffff \
                            -indicatorcolor.disabled #f0f0f0 \
                            -indicatordiameter 7p \
                            -checkchar \u2713 \
                            -charfg.active #0000ff \
                            -charfg.pressed #000000 \
                            -charfg.disabled #a0a0a0 \
                            -padding 3 \
                            ] \
        Winxpblue       [list  \
                            -bg #ece9d8 \
                            -bg.active #c1d2ee \
                            -bg.pressed #bab5ab \
                            -fg #000000 \
                            -fg.disabled #565248 \
                            -indicatorcolor #f9f9f8 \
                            -indicatorcolor.disabled #f9f9f8 \
                            -indicatordiameter 9p \
                            -border other \
                            -bordercolor #1c5180 \
                            -bordercolor.disabled #1c5180 \
                            -bordercolor.active #1c5180 \
                            -bordercolor.pressed #1c5180 \
                            -checkchar \u2714 \
                            -charfg #21a121 \
                            -charfg.active #21a121 \
                            -charfg.disabled #21a121 \
                            -relief flat \
                            -padding 0 \
                            ] \
        Xpnative        [list  \
                            -bg #ece9d8 \
                            -bg.active #ece9d8 \
                            -bg.pressed #ece9d8 \
                            -fg #000000 \
                            -fg.disabled #565248 \
                            -indicatorcolor #ececec \
                            -indicatorcolor.active #fdd891 \
                            -indicatorcolor.pressed #e0e0db \
                            -indicatorcolor.disabled #ffffff \
                            -indicatordiameter 9p \
                            -border other \
                            -bordercolor #1c5180 \
                            -bordercolor.active #1c5180 \
                            -bordercolor.pressed #1c5180 \
                            -bordercolor.disabled #cac8bb \
                            -checkchar x \
                            -charfg #21a121 \
                            -charfg.active #21a121 \
                            -charfg.disabled #a0a0a0 \
                            -relief flat \
                            ] \
        ]
    setTheme
    bind . <<ThemeChanged>> +[namespace current]::setTheme
    set vars(macosx) false
    if { $::tcl_platform(os) eq "Darwin" } {
      set vars(macosx) true
    }
    set vars(usespacer) true
    if { $vars(macosx) &&
        [package vcompare [info patch] 8.6.6] < 0 } {
      set vars(usespacer) false
    }
  }

  proc _initCommon { theme } {
    variable vars

    # initialize the common settings
    set themedata [dict get $vars(theme.dict) $theme]
    foreach {opt} [list -indicatorcolor -bg -fg -charfg \
        -bordercolor -selectcolor -highlightcolor] {
      set bopt $opt
      if { $opt eq "-charfg" } {
        set bopt -fg
      }
      if { $opt eq "-highlightcolor" } {
        set bopt -fg
      }
      if { $opt eq "-bordercolor" } {
        set bopt -indicatorcolor
      }
      if { $opt eq "-selectcolor" } {
        set bopt -indicatorcolor
      }
      if { $opt eq "-disabledcolor" } {
        set bopt -indicatorcolor
      }
      if { ! [dict exists $themedata ${opt}] } {
        set val [dict get $themedata ${bopt}]
        dict set vars(theme.dict) $theme ${opt} $val
        dict set themedata ${opt} $val
      }
      foreach {state p c} [list disabled _darken 0 active _lighten 1 \
          pressed _lighten 1 readonly _darken 0 background _darken 0] {
        if { ! [dict exists $themedata $opt.$state] } {
          if { $opt eq "-fg" && $state eq "disabled" } {
            set bopt -bg
          }
          set val [dict get $themedata $bopt]
          if { $c != 0 } {
            set val [$p $val $c]
          }
          if { $opt eq "-bg" && $state eq "disabled" } {
            set val [dict get $themedata $opt]
          }
          if { [dict exists $themedata $bopt.$state] } {
            set val [dict get $themedata $bopt.$state]
          }
          dict set vars(theme.dict) $theme $opt.$state $val
          dict set themedata $opt.$state $val
        }
      }
    }
    foreach {opt} [list -selectrelief -activerelief] {
      if { ! [dict exists $themedata $opt] &&
          [dict exists $themedata -relief] } {
        dict set vars(theme.dict) $theme $opt \
            [dict get $themedata -relief]
        dict set $themedata $opt \
            [dict get $themedata -relief]
      }
    }
  }

  proc changeColor { bg } {
    variable vars

    set theme [string totitle [ttk::style theme use]]
    if { $theme ne $vars(theme.current) } {
      setTheme
    }
    set light [_lighten $bg]
    set dark [_darken $bg]

    dict set vars(theme.dict) $vars(theme.current) -bg $bg
    dict set vars(theme.dict) $vars(theme.current) -bg.pressed $light
    dict set vars(theme.dict) $vars(theme.current) -bg.active $light
    dict set vars(theme.dict) $vars(theme.current) -bg.disabled $bg
    if { [dict get $vars(theme.dict) $vars(theme.current) -border] eq "bg" } {
      dict set vars(theme.dict) $vars(theme.current) -bordercolor $dark
      dict set vars(theme.dict) $vars(theme.current) -bordercolor.pressed $dark
      dict set vars(theme.dict) $vars(theme.current) -bordercolor.active $dark
      dict set vars(theme.dict) $vars(theme.current) -bordercolor.disabled $dark
    }
  }

  proc setTheme { } {
    variable vars

    set theme [string totitle [ttk::style theme use]]
    set rc 0
    # <<ThemeChanged>> fires for many different widgets
    if { $vars(theme.current) ne $theme } {
      if { [dict exists $vars(theme.dict) $theme] } {
        ### need to update all the known widgets
        set vars(theme.current) $theme
        _initCommon $theme
      }
    }
    return $rc
  }

  proc nsjoin { ns var } {
    set var $ns$var
    if { [string match ::::* $var] } {
      set var [string range $var 2 end]
    }
    return $var
  }

  proc updateColors { self } {
    variable vars

    set suffix {}
    if { [dict get $vars($self.state) disabled] } {
      set suffix .disabled
    } elseif { [dict get $vars($self.state) background] } {
      set suffix .background
    } elseif { [dict get $vars($self.state) active] } {
      if { [dict get $vars($self.state) pressed] } {
        set suffix .pressed
      } else {
        set suffix .active
      }
    }

    # main frame
    #   the main frame will have a highlight and border.
    ${self} configure \
        -background $vars($self.-bg${suffix})
    # the indicator border
    set trelief $vars($self.-relief)
    if { [dict get $vars($self.state) selected] } {
      set trelief $vars($self.-selectrelief)
    }
    if { [dict get $vars($self.state) active] } {
      set trelief $vars($self.-activerelief)
    }
    ${self}.cbouter configure \
        -background $vars($self.-bordercolor${suffix}) \
        -relief $trelief
    # the indicator
    set tcol $vars($self.-indicatorcolor${suffix})
    if { [dict get $vars($self.state) selected] } {
      set tcol $vars($self.-selectcolor${suffix})
    }
    ${self}.cbindicator configure \
        -background $tcol
    # the text in the indicator (if any)
    if { $vars($self.-checkchar) ne {} } {
      set fg $vars($self.-indicatorcolor${suffix})
      set bg $vars($self.-indicatorcolor${suffix})
      if { [dict get $vars($self.state) selected] } {
        set fg $vars($self.-charfg${suffix})
        set bg $vars($self.-selectcolor${suffix})
      }
      if { $vars($self.-char) ne {} } {
        ${self}.cbchar configure \
            -foreground $fg \
            -background $bg
      }
    }
    if { ! $vars(usespacer) } {
      ${self}.cbspacer2 configure \
          -background $vars($self.-bg${suffix})
    }
    ${self}.cbtext configure \
        -foreground $vars($self.-fg${suffix}) \
        -background $vars($self.-bg${suffix})
  }

  proc removeTrace { self } {
    variable vars

    if { [info exists vars($self.fqvn)] } {
      trace remove variable $vars($self.fqvn) [list read write unset] \
          [list ::checkButtonScaled::traceVar $self]
    }
  }

  proc configureTextVariable { self varnm } {
    variable vars

    if { [info exists $varnm] } {
      set vars($self.-text) {}
      if { $vars($self.-textvariable) ne {} } {
        trace remove variable $vars($self.fqtvn) unset \
            [list ::checkButtonScaled::traceTextVar $self]
      }
      try {
        trace add variable $varnm unset \
            [list ::checkButtonScaled::traceTextVar $self]
        set vars($self.fqtvn) $varnm
      } on error {err res} {
        return 1
      }
      $self.cbtext configure -textvariable $vars($self.fqtvn)
      return 0
    }
    return 1
  }

  proc configureVariable { self varnm } {
    variable vars

    if { ! [winfo exists $self] } {
      return 1
    }
    try {
      dict set vars($self.state) alternate 0
      removeTrace $self
      trace add variable $varnm [list read write unset] \
          [list ::checkButtonScaled::traceVar $self]
      if { [info exists vars($self.fqvn)] &&
          $vars($self.-variable) eq $self &&
          $varnm ne $vars($self.fqvn) &&
          [info exists $vars($self.fqvn)] } {
        unset $vars($self.fqvn) ; # clean up global namespace
      }
      set vars($self.fqvn) $varnm
    } on error {err res} {
      return 1
    }
    return 0
  }

  proc traceTextVar { self args } {
    variable vars

    lassign $args tvarnm nm2 type
    if { $type eq "unset" } {
      $self.cbtext configure -textvariable {}
      set vars($self.-text) {}
      set vars($self.-textvariable) {}
      set vars($self.fqtvn) {}
      unset -nocomplain $tvarnm
    }
  }

  proc traceVar { self args } {
    variable vars

    lassign $args tvarnm nm2 type

    if { $type eq "unset" } {
      dict set vars($self.state) selected 0
      dict set vars($self.state) alternate 1
      set vars($self.-variable) {}
      set vars($self.fqvn) {}
      unset -nocomplain tvarnm
    } else {
      dict set vars($self.state) alternate 0
      if { [set $vars($self.fqvn)] eq $vars($self.-onvalue) } {
        dict set vars($self.state) selected 1
      } else {
        dict set vars($self.state) selected 0
      }
    }
    updateColors $self
  }

  proc selfdestroy { self } {
    variable vars

    if { [info exists vars($self.fqvn)] && $vars($self.fqvn) ne {} } {
      trace remove variable $vars($self.fqvn) [list read write unset] \
        [list ::checkButtonScaled::traceVar $self]
    }
    if { [info exists vars($self.aliastoken)] } {
      interp alias {} $vars($self.aliastoken) {}
    }
    foreach {k} [array names vars ${self}.*] {
      unset vars($k)
    }
    if { [info commands $self] eq $self } {
      rename $self {}
    }
  }

  proc enterMain { self } {
    variable vars

    if { ! [dict get $vars($self.state) disabled] } {
      dict set vars($self.state) hover 1
      ::checkButtonScaled::widgetProcess $self state hover
    }
  }

  proc leaveMain { self } {
    variable vars

    if { ! [dict get $vars($self.state) disabled] } {
      dict set vars($self.state) hover 0
      ::checkButtonScaled::widgetProcess $self state !hover
    }
  }

  proc enter { self } {
    variable vars

    if { ! [dict get $vars($self.state) disabled] &&
        ! [dict get $vars($self.state) active] } {
      dict set vars($self.state) active 1
      ::checkButtonScaled::widgetProcess $self state {active hover}
    }
  }

  proc leave { self } {
    variable vars

    if { ! [dict get $vars($self.state) disabled] &&
        [dict get $vars($self.state) active] } {
      dict set vars($self.state) active 0
      ::checkButtonScaled::widgetProcess $self state {!active !hover}
    }
  }

  proc toggle { self } {
    variable vars

    if { [dict get $vars($self.state) disabled] } {
      return
    }
    dict set vars($self.state) selected \
        [expr {1-[dict get $vars($self.state) selected]}]
    if { $vars($self.fqvn) ne {} } {
      dict set vars($self.state) alternate 0
      if { [dict get $vars($self.state) selected] } {
        set $vars($self.fqvn) $vars($self.-onvalue)
      } else {
        set $vars($self.fqvn) $vars($self.-offvalue)
      }
    }
    if { [winfo exists $self] } {
      if { $vars($self.-command) ne {} } {
        # this could be a list or a string.
        {*}$vars($self.-command)
      }
    } else {
      return -code error
    }
    return 0
  }

  proc release { self } {
    variable vars

    if { [dict get $vars($self.state) disabled] ||
        ! [dict get $vars($self.state) active] ||
        ! [dict get $vars($self.state) pressed] } {
      return
    }
    dict set vars($self.state) pressed 0
    dict set vars($self.state) focus 1
    focus $self.cbtext
    toggle $self ; # this will also fire the trace if -variable is set.
    if { $vars($self.-variable) eq $self } {
      updateColors $self
    }
  }

  proc mapColorSpec { arg } {
    if { $arg eq "-foreground" } { set arg -fg }
    if { $arg eq "-background" } { set arg -bg }
    if { $arg eq "-disabledbg" } { set arg -bg.disabled }
    if { $arg eq "-selectbackground" } { set arg -selectcolor }
    if { $arg eq "-disabledfg" } { set arg -fg.disabled }
    return $arg
  }

  proc getFontSize { font } {
    set a [font metrics $font -ascent]
#    set d [font metrics $val -descent]
    set l [font metrics $font -linespace]
    set sz [expr {round($a-$l*0.1)}]
    return $sz
  }

  proc loadStyle { self } {
    variable vars

    foreach {o} [list -background -foreground -font -indicatorcolor] {
      set val [ttk::style lookup $vars($self.-style) $o]
      if { $val ne {} } {
        set vars($self.$o) $val
      }
      if { $o eq "-font" } {
        if { $val ne {} } {
          set sz [getFontSize $val]
          $self.cbindicator configure -height $sz -width $sz
          if { $vars($self.-char) ne {} } {
            $self.cbchar configure -font [createFont $sz]
          }
        }
        continue
      }
      foreach state [list selected disabled active \
          pressed readonly focus alternate invalid \
          hover background] {
        set val [ttk::style lookup $vars($self.-style) $o $state]
        if { $val ne {} } {
          set vars($self.$o.$state) $val
        }
      }
    }
  }

  proc widgetProcess { self cmd args } {
    variable vars

    set rval {}

    switch -exact -- $cmd {
      instate {
        set rval 1
        lassign $args statespec script
        foreach {val} {*}$statespec {
          set rval [expr {$rval & [dict get $vars($self.state) $val]}]
        }
        if { $rval && $script ne {} } {
          return [eval $script]
        }
      }

      invoke {
        set rval [toggle $self]
      }

      state {
        set rlist [list]
        set tfocus [focus]
        dict set vars($self.state) focus 0
        if { [string match ${self}* $tfocus] } {
          dict set vars($self.state) focus 1
        }
        dict for {state val} $vars($self.state) {
          if { $val == 1 } {
            lappend rlist $state
          }
        }

        if { [info exists args] && [llength $args] > 0 } {
          foreach {val} {*}$args {
            set sval 1
            if { [string match !* $val] } {
              set val [string range $val 1 end]
              set sval 0
            }
            # append any changed states
            set tsval [dict get $vars($self.state) $val]
            if { $tsval ne $sval } {
              if { $tsval == 1 } {
                lappend rlist $state
              } else {
                lappend rlist !$state
              }
            }
            # and set the state
            dict set vars($self.state) $val $sval
            if { $val eq "disabled" && $sval == 1 } {
              dict set vars($self.state) active 0
              dict set vars($self.state) pressed 0
            }
            updateColors $self
          }
        }

        set rval $rlist
      }

      cget {
        set rval {}
        set arg [lindex $args 0]
        set arg [mapColorSpec $arg]
        if { [info exists vars($self.$arg)] } {
          set rval $vars($self.$arg)
          # original checkbutton returns -textvariable
          # when asked for -text
          if { $arg eq "-text" && $vars($self.-textvariable) ne {} } {
            set rval [set $vars($self.fqtvn)]
          }
        }
      }

      map {
        foreach {arg clist} $args {
          set arg [mapColorSpec $arg]
          foreach {state val} $clist {
            set vars($self.$arg$state) $val
          }
        }
        updateColors $self
      }

      configure {
        if { [llength $args] == 1 } {
          set arg [lindex $args 0]
          if { [info exists vars($self.$arg)] } {
            # option name, database name, database class,
            #   default value, curr value
            return [list $arg [string trimleft $arg -] {} {} $vars($self.$arg)]
          }
        }

        foreach {arg val} $args {
          set arg [mapColorSpec $arg]

          if { $arg eq "-checkchar" &&
              $vars($self.-char) ne {} } {
            $self.cbchar configure -text $val
          }
          if { $arg eq "-value" } {
            set vars($self.-onvalue) $val
          }
          if { $arg eq "-indicatordiameter" } {
            $self.cbindicator configure -height $val -width $val
            if { $vars($self.-char) ne {} } {
              $self.cbchar configure -font [createFont $val]
            }
          }
          if { $arg eq "-font" } {
            set sz [getFontSize $val]
            $self.cbindicator configure -height $sz -width $sz
            if { $vars($self.-char) ne {} } {
              $self.cbchar configure -font [createFont $sz]
            }
          }
          if { $arg eq "-cursor" } {
            configCursor $self $val
          }
          if { $arg eq "-textvariable" } {
            if { $val ne {} } {
              set varnm [nsjoin $vars($self.ns) $val]
              set rc [configureTextVariable $self $varnm]
              if { $rc != 0 } {
                return -code error {}
              }
            }
          }
          if { $arg eq "-variable" } {
            set varnm [nsjoin $vars($self.ns) $val]
            set rc [configureVariable $self $varnm]
            if { $rc != 0 } {
              return -code error $::errorInfo
            }
            set vars($self.fqvn) $varnm
          }
          if { $arg eq "-style" } {
            loadStyle $self
          }

          if { $arg eq "-state" } {
            if { $val eq "normal" } {
              set val !disabled
              widgetProcess $self state $val
            }
          } else {
            set vars($self.$arg) $val
          }
          processArguments $self
          configureLabel $self
          updateColors $self
        }
      }

      default {
      }
    }

    return -code ok $rval
  }

  proc configCursor { self val } {
    $self.cbouter configure -cursor $val
    $self.cbindicator configure -cursor $val
    if { $vars($self.-char) ne {} } {
      $self.cbchar configure -cursor $val
    }
    $self.cbtext configure -cursor $val
    if { ! $vars(usespacer) } {
      $self.cbspacer2 configure -cursor $val
    }
  }

  proc createFont { sz } {
    variable vars

    set sz [string trimright $sz p]
    set sz [expr {$sz-($sz*0.2)}]
    if { ! [info exists vars(cache.font.$sz)] } {
      font create _cbsFont$sz
      font configure _cbsFont$sz -size [expr {round($sz+1)}] -weight bold
      set vars(cache.font.$sz) 1
    }
    return _cbsFont$sz
  }

  proc processArguments { self } {
    variable vars

    try {
      dict set vars($self.state) alternate 1
      if { $vars($self.-variable) ne {} } {
        if { [info exists $vars($self.fqvn)] } {
          dict set vars($self.state) alternate 0
        if { [set $vars($self.fqvn)] eq $vars($self.-onvalue) } {
            dict set vars($self.state) selected 1
          } else {
            dict set vars($self.state) selected 0
          }
        }
      }

      set vars($self.textonly) 0
      set vars($self.imageonly) 0
      set vars($self.havelabel) 0
      if { $vars($self.-compound) eq "text" } {
        set vars($self.textonly) 1
      }
      if { $vars($self.-compound) eq "image" ||
          ($vars($self.-compound) eq "none" && $vars($self.-image) ne {}) } {
        set vars($self.imageonly) 1
      }
      if { $vars($self.-textvariable) ne {} &&
          [set $vars($self.fqtvn)] ne {} } {
        set vars($self.havelabel) 1
      }
      if { $vars($self.-text) ne {} } {
        set vars($self.havelabel) 1
      }
      if { $vars($self.-image) ne {} } {
        set vars($self.havelabel) 1
      }

      # because mac os x has a large amount of extra whitespace
      # attached to the label, pack and unpack the text label
      # as needed.
      if { ! $vars($self.havelabel) } {
        if { ! $vars(usespacer) } {
          pack forget $self.cbspacer2
        }
        pack forget $self.cbtext
      } else {
        if { ! $vars(usespacer) } {
          pack $self.cbspacer2 -in $self \
            -side left \
            -ipadx 0 \
            -ipady 1p
        }
        pack $self.cbtext -in $self \
            -anchor $vars($self.-anchor) \
            -side left \
            -ipady 1p
        if { ! $vars(usespacer) } {
          pack configure $self.cbtext \
              -ipadx 1p
        }
      }
    } on error {err res} {
      return -code error {widget has been destroyed}
    }
    return 0
  }

  proc configureLabel { self } {
    variable vars

    set cbtextargs [list \
        -justify left \
        -takefocus 0 \
        -borderwidth 0 \
        -highlightthickness 0 \
        ]
    foreach {o} [list -font -height -underline] {
      if { $vars($self.$o) ne {} } {
        lappend cbtextargs $o $vars($self.$o)
      }
    }
    set havelab 0
    if { ! $vars($self.imageonly) } {
      lappend cbtextargs -text $vars($self.-text)
      if { $vars($self.-text) ne {} } {
        set havelab 1
      }
    }
    if { ! $vars($self.imageonly) && $vars($self.-textvariable) ne {} } {
      lappend cbtextargs -textvariable $vars($self.fqtvn)
      set havelab 1
    }
    if { $vars($self.textonly) && $vars($self.-image) ne {} } {
      lappend cbtextargs -image {}
    }
    if { ! $vars($self.textonly) && $vars($self.-image) ne {} } {
      lappend cbtextargs -image $vars($self.-image)
    }
    if { $vars($self.-compound) ne "text" && $vars($self.-compound) ne "image" } {
      lappend cbtextargs -compound $vars($self.-compound)
    } else {
      lappend cbtextargs -compound none
    }
    ${self}.cbtext configure {*}$cbtextargs
  }

  proc checkButtonScaled { nm args } {
    variable vars

    set theme [string totitle [ttk::style theme use]]
    if { $theme ne $vars(theme.current) } {
      setTheme
    }

    set vars($nm.ns) [uplevel namespace current]
    array set opts $args

    # fedora 25 has a bug where 'Inf' is returned
    # but once set is ok...
    set tkscale [tk scaling]
    if { $tkscale eq "Inf" } {
      tk scaling -displayof . 1.3333
    }

    # defaults
    set vars($nm.-borderwidth) [expr {1/[tk scaling]}]p
    set vars($nm.-indicatordiameter) 8p
    set vars($nm.-onvalue) 1
    set vars($nm.-offvalue) 0
    set vars($nm.-cursor) {}
    set vars($nm.-takefocus) 1
    set vars($nm.-relief) sunken
    set vars($nm.-selectrelief) sunken
    set vars($nm.-activerelief) sunken
    set vars($nm.-text) {}
    set vars($nm.-textvariable) {}
    set vars($nm.state) [list selected 0 disabled 0 active 0 \
        pressed 0 readonly 0 focus 0 alternate 1 invalid 0 \
        hover 0 background 0]
    set vars($nm.-padding) [expr {1/[tk scaling]}]p
    set vars($nm.-anchor) center
    set vars($nm.-image) {}
    set vars($nm.-compound) none
    set vars($nm.-underline) {}
    set vars($nm.-command) {}
    set vars($nm.-variable) $nm
    set vars($nm.-height) {}
    set vars($nm.-style) {}
    set vars($nm.-font) {}
    set vars($nm.-value) 1
    set vars($nm.-checkchar) {}

    # override with settings from theme
    set theme [string totitle [ttk::style theme use]]
    set themedata [dict get $vars(theme.dict) $theme]
    dict for {opt val} $themedata {
      set vars($nm.$opt) $val
    }

    set vars($nm.-padx) $vars($nm.-padding)
    set vars($nm.-pady) $vars($nm.-padding)

    # override with user settings
    foreach {o} [list \
        -bordercolor -borderwidth -checkchar \
        -command -compound -cursor -font -height -image \
        -indicatordiameter -offvalue -onvalue \
        -highlightcolor -highlightthickness -highlightbackground \
        -padx -pady -relief -style -takefocus \
        -text -underline -value -variable \
        ] {
      if { [info exists opts($o)] && $opts($o) ne {} } {
        set vars($nm.$o) $opts($o)
      }
    }

    set vars($nm.-char) $vars($nm.-checkchar)
    if { $vars($nm.-font) eq {} } {
      set sz [getFontSize TkDefaultFont]
    } else {
      set sz [getFontSize $vars($nm.-font)]
    }
    if { [info exists opts($nm.-indicatordiameter)] &&
        $opts($nm.-indicatordiameter) ne {} } {
      set sz $vars($nm.-indicatordiameter)
    }

    # main frame
    #   the main frame will have a highlight and border.
    frame ${nm} \
        -padx $vars($nm.-padx) \
        -pady $vars($nm.-pady) \
        -takefocus $vars($nm.-takefocus) \
        -highlightthickness 1 \
        -highlightbackground $vars($nm.-bg) \
        -highlightcolor $vars($nm.-highlightcolor)
    # the indicator border
    set bsz $vars($nm.-borderwidth)
    frame ${nm}.cbouter \
        -borderwidth ${bsz} \
        -takefocus 0 \
        -highlightthickness 0 \
        -relief $vars($nm.-relief)
    set val [expr {1/[tk scaling]}]p
    pack ${nm}.cbouter -in ${nm} \
        -side left -expand false -padx ${val}p -pady ${val}p -fill none
    # the indicator
    frame ${nm}.cbindicator \
        -width $sz \
        -height $sz \
        -takefocus 0 \
        -highlightthickness 0 \
        -relief flat
    pack ${nm}.cbindicator -in ${nm}.cbouter \
        -expand false -padx 0 -pady 0 -ipadx 0 -ipady 0 -fill none
    pack propagate ${nm}.cbindicator false
    # the text in the indicator (if any)
    if { $vars($nm.-char) ne {} } {
      label ${nm}.cbchar \
          -text $vars($nm.-char) \
          -justify center \
          -takefocus 0 \
          -font [createFont $sz] \
          -highlightthickness 0 \
          -borderwidth 0
      pack ${nm}.cbchar -in ${nm}.cbindicator \
          -padx 0 -pady 0 -ipadx 0 -ipady 0
    }
    if { ! $vars(usespacer) } {
      frame ${nm}.cbspacer2 \
          -takefocus 0 \
          -highlightthickness 0 \
          -borderwidth 0 \
          -width 0.25p
    }
    # labels on mac os x have a large amount of extra whitespace
    label ${nm}.cbtext

    if { $vars($nm.-style) ne {} } {
      loadStyle $nm
    }

    rename $nm ::checkButtonScaled::$nm ; # main frame command
    set vars($nm.aliastoken) [interp alias {} $nm {} \
        ::checkButtonScaled::widgetProcess $nm]

    set varnm [nsjoin $vars($nm.ns) $vars($nm.-variable)]
    set rc [configureVariable $nm $varnm]
    if { $rc != 0 } {
      destroy $nm
      return -code error $::errorInfo
    }

    set o -textvariable
    if { [info exists opts($o)] && $opts($o) ne {} } {
      set varnm [nsjoin $vars($nm.ns) $opts($o)]
      set rc [configureTextVariable $nm $varnm]
      if { $rc != 0 } {
        destroy $nm
        return -code ok {}
      }
      set vars($nm.$o) $opts($o)
    }

    set rc [processArguments $nm]
    if { $rc != 0 } {
      destroy $nm
      return -code ok {}
    }
    if { ! [winfo exists $nm] } {
      selfdestroy $nm
      return -code error {widget has been destroyed}
    }

    if { $vars($nm.-cursor) ne {} } {
      configCursor $nm $vars($nm.-cursor)
    }

    configureLabel $nm
    updateColors $nm

    bind $nm <Destroy> \
        +[list ::checkButtonScaled::selfdestroy $nm]
    bind $nm <Enter> \
        +[list ::checkButtonScaled::enterMain $nm]
    bind $nm <Leave> \
        +[list ::checkButtonScaled::leaveMain $nm]
    bind $nm <space> \
        +[list ::checkButtonScaled::toggle $nm]
    bind $nm <ButtonPress-1> \
        +[list ::checkButtonScaled::widgetProcess $nm state {active pressed}]
    bind $nm <ButtonRelease-1> \
        +[list ::checkButtonScaled::release $nm]

    foreach {w} [list $nm.cbouter $nm.cbindicator $nm.cbchar \
        $nm.cbspacer2 $nm.cbtext] {
      if { ! [winfo exists $w] } {
        continue
      }
      set taglist [bindtags $w]
      bindtags $w [list $nm {*}$taglist]
      bind $w <space> \
          +[list ::checkButtonScaled::toggle $nm]
      bind $w <Enter> \
          +[list ::checkButtonScaled::enter $nm]
      bind $w <Leave> \
          +[list ::checkButtonScaled::leave $nm]
      bind $w <ButtonPress-1> \
          +[list ::checkButtonScaled::widgetProcess $nm state {active pressed}]
      bind $w <ButtonRelease-1> \
          +[list ::checkButtonScaled::release $nm]
    }

    return -code ok $nm
  }

  # initialize
  _init
}

if { 0 } {
  proc do5000 { } {
    .cbon configure -background green
    .cboff configure -foreground blue
  }

  proc toggleState { s } {
    set cs [.cbonoff state $s]
    set val {}
    if { $s in $cs } {
      set val !
    }
    .cbonoff state $val$s
    return
  }

  proc setUline { } {
    .cbonoff configure -underline $::u
  }

  proc setCursor { } {
    .cbonoff configure -cursor $::c
  }

  proc setText { } {
    .cbonoff configure -text $::t
  }

  proc setTextVariable { } {
    .cbonoff configure -textvariable $::tv
  }

  proc setOnvalue { } {
    .cbonoff configure -onvalue $::onvalue
  }

  proc setOffvalue { } {
    .cbonoff configure -offvalue $::offvalue
  }

  proc setVariable { } {
    .cbonoff configure -variable $::var
  }

  proc setCommand { } {
    .cbonoff configure -command $::cmd
  }

  proc setImage { } {
    set img [image create photo -file $::image]
    .cbonoff configure -image $img
  }

  proc setCompound { } {
    .cbonoff configure -compound $::compound
  }

  proc putstate { w } {
    puts "$w:[$w state]"
  }

  proc demo { } {
    set ::onoff ON
    set ::onofflab ONOFF
    set ::u 1
    set ::c {}
    set ::t ONOFF
    set ::tv ::onofflab
    set ::onvalue ON
    set ::offvalue OFF
    set ::on 1
    set ::off 0
    set ::var ::onoff
    set ::cmd {}
    set ::image {}
    set ::compound none

    ttk::label .laa -text {basic display check}
    checkButtonScaled .cbon -variable on -text hello \
        -command [list putstate .cbon]
    checkButtonScaled .cbond -variable on -text hello
    .cbond state disabled
    checkButtonScaled .cbonr -variable on -text hello
    .cbonr state readonly
    checkButtonScaled .cboff -variable off -text hello \
        -command [list putstate .cboff]
    checkButtonScaled .cboffd -variable off -text hello
    .cboffd state disabled
    checkButtonScaled .cboffr -variable off -text hello
    .cboffr state readonly
    ttk::label .lbb -text { }
    pack .laa .cbon .cbond .cbonr .cboff .cboffd .cboffr .lbb \
        -side top -anchor w

    checkButtonScaled .cbonoff -variable onoff -textvariable ::onofflab \
        -onvalue ON -offvalue OFF -underline 1 \
        -command [list putstate .cbonoff]
    pack .cbonoff -side top -anchor w

    ttk::frame .fa
    ttk::label .lonofflab -text {Value: }
    ttk::label .lonoff -textvariable onoff
    pack .fa -side top -anchor w
    pack .lonofflab .lonoff -in .fa -side left -anchor w

    checkButtonScaled .cbonoffd -text disabled \
        -command [list toggleState disabled]
    pack .cbonoffd -side top -anchor w
    checkButtonScaled .cbonoffa -text active \
        -command [list toggleState active]
    pack .cbonoffa -side top -anchor w
    checkButtonScaled .cbonoffp -text pressed \
        -command [list toggleState pressed]
    pack .cbonoffp -side top -anchor w
    checkButtonScaled .cbonoffr -text readonly \
        -command [list toggleState readonly]
    pack .cbonoffr -side top -anchor w

    ttk::frame .fb
    ttk::label .lb -text {Underline: }
    ttk::entry .eb -textvariable u
    bind .eb <Return> [list setUline]
    pack .fb -side top -anchor w
    pack .lb .eb -in .fb -side left -anchor w

    ttk::frame .fc
    ttk::label .lc -text {Cursor: }
    ttk::entry .ec -textvariable c
    bind .ec <Return> [list setCursor]
    pack .fc -side top -anchor w
    pack .lc .ec -in .fc -side left -anchor w

    ttk::frame .fd
    ttk::label .ld -text {Text: }
    ttk::entry .ed -textvariable t
    bind .ed <Return> [list setText]
    pack .fd -side top -anchor w
    pack .ld .ed -in .fd -side left -anchor w

    ttk::frame .fe
    ttk::label .le -text {Text Variable: }
    ttk::entry .ee -textvariable tv
    bind .ee <Return> [list setTextVariable]
    pack .fe -side top -anchor w
    pack .le .ee -in .fe -side left -anchor w

    ttk::frame .ff
    ttk::label .lf -text {On Value }
    ttk::entry .ef -textvariable ::onvalue
    bind .ef <Return> [list setOnvalue]
    pack .ff -side top -anchor w
    pack .lf .ef -in .ff -side left -anchor w

    ttk::frame .fg
    ttk::label .lg -text {Off Value }
    ttk::entry .eg -textvariable ::offvalue
    bind .eg <Return> [list setOffvalue]
    pack .fg -side top -anchor w
    pack .lg .eg -in .fg -side left -anchor w

    ttk::frame .fh
    ttk::label .lh -text {Variable: }
    ttk::entry .eh -textvariable ::var
    bind .eh <Return> [list setVariable]
    pack .fh -side top -anchor w
    pack .lh .eh -in .fh -side left -anchor w

    ttk::frame .fi
    ttk::label .li -text {Command: }
    ttk::entry .ei -textvariable ::cmd
    bind .ei <Return> [list setCommand]
    pack .fi -side top -anchor w
    pack .li .ei -in .fi -side left -anchor w

    ttk::frame .fj
    ttk::label .lj -text {Image: }
    ttk::entry .ej -textvariable ::image
    bind .ej <Return> [list setImage]
    pack .fj -side top -anchor w
    pack .lj .ej -in .fj -side left -anchor w

    ttk::frame .fk
    ttk::label .lk -text {Image: }
    ttk::entry .ek -textvariable ::compound
    bind .ek <Return> [list setCompound]
    pack .fk -side top -anchor w
    pack .lk .ek -in .fk -side left -anchor w

    update
    after 5000 do5000
  }

  demo
}

package provide checkButtonScaled 1.20