#
# Copyright (c) 2005, 2006 Art Haas
#
# This file is part of PythonCAD.
#
# PythonCAD 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.
#
# PythonCAD 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 PythonCAD; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# code for adding graphical methods to drawing entities
#

import types

import pygtk
pygtk.require('2.0')
import gtk
import pango

from PythonCAD.Generic import color
from PythonCAD.Generic import point
from PythonCAD.Generic import segment
from PythonCAD.Generic import circle
from PythonCAD.Generic import arc
from PythonCAD.Generic import leader
from PythonCAD.Generic import polyline
from PythonCAD.Generic import segjoint
from PythonCAD.Generic import conobject
from PythonCAD.Generic import hcline
from PythonCAD.Generic import vcline
from PythonCAD.Generic import acline
from PythonCAD.Generic import cline
from PythonCAD.Generic import ccircle
from PythonCAD.Generic import text
from PythonCAD.Generic import dimension
from PythonCAD.Generic import layer

from PythonCAD.Interface.Gtk import gtkimage

def _set_gc_values(gc, dl, c, t):
    if dl is None:
        _lt = gtk.gdk.LINE_SOLID
    else:
        _lt = gtk.gdk.LINE_DOUBLE_DASH
        gc.set_dashes(0, dl)
    gc.set_foreground(c)
    _t = int(round(t))
    if _t < 1: # no zero-pixel lines
        _t = 1
    gc.set_function(gtk.gdk.COPY)
    gc.set_line_attributes(_t, _lt, gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_MITER)

_point_color = color.Color(255, 255, 255) # white

def _draw_point(self, gimage, col=None):
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _x, _y = self.getCoords()
    _px, _py = gimage.coordToPixTransform(_x, _y)
    _w, _h = gimage.getSize()
    if (((_x + 5) < 0) or
        ((_y + 5) < 0) or
        ((_x - 5) > _w) or
        ((_y - 5) > _h)):
        return
    _gc = gimage.getGC()
    if _col is None:
        _col = _point_color
    _gc.set_foreground(gimage.getColor(_col))
    _pixmap = gimage.getPixmap()
    _pixmap.draw_point(_gc, _px, _py)
    if gimage.getOption('HIGHLIGHT_POINTS'):
        _count = 0
        for _user in self.getUsers():
            if not isinstance(_user, dimension.Dimension):
                _count = _count + 1
            if _count > 1:
                break
        if _count > 1:
            _col = gimage.getOption('MULTI_POINT_COLOR')
        else:
            _col = gimage.getOption('SINGLE_POINT_COLOR')
        _set_gc_values(_gc, None, gimage.getColor(_col), 1)
        _pixmap.draw_rectangle(_gc, False, (_px - 5), (_py - 5), 10, 10)

def _erase_point(self, gimage):
    _x, _y = self.getCoords()
    _px, _py = gimage.coordToPixTransform(_x, _y)
    _gc = gimage.getGC()
    _col = gimage.getOption('BACKGROUND_COLOR')
    _gc.set_foreground(gimage.getColor(_col))
    _pixmap = gimage.getPixmap()
    _pixmap.draw_point(_gc, _px, _py)
    if gimage.getOption('HIGHLIGHT_POINTS'):
        _gc.set_function(gtk.gdk.COPY)
        _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID,
                                gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_MITER)
        _pixmap.draw_rectangle(_gc, False, (_px - 5), (_py - 5), 10, 10)

