Skip to content

Commit

Permalink
Merge pull request #475 from nucleic/qt6-support
Browse files Browse the repository at this point in the history
Qt6 support
  • Loading branch information
MatthieuDartiailh committed Mar 29, 2022
2 parents 3d24a5b + 885cfec commit d482957
Show file tree
Hide file tree
Showing 24 changed files with 194 additions and 149 deletions.
42 changes: 20 additions & 22 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,14 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.8', '3.9', '3.10']
qt-binding: [pyqt5, pyside2]
qt-version: [5, 6]
qt-binding: [pyqt, pyside]
exclude:
- os: ubuntu-latest
python-version: '3.10'
qt-binding: pyside2
- os: windows-latest
python-version: '3.10'
qt-binding: pyside2
- os: macos-latest
python-version: '3.10'
qt-binding: pyside2
- python-version: '3.10'
qt-version: 5
qt-binding: pyside
- python-version: '3.8'
qt-version: 6
fail-fast: false
steps:
- name: Install linux only test dependency
Expand All @@ -54,32 +51,33 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ply
pip install numpy
pip install git+https://github.com/MatthieuDartiailh/bytecode@main
pip install git+https://github.com/nucleic/atom@main
pip install git+https://github.com/nucleic/kiwi@main
- name: Install Qt bindings
- name: Install project
env:
CPPFLAGS: --coverage
run: |
pip install numpy qtpy '${{matrix.qt-binding}}'
pip install -e .[qt${{ matrix.qt-version }}-${{ matrix.qt-binding }}]
- name: Install extra dependencies
if: matrix.python-version == '3.9'
run: |
pip install matplotlib ipython qtconsole
- name: Install QScintilla
if: matrix.python-version == '3.9' && matrix.qt-binding == 'pyqt5'
- name: Install QScintilla (Qt5)
if: matrix.python-version == '3.9' && matrix.qt-binding == 'pyqt' && matrix.qt-version== 5
run: |
pip install Cython QScintilla
- name: Install project
env:
CPPFLAGS: --coverage
pip install QScintilla
- name: Install QScintilla (Qt6)
if: matrix.python-version == '3.9' && matrix.qt-binding == 'pyqt' && matrix.qt-version== 6
run: |
python setup.py develop
pip install PyQt6-QScintilla
- name: Install pytest
run: |
pip install pytest pytest-cov pytest-qt
- name: Run tests (Windows, Mac)
if: matrix.os != 'ubuntu-latest'
run: python -X dev -m pytest tests --cov enaml --cov-report xml
run: python -X dev -m pytest tests --cov enaml --cov-report xml -rs
- name: Run tests (Linux)
if: matrix.os == 'ubuntu-latest'
shell: bash -l {0}
Expand All @@ -89,7 +87,7 @@ jobs:
sleep 3
exec /usr/bin/startfluxbox &
sleep 1
python -X dev -m pytest tests --cov enaml --cov-report xml
python -X dev -m pytest tests --cov enaml --cov-report xml -rs
- name: Generate C++ coverage reports
if: (github.event_name != 'schedule' && matrix.os != 'windows-latest')
run: |
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
python-version: '3.9'
- name: Build sdist
run: |
pip install --upgrade pip
Expand All @@ -41,14 +41,14 @@ jobs:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
python: [37, 38, 39, 310]
python: [38, 39, 310]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
python-version: '3.9'
- name: Install cibuildwheel
run: |
python -m pip install --upgrade pip
Expand Down
16 changes: 16 additions & 0 deletions enaml/qt/Qsci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#------------------------------------------------------------------------------
# Copyright (c) 2022, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
from . import QT_API, PYQT5_API, PYQT6_API

if QT_API in PYQT6_API:
from PyQt6.Qsci import *
elif QT_API in PYQT5_API:
from PyQt5.Qsci import *
else:
msg = 'the Qt Scintilla widget is only available when using PyQt5 or PyQt6'
raise ImportError(msg)
15 changes: 11 additions & 4 deletions enaml/qt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
#------------------------------------------------------------------------------
# Copyright (c) 2013-2020, Nucleic Development Team.
# ------------------------------------------------------------------------------
# Copyright (c) 2013-2022, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
from qtpy import API as QT_API, PYQT5_API, PYSIDE2_API, QT_VERSION
# ------------------------------------------------------------------------------
from qtpy import (
API as QT_API,
PYQT5_API,
PYSIDE2_API,
PYQT6_API,
PYSIDE6_API,
QT_VERSION,
)
22 changes: 22 additions & 0 deletions enaml/qt/compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# ------------------------------------------------------------------------------
# Copyright (c) 2022, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
# ------------------------------------------------------------------------------
from qtpy.QtCore import QEvent

