CURA-4525 created CuraSceneController and took out logic from ObjectsModel and BuildPlateModel

This commit is contained in:
Jack Ha 2018-01-04 09:26:15 +01:00
parent 9e5f0e10b9
commit 8c7a0d4a8e
6 changed files with 187 additions and 145 deletions

View file

@ -1,7 +1,6 @@
from UM.Qt.ListModel import ListModel
from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode from UM.Qt.ListModel import ListModel
from UM.Scene.Selection import Selection from UM.Scene.Selection import Selection
from UM.Logger import Logger from UM.Logger import Logger
from UM.Application import Application from UM.Application import Application
@ -14,7 +13,6 @@ class BuildPlateModel(ListModel):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
Application.getInstance().getController().getScene().sceneChanged.connect(self.updateMaxBuildPlate) # it may be a bit inefficient when changing a lot simultaneously
Application.getInstance().getController().getScene().sceneChanged.connect(self._updateSelectedObjectBuildPlateNumbers) Application.getInstance().getController().getScene().sceneChanged.connect(self._updateSelectedObjectBuildPlateNumbers)
Selection.selectionChanged.connect(self._updateSelectedObjectBuildPlateNumbers) Selection.selectionChanged.connect(self._updateSelectedObjectBuildPlateNumbers)
@ -22,50 +20,22 @@ class BuildPlateModel(ListModel):
self._active_build_plate = -1 self._active_build_plate = -1
self._selection_build_plates = [] self._selection_build_plates = []
@pyqtSlot(int) def setMaxBuildPlate(self, max_build_plate):
def setActiveBuildPlate(self, nr): self._max_build_plate = max_build_plate
if nr == self._active_build_plate: self.maxBuildPlateChanged.emit()
return
Logger.log("d", "Select build plate: %s" % nr)
self._active_build_plate = nr
Selection.clear()
self.activeBuildPlateChanged.emit()
@pyqtProperty(int, notify = activeBuildPlateChanged)
def activeBuildPlate(self):
return self._active_build_plate
## Return the highest build plate number ## Return the highest build plate number
@pyqtProperty(int, notify = maxBuildPlateChanged) @pyqtProperty(int, notify = maxBuildPlateChanged)
def maxBuildPlate(self): def maxBuildPlate(self):
return self._max_build_plate return self._max_build_plate
def updateMaxBuildPlate(self, *args): def setActiveBuildPlate(self, nr):
if args: self._active_build_plate = nr
source = args[0] self.activeBuildPlateChanged.emit()
else:
source = None
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): @pyqtProperty(int, notify = activeBuildPlateChanged)
max_build_plate = 0 def activeBuildPlate(self):
for node in DepthFirstIterator(Application.getInstance().getController().getScene().getRoot()): return self._active_build_plate
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 @staticmethod
def createBuildPlateModel(): def createBuildPlateModel():

View file

