Merge branch 'master' into feature_accelerations_and_jerk_per_feature_settigns_rework

This commit is contained in:
Tim Kuipers 2016-06-10 12:29:06 +02:00
commit 149af8af28
119 changed files with 3484 additions and 1784 deletions

9
.gitignore vendored
View File

@ -7,6 +7,7 @@ docs/html
*.log *.log
resources/i18n/en resources/i18n/en
resources/i18n/x-test resources/i18n/x-test
resources/firmware
# Editors and IDEs. # Editors and IDEs.
*kdev* *kdev*
@ -15,3 +16,11 @@ resources/i18n/x-test
*~ *~
*.qm *.qm
.idea .idea
# Eclipse+PyDev
.project
.pydevproject
.settings
# Debian packaging
debian*

View File

@ -7,6 +7,7 @@ include(GNUInstallDirs)
set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository") set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository")
set(CURA_VERSION "master" CACHE STRING "Version name of Cura") set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")
configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY) configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY)
# Macro needed to list all sub-directory of a directory. # Macro needed to list all sub-directory of a directory.

View File

@ -0,0 +1,93 @@
from UM.Application import Application
from UM.Qt.ListModel import ListModel
from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.SettingFunction import SettingFunction
class ContainerSettingsModel(ListModel):
LabelRole = Qt.UserRole + 1
CategoryRole = Qt.UserRole + 2
UnitRole = Qt.UserRole + 3
ValuesRole = Qt.UserRole + 4
def __init__(self, parent = None):
super().__init__(parent)
self.addRoleName(self.LabelRole, "label")
self.addRoleName(self.CategoryRole, "category")
self.addRoleName(self.UnitRole, "unit")
self.addRoleName(self.ValuesRole, "values")
self._container_ids = []
self._containers = []
def _onPropertyChanged(self, key, property_name):
if property_name == "value":
self._update()
def _update(self):
self.clear()
if len(self._container_ids) == 0:
return
keys = []
for container in self._containers:
keys = keys + list(container.getAllKeys())
keys = list(set(keys)) # remove duplicate keys
keys.sort()
for key in keys:
definition = None
category = None
values = []
for container in self._containers:
instance = container.getInstance(key)
if instance:
definition = instance.definition
# Traverse up to find the category
category = definition
while category.type != "category":
category = category.parent
value = container.getProperty(key, "value")
if type(value) == SettingFunction:
values.append("=\u0192")
else:
values.append(container.getProperty(key, "value"))
else:
values.append("")
self.appendItem({
"key": key,
"values": values,
"label": definition.label,
"unit": definition.unit,
"category": category.label
})
## Set the ids of the containers which have the settings this model should list.
# Also makes sure the model updates when the containers have property changes
def setContainers(self, container_ids):
for container in self._containers:
container.propertyChanged.disconnect(self._onPropertyChanged)
self._container_ids = container_ids
self._containers = []
for container_id in self._container_ids:
containers = ContainerRegistry.getInstance().findContainers(id = container_id)
if containers:
containers[0].propertyChanged.connect(self._onPropertyChanged)
self._containers.append(containers[0])
self._update()
containersChanged = pyqtSignal()
@pyqtProperty("QVariantList", fset = setContainers, notify = containersChanged)
def containers(self):
return self.container_ids

View File

@ -27,7 +27,9 @@ class ConvexHullDecorator(SceneNodeDecorator):
# Keep track of the previous parent so we can clear its convex hull when the object is reparented # Keep track of the previous parent so we can clear its convex hull when the object is reparented
self._parent_node = None self._parent_node = None
self._profile = None self._global_stack = None
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
self._onGlobalStackChanged()
#Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged) #Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
#Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveMachineInstanceChanged) #Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveMachineInstanceChanged)
#self._onActiveProfileChanged() #self._onActiveProfileChanged()
@ -95,22 +97,11 @@ class ConvexHullDecorator(SceneNodeDecorator):
def setConvexHullNode(self, node): def setConvexHullNode(self, node):
self._convex_hull_node = node self._convex_hull_node = node
def _onActiveProfileChanged(self): def _onSettingValueChanged(self, key, property_name):
if self._profile: if key == "print_sequence" and property_name == "value":
self._profile.settingValueChanged.disconnect(self._onSettingValueChanged) self._onChanged()
self._profile = Application.getInstance().getMachineManager().getWorkingProfile() def _onChanged(self, *args):
if self._profile:
self._profile.settingValueChanged.connect(self._onSettingValueChanged)
def _onActiveMachineInstanceChanged(self):
if self._convex_hull_job:
self._convex_hull_job.cancel()
self.setConvexHull(None)
def _onSettingValueChanged(self, setting):
if setting == "print_sequence":
if self._convex_hull_job: if self._convex_hull_job:
self._convex_hull_job.cancel() self._convex_hull_job.cancel()
self.setConvexHull(None) self.setConvexHull(None)
@ -120,3 +111,16 @@ class ConvexHullDecorator(SceneNodeDecorator):
if self._parent_node and self._parent_node.callDecoration("isGroup"): if self._parent_node and self._parent_node.callDecoration("isGroup"):
self._parent_node.callDecoration("setConvexHull", None) self._parent_node.callDecoration("setConvexHull", None)
self._parent_node = self.getNode().getParent() self._parent_node = self.getNode().getParent()
def _onGlobalStackChanged(self):
if self._global_stack:
self._global_stack.propertyChanged.disconnect(self._onSettingValueChanged)
self._global_stack.containersChanged.disconnect(self._onChanged)
self._global_stack = Application.getInstance().getGlobalContainerStack()
if self._global_stack:
self._global_stack.propertyChanged.connect(self._onSettingValueChanged)
self._global_stack.containersChanged.connect(self._onChanged)
self._onChanged()

View File

@ -18,6 +18,7 @@ from UM.JobQueue import JobQueue
from UM.SaveFile import SaveFile from UM.SaveFile import SaveFile
from UM.Scene.Selection import Selection from UM.Scene.Selection import Selection
from UM.Scene.GroupDecorator import GroupDecorator from UM.Scene.GroupDecorator import GroupDecorator
import UM.Settings.Validator
from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
@ -30,6 +31,8 @@ from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from . import ExtruderManager
from . import ExtrudersModel
from . import PlatformPhysics from . import PlatformPhysics
from . import BuildVolume from . import BuildVolume
from . import CameraAnimation from . import CameraAnimation
@ -39,11 +42,13 @@ from . import MultiMaterialDecorator
from . import ZOffsetDecorator from . import ZOffsetDecorator
from . import CuraSplashScreen from . import CuraSplashScreen
from . import MachineManagerModel from . import MachineManagerModel
from . import ContainerSettingsModel
from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
from PyQt5.QtGui import QColor, QIcon from PyQt5.QtGui import QColor, QIcon
from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
import ast #For literal eval of extruder setting types.
import platform import platform
import sys import sys
import os.path import os.path
@ -61,9 +66,10 @@ if platform.system() == "Linux": # Needed for platform.linux_distribution, which
ctypes.CDLL(find_library('GL'), ctypes.RTLD_GLOBAL) ctypes.CDLL(find_library('GL'), ctypes.RTLD_GLOBAL)
try: try:
from cura.CuraVersion import CuraVersion from cura.CuraVersion import CuraVersion, CuraBuildType
except ImportError: except ImportError:
CuraVersion = "master" # [CodeStyle: Reflecting imported value] CuraVersion = "master" # [CodeStyle: Reflecting imported value]
CuraBuildType = ""
class CuraApplication(QtApplication): class CuraApplication(QtApplication):
@ -87,9 +93,13 @@ class CuraApplication(QtApplication):
self._open_file_queue = [] # Files to open when plug-ins are loaded. self._open_file_queue = [] # Files to open when plug-ins are loaded.
# Need to do this before ContainerRegistry tries to load the machines # Need to do this before ContainerRegistry tries to load the machines
SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False) SettingDefinition.addSupportedProperty("settable_per_mesh", DefinitionPropertyType.Any, default = True)
SettingDefinition.addSupportedProperty("settable_per_extruder", DefinitionPropertyType.Any, default = True)
SettingDefinition.addSupportedProperty("settable_per_meshgroup", DefinitionPropertyType.Any, default = True)
SettingDefinition.addSupportedProperty("settable_globally", DefinitionPropertyType.Any, default = True)
SettingDefinition.addSettingType("extruder", int, str, UM.Settings.Validator)
super().__init__(name = "cura", version = CuraVersion) super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType)
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
@ -116,6 +126,7 @@ class CuraApplication(QtApplication):
self._center_after_select = False self._center_after_select = False
self._camera_animation = None self._camera_animation = None
self._cura_actions = None self._cura_actions = None
self._started = False
self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity) self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity)
self.getController().toolOperationStopped.connect(self._onToolOperationStopped) self.getController().toolOperationStopped.connect(self._onToolOperationStopped)
@ -127,17 +138,34 @@ class CuraApplication(QtApplication):
Resources.addStorageType(self.ResourceTypes.QualityInstanceContainer, "quality") Resources.addStorageType(self.ResourceTypes.QualityInstanceContainer, "quality")
Resources.addStorageType(self.ResourceTypes.VariantInstanceContainer, "variants") Resources.addStorageType(self.ResourceTypes.VariantInstanceContainer, "variants")
Resources.addStorageType(self.ResourceTypes.MaterialInstanceContainer, "materials") Resources.addStorageType(self.ResourceTypes.MaterialInstanceContainer, "materials")
Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders")
Resources.addStorageType(self.ResourceTypes.UserInstanceContainer, "user") Resources.addStorageType(self.ResourceTypes.UserInstanceContainer, "user")
Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders")
Resources.addStorageType(self.ResourceTypes.MachineStack, "machine_instances") Resources.addStorageType(self.ResourceTypes.MachineStack, "machine_instances")
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.VariantInstanceContainer) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.VariantInstanceContainer)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MaterialInstanceContainer) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MaterialInstanceContainer)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.ExtruderStack)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.UserInstanceContainer) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.UserInstanceContainer)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.ExtruderStack)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MachineStack) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MachineStack)
# Add empty variant, material and quality containers.
# Since they are empty, they should never be serialized and instead just programmatically created.
# We need them to simplify the switching between materials.
empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
empty_variant_container = copy.deepcopy(empty_container)
empty_variant_container._id = "empty_variant"
empty_variant_container.addMetaDataEntry("type", "variant")
ContainerRegistry.getInstance().addContainer(empty_variant_container)
empty_material_container = copy.deepcopy(empty_container)
empty_material_container._id = "empty_material"
empty_material_container.addMetaDataEntry("type", "material")
ContainerRegistry.getInstance().addContainer(empty_material_container)
empty_quality_container = copy.deepcopy(empty_container)
empty_quality_container._id = "empty_quality"
empty_quality_container.addMetaDataEntry("type", "quality")
ContainerRegistry.getInstance().addContainer(empty_quality_container)
ContainerRegistry.getInstance().load() ContainerRegistry.getInstance().load()
Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/active_mode", "simple")
@ -192,7 +220,7 @@ class CuraApplication(QtApplication):
JobQueue.getInstance().jobFinished.connect(self._onJobFinished) JobQueue.getInstance().jobFinished.connect(self._onJobFinished)
self.applicationShuttingDown.connect(self._onExit) self.applicationShuttingDown.connect(self.saveSettings)
self._recent_files = [] self._recent_files = []
files = Preferences.getInstance().getValue("cura/recent_files").split(";") files = Preferences.getInstance().getValue("cura/recent_files").split(";")
@ -203,7 +231,12 @@ class CuraApplication(QtApplication):
self._recent_files.append(QUrl.fromLocalFile(f)) self._recent_files.append(QUrl.fromLocalFile(f))
## Cura has multiple locations where instance containers need to be saved, so we need to handle this differently. ## Cura has multiple locations where instance containers need to be saved, so we need to handle this differently.
def _onExit(self): #
# Note that the AutoSave plugin also calls this method.
def saveSettings(self):
if not self._started: # Do not do saving during application start
return
for instance in ContainerRegistry.getInstance().findInstanceContainers(): for instance in ContainerRegistry.getInstance().findInstanceContainers():
if not instance.isDirty(): if not instance.isDirty():
continue continue
@ -245,7 +278,13 @@ class CuraApplication(QtApplication):
continue continue
file_name = urllib.parse.quote_plus(stack.getId()) + ".stack.cfg" file_name = urllib.parse.quote_plus(stack.getId()) + ".stack.cfg"
stack_type = stack.getMetaDataEntry("type", None)
path = None
if not stack_type or stack_type == "machine":
path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name) path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name)
elif stack_type == "extruder":
path = Resources.getStoragePath(self.ResourceTypes.ExtruderStack, file_name)
if path:
with SaveFile(path, "wt", -1, "utf-8") as f: with SaveFile(path, "wt", -1, "utf-8") as f:
f.write(data) f.write(data)
@ -258,6 +297,7 @@ class CuraApplication(QtApplication):
# \sa PluginRegistery # \sa PluginRegistery
def _loadPlugins(self): def _loadPlugins(self):
self._plugin_registry.addType("profile_reader", self._addProfileReader) self._plugin_registry.addType("profile_reader", self._addProfileReader)
self._plugin_registry.addType("profile_writer", self._addProfileWriter)
self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura")) self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura"))
if not hasattr(sys, "frozen"): if not hasattr(sys, "frozen"):
self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins")) self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins"))
@ -320,6 +360,7 @@ class CuraApplication(QtApplication):
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface..."))
ExtruderManager.ExtruderManager.getInstance() #Initialise extruder so as to listen to global container stack changes before the first global container stack is set.
qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager",
MachineManagerModel.createMachineManagerModel) MachineManagerModel.createMachineManagerModel)
@ -335,6 +376,8 @@ class CuraApplication(QtApplication):
for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading. for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading.
self._openFile(file_name) self._openFile(file_name)
self._started = True
self.exec_() self.exec_()
## Handle Qt events ## Handle Qt events
@ -351,6 +394,9 @@ class CuraApplication(QtApplication):
def getPrintInformation(self): def getPrintInformation(self):
return self._print_information return self._print_information
## Registers objects for the QML engine to use.
#
# \param engine The QML engine.
def registerObjects(self, engine): def registerObjects(self, engine):
engine.rootContext().setContextProperty("Printer", self) engine.rootContext().setContextProperty("Printer", self)
self._print_information = PrintInformation.PrintInformation() self._print_information = PrintInformation.PrintInformation()
@ -360,6 +406,21 @@ class CuraApplication(QtApplication):
qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type")
qmlRegisterType(ExtrudersModel.ExtrudersModel, "Cura", 1, 0, "ExtrudersModel")
qmlRegisterType(ContainerSettingsModel.ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel")
qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions")
engine.rootContext().setContextProperty("ExtruderManager", ExtruderManager.ExtruderManager.getInstance())
for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles):
type_name = os.path.splitext(os.path.basename(path))[0]
if type_name in ("Cura", "Actions"):
continue
qmlRegisterType(QUrl.fromLocalFile(path), "Cura", 1, 0, type_name)
def onSelectionChanged(self): def onSelectionChanged(self):
if Selection.hasSelection(): if Selection.hasSelection():
if not self.getController().getActiveTool(): if not self.getController().getActiveTool():
@ -419,21 +480,6 @@ class CuraApplication(QtApplication):
self._platform_activity = True if count > 0 else False self._platform_activity = True if count > 0 else False
self.activityChanged.emit() self.activityChanged.emit()
@pyqtSlot(str)
def setJobName(self, name):
# when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its
# extension. This cuts the extension off if necessary.
name = os.path.splitext(name)[0]
if self._job_name != name:
self._job_name = name
self.jobNameChanged.emit()
jobNameChanged = pyqtSignal()
@pyqtProperty(str, notify = jobNameChanged)
def jobName(self):
return self._job_name
# Remove all selected objects from the scene. # Remove all selected objects from the scene.
@pyqtSlot() @pyqtSlot()
def deleteSelection(self): def deleteSelection(self):
@ -702,10 +748,12 @@ class CuraApplication(QtApplication):
def _onActiveMachineChanged(self): def _onActiveMachineChanged(self):
pass pass
fileLoaded = pyqtSignal(str)
def _onFileLoaded(self, job): def _onFileLoaded(self, job):
node = job.getResult() node = job.getResult()
if node != None: if node != None:
self.setJobName(os.path.basename(job.getFileName())) self.fileLoaded.emit(job.getFileName())
node.setSelectable(True) node.setSelectable(True)
node.setName(os.path.basename(job.getFileName())) node.setName(os.path.basename(job.getFileName()))
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot()) op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
@ -744,3 +792,6 @@ class CuraApplication(QtApplication):
def _addProfileReader(self, profile_reader): def _addProfileReader(self, profile_reader):
# TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles. # TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles.
pass pass
def _addProfileWriter(self, profile_writer):
pass

View File

@ -21,6 +21,9 @@ class CuraSplashScreen(QSplashScreen):
painter.setPen(QColor(0, 0, 0, 255)) painter.setPen(QColor(0, 0, 0, 255))
version = Application.getInstance().getVersion().split("-") version = Application.getInstance().getVersion().split("-")
buildtype = Application.getInstance().getBuildType()
if buildtype:
version[0] += " (%s)" %(buildtype)
painter.setFont(QFont("Proxima Nova Rg", 20 )) painter.setFont(QFont("Proxima Nova Rg", 20 ))
painter.drawText(0, 0, 330 * self._scale, 230 * self._scale, Qt.AlignHCenter | Qt.AlignBottom, version[0]) painter.drawText(0, 0, 330 * self._scale, 230 * self._scale, Qt.AlignHCenter | Qt.AlignBottom, version[0])

View File

@ -2,3 +2,4 @@
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
CuraVersion = "@CURA_VERSION@" CuraVersion = "@CURA_VERSION@"
CuraBuildType = "@CURA_BUILDTYPE@"

207
cura/ExtruderManager.py Normal file
View File