from . import QT_API, PYQT6_API, QT_VERSION

def coerce_to_qevent_type(event_value):
if QT_API in PYQT6_API:
return event_value
return QEvent.Type(event_value)


def global_pos_from_event(event):
if QT_VERSION[0] == "6":
return event.globalPosition().toPoint()
else:
return event.globalPos()
12 changes: 7 additions & 5 deletions enaml/qt/docking/dock_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
# WARNING! All changes made in this file will be lost!

# this line manually edited
import qtpy
from enaml.qt import QtCore

qt_resource_data = b"\
Expand Down Expand Up @@ -578,10 +579,11 @@
\x00\x00\x01\xde\x00\x00\x00\x00\x00\x01\x00\x00\x15\x13\
"

def qInitResources():
QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
if qtpy.QT_VERSION[0] == "5":
def qInitResources():
QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)

def qCleanupResources():
QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
def qCleanupResources():
QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)

qInitResources()
qInitResources()
23 changes: 12 additions & 11 deletions enaml/qt/docking/event_types.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,48 @@
#------------------------------------------------------------------------------
# Copyright (c) 2013-2017, Nucleic Development Team.
# Copyright (c) 2013-2022, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
from enaml.qt.compat import coerce_to_qevent_type
from enaml.qt.QtCore import QEvent


#: An event type which indicates the contents of a dock area changed.
DockAreaContentsChanged = QEvent.Type(QEvent.registerEventType())
DockAreaContentsChanged = coerce_to_qevent_type(QEvent.registerEventType())


#: An event type which indicates the dock item was docked.
DockItemDocked = QEvent.Type(QEvent.registerEventType())
DockItemDocked = coerce_to_qevent_type(QEvent.registerEventType())


#: An event type which indicates the dock item was undock.
DockItemUndocked = QEvent.Type(QEvent.registerEventType())
DockItemUndocked = coerce_to_qevent_type(QEvent.registerEventType())


#: An event type which indicates the dock item was extended.
DockItemExtended = QEvent.Type(QEvent.registerEventType())
DockItemExtended = coerce_to_qevent_type(QEvent.registerEventType())


#: An event type which indicates the dock item was retracted.
DockItemRetracted = QEvent.Type(QEvent.registerEventType())
DockItemRetracted = coerce_to_qevent_type(QEvent.registerEventType())


#: An event type which indicates the dock item was shown.
DockItemShown = QEvent.Type(QEvent.registerEventType())
DockItemShown = coerce_to_qevent_type(QEvent.registerEventType())


#: An event type which indicates the dock item was hidden.
DockItemHidden = QEvent.Type(QEvent.registerEventType())
DockItemHidden = coerce_to_qevent_type(QEvent.registerEventType())


#: An event type which indicates the dock item was closed.
DockItemClosed = QEvent.Type(QEvent.registerEventType())
DockItemClosed = coerce_to_qevent_type(QEvent.registerEventType())


#: An event type which indicates a dock tab was selected.
DockTabSelected = QEvent.Type(QEvent.registerEventType())
DockTabSelected = coerce_to_qevent_type(QEvent.registerEventType())