@ -33,7 +33,10 @@ from UM.Operations.GroupedOperation import GroupedOperation
from UM.Operations.SetTransformOperation import SetTransformOperation from UM.Operations.SetTransformOperation import SetTransformOperation
from cura.Arranging.Arrange import Arrange from cura.Arranging.Arrange import Arrange
from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob
from cura.Arranging.ArrangeObjectsAllBuildPlatesJob import ArrangeObjectsAllBuildPlatesJob
from cura.Arranging.ShapeArray import ShapeArray from cura.Arranging.ShapeArray import ShapeArray
from cura.MultiplyObjectsJob import MultiplyObjectsJob
from cura.Scene.ConvexHullDecorator import ConvexHullDecorator from cura.Scene.ConvexHullDecorator import ConvexHullDecorator
from cura.Operations.SetParentOperation import SetParentOperation from cura.Operations.SetParentOperation import SetParentOperation
from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator
@ -41,9 +44,7 @@ from cura.Scene.BlockSlicingDecorator import BlockSlicingDecorator
from cura.Scene.BuildPlateDecorator import BuildPlateDecorator from cura.Scene.BuildPlateDecorator import BuildPlateDecorator
from cura.Scene.CuraSceneNode import CuraSceneNode from cura.Scene.CuraSceneNode import CuraSceneNode
from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob from cura.CuraSceneController import CuraSceneController
from cura.Arranging.ArrangeObjectsAllBuildPlatesJob import ArrangeObjectsAllBuildPlatesJob
from cura.MultiplyObjectsJob import MultiplyObjectsJob
from UM.Settings.SettingDefinition import SettingDefinition, DefinitionPropertyType from UM.Settings.SettingDefinition import SettingDefinition, DefinitionPropertyType
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
@ -77,7 +78,7 @@ from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisi
from cura.Settings.QualitySettingsModel import QualitySettingsModel from cura.Settings.QualitySettingsModel import QualitySettingsModel
from cura.Settings.ContainerManager import ContainerManager from cura.Settings.ContainerManager import ContainerManager
from cura.ObjectManager import ObjectManager from cura.ObjectsModel import ObjectsModel
from cura.BuildPlateModel import BuildPlateModel from cura.BuildPlateModel import BuildPlateModel
from PyQt5.QtCore import QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS from PyQt5.QtCore import QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
@ -211,6 +212,7 @@ class CuraApplication(QtApplication):
self._build_plate_model = None self._build_plate_model = None
self._setting_inheritance_manager = None self._setting_inheritance_manager = None
self._simple_mode_settings_manager = None self._simple_mode_settings_manager = None
self._cura_scene_controller = None
self._additional_components = {} # Components to add to certain areas in the interface self._additional_components = {} # Components to add to certain areas in the interface
@ -398,6 +400,8 @@ class CuraApplication(QtApplication):
self._plugin_registry.addSupportedPluginExtension("curaplugin", "Cura Plugin") self._plugin_registry.addSupportedPluginExtension("curaplugin", "Cura Plugin")
self.getCuraSceneController().setActiveBuildPlate(0) # Initialize
def _onEngineCreated(self): def _onEngineCreated(self):
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider()) self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
@ -699,8 +703,9 @@ class CuraApplication(QtApplication):
qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 2, "SimpleModeSettingsManager", qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 2, "SimpleModeSettingsManager",
self.getSimpleModeSettingsManager) self.getSimpleModeSettingsManager)
qmlRegisterSingletonType(ObjectManager, "Cura", 1, 2, "ObjectManager", self.getObjectManager) qmlRegisterSingletonType(ObjectsModel, "Cura", 1, 2, "ObjectsModel", self.getObjectsModel)
qmlRegisterSingletonType(BuildPlateModel, "Cura", 1, 2, "BuildPlateModel", self.getBuildPlateModel) qmlRegisterSingletonType(BuildPlateModel, "Cura", 1, 2, "BuildPlateModel", self.getBuildPlateModel)
qmlRegisterSingletonType(CuraSceneController, "Cura", 1, 2, "SceneController", self.getCuraSceneController)
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager)
@ -739,18 +744,22 @@ class CuraApplication(QtApplication):
self._material_manager = MaterialManager.createMaterialManager() self._material_manager = MaterialManager.createMaterialManager()
return self._material_manager return self._material_manager
def getObjectManager(self, *args): def getObjectsModel(self, *args):
if self._object_manager is None: if self._object_manager is None:
self._object_manager = ObjectManager.createObjectManager() self._object_manager = ObjectsModel.createObjectsModel()
return self._object_manager return self._object_manager
def getBuildPlateModel(self, *args): def getBuildPlateModel(self, *args):
if self._build_plate_model is None: if self._build_plate_model is None:
self._build_plate_model = BuildPlateModel.createBuildPlateModel() self._build_plate_model = BuildPlateModel.createBuildPlateModel()
self._build_plate_model.setActiveBuildPlate(0) # default value
return self._build_plate_model return self._build_plate_model
def getCuraSceneController(self, *args):
if self._cura_scene_controller is None:
self._cura_scene_controller = CuraSceneController.createCuraSceneController()
return self._cura_scene_controller
def getSettingInheritanceManager(self, *args): def getSettingInheritanceManager(self, *args):
if self._setting_inheritance_manager is None: if self._setting_inheritance_manager is None:
self._setting_inheritance_manager = SettingInheritanceManager.createSettingInheritanceManager() self._setting_inheritance_manager = SettingInheritanceManager.createSettingInheritanceManager()
@ -1115,7 +1124,7 @@ class CuraApplication(QtApplication):
nodes.append(node) nodes.append(node)
job = ArrangeObjectsAllBuildPlatesJob(nodes) job = ArrangeObjectsAllBuildPlatesJob(nodes)
job.start() job.start()
self.getBuildPlateModel().setActiveBuildPlate(0) self.getCuraSceneController().setActiveBuildPlate(0) # Initialize
# Single build plate # Single build plate
@pyqtSlot() @pyqtSlot()

101
cura/CuraSceneController.py Normal file
View file

