vectorgraphics / asymptote

2D & 3D TeX-Aware Vector Graphics Language
https://asymptote.sourceforge.io/
GNU General Public License v3.0
533 stars 89 forks source link

[xasy] migrate to python-pyqt6 #465

Closed vp1981 closed 1 week ago

vp1981 commented 1 week ago

Hello.

I prepared (rude) patch to make xasy use python-pyqt6. I only checked that the xasy is run, but actually I don't use it.

Below is a patch, this is the source.

From 9993a6353f41dde6b184663b0817128c1a04a8fb Mon Sep 17 00:00:00 2001
From: Vladimir Lomov <vladimir@bnode.bkoty.ru>
Date: Mon, 24 Jun 2024 13:37:19 +0800
Subject: [PATCH 2/2] Migrate to python-pyqt6

Signed-off-by: Vladimir Lomov <vladimir@bnode.bkoty.ru>
---
 GUI/ContextWindow.py       |  6 +++---
 GUI/CustMatTransform.py    |  6 +++---
 GUI/GuidesManager.py       |  4 ++--
 GUI/InplaceAddObj.py       |  4 ++--
 GUI/PrimitiveShape.py      |  4 ++--
 GUI/SetCustomAnchor.py     |  6 +++---
 GUI/Widg_addLabel.py       |  4 ++--
 GUI/Widg_addPolyOpt.py     |  4 ++--
 GUI/Widg_editBezier.py     |  4 ++--
 GUI/Window1.py             | 27 +++++++++++++--------------
 GUI/labelEditor.py         |  8 ++++----
 GUI/requirements.txt       |  8 ++++----
 GUI/xasy.py                |  8 +++-----
 GUI/xasy2asy.py            |  8 ++++----
 GUI/xasyArgs.py            |  2 +-
 GUI/xasyBezierInterface.py |  6 +++---
 GUI/xasySvg.py             |  4 ++--
 GUI/xasyTransform.py       |  4 ++--
 Makefile.in                |  4 ++--
 19 files changed, 59 insertions(+), 62 deletions(-)

diff --git a/GUI/ContextWindow.py b/GUI/ContextWindow.py
index 53044726..b5bf3f1a 100644
--- a/GUI/ContextWindow.py
+++ b/GUI/ContextWindow.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3

-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
+import PyQt6.QtWidgets as Qw
+import PyQt6.QtGui as Qg
+import PyQt6.QtCore as Qc
 import xasyVersion

 import xasyUtils as xu
diff --git a/GUI/CustMatTransform.py b/GUI/CustMatTransform.py
index 0a66807d..4ffcde19 100644
--- a/GUI/CustMatTransform.py
+++ b/GUI/CustMatTransform.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3

-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
 import numpy as numpy
 import xasy2asy as xasy2asy
 from pyUIClass.custMatTransform import Ui_Dialog
diff --git a/GUI/GuidesManager.py b/GUI/GuidesManager.py
index fd317439..cdfd4cdb 100644
--- a/GUI/GuidesManager.py
+++ b/GUI/GuidesManager.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
 import numpy as numpy

 class Guide:
diff --git a/GUI/InplaceAddObj.py b/GUI/InplaceAddObj.py
index 9bacd5f5..a0437a72 100644
--- a/GUI/InplaceAddObj.py
+++ b/GUI/InplaceAddObj.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3

-import PyQt5.QtCore as QtCore
-import PyQt5.QtGui as QtGui
+import PyQt6.QtCore as QtCore
+import PyQt6.QtGui as QtGui
 import xasy2asy as xasy2asy

 import PrimitiveShape
diff --git a/GUI/PrimitiveShape.py b/GUI/PrimitiveShape.py
index bbb24148..09aa40f6 100644
--- a/GUI/PrimitiveShape.py
+++ b/GUI/PrimitiveShape.py
@@ -3,8 +3,8 @@
 import xasy2asy as xasy2asy
 import numpy as numpy
 import math
-import PyQt5.QtCore as QtCore
-import PyQt5.QtGui as QtGui
+import PyQt6.QtCore as QtCore
+import PyQt6.QtGui as QtGui

 class PrimitiveShape:
diff --git a/GUI/SetCustomAnchor.py b/GUI/SetCustomAnchor.py
index e4414fec..1eb58234 100644
--- a/GUI/SetCustomAnchor.py
+++ b/GUI/SetCustomAnchor.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3

-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
 from pyUIClass.setCustomAnchor import Ui_Dialog

diff --git a/GUI/Widg_addLabel.py b/GUI/Widg_addLabel.py
index a5a65035..7a12dfd3 100644
--- a/GUI/Widg_addLabel.py
+++ b/GUI/Widg_addLabel.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3

 from pyUIClass.widg_addLabel import Ui_Form
