Updating download.html page with Git information
[pythoncad.git] / PythonCAD / Generic / color.py
blob8bc9a0509e9fb4a9f2d2fe8d1976e7cba234c9ab
2 # Copyright (c) 2002, 2003, 2004, 2005 Art Haas
4 # This file is part of PythonCAD.
5 #
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
21 # classes for colors
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'):
33 _val = int(cstr, 16)
34 elif cstr.startswith('#'):
35 _val = int(cstr[1:], 16)
36 else:
37 _val = int(cstr)
38 return _val
40 class Color(object):
41 """An object representing an RGB color.
43 The class purpose is self evident.
45 A Color object has three attributes:
47 r: Red (0-255)
48 g: Green (0-255)
49 b: Blue (0-255)
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.
62 """
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
73 b = (0xff & value)
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.
77 """
78 _r = r
79 _g = g
80 _b = b
81 if isinstance(_r, str):
82 _val = color_str_to_int(_r)
83 _r = (0xff0000 & _val) >> 16
84 _g = (0xff00 & _val) >> 8
85 _b = (0xff & _val)
86 elif isinstance(_r, int) and _g is None and _b is None:
87 _r = (0xff0000 & r) >> 16
88 _g = (0xff00 & r) >> 8
89 _b = (0xff & r)
90 elif (isinstance(_r, int) and
91 isinstance(_g, int) and
92 isinstance(_b, int)):
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:
100 _r = 255
101 _g = 255
102 _b = 255
103 else:
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):
111 return False
112 return self.getColors() == obj.getColors()
114 def __ne__(self, obj):
115 """Compare two Color objects for equivalence.
117 if not isinstance(obj, Color):
118 return True
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`
134 _val = self.__color
135 _objval = hash(obj)
136 return cmp(_val, _objval)
138 def __hash__(self):
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.
144 return self.__color
146 def __repr__(self):
147 _val = self.__color
148 _r = (_val & 0xff0000) >> 16
149 _g = (_val & 0xff00) >> 8
150 _b = (_val & 0xff)
151 return "Color(%d,%d,%d)" % (_r, _g, _b)
153 def __str__(self):
154 return "#%06x" % self.__color
156 def getColors(self):
157 """Return a three-item tuple with the values comprising this color.
159 getColors()
161 _val = self.__color
162 _r = (_val & 0xff0000) >> 16
163 _g = (_val & 0xff00) >> 8
164 _b = (_val & 0xff)
165 return _r, _g, _b
167 def getRed(self):
168 """Return the red value of the color.
170 getRed()
172 return (self.__color & 0xff0000) >> 16
174 r = property(getRed, None, None, "Red value of the color.")
176 def getGreen(self):
177 """Return the green value of the color.
179 getGreen()
181 return (self.__color & 0xff00) >> 8
183 g = property(getGreen, None, None, "Green value of the color.")
185 def getBlue(self):
186 """Return the blue value of the color.
188 getBlue()
190 return (self.__color & 0xff)
192 b = property(getBlue, None, None, "Blue value of the color.")
194 def clone(self):
195 """Return a new Color object with the same color values.
197 clone()
199 _val = self.__color
200 return Color(_val)
203 # ColorDict Class
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):
211 def __init__(self):
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`
229 if r < 0 or r > 255:
230 raise ValueError, "Invalid red value: %d" % r
231 if not isinstance(g, int):
232 raise TypeError, "Invalid green value:" + `g`
233 if g < 0 or g > 255:
234 raise ValueError, "Invalid green value: %d" % g
235 if not isinstance(b, int):
236 raise TypeError, "Invalid blue value:" + `b`
237 if b < 0 or b > 255:
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]
242 else:
243 globals.colors[_color] = _color
244 return _color