#
#   Python GUI - Components - PyObjC
#

import AppKit
from Foundation import NSRect, NSPoint, NSSize, NSObject
from Events import Event
from GComponents import Component as GComponent

#------------------------------------------------------------------------------

#_ns_autoresizing_mask = AppKit.NSViewMinYMargin

_ns_view_to_component = {}  # Mapping from NSView to corresponding Component

#------------------------------------------------------------------------------

class Component(GComponent):

    _has_local_coords = True

    def __init__(self, _ns_view, _ns_inner_view = None,
            _ns_set_autoresizing_mask = True, **kwds):
        self._ns_view = _ns_view
        if not _ns_inner_view:
            _ns_inner_view = _ns_view
        self._ns_inner_view = _ns_inner_view
        _ns_view_to_component[_ns_view] = self
        GComponent.__init__(self, **kwds)

    def destroy(self):
        #print "Component.destroy:", self ###
        GComponent.destroy(self)
        _ns_view = self._ns_view
        if _ns_view in _ns_view_to_component:
            #print "Component.destroy: removing", _ns_view, "from mapping" ###
            del _ns_view_to_component[_ns_view]
        #print "Component.destroy: breaking link to", self._ns_view ###
        self._ns_view = None
        #if self._ns_inner_view: print "Component.destroy: breaking inner link to", self._ns_inner_view ###
        self._ns_inner_view = None
    
    def get_bounds(self):
        (l, t), (w, h) = self._ns_view.frame()
        return (l, t, l + w, t + h)
    
    def set_bounds(self, (l, t, r, b)):
        ns_frame = NSRect(NSPoint(l, t), NSSize(r - l, b - t))
        self._ns_view.setFrame_(ns_frame)

    def become_target(self):
        ns_view = self._ns_view
        ns_window = ns_view.window()
        if ns_window:
            ns_window.makeFirstResponder_(ns_view)

#------------------------------------------------------------------------------

class PyGUI_NSActionTarget(NSObject):
    #  A shared instance of this class is used as the target of
    #  all action messages from the NSViews of Components. It
    #  performs the action by calling the similarly-named method of
    #  the corresponding Component.
    
    def doAction_(self, ns_sender):
        self.call_method('do_action', ns_sender)
    
    def call_method(self, method_name, ns_sender):
        component = _ns_view_to_component.get(ns_sender)
        if component:
            getattr(component, method_name)()

_ns_action_target = PyGUI_NSActionTarget.alloc().init()

def ns_set_action(ns_control, method_name):
    #  Arrange for the 'action' message of the NSControl to
    #  invoke the indicated method of its associated Component.
    ns_control.setAction_(method_name)
    ns_control.setTarget_(_ns_action_target)

#------------------------------------------------------------------------------

class PyGUI_NS_EventHandler:
    #  Methods to be mixed in with NSView subclasses that are
    #  to relay mouse and keyboard events to a Component.
    #
    #  pygui_component   Component

    def mouseDown_(self, ns_event):
        #print "PyGUI_NS_EventHandler.mouseDown_" ###
        self._ns_mouse_event(ns_event)

    def mouseUp_(self, ns_event):
        self._ns_mouse_event(ns_event)

    def mouseDragged_(self, ns_event):
        self._ns_mouse_event(ns_event)

    def rightMouseDown_(self, ns_event):
        self._ns_mouse_event(ns_event)

    def rightMouseUp_(self, ns_event):
        self._ns_mouse_event(ns_event)

    def rightMouseDragged_(self, ns_event):
        self._ns_mouse_event(ns_event)

    def otherMouseDown_(self, ns_event):
        self._ns_mouse_event(ns_event)

    def otherMouseUp_(self, ns_event):
        self._ns_mouse_event(ns_event)

    def otherMouseDragged_(self, ns_event):
        self._ns_mouse_event(ns_event)

    #def mouseMoved_(self, ns_event):
    #	self._ns_mouse_event(ns_event)

    def mouseEntered_(self, ns_event):
        self._ns_mouse_event(ns_event)

    def mouseExited_(self, ns_event):
        self._ns_mouse_event(ns_event)

    def keyDown_(self, ns_event):
        self._ns_other_event(ns_event)

    def keyUp_(self, ns_event):
        self._ns_other_event(ns_event)

    def _ns_mouse_event(self, ns_event):
        #print "PyGUI_NS_EventHandler._ns_mouse_event" ###
        event = self._ns_mouse_event_to_event(ns_event)
        #print "...sending to", self.pygui_component ###
        component = self.pygui_component
        if component:
            component.handle_event_here(event)
    
    def _ns_mouse_event_to_event(self, ns_event):
        event = Event(ns_event)
        event.position = tuple(self._ns_event_position(ns_event))
        return event

    def _ns_event_position(self, ns_event):
        #print "PyGUI_NS_EventHandler._ns_event_position:", self ###
        #print "...mro =", self.__class__.__mro__ ###
        ns_win_pos = ns_event.locationInWindow()
        return self.convertPoint_fromView_(ns_win_pos, None)

    def _ns_other_event(self, ns_event):
        event = Event(ns_event)
        component = self.pygui_component
        if component:
            component.handle_event(event)