@ -0,0 +1,101 @@
from UM.Logger import Logger
from PyQt5.QtCore import Qt, pyqtSlot, QObject
from PyQt5.QtWidgets import QApplication
from cura.ObjectsModel import ObjectsModel
from cura.BuildPlateModel import BuildPlateModel
from UM.Application import Application
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.Scene.Selection import Selection
class CuraSceneController(QObject):
def __init__(self, objects_model: ObjectsModel, build_plate_model: BuildPlateModel):
super().__init__()
self._objects_model = objects_model
self._build_plate_model = build_plate_model
self._active_build_plate = -1
self._last_selected_index = 0
self._max_build_plate = 1 # default
Application.getInstance().getController().getScene().sceneChanged.connect(self.updateMaxBuildPlate) # it may be a bit inefficient when changing a lot simultaneously
def updateMaxBuildPlate(self, *args):
if args:
source = args[0]
else:
source = None
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._build_plate_model.setMaxBuildPlate(self._max_build_plate)
build_plates = [{"name": "Build Plate %d" % (i + 1), "buildPlateNumber": i} for i in range(self._max_build_plate + 1)]
self._build_plate_model.setItems(build_plates)
# self.buildPlateItemsChanged.emit() # TODO: necessary after setItems?
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
## Either select or deselect an item
@pyqtSlot(int)
def changeSelection(self, index):
modifiers = QApplication.keyboardModifiers()
ctrl_is_active = modifiers & Qt.ControlModifier
shift_is_active = modifiers & Qt.ShiftModifier
if ctrl_is_active:
item = self._objects_model.getItem(index)
node = item["node"]
if Selection.isSelected(node):
Selection.remove(node)
else:
Selection.add(node)
elif shift_is_active:
polarity = 1 if index + 1 > self._last_selected_index else -1
for i in range(self._last_selected_index, index + polarity, polarity):
item = self._objects_model.getItem(i)
node = item["node"]
Selection.add(node)
else:
# Single select
item = self._objects_model.getItem(index)
node = item["node"]
Selection.clear()
Selection.add(node)
build_plate_number = node.callDecoration("getBuildPlateNumber")
if build_plate_number is not None and build_plate_number != -1:
self._build_plate_model.setActiveBuildPlate(build_plate_number)
self._last_selected_index = index
@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
Selection.clear()
self._build_plate_model.setActiveBuildPlate(nr)
self._objects_model.setActiveBuildPlate(nr)
@staticmethod
def createCuraSceneController():
objects_model = Application.getInstance().getObjectsModel()
build_plate_model = Application.getInstance().getBuildPlateModel()
return CuraSceneController(objects_model = objects_model, build_plate_model = build_plate_model)

View file

@ -1,87 +0,0 @@
from UM.Logger import Logger
from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot
from UM.Application import Application
from UM.Qt.ListModel import ListModel
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.Scene.Selection import Selection
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication
#from cura.Scene.CuraSceneNode import CuraSceneNode
from UM.Preferences import Preferences
## Keep track of all objects in the project
class ObjectManager(ListModel):
def __init__(self):
super().__init__()
self._last_selected_index = 0
self._build_plate_model = Application.getInstance().getBuildPlateModel()
Application.getInstance().getController().getScene().sceneChanged.connect(self._update)
Preferences.getInstance().preferenceChanged.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 = 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
if not node.callDecoration("isSliceable"):
continue
node_build_plate_number = node.callDecoration("getBuildPlateNumber")
if filter_current_build_plate and node_build_plate_number != active_build_plate_number:
continue
nodes.append({
"name": node.getName(),
"isSelected": Selection.isSelected(node),
"isOutsideBuildArea": node.isOutsideBuildArea(),
"buildPlateNumber": node_build_plate_number,
"node": node
})
nodes = sorted(nodes, key=lambda n: n["name"])
self.setItems(nodes)
self.itemsChanged.emit()
## Either select or deselect an item
@pyqtSlot(int)
def changeSelection(self, index):
modifiers = QApplication.keyboardModifiers()
ctrl_is_active = modifiers & Qt.ControlModifier
shift_is_active = modifiers & Qt.ShiftModifier
if ctrl_is_active:
item = self.getItem(index)
node = item["node"]
if Selection.isSelected(node):
Selection.remove(node)
else:
Selection.add(node)
elif shift_is_active:
polarity = 1 if index + 1 > self._last_selected_index else -1
for i in range(self._last_selected_index, index + polarity, polarity):
item = self.getItem(i)
node = item["node"]
Selection.add(node)
else:
# Single select
item = self.getItem(index)
node = item["node"]
Selection.clear()
Selection.add(node)
build_plate_number = node.callDecoration("getBuildPlateNumber")
if build_plate_number is not None and build_plate_number != -1:
self._build_plate_model.setActiveBuildPlate(build_plate_number)
self._last_selected_index = index
# testing
for node in DepthFirstIterator(Application.getInstance().getController().getScene().getRoot()):
if node.callDecoration("getLayerData"):
Logger.log("d", " ##### NODE: %s", node)
@staticmethod
def createObjectManager():
return ObjectManager()