def _draw_segment(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _xmin, _ymin, _xmax, _ymax = gimage.getView()
    _coords = self.clipToRegion(_xmin, _ymin, _xmax, _ymax)
    if _coords is not None:
        _p1, _p2 = self.getEndpoints()
        _p1.draw(gimage, _col)
        _p2.draw(gimage, _col)
        _x1, _y1, _x2, _y2 = _coords
        _p1x, _p1y = gimage.coordToPixTransform(_x1, _y1)
        _p2x, _p2y = gimage.coordToPixTransform(_x2, _y2)
        _gc = gimage.getGC()
        if _col is None:
            _col = self.getColor()
        _set_gc_values(_gc,
                       self.getLinetype().getList(),
                       gimage.getColor(_col),
                       self.getThickness()/gimage.getUnitsPerPixel())
        gimage.getPixmap().draw_line(_gc, _p1x, _p1y, _p2x, _p2y)

def _erase_segment(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_circle(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _cp = self.getCenter()
    _cp.draw(gimage, _col)
    _x, _y = _cp.getCoords()
    _r = self.getRadius()
    _px, _py = gimage.coordToPixTransform(_x, _y)
    _rx, _ry = gimage.coordToPixTransform((_x + _r), _y)
    _rad = _rx - _px
    _pxmin = _px - _rad
    _pymin = _py - _rad
    _cw = _ch = _rad * 2
    _gc = gimage.getGC()
    if _col is None:
        _col = self.getColor()
    _set_gc_values(_gc,
                   self.getLinetype().getList(),
                   gimage.getColor(_col),
                   self.getThickness()/gimage.getUnitsPerPixel())
    gimage.getPixmap().draw_arc(_gc, False,
                                _pxmin, _pymin,
                                _cw, _ch,
                                0, (360*64))

def _erase_circle(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_arc(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _layer = self.getParent()
    if _layer is None:
        raise RuntimeError, "No parent Layer for Arc"
    _cp = self.getCenter()
    _x, _y = _cp.getCoords()
    _r = self.getRadius()
    _sa = self.getStartAngle()
    _ea = self.getEndAngle()
    for _ep in self.getEndpoints():
        _ex, _ey = _ep
        _pts = _layer.find('point', _ex, _ey)
        if len(_pts) == 0:
            raise RuntimeError, "No Arc endpoint at: " + str(_ep)
        _ept = None
        for _pt in _pts:
            for _user in _pt.getUsers():
                if _user is self:
                    _ept = _pt
                    break
            if _ept is not None:
                break
        _ept.draw(gimage, _col)
        if abs(_sa - _ea) < 1e-10:
            break
    _cp.draw(gimage, _col)
    _px, _py = gimage.coordToPixTransform(_x, _y)
    _rx, _ry = gimage.coordToPixTransform((_x + _r), _y)
    _rad = _rx - _px
    _pxmin = _px - _rad
    _pymin = _py - _rad
    _cw = _ch = _rad * 2
    _gc = gimage.getGC()
    if _col is None:
        _col = self.getColor()
    _set_gc_values(_gc,
                   self.getLinetype().getList(),
                   gimage.getColor(_col),
                   self.getThickness()/gimage.getUnitsPerPixel())
    if abs(_sa - _ea) < 1e-10:
        _sweep = 360.0
    elif _sa > _ea:
        _sweep = 360.0 - (_sa - _ea)
    else:
        _sweep = _ea - _sa
    gimage.getPixmap().draw_arc(_gc, False,
                                _pxmin, _pymin,
                                _cw, _ch,
                                int(round(_sa * 64)),
                                int(round(_sweep * 64)))
def _erase_arc(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_leader(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _pts = []
    _p1, _p2, _p3 = self.getPoints()
    _p1.draw(gimage, _col)
    _p1x, _p1y = gimage.coordToPixTransform(_p1.x, _p1.y)
    _pts.append((_p1x, _p1y))
    _p2.draw(gimage, _col)
    _p2x, _p2y = gimage.coordToPixTransform(_p2.x, _p2.y)
    _pts.append((_p2x, _p2y))
    _p3.draw(gimage, _col)
    _p3x, _p3y = gimage.coordToPixTransform(_p3.x, _p3.y)
    _pts.append((_p3x, _p3y))
    _gc = gimage.getGC()
    if _col is None:
        _col = self.getColor()
    _set_gc_values(_gc,
                   self.getLinetype().getList(),
                   gimage.getColor(_col),
                   self.getThickness()/gimage.getUnitsPerPixel())
    _pixmap = gimage.getPixmap()
    _pixmap.draw_lines(_gc, _pts)
    _apts = []
    _apts.append((_p3x, _p3y))
    _pts = self.getArrowPoints()
    _a1x, _a1y = gimage.coordToPixTransform(_pts[0], _pts[1])
    _apts.append((_a1x, _a1y))
    _a2x, _a2y = gimage.coordToPixTransform(_pts[2], _pts[3])
    _apts.append((_a2x, _a2y))
    _pixmap.draw_polygon(_gc, True, _apts)

def _erase_leader(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_polyline(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _pts = []
    for _pt in self.getPoints():
        _pt.draw(gimage, _col)
        _x, _y = _pt.getCoords()
        _px, _py = gimage.coordToPixTransform(_x, _y)
        _pts.append((_px, _py))
    _gc = gimage.getGC()
    if _col is None:
        _col = self.getColor()
    _set_gc_values(_gc,
                   self.getLinetype().getList(),
                   gimage.getColor(_col),
                   self.getThickness()/gimage.getUnitsPerPixel())
    gimage.getPixmap().draw_lines(_gc, _pts)

def _erase_polyline(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_chamfer(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _p1, _p2 = self.getMovingPoints()
    _p1x, _p1y = gimage.coordToPixTransform(_p1.x, _p1.y)
    _p2x, _p2y = gimage.coordToPixTransform(_p2.x, _p2.y)
    _gc = gimage.getGC()
    if _col is None:
        _col = self.getColor()
    _set_gc_values(_gc,
                   self.getLinetype().getList(),
                   gimage.getColor(_col),
                   self.getThickness()/gimage.getUnitsPerPixel())
    gimage.getPixmap().draw_line(_gc, _p1x, _p1y, _p2x, _p2y)

def _erase_chamfer(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_fillet(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _cx, _cy = self.getCenter()
    _pcx, _pcy = gimage.coordToPixTransform(_cx, _cy)
    _p1, _p2 = self.getMovingPoints()
    _p1x, _p1y = gimage.coordToPixTransform(_p1.x, _p1.y)
    _p2x, _p2y = gimage.coordToPixTransform(_p2.x, _p2.y)
    _r = self.getRadius()
    _rx, _ry = gimage.coordToPixTransform((_cx + _r), _cy)
    _pr = _rx - _pcx
    _pxmin = _pcx - _pr
    _pymin = _pcy - _pr
    _cw = _ch = _pr * 2
    _sa1, _sa2 = self.getAngles()
    _amin = min(_sa1, _sa2)
    _amax = max(_sa1, _sa2)
    if _amax - _amin > 180.0:
        _a1 = _amax
        _a2 = _amin
    else:
        _a1 = _amin
        _a2 = _amax
    # print "a1: %g" % _a1
    # print "a2: %g" % _a2
    if _a1 > _a2:
        _sweep = 360.0 - (_a1 - _a2)
    else:
        _sweep = _a2 - _a1
    _gc = gimage.getGC()
    if _col is None:
        _col = self.getColor()
    _set_gc_values(_gc,
                   self.getLinetype().getList(),
                   gimage.getColor(_col),
                   self.getThickness()/gimage.getUnitsPerPixel())
    gimage.getPixmap().draw_arc(_gc, False,
                                _pxmin, _pymin,
                                _cw, _ch,
                                int(round(_a1 * 64)),
                                int(round(_sweep * 64)))

def _erase_fillet(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_hcline(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _lp = self.getLocation()
    _lp.draw(gimage, _col)
    _x, _y = _lp.getCoords()
    _px, _py = gimage.coordToPixTransform(_x, _y)
    _gc = gimage.getGC()
    if _col is None:
        _col = self.getColor()
    _set_gc_values(_gc,
                   self.getLinetype().getList(),
                   gimage.getColor(_col),
                   1.0)
    _w, _h = gimage.getSize()
    gimage.getPixmap().draw_line(_gc, 0, _py, _w, _py)

def _erase_hcline(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_vcline(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _lp = self.getLocation()
    _lp.draw(gimage, _col)
    _x, _y = _lp.getCoords()
    _px, _py = gimage.coordToPixTransform(_x, _y)
    _gc = gimage.getGC()
    if _col is None:
        _col = self.getColor()
    _set_gc_values(_gc,
                   self.getLinetype().getList(),
                   gimage.getColor(_col),
                   1.0)
    _w, _h = gimage.getSize()
    gimage.getPixmap().draw_line(_gc, _px, 0, _px, _h)

def _erase_vcline(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_acline(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _xmin, _ymin, _xmax, _ymax = gimage.getView()
    _coords = self.clipToRegion(_xmin, _ymin, _xmax, _ymax)
    if _coords is not None:
        _lp = self.getLocation()
        _lp.draw(gimage, _col)
        _x1, _y1, _x2, _y2 = _coords
        _p1x, _p1y = gimage.coordToPixTransform(_x1, _y1)
        _p2x, _p2y = gimage.coordToPixTransform(_x2, _y2)
        _gc = gimage.getGC()
        if _col is None:
            _col = self.getColor()
        _set_gc_values(_gc,
                       self.getLinetype().getList(),
                       gimage.getColor(_col),
                       1.0)
        gimage.getPixmap().draw_line(_gc, _p1x, _p1y, _p2x, _p2y)

def _erase_acline(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_cline(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _xmin, _ymin, _xmax, _ymax = gimage.getView()
    _coords = self.clipToRegion(_xmin, _ymin, _xmax, _ymax)
    if _coords is not None:
        _p1, _p2 = self.getKeypoints()
        _p1.draw(gimage, _col)
        _p2.draw(gimage, _col)
        _x1, _y1, _x2, _y2 = _coords
        _p1x, _p1y = gimage.coordToPixTransform(_x1, _y1)
        _p2x, _p2y = gimage.coordToPixTransform(_x2, _y2)
        _gc = gimage.getGC()
        if _col is None:
            _col = self.getColor()
        _set_gc_values(_gc,
                       self.getLinetype().getList(),
                       gimage.getColor(_col),
                       1.0)
        gimage.getPixmap().draw_line(_gc, _p1x, _p1y, _p2x, _p2y)

def _erase_cline(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_ccircle(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _cp = self.getCenter()
    _cp.draw(gimage, _col)
    _x, _y = _cp.getCoords()
    _r = self.getRadius()
    _px, _py = gimage.coordToPixTransform(_x, _y)
    _rx, _ry = gimage.coordToPixTransform((_x + _r), _y)
    _rad = _rx - _px
    _pxmin = _px - _rad
    _pymin = _py - _rad
    _cw = _ch = _rad * 2
    _gc = gimage.getGC()
    if _col is None:
        _col = self.getColor()
    _set_gc_values(_gc,
                   self.getLinetype().getList(),
                   gimage.getColor(_col),
                   self.getThickness()/gimage.getUnitsPerPixel())
    gimage.getPixmap().draw_arc(_gc, False,
                                _pxmin, _pymin,
                                _cw, _ch,
                                0, (360*64))

def _erase_ccircle(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _format_layout(self, gimage, layout):
    _fd = pango.FontDescription()
    _fd.set_family(self.getFamily())
    _val = self.getStyle()
    if _val == text.TextStyle.FONT_NORMAL:
        _style = pango.STYLE_NORMAL
    elif _val == text.TextStyle.FONT_OBLIQUE:
        _style = pango.STYLE_OBLIQUE
    elif _val == text.TextStyle.FONT_ITALIC:
        _style = pango.STYLE_ITALIC
    else:
        raise ValueError, "Unexpected TextBlock font style: %d" % _val
    _fd.set_style(_style)
    _val = self.getWeight()
    if _val == text.TextStyle.WEIGHT_NORMAL:
        _weight = pango.WEIGHT_NORMAL
    elif _val == text.TextStyle.WEIGHT_LIGHT:
        _weight = pango.WEIGHT_LIGHT
    elif _val == text.TextStyle.WEIGHT_BOLD:
        _weight = pango.WEIGHT_BOLD
    elif _val == text.TextStyle.WEIGHT_HEAVY:
        _weight = pango.WEIGHT_HEAVY
    else:
        raise ValueError, "Unexpected TextBlock font weight: %d" % _val
    _fd.set_weight(_weight)
    _upp = gimage.getUnitsPerPixel()
    _sz = int(pango.SCALE * (self.getSize()/_upp))
    if _sz < pango.SCALE:
        _sz = pango.SCALE
    # print "pango units text size: %d" % _sz        
    _fd.set_size(_sz)
    #
    # todo: handle drawing rotated text
    #
    _align = self.getAlignment()
    if _align == text.TextStyle.ALIGN_LEFT:
        layout.set_alignment(pango.ALIGN_LEFT)
    elif _align == text.TextStyle.ALIGN_CENTER:
        layout.set_alignment(pango.ALIGN_CENTER)
    elif _align == text.TextStyle.ALIGN_RIGHT:
        layout.set_alignment(pango.ALIGN_RIGHT)
    else:
        raise ValueError, "Unexpected TextBlock alignment value: %d" % _align
    layout.set_font_description(_fd)
    if self.getLineCount() > 0:
        _w, _h = layout.get_pixel_size()
        self.setBounds((_w * _upp), (_h * _upp))

def _draw_textblock(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _text = self.getText()
    _layout = gimage.getDA().create_pango_layout(_text)
    self._formatLayout(gimage, _layout)
    _x, _y = self.getLocation()
    _px, _py = gimage.coordToPixTransform(_x, _y)
    _gc = gimage.getGC()
    if _col is None:
        _col = self.getColor()
    _gc.set_foreground(gimage.getColor(_col))
    _gc.set_function(gtk.gdk.COPY)
    gimage.getPixmap().draw_layout(_gc, _px, _py, _layout)
    _layout = None
    
def _erase_textblock(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_dimstrings(self, gimage, col=None):
    _da = gimage.getDA()
    #
    # fixme - calculating dimensions needs rework!
    #
    _slen = gimage.scaleLength(self.calculate())
    _dims = self.getDimensions(_slen)
    _dx, _dy = self.getLocation()
    _ds1 = _ds2 = _l1 = _l2 = _x1 = _y1 = _x2 = _y2 = None
    if self.getDualDimMode():
        _off = self.getDualModeOffset()
        _ds1 = self.getPrimaryDimstring()
        _l1 = _da.create_pango_layout(_ds1.getText())
        _ds1._formatLayout(gimage, _l1)
        _w1, _h1 = _ds1.getBounds()
        _ds1.setLocation((_dx - (_w1/2.0)), (_dy + _h1 + _off))
        _x1, _y1 = _ds1.getLocation()
        _ds2 = self.getSecondaryDimstring()
        _l2 = _da.create_pango_layout(_ds2.getText())
        _ds2._formatLayout(gimage, _l2)
        _w2, _h2 = _ds2.getBounds()
        _ds2.setLocation((_dx - (_w2/2.0)), (_dy - _off))
        _x2, _y2 = _ds2.getLocation()
        _brect = (min(_x1, _x2), # xmin
                  _y1, # ymax
                  max((_x1 + _w1), (_x2 + _w2)), # xmax
                  (_y2 - _h2)) # ymin
    else:
        _ds1 = self.getPrimaryDimstring()
        _l1 = _da.create_pango_layout(_ds1.getText())
        _ds1._formatLayout(gimage, _l1)
        _w, _h = _ds1.getBounds()
        _ds1.setLocation((_dx - (_w/2.0)), (_dy + (_h/2.0)))
        _x1, _y1 = _ds1.getLocation()
        _brect = (_x1, _y1, (_x1 + _w), (_y1 - _h))
    _bx1, _by1 = gimage.coordToPixTransform(_brect[0], _brect[1])
    _bx2, _by2 = gimage.coordToPixTransform(_brect[2], _brect[3])
    _gc = gimage.getGC()
    _gc.set_function(gtk.gdk.COPY)
    _bgcol = gimage.getOption('BACKGROUND_COLOR')
    _gc.set_foreground(gimage.getColor(_bgcol))
    _pixmap = gimage.getPixmap()
    _pixmap.draw_rectangle(_gc, True, (_bx1 - 2), (_by1 - 2),
                           ((_bx2 - _bx1) + 4), ((_by2 - _by1) + 4))
    _col = col
    if _col is None:
        _col = _ds1.getColor()
    _gc.set_foreground(gimage.getColor(_col))
    _pixmap = gimage.getPixmap()
    _px, _py = gimage.coordToPixTransform(_x1, _y1)
    _pixmap.draw_layout(_gc, _px, _py, _l1)
    if _ds2 is not None:
        _col = col
        if _col is None:
            _col = _ds2.getColor()
        _gc.set_foreground(gimage.getColor(_col))
        _px, _py = gimage.coordToPixTransform(_x2, _y2)
        _pixmap.draw_layout(_gc, _px, _py, _l2)
        _col = col
        if _col is None:
            _col = self.getColor()
        _gc.set_foreground(gimage.getColor(_col))            
        _px1, _py1 = gimage.coordToPixTransform(_brect[0], _dy)
        _px2, _py2 = gimage.coordToPixTransform(_brect[2], _dy)
        _pixmap.draw_line(_gc, _px1, _py1, _px2, _py2)
        _l2 = None
    _l1 = None
    
def _draw_ldim(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _bar1, _bar2 = self.getDimBars()
    _cbar = self.getDimCrossbar()
    _gc = gimage.getGC()
    _gc.set_function(gtk.gdk.COPY)
    if _col is None:
        _col = self.getColor()
    _gc.set_foreground(gimage.getColor(_col))
    _t = int(round(self.getThickness()/gimage.getUnitsPerPixel()))
    if _t < 1: # no zero-pixel lines
        _t = 1
    _gc.set_line_attributes(_t, gtk.gdk.LINE_SOLID,
                            gtk.gdk.CAP_BUTT,
                            gtk.gdk.JOIN_MITER)
    #
    # draw bars and crossbar
    #
    _tlist = []
    _ep1, _ep2 = _bar1.getEndpoints()
    _px1, _py1 = gimage.coordToPixTransform(_ep1[0], _ep1[1])
    _px2, _py2 = gimage.coordToPixTransform(_ep2[0], _ep2[1])
    _tlist.append((_px1, _py1, _px2, _py2))
    _ep1, _ep2 = _bar2.getEndpoints()
    _px1, _py1 = gimage.coordToPixTransform(_ep1[0], _ep1[1])
    _px2, _py2 = gimage.coordToPixTransform(_ep2[0], _ep2[1])
    _tlist.append((_px1, _py1, _px2, _py2))
    _ep1, _ep2 = _cbar.getEndpoints()
    _px1, _py1 = gimage.coordToPixTransform(_ep1[0], _ep1[1])
    _px2, _py2 = gimage.coordToPixTransform(_ep2[0], _ep2[1])
    _tlist.append((_px1, _py1, _px2, _py2))
    _pixmap = gimage.getPixmap()
    _pixmap.draw_segments(_gc, _tlist)    
    #
    # draw endpoints
    #
    _etype = self.getEndpointType()
    if _etype != dimension.Dimension.DIM_ENDPT_NONE:
        del _tlist[:]
        _mpts = _cbar.getCrossbarPoints()
        _mx, _my = _mpts[0]
        _mp1x, _mp1y = gimage.coordToPixTransform(_mx, _my)
        _mx, _my = _mpts[1]
        _mp2x, _mp2y = gimage.coordToPixTransform(_mx, _my)
        if (_etype == dimension.Dimension.DIM_ENDPT_ARROW or
            _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW or
            _etype == dimension.Dimension.DIM_ENDPT_SLASH):
            _epts = _cbar.getMarkerPoints()
            if _etype == dimension.Dimension.DIM_ENDPT_ARROW:
                _ep = _epts[0]
                _px1, _py1 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_px1, _py1, _mp1x, _mp1y))
                _ep = _epts[1]
                _px1, _py1 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_px1, _py1, _mp1x, _mp1y))
                _ep = _epts[2]
                _px1, _py1 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_px1, _py1, _mp2x, _mp2y))
                _ep = _epts[3]
                _px1, _py1 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_px1, _py1, _mp2x, _mp2y))
                _pixmap.draw_segments(_gc, _tlist)
            elif _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW:
                _ep = _epts[0]
                _px1, _py1 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_px1, _py1))
                _ep = _epts[1]
                _px1, _py1 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_px1, _py1))
                _tlist.append((_mp1x, _mp1y))
                _pixmap.draw_polygon(_gc, True, _tlist)
                del _tlist[:]
                _ep = _epts[2]
                _px1, _py1 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_px1, _py1))
                _ep = _epts[3]
                _px1, _py1 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_px1, _py1))
                _tlist.append((_mp2x, _mp2y))
                _pixmap.draw_polygon(_gc, True, _tlist)
            elif _etype == dimension.Dimension.DIM_ENDPT_SLASH:
                _ep = _epts[0]
                _px1, _py1 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _ep = _epts[1]
                _px2, _py2 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_px1, _py1, _px2, _py2))
                _ep = _epts[2]
                _px1, _py1 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _ep = _epts[3]
                _px2, _py2 = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_px1, _py1, _px2, _py2))
                _pixmap.draw_segments(_gc, _tlist)
        elif _etype == dimension.Dimension.DIM_ENDPT_CIRCLE:
            _r = self.getEndpointSize()/2.0
            _pw = int(round(_r/gimage.getUnitsPerPixel()))
            _cw = _ch = _pw * 2
            _xm = _mp1x - _pw
            _ym = _mp1y - _pw
            _pixmap.draw_arc(_gc, True, _xm, _ym, _cw, _ch, 0, (360 * 64))
            _xm = _mp2x - _pw
            _ym = _mp2y - _pw
            _pixmap.draw_arc(_gc, True, _xm, _ym, _cw, _ch, 0, (360 * 64))
        else:
            raise ValueError, "Unexpected endpoint value: %d" % _etype
    self._drawDimStrings(gimage, col)

def _draw_rdim(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _gc = gimage.getGC()
    _gc.set_function(gtk.gdk.COPY)
    if _col is None:
        _col = self.getColor()
    _gc.set_foreground(gimage.getColor(_col))
    _t = int(round(self.getThickness()/gimage.getUnitsPerPixel()))
    if _t < 1: # no zero-pixel lines
        _t = 1
    _gc.set_line_attributes(_t, gtk.gdk.LINE_SOLID,
                            gtk.gdk.CAP_BUTT,
                            gtk.gdk.JOIN_MITER)
    _cbar = self.getDimCrossbar()
    _ep1, _ep2 = _cbar.getEndpoints()
    _p1x, _p1y = gimage.coordToPixTransform(_ep1[0], _ep1[1])
    _p2x, _p2y = gimage.coordToPixTransform(_ep2[0], _ep2[1])
    _tlist = []
    _tlist.append((_p1x, _p1y, _p2x, _p2y))
    _dx, _dy = self.getLocation()
    _pdx, _pdy = gimage.coordToPixTransform(_dx, _dy)
    #
    # draw marker points
    #
    _pixmap = gimage.getPixmap()
    _etype = self.getEndpointType()
    if _etype != dimension.Dimension.DIM_ENDPT_NONE:
        _mp1, _mp2 = _cbar.getCrossbarPoints()
        _mp1x, _mp1y = gimage.coordToPixTransform(_mp1[0], _mp1[1])
        _dia_mode = self.getDiaMode()
        if (_etype == dimension.Dimension.DIM_ENDPT_ARROW or
            _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW or
            _etype == dimension.Dimension.DIM_ENDPT_SLASH):
            _epts = _cbar.getMarkerPoints()
            if _etype == dimension.Dimension.DIM_ENDPT_ARROW:
                if _dia_mode:
                    _ex, _ey = _epts[0]
                    _epx1, _epy1 = gimage.coordToPixTransform(_ex, _ey)
                    _tlist.append((_epx1, _epy1, _mp1x, _mp1y))
                    _ex, _ey = _epts[1]
                    _epx2, _epy2 = gimage.coordToPixTransform(_ex, _ey)
                    _tlist.append((_epx2, _epy2, _mp1x, _mp1y))
                _mp2x, _mp2y = gimage.coordToPixTransform(_mp2[0], _mp2[1])
                _ex, _ey = _epts[2]
                _epx1, _epy1 = gimage.coordToPixTransform(_ex, _ey)
                _tlist.append((_epx1, _epy1, _mp2x, _mp2y))
                _ex, _ey = _epts[3]
                _epx2, _epy2 = gimage.coordToPixTransform(_ex, _ey)
                _tlist.append((_epx2, _epy2, _mp2x, _mp2y))
            elif _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW:
                _tuples = []
                if _dia_mode:            
                    _ex, _ey = _epts[0]
                    _epx1, _epy1 =  gimage.coordToPixTransform(_ex, _ey)
                    _tuples.append((_epx1, _epy1))
                    _ex, _ey = _epts[1]
                    _epx2, _epy2 =  gimage.coordToPixTransform(_ex, _ey)
                    _tuples.append((_epx2, _epy2))
                    _tuples.append((_mp1x, _mp1y))
                    _pixmap.draw_polygon(_gc, True, _tuples)
                    del _tuples[:]
                _mp2x, _mp2y = gimage.coordToPixTransform(_mp2[0], _mp2[1])
                _ex, _ey = _epts[2]
                _epx1, _epy1 =  gimage.coordToPixTransform(_ex, _ey)
                _tuples.append((_epx1, _epy1))
                _ex, _ey = _epts[3]
                _epx2, _epy2 =  gimage.coordToPixTransform(_ex, _ey)
                _tuples.append((_epx2, _epy2))
                _tuples.append((_mp2x, _mp2y))
                _pixmap.draw_polygon(_gc, True, _tuples)
            elif _etype == dimension.Dimension.DIM_ENDPT_SLASH:
                if _dia_mode:
                    _ex, _ey = _epts[0]
                    _epx1, _epy1 =  gimage.coordToPixTransform(_ex, _ey)
                    _ex, _ey = _epts[1]
                    _epx2, _epy2 =  gimage.coordToPixTransform(_ex, _ey)
                    _tlist.append((_epx1, _epy1, _epx2, _epy2))
                _ex, _ey = _epts[2]
                _epx1, _epy1 =  gimage.coordToPixTransform(_ex, _ey)
                _ex, _ey = _epts[3]
                _epx2, _epy2 =  gimage.coordToPixTransform(_ex, _ey)
                _tlist.append((_epx1, _epy1, _epx2, _epy2))
            else:
                raise ValueError, "Unexpected endpoint type value: %d" % _etype
        elif _etype == dimension.Dimension.DIM_ENDPT_CIRCLE:
            _r = self.getEndpointSize()/2.0
            _pw = int(_r/gimage.getUnitsPerPixel())
            _cw = _ch = _pw * 2
            if _dia_mode:
                _xmin = _mp1x - _pw
                _ymin = _mp1y - _pw
                _pixmap.draw_arc(_gc, True, _xmin, _ymin, _cw, _ch,
                                 0, (360 * 64))
            _mp2x, _mp2y = gimage.coordToPixTransform(_mp2[0], _mp2[1])
            _xmin = _mp2x - _pw
            _ymin = _mp2y - _pw
            _pixmap.draw_arc(_gc, True, _xmin, _ymin, _cw, _ch,
                             0, (360 * 64))
        else:
            raise ValueError, "Unexpected endpoint type value: %d" % _etype
    _pixmap.draw_segments(_gc, _tlist)
    self._drawDimStrings(gimage, col)

def _draw_adim(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    _gc = gimage.getGC()
    _gc.set_function(gtk.gdk.COPY)
    if _col is None:
        _col = self.getColor()
    _gc.set_foreground(gimage.getColor(_col))
    _t = int(round(self.getThickness()/gimage.getUnitsPerPixel()))
    if _t < 1: # no zero-pixel lines
        _t = 1
    _gc.set_line_attributes(_t, gtk.gdk.LINE_SOLID,
                            gtk.gdk.CAP_BUTT,
                            gtk.gdk.JOIN_MITER)
    _pixmap = gimage.getPixmap()
    _bar1, _bar2 = self.getDimBars()
    _carc = self.getDimCrossarc()
    #
    # draw dimension lines
    #
    _tlist = []
    _ep1, _ep2 = _bar1.getEndpoints()        
    _p1x, _p1y = gimage.coordToPixTransform(_ep1[0], _ep1[1])
    _p2x, _p2y = gimage.coordToPixTransform(_ep2[0], _ep2[1])
    _tlist.append((_p1x, _p1y, _p2x, _p2y))
    _ep1, _ep2 = _bar2.getEndpoints()
    _p1x, _p1y = gimage.coordToPixTransform(_ep1[0], _ep1[1])
    _p2x, _p2y = gimage.coordToPixTransform(_ep2[0], _ep2[1])
    _tlist.append((_p1x, _p1y, _p2x, _p2y))
    #
    # draw the dimension crossbar/arc
    #
    _vx, _vy = self.getVertexPoint().getCoords()
    _px, _py = gimage.coordToPixTransform(_vx, _vy)
    _dx, _dy = self.getLocation()
    _pdx, _pdy = gimage.coordToPixTransform(_dx, _dy)
    _pr = int(_carc.getRadius()/gimage.getUnitsPerPixel())
    _pxmin = _px - _pr
    _pymin = _py - _pr
    _cw = _ch = _pr * 2
    _sa = _carc.getStartAngle()
    _ea = _carc.getEndAngle()
    if _sa < _ea:
        _sweep = _ea - _sa
    else:
        _sweep = 360.0 - (_sa - _ea)
    _pixmap = gimage.getPixmap()        
    _pixmap.draw_arc(_gc, False, _pxmin, _pymin, _cw, _ch,
                     int(_sa * 64), int(_sweep * 64))
    #
    # draw endpont markers
    #
    _etype = self.getEndpointType()
    _mp1, _mp2 = _carc.getCrossbarPoints()
    _mp1x, _mp1y = gimage.coordToPixTransform(_mp1[0], _mp1[1])
    _mp2x, _mp2y = gimage.coordToPixTransform(_mp2[0], _mp2[1])
    if _etype != dimension.Dimension.DIM_ENDPT_NONE:    
        if (_etype == dimension.Dimension.DIM_ENDPT_ARROW or
            _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW or
            _etype == dimension.Dimension.DIM_ENDPT_SLASH):
            _epts = _carc.getMarkerPoints()
            if _etype == dimension.Dimension.DIM_ENDPT_ARROW:
                _ep = _epts[0]
                _p1x, _p1y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_p1x, _p1y, _mp1x, _mp1y))
                _ep = _epts[1]
                _p1x, _p1y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_p1x, _p1y, _mp1x, _mp1y))
                _ep = _epts[2]
                _p1x, _p1y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_p1x, _p1y, _mp2x, _mp2y))
                _ep = _epts[3]
                _p1x, _p1y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_p1x, _p1y, _mp2x, _mp2y))
            elif _etype == dimension.Dimension.DIM_ENDPT_FILLED_ARROW:
                _tuples = []
                _ep = _epts[0]
                _p1x, _p1y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tuples.append((_p1x, _p1y))
                _ep = _epts[1]
                _p1x, _p1y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tuples.append((_p1x, _p1y))
                _tuples.append((_mp1x, _mp1y))
                _pixmap.draw_polygon(_gc, True, _tuples)
                del _tuples[:]
                _ep = _epts[2]
                _p1x, _p1y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tuples.append((_p1x, _p1y))
                _ep = _epts[3]
                _p1x, _p1y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tuples.append((_p1x, _p1y))
                _tuples.append((_mp2x, _mp2y))
                _pixmap.draw_polygon(_gc, True, _tuples)
            elif _etype == dimension.Dimension.DIM_ENDPT_SLASH:
                _ep = _epts[0]
                _p1x, _p1y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _ep = _epts[1]
                _p2x, _p2y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_p1x, _p1y, _p2x, _p2y))
                _ep = _epts[2]
                _p1x, _p1y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _ep = _epts[3]
                _p2x, _p2y = gimage.coordToPixTransform(_ep[0], _ep[1])
                _tlist.append((_p1x, _p1y, _p2x, _p2y))
            else:
                raise ValueError, "Unexpected end point type: %d" % _etype
        elif _etype == dimension.Dimension.DIM_ENDPT_CIRCLE:
            _r = self.getEndpointSize()/2.0
            _pw = int(_r/gimage.getUnitsPerPixel())
            _cw = _ch = _pw * 2
            _xmin = _mp1x - _pw
            _ymin = _mp1y - _pw
            _pixmap.draw_arc(_gc, True, _xmin, _ymin, _cw, _ch,
                             0, (360 * 64))
            _xmin = _mp2x - _pw
            _ymin = _mp2y - _pw
            _pixmap.draw_arc(_gc, True, _xmin, _ymin, _cw, _ch,
                             0, (360 * 64))
        else:
            raise ValueError, "Unexpected end point type: %d" % _etype
    _pixmap.draw_segments(_gc, _tlist)    
    self._drawDimStrings(gimage, col)