@ -0,0 +1,207 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject, QVariant #For communicating data and events to Qt.
import UM.Application #To get the global container stack to find the current machine.
import UM.Logger
import UM.Settings.ContainerRegistry #Finding containers by ID.
## Manages all existing extruder stacks.
#
# This keeps a list of extruder stacks for each machine.
class ExtruderManager(QObject):
## Signal to notify other components when the list of extruders changes.
extrudersChanged = pyqtSignal(QVariant)
## Notify when the user switches the currently active extruder.
activeExtruderChanged = pyqtSignal()
## Registers listeners and such to listen to changes to the extruders.
def __init__(self, parent = None):
super().__init__(parent)
self._extruder_trains = { } #Per machine, a dictionary of extruder container stack IDs.
self._active_extruder_index = 0
UM.Application.getInstance().globalContainerStackChanged.connect(self._addCurrentMachineExtruders)
## Gets the unique identifier of the currently active extruder stack.
#
# The currently active extruder stack is the stack that is currently being
# edited.
#
# \return The unique ID of the currently active extruder stack.
@pyqtProperty(str, notify = activeExtruderChanged)
def activeExtruderStackId(self):
if not UM.Application.getInstance().getGlobalContainerStack():
return None #No active machine, so no active extruder.
try:
return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)].getId()
except KeyError: #Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong.
return None
## The instance of the singleton pattern.
#
# It's None if the extruder manager hasn't been created yet.
__instance = None
## Gets an instance of the extruder manager, or creates one if no instance
# exists yet.
#
# This is an implementation of singleton. If an extruder manager already
# exists, it is re-used.
#
# \return The extruder manager.
@classmethod
def getInstance(cls):
if not cls.__instance:
cls.__instance = ExtruderManager()
return cls.__instance
## Changes the active extruder by index.
#
# \param index The index of the new active extruder.
@pyqtSlot(int)
def setActiveExtruderIndex(self, index):
self._active_extruder_index = index
self.activeExtruderChanged.emit()
## Adds all extruders of a specific machine definition to the extruder
# manager.
#
# \param machine_definition The machine to add the extruders for.
def addMachineExtruders(self, machine_definition):
machine_id = machine_definition.getId()
if machine_id not in self._extruder_trains:
self._extruder_trains[machine_id] = { }
container_registry = UM.Settings.ContainerRegistry.getInstance()
if not container_registry: #Then we shouldn't have any machine definition either. In any case, there are no extruder trains then so bye bye.
return
#Add the extruder trains that don't exist yet.
for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition.getId()):
position = extruder_definition.getMetaDataEntry("position", None)
if not position:
UM.Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId())
if not container_registry.findContainerStacks(machine = machine_id, position = position): #Doesn't exist yet.
self.createExtruderTrain(extruder_definition, machine_definition, position)
#Gets the extruder trains that we just created as well as any that still existed.
extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_definition.getId())
for extruder_train in extruder_trains:
self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train
if extruder_trains:
self.extrudersChanged.emit(machine_definition)
## Creates a container stack for an extruder train.
#
# The container stack has an extruder definition at the bottom, which is
# linked to a machine definition. Then it has a nozzle profile, a material
# profile, a quality profile and a user profile, in that order.
#
# The resulting container stack is added to the registry.
#
# \param extruder_definition The extruder to create the extruder train
# for.
# \param machine_definition The machine that the extruder train belongs
# to.
# \param position The position of this extruder train in the extruder
# slots of the machine.
def createExtruderTrain(self, extruder_definition, machine_definition, position):
#Cache some things.
container_registry = UM.Settings.ContainerRegistry.getInstance()
machine_id = machine_definition.getId()
#Create a container stack for this extruder.
extruder_stack_id = container_registry.uniqueName(extruder_definition.getId())
container_stack = UM.Settings.ContainerStack(extruder_stack_id)
container_stack.setName(extruder_definition.getName()) #Take over the display name to display the stack with.
container_stack.addMetaDataEntry("type", "extruder_train")
container_stack.addMetaDataEntry("machine", machine_definition.getId())
container_stack.addMetaDataEntry("position", position)
container_stack.addContainer(extruder_definition)
#Find the nozzle to use for this extruder.
nozzle = container_registry.getEmptyInstanceContainer()
if machine_definition.getMetaDataEntry("has_nozzles", default = "False") == "True":
#First add any nozzle. Later, overwrite with preference if the preference is valid.
nozzles = container_registry.findInstanceContainers(machine = machine_id, type = "nozzle")
if len(nozzles) >= 1:
nozzle = nozzles[0]
preferred_nozzle_id = machine_definition.getMetaDataEntry("preferred_nozzle")
if preferred_nozzle_id:
preferred_nozzles = container_registry.findInstanceContainers(id = preferred_nozzle_id, type = "nozzle")
if len(preferred_nozzles) >= 1:
nozzle = preferred_nozzles[0]
else:
UM.Logger.log("w", "The preferred nozzle \"%s\" of machine %s doesn't exist or is not a nozzle profile.", preferred_nozzle_id, machine_id)
#And leave it at the default nozzle.
container_stack.addContainer(nozzle)
#Find a material to use for this nozzle.
material = container_registry.getEmptyInstanceContainer()
if machine_definition.getMetaDataEntry("has_materials", default = "False") == "True":
#First add any material. Later, overwrite with preference if the preference is valid.
if machine_definition.getMetaDataEntry("has_nozzle_materials", default = "False") == "True":
materials = container_registry.findInstanceContainers(type = "material", machine = machine_id, nozzle = nozzle.getId())
else:
materials = container_registry.findInstanceContainers(type = "material", machine = machine_id)
if len(materials) >= 1:
material = materials[0]
preferred_material_id = machine_definition.getMetaDataEntry("preferred_material")
if preferred_material_id:
preferred_materials = container_registry.findInstanceContainers(id = preferred_material_id, type = "material")
if len(preferred_materials) >= 1:
material = preferred_materials[0]
else:
UM.Logger.log("w", "The preferred material \"%s\" of machine %s doesn't exist or is not a material profile.", preferred_material_id, machine_id)
#And leave it at the default material.
container_stack.addContainer(material)
#Find a quality to use for this extruder.
quality = container_registry.getEmptyInstanceContainer()
if machine_definition.getMetaDataEntry("has_machine_quality"):
#First add any quality. Later, overwrite with preference if the preference is valid.
qualities = container_registry.findInstanceContainers(type = "quality")
if len(qualities) >= 1:
quality = qualities[0]
preferred_quality_id = machine_definition.getMetaDataEntry("preferred_quality")
if preferred_quality_id:
preferred_quality = container_registry.findInstanceContainers(id = preferred_quality_id.lower(), type = "quality")
if len(preferred_quality) >= 1:
quality = preferred_quality[0]
else:
UM.Logger.log("w", "The preferred quality \"%s\" of machine %s doesn't exist or is not a quality profile.", preferred_quality_id, machine_id)
#And leave it at the default quality.
container_stack.addContainer(quality)
user_profile = container_registry.findInstanceContainers(id = extruder_stack_id + "_current_settings")
if user_profile: #There was already a user profile, loaded from settings.
user_profile = user_profile[0]
else:
user_profile = UM.Settings.InstanceContainer(extruder_stack_id + "_current_settings") #Add an empty user profile.
user_profile.addMetaDataEntry("type", "user")
user_profile.setDefinition(machine_definition)
container_registry.addContainer(user_profile)
container_stack.addContainer(user_profile)
container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack())
container_registry.addContainer(container_stack)
## Generates extruders for a specific machine.
#
# \param machine_id The machine to get the extruders of.
def getMachineExtruders(self, machine_id):
if machine_id not in self._extruder_trains:
UM.Logger.log("w", "Tried to get the extruder trains for machine %s, which doesn't exist.", machine_id)
return
for name in self._extruder_trains[machine_id]:
yield self._extruder_trains[machine_id][name]
## Adds the extruders of the currently active machine.
def _addCurrentMachineExtruders(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
if global_stack and global_stack.getBottom():
self.addMachineExtruders(global_stack.getBottom())

103
cura/ExtrudersModel.py Normal file
View File

@ -0,0 +1,103 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty
import cura.ExtruderManager
import UM.Qt.ListModel
## Model that holds extruders.
#
# This model is designed for use by any list of extruders, but specifically
# intended for drop-down lists of the current machine's extruders in place of
# settings.
class ExtrudersModel(UM.Qt.ListModel.ListModel):
# The ID of the container stack for the extruder.
IdRole = Qt.UserRole + 1
## Human-readable name of the extruder.
NameRole = Qt.UserRole + 2
## Colour of the material loaded in the extruder.
ColourRole = Qt.UserRole + 3
## Index of the extruder, which is also the value of the setting itself.
#
# An index of 0 indicates the first extruder, an index of 1 the second
# one, and so on. This is the value that will be saved in instance
# containers.
IndexRole = Qt.UserRole + 4
## Colour to display if there is no material or the material has no known
# colour.
defaultColour = "#FFFF00"
## Initialises the extruders model, defining the roles and listening for
# changes in the data.
#
# \param parent Parent QtObject of this list.
def __init__(self, parent = None):
super().__init__(parent)
self.addRoleName(self.IdRole, "id")
self.addRoleName(self.NameRole, "name")
self.addRoleName(self.ColourRole, "colour")
self.addRoleName(self.IndexRole, "index")
self._add_global = False
#Listen to changes.
manager = cura.ExtruderManager.ExtruderManager.getInstance()
manager.extrudersChanged.connect(self._updateExtruders) #When the list of extruders changes in general.
UM.Application.globalContainerStackChanged.connect(self._updateExtruders) #When the current machine changes.
self._updateExtruders()
def setAddGlobal(self, add):
if add != self._add_global:
self._add_global = add
self._updateExtruders()
self.addGlobalChanged.emit()
addGlobalChanged = pyqtSignal()
@pyqtProperty(bool, fset = setAddGlobal, notify = addGlobalChanged)
def addGlobal(self):
return self._add_global
## Update the list of extruders.
#
# This should be called whenever the list of extruders changes.
def _updateExtruders(self):
self.clear()
manager = cura.ExtruderManager.ExtruderManager.getInstance()
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
if not global_container_stack:
return #There is no machine to get the extruders of.
if self._add_global:
material = global_container_stack.findContainer({ "type": "material" })
colour = material.getMetaDataEntry("color_code", default = self.defaultColour) if material else self.defaultColour
item = {
"id": global_container_stack.getId(),
"name": "Global",
"colour": colour,
"index": -1
}
self.appendItem(item)
for extruder in manager.getMachineExtruders(global_container_stack.getBottom().getId()):
material = extruder.findContainer({ "type": "material" })
colour = material.getMetaDataEntry("color_code", default = self.defaultColour) if material else self.defaultColour
position = extruder.getBottom().getMetaDataEntry("position", default = "0") #Position in the definition.
try:
position = int(position)
except ValueError: #Not a proper int.
position = -1
item = { #Construct an item with only the relevant information.
"id": extruder.getId(),
"name": extruder.getName(),
"colour": colour,
"index": position
}
self.appendItem(item)
self.sort(lambda item: item["index"])

View File

@ -1,11 +1,18 @@
import re
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
from UM.Application import Application from UM.Application import Application
from UM.Preferences import Preferences from UM.Preferences import Preferences
import UM.Settings import UM.Settings
from UM.Settings.Validator import ValidatorState
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerStack import ContainerStack
from . import ExtruderManager
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
import re
class MachineManagerModel(QObject): class MachineManagerModel(QObject):
def __init__(self, parent = None): def __init__(self, parent = None):
@ -13,6 +20,7 @@ class MachineManagerModel(QObject):
self._global_container_stack = None self._global_container_stack = None
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
self._global_stack_valid = None
self._onGlobalContainerChanged() self._onGlobalContainerChanged()
## When the global container is changed, active material probably needs to be updated. ## When the global container is changed, active material probably needs to be updated.
@ -20,6 +28,10 @@ class MachineManagerModel(QObject):
self.globalContainerChanged.connect(self.activeVariantChanged) self.globalContainerChanged.connect(self.activeVariantChanged)
self.globalContainerChanged.connect(self.activeQualityChanged) self.globalContainerChanged.connect(self.activeQualityChanged)
self._empty_variant_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_variant")[0]
self._empty_material_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_material")[0]
self._empty_quality_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_quality")[0]
Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_machine", "")
active_machine_id = Preferences.getInstance().getValue("cura/active_machine") active_machine_id = Preferences.getInstance().getValue("cura/active_machine")
@ -29,15 +41,42 @@ class MachineManagerModel(QObject):
self.setActiveMachine(active_machine_id) self.setActiveMachine(active_machine_id)
pass pass
globalContainerChanged = pyqtSignal() globalContainerChanged = pyqtSignal()
activeMaterialChanged = pyqtSignal() activeMaterialChanged = pyqtSignal()
activeVariantChanged = pyqtSignal() activeVariantChanged = pyqtSignal()
activeQualityChanged = pyqtSignal() activeQualityChanged = pyqtSignal()
globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed.
globalValidationChanged = pyqtSignal() # Emitted whenever a validation inside global container is changed.
@pyqtProperty("QVariantMap", notify = globalContainerChanged)
def extrudersIds(self):
## Find all extruders that reference the new stack
extruders = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(**{"machine": self._global_container_stack.getId()})
result = {}
for extruder in extruders:
result[extruder.getMetaDataEntry("position")] = extruder.getId()
return result
def _onGlobalPropertyChanged(self, key, property_name):
if property_name == "value":
self.globalValueChanged.emit()
if property_name == "validationState":
if self._global_stack_valid:
changed_validation_state = self._global_container_stack.getProperty(key, property_name)
if changed_validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
self._global_stack_valid = False
self.globalValidationChanged.emit()
else:
new_validation_state = self._checkStackForErrors(self._global_container_stack)
if new_validation_state:
self._global_stack_valid = True
self.globalValidationChanged.emit()
def _onGlobalContainerChanged(self): def _onGlobalContainerChanged(self):
if self._global_container_stack: if self._global_container_stack:
self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged) self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
self._global_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged)
self._global_container_stack = Application.getInstance().getGlobalContainerStack() self._global_container_stack = Application.getInstance().getGlobalContainerStack()
self.globalContainerChanged.emit() self.globalContainerChanged.emit()
@ -45,6 +84,8 @@ class MachineManagerModel(QObject):
if self._global_container_stack: if self._global_container_stack:
Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId()) Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId())
self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged) self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
self._global_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged)
self._global_stack_valid = not self._checkStackForErrors(self._global_container_stack)
def _onInstanceContainersChanged(self, container): def _onInstanceContainersChanged(self, container):
container_type = container.getMetaDataEntry("type") container_type = container.getMetaDataEntry("type")
@ -66,51 +107,14 @@ class MachineManagerModel(QObject):
definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = definition_id) definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = definition_id)
if definitions: if definitions:
definition = definitions[0] definition = definitions[0]
name = self._uniqueMachineName(name, definition.getName()) name = self._createUniqueName("machine", "", name, definition.getName())
new_global_stack = UM.Settings.ContainerStack(name) new_global_stack = UM.Settings.ContainerStack(name)
new_global_stack.addMetaDataEntry("type", "machine") new_global_stack.addMetaDataEntry("type", "machine")
UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack)
empty_container = UM.Settings.ContainerRegistry.getInstance().getEmptyInstanceContainer() variant_instance_container = self._updateVariantContainer(definition)
material_instance_container = self._updateMaterialContainer(definition, variant_instance_container)
variants = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id) quality_instance_container = self._updateQualityContainer(definition, material_instance_container)
if variants:
new_global_stack.addMetaDataEntry("has_variants", True)
preferred_variant_id = definitions[0].getMetaDataEntry("preferred_variant")
variant_instance_container = empty_container
if preferred_variant_id:
preferred_variant_id = preferred_variant_id.lower()
container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_id)
if container:
variant_instance_container = container[0]
if variants and variant_instance_container == empty_container:
variant_instance_container = variants[0]
materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id)
if materials:
new_global_stack.addMetaDataEntry("has_materials", True)
preferred_material_id = definitions[0].getMetaDataEntry("preferred_material")
material_instance_container = empty_container
if preferred_material_id:
preferred_material_id = preferred_material_id.lower()
container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_material_id)
if container:
material_instance_container = container[0]
if materials and material_instance_container == empty_container:
material_instance_container = materials[0]
preferred_quality_id = definitions[0].getMetaDataEntry("preferred_quality")
quality_instance_container = empty_container
if preferred_quality_id:
preferred_quality_id = preferred_quality_id.lower()
container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_quality_id)
if container:
quality_instance_container = container[0]
current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings") current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings")
current_settings_instance_container.addMetaDataEntry("machine", name) current_settings_instance_container.addMetaDataEntry("machine", name)
@ -119,7 +123,7 @@ class MachineManagerModel(QObject):
UM.Settings.ContainerRegistry.getInstance().addContainer(current_settings_instance_container) UM.Settings.ContainerRegistry.getInstance().addContainer(current_settings_instance_container)
# If a definition is found, its a list. Should only have one item. # If a definition is found, its a list. Should only have one item.
new_global_stack.addContainer(definitions[0]) new_global_stack.addContainer(definition)
if variant_instance_container: if variant_instance_container:
new_global_stack.addContainer(variant_instance_container) new_global_stack.addContainer(variant_instance_container)
if material_instance_container: if material_instance_container:
@ -128,27 +132,85 @@ class MachineManagerModel(QObject):
new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(quality_instance_container)
new_global_stack.addContainer(current_settings_instance_container) new_global_stack.addContainer(current_settings_instance_container)
ExtruderManager.ExtruderManager.getInstance().addMachineExtruders(definition)
Application.getInstance().setGlobalContainerStack(new_global_stack) Application.getInstance().setGlobalContainerStack(new_global_stack)
# Create a name that is not empty and unique ## Create a name that is not empty and unique
def _uniqueMachineName(self, name, fallback_name): # \param container_type \type{string} Type of the container (machine, quality, ...)
name = name.strip() # \param current_name \type{} Current name of the container, which may be an acceptable option
num_check = re.compile("(.*?)\s*#\d$").match(name) # \param new_name \type{string} Base name, which may not be unique
if(num_check): # \param fallback_name \type{string} Name to use when (stripped) new_name is empty
name = num_check.group(1) # \return \type{string} Name that is unique for the specified type and name/id
if name == "": def _createUniqueName(self, container_type, current_name, new_name, fallback_name):
name = fallback_name new_name = new_name.strip()
unique_name = name num_check = re.compile("(.*?)\s*#\d+$").match(new_name)
i = 1 if num_check:
new_name = num_check.group(1)
if new_name == "":
new_name = fallback_name
#Check both the id and the name, because they may not be the same and it is better if they are both unique unique_name = new_name
while UM.Settings.ContainerRegistry.getInstance().findContainers(None, id = unique_name) or \ i = 1
UM.Settings.ContainerRegistry.getInstance().findContainers(None, name = unique_name): # In case we are renaming, the current name of the container is also a valid end-result
i = i + 1 while self._containerExists(container_type, unique_name) and unique_name != current_name:
unique_name = "%s #%d" % (name, i) i += 1
unique_name = "%s #%d" % (new_name, i)
return unique_name return unique_name
## Check if a container with of a certain type and a certain name or id exists
# Both the id and the name are checked, because they may not be the same and it is better if they are both unique
# \param container_type \type{string} Type of the container (machine, quality, ...)
# \param container_name \type{string} Name to check
def _containerExists(self, container_type, container_name):
container_class = ContainerStack if container_type == "machine" else InstanceContainer
return UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = container_name, type = container_type) or \
UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = container_name, type = container_type)
## Convenience function to check if a stack has errors.
def _checkStackForErrors(self, stack):
if stack is None:
return False
for key in stack.getAllKeys():
validation_state = stack.getProperty(key, "validationState")
if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
return True
return False
## Remove all instances from the top instanceContainer (effectively removing all user-changed settings)
@pyqtSlot()
def clearUserSettings(self):
if not self._global_container_stack:
return
user_settings = self._global_container_stack.getTop()
user_settings.clear()
## Check if the global_container has instances in the user container
@pyqtProperty(bool, notify = globalValueChanged)
def hasUserSettings(self):
if not self._global_container_stack:
return
user_settings = self._global_container_stack.getTop().findInstances(**{})
return len(user_settings) != 0
## Check if the global profile does not contain error states
# Note that the _global_stack_valid is cached due to performance issues
# Calling _checkStackForErrors on every change is simply too expensive
@pyqtProperty(bool, notify = globalValidationChanged)
def isGlobalStackValid(self):
return self._global_stack_valid
@pyqtProperty(str, notify = globalContainerChanged)
def activeUserProfileId(self):
if self._global_container_stack:
return self._global_container_stack.getTop().getId()
return ""
@pyqtProperty(str, notify = globalContainerChanged) @pyqtProperty(str, notify = globalContainerChanged)
def activeMachineName(self): def activeMachineName(self):
if self._global_container_stack: if self._global_container_stack:
@ -197,6 +259,101 @@ class MachineManagerModel(QObject):
return quality.getId() return quality.getId()
return "" return ""
## Check if a container is read_only
@pyqtSlot(str, result = bool)
def isReadOnly(self, container_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id)
if not containers or not self._global_container_stack:
return True
return containers[0].isReadOnly()
@pyqtSlot(result = str)
def newQualityContainerFromQualityAndUser(self):
new_container_id = self.duplicateContainer(self.activeQualityId)
if new_container_id == "":
return
self.setActiveQuality(new_container_id)
self.updateQualityContainerFromUserContainer()
@pyqtSlot(str, result=str)
def duplicateContainer(self, container_id):
if not self._global_container_stack:
return ""
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id)
if containers:
new_name = self._createUniqueName("quality", "", containers[0].getName(), catalog.i18nc("@label", "Custom profile"))
new_container = InstanceContainer("")
## Copy all values
new_container.deserialize(containers[0].serialize())
new_container.setReadOnly(False)
new_container.setName(new_name)
new_container._id = new_name
UM.Settings.ContainerRegistry.getInstance().addContainer(new_container)
return new_name
return ""
@pyqtSlot(str, str)
def renameQualityContainer(self, container_id, new_name):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality")
if containers:
new_name = self._createUniqueName("quality", containers[0].getName(), new_name,
catalog.i18nc("@label", "Custom profile"))
# As we also want the id of the container to be changed (so that profile name is the name of the file
# on disk. We need to create a new instance and remove it (so the old file of the container is removed)
# If we don't do that, we might get duplicates & other weird issues.
new_container = InstanceContainer("")
new_container.deserialize(containers[0].serialize())
# Actually set the name
new_container.setName(new_name)
new_container._id = new_name # Todo: Fix proper id change function for this.
# Add the "new" container.
UM.Settings.ContainerRegistry.getInstance().addContainer(new_container)
# Ensure that the renamed profile is saved -before- we remove the old profile.
Application.getInstance().saveSettings()
# Actually set & remove new / old quality.
self.setActiveQuality(new_name)
self.removeQualityContainer(containers[0].getId())
@pyqtSlot(str)
def removeQualityContainer(self, container_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id)
if not containers or not self._global_container_stack:
return
# If the container that is being removed is the currently active container, set another machine as the active container
activate_new_container = container_id == self.activeQualityId
UM.Settings.ContainerRegistry.getInstance().removeContainer(container_id)
if activate_new_container:
definition_id = "fdmprinter" if not self.filterQualityByMachine else self.activeDefinitionId
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition_id)
if containers:
self.setActiveQuality(containers[0].getId())
self.activeQualityChanged.emit()
@pyqtSlot()
def updateQualityContainerFromUserContainer(self):
if not self._global_container_stack:
return
user_settings = self._global_container_stack.getTop()
quality = self._global_container_stack.findContainer({"type": "quality"})
for key in user_settings.getAllKeys():
quality.setProperty(key, "value", user_settings.getProperty(key, "value"))
self.clearUserSettings() # As all users settings are noq a quality, remove them.
@pyqtSlot(str) @pyqtSlot(str)
def setActiveMaterial(self, material_id): def setActiveMaterial(self, material_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=material_id) containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=material_id)
@ -208,6 +365,8 @@ class MachineManagerModel(QObject):
material_index = self._global_container_stack.getContainerIndex(old_material) material_index = self._global_container_stack.getContainerIndex(old_material)
self._global_container_stack.replaceContainer(material_index, containers[0]) self._global_container_stack.replaceContainer(material_index, containers[0])
self.setActiveQuality(self._updateQualityContainer(self._global_container_stack.getBottom(), containers[0]).id)
@pyqtSlot(str) @pyqtSlot(str)
def setActiveVariant(self, variant_id): def setActiveVariant(self, variant_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=variant_id) containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=variant_id)
@ -219,6 +378,8 @@ class MachineManagerModel(QObject):
variant_index = self._global_container_stack.getContainerIndex(old_variant) variant_index = self._global_container_stack.getContainerIndex(old_variant)
self._global_container_stack.replaceContainer(variant_index, containers[0]) self._global_container_stack.replaceContainer(variant_index, containers[0])
self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), containers[0]).id)
@pyqtSlot(str) @pyqtSlot(str)
def setActiveQuality(self, quality_id): def setActiveQuality(self, quality_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_id) containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_id)
@ -261,31 +422,116 @@ class MachineManagerModel(QObject):
def renameMachine(self, machine_id, new_name): def renameMachine(self, machine_id, new_name):
containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id)
if containers: if containers:
new_name = self._uniqueMachineName(new_name, containers[0].getBottom().getName()) new_name = self._createUniqueName("machine", containers[0].getName(), new_name, containers[0].getBottom().getName())
containers[0].setName(new_name) containers[0].setName(new_name)
self.globalContainerChanged.emit()
@pyqtSlot(str) @pyqtSlot(str)
def removeMachine(self, machine_id): def removeMachine(self, machine_id):
# If the machine that is being removed is the currently active machine, set another machine as the active machine # If the machine that is being removed is the currently active machine, set another machine as the active machine
if self._global_container_stack and self._global_container_stack.getId() == machine_id: activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id)
containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks()
if containers: current_settings_id = machine_id + "_current_settings"
Application.getInstance().setGlobalContainerStack(containers[0]) containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = current_settings_id)
for container in containers:
UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId())
UM.Settings.ContainerRegistry.getInstance().removeContainer(machine_id) UM.Settings.ContainerRegistry.getInstance().removeContainer(machine_id)
if activate_new_machine:
stacks = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(type = "machine")
if stacks:
Application.getInstance().setGlobalContainerStack(stacks[0])
@pyqtProperty(bool, notify = globalContainerChanged) @pyqtProperty(bool, notify = globalContainerChanged)
def hasMaterials(self): def hasMaterials(self):
if self._global_container_stack: if self._global_container_stack:
return self._global_container_stack.getMetaDataEntry("has_materials", False) return bool(self._global_container_stack.getMetaDataEntry("has_materials", False))
return False return False
@pyqtProperty(bool, notify = globalContainerChanged) @pyqtProperty(bool, notify = globalContainerChanged)
def hasVariants(self): def hasVariants(self):
if self._global_container_stack: if self._global_container_stack:
return self._global_container_stack.getMetaDataEntry("has_variants", False) return bool(self._global_container_stack.getMetaDataEntry("has_variants", False))
return False return False
@pyqtProperty(bool, notify = globalContainerChanged)
def filterMaterialsByMachine(self):
if self._global_container_stack:
return bool(self._global_container_stack.getMetaDataEntry("has_machine_materials", False))
return False
@pyqtProperty(bool, notify = globalContainerChanged)
def filterQualityByMachine(self):
if self._global_container_stack:
return bool(self._global_container_stack.getMetaDataEntry("has_machine_quality", False))
return False
def _updateVariantContainer(self, definition):
if not definition.getMetaDataEntry("has_variants"):
return self._empty_variant_container
containers = []
preferred_variant = definition.getMetaDataEntry("preferred_variant")
if preferred_variant:
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id, id = preferred_variant)
if not containers:
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id)
if containers:
return containers[0]
return self._empty_variant_container
def _updateMaterialContainer(self, definition, variant_container = None):
if not definition.getMetaDataEntry("has_materials"):
return self._empty_material_container
search_criteria = { "type": "material" }
if definition.getMetaDataEntry("has_machine_materials"):
search_criteria["definition"] = definition.id
if definition.getMetaDataEntry("has_variants") and variant_container:
search_criteria["variant"] = variant_container.id
else:
search_criteria["definition"] = "fdmprinter"
preferred_material = definition.getMetaDataEntry("preferred_material")
if preferred_material:
search_criteria["id"] = preferred_material
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if containers:
return containers[0]
return self._empty_material_container
def _updateQualityContainer(self, definition, material_container = None):
search_criteria = { "type": "quality" }
if definition.getMetaDataEntry("has_machine_quality"):
search_criteria["definition"] = definition.id
if definition.getMetaDataEntry("has_materials") and material_container:
search_criteria["material"] = material_container.id
else:
search_criteria["definition"] = "fdmprinter"
preferred_quality = definition.getMetaDataEntry("preferred_quality")
if preferred_quality:
search_criteria["id"] = preferred_quality
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if containers:
return containers[0]
return self._empty_quality_container
def createMachineManagerModel(engine, script_engine): def createMachineManagerModel(engine, script_engine):
return MachineManagerModel() return MachineManagerModel()

View File