-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtGui as QtGui
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui

 import labelEditor
 import xasyUtils as xu
diff --git a/GUI/Widg_addPolyOpt.py b/GUI/Widg_addPolyOpt.py
index 3d1e419d..8434c0ca 100644
--- a/GUI/Widg_addPolyOpt.py
+++ b/GUI/Widg_addPolyOpt.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3

 from pyUIClass.widg_addPolyOpt import Ui_Form
-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtGui as QtGui
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui

 import sys

diff --git a/GUI/Widg_editBezier.py b/GUI/Widg_editBezier.py
index 161715e0..b3b50327 100644
--- a/GUI/Widg_editBezier.py
+++ b/GUI/Widg_editBezier.py
@@ -2,8 +2,8 @@

 from pyUIClass.widg_editBezier import Ui_Form

-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtCore as QtCore
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtCore as QtCore

 class LockMode:
     noLock = 0
diff --git a/GUI/Window1.py b/GUI/Window1.py
index 1e65b235..b7ccbedd 100644
--- a/GUI/Window1.py
+++ b/GUI/Window1.py
@@ -2,9 +2,9 @@

 from pyUIClass.window1 import Ui_MainWindow

-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
+import PyQt6.QtWidgets as Qw
+import PyQt6.QtGui as Qg
+import PyQt6.QtCore as Qc
 import xasyVersion

 import numpy as np
@@ -203,7 +203,7 @@ class MainWindow1(Qw.QMainWindow):
         self.panOffset = [0, 0]

         # Keyboard can focus outside of textboxes
-        self.setFocusPolicy(Qc.Qt.StrongFocus)
+        self.setFocusPolicy(Qc.Qt.FocusPolicy.StrongFocus)

         super().setMouseTracking(True)
         # setMouseTracking(True)
@@ -1121,7 +1121,7 @@ class MainWindow1(Qw.QMainWindow):
         """Inverts the mapping of the key
            Input map is in format 'Action' : 'Key Sequence' """
         for action, key in self.keyMaps.options.items():
-            shortcut = Qw.QShortcut(self)
+            shortcut = Qg.QShortcut(self)
             shortcut.setKey(Qg.QKeySequence(key))

             # hate doing this, but python doesn't have explicit way to pass a
@@ -1146,7 +1146,7 @@ class MainWindow1(Qw.QMainWindow):

     #We include this function to keep the general program flow consistent
     def closeEvent(self, event):
-        if self.actionClose() == Qw.QMessageBox.Cancel:
+        if self.actionClose() == Qw.QMessageBox.StandardButton.Cancel:
             event.ignore()

     def actionNewFile(self):
@@ -1361,7 +1361,7 @@ class MainWindow1(Qw.QMainWindow):
             if self.mainCanvas.isActive():
                 self.mainCanvas.end()
             self.canvSize = self.ui.imgFrame.size()*devicePixelRatio
-            self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Ignored, Qw.QSizePolicy.Ignored)
+            self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Policy.Ignored, Qw.QSizePolicy.Ignored)
             self.canvasPixmap = Qg.QPixmap(self.canvSize)
             self.canvasPixmap.setDevicePixelRatio(devicePixelRatio)
             self.postCanvasPixmap = Qg.QPixmap(self.canvSize)
@@ -1746,7 +1746,7 @@ class MainWindow1(Qw.QMainWindow):

     def createMainCanvas(self):
         self.canvSize = devicePixelRatio*self.ui.imgFrame.size()
-        self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Ignored, Qw.QSizePolicy.Ignored)
+        self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Policy.Ignored, Qw.QSizePolicy.Ignored)
         factor=0.5/devicePixelRatio;
         x, y = self.canvSize.width()*factor, self.canvSize.height()*factor

@@ -1762,9 +1762,8 @@ class MainWindow1(Qw.QMainWindow):
         self.postCanvasPixmap.setDevicePixelRatio(devicePixelRatio)

         self.mainCanvas = Qg.QPainter(self.canvasPixmap)
-        self.mainCanvas.setRenderHint(Qg.QPainter.Antialiasing)
-        self.mainCanvas.setRenderHint(Qg.QPainter.SmoothPixmapTransform)
-        self.mainCanvas.setRenderHint(Qg.QPainter.HighQualityAntialiasing)
+        self.mainCanvas.setRenderHint(Qg.QPainter.RenderHint.Antialiasing)
+        self.mainCanvas.setRenderHint(Qg.QPainter.RenderHint.SmoothPixmapTransform)
         self.xasyDrawObj['canvas'] = self.mainCanvas

         self.mainTransformation = Qg.QTransform()
