Changeset 155

Show
Ignore:
Timestamp:
09/21/07 17:47:07 (16 months ago)
Author:
fdb
Message:

- NodeBox? moved into package now: you can do "from nodebox.graphics import GraphicsContext?".
- old setup.py is now macsetup.py
- There's a new setup.py that is meant to install NodeBox? as a package: you can do "python setup.py install" to install.
- build_dist.sh became macbuild.sh
- DrawingPrimitives? deprecated in favor of nodebox.graphics

Location:
nodebox/trunk/src
Files:
25 added
13 removed
3 modified

Legend:

Unmodified
Added
Removed
  • nodebox/trunk/src/Changes.txt

    r154 r155  
    1 NodeBox 1.8.6 
     1NodeBox 1.9.0 
    22------------- 
    33* You can now export to PNG, JPEG, TIFF and GIF. 
     
    2222* You can save and clear the canvas at any time during execution: 
    2323 
    24         rect(0, 0, 100, 100) 
    25         _ctx._canvas.save('one-rect.tiff') 
    26         rect(110, 0, 100, 100) 
    27         _ctx._canvas.save('two-rects.tiff') 
    28         _ctx._canvas.clear() # The canvas is now empty when drawn on-screen 
    29          
     24    rect(0, 0, 100, 100) 
     25    _ctx._canvas.save('one-rect.tiff') 
     26    rect(110, 0, 100, 100) 
     27    _ctx._canvas.save('two-rects.tiff') 
     28    _ctx._canvas.clear() # The canvas is now empty when drawn on-screen 
     29     
    3030* Fullscreen mode now has the correct mouse position, and is clipped correctly. 
    3131* QuickTime export uses QTKit. 
    3232* Errors while drawing now appear in the output view. 
     33* NodeBox is now packaged: DrawingPrimitives is obsoleted in favor of nodebox.graphics. 
     34* Access NodeBox from the command line: 
     35 
     36    from nodebox.console import make_movie 
     37    make_movie('text(FRAME, 100, 100)', 'test.mov', 100) 
    3338 
    3439NodeBox 1.8.5 
  • nodebox/trunk/src/DrawingPrimitives.py

    r154 r155  
    1 import os 
    2 from random import choice, shuffle 
    3 from AppKit import * 
    4 from Foundation import * 
     1# This file is obsolete. 
     2# NodeBox now uses a package structure. 
     3# The drawing primitives are now in the new "nodebox.graphics" package. 
     4# This will also ensure you get the graphics package for the correct platform. 
    55 
    6 __all__ = [ 
    7         "DEFAULT_WIDTH", "DEFAULT_HEIGHT", 
    8         "inch", "cm", "mm", 
    9         "RGB", "HSB", "CMYK", 
    10         "CENTER", "CORNER", 
    11         "MOVETO", "LINETO", "CURVETO", "CLOSE", 
    12         "LEFT", "RIGHT", "CENTER", "JUSTIFY", 
    13         "NORMAL","FORTYFIVE", 
    14         "NUMBER", "TEXT", "BOOLEAN","BUTTON", 
    15         "Point", "Grob", "BezierPath", "PathElement", "ClippingPath", "Rect", "Oval", "Color", "Transform", "Image", "Text", 
    16         "Variable", "Canvas", "Context", 
    17         "grid", "random","choice", "files","autotext", 
    18         ] 
     6import nodebox.graphics.cocoa 
     7from nodebox.graphics.cocoa import * 
    198 
    20 DEFAULT_WIDTH, DEFAULT_HEIGHT = 1000, 1000 
    21  
    22 inch = 72 
    23 cm = 28.3465 
    24 mm = 2.8346 
    25  
    26 RGB = "rgb" 
    27 HSB = "hsb" 
    28 CMYK = "cmyk" 
    29  
    30 CENTER = "center" 
    31 CORNER = "corner" 
    32  
    33 MOVETO = NSMoveToBezierPathElement 
    34 LINETO = NSLineToBezierPathElement 
    35 CURVETO = NSCurveToBezierPathElement 
    36 CLOSE = NSClosePathBezierPathElement 
    37  
    38 LEFT = NSLeftTextAlignment 
    39 RIGHT = NSRightTextAlignment 
    40 CENTER = NSCenterTextAlignment 
    41 JUSTIFY = NSJustifiedTextAlignment 
    42  
    43 NORMAL=1 
    44 FORTYFIVE=2 
    45  
    46 NUMBER = 1 
    47 TEXT = 2 
    48 BOOLEAN = 3 
    49 BUTTON = 4 
    50  
    51 _STATE_NAMES = { 
    52     '_outputmode':    'outputmode', 
    53     '_colorrange':    'colorrange', 
    54     '_fillcolor':     'fill', 
    55     '_strokecolor':   'stroke', 
    56     '_strokewidth':   'strokewidth', 
    57     '_transform':     'transform', 
    58     '_transformmode': 'transformmode', 
    59     '_fontname':      'font', 
    60     '_fontsize':      'fontsize', 
    61     '_align':         'align', 
    62     '_lineheight':    'lineheight', 
    63 } 
    64  
    65 def _save(): 
    66     NSGraphicsContext.currentContext().saveGraphicsState() 
    67  
    68 def _restore(): 
    69     NSGraphicsContext.currentContext().restoreGraphicsState() 
    70  
    71 class NodeBoxError(Exception): pass 
    72  
    73 class Point(object): 
    74  
    75     def __init__(self, *args): 
    76         if len(args) == 2: 
    77             self.x, self.y = args 
    78         elif len(args) == 1: 
    79             self.x, self.y = args[0] 
    80         elif len(args) == 0: 
    81             self.x = self.y = 0.0 
    82         else: 
    83             raise NodeBoxError, "Wrong initializer for Point object" 
    84  
    85     def __repr__(self): 
    86         return "Point(x=%.3f, y=%.3f)" % (self.x, self.y) 
    87          
    88     def __eq__(self, other): 
    89         if other is None: return False 
    90         return self.x == other.x and self.y == other.y 
    91          
    92     def __ne__(self, other): 
    93         return not self.__eq__(other) 
    94  
    95 class Grob(object): 
    96     """A GRaphic OBject is the base class for all DrawingPrimitives.""" 
    97  
    98     def __init__(self, ctx): 
    99         """Initializes this object with the current context.""" 
    100         self._ctx = ctx 
    101  
    102     def draw(self): 
    103         """Appends the grob to the canvas. 
    104            This will result in a draw later on, when the scene graph is rendered.""" 
    105         self._ctx._canvas.append( self ) 
    106          
    107     def copy(self): 
    108         """Returns a deep copy of this grob.""" 
    109         raise NotImplementedError, "Copy is not implemented on this Grob class." 
    110          
    111     def inheritFromContext(self, ignore=()): 
    112         attrs_to_copy = list(self.__class__.stateAttributes) 
    113         [attrs_to_copy.remove(k) for k, v in _STATE_NAMES.items() if v in ignore] 
    114         _copy_attrs(self._ctx, self, attrs_to_copy) 
    115          
    116     def checkKwargs(self, kwargs): 
    117         remaining = [arg for arg in kwargs.keys() if arg not in self.kwargs] 
    118         if remaining: 
    119             raise NodeBoxError, "Unknown argument(s) '%s'" % ", ".join(remaining) 
    120     checkKwargs = classmethod(checkKwargs) 
    121  
    122 class TransformMixin(object): 
    123  
    124     """Mixin class for transformation support. 
    125     Adds the _transform and _transformmode attributes to the class.""" 
    126      
    127     def __init__(self): 
    128         self._reset() 
    129          
    130     def _reset(self): 
    131         self._transform = Transform() 
    132         self._transformmode = CENTER 
    133          
    134     def transform(self, mode): 
    135         self._transformmode = mode 
    136          
    137     def translate(self, x, y): 
    138         self._transform.translate(x, y) 
    139          
    140     def transform(self, mode=None): 
    141         if mode is not None: 
    142             self._transformmode = mode 
    143         return self._transformmode 
    144  
    145     def reset(self): 
    146         self._transform = Transform() 
    147  
    148     def rotate(self, degrees=0, radians=0): 
    149         self._transform.rotate(-degrees,-radians) 
    150  
    151     def translate(self, x=0, y=0): 
    152         self._transform.translate(x,y) 
    153  
    154     def scale(self, x=1, y=None): 
    155         self._transform.scale(x,y) 
    156  
    157     def skew(self, x=0, y=0): 
    158         self._transform.skew(x,y) 
    159          
    160 class ColorMixin(object): 
    161      
    162     """Mixin class for color support. 
    163     Adds the _fillcolor, _strokecolor and _strokewidth attributes to the class.""" 
    164  
    165     def __init__(self, **kwargs): 
    166         try: 
    167             self._fillcolor = Color(self._ctx, kwargs['fill']) 
    168         except KeyError: 
    169             self._fillcolor = Color(self._ctx) 
    170         try: 
    171             self._strokecolor = Color(self._ctx, kwargs['stroke']) 
    172         except KeyError: 
    173             self._strokecolor = None 
    174         self._strokewidth = kwargs.get('strokewidth', 1.0) 
    175  
    176     def nofill(self): 
    177         self._fillcolor = None 
    178  
    179     def fill(self, *args): 
    180         if len(args) > 0: 
    181             self._fillcolor = Color(self._ctx, *args) 
    182         return self._fillcolor 
    183  
    184     def nostroke(self): 
    185         self._strokecolor = None 
    186  
    187     def stroke(self, *args): 
    188         if len(args) > 0: 
    189             self._strokecolor = Color(self._ctx, *args) 
    190         return self._strokecolor 
    191  
    192     def strokewidth(self, width=None): 
    193         if width is not None: 
    194             self._strokewidth = width 
    195         return self._strokewidth 
    196  
    197 class BezierPath(Grob, TransformMixin, ColorMixin): 
    198     """A BezierPath provides a wrapper around NSBezierPath.""" 
    199      
    200     stateAttributes = ('_fillcolor', '_strokecolor', '_strokewidth', '_transform', '_transformmode') 
    201     kwargs = ('fill', 'stroke', 'strokewidth') 
    202  
    203     def __init__(self, ctx, path=None, **kwargs): 
    204         super(BezierPath, self).__init__(ctx) 
    205         TransformMixin.__init__(self) 
    206         ColorMixin.__init__(self, **kwargs) 
    207         self._segment_cache = None 
    208         if path is None: 
    209             self.path = NSBezierPath.bezierPath() 
    210         elif isinstance(path, list): 
    211             self.path = NSBezierPath.bezierPath() 
    212             self.extend(path) 
    213         elif isinstance(path, BezierPath): 
    214             self.path = path.path.copy() 
    215             _copy_attrs(path, self, self.stateAttributes) 
    216         elif isinstance(path, NSBezierPath): 
    217             self.path = path 
    218         else: 
    219             raise NodeBoxError, "Don't know what to do with %s." % path 
    220  
    221     def copy(self): 
    222         return self.__class__(self._ctx, self) 
    223  
    224     ### Path methods ### 
    225  
    226     def moveto(self, x, y): 
    227         self._segment_cache = None 
    228         self.path.moveToPoint_( (x, y) ) 
    229  
    230     def lineto(self, x, y): 
    231         self._segment_cache = None 
    232         self.path.lineToPoint_( (x, y) ) 
    233  
    234     def curveto(self, x1, y1, x2, y2, x3, y3): 
    235         self._segment_cache = None 
    236         self.path.curveToPoint_controlPoint1_controlPoint2_( (x3, y3), (x1, y1), (x2, y2) ) 
    237  
    238     def closepath(self): 
    239         self._segment_cache = None 
    240         self.path.closePath() 
    241  
    242     def setlinewidth(self, width): 
    243         self.linewidth = width 
    244  
    245     def _get_bounds(self): 
    246         try: 
    247             return self.path.bounds() 
    248         except: 
    249             # Path is empty -- no bounds 
    250             return (0,0) , (0,0) 
    251  
    252     bounds = property(_get_bounds) 
    253  
    254     def contains(self, x, y): 
    255         return self.path.containsPoint_((x,y)) 
    256          
    257     ### Basic shapes ### 
    258      
    259     def rect(self, x, y, width, height): 
    260         self._segment_cache = None 
    261         self.path.appendBezierPathWithRect_( ((x, y), (width, height)) ) 
    262          
    263     def oval(self, x, y, width, height): 
    264         self._segment_cache = None 
    265         self.path.appendBezierPathWithOvalInRect_( ((x, y), (width, height)) ) 
    266          
    267     def line(self, x1, y1, x2, y2): 
    268         self._segment_cache = None 
    269         self.path.moveToPoint_( (x1, y1) ) 
    270         self.path.lineToPoint_( (x2, y2) ) 
    271  
    272     ### List methods ### 
    273  
    274     def __getitem__(self, index): 
    275         cmd, el = self.path.elementAtIndex_associatedPoints_(index) 
    276         return PathElement(cmd, el) 
    277  
    278     def __iter__(self): 
    279         for i in range(len(self)): 
    280             yield self[i] 
    281  
    282     def __len__(self): 
    283         return self.path.elementCount() 
    284  
    285     def extend(self, pathElements): 
    286         self._segment_cache = None 
    287         for el in pathElements: 
    288             self.append(el) 
    289  
    290     def append(self, el): 
    291         self._segment_cache = None 
    292         if el.cmd == MOVETO: 
    293             self.moveto(el.x, el.y) 
    294         elif el.cmd == LINETO: 
    295             self.lineto(el.x, el.y) 
    296         elif el.cmd == CURVETO: 
    297             self.curveto(el.ctrl1.x, el.ctrl1.y, el.ctrl2.x, el.ctrl2.y, el.x, el.y) 
    298         elif el.cmd == CLOSE: 
    299             self.closepath() 
    300              
    301     def _get_contours(self): 
    302         import bezier 
    303         return bezier.contours(self) 
    304     contours = property(_get_contours) 
    305  
    306     ### Drawing methods ### 
    307  
    308     def _get_transform(self): 
    309         trans = self._transform.copy() 
    310  
    311         if (self._transformmode == CENTER): 
    312             (x, y), (w, h) = self.bounds 
    313             deltax = x+w/2 
    314             deltay = y+h/2 
    315             t = Transform() 
    316             t.translate(-deltax,-deltay) 
    317             trans.prepend(t) 
    318             t = Transform() 
    319             t.translate(deltax,deltay) 
    320             trans.append(t) 
    321  
    322         return trans 
    323  
    324     transform = property(_get_transform) 
    325  
    326     def _draw(self): 
    327         _save() 
    328         self.transform.concat() 
    329         if (self._fillcolor): 
    330             self._fillcolor.set() 
    331             self.path.fill() 
    332         if (self._strokecolor): 
    333             self._strokecolor.set() 
    334             self.path.setLineWidth_(self._strokewidth) 
    335             self.path.stroke() 
    336         _restore() 
    337          
    338     ### Mathematics ### 
    339      
    340     def segmentlengths(self, relative=False, n=10): 
    341         import bezier 
    342         if relative: # Use the opportunity to store the segment cache. 
    343             if self._segment_cache is None: 
    344                 self._segment_cache = bezier.segment_lengths(self, relative=True, n=n) 
    345             return self._segment_cache 
    346         else: 
    347             return bezier.segment_lengths(self, relative=False, n=n) 
    348  
    349     def _get_length(self, segmented=False, n=10): 
    350         import bezier 
    351         return bezier.length(self, segmented=segmented, n=n) 
    352     length = property(_get_length) 
    353          
    354     def point(self, t): 
    355         import bezier 
    356         return bezier.point(self, t) 
    357          
    358     def points(self, amount=100): 
    359         import bezier 
    360         if len(self) == 0: 
    361             raise NodeBoxError, "The given path is empty" 
    362  
    363         # The delta value is divided by amount - 1, because we also want the last point (t=1.0) 
    364         # If I wouldn't use amount - 1, I fall one point short of the end. 
    365         # E.g. if amount = 4, I want point at t 0.0, 0.33, 0.66 and 1.0, 
    366         # if amount = 2, I want point at t 0.0 and t 1.0 
    367         try: 
    368             delta = 1.0/(amount-1) 
    369         except ZeroDivisionError: 
    370             delta = 1.0 
    371  
    372         for i in xrange(amount): 
    373             yield self.point(delta*i) 
    374              
    375     def addpoint(self, t): 
    376         import bezier 
    377         self.path = bezier.insert_point(self, t).path 
    378         self._segment_cache = None 
    379  
    380 class PathElement(object): 
    381  
    382     def __init__(self, cmd=None, pts=None): 
    383         self.cmd = cmd 
    384         if cmd == MOVETO: 
    385             assert len(pts) == 1 
    386             self.x, self.y = pts[0] 
    387             self.ctrl1 = Point(pts[0]) 
    388             self.ctrl2 = Point(pts[0]) 
    389         elif cmd == LINETO: 
    390             assert len(pts) == 1 
    391             self.x, self.y = pts[0] 
    392             self.ctrl1 = Point(pts[0]) 
    393             self.ctrl2 = Point(pts[0]) 
    394         elif cmd == CURVETO: 
    395             assert len(pts) == 3 
    396             self.ctrl1 = Point(pts[0]) 
    397             self.ctrl2 = Point(pts[1]) 
    398             self.x, self.y = pts[2] 
    399         elif cmd == CLOSE: 
    400             assert pts is None or len(pts) == 0 
    401             self.x = self.y = 0.0 
    402             self.ctrl1 = Point(0.0, 0.0) 
    403             self.ctrl2 = Point(0.0, 0.0) 
    404         else: 
    405             self.x = self.y = 0.0 
    406             self.ctrl1 = Point() 
    407             self.ctrl2 = Point() 
    408  
    409     def __repr__(self): 
    410         if self.cmd == MOVETO: 
    411             return "PathElement(MOVETO, ((%.3f, %.3f),))" % (self.x, self.y) 
    412         elif self.cmd == LINETO: 
    413             return "PathElement(LINETO, ((%.3f, %.3f),))" % (self.x, self.y) 
    414         elif self.cmd == CURVETO: 
    415             return "PathElement(CURVETO, ((%.3f, %.3f), (%.3f, %s), (%.3f, %.3f))" % \ 
    416                 (self.ctrl1.x, self.ctrl1.y, self.ctrl2.x, self.ctrl2.y, self.x, self.y) 
    417         elif self.cmd == CLOSE: 
    418             return "PathElement(CLOSE)" 
    419              
    420     def __eq__(self, other): 
    421         if other is None: return False 
    422         if self.cmd != other.cmd: return False 
    423         return self.x == other.x and self.y == other.y \ 
    424             and self.ctrl1 == other.ctrl1 and self.ctrl2 == other.ctrl2 
    425          
    426     def __ne__(self, other): 
    427         return not self.__eq__(other) 
    428  
    429 class ClippingPath(Grob): 
    430  
    431     def __init__(self, ctx, path): 
    432         self._ctx = ctx 
    433         self.path = path 
    434         self._grobs = [] 
    435          
    436     def append(self, grob): 
    437         self._grobs.append(grob) 
    438          
    439     def _draw(self): 
    440         _save() 
    441         cp = self.path.transform.transformBezierPath(self.path) 
    442         cp.path.addClip() 
    443         for grob in self._grobs: 
    444             grob._draw() 
    445         _restore() 
    446  
    447 class Rect(BezierPath): 
    448  
    449     def __init__(self, ctx, x, y, width, height, **kwargs): 
    450         r = (x,y), (width,height) 
    451         super(Rect, self).__init__(ctx, NSBezierPath.bezierPathWithRect_(r), **kwargs) 
    452  
    453     def copy(self): 
    454         raise NotImplementedError, "Please don't use Rect anymore" 
    455  
    456 class Oval(BezierPath): 
    457  
    458     def __init__(self, ctx, x, y, width, height, **kwargs): 
    459         r = (x,y), (width,height) 
    460         super(Oval, self).__init__(ctx, NSBezierPath.bezierPathWithOvalInRect_(r), **kwargs) 
    461  
    462     def copy(self): 
    463         raise NotImplementedError, "Please don't use Oval anymore" 
    464  
    465 class Color(object): 
    466  
    467     def __init__(self, ctx, *args): 
    468         self._ctx = ctx 
    469         params = len(args) 
    470  
    471         # Decompose the arguments into tuples.  
    472         if params == 1 and isinstance(args[0], tuple): 
    473             args = args[0] 
    474             params = len(args) 
    475  
    476         if params == 1 and isinstance(args[0], Color): 
    477             clr = args[0]._cmyk 
    478         elif params == 1 and isinstance(args[0], NSColor): 
    479             clr = args[0] 
    480         elif params == 1: # Gray, no alpha 
    481             args = self._normalizeList(args) 
    482             g, = args 
    483             clr = NSColor.colorWithDeviceWhite_alpha_(g, 1) 
    484         elif params == 2: # Gray and alpha 
    485             args = self._normalizeList(args) 
    486             g, a = args 
    487             clr = NSColor.colorWithDeviceWhite_alpha_(g, a) 
    488         elif params == 3 and self._ctx._colormode == RGB: # RGB, no alpha 
    489             args = self._normalizeList(args) 
    490             r,g,b = args 
    491             clr = NSColor.colorWithDeviceRed_green_blue_alpha_(r, g, b, 1) 
    492         elif params == 3 and self._ctx._colormode == HSB: # HSB, no alpha 
    493             args = self._normalizeList(args) 
    494             h, s, b = args 
    495             clr = NSColor.colorWithDeviceHue_saturation_brightness_alpha_(h, s, b, 1) 
    496         elif params == 4 and self._ctx._colormode == RGB: # RGB and alpha 
    497             args = self._normalizeList(args) 
    498             r,g,b, a = args 
    499             clr = NSColor.colorWithDeviceRed_green_blue_alpha_(r, g, b, a) 
    500         elif params == 4 and self._ctx._colormode == HSB: # HSB and alpha 
    501             args = self._normalizeList(args) 
    502             h, s, b, a = args 
    503             clr = NSColor.colorWithDeviceHue_saturation_brightness_alpha_(h, s, b, a) 
    504         elif params == 4 and self._ctx._colormode == CMYK: # CMYK, no alpha 
    505             args = self._normalizeList(args) 
    506             c, m, y, k  = args 
    507             clr = NSColor.colorWithDeviceCyan_magenta_yellow_black_alpha_(c, m, y, k, 1) 
    508         elif params == 5 and self._ctx._colormode == CMYK: # CMYK and alpha 
    509             args = self._normalizeList(args) 
    510             c, m, y, k, a  = args 
    511             clr = NSColor.colorWithDeviceCyan_magenta_yellow_black_alpha_(c, m, y, k, a) 
    512         else: 
    513             clr = NSColor.colorWithDeviceWhite_alpha_(0, 1) 
    514  
    515         self._cmyk = clr.colorUsingColorSpaceName_(NSDeviceCMYKColorSpace) 
    516         self._rgb = clr.colorUsingColorSpaceName_(NSDeviceRGBColorSpace) 
    517  
    518     def __repr__(self): 
    519         return "%s(%.3f, %.3f, %.3f, %.3f)" % (self.__class__.__name__, self.red, 
    520                 self.green, self.blue, self.alpha) 
    521  
    522     def set(self): 
    523         self.nsColor.set() 
    524      
    525     def _get_nsColor(self): 
    526         if self._ctx._outputmode == RGB: 
    527             return self._rgb 
    528         else: 
    529             return self._cmyk 
    530     nsColor = property(_get_nsColor) 
    531          
    532  
    533     def copy(self): 
    534         new = self.__class__(self._ctx) 
    535         new._rgb = self._rgb.copy() 
    536         new._updateCmyk() 
    537         return new 
    538  
    539     def _updateCmyk(self): 
    540         self._cmyk = self._rgb.colorUsingColorSpaceName_(NSDeviceCMYKColorSpace) 
    541  
    542     def _updateRgb(self): 
    543         self._rgb = self._cmyk.colorUsingColorSpaceName_(NSDeviceRGBColorSpace) 
    544  
    545     def _get_hue(self): 
    546         return self._rgb.hueComponent() 
    547     def _set_hue(self, val): 
    548         val = self._normalize(val) 
    549         h, s, b, a = self._rgb.getHue_saturation_brightness_alpha_() 
    550         self._rgb = NSColor.colorWithDeviceHue_saturation_brightness_alpha_(val, s, b, a) 
    551         self._updateCmyk() 
    552     h = hue = property(_get_hue, _set_hue, doc="the hue of the color") 
    553  
    554     def _get_saturation(self): 
    555         return self._rgb.saturationComponent() 
    556     def _set_saturation(self, val): 
    557         val = self._normalize(val) 
    558         h, s, b, a = self._rgb.getHue_saturation_brightness_alpha_() 
    559         self._rgb = NSColor.colorWithDeviceHue_saturation_brightness_alpha_(h, val, b, a) 
    560         self._updateCmyk() 
    561     s = saturation = property(_get_saturation, _set_saturation, doc="the saturation of the color") 
    562  
    563     def _get_brightness(self): 
    564         return self._rgb.brightnessComponent() 
    565     def _set_brightness(self, val): 
    566         val = self._normalize(val) 
    567         h, s, b, a = self._rgb.getHue_saturation_brightness_alpha_() 
    568         self._rgb = NSColor.colorWithDeviceHue_saturation_brightness_alpha_(h, s, val, a) 
    569         self._updateCmyk() 
    570     v = brightness = property(_get_brightness, _set_brightness, doc="the brightness of the color") 
    571  
    572     def _get_hsba(self): 
    573         return self._rgb.getHue_saturation_brightness_alpha_() 
    574     def _set_hsba(self, values): 
    575         val = self._normalize(val) 
    576         h, s, b, a = values 
    577         self._rgb = NSColor.colorWithDeviceHue_saturation_brightness_alpha_(h, s, b, a) 
    578         self._updateCmyk() 
    579     hsba = property(_get_hsba, _set_hsba, doc="the hue, saturation, brightness and alpha of the color") 
    580  
    581     def _get_red(self): 
    582         return self._rgb.redComponent() 
    583     def _set_red(self, val): 
    584         val = self._normalize(val) 
    585         r, g, b, a = self._rgb.getRed_green_blue_alpha_() 
    586         self._rgb = NSColor.colorWithDeviceRed_green_blue_alpha_(val, g, b, a) 
    587         self._updateCmyk() 
    588     r = red = property(_get_red, _set_red, doc="the red component of the color") 
    589  
    590     def _get_green(self): 
    591         return self._rgb.greenComponent() 
    592     def _set_green(self, val): 
    593         val = self._normalize(val) 
    594         r, g, b, a = self._rgb.getRed_green_blue_alpha_() 
    595         self._rgb = NSColor.colorWithDeviceRed_green_blue_alpha_(r, val, b, a) 
    596         self._updateCmyk() 
    597     g = green = property(_get_green, _set_green, doc="the green component of the color") 
    598  
    599     def _get_blue(self): 
    600         return self._rgb.blueComponent() 
    601     def _set_blue(self, val): 
    602         val = self._normalize(val) 
    603         r, g, b, a = self._rgb.getRed_green_blue_alpha_() 
    604         self._rgb = NSColor.colorWithDeviceRed_green_blue_alpha_(r, g, val, a) 
    605         self._updateCmyk() 
    606     b = blue = property(_get_blue, _set_blue, doc="the blue component of the color") 
    607  
    608     def _get_alpha(self): 
    609         return self._rgb.alphaComponent() 
    610     def _set_alpha(self, val): 
    611         val = self._normalize(val) 
    612         r, g, b, a = self._rgb.getRed_green_blue_alpha_() 
    613         self._rgb = NSColor.colorWithDeviceRed_green_blue_alpha_(r, g, b, val) 
    614         self._updateCmyk() 
    615     a = alpha = property(_get_alpha, _set_alpha, doc="the alpha component of the color") 
    616  
    617     def _get_rgba(self): 
    618         return self._rgb.getRed_green_blue_alpha_() 
    619     def _set_rgba(self, val): 
    620         val = self._normalizeList(val) 
    621         r, g, b, a = val 
    622         self._rgb = NSColor.colorWithDeviceRed_green_blue_alpha_(r, g, b, a) 
    623         self._updateCmyk() 
    624     rgba = property(_get_rgba, _set_rgba, doc="the red, green, blue and alpha values of the color") 
    625  
    626     def _get_cyan(self): 
    627         return self._cmyk.cyanComponent() 
    628     def _set_cyan(self, val): 
    629         val = self._normalize(val) 
    630         c, m, y, k, a = self.cmyka # self._cmyk.getCyan_magenta_yellow_black_alpha_() 
    631         self._cmyk = NSColor.colorWithDeviceCyan_magenta_yellow_black_alpha_(val, m, y, k, a) 
    632         self._updateRgb() 
    633     c = cyan = property(_get_cyan, _set_cyan, doc="the cyan component of the color") 
    634  
    635     def _get_magenta(self): 
    636         return self._cmyk.magentaComponent() 
    637     def _set_magenta(self, val): 
    638         val = self._normalize(val) 
    639         c, m, y, k, a = self.cmyka # self._cmyk.getCyan_magenta_yellow_black_alpha_()