@ -1,14 +1,17 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot
from UM.Application import Application from UM.Application import Application
from UM.Qt.Duration import Duration from UM.Qt.Duration import Duration
from UM.Preferences import Preferences
import math import math
import os.path
import unicodedata
## A class for processing and calculating minimum, current and maximum print time. ## A class for processing and calculating minimum, current and maximum print time as well as managing the job name
# #
# This class contains all the logic relating to calculation and slicing for the # This class contains all the logic relating to calculation and slicing for the
# time/quality slider concept. It is a rather tricky combination of event handling # time/quality slider concept. It is a rather tricky combination of event handling
@ -22,6 +25,8 @@ import math
# - When that is done, we update the minimum print time and start the final slice pass, the "high quality settings pass". # - When that is done, we update the minimum print time and start the final slice pass, the "high quality settings pass".
# - When the high quality pass is done, we update the maximum print time. # - When the high quality pass is done, we update the maximum print time.
# #
# This class also mangles the current machine name and the filename of the first loaded mesh into a job name.
# This job name is requested by the JobSpecs qml file.
class PrintInformation(QObject): class PrintInformation(QObject):
class SlicePass: class SlicePass:
CurrentSettings = 1 CurrentSettings = 1
@ -45,6 +50,12 @@ class PrintInformation(QObject):
if self._backend: if self._backend:
self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._backend.printDurationMessage.connect(self._onPrintDurationMessage)
self._job_name = ""
self._abbr_machine = ""
Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName)
Application.getInstance().fileLoaded.connect(self.setJobName)
currentPrintTimeChanged = pyqtSignal() currentPrintTimeChanged = pyqtSignal()
@pyqtProperty(Duration, notify = currentPrintTimeChanged) @pyqtProperty(Duration, notify = currentPrintTimeChanged)
@ -66,3 +77,46 @@ class PrintInformation(QObject):
r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2 r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2
self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2) self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2)
self.materialAmountChanged.emit() self.materialAmountChanged.emit()
@pyqtSlot(str)
def setJobName(self, name):
# when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its
# extension. This cuts the extension off if necessary.
name = os.path.splitext(name)[0]
if self._job_name != name:
self._job_name = name
self.jobNameChanged.emit()
jobNameChanged = pyqtSignal()
@pyqtProperty(str, notify = jobNameChanged)
def jobName(self):
return self._job_name
@pyqtSlot(str, result = str)
def createJobName(self, base_name):
base_name = self._stripAccents(base_name)
if Preferences.getInstance().getValue("cura/jobname_prefix"):
return self._abbr_machine + "_" + base_name
else:
return base_name
## Created an acronymn-like abbreviated machine name from the currently active machine name
# Called each time the global stack is switched
def _setAbbreviatedMachineName(self):
global_stack_name = Application.getInstance().getGlobalContainerStack().getName()
split_name = global_stack_name.split(" ")
abbr_machine = ""
for word in split_name:
if word.lower() == "ultimaker":
abbr_machine += "UM"
elif word.isdigit():
abbr_machine += word
else:
abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0]
self._abbr_machine = abbr_machine
## Utility method that strips accents from characters (eg: â -> a)
def _stripAccents(self, str):
return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')

25
cura/ProfileWriter.py Normal file
View File

@ -0,0 +1,25 @@
# Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.
from UM.PluginObject import PluginObject
## Base class for profile writer plugins.
#
# This class defines a write() function to write profiles to files with.
class ProfileWriter(PluginObject):
## Initialises the profile writer.
#
# This currently doesn't do anything since the writer is basically static.
def __init__(self):
super().__init__()
## Writes a profile to the specified file path.
#
# The profile writer may write its own file format to the specified file.
#
# \param path \type{string} The file to output to.
# \param profile \type{Profile} The profile to write to the file.
# \return \code True \endcode if the writing was successful, or \code
# False \endcode if it wasn't.
def write(self, path, node):
raise NotImplementedError("Profile writer plugin was not correctly implemented. No write was specified.")

View File

@ -1,31 +1,78 @@
# Copyright (c) 2016 Ultimaker B.V. # Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
import copy
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
from UM.Signal import Signal, signalemitter
from UM.Settings.ContainerStack import ContainerStack from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
import UM.Logger
from UM.Application import Application from UM.Application import Application
## A decorator that adds a container stack to a Node. This stack should be queried for all settings regarding ## A decorator that adds a container stack to a Node. This stack should be queried for all settings regarding
# the linked node. The Stack in question will refer to the global stack (so that settings that are not defined by # the linked node. The Stack in question will refer to the global stack (so that settings that are not defined by
# this stack still resolve. # this stack still resolve.
@signalemitter
class SettingOverrideDecorator(SceneNodeDecorator): class SettingOverrideDecorator(SceneNodeDecorator):
## Event indicating that the user selected a different extruder.
activeExtruderChanged = Signal()
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._stack = ContainerStack(stack_id = id(self)) self._stack = ContainerStack(stack_id = id(self))
self._stack.setDirty(False) # This stack does not need to be saved.
self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer") self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer")
self._stack.addContainer(self._instance) self._stack.addContainer(self._instance)
self._extruder_stack = None #Stack upon which our stack is based.
self._stack.propertyChanged.connect(self._onSettingChanged)
ContainerRegistry.getInstance().addContainer(self._stack) ContainerRegistry.getInstance().addContainer(self._stack)
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) Application.getInstance().globalContainerStackChanged.connect(self._updateNextStack)
self._onGlobalContainerStackChanged() self.activeExtruderChanged.connect(self._updateNextStack)
self._updateNextStack()
def _onGlobalContainerStackChanged(self): def __deepcopy__(self, memo):
## Ensure that the next stack is always the global stack. ## Create a fresh decorator object
deep_copy = SettingOverrideDecorator()
## Copy the instance
deep_copy._instance = copy.deepcopy(self._instance, memo)
## Set the copied instance as the first (and only) instance container of the stack.
deep_copy._stack.replaceContainer(0, deep_copy._instance)
return deep_copy
## Gets the currently active extruder to print this object with.
#
# \return An extruder's container stack.
def getActiveExtruder(self):
return self._extruder_stack
def _onSettingChanged(self, instance, property):
if property == "value": # Only reslice if the value has changed.
Application.getInstance().getBackend().forceSlice()
## Makes sure that the stack upon which the container stack is placed is
# kept up to date.
def _updateNextStack(self):
if self._extruder_stack:
extruder_stack = ContainerRegistry.getInstance().findContainerStacks(id = self._extruder_stack)
if extruder_stack:
self._stack.setNextStack(extruder_stack)
else:
UM.Logger.log("e", "Extruder stack %s below per-object settings does not exist.", self._extruder_stack)
else:
self._stack.setNextStack(Application.getInstance().getGlobalContainerStack()) self._stack.setNextStack(Application.getInstance().getGlobalContainerStack())
## Changes the extruder with which to print this node.
#
# \param extruder_stack_id The new extruder stack to print with.
def setActiveExtruder(self, extruder_stack_id):
self._extruder_stack = extruder_stack_id
self.activeExtruderChanged.emit()
def getStack(self): def getStack(self):
return self._stack return self._stack

View File

@ -36,7 +36,6 @@ import Arcus #@UnusedImport
import cura.CuraApplication import cura.CuraApplication
if sys.platform == "win32" and hasattr(sys, "frozen"): if sys.platform == "win32" and hasattr(sys, "frozen"):
import os
dirpath = os.path.expanduser("~/AppData/Local/cura/") dirpath = os.path.expanduser("~/AppData/Local/cura/")
os.makedirs(dirpath, exist_ok = True) os.makedirs(dirpath, exist_ok = True)
sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w") sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w")

View File

@ -13,7 +13,7 @@ def getMetaData():
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for reading 3MF files."), "description": catalog.i18nc("@info:whatsthis", "Provides support for reading 3MF files."),
"api": 2 "api": 3
}, },
"mesh_reader": [ "mesh_reader": [
{ {

View File

@ -15,15 +15,9 @@ class AutoSave(Extension):
Preferences.getInstance().preferenceChanged.connect(self._triggerTimer) Preferences.getInstance().preferenceChanged.connect(self._triggerTimer)
machine_manager = Application.getInstance().getMachineManager() self._global_stack = None
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
self._profile = None self._onGlobalStackChanged()
machine_manager.activeProfileChanged.connect(self._onActiveProfileChanged)
machine_manager.profileNameChanged.connect(self._triggerTimer)
machine_manager.profilesChanged.connect(self._triggerTimer)
machine_manager.machineInstanceNameChanged.connect(self._triggerTimer)
machine_manager.machineInstancesChanged.connect(self._triggerTimer)
self._onActiveProfileChanged()
Preferences.getInstance().addPreference("cura/autosave_delay", 1000 * 10) Preferences.getInstance().addPreference("cura/autosave_delay", 1000 * 10)
@ -38,24 +32,23 @@ class AutoSave(Extension):
if not self._saving: if not self._saving:
self._change_timer.start() self._change_timer.start()
def _onActiveProfileChanged(self): def _onGlobalStackChanged(self):
if self._profile: if self._global_stack:
self._profile.settingValueChanged.disconnect(self._triggerTimer) self._global_stack.propertyChanged.disconnect(self._triggerTimer)
self._global_stack.containersChanged.disconnect(self._triggerTimer)
self._profile = Application.getInstance().getMachineManager().getWorkingProfile() self._global_stack = Application.getInstance().getGlobalContainerStack()
if self._profile: if self._global_stack:
self._profile.settingValueChanged.connect(self._triggerTimer) self._global_stack.propertyChanged.connect(self._triggerTimer)
self._global_stack.containersChanged.connect(self._triggerTimer)
def _onTimeout(self): def _onTimeout(self):
self._saving = True # To prevent the save process from triggering another autosave. self._saving = True # To prevent the save process from triggering another autosave.
Logger.log("d", "Autosaving preferences, instances and profiles") Logger.log("d", "Autosaving preferences, instances and profiles")
machine_manager = Application.getInstance().getMachineManager() Application.getInstance().saveSettings()
machine_manager.saveVisibility()
machine_manager.saveMachineInstances()
machine_manager.saveProfiles()
Preferences.getInstance().writeToFile(Resources.getStoragePath(Resources.Preferences, Application.getInstance().getApplicationName() + ".cfg")) Preferences.getInstance().writeToFile(Resources.getStoragePath(Resources.Preferences, Application.getInstance().getApplicationName() + ".cfg"))
self._saving = False self._saving = False

View File

@ -13,7 +13,7 @@ def getMetaData():
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Automatically saves Preferences, Machines and Profiles after changes."), "description": catalog.i18nc("@info:whatsthis", "Automatically saves Preferences, Machines and Profiles after changes."),
"api": 2 "api": 3
}, },
} }

View File

@ -48,6 +48,7 @@ class ChangeLog(Extension, QObject,):
result += "<h1>" + str(version) + "</h1><br>" result += "<h1>" + str(version) + "</h1><br>"
result += "" result += ""
for change in logs[version]: for change in logs[version]:
if str(change) != "":
result += "<b>" + str(change) + "</b><br>" result += "<b>" + str(change) + "</b><br>"
for line in logs[version][change]: for line in logs[version][change]:
result += str(line) + "<br>" result += str(line) + "<br>"
@ -60,19 +61,20 @@ class ChangeLog(Extension, QObject,):
self._change_logs = collections.OrderedDict() self._change_logs = collections.OrderedDict()
with open(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.txt"), "r",-1, "utf-8") as f: with open(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.txt"), "r",-1, "utf-8") as f:
open_version = None open_version = None
open_header = None open_header = "" # Initialise to an empty header in case there is no "*" in the first line of the changelog
for line in f: for line in f:
line = line.replace("\n","") line = line.replace("\n","")
if "[" in line and "]" in line: if "[" in line and "]" in line:
line = line.replace("[","") line = line.replace("[","")
line = line.replace("]","") line = line.replace("]","")
open_version = Version(line) open_version = Version(line)
self._change_logs[Version(line)] = collections.OrderedDict() self._change_logs[open_version] = collections.OrderedDict()
elif line.startswith("*"): elif line.startswith("*"):
open_header = line.replace("*","") open_header = line.replace("*","")
self._change_logs[open_version][open_header] = [] self._change_logs[open_version][open_header] = []
else: elif line != "":
if line != "": if open_header not in self._change_logs[open_version]:
self._change_logs[open_version][open_header] = []
self._change_logs[open_version][open_header].append(line) self._change_logs[open_version][open_header].append(line)
def _onEngineCreated(self): def _onEngineCreated(self):
@ -105,4 +107,3 @@ class ChangeLog(Extension, QObject,):
self._changelog_context = QQmlContext(Application.getInstance()._engine.rootContext()) self._changelog_context = QQmlContext(Application.getInstance()._engine.rootContext())
self._changelog_context.setContextProperty("manager", self) self._changelog_context.setContextProperty("manager", self)
self._changelog_window = component.create(self._changelog_context) self._changelog_window = component.create(self._changelog_context)
#print(self._changelog_window)

View File

@ -1,7 +1,6 @@
[2.1.0] [2.1.2]
*2.1 Beta release Cura has been completely reengineered from the ground up for an even more seamless integration between hardware, software and materials. Together with its intuitive new user interface, its now also ready for any future developments. For the beginner Cura makes 3D printing incredibly easy, and for more advanced users, there are over 140 new customisable settings.
Cura has been completely reengineered from the ground up for an even more seamless integration between hardware, software and materials. Together with its intuitive new user interface, its now also ready for any future developments. For the beginner, Cura makes 3D printing incredibly easy, and for more advanced users, there are over 140 new customisable settings.
*Select Multiple Objects *Select Multiple Objects
You now have the freedom to select and manipulate multiple objects at the same time. You now have the freedom to select and manipulate multiple objects at the same time.

View File

@ -13,7 +13,7 @@ def getMetaData():
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Shows changes since latest checked version."), "description": catalog.i18nc("@info:whatsthis", "Shows changes since latest checked version."),
"api": 2 "api": 3
} }
} }

View File

@ -5,12 +5,20 @@ package cura.proto;
message ObjectList message ObjectList
{ {
repeated Object objects = 1; repeated Object objects = 1;
repeated Setting settings = 2; repeated Setting settings = 2; // meshgroup settings (for one-at-a-time printing)
} }
message Slice message Slice
{ {
repeated ObjectList object_lists = 1; repeated ObjectList object_lists = 1; // The meshgroups to be printed one after another
SettingList global_settings = 2; // The global settings used for the whole print job
repeated Extruder extruders = 3; // The settings sent to each extruder object
}
message Extruder
{
int32 id = 1;
SettingList settings = 2;
} }
message Object message Object
@ -29,10 +37,10 @@ message Progress
message Layer { message Layer {
int32 id = 1; int32 id = 1;
float height = 2; float height = 2; // Z position
float thickness = 3; float thickness = 3; // height of a single layer
repeated Polygon polygons = 4; repeated Polygon polygons = 4; // layer data
} }
message Polygon { message Polygon {
@ -48,19 +56,19 @@ message Polygon {
MoveCombingType = 8; MoveCombingType = 8;
MoveRetractionType = 9; MoveRetractionType = 9;
} }
Type type = 1; Type type = 1; // Type of move
bytes points = 2; bytes points = 2; // The points of the polygon, or two points if only a line segment (Currently only line segments are used)
float line_width = 3; float line_width = 3; // The width of the line being laid down
} }
message GCodeLayer { message GCodeLayer {
bytes data = 2; bytes data = 2;
} }
message ObjectPrintTime { message ObjectPrintTime { // The print time for the whole print and material estimates for the first extruder
int64 id = 1; int64 id = 1;
float time = 2; float time = 2; // Total time estimate
float material_amount = 3; float material_amount = 3; // material used in the first extruder
} }
message SettingList { message SettingList {
@ -68,13 +76,13 @@ message SettingList {
} }
message Setting { message Setting {
string name = 1; string name = 1; // Internal key to signify a setting
bytes value = 2; bytes value = 2; // The value of the setting
} }
message GCodePrefix { message GCodePrefix {
bytes data = 2; bytes data = 2; // Header string to be prenpended before the rest of the gcode sent from the engine
} }
message SlicingFinished { message SlicingFinished {

View File

@ -145,8 +145,7 @@ class CuraEngineBackend(Backend):
self.slicingStarted.emit() self.slicingStarted.emit()
slice_message = self._socket.createMessage("cura.proto.Slice") slice_message = self._socket.createMessage("cura.proto.Slice")
settings_message = self._socket.createMessage("cura.proto.SettingList") self._start_slice_job = StartSliceJob.StartSliceJob(slice_message)
self._start_slice_job = StartSliceJob.StartSliceJob(slice_message, settings_message)
self._start_slice_job.start() self._start_slice_job.start()
self._start_slice_job.finished.connect(self._onStartSliceCompleted) self._start_slice_job.finished.connect(self._onStartSliceCompleted)
@ -205,7 +204,6 @@ class CuraEngineBackend(Backend):
return return
# Preparation completed, send it to the backend. # Preparation completed, send it to the backend.
self._socket.sendMessage(job.getSettingsMessage())
self._socket.sendMessage(job.getSliceMessage()) self._socket.sendMessage(job.getSliceMessage())
## Listener for when the scene has changed. ## Listener for when the scene has changed.

View File

@ -103,7 +103,7 @@ class ProcessSlicedLayersJob(Job):
Job.yieldThread() Job.yieldThread()
Job.yieldThread() Job.yieldThread()
current_layer += 1 current_layer += 1
progress = (current_layer / layer_count) * 100 progress = (current_layer / layer_count) * 99
# TODO: Rebuild the layer data mesh once the layer has been processed. # TODO: Rebuild the layer data mesh once the layer has been processed.
# This needs some work in LayerData so we can add the new layers instead of recreating the entire mesh. # This needs some work in LayerData so we can add the new layers instead of recreating the entire mesh.

View File

@ -3,7 +3,6 @@
import numpy import numpy
from string import Formatter from string import Formatter
import traceback
from enum import IntEnum from enum import IntEnum
from UM.Job import Job from UM.Job import Job
@ -16,6 +15,7 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Settings.Validator import ValidatorState from UM.Settings.Validator import ValidatorState
from cura.OneAtATimeIterator import OneAtATimeIterator from cura.OneAtATimeIterator import OneAtATimeIterator
from cura.ExtruderManager import ExtruderManager
class StartJobResult(IntEnum): class StartJobResult(IntEnum):
Finished = 1 Finished = 1
@ -38,20 +38,30 @@ class GcodeStartEndFormatter(Formatter):
## Job class that builds up the message of scene data to send to CuraEngine. ## Job class that builds up the message of scene data to send to CuraEngine.
class StartSliceJob(Job): class StartSliceJob(Job):
def __init__(self, slice_message, settings_message): def __init__(self, slice_message):
super().__init__() super().__init__()
self._scene = Application.getInstance().getController().getScene() self._scene = Application.getInstance().getController().getScene()
self._slice_message = slice_message self._slice_message = slice_message
self._settings_message = settings_message
self._is_cancelled = False self._is_cancelled = False
def getSettingsMessage(self):
return self._settings_message
def getSliceMessage(self): def getSliceMessage(self):
return self._slice_message return self._slice_message
## Check if a stack has any errors.
## returns true if it has errors, false otherwise.
def _checkStackForErrors(self, stack):
if stack is None:
return False
for key in stack.getAllKeys():
validation_state = stack.getProperty(key, "validationState")
if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
Logger.log("w", "Setting %s is not valid, but %s. Aborting slicing.", key, validation_state)
return True
Job.yieldThread()
return False
## Runs the job that initiates the slicing. ## Runs the job that initiates the slicing.
def run(self): def run(self):
stack = Application.getInstance().getGlobalContainerStack() stack = Application.getInstance().getGlobalContainerStack()
@ -60,14 +70,18 @@ class StartSliceJob(Job):
return return
# Don't slice if there is a setting with an error value. # Don't slice if there is a setting with an error value.
for key in stack.getAllKeys(): if self._checkStackForErrors(stack):
validation_state = stack.getProperty(key, "validationState")
if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
Logger.log("w", "Setting %s is not valid, but %s. Aborting slicing.", key, validation_state)
self.setResult(StartJobResult.SettingError) self.setResult(StartJobResult.SettingError)
return return
Job.yieldThread() # Don't slice if there is a per object setting with an error value.
for node in DepthFirstIterator(self._scene.getRoot()):
if type(node) is not SceneNode or not node.isSelectable():
continue
if self._checkStackForErrors(node.callDecoration("getStack")):
self.setResult(StartJobResult.SettingError)
return
with self._scene.getSceneLock(): with self._scene.getSceneLock():
# Remove old layer data. # Remove old layer data.
@ -114,6 +128,9 @@ class StartSliceJob(Job):
self._buildGlobalSettingsMessage(stack) self._buildGlobalSettingsMessage(stack)
for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(stack.getBottom().getId()):
self._buildExtruderMessage(extruder_stack)
for group in object_groups: for group in object_groups:
group_message = self._slice_message.addRepeatedMessage("object_lists") group_message = self._slice_message.addRepeatedMessage("object_lists")
if group[0].getParent().callDecoration("isGroup"): if group[0].getParent().callDecoration("isGroup"):
@ -153,6 +170,15 @@ class StartSliceJob(Job):
Logger.logException("w", "Unable to do token replacement on start/end gcode") Logger.logException("w", "Unable to do token replacement on start/end gcode")
return str(value).encode("utf-8") return str(value).encode("utf-8")
def _buildExtruderMessage(self, stack):
message = self._slice_message.addRepeatedMessage("extruders")
message.id = int(stack.getMetaDataEntry("position"))
for key in stack.getAllKeys():
setting = message.getMessage("settings").addRepeatedMessage("settings")
setting.name = key
setting.value = str(stack.getProperty(key, "value")).encode("utf-8")
Job.yieldThread()
## Sends all global settings to the engine. ## Sends all global settings to the engine.
# #
# The settings are taken from the global stack. This does not include any # The settings are taken from the global stack. This does not include any
@ -168,7 +194,7 @@ class StartSliceJob(Job):
settings["material_print_temp_prepend"] = "{material_print_temperature}" not in start_gcode settings["material_print_temp_prepend"] = "{material_print_temperature}" not in start_gcode
for key, value in settings.items(): #Add all submessages for each individual setting. for key, value in settings.items(): #Add all submessages for each individual setting.
setting_message = self._settings_message.addRepeatedMessage("settings") setting_message = self._slice_message.getMessage("global_settings").addRepeatedMessage("settings")
setting_message.name = key setting_message.name = key
if key == "machine_start_gcode" or key == "machine_end_gcode": #If it's a g-code message, use special formatting. if key == "machine_start_gcode" or key == "machine_end_gcode": #If it's a g-code message, use special formatting.
setting_message.value = self._expandGcodeTokens(key, value, settings) setting_message.value = self._expandGcodeTokens(key, value, settings)
@ -176,21 +202,10 @@ class StartSliceJob(Job):
setting_message.value = str(value).encode("utf-8") setting_message.value = str(value).encode("utf-8")
def _handlePerObjectSettings(self, node, message): def _handlePerObjectSettings(self, node, message):
profile = node.callDecoration("getProfile") stack = node.callDecoration("getStack")
if profile: if stack:
for key, value in profile.getAllSettingValues().items(): for key in stack.getAllKeys():
setting = message.addRepeatedMessage("settings") setting = message.addRepeatedMessage("settings")
setting.name = key setting.name = key
setting.value = str(value).encode() setting.value = str(stack.getProperty(key, "value")).encode("utf-8")
Job.yieldThread()
object_settings = node.callDecoration("getAllSettingValues")
if not object_settings:
return
for key, value in object_settings.items():
setting = message.addRepeatedMessage("settings")
setting.name = key
setting.value = str(value).encode()
Job.yieldThread() Job.yieldThread()

View File

@ -1,11 +1,12 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
import os.path
from UM.Application import Application #To get the machine manager to create the new profile in. from UM.Application import Application #To get the machine manager to create the new profile in.
from UM.Logger import Logger from UM.Logger import Logger
from UM.Settings.Profile import Profile from UM.Settings.InstanceContainer import InstanceContainer #The new profile to make.
from UM.Settings.ProfileReader import ProfileReader from cura.ProfileReader import ProfileReader
## A plugin that reads profile data from Cura profile files. ## A plugin that reads profile data from Cura profile files.
# #
@ -25,17 +26,17 @@ class CuraProfileReader(ProfileReader):
# returned. # returned.
def read(self, file_name): def read(self, file_name):
# Create an empty profile. # Create an empty profile.
profile = Profile(machine_manager = Application.getInstance().getMachineManager(), read_only = False) profile = InstanceContainer(os.path.basename(os.path.splitext(file_name)[0]))
serialised = "" profile.addMetaDataEntry("type", "quality")
try: try:
with open(file_name) as f: # Open file for reading. with open(file_name) as f: # Open file for reading.
serialised = f.read() serialized = f.read()
except IOError as e: except IOError as e:
Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e)) Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e))
return None return None
try: try:
profile.unserialise(serialised) profile.deserialize(serialized)
except Exception as e: # Parsing error. This is not a (valid) Cura profile then. except Exception as e: # Parsing error. This is not a (valid) Cura profile then.
Logger.log("e", "Error while trying to parse profile: %s", str(e)) Logger.log("e", "Error while trying to parse profile: %s", str(e))
return None return None

View File