@@ -1921,7 +1920,7 @@ class MainWindow1(Qw.QMainWindow):
     def updateScreen(self):
         self.finalPixmap = Qg.QPixmap(self.canvSize)
         self.finalPixmap.setDevicePixelRatio(devicePixelRatio)
-        self.finalPixmap.fill(Qc.Qt.black)
+        self.finalPixmap.fill(Qg.QColorConstants.Svg.black)
         with Qg.QPainter(self.finalPixmap) as finalPainter:
             drawPoint = Qc.QPoint(0, 0)
             finalPainter.drawPixmap(drawPoint, self.canvasPixmap)
@@ -2017,7 +2016,7 @@ class MainWindow1(Qw.QMainWindow):
         preCanvas.setTransform(self.getScrsTransform())

         if self.drawAxes:
-            preCanvas.setPen(Qc.Qt.gray)
+            preCanvas.setPen(Qg.QColorConstants.Svg.gray)
             self.makePenCosmetic(preCanvas)
             preCanvas.drawLine(Qc.QLine(-9999, 0, 9999, 0))
             preCanvas.drawLine(Qc.QLine(0, -9999, 0, 9999))
@@ -2069,7 +2068,7 @@ class MainWindow1(Qw.QMainWindow):
             painter.restore()

     def postDraw(self):
-        self.postCanvasPixmap.fill(Qc.Qt.transparent)
+        self.postCanvasPixmap.fill(Qg.QColorConstants.Transparent)
         with Qg.QPainter(self.postCanvasPixmap) as postCanvas:
             postCanvas.setRenderHints(self.mainCanvas.renderHints())
             postCanvas.setTransform(self.getScrsTransform())
diff --git a/GUI/labelEditor.py b/GUI/labelEditor.py
index 7da1c5f9..aacc3422 100644
--- a/GUI/labelEditor.py
+++ b/GUI/labelEditor.py
@@ -1,10 +1,10 @@
 #!/usr/bin/env python3

 from pyUIClass.labelTextEditor import Ui_Dialog
-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtSvg as QtSvg
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtSvg as QtSvg
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
 import xasyArgs as xasyArgs
 import xasy2asy as xasy2asy
 import xasyOptions as xasyOptions
diff --git a/GUI/requirements.txt b/GUI/requirements.txt
index 6e0a4419..62fcb415 100644
--- a/GUI/requirements.txt
+++ b/GUI/requirements.txt
@@ -1,4 +1,4 @@
-numpy==1.22.0
-cson==0.7
-PyQt5==5.11
-rsvg-convert==2.42.3
+numpy==2.0.0
+cson==0.8
+PyQt6==6.7.0
+rsvg-convert==2.58.1
diff --git a/GUI/xasy.py b/GUI/xasy.py
index a078690b..6bbfb7f6 100755
--- a/GUI/xasy.py
+++ b/GUI/xasy.py
@@ -1,19 +1,17 @@
 #!/usr/bin/env python3

 import sys, signal, os
-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtCore as QtCore
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtCore as QtCore
 from Window1 import MainWindow1

 def main(args):
     os.environ["QT_LOGGING_RULES"]="*.debug=false;qt.qpa.*=false"
-    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps,True)
-    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling,True)
     qtApp = QtWidgets.QApplication(args)
     signal.signal(signal.SIGINT,signal.SIG_DFL)
     mainWin1 = MainWindow1()
     mainWin1.show()
-    return qtApp.exec_()
+    return qtApp.exec()

 if __name__ == '__main__':
diff --git a/GUI/xasy2asy.py b/GUI/xasy2asy.py
index cf1edb8a..eccd5a3a 100644
--- a/GUI/xasy2asy.py
+++ b/GUI/xasy2asy.py
@@ -9,10 +9,10 @@
 #
 ###########################################################################

-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
-import PyQt5.QtSvg as QtSvg
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
+import PyQt6.QtSvg as QtSvg

 import numpy as numpy

diff --git a/GUI/xasyArgs.py b/GUI/xasyArgs.py
index b9e1518f..82c11259 100644
--- a/GUI/xasyArgs.py
+++ b/GUI/xasyArgs.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 import argparse
 import xasyVersion
-import PyQt5.QtCore as QtCore
+import PyQt6.QtCore as QtCore
 # Add arguments here.

diff --git a/GUI/xasyBezierInterface.py b/GUI/xasyBezierInterface.py
index abe8d9b0..4fd67bc9 100644
--- a/GUI/xasyBezierInterface.py
+++ b/GUI/xasyBezierInterface.py
@@ -1,9 +1,9 @@
 #!/usr/bin/env python3

