diff --git a/cura/BuildPlateModel.py b/cura/BuildPlateModel.py index 139597f9cb..35a311dc5f 100644 --- a/cura/BuildPlateModel.py +++ b/cura/BuildPlateModel.py @@ -1,2 +1,62 @@ +from UM.Qt.ListModel import ListModel +from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot +from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator +from UM.Scene.SceneNode import SceneNode +from UM.Logger import Logger +from UM.Application import Application +class BuildPlateModel(ListModel): + maxBuildPlateChanged = pyqtSignal() + activeBuildPlateChanged = pyqtSignal() + + def __init__(self): + super().__init__() + Application.getInstance().getController().getScene().sceneChanged.connect(self.updateMaxBuildPlate) # it may be a bit inefficient when changing a lot simultaneously + + self._max_build_plate = 1 # default + self._active_build_plate = 0 + + @pyqtSlot(int) + def setActiveBuildPlate(self, nr): + if nr == self._active_build_plate: + return + Logger.log("d", "Select build plate: %s" % nr) + self._active_build_plate = nr + + self.activeBuildPlateChanged.emit() + + @pyqtProperty(int, notify = activeBuildPlateChanged) + def activeBuildPlate(self): + return self._active_build_plate + + ## Return the highest build plate number + @pyqtProperty(int, notify = maxBuildPlateChanged) + def maxBuildPlate(self): + return self._max_build_plate + + def updateMaxBuildPlate(self, source): + if not issubclass(type(source), SceneNode): + return + max_build_plate = self._calcMaxBuildPlate() + changed = False + if max_build_plate != self._max_build_plate: + self._max_build_plate = max_build_plate + changed = True + if changed: + self.maxBuildPlateChanged.emit() + build_plates = [{"name": "Build Plate %d" % (i + 1), "buildPlateNumber": i} for i in range(self._max_build_plate + 1)] + self.setItems(build_plates) + self.itemsChanged.emit() + + def _calcMaxBuildPlate(self): + max_build_plate = 0 + for node in DepthFirstIterator(Application.getInstance().getController().getScene().getRoot()): + if node.callDecoration("isSliceable"): + build_plate_number = node.callDecoration("getBuildPlateNumber") + max_build_plate = max(build_plate_number, max_build_plate) + return max_build_plate + + @staticmethod + def createBuildPlateModel(): + return BuildPlateModel() diff --git a/cura/ConvexHullNode.py b/cura/ConvexHullNode.py index c6ff80670d..cec9d3d698 100644 --- a/cura/ConvexHullNode.py +++ b/cura/ConvexHullNode.py @@ -64,7 +64,7 @@ class ConvexHullNode(SceneNode): ConvexHullNode.shader.setUniformValue("u_diffuseColor", self._color) ConvexHullNode.shader.setUniformValue("u_opacity", 0.6) - if self.getParent() and self.getParent().callDecoration("getBuildPlateNumber") == Application.getInstance().activeBuildPlate: + if self.getParent() and self.getParent().callDecoration("getBuildPlateNumber") == Application.getInstance().getBuildPlateModel().activeBuildPlate: if self.getMeshData(): renderer.queueNode(self, transparent = True, shader = ConvexHullNode.shader, backface_cull = True, sort = -8) if self._convex_hull_head_mesh: diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 7667d6dad8..08b81d568c 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -40,7 +40,6 @@ from cura.ConvexHullDecorator import ConvexHullDecorator from cura.SetParentOperation import SetParentOperation from cura.SliceableObjectDecorator import SliceableObjectDecorator from cura.BlockSlicingDecorator import BlockSlicingDecorator -# research from cura.Scene.BuildPlateDecorator import BuildPlateDecorator from cura.Scene.CuraSceneNode import CuraSceneNode @@ -83,6 +82,7 @@ from cura.Settings.GlobalStack import GlobalStack from cura.Settings.ExtruderStack import ExtruderStack from cura.ObjectManager import ObjectManager +from cura.BuildPlateModel import BuildPlateModel from PyQt5.QtCore import QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS from UM.FlameProfiler import pyqtSlot @@ -211,6 +211,7 @@ class CuraApplication(QtApplication): self._machine_manager = None # This is initialized on demand. self._material_manager = None self._object_manager = None + self._build_plate_model = None self._setting_inheritance_manager = None self._simple_mode_settings_manager = None @@ -258,7 +259,6 @@ class CuraApplication(QtApplication): self._i18n_catalog = i18nCatalog("cura") self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity) - self.getController().getScene().sceneChanged.connect(self.updateMaxBuildPlate) # it may be a bit inefficient when changing a lot simultaneously self.getController().toolOperationStopped.connect(self._onToolOperationStopped) self.getController().contextMenuRequested.connect(self._onContextMenuRequested) @@ -389,10 +389,6 @@ class CuraApplication(QtApplication): self._plugin_registry.addSupportedPluginExtension("curaplugin", "Cura Plugin") - # research - self._num_build_plates = 1 # default - self._active_build_plate = 0 - def _onEngineCreated(self): self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider()) @@ -724,8 +720,8 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 2, "SimpleModeSettingsManager", self.getSimpleModeSettingsManager) - Logger.log("d", " #### going to register object manager") qmlRegisterSingletonType(ObjectManager, "Cura", 1, 2, "ObjectManager", self.getObjectManager) + qmlRegisterSingletonType(BuildPlateModel, "Cura", 1, 2, "BuildPlateModel", self.getBuildPlateModel) qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) @@ -759,6 +755,11 @@ class CuraApplication(QtApplication): self._object_manager = ObjectManager.createObjectManager() return self._object_manager + def getBuildPlateModel(self, *args): + if self._build_plate_model is None: + self._build_plate_model = BuildPlateModel.createBuildPlateModel() + return self._build_plate_model + def getSettingInheritanceManager(self, *args): if self._setting_inheritance_manager is None: self._setting_inheritance_manager = SettingInheritanceManager.createSettingInheritanceManager() @@ -881,8 +882,6 @@ class CuraApplication(QtApplication): activityChanged = pyqtSignal() sceneBoundingBoxChanged = pyqtSignal() preferredOutputMimetypeChanged = pyqtSignal() - numBuildPlatesChanged = pyqtSignal() - activeBuildPlateChanged = pyqtSignal() @pyqtProperty(bool, notify = activityChanged) def platformActivity(self): @@ -1130,12 +1129,13 @@ class CuraApplication(QtApplication): nodes.append(node) job = ArrangeObjectsAllBuildPlatesJob(nodes) job.start() - self.setActiveBuildPlate(0) + self.getBuildPlateModel().setActiveBuildPlate(0) # Single build plate @pyqtSlot() def arrangeAll(self): nodes = [] + active_build_plate = self.getBuildPlateModel().activeBuildPlate for node in DepthFirstIterator(self.getController().getScene().getRoot()): if not issubclass(type(node), SceneNode): continue @@ -1147,7 +1147,7 @@ class CuraApplication(QtApplication): continue # i.e. node with layer data if not node.callDecoration("isSliceable"): continue # i.e. node with layer data - if node.callDecoration("getBuildPlateNumber") == self._active_build_plate: + if node.callDecoration("getBuildPlateNumber") == active_build_plate: # Skip nodes that are too big if node.getBoundingBox().width < self._volume.getBoundingBox().width or node.getBoundingBox().depth < self._volume.getBoundingBox().depth: nodes.append(node) @@ -1284,7 +1284,7 @@ class CuraApplication(QtApplication): group_decorator = GroupDecorator() group_node.addDecorator(group_decorator) group_node.addDecorator(ConvexHullDecorator()) - group_node.addDecorator(BuildPlateDecorator(self.activeBuildPlate)) + group_node.addDecorator(BuildPlateDecorator(self.getBuildPlateModel().activeBuildPlate)) group_node.setParent(self.getController().getScene().getRoot()) group_node.setSelectable(True) center = Selection.getSelectionCenter() @@ -1510,43 +1510,3 @@ class CuraApplication(QtApplication): node = node.getParent() Selection.add(node) - - #### research - hacky place for these kind of thing - @pyqtSlot(int) - def setActiveBuildPlate(self, nr): - if nr == self._active_build_plate: - return - Logger.log("d", "Select build plate: %s" % nr) - self._active_build_plate = nr - - self.activeBuildPlateChanged.emit() - - @pyqtSlot() - def newBuildPlate(self): - Logger.log("d", "New build plate") - #self._num_build_plates += 1 - self.numBuildPlatesChanged.emit() - - @pyqtProperty(int, notify = numBuildPlatesChanged) - def numBuildPlates(self): - return self._num_build_plates - - @pyqtProperty(int, notify = activeBuildPlateChanged) - def activeBuildPlate(self): - return self._active_build_plate - - def updateMaxBuildPlate(self, source): - if not issubclass(type(source), SceneNode): - return - num_build_plates = self._calcMaxBuildPlate() - if num_build_plates != self._num_build_plates: - self._num_build_plates = num_build_plates - self.numBuildPlatesChanged.emit() - - def _calcMaxBuildPlate(self): - max_build_plate = 0 - for node in DepthFirstIterator(self.getController().getScene().getRoot()): - if node.callDecoration("isSliceable"): - build_plate_number = node.callDecoration("getBuildPlateNumber") - max_build_plate = max(build_plate_number, max_build_plate) - return max_build_plate diff --git a/cura/ObjectManager.py b/cura/ObjectManager.py index a148c05f28..8361e43d71 100644 --- a/cura/ObjectManager.py +++ b/cura/ObjectManager.py @@ -15,14 +15,15 @@ class ObjectManager(ListModel): def __init__(self): super().__init__() self._last_selected_index = 0 - Application.getInstance().getController().getScene().sceneChanged.connect(self._update_scene_changed) + self._build_plate_model = Application.getInstance().getBuildPlateModel() + Application.getInstance().getController().getScene().sceneChanged.connect(self._update) Preferences.getInstance().preferenceChanged.connect(self._update) - Application.getInstance().activeBuildPlateChanged.connect(self._update) + self._build_plate_model.activeBuildPlateChanged.connect(self._update) def _update(self, *args): nodes = [] filter_current_build_plate = Preferences.getInstance().getValue("view/filter_current_build_plate") - active_build_plate_number = Application.getInstance().activeBuildPlate + active_build_plate_number = self._build_plate_model.activeBuildPlate for node in DepthFirstIterator(Application.getInstance().getController().getScene().getRoot()): if not issubclass(type(node), SceneNode) or (not node.getMeshData() and not node.callDecoration("getLayerData")): continue @@ -43,12 +44,6 @@ class ObjectManager(ListModel): self.itemsChanged.emit() - def _update_scene_changed(self, *args): - # if args and type(args[0]) is not CuraSceneNode: - # Logger.log("d", " ascdf %s", args) - # return - self._update(*args) - ## Either select or deselect an item @pyqtSlot(int) def changeSelection(self, index): @@ -77,7 +72,7 @@ class ObjectManager(ListModel): Selection.add(node) build_plate_number = node.callDecoration("getBuildPlateNumber") if build_plate_number is not None and build_plate_number != -1: - Application.getInstance().setActiveBuildPlate(build_plate_number) + self._build_plate_model.setActiveBuildPlate(build_plate_number) self._last_selected_index = index diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index ccec76b53d..e68405daf6 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -18,10 +18,10 @@ class CuraSceneNode(SceneNode): return self._outside_buildarea or self.callDecoration("getBuildPlateNumber") < 0 def isVisible(self): - return super().isVisible() and self.callDecoration("getBuildPlateNumber") == Application.getInstance().activeBuildPlate + return super().isVisible() and self.callDecoration("getBuildPlateNumber") == Application.getInstance().getBuildPlateModel().activeBuildPlate def isSelectable(self) -> bool: - return super().isSelectable() and self.callDecoration("getBuildPlateNumber") == Application.getInstance().activeBuildPlate + return super().isSelectable() and self.callDecoration("getBuildPlateNumber") == Application.getInstance().getBuildPlateModel().activeBuildPlate ## Taken from SceneNode, but replaced SceneNode with CuraSceneNode def __deepcopy__(self, memo): diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index f8b68e118a..c250b9019c 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -70,7 +70,7 @@ class CuraEngineBackend(QObject, Backend): # Workaround to disable layer view processing if layer view is not active. self._layer_view_active = False Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged) - Application.getInstance().activeBuildPlateChanged.connect(self._onActiveViewChanged) + Application.getInstance().getBuildPlateModel().activeBuildPlateChanged.connect(self._onActiveViewChanged) self._onActiveViewChanged() self._stored_layer_data = [] self._stored_optimized_layer_data = {} # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob @@ -564,7 +564,7 @@ class CuraEngineBackend(QObject, Backend): Logger.log("d", "Slicing took %s seconds", time() - self._slice_start_time ) # See if we need to process the sliced layers job. - active_build_plate = Application.getInstance().activeBuildPlate + active_build_plate = Application.getInstance().getBuildPlateModel().activeBuildPlate if self._layer_view_active and (self._process_layers_job is None or not self._process_layers_job.isRunning()) and active_build_plate == self._start_slice_job_build_plate: self._startProcessSlicedLayersJob(active_build_plate) # self._onActiveViewChanged() @@ -682,7 +682,7 @@ class CuraEngineBackend(QObject, Backend): application = Application.getInstance() view = application.getController().getActiveView() if view: - active_build_plate = application.activeBuildPlate + active_build_plate = application.getBuildPlateModel().activeBuildPlate if view.getPluginId() == "LayerView": # If switching to layer view, we should process the layers if that hasn't been done yet. self._layer_view_active = True # There is data and we're not slicing at the moment diff --git a/plugins/LayerView/LayerPass.py b/plugins/LayerView/LayerPass.py index 2b0e82d4b3..e6f60df723 100755 --- a/plugins/LayerView/LayerPass.py +++ b/plugins/LayerView/LayerPass.py @@ -66,7 +66,7 @@ class LayerPass(RenderPass): self.bind() tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Overlay) - active_build_plate = Application.getInstance().activeBuildPlate + active_build_plate = Application.getInstance().getBuildPlateModel().activeBuildPlate for node in DepthFirstIterator(self._scene.getRoot()): diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index 699cec23f5..973b513794 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -71,11 +71,9 @@ class SolidView(View): else: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) - activeBuildPlateNumber = Application.getInstance().activeBuildPlate - for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): - if node.getMeshData() and node.isVisible(): # and (node.callDecoration("getBuildPlateNumber") == activeBuildPlateNumber): + if node.getMeshData() and node.isVisible(): uniforms = {} shade_factor = 1.0 diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 29d8b439a8..1db6e2a511 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -324,6 +324,7 @@ UM.MainWindow } } + /* Button { id: openFileButton; @@ -339,17 +340,19 @@ UM.MainWindow } action: Cura.Actions.open; } + */ Button { id: objectsButton; text: catalog.i18nc("@action:button","Objects"); - iconSource: UM.Theme.getIcon("load") + iconSource: UM.Theme.getIcon("plus") style: UM.Theme.styles.tool_button tooltip: ''; anchors { - top: openFileButton.bottom; + top: topbar.bottom; + //top: openFileButton.bottom; topMargin: UM.Theme.getSize("default_margin").height; left: parent.left; } diff --git a/resources/qml/Menus/ContextMenu.qml b/resources/qml/Menus/ContextMenu.qml index 175410773e..2aa3bd6bdb 100644 --- a/resources/qml/Menus/ContextMenu.qml +++ b/resources/qml/Menus/ContextMenu.qml @@ -7,7 +7,7 @@ import QtQuick.Dialogs 1.2 import QtQuick.Window 2.1 import UM 1.2 as UM -import Cura 1.0 as Cura +import Cura 1.2 as Cura Menu { @@ -40,21 +40,21 @@ Menu } MenuSeparator {} - MenuItem { - text: "build plate 0"; - onTriggered: CuraActions.setBuildPlateForSelection(0); - checkable: true - checked: false + Instantiator + { + model: Cura.BuildPlateModel + MenuItem { + text: Cura.BuildPlateModel.getItem(index).name; + onTriggered: CuraActions.setBuildPlateForSelection(Cura.BuildPlateModel.getItem(index).buildPlateNumber); + checkable: true + checked: Cura.BuildPlateModel.getItem(index).buildPlateNumber == Cura.BuildPlateModel.activeBuildPlate + } + onObjectAdded: base.insertItem(index, object); + onObjectRemoved: base.removeItem(object) } MenuItem { - text: "build plate 1"; - onTriggered: CuraActions.setBuildPlateForSelection(1); - checkable: true - checked: false - } - MenuItem { - text: "build plate 2"; - onTriggered: CuraActions.setBuildPlateForSelection(2); + text: "New build plate"; + onTriggered: CuraActions.setBuildPlateForSelection(Cura.BuildPlateModel.maxBuildPlate + 1); checkable: true checked: false } diff --git a/resources/qml/Menus/ViewMenu.qml b/resources/qml/Menus/ViewMenu.qml index 3c5485da32..a78e465c85 100644 --- a/resources/qml/Menus/ViewMenu.qml +++ b/resources/qml/Menus/ViewMenu.qml @@ -5,12 +5,12 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import UM 1.2 as UM -import Cura 1.0 as Cura +import Cura 1.2 as Cura Menu { title: catalog.i18nc("@title:menu menubar:toplevel", "&View"); - id: menu + id: base enabled: !PrintInformation.preSliced Instantiator { @@ -23,30 +23,27 @@ Menu exclusiveGroup: group; onTriggered: UM.Controller.setActiveView(model.id); } - onObjectAdded: menu.insertItem(index, object) - onObjectRemoved: menu.removeItem(object) + onObjectAdded: base.insertItem(index, object) + onObjectRemoved: base.removeItem(object) } ExclusiveGroup { id: group; } MenuSeparator {} - MenuItem { - text: "build plate 0"; - onTriggered: CuraApplication.setActiveBuildPlate(0); - } - MenuItem { - text: "build plate 1"; - onTriggered: CuraApplication.setActiveBuildPlate(1); - } - MenuItem { - text: "build plate 2"; - onTriggered: CuraApplication.setActiveBuildPlate(2); + MenuItem { action: Cura.Actions.homeCamera; } + + MenuSeparator {} + Instantiator + { + model: Cura.BuildPlateModel + MenuItem { + text: Cura.BuildPlateModel.getItem(index).name; + onTriggered: Cura.BuildPlateModel.setActiveBuildPlate(Cura.BuildPlateModel.getItem(index).buildPlateNumber); + checkable: true; + checked: Cura.BuildPlateModel.getItem(index).buildPlateNumber == Cura.BuildPlateModel.activeBuildPlate; + exclusiveGroup: buildPlateGroup; + } + onObjectAdded: base.insertItem(index, object); + onObjectRemoved: base.removeItem(object) } ExclusiveGroup { id: buildPlateGroup; } - - MenuItem { - text: "New build plate"; - onTriggered: CuraApplication.newBuildPlate(); - } - MenuSeparator {} - MenuItem { action: Cura.Actions.homeCamera; } } diff --git a/resources/qml/ObjectsList.qml b/resources/qml/ObjectsList.qml index 4eeb0cd568..bf7d92c4d6 100644 --- a/resources/qml/ObjectsList.qml +++ b/resources/qml/ObjectsList.qml @@ -52,7 +52,6 @@ Rectangle id: nodeNameLabel anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width - //anchors.right: parent.right width: parent.width - 2 * UM.Theme.getSize("default_margin").width - 30 text: Cura.ObjectManager.getItem(index) ? Cura.ObjectManager.getItem(index).name : ""; color: Cura.ObjectManager.getItem(index).isSelected ? palette.highlightedText : (Cura.ObjectManager.getItem(index).isOutsideBuildArea ? palette.mid : palette.text) @@ -66,7 +65,7 @@ Rectangle anchors.left: nodeNameLabel.right anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.right: parent.right - text: Cura.ObjectManager.getItem(index) ? Cura.ObjectManager.getItem(index).buildPlateNumber : 0; + text: Cura.ObjectManager.getItem(index).buildPlateNumber != -1 ? Cura.ObjectManager.getItem(index).buildPlateNumber + 1 : ""; color: Cura.ObjectManager.getItem(index).isSelected ? palette.highlightedText : palette.text elide: Text.ElideRight } @@ -134,41 +133,22 @@ Rectangle } } - ListModel - { - id: buildPlatesModel - - ListElement - { - name: "build plate 0" - buildPlateNumber: 0 - } - ListElement - { - name: "build plate 1" - buildPlateNumber: 1 - } - ListElement - { - name: "build plate 2" - buildPlateNumber: 2 - } - } Component { id: buildPlateDelegate Rectangle { height: childrenRect.height - color: CuraApplication.activeBuildPlate == buildPlateNumber ? palette.highlight : index % 2 ? palette.base : palette.alternateBase + color: Cura.BuildPlateModel.getItem(index).buildPlateNumber == Cura.BuildPlateModel.activeBuildPlate ? palette.highlight : index % 2 ? palette.base : palette.alternateBase width: parent.width Label { + id: buildPlateNameLabel anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.right: parent.right - text: name //Cura.ObjectManager.getItem(index).name; - color: CuraApplication.activeBuildPlate == buildPlateNumber ? palette.highlightedText : palette.text + width: parent.width - 2 * UM.Theme.getSize("default_margin").width - 30 + text: Cura.BuildPlateModel.getItem(index) ? Cura.BuildPlateModel.getItem(index).name : ""; + color: Cura.BuildPlateModel.activeBuildPlate == index ? palette.highlightedText : palette.text elide: Text.ElideRight } @@ -177,7 +157,7 @@ Rectangle anchors.fill: parent; onClicked: { - CuraApplication.setActiveBuildPlate(buildPlateNumber); + Cura.BuildPlateModel.setActiveBuildPlate(index); } } } @@ -192,7 +172,6 @@ Rectangle anchors { - // top: objectsList.bottom; topMargin: UM.Theme.getSize("default_margin").height; left: parent.left; leftMargin: UM.Theme.getSize("default_margin").height; @@ -210,21 +189,8 @@ Rectangle ListView { id: buildPlateListView - model: buildPlatesModel - - onModelChanged: - { - //currentIndex = -1; - } + model: Cura.BuildPlateModel width: parent.width - currentIndex: -1 - onCurrentIndexChanged: - { - //base.selectedPrinter = listview.model[currentIndex]; - // Only allow connecting if the printer has responded to API query since the last refresh - //base.completeProperties = base.selectedPrinter != null && base.selectedPrinter.getProperty("incomplete") != "true"; - } - //Component.onCompleted: manager.startDiscovery() delegate: buildPlateDelegate } }