@ -13,7 +13,7 @@ def getMetaData():
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for importing Cura profiles."), "description": catalog.i18nc("@info:whatsthis", "Provides support for importing Cura profiles."),
"api": 2 "api": 3
}, },
"profile_reader": [ "profile_reader": [
{ {

View File

@ -4,7 +4,7 @@
from UM.Logger import Logger from UM.Logger import Logger
from UM.SaveFile import SaveFile from UM.SaveFile import SaveFile
from UM.Settings.ProfileWriter import ProfileWriter from cura.ProfileWriter import ProfileWriter
## Writes profiles to Cura's own profile format with config files. ## Writes profiles to Cura's own profile format with config files.
@ -16,10 +16,10 @@ class CuraProfileWriter(ProfileWriter):
# \return \code True \endcode if the writing was successful, or \code # \return \code True \endcode if the writing was successful, or \code
# False \endcode if it wasn't. # False \endcode if it wasn't.
def write(self, path, profile): def write(self, path, profile):
serialised = profile.serialise() serialized = profile.serialize()
try: try:
with SaveFile(path, "wt", -1, "utf-8") as f: # Open the specified file. with SaveFile(path, "wt", -1, "utf-8") as f: # Open the specified file.
f.write(serialised) f.write(serialized)
except Exception as e: except Exception as e:
Logger.log("e", "Failed to write profile to %s: %s", path, str(e)) Logger.log("e", "Failed to write profile to %s: %s", path, str(e))
return False return False

View File

@ -13,7 +13,7 @@ def getMetaData():
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for exporting Cura profiles."), "description": catalog.i18nc("@info:whatsthis", "Provides support for exporting Cura profiles."),
"api": 2 "api": 3
}, },
"profile_writer": [ "profile_writer": [
{ {

View File

@ -13,7 +13,7 @@ def getMetaData():
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": i18n_catalog.i18nc("@info:whatsthis", "Enables ability to generate printable geometry from 2D image files."), "description": i18n_catalog.i18nc("@info:whatsthis", "Enables ability to generate printable geometry from 2D image files."),
"api": 2 "api": 3
}, },
"mesh_reader": [ "mesh_reader": [
{ {

View File

@ -10,6 +10,7 @@ from UM.Scene.Selection import Selection
from UM.Math.Color import Color from UM.Math.Color import Color
from UM.Mesh.MeshData import MeshData from UM.Mesh.MeshData import MeshData
from UM.Job import Job from UM.Job import Job
from UM.Preferences import Preferences
from UM.View.RenderBatch import RenderBatch from UM.View.RenderBatch import RenderBatch
from UM.View.GL.OpenGL import OpenGL from UM.View.GL.OpenGL import OpenGL
@ -41,7 +42,10 @@ class LayerView(View):
self._top_layers_job = None self._top_layers_job = None
self._activity = False self._activity = False
self._solid_layers = 5 Preferences.getInstance().addPreference("view/top_layer_count", 1)
Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count"))
self._top_layer_timer = QTimer() self._top_layer_timer = QTimer()
self._top_layer_timer.setInterval(50) self._top_layer_timer.setInterval(50)
@ -209,6 +213,16 @@ class LayerView(View):
self._top_layers_job = None self._top_layers_job = None
def _onPreferencesChanged(self, preference):
if preference != "view/top_layer_count":
return
self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count"))
self._current_layer_mesh = None
self._current_layer_jumps = None
self._top_layer_timer.start()
class _CreateTopLayersJob(Job): class _CreateTopLayersJob(Job):
def __init__(self, scene, layer_number, solid_layers): def __init__(self, scene, layer_number, solid_layers):
super().__init__() super().__init__()

View File

@ -5,7 +5,8 @@ from UM.Logger import Logger
from cura.SettingOverrideDecorator import SettingOverrideDecorator from cura.SettingOverrideDecorator import SettingOverrideDecorator
## The per object setting visibility handler ensures that only setting defintions that have a matching instance Container
# are returned as visible.
class PerObjectSettingVisibilityHandler(QObject): class PerObjectSettingVisibilityHandler(QObject):
def __init__(self, parent = None, *args, **kwargs): def __init__(self, parent = None, *args, **kwargs):
super().__init__(parent = parent, *args, **kwargs) super().__init__(parent = parent, *args, **kwargs)

View File

@ -1,75 +0,0 @@
# Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import Qt, pyqtSlot, QUrl
from UM.Application import Application
from UM.Qt.ListModel import ListModel
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
from UM.Scene.SceneNode import SceneNode
#from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator
#from UM.Settings.ProfileOverrideDecorator import ProfileOverrideDecorator
from . import SettingOverrideModel
class PerObjectSettingsModel(ListModel):
IdRole = Qt.UserRole + 1 # ID of the node
def __init__(self, parent = None):
super().__init__(parent)
self._scene = Application.getInstance().getController().getScene()
self._root = self._scene.getRoot()
self.addRoleName(self.IdRole,"id")
self._updateModel()
@pyqtSlot("quint64", str)
def setObjectProfile(self, object_id, profile_name):
self.setProperty(self.find("id", object_id), "profile", profile_name)
profile = None
'''if profile_name != "global":
profile = Application.getInstance().getMachineManager().findProfile(profile_name)
node = self._scene.findObject(object_id)
if profile:
if not node.getDecorator(ProfileOverrideDecorator):
node.addDecorator(ProfileOverrideDecorator())
node.callDecoration("setProfile", profile)
else:
if node.getDecorator(ProfileOverrideDecorator):
node.removeDecorator(ProfileOverrideDecorator)'''
@pyqtSlot("quint64", str)
def addOverride(self, object_id, key):
machine = Application.getInstance().getMachineManager().getActiveMachineInstance()
if not machine:
return
node = self._scene.findObject(object_id)
#if not node.getDecorator(SettingOverrideDecorator):
# node.addDecorator(SettingOverrideDecorator())
node.callDecoration("addSetting", key)
@pyqtSlot("quint64", str)
def removerOverride(self, object_id, key):
node = self._scene.findObject(object_id)
node.callDecoration("removeSetting", key)
#if len(node.callDecoration("getAllSettings")) == 0:
# node.removeDecorator(SettingOverrideDecorator)
def _updateModel(self):
self.clear()
for node in BreadthFirstIterator(self._root):
if type(node) is not SceneNode or not node.isSelectable():
continue
node_stack = node.callDecoration("getStack")
if not node_stack:
self.appendItem({
"id": id(node)
})

View File

@ -1,4 +1,4 @@
// Copyright (c) 2015 Ultimaker B.V. // Copyright (c) 2016 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher. // Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
@ -18,12 +18,6 @@ Item {
width: childrenRect.width; width: childrenRect.width;
height: childrenRect.height; height: childrenRect.height;
function updateContainerID()
{
console.log("containerid",UM.ActiveTool.properties.getValue("ContainerID"))
}
Column Column
{ {
id: items id: items
@ -32,6 +26,99 @@ Item {
spacing: UM.Theme.getSize("default_margin").height; spacing: UM.Theme.getSize("default_margin").height;
Row
{
ComboBox
{
id: extruderSelector
model: Cura.ExtrudersModel
{
id: extruders_model
}
visible: extruders_model.rowCount() > 1
textRole: "name"
width: items.width
height: UM.Theme.getSize("section").height
MouseArea
{
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: wheel.accepted = true;
}
style: ComboBoxStyle
{
background: Rectangle
{
color:
{
if(extruderSelector.hovered || base.activeFocus)
{
return UM.Theme.getColor("setting_control_highlight");
}
else
{
return extruders_model.getItem(extruderSelector.currentIndex).colour;
}
}
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("setting_control_border")
}
label: Item
{
Label
{
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_lining").width
anchors.right: downArrow.left
anchors.rightMargin: UM.Theme.getSize("default_lining").width
anchors.verticalCenter: parent.verticalCenter
text: extruderSelector.currentText
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("setting_control_disabled_text")
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
UM.RecolorImage
{
id: downArrow
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_lining").width * 2
anchors.verticalCenter: parent.verticalCenter
source: UM.Theme.getIcon("arrow_bottom")
width: UM.Theme.getSize("standard_arrow").width
height: UM.Theme.getSize("standard_arrow").height
sourceSize.width: width + 5
sourceSize.height: width + 5
color: UM.Theme.getColor("setting_control_text")
}
}
}
onActivated: UM.ActiveTool.setProperty("SelectedActiveExtruder", extruders_model.getItem(index).id);
onModelChanged: updateCurrentIndex();
function updateCurrentIndex()
{
for(var i = 0; i < extruders_model.rowCount(); ++i)
{
if(extruders_model.getItem(i).id == UM.ActiveTool.properties.getValue("SelectedActiveExtruder"))
{
extruderSelector.currentIndex = i;
return;
}
}
extruderSelector.currentIndex = -1;
}
}
}
Repeater Repeater
{ {
id: contents id: contents
@ -47,10 +134,13 @@ Item {
} }
} }
delegate: Loader delegate: Row
{ {
Loader
{
id: settingLoader
width: UM.Theme.getSize("setting").width; width: UM.Theme.getSize("setting").width;
height: UM.Theme.getSize("setting").height; height: UM.Theme.getSize("section").height;
property var definition: model property var definition: model
property var settingDefinitionsModel: addedSettingsModel property var settingDefinitionsModel: addedSettingsModel
@ -58,42 +148,77 @@ Item {
//Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
//In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
//causing nasty issues when selecting differnt options. So disable asynchronous loading of enum type completely. //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
asynchronous: model.type != "enum" asynchronous: model.type != "enum" && model.type != "extruder"
source: onLoaded: {
settingLoader.item.showRevertButton = false
settingLoader.item.showInheritButton = false
settingLoader.item.doDepthIndentation = false
}
sourceComponent:
{ {
switch(model.type) // TODO: This needs to be fixed properly. Got frustrated with it not working, so this is the patch job! switch(model.type)
{ {
case "int": case "int":
return "../../resources/qml/Settings/SettingTextField.qml" return settingTextField
case "float": case "float":
return "../../resources/qml/Settings/SettingTextField.qml" return settingTextField
case "enum": case "enum":
return "../../resources/qml/Settings/SettingComboBox.qml" return settingComboBox
case "extruder":
return settingExtruder
case "bool": case "bool":
return "../../resources/qml/Settings/SettingCheckBox.qml" return settingCheckBox
case "str": case "str":
return "../../resources/qml/Settings/SettingTextField.qml" return settingTextField
case "category": case "category":
return "../../resources/qml/Settings/SettingCategory.qml" return settingCategory
default: default:
return "../../resources/qml/Settings/SettingUnknown.qml" return settingUnknown
}
} }
} }
Button
{
width: UM.Theme.getSize("setting").height;
height: UM.Theme.getSize("setting").height;
onClicked: addedSettingsModel.setVisible(model.key, false);
style: ButtonStyle
{
background: Rectangle
{
color: control.hovered ? control.parent.style.controlHighlightColor : control.parent.style.controlColor;
UM.RecolorImage
{
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width/2
height: parent.height/2
sourceSize.width: width
sourceSize.height: width
color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button")
source: UM.Theme.getIcon("cross1")
}
}
}
}
UM.SettingPropertyProvider UM.SettingPropertyProvider
{ {
id: provider id: provider
containerStackId: UM.ActiveTool.properties.getValue("ContainerID") containerStackId: UM.ActiveTool.properties.getValue("ContainerID")
key: model.key key: model.key
watchedProperties: [ "value", "enabled", "state", "validationState" ] watchedProperties: [ "value", "enabled", "validationState" ]
storeIndex: 0 storeIndex: 0
} }
} }
} }
Button Button
{ {
id: customise_settings_button; id: customise_settings_button;
@ -158,11 +283,11 @@ Item {
{ {
if(text != "") if(text != "")
{ {
listview.model.filter = {"global_only": false, "label": "*" + text} listview.model.filter = {"settable_per_mesh": true, "label": "*" + text}
} }
else else
{ {
listview.model.filter = {"global_only": false} listview.model.filter = {"settable_per_mesh": true}
} }
} }
} }
@ -187,7 +312,7 @@ Item {
containerId: Cura.MachineManager.activeDefinitionId containerId: Cura.MachineManager.activeDefinitionId
filter: filter:
{ {
"global_only": false "settable_per_mesh": true
} }
visibilityHandler: UM.SettingPreferenceVisibilityHandler {} visibilityHandler: UM.SettingPreferenceVisibilityHandler {}
} }
@ -227,4 +352,46 @@ Item {
} }
SystemPalette { id: palette; } SystemPalette { id: palette; }
Component
{
id: settingTextField;
Cura.SettingTextField { }
}
Component
{
id: settingComboBox;
Cura.SettingComboBox { }
}
Component
{
id: settingExtruder;
Cura.SettingExtruder { }
}
Component
{
id: settingCheckBox;
Cura.SettingCheckBox { }
}
Component
{
id: settingCategory;
Cura.SettingCategory { }
}
Component
{
id: settingUnknown;
Cura.SettingUnknown { }
}
} }

View File

@ -1,19 +1,20 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2016 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher. # Uranium is released under the terms of the AGPLv3 or higher.
from UM.Tool import Tool from UM.Tool import Tool
from UM.Scene.Selection import Selection from UM.Scene.Selection import Selection
from UM.Application import Application from UM.Application import Application
from UM.Preferences import Preferences from UM.Preferences import Preferences
from cura.SettingOverrideDecorator import SettingOverrideDecorator
from . import PerObjectSettingsModel ## This tool allows the user to add & change settings per node in the scene.
# The settings per object are kept in a ContainerStack, which is linked to a node by decorator.
class PerObjectSettingsTool(Tool): class PerObjectSettingsTool(Tool):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._model = None self._model = None
self.setExposedProperties("SelectedObjectId","ContainerID") self.setExposedProperties("SelectedObjectId", "ContainerID", "SelectedActiveExtruder")
Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged) Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged)
Selection.selectionChanged.connect(self.propertyChanged) Selection.selectionChanged.connect(self.propertyChanged)
@ -33,21 +34,31 @@ class PerObjectSettingsTool(Tool):
return selected_object_id return selected_object_id
def getContainerID(self): def getContainerID(self):
try:
selected_object = Selection.getSelectedObject(0) selected_object = Selection.getSelectedObject(0)
if selected_object.getParent().callDecoration("isGroup"): if selected_object.getParent().callDecoration("isGroup"):
selected_object = selected_object.getParent() selected_object = selected_object.getParent()
try: try:
return selected_object.callDecoration("getStack").getId() return selected_object.callDecoration("getStack").getId()
except: except AttributeError:
print(":(") return ""
return
except:
print(":((")
return
def setContainerID(self, value): ## Gets the active extruder of the currently selected object.
pass #
# \return The active extruder of the currently selected object.
def getSelectedActiveExtruder(self):
selected_object = Selection.getSelectedObject(0)
selected_object.callDecoration("getActiveExtruder")
## Changes the active extruder of the currently selected object.
#
# \param extruder_stack_id The ID of the extruder to print the currently
# selected object with.
def setSelectedActiveExtruder(self, extruder_stack_id):
selected_object = Selection.getSelectedObject(0)
stack = selected_object.callDecoration("getStack") #Don't try to get the active extruder since it may be None anyway.
if not stack:
selected_object.addDecorator(SettingOverrideDecorator())
selected_object.callDecoration("setActiveExtruder", extruder_stack_id)
def _onPreferenceChanged(self, preference): def _onPreferenceChanged(self, preference):
if preference == "cura/active_mode": if preference == "cura/active_mode":

View File

@ -1,138 +0,0 @@
# Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import Qt, pyqtSlot, QUrl
from UM.Application import Application
from UM.Qt.ListModel import ListModel
#from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator
class SettingOverrideModel(ListModel):
KeyRole = Qt.UserRole + 1
LabelRole = Qt.UserRole + 2
DescriptionRole = Qt.UserRole + 3
ValueRole = Qt.UserRole + 4
TypeRole = Qt.UserRole + 5
UnitRole = Qt.UserRole + 6
ValidRole = Qt.UserRole + 7
OptionsRole = Qt.UserRole + 8
WarningDescriptionRole = Qt.UserRole + 9
ErrorDescriptionRole = Qt.UserRole + 10
GlobalOnlyRole = Qt.UserRole + 11
def __init__(self, node, parent = None):
super().__init__(parent)
self._ignore_setting_change = None
self._node = node
self._node.decoratorsChanged.connect(self._onDecoratorsChanged)
self._onDecoratorsChanged(None)
#self._activeProfile = Application.getInstance().getMachineManager().getWorkingProfile() #To be able to get notified when a setting changes.
#self._activeProfile.settingValueChanged.connect(self._onProfileSettingValueChanged)
#Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onProfileChanged)
self.addRoleName(self.KeyRole, "key")
self.addRoleName(self.LabelRole, "label")
self.addRoleName(self.DescriptionRole, "description")
self.addRoleName(self.ValueRole,"value")
self.addRoleName(self.TypeRole, "type")
self.addRoleName(self.UnitRole, "unit")
self.addRoleName(self.ValidRole, "valid")
self.addRoleName(self.OptionsRole, "options")
self.addRoleName(self.WarningDescriptionRole, "warning_description")
self.addRoleName(self.ErrorDescriptionRole, "error_description")
self.addRoleName(self.GlobalOnlyRole, "global_only")
@pyqtSlot(str, "QVariant")
def setSettingValue(self, key, value):
if not self._decorator:
return
self._decorator.setSettingValue(key, value)
def _onDecoratorsChanged(self, node):
return
'''if not self._node.getDecorator(SettingOverrideDecorator):
self.clear()
return
self._decorator = self._node.getDecorator(SettingOverrideDecorator)
self._decorator.settingAdded.connect(self._onSettingsChanged)
self._decorator.settingRemoved.connect(self._onSettingsChanged)
self._decorator.settingValueChanged.connect(self._onSettingValueChanged)
self._onSettingsChanged()'''
def _createOptionsModel(self, options):
if not options:
return None
model = ListModel()
model.addRoleName(Qt.UserRole + 1, "value")
model.addRoleName(Qt.UserRole + 2, "name")
for value, name in options.items():
model.appendItem({"value": str(value), "name": str(name)})
return model
## Updates the active profile in this model if the active profile is
# changed.
#
# This links the settingValueChanged of the new profile to this model's
# _onSettingValueChanged function, so that it properly listens to those
# events again.
def _onProfileChanged(self):
if self._activeProfile: #Unlink from the old profile.
self._activeProfile.settingValueChanged.disconnect(self._onProfileSettingValueChanged)
old_profile = self._activeProfile
self._activeProfile = Application.getInstance().getMachineManager().getWorkingProfile()
self._activeProfile.settingValueChanged.connect(self._onProfileSettingValueChanged) #Re-link to the new profile.
for setting_name in old_profile.getChangedSettings().keys(): #Update all changed settings in the old and new profiles.
self._onProfileSettingValueChanged(setting_name)
for setting_name in self._activeProfile.getChangedSettings().keys():
self._onProfileSettingValueChanged(setting_name)
## Updates the global_only property of a setting once a setting value
# changes.
#
# This method should only get called on settings that are dependent on the
# changed setting.
#
# \param setting_name The setting that needs to be updated.
def _onProfileSettingValueChanged(self, setting_name):
index = self.find("key", setting_name)
if index != -1:
self.setProperty(index, "global_only", Application.getInstance().getMachineManager().getActiveMachineInstance().getMachineDefinition().getSetting(setting_name).getGlobalOnly())
def _onSettingsChanged(self):
self.clear()
items = []
for key, setting in self._decorator.getAllSettings().items():
value = self._decorator.getSettingValue(key)
items.append({
"key": key,
"label": setting.getLabel(),
"description": setting.getDescription(),
"value": str(value),
"type": setting.getType(),
"unit": setting.getUnit(),
"valid": setting.validate(value),
"options": self._createOptionsModel(setting.getOptions()),
"warning_description": setting.getWarningDescription(),
"error_description": setting.getErrorDescription(),
"global_only": setting.getGlobalOnly()
})
items.sort(key = lambda i: i["key"])
for item in items:
self.appendItem(item)
def _onSettingValueChanged(self, setting):
index = self.find("key", setting.getKey())
value = self._decorator.getSettingValue(setting.getKey())
if index != -1:
self.setProperty(index, "value", str(value))
self.setProperty(index, "valid", setting.validate(value))
self.setProperty(index, "global_only", setting.getGlobalOnly())

View File

@ -13,7 +13,7 @@ def getMetaData():
"author": "Ultimaker B.V.", "author": "Ultimaker B.V.",
"description": catalog.i18nc("@info:whatsthis", "Provides removable drive hotplugging and writing support."), "description": catalog.i18nc("@info:whatsthis", "Provides removable drive hotplugging and writing support."),
"version": "1.0", "version": "1.0",
"api": 2 "api": 3
} }
} }

View File

@ -45,6 +45,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
self.addMetaDataEntry("material", material.text) self.addMetaDataEntry("material", material.text)
self.addMetaDataEntry("color_name", color.text) self.addMetaDataEntry("color_name", color.text)
continue
self.addMetaDataEntry(tag_name, entry.text) self.addMetaDataEntry(tag_name, entry.text)
property_values = {} property_values = {}
@ -78,6 +80,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
if key in self.__material_property_setting_map: if key in self.__material_property_setting_map:
self.setProperty(self.__material_property_setting_map[key], "value", entry.text, self._definition) self.setProperty(self.__material_property_setting_map[key], "value", entry.text, self._definition)
global_setting_values[self.__material_property_setting_map[key]] = entry.text global_setting_values[self.__material_property_setting_map[key]] = entry.text
else:
Logger.log("d", "Unsupported material setting %s", key)
machines = data.iterfind("./um:settings/um:machine", self.__namespaces) machines = data.iterfind("./um:settings/um:machine", self.__namespaces)
for machine in machines: for machine in machines:
@ -87,6 +91,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
key = entry.get("key") key = entry.get("key")
if key in self.__material_property_setting_map: if key in self.__material_property_setting_map:
machine_setting_values[self.__material_property_setting_map[key]] = entry.text machine_setting_values[self.__material_property_setting_map[key]] = entry.text
else:
Logger.log("d", "Unsupported material setting %s", key)
identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces) identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces)
for identifier in identifiers: for identifier in identifiers:
@ -100,28 +106,74 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
Logger.log("w", "No definition found for machine ID %s", machine_id) Logger.log("w", "No definition found for machine ID %s", machine_id)
continue continue
definition = definitions[0]
new_material = XmlMaterialProfile(self.id + "_" + machine_id) new_material = XmlMaterialProfile(self.id + "_" + machine_id)
new_material.setName(self.getName()) new_material.setName(self.getName())
new_material.setMetaData(self.getMetaData()) new_material.setMetaData(copy.deepcopy(self.getMetaData()))
new_material.setDefinition(definitions[0]) new_material.setDefinition(definition)
for key, value in global_setting_values.items(): for key, value in global_setting_values.items():
new_material.setProperty(key, "value", value, definitions[0]) new_material.setProperty(key, "value", value, definition)
for key, value in machine_setting_values.items(): for key, value in machine_setting_values.items():
new_material.setProperty(key, "value", value, definitions[0]) new_material.setProperty(key, "value", value, definition)
new_material._dirty = False new_material._dirty = False
UM.Settings.ContainerRegistry.getInstance().addContainer(new_material) UM.Settings.ContainerRegistry.getInstance().addContainer(new_material)
hotends = machine.iterfind("./um:hotend", self.__namespaces)
for hotend in hotends:
hotend_id = hotend.get("id")
if hotend_id is None:
continue
variant_containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = hotend_id)
if not variant_containers:
# It is not really properly defined what "ID" is so also search for variants by name.
variant_containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(definition = definition.id, name = hotend_id)
if not variant_containers:
Logger.log("d", "No variants found with ID or name %s for machine %s", hotend_id, definition.id)
continue
new_hotend_material = XmlMaterialProfile(self.id + "_" + machine_id + "_" + hotend_id.replace(" ", "_"))
new_hotend_material.setName(self.getName())
new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData()))
new_hotend_material.setDefinition(definition)
new_hotend_material.addMetaDataEntry("variant", variant_containers[0].id)
for key, value in global_setting_values.items():
new_hotend_material.setProperty(key, "value", value, definition)
for key, value in machine_setting_values.items():
new_hotend_material.setProperty(key, "value", value, definition)
settings = hotend.iterfind("./um:setting", self.__namespaces)
for entry in settings:
key = entry.get("key")
if key in self.__material_property_setting_map:
new_hotend_material.setProperty(self.__material_property_setting_map[key], "value", entry.text, definition)
else:
Logger.log("d", "Unsupported material setting %s", key)
new_hotend_material._dirty = False
UM.Settings.ContainerRegistry.getInstance().addContainer(new_hotend_material)
# Map XML file setting names to internal names
__material_property_setting_map = { __material_property_setting_map = {
"print temperature": "material_print_temperature", "print temperature": "material_print_temperature",
"heated bed temperature": "material_bed_temperature", "heated bed temperature": "material_bed_temperature",
"standby temperature": "material_standby_temperature", "standby temperature": "material_standby_temperature",
"print cooling": "cool_fan_speed",
"retraction amount": "retraction_amount",
"retraction speed": "retraction_speed",
} }
# Map XML file product names to internal ids
__product_id_map = { __product_id_map = {
"Ultimaker2": "ultimaker2", "Ultimaker2": "ultimaker2",
"Ultimaker2+": "ultimaker2_plus", "Ultimaker2+": "ultimaker2_plus",

View File

@ -22,9 +22,13 @@
{ {
"label": "Extruder", "label": "Extruder",
"description": "The extruder train used for printing. This is used in multi-extrusion.", "description": "The extruder train used for printing. This is used in multi-extrusion.",
"type": "int", "type": "extruder",
"default_value": 0, "default_value": 0,
"minimum_value": "0" "minimum_value": "0",
"settable_per_mesh": true,
"settable_per_extruder": false,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_nozzle_offset_x": "machine_nozzle_offset_x":
{ {
@ -33,7 +37,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_nozzle_offset_y": "machine_nozzle_offset_y":
{ {
@ -42,7 +49,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_start_code": "machine_extruder_start_code":
{ {
@ -50,7 +60,10 @@
"description": "Start g-code to execute whenever turning the extruder on.", "description": "Start g-code to execute whenever turning the extruder on.",
"type": "str", "type": "str",
"default_value": "", "default_value": "",
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_start_pos_abs": "machine_extruder_start_pos_abs":
{ {
@ -58,7 +71,10 @@
"description": "Make the extruder starting position absolute rather than relative to the last-known location of the head.", "description": "Make the extruder starting position absolute rather than relative to the last-known location of the head.",
"type": "bool", "type": "bool",
"default_value": false, "default_value": false,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_start_pos_x": "machine_extruder_start_pos_x":
{ {
@ -67,7 +83,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_start_pos_y": "machine_extruder_start_pos_y":
{ {
@ -76,7 +95,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_end_code": "machine_extruder_end_code":
{ {
@ -84,7 +106,10 @@
"description": "End g-code to execute whenever turning the extruder off.", "description": "End g-code to execute whenever turning the extruder off.",
"type": "str", "type": "str",
"default_value": "", "default_value": "",
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_end_pos_abs": "machine_extruder_end_pos_abs":
{ {
@ -92,7 +117,10 @@
"description": "Make the extruder ending position absolute rather than relative to the last-known location of the head.", "description": "Make the extruder ending position absolute rather than relative to the last-known location of the head.",
"type": "bool", "type": "bool",
"default_value": false, "default_value": false,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_end_pos_x": "machine_extruder_end_pos_x":
{ {
@ -101,7 +129,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_end_pos_y": "machine_extruder_end_pos_y":
{ {
@ -110,7 +141,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -5,10 +5,7 @@
"inherits": "fdmprinter", "inherits": "fdmprinter",
"metadata": { "metadata": {
"author": "Ultimaker", "author": "Ultimaker",
"manufacturer": "Ultimaker", "manufacturer": "Ultimaker"
"visible": false, "visible": false,
"preferred_profile": "Normal Quality",
"preferred_nozzle": "0.4 mm",
"preferred_material": "PLA"
} }
} }

View File

@ -12,8 +12,12 @@
"platform": "ultimaker2_platform.obj", "platform": "ultimaker2_platform.obj",
"platform_texture": "Ultimaker2Plusbackplate.png", "platform_texture": "Ultimaker2Plusbackplate.png",
"preferred_variant": "ultimaker2_plus_0.4", "preferred_variant": "ultimaker2_plus_0.4",
"preferred_material": "pla", "preferred_material": "*pla*",
"preferred_quality": "high" "preferred_quality": "*normal*",
"has_variants": true,
"has_materials": true,
"has_machine_materials": true,
"has_machine_quality": true
}, },
"overrides": { "overrides": {

View File

@ -11,6 +11,9 @@
"file_formats": "text/x-gcode", "file_formats": "text/x-gcode",
"icon": "icon_ultimaker.png", "icon": "icon_ultimaker.png",
"platform": "ultimaker_platform.stl", "platform": "ultimaker_platform.stl",
"has_materials": true,
"preferred_material": "*pla*",
"preferred_quality": "*normal*",
"pages": [ "pages": [
"SelectUpgradedParts", "SelectUpgradedParts",
"UpgradeFirmware", "UpgradeFirmware",

View File

@ -1,9 +0,0 @@
[general]
version = 2
name = high
definition = fdmprinter
[metadata]
type = quality
[values]

View File

@ -1,9 +0,0 @@
[general]
version = 2
name = normal
definition = fdmprinter
[metadata]
type = quality
[values]

View File

@ -1,12 +0,0 @@
[general]
version = 2
name = ABS
definition = fdmprinter
[metadata]
type = material
[values]
material_print_temperature = 250
material_bed_temperature = 80
material_flow = 107

View File

@ -1,11 +0,0 @@
[general]
version = 2
name = CPE
definition = fdmprinter
[metadata]
type = material
[values]
material_print_temperature = 250
material_bed_temperature = 70

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Generic PLA profile. Serves as an example file, data in this file is not correct.
-->
<fdmmaterial xmlns="http://www.ultimaker.com/material">
<metadata>
<name>
<brand>Generic</brand>
<material>ABS</material>
<color>Generic</color>
</name>
<GUID>506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9</GUID>
<version>0</version>
<color_code>#FF0000</color_code>
</metadata>
<properties>
<density>1.07</density>
<diameter>2.85</diameter>
</properties>
<settings>
<setting key="print temperature">250</setting>
<setting key="heated bed temperature">80</setting>
<machine>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2extended+"/>
<hotend id="0.25 mm" />
<hotend id="0.4 mm" />
<hotend id="0.6 mm" />
<hotend id="0.8 mm" />
</machine>
</settings>
</fdmmaterial>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Generic PLA profile. Serves as an example file, data in this file is not correct.
-->
<fdmmaterial xmlns="http://www.ultimaker.com/material">
<metadata>
<name>
<brand>Generic</brand>
<material>CPE</material>
<color>Generic</color>
</name>
<GUID>506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9</GUID>
<version>0</version>
<color_code>#0000FF</color_code>
</metadata>
<properties>
<density>0.94</density>
<diameter>2.85</diameter>
</properties>
<settings>
<setting key="print temperature">250</setting>
<setting key="heated bed temperature">70</setting>
<machine>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2extended+"/>
<hotend id="0.25 mm" />
<hotend id="0.4 mm" />
<hotend id="0.6 mm" />
<hotend id="0.8 mm" />
</machine>
</settings>
</fdmmaterial>

View File

@ -11,7 +11,7 @@ Generic PLA profile. Serves as an example file, data in this file is not correct
</name> </name>
<GUID>506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9</GUID> <GUID>506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9</GUID>
<version>0</version> <version>0</version>
<color_code>#FFFFFF</color_code> <color_code>#00FF00</color_code>
</metadata> </metadata>
<properties> <properties>
<density>1.3</density> <density>1.3</density>
@ -20,28 +20,15 @@ Generic PLA profile. Serves as an example file, data in this file is not correct
<settings> <settings>
<setting key="print temperature">210</setting> <setting key="print temperature">210</setting>
<setting key="heated bed temperature">60</setting> <setting key="heated bed temperature">60</setting>
<setting key="standby temperature">175</setting>
<machine> <machine>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2+"/> <machine_identifier manufacturer="Ultimaker" product="Ultimaker2+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2extended+"/> <machine_identifier manufacturer="Ultimaker" product="Ultimaker2extended+"/>
<setting key="standby temperature">150</setting>
<setting key="processing temperature graph">
<point flow="2" temperature="180"/>
<point flow="10" temperature="230"/>
</setting>
</machine>
<machine> <hotend id="0.25 mm" />
<machine_identifier manufacturer="Ultimaker" product="Ultimaker Original"/> <hotend id="0.4 mm" />
<machine_identifier manufacturer="Ultimaker" product="Ultimaker Original+"/> <hotend id="0.6 mm" />
<setting key="standby temperature">150</setting> <hotend id="0.8 mm" />
<hotend id="0.8mm">
<setting key="standby temperature">80</setting>
</hotend>
<hotend id="0.6mm">
<setting key="standby temperature">100</setting>
</hotend>
</machine> </machine>
</settings> </settings>
</fdmmaterial> </fdmmaterial>

View File

@ -1,10 +0,0 @@
[general]
version = 2
name = PLA
definition = fdmprinter
[metadata]
type = material
[values]
material_bed_temperature = 60

View File

@ -1,10 +0,0 @@
[general]
version = 1
name = High Quality
weight = -3
[settings]
layer_height = 0.06
speed_topbottom = 15
speed_infill = 80

View File

@ -1,8 +0,0 @@
[general]
version = 1
name = Normal Quality
weight = -2
[settings]
speed_topbottom = 15
speed_infill = 80

View File

@ -1,9 +0,0 @@
[general]
version = 1
name = Ulti Quality
weight = -4
[settings]
layer_height = 0.04
speed_topbottom = 15
speed_infill = 80

View File

@ -1,9 +0,0 @@
[general]
version = 1
type = material
name = ABS
[settings]
material_print_temperature = 250
material_bed_temperature = 80
material_flow = 107

View File

@ -1,8 +0,0 @@
[general]
version = 1
type = material
name = CPE
[settings]
material_print_temperature = 250
material_bed_temperature = 70

View File

@ -1,7 +0,0 @@
[general]
version = 1
type = material
name = PLA
[settings]
material_bed_temperature = 60

View File

@ -1,21 +0,0 @@
[general]
version = 1
name = Ulti Quality
machine_type = ultimaker2plus
machine_variant = 0.4 mm
material = PLA
weight = -4
[settings]
line_width = 0.35
layer_height = 0.04
layer_height_0 = 0.26
wall_thickness = 1.4
top_bottom_thickness = 1.12
infill_sparse_density = 25
speed_print = 30
speed_infill = 50
speed_wall_x = 40
speed_topbottom = 20
speed_layer_0 = 25
cool_min_layer_time_fan_speed_max = 15

View File

@ -6,6 +6,7 @@ pragma Singleton
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import UM 1.1 as UM import UM 1.1 as UM
import Cura 1.0 as Cura
Item Item
{ {
@ -109,24 +110,24 @@ Item
Action Action
{ {
id: updateProfileAction; id: updateProfileAction;
enabled: UM.ActiveProfile.valid && !UM.ActiveProfile.readOnly && UM.ActiveProfile.hasCustomisedValues enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
text: catalog.i18nc("@action:inmenu menubar:profile","&Update Current Profile"); text: catalog.i18nc("@action:inmenu menubar:profile","&Update profile with current settings");
onTriggered: UM.ActiveProfile.updateProfile(); onTriggered: Cura.MachineManager.updateQualityContainerFromUserContainer()
} }
Action Action
{ {
id: resetProfileAction; id: resetProfileAction;
enabled: UM.ActiveProfile.valid && UM.ActiveProfile.hasCustomisedValues enabled: Cura.MachineManager.hasUserSettings
text: catalog.i18nc("@action:inmenu menubar:profile","&Reload Current Profile"); text: catalog.i18nc("@action:inmenu menubar:profile","&Discard current settings");
onTriggered: UM.ActiveProfile.discardChanges(); onTriggered: Cura.MachineManager.clearUserSettings();
} }
Action Action
{ {
id: addProfileAction; id: addProfileAction;
enabled: UM.ActiveProfile.valid enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings
text: catalog.i18nc("@action:inmenu menubar:profile","&Create New Profile..."); text: catalog.i18nc("@action:inmenu menubar:profile","&Create profile from current settings...");
} }
Action Action

View File

@ -10,8 +10,6 @@ import QtQuick.Dialogs 1.1
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
import "."
UM.MainWindow UM.MainWindow
{ {
id: base id: base
@ -56,7 +54,7 @@ UM.MainWindow
title: catalog.i18nc("@title:menu menubar:toplevel","&File"); title: catalog.i18nc("@title:menu menubar:toplevel","&File");
MenuItem { MenuItem {
action: Actions.open; action: Cura.Actions.open;
} }
Menu Menu
@ -95,7 +93,7 @@ UM.MainWindow
text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File"); text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File");
enabled: UM.Selection.hasSelection; enabled: UM.Selection.hasSelection;
iconName: "document-save-as"; iconName: "document-save-as";
onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", Printer.jobName, { "filter_by_machine": false }); onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false });
} }
Menu Menu
{ {
@ -111,18 +109,18 @@ UM.MainWindow
MenuItem MenuItem
{ {
text: model.description; text: model.description;
onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id, Printer.jobName, { "filter_by_machine": false }); onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id, PrintInformation.jobName, { "filter_by_machine": false });
} }
onObjectAdded: saveAllMenu.insertItem(index, object) onObjectAdded: saveAllMenu.insertItem(index, object)
onObjectRemoved: saveAllMenu.removeItem(object) onObjectRemoved: saveAllMenu.removeItem(object)
} }
} }
MenuItem { action: Actions.reloadAll; } MenuItem { action: Cura.Actions.reloadAll; }
MenuSeparator { } MenuSeparator { }
MenuItem { action: Actions.quit; } MenuItem { action: Cura.Actions.quit; }
} }
Menu Menu
@ -130,17 +128,17 @@ UM.MainWindow
//: Edit menu //: Edit menu
title: catalog.i18nc("@title:menu menubar:toplevel","&Edit"); title: catalog.i18nc("@title:menu menubar:toplevel","&Edit");
MenuItem { action: Actions.undo; } MenuItem { action: Cura.Actions.undo; }
MenuItem { action: Actions.redo; } MenuItem { action: Cura.Actions.redo; }
MenuSeparator { } MenuSeparator { }
MenuItem { action: Actions.deleteSelection; } MenuItem { action: Cura.Actions.deleteSelection; }
MenuItem { action: Actions.deleteAll; } MenuItem { action: Cura.Actions.deleteAll; }
MenuItem { action: Actions.resetAllTranslation; } MenuItem { action: Cura.Actions.resetAllTranslation; }
MenuItem { action: Actions.resetAll; } MenuItem { action: Cura.Actions.resetAll; }
MenuSeparator { } MenuSeparator { }
MenuItem { action: Actions.groupObjects;} MenuItem { action: Cura.Actions.groupObjects;}
MenuItem { action: Actions.mergeObjects;} MenuItem { action: Cura.Actions.mergeObjects;}
MenuItem { action: Actions.unGroupObjects;} MenuItem { action: Cura.Actions.unGroupObjects;}
} }
Menu Menu
@ -180,7 +178,7 @@ UM.MainWindow
text: model.name; text: model.name;
checkable: true; checkable: true;
checked: Cura.MachineManager.activeMachineId == model.id checked: Cura.MachineManager.activeMachineId == model.id
exclusiveGroup: machineSelectionMenuGroup; exclusiveGroup: machineMenuGroup;
onTriggered: Cura.MachineManager.setActiveMachine(model.id); onTriggered: Cura.MachineManager.setActiveMachine(model.id);
} }
onObjectAdded: machineMenu.insertItem(index, object) onObjectAdded: machineMenu.insertItem(index, object)
@ -216,8 +214,8 @@ UM.MainWindow
MenuSeparator { visible: Cura.MachineManager.hasVariants; } MenuSeparator { visible: Cura.MachineManager.hasVariants; }
MenuItem { action: Actions.addMachine; } MenuItem { action: Cura.Actions.addMachine; }
MenuItem { action: Actions.configureMachines; } MenuItem { action: Cura.Actions.configureMachines; }
} }
Menu Menu
@ -228,7 +226,26 @@ UM.MainWindow
Instantiator Instantiator
{ {
id: profileMenuInstantiator id: profileMenuInstantiator
// model: UM.ProfilesModel {} model: UM.InstanceContainersModel
{
filter:
{
var result = { "type": "quality" };
if(Cura.MachineManager.filterQualityByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId;
if(Cura.MachineManager.hasMaterials)
{
result.material = Cura.MachineManager.activeMaterialId;
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
}
property int separatorIndex: -1 property int separatorIndex: -1
Loader { Loader {
@ -271,30 +288,20 @@ UM.MainWindow
{ {
id: item id: item
text: model_data ? model_data.name : "" text: model_data ? model_data.name : ""
checkable: true; checkable: true
checked: model_data ? model_data.active : false; checked: Cura.MachineManager.activeQualityId == model_data.id
exclusiveGroup: profileMenuGroup; exclusiveGroup: profileMenuGroup
onTriggered: onTriggered: Cura.MachineManager.setActiveQuality(model_data.id)
{
UM.MachineManager.setActiveProfile(model_data.name);
if (!model_data.active) {
//Selecting a profile was canceled; undo menu selection
profileMenuInstantiator.model.setProperty(model_index, "active", false);
var activeProfileName = UM.MachineManager.activeProfile;
var activeProfileIndex = profileMenuInstantiator.model.find("name", activeProfileName);
profileMenuInstantiator.model.setProperty(activeProfileIndex, "active", true);
}
}
} }
} }
MenuSeparator { id: profileMenuSeparator } MenuSeparator { id: profileMenuSeparator }
MenuItem { action: Actions.updateProfile; } MenuItem { action: Cura.Actions.addProfile }
MenuItem { action: Actions.resetProfile; } MenuItem { action: Cura.Actions.updateProfile }
MenuItem { action: Actions.addProfile; } MenuItem { action: Cura.Actions.resetProfile }
MenuSeparator { } MenuSeparator { }
MenuItem { action: Actions.manageProfiles; } MenuItem { action: Cura.Actions.manageProfiles }
} }
Menu Menu
@ -305,7 +312,7 @@ UM.MainWindow
Instantiator Instantiator
{ {
id: extenions id: extensions
model: UM.ExtensionModel { } model: UM.ExtensionModel { }
Menu Menu
@ -320,7 +327,7 @@ UM.MainWindow
MenuItem MenuItem
{ {
text: model.text text: model.text
onTriggered: extenions.model.subMenuTriggered(name, model.text) onTriggered: extensions.model.subMenuTriggered(name, model.text)
} }
onObjectAdded: sub_menu.insertItem(index, object) onObjectAdded: sub_menu.insertItem(index, object)
onObjectRemoved: sub_menu.removeItem(object) onObjectRemoved: sub_menu.removeItem(object)
@ -337,7 +344,7 @@ UM.MainWindow
//: Settings menu //: Settings menu
title: catalog.i18nc("@title:menu menubar:toplevel","&Settings"); title: catalog.i18nc("@title:menu menubar:toplevel","&Settings");
MenuItem { action: Actions.preferences; } MenuItem { action: Cura.Actions.preferences; }
} }
Menu Menu
@ -345,11 +352,11 @@ UM.MainWindow
//: Help menu //: Help menu
title: catalog.i18nc("@title:menu menubar:toplevel","&Help"); title: catalog.i18nc("@title:menu menubar:toplevel","&Help");
MenuItem { action: Actions.showEngineLog; } MenuItem { action: Cura.Actions.showEngineLog; }
MenuItem { action: Actions.documentation; } MenuItem { action: Cura.Actions.documentation; }
MenuItem { action: Actions.reportBug; } MenuItem { action: Cura.Actions.reportBug; }
MenuSeparator { } MenuSeparator { }
MenuItem { action: Actions.about; } MenuItem { action: Cura.Actions.about; }
} }
} }
@ -439,7 +446,7 @@ UM.MainWindow
left: parent.left; left: parent.left;
//leftMargin: UM.Theme.getSize("loadfile_margin").width //leftMargin: UM.Theme.getSize("loadfile_margin").width
} }
action: Actions.open; action: Cura.Actions.open;
} }
Image Image
@ -526,13 +533,6 @@ UM.MainWindow
} }
width: UM.Theme.getSize("sidebar").width; width: UM.Theme.getSize("sidebar").width;
addMachineAction: Actions.addMachine;
configureMachinesAction: Actions.configureMachines;
addProfileAction: Actions.addProfile;
updateProfileAction: Actions.updateProfile;
resetProfileAction: Actions.resetProfile;
manageProfilesAction: Actions.manageProfiles;
} }
} }
} }
@ -573,16 +573,16 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.preferences target: Cura.Actions.preferences
onTriggered: preferences.visible = true onTriggered: preferences.visible = true
} }
Connections Connections
{ {
target: Actions.addProfile target: Cura.Actions.addProfile
onTriggered: onTriggered:
{ {
UM.MachineManager.createProfile(); Cura.MachineManager.newQualityContainerFromQualityAndUser();
preferences.setPage(5); preferences.setPage(5);
preferences.show(); preferences.show();
@ -593,7 +593,7 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.configureMachines target: Cura.Actions.configureMachines
onTriggered: onTriggered:
{ {
preferences.visible = true; preferences.visible = true;
@ -603,7 +603,7 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.manageProfiles target: Cura.Actions.manageProfiles
onTriggered: onTriggered:
{ {
preferences.visible = true; preferences.visible = true;
@ -613,7 +613,7 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.configureSettingVisibility target: Cura.Actions.configureSettingVisibility
onTriggered: onTriggered:
{ {
preferences.visible = true; preferences.visible = true;
@ -636,22 +636,22 @@ UM.MainWindow
id: objectContextMenu; id: objectContextMenu;
property variant objectId: -1; property variant objectId: -1;
MenuItem { action: Actions.centerObject; } MenuItem { action: Cura.Actions.centerObject; }
MenuItem { action: Actions.deleteObject; } MenuItem { action: Cura.Actions.deleteObject; }
MenuItem { action: Actions.multiplyObject; } MenuItem { action: Cura.Actions.multiplyObject; }
MenuSeparator { } MenuSeparator { }
MenuItem { action: Actions.deleteAll; } MenuItem { action: Cura.Actions.deleteAll; }
MenuItem { action: Actions.reloadAll; } MenuItem { action: Cura.Actions.reloadAll; }
MenuItem { action: Actions.resetAllTranslation; } MenuItem { action: Cura.Actions.resetAllTranslation; }
MenuItem { action: Actions.resetAll; } MenuItem { action: Cura.Actions.resetAll; }
MenuSeparator { } MenuSeparator { }
MenuItem { action: Actions.groupObjects; } MenuItem { action: Cura.Actions.groupObjects; }
MenuItem { action: Actions.mergeObjects; } MenuItem { action: Cura.Actions.mergeObjects; }
MenuItem { action: Actions.unGroupObjects; } MenuItem { action: Cura.Actions.unGroupObjects; }
Connections Connections
{ {
target: Actions.deleteObject target: Cura.Actions.deleteObject
onTriggered: onTriggered:
{ {
if(objectContextMenu.objectId != 0) if(objectContextMenu.objectId != 0)
@ -664,7 +664,7 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.multiplyObject target: Cura.Actions.multiplyObject
onTriggered: onTriggered:
{ {
if(objectContextMenu.objectId != 0) if(objectContextMenu.objectId != 0)
@ -677,7 +677,7 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.centerObject target: Cura.Actions.centerObject
onTriggered: onTriggered:
{ {
if(objectContextMenu.objectId != 0) if(objectContextMenu.objectId != 0)
@ -692,14 +692,14 @@ UM.MainWindow
Menu Menu
{ {
id: contextMenu; id: contextMenu;
MenuItem { action: Actions.deleteAll; } MenuItem { action: Cura.Actions.deleteAll; }
MenuItem { action: Actions.reloadAll; } MenuItem { action: Cura.Actions.reloadAll; }
MenuItem { action: Actions.resetAllTranslation; } MenuItem { action: Cura.Actions.resetAllTranslation; }
MenuItem { action: Actions.resetAll; } MenuItem { action: Cura.Actions.resetAll; }
MenuSeparator { } MenuSeparator { }
MenuItem { action: Actions.groupObjects; } MenuItem { action: Cura.Actions.groupObjects; }
MenuItem { action: Actions.mergeObjects; } MenuItem { action: Cura.Actions.mergeObjects; }
MenuItem { action: Actions.unGroupObjects; } MenuItem { action: Cura.Actions.unGroupObjects; }
} }
Connections Connections
@ -720,13 +720,13 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.quit target: Cura.Actions.quit
onTriggered: base.visible = false; onTriggered: base.visible = false;
} }
Connections Connections
{ {
target: Actions.toggleFullScreen target: Cura.Actions.toggleFullScreen
onTriggered: base.toggleFullscreen(); onTriggered: base.toggleFullscreen();
} }
@ -756,7 +756,7 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.open target: Cura.Actions.open
onTriggered: openDialog.open() onTriggered: openDialog.open()
} }
@ -767,7 +767,7 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.showEngineLog target: Cura.Actions.showEngineLog
onTriggered: engineLog.visible = true; onTriggered: engineLog.visible = true;
} }
@ -778,7 +778,7 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.addMachine target: Cura.Actions.addMachine
onTriggered: addMachineDialog.visible = true; onTriggered: addMachineDialog.visible = true;
} }
@ -789,7 +789,7 @@ UM.MainWindow
Connections Connections
{ {
target: Actions.about target: Cura.Actions.about
onTriggered: aboutDialog.visible = true; onTriggered: aboutDialog.visible = true;
} }

View File

@ -5,7 +5,6 @@ import QtQuick 2.1
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import QtQml.Models 2.2
import UM 1.1 as UM import UM 1.1 as UM
@ -207,10 +206,11 @@ UM.PreferencesPage
} }
} }
DelegateModel ListView
{ {
id: plugins id: plugins
model: UM.PluginsModel { } model: UM.PluginsModel { }
visible: false
} }
} }
} }

View File

@ -10,62 +10,25 @@ import UM 1.1 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Rectangle { Rectangle {
id: base; id: base
property bool activity: Printer.getPlatformActivity; property bool activity: Printer.getPlatformActivity
property string fileBaseName property string fileBaseName
property variant activeMachineName: Cura.MachineManager.activeMachineName property variant activeMachineName: Cura.MachineManager.activeMachineName
onActiveMachineNameChanged: onActiveMachineNameChanged:
{ {
base.createFileName() printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
} }
UM.I18nCatalog { id: catalog; name:"cura"} UM.I18nCatalog { id: catalog; name:"cura"}
property variant printDuration: PrintInformation.currentPrintTime; property variant printDuration: PrintInformation.currentPrintTime
property real printMaterialAmount: PrintInformation.materialAmount; property real printMaterialAmount: PrintInformation.materialAmount
height: childrenRect.height height: childrenRect.height
color: "transparent" color: "transparent"
function createFileName()
{
var splitMachineName = Cura.MachineManager.activeMachineName.split(" ")
var abbrMachine = "";
if ((UM.Preferences.getValue("cura/jobname_prefix")))
{
for (var i = 0; i < splitMachineName.length; i++)
{
if (splitMachineName[i].search(/ultimaker/i) != -1)
{
abbrMachine += "UM";
}
else
{
if (splitMachineName[i].charAt(0).search(/[0-9]/g) == -1)
{
abbrMachine += splitMachineName[i].charAt(0);
}
}
}
var regExpAdditives = /[0-9\+]/g;
var resultAdditives = splitMachineName[i].match(regExpAdditives);
if (resultAdditives != null)
{
for (var j = 0; j < resultAdditives.length; j++)
{
abbrMachine += resultAdditives[j];
}
}
printJobTextfield.text = abbrMachine + "_" + base.fileBaseName;
}
else
{
printJobTextfield.text = base.fileBaseName;
}
}
Connections Connections
{ {
target: backgroundItem target: backgroundItem
@ -78,16 +41,16 @@ Rectangle {
onActivityChanged: { onActivityChanged: {
if (activity == true && base.fileBaseName == ''){ if (activity == true && base.fileBaseName == ''){
//this only runs when you open a file from the terminal (or something that works the same way; for example when you drag a file on the icon in MacOS or use 'open with' on Windows) //this only runs when you open a file from the terminal (or something that works the same way; for example when you drag a file on the icon in MacOS or use 'open with' on Windows)
base.fileBaseName = Printer.jobName //it gets the fileBaseName from CuraApplication.py because this saves the filebase when the file is opened using the terminal (or something alike) base.fileBaseName = PrintInformation.jobName; //get the fileBaseName from PrintInformation.py because this saves the filebase when the file is opened using the terminal (or something alike)
base.createFileName() printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
} }
if (activity == true && base.fileBaseName != ''){ if (activity == true && base.fileBaseName != ''){
//this runs in all other cases where there is a mesh on the buildplate (activity == true). It uses the fileBaseName from the hasMesh signal //this runs in all other cases where there is a mesh on the buildplate (activity == true). It uses the fileBaseName from the hasMesh signal
base.createFileName() printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
} }
if (activity == false){ if (activity == false){
//When there is no mesh in the buildplate; the printJobTextField is set to an empty string so it doesn't set an empty string as a jobName (which is later used for saving the file) //When there is no mesh in the buildplate; the printJobTextField is set to an empty string so it doesn't set an empty string as a jobName (which is later used for saving the file)
printJobTextfield.text = '' printJobTextfield.text = '';
} }
} }
@ -114,8 +77,8 @@ Rectangle {
onClicked: onClicked:
{ {
printJobTextfield.selectAll() printJobTextfield.selectAll();
printJobTextfield.focus = true printJobTextfield.focus = true;
} }
style: ButtonStyle style: ButtonStyle
{ {
@ -124,10 +87,10 @@ Rectangle {
color: "transparent" color: "transparent"
UM.RecolorImage UM.RecolorImage
{ {
width: UM.Theme.getSize("save_button_specs_icons").width width: UM.Theme.getSize("save_button_specs_icons").width;
height: UM.Theme.getSize("save_button_specs_icons").height height: UM.Theme.getSize("save_button_specs_icons").height;
sourceSize.width: width sourceSize.width: width;
sourceSize.height: width sourceSize.height: width;
color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("text"); color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("text");
source: UM.Theme.getIcon("pencil"); source: UM.Theme.getIcon("pencil");
} }
@ -147,15 +110,15 @@ Rectangle {
text: '' text: ''
horizontalAlignment: TextInput.AlignRight horizontalAlignment: TextInput.AlignRight
onTextChanged: { onTextChanged: {
Printer.setJobName(text) PrintInformation.setJobName(text);
} }
onEditingFinished: { onEditingFinished: {
if (printJobTextfield.text != ''){ if (printJobTextfield.text != ''){
printJobTextfield.focus = false printJobTextfield.focus = false;
} }
} }
validator: RegExpValidator { validator: RegExpValidator {
regExp: /^[^\\ \/ \.]*$/ regExp: /^[^\\ \/ \*\?\|\[\]]*$/
} }
style: TextFieldStyle{ style: TextFieldStyle{
textColor: UM.Theme.getColor("setting_control_text"); textColor: UM.Theme.getColor("setting_control_text");
@ -200,7 +163,7 @@ Rectangle {
sourceSize.width: width sourceSize.width: width
sourceSize.height: width sourceSize.height: width
color: UM.Theme.getColor("text_subtext") color: UM.Theme.getColor("text_subtext")
source: UM.Theme.getIcon("print_time"); source: UM.Theme.getIcon("print_time")
} }
Label{ Label{
id: timeSpec id: timeSpec
@ -221,7 +184,7 @@ Rectangle {
sourceSize.width: width sourceSize.width: width
sourceSize.height: width sourceSize.height: width
color: UM.Theme.getColor("text_subtext") color: UM.Theme.getColor("text_subtext")
source: UM.Theme.getIcon("category_material"); source: UM.Theme.getIcon("category_material")
} }
Label{ Label{
id: lengthSpec id: lengthSpec
@ -229,7 +192,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
font: UM.Theme.getFont("small") font: UM.Theme.getFont("small")
color: UM.Theme.getColor("text_subtext") color: UM.Theme.getColor("text_subtext")
text: base.printMaterialAmount <= 0 ? catalog.i18nc("@label", "0.0 m") : catalog.i18nc("@label", "%1 m").arg(base.printMaterialAmount) text: catalog.i18nc("@label", "%1 m").arg(base.printMaterialAmount > 0 ? base.printMaterialAmount : 0)
} }
} }
} }

View File

@ -12,11 +12,19 @@ UM.ManagementPage
id: base; id: base;
title: catalog.i18nc("@title:tab", "Printers"); title: catalog.i18nc("@title:tab", "Printers");
property int numInstances: model.rowCount();
model: UM.ContainerStacksModel model: UM.ContainerStacksModel
{ {
filter: {"type": "machine"} filter: {"type": "machine"}
onDataChanged: numInstances = model.rowCount() }
activeId: Cura.MachineManager.activeMachineId
activeIndex: {
for(var i = 0; i < model.rowCount(); i++) {
if (model.getItem(i).id == Cura.MachineManager.activeMachineId) {
return i;
}
}
return -1;
} }
onAddObject: Printer.requestAddPrinter() onAddObject: Printer.requestAddPrinter()
@ -24,9 +32,9 @@ UM.ManagementPage
onRenameObject: renameDialog.open(); onRenameObject: renameDialog.open();
onActivateObject: Cura.MachineManager.setActiveMachine(base.currentItem.id) onActivateObject: Cura.MachineManager.setActiveMachine(base.currentItem.id)
removeEnabled: base.currentItem != null && numInstances > 1 removeEnabled: base.currentItem != null && model.rowCount() > 1
renameEnabled: base.currentItem != null && numInstances > 0 renameEnabled: base.currentItem != null
activateEnabled: base.currentItem != null activateEnabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMachineId
Flow Flow
{ {

View File

@ -14,13 +14,37 @@ UM.ManagementPage
title: catalog.i18nc("@title:tab", "Materials"); title: catalog.i18nc("@title:tab", "Materials");
model: UM.InstanceContainersModel { filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId } } model: UM.InstanceContainersModel
/* {
onAddObject: { var selectedMaterial = UM.MaterialManager.createProfile(); base.selectMaterial(selectedMaterial); } filter:
onRemoveObject: confirmDialog.open(); {
onRenameObject: { renameDialog.open(); renameDialog.selectText(); } var result = { "type": "material" }
*/ if(Cura.MachineManager.filterMaterialsByMachine)
// activateEnabled: false {
result.definition = Cura.MachineManager.activeDefinitionId
if(Cura.MachineManager.hasVariants)
{
result.variant = Cura.MachineManager.activeVariantId
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
}
activeId: Cura.MachineManager.activeMaterialId
activeIndex: {
for(var i = 0; i < model.rowCount(); i++) {
if (model.getItem(i).id == Cura.MachineManager.activeMaterialId) {
return i;
}
}
return -1;
}
addEnabled: false addEnabled: false
removeEnabled: false removeEnabled: false
renameEnabled: false renameEnabled: false
@ -185,7 +209,7 @@ UM.ManagementPage
onCurrentItemChanged: onCurrentItemChanged:
{ {
if(!currentItem == null) if(currentItem == null)
{ {
return return
} }

View File

@ -6,25 +6,70 @@ import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura
UM.ManagementPage UM.ManagementPage
{ {
id: base; id: base;
title: catalog.i18nc("@title:tab", "Profiles"); title: catalog.i18nc("@title:tab", "Profiles");
addText: catalog.i18nc("@label", "Duplicate") addText: base.currentItem && (base.currentItem.id == Cura.MachineManager.activeQualityId) ? catalog.i18nc("@label", "Create") : catalog.i18nc("@label", "Duplicate")
model: UM.InstanceContainersModel { filter: { "type": "quality" } } model: UM.InstanceContainersModel
{
onAddObject: { filter:
var selectedProfile; {
if (objectList.currentIndex == 0) { var result = { "type": "quality" };
// Current settings if(Cura.MachineManager.filterQualityByMachine)
selectedProfile = UM.MachineManager.createProfile(); {
} else { result.definition = Cura.MachineManager.activeDefinitionId;
selectedProfile = UM.MachineManager.duplicateProfile(currentItem.name); if(Cura.MachineManager.hasMaterials)
{
result.material = Cura.MachineManager.activeMaterialId;
} }
base.selectProfile(selectedProfile); }
else
{
result.definition = "fdmprinter"
}
return result
}
}
section.property: "readOnly"
section.delegate: Rectangle
{
width: objectListContainer.viewport.width;
height: childrenRect.height;
Label
{
anchors.left: parent.left;
anchors.leftMargin: UM.Theme.getSize("default_lining").width;
text: section == "true" ? catalog.i18nc("@label", "Protected profiles") : catalog.i18nc("@label", "Custom profiles")
font.bold: true
}
}
activeId: Cura.MachineManager.activeQualityId
activeIndex: {
for(var i = 0; i < model.rowCount(); i++) {
if (model.getItem(i).id == Cura.MachineManager.activeQualityId) {
return i;
}
}
return -1;
}
onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id)
onAddObject: {
var selectedContainer;
if (objectList.currentItem.id == Cura.MachineManager.activeQualityId) {
selectedContainer = Cura.MachineManager.newQualityContainerFromQualityAndUser();
} else {
selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id);
}
base.selectContainer(selectedContainer);
renameDialog.removeWhenRejected = true; renameDialog.removeWhenRejected = true;
renameDialog.open(); renameDialog.open();
@ -33,15 +78,19 @@ UM.ManagementPage
onRemoveObject: confirmDialog.open(); onRemoveObject: confirmDialog.open();
onRenameObject: { renameDialog.removeWhenRejected = false; renameDialog.open(); renameDialog.selectText(); } onRenameObject: { renameDialog.removeWhenRejected = false; renameDialog.open(); renameDialog.selectText(); }
activateEnabled: currentItem != null ? currentItem.id != Cura.MachineManager.activeQualityId : false;
addEnabled: currentItem != null; addEnabled: currentItem != null;
removeEnabled: currentItem != null ? !currentItem.readOnly : false; removeEnabled: currentItem != null ? !currentItem.readOnly : false;
renameEnabled: currentItem != null ? !currentItem.readOnly : false; renameEnabled: currentItem != null ? !currentItem.readOnly : false;
scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(UM.MachineManager.activeMachineInstance) scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName)
signal selectProfile(string name) signal showProfileNameDialog()
onSelectProfile: { onShowProfileNameDialog: { renameDialog.removeWhenRejected = true; renameDialog.open(); renameDialog.selectText(); }
objectList.currentIndex = objectList.model.find("name", name);
signal selectContainer(string id)
onSelectContainer: {
objectList.currentIndex = objectList.model.find("id", id);
} }
Item { Item {
@ -56,70 +105,108 @@ UM.ManagementPage
elide: Text.ElideRight elide: Text.ElideRight
} }
ScrollView { Row {
id: currentSettingsActions
visible: currentItem.id == Cura.MachineManager.activeQualityId
anchors.left: parent.left anchors.left: parent.left
anchors.top: profileName.bottom anchors.top: profileName.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
Button
{
text: {
return catalog.i18nc("@action:button", "Update profile with current settings");
}
enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
onClicked: Cura.MachineManager.updateQualityContainerFromUserContainer()
}
Button
{
text: catalog.i18nc("@action:button", "Discard current settings");
enabled: Cura.MachineManager.hasUserSettings
onClicked: Cura.MachineManager.clearUserSettings();
}
}
Column {
id: profileNotices
anchors.top: currentSettingsActions.visible ? currentSettingsActions.bottom : currentSettingsActions.anchors.top
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: parent.left
anchors.right: parent.right
spacing: UM.Theme.getSize("default_margin").height
Label {
id: defaultsMessage
visible: !currentItem.metadata.has_settings
text: catalog.i18nc("@action:label", "This profile has no settings and uses the defaults specified by the printer.")
wrapMode: Text.WordWrap
width: parent.width
}
Label {
id: noCurrentSettingsMessage
visible: currentItem.id == Cura.MachineManager.activeQualityId && !Cura.MachineManager.hasUserSettings
text: catalog.i18nc("@action:label", "Your current settings match the selected profile.")
wrapMode: Text.WordWrap
width: parent.width
}
}
ScrollView {
id: scrollView
anchors.left: parent.left
anchors.top: profileNotices.visible ? profileNotices.bottom : profileNotices.anchors.top
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
Column ListView {
{ model: Cura.ContainerSettingsModel{ containers: (currentItem.id == Cura.MachineManager.activeQualityId) ? [base.currentItem.id, Cura.MachineManager.activeUserProfileId] : [base.currentItem.id] }
spacing: UM.Theme.getSize("default_margin").height delegate: Row {
property variant setting: model
Row spacing: UM.Theme.getSize("default_margin").width/2
{ Label {
visible: base.currentItem.id == -1 || base.currentItem.active text: model.label
Button elide: Text.ElideMiddle
{ width: scrollView.width / 100 * 40
text: {
var profileName = UM.MachineManager.activeProfile;
profileName = (profileName.length > 20) ? profileName.substring(0, 20) + '...' : profileName;
return catalog.i18nc("@action:button", "Update \"%1\"".arg(profileName));
} }
enabled: UM.ActiveProfile.hasCustomisedValues && !UM.ActiveProfile.readOnly Repeater {
onClicked: UM.ActiveProfile.updateProfile() model: setting.values.length
} Label {
text: setting.values[index].toString()
Button width: scrollView.width / 100 * 15
{ elide: Text.ElideRight
text: catalog.i18nc("@action:button", "Discard changes"); font.strikeout: index < setting.values.length - 1 && setting.values[index + 1] != ""
enabled: UM.ActiveProfile.hasCustomisedValues opacity: font.strikeout ? 0.5 : 1
onClicked: UM.ActiveProfile.discardChanges()
} }
} }
Label {
Grid text: model.unit
{ }
id: containerGrid }
columns: 2 header: Row {
visible: currentItem.id == Cura.MachineManager.activeQualityId
spacing: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("default_margin").width
Label { Label {
text: base.currentItem == null ? "" : text: catalog.i18nc("@action:label", "Profile:")
base.currentItem.id == -1 ? catalog.i18nc("@label", "Based on") : catalog.i18nc("@label", "Profile type") width: scrollView.width / 100 * 55
horizontalAlignment: Text.AlignRight
font.bold: true
} }
Label { Label {
text: base.currentItem == null ? "" : text: catalog.i18nc("@action:label", "Current:")
base.currentItem.id == -1 ? UM.MachineManager.activeProfile : visible: currentItem.id == Cura.MachineManager.activeQualityId
base.currentItem.readOnly ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile") font.bold: true
}
Column {
Repeater {
model: base.currentItem ? base.currentItem.settings : null
Label {
text: modelData.name.toString();
elide: Text.ElideMiddle;
}
}
}
Column {
Repeater {
model: base.currentItem ? base.currentItem.settings : null
Label { text: modelData.value.toString(); }
} }
} }
section.property: "category"
section.criteria: ViewSection.FullString
section.delegate: Label {
text: section
font.bold: true
} }
} }
} }
@ -136,9 +223,10 @@ UM.ManagementPage
Button Button
{ {
text: catalog.i18nc("@action:button", "Export"); text: catalog.i18nc("@action:button", "Export")
iconName: "document-export"; iconName: "document-export"
onClicked: exportDialog.open(); onClicked: exportDialog.open()
enabled: currentItem != null
} }
} }
@ -148,19 +236,19 @@ UM.ManagementPage
UM.ConfirmRemoveDialog UM.ConfirmRemoveDialog
{ {
id: confirmDialog; id: confirmDialog
object: base.currentItem != null ? base.currentItem.name : ""; object: base.currentItem != null ? base.currentItem.name : ""
onYes: base.model.removeProfile(base.currentItem.name); onYes: Cura.MachineManager.removeQualityContainer(base.currentItem.id)
} }
UM.RenameDialog UM.RenameDialog
{ {
id: renameDialog; id: renameDialog;
object: base.currentItem != null ? base.currentItem.name : ""; object: base.currentItem != null ? base.currentItem.name : ""
property bool removeWhenRejected: false; property bool removeWhenRejected: false
onAccepted: base.model.renameProfile(base.currentItem.name, newName.trim()); onAccepted: Cura.MachineManager.renameQualityContainer(base.currentItem.id, newName)
onRejected: { onRejected: {
if(removeWhenRejected) { if(removeWhenRejected) {
base.model.removeProfile(base.currentItem.name) Cura.MachineManager.removeQualityContainer(base.currentItem.id)
} }
} }
} }
@ -208,7 +296,7 @@ UM.ManagementPage
folder: base.model.getDefaultPath() folder: base.model.getDefaultPath()
onAccepted: onAccepted:
{ {
var result = base.model.exportProfile(base.currentItem.id, base.currentItem.name, fileUrl, selectedNameFilter) var result = base.model.exportProfile(base.currentItem.id, fileUrl, selectedNameFilter)
if(result && result.status == "error") if(result && result.status == "error")
{ {
messageDialog.icon = StandardIcon.Critical messageDialog.icon = StandardIcon.Critical

View File

@ -1,160 +0,0 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Item{
id: base;
UM.I18nCatalog { id: catalog; name:"cura"}
property int totalHeightProfileSetup: childrenRect.height
property Action manageProfilesAction
property Action addProfileAction
property Action updateProfileAction
property Action resetProfileAction
signal showTooltip(Item item, point location, string text)
signal hideTooltip()
Rectangle{
id: globalProfileRow
anchors.top: base.top
height: UM.Theme.getSize("sidebar_setup").height
width: base.width
Label{
id: globalProfileLabel
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width;
anchors.verticalCenter: parent.verticalCenter
text: catalog.i18nc("@label","Profile:");
width: parent.width/100*45
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
ToolButton {
property int rightMargin: customisedSettings.visible ? customisedSettings.width + UM.Theme.getSize("default_margin").width / 2 : 0
id: globalProfileSelection
text: Cura.MachineManager.activeQualityName
width: parent.width/100*55
height: UM.Theme.getSize("setting_control").height
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter
tooltip: Cura.MachineManager.activeQualityName
style: UM.Theme.styles.sidebar_header_button
menu: Menu
{
id: profileSelectionMenu
Instantiator
{
id: profileSelectionInstantiator
model: UM.InstanceContainersModel
{
filter: {"type": "quality"}
}
property int separatorIndex: -1
Loader {
property QtObject model_data: model
property int model_index: index
sourceComponent: menuItemDelegate
}
onObjectAdded:
{
//Insert a separator between readonly and custom profiles
if(separatorIndex < 0 && index > 0) {
if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) {
profileSelectionMenu.insertSeparator(index);
separatorIndex = index;
}
}
//Because of the separator, custom profiles move one index lower
profileSelectionMenu.insertItem((model.getItem(index).readOnly) ? index : index + 1, object.item);
}
onObjectRemoved:
{
//When adding a profile, the menu is rebuild by removing all items.
//If a separator was added, we need to remove that too.
if(separatorIndex >= 0)
{
profileSelectionMenu.removeItem(profileSelectionMenu.items[separatorIndex])
separatorIndex = -1;
}
profileSelectionMenu.removeItem(object.item);
}
}
ExclusiveGroup { id: profileSelectionMenuGroup; }
Component
{
id: menuItemDelegate
MenuItem
{
id: item
text: model_data ? model_data.name : ""
checkable: true;
checked: Cura.MachineManager.activeQualityId == model_data.id
exclusiveGroup: profileSelectionMenuGroup;
onTriggered:
{
Cura.MachineManager.setActiveQuality(model_data.id);
/*if (!model_data.active) {
//Selecting a profile was canceled; undo menu selection
profileSelectionInstantiator.model.setProperty(model_index, "active", false);
var activeProfileName = UM.MachineManager.activeProfile;
var activeProfileIndex = profileSelectionInstantiator.model.find("name", activeProfileName);
profileSelectionInstantiator.model.setProperty(activeProfileIndex, "active", true);
}*/
}
}
}
MenuSeparator { }
MenuItem {
action: base.updateProfileAction;
}
MenuItem {
action: base.resetProfileAction;
}
MenuItem {
action: base.addProfileAction;
}
MenuSeparator { }
MenuItem {
action: base.manageProfilesAction;
}
}
}
UM.SimpleButton {
id: customisedSettings
visible: UM.ActiveProfile.hasCustomisedValues
height: parent.height * 0.6
width: parent.height * 0.6
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width
color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button");
iconSource: UM.Theme.getIcon("star");
onClicked: base.manageProfilesAction.trigger()
onEntered:
{
var content = catalog.i18nc("@tooltip","Some setting values are different from the values stored in the profile.\n\nClick to open the profile manager.")
base.showTooltip(globalProfileRow, Qt.point(0, globalProfileRow.height / 2), content)
}
onExited: base.hideTooltip()
}
}
}

View File

@ -98,7 +98,7 @@ Rectangle {
text: UM.OutputDeviceManager.activeDeviceShortDescription text: UM.OutputDeviceManager.activeDeviceShortDescription
onClicked: onClicked:
{ {
UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, Printer.jobName, { "filter_by_machine": true }) UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName, { "filter_by_machine": true })
} }
style: ButtonStyle { style: ButtonStyle {

View File

@ -7,8 +7,7 @@ import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import UM 1.1 as UM import UM 1.1 as UM
import Cura 1.0 as Cura
import ".."
Button { Button {
id: base; id: base;
@ -45,7 +44,7 @@ Button {
iconSource: UM.Theme.getIcon("settings"); iconSource: UM.Theme.getIcon("settings");
onClicked: { onClicked: {
Actions.configureSettingVisibility.trigger(definition) Cura.Actions.configureSettingVisibility.trigger(definition)
} }
} }
@ -57,9 +56,9 @@ Button {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width
visible: hiddenValuesCount > 0 visible: false //hiddenValuesCount > 0
height: parent.height / 2; height: parent.height / 2
width: height; width: height
onClicked: { onClicked: {
base.showAllHiddenInheritedSettings() base.showAllHiddenInheritedSettings()

View File

@ -16,6 +16,7 @@ SettingItem
{ {
id: control id: control
anchors.fill: parent anchors.fill: parent
hoverEnabled: true
property bool checked: property bool checked:
{ {

View File

@ -0,0 +1,114 @@
// Copyright (c) 2016 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.1 as UM
import Cura 1.0 as Cura
SettingItem
{
id: base
contents: ComboBox
{
id: control
model: Cura.ExtrudersModel
{
id: extruders_model
}
textRole: "name"
anchors.fill: parent
MouseArea
{
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: wheel.accepted = true;
}
style: ComboBoxStyle
{
background: Rectangle
{
color:
{
if (!enabled)
{
return UM.Theme.getColor("setting_control_disabled");
}
if(control.hovered || base.activeFocus)
{
return UM.Theme.getColor("setting_control_highlight");
}
else
{
return extruders_model.getItem(index).colour;
}
}
border.width: UM.Theme.getSize("default_lining").width
border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : control.hovered ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border")
}
label: Item
{
Label
{
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_lining").width
anchors.right: downArrow.left
anchors.rightMargin: UM.Theme.getSize("default_lining").width
anchors.verticalCenter: parent.verticalCenter
text: control.currentText
font: UM.Theme.getFont("default")
color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : extruders_model.getItem(index).colour
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
UM.RecolorImage
{
id: downArrow
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_lining").width * 2
anchors.verticalCenter: parent.verticalCenter
source: UM.Theme.getIcon("arrow_bottom")
width: UM.Theme.getSize("standard_arrow").width
height: UM.Theme.getSize("standard_arrow").height
sourceSize.width: width + 5
sourceSize.height: width + 5
color: UM.Theme.getColor("setting_control_text")
}
}
}
onActivated: provider.setPropertyValue("value", extruders_model.getItem(index).index);
onModelChanged: updateCurrentIndex();
Connections
{
target: provider
onPropertiesChanged: control.updateCurrentIndex();
}
function updateCurrentIndex()
{
for(var i = 0; i < extruders_model.rowCount(); ++i)
{
if(extruders_model.getItem(i).index == provider.properties.value)
{
currentIndex = i;
return;
}
}
currentIndex = -1;
}
}
}

View File

@ -18,10 +18,51 @@ Item {
property alias contents: controlContainer.children; property alias contents: controlContainer.children;
property alias hovered: mouse.containsMouse property alias hovered: mouse.containsMouse
property var showRevertButton: true
property var showInheritButton: true
property var doDepthIndentation: true
// Create properties to put property provider stuff in (bindings break in qt 5.5.1 otherwise)
property var state: propertyProvider.properties.state
property var stackLevels: propertyProvider.stackLevels
property var stackLevel: stackLevels[0]
signal contextMenuRequested() signal contextMenuRequested()
signal showTooltip(string text); signal showTooltip(string text);
signal hideTooltip(); signal hideTooltip();
property string tooltipText:
{
var affects = settingDefinitionsModel.getRequiredBy(definition.key, "value")
var affected_by = settingDefinitionsModel.getRequires(definition.key, "value")
var affected_by_list = ""
for(var i in affected_by)
{
affected_by_list += "<li>%1</li>\n".arg(affected_by[i].label)
}
var affects_list = ""
for(var i in affects)
{
affects_list += "<li>%1</li>\n".arg(affects[i].label)
}
var tooltip = "<b>%1</b>\n<p>%2</p>".arg(definition.label).arg(definition.description)
if(affects_list != "")
{
tooltip += "<br/><b>%1</b>\n<ul>\n%2</ul>".arg(catalog.i18nc("@label", "Affects")).arg(affects_list)
}
if(affected_by_list != "")
{
tooltip += "<br/><b>%1</b>\n<ul>\n%2</ul>".arg(catalog.i18nc("@label", "Affected By")).arg(affected_by_list)
}
return tooltip
}
MouseArea MouseArea
{ {
id: mouse; id: mouse;
@ -50,7 +91,10 @@ Item {
interval: 500; interval: 500;
repeat: false; repeat: false;
onTriggered: base.showTooltip(definition.description); onTriggered:
{
base.showTooltip(base.tooltipText);
}
} }
Label Label
@ -58,7 +102,7 @@ Item {
id: label; id: label;
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: (UM.Theme.getSize("section_icon_column").width + 5) + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width) anchors.leftMargin: doDepthIndentation ? (UM.Theme.getSize("section_icon_column").width + 5) + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width) : 0
anchors.right: settingControls.left; anchors.right: settingControls.left;
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@ -89,7 +133,7 @@ Item {
{ {
id: revertButton; id: revertButton;
visible: propertyProvider.stackLevel == 0 visible: base.stackLevel == 0 && base.showRevertButton
height: parent.height; height: parent.height;
width: height; width: height;
@ -106,24 +150,72 @@ Item {
propertyProvider.removeFromContainer(0) propertyProvider.removeFromContainer(0)
} }
onEntered: base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) }
onExited: base.showTooltip(definition.description); onExited: base.showTooltip(base.tooltipText);
} }
UM.SimpleButton UM.SimpleButton
{ {
// This button shows when the setting has an inherited function, but is overriden by profile. // This button shows when the setting has an inherited function, but is overriden by profile.
id: inheritButton; id: inheritButton;
// Inherit button needs to be visible if;
//visible: has_profile_value && base.has_inherit_function && base.is_enabled // - User made changes that override any loaded settings
visible: propertyProvider.properties.state == "InstanceState.User" && propertyProvider.stackLevel > 0 // - This setting item uses inherit button at all
// - The type of the value of any deeper container is an "object" (eg; is a function)
visible:
{
var state = base.state == "InstanceState.User";
var has_setting_function = false;
for (var i = 1; i < base.stackLevels.length; i++)
{
has_setting_function = typeof(propertyProvider.getPropertyValue("value", base.stackLevels[i])) == "object";
if(has_setting_function)
{
break;
}
}
return state && base.showInheritButton && has_setting_function && typeof(propertyProvider.getPropertyValue("value", base.stackLevels[0])) != "object"
}
height: parent.height; height: parent.height;
width: height; width: height;
onClicked: { onClicked: {
focus = true; focus = true;
propertyProvider.removeFromContainer(propertyProvider.stackLevel)
// Get the most shallow function value (eg not a number) that we can find.
var last_entry = propertyProvider.stackLevels[propertyProvider.stackLevels.length]
for (var i = 1; i < base.stackLevels.length; i++)
{
var has_setting_function = typeof(propertyProvider.getPropertyValue("value", base.stackLevels[i])) == "object";
if(has_setting_function)
{
last_entry = propertyProvider.stackLevels[i]
break;
}
}
if(last_entry == 4 && base.stackLevel == 0 && base.stackLevels.length == 2)
{
// Special case of the inherit reset. If only the definition (4th container) and the first
// entry (user container) are set, we can simply remove the container.
propertyProvider.removeFromContainer(0)
}
else if(last_entry - 1 == base.stackLevel)
{
// Another special case. The setting that is overriden is only 1 instance container deeper,
// so we can remove it.
propertyProvider.removeFromContainer(0)
}
else
{
// Put that entry into the "top" instance container.
// This ensures that the value in any of the deeper containers need not be removed, which is
// needed for the reset button (which deletes the top value) to correctly go back to profile
// defaults.
propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry))
propertyProvider.setPropertyValue("state", "InstanceState.Calculated")
}
} }
backgroundColor: UM.Theme.getColor("setting_control"); backgroundColor: UM.Theme.getColor("setting_control");
@ -133,8 +225,8 @@ Item {
iconSource: UM.Theme.getIcon("notice"); iconSource: UM.Theme.getIcon("notice");
onEntered: base.showTooltip(catalog.i18nc("@label", "This setting is normally calculated, but it currently has an absolute value set.\n\nClick to restore the calculated value.")) onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting is normally calculated, but it currently has an absolute value set.\n\nClick to restore the calculated value.")) }
onExited: base.showTooltip(definition.description); onExited: base.showTooltip(base.tooltipText);
} }
} }
@ -143,6 +235,8 @@ Item {
{ {
id: controlContainer; id: controlContainer;
enabled: provider.isValueUsed
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter; anchors.verticalCenter: parent.verticalCenter;

View File

@ -16,8 +16,6 @@ SettingItem
anchors.fill: parent anchors.fill: parent
property alias hovered: mouseArea.containsMouse;
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : hovered ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border") border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : hovered ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border")
@ -74,7 +72,7 @@ SettingItem
{ {
id: mouseArea id: mouseArea
anchors.fill: parent; anchors.fill: parent;
hoverEnabled: true; //hoverEnabled: true;
cursorShape: Qt.IBeamCursor cursorShape: Qt.IBeamCursor
} }
@ -92,21 +90,11 @@ SettingItem
Keys.onReleased: Keys.onReleased:
{ {
// text = text.replace(",", ".") // User convenience. We use dots for decimal values
// if(parseFloat(text) != base.parentValue)
// {
// base.valueChanged(parseFloat(text));
// }
propertyProvider.setPropertyValue("value", text) propertyProvider.setPropertyValue("value", text)
} }
onEditingFinished: onEditingFinished:
{ {
// if(parseFloat(text) != base.parentValue)
// {
// base.valueChanged(parseFloat(text));
// }
propertyProvider.setPropertyValue("value", text) propertyProvider.setPropertyValue("value", text)
} }
@ -123,33 +111,9 @@ SettingItem
{ {
target: input target: input
property: "text" property: "text"
value: control.format(propertyProvider.properties.value) value: propertyProvider.properties.value
when: !input.activeFocus when: !input.activeFocus
} }
} }
//Rounds a floating point number to 4 decimals. This prevents floating
//point rounding errors.
//
//input: The number to round.
//decimals: The number of decimals (digits after the radix) to round to.
//return: The rounded number.
function roundFloat(input, decimals)
{
//First convert to fixed-point notation to round the number to 4 decimals and not introduce new floating point errors.
//Then convert to a string (is implicit). The fixed-point notation will be something like "3.200".
//Then remove any trailing zeroes and the radix.
return input.toFixed(decimals).replace(/\.?0*$/, ""); //Match on periods, if any ( \.? ), followed by any number of zeros ( 0* ), then the end of string ( $ ).
}
//Formats a value for display in the text field.
//
//This correctly handles formatting of float values.
//
//input: The string value to format.
//return: The formatted string.
function format(inputValue) {
return parseFloat(inputValue) ? roundFloat(parseFloat(inputValue), 4) : inputValue //If it's a float, round to four decimals.
}
} }
} }

View File

@ -9,8 +9,6 @@ import QtQuick.Layouts 1.1
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
import ".."
ScrollView ScrollView
{ {
id: base; id: base;
@ -26,11 +24,22 @@ ScrollView
{ {
id: contents id: contents
spacing: UM.Theme.getSize("default_lining").height; spacing: UM.Theme.getSize("default_lining").height;
cacheBuffer: 1000000; // Set a large cache to effectively just cache every list item.
model: UM.SettingDefinitionsModel { model: UM.SettingDefinitionsModel {
id: definitionsModel; id: definitionsModel;
containerId: Cura.MachineManager.activeDefinitionId containerId: Cura.MachineManager.activeDefinitionId
exclude: ["machine_settings"]
visibilityHandler: UM.SettingPreferenceVisibilityHandler { } visibilityHandler: UM.SettingPreferenceVisibilityHandler { }
filter:
{
if(ExtruderManager.activeExtruderStackId)
{
return { "settable_per_extruder": true }
}
return { }
}
} }
delegate: Loader delegate: Loader
@ -50,8 +59,9 @@ ScrollView
//Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
//In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
//causing nasty issues when selecting differnt options. So disable asynchronous loading of enum type completely. //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
asynchronous: model.type != "enum" asynchronous: model.type != "enum" && model.type != "extruder"
active: model.type != undefined
source: source:
{ {
@ -63,6 +73,8 @@ ScrollView
return "SettingTextField.qml" return "SettingTextField.qml"
case "enum": case "enum":
return "SettingComboBox.qml" return "SettingComboBox.qml"
case "extruder":
return "SettingExtruder.qml"
case "bool": case "bool":
return "SettingCheckBox.qml" return "SettingCheckBox.qml"
case "str": case "str":
@ -78,8 +90,8 @@ ScrollView
{ {
id: provider id: provider
containerStackId: Cura.MachineManager.activeMachineId containerStackId: ExtruderManager.activeExtruderStackId ? ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId
key: model.key key: model.key ? model.key : ""
watchedProperties: [ "value", "enabled", "state", "validationState" ] watchedProperties: [ "value", "enabled", "state", "validationState" ]
storeIndex: 0 storeIndex: 0
} }
@ -134,7 +146,7 @@ ScrollView
//: Settings context menu action //: Settings context menu action
text: catalog.i18nc("@action:menu", "Configure setting visiblity..."); text: catalog.i18nc("@action:menu", "Configure setting visiblity...");
onTriggered: Actions.configureSettingVisibility.trigger(contextMenu); onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu);
} }
} }
} }

View File

@ -1,119 +0,0 @@
// Copyright (c) 2015 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Controls.Styles 1.1
import QtQml 2.2
import UM 1.1 as UM
import "../Preferences"
PreferencesPage
{
//: Machine configuration page title.
title: catalog.i18nc("@title:tab","Machine");
id: base
contents: ColumnLayout
{
z: base.z
anchors.fill: parent;
UM.I18nCatalog { id: catalog; name:"uranium"}
RowLayout
{
//: Active machine combo box label
Label { text: catalog.i18nc("@label:listbox","Active Machine:"); }
ComboBox
{
id: machineCombo;
Layout.fillWidth: true;
model: UM.Models.machinesModel;
textRole: "name";
onActivated:
{
if(index != -1)
UM.Models.machinesModel.setActive(index);
}
Connections
{
id: machineChange
target: UM.Application
onMachineChanged: machineCombo.currentIndex = machineCombo.find(UM.Application.machineName);
}
Component.onCompleted: machineCombo.currentIndex = machineCombo.find(UM.Application.machineName);
}
//: Remove active machine button
Button { text: catalog.i18nc("@action:button","Remove"); onClicked: confirmRemoveDialog.open(); }
}
ScrollView
{
id: settingsScrollView
Layout.fillWidth: true;
Layout.fillHeight: true;
ListView
{
id: settingsListView
delegate: settingDelegate
model: UM.Models.settingsModel
x: 0
section.property: "category"
section.delegate: Label { text: section }
}
}
}
Component
{
id: settingDelegate
CheckBox
{
z:0
id: settingCheckBox
text: model.name;
x: depth * 25
checked: model.visibility
onClicked: ListView.view.model.setVisibility(model.key, checked)
//enabled: !model.disabled
onHoveredChanged:
{
if(hovered)
{
var xPos = parent.x + settingCheckBox.width;
var yPos = parent.y;
toolTip.show(model.description, 1000, 200, undefined, undefined) //tooltip-text, hover-delay in msec, animation-length in msec, position X, position Y (both y en x == undefined: gives the tooltip a standard placement in the right corner)
} else
{
toolTip.hide(0, 0)//hover-delay in msec, animation-length in msec
}
}
}
}
PreferencesToolTip
{
id: toolTip;
}
MessageDialog
{
id: confirmRemoveDialog;
icon: StandardIcon.Question;
//: Remove machine confirmation dialog title
title: catalog.i18nc("@title:window","Confirm Machine Deletion");
//: Remove machine confirmation dialog text
text: catalog.i18nc("@label","Are you sure you wish to remove the machine?");
standardButtons: StandardButton.Yes | StandardButton.No;
onYes: UM.Models.machinesModel.removeMachine(machineCombo.currentIndex);
}
}

View File

@ -12,13 +12,6 @@ Rectangle
{ {
id: base; id: base;
property Action addMachineAction;
property Action configureMachinesAction;
property Action addProfileAction;
property Action updateProfileAction;
property Action resetProfileAction;
property Action manageProfilesAction;
property Action configureSettingsAction;
property int currentModeIndex; property int currentModeIndex;
color: UM.Theme.getColor("sidebar"); color: UM.Theme.getColor("sidebar");
@ -52,20 +45,8 @@ Rectangle
width: parent.width width: parent.width
height: totalHeightHeader height: totalHeightHeader
addMachineAction: base.addMachineAction; anchors.top: parent.top
configureMachinesAction: base.configureMachinesAction;
}
ProfileSetup {
id: profileItem
addProfileAction: base.addProfileAction
updateProfileAction: base.updateProfileAction
resetProfileAction: base.resetProfileAction
manageProfilesAction: base.manageProfilesAction
anchors.top: header.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width
height: totalHeightProfileSetup
onShowTooltip: base.showTooltip(item, location, text) onShowTooltip: base.showTooltip(item, location, text)
onHideTooltip: base.hideTooltip() onHideTooltip: base.hideTooltip()
@ -76,7 +57,7 @@ Rectangle
width: parent.width width: parent.width
height: UM.Theme.getSize("sidebar_lining").height height: UM.Theme.getSize("sidebar_lining").height
color: UM.Theme.getColor("sidebar_lining") color: UM.Theme.getColor("sidebar_lining")
anchors.top: profileItem.bottom anchors.top: header.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
} }

View File

@ -8,54 +8,54 @@ import QtQuick.Controls.Styles 1.1
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Item Column
{ {
id: base; id: base;
// Machine Setup
property Action addMachineAction;
property Action configureMachinesAction;
UM.I18nCatalog { id: catalog; name:"cura"}
property int totalHeightHeader: childrenRect.height property int totalHeightHeader: childrenRect.height
property int currentExtruderIndex; property int currentExtruderIndex;
Rectangle { spacing: UM.Theme.getSize("default_margin").height
id: sidebarTabRow
width: base.width signal showTooltip(Item item, point location, string text)
height: 0 signal hideTooltip()
anchors.top: parent.top
color: UM.Theme.getColor("sidebar_header_bar") Row
{
id: machineSelectionRow
height: UM.Theme.getSize("sidebar_setup").height
anchors
{
left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width
right: parent.right
rightMargin: UM.Theme.getSize("default_margin").width
} }
Rectangle { Label
id: machineSelectionRow {
width: base.width
height: UM.Theme.getSize("sidebar_setup").height
anchors.top: sidebarTabRow.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.horizontalCenter: parent.horizontalCenter
Label{
id: machineSelectionLabel id: machineSelectionLabel
//: Machine selection label
text: catalog.i18nc("@label:listbox", "Printer:"); text: catalog.i18nc("@label:listbox", "Printer:");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
font: UM.Theme.getFont("default"); font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text"); color: UM.Theme.getColor("text");
width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width
} }
ToolButton { ToolButton
{
id: machineSelection id: machineSelection
text: Cura.MachineManager.activeMachineName; text: Cura.MachineManager.activeMachineName;
width: parent.width/100*55
height: UM.Theme.getSize("setting_control").height height: UM.Theme.getSize("setting_control").height
tooltip: Cura.MachineManager.activeMachineName; tooltip: Cura.MachineManager.activeMachineName;
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
style: UM.Theme.styles.sidebar_header_button style: UM.Theme.styles.sidebar_header_button
width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width
menu: Menu menu: Menu
{ {
id: machineSelectionMenu id: machineSelectionMenu
@ -81,37 +81,57 @@ Item
MenuSeparator { } MenuSeparator { }
MenuItem { action: base.addMachineAction; } MenuItem { action: Cura.Actions.addMachine; }
MenuItem { action: base.configureMachinesAction; } MenuItem { action: Cura.Actions.configureMachines; }
} }
} }
} }
Rectangle { ListView
id: extruderSelection {
width: parent.width/100*55 id: extrudersList
property var index: 0
visible: machineExtruderCount.properties.value > 1 visible: machineExtruderCount.properties.value > 1
height: visible ? UM.Theme.getSize("sidebar_header_mode_toggle").height : 0 height: UM.Theme.getSize("sidebar_header_mode_toggle").height
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width boundsBehavior: Flickable.StopAtBounds
anchors.top: machineSelectionRow.bottom
anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0 anchors
Component{ {
id: wizardDelegate left: parent.left
Button { leftMargin: UM.Theme.getSize("default_margin").width
height: extruderSelection.height right: parent.right
anchors.left: parent.left rightMargin: UM.Theme.getSize("default_margin").width
anchors.leftMargin: model.index * (extruderSelection.width / machineExtruderCount.properties.value) }
anchors.verticalCenter: parent.verticalCenter
width: parent.width / machineExtruderCount.properties.value ExclusiveGroup { id: extruderMenuGroup; }
text: model.text
orientation: ListView.Horizontal
model: Cura.ExtrudersModel { id: extrudersModel; addGlobal: true }
delegate: Button
{
height: ListView.view.height
width: ListView.view.width / extrudersModel.rowCount()
text: model.name
exclusiveGroup: extruderMenuGroup; exclusiveGroup: extruderMenuGroup;
checkable: true; checkable: true;
checked: base.currentExtruderIndex == index checked: base.currentExtruderIndex == index
onClicked: base.currentExtruderIndex = index
style: ButtonStyle { onClicked:
background: Rectangle { {
focus = true; //Changing focus applies the currently-being-typed values so it can change the displayed setting values.
base.currentExtruderIndex = index;
ExtruderManager.setActiveExtruderIndex(index);
}
style: ButtonStyle
{
background: Rectangle
{
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: control.checked ? UM.Theme.getColor("toggle_checked_border") : border.color: control.checked ? UM.Theme.getColor("toggle_checked_border") :
control.pressed ? UM.Theme.getColor("toggle_active_border") : control.pressed ? UM.Theme.getColor("toggle_active_border") :
@ -120,11 +140,14 @@ Item
control.pressed ? UM.Theme.getColor("toggle_active") : control.pressed ? UM.Theme.getColor("toggle_active") :
control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked") control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked")
Behavior on color { ColorAnimation { duration: 50; } } Behavior on color { ColorAnimation { duration: 50; } }
Label {
Label
{
anchors.centerIn: parent anchors.centerIn: parent
color: control.checked ? UM.Theme.getColor("toggle_checked_text") : color: control.checked ? UM.Theme.getColor("toggle_checked_text") :
control.pressed ? UM.Theme.getColor("toggle_active_text") : control.pressed ? UM.Theme.getColor("toggle_active_text") :
control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text") control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text")
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
text: control.text; text: control.text;
} }
@ -133,67 +156,39 @@ Item
} }
} }
} }
ExclusiveGroup { id: extruderMenuGroup; }
ListView{
id: extrudersList
property var index: 0
model: extrudersListModel
delegate: wizardDelegate
anchors.top: parent.top
anchors.left: parent.left
width: parent.width
}
}
ListModel Row
{ {
id: extrudersListModel
Component.onCompleted: populateExtruderModel()
}
Connections
{
id: machineChange
target: Cura.MachineManager
onGlobalContainerChanged: populateExtruderModel()
}
function populateExtruderModel()
{
extrudersListModel.clear();
for(var extruder = 0; extruder < machineExtruderCount.properties.value ; extruder++) {
extrudersListModel.append({
text: catalog.i18nc("@label", "Extruder %1").arg(extruder + 1)
})
}
}
Rectangle {
id: variantRow id: variantRow
anchors.top: extruderSelection.visible ? extruderSelection.bottom : machineSelectionRow.bottom
anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0 height: UM.Theme.getSize("sidebar_setup").height
width: base.width
height: visible ? UM.Theme.getSize("sidebar_setup").height : 0
visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials
Label{ anchors
{
left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width
right: parent.right
rightMargin: UM.Theme.getSize("default_margin").width
}
Label
{
id: variantLabel id: variantLabel
text: (Cura.MachineManager.hasVariants && Cura.MachineManager.hasMaterials) ? catalog.i18nc("@label","Nozzle & Material:"): text: (Cura.MachineManager.hasVariants && Cura.MachineManager.hasMaterials) ? catalog.i18nc("@label","Nozzle & Material:"):
Cura.MachineManager.hasVariants ? catalog.i18nc("@label","Nozzle:") : catalog.i18nc("@label","Material:"); Cura.MachineManager.hasVariants ? catalog.i18nc("@label","Nozzle:") : catalog.i18nc("@label","Material:");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: parent.width/100*45 width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width
font: UM.Theme.getFont("default"); font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text"); color: UM.Theme.getColor("text");
} }
Rectangle Rectangle
{ {
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: parent.width/100*55 width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("setting_control").height height: UM.Theme.getSize("setting_control").height
ToolButton { ToolButton {
@ -230,13 +225,6 @@ Item
onTriggered: onTriggered:
{ {
Cura.MachineManager.setActiveVariant(model.id); Cura.MachineManager.setActiveVariant(model.id);
/*if (typeof(model) !== "undefined" && !model.active) {
//Selecting a variant was canceled; undo menu selection
variantSelectionInstantiator.model.setProperty(index, "active", false);
var activeMachineVariantName = UM.MachineManager.activeMachineVariant;
var activeMachineVariantIndex = variantSelectionInstantiator.model.find("name", activeMachineVariantName);
variantSelectionInstantiator.model.setProperty(activeMachineVariantIndex, "active", true);
}*/
} }
} }
onObjectAdded: variantsSelectionMenu.insertItem(index, object) onObjectAdded: variantsSelectionMenu.insertItem(index, object)
@ -266,7 +254,23 @@ Item
id: materialSelectionInstantiator id: materialSelectionInstantiator
model: UM.InstanceContainersModel model: UM.InstanceContainersModel
{ {
filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId } filter:
{
var result = { "type": "material" }
if(Cura.MachineManager.filterMaterialsByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId
if(Cura.MachineManager.hasVariants)
{
result.variant = Cura.MachineManager.activeVariantId
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
} }
MenuItem MenuItem
{ {
@ -277,13 +281,6 @@ Item
onTriggered: onTriggered:
{ {
Cura.MachineManager.setActiveMaterial(model.id); Cura.MachineManager.setActiveMaterial(model.id);
/*if (typeof(model) !== "undefined" && !model.active) {
//Selecting a material was canceled; undo menu selection
materialSelectionInstantiator.model.setProperty(index, "active", false);
var activeMaterialName = Cura.MachineManager.activeMaterialName
var activeMaterialIndex = materialSelectionInstantiator.model.find("name", activeMaterialName);
materialSelectionInstantiator.model.setProperty(activeMaterialIndex, "active", true);
}*/
} }
} }
onObjectAdded: materialSelectionMenu.insertItem(index, object) onObjectAdded: materialSelectionMenu.insertItem(index, object)
@ -296,6 +293,147 @@ Item
} }
} }
Row
{
id: globalProfileRow
height: UM.Theme.getSize("sidebar_setup").height
anchors
{
left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width
right: parent.right
rightMargin: UM.Theme.getSize("default_margin").width
}
Label
{
id: globalProfileLabel
text: catalog.i18nc("@label","Profile:");
width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
ToolButton
{
id: globalProfileSelection
text: Cura.MachineManager.activeQualityName
width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("setting_control").height
tooltip: Cura.MachineManager.activeQualityName
style: UM.Theme.styles.sidebar_header_button
menu: Menu
{
id: profileSelectionMenu
Instantiator
{
id: profileSelectionInstantiator
model: UM.InstanceContainersModel
{
filter:
{
var result = { "type": "quality" };
if(Cura.MachineManager.filterQualityByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId;
if(Cura.MachineManager.hasMaterials)
{
result.material = Cura.MachineManager.activeMaterialId;
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
}
property int separatorIndex: -1
Loader {
property QtObject model_data: model
property int model_index: index
sourceComponent: menuItemDelegate
}
onObjectAdded:
{
//Insert a separator between readonly and custom profiles
if(separatorIndex < 0 && index > 0)
{
if(model.getItem(index-1).readOnly != model.getItem(index).readOnly)
{
profileSelectionMenu.insertSeparator(index);
separatorIndex = index;
}
}
//Because of the separator, custom profiles move one index lower
profileSelectionMenu.insertItem((model.getItem(index).readOnly) ? index : index + 1, object.item);
}
onObjectRemoved:
{
//When adding a profile, the menu is rebuilt by removing all items.
//If a separator was added, we need to remove that too.
if(separatorIndex >= 0)
{
profileSelectionMenu.removeItem(profileSelectionMenu.items[separatorIndex])
separatorIndex = -1;
}
profileSelectionMenu.removeItem(object.item);
}
}
ExclusiveGroup { id: profileSelectionMenuGroup; }
Component
{
id: menuItemDelegate
MenuItem
{
id: item
text: model_data ? model_data.name : ""
checkable: true
checked: model_data != null ? Cura.MachineManager.activeQualityId == model_data.id : false
exclusiveGroup: profileSelectionMenuGroup;
onTriggered: Cura.MachineManager.setActiveQuality(model_data.id)
}
}
MenuSeparator { }
MenuItem { action: Cura.Actions.addProfile }
MenuItem { action: Cura.Actions.updateProfile }
MenuItem { action: Cura.Actions.resetProfile }
MenuSeparator { }
MenuItem { action: Cura.Actions.manageProfiles }
}
UM.SimpleButton
{
id: customisedSettings
visible: Cura.MachineManager.hasUserSettings
height: parent.height * 0.6
width: parent.height * 0.6
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width - UM.Theme.getSize("default_margin").width
color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button");
iconSource: UM.Theme.getIcon("star");
onClicked: Cura.Actions.manageProfiles.trigger()
onEntered:
{
var content = catalog.i18nc("@tooltip","Some setting values are different from the values stored in the profile.\n\nClick to open the profile manager.")
base.showTooltip(globalProfileRow, Qt.point(0, globalProfileRow.height / 2), content)
}
onExited: base.hideTooltip()
}
}
}
UM.SettingPropertyProvider UM.SettingPropertyProvider
{ {
id: machineExtruderCount id: machineExtruderCount
@ -305,4 +443,6 @@ Item
watchedProperties: [ "value" ] watchedProperties: [ "value" ]
storeIndex: 0 storeIndex: 0
} }
UM.I18nCatalog { id: catalog; name:"cura" }
} }

View File

@ -85,7 +85,7 @@ Item
{ {
return UM.Theme.getColor("setting_control_selected") return UM.Theme.getColor("setting_control_selected")
} }
else if(mousearea.containsMouse) else if(infillMouseArea.containsMouse)
{ {
return UM.Theme.getColor("setting_control_border_highlight") return UM.Theme.getColor("setting_control_border_highlight")
} }
@ -106,7 +106,7 @@ Item
} }
MouseArea { MouseArea {
id: mousearea id: infillMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onClicked: { onClicked: {
@ -196,7 +196,7 @@ Item
CheckBox{ CheckBox{
id: brimCheckBox id: brimCheckBox
property bool hovered_ex: false property alias _hovered: brimMouseArea.containsMouse
anchors.top: parent.top anchors.top: parent.top
anchors.left: adhesionHelperLabel.right anchors.left: adhesionHelperLabel.right
@ -209,6 +209,7 @@ Item
checked: platformAdhesionType.properties.value == "brim" checked: platformAdhesionType.properties.value == "brim"
MouseArea { MouseArea {
id: brimMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onClicked: onClicked:
@ -217,13 +218,11 @@ Item
} }
onEntered: onEntered:
{ {
parent.hovered_ex = true
base.showTooltip(brimCheckBox, Qt.point(-brimCheckBox.x, 0), base.showTooltip(brimCheckBox, Qt.point(-brimCheckBox.x, 0),
catalog.i18nc("@label", "Enable printing a brim. This will add a single-layer-thick flat area around your object which is easy to cut off afterwards.")); catalog.i18nc("@label", "Enable printing a brim. This will add a single-layer-thick flat area around your object which is easy to cut off afterwards."));
} }
onExited: onExited:
{ {
parent.hovered_ex = false
base.hideTooltip(); base.hideTooltip();
} }
} }
@ -244,7 +243,7 @@ Item
CheckBox{ CheckBox{
id: supportCheckBox id: supportCheckBox
visible: machineExtruderCount.properties.value <= 1 visible: machineExtruderCount.properties.value <= 1
property bool hovered_ex: false property alias _hovered: supportMouseArea.containsMouse
anchors.top: brimCheckBox.bottom anchors.top: brimCheckBox.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
@ -257,6 +256,7 @@ Item
checked: supportEnabled.properties.value == "True" checked: supportEnabled.properties.value == "True"
MouseArea { MouseArea {
id: supportMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onClicked: onClicked:
@ -265,13 +265,11 @@ Item
} }
onEntered: onEntered:
{ {
parent.hovered_ex = true
base.showTooltip(supportCheckBox, Qt.point(-supportCheckBox.x, 0), base.showTooltip(supportCheckBox, Qt.point(-supportCheckBox.x, 0),
catalog.i18nc("@label", "Enable printing support structures. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air.")); catalog.i18nc("@label", "Enable printing support structures. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air."));
} }
onExited: onExited:
{ {
parent.hovered_ex = false
base.hideTooltip(); base.hideTooltip();
} }
} }
@ -289,7 +287,7 @@ Item
width: parent.width / 100 * 45 width: parent.width / 100 * 45
style: UM.Theme.styles.combobox style: UM.Theme.styles.combobox
property bool hovered_ex: false property alias _hovered: supportExtruderMouseArea.containsMouse
currentIndex: supportEnabled.properties.value == "True" ? parseFloat(supportExtruderNr.properties.value) + 1 : 0 currentIndex: supportEnabled.properties.value == "True" ? parseFloat(supportExtruderNr.properties.value) + 1 : 0
onActivated: { onActivated: {
@ -301,18 +299,17 @@ Item
} }
} }
MouseArea { MouseArea {
id: supportExtruderMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
onEntered: onEntered:
{ {
parent.hovered_ex = true
base.showTooltip(supportExtruderCombobox, Qt.point(-supportExtruderCombobox.x, 0), base.showTooltip(supportExtruderCombobox, Qt.point(-supportExtruderCombobox.x, 0),
catalog.i18nc("@label", "Select which extruder to use for support. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air.")); catalog.i18nc("@label", "Select which extruder to use for support. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air."));
} }
onExited: onExited:
{ {
parent.hovered_ex = false
base.hideTooltip(); base.hideTooltip();
} }
} }
@ -374,8 +371,6 @@ Item
key: "infill_sparse_density" key: "infill_sparse_density"
watchedProperties: [ "value" ] watchedProperties: [ "value" ]
storeIndex: 0 storeIndex: 0
onPropertiesChanged: console.log(properties.value)
} }
UM.SettingPropertyProvider UM.SettingPropertyProvider

View File

@ -19,6 +19,7 @@ UM.PreferencesPage
{ {
UM.Preferences.resetPreference("view/show_overhang"); UM.Preferences.resetPreference("view/show_overhang");
UM.Preferences.resetPreference("view/center_on_select"); UM.Preferences.resetPreference("view/center_on_select");
UM.Preferences.resetPreference("view/top_layer_count");
} }
Column Column
@ -57,12 +58,38 @@ UM.PreferencesPage
} }
} }
UM.TooltipArea {
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip","Display 5 top layers in layer view or only the top-most layer. Rendering 5 layers takes longer, but may show more information.")
CheckBox
{
id: topLayerCheckbox
text: catalog.i18nc("@action:button","Display five top layers in layer view.");
checked: UM.Preferences.getValue("view/top_layer_count") == 5
onClicked:
{
if(UM.Preferences.getValue("view/top_layer_count") == 5)
{
UM.Preferences.setValue("view/top_layer_count", 1)
}
else
{
UM.Preferences.setValue("view/top_layer_count", 5)
}
}
}
}
Connections { Connections {
target: UM.Preferences target: UM.Preferences
onPreferenceChanged: onPreferenceChanged:
{ {
overhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang")) overhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang"))
centerCheckbox.checked = boolCheck(UM.Preferences.getValue("view/center_on_select")) centerCheckbox.checked = boolCheck(UM.Preferences.getValue("view/center_on_select"))
topLayerCheckbox = UM.Preferences.getValue("view/top_layer_count") == 5
} }
} }
} }

View File

@ -1,3 +0,0 @@
module Cura
singleton Actions 1.0 Actions.qml

View File

@ -5,6 +5,9 @@ definition = fdmprinter
[metadata] [metadata]
type = quality type = quality
weight = -3
[values] [values]
layer_height = 0.06 layer_height = 0.06
speed_topbottom = 15
speed_infill = 80

View File

@ -1,9 +1,13 @@
[general] [general]
version = 1 version = 2
name = Low Quality name = Low Quality
definition = fdmprinter
[metadata]
type = quality
weight = -1 weight = -1
[settings] [values]
infill_sparse_density = 10 infill_sparse_density = 10
layer_height = 0.15 layer_height = 0.15
cool_min_layer_time = 3 cool_min_layer_time = 3
@ -12,4 +16,3 @@ speed_wall_x = 80
speed_infill = 100 speed_infill = 100
wall_thickness = 1 wall_thickness = 1
speed_topbottom = 30 speed_topbottom = 30

View File

@ -5,5 +5,6 @@ definition = fdmprinter
[metadata] [metadata]
type = quality type = quality
weight = -2
[values] [values]

View File

@ -0,0 +1,22 @@
[general]
version = 2
name = High Quality
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_abs_ultimaker2_extended_plus_0.25_mm
weight = -2
[values]
layer_height = 0.06
wall_thickness = 0.88
top_bottom_thickness = 0.72
infill_sparse_density = 22
speed_print = 30
cool_min_layer_time = 3
cool_fan_speed_min = 20
cool_min_speed = 10
cool_min_layer_time_fan_speed_max = 15

View File

@ -0,0 +1,25 @@
[general]
version = 2
name = Fast Print
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_abs_ultimaker2_extended_plus_0.4_mm
weight = -1
[values]
layer_height = 0.15
wall_thickness = 0.7
top_bottom_thickness = 0.75
infill_sparse_density = 18
speed_print = 55
speed_wall = 40
speed_topbottom = 30
speed_travel = 150
speed_layer_0 = 30
cool_min_layer_time = 3
cool_fan_speed_min = 20
cool_min_speed = 10
cool_min_layer_time_fan_speed_max = 15

View File

@ -0,0 +1,22 @@
[general]
version = 2
name = High Quality
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_abs_ultimaker2_extended_plus_0.4_mm
weight = -3
[values]
layer_height = 0.06
wall_thickness = 1.05
top_bottom_thickness = 0.72
infill_sparse_density = 22
speed_print = 45
speed_wall = 30
cool_min_layer_time = 3
cool_fan_speed_min = 20
cool_min_speed = 10
cool_min_layer_time_fan_speed_max = 15

View File

@ -0,0 +1,21 @@
[general]
version = 2
name = Normal Quality
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_abs_ultimaker2_extended_plus_0.4_mm
weight = -2
[values]
layer_height = 0.1
wall_thickness = 1.05
top_bottom_thickness = 0.8
infill_sparse_density = 20
speed_print = 45
speed_wall = 30
cool_min_layer_time = 3
cool_fan_speed_min = 20
cool_min_speed = 10
cool_min_layer_time_fan_speed_max = 15

View File

@ -0,0 +1,23 @@
[general]
version = 2
name = Normal Quality
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_abs_ultimaker2_extended_plus_0.6_mm
weight = -2
[values]
layer_height = 0.15
wall_thickness = 1.59
top_bottom_thickness = 1.2
infill_sparse_density = 20
speed_print = 40
speed_infill = 55
cool_min_layer_time = 3
cool_fan_speed_min = 50
cool_min_speed = 20
cool_min_layer_time_fan_speed_max = 20

View File

@ -0,0 +1,21 @@
[general]
version = 2
name = Fast Print
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_abs_ultimaker2_extended_plus_0.8_mm
weight = -2
[values]
layer_height = 0.2
wall_thickness = 2.1
top_bottom_thickness = 1.2
infill_sparse_density = 20
speed_print = 40
cool_min_layer_time = 3
cool_fan_speed_min = 50
cool_min_speed = 15
cool_min_layer_time_fan_speed_max = 25

View File

@ -0,0 +1,21 @@
[general]
version = 2
name = High Quality
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_cpe_ultimaker2_extended_plus_0.25_mm
weight = -2
[values]
layer_height = 0.06
wall_thickness = 0.88
top_bottom_thickness = 0.72
infill_sparse_density = 22
speed_print = 30
cool_min_layer_time = 2
cool_fan_speed_min = 20
cool_min_speed = 15
cool_min_layer_time_fan_speed_max = 15

View File

@ -0,0 +1,25 @@
[general]
version = 2
name = Fast Print
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_cpe_ultimaker2_extended_plus_0.4_mm
weight = -1
[values]
layer_height = 0.15
wall_thickness = 0.7
top_bottom_thickness = 0.75
infill_sparse_density = 18
speed_print = 45
speed_wall = 40
speed_travel = 150
speed_layer_0 = 30
cool_min_layer_time = 3
cool_fan_speed_min = 80
cool_min_speed = 10
cool_min_layer_time_fan_speed_max = 15

View File

@ -0,0 +1,21 @@
[general]
version = 2
name = High Quality
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_cpe_ultimaker2_extended_plus_0.4_mm
weight = -3
[values]
layer_height = 0.06
wall_thickness = 1.05
top_bottom_thickness = 0.72
infill_sparse_density = 22
speed_print = 45
speed_wall = 30
cool_min_layer_time = 2
cool_fan_speed_min = 80
cool_min_speed = 15
cool_min_layer_time_fan_speed_max = 15

View File

@ -0,0 +1,22 @@
[general]
version = 2
name = Normal Quality
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_cpe_ultimaker2_extended_plus_0.4_mm
weight = -2
[values]
layer_height = 0.1
wall_thickness = 1.05
top_bottom_thickness = 0.8
infill_sparse_density = 20
speed_print = 45
speed_wall = 30
cool_min_layer_time = 3
cool_fan_speed_min = 80
cool_min_speed = 10
cool_min_layer_time_fan_speed_max = 15

View File

@ -0,0 +1,20 @@
[general]
version = 2
name = Normal Quality
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_cpe_ultimaker2_extended_plus_0.6_mm
weight = -2
[values]
layer_height = 0.15
wall_thickness = 1.59
top_bottom_thickness = 1.2
infill_sparse_density = 20
speed_print = 40
cool_min_layer_time = 5
cool_fan_speed_min = 80
cool_min_speed = 8
cool_min_layer_time_fan_speed_max = 20

View File

@ -0,0 +1,20 @@
[general]
version = 2
name = Fast Print
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_cpe_ultimaker2_extended_plus_0.8_mm
weight = -2
[values]
layer_height = 0.2
wall_thickness = 2.1
top_bottom_thickness = 1.2
infill_sparse_density = 20
speed_print = 40
cool_min_layer_time = 3
cool_fan_speed_min = 80
cool_min_speed = 8
cool_min_layer_time_fan_speed_max = 25

View File

@ -0,0 +1,18 @@
[general]
version = 2
name = High Quality
definition = ultimaker2_extended_plus
[metadata]
type = quality
material = generic_pla_ultimaker2_extended_plus_0.25_mm
weight = -2
[values]
layer_height = 0.06
wall_thickness = 0.88
top_bottom_thickness = 0.72
infill_sparse_density = 22
speed_print = 30
cool_min_layer_time = 5
cool_min_speed = 10

View File

@ -1,12 +1,14 @@
[general] [general]
version = 1 version = 2
name = Fast Print name = Fast Print
machine_type = ultimaker2plus definition = ultimaker2_extended_plus
machine_variant = 0.4 mm
material = PLA [metadata]
type = quality
material = generic_pla_ultimaker2_extended_plus_0.4_mm
weight = -1 weight = -1
[settings] [values]
layer_height = 0.15 layer_height = 0.15
wall_thickness = 0.7 wall_thickness = 0.7
top_bottom_thickness = 0.75 top_bottom_thickness = 0.75

View File

@ -1,12 +1,14 @@
[general] [general]
version = 1 version = 2
name = High Quality name = High Quality
machine_type = ultimaker2plus definition = ultimaker2_extended_plus
machine_variant = 0.4 mm
material = PLA [metadata]
type = quality
material = generic_pla_ultimaker2_extended_plus_0.4_mm
weight = -3 weight = -3
[settings] [values]
layer_height = 0.06 layer_height = 0.06
wall_thickness = 1.05 wall_thickness = 1.05
top_bottom_thickness = 0.72 top_bottom_thickness = 0.72

View File

@ -1,12 +1,14 @@
[general] [general]
version = 1 version = 2
name = Normal Quality name = Normal Quality
machine_type = ultimaker2plus definition = ultimaker2_extended_plus
machine_variant = 0.4 mm
material = PLA [metadata]
type = quality
material = generic_pla_ultimaker2_extended_plus_0.4_mm
weight = -2 weight = -2
[settings] [values]
layer_height = 0.1 layer_height = 0.1
wall_thickness = 1.05 wall_thickness = 1.05
top_bottom_thickness = 0.8 top_bottom_thickness = 0.8

View File

@ -1,12 +1,14 @@
[general] [general]
version = 1 version = 2
name = Normal Quality name = Normal Quality
machine_type = ultimaker2plus definition = ultimaker2_extended_plus
machine_variant = 0.6 mm
material = PLA [metadata]
material = generic_pla_ultimaker2_extended_plus_0.6_mm
type = quality
weight = -2 weight = -2
[settings] [values]
layer_height = 0.15 layer_height = 0.15
wall_thickness = 1.59 wall_thickness = 1.59
top_bottom_thickness = 1.2 top_bottom_thickness = 1.2

View File

@ -1,12 +1,14 @@
[general] [general]
version = 1 version = 2
name = Fast Print name = Fast Print
machine_type = ultimaker2plus definition = ultimaker2_extended_plus
machine_variant = 0.8 mm
material = PLA [metadata]
material = generic_pla_ultimaker2_extended_plus_0.8_mm
type = quality
weight = -2 weight = -2
[settings] [values]
layer_height = 0.2 layer_height = 0.2
wall_thickness = 2.1 wall_thickness = 2.1
top_bottom_thickness = 1.2 top_bottom_thickness = 1.2

View File

@ -1,12 +1,14 @@
[general] [general]
version = 1 version = 2
name = High Quality name = High Quality
machine_type = ultimaker2plus definition = ultimaker2_plus
machine_variant = 0.25 mm
material = PLA [metadata]
type = quality
material = generic_pla_ultimaker2_plus_0.25_mm
weight = -2 weight = -2
[settings] [values]
layer_height = 0.06 layer_height = 0.06
wall_thickness = 0.88 wall_thickness = 0.88
top_bottom_thickness = 0.72 top_bottom_thickness = 0.72

Some files were not shown because too many files have changed in this diff Show More