glumpy
glumpy copied to clipboard
On Pyside2...
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved.
# Distributed under the (new) BSD License.
# -----------------------------------------------------------------------------
"""
`PySide <http://pyside.github.io/docs/pyside/>`_ is the Python Qt bindings
project, providing access the complete Qt 4.8 framework as well as to generator
tools for rapidly generating bindings for any C++ libraries.
**Usage**
.. code:: python
from glumpy import app
app.use("pyside2")
window = app.Window()
**Capability**
========================== ======== ======================== ========
Multiple windows ✓ Set GL API ✓
-------------------------- -------- ------------------------ --------
Non-decorated windows ✓ Set GL Profile ✓
-------------------------- -------- ------------------------ --------
Resize windows ✓ Share GL Context ✓
-------------------------- -------- ------------------------ --------
Move windows ✓ Unicode handling ✓
-------------------------- -------- ------------------------ --------
Fullscreen ✓ Scroll event ✓
========================== ======== ======================== ========
"""
import os
import sys
from glumpy import gl
from glumpy.log import log
from glumpy.app import configuration
from glumpy.app.window import window
# Backend name
__name__ = "PySide2"
# Backend version (if available)
__version__ = ""
# Backend availability
__availability__ = False
# Whether the framework has been initialized
__initialized__ = False
# Active windows
__windows__ = []
# GL Format
__glformat__ = None
# ---------------------------------------------------- convenient functions ---
def name():
return __name__
def version():
return __version__
def available():
return __availability__
# --------------------------------------------------------------- init/exit ---
def __init__():
global __initialized__
__app__ = QtWidgets.QApplication.instance()
if __app__ is None:
__app__ = QtWidgets.QApplication(sys.argv)
__initialized__ = True
def __exit__():
global __initialized__
__initialized__ = False
# ------------------------------------------------------------ availability ---
try:
from PySide2 import QtGui, QtCore, QtOpenGL, QtWidgets
if not __initialized__:
__init__()
__availability__ = True
__version__ = QtCore.__version__
__mouse_map__ = {
0: window.mouse.LEFT,
1: window.mouse.MIDDLE,
2: window.mouse.RIGHT
}
__key_map__ = {
QtCore.Qt.Key_Left: window.key.LEFT,
QtCore.Qt.Key_Up: window.key.UP,
QtCore.Qt.Key_Right: window.key.RIGHT,
QtCore.Qt.Key_Down: window.key.DOWN,
QtCore.Qt.Key_PageUp: window.key.PAGEUP,
QtCore.Qt.Key_PageDown: window.key.PAGEDOWN,
QtCore.Qt.Key_Insert: window.key.INSERT,
QtCore.Qt.Key_Delete: window.key.DELETE,
QtCore.Qt.Key_Home: window.key.HOME,
QtCore.Qt.Key_End: window.key.END,
QtCore.Qt.Key_Escape: window.key.ESCAPE,
QtCore.Qt.Key_Backspace: window.key.BACKSPACE,
QtCore.Qt.Key_F1: window.key.F1,
QtCore.Qt.Key_F2: window.key.F2,
QtCore.Qt.Key_F3: window.key.F3,
QtCore.Qt.Key_F4: window.key.F4,
QtCore.Qt.Key_F5: window.key.F5,
QtCore.Qt.Key_F6: window.key.F6,
QtCore.Qt.Key_F7: window.key.F7,
QtCore.Qt.Key_F8: window.key.F8,
QtCore.Qt.Key_F9: window.key.F9,
QtCore.Qt.Key_F10: window.key.F10,
QtCore.Qt.Key_F11: window.key.F11,
QtCore.Qt.Key_F12: window.key.F12,
QtCore.Qt.Key_Space: window.key.SPACE,
QtCore.Qt.Key_Enter: window.key.ENTER,
QtCore.Qt.Key_Return: window.key.ENTER,
QtCore.Qt.Key_Tab: window.key.TAB
}
except ImportError:
__availability__ = False
__version__ = None
# -------------------------------------------------------------- capability ---
capability = {
"Window position get/set": True,
"Window size get/set": True,
"Multiple windows": True,
"Mouse scroll events": True,
"Non-decorated window": True,
"Non-sizeable window": True,
"Fullscreen mode": True,
"Unicode processing": True,
"Set GL version": True,
"Set GL profile": True,
"Share GL context": True,
}
# ------------------------------------------------------- set_configuration ---
def set_configuration(config):
global __glformat__
# WARNING: does not work on osx
# http://stackoverflow.com/questions/...
# ...7868882/enabling-opengl-core-profile-in-qt4-on-os-x
__glformat__ = QtOpenGL.QGLFormat()
__glformat__.setRedBufferSize(config.red_size)
__glformat__.setGreenBufferSize(config.green_size)
__glformat__.setBlueBufferSize(config.blue_size)
__glformat__.setAlphaBufferSize(config.alpha_size)
__glformat__.setAccum(False)
__glformat__.setRgba(True)
if config.double_buffer:
__glformat__.setDoubleBuffer(True)
else:
__glformat__.setDoubleBuffer(False)
if config.depth_size:
__glformat__.setDepth(True)
__glformat__.setDepthBufferSize(config.depth_size)
else:
__glformat__.setDepth(False)
__glformat__.setDepthBufferSize(0)
if config.stencil_size:
__glformat__.setStencil(True)
__glformat__.setStencilBufferSize(config.stencil_size)
else:
__glformat__.setStencil(False)
__glformat__.setStencilBufferSize(0)
if config.samples:
__glformat__.setSampleBuffers(True)
__glformat__.setSamples(config.samples)
else:
__glformat__.setSampleBuffers(False)
__glformat__.setSamples(0)
__glformat__.setStereo(config.stereo)
__glformat__.setVersion(config.major_version, config.minor_version)
if config.major_version >= 3 and config.profile == "core":
__glformat__.setProfile(__glformat__.CoreProfile)
elif config.major_version >= 3 and config.profile == "compatibility":
__glformat__.setProfile(__glformat__.CompatibilityProfile)
else:
__glformat__.setProfile(__glformat__.NoProfile)
# ------------------------------------------------------------------ Window ---
class Window(window.Window):
def __init__(self,
width=256,
height=256,
title=None,
visible=True,
aspect=None,
decoration=True,
fullscreen=False,
config=None,
context=None,
color=(0, 0, 0, 1),
vsync=False):
window.Window.__init__(self,
width=width,
height=height,
title=title,
visible=visible,
aspect=aspect,
decoration=decoration,
fullscreen=fullscreen,
config=config,
context=context,
color=color)
if config is None:
config = configuration.Configuration()
set_configuration(config)
__glformat__.setSwapInterval(1 if vsync else 0)
self._native_app = QtWidgets.QApplication.instance()
if self._native_app is None:
self._native_app = QtWidgets.QApplication(sys.argv)
context = QtOpenGL.QGLContext(__glformat__)
if context.isValid():
self._native_window = QtOpenGL.QGLWidget(context)
else:
self._native_window = QtOpenGL.QGLWidget(__glformat__)
self._native_window.resize(width, height)
self._native_window.makeCurrent()
self._native_window.setAutoBufferSwap(False)
self._native_window.setMouseTracking(True)
self._native_window.setWindowTitle(self._title)
self._native_window.show()
def paint_gl():
self.dispatch_event("on_draw", 0.0)
self._native_window.paintGL = paint_gl
def resize_gl(width, height):
self.dispatch_event("on_resize", width, height)
self._native_window.resizeGL = resize_gl
def close_event(event):
__windows__.remove(self)
for i in range(len(self._timer_stack)):
handler, interval = self._timer_stack[i]
self._clock.unschedule(handler)
self.dispatch_event("on_close")
self._native_window.closeEvent = close_event
def mouse_press_event(event):
x = event.pos().x()
y = event.pos().y()
button = __mouse_map__.get(event.button(), window.mouse.UNKNOWN)
self._button = button
self._mouse_x = x
self._mouse_y = y
self.dispatch_event("on_mouse_press", x, y, button)
self._native_window.mousePressEvent = mouse_press_event
def mouse_release_event(event):
x = event.pos().x()
y = event.pos().y()
button = __mouse_map__.get(event.button(), window.mouse.UNKNOWN)
self._button = window.mouse.NONE
self._mouse_x = x
self._mouse_y = y
self.dispatch_event("on_mouse_release", x, y, button)
self._native_window.mouseReleaseEvent = mouse_release_event
def mouse_move_event(event):
x = event.pos().x()
y = event.pos().y()
dx = x - self._mouse_x
dy = y - self._mouse_y
self._mouse_x = x
self._mouse_y = y
if self._button is not window.mouse.NONE:
self.dispatch_event('on_mouse_drag', x, y, dx, dy,
self._button)
else:
self.dispatch_event('on_mouse_motion', x, y, dx, dy)
self._native_window.mouseMoveEvent = mouse_move_event
def wheel_event(event):
if event.orientation == QtCore.Qt.Horizontal:
offset_x = event.delta()
offset_y = 0
else:
offset_x = 0
offset_y = event.delta()
x = event.pos().x()
y = event.pos().y()
self.dispatch_event("on_mouse_scroll", x, y, offset_x / 10.0,
offset_y / 10.0)
self._native_window.wheelEvent = wheel_event
def key_press_event(event):
code = self._keyboard_translate(event.key())
modifiers = self._modifiers_translate(event.modifiers())
self.dispatch_event("on_key_press", code, modifiers)
self.dispatch_event("on_character", event.text())
self._native_window.keyPressEvent = key_press_event
def key_release_event(event):
code = self._keyboard_translate(event.key())
modifiers = self._modifiers_translate(event.modifiers())
self.dispatch_event("on_key_release", code, modifiers)
self._native_window.keyReleaseEvent = key_release_event
__windows__.append(self)
def _keyboard_translate(self, code):
if code in __key_map__:
return __key_map__[code]
if 32 <= code <= 96 or code in [161, 162]:
return code
return window.key.UNKNOWN
def _modifiers_translate(self, modifiers):
_modifiers = 0
if QtCore.Qt.ShiftModifier & modifiers:
_modifiers |= window.key.MOD_SHIFT
if QtCore.Qt.ControlModifier & modifiers:
_modifiers |= window.key.MOD_CONTROL
if QtCore.Qt.AltModifier & modifiers:
_modifiers |= window.key.MOD_ALT
if QtCore.Qt.MetaModifier & modifiers:
_modifiers |= window.key.MOD_META
return _modifiers
def _modifiers_translate(self, modifiers):
_modifiers = 0
if QtCore.Qt.ShiftModifier & modifiers:
_modifiers |= window.key.MOD_SHIFT
if QtCore.Qt.ControlModifier & modifiers:
_modifiers |= window.key.MOD_CONTROL
if QtCore.Qt.AltModifier & modifiers:
_modifiers |= window.key.MOD_ALT
if QtCore.Qt.MetaModifier & modifiers:
_modifiers |= window.key.MOD_META
return _modifiers
def close(self):
self._native_window.close()
def show(self):
self._native_window.show()
self.dispatch_event('on_show')
def hide(self):
self._native_window.hide()
self.dispatch_event('on_hide')
def set_title(self, title):
self._native_window.setWindowTitle(self._title)
self._title = title
def get_title(self, title):
return self._title
def set_size(self, width, height):
self._native_window.resize(width, height)
self._width = self._native_window.geometry().width()
self._height = self._native_window.geometry().height()
def get_size(self):
self._width = self._native_window.geometry().width()
self._height = self._native_window.geometry().height()
return self._width, self._height
def set_position(self, x, y):
self._native_window.move(x, y)
self._x = self._native_window.geometry().x()
self._y = self._native_window.geometry().y()
def get_position(self):
self._x = self._native_window.geometry().x()
self._y = self._native_window.geometry().y()
return self._x, self._y
def swap(self):
self._native_window.swapBuffers()
def activate(self):
self._native_window.makeCurrent()
# ----------------------------------------------------------------- windows ---
def windows():
return __windows__
# ----------------------------------------------------------------- process ---
def process(dt):
for window in __windows__:
# Poll for and process events
window._native_app.processEvents()
# window._native_app.flush()
for window in __windows__:
# Make window active
window.activate()
# Dispatch the main draw event
window.dispatch_event('on_draw', dt)
# Dispatch the idle event
window.dispatch_event('on_idle', dt)
# Swap buffers
window.swap()
return len(__windows__)
Oh nice. This is the backend for pyside2? Could you make a PR out of it ?
Yes, is the changes needed for pyside2. Let me see how to do the PR, ;)
It means more or less to fork glumpy on your github account, then clone this for on your computer, create a new branch (let's say pyside2), add your files and push to your repo. Then, on GitHub and on your forked repo, you'll see an option to make a Pull request.