CURA-4525 automatic build plate menu items using BuildPlateModel

This commit is contained in:
Jack Ha 2017-11-14 14:27:46 +01:00
parent 97f61366a8
commit bd8aa8d989
12 changed files with 131 additions and 152 deletions

View file

@ -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()

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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):

View file

@ -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

View file

@ -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()):

View file

@ -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

View file

@ -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;
}

View file

@ -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 {}
Instantiator
{
model: Cura.BuildPlateModel
MenuItem {
text: "build plate 0";
onTriggered: CuraActions.setBuildPlateForSelection(0);
text: Cura.BuildPlateModel.getItem(index).name;
onTriggered: CuraActions.setBuildPlateForSelection(Cura.BuildPlateModel.getItem(index).buildPlateNumber);
checkable: true
checked: false
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
}

View file

@ -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 { action: Cura.Actions.homeCamera; }
MenuSeparator {}
Instantiator
{
model: Cura.BuildPlateModel
MenuItem {
text: "build plate 0";
onTriggered: CuraApplication.setActiveBuildPlate(0);
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;
}
MenuItem {
text: "build plate 1";
onTriggered: CuraApplication.setActiveBuildPlate(1);
}
MenuItem {
text: "build plate 2";
onTriggered: CuraApplication.setActiveBuildPlate(2);
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; }
}

View file

@ -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
}
}