File: color.tcl

package info (click to toggle)
dotfile 1%3A2.4-1
  • links: PTS
  • area: main
  • in suites: potato
  • size: 5,472 kB
  • ctags: 523
  • sloc: tcl: 14,072; sh: 918; makefile: 177; lisp: 18; ansic: 7
file content (401 lines) | stat: -rw-r--r-- 13,875 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
### Copyright (C) 1995-1997 Jesper K. Pedersen
### This program is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation; either version 2 of the License, or
### (at your option) any later version.
###
### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
### GNU General Public License for more details.
###
### You should have received a copy of the GNU General Public License
### along with this program; if not, write to the Free Software
### Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

set __colorSet 0

######################################################################
# This function create a color scale window.
# The arguments are as follows:
# rgbList      : a list of list with four elements: the
#                color name the r,g,b values.
# defaultColor : the default color with a format as: #FF0FAA, or as
#                a name from the rgbList.
# greyScaled   : a boolean which indicate wether the
#                element only shall display grey scaled colors
# The function will first return when the window disapear.
# The return value is a list were the first argument is a color, and the
# second determine wether the color should be edited in greyscaled.
# Iff a value is selected in the listbox, the name will be returned
# otherwise the RGB value will be returned.
# Iff the cancel button is pressed, the value given as argument will
# be returned.
######################################################################
proc ColorWidget {rgbList defaultColor greyScaled} {
  global __greyscaled __colorMap __result __language
  set labels "$__language(color,1) $__language(color,2) $__language(color,3)"
  set __result ""
  toplevel .scale
  grabSet .scale

  ### calculate the defaultColor
  if {[regexp {\#([0-9ABCDEF][0-9ABCDEF])([0-9ABCDEF][0-9ABCDEF])([0-9ABCDEF][0-9ABCDEF])$} $defaultColor all r g b] } {
    set rgb [list [htoi $r] [htoi $g] [htoi $b]]
  } else {
    set defaultColor [string tolower $defaultColor]
    set defaultColorIndex 0
    set found 0
    foreach color $rgbList {
      if {[lindex $color 0] == $defaultColor} {
        set rgb [lindex $color 1]
        set found 1
        break
      }
      incr defaultColorIndex
    }
    ### This should only happend if a system save file says something about
    ### a font, which isn't installed on the system
    if {!$found} {
      set defaultColorIndex 0
      set rgb [lindex [lindex $rgbList 0] 1]
    }
  }

  ### The test label with the actual color
  ### The double frame is needed otherwise the border will flicker
  pack [frame .scale.frame -bd 4 -relief sunken] -pady 10
  frame .scale.frame.test -width 300 -height 100
  pack  .scale.frame.test
  bind .scale.frame.test <1> testClosestColor
  
  ### seperator line
  frame .scale.line1 -height 0.1c -relief sunken -bd 1
  pack .scale.line1 -fill x -expand 1 -pady 20
  
  ### Creating the scales
  for {set i 0} {$i < 3} {incr i} {
    pack [frame .scale.$i]
    label .scale.$i.label -text "[lindex $labels $i]:\t"
    scale .scale.$i.scale -from 0 -to 255 -orient horizontal -length 10c \
        -command setColor
    pack .scale.$i.label .scale.$i.scale -side left -anchor s
    .scale.$i.scale set [lindex $rgb $i]
  }

  ### Seperator line
  frame .scale.line2 -height 0.1c -relief sunken -bd 1
  pack .scale.line2 -fill x -expand 1 -pady 20

  ### The grey scale check button
  checkbutton .scale.grey -text "Grey scaled" -variable __greyscaled \
      -command {
        if {$__greyscaled} {
          bindtags .scale.lb.box None
          bindtags .scale.lb.scroll None
          .scale.lb.box configure -foreground grey -selectforeground black \
            -selectbackground white
        } else {
          bindtags .scale.lb.box {Listbox .scale.lb.box .}
          bindtags .scale.lb.scroll {Scrollbar .scale.lb.scroll}
          .scale.lb.box configure -foreground black -selectforeground white \
              -selectbackground black
        }
      }
  pack .scale.grey -anchor w

  ### The listbox for the colors
  pack [frame .scale.lb]
  listbox .scale.lb.box -yscrollcommand ".scale.lb.scroll set" -width 45
  scrollbar .scale.lb.scroll -command ".scale.lb.box yview"
  pack .scale.lb.box .scale.lb.scroll -side left -fill y

  ### inserting elements into the listbox
  set __colorMap $rgbList
  foreach color $rgbList {
    set name [lindex $color 0]
    .scale.lb.box insert end $name
  }
  
  ### setting the defaults
  set __greyscaled $greyScaled
  if {[info exists defaultColorIndex]} {
    update
    .scale.lb.box selection set $defaultColorIndex
    .scale.lb.box yview $defaultColorIndex
  }

  ### binding the scroll commands
  bind .scale.lb.box <1> {
    setColorAtPos [.scale.lb.box nearest %y]
  }
  bind .scale.lb.box <B1-Motion> {
    setColorAtPos [.scale.lb.box nearest %y]
  }

  ### The buttons
  pack [frame .scale.buttons]  -fill x
  button .scale.buttons.ok -text OK -command colorOk
  button .scale.buttons.cancel -text CANCEL -command colorCancel
  pack .scale.buttons.ok .scale.buttons.cancel -padx 5 -side left

  ### wait until the ok or cancel button has been presed.
  tkwait window .scale
  if {$__result == ""} {
    return [list $defaultColor $greyScaled]
  } else {
    return [list $__result $__greyscaled]
  }
}
######################################################################
# This function is called when the ok button is pressed
######################################################################
proc colorOk {} {
  global __result __colorMap
  if {[.scale.lb.box curselection] != ""} {
    set __result [lindex [lindex $__colorMap [.scale.lb.box curselection]] 0]
  } else {
    set r [itoh [.scale.0.scale get]]
    set g [itoh [.scale.1.scale get]]
    set b [itoh [.scale.2.scale get]]
    set __result "\#$r$g$b"
  }
  grab release .scale
  destroy .scale
}
######################################################################
# This function is called when the cancel button is pressed
######################################################################
proc colorCancel {} {
  global __result
  grab release .scale
  set __result ""
  destroy .scale
}
######################################################################
# This function set the color to the color of the element in the
# listbox at index 'index'. It furher more updates the scales.
# This function is called when an element is selected in the listbox
######################################################################
proc setColorAtPos {index} {
  global __colorMap __colorSet
  set elm [lindex $__colorMap $index]
  set rgb [lindex $elm 1]
  set r [lindex $rgb 0]
  set g [lindex $rgb 1]
  set b [lindex $rgb 2]
  set __colorSet 1
  .scale.0.scale set $r
  .scale.1.scale set $g
  .scale.2.scale set $b
  .scale.frame.test configure -bg "#[itoh $r][itoh $g][itoh $b]"
  update idletasks
  set __colorSet 0
}
######################################################################
# This function set the color to the color of the scales
# iff the greyscaled options isn't set. Iff it's set, the scales
# and the palete is set to the color of rgb='index,index,index'
######################################################################
proc setColor {index} {
  global __greyscaled __colorSet
  if {$__colorSet} {
    return
  }
  if {$__greyscaled} {
    .scale.frame.test configure \
        -bg "#[itoh $index][itoh $index][itoh $index]"
    for {set i 0} {$i < 3} {incr i} {
      .scale.$i.scale set $index
    }
  } else {
    set r [itoh [.scale.0.scale get]]
    set g [itoh [.scale.1.scale get]]
    set b [itoh [.scale.2.scale get]]
    .scale.frame.test configure -bg "#$r$g$b"
  }
  .scale.lb.box  selection clear 0 end
}
######################################################################
# This function converts the output from the showrgb program to
# a list which can be use by the color widget
######################################################################
proc showRgb2list {} {
  global setup
  set path [auto_execok showrgb]
  if {$path != 0 && $path != ""} {
    set names {}
    set lines [split [exec showrgb] "\n"]
    foreach line $lines {
      set r [lindex $line 0]
      set g [lindex $line 1]
      set b [lindex $line 2]
      set name [string tolower [lrange $line 3 end]]
      set color($name) [list $r $g $b]
    }

    set colors [lsort [array names color]]
    foreach name $colors {
      lappend names [list $name $color($name)]
    }
    return $names
  } else {
    return ""
  }
}
######################################################################
# This function compares two string case insensitive.
# OBSOLETE!
######################################################################
proc caseInsensitiveMatch {string1 string2} {
  set length1 [string length $string1]
  set length2 [string length $string2]
  if {$length1 < $length2} {
    set min $length1
  } else {
    set min $length2
  }

  for {set i 0} {$i < $min} {incr i} {
    set c1 [string index $string1 $i]
    set c2 [string index $string2 $i]
    if {[charLess $c1 $c2]} {
      return -1
    }
    if {[charLess $c2 $c1]} {
      return 1
    }
  }
  if {$length1 < $length2} {
    return -1
  }
  if {$length1 > $length2} {
    return 1
  }
  return 0
}
######################################################################
# This function compares two letters case insensitice
######################################################################
proc charLess {c1 c2} {
  set chars "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
  set i1 [string first $c1 $chars ]
  set i2 [string first $c2 $chars]
  return [expr $i1 < $i2]
}

######################################################################
# This function return the color name which is closest to a given
# rgb value
######################################################################
proc findClosestColor {rgb {colorList "NONE"}} {
  if {![regexp {\#([0-9ABCDEF][0-9ABCDEF])([0-9ABCDEF][0-9ABCDEF])([0-9ABCDEF][0-9ABCDEF])$} $rgb all rh gh bh]} {
    error "Internal error: $rgb didn't match pattern"
  }
  
  set r [htoi $rh]
  set g [htoi $gh]
  set b [htoi $bh]
  
  global __colorMap __closestColor
  set minDist 200000
  set minName ""
  set index 0
  set minIndex 0
  if {$colorList == "NONE"} {
    set colorMap $__colorMap
  } else {
    set colorMap $colorList
  }
   
  
  foreach color $colorMap {
    set name [lindex $color 0]
    set _r [lindex [lindex $color 1] 0]
    set _g [lindex [lindex $color 1] 1]
    set _b [lindex [lindex $color 1] 2]
    set dr [expr $r - $_r]
    set dg [expr $g - $_g]
    set db [expr $b - $_b]
    set dist [expr $dr * $dr + $dg * $dg + $db * $db]
    if {$dist < $minDist} {
      set minDist $dist
      set minName $name
      set r_ $_r
      set g_ $_g
      set b_ $_b
      set minIndex $index
    }
    incr index
  }
  set __closestColor [list $minIndex $r_ $g_ $b_]
  return $minName
}

######################################################################
# This function search for the closes color to the one selected with
# the scales. When it has found one, the element in the listbox
# is selected
######################################################################
proc testClosestColor {} {
  global __closestColor __origColor __colorSet

  set current_r [.scale.0.scale get]
  set current_g [.scale.1.scale get]
  set current_b [.scale.2.scale get]
  set __colorSet 1
  if {[info exists __closestColor]} {
    set closest_index [lindex $__closestColor 0]
    set closest_r [lindex $__closestColor 1]
    set closest_g [lindex $__closestColor 2]
    set closest_b [lindex $__closestColor 3]
    
    set orig_r [lindex $__origColor 0]
    set orig_g [lindex $__origColor 1]
    set orig_b [lindex $__origColor 2]

    if {$current_r == $orig_r &&
              $current_g == $orig_g &&
              $current_b == $orig_b} {
      .scale.0.scale set $closest_r
      .scale.1.scale set $closest_g
      .scale.2.scale set $closest_b
      .scale.frame.test configure \
          -bg "#[itoh $closest_r][itoh $closest_g][itoh $closest_b]"
      .scale.lb.box selection set $closest_index
      .scale.lb.box yview $closest_index
    } elseif {$current_r == $closest_r &&
        $current_g == $closest_g &&
        $current_b == $closest_b} {
      .scale.0.scale set $orig_r
      .scale.1.scale set $orig_g
      .scale.2.scale set $orig_b
      .scale.frame.test configure \
          -bg "#[itoh $orig_r][itoh $orig_g][itoh $orig_b]"
      .scale.lb.box  selection clear 0 end
    } else {
      findClosestColor "\#[itoh $current_r][itoh $current_g][itoh $current_b]"
      set __origColor [list $current_r $current_g $current_b]
      .scale.0.scale set [lindex $__closestColor 1]
      .scale.1.scale set [lindex $__closestColor 2]
      .scale.2.scale set [lindex $__closestColor 3]
      .scale.frame.test configure \
          -bg "#[itoh $current_r][itoh $current_g][itoh $current_b]"
      .scale.lb.box selection set [lindex $__closestColor 0]
      .scale.lb.box yview [lindex $__closestColor 0]
    }
  } else {
    findClosestColor "\#[itoh $current_r][itoh $current_g][itoh $current_b]"
    set __origColor [list $current_r $current_g $current_b]
    .scale.0.scale set [lindex $__closestColor 1]
    .scale.1.scale set [lindex $__closestColor 2]
    .scale.2.scale set [lindex $__closestColor 3]
    .scale.frame.test configure \
        -bg \#[itoh [lindex $__closestColor 1]][itoh [lindex $__closestColor 2]][itoh [lindex $__closestColor 3]]
    .scale.lb.box selection set [lindex $__closestColor 0]
    .scale.lb.box yview [lindex $__closestColor 0]
  }
  update
  set __colorSet 0
}