class QDockItemEvent(QEvent):
Expand All @@ -53,7 +54,7 @@ def __init__(self, type, name):
Parameters
----------
type : QEvent.Type
type : coerce_to_qevent_type
The event type for the event.
name : unicode
Expand Down
5 changes: 3 additions & 2 deletions enaml/qt/docking/q_bitmap_button.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#------------------------------------------------------------------------------
# Copyright (c) 2013-2017, Nucleic Development Team.
# Copyright (c) 2013-2022, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
from enaml.qt.compat import global_pos_from_event
from enaml.qt.QtCore import QPoint, QRect, QEvent
from enaml.qt.QtGui import QPainter, QColor
from enaml.qt.QtWidgets import (
Expand Down Expand Up @@ -217,7 +218,7 @@ def event(self, event):
if event.type() == QEvent.ToolTip:
tool_tip = self._effectiveToolTip()
if tool_tip:
QToolTip.showText(event.globalPos(), tool_tip, self)
QToolTip.showText(global_pos_from_event(event), tool_tip, self)
return True
return super(QCheckedBitmapButton, self).event(event)

Expand Down
3 changes: 2 additions & 1 deletion enaml/qt/docking/q_dock_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#------------------------------------------------------------------------------
from atom.api import Typed, Bool

from enaml.qt.compat import global_pos_from_event
from enaml.qt.QtCore import Qt, QMargins, QPoint, QRect, QEvent, Signal
from enaml.qt.QtGui import QIcon, QCursor
from enaml.qt.QtWidgets import QApplication, QLayout
Expand Down Expand Up @@ -736,7 +737,7 @@ def titleBarMouseMoveEvent(self, event):
# If dragging and floating, move the container's position and
# notify the manager of that the container was mouse moved. If
# the container is maximized, it is first restored before.
global_pos = event.globalPos()
global_pos = global_pos_from_event(event)
if state.dragging:
if self.isWindow():
target_pos = global_pos - state.press_pos
Expand Down
13 changes: 5 additions & 8 deletions enaml/qt/docking/q_dock_tab_widget.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
#------------------------------------------------------------------------------
# Copyright (c) 2013-2017, Nucleic Development Team.
# Copyright (c) 2013-2022, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
from weakref import ref

from enaml.qt import QT_API, PYQT5_API, PYSIDE2_API
from enaml.qt.compat import global_pos_from_event
from enaml.qt.QtCore import Qt, QPoint, QSize, QMetaObject, QEvent, QRect
from enaml.qt.QtGui import (
QMouseEvent, QResizeEvent, QCursor, QPainter, QPixmap
)
from enaml.qt.QtWidgets import (
QApplication, QTabBar, QTabWidget, QSplitter, QStyle, QStylePainter
)
if QT_API in PYQT5_API or QT_API in PYSIDE2_API:
from enaml.qt.QtWidgets import QStyleOptionTab
else:
from enaml.qt.QtWidgets import QStyleOptionTabV3 as QStyleOptionTab
from enaml.qt.QtWidgets import QStyleOptionTab

from enaml.qt.qt_menu import QCustomMenu

Expand Down Expand Up @@ -305,7 +302,7 @@ def mousePressEvent(self, event):
if button.geometry().contains(event.pos()):
return
item = self.parent().widget(index).dockItem()
item.titleBarRightClicked.emit(event.globalPos())
item.titleBarRightClicked.emit(global_pos_from_event(event))
# Emitting the clicked signal may have caused a popup
# menu to open, which will have grabbed the mouse. When
# this happens, the hover leave event is not sent and
Expand Down Expand Up @@ -341,7 +338,7 @@ def mouseMoveEvent(self, event):
evt = QMouseEvent(QEvent.MouseButtonRelease, pos, btn, btn, mod)
QApplication.sendEvent(self, evt)
container = self.parent().widget(self.currentIndex())
container.untab(event.globalPos())
container.untab(global_pos_from_event(event))
self._has_mouse = False

def mouseReleaseEvent(self, event):
Expand Down
7 changes: 4 additions & 3 deletions enaml/qt/docking/q_dock_title_bar.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#------------------------------------------------------------------------------
# Copyright (c) 2013-2018, Nucleic Development Team.
# Copyright (c) 2013-2022, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
from enaml.qt.compat import global_pos_from_event
from enaml.qt.QtCore import Qt, QSize, QPoint, QMargins, Signal
from enaml.qt.QtWidgets import (
QWidget, QFrame, QLineEdit, QHBoxLayout, QSizePolicy
Expand Down Expand Up @@ -417,7 +418,7 @@ def mouseDoubleClickEvent(self, event):
event.accept()
return
if self._clickableGeometry().contains(pos):
self.leftDoubleClicked.emit(event.globalPos())
self.leftDoubleClicked.emit(global_pos_from_event(event))
event.accept()
return

Expand All @@ -428,7 +429,7 @@ def mousePressEvent(self, event):
event.ignore()
if event.button() == Qt.RightButton:
if self._clickableGeometry().contains(event.pos()):
self.rightClicked.emit(event.globalPos())
self.rightClicked.emit(global_pos_from_event(event))
event.accept()
return

Expand Down
5 changes: 3 additions & 2 deletions enaml/qt/docking/q_dock_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#------------------------------------------------------------------------------
from atom.api import Bool, Typed

from enaml.qt.compat import global_pos_from_event
from enaml.qt.QtCore import (
Qt, QMetaObject, QMargins, QPoint, QRect, QSize, Signal
)
Expand Down Expand Up @@ -461,7 +462,7 @@ def titleBarMouseMoveEvent(self, event):
"""
state = self.frame_state
if state.press_pos is not None:
global_pos = event.globalPos()
global_pos = global_pos_from_event(event)
if self.isMaximized():
coeff = state.press_pos.x() / float(self.width())
self.showNormal()
Expand Down Expand Up @@ -489,7 +490,7 @@ def titleBarMouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
state = self.frame_state
if state.press_pos is not None:
self.manager().drag_release_frame(self, event.globalPos())
self.manager().drag_release_frame(self, global_pos_from_event(event))
state.dragging = False
state.press_pos = None
return True
Expand Down

0 comments on commit d482957

Please sign in to comment.