def _erase_dim(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))

def _draw_layer(self, gimage, col=None):
    if not isinstance(gimage, gtkimage.GTKImage):
        raise TypeError, "Invalid GTKImage: " + `type(gimage)`
    _col = col
    if _col is not None and not isinstance(_col, color.Color):
        raise TypeError, "Invalid Color: " + `type(_col)`
    if _col is None:
        if self.isVisible() and gimage.getActiveLayer() is not self:
            _col = gimage.getOption('INACTIVE_LAYER_COLOR')
        else:
            _col = gimage.getOption('BACKGROUND_COLOR')
    for _obj in self.getLayerEntities('point'):
        if _obj.isVisible():
            _obj.draw(gimage, _col)
    _ctypes = ['hcline', 'vcline', 'acline', 'cline', 'ccircle']
    for _ctype in _ctypes:
        for _obj in self.getLayerEntities(_ctype):
            if _obj.isVisible():
                _obj.draw(gimage, _col)
    _gtypes = ['segment', 'circle', 'arc', 'leader', 'polyline',
               'chamfer', 'fillet', 'textblock', 'linear_dimension',
               'horizontal_dimension', 'vertical_dimension',
               'radial_dimension', 'angular_dimension']
    for _gtype in _gtypes:
        for _obj in self.getLayerEntities(_gtype):
            if _obj.isVisible():
                _obj.draw(gimage, _col)
            
