Skip to content

Commit 7e511a3

Browse files
authored
fix: add option to separate visualisation/modelling widget
1 parent 9eb95fd commit 7e511a3

File tree

7 files changed

+171
-31
lines changed

7 files changed

+171
-31
lines changed

loopstructural/3d_icon.png

848 KB
Loading

loopstructural/gui/dlg_settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ def apply(self):
8585

8686
# misc
8787
settings.debug_mode = self.opt_debug.isChecked()
88+
settings.separate_dock_widgets = self.opt_separate_dock_widgets.isChecked()
8889
settings.interpolator_nelements = self.n_elements_spin_box.value()
8990
settings.interpolator_npw = self.npw_spin_box.value()
9091
settings.interpolator_cpw = self.cpw_spin_box.value()
@@ -106,6 +107,7 @@ def load_settings(self):
106107

107108
# global
108109
self.opt_debug.setChecked(settings.debug_mode)
110+
self.opt_separate_dock_widgets.setChecked(settings.separate_dock_widgets)
109111
self.lbl_version_saved_value.setText(settings.version)
110112
# self.interpolator_type_combo.setCurrentText(settings.interpolator_type)
111113
self.n_elements_spin_box.setValue(settings.interpolator_nelements)

loopstructural/gui/dlg_settings.ui

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,37 @@
226226
</property>
227227
</widget>
228228
</item>
229+
<item row="2" column="0" colspan="2">
230+
<widget class="QCheckBox" name="opt_separate_dock_widgets">
231+
<property name="minimumSize">
232+
<size>
233+
<width>0</width>
234+
<height>25</height>
235+
</size>
236+
</property>
237+
<property name="maximumSize">
238+
<size>
239+
<width>16777215</width>
240+
<height>30</height>
241+
</size>
242+
</property>
243+
<property name="toolTip">
244+
<string>Show modelling and visualisation in separate dock widgets.</string>
245+
</property>
246+
<property name="autoFillBackground">
247+
<bool>true</bool>
248+
</property>
249+
<property name="locale">
250+
<locale language="English" country="UnitedStates"/>
251+
</property>
252+
<property name="text">
253+
<string>Use separate dock widgets for modelling and visualisation</string>
254+
</property>
255+
<property name="tristate">
256+
<bool>false</bool>
257+
</property>
258+
</widget>
259+
</item>
229260
<item row="0" column="1">
230261
<widget class="QPushButton" name="btn_report">
231262
<property name="minimumSize">

loopstructural/gui/loop_widget.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,23 @@ def __init__(
5151
)
5252
tabWidget.addTab(self.modelling_widget, "Modelling")
5353
tabWidget.addTab(self.visualisation_widget, "Visualisation")
54+
55+
def get_modelling_widget(self):
56+
"""Return the modelling widget instance.
57+
58+
Returns
59+
-------
60+
ModellingWidget
61+
The modelling widget.
62+
"""
63+
return self.modelling_widget
64+
65+
def get_visualisation_widget(self):
66+
"""Return the visualisation widget instance.
67+
68+
Returns
69+
-------
70+
VisualisationWidget
71+
The visualisation widget.
72+
"""
73+
return self.visualisation_widget

loopstructural/plugin_main.py

Lines changed: 112 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from loopstructural.gui.loop_widget import LoopWidget
3636
from loopstructural.main.data_manager import ModellingDataManager
3737
from loopstructural.main.model_manager import GeologicalModelManager
38-
from loopstructural.toolbelt import PlgLogger
38+
from loopstructural.toolbelt import PlgLogger, PlgOptionsManager
3939

4040
# ############################################################################
4141
# ########## Classes ###############
@@ -127,9 +127,13 @@ def initGui(self):
127127
self.tr("LoopStructural Modelling"),
128128
self.iface.mainWindow(),
129129
)
130+
self.action_visualisation = QAction(
131+
QIcon(os.path.dirname(__file__) + "/3D_icon.png"),
132+
self.tr("LoopStructural Visualisation"),
133+
self.iface.mainWindow(),
134+
)
130135

