palette.tcl 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. # palette.tcl --
  2. #
  3. # This file contains procedures that change the color palette used
  4. # by Tk.
  5. #
  6. # Copyright © 1995-1997 Sun Microsystems, Inc.
  7. #
  8. # See the file "license.terms" for information on usage and redistribution
  9. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10. #
  11. # ::tk_setPalette --
  12. # Changes the default color scheme for a Tk application by setting
  13. # default colors in the option database and by modifying all of the
  14. # color options for existing widgets that have the default value.
  15. #
  16. # Arguments:
  17. # The arguments consist of either a single color name, which
  18. # will be used as the new background color (all other colors will
  19. # be computed from this) or an even number of values consisting of
  20. # option names and values. The name for an option is the one used
  21. # for the option database, such as activeForeground, not -activeforeground.
  22. proc ::tk_setPalette {args} {
  23. if {[winfo depth .] == 1} {
  24. # Just return on monochrome displays, otherwise errors will occur
  25. return
  26. }
  27. # Create an array that has the complete new palette. If some colors
  28. # aren't specified, compute them from other colors that are specified.
  29. if {[llength $args] == 1} {
  30. set new(background) [lindex $args 0]
  31. } else {
  32. array set new $args
  33. }
  34. if {![info exists new(background)]} {
  35. return -code error -errorcode {TK SET_PALETTE BACKGROUND} \
  36. "must specify a background color"
  37. }
  38. set bg [winfo rgb . $new(background)]
  39. if {![info exists new(foreground)]} {
  40. # Note that the range of each value in the triple returned by
  41. # [winfo rgb] is 0-65535, and your eyes are more sensitive to
  42. # green than to red, and more to red than to blue.
  43. foreach {r g b} $bg {break}
  44. if {$r+1.5*$g+0.5*$b > 100000} {
  45. set new(foreground) black
  46. } else {
  47. set new(foreground) white
  48. }
  49. }
  50. lassign [winfo rgb . $new(foreground)] fg_r fg_g fg_b
  51. lassign $bg bg_r bg_g bg_b
  52. set darkerBg [format #%02x%02x%02x [expr {(9*$bg_r)/2560}] \
  53. [expr {(9*$bg_g)/2560}] [expr {(9*$bg_b)/2560}]]
  54. foreach i {activeForeground insertBackground selectForeground \
  55. highlightColor} {
  56. if {![info exists new($i)]} {
  57. set new($i) $new(foreground)
  58. }
  59. }
  60. if {![info exists new(disabledForeground)]} {
  61. set new(disabledForeground) [format #%02x%02x%02x \
  62. [expr {(3*$bg_r + $fg_r)/1024}] \
  63. [expr {(3*$bg_g + $fg_g)/1024}] \
  64. [expr {(3*$bg_b + $fg_b)/1024}]]
  65. }
  66. if {![info exists new(highlightBackground)]} {
  67. set new(highlightBackground) $new(background)
  68. }
  69. # 'buttonBackground' is the background color of the buttons in
  70. # the spinbox widget.
  71. if {![info exists new(buttonBackground)]} {
  72. set new(buttonBackground) $new(background)
  73. }
  74. # 'selectColor' is the background of check & radio buttons.
  75. if {![info exists new(selectColor)]} {
  76. foreach {r g b} $bg {break}
  77. if {$r+1.5*$g+0.5*$b > 100000} {
  78. set new(selectColor) white
  79. } else {
  80. set new(selectColor) black
  81. }
  82. }
  83. if {![info exists new(activeBackground)]} {
  84. # Pick a default active background that islighter than the
  85. # normal background. To do this, round each color component
  86. # up by 15% or 1/3 of the way to full white, whichever is
  87. # greater.
  88. foreach i {0 1 2} color $bg {
  89. set light($i) [expr {$color/256}]
  90. set inc1 [expr {($light($i)*15)/100}]
  91. set inc2 [expr {(255-$light($i))/3}]
  92. if {$inc1 > $inc2} {
  93. incr light($i) $inc1
  94. } else {
  95. incr light($i) $inc2
  96. }
  97. if {$light($i) > 255} {
  98. set light($i) 255
  99. }
  100. }
  101. set new(activeBackground) [format #%02x%02x%02x $light(0) \
  102. $light(1) $light(2)]
  103. }
  104. if {![info exists new(selectBackground)]} {
  105. set new(selectBackground) $darkerBg
  106. }
  107. if {![info exists new(troughColor)]} {
  108. set new(troughColor) $darkerBg
  109. }
  110. # let's make one of each of the widgets so we know what the
  111. # defaults are currently for this platform.
  112. toplevel .___tk_set_palette
  113. wm withdraw .___tk_set_palette
  114. foreach q {
  115. button canvas checkbutton entry frame label labelframe
  116. listbox menubutton menu message radiobutton scale scrollbar
  117. spinbox text
  118. } {
  119. $q .___tk_set_palette.$q
  120. }
  121. # Walk the widget hierarchy, recoloring all existing windows.
  122. # The option database must be set according to what we do here,
  123. # but it breaks things if we set things in the database while
  124. # we are changing colors...so, ::tk::RecolorTree now returns the
  125. # option database changes that need to be made, and they
  126. # need to be evalled here to take effect.
  127. # We have to walk the whole widget tree instead of just
  128. # relying on the widgets we've created above to do the work
  129. # because different extensions may provide other kinds
  130. # of widgets that we don't currently know about, so we'll
  131. # walk the whole hierarchy just in case.
  132. eval [tk::RecolorTree . new]
  133. destroy .___tk_set_palette
  134. # Change the option database so that future windows will get the
  135. # same colors.
  136. foreach option [array names new] {
  137. option add *$option $new($option) widgetDefault
  138. }
  139. # Save the options in the variable ::tk::Palette, for use the
  140. # next time we change the options.
  141. array set ::tk::Palette [array get new]
  142. if {[tk windowingsystem] ne "x11" || [ttk::style theme use] ne "default"} {
  143. return
  144. }
  145. # Update the 'default' ttk theme with the new palette,
  146. # and then set 'default' as the current ttk theme,
  147. # in order to apply the new palette to the ttk widgets.
  148. foreach option [array names new] {
  149. if {[info exists ttk::theme::default::colorOptionLookup($option)]} {
  150. foreach colorName $ttk::theme::default::colorOptionLookup($option) {
  151. set ttk::theme::default::colors($colorName) $new($option)
  152. }
  153. }
  154. }
  155. ttk::theme::default::reconfigureDefaultTheme
  156. ttk::setTheme default
  157. return
  158. }
  159. # ::tk::RecolorTree --
  160. # This procedure changes the colors in a window and all of its
  161. # descendants, according to information provided by the colors
  162. # argument. This looks at the defaults provided by the option
  163. # database, if it exists, and if not, then it looks at the default
  164. # value of the widget itself.
  165. #
  166. # Arguments:
  167. # w - The name of a window. This window and all its
  168. # descendants are recolored.
  169. # colors - The name of an array variable in the caller,
  170. # which contains color information. Each element
  171. # is named after a widget configuration option, and
  172. # each value is the value for that option.
  173. # Return Value:
  174. # A list of commands which can be run to update
  175. # the defaults database when exec'ed.
  176. proc ::tk::RecolorTree {w colors} {
  177. upvar $colors c
  178. set result {}
  179. set prototype .___tk_set_palette.[string tolower [winfo class $w]]
  180. if {![winfo exists $prototype]} {
  181. unset prototype
  182. }
  183. foreach dbOption [array names c] {
  184. set option -[string tolower $dbOption]
  185. set class [string replace $dbOption 0 0 [string toupper \
  186. [string index $dbOption 0]]]
  187. # Make sure this option is valid for this window.
  188. if {![catch {$w configure $option} value]} {
  189. # Update the option for this window.
  190. $w configure $option $c($dbOption)
  191. # Retrieve a default value for this option. First check
  192. # the option database. If it is not in the database use
  193. # the value for the temporary prototype widget.
  194. set defaultcolor [option get $w $dbOption $class]
  195. if {$defaultcolor eq "" || \
  196. ([info exists prototype] && \
  197. [$prototype cget $option] ne "$defaultcolor")} {
  198. set defaultcolor [lindex $value 3]
  199. }
  200. if {$defaultcolor ne ""} {
  201. set defaultcolor [winfo rgb . $defaultcolor]
  202. }
  203. # If the color requested for this option differs from
  204. # the default, append a command to update the default.
  205. set requestcolor [lindex $value 4]
  206. if {$requestcolor ne ""} {
  207. set requestcolor [winfo rgb . $requestcolor]
  208. }
  209. if {![string match $defaultcolor $requestcolor]} {
  210. append result ";\noption add [list \
  211. *[winfo class $w].$dbOption $c($dbOption) 60]"
  212. }
  213. }
  214. }
  215. foreach child [winfo children $w] {
  216. append result ";\n[::tk::RecolorTree $child c]"
  217. }
  218. return $result
  219. }
  220. # ::tk::Darken --
  221. # Given a color name, computes a new color value that darkens (or
  222. # brightens) the given color by a given percent.
  223. #
  224. # Arguments:
  225. # color - Name of starting color.
  226. # percent - Integer telling how much to brighten or darken as a
  227. # percent: 50 means darken by 50%, 110 means brighten
  228. # by 10%.
  229. proc ::tk::Darken {color percent} {
  230. if {$percent < 0} {
  231. return #000000
  232. } elseif {$percent > 200} {
  233. return #ffffff
  234. } elseif {$percent <= 100} {
  235. lassign [winfo rgb . $color] r g b
  236. set r [expr {($r/256)*$percent/100}]
  237. set g [expr {($g/256)*$percent/100}]
  238. set b [expr {($b/256)*$percent/100}]
  239. } elseif {$percent > 100} {
  240. lassign [winfo rgb . $color] r g b
  241. set r [expr {255 - ((65535-$r)/256)*(200-$percent)/100}]
  242. set g [expr {255 - ((65535-$g)/256)*(200-$percent)/100}]
  243. set b [expr {255 - ((65535-$b)/256)*(200-$percent)/100}]
  244. }
  245. return [format #%02x%02x%02x $r $g $b]
  246. }
  247. # ::tk_bisque --
  248. # Reset the Tk color palette to the old "bisque" colors.
  249. #
  250. # Arguments:
  251. # None.
  252. proc ::tk_bisque {} {
  253. tk_setPalette activeBackground #e6ceb1 activeForeground black \
  254. background #ffe4c4 disabledForeground #b0b0b0 foreground black \
  255. highlightBackground #ffe4c4 highlightColor black \
  256. insertBackground black \
  257. selectBackground #e6ceb1 selectForeground black \
  258. troughColor #cdb79e
  259. }