#
#   PyGUI - Clip Components - Macintosh
#

from Carbon.Qd import NewRgn, CopyRgn, OffsetRgn, RectRgn, SectRgn, \
    SetEmptyRgn, SetOrigin, GetClip, SetClip, GetPort, SetPort, FrameRect, EraseRect
from MacDummy import _mac_dummy_port, _mac_dummy_window
from GClipComponents import ClipComponent as GClipComponent

class ClipComponent(GClipComponent):

    #  _bounds         rect                Bounds in container's coordinates
    #  _window         Window              Ultimate containing window, or None
    #  _mac_origin     point               Grafport origin when focused
    #  _mac_vis_rgn    Region              Clipping region in local coords
    #  _mac_window     Carbon.Win.Window   Macintosh window
    #  _mac_port       Carbon.Qd.GrafPort  Macintosh grafport

    def __init__(self, mac_window = _mac_dummy_window, **kwds):
        self._bounds = (0, 0, 100, 100)
        self._mac_origin = (0, 0)
        self._mac_vis_rgn = NewRgn()
        self._mac_window = mac_window
        self._mac_port = mac_window.GetWindowPort()
        GClipComponent.__init__(self, **kwds)

    def get_window(self):
        return self._window

    def get_bounds(self):
        return self._bounds
    
    def _mac_component_change_bounds(self, v):
        self._bounds = v
        self._mac_update_viewport()

    def _mac_update_viewport(self):
        # Update cached window reference and calculate origin and 
        # clip region settings for this component and all its
        # subcomponents. Must be called whenever component's
        # container, bounds, scroll offset or visibility changes.
        #print "ClipComponent._mac_update_viewport:", self ###
        window = None
        container = self._container
        if container:
            window = container.window
            if window:
                #print "...calculating viewport" ###
                cx, cy = container._mac_origin
                #print "...container origin =", cx, cy ###
                dx, dy = self.local_to_container_offset()
                #print "...local_to_container_offset =", dx, dy
                self._mac_origin = (cx - dx, cy - dy)
                #print "..._mac_origin =", self._mac_origin ###
                vis_rgn = self._mac_vis_rgn
                if self._visible:
                    #print "...calculating clip region" ###
                    #from Carbon.Qd import GetRegionBounds ###
                    RectRgn(vis_rgn, self.bounds)
                    #print "...view region bounds =", GetRegionBounds(vis_rgn) ###
                    SectRgn(container._mac_vis_rgn, vis_rgn, vis_rgn)
                    #print "...after intersection:", GetRegionBounds(vis_rgn) ###
                    OffsetRgn(vis_rgn, -dx, -dy)
                    #print "...after offsetting:", GetRegionBounds(vis_rgn) ###
                else:
                    #print "...setting clip region to empty" ###
                    SetEmptyRgn(vis_rgn)
        self._window = window
        if window:
            self._mac_window = window._mac_window
            self._mac_port = window._mac_port
        else:
            self._mac_window = _mac_dummy_window
            self._mac_port = _mac_dummy_port

    def invalidate_rect(self, rect):
        rgn = NewRgn()
        RectRgn(rgn, rect)
        self._with_focus(self._mac_inval_rgn, rgn)
    
    def _mac_inval_rect(self, rect):
        # Invalidate the given region.
        # NOTE: Must be called inside _with_focus.
        self._mac_window.InvalWindowRect(rect)
    
    def _mac_inval_rgn(self, rgn):
        # Invalidate the given region. 
        # NOTE: (1) Modifies the given region.
        #       (2) Must be called inside _with_focus.
        #print "Container._mac_inval_rgn: _mac_origin =", self._mac_origin ###
        #from Carbon.Qd import GetRegionBounds ###
        #print "...region bounds =", GetRegionBounds(rgn) ###
        SectRgn(self._mac_vis_rgn, rgn, rgn)
        self._mac_window.InvalWindowRgn(rgn)
    
    def _mac_update(self):
        # Respond to an update event, making no assumptions about
        # the drawing state.
        self._with_focus(self._mac_draw)
    
    def _mac_draw(self):
        # Draw this component, assuming that the grafport is focused
        # on it.
        pass

    def _with_focus(self, proc, *args):
        # Focus the grafport on this component, execute the
        # procedure, and then restore the previous focus.
        old_port = GetPort()
        new_port = self._mac_port
        SetPort(new_port)
        old_origin = new_port.GetPortBounds()[:2]
        old_clip = NewRgn()
        GetClip(old_clip)
        #print "Frame._with_focus: setting origin to", self._mac_origin ###
        SetOrigin(*self._mac_origin)
        SetClip(self._mac_vis_rgn)
        try:
            proc(*args)
        finally:
            SetOrigin(*old_origin)
            SetClip(old_clip)
            SetPort(old_port)

