diff --git a/DataStorage.py b/DataStorage.py
index 63aeff1..24d8b05 100644
--- a/DataStorage.py
+++ b/DataStorage.py
@@ -1,5 +1,5 @@
-from typing import List, Tuple, Union, Any
+from typing import List, Optional, Tuple, Union, Any
class DataStorage:
@@ -14,6 +14,13 @@ class DataStorage:
currentCRS = None
currentUnits = "m"
+ custom_lat: Optional[float] = None
+ custom_lon: Optional[float] = None
+
+ crs_offset_x: Optional[float] = None
+ crs_offset_y: Optional[float] = None
+ crs_rotation: Optional[float] = None
+
current_layers: Union[List[Tuple[Any, str, str]], None] = None
saved_layers: Union[List, None] = None
sending_layers: None
diff --git a/dockwidget_main.py b/dockwidget_main.py
index 6a8e83b..b85b396 100644
--- a/dockwidget_main.py
+++ b/dockwidget_main.py
@@ -2,6 +2,7 @@
import inspect
import os
+from specklepy_qt_ui.widget_custom_crs import CustomCRSDialog
from specklepy_qt_ui.widget_transforms import MappingSendDialog
from specklepy_qt_ui.LogWidget import LogWidget
@@ -49,6 +50,7 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
msgLog: LogWidget = None
dataStorage: DataStorage = None
mappingSendDialog = None
+ custom_crs_modal = None
signal_1 = pyqtSignal(object)
signal_2 = pyqtSignal(object)
@@ -70,7 +72,7 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
self.streams_add_button.setFlat(True)
self.streams_remove_button.setFlat(True)
- self.saveSurveyPoint.setFlat(True)
+ #self.saveSurveyPoint.setFlat(True)
self.saveLayerSelection.setFlat(True)
self.reloadButton.setFlat(True)
self.closeButton.setFlat(True)
@@ -88,7 +90,7 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
self.streams_remove_button.setStyleSheet("QPushButton {padding:3px;padding-left:5px;border: none; text-align: left; image-position:right} QPushButton:hover { " + f"background-color: rgb{str(COLOR_HIGHLIGHT)};" + f"{COLOR}" + " }") #+ f"{backgr_image_del}"
self.saveLayerSelection.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
- self.saveSurveyPoint.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
+ #self.saveSurveyPoint.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
self.reloadButton.setStyleSheet("QPushButton {text-align: left;} QPushButton:hover { " + f"{COLOR}" + " }")
self.closeButton.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
@@ -113,6 +115,7 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
# l_item = self.verticalLayout.itemAt(i).widget()
# add row with "experimental" checkbox
+ r'''
box = QWidget()
box.layout = QHBoxLayout(box)
btn = QtWidgets.QCheckBox("Send/receive in the background (experimental!)")
@@ -122,6 +125,7 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
self.formLayout.insertRow(10,box)
self.experimental = btn
self.experimental.setChecked(True)
+ '''
def runSetup(self, plugin):
@@ -142,7 +146,8 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
self.msgLog.active_account = plugin.dataStorage.active_account
self.msgLog.speckle_version = plugin.version
- # add row with "experimental" checkbox
+ # add Transforms button
+ r'''
box = QWidget()
box.layout = QHBoxLayout(box)
btn = QtWidgets.QPushButton("Apply transformations on Send")
@@ -152,6 +157,13 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
box.layout.setContentsMargins(65, 0, 0, 0)
self.formLayout.insertRow(9,box)
self.setMapping = btn
+ '''
+
+ self.setMapping.setFlat(True)
+ self.setMapping.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
+
+ self.crsSettings.setFlat(True)
+ self.crsSettings.setStyleSheet("QPushButton {text-align: right;} QPushButton:hover { " + f"{COLOR}" + " }")
def addDataStorage(self, plugin):
self.dataStorage = plugin.dataStorage
@@ -288,7 +300,9 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
self.streams_add_button.clicked.connect( plugin.onStreamAddButtonClicked )
self.reloadButton.clicked.connect(lambda: self.refreshClicked(plugin))
self.closeButton.clicked.connect(lambda: self.closeClicked(plugin))
- self.saveSurveyPoint.clicked.connect(plugin.set_survey_point)
+
+ self.crsSettings.clicked.connect(self.customCRSDialogCreate)
+ #self.saveSurveyPoint.clicked.connect(plugin.set_survey_point)
self.sendModeButton.clicked.connect(lambda: self.setSendMode(plugin))
self.layerSendModeDropdown.currentIndexChanged.connect( lambda: self.layerSendModeChange(plugin) )
@@ -406,7 +420,6 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
self.populateLayerSendModeDropdown()
self.populateProjectStreams(plugin)
- self.populateSurveyPoint(plugin)
self.runBtnStatusChanged(plugin)
self.runButton.setEnabled(False)
@@ -535,17 +548,6 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
return
- def populateSurveyPoint(self, plugin):
- if not self:
- return
- try:
- self.surveyPointLat.clear()
- self.surveyPointLat.setText(str(plugin.lat))
- self.surveyPointLon.clear()
- self.surveyPointLon.setText(str(plugin.lon))
- except Exception as e:
- logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
- return
def enableElements(self, plugin):
try:
@@ -562,7 +564,58 @@ class SpeckleQGISDialog(QtWidgets.QDockWidget, FORM_CLASS):
except Exception as e:
logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
return
+
+ def customCRSDialogCreate(self):
+ try:
+ self.custom_crs_modal = CustomCRSDialog(None)
+ self.custom_crs_modal.dataStorage = self.dataStorage
+ self.custom_crs_modal.dialog_button_box.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(self.customCRSCreate)
+ #self.custom_crs_modal.handleBranchCreate.connect(self.handleBranchCreate)
+ self.custom_crs_modal.show()
+ #self.custom_crs_modal.populateSurveyPoint()
+ except Exception as e:
+ logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
+ return
+
+
+ def customCRSApply(self):
+ index = self.custom_crs_modal.modeDropdown.currentIndex()
+ if index == 0: #create custom CRS
+ self.customCRSCreate()
+ if index == 1:
+ self.crsOffsetsApply()
+ def crsOffsetsApply(self):
+ try:
+ from speckle.utils.project_vars import set_crs_offsets_rotation
+
+ if float(self.custom_crs_modal.offsetX.text()) is not None and float(self.custom_crs_modal.offsetY.text()) is not None:
+ self.dataStorage.crs_offset_x = float(self.custom_crs_modal.offsetX.text())
+ self.dataStorage.crs_offset_y = float(self.custom_crs_modal.offsetY.text())
+ if float(self.custom_crs_modal.rotation.text()) is not None:
+ self.dataStorage.crs_rotation = float(self.custom_crs_modal.rotation.text())
+ set_crs_offsets_rotation(self.dataStorage, self)
+ self.custom_crs_modal.close()
+ except: pass
+
+ def customCRSCreate(self):
+ try:
+ vals =[ str(self.custom_crs_modal.surveyPointLat.text()), str(self.custom_crs_modal.surveyPointLon.text()) ]
+ custom_lat, custom_lon = [float(i.replace(" ","")) for i in vals]
+ if custom_lat>180 or custom_lat<-180 or custom_lon >180 or custom_lon<-180:
+ logToUser("LAT LON values must be within (-180, 180). You can right-click on the canvas location to copy coordinates in WGS 84", level = 1, plugin=self)
+ return True
+
+ from speckle.utils.project_vars import set_survey_point, setProjectReferenceSystem
+ self.dataStorage.custom_lat = custom_lat
+ self.dataStorage.custom_lon = custom_lon
+ set_survey_point(self.dataStorage, self)
+ setProjectReferenceSystem(self.dataStorage, self)
+
+ except Exception as e:
+ logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
+ return
+
def populateProjectStreams(self, plugin):
try:
from speckle.utils.project_vars import set_project_streams
diff --git a/ui/custom_crs.ui b/ui/custom_crs.ui
new file mode 100644
index 0000000..5eed901
--- /dev/null
+++ b/ui/custom_crs.ui
@@ -0,0 +1,132 @@
+
+
+ CreateStreamDialog
+
+
+ Qt::NonModal
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+ -
+
+
+ QLayout::SetNoConstraint
+
+
-
+
+
+
-
+
+
+
+ -
+
+
-
+
+
+ lat (y)
+
+
+
+
+ -
+
+
+ °
+
+
+
+
+ -
+
+
+ lon (x)
+
+
+
+
+ -
+
+
+ °
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ lat (y)
+
+
+
+
+ -
+
+
+ lon (x)
+
+
+
+
+ -
+
+
+ rotation
+
+
+
+
+ -
+
+
+ °
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Close
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/dockwidget_main.ui b/ui/dockwidget_main.ui
index 5529cee..2f551a4 100644
--- a/ui/dockwidget_main.ui
+++ b/ui/dockwidget_main.ui
@@ -181,14 +181,72 @@
- -
+
-
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Expanding
+
+
+
+
+ -
+
+
+ true
+
+
+ Apply transformations on Send
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Expanding
+
+
+
+
+ -
+
+
+ true
+
+
+ CRS Settings
+
+
+
+
+
+
+
+
+
+
+
+ -
Message
- -
+
-
Sent XXX objects from QGIS
@@ -198,7 +256,7 @@
-
-
+
-
-
@@ -233,62 +291,8 @@
- -
-
-
- Lat, Lon
-
-
-
- -
-
-
-
-
-
- 0.0
-
-
-
-
- -
-
-
- °
-
-
-
-
- -
-
-
- 0.0
-
-
-
-
- -
-
-
- °
-
-
-
-
- -
-
-
- true
-
-
- Set as a project center
-
-
-
-
-
-
- -
+
-
-
diff --git a/widget_custom_crs.py b/widget_custom_crs.py
new file mode 100644
index 0000000..69eb691
--- /dev/null
+++ b/widget_custom_crs.py
@@ -0,0 +1,135 @@
+import inspect
+import os
+from typing import List, Tuple, Union
+from specklepy_qt_ui.DataStorage import DataStorage
+from specklepy_qt_ui.logger import logToUser
+
+from PyQt5 import QtWidgets, uic, QtCore
+from PyQt5.QtWidgets import QCheckBox, QListWidgetItem, QHBoxLayout, QWidget
+from PyQt5.QtCore import pyqtSignal
+
+from specklepy.api.client import SpeckleClient
+
+from specklepy_qt_ui.global_resources import COLOR
+
+# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
+FORM_CLASS, _ = uic.loadUiType(
+ os.path.join(os.path.join(os.path.dirname(__file__), "ui", "custom_crs.ui") )
+)
+
+class CustomCRSDialog(QtWidgets.QWidget, FORM_CLASS):
+
+ name_field: QtWidgets.QLineEdit = None
+ description_field: QtWidgets.QLineEdit = None
+ dialog_button_box: QtWidgets.QDialogButtonBox = None
+ saveSurveyPoint: QtWidgets.QPushButton = None
+ speckle_client: Union[SpeckleClient, None] = None
+ dataStorage: DataStorage = None
+
+ #Events
+ handleCRSCreate = pyqtSignal(str,str)
+
+ def __init__(self, parent=None, speckle_client: SpeckleClient = None):
+ super(CustomCRSDialog,self).__init__(parent,QtCore.Qt.WindowStaysOnTopHint)
+ self.speckle_client = speckle_client
+ self.setupUi(self)
+ self.setWindowTitle("CustomCRS")
+
+ #self.saveSurveyPoint.setFlat(True)
+ #self.saveSurveyPoint.setStyleSheet("QPushButton {text-align: left;} QPushButton:hover { " + f"{COLOR}" + " }")
+ #self.saveOffsets.setFlat(True)
+ #self.saveOffsets.setStyleSheet("QPushButton {text-align: left;} QPushButton:hover { " + f"{COLOR}" + " }")
+
+ #self.label_offsets.setEnabled(False)
+ self.offsetX.setEnabled(False)
+ self.offsetY.setEnabled(False)
+ self.rotation.setEnabled(False)
+ #self.saveOffsets.setEnabled(False)
+
+
+ self.dialog_button_box.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(self.onCancelClicked)
+ self.modeDropdown.currentIndexChanged.connect(self.onModeChanged)
+
+ self.populateModeDropdown()
+ self.populateSurveyPoint()
+
+ def onModeChanged(self):
+ try:
+ if not self: return
+ index = self.modeDropdown.currentIndex()
+ if index == 0:
+ #self.label_customCRS.setEnabled(True)
+ self.surveyPointLat.setEnabled(True)
+ self.surveyPointLon.setEnabled(True)
+ #self.saveSurveyPoint.setEnabled(True)
+
+ #self.label_offsets.setEnabled(False)
+ self.offsetX.setEnabled(False)
+ self.offsetY.setEnabled(False)
+ self.rotation.setEnabled(False)
+ #self.saveOffsets.setEnabled(False)
+
+ elif index == 1:
+ #self.label_customCRS.setEnabled(False)
+ self.surveyPointLat.setEnabled(False)
+ self.surveyPointLon.setEnabled(False)
+ #self.saveSurveyPoint.setEnabled(False)
+
+ #self.label_offsets.setEnabled(True)
+ self.offsetX.setEnabled(True)
+ self.offsetY.setEnabled(True)
+ self.rotation.setEnabled(True)
+ #self.saveOffsets.setEnabled(True)
+
+ except Exception as e:
+ logToUser(e, level = 2, func = inspect.stack()[0][3])
+ return
+
+ def populateModeDropdown(self):
+ if not self: return
+ try:
+ self.modeDropdown.clear()
+ self.modeDropdown.addItems(
+ ["Create custom CRS", "Add offsets / rotation to the current Project CRS"]
+ )
+ except Exception as e:
+ logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
+ return
+
+ def populateSurveyPoint(self):
+ if not self:
+ return
+ try:
+ self.surveyPointLat.clear()
+ self.surveyPointLon.clear()
+ if self.dataStorage.custom_lat is not None and self.dataStorage.custom_lon is not None:
+ self.surveyPointLat.setText(str(self.dataStorage.custom_lat))
+ self.surveyPointLon.setText(str(self.dataStorage.custom_lon))
+
+ except Exception as e:
+ logToUser(e, level = 2, func = inspect.stack()[0][3], plugin=self)
+ return
+
+ def onOkClicked(self):
+ return
+ try:
+ self.close()
+ except Exception as e:
+ logToUser(e, level = 2, func = inspect.stack()[0][3])
+ return
+
+ def onCancelClicked(self):
+ try:
+ self.close()
+ except Exception as e:
+ logToUser(e, level = 2, func = inspect.stack()[0][3])
+ return
+
+ def onAccountSelected(self, index):
+ try:
+ account = self.speckle_accounts[index]
+ self.speckle_client = SpeckleClient(account.serverInfo.url, account.serverInfo.url.startswith("https"))
+ self.speckle_client.authenticate_with_token(token=account.token)
+ except Exception as e:
+ logToUser(e, level = 2, func = inspect.stack()[0][3])
+ return