Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added loopstructural/3d_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions loopstructural/gui/dlg_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def apply(self):

# misc
settings.debug_mode = self.opt_debug.isChecked()
settings.separate_dock_widgets = self.opt_separate_dock_widgets.isChecked()
settings.interpolator_nelements = self.n_elements_spin_box.value()
settings.interpolator_npw = self.npw_spin_box.value()
settings.interpolator_cpw = self.cpw_spin_box.value()
Expand All @@ -106,6 +107,7 @@ def load_settings(self):

# global
self.opt_debug.setChecked(settings.debug_mode)
self.opt_separate_dock_widgets.setChecked(settings.separate_dock_widgets)
self.lbl_version_saved_value.setText(settings.version)
# self.interpolator_type_combo.setCurrentText(settings.interpolator_type)
self.n_elements_spin_box.setValue(settings.interpolator_nelements)
Expand Down
31 changes: 31 additions & 0 deletions loopstructural/gui/dlg_settings.ui
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,37 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="opt_separate_dock_widgets">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>Show modelling and visualisation in separate dock widgets.</string>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="locale">
<locale language="English" country="UnitedStates"/>
</property>
<property name="text">
<string>Use separate dock widgets for modelling and visualisation</string>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="btn_report">
<property name="minimumSize">
Expand Down
20 changes: 20 additions & 0 deletions loopstructural/gui/loop_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,23 @@ def __init__(
)
tabWidget.addTab(self.modelling_widget, "Modelling")
tabWidget.addTab(self.visualisation_widget, "Visualisation")

def get_modelling_widget(self):
"""Return the modelling widget instance.

Returns
-------
ModellingWidget
The modelling widget.
"""
return self.modelling_widget

def get_visualisation_widget(self):
"""Return the visualisation widget instance.

Returns
-------
VisualisationWidget
The visualisation widget.
"""
return self.visualisation_widget
143 changes: 112 additions & 31 deletions loopstructural/plugin_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from loopstructural.gui.loop_widget import LoopWidget
from loopstructural.main.data_manager import ModellingDataManager
from loopstructural.main.model_manager import GeologicalModelManager
from loopstructural.toolbelt import PlgLogger
from loopstructural.toolbelt import PlgLogger, PlgOptionsManager

# ############################################################################
# ########## Classes ###############
Expand Down Expand Up @@ -127,9 +127,13 @@ def initGui(self):
self.tr("LoopStructural Modelling"),
self.iface.mainWindow(),
)
self.action_visualisation = QAction(
QIcon(os.path.dirname(__file__) + "/3D_icon.png"),
self.tr("LoopStructural Visualisation"),
self.iface.mainWindow(),
)

self.toolbar.addAction(self.action_modelling)

# -- Menu
self.iface.addPluginToMenu(__title__, self.action_settings)
self.iface.addPluginToMenu(__title__, self.action_help)
Expand All @@ -150,36 +154,102 @@ def initGui(self):
self.iface.pluginHelpMenu().addAction(self.action_help_plugin_menu_documentation)

## --- dock widget
self.loop_dockwidget = QDockWidget(self.tr("Loop"), self.iface.mainWindow())
self.loop_widget = LoopWidget(
self.iface.mainWindow(),
mapCanvas=self.iface.mapCanvas(),
logger=self.log,
data_manager=self.data_manager,
model_manager=self.model_manager,
)
# Get the setting for separate dock widgets
settings = PlgOptionsManager.get_plg_settings()

if settings.separate_dock_widgets:
# Create separate dock widgets for modelling and visualisation
self.loop_widget = LoopWidget(
self.iface.mainWindow(),
mapCanvas=self.iface.mapCanvas(),
logger=self.log,
data_manager=self.data_manager,
model_manager=self.model_manager,
)
self.toolbar.addAction(self.action_visualisation)

self.loop_dockwidget.setWidget(self.loop_widget)
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.loop_dockwidget)
right_docks = [
d
for d in self.iface.mainWindow().findChildren(QDockWidget)
if self.iface.mainWindow().dockWidgetArea(d) == Qt.RightDockWidgetArea
]
# If there are other dock widgets, tab this one with the first one found
if right_docks:
for dock in right_docks:
if dock != self.loop_dockwidget:
self.iface.mainWindow().tabifyDockWidget(dock, self.loop_dockwidget)
# Optionally, bring your plugin tab to the front
self.loop_dockwidget.raise_()
break
self.loop_dockwidget.show()

self.loop_dockwidget.close()

