mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-13 21:15:53 +08:00
Merge branch 'master' into fix_simple_mode_disabled_features
# Conflicts: # resources/qml/SidebarSimple.qml
This commit is contained in:
commit
adc1630a20
@ -52,6 +52,8 @@ if(NOT APPLE AND NOT WIN32)
|
||||
DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages/cura)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/cura.desktop
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/resources/images/cura-icon.png
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/128x128/apps/)
|
||||
install(FILES cura.appdata.xml
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/appdata)
|
||||
install(FILES cura.sharedmimeinfo
|
||||
|
@ -50,12 +50,11 @@ Third party plugins
|
||||
* [X3G Writer](https://github.com/Ghostkeeper/X3GWriter): Adds support for exporting X3G files.
|
||||
* [Auto orientation](https://github.com/nallath/CuraOrientationPlugin): Calculate the optimal orientation for a model.
|
||||
* [OctoPrint Plugin](https://github.com/fieldofview/OctoPrintPlugin): Send printjobs directly to OctoPrint and monitor their progress in Cura.
|
||||
* [WirelessPrinting Plugin](https://github.com/probonopd/WirelessPrinting): Print wirelessly from Cura to your 3D printer connected to an ESP8266 module.
|
||||
* [Electric Print Cost Calculator Plugin](https://github.com/zoff99/ElectricPrintCostCalculator): Calculate the electric costs of a print.
|
||||
|
||||
Making profiles for other printers
|
||||
----------------------------------
|
||||
There are two ways of doing it. You can either use the generator [here](http://quillford.github.io/CuraProfileMaker/) or you can use [this](https://github.com/Ultimaker/Cura/blob/master/resources/definitions/ultimaker_original.def.json) as a template.
|
||||
If your make of printer is not in the list of supported printers, and using the "Custom FDM Printer" does not offer enough flexibility, you can use [this](https://github.com/Ultimaker/Cura/blob/master/resources/definitions/ultimaker_original.def.json) as a template.
|
||||
|
||||
* Change the machine ID to something unique
|
||||
* Change the machine_name to your printer's name
|
||||
@ -63,12 +62,12 @@ There are two ways of doing it. You can either use the generator [here](http://q
|
||||
* Set your machine's dimensions with machine_width, machine_depth, and machine_height
|
||||
* If your printer's origin is in the center of the bed, set machine_center_is_zero to true.
|
||||
* Set your print head dimensions with the machine_head_shape parameters
|
||||
* Set the nozzle offset with machine_nozzle_offset_x and machine_nozzle_offset_y
|
||||
* Set the start and end gcode in machine_start_gcode and machine_end_gcode
|
||||
* If your printer has a heated bed, set visible to true under material_bed_temperature
|
||||
|
||||
Once you are done, put the profile you have made into resources/definitions, or in definitions in your cura profile folder.
|
||||
|
||||
If you want to make a definition for a multi-extrusion printer, have a look at [this](https://github.com/Ultimaker/Cura/blob/master/resources/definitions/ultimaker_original_dual.def.json) as a template, along with the two extruder definitions it references [here](https://github.com/Ultimaker/Cura/blob/master/resources/extruders/ultimaker_original_dual_1st.def.json) and [here](https://github.com/Ultimaker/Cura/blob/master/resources/extruders/ultimaker_original_dual_2nd.def.json)
|
||||
|
||||
Translating Cura
|
||||
----------------
|
||||
If you'd like to contribute a translation of Cura, please first look for [any existing translation](https://github.com/Ultimaker/Cura/tree/master/resources/i18n). If your language is already there in the source code but not in Cura's interface, it may be partially translated.
|
||||
@ -89,4 +88,4 @@ To submit your translation, ideally you would make two pull requests where all `
|
||||
|
||||
After the translation is submitted, the Cura maintainers will check for its completeness and check whether it is consistent. We will take special care to look for common mistakes, such as translating mark-up `<message>` code and such. We are often not fluent in every language, so we expect the translator and the international users to make corrections where necessary. Of course, there will always be some mistakes in every translation.
|
||||
|
||||
When the next Cura release comes around, some of the texts will have changed and some new texts will have been added. Around the time when the beta is released we will invoke a string freeze, meaning that no developer is allowed to make changes to the texts. Then we will update the translation template `.pot` files and ask all our translators to update their translations. If you are unable to update the translation in time for the actual release, we will remove the language from the drop-down menu in the Preferences window. The translation stays in Cura however, so that someone might pick it up again later and update it with the newest texts. Also, users who had previously selected the language can still continue Cura in their language but English text will appear among the original text.
|
||||
When the next Cura release comes around, some of the texts will have changed and some new texts will have been added. Around the time when the beta is released we will invoke a string freeze, meaning that no developer is allowed to make changes to the texts. Then we will update the translation template `.pot` files and ask all our translators to update their translations. If you are unable to update the translation in time for the actual release, we will remove the language from the drop-down menu in the Preferences window. The translation stays in Cura however, so that someone might pick it up again later and update it with the newest texts. Also, users who had previously selected the language can still continue Cura in their language but English text will appear among the original text.
|
||||
|
@ -7,9 +7,9 @@ Comment=Cura converts 3D models into paths for a 3D printer. It prepares your pr
|
||||
Comment[de]=Cura wandelt 3D-Modelle in Pfade für einen 3D-Drucker um. Es bereitet Ihren Druck für maximale Genauigkeit, minimale Druckzeit und guter Zuverlässigkeit mit vielen zusätzlichen Funktionen vor, damit Ihr Druck großartig wird.
|
||||
Exec=@CMAKE_INSTALL_FULL_BINDIR@/cura %F
|
||||
TryExec=@CMAKE_INSTALL_FULL_BINDIR@/cura
|
||||
Icon=@CMAKE_INSTALL_FULL_DATADIR@/cura/resources/images/cura-icon.png
|
||||
Icon=cura-icon
|
||||
Terminal=false
|
||||
Type=Application
|
||||
MimeType=application/sla;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png
|
||||
MimeType=application/sla;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png;
|
||||
Categories=Graphics;
|
||||
Keywords=3D;Printing;
|
||||
|
@ -174,7 +174,7 @@ class BuildVolume(SceneNode):
|
||||
self._plate_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader"))
|
||||
theme = Application.getInstance().getTheme()
|
||||
self._plate_shader.setUniformValue("u_color", Color(*theme.getColor("buildplate").getRgb()))
|
||||
self._plate_shader.setUniformValue("u_z_bias", 0.01)
|
||||
self._plate_shader.setUniformValue("u_z_bias", 0.000001)
|
||||
|
||||
renderer.queueNode(self, mode = RenderBatch.RenderMode.Lines)
|
||||
renderer.queueNode(self, mesh = self._origin_mesh)
|
||||
|
@ -205,6 +205,8 @@ class CuraApplication(QtApplication):
|
||||
super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType,
|
||||
tray_icon_name = "cura-icon-32.png")
|
||||
|
||||
self.default_theme = "cura-light"
|
||||
|
||||
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
|
||||
|
||||
self.setRequiredPlugins([
|
||||
@ -486,7 +488,7 @@ class CuraApplication(QtApplication):
|
||||
f.write(data)
|
||||
|
||||
|
||||
@pyqtSlot(str, result = QUrl)
|
||||
@pyqtSlot(str, result=QUrl)
|
||||
def getDefaultPath(self, key):
|
||||
default_path = Preferences.getInstance().getValue("local_file/%s" % key)
|
||||
return QUrl.fromLocalFile(default_path)
|
||||
@ -1126,7 +1128,7 @@ class CuraApplication(QtApplication):
|
||||
|
||||
expandedCategoriesChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty("QStringList", notify = expandedCategoriesChanged)
|
||||
@pyqtProperty("QStringList", notify=expandedCategoriesChanged)
|
||||
def expandedCategories(self):
|
||||
return Preferences.getInstance().getValue("cura/categories_expanded").split(";")
|
||||
|
||||
|
@ -233,13 +233,16 @@ class QualityManager:
|
||||
filter_by_material = False
|
||||
|
||||
machine_definition = self.getParentMachineDefinition(machine_definition)
|
||||
criteria["definition"] = machine_definition.getId()
|
||||
found_containers_with_machine_definition = ContainerRegistry.getInstance().findInstanceContainers(**criteria)
|
||||
whole_machine_definition = self.getWholeMachineDefinition(machine_definition)
|
||||
if whole_machine_definition.getMetaDataEntry("has_machine_quality"):
|
||||
definition_id = machine_definition.getMetaDataEntry("quality_definition", whole_machine_definition.getId())
|
||||
criteria["definition"] = definition_id
|
||||
|
||||
filter_by_material = whole_machine_definition.getMetaDataEntry("has_materials")
|
||||
else:
|
||||
# only fall back to "fdmprinter" when there is no container for this machine
|
||||
elif not found_containers_with_machine_definition:
|
||||
criteria["definition"] = "fdmprinter"
|
||||
|
||||
# Stick the material IDs in a set
|
||||
|
@ -432,6 +432,7 @@ class CuraContainerStack(ContainerStack):
|
||||
# - If the machine definition has a metadata entry "has_machine_materials", the definition of the material should
|
||||
# be the same as the machine definition for this stack. Otherwise, the definition should be "fdmprinter".
|
||||
# - The container should have a metadata entry "type" with value "material".
|
||||
# - The material should have an approximate diameter that matches the machine
|
||||
# - If the machine definition has a metadata entry "has_variants" and set to True, the "variant" metadata entry of
|
||||
# the material should be the same as the ID of the variant in the stack. Only applies if "has_machine_materials" is also True.
|
||||
# - If the stack currently has a material set, try to find a material that matches the current material by name.
|
||||
@ -460,6 +461,9 @@ class CuraContainerStack(ContainerStack):
|
||||
if preferred_material:
|
||||
search_criteria["id"] = preferred_material
|
||||
|
||||
approximate_material_diameter = str(round(self.getProperty("material_diameter", "value")))
|
||||
search_criteria["approximate_diameter"] = approximate_material_diameter
|
||||
|
||||
materials = ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
|
||||
if not materials:
|
||||
Logger.log("w", "The preferred material \"{material}\" could not be found for stack {stack}", material = preferred_material, stack = self.id)
|
||||
|
@ -7,7 +7,7 @@ from UM.Decorators import override
|
||||
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Settings.Interfaces import ContainerInterface
|
||||
from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext
|
||||
|
||||
from . import Exceptions
|
||||
from .CuraContainerStack import CuraContainerStack
|
||||
@ -57,21 +57,32 @@ class ExtruderStack(CuraContainerStack):
|
||||
# \throws Exceptions.NoGlobalStackError Raised when trying to get a property from an extruder without
|
||||
# having a next stack set.
|
||||
@override(ContainerStack)
|
||||
def getProperty(self, key: str, property_name: str) -> Any:
|
||||
def getProperty(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> Any:
|
||||
if not self._next_stack:
|
||||
raise Exceptions.NoGlobalStackError("Extruder {id} is missing the next stack!".format(id = self.id))
|
||||
|
||||
if not super().getProperty(key, "settable_per_extruder"):
|
||||
return self.getNextStack().getProperty(key, property_name)
|
||||
if context is None:
|
||||
context = PropertyEvaluationContext()
|
||||
context.pushContainer(self)
|
||||
|
||||
limit_to_extruder = super().getProperty(key, "limit_to_extruder")
|
||||
if not super().getProperty(key, "settable_per_extruder", context):
|
||||
result = self.getNextStack().getProperty(key, property_name, context)
|
||||
context.popContainer()
|
||||
return result
|
||||
|
||||
limit_to_extruder = super().getProperty(key, "limit_to_extruder", context)
|
||||
if limit_to_extruder is not None:
|
||||
limit_to_extruder = str(limit_to_extruder)
|
||||
if (limit_to_extruder is not None and limit_to_extruder != "-1") and self.getMetaDataEntry("position") != str(limit_to_extruder):
|
||||
if str(limit_to_extruder) in self.getNextStack().extruders:
|
||||
result = self.getNextStack().extruders[str(limit_to_extruder)].getProperty(key, property_name)
|
||||
result = self.getNextStack().extruders[str(limit_to_extruder)].getProperty(key, property_name, context)
|
||||
if result is not None:
|
||||
context.popContainer()
|
||||
return result
|
||||
|
||||
return super().getProperty(key, property_name)
|
||||
result = super().getProperty(key, property_name, context)
|
||||
context.popContainer()
|
||||
return result
|
||||
|
||||
@override(CuraContainerStack)
|
||||
def _getMachineDefinition(self) -> ContainerInterface:
|
||||
|
@ -11,6 +11,7 @@ from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.SettingInstance import InstanceState
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Settings.Interfaces import PropertyEvaluationContext
|
||||
from UM.Logger import Logger
|
||||
|
||||
from . import Exceptions
|
||||
@ -91,29 +92,38 @@ class GlobalStack(CuraContainerStack):
|
||||
#
|
||||
# \return The value of the property for the specified setting, or None if not found.
|
||||
@override(ContainerStack)
|
||||
def getProperty(self, key: str, property_name: str) -> Any:
|
||||
def getProperty(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> Any:
|
||||
if not self.definition.findDefinitions(key = key):
|
||||
return None
|
||||
|
||||
# Handle the "resolve" property.
|
||||
if self._shouldResolve(key, property_name):
|
||||
self._resolving_settings.add(key)
|
||||
resolve = super().getProperty(key, "resolve")
|
||||
resolve = super().getProperty(key, "resolve", context)
|
||||
self._resolving_settings.remove(key)
|
||||
if resolve is not None:
|
||||
return resolve
|
||||
|
||||
if context is None:
|
||||
context = PropertyEvaluationContext()
|
||||
context.pushContainer(self)
|
||||
|
||||
# Handle the "limit_to_extruder" property.
|
||||
limit_to_extruder = super().getProperty(key, "limit_to_extruder")
|
||||
limit_to_extruder = super().getProperty(key, "limit_to_extruder", context)
|
||||
if limit_to_extruder is not None:
|
||||
limit_to_extruder = str(limit_to_extruder)
|
||||
if limit_to_extruder is not None and limit_to_extruder != "-1" and limit_to_extruder in self._extruders:
|
||||
if super().getProperty(key, "settable_per_extruder"):
|
||||
result = self._extruders[str(limit_to_extruder)].getProperty(key, property_name)
|
||||
if super().getProperty(key, "settable_per_extruder", context):
|
||||
result = self._extruders[str(limit_to_extruder)].getProperty(key, property_name, context)
|
||||
if result is not None:
|
||||
context.popContainer()
|
||||
return result
|
||||
else:
|
||||
Logger.log("e", "Setting {setting} has limit_to_extruder but is not settable per extruder!", setting = key)
|
||||
|
||||
return super().getProperty(key, property_name)
|
||||
result = super().getProperty(key, property_name, context)
|
||||
context.popContainer()
|
||||
return result
|
||||
|
||||
## Overridden from ContainerStack
|
||||
#
|
||||
|
@ -649,6 +649,23 @@ class MachineManager(QObject):
|
||||
return Util.parseBool(quality.getMetaDataEntry("supported", True))
|
||||
return False
|
||||
|
||||
## Returns whether there is anything unsupported in the current set-up.
|
||||
#
|
||||
# The current set-up signifies the global stack and all extruder stacks,
|
||||
# so this indicates whether there is any container in any of the container
|
||||
# stacks that is not marked as supported.
|
||||
@pyqtProperty(bool, notify = activeQualityChanged)
|
||||
def isCurrentSetupSupported(self) -> bool:
|
||||
if not self._global_container_stack:
|
||||
return False
|
||||
for stack in [self._global_container_stack] + list(self._global_container_stack.extruders.values()):
|
||||
for container in stack.getContainers():
|
||||
if not container:
|
||||
return False
|
||||
if not Util.parseBool(container.getMetaDataEntry("supported", True)):
|
||||
return False
|
||||
return True
|
||||
|
||||
## Get the Quality ID associated with the currently active extruder
|
||||
# Note that this only returns the "quality", not the "quality_changes"
|
||||
# \returns QualityID (string) if found, empty string otherwise
|
||||
|
65
cura/Settings/PerObjectContainerStack.py
Normal file
65
cura/Settings/PerObjectContainerStack.py
Normal file
@ -0,0 +1,65 @@
|
||||
from typing import Any, Optional
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Decorators import override
|
||||
from UM.Settings.Interfaces import PropertyEvaluationContext
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.SettingInstance import InstanceState
|
||||
|
||||
|
||||
class PerObjectContainerStack(ContainerStack):
|
||||
|
||||
@override(ContainerStack)
|
||||
def getProperty(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> Any:
|
||||
if context is None:
|
||||
context = PropertyEvaluationContext()
|
||||
context.pushContainer(self)
|
||||
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
|
||||
# Return the user defined value if present, otherwise, evaluate the value according to the default routine.
|
||||
if self.getContainer(0).hasProperty(key, property_name):
|
||||
if self.getContainer(0)._instances[key].state == InstanceState.User:
|
||||
result = super().getProperty(key, property_name, context)
|
||||
context.popContainer()
|
||||
return result
|
||||
|
||||
# Handle the "limit_to_extruder" property.
|
||||
limit_to_extruder = super().getProperty(key, "limit_to_extruder", context)
|
||||
if limit_to_extruder is not None:
|
||||
limit_to_extruder = str(limit_to_extruder)
|
||||
|
||||
# if this stack has the limit_to_extruder "not overriden", use the original limit_to_extruder as the current
|
||||
# limit_to_extruder, so the values retrieved will be from the perspective of the original limit_to_extruder
|
||||
# stack.
|
||||
if limit_to_extruder == "-1":
|
||||
if "original_limit_to_extruder" in context.context:
|
||||
limit_to_extruder = context.context["original_limit_to_extruder"]
|
||||
|
||||
if limit_to_extruder is not None and limit_to_extruder != "-1" and limit_to_extruder in global_stack.extruders:
|
||||
# set the original limit_to_extruder if this is the first stack that has a non-overriden limit_to_extruder
|
||||
if "original_limit_to_extruder" not in context.context:
|
||||
context.context["original_limit_to_extruder"] = limit_to_extruder
|
||||
|
||||
if super().getProperty(key, "settable_per_extruder", context):
|
||||
result = global_stack.extruders[str(limit_to_extruder)].getProperty(key, property_name, context)
|
||||
if result is not None:
|
||||
context.popContainer()
|
||||
return result
|
||||
|
||||
result = super().getProperty(key, property_name, context)
|
||||
context.popContainer()
|
||||
return result
|
||||
|
||||
@override(ContainerStack)
|
||||
def setNextStack(self, stack: ContainerStack):
|
||||
super().setNextStack(stack)
|
||||
|
||||
# trigger signal to re-evaluate all default settings
|
||||
for key, instance in self.getContainer(0)._instances.items():
|
||||
# only evaluate default settings
|
||||
if instance.state != InstanceState.Default:
|
||||
continue
|
||||
|
||||
self._collectPropertyChanges(key, "value")
|
||||
self._emitCollectedPropertyChanges()
|
@ -5,13 +5,13 @@ import copy
|
||||
|
||||
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
|
||||
from UM.Signal import Signal, signalemitter
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Logger import Logger
|
||||
|
||||
from UM.Application import Application
|
||||
|
||||
from cura.Settings.PerObjectContainerStack import PerObjectContainerStack
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
|
||||
## A decorator that adds a container stack to a Node. This stack should be queried for all settings regarding
|
||||
@ -24,7 +24,7 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._stack = ContainerStack(stack_id = id(self))
|
||||
self._stack = PerObjectContainerStack(stack_id = id(self))
|
||||
self._stack.setDirty(False) # This stack does not need to be saved.
|
||||
self._stack.addContainer(InstanceContainer(container_id = "SettingOverrideInstanceContainer"))
|
||||
|
||||
|
@ -818,29 +818,27 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
each_extruder_stack.definitionChanges = each_changes_container
|
||||
|
||||
if self._resolve_strategies["material"] == "new":
|
||||
# the actual material instance container can have an ID such as
|
||||
# <material>_<machine>_<variant>
|
||||
# which cannot be determined immediately, so here we use a HACK to find the right new material
|
||||
# instance ID:
|
||||
# - get the old material IDs for all material
|
||||
# - find the old material with the longest common prefix in ID, that's the old material
|
||||
# - update the name by replacing the old prefix with the new
|
||||
# - find the new material container and set it to the stack
|
||||
old_to_new_material_dict = {}
|
||||
for each_material in material_containers:
|
||||
old_material = global_stack.material
|
||||
|
||||
# check if the old material container has been renamed to this material container ID
|
||||
# if the container hasn't been renamed, we do nothing.
|
||||
new_id = self._id_mapping.get(old_material.getId())
|
||||
if new_id is None or new_id != each_material.getId():
|
||||
continue
|
||||
|
||||
if old_material.getId() in self._id_mapping:
|
||||
global_stack.material = each_material
|
||||
# find the material's old name
|
||||
for old_id, new_id in self._id_mapping.items():
|
||||
if each_material.getId() == new_id:
|
||||
old_to_new_material_dict[old_id] = each_material
|
||||
break
|
||||
|
||||
# replace old material in global and extruder stacks with new
|
||||
self._replaceStackMaterialWithNew(global_stack, old_to_new_material_dict)
|
||||
if extruder_stacks:
|
||||
for each_extruder_stack in extruder_stacks:
|
||||
old_material = each_extruder_stack.material
|
||||
|
||||
# check if the old material container has been renamed to this material container ID
|
||||
# if the container hasn't been renamed, we do nothing.
|
||||
new_id = self._id_mapping.get(old_material.getId())
|
||||
if new_id is None or new_id != each_material.getId():
|
||||
continue
|
||||
|
||||
if old_material.getId() in self._id_mapping:
|
||||
each_extruder_stack.material = each_material
|
||||
self._replaceStackMaterialWithNew(each_extruder_stack, old_to_new_material_dict)
|
||||
|
||||
if extruder_stacks:
|
||||
for stack in extruder_stacks:
|
||||
@ -865,6 +863,61 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
nodes = []
|
||||
return nodes
|
||||
|
||||
## HACK: Replaces the material container in the given stack with a newly created material container.
|
||||
# This function is used when the user chooses to resolve material conflicts by creating new ones.
|
||||
def _replaceStackMaterialWithNew(self, stack, old_new_material_dict):
|
||||
# The material containers in the project file are 'parent' material such as "generic_pla",
|
||||
# but a material container used in a global/extruder stack is a 'child' material,
|
||||
# such as "generic_pla_ultimaker3_AA_0.4", which can be formalised as the following:
|
||||
#
|
||||
# <material_name>_<machine_name>_<variant_name>
|
||||
#
|
||||
# In the project loading, when a user chooses to resolve material conflicts by creating new ones,
|
||||
# the old 'parent' material ID and the new 'parent' material ID are known, but not the child material IDs.
|
||||
# In this case, the global stack and the extruder stacks need to use the newly created material, but the
|
||||
# material containers they use are 'child' material. So, here, we need to find the right 'child' material for
|
||||
# the stacks.
|
||||
#
|
||||
# This hack approach works as follows:
|
||||
# - No matter there is a child material or not, the actual material we are looking for has the prefix
|
||||
# "<material_name>", which is the old material name. For the material in a stack, we know that the new
|
||||
# material's ID will be "<new_material_name>_blabla..", so we just need to replace the old material ID
|
||||
# with the new one to get the new 'child' material.
|
||||
# - Because the material containers have IDs such as "m #nn", if we use simple prefix matching, there can
|
||||
# be a problem in the following scenario:
|
||||
# - there are two materials in the project file, namely "m #1" and "m #11"
|
||||
# - the child materials in use are for example: "m #1_um3_aa04", "m #11_um3_aa04"
|
||||
# - if we only check for a simple prefix match, then "m #11_um3_aa04" will match with "m #1", but they
|
||||
# are not the same material
|
||||
# To avoid this, when doing the prefix matching, we use the result with the longest mactching prefix.
|
||||
|
||||
# find the old material ID
|
||||
old_material_id_in_stack = stack.material.getId()
|
||||
best_matching_old_material_id = None
|
||||
best_matching_old_meterial_prefix_length = -1
|
||||
for old_parent_material_id in old_new_material_dict:
|
||||
if len(old_parent_material_id) < best_matching_old_meterial_prefix_length:
|
||||
continue
|
||||
if len(old_parent_material_id) <= len(old_material_id_in_stack):
|
||||
if old_parent_material_id == old_material_id_in_stack[0:len(old_parent_material_id)]:
|
||||
best_matching_old_meterial_prefix_length = len(old_parent_material_id)
|
||||
best_matching_old_material_id = old_parent_material_id
|
||||
|
||||
if best_matching_old_material_id is None:
|
||||
Logger.log("w", "Cannot find any matching old material ID for stack [%s] material [%s]. Something can go wrong",
|
||||
stack.getId(), old_material_id_in_stack)
|
||||
return
|
||||
|
||||
# find the new material container
|
||||
new_material_id = old_new_material_dict[best_matching_old_material_id].getId() + old_material_id_in_stack[len(best_matching_old_material_id):]
|
||||
new_material_containers = self._container_registry.findInstanceContainers(id = new_material_id, type = "material")
|
||||
if not new_material_containers:
|
||||
Logger.log("e", "Cannot find new material container [%s]", new_material_id)
|
||||
return
|
||||
|
||||
# replace the material in the given stack
|
||||
stack.material = new_material_containers[0]
|
||||
|
||||
def _stripFileToId(self, file):
|
||||
mime_type = MimeTypeDatabase.getMimeTypeForFile(file)
|
||||
file = mime_type.stripExtension(file)
|
||||
|
@ -56,6 +56,9 @@ Extra tooltips have been added to clarify the machine settings.
|
||||
*Polish now supported
|
||||
Polish language support added. This can be selected in the preferences menu.
|
||||
|
||||
*Chinese now supported
|
||||
Chinese language support added. This can be selected in the preferences menu.
|
||||
|
||||
*Bug fixes
|
||||
- Cura project Mac extensions
|
||||
- Crashes when adding printers
|
||||
|
@ -427,6 +427,7 @@ class CuraEngineBackend(QObject, Backend):
|
||||
|
||||
## Convenient function: set need_slicing, emit state and clear layer data
|
||||
def needsSlicing(self):
|
||||
self.stopSlicing()
|
||||
self._need_slicing = True
|
||||
self.processingProgress.emit(0.0)
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
|
@ -224,7 +224,18 @@ class StartSliceJob(Job):
|
||||
|
||||
material_instance_container = stack.findContainer({"type": "material"})
|
||||
|
||||
settings = {}
|
||||
for key in stack.getAllKeys():
|
||||
settings[key] = stack.getProperty(key, "value")
|
||||
Job.yieldThread()
|
||||
|
||||
settings["print_bed_temperature"] = settings["material_bed_temperature"] #Renamed settings.
|
||||
settings["print_temperature"] = settings["material_print_temperature"]
|
||||
settings["time"] = time.strftime("%H:%M:%S") #Some extra settings.
|
||||
settings["date"] = time.strftime("%d-%m-%Y")
|
||||
settings["day"] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][int(time.strftime("%w"))]
|
||||
|
||||
for key, value in settings.items():
|
||||
# Do not send settings that are not settable_per_extruder.
|
||||
if not stack.getProperty(key, "settable_per_extruder"):
|
||||
continue
|
||||
@ -233,6 +244,8 @@ class StartSliceJob(Job):
|
||||
if key == "material_guid" and material_instance_container:
|
||||
# Also send the material GUID. This is a setting in fdmprinter, but we have no interface for it.
|
||||
setting.value = str(material_instance_container.getMetaDataEntry("GUID", "")).encode("utf-8")
|
||||
elif key == "machine_extruder_start_code" or key == "machine_extruder_end_code":
|
||||
setting.value = self._expandGcodeTokens(key, value, settings)
|
||||
else:
|
||||
setting.value = str(stack.getProperty(key, "value")).encode("utf-8")
|
||||
Job.yieldThread()
|
||||
@ -278,7 +291,7 @@ class StartSliceJob(Job):
|
||||
for key, value in settings.items(): #Add all submessages for each individual setting.
|
||||
setting_message = self._slice_message.getMessage("global_settings").addRepeatedMessage("settings")
|
||||
setting_message.name = key
|
||||
if key == "machine_start_gcode" or key == "machine_end_gcode" or key == "machine_extruder_start_code" or key == "machine_extruder_end_code": #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)
|
||||
else:
|
||||
setting_message.value = str(value).encode("utf-8")
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2015 Ultimaker B.V.
|
||||
// Copyright (c) 2017 Ultimaker B.V.
|
||||
// Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
@ -71,7 +71,7 @@ Item
|
||||
id: layersLabel
|
||||
anchors.left: parent.left
|
||||
text: catalog.i18nc("@label","View Mode: Layers")
|
||||
font.bold: true
|
||||
font: UM.Theme.getFont("default_bold");
|
||||
color: UM.Theme.getColor("text")
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideMiddle;
|
||||
@ -90,6 +90,7 @@ Item
|
||||
id: layerViewTypesLabel
|
||||
anchors.left: parent.left
|
||||
text: catalog.i18nc("@label","Color scheme")
|
||||
font: UM.Theme.getFont("default");
|
||||
visible: !UM.LayerView.compatibilityMode
|
||||
Layout.fillWidth: true
|
||||
color: UM.Theme.getColor("text")
|
||||
@ -148,6 +149,7 @@ Item
|
||||
id: compatibilityModeLabel
|
||||
anchors.left: parent.left
|
||||
text: catalog.i18nc("@label","Compatibility Mode")
|
||||
font: UM.Theme.getFont("default")
|
||||
color: UM.Theme.getColor("text")
|
||||
visible: UM.LayerView.compatibilityMode
|
||||
Layout.fillWidth: true
|
||||
@ -210,6 +212,7 @@ Item
|
||||
text: model.name
|
||||
elide: Text.ElideRight
|
||||
color: UM.Theme.getColor("text")
|
||||
font: UM.Theme.getFont("default")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: extrudersModelCheckBox.left;
|
||||
anchors.right: extrudersModelCheckBox.right;
|
||||
@ -275,6 +278,7 @@ Item
|
||||
Label
|
||||
{
|
||||
text: label
|
||||
font: UM.Theme.getFont("default")
|
||||
elide: Text.ElideRight
|
||||
color: UM.Theme.getColor("text")
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@ -340,6 +344,7 @@ Item
|
||||
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
|
||||
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
|
||||
color: UM.Theme.getColor("text")
|
||||
font: UM.Theme.getFont("default")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -487,6 +492,8 @@ Item
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
radius: parent.handleRadius
|
||||
color: parent.upperHandleColor
|
||||
border.width: UM.Theme.getSize("default_lining").width
|
||||
border.color: UM.Theme.getColor("slider_handle_border")
|
||||
|
||||
visible: slider.layersVisible
|
||||
|
||||
@ -526,6 +533,8 @@ Item
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
radius: parent.handleRadius
|
||||
color: parent.lowerHandleColor
|
||||
border.width: UM.Theme.getSize("default_lining").width
|
||||
border.color: UM.Theme.getColor("slider_handle_border")
|
||||
|
||||
visible: slider.layersVisible
|
||||
|
||||
|
@ -233,6 +233,7 @@ Cura.MachineAction
|
||||
property string label: catalog.i18nc("@label", "Gantry height")
|
||||
property string unit: catalog.i18nc("@label", "mm")
|
||||
property string tooltip: catalog.i18nc("@tooltip", "The height difference between the tip of the nozzle and the gantry system (X and Y axes). Used to prevent collisions between previous prints and the gantry when printing \"One at a Time\".")
|
||||
property bool forceUpdateOnChange: true
|
||||
}
|
||||
|
||||
Item { width: UM.Theme.getSize("default_margin").width; height: UM.Theme.getSize("default_margin").height }
|
||||
@ -823,7 +824,7 @@ Cura.MachineAction
|
||||
polygon.push([-printHeadPolygon["x"]["min"], printHeadPolygon["y"]["max"]]);
|
||||
polygon.push([-printHeadPolygon["x"]["min"],-printHeadPolygon["y"]["min"]]);
|
||||
polygon.push([ printHeadPolygon["x"]["max"], printHeadPolygon["y"]["max"]]);
|
||||
polygon.push([ printHeadPolygon["x"]["max"],-printHeadPolygon["y"]["mìn"]]);
|
||||
polygon.push([ printHeadPolygon["x"]["max"],-printHeadPolygon["y"]["min"]]);
|
||||
var polygon_string = JSON.stringify(polygon);
|
||||
if(polygon_string != machineHeadPolygonProvider.properties.value)
|
||||
{
|
||||
|
@ -135,6 +135,8 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Specialty provider that only watches global_inherits (we cant filter on what property changed we get events
|
||||
// so we bypass that to make a dedicated provider).
|
||||
UM.SettingPropertyProvider
|
||||
{
|
||||
id: provider
|
||||
@ -146,8 +148,6 @@ Item {
|
||||
removeUnusedValue: false
|
||||
}
|
||||
|
||||
// Specialty provider that only watches global_inherits (we cant filter on what property changed we get events
|
||||
// so we bypass that to make a dedicated provider).
|
||||
UM.SettingPropertyProvider
|
||||
{
|
||||
id: inheritStackProvider
|
||||
@ -156,36 +156,42 @@ Item {
|
||||
watchedProperties: [ "limit_to_extruder" ]
|
||||
}
|
||||
|
||||
Binding
|
||||
Connections
|
||||
{
|
||||
target: provider
|
||||
property: "containerStackId"
|
||||
when: model.settable_per_extruder || (inheritStackProvider.properties.limit_to_extruder != null && inheritStackProvider.properties.limit_to_extruder >= 0);
|
||||
value:
|
||||
target: inheritStackProvider
|
||||
onPropertiesChanged:
|
||||
{
|
||||
// associate this binding with Cura.MachineManager.activeMachineId in the beginning so this
|
||||
// binding will be triggered when activeMachineId is changed too.
|
||||
// Otherwise, if this value only depends on the extruderIds, it won't get updated when the
|
||||
// machine gets changed.
|
||||
var activeMachineId = Cura.MachineManager.activeMachineId;
|
||||
provider.forcePropertiesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
if(!model.settable_per_extruder || machineExtruderCount.properties.value == 1)
|
||||
Connections
|
||||
{
|
||||
target: UM.ActiveTool
|
||||
onPropertiesChanged:
|
||||
{
|
||||
// the values cannot be bound with UM.ActiveTool.properties.getValue() calls,
|
||||
// so here we connect to the signal and update the those values.
|
||||
if (typeof UM.ActiveTool.properties.getValue("SelectedObjectId") !== "undefined")
|
||||
{
|
||||
//Not settable per extruder or there only is global, so we must pick global.
|
||||
return activeMachineId;
|
||||
const selectedObjectId = UM.ActiveTool.properties.getValue("SelectedObjectId");
|
||||
if (addedSettingsModel.visibilityHandler.selectedObjectId != selectedObjectId)
|
||||
{
|
||||
addedSettingsModel.visibilityHandler.selectedObjectId = selectedObjectId;
|
||||
}
|
||||
}
|
||||
if(inheritStackProvider.properties.limit_to_extruder != null && inheritStackProvider.properties.limit_to_extruder >= 0)
|
||||
if (typeof UM.ActiveTool.properties.getValue("ContainerID") !== "undefined")
|
||||
{
|
||||
//We have limit_to_extruder, so pick that stack.
|
||||
return ExtruderManager.extruderIds[String(inheritStackProvider.properties.limit_to_extruder)];
|
||||
const containerId = UM.ActiveTool.properties.getValue("ContainerID");
|
||||
if (provider.containerStackId != containerId)
|
||||
{
|
||||
provider.containerStackId = containerId;
|
||||
}
|
||||
if (inheritStackProvider.containerStackId != containerId)
|
||||
{
|
||||
inheritStackProvider.containerStackId = containerId;
|
||||
}
|
||||
}
|
||||
if(ExtruderManager.activeExtruderStackId)
|
||||
{
|
||||
//We're on an extruder tab. Pick the current extruder.
|
||||
return ExtruderManager.activeExtruderStackId;
|
||||
}
|
||||
//No extruder tab is selected. Pick the global stack. Shouldn't happen any more since we removed the global tab.
|
||||
return activeMachineId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ from UM.Qt.ListModel import ListModel
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.Application import Application
|
||||
from UM.Version import Version
|
||||
from UM.Message import Message
|
||||
|
||||
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
|
||||
from PyQt5.QtCore import QUrl, QObject, Qt, pyqtProperty, pyqtSignal, pyqtSlot
|
||||
@ -15,6 +16,8 @@ from PyQt5.QtQml import QQmlComponent, QQmlContext
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import platform
|
||||
import zipfile
|
||||
|
||||
i18n_catalog = i18nCatalog("cura")
|
||||
|
||||
@ -43,12 +46,43 @@ class PluginBrowser(QObject, Extension):
|
||||
|
||||
self._is_downloading = False
|
||||
|
||||
self._request_header = [b"User-Agent", str.encode("%s - %s" % (Application.getInstance().getApplicationName(), Application.getInstance().getVersion()))]
|
||||
self._request_header = [b"User-Agent",
|
||||
str.encode("%s/%s (%s %s)" % (Application.getInstance().getApplicationName(),
|
||||
Application.getInstance().getVersion(),
|
||||
platform.system(),
|
||||
platform.machine(),
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
# Installed plugins are really installed after reboot. In order to prevent the user from downloading the
|
||||
# same file over and over again, we keep track of the upgraded plugins.
|
||||
self._newly_installed_plugin_ids = []
|
||||
|
||||
# variables for the license agreement dialog
|
||||
self._license_dialog_plugin_name = ""
|
||||
self._license_dialog_license_content = ""
|
||||
self._license_dialog_plugin_file_location = ""
|
||||
|
||||
showLicenseDialog = pyqtSignal()
|
||||
|
||||
@pyqtSlot(result = str)
|
||||
def getLicenseDialogPluginName(self):
|
||||
return self._license_dialog_plugin_name
|
||||
|
||||
@pyqtSlot(result = str)
|
||||
def getLicenseDialogPluginFileLocation(self):
|
||||
return self._license_dialog_plugin_file_location
|
||||
|
||||
@pyqtSlot(result = str)
|
||||
def getLicenseDialogLicenseContent(self):
|
||||
return self._license_dialog_license_content
|
||||
|
||||
def openLicenseDialog(self, plugin_name, license_content, plugin_file_location):
|
||||
self._license_dialog_plugin_name = plugin_name
|
||||
self._license_dialog_license_content = license_content
|
||||
self._license_dialog_plugin_file_location = plugin_file_location
|
||||
self.showLicenseDialog.emit()
|
||||
|
||||
pluginsMetadataChanged = pyqtSignal()
|
||||
onDownloadProgressChanged = pyqtSignal()
|
||||
@ -63,7 +97,7 @@ class PluginBrowser(QObject, Extension):
|
||||
self.requestPluginList()
|
||||
|
||||
if not self._dialog:
|
||||
self._createDialog()
|
||||
self._dialog = self._createDialog("PluginBrowser.qml")
|
||||
self._dialog.show()
|
||||
|
||||
@pyqtSlot()
|
||||
@ -74,19 +108,20 @@ class PluginBrowser(QObject, Extension):
|
||||
self._plugin_list_request.setRawHeader(*self._request_header)
|
||||
self._network_manager.get(self._plugin_list_request)
|
||||
|
||||
def _createDialog(self):
|
||||
Logger.log("d", "PluginBrowser")
|
||||
def _createDialog(self, qml_name):
|
||||
Logger.log("d", "Creating dialog [%s]", qml_name)
|
||||
|
||||
path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "PluginBrowser.qml"))
|
||||
path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), qml_name))
|
||||
self._qml_component = QQmlComponent(Application.getInstance()._engine, path)
|
||||
|
||||
# We need access to engine (although technically we can't)
|
||||
self._qml_context = QQmlContext(Application.getInstance()._engine.rootContext())
|
||||
self._qml_context.setContextProperty("manager", self)
|
||||
self._dialog = self._qml_component.create(self._qml_context)
|
||||
if self._dialog is None:
|
||||
dialog = self._qml_component.create(self._qml_context)
|
||||
if dialog is None:
|
||||
Logger.log("e", "QQmlComponent status %s", self._qml_component.status())
|
||||
Logger.log("e", "QQmlComponent errorString %s", self._qml_component.errorString())
|
||||
return dialog
|
||||
|
||||
def setIsDownloading(self, is_downloading):
|
||||
if self._is_downloading != is_downloading:
|
||||
@ -109,17 +144,61 @@ class PluginBrowser(QObject, Extension):
|
||||
self._temp_plugin_file.write(self._download_plugin_reply.readAll())
|
||||
self._temp_plugin_file.close()
|
||||
|
||||
# open as read
|
||||
if not location.startswith("/"):
|
||||
location = "/" + location # Ensure that it starts with a /, as otherwise it doesn't work on windows.
|
||||
result = PluginRegistry.getInstance().installPlugin("file://" + location)
|
||||
self._checkPluginLicenseOrInstall(location)
|
||||
return
|
||||
|
||||
self._newly_installed_plugin_ids.append(result["id"])
|
||||
self.pluginsMetadataChanged.emit()
|
||||
## Checks if the downloaded plugin ZIP file contains a license file or not.
|
||||
# If it does, it will show a popup dialog displaying the license to the user. The plugin will be installed if the
|
||||
# user accepts the license.
|
||||
# If there is no license file, the plugin will be directory installed.
|
||||
def _checkPluginLicenseOrInstall(self, file_path):
|
||||
with zipfile.ZipFile(file_path, "r") as zip_ref:
|
||||
plugin_id = None
|
||||
for file in zip_ref.infolist():
|
||||
if file.filename.endswith("/"):
|
||||
plugin_id = file.filename.strip("/")
|
||||
break
|
||||
|
||||
Application.getInstance().messageBox(i18n_catalog.i18nc("@window:title", "Plugin browser"), result["message"])
|
||||
if plugin_id is None:
|
||||
msg = i18n_catalog.i18nc("@info:status", "Failed to get plugin ID from <filename>{0}</filename>", file_path)
|
||||
self._progress_message = Message(msg, lifetime=0, dismissable=False)
|
||||
return
|
||||
|
||||
self._temp_plugin_file.close() # Plugin was installed, delete temp file
|
||||
# find a potential license file
|
||||
plugin_root_dir = plugin_id + "/"
|
||||
license_file = None
|
||||
for f in zip_ref.infolist():
|
||||
# skip directories (with file_size = 0) and files not in the plugin directory
|
||||
if f.file_size == 0 or not f.filename.startswith(plugin_root_dir):
|
||||
continue
|
||||
file_name = os.path.basename(f.filename).lower()
|
||||
file_base_name, file_ext = os.path.splitext(file_name)
|
||||
if file_base_name in ["license", "licence"]:
|
||||
license_file = f.filename
|
||||
break
|
||||
|
||||
# show a dialog for user to read and accept/decline the license
|
||||
if license_file is not None:
|
||||
Logger.log("i", "Found license file for plugin [%s], showing the license dialog to the user", plugin_id)
|
||||
license_content = zip_ref.read(license_file).decode('utf-8')
|
||||
self.openLicenseDialog(plugin_id, license_content, file_path)
|
||||
return
|
||||
|
||||
# there is no license file, directly install the plugin
|
||||
self.installPlugin(file_path)
|
||||
|
||||
@pyqtSlot(str)
|
||||
def installPlugin(self, file_path):
|
||||
if not file_path.startswith("/"):
|
||||
location = "/" + file_path # Ensure that it starts with a /, as otherwise it doesn't work on windows.
|
||||
else:
|
||||
location = file_path
|
||||
result = PluginRegistry.getInstance().installPlugin("file://" + location)
|
||||
|
||||
self._newly_installed_plugin_ids.append(result["id"])
|
||||
self.pluginsMetadataChanged.emit()
|
||||
|
||||
Application.getInstance().messageBox(i18n_catalog.i18nc("@window:title", "Plugin browser"), result["message"])
|
||||
|
||||
@pyqtProperty(int, notify = onDownloadProgressChanged)
|
||||
def downloadProgress(self):
|
||||
@ -246,4 +325,4 @@ class PluginBrowser(QObject, Extension):
|
||||
|
||||
self._network_manager = QNetworkAccessManager()
|
||||
self._network_manager.finished.connect(self._onRequestFinished)
|
||||
self._network_manager.networkAccessibleChanged.connect(self._onNetworkAccesibleChanged)
|
||||
self._network_manager.networkAccessibleChanged.connect(self._onNetworkAccesibleChanged)
|
||||
|
@ -11,6 +11,8 @@ UM.Dialog
|
||||
title: catalog.i18nc("@title:window", "Find & Update plugins")
|
||||
width: 600
|
||||
height: 450
|
||||
minimumWidth: 350
|
||||
minimumHeight: 350
|
||||
Item
|
||||
{
|
||||
anchors.fill: parent
|
||||
@ -58,7 +60,7 @@ UM.Dialog
|
||||
id: bottomBar
|
||||
width: parent.width
|
||||
height: closeButton.height
|
||||
anchors.bottom:parent.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
ProgressBar
|
||||
{
|
||||
@ -177,6 +179,84 @@ UM.Dialog
|
||||
|
||||
}
|
||||
}
|
||||
UM.I18nCatalog { id: catalog; name:"cura" }
|
||||
UM.I18nCatalog { id: catalog; name: "cura" }
|
||||
|
||||
Connections
|
||||
{
|
||||
target: manager
|
||||
onShowLicenseDialog:
|
||||
{
|
||||
licenseDialog.pluginName = manager.getLicenseDialogPluginName();
|
||||
licenseDialog.licenseContent = manager.getLicenseDialogLicenseContent();
|
||||
licenseDialog.pluginFileLocation = manager.getLicenseDialogPluginFileLocation();
|
||||
licenseDialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
UM.Dialog
|
||||
{
|
||||
id: licenseDialog
|
||||
title: catalog.i18nc("@title:window", "Plugin License Agreement")
|
||||
|
||||
minimumWidth: UM.Theme.getSize("license_window_minimum").width
|
||||
minimumHeight: UM.Theme.getSize("license_window_minimum").height
|
||||
width: minimumWidth
|
||||
height: minimumHeight
|
||||
|
||||
property var pluginName;
|
||||
property var licenseContent;
|
||||
property var pluginFileLocation;
|
||||
|
||||
Item
|
||||
{
|
||||
anchors.fill: parent
|
||||
|
||||
Label
|
||||
{
|
||||
id: licenseTitle
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
text: licenseDialog.pluginName + catalog.i18nc("@label", " plugin contains a license.\nYou need to accept this license to install this plugin.\nDo you agree with the terms below?")
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
TextArea
|
||||
{
|
||||
id: licenseText
|
||||
anchors.top: licenseTitle.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
readOnly: true
|
||||
text: licenseDialog.licenseContent != null ? licenseDialog.licenseContent : ""
|
||||
}
|
||||
}
|
||||
|
||||
rightButtons: [
|
||||
Button
|
||||
{
|
||||
id: acceptButton
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
text: catalog.i18nc("@action:button", "Accept")
|
||||
onClicked:
|
||||
{
|
||||
licenseDialog.close();
|
||||
manager.installPlugin(licenseDialog.pluginFileLocation);
|
||||
}
|
||||
},
|
||||
Button
|
||||
{
|
||||
id: declineButton
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
text: catalog.i18nc("@action:button", "Decline")
|
||||
onClicked:
|
||||
{
|
||||
licenseDialog.close();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,8 +123,17 @@ class RemovableDriveOutputDevice(OutputDevice):
|
||||
def _onFinished(self, job):
|
||||
if self._stream:
|
||||
# Explicitly closing the stream flushes the write-buffer
|
||||
self._stream.close()
|
||||
self._stream = None
|
||||
try:
|
||||
self._stream.close()
|
||||
self._stream = None
|
||||
except:
|
||||
Logger.logException("w", "An execption occured while trying to write to removable drive.")
|
||||
message = Message(catalog.i18nc("@info:status", "Could not save to removable drive {0}: {1}").format(self.getName(),
|
||||
str(
|
||||
job.getError())))
|
||||
message.show()
|
||||
self.writeError.emit(self)
|
||||
return
|
||||
|
||||
self._writing = False
|
||||
self.writeFinished.emit(self)
|
||||
|
@ -12,6 +12,7 @@ import UM.Settings.ContainerRegistry
|
||||
import UM.Version #To compare firmware version numbers.
|
||||
|
||||
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
|
||||
from cura.Settings.ContainerManager import ContainerManager
|
||||
import cura.Settings.ExtruderManager
|
||||
|
||||
from PyQt5.QtNetwork import QHttpMultiPart, QHttpPart, QNetworkRequest, QNetworkAccessManager, QNetworkReply
|
||||
@ -312,6 +313,18 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
self.targetBedTemperatureChanged.emit()
|
||||
return True
|
||||
|
||||
## Updates the target hotend temperature from the printer, and emit a signal if it was changed.
|
||||
#
|
||||
# /param index The index of the hotend.
|
||||
# /param temperature The new target temperature of the hotend.
|
||||
# /return boolean, True if the temperature was changed, false if the new temperature has the same value as the already stored temperature
|
||||
def _updateTargetHotendTemperature(self, index, temperature):
|
||||
if self._target_hotend_temperatures[index] == temperature:
|
||||
return False
|
||||
self._target_hotend_temperatures[index] = temperature
|
||||
self.targetHotendTemperaturesChanged.emit()
|
||||
return True
|
||||
|
||||
def _stopCamera(self):
|
||||
if self._camera_timer.isActive():
|
||||
self._camera_timer.stop()
|
||||
@ -534,8 +547,9 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
def _spliceJSONData(self):
|
||||
# Check for hotend temperatures
|
||||
for index in range(0, self._num_extruders):
|
||||
temperature = self._json_printer_state["heads"][0]["extruders"][index]["hotend"]["temperature"]["current"]
|
||||
self._setHotendTemperature(index, temperature)
|
||||
temperatures = self._json_printer_state["heads"][0]["extruders"][index]["hotend"]["temperature"]
|
||||
self._setHotendTemperature(index, temperatures["current"])
|
||||
self._updateTargetHotendTemperature(index, temperatures["target"])
|
||||
try:
|
||||
material_id = self._json_printer_state["heads"][0]["extruders"][index]["active_material"]["guid"]
|
||||
except KeyError:
|
||||
@ -547,10 +561,9 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
hotend_id = ""
|
||||
self._setHotendId(index, hotend_id)
|
||||
|
||||
bed_temperature = self._json_printer_state["bed"]["temperature"]["current"]
|
||||
self._setBedTemperature(bed_temperature)
|
||||
target_bed_temperature = self._json_printer_state["bed"]["temperature"]["target"]
|
||||
self._updateTargetBedTemperature(target_bed_temperature)
|
||||
bed_temperatures = self._json_printer_state["bed"]["temperature"]
|
||||
self._setBedTemperature(bed_temperatures["current"])
|
||||
self._updateTargetBedTemperature(bed_temperatures["target"])
|
||||
|
||||
head_x = self._json_printer_state["heads"][0]["position"]["x"]
|
||||
head_y = self._json_printer_state["heads"][0]["position"]["y"]
|
||||
@ -743,6 +756,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
|
||||
self._createNetworkManager()
|
||||
|
||||
self._last_response_time = time() # Ensure we reset the time when trying to connect (again)
|
||||
|
||||
self.setConnectionState(ConnectionState.connecting)
|
||||
self._update() # Manually trigger the first update, as we don't want to wait a few secs before it starts.
|
||||
if not self._use_stream:
|
||||
@ -915,6 +930,13 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
xml_data = container.serialize()
|
||||
if xml_data == "" or xml_data is None:
|
||||
continue
|
||||
|
||||
names = ContainerManager.getInstance().getLinkedMaterials(container.getId())
|
||||
if names:
|
||||
# There are other materials that share this GUID.
|
||||
if not container.isReadOnly():
|
||||
continue # If it's not readonly, it's created by user, so skip it.
|
||||
|
||||
material_multi_part = QHttpMultiPart(QHttpMultiPart.FormDataType)
|
||||
|
||||
material_part = QHttpPart()
|
||||
|
@ -230,12 +230,14 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
|
||||
|
||||
## If one of the states of the connected devices change, we might need to add / remove them from the global list.
|
||||
def _onConnectionStateChanged(self, serial_port):
|
||||
success = True
|
||||
try:
|
||||
if self._usb_output_devices[serial_port].connectionState == ConnectionState.connected:
|
||||
self.getOutputDeviceManager().addOutputDevice(self._usb_output_devices[serial_port])
|
||||
else:
|
||||
self.getOutputDeviceManager().removeOutputDevice(serial_port)
|
||||
self.connectionStateChanged.emit()
|
||||
success = success and self.getOutputDeviceManager().removeOutputDevice(serial_port)
|
||||
if success:
|
||||
self.connectionStateChanged.emit()
|
||||
except KeyError:
|
||||
Logger.log("w", "Connection state of %s changed, but it was not found in the list")
|
||||
|
||||
|
@ -0,0 +1,56 @@
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import configparser #To parse preference files.
|
||||
import io #To serialise the preference files afterwards.
|
||||
|
||||
from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this.
|
||||
|
||||
_renamed_themes = {
|
||||
"cura": "cura-light"
|
||||
}
|
||||
|
||||
class VersionUpgrade27to30(VersionUpgrade):
|
||||
## Gets the version number from a CFG file in Uranium's 2.7 format.
|
||||
#
|
||||
# Since the format may change, this is implemented for the 2.7 format only
|
||||
# and needs to be included in the version upgrade system rather than
|
||||
# globally in Uranium.
|
||||
#
|
||||
# \param serialised The serialised form of a CFG file.
|
||||
# \return The version number stored in the CFG file.
|
||||
# \raises ValueError The format of the version number in the file is
|
||||
# incorrect.
|
||||
# \raises KeyError The format of the file is incorrect.
|
||||
def getCfgVersion(self, serialised):
|
||||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(serialised)
|
||||
format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
|
||||
setting_version = int(parser.get("metadata", "setting_version", fallback = 0))
|
||||
return format_version * 1000000 + setting_version
|
||||
|
||||
## Upgrades a preferences file from version 2.7 to 3.0.
|
||||
#
|
||||
# \param serialised The serialised form of a preferences file.
|
||||
# \param filename The name of the file to upgrade.
|
||||
def upgradePreferences(self, serialised, filename):
|
||||
parser = configparser.ConfigParser(interpolation=None)
|
||||
parser.read_string(serialised)
|
||||
|
||||
# Update version numbers
|
||||
if "general" not in parser:
|
||||
parser["general"] = {}
|
||||
parser["general"]["version"] = "5"
|
||||
if "metadata" not in parser:
|
||||
parser["metadata"] = {}
|
||||
parser["metadata"]["setting_version"] = "2"
|
||||
|
||||
#Renamed themes.
|
||||
if "theme" in parser["general"]:
|
||||
if parser["general"]["theme"] in _renamed_themes:
|
||||
parser["general"]["theme"] = _renamed_themes[parser["general"]["theme"]]
|
||||
|
||||
# Re-serialise the file.
|
||||
output = io.StringIO()
|
||||
parser.write(output)
|
||||
return [filename], [output.getvalue()]
|
23
plugins/VersionUpgrade/VersionUpgrade27to30/__init__.py
Normal file
23
plugins/VersionUpgrade/VersionUpgrade27to30/__init__.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from . import VersionUpgrade27to30
|
||||
|
||||
upgrade = VersionUpgrade27to30.VersionUpgrade27to30()
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
"version_upgrade": {
|
||||
# From To Upgrade function
|
||||
("preferences", 4000002): ("preferences", 5000002, upgrade.upgradePreferences),
|
||||
},
|
||||
"sources": {
|
||||
"preferences": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"."}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
def register(app):
|
||||
return { "version_upgrade": upgrade }
|
8
plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json
Normal file
8
plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "Version Upgrade 2.7 to 3.0",
|
||||
"author": "Ultimaker B.V.",
|
||||
"version": "1.0.0",
|
||||
"description": "Upgrades configurations from Cura 2.7 to Cura 3.0.",
|
||||
"api": 4,
|
||||
"i18n-catalog": "cura"
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import configparser #To parse the resulting config files.
|
||||
import pytest #To register tests with.
|
||||
|
||||
import VersionUpgrade27to30 #The module we're testing.
|
||||
|
||||
## Creates an instance of the upgrader to test with.
|
||||
@pytest.fixture
|
||||
def upgrader():
|
||||
return VersionUpgrade27to30.VersionUpgrade27to30()
|
||||
|
||||
test_cfg_version_good_data = [
|
||||
{
|
||||
"test_name": "Simple",
|
||||
"file_data": """[general]
|
||||
version = 1
|
||||
""",
|
||||
"version": 1000000
|
||||
},
|
||||
{
|
||||
"test_name": "Other Data Around",
|
||||
"file_data": """[nonsense]
|
||||
life = good
|
||||
|
||||
[general]
|
||||
version = 3
|
||||
|
||||
[values]
|
||||
layer_height = 0.12
|
||||
infill_sparse_density = 42
|
||||
""",
|
||||
"version": 3000000
|
||||
},
|
||||
{
|
||||
"test_name": "Negative Version", #Why not?
|
||||
"file_data": """[general]
|
||||
version = -20
|
||||
""",
|
||||
"version": -20000000
|
||||
},
|
||||
{
|
||||
"test_name": "Setting Version",
|
||||
"file_data": """[general]
|
||||
version = 1
|
||||
[metadata]
|
||||
setting_version = 1
|
||||
""",
|
||||
"version": 1000001
|
||||
},
|
||||
{
|
||||
"test_name": "Negative Setting Version",
|
||||
"file_data": """[general]
|
||||
version = 1
|
||||
[metadata]
|
||||
setting_version = -3
|
||||
""",
|
||||
"version": 999997
|
||||
}
|
||||
]
|
||||
|
||||
## Tests the technique that gets the version number from CFG files.
|
||||
#
|
||||
# \param data The parametrised data to test with. It contains a test name
|
||||
# to debug with, the serialised contents of a CFG file and the correct
|
||||
# version number in that CFG file.
|
||||
# \param upgrader The instance of the upgrade class to test.
|
||||
@pytest.mark.parametrize("data", test_cfg_version_good_data)
|
||||
def test_cfgVersionGood(data, upgrader):
|
||||
version = upgrader.getCfgVersion(data["file_data"])
|
||||
assert version == data["version"]
|
||||
|
||||
test_cfg_version_bad_data = [
|
||||
{
|
||||
"test_name": "Empty",
|
||||
"file_data": "",
|
||||
"exception": configparser.Error #Explicitly not specified further which specific error we're getting, because that depends on the implementation of configparser.
|
||||
},
|
||||
{
|
||||
"test_name": "No General",
|
||||
"file_data": """[values]
|
||||
layer_height = 0.1337
|
||||
""",
|
||||
"exception": configparser.Error
|
||||
},
|
||||
{
|
||||
"test_name": "No Version",
|
||||
"file_data": """[general]
|
||||
true = false
|
||||
""",
|
||||
"exception": configparser.Error
|
||||
},
|
||||
{
|
||||
"test_name": "Not a Number",
|
||||
"file_data": """[general]
|
||||
version = not-a-text-version-number
|
||||
""",
|
||||
"exception": ValueError
|
||||
},
|
||||
{
|
||||
"test_name": "Setting Value NaN",
|
||||
"file_data": """[general]
|
||||
version = 4
|
||||
[metadata]
|
||||
setting_version = latest_or_something
|
||||
""",
|
||||
"exception": ValueError
|
||||
},
|
||||
{
|
||||
"test_name": "Major-Minor",
|
||||
"file_data": """[general]
|
||||
version = 1.2
|
||||
""",
|
||||
"exception": ValueError
|
||||
}
|
||||
]
|
||||
|
||||
## Tests whether getting a version number from bad CFG files gives an
|
||||
# exception.
|
||||
#
|
||||
# \param data The parametrised data to test with. It contains a test name
|
||||
# to debug with, the serialised contents of a CFG file and the class of
|
||||
# exception it needs to throw.
|
||||
# \param upgrader The instance of the upgrader to test.
|
||||
@pytest.mark.parametrize("data", test_cfg_version_bad_data)
|
||||
def test_cfgVersionBad(data, upgrader):
|
||||
with pytest.raises(data["exception"]):
|
||||
upgrader.getCfgVersion(data["file_data"])
|
||||
|
||||
test_translate_theme_data = [
|
||||
(
|
||||
"Original Cura theme",
|
||||
"""[general]
|
||||
version = 4
|
||||
theme = cura
|
||||
[metadata]
|
||||
setting_version = 2
|
||||
""",
|
||||
"cura-light"
|
||||
),
|
||||
(
|
||||
"No theme",
|
||||
"""[general]
|
||||
version = 4
|
||||
[metadata]
|
||||
setting_version = 2
|
||||
""",
|
||||
None #Indicates that the theme should be absent in the new file.
|
||||
)
|
||||
]
|
||||
|
||||
## Tests whether the theme is properly translated.
|
||||
@pytest.mark.parametrize("test_name, file_data, new_theme", test_translate_theme_data)
|
||||
def test_translateTheme(test_name, file_data, new_theme, upgrader):
|
||||
#Read old file.
|
||||
original_parser = configparser.ConfigParser(interpolation = None)
|
||||
original_parser.read_string(file_data)
|
||||
|
||||
#Perform the upgrade.
|
||||
_, upgraded_stacks = upgrader.upgradePreferences(file_data, "<string>")
|
||||
upgraded_stack = upgraded_stacks[0]
|
||||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(upgraded_stack)
|
||||
|
||||
#Check whether the theme was properly translated.
|
||||
if not new_theme:
|
||||
assert "theme" not in parser["general"]
|
||||
else:
|
||||
assert "theme" in parser["general"]
|
||||
assert parser["general"]["theme"] == new_theme
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "rikky",
|
||||
"manufacturer": "101Hero",
|
||||
"category": "Other",
|
||||
"machine_extruder_trains":
|
||||
{
|
||||
"0": "fdmextruder"
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "3Dator GmbH",
|
||||
"manufacturer": "3Dator GmbH",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2",
|
||||
"supports_usb_connection": true,
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "ABAX 3d Technologies",
|
||||
"manufacturer": "ABAX 3d Technologies",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "ABAX 3d Technologies",
|
||||
"manufacturer": "ABAX 3d Technologies",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "ABAX 3d Technologies",
|
||||
"manufacturer": "ABAX 3d Technologies",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "ALYA",
|
||||
"manufacturer": "ALYA",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "BFB",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "BQ",
|
||||
"manufacturer": "BQ",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "bq_hephestos_platform.stl",
|
||||
"platform_offset": [ 0, -82, 0]
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "BQ",
|
||||
"manufacturer": "BQ",
|
||||
"category": "Other",
|
||||
"platform": "bq_hephestos_2_platform.stl",
|
||||
"platform_offset": [6, 1320, 0 ],
|
||||
"file_formats": "text/x-gcode"
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"manufacturer": "BQ",
|
||||
"author": "BQ",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-code",
|
||||
"platform": "bq_hephestos_platform.stl",
|
||||
"platform_offset": [ 0, -82, 0]
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "BQ",
|
||||
"manufacturer": "BQ",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "bq_witbox_platform.stl",
|
||||
"platform_offset": [ 0, -145, -38]
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "BQ",
|
||||
"manufacturer": "BQ",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "bq_witbox_platform.stl",
|
||||
"platform_offset": [0, -145, -38]
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Scheepers",
|
||||
"manufacturer": "Cartesio bv",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
|
||||
"has_machine_quality": true,
|
||||
|
@ -1,13 +1,12 @@
|
||||
{
|
||||
"id": "creality-cr10",
|
||||
"name": "Creality CR-10",
|
||||
"id": "creality-cr10_beta",
|
||||
"name": "Creality CR-10 Beta",
|
||||
"version": 2,
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "Michael Wildermuth",
|
||||
"manufacturer": "Creality3D",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
@ -20,6 +19,48 @@
|
||||
"machine_depth": {
|
||||
"default_value": 300
|
||||
},
|
||||
"material_diameter": {
|
||||
"default_value": 1.75
|
||||
},
|
||||
"machine_nozzle_size": {
|
||||
"default_value": 0.4
|
||||
},
|
||||
"layer_height": {
|
||||
"default_value": 0.2
|
||||
},
|
||||
"layer_height_0": {
|
||||
"default_value": 0.2
|
||||
},
|
||||
"top_bottom_thickness": {
|
||||
"default_value": 0.6
|
||||
},
|
||||
"top_bottom_pattern": {
|
||||
"default_value": "concentric"
|
||||
},
|
||||
"infill_pattern": {
|
||||
"value": "'triangles'"
|
||||
},
|
||||
"retraction_enable": {
|
||||
"default_value": true
|
||||
},
|
||||
"retraction_amount": {
|
||||
"default_value": 5
|
||||
},
|
||||
"retraction_speed": {
|
||||
"default_value": 40
|
||||
},
|
||||
"cool_min_layer_time": {
|
||||
"default_value": 15
|
||||
},
|
||||
"adhesion_type": {
|
||||
"default_value": "skirt"
|
||||
},
|
||||
"skirt_line_count": {
|
||||
"default_value": 4
|
||||
},
|
||||
"skirt_gap": {
|
||||
"default_value": 5
|
||||
},
|
||||
"machine_start_gcode": {
|
||||
"default_value": "G21 ;metric values\nG90 ;absolute Positioning\nG28 ; home all axes\nG1 Z5 F3000 ; lift\nG1 X20 Y2 F1500 ; avoid binder clips\nG1 Z0.2 F3000 ; get ready to prime\nG92 E0 ; reset extrusion distance\nG1 X120 E10 F600 ; prime nozzle\nG1 X150 F5000 ; quick wipe"
|
||||
},
|
||||
@ -38,11 +79,17 @@
|
||||
"acceleration_print": {
|
||||
"default_value": 500
|
||||
},
|
||||
"acceleration_travel": {
|
||||
"default_value": 500
|
||||
},
|
||||
"jerk_enabled": {
|
||||
"default_value": true
|
||||
},
|
||||
"jerk_print": {
|
||||
"default_value": 20
|
||||
},
|
||||
"jerk_travel": {
|
||||
"default_value": 20
|
||||
}
|
||||
}
|
||||
}
|
23
resources/definitions/creality_cr10s4_beta.def.json
Normal file
23
resources/definitions/creality_cr10s4_beta.def.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"id": "creality-cr10s4_beta",
|
||||
"name": "Creality CR-10 S4 Beta",
|
||||
"version": 2,
|
||||
"inherits": "creality_cr10_beta",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "Michael Wildermuth",
|
||||
"manufacturer": "Creality3D",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
"machine_width": {
|
||||
"default_value": 400
|
||||
},
|
||||
"machine_height": {
|
||||
"default_value": 400
|
||||
},
|
||||
"machine_depth": {
|
||||
"default_value": 400
|
||||
}
|
||||
}
|
||||
}
|
23
resources/definitions/creality_cr10s5_beta.def.json
Normal file
23
resources/definitions/creality_cr10s5_beta.def.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"id": "creality-cr10s5_beta",
|
||||
"name": "Creality CR-10 S5 Beta",
|
||||
"version": 2,
|
||||
"inherits": "creality_cr10_beta",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "Michael Wildermuth",
|
||||
"manufacturer": "Creality3D",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
"machine_width": {
|
||||
"default_value": 500
|
||||
},
|
||||
"machine_height": {
|
||||
"default_value": 500
|
||||
},
|
||||
"machine_depth": {
|
||||
"default_value": 500
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Dagoma",
|
||||
"manufacturer": "Dagoma",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
"platform": "discoeasy200.stl",
|
||||
|
@ -4,39 +4,38 @@
|
||||
"version": 2,
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "Deltaprintr",
|
||||
"manufacturer": "Deltaprintr",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0],
|
||||
"platform": ""
|
||||
},
|
||||
"visible": true,
|
||||
"author": "Deltaprintr",
|
||||
"manufacturer": "Deltaprintr",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [0, 0, 0],
|
||||
"platform": ""
|
||||
},
|
||||
"overrides": {
|
||||
"machine_name": { "default_value": "Delta Go" },
|
||||
"material_diameter": { "default_value": 1.75 },
|
||||
"default_material_print_temperature": { "default_value": 210 },
|
||||
"speed_travel": { "default_value": 150 },
|
||||
"prime_tower_size": { "default_value": 8.66 },
|
||||
"infill_sparse_density": { "default_value": 10 },
|
||||
"speed_wall_x": { "default_value": 30 },
|
||||
"speed_wall_0": { "default_value": 30 },
|
||||
"speed_topbottom": { "default_value": 20 },
|
||||
"layer_height": { "default_value": 0.15 },
|
||||
"speed_print": { "default_value": 30 },
|
||||
"machine_heated_bed": { "default_value": false },
|
||||
"machine_center_is_zero": { "default_value": true },
|
||||
"machine_height": { "default_value": 154 },
|
||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||
"machine_depth": { "default_value": 115 },
|
||||
"machine_width": { "default_value": 115 },
|
||||
"raft_airgap": { "default_value": 0.15 },
|
||||
"retraction_hop_enabled": { "value": "True" },
|
||||
"retraction_amount": { "default_value": 4.1 },
|
||||
"retraction_speed": { "default_value": 500 },
|
||||
"retraction_hop": { "value": "0.2" },
|
||||
"retraction_hop_only_when_collides": { "value": "True" },
|
||||
"brim_width": { "value": "5" },
|
||||
"machine_shape": { "default_value": "elliptic"}
|
||||
}
|
||||
"machine_name": { "default_value": "Delta Go" },
|
||||
"material_diameter": { "default_value": 1.75 },
|
||||
"default_material_print_temperature": { "default_value": 210 },
|
||||
"speed_travel": { "default_value": 150 },
|
||||
"prime_tower_size": { "default_value": 8.66 },
|
||||
"infill_sparse_density": { "default_value": 10 },
|
||||
"speed_wall_x": { "default_value": 30 },
|
||||
"speed_wall_0": { "default_value": 30 },
|
||||
"speed_topbottom": { "default_value": 20 },
|
||||
"layer_height": { "default_value": 0.15 },
|
||||
"speed_print": { "default_value": 30 },
|
||||
"machine_heated_bed": { "default_value": false },
|
||||
"machine_center_is_zero": { "default_value": true },
|
||||
"machine_height": { "default_value": 154 },
|
||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||
"machine_depth": { "default_value": 115 },
|
||||
"machine_width": { "default_value": 115 },
|
||||
"raft_airgap": { "default_value": 0.15 },
|
||||
"retraction_hop_enabled": { "value": "True" },
|
||||
"retraction_amount": { "default_value": 4.1 },
|
||||
"retraction_speed": { "default_value": 500 },
|
||||
"retraction_hop": { "value": "0.2" },
|
||||
"retraction_hop_only_when_collides": { "value": "True" },
|
||||
"brim_width": { "value": "5" },
|
||||
"machine_shape": { "default_value": "elliptic"}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Danny Lu",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "nliaudat",
|
||||
"manufacturer": "EasyArts (discontinued)",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode"
|
||||
},
|
||||
"overrides": {
|
||||
|
71
resources/definitions/fabtotum.def.json
Normal file
71
resources/definitions/fabtotum.def.json
Normal file
@ -0,0 +1,71 @@
|
||||
{
|
||||
"id": "fabtotum",
|
||||
"version": 2,
|
||||
"name": "FABtotum Personal Fabricator",
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "FABtotum",
|
||||
"manufacturer": "FABtotum",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "fabtotum_platform.stl",
|
||||
"icon": "fabtotum_platform.png",
|
||||
"has_machine_quality": true,
|
||||
"has_variants": true,
|
||||
"variants_name": "Head",
|
||||
"preferred_variant": "*lite04*",
|
||||
"preferred_material": "*fabtotum_pla*",
|
||||
"supports_usb_connection": false
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_name": { "default_value": "FABtotum Personal Fabricator" },
|
||||
"machine_start_gcode": {
|
||||
"default_value": ";Layer height: {layer_height}\n;Walls: {wall_thickness}\n;Fill: {infill_sparse_density}\n;Top\\Bottom Thickness: {top_bottom_thickness}\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nG4 S1 ;1 millisecond pause to buffer the bep bep \nM728 ;FAB bep bep (start the print, go check the oozing and skirt lines adesion) \nG4 S1 ;1 second pause to reach the printer (run fast)\nG92 E0 ;zero the extruded length \nG1 F200 E35 ;slowly extrude 35mm of filament to clean the nozzle and build up extrusion pressure \nG92 E0 ;zero the extruded length again \nG1 F{speed_travel} ;Set travel speed \n;print"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-3 X+5 Y+5 F5000 ;move Z up a bit and retract filament even more\n;end of the print\nM84 ;steppers off\nG90 ;absolute positioning\nM728 ;FAB bep bep (end print)"
|
||||
},
|
||||
"gantry_height": { "default_value": 55 },
|
||||
"machine_width": { "default_value": 214 },
|
||||
"machine_height": { "default_value": 241.5 },
|
||||
"machine_depth": { "default_value": 234 },
|
||||
"machine_center_is_zero": { "default_value": false },
|
||||
"machine_heated_bed": { "default_value": true },
|
||||
"machine_nozzle_size": { "default_value": 0.4 },
|
||||
"machine_head_with_fans_polygon": { "default_value": [[-75, 35], [-75, -18], [18, 35], [18, -18]] },
|
||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||
"machine_max_feedrate_x": { "default_value": 250 },
|
||||
"machine_max_feedrate_y": { "default_value": 250 },
|
||||
"machine_max_feedrate_z": { "default_value": 15 },
|
||||
"machine_max_acceleration_x": { "default_value": 10000 },
|
||||
"machine_max_acceleration_y": { "default_value": 10000 },
|
||||
"machine_max_acceleration_z": { "default_value": 50 },
|
||||
"machine_max_acceleration_e": { "default_value": 100 },
|
||||
"machine_acceleration": { "default_value": 4000 },
|
||||
"machine_max_jerk_xy": { "default_value": 25.0 },
|
||||
"machine_max_jerk_z": { "default_value": 0.4 },
|
||||
"machine_max_jerk_e": { "default_value": 1.0 },
|
||||
"retraction_hop_enabled": { "default_value": false },
|
||||
"material_diameter": { "default_value": 1.75 },
|
||||
"material_final_print_temperature": { "value": "material_print_temperature - 5" },
|
||||
"material_initial_print_temperature": { "value": "material_print_temperature" },
|
||||
"travel_avoid_distance": { "default_value": 1, "value": 1 },
|
||||
"speed_travel": { "default_value": 200, "value": 200 },
|
||||
"speed_infill": { "value": "round(speed_print * 1.05, 0)" },
|
||||
"speed_topbottom": { "value": "round(speed_print * 0.95, 0)" },
|
||||
"speed_wall": { "value": "speed_print" },
|
||||
"speed_wall_0": { "value": "round(speed_print * 0.9, 0)" },
|
||||
"speed_wall_x": { "value": "speed_wall" },
|
||||
"speed_layer_0": { "value": "min(round(speed_print * 0.75, 0), 45.0)" },
|
||||
"speed_travel_layer_0": { "value": "round(speed_travel * 0.7, 0)" },
|
||||
"skirt_brim_speed": { "value": "speed_layer_0" },
|
||||
"skirt_line_count": { "default_value": 3 },
|
||||
"skirt_brim_minimal_length": { "default_value": 150 },
|
||||
"infill_sparse_density": { "default_value": 24 },
|
||||
"top_bottom_thickness": { "default_value": 0.6 },
|
||||
"support_z_distance": { "default_value": 0.2, "value": "min(2 * layer_height, machine_nozzle_size * 0.75)" },
|
||||
"support_interface_enable": { "default_value": true }
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
{
|
||||
"type": "machine",
|
||||
"author": "Ultimaker",
|
||||
"category": "Ultimaker",
|
||||
"category": "Other",
|
||||
"manufacturer": "Unknown",
|
||||
"setting_version": 1,
|
||||
"file_formats": "text/x-gcode;application/x-stl-ascii;application/x-stl-binary;application/x-wavefront-obj;application/x3g",
|
||||
@ -940,7 +940,7 @@
|
||||
"settable_per_extruder": false,
|
||||
"settable_per_meshgroup": true,
|
||||
"settable_globally": true,
|
||||
"enabled": "machine_extruder_count > 1 and roofing_layer_count > 0 and top_layers > 0"
|
||||
"enabled": "machine_extruder_count > 1 and max(extruderValues('roofing_layer_count')) > 0 and max(extruderValues('top_layers')) > 0"
|
||||
},
|
||||
"roofing_layer_count":
|
||||
{
|
||||
@ -1228,7 +1228,8 @@
|
||||
{
|
||||
"back": "User Specified",
|
||||
"shortest": "Shortest",
|
||||
"random": "Random"
|
||||
"random": "Random",
|
||||
"sharpest_corner": "Sharpest Corner"
|
||||
},
|
||||
"default_value": "shortest",
|
||||
"limit_to_extruder": "wall_0_extruder_nr",
|
||||
@ -1258,6 +1259,23 @@
|
||||
"limit_to_extruder": "wall_0_extruder_nr",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"z_seam_corner":
|
||||
{
|
||||
"label": "Seam Corner Preference",
|
||||
"description": "Control whether corners on the model outline influence the position of the seam. None means that corners have no influence on the seam position. Hide Seam makes the seam more likely to occur on an inside corner. Expose Seam makes the seam more likely to occur on an outside corner. Hide or Expose Seam makes the seam more likely to occur at an inside or outside corner.",
|
||||
"type": "enum",
|
||||
"options":
|
||||
{
|
||||
"z_seam_corner_none": "None",
|
||||
"z_seam_corner_inner": "Hide Seam",
|
||||
"z_seam_corner_outer": "Expose Seam",
|
||||
"z_seam_corner_any": "Hide or Expose Seam"
|
||||
},
|
||||
"default_value": "z_seam_corner_inner",
|
||||
"enabled": "z_seam_type != 'random'",
|
||||
"limit_to_extruder": "wall_0_extruder_nr",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"z_seam_relative":
|
||||
{
|
||||
"label": "Z Seam Relative",
|
||||
@ -1322,7 +1340,7 @@
|
||||
"default_value": 2,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "infill_line_width",
|
||||
"value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == 'grid' else (3 if infill_pattern == 'triangles' or infill_pattern == 'cubic' or infill_pattern == 'cubicsubdiv' else (2 if infill_pattern == 'tetrahedral' else 1)))",
|
||||
"value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == 'grid' else (3 if infill_pattern == 'triangles' or infill_pattern == 'cubic' or infill_pattern == 'cubicsubdiv' else (2 if infill_pattern == 'tetrahedral' or infill_pattern == 'quarter_cubic' else 1)))",
|
||||
"limit_to_extruder": "infill_extruder_nr",
|
||||
"settable_per_mesh": true
|
||||
}
|
||||
@ -1331,7 +1349,7 @@
|
||||
"infill_pattern":
|
||||
{
|
||||
"label": "Infill Pattern",
|
||||
"description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, cubic, tetrahedral and concentric patterns are fully printed every layer. Cubic and tetrahedral infill change with every layer to provide a more equal distribution of strength over each direction.",
|
||||
"description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, cubic, octet, quarter cubic and concentric patterns are fully printed every layer. Cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction.",
|
||||
"type": "enum",
|
||||
"options":
|
||||
{
|
||||
@ -1340,7 +1358,8 @@
|
||||
"triangles": "Triangles",
|
||||
"cubic": "Cubic",
|
||||
"cubicsubdiv": "Cubic Subdivision",
|
||||
"tetrahedral": "Tetrahedral",
|
||||
"tetrahedral": "Octet",
|
||||
"quarter_cubic": "Quarter Cubic",
|
||||
"concentric": "Concentric",
|
||||
"concentric_3d": "Concentric 3D",
|
||||
"zigzag": "Zig Zag"
|
||||
@ -1510,6 +1529,44 @@
|
||||
"limit_to_extruder": "infill_extruder_nr",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"skin_preshrink":
|
||||
{
|
||||
"label": "Skin Pre-Shrink Distance",
|
||||
"description": "The distance the skins are shrunk before considering them for skin expansion. Every skin area smaller than this value will disappear. This can help in limiting the amount of time and material spent on printing top/bottom skin at slanted surfaces in the model.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 0,
|
||||
"minimum_value": "0",
|
||||
"limit_to_extruder": "top_bottom_extruder_nr",
|
||||
"settable_per_mesh": true,
|
||||
"children":
|
||||
{
|
||||
"top_skin_preshrink":
|
||||
{
|
||||
"label": "Top Skin Pre-Shrink Distance",
|
||||
"description": "The distance the top skins are shrunk before considering them for skin expansion. Every skin area smaller than this value will disappear. This can help in limiting the amount of time and material spent on printing top skin at slanted surfaces in the model.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 0,
|
||||
"value": "skin_preshrink",
|
||||
"minimum_value": "0",
|
||||
"limit_to_extruder": "top_bottom_extruder_nr",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"bottom_skin_preshrink":
|
||||
{
|
||||
"label": "Bottom Skin Pre-Shrink Distance",
|
||||
"description": "The distance the bottom skins are shrunk before considering them for skin expansion. Every skin area smaller than this value will disappear. This can help in limiting the amount of time and material spent on printing bottom skin at slanted surfaces in the model.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 0,
|
||||
"value": "skin_preshrink",
|
||||
"minimum_value": "0",
|
||||
"limit_to_extruder": "top_bottom_extruder_nr",
|
||||
"settable_per_mesh": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"expand_skins_into_infill":
|
||||
{
|
||||
"label": "Expand Skins Into Infill",
|
||||
@ -4016,6 +4073,30 @@
|
||||
"settable_per_extruder": true,
|
||||
"limit_to_extruder": "adhesion_extruder_nr"
|
||||
},
|
||||
"z_offset_layer_0":
|
||||
{
|
||||
"label": "Initial Layer Z Offset",
|
||||
"description": "The extruder is offset from the normal height of the first layer by this amount. It can be positive (raised) or negative (lowered). Some filament types adhere to the build plate better if the extruder is raised slightly.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 0,
|
||||
"minimum_value_warning": "0",
|
||||
"maximum_value_warning": "layer_height_0",
|
||||
"enabled": "resolveOrValue('adhesion_type') != 'raft'",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": false
|
||||
},
|
||||
"z_offset_taper_layers":
|
||||
{
|
||||
"label": "Z Offset Taper Layers",
|
||||
"description": "When non-zero, the Z offset is reduced to 0 over that many layers. A value of 0 means that the Z offset remains constant for all the layers in the print.",
|
||||
"type": "int",
|
||||
"default_value": 0,
|
||||
"minimum_value": "0",
|
||||
"enabled": "resolveOrValue('adhesion_type') != 'raft' and z_offset_layer_0 != 0",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": false
|
||||
},
|
||||
"raft_margin":
|
||||
{
|
||||
"label": "Raft Extra Margin",
|
||||
@ -4626,7 +4707,7 @@
|
||||
"unit": "mm³",
|
||||
"default_value": 0,
|
||||
"minimum_value": "0",
|
||||
"maximum_value_warning": "0.5",
|
||||
"maximum_value_warning": "1",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": true
|
||||
},
|
||||
|
@ -6,7 +6,6 @@
|
||||
"visible": true,
|
||||
"author": "Jaime van Kessel & Paul Bussiere",
|
||||
"manufacturer": "Folger Tech",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "FT-5_build_plate.stl"
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Simon Cor",
|
||||
"manufacturer": "German RepRap",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker.png",
|
||||
"platform": "grr_neo_platform.stl"
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "BEEVERYCREATIVE",
|
||||
"manufacturer": "BEEVERYCREATIVE",
|
||||
"category": "Other",
|
||||
"platform": "BEEVERYCREATIVE-helloBEEprusa.stl",
|
||||
"platform_offset": [-226, -75, -196],
|
||||
"file_formats": "text/x-gcode",
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "IMADE3D",
|
||||
"manufacturer": "IMADE3D",
|
||||
"category": "Other",
|
||||
"platform": "imade3d_jellybox_platform.stl",
|
||||
"platform_offset": [ 0, -0.3, 0],
|
||||
"file_formats": "text/x-gcode",
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Adam Rumjahn",
|
||||
"manufacturer": "Innovo",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "inventor_platform.stl",
|
||||
"platform_offset": [-180, -0.25, 160]
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Fracktal",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "KEMIQ",
|
||||
"manufacturer": "KEMIQ",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "kemiq_q2.stl",
|
||||
"has_machine_quality": true,
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "KEMIQ",
|
||||
"manufacturer": "KEMIQ",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "kemiq_q2.stl",
|
||||
"has_machine_quality": true,
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Claudio Sampaio (Patola)",
|
||||
"manufacturer": "Other",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2",
|
||||
"platform": "kossel_platform.stl",
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Chris Petersen",
|
||||
"manufacturer": "OpenBeam",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2",
|
||||
"platform": "kossel_pro_build_platform.stl",
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Kupido",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ruben Dulek",
|
||||
"manufacturer": "Malyan",
|
||||
"category": "Other",
|
||||
"file_formats": "application/x3g"
|
||||
},
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "makeR",
|
||||
"manufacturer": "makeR",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2",
|
||||
"platform": "makeR_pegasus_platform.stl",
|
||||
|
@ -7,11 +7,10 @@
|
||||
"visible": true,
|
||||
"author": "makeR",
|
||||
"manufacturer": "makeR",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2",
|
||||
"platform": "makeR_prusa_tairona_i3_platform.stl",
|
||||
"platform_offset": [-2,0,0]
|
||||
"platform_offset": [-2, 0, 0]
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "NA",
|
||||
"manufacturer": "NA",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"has_materials": false,
|
||||
"supported_actions": [ "MachineSettingsAction", "UpgradeFirmware" ],
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "NA",
|
||||
"manufacturer": "NA",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"has_materials": false,
|
||||
"supported_actions": [ "MachineSettingsAction", "UpgradeFirmware" ],
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "tvlgiao",
|
||||
"manufacturer": "3DMaker",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode;application/x-stl-ascii;application/x-stl-binary;application/x-wavefront-obj",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
"platform": "makerstarter_platform.stl"
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "MakerBot",
|
||||
"category": "Other",
|
||||
"file_formats": "application/x3g",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "RBC",
|
||||
"manufacturer": "Mankati",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "mankati_fullscale_xt_plus_platform.stl"
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
{
|
||||
"visible": true,
|
||||
"author": "Bo Herrmannsen",
|
||||
"category": "Other",
|
||||
"manufacturer": "Nophead",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "mendel90_platform.stl",
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "ORD Solutions",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"machine_extruder_trains":
|
||||
{
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "fieldOfView",
|
||||
"manufacturer": "Peopoly",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"has_machine_quality": true,
|
||||
"has_materials": false
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Chris Pearson",
|
||||
"manufacturer": "Printrbot",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "printrbot_play.stl"
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Chris Pearson",
|
||||
"manufacturer": "Printrbot",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": ""
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Calvindog717",
|
||||
"manufacturer": "PrintrBot",
|
||||
"category": "Other",
|
||||
"platform": "printrbot_simple_metal_platform.stl",
|
||||
"platform_offset": [0, -3.45, 0],
|
||||
"file_formats": "text/x-gcode"
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "samsector",
|
||||
"manufacturer": "PrintrBot",
|
||||
"category": "Other",
|
||||
"platform": "printrbot_simple_metal_upgrade.stl",
|
||||
"platform_offset": [0, -0.3, 0],
|
||||
"file_formats": "text/x-gcode"
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Quillford",
|
||||
"manufacturer": "Prusajr",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2",
|
||||
"platform": "prusai3_platform.stl"
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Apsu",
|
||||
"manufacturer": "Prusa Research",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2",
|
||||
"platform": "prusai3_platform.stl",
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "guigashm",
|
||||
"manufacturer": "Prusajr",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
"platform": "prusai3_xl_platform.stl"
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Punchtec",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"machine_extruder_trains":
|
||||
{
|
||||
|
@ -5,7 +5,6 @@
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"author": "Simon Peter (based on RF100.ini by Conrad Electronic SE)",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"manufacturer": "Renkforce",
|
||||
"visible": true
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Rigid3D",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Rigid3D",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Rigid3D",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Rigid3D",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Rigid3D",
|
||||
"manufacturer": "Rigid3D",
|
||||
"category": "Other",
|
||||
"has_materials": false,
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "rigid3d_zero2_platform.stl",
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "RBC",
|
||||
"manufacturer": "RigidBot",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "rigidbot_platform.stl"
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "RBC",
|
||||
"manufacturer": "RigidBot",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "rigidbotbig_platform.stl"
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Robo 3D",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform_offset": [ 0, 0, 0]
|
||||
},
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "typeamachines",
|
||||
"manufacturer": "typeamachines",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "tam_series1.stl",
|
||||
"platform_offset": [-580.0, -6.23, 253.5],
|
||||
|
@ -6,6 +6,7 @@
|
||||
"metadata": {
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"visible": false
|
||||
},
|
||||
"overrides": {
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"weight": 3,
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"metadata": {
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"quality_definition": "ultimaker2",
|
||||
"weight": 3,
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
|
@ -6,7 +6,6 @@
|
||||
"metadata": {
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"quality_definition": "ultimaker2_plus",
|
||||
"weight": 2,
|
||||
"file_formats": "text/x-gcode",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"metadata": {
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"quality_definition": "ultimaker2",
|
||||
"weight": 3,
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
|
@ -6,7 +6,6 @@
|
||||
"metadata": {
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"weight": 1,
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "ultimaker2_platform.obj",
|
||||
|
@ -6,7 +6,6 @@
|
||||
"metadata": {
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"visible": true,
|
||||
"file_formats": "text/x-gcode",
|
||||
"platform": "ultimaker3_platform.obj",
|
||||
|
@ -6,7 +6,6 @@
|
||||
"metadata": {
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"quality_definition": "ultimaker3",
|
||||
"visible": true,
|
||||
"file_formats": "text/x-gcode",
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"weight": 4,
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker.png",
|
||||
|
@ -7,7 +7,6 @@
|
||||
"visible": true,
|
||||
"author": "Ultimaker",
|
||||
"manufacturer": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"weight": 4,
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker.png",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user