- using PyQt6 with multi monitors, when the pixel ratio (scaling in WIndows) is different than 1.0 there are visual issues in the 3D canvas - trying to solve by updating the dpi - partial solve

- failing to load the #d graphic engine is now reported on the log.txt file found in the Preferences folder (in appData/Roaming/app_name for Windows)
This commit is contained in:
Marius Stanciu
2021-08-24 18:09:22 +03:00
parent bbe8f237af
commit 30d995bf12
3 changed files with 234 additions and 200 deletions

View File

@@ -49,6 +49,7 @@ class MainGUI(QtWidgets.QMainWindow):
# Emitted when persistent window geometry needs to be retained
geom_update = QtCore.pyqtSignal(int, int, int, int, int, name='geomUpdate')
final_save = QtCore.pyqtSignal(name='saveBeforeExit')
screenChanged = QtCore.pyqtSignal(QtGui.QScreen, QtGui.QScreen)
# https://www.w3.org/TR/SVG11/types.html#ColorKeywords
def __init__(self, app):
@@ -1987,6 +1988,24 @@ class MainGUI(QtWidgets.QMainWindow):
self.infobar.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.ActionsContextMenu)
self.build_infobar_context_menu()
self.screenChanged.connect(self.on_screen_change)
def on_screen_change(self, old_screen, new_screen):
"""
Handler of a signal that emits when screens are changed in a multi-monitor setup
:param old_screen: QtGui.QScreen where the app windows was located before move
:param new_screen: QtGui.QScreen where the app windows is located after move
:return:
"""
old_pixel_ratio = old_screen.devicePixelRatio()
new_pixel_ratio = new_screen.devicePixelRatio()
if old_pixel_ratio != 1.0 or new_pixel_ratio != 1.0:
# update canvas dpi
ratio = new_pixel_ratio / old_pixel_ratio
self.app.plotcanvas.dpi = self.app.plotcanvas.dpi * ratio
def set_ui_title(self, name):
"""
Sets the title of the main window.
@@ -2157,22 +2176,6 @@ class MainGUI(QtWidgets.QMainWindow):
self.app.defaults["global_statusbar_show"] = checked
self.status_toolbar.setVisible(checked)
def eventFilter(self, obj, event):
"""
Filter the ToolTips display based on a Preferences setting
:param obj:
:param event: QT event to filter
:return:
"""
if self.app.defaults["global_toggle_tooltips"] is False:
if event.type() == QtCore.QEvent.Type.ToolTip:
return True
else:
return False
return False
def on_preferences_open_folder(self):
"""
Will open an Explorer window set to the folder path where the FlatCAM preferences files are usually saved.
@@ -2535,6 +2538,198 @@ class MainGUI(QtWidgets.QMainWindow):
self.grb_edit_toolbar.setVisible(True)
self.grb_edit_toolbar.setDisabled(True)
def on_shortcut_list(self):
# add the tab if it was closed
self.plot_tab_area.addTab(self.shortcuts_tab, _("Key Shortcut List"))
# delete the absolute and relative position and messages in the infobar
# self.ui.position_label.setText("")
# self.ui.rel_position_label.setText("")
# hide coordinates toolbars in the infobar while in DB
self.coords_toolbar.hide()
self.delta_coords_toolbar.hide()
# Switch plot_area to preferences page
self.plot_tab_area.setCurrentWidget(self.shortcuts_tab)
# self.show()
def on_select_tab(self, name):
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
if self.splitter.sizes()[0] == 0:
self.splitter.setSizes([1, 1])
else:
if self.notebook.currentWidget().objectName() == name + '_tab':
self.splitter.setSizes([0, 1])
if name == 'project':
self.notebook.setCurrentWidget(self.project_tab)
elif name == 'properties':
self.notebook.setCurrentWidget(self.properties_tab)
elif name == 'tool':
self.notebook.setCurrentWidget(self.plugin_tab)
def createPopupMenu(self):
menu = super().createPopupMenu()
menu.addSeparator()
menu.addAction(self.lock_action)
return menu
def lock_toolbar(self, lock=False):
"""
Used to (un)lock the toolbars of the app.
:param lock: boolean, will lock all toolbars in place when set True
:return: None
"""
if lock:
for widget in self.children():
if isinstance(widget, QtWidgets.QToolBar):
widget.setMovable(False)
else:
for widget in self.children():
if isinstance(widget, QtWidgets.QToolBar):
widget.setMovable(True)
def on_fullscreen(self, disable=False):
"""
:param disable:
:return:
"""
flags = self.windowFlags()
if self.toggle_fscreen is False and disable is False:
# self.ui.showFullScreen()
self.setWindowFlags(flags | Qt.WindowType.FramelessWindowHint)
a = self.geometry()
self.x_pos = a.x()
self.y_pos = a.y()
self.width = a.width()
self.height = a.height()
self.titlebar_height = self.app.qapp.style().pixelMetric(QtWidgets.QStyle.PixelMetric.PM_TitleBarHeight)
# set new geometry to full desktop rect
# Subtracting and adding the pixels below it's hack to bypass a bug in Qt5 and OpenGL that made that a
# window drawn with OpenGL in fullscreen will not show any other windows on top which means that menus and
# everything else will not work without this hack. This happen in Windows.
# https://bugreports.qt.io/browse/QTBUG-41309
# desktop = self.app.qapp.desktop()
# screen = desktop.screenNumber(QtGui.QCursor.pos())
# rec = desktop.screenGeometry(screen)
# x = rec.x() - 1
# y = rec.y() - 1
# h = rec.height() + 2
# w = rec.width() + 2
#
# self.setGeometry(x, y, w, h)
# self.show()
self.app.ui.showFullScreen()
# hide all Toolbars
for tb in self.findChildren(QtWidgets.QToolBar):
tb.setVisible(False)
self.coords_toolbar.setVisible(self.app.defaults["global_coordsbar_show"])
self.delta_coords_toolbar.setVisible(self.app.defaults["global_delta_coordsbar_show"])
self.grid_toolbar.setVisible(self.app.defaults["global_gridbar_show"])
self.status_toolbar.setVisible(self.app.defaults["global_statusbar_show"])
self.splitter.setSizes([0, 1])
self.toggle_fscreen = True
elif self.toggle_fscreen is True or disable is True:
self.setWindowFlags(flags & ~Qt.WindowType.FramelessWindowHint)
# the additions are made to account for the pixels we subtracted/added above in the (x, y, h, w)
# self.setGeometry(self.x_pos+1, self.y_pos+self.titlebar_height+4, self.width, self.height)
self.setGeometry(self.x_pos+1, self.y_pos+self.titlebar_height+13, self.width, self.height)
self.showNormal()
self.restore_toolbar_view()
self.toggle_fscreen = False
def on_toggle_plotarea(self):
"""
:return:
"""
try:
name = self.plot_tab_area.widget(0).objectName()
except AttributeError:
self.plot_tab_area.addTab(self.plot_tab, _("Plot Area"))
# remove the close button from the Plot Area tab (first tab index = 0) as this one will always be ON
self.plot_tab_area.protectTab(0)
return
if name != 'plotarea_tab':
self.plot_tab_area.insertTab(0, self.plot_tab, _("Plot Area"))
# remove the close button from the Plot Area tab (first tab index = 0) as this one will always be ON
self.plot_tab_area.protectTab(0)
else:
self.plot_tab_area.closeTab(0)
def on_toggle_notebook(self):
"""
:return:
"""
if self.splitter.sizes()[0] == 0:
self.splitter.setSizes([1, 1])
self.menu_toggle_nb.setChecked(True)
else:
self.splitter.setSizes([0, 1])
self.menu_toggle_nb.setChecked(False)
def on_toggle_grid(self):
"""
:return:
"""
self.grid_snap_btn.trigger()
def toggle_shell_ui(self):
"""
Toggle shell dock: if is visible close it, if it is closed then open it
:return: None
"""
if self.shell_dock.isVisible():
self.shell_dock.hide()
self.app.plotcanvas.native.setFocus()
else:
self.shell_dock.show()
# I want to take the focus and give it to the Tcl Shell when the Tcl Shell is run
# self.shell._edit.setFocus()
QtCore.QTimer.singleShot(0, lambda: self.shell_dock.widget()._edit.setFocus())
# HACK - simulate a mouse click - alternative
# no_km = QtCore.Qt.KeyboardModifier(QtCore.Qt.KeyboardModifier.NoModifier) # no KB modifier
# pos = QtCore.QPoint((self.shell._edit.width() - 40), (self.shell._edit.height() - 2))
# e = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, pos, QtCore.Qt.LeftButton, QtCore.Qt.LeftButton,
# no_km)
# QtCore.QCoreApplication.instance().sendEvent(self.shell._edit, e)
# f = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonRelease, pos, QtCore.Qt.LeftButton, QtCore.Qt.LeftButton,
# no_km)
# QtCore.QCoreApplication.instance().sendEvent(self.shell._edit, f)
def on_shelldock_toggled(self, visibility):
if visibility is True:
self.shell_status_label.setStyleSheet("""
QLabel
{
color: black;
background-color: lightcoral;
}
""")
self.app.inform[str, bool].emit(_("Shell enabled."), False)
else:
self.shell_status_label.setStyleSheet("")
self.app.inform[str, bool].emit(_("Shell disabled."), False)
def keyPressEvent(self, event):
"""
Key event handler for the entire app.
@@ -3941,59 +4136,21 @@ class MainGUI(QtWidgets.QMainWindow):
if key == QtCore.Qt.Key.Key_J or key == 'J':
self.app.on_jump_to()
def on_shortcut_list(self):
# add the tab if it was closed
self.plot_tab_area.addTab(self.shortcuts_tab, _("Key Shortcut List"))
# delete the absolute and relative position and messages in the infobar
# self.ui.position_label.setText("")
# self.ui.rel_position_label.setText("")
# hide coordinates toolbars in the infobar while in DB
self.coords_toolbar.hide()
self.delta_coords_toolbar.hide()
# Switch plot_area to preferences page
self.plot_tab_area.setCurrentWidget(self.shortcuts_tab)
# self.show()
def on_select_tab(self, name):
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
if self.splitter.sizes()[0] == 0:
self.splitter.setSizes([1, 1])
else:
if self.notebook.currentWidget().objectName() == name + '_tab':
self.splitter.setSizes([0, 1])
if name == 'project':
self.notebook.setCurrentWidget(self.project_tab)
elif name == 'properties':
self.notebook.setCurrentWidget(self.properties_tab)
elif name == 'tool':
self.notebook.setCurrentWidget(self.plugin_tab)
def createPopupMenu(self):
menu = super().createPopupMenu()
menu.addSeparator()
menu.addAction(self.lock_action)
return menu
def lock_toolbar(self, lock=False):
def eventFilter(self, obj, event):
"""
Used to (un)lock the toolbars of the app.
Filter the ToolTips display based on a Preferences setting
:param lock: boolean, will lock all toolbars in place when set True
:return: None
:param obj:
:param event: QT event to filter
:return:
"""
if self.app.defaults["global_toggle_tooltips"] is False:
if event.type() == QtCore.QEvent.Type.ToolTip:
return True
else:
return False
if lock:
for widget in self.children():
if isinstance(widget, QtWidgets.QToolBar):
widget.setMovable(False)
else:
for widget in self.children():
if isinstance(widget, QtWidgets.QToolBar):
widget.setMovable(True)
return False
def dragEnterEvent(self, event):
if event.mimeData().hasUrls:
@@ -4080,143 +4237,14 @@ class MainGUI(QtWidgets.QMainWindow):
# sys.exit(0)
event.ignore()
def on_fullscreen(self, disable=False):
"""
def moveEvent(self, event):
oldScreen = QtWidgets.QApplication.screenAt(event.oldPos())
newScreen = QtWidgets.QApplication.screenAt(event.pos())
:param disable:
:return:
"""
flags = self.windowFlags()
if self.toggle_fscreen is False and disable is False:
# self.ui.showFullScreen()
self.setWindowFlags(flags | Qt.WindowType.FramelessWindowHint)
a = self.geometry()
self.x_pos = a.x()
self.y_pos = a.y()
self.width = a.width()
self.height = a.height()
self.titlebar_height = self.app.qapp.style().pixelMetric(QtWidgets.QStyle.PixelMetric.PM_TitleBarHeight)
if not oldScreen == newScreen:
self.screenChanged.emit(oldScreen, newScreen)
# set new geometry to full desktop rect
# Subtracting and adding the pixels below it's hack to bypass a bug in Qt5 and OpenGL that made that a
# window drawn with OpenGL in fullscreen will not show any other windows on top which means that menus and
# everything else will not work without this hack. This happen in Windows.
# https://bugreports.qt.io/browse/QTBUG-41309
# desktop = self.app.qapp.desktop()
# screen = desktop.screenNumber(QtGui.QCursor.pos())
# rec = desktop.screenGeometry(screen)
# x = rec.x() - 1
# y = rec.y() - 1
# h = rec.height() + 2
# w = rec.width() + 2
#
# self.setGeometry(x, y, w, h)
# self.show()
self.app.ui.showFullScreen()
# hide all Toolbars
for tb in self.findChildren(QtWidgets.QToolBar):
tb.setVisible(False)
self.coords_toolbar.setVisible(self.app.defaults["global_coordsbar_show"])
self.delta_coords_toolbar.setVisible(self.app.defaults["global_delta_coordsbar_show"])
self.grid_toolbar.setVisible(self.app.defaults["global_gridbar_show"])
self.status_toolbar.setVisible(self.app.defaults["global_statusbar_show"])
self.splitter.setSizes([0, 1])
self.toggle_fscreen = True
elif self.toggle_fscreen is True or disable is True:
self.setWindowFlags(flags & ~Qt.WindowType.FramelessWindowHint)
# the additions are made to account for the pixels we subtracted/added above in the (x, y, h, w)
# self.setGeometry(self.x_pos+1, self.y_pos+self.titlebar_height+4, self.width, self.height)
self.setGeometry(self.x_pos+1, self.y_pos+self.titlebar_height+13, self.width, self.height)
self.showNormal()
self.restore_toolbar_view()
self.toggle_fscreen = False
def on_toggle_plotarea(self):
"""
:return:
"""
try:
name = self.plot_tab_area.widget(0).objectName()
except AttributeError:
self.plot_tab_area.addTab(self.plot_tab, _("Plot Area"))
# remove the close button from the Plot Area tab (first tab index = 0) as this one will always be ON
self.plot_tab_area.protectTab(0)
return
if name != 'plotarea_tab':
self.plot_tab_area.insertTab(0, self.plot_tab, _("Plot Area"))
# remove the close button from the Plot Area tab (first tab index = 0) as this one will always be ON
self.plot_tab_area.protectTab(0)
else:
self.plot_tab_area.closeTab(0)
def on_toggle_notebook(self):
"""
:return:
"""
if self.splitter.sizes()[0] == 0:
self.splitter.setSizes([1, 1])
self.menu_toggle_nb.setChecked(True)
else:
self.splitter.setSizes([0, 1])
self.menu_toggle_nb.setChecked(False)
def on_toggle_grid(self):
"""
:return:
"""
self.grid_snap_btn.trigger()
def toggle_shell_ui(self):
"""
Toggle shell dock: if is visible close it, if it is closed then open it
:return: None
"""
if self.shell_dock.isVisible():
self.shell_dock.hide()
self.app.plotcanvas.native.setFocus()
else:
self.shell_dock.show()
# I want to take the focus and give it to the Tcl Shell when the Tcl Shell is run
# self.shell._edit.setFocus()
QtCore.QTimer.singleShot(0, lambda: self.shell_dock.widget()._edit.setFocus())
# HACK - simulate a mouse click - alternative
# no_km = QtCore.Qt.KeyboardModifier(QtCore.Qt.KeyboardModifier.NoModifier) # no KB modifier
# pos = QtCore.QPoint((self.shell._edit.width() - 40), (self.shell._edit.height() - 2))
# e = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, pos, QtCore.Qt.LeftButton, QtCore.Qt.LeftButton,
# no_km)
# QtCore.QCoreApplication.instance().sendEvent(self.shell._edit, e)
# f = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonRelease, pos, QtCore.Qt.LeftButton, QtCore.Qt.LeftButton,
# no_km)
# QtCore.QCoreApplication.instance().sendEvent(self.shell._edit, f)
def on_shelldock_toggled(self, visibility):
if visibility is True:
self.shell_status_label.setStyleSheet("""
QLabel
{
color: black;
background-color: lightcoral;
}
""")
self.app.inform[str, bool].emit(_("Shell enabled."), False)
else:
self.shell_status_label.setStyleSheet("")
self.app.inform[str, bool].emit(_("Shell disabled."), False)
return super().moveEvent(event)
class ShortcutsTab(QtWidgets.QWidget):