# -- Connect actions
self.action_modelling.triggered.connect(self.loop_dockwidget.toggleViewAction().trigger)
# Create modelling dock
self.modelling_dockwidget = QDockWidget(
self.tr("Loop - Modelling"), self.iface.mainWindow()
)
self.modelling_dockwidget.setWidget(self.loop_widget.get_modelling_widget())
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.modelling_dockwidget)

# Create visualisation dock
self.visualisation_dockwidget = QDockWidget(
self.tr("Loop - Visualisation"), self.iface.mainWindow()
)
self.visualisation_dockwidget.setWidget(self.loop_widget.get_visualisation_widget())
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.visualisation_dockwidget)

# Tab them with other right docks if available
right_docks = [
d
for d in self.iface.mainWindow().findChildren(QDockWidget)
if self.iface.mainWindow().dockWidgetArea(d) == Qt.RightDockWidgetArea
]
if right_docks:
for dock in right_docks:
if dock != self.modelling_dockwidget and dock != self.visualisation_dockwidget:
self.iface.mainWindow().tabifyDockWidget(dock, self.modelling_dockwidget)
self.modelling_dockwidget.raise_()
break

# Tab visualisation with modelling
self.iface.mainWindow().tabifyDockWidget(
self.modelling_dockwidget, self.visualisation_dockwidget
)

self.modelling_dockwidget.show()
self.visualisation_dockwidget.show()
self.modelling_dockwidget.close()
self.visualisation_dockwidget.close()

# Connect action to toggle modelling dock
self.action_modelling.triggered.connect(
self.modelling_dockwidget.toggleViewAction().trigger
)
self.action_visualisation.triggered.connect(
self.visualisation_dockwidget.toggleViewAction().trigger
)
# Store reference to main dock as None for unload compatibility
self.loop_dockwidget = None
else:
# Create single dock widget with tabs (default behavior)
self.loop_dockwidget = QDockWidget(self.tr("Loop"), self.iface.mainWindow())
self.loop_widget = LoopWidget(
self.iface.mainWindow(),
mapCanvas=self.iface.mapCanvas(),
logger=self.log,
data_manager=self.data_manager,
model_manager=self.model_manager,
)

self.loop_dockwidget.setWidget(self.loop_widget)
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.loop_dockwidget)
right_docks = [
d
for d in self.iface.mainWindow().findChildren(QDockWidget)
if self.iface.mainWindow().dockWidgetArea(d) == Qt.RightDockWidgetArea
]
# If there are other dock widgets, tab this one with the first one found
if right_docks:
for dock in right_docks:
if dock != self.loop_dockwidget:
self.iface.mainWindow().tabifyDockWidget(dock, self.loop_dockwidget)
# Optionally, bring your plugin tab to the front
self.loop_dockwidget.raise_()
break
self.loop_dockwidget.show()

self.loop_dockwidget.close()

# -- Connect actions
self.action_modelling.triggered.connect(self.loop_dockwidget.toggleViewAction().trigger)

# Store references to separate docks as None for unload compatibility
self.modelling_dockwidget = None
self.visualisation_dockwidget = None

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

def unload(self):
"""Clean up when plugin is disabled or uninstalled."""
# -- Clean up dock widgets
if self.loop_dockwidget:
self.iface.removeDockWidget(self.loop_dockwidget)
del self.loop_dockwidget
if self.modelling_dockwidget:
self.iface.removeDockWidget(self.modelling_dockwidget)
del self.modelling_dockwidget
if self.visualisation_dockwidget:
self.iface.removeDockWidget(self.visualisation_dockwidget)
del self.visualisation_dockwidget

# -- Clean up menu
self.iface.removePluginMenu(__title__, self.action_help)
self.iface.removePluginMenu(__title__, self.action_settings)
Expand Down
1 change: 1 addition & 0 deletions loopstructural/toolbelt/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class PlgSettingsStructure:
interpolator_regularisation: float = 1.0
interpolator_cpw: float = 1.0
interpolator_npw: float = 1.0
separate_dock_widgets: bool = False


class PlgOptionsManager:
Expand Down
5 changes: 5 additions & 0 deletions tests/qgis/test_plg_preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ def test_plg_preferences_structure(self):
self.assertIsInstance(settings.version, str)
self.assertEqual(settings.version, __version__)

# dock widgets setting
self.assertTrue(hasattr(settings, "separate_dock_widgets"))
self.assertIsInstance(settings.separate_dock_widgets, bool)
self.assertEqual(settings.separate_dock_widgets, False)


# ############################################################################
# ####### Stand-alone run ########
Expand Down