2 # Copyright (c) 2002, 2003, 2004, 2005 Art Haas
4 # This file is part of PythonCAD.
6 # PythonCAD is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # PythonCAD is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with PythonCAD; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 from PythonCAD
.Generic
import globals
27 # a seemingly good way to convert from string to integer
28 # for a couple of common ways of expressing colors ...
31 def color_str_to_int(cstr
):
32 if cstr
.startswith('0x') or cstr
.startswith('0X'):
34 elif cstr
.startswith('#'):
35 _val
= int(cstr
[1:], 16)
41 """An object representing an RGB color.
43 The class purpose is self evident.
45 A Color object has three attributes:
51 There is no alpha-channel attribute (yet)...
53 A Color object has the following methods:
55 getRed(): Get the Red value in the Color.
56 getBlue(): Get the Blue value in the Color.
57 getGreen(): Get the Green value in the Color.
58 clone(): Return an identical copy of a Color.
60 Once a color object is created, the values it
61 contains may not be changed.
63 def __init__(self
, r
=None, g
=None, b
=None):
64 """Initialize a Color object.
66 There are several ways to create a color object:
68 Color(r,g,b) => r, g, and b values are all integers 0 <= value <= 255
69 Color(0xxxxx) => A hexidecimal value - it must begin with 0x. The color
70 is computed as follows:
71 r = (0xff0000 & value) >> 16
72 g = (0xff00 & value) >> 8
74 Color('#hexvalue') => A string prefixed with '#', with the remaining
75 characters representing a hexidecimal value.
76 Color() => A default color with r = g = b = 255.
81 if isinstance(_r
, str):
82 _val
= color_str_to_int(_r
)
83 _r
= (0xff0000 & _val
) >> 16
84 _g
= (0xff00 & _val
) >> 8
86 elif isinstance(_r
, int) and _g
is None and _b
is None:
87 _r
= (0xff0000 & r
) >> 16
88 _g
= (0xff00 & r
) >> 8
90 elif (isinstance(_r
, int) and
91 isinstance(_g
, int) and
93 if _r
< 0 or _r
> 255:
94 raise ValueError, "Invalid Red value: %d" % _r
95 if _g
< 0 or _g
> 255:
96 raise ValueError, "Invalid Green value: %d" % _g
97 if _b
< 0 or _b
> 255:
98 raise ValueError, "Invalid Blue value: %d" % _b
99 elif _r
is None and _g
is None and _b
is None:
104 raise SyntaxError, "Invalid call to Color()."
105 self
.__color
= (_r
<< 16) |
(_g
<< 8) | _b
107 def __eq__(self
, obj
):
108 """Compare two Color objects for equivalence.
110 if not isinstance(obj
, Color
):
112 return self
.getColors() == obj
.getColors()
114 def __ne__(self
, obj
):
115 """Compare two Color objects for equivalence.
117 if not isinstance(obj
, Color
):
119 return self
.getColors() != obj
.getColors()
121 def __cmp__(self
, obj
):
122 """Compare two Color objects.
124 The comparison is done based on the RGB values.
126 red value of C1 < red value of C2 ==> return -1
127 red value of C1 > red value of C2 ==> return 1
129 Then green values are compared, then blue. If
130 all values are equal, return 0.
132 if not isinstance(obj
, Color
):
133 raise TypeError, "Invalid object for color comparison: " + `obj`
136 return cmp(_val
, _objval
)
139 """Return a hash value for the Color object.
141 Providing this method means that Color objects can be used
142 as keys in dictionaries.
148 _r
= (_val
& 0xff0000) >> 16
149 _g
= (_val
& 0xff00) >> 8
151 return "Color(%d,%d,%d)" % (_r
, _g
, _b
)
154 return "#%06x" % self
.__color
157 """Return a three-item tuple with the values comprising this color.
162 _r
= (_val
& 0xff0000) >> 16
163 _g
= (_val
& 0xff00) >> 8
168 """Return the red value of the color.
172 return (self
.__color
& 0xff0000) >> 16
174 r
= property(getRed
, None, None, "Red value of the color.")
177 """Return the green value of the color.
181 return (self
.__color
& 0xff00) >> 8
183 g
= property(getGreen
, None, None, "Green value of the color.")
186 """Return the blue value of the color.
190 return (self
.__color
& 0xff)
192 b
= property(getBlue
, None, None, "Blue value of the color.")
195 """Return a new Color object with the same color values.
205 # The ColorDict is built from the dict object. Using instances
206 # of this class will guarantee than only Color objects will be
207 # stored in the instance
210 class ColorDict(dict):
212 super(ColorDict
, self
).__init
__()
214 def __setitem__(self
, key
, value
):
215 if not isinstance(key
, Color
):
216 raise TypeError, "ColorDict keys must be color objects: " + `key`
217 if not isinstance(value
, Color
):
218 raise TypeError, "ColorDict values must be Color objects: " + `value`
219 super(ColorDict
, self
).__setitem
__(key
, value
)
222 # find a Color object stored in the global color dictionary
223 # or make a new one and store it
226 def get_color(r
, g
, b
):
227 if not isinstance(r
, int):
228 raise TypeError, "Invalid red value:" + `r`
230 raise ValueError, "Invalid red value: %d" % r
231 if not isinstance(g
, int):
232 raise TypeError, "Invalid green value:" + `g`
234 raise ValueError, "Invalid green value: %d" % g
235 if not isinstance(b
, int):
236 raise TypeError, "Invalid blue value:" + `b`
238 raise ValueError, "Invalid blue value: %d" % b
239 _color
= Color(r
, g
, b
)
240 if _color
in globals.colors
:
241 _color
= globals.colors
[_color
]
243 globals.colors
[_color
] = _color