# Allow mouse modes to work with mouse on Acer or Sony 3D displays.
# Both these displays create a fullscreen window. This mouse mode support
# works by creating a backing full-screen Qt window which receives the
# mouse events.

def enable_xr_mouse_modes(session):
    screen = find_xr_screen(session)
    from Qt.QtWidgets import QWidget
    w = QWidget()
    session._xr_mouse_backing_window = w
    w.move(screen.geometry().topLeft())
    w.showFullScreen()
    w.mousePressEvent = lambda e: dispatch_mouse_event(e, "mouse_down", session)
    w.mouseMoveEvent = lambda e: dispatch_mouse_event(e, "mouse_drag", session)
    w.mouseReleaseEvent = lambda e: dispatch_mouse_event(e, "mouse_up", session)
    w.mouseDoubleClickEvent = lambda e: dispatch_mouse_event(e, "mouse_double_click", session)
    w.wheelEvent = lambda e: dispatch_wheel_event(e, session)

def dispatch_mouse_event(event, action, session):
    '''
    Convert a mouse event from 3D screen coordinates to
    graphics pane coordinates and dispatch it.
    '''
    p = event.position()
    gx, gy = map_event_coordinates(p.x(), p.y(), session)
    e = repositioned_event(event, gx, gy)
    session.ui.mouse_modes._dispatch_mouse_event(e, action)

def dispatch_wheel_event(event, session):
    '''
    Convert a wheel event from 3D screen coordinates to
    graphics pane coordinates and dispatch it.
    '''
    p = event.position()
    gx, gy = map_event_coordinates(p.x(), p.y(), session)
    e = repositioned_event(event, gx, gy)
    session.ui.mouse_modes._wheel_event(e)

def map_event_coordinates(x, y, session):
    '''
    Handle different aspect ratio of 3D screen window and
    graphics window.  Graphics window has cropped version
    of 3D window image.
    '''
    w3d = session._xr_mouse_backing_window
    w, h = w3d.width(), w3d.height()
    gw, gh = session.main_view.window_size
    if w == 0 or h == 0 or gw == 0 or gh == 0:
        return x, y
    fx,fy = x/w, y/h
    af = w*gh/(h*gw)
    if af > 1:
        afx = 0.5 + af * (fx - 0.5)
        afy = fy
    else:
        afx = fx
        afy = 0.5 + (1/af) * (fy - 0.5)
    gx, gy = afx * gw, afy * gh
    return gx, gy

def repositioned_event(event, x, y):
    from Qt.QtGui import QMouseEvent, QWheelEvent
    from Qt.QtCore import QPointF
    pos = QPointF(x, y)
    if isinstance(event, QMouseEvent):
        e = QMouseEvent(event.type(), pos, event.globalPosition(), event.button(), event.buttons(), event.modifiers(), event.device())
    elif isinstance(event, QWheelEvent):
        e = QWheelEvent(pos, event.globalPosition(), event.pixelDelta(), event.angleDelta(), event.buttons(), event.modifiers(), event.phase(), event.inverted(), device = event.device())
    else:
        raise RuntimeError(f'Event type is not mouse or wheel event {event}')
    return e

def find_xr_screen(session):
    known_screen_models = ['ASV27-2P']
    screens = session.ui.screens()
    for screen in screens:
        if screen.model() in known_screen_models:
            return screen
    mnames = [screen.model() for screen in screens]
    msg = f'Could not find Acer 3D screen model {", ".join(known_screen_models)} , only found {", ".join(mnames)}'
    raise RuntimeError(msg)

enable_xr_mouse_modes(session)

# When OpenXR turned off delete the backing window with
#   session._xr_mouse_backing_window.deleteLater()
#   session._xr_mouse_backing_window = None
