diff --git a/cq_editor/main_window.py b/cq_editor/main_window.py index bece4094..ba52373b 100644 --- a/cq_editor/main_window.py +++ b/cq_editor/main_window.py @@ -12,6 +12,8 @@ QAction, QApplication, QMenu, + QProxyStyle, + QStyle, ) from logbook import Logger import cadquery as cq @@ -63,6 +65,23 @@ def new_stdout_write(text: str): PRINT_REDIRECTOR = _PrintRedirectorSingleton() +class DockSeparatorStyle(QProxyStyle): + """Widens the dock separators so that they are easier to grab (#277). + + A style proxy is used instead of a stylesheet because setting a stylesheet + on the main window moves its whole widget subtree to QStyleSheetStyle, + which discards palette based theming (e.g. editor syntax highlighting). + """ + + def pixelMetric(self, metric, option=None, widget=None): + + extent = super().pixelMetric(metric, option, widget) + if metric == QStyle.PM_DockWidgetSeparatorExtent: + return max(extent, 6) + + return extent + + class MainWindow(QMainWindow, MainMixin): name = "CQ-Editor" @@ -100,6 +119,11 @@ def __init__(self, parent=None, filename=None): self.viewer = OCCViewer(self) self.setCentralWidget(self.viewer.canvas) + # Make sure the dock separators are wide enough to grab on high-DPI displays. + # setStyle does not take ownership, so keep a reference on self. + self._separator_style = DockSeparatorStyle() + self.setStyle(self._separator_style) + self.prepare_panes() self.registerComponent("viewer", self.viewer) self.prepare_toolbar() diff --git a/tests/test_app.py b/tests/test_app.py index 76deda64..3a25db17 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -12,10 +12,11 @@ import cadquery as cq from PyQt5.QtCore import Qt, QSettings, QPoint, QEvent, QSize -from PyQt5.QtWidgets import QFileDialog, QMessageBox +from PyQt5.QtWidgets import QApplication, QFileDialog, QMessageBox, QStyle, QStyleFactory from PyQt5.QtGui import QMouseEvent from cq_editor.__main__ import MainWindow +from cq_editor.main_window import DockSeparatorStyle from cq_editor.widgets.editor import Editor from cq_editor.cq_utils import export, get_occ_color @@ -1708,6 +1709,31 @@ def test_launch_syntax_error(tmp_path): assert win.isVisible() +def test_dock_separator_width(qtbot): + + win = MainWindow() + qtbot.addWidget(win) + + # separators are widened through a style proxy, not a stylesheet: a + # stylesheet on the main window would break palette based theming (#595) + assert win.styleSheet() == "" + assert win.style().pixelMetric(QStyle.PM_DockWidgetSeparatorExtent, None, win) >= 6 + + # child widgets keep the application style + editor = win.components["editor"] + assert editor.style().objectName() == QApplication.instance().style().objectName() + + +def test_dock_separator_style_widens_small_extents(qtbot): + + base = QStyleFactory.create("Windows") + assert base.pixelMetric(QStyle.PM_DockWidgetSeparatorExtent) < 6 + + style = DockSeparatorStyle(base) + + assert style.pixelMetric(QStyle.PM_DockWidgetSeparatorExtent) == 6 + + code_import_module_makebox = """ from module_makebox import * z = 1