def _erase_layer(self, gimage):
    self.draw(gimage, gimage.getOption('BACKGROUND_COLOR'))
    
def add_graphic_methods():
    _class = point.Point
    _class.draw = types.MethodType(_draw_point, None, _class)
    _class.erase = types.MethodType(_erase_point, None, _class)
    _class = segment.Segment
    _class.draw = types.MethodType(_draw_segment, None, _class)
    _class.erase = types.MethodType(_erase_segment, None, _class)
    _class = circle.Circle
    _class.draw = types.MethodType(_draw_circle, None, _class)
    _class.erase = types.MethodType(_erase_circle, None, _class)
    _class = arc.Arc
    _class.draw = types.MethodType(_draw_arc, None, _class)
    _class.erase = types.MethodType(_erase_arc, None, _class)
    _class = leader.Leader
    _class.draw = types.MethodType(_draw_leader, None, _class)
    _class.erase = types.MethodType(_erase_leader, None, _class)
    _class = polyline.Polyline
    _class.draw = types.MethodType(_draw_polyline, None, _class)
    _class.erase = types.MethodType(_erase_polyline, None, _class)
    _class = segjoint.Chamfer
    _class.draw = types.MethodType(_draw_chamfer, None, _class)
    _class.erase = types.MethodType(_erase_chamfer, None, _class)
    _class = segjoint.Fillet
    _class.draw = types.MethodType(_draw_fillet, None, _class)
    _class.erase = types.MethodType(_erase_fillet, None, _class)
    _class = hcline.HCLine
    _class.draw = types.MethodType(_draw_hcline, None, _class)
    _class.erase = types.MethodType(_erase_hcline, None, _class)
    _class = vcline.VCLine
    _class.draw = types.MethodType(_draw_vcline, None, _class)
    _class.erase = types.MethodType(_erase_vcline, None, _class)
    _class = acline.ACLine
    _class.draw = types.MethodType(_draw_acline, None, _class)
    _class.erase = types.MethodType(_erase_acline, None, _class)
    _class = cline.CLine
    _class.draw = types.MethodType(_draw_cline, None, _class)
    _class.erase = types.MethodType(_erase_cline, None, _class)
    _class = ccircle.CCircle
    _class.draw = types.MethodType(_draw_ccircle, None, _class)
    _class.erase = types.MethodType(_erase_ccircle, None, _class)
    _class = text.TextBlock
    _class._formatLayout = types.MethodType(_format_layout, None, _class)
    _class.draw = types.MethodType(_draw_textblock, None, _class)
    _class.erase = types.MethodType(_erase_textblock, None, _class)
    _class = dimension.LinearDimension
    _class.draw = types.MethodType(_draw_ldim, None, _class)
    _class = dimension.RadialDimension
    _class.draw = types.MethodType(_draw_rdim, None, _class)
    _class = dimension.AngularDimension
    _class.draw = types.MethodType(_draw_adim, None, _class)
    _class = dimension.Dimension
    _class.erase = types.MethodType(_erase_dim, None, _class)
    _class._drawDimStrings = types.MethodType(_draw_dimstrings, None, _class)
    _class = layer.Layer
    _class.draw = types.MethodType(_draw_layer, None, _class)
    _class.erase = types.MethodType(_erase_layer, None, _class)