-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtCore as QtCore
-import PyQt5.QtGui as QtGui
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtCore as QtCore
+import PyQt6.QtGui as QtGui
 import xasy2asy as xasy2asy
 import xasyUtils as xasyUtils
 import Widg_editBezier as Web
diff --git a/GUI/xasySvg.py b/GUI/xasySvg.py
index 7261dc5b..8aa5ec60 100644
--- a/GUI/xasySvg.py
+++ b/GUI/xasySvg.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3

-import PyQt5.QtGui as QtGui
-import PyQt5.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui
+import PyQt6.QtWidgets as QtWidgets
 import io
 import subprocess
 import sys
diff --git a/GUI/xasyTransform.py b/GUI/xasyTransform.py
index cb70bf1e..da444906 100644
--- a/GUI/xasyTransform.py
+++ b/GUI/xasyTransform.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 import xasy2asy as xasy2asy
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
 import numpy as numpy
 import math

diff --git a/Makefile.in b/Makefile.in
index 1c7866fe..35d1245f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -19,8 +19,8 @@ CMAKE ?= cmake
 PERL ?= perl
 PYTHON ?= python3
 BISON ?= bison
-PYRCC ?= pyrcc5
-PYUIC ?= pyuic5
+PYRCC ?= pyrcc6
+PYUIC ?= pyuic6

 # Libraries needed to make asymptote.so.
 # We have to remove OpenGL, threading, GC, etc from this.
-- 
2.45.2
johncbowman commented 1 week ago

