#
#   Python GUI - Drawing - PyObjC
#

from Foundation import NSPoint, NSMakeRect, NSString
from AppKit import NSGraphicsContext, NSBezierPath, NSEvenOddWindingRule, \
    NSFontAttributeName, NSForegroundColorAttributeName
from GCanvases import Canvas as GCanvas

class Canvas(GCanvas):

    def __init__(self):
        self._ns_path = NSBezierPath.bezierPath()
        self._ns_path.setWindingRule_(NSEvenOddWindingRule)
        GCanvas.__init__(self)
        self.initgraphics()
    
    def get_forecolor(self):
        return self._forecolor
    
    def set_forecolor(self, c):
        self._forecolor = c
    
    def get_backcolor(self):
        return self._backcolor
    
    def set_backcolor(self, c):
        self._backcolor = c
    
    def get_pensize(self):
        return self._pensize
    
    def set_pensize(self, d):
        self._pensize = d
        self._ns_path.setLineWidth_(d)
    
    def get_font(self):
        return self._font
    
    def set_font(self, f):
        self._font = f
    
    def newpath(self):
        self._ns_path.removeAllPoints()
    
    def moveto(self, x, y):
        self._ns_path.moveToPoint_(NSPoint(x, y))
    
    def rmoveto(self, dx, dy):
        self._ns_path.relativeMoveToPoint_(NSPoint(dx, dy))

    def lineto(self, x, y):
        self._ns_path.lineToPoint_(NSPoint(x, y))

    def rlineto(self, dx, dy):
        self._ns_path.relativeLineToPoint_(NSPoint(dx, dy))

    def closepath(self):
        self._ns_path.closePath()

    def clip(self):
        self._ns_path.addClip()

    def rectclip(self, (l, t, r, b)):
        ns_rect = NSMakeRect(l, t, r - l, b - t)
        NSBezierPath.clipRect_(ns_rect)

    def gsave(self):
        NSGraphicsContext.currentContext().saveGraphicsState()
    
    def grestore(self):
        NSGraphicsContext.currentContext().restoreGraphicsState()
    
    def stroke(self):
        self._forecolor._ns_color.set()
        self._ns_path.stroke()
    
    def fill(self):
        self._forecolor._ns_color.set()
        self._ns_path.fill()
    
    def show_text(self, text):
        x, y = self._ns_path.currentPoint()
        font = self._font
        ns_font = font._ns_font
        ns_color = self._forecolor._ns_color
        ns_string = NSString.stringWithString_(text)
        ns_attrs = {
            NSFontAttributeName: ns_font,
            NSForegroundColorAttributeName: ns_color,
        }
        #print "size:", ns_font.pointSize() ###
        #print "ascender:", ns_font.ascender() ###
        #print "descender:", ns_font.descender() ###
        #print "capHeight:", ns_font.capHeight() ###
        #print "defaultLineHeightForFont:", ns_font.defaultLineHeightForFont() ###
        h = font.line_height #ns_font.defaultLineHeightForFont()
        d = -ns_font.descender()
        ns_point = NSPoint(x, y - h + d)
        ns_string.drawAtPoint_withAttributes_(ns_point, ns_attrs)
        dx = ns_font.widthOfString_(ns_string)
        self._ns_path.relativeMoveToPoint_(NSPoint(x + dx, y))
    
    def _ns_frame_rect(self, (l, t, r, b)):
        p = self._pensize
        q = 0.5 * p
        return NSMakeRect(l + q, t + q, r - l - p, b - t - p)

    def stroke_rect(self, r):
        self._forecolor._ns_color.set()
        NSBezierPath.setDefaultLineWidth_(self._pensize)
        NSBezierPath.strokeRect_(_ns_rect(r))

    def frame_rect(self, r):
        self._forecolor._ns_color.set()
        NSBezierPath.setDefaultLineWidth_(self._pensize)
        NSBezierPath.strokeRect_(self._ns_frame_rect(r))
    
    def fill_rect(self, r):
        self._forecolor._ns_color.set()
        NSBezierPath.fillRect_(_ns_rect(r))
    
    def _ns_oval_path(self, ns_rect):
        ns_path = NSBezierPath.bezierPathWithOvalInRect_(ns_rect)
        ns_path.setLineWidth_(self._pensize)
        return ns_path
    
    def stroke_oval(self, r):
        self._forecolor._ns_color.set()
        self._ns_oval_path(_ns_rect(r)).stroke()
    
    def frame_oval(self, r):
        self._forecolor._ns_color.set()
        self._ns_oval_path(self._ns_frame_rect(r)).stroke()
    
    def fill_oval(self, r):
        self._forecolor._ns_color.set()
        self._ns_oval_path(_ns_rect(r)).fill()
    
    def _ns_arc_path(self, c, r, sa, aa):
        ns_path = NSBezierPath.bezierPath()
        ns_path.setLineWidth_(self._pensize)
        ns_path.\
            appendBezierPathWithArcWithCenter_radius_startAngle_endAngle_clockwise_(
                c, r, sa, sa + aa, aa < 0)
        return ns_path
    
    def stroke_arc(self, center, radius, start_angle, arc_angle):
        self._forecolor._ns_color.set()
        self._ns_arc_path(center, radius, start_angle, arc_angle).stroke()
    
    def frame_arc(self, center, radius, start_angle, arc_angle):
        self._forecolor._ns_color.set()
        r = radius - 0.5 * self._pensize
        self._ns_arc_path(center, r, start_angle, arc_angle).stroke()
    
    def fill_arc(self, center, radius, start_angle, arc_angle):
        self._forecolor._ns_color.set()
        ns_path = self._ns_arc_path(center, radius, start_angle, arc_angle)
        ns_path.lineToPoint_(center)
        ns_path.closePath()
        ns_path.fill()


def _ns_rect((l, t, r, b)):
    return NSMakeRect(l, t, r - l, b - t)

