From d1d797e9c0311e11592b4dc3a269077a37c29efa Mon Sep 17 00:00:00 2001 From: Guillaume Favelier Date: Mon, 22 Mar 2021 11:34:36 +0100 Subject: [PATCH 01/10] Move to dock --- mne/viz/backends/_qt.py | 45 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index 6405a6d2bc7..14f3c706363 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -16,7 +16,7 @@ QHBoxLayout, QLabel, QToolButton, QMenuBar, QSlider, QSpinBox, QVBoxLayout, QWidget, QSizePolicy, QScrollArea, QStyle, QProgressBar, - QStyleOptionSlider, QLayout, QSplitter) + QStyleOptionSlider, QLayout) from ._pyvista import _PyVistaRenderer from ._pyvista import (_close_all, _close_3d_figure, _check_3d_figure, # noqa: F401,E501 analysis:ignore @@ -42,18 +42,10 @@ def _layout_add_widget(self, layout, widget, max_width=None): class _QtDock(_AbstractDock, _QtLayout): def _dock_initialize(self, window=None): - self.dock = QDockWidget() - self.scroll = QScrollArea(self.dock) - self.dock.setWidget(self.scroll) - widget = QWidget(self.scroll) - self.scroll.setWidget(widget) - self.scroll.setWidgetResizable(True) - self.dock.setAllowedAreas(Qt.LeftDockWidgetArea) - self.dock.setFeatures(QDockWidget.NoDockWidgetFeatures) window = self._window if window is None else window - window.addDockWidget(Qt.LeftDockWidgetArea, self.dock) - self.dock_layout = QVBoxLayout() - widget.setLayout(self.dock_layout) + self.dock, self.dock_layout = _create_dock_widget( + self._window, "Controls", Qt.LeftDockWidgetArea) + window.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea) def _dock_finalize(self): self.dock.setMinimumSize(self.dock.sizeHint().width(), 0) @@ -387,16 +379,9 @@ def _window_get_mplcanvas(self, brain, interactor_fraction, show_traces, def _window_adjust_mplcanvas_layout(self): canvas = self._mplcanvas.canvas - vlayout = self._interactor.frame.layout() - vlayout.removeWidget(self._interactor) - splitter = QSplitter( - orientation=Qt.Vertical, - parent=self._interactor.frame - ) - vlayout.addWidget(splitter) - splitter.addWidget(self._interactor) - splitter.addWidget(canvas) - self._splitter = splitter + dock, dock_layout = _create_dock_widget( + self._window, "Traces", Qt.BottomDockWidgetArea) + dock_layout.addWidget(canvas) def _window_get_cursor(self): return self._interactor.cursor() @@ -417,7 +402,6 @@ def _window_ensure_minimum_sizes(self, sz): try: yield finally: - self._splitter.setSizes([sz[1], mpl_h]) # 1. Process events self._process_events() self._process_events() @@ -465,6 +449,21 @@ class _Renderer(_PyVistaRenderer, _QtDock, _QtToolBar, _QtMenuBar, pass +def _create_dock_widget(window, name, area): + dock = QDockWidget() + scroll = QScrollArea(dock) + dock.setWidget(scroll) + widget = QWidget(scroll) + scroll.setWidget(widget) + scroll.setWidgetResizable(True) + dock.setAllowedAreas(area) + dock.setTitleBarWidget(QLabel(name)) + window.addDockWidget(area, dock) + dock_layout = QVBoxLayout() + widget.setLayout(dock_layout) + return dock, dock_layout + + @contextmanager def _testing_context(interactive): from . import renderer From 8dd53d8d808c83afc3e60ab1c23b304f0b44fcb1 Mon Sep 17 00:00:00 2001 From: Guillaume Favelier Date: Mon, 22 Mar 2021 11:55:39 +0100 Subject: [PATCH 02/10] Refactor --- mne/viz/_brain/_brain.py | 8 +++--- mne/viz/backends/_abstract.py | 4 +-- mne/viz/backends/_notebook.py | 4 +-- mne/viz/backends/_qt.py | 51 +++++++++++++++++------------------ 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/mne/viz/_brain/_brain.py b/mne/viz/_brain/_brain.py index d4130b95aba..e62cd26b203 100644 --- a/mne/viz/_brain/_brain.py +++ b/mne/viz/_brain/_brain.py @@ -413,7 +413,7 @@ def __init__(self, subject_id, hemi, surf, title=None, if len(size) not in (1, 2): raise ValueError('"size" parameter must be an int or length-2 ' 'sequence of ints.') - self._size = size if len(size) == 2 else size * 2 # 1-tuple to 2-tuple + size = size if len(size) == 2 else size * 2 # 1-tuple to 2-tuple subjects_dir = get_subjects_dir(subjects_dir) self.time_viewer = False @@ -466,7 +466,7 @@ def __init__(self, subject_id, hemi, surf, title=None, offset = (surf == 'inflated') offset = None if (not offset or hemi != 'both') else 0.0 - self._renderer = _get_renderer(name=self._title, size=self._size, + self._renderer = _get_renderer(name=self._title, size=size, bgcolor=background, shape=shape, fig=figure) @@ -654,7 +654,7 @@ def setup_time_viewer(self, time_viewer=True, show_traces=True): self._configure_help() # show everything at the end self.toggle_interface() - self._renderer._window_show(self._size) + self._renderer._window_show() # sizes could change, update views for hemi in ('lh', 'rh'): @@ -717,7 +717,7 @@ def toggle_interface(self, value=None): self.visibility = value # update tool bar and dock - with self._renderer._window_ensure_minimum_sizes(self._size): + with self._renderer._window_ensure_minimum_sizes(): if self.visibility: self._renderer._dock_show() self._renderer._tool_bar_update_button_icon( diff --git a/mne/viz/backends/_abstract.py b/mne/viz/backends/_abstract.py index f8046fffa91..5e0c3b1c8d1 100644 --- a/mne/viz/backends/_abstract.py +++ b/mne/viz/backends/_abstract.py @@ -757,9 +757,9 @@ def _window_set_cursor(self, cursor): pass @abstractmethod - def _window_ensure_minimum_sizes(self, sz): + def _window_ensure_minimum_sizes(self): pass @abstractmethod - def _window_show(self, sz): + def _window_show(self): pass diff --git a/mne/viz/backends/_notebook.py b/mne/viz/backends/_notebook.py index 44b2604e8d6..c5c5017ed0d 100644 --- a/mne/viz/backends/_notebook.py +++ b/mne/viz/backends/_notebook.py @@ -282,10 +282,10 @@ def _window_set_cursor(self, cursor): pass @contextmanager - def _window_ensure_minimum_sizes(self, sz): + def _window_ensure_minimum_sizes(self): yield - def _window_show(self, sz): + def _window_show(self): self.show() diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index 14f3c706363..7a8e05c5c11 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -369,12 +369,17 @@ def _window_get_simple_canvas(self, width, height, dpi): def _window_get_mplcanvas(self, brain, interactor_fraction, show_traces, separate_canvas): + sz = self.figure.store['window_size'] w, h = self._window_get_mplcanvas_size(interactor_fraction) self._interactor_fraction = interactor_fraction self._show_traces = show_traces self._separate_canvas = separate_canvas self._mplcanvas = _QtBrainMplCanvas( brain, w, h, self._window_get_dpi()) + if self._show_traces and not self._separate_canvas: + mpl_h = int(round((sz[1] * self._interactor_fraction) / + (1 - self._interactor_fraction))) + self._mplcanvas.canvas.setMinimumSize(sz[0], mpl_h) return self._mplcanvas def _window_adjust_mplcanvas_layout(self): @@ -390,38 +395,32 @@ def _window_set_cursor(self, cursor): self._interactor.setCursor(cursor) @contextmanager - def _window_ensure_minimum_sizes(self, sz): + def _window_ensure_minimum_sizes(self): """Ensure that widgets respect the windows size.""" - adjust_mpl = (self._show_traces and not self._separate_canvas) - if not adjust_mpl: + sz = self.figure.store['window_size'] + try: yield - else: - mpl_h = int(round((sz[1] * self._interactor_fraction) / - (1 - self._interactor_fraction))) - self._mplcanvas.canvas.setMinimumSize(sz[0], mpl_h) - try: - yield - finally: - # 1. Process events - self._process_events() - self._process_events() - # 2. Get the window size that accommodates the size - sz = self._window.size() - # 3. Call app_window.setBaseSize and resize (in pyvistaqt) - self.figure.plotter.window_size = (sz.width(), sz.height()) - # 4. Undo the min size setting and process events - self._interactor.setMinimumSize(0, 0) - self._process_events() - self._process_events() - # 5. Resize the window (again!) to the correct size - # (not sure why, but this is required on macOS at least) - self.figure.plotter.window_size = (sz.width(), sz.height()) + finally: + # 1. Process events + self._process_events() + self._process_events() + # 2. Get the window size that accommodates the size + sz = self._window.size() + # 3. Call app_window.setBaseSize and resize (in pyvistaqt) + self.figure.plotter.window_size = (sz.width(), sz.height()) + # 4. Undo the min size setting and process events + self._interactor.setMinimumSize(0, 0) self._process_events() self._process_events() + # 5. Resize the window (again!) to the correct size + # (not sure why, but this is required on macOS at least) + self.figure.plotter.window_size = (sz.width(), sz.height()) + self._process_events() + self._process_events() - def _window_show(self, sz): + def _window_show(self): with _qt_disable_paint(self._interactor): - with self._window_ensure_minimum_sizes(sz): + with self._window_ensure_minimum_sizes(): self.show() From 0a00a82ea6e1cbdadf281cc0d991d01d549182b9 Mon Sep 17 00:00:00 2001 From: Guillaume Favelier Date: Mon, 22 Mar 2021 12:28:54 +0100 Subject: [PATCH 03/10] Refactor --- mne/viz/_brain/_brain.py | 2 +- mne/viz/backends/_abstract.py | 4 ---- mne/viz/backends/_notebook.py | 3 --- mne/viz/backends/_pyvista.py | 37 +----------------------------- mne/viz/backends/_qt.py | 42 ++++++++++++++++++++--------------- 5 files changed, 26 insertions(+), 62 deletions(-) diff --git a/mne/viz/_brain/_brain.py b/mne/viz/_brain/_brain.py index e62cd26b203..fd4b940368b 100644 --- a/mne/viz/_brain/_brain.py +++ b/mne/viz/_brain/_brain.py @@ -654,7 +654,7 @@ def setup_time_viewer(self, time_viewer=True, show_traces=True): self._configure_help() # show everything at the end self.toggle_interface() - self._renderer._window_show() + self._renderer.show() # sizes could change, update views for hemi in ('lh', 'rh'): diff --git a/mne/viz/backends/_abstract.py b/mne/viz/backends/_abstract.py index 5e0c3b1c8d1..3dd66f5369d 100644 --- a/mne/viz/backends/_abstract.py +++ b/mne/viz/backends/_abstract.py @@ -759,7 +759,3 @@ def _window_set_cursor(self, cursor): @abstractmethod def _window_ensure_minimum_sizes(self): pass - - @abstractmethod - def _window_show(self): - pass diff --git a/mne/viz/backends/_notebook.py b/mne/viz/backends/_notebook.py index c5c5017ed0d..13cb93b3e42 100644 --- a/mne/viz/backends/_notebook.py +++ b/mne/viz/backends/_notebook.py @@ -285,9 +285,6 @@ def _window_set_cursor(self, cursor): def _window_ensure_minimum_sizes(self): yield - def _window_show(self): - self.show() - class _IpyWidget(_AbstractWidget): def set_value(self, value): diff --git a/mne/viz/backends/_pyvista.py b/mne/viz/backends/_pyvista.py index c596e2bbce8..38c429a3de4 100644 --- a/mne/viz/backends/_pyvista.py +++ b/mne/viz/backends/_pyvista.py @@ -23,8 +23,7 @@ from ._abstract import _AbstractRenderer from ._utils import (_get_colormap_from_array, _alpha_blend_background, - ALLOWED_QUIVER_MODES, _init_qt_resources, - _qt_disable_paint) + ALLOWED_QUIVER_MODES, _init_qt_resources) from ...fixes import _get_args from ...transforms import apply_trans from ...utils import copy_base_doc_to_subclass_doc, _check_option @@ -211,35 +210,6 @@ def _get_screenshot_filename(self): dt_string = now.strftime("_%Y-%m-%d_%H-%M-%S") return "MNE" + dt_string + ".png" - @contextmanager - def _ensure_minimum_sizes(self): - sz = self.figure.store['window_size'] - # plotter: pyvista.plotting.qt_plotting.BackgroundPlotter - # plotter.interactor: vtk.qt.QVTKRenderWindowInteractor.QVTKRenderWindowInteractor -> QWidget # noqa - # plotter.app_window: pyvista.plotting.qt_plotting.MainWindow -> QMainWindow # noqa - # plotter.frame: QFrame with QVBoxLayout with plotter.interactor as centralWidget # noqa - # plotter.ren_win: vtkXOpenGLRenderWindow - self.plotter.interactor.setMinimumSize(*sz) - try: - yield # show - finally: - # 1. Process events - _process_events(self.plotter) - _process_events(self.plotter) - # 2. Get the window and interactor sizes that work - win_sz = self.plotter.app_window.size() - ren_sz = self.plotter.interactor.size() - # 3. Undo the min size setting and process events - self.plotter.interactor.setMinimumSize(0, 0) - _process_events(self.plotter) - _process_events(self.plotter) - # 4. Resize the window and interactor to the correct size - # (not sure why, but this is required on macOS at least) - self.plotter.window_size = (win_sz.width(), win_sz.height()) - self.plotter.interactor.resize(ren_sz.width(), ren_sz.height()) - _process_events(self.plotter) - _process_events(self.plotter) - def _index_to_loc(self, idx): _ncols = self.figure._ncols row = idx // _ncols @@ -625,11 +595,6 @@ def scalarbar(self, source, color="white", title=None, n_labels=4, def show(self): self.plotter.show() - if hasattr(self.plotter, "app_window"): - with _qt_disable_paint(self.plotter): - with self._ensure_minimum_sizes(): - self.plotter.app_window.show() - self.plotter.update() return self.scene() def close(self): diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index 7a8e05c5c11..c1f48c9fe9c 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -396,32 +396,32 @@ def _window_set_cursor(self, cursor): @contextmanager def _window_ensure_minimum_sizes(self): - """Ensure that widgets respect the windows size.""" sz = self.figure.store['window_size'] + # plotter: pyvista.plotting.qt_plotting.BackgroundPlotter + # plotter.interactor: vtk.qt.QVTKRenderWindowInteractor.QVTKRenderWindowInteractor -> QWidget # noqa + # plotter.app_window: pyvista.plotting.qt_plotting.MainWindow -> QMainWindow # noqa + # plotter.frame: QFrame with QVBoxLayout with plotter.interactor as centralWidget # noqa + # plotter.ren_win: vtkXOpenGLRenderWindow + self.plotter.interactor.setMinimumSize(*sz) try: - yield + yield # show finally: # 1. Process events self._process_events() self._process_events() - # 2. Get the window size that accommodates the size - sz = self._window.size() - # 3. Call app_window.setBaseSize and resize (in pyvistaqt) - self.figure.plotter.window_size = (sz.width(), sz.height()) - # 4. Undo the min size setting and process events - self._interactor.setMinimumSize(0, 0) + # 2. Get the window and interactor sizes that work + win_sz = self.plotter.app_window.size() + ren_sz = self.plotter.interactor.size() + # 3. Undo the min size setting and process events + self.plotter.interactor.setMinimumSize(0, 0) self._process_events() self._process_events() - # 5. Resize the window (again!) to the correct size + # 4. Resize the window and interactor to the correct size # (not sure why, but this is required on macOS at least) - self.figure.plotter.window_size = (sz.width(), sz.height()) - self._process_events() - self._process_events() - - def _window_show(self): - with _qt_disable_paint(self._interactor): - with self._window_ensure_minimum_sizes(): - self.show() + self.plotter.window_size = (win_sz.width(), win_sz.height()) + self.plotter.interactor.resize(ren_sz.width(), ren_sz.height()) + self._process_events() + self._process_events() class _QtWidget(_AbstractWidget): @@ -445,7 +445,13 @@ def get_value(self): class _Renderer(_PyVistaRenderer, _QtDock, _QtToolBar, _QtMenuBar, _QtStatusBar, _QtWindow, _QtPlayback): - pass + def show(self): + super().show() + with _qt_disable_paint(self.plotter): + with self._window_ensure_minimum_sizes(): + self.plotter.app_window.show() + self.plotter.update() + return self.scene() def _create_dock_widget(window, name, area): From 164b3e9ef47abfca9f14ff7ce5b7ff0b12561c5d Mon Sep 17 00:00:00 2001 From: Guillaume Favelier Date: Mon, 22 Mar 2021 13:28:41 +0100 Subject: [PATCH 04/10] Handle margins --- mne/viz/backends/_qt.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index c1f48c9fe9c..377e7055b14 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -385,7 +385,7 @@ def _window_get_mplcanvas(self, brain, interactor_fraction, show_traces, def _window_adjust_mplcanvas_layout(self): canvas = self._mplcanvas.canvas dock, dock_layout = _create_dock_widget( - self._window, "Traces", Qt.BottomDockWidgetArea) + self._window, "Traces", Qt.BottomDockWidgetArea, False) dock_layout.addWidget(canvas) def _window_get_cursor(self): @@ -454,7 +454,7 @@ def show(self): return self.scene() -def _create_dock_widget(window, name, area): +def _create_dock_widget(window, name, area, margin=True): dock = QDockWidget() scroll = QScrollArea(dock) dock.setWidget(scroll) @@ -465,6 +465,8 @@ def _create_dock_widget(window, name, area): dock.setTitleBarWidget(QLabel(name)) window.addDockWidget(area, dock) dock_layout = QVBoxLayout() + if not margin: + dock_layout.setContentsMargins(0, 0, 0, 0) widget.setLayout(dock_layout) return dock, dock_layout From 43f86f6d080f6bfa6d59818e8cbdede8bac77fcd Mon Sep 17 00:00:00 2001 From: Guillaume Favelier Date: Mon, 22 Mar 2021 13:39:41 +0100 Subject: [PATCH 05/10] Remove cruft --- mne/viz/backends/_notebook.py | 1 - mne/viz/backends/_qt.py | 1 - 2 files changed, 2 deletions(-) diff --git a/mne/viz/backends/_notebook.py b/mne/viz/backends/_notebook.py index 13cb93b3e42..e6593202480 100644 --- a/mne/viz/backends/_notebook.py +++ b/mne/viz/backends/_notebook.py @@ -250,7 +250,6 @@ def _window_initialize(self, func=None): self._mplcanvas = None self._show_traces = None self._separate_canvas = None - self._splitter = None self._interactor_fraction = None def _window_get_dpi(self): diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index 412d9d4f677..1d7fa682690 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -351,7 +351,6 @@ def _window_initialize(self, func=None): self._mplcanvas = None self._show_traces = None self._separate_canvas = None - self._splitter = None self._interactor_fraction = None self._window.setLocale(QLocale(QLocale.Language.English)) if func is not None: From 736fb29eda833ee4a4129d09c3fcaf2bcbe97acd Mon Sep 17 00:00:00 2001 From: Guillaume Favelier Date: Tue, 23 Mar 2021 10:45:24 +0100 Subject: [PATCH 06/10] Adjust mplcanvas size --- mne/viz/_brain/tests/test_brain.py | 2 +- mne/viz/backends/_qt.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mne/viz/_brain/tests/test_brain.py b/mne/viz/_brain/tests/test_brain.py index 9b80f9ccdd8..4e9eec86156 100644 --- a/mne/viz/_brain/tests/test_brain.py +++ b/mne/viz/_brain/tests/test_brain.py @@ -378,7 +378,7 @@ def test_brain_save_movie(tmpdir, renderer, brain_gc): brain.close() -_TINY_SIZE = (300, 250) +_TINY_SIZE = (350, 300) def tiny(tmpdir): diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index 1d7fa682690..ccd15425314 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -369,23 +369,18 @@ def _window_get_simple_canvas(self, width, height, dpi): def _window_get_mplcanvas(self, brain, interactor_fraction, show_traces, separate_canvas): - sz = self.figure.store['window_size'] w, h = self._window_get_mplcanvas_size(interactor_fraction) self._interactor_fraction = interactor_fraction self._show_traces = show_traces self._separate_canvas = separate_canvas self._mplcanvas = _QtBrainMplCanvas( brain, w, h, self._window_get_dpi()) - if self._show_traces and not self._separate_canvas: - mpl_h = int(round((sz[1] * self._interactor_fraction) / - (1 - self._interactor_fraction))) - self._mplcanvas.canvas.setMinimumSize(sz[0], mpl_h) return self._mplcanvas def _window_adjust_mplcanvas_layout(self): canvas = self._mplcanvas.canvas dock, dock_layout = _create_dock_widget( - self._window, "Traces", Qt.BottomDockWidgetArea, False) + self._window, "Traces", Qt.BottomDockWidgetArea) dock_layout.addWidget(canvas) def _window_get_cursor(self): @@ -397,12 +392,17 @@ def _window_set_cursor(self, cursor): @contextmanager def _window_ensure_minimum_sizes(self): sz = self.figure.store['window_size'] + adjust_mplcanvas = (self._show_traces and not self._separate_canvas) # plotter: pyvista.plotting.qt_plotting.BackgroundPlotter # plotter.interactor: vtk.qt.QVTKRenderWindowInteractor.QVTKRenderWindowInteractor -> QWidget # noqa # plotter.app_window: pyvista.plotting.qt_plotting.MainWindow -> QMainWindow # noqa # plotter.frame: QFrame with QVBoxLayout with plotter.interactor as centralWidget # noqa # plotter.ren_win: vtkXOpenGLRenderWindow self.plotter.interactor.setMinimumSize(*sz) + if adjust_mplcanvas: + mpl_h = int(round((sz[1] * self._interactor_fraction) / + (1 - self._interactor_fraction))) + self._mplcanvas.canvas.setMinimumSize(sz[0], mpl_h) try: yield # show finally: @@ -414,6 +414,8 @@ def _window_ensure_minimum_sizes(self): ren_sz = self.plotter.interactor.size() # 3. Undo the min size setting and process events self.plotter.interactor.setMinimumSize(0, 0) + if adjust_mplcanvas: + self._mplcanvas.canvas.setMinimumSize(0, 0) self._process_events() self._process_events() # 4. Resize the window and interactor to the correct size @@ -454,7 +456,7 @@ def show(self): return self.scene() -def _create_dock_widget(window, name, area, margin=True): +def _create_dock_widget(window, name, area): dock = QDockWidget() scroll = QScrollArea(dock) dock.setWidget(scroll) @@ -465,8 +467,6 @@ def _create_dock_widget(window, name, area, margin=True): dock.setTitleBarWidget(QLabel(name)) window.addDockWidget(area, dock) dock_layout = QVBoxLayout() - if not margin: - dock_layout.setContentsMargins(0, 0, 0, 0) widget.setLayout(dock_layout) return dock, dock_layout From 11c05f6aa054c26dddc172b07ca0d5b4ce60926e Mon Sep 17 00:00:00 2001 From: Guillaume Favelier Date: Tue, 23 Mar 2021 11:33:37 +0100 Subject: [PATCH 07/10] Refactor --- mne/viz/_brain/_brain.py | 3 +-- mne/viz/backends/_abstract.py | 10 +++++++++- mne/viz/backends/_notebook.py | 9 ++------- mne/viz/backends/_pyvista.py | 1 - mne/viz/backends/_qt.py | 37 ++++++++++++++++++----------------- 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/mne/viz/_brain/_brain.py b/mne/viz/_brain/_brain.py index fdb25bbf2f5..e6d32bbefb9 100644 --- a/mne/viz/_brain/_brain.py +++ b/mne/viz/_brain/_brain.py @@ -478,8 +478,7 @@ def __init__(self, subject_id, hemi, surf, title=None, bgcolor=background, shape=shape, fig=figure) - - self._renderer._window_initialize(self._clean) + self._renderer._window_close_connect(self._clean) self._renderer._window_set_theme(theme) self.plotter = self._renderer.plotter diff --git a/mne/viz/backends/_abstract.py b/mne/viz/backends/_abstract.py index cc1465e82b4..d61b83f8c04 100644 --- a/mne/viz/backends/_abstract.py +++ b/mne/viz/backends/_abstract.py @@ -720,8 +720,16 @@ def clear(self): class _AbstractWindow(ABC): + def _window_initialize(self): + self._window = None + self._interactor = None + self._mplcanvas = None + self._show_traces = None + self._separate_canvas = None + self._interactor_fraction = None + @abstractmethod - def _window_initialize(self, func=None): + def _window_close_connect(self, func): pass @abstractmethod diff --git a/mne/viz/backends/_notebook.py b/mne/viz/backends/_notebook.py index 40e35bc59b7..3c3a11d2f0d 100644 --- a/mne/viz/backends/_notebook.py +++ b/mne/viz/backends/_notebook.py @@ -247,13 +247,8 @@ def __init__(self, brain, width, height, dpi): class _IpyWindow(_AbstractWindow): - def _window_initialize(self, func=None): - self._window = None - self._interactor = None - self._mplcanvas = None - self._show_traces = None - self._separate_canvas = None - self._interactor_fraction = None + def _window_close_connect(self, func): + pass def _window_get_dpi(self): return 96 diff --git a/mne/viz/backends/_pyvista.py b/mne/viz/backends/_pyvista.py index 38c429a3de4..bc01a2da8e8 100644 --- a/mne/viz/backends/_pyvista.py +++ b/mne/viz/backends/_pyvista.py @@ -595,7 +595,6 @@ def scalarbar(self, source, color="white", title=None, n_labels=4, def show(self): self.plotter.show() - return self.scene() def close(self): _close_3d_figure(figure=self.figure) diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index db39de2172c..a6bb1f6ce2b 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -356,16 +356,14 @@ def __init__(self, brain, width, height, dpi): class _QtWindow(_AbstractWindow): - def _window_initialize(self, func=None): - self._window = self.figure.plotter.app_window + def _window_initialize(self): + super()._window_initialize() self._interactor = self.figure.plotter.interactor - self._mplcanvas = None - self._show_traces = None - self._separate_canvas = None - self._interactor_fraction = None + self._window = self.figure.plotter.app_window self._window.setLocale(QLocale(QLocale.Language.English)) - if func is not None: - self._window.signal_close.connect(func) + + def _window_close_connect(self, func): + self._window.signal_close.connect(func) def _window_get_dpi(self): return self._window.windowHandle().screen().logicalDotsPerInch() @@ -403,14 +401,14 @@ def _window_set_cursor(self, cursor): @contextmanager def _window_ensure_minimum_sizes(self): sz = self.figure.store['window_size'] - adjust_mplcanvas = (self._show_traces and not self._separate_canvas) + adjust_mpl = (self._show_traces and not self._separate_canvas) # plotter: pyvista.plotting.qt_plotting.BackgroundPlotter # plotter.interactor: vtk.qt.QVTKRenderWindowInteractor.QVTKRenderWindowInteractor -> QWidget # noqa # plotter.app_window: pyvista.plotting.qt_plotting.MainWindow -> QMainWindow # noqa # plotter.frame: QFrame with QVBoxLayout with plotter.interactor as centralWidget # noqa # plotter.ren_win: vtkXOpenGLRenderWindow - self.plotter.interactor.setMinimumSize(*sz) - if adjust_mplcanvas: + self._interactor.setMinimumSize(*sz) + if adjust_mpl: mpl_h = int(round((sz[1] * self._interactor_fraction) / (1 - self._interactor_fraction))) self._mplcanvas.canvas.setMinimumSize(sz[0], mpl_h) @@ -421,18 +419,18 @@ def _window_ensure_minimum_sizes(self): self._process_events() self._process_events() # 2. Get the window and interactor sizes that work - win_sz = self.plotter.app_window.size() - ren_sz = self.plotter.interactor.size() + win_sz = self._window.size() + ren_sz = self._interactor.size() # 3. Undo the min size setting and process events - self.plotter.interactor.setMinimumSize(0, 0) - if adjust_mplcanvas: + self._interactor.setMinimumSize(0, 0) + if adjust_mpl: self._mplcanvas.canvas.setMinimumSize(0, 0) self._process_events() self._process_events() # 4. Resize the window and interactor to the correct size # (not sure why, but this is required on macOS at least) - self.plotter.window_size = (win_sz.width(), win_sz.height()) - self.plotter.interactor.resize(ren_sz.width(), ren_sz.height()) + self._interactor.window_size = (win_sz.width(), win_sz.height()) + self._interactor.resize(ren_sz.width(), ren_sz.height()) self._process_events() self._process_events() @@ -479,13 +477,16 @@ def get_value(self): class _Renderer(_PyVistaRenderer, _QtDock, _QtToolBar, _QtMenuBar, _QtStatusBar, _QtWindow, _QtPlayback): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._window_initialize() + def show(self): super().show() with _qt_disable_paint(self.plotter): with self._window_ensure_minimum_sizes(): self.plotter.app_window.show() self.plotter.update() - return self.scene() def _create_dock_widget(window, name, area): From 8d836cd3e5ca1e556a7961b8253394d71fd7df16 Mon Sep 17 00:00:00 2001 From: Guillaume Favelier Date: Wed, 24 Mar 2021 14:43:17 +0100 Subject: [PATCH 08/10] TST: Try central dock widget --- mne/viz/backends/_qt.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index a6bb1f6ce2b..72c6c5a6d9f 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -44,8 +44,9 @@ class _QtDock(_AbstractDock, _QtLayout): def _dock_initialize(self, window=None): window = self._window if window is None else window self.dock, self.dock_layout = _create_dock_widget( - self._window, "Controls", Qt.LeftDockWidgetArea) - window.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea) + self._window, "Controls", Qt.AllDockWidgetAreas, + Qt.LeftDockWidgetArea) + # window.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea) def _dock_finalize(self): self.dock.setMinimumSize(self.dock.sizeHint().width(), 0) @@ -362,6 +363,16 @@ def _window_initialize(self): self._window = self.figure.plotter.app_window self._window.setLocale(QLocale(QLocale.Language.English)) + name = "Plot" + window = self._window + window.setCentralWidget(QLabel("")) + window.centralWidget().hide() + dock = QDockWidget() + dock.setWidget(self._interactor) + dock.setAllowedAreas(Qt.AllDockWidgetAreas) + dock.setTitleBarWidget(QLabel(name)) + window.addDockWidget(Qt.TopDockWidgetArea, dock) + def _window_close_connect(self, func): self._window.signal_close.connect(func) @@ -389,7 +400,8 @@ def _window_get_mplcanvas(self, brain, interactor_fraction, show_traces, def _window_adjust_mplcanvas_layout(self): canvas = self._mplcanvas.canvas dock, dock_layout = _create_dock_widget( - self._window, "Traces", Qt.BottomDockWidgetArea) + self._window, "Traces", Qt.AllDockWidgetAreas, + Qt.BottomDockWidgetArea) dock_layout.addWidget(canvas) def _window_get_cursor(self): @@ -489,16 +501,16 @@ def show(self): self.plotter.update() -def _create_dock_widget(window, name, area): +def _create_dock_widget(window, name, allowed_area, default_area): dock = QDockWidget() scroll = QScrollArea(dock) dock.setWidget(scroll) widget = QWidget(scroll) scroll.setWidget(widget) scroll.setWidgetResizable(True) - dock.setAllowedAreas(area) + dock.setAllowedAreas(allowed_area) dock.setTitleBarWidget(QLabel(name)) - window.addDockWidget(area, dock) + window.addDockWidget(default_area, dock) dock_layout = QVBoxLayout() widget.setLayout(dock_layout) return dock, dock_layout From fd043abdefffcf270252021f75d94bbfe717f396 Mon Sep 17 00:00:00 2001 From: Guillaume Favelier Date: Wed, 24 Mar 2021 14:43:33 +0100 Subject: [PATCH 09/10] Revert "TST: Try central dock widget" This reverts commit 8d836cd3e5ca1e556a7961b8253394d71fd7df16. --- mne/viz/backends/_qt.py | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index 72c6c5a6d9f..a6bb1f6ce2b 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -44,9 +44,8 @@ class _QtDock(_AbstractDock, _QtLayout): def _dock_initialize(self, window=None): window = self._window if window is None else window self.dock, self.dock_layout = _create_dock_widget( - self._window, "Controls", Qt.AllDockWidgetAreas, - Qt.LeftDockWidgetArea) - # window.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea) + self._window, "Controls", Qt.LeftDockWidgetArea) + window.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea) def _dock_finalize(self): self.dock.setMinimumSize(self.dock.sizeHint().width(), 0) @@ -363,16 +362,6 @@ def _window_initialize(self): self._window = self.figure.plotter.app_window self._window.setLocale(QLocale(QLocale.Language.English)) - name = "Plot" - window = self._window - window.setCentralWidget(QLabel("")) - window.centralWidget().hide() - dock = QDockWidget() - dock.setWidget(self._interactor) - dock.setAllowedAreas(Qt.AllDockWidgetAreas) - dock.setTitleBarWidget(QLabel(name)) - window.addDockWidget(Qt.TopDockWidgetArea, dock) - def _window_close_connect(self, func): self._window.signal_close.connect(func) @@ -400,8 +389,7 @@ def _window_get_mplcanvas(self, brain, interactor_fraction, show_traces, def _window_adjust_mplcanvas_layout(self): canvas = self._mplcanvas.canvas dock, dock_layout = _create_dock_widget( - self._window, "Traces", Qt.AllDockWidgetAreas, - Qt.BottomDockWidgetArea) + self._window, "Traces", Qt.BottomDockWidgetArea) dock_layout.addWidget(canvas) def _window_get_cursor(self): @@ -501,16 +489,16 @@ def show(self): self.plotter.update() -def _create_dock_widget(window, name, allowed_area, default_area): +def _create_dock_widget(window, name, area): dock = QDockWidget() scroll = QScrollArea(dock) dock.setWidget(scroll) widget = QWidget(scroll) scroll.setWidget(widget) scroll.setWidgetResizable(True) - dock.setAllowedAreas(allowed_area) + dock.setAllowedAreas(area) dock.setTitleBarWidget(QLabel(name)) - window.addDockWidget(default_area, dock) + window.addDockWidget(area, dock) dock_layout = QVBoxLayout() widget.setLayout(dock_layout) return dock, dock_layout From 0b5e046f5fdae85e05be32aecc3192bc01a95a2e Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Wed, 24 Mar 2021 10:23:08 -0400 Subject: [PATCH 10/10] FIX: Grip --- mne/viz/backends/_qt.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mne/viz/backends/_qt.py b/mne/viz/backends/_qt.py index a6bb1f6ce2b..77124df2e82 100644 --- a/mne/viz/backends/_qt.py +++ b/mne/viz/backends/_qt.py @@ -501,6 +501,9 @@ def _create_dock_widget(window, name, area): window.addDockWidget(area, dock) dock_layout = QVBoxLayout() widget.setLayout(dock_layout) + # Fix resize grip size + # https://stackoverflow.com/a/65050468/2175965 + dock.setStyleSheet("QDockWidget { margin: 4px; }") return dock, dock_layout