131136
self.toolbar.addAction(self.action_modelling)
132-
133137
# -- Menu
134138
self.iface.addPluginToMenu(__title__, self.action_settings)
135139
self.iface.addPluginToMenu(__title__, self.action_help)
@@ -150,36 +154,102 @@ def initGui(self):
150154
self.iface.pluginHelpMenu().addAction(self.action_help_plugin_menu_documentation)
151155

152156
## --- dock widget
153-
self.loop_dockwidget = QDockWidget(self.tr("Loop"), self.iface.mainWindow())
154-
self.loop_widget = LoopWidget(
155-
self.iface.mainWindow(),
156-
mapCanvas=self.iface.mapCanvas(),
157-
logger=self.log,
158-
data_manager=self.data_manager,
159-
model_manager=self.model_manager,
160-
)
157+
# Get the setting for separate dock widgets
158+
settings = PlgOptionsManager.get_plg_settings()
159+
160+
if settings.separate_dock_widgets:
161+
# Create separate dock widgets for modelling and visualisation
162+
self.loop_widget = LoopWidget(
163+
self.iface.mainWindow(),
164+
mapCanvas=self.iface.mapCanvas(),
165+
logger=self.log,
166+
data_manager=self.data_manager,
167+
model_manager=self.model_manager,
168+
)
169+
self.toolbar.addAction(self.action_visualisation)
161170

162-
self.loop_dockwidget.setWidget(self.loop_widget)
163-
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.loop_dockwidget)
164-
right_docks = [
165-
d
166-
for d in self.iface.mainWindow().findChildren(QDockWidget)
167-
if self.iface.mainWindow().dockWidgetArea(d) == Qt.RightDockWidgetArea
168-
]
169-
# If there are other dock widgets, tab this one with the first one found
170-
if right_docks:
171-
for dock in right_docks:
172-
if dock != self.loop_dockwidget:
173-
self.iface.mainWindow().tabifyDockWidget(dock, self.loop_dockwidget)
174-
# Optionally, bring your plugin tab to the front
175-
self.loop_dockwidget.raise_()
176-
break
177-
self.loop_dockwidget.show()
178-
179-
self.loop_dockwidget.close()
180-
181-
# -- Connect actions
182-
self.action_modelling.triggered.connect(self.loop_dockwidget.toggleViewAction().trigger)
171+
# Create modelling dock
172+
self.modelling_dockwidget = QDockWidget(
173+
self.tr("Loop - Modelling"), self.iface.mainWindow()
174+
)
175+
self.modelling_dockwidget.setWidget(self.loop_widget.get_modelling_widget())
176+
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.modelling_dockwidget)
177+
178+
# Create visualisation dock
179+
self.visualisation_dockwidget = QDockWidget(
180+
self.tr("Loop - Visualisation"), self.iface.mainWindow()
181+
)
182+
self.visualisation_dockwidget.setWidget(self.loop_widget.get_visualisation_widget())
183+
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.visualisation_dockwidget)
184+
185+
# Tab them with other right docks if available
186+
right_docks = [
187+
d
188+
for d in self.iface.mainWindow().findChildren(QDockWidget)
189+
if self.iface.mainWindow().dockWidgetArea(d) == Qt.RightDockWidgetArea
190+
]
191+
if right_docks:
192+
for dock in right_docks:
193+
if dock != self.modelling_dockwidget and dock != self.visualisation_dockwidget:
194+
self.iface.mainWindow().tabifyDockWidget(dock, self.modelling_dockwidget)
195+
self.modelling_dockwidget.raise_()
196+
break
197+
198+
# Tab visualisation with modelling
199+
self.iface.mainWindow().tabifyDockWidget(
200+
self.modelling_dockwidget, self.visualisation_dockwidget
201+
)
202+
203+
self.modelling_dockwidget.show()
204+
self.visualisation_dockwidget.show()
205+
self.modelling_dockwidget.close()
206+
self.visualisation_dockwidget.close()
207+
208+
# Connect action to toggle modelling dock
209+
self.action_modelling.triggered.connect(
210+
self.modelling_dockwidget.toggleViewAction().trigger
211+
)
212+
self.action_visualisation.triggered.connect(
213+
self.visualisation_dockwidget.toggleViewAction().trigger
214+
)
215+
# Store reference to main dock as None for unload compatibility
216+
self.loop_dockwidget = None
217+
else:
218+
# Create single dock widget with tabs (default behavior)
219+
self.loop_dockwidget = QDockWidget(self.tr("Loop"), self.iface.mainWindow())
220+
self.loop_widget = LoopWidget(
221+
self.iface.mainWindow(),
222+
mapCanvas=self.iface.mapCanvas(),
223+
logger=self.log,
224+
data_manager=self.data_manager,
225+
model_manager=self.model_manager,
226+
)
227+
228+
self.loop_dockwidget.setWidget(self.loop_widget)
229+
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.loop_dockwidget)
230+
right_docks = [
231+
d
232+
for d in self.iface.mainWindow().findChildren(QDockWidget)
233+
if self.iface.mainWindow().dockWidgetArea(d) == Qt.RightDockWidgetArea
234+
]
235+
# If there are other dock widgets, tab this one with the first one found
236+
if right_docks:
237+
for dock in right_docks:
238+
if dock != self.loop_dockwidget:
239+
self.iface.mainWindow().tabifyDockWidget(dock, self.loop_dockwidget)
240+
# Optionally, bring your plugin tab to the front
241+
self.loop_dockwidget.raise_()
242+
break
243+
self.loop_dockwidget.show()
244+
245+
self.loop_dockwidget.close()
246+
247+
# -- Connect actions
248+
self.action_modelling.triggered.connect(self.loop_dockwidget.toggleViewAction().trigger)
249+
250+
# Store references to separate docks as None for unload compatibility
251+
self.modelling_dockwidget = None
252+
self.visualisation_dockwidget = None
183253