49
cura/ObjectsModel.py Normal file
View file

@ -0,0 +1,49 @@
from UM.Application import Application
from UM.Qt.ListModel import ListModel
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.Scene.Selection import Selection
from UM.Preferences import Preferences
## Keep track of all objects in the project
class ObjectsModel(ListModel):
def __init__(self):
super().__init__()
Application.getInstance().getController().getScene().sceneChanged.connect(self._update)
Preferences.getInstance().preferenceChanged.connect(self._update)
self._build_plate_number = -1
def setActiveBuildPlate(self, nr):
self._build_plate_number = nr
self._update()
def _update(self, *args):
nodes = []
filter_current_build_plate = Preferences.getInstance().getValue("view/filter_current_build_plate")
active_build_plate_number = self._build_plate_number
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
if not node.callDecoration("isSliceable"):
continue
node_build_plate_number = node.callDecoration("getBuildPlateNumber")
if filter_current_build_plate and node_build_plate_number != active_build_plate_number:
continue
nodes.append({
"name": node.getName(),
"isSelected": Selection.isSelected(node),
"isOutsideBuildArea": node.isOutsideBuildArea(),
"buildPlateNumber": node_build_plate_number,
"node": node
})
nodes = sorted(nodes, key=lambda n: n["name"])
self.setItems(nodes)
self.itemsChanged.emit()
@staticmethod
def createObjectsModel():
return ObjectsModel()

View file

@ -85,7 +85,7 @@ Rectangle
anchors.fill: parent; anchors.fill: parent;
onClicked: onClicked:
{ {
Cura.BuildPlateModel.setActiveBuildPlate(index); Cura.SceneController.setActiveBuildPlate(index);
} }
} }
} }
@ -131,7 +131,7 @@ Rectangle
Rectangle Rectangle
{ {
height: childrenRect.height height: childrenRect.height
color: Cura.ObjectManager.getItem(index).isSelected ? palette.highlight : index % 2 ? palette.base : palette.alternateBase color: Cura.ObjectsModel.getItem(index).isSelected ? palette.highlight : index % 2 ? palette.base : palette.alternateBase
width: parent.width width: parent.width
Label Label
{ {
@ -139,8 +139,8 @@ Rectangle
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.leftMargin: UM.Theme.getSize("default_margin").width
width: parent.width - 2 * UM.Theme.getSize("default_margin").width - 30 width: parent.width - 2 * UM.Theme.getSize("default_margin").width - 30
text: Cura.ObjectManager.getItem(index) ? Cura.ObjectManager.getItem(index).name : ""; text: Cura.ObjectsModel.getItem(index) ? Cura.ObjectsModel.getItem(index).name : "";
color: Cura.ObjectManager.getItem(index).isSelected ? palette.highlightedText : (Cura.ObjectManager.getItem(index).isOutsideBuildArea ? palette.mid : palette.text) color: Cura.ObjectsModel.getItem(index).isSelected ? palette.highlightedText : (Cura.ObjectsModel.getItem(index).isOutsideBuildArea ? palette.mid : palette.text)
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -151,8 +151,8 @@ Rectangle
anchors.left: nodeNameLabel.right anchors.left: nodeNameLabel.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: parent.right anchors.right: parent.right
text: Cura.ObjectManager.getItem(index).buildPlateNumber != -1 ? Cura.ObjectManager.getItem(index).buildPlateNumber + 1 : ""; text: Cura.ObjectsModel.getItem(index).buildPlateNumber != -1 ? Cura.ObjectsModel.getItem(index).buildPlateNumber + 1 : "";
color: Cura.ObjectManager.getItem(index).isSelected ? palette.highlightedText : palette.text color: Cura.ObjectsModel.getItem(index).isSelected ? palette.highlightedText : palette.text
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -161,7 +161,7 @@ Rectangle
anchors.fill: parent; anchors.fill: parent;
onClicked: onClicked:
{ {
Cura.ObjectManager.changeSelection(index); Cura.SceneController.changeSelection(index);
} }
} }
} }
@ -195,7 +195,7 @@ Rectangle
ListView ListView
{ {
id: listview id: listview
model: Cura.ObjectManager model: Cura.ObjectsModel
width: parent.width width: parent.width
delegate: objectDelegate delegate: objectDelegate
} }