xasy doesn't run yet with this patch but I've committed it to the qt6 branch (along with regenerated windows/*.ui files) for further development:

xasy
Traceback (most recent call last):
  File "/u/bowman/bin/xasy", line 18, in <module>
    sys.exit(main(sys.argv) or 0)
             ^^^^^^^^^^^^^^
  File "/u/bowman/bin/xasy", line 12, in main
    mainWin1 = MainWindow1()
               ^^^^^^^^^^^^^
  File "/u/bowman/asymptote/GUI/Window1.py", line 331, in __init__
    self.populateOpenRecent()
  File "/u/bowman/asymptote/GUI/Window1.py", line 1204, in populateOpenRecent
    action = Qw.QAction(path, self, triggered = lambda state, path = path: self.actionOpen(fileName = path))
             ^^^^^^^^^^
AttributeError: module 'PyQt6.QtWidgets' has no attribute 'QAction'
vp1981 commented 1 week ago

Hello.

I found one other missed part in the previous patch and also fixed this issue.

From e5eeb94cad2e73d76df68f0a3536faf61b4a2306 Mon Sep 17 00:00:00 2001
From: Vladimir Lomov <vladimir@bnode.bkoty.ru>
Date: Thu, 27 Jun 2024 13:44:52 +0800
Subject: [PATCH 2/2] Migrate to python pyqt6

Signed-off-by: Vladimir Lomov <vladimir@bnode.bkoty.ru>
---
 GUI/ContextWindow.py       |  6 +++---
 GUI/CustMatTransform.py    |  6 +++---
 GUI/GuidesManager.py       |  4 ++--
 GUI/InplaceAddObj.py       |  4 ++--
 GUI/PrimitiveShape.py      |  4 ++--
 GUI/SetCustomAnchor.py     |  6 +++---
 GUI/Widg_addLabel.py       |  4 ++--
 GUI/Widg_addPolyOpt.py     |  4 ++--
 GUI/Widg_editBezier.py     |  4 ++--
 GUI/Window1.py             | 29 ++++++++++++++---------------
 GUI/labelEditor.py         |  8 ++++----
 GUI/requirements.txt       |  8 ++++----
 GUI/xasy.py                |  8 +++-----
 GUI/xasy2asy.py            |  8 ++++----
 GUI/xasyArgs.py            |  2 +-
 GUI/xasyBezierInterface.py |  6 +++---
 GUI/xasySvg.py             |  4 ++--
 GUI/xasyTransform.py       |  4 ++--
 Makefile.in                |  4 ++--
 19 files changed, 60 insertions(+), 63 deletions(-)

diff --git a/GUI/ContextWindow.py b/GUI/ContextWindow.py
index 53044726..b5bf3f1a 100644
--- a/GUI/ContextWindow.py
+++ b/GUI/ContextWindow.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3

-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
+import PyQt6.QtWidgets as Qw
+import PyQt6.QtGui as Qg
+import PyQt6.QtCore as Qc
 import xasyVersion

 import xasyUtils as xu
diff --git a/GUI/CustMatTransform.py b/GUI/CustMatTransform.py
index 0a66807d..4ffcde19 100644
--- a/GUI/CustMatTransform.py
+++ b/GUI/CustMatTransform.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3

-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
 import numpy as numpy
 import xasy2asy as xasy2asy
 from pyUIClass.custMatTransform import Ui_Dialog
diff --git a/GUI/GuidesManager.py b/GUI/GuidesManager.py
index fd317439..cdfd4cdb 100644
--- a/GUI/GuidesManager.py
+++ b/GUI/GuidesManager.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
 import numpy as numpy

 class Guide:
diff --git a/GUI/InplaceAddObj.py b/GUI/InplaceAddObj.py
index 9bacd5f5..a0437a72 100644
--- a/GUI/InplaceAddObj.py
+++ b/GUI/InplaceAddObj.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3

-import PyQt5.QtCore as QtCore
-import PyQt5.QtGui as QtGui
+import PyQt6.QtCore as QtCore
+import PyQt6.QtGui as QtGui
 import xasy2asy as xasy2asy

 import PrimitiveShape
diff --git a/GUI/PrimitiveShape.py b/GUI/PrimitiveShape.py
index bbb24148..09aa40f6 100644
--- a/GUI/PrimitiveShape.py
+++ b/GUI/PrimitiveShape.py
@@ -3,8 +3,8 @@
 import xasy2asy as xasy2asy
 import numpy as numpy
 import math
-import PyQt5.QtCore as QtCore
-import PyQt5.QtGui as QtGui
+import PyQt6.QtCore as QtCore
+import PyQt6.QtGui as QtGui

 class PrimitiveShape:
diff --git a/GUI/SetCustomAnchor.py b/GUI/SetCustomAnchor.py
index e4414fec..1eb58234 100644
--- a/GUI/SetCustomAnchor.py
+++ b/GUI/SetCustomAnchor.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3

-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
 from pyUIClass.setCustomAnchor import Ui_Dialog

diff --git a/GUI/Widg_addLabel.py b/GUI/Widg_addLabel.py
index a5a65035..7a12dfd3 100644
--- a/GUI/Widg_addLabel.py
+++ b/GUI/Widg_addLabel.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3

 from pyUIClass.widg_addLabel import Ui_Form
-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtGui as QtGui
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui

 import labelEditor
 import xasyUtils as xu
diff --git a/GUI/Widg_addPolyOpt.py b/GUI/Widg_addPolyOpt.py
index 3d1e419d..8434c0ca 100644
--- a/GUI/Widg_addPolyOpt.py
+++ b/GUI/Widg_addPolyOpt.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3

 from pyUIClass.widg_addPolyOpt import Ui_Form
-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtGui as QtGui
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui

 import sys

diff --git a/GUI/Widg_editBezier.py b/GUI/Widg_editBezier.py
index 161715e0..b3b50327 100644
--- a/GUI/Widg_editBezier.py
+++ b/GUI/Widg_editBezier.py
@@ -2,8 +2,8 @@

 from pyUIClass.widg_editBezier import Ui_Form

-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtCore as QtCore
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtCore as QtCore

 class LockMode:
     noLock = 0
diff --git a/GUI/Window1.py b/GUI/Window1.py
index 1e65b235..0cade188 100644
--- a/GUI/Window1.py
+++ b/GUI/Window1.py
@@ -2,9 +2,9 @@

 from pyUIClass.window1 import Ui_MainWindow

-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
+import PyQt6.QtWidgets as Qw
+import PyQt6.QtGui as Qg
+import PyQt6.QtCore as Qc
 import xasyVersion

 import numpy as np
@@ -203,7 +203,7 @@ class MainWindow1(Qw.QMainWindow):
         self.panOffset = [0, 0]

         # Keyboard can focus outside of textboxes
-        self.setFocusPolicy(Qc.Qt.StrongFocus)
+        self.setFocusPolicy(Qc.Qt.FocusPolicy.StrongFocus)

         super().setMouseTracking(True)
         # setMouseTracking(True)
@@ -1121,7 +1121,7 @@ class MainWindow1(Qw.QMainWindow):
         """Inverts the mapping of the key
            Input map is in format 'Action' : 'Key Sequence' """
         for action, key in self.keyMaps.options.items():
-            shortcut = Qw.QShortcut(self)
+            shortcut = Qg.QShortcut(self)
             shortcut.setKey(Qg.QKeySequence(key))

             # hate doing this, but python doesn't have explicit way to pass a
@@ -1146,7 +1146,7 @@ class MainWindow1(Qw.QMainWindow):

     #We include this function to keep the general program flow consistent
     def closeEvent(self, event):
-        if self.actionClose() == Qw.QMessageBox.Cancel:
+        if self.actionClose() == Qw.QMessageBox.StandardButton.Cancel:
             event.ignore()

     def actionNewFile(self):
@@ -1201,7 +1201,7 @@ class MainWindow1(Qw.QMainWindow):
         for count, path in enumerate(self.openRecent.pathList):
             if count > 8:
                 break
-            action = Qw.QAction(path, self, triggered = lambda state, path = path: self.actionOpen(fileName = path))
+            action = Qg.QAction(path, self, triggered = lambda state, path = path: self.actionOpen(fileName = path))
             self.ui.menuOpenRecent.addAction(action)
         self.ui.menuOpenRecent.addSeparator()
         self.ui.menuOpenRecent.addAction("Clear", self.actionClearRecent)
@@ -1361,7 +1361,7 @@ class MainWindow1(Qw.QMainWindow):
             if self.mainCanvas.isActive():
                 self.mainCanvas.end()
             self.canvSize = self.ui.imgFrame.size()*devicePixelRatio
-            self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Ignored, Qw.QSizePolicy.Ignored)
+            self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Policy.Ignored, Qw.QSizePolicy.Policy.Ignored)
             self.canvasPixmap = Qg.QPixmap(self.canvSize)
             self.canvasPixmap.setDevicePixelRatio(devicePixelRatio)
             self.postCanvasPixmap = Qg.QPixmap(self.canvSize)
@@ -1746,7 +1746,7 @@ class MainWindow1(Qw.QMainWindow):

     def createMainCanvas(self):
         self.canvSize = devicePixelRatio*self.ui.imgFrame.size()
-        self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Ignored, Qw.QSizePolicy.Ignored)
+        self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Policy.Ignored, Qw.QSizePolicy.Policy.Ignored)
         factor=0.5/devicePixelRatio;
         x, y = self.canvSize.width()*factor, self.canvSize.height()*factor

@@ -1762,9 +1762,8 @@ class MainWindow1(Qw.QMainWindow):
         self.postCanvasPixmap.setDevicePixelRatio(devicePixelRatio)

         self.mainCanvas = Qg.QPainter(self.canvasPixmap)
-        self.mainCanvas.setRenderHint(Qg.QPainter.Antialiasing)
-        self.mainCanvas.setRenderHint(Qg.QPainter.SmoothPixmapTransform)
-        self.mainCanvas.setRenderHint(Qg.QPainter.HighQualityAntialiasing)
+        self.mainCanvas.setRenderHint(Qg.QPainter.RenderHint.Antialiasing)
+        self.mainCanvas.setRenderHint(Qg.QPainter.RenderHint.SmoothPixmapTransform)
         self.xasyDrawObj['canvas'] = self.mainCanvas

         self.mainTransformation = Qg.QTransform()
@@ -1921,7 +1920,7 @@ class MainWindow1(Qw.QMainWindow):
     def updateScreen(self):
         self.finalPixmap = Qg.QPixmap(self.canvSize)
         self.finalPixmap.setDevicePixelRatio(devicePixelRatio)
-        self.finalPixmap.fill(Qc.Qt.black)
+        self.finalPixmap.fill(Qg.QColorConstants.Svg.black)
         with Qg.QPainter(self.finalPixmap) as finalPainter:
             drawPoint = Qc.QPoint(0, 0)
             finalPainter.drawPixmap(drawPoint, self.canvasPixmap)
@@ -2017,7 +2016,7 @@ class MainWindow1(Qw.QMainWindow):
         preCanvas.setTransform(self.getScrsTransform())

         if self.drawAxes:
-            preCanvas.setPen(Qc.Qt.gray)
+            preCanvas.setPen(Qg.QColorConstants.Svg.gray)
             self.makePenCosmetic(preCanvas)
             preCanvas.drawLine(Qc.QLine(-9999, 0, 9999, 0))
             preCanvas.drawLine(Qc.QLine(0, -9999, 0, 9999))
@@ -2069,7 +2068,7 @@ class MainWindow1(Qw.QMainWindow):
             painter.restore()

     def postDraw(self):
-        self.postCanvasPixmap.fill(Qc.Qt.transparent)
+        self.postCanvasPixmap.fill(Qg.QColorConstants.Transparent)
         with Qg.QPainter(self.postCanvasPixmap) as postCanvas:
             postCanvas.setRenderHints(self.mainCanvas.renderHints())
             postCanvas.setTransform(self.getScrsTransform())
diff --git a/GUI/labelEditor.py b/GUI/labelEditor.py
index 7da1c5f9..aacc3422 100644
--- a/GUI/labelEditor.py
+++ b/GUI/labelEditor.py
@@ -1,10 +1,10 @@
 #!/usr/bin/env python3

 from pyUIClass.labelTextEditor import Ui_Dialog
-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtSvg as QtSvg
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtSvg as QtSvg
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
 import xasyArgs as xasyArgs
 import xasy2asy as xasy2asy
 import xasyOptions as xasyOptions
diff --git a/GUI/requirements.txt b/GUI/requirements.txt
index 6e0a4419..62fcb415 100644
--- a/GUI/requirements.txt
+++ b/GUI/requirements.txt
@@ -1,4 +1,4 @@
-numpy==1.22.0
-cson==0.7
-PyQt5==5.11
-rsvg-convert==2.42.3
+numpy==2.0.0
+cson==0.8
+PyQt6==6.7.0
+rsvg-convert==2.58.1
diff --git a/GUI/xasy.py b/GUI/xasy.py
index a078690b..6bbfb7f6 100755
--- a/GUI/xasy.py
+++ b/GUI/xasy.py
@@ -1,19 +1,17 @@
 #!/usr/bin/env python3

 import sys, signal, os
-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtCore as QtCore
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtCore as QtCore
 from Window1 import MainWindow1

 def main(args):
     os.environ["QT_LOGGING_RULES"]="*.debug=false;qt.qpa.*=false"
-    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps,True)
-    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling,True)
     qtApp = QtWidgets.QApplication(args)
     signal.signal(signal.SIGINT,signal.SIG_DFL)
     mainWin1 = MainWindow1()
     mainWin1.show()
-    return qtApp.exec_()
+    return qtApp.exec()

 if __name__ == '__main__':
diff --git a/GUI/xasy2asy.py b/GUI/xasy2asy.py
index cf1edb8a..eccd5a3a 100644
--- a/GUI/xasy2asy.py
+++ b/GUI/xasy2asy.py
@@ -9,10 +9,10 @@
 #
 ###########################################################################

-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
-import PyQt5.QtSvg as QtSvg
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
+import PyQt6.QtSvg as QtSvg

 import numpy as numpy

diff --git a/GUI/xasyArgs.py b/GUI/xasyArgs.py
index b9e1518f..82c11259 100644
--- a/GUI/xasyArgs.py
+++ b/GUI/xasyArgs.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 import argparse
 import xasyVersion
-import PyQt5.QtCore as QtCore
+import PyQt6.QtCore as QtCore
 # Add arguments here.

diff --git a/GUI/xasyBezierInterface.py b/GUI/xasyBezierInterface.py
index abe8d9b0..4fd67bc9 100644
--- a/GUI/xasyBezierInterface.py
+++ b/GUI/xasyBezierInterface.py
@@ -1,9 +1,9 @@
 #!/usr/bin/env python3

-import PyQt5.QtWidgets as QtWidgets
-import PyQt5.QtCore as QtCore
-import PyQt5.QtGui as QtGui
+import PyQt6.QtWidgets as QtWidgets
+import PyQt6.QtCore as QtCore
+import PyQt6.QtGui as QtGui
 import xasy2asy as xasy2asy
 import xasyUtils as xasyUtils
 import Widg_editBezier as Web
diff --git a/GUI/xasySvg.py b/GUI/xasySvg.py
index 7261dc5b..8aa5ec60 100644
--- a/GUI/xasySvg.py
+++ b/GUI/xasySvg.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3

-import PyQt5.QtGui as QtGui
-import PyQt5.QtWidgets as QtWidgets
+import PyQt6.QtGui as QtGui
+import PyQt6.QtWidgets as QtWidgets
 import io
 import subprocess
 import sys
diff --git a/GUI/xasyTransform.py b/GUI/xasyTransform.py
index cb70bf1e..da444906 100644
--- a/GUI/xasyTransform.py
+++ b/GUI/xasyTransform.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 import xasy2asy as xasy2asy
-import PyQt5.QtGui as QtGui
-import PyQt5.QtCore as QtCore
+import PyQt6.QtGui as QtGui
+import PyQt6.QtCore as QtCore
 import numpy as numpy
 import math

diff --git a/Makefile.in b/Makefile.in
index 1c7866fe..35d1245f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -19,8 +19,8 @@ CMAKE ?= cmake
 PERL ?= perl
 PYTHON ?= python3
 BISON ?= bison
-PYRCC ?= pyrcc5
-PYUIC ?= pyuic5
+PYRCC ?= pyrcc6
+PYUIC ?= pyuic6

 # Libraries needed to make asymptote.so.
 # We have to remove OpenGL, threading, GC, etc from this.
-- 
2.45.2

Source

Sorry, no PR this yet (I couldn't get how to work with PR, plain patches are more simple for me).

johncbowman commented 1 week ago

Could you please post a patch relative to the qt6 branch, which already contains your previous patch? Or better, I could give you developer access if you send me your GitHub user ID.

vp1981 commented 1 week ago

Ok, this one

From 1fe21e1e9acb5bb528aa6fa6f304073912317aff Mon Sep 17 00:00:00 2001
From: Vladimir Lomov <vladimir@bnode.bkoty.ru>
Date: Fri, 28 Jun 2024 09:15:01 +0800
Subject: [PATCH] Fixed QAction and QSizePolicy issues

  - QAction is now part of QGui;
  - QSizePolicy flags are now accessible via QSizePolicy.Policy.

Signed-off-by: Vladimir Lomov <vladimir@bnode.bkoty.ru>
---
 GUI/Window1.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/GUI/Window1.py b/GUI/Window1.py
index b7ccbedd..38e06e87 100644
--- a/GUI/Window1.py
+++ b/GUI/Window1.py
@@ -1201,7 +1201,7 @@ class MainWindow1(Qw.QMainWindow):
         for count, path in enumerate(self.openRecent.pathList):
             if count > 8:
                 break
-            action = Qw.QAction(path, self, triggered = lambda state, path = path: self.actionOpen(fileName = path))
+            action = Qg.QAction(path, self, triggered = lambda state, path = path: self.actionOpen(fileName = path))
             self.ui.menuOpenRecent.addAction(action)
         self.ui.menuOpenRecent.addSeparator()
         self.ui.menuOpenRecent.addAction("Clear", self.actionClearRecent)
@@ -1361,7 +1361,7 @@ class MainWindow1(Qw.QMainWindow):
             if self.mainCanvas.isActive():
                 self.mainCanvas.end()
             self.canvSize = self.ui.imgFrame.size()*devicePixelRatio
-            self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Policy.Ignored, Qw.QSizePolicy.Ignored)
+            self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Policy.Ignored, Qw.QSizePolicy.Policy.Ignored)
             self.canvasPixmap = Qg.QPixmap(self.canvSize)
             self.canvasPixmap.setDevicePixelRatio(devicePixelRatio)
             self.postCanvasPixmap = Qg.QPixmap(self.canvSize)
@@ -1746,7 +1746,7 @@ class MainWindow1(Qw.QMainWindow):

     def createMainCanvas(self):
         self.canvSize = devicePixelRatio*self.ui.imgFrame.size()
-        self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Policy.Ignored, Qw.QSizePolicy.Ignored)
+        self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Policy.Ignored, Qw.QSizePolicy.Policy.Ignored)
         factor=0.5/devicePixelRatio;
         x, y = self.canvSize.width()*factor, self.canvSize.height()*factor

-- 
2.45.2
johncbowman commented 1 week ago

Ok, I've applied that patch to the qt6 branch, without these two extraneous lines, which should be removed:

-- 
2.45.2

xasy now loads but the icons are missing...

johncbowman commented 1 week ago

Another issue... xasy examples/venn.asy Traceback (most recent call last): File "/u/bowman/asymptote/GUI/Window1.py", line 1485, in mouseMoveEvent selectedIndex, selKeyList = self.selectObject() ^^^^^^^^^^^^^^^^^^^ File "/u/bowman/asymptote/GUI/Window1.py", line 1803, in selectObject if obj.collide(canvasCoords) and (obj.key, obj.keyIndex) not in self.hiddenKeys: ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/u/bowman/asymptote/GUI/xasy2asy.py", line 1869, in collide return self.boundingBox.marginsAdded(newMargin).contains(coords) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: arguments did not match any overloaded call: contains(self, p: QPointF): argument 1 has unexpected type 'QPoint' contains(self, r: QRectF): argument 1 has unexpected type 'QPoint' contains(self, ax: float, ay: float): argument 1 has unexpected type 'QPoint' Traceback (most recent call last): File "/u/bowman/asymptote/GUI/Window1.py", line 1485, in mouseMoveEvent selectedIndex, selKeyList = self.selectObject() ^^^^^^^^^^^^^^^^^^^ File "/u/bowman/asymptote/GUI/Window1.py", line 1803, in selectObject if obj.collide(canvasCoords) and (obj.key, obj.keyIndex) not in self.hiddenKeys: ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/u/bowman/asymptote/GUI/xasy2asy.py", line 1869, in collide return self.boundingBox.marginsAdded(newMargin).contains(coords) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: arguments did not match any overloaded call: contains(self, p: QPointF): argument 1 has unexpected type 'QPoint' contains(self, r: QRectF): argument 1 has unexpected type 'QPoint' contains(self, ax: float, ay: float): argument 1 has unexpected type 'QPoint' Abort (core dumped)

vp1981 commented 1 week ago

Before I dive into it, could you enlighten me, should we use QPoint or QPointF? The former uses integers and the latter uses floats. If both are used, then I will carefully go through the code to see how they are used.

johncbowman commented 1 week ago

I think you want to use QPointF everywhere.