184254
def tr(self, message: str) -> str:
185255
"""Translate a string using Qt translation API.
@@ -198,6 +268,17 @@ def tr(self, message: str) -> str:
198268

199269
def unload(self):
200270
"""Clean up when plugin is disabled or uninstalled."""
271+
# -- Clean up dock widgets
272+
if self.loop_dockwidget:
273+
self.iface.removeDockWidget(self.loop_dockwidget)
274+
del self.loop_dockwidget
275+
if self.modelling_dockwidget:
276+
self.iface.removeDockWidget(self.modelling_dockwidget)
277+
del self.modelling_dockwidget
278+
if self.visualisation_dockwidget:
279+
self.iface.removeDockWidget(self.visualisation_dockwidget)
280+
del self.visualisation_dockwidget
281+
201282
# -- Clean up menu
202283
self.iface.removePluginMenu(__title__, self.action_help)
203284
self.iface.removePluginMenu(__title__, self.action_settings)

loopstructural/toolbelt/preferences.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class PlgSettingsStructure:
3333
interpolator_regularisation: float = 1.0
3434
interpolator_cpw: float = 1.0
3535
interpolator_npw: float = 1.0
36+
separate_dock_widgets: bool = False
3637

3738

3839
class PlgOptionsManager:

tests/qgis/test_plg_preferences.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ def test_plg_preferences_structure(self):
3636
self.assertIsInstance(settings.version, str)
3737
self.assertEqual(settings.version, __version__)
3838

39+
# dock widgets setting
40+
self.assertTrue(hasattr(settings, "separate_dock_widgets"))
41+
self.assertIsInstance(settings.separate_dock_widgets, bool)
42+
self.assertEqual(settings.separate_dock_widgets, False)
43+
3944

4045
# ############################################################################
4146
# ####### Stand-alone run ########

0 commit comments

Comments
 (0)