Merge branch 'master' of github.com:Ultimaker/Cura into cura_connect_UI_rework

This commit is contained in:
Jaime van Kessel 2018-09-06 10:50:51 +02:00
commit 53d083e232
27 changed files with 59138 additions and 123 deletions

View File

@ -6,10 +6,10 @@ from PyQt5.QtCore import Qt
from UM.Application import Application
from UM.Logger import Logger
from UM.Qt.ListModel import ListModel
from UM.Settings.SettingFunction import SettingFunction
from cura.Machines.QualityManager import QualityGroup
#
# QML Model for all built-in quality profiles. This model is used for the drop-down quality menu.
#
@ -106,4 +106,8 @@ class QualityProfilesDropDownMenuModel(ListModel):
container = global_stack.definition
if container and container.hasProperty("layer_height", "value"):
layer_height = container.getProperty("layer_height", "value")
if isinstance(layer_height, SettingFunction):
layer_height = layer_height(global_stack)
return float(layer_height)

View File

@ -200,7 +200,9 @@ class QualityManager(QObject):
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition)
# This determines if we should only get the global qualities for the global stack and skip the global qualities for the extruder stacks
has_variant_materials = parseBool(machine.getMetaDataEntry("has_variant_materials", False))
has_variants = machine.getHasVariants()
has_materials = machine.getHasMaterials()
has_variants_or_materials = has_variants or has_materials
# To find the quality container for the GlobalStack, check in the following fall-back manner:
# (1) the machine-specific node
@ -214,7 +216,7 @@ class QualityManager(QObject):
for node in nodes_to_check:
if node and node.quality_type_map:
# Only include global qualities
if has_variant_materials:
if has_variants_or_materials:
quality_node = list(node.quality_type_map.values())[0]
is_global_quality = parseBool(quality_node.metadata.get("global_quality", False))
if not is_global_quality:
@ -302,7 +304,7 @@ class QualityManager(QObject):
for node in nodes_to_check:
if node and node.quality_type_map:
if has_variant_materials:
if has_variants_or_materials:
# Only include variant qualities; skip non global qualities
quality_node = list(node.quality_type_map.values())[0]
is_global_quality = parseBool(quality_node.metadata.get("global_quality", False))
@ -363,8 +365,19 @@ class QualityManager(QObject):
@pyqtSlot(QObject)
def removeQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup"):
Logger.log("i", "Removing quality changes group [%s]", quality_changes_group.name)
removed_quality_changes_ids = set()
for node in quality_changes_group.getAllNodes():
self._container_registry.removeContainer(node.getMetaDataEntry("id"))
container_id = node.getMetaDataEntry("id")
self._container_registry.removeContainer(container_id)
removed_quality_changes_ids.add(container_id)
# Reset all machines that have activated this quality changes to empty.
for global_stack in self._container_registry.findContainerStacks(type = "machine"):
if global_stack.qualityChanges.getId() in removed_quality_changes_ids:
global_stack.qualityChanges = self._empty_quality_changes_container
for extruder_stack in self._container_registry.findContainerStacks(type = "extruder_train"):
if extruder_stack.qualityChanges.getId() in removed_quality_changes_ids:
extruder_stack.qualityChanges = self._empty_quality_changes_container
#
# Rename a set of quality changes containers. Returns the new name.

View File

@ -13,6 +13,8 @@ from UM.Settings.SettingInstance import InstanceState
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.Interfaces import PropertyEvaluationContext
from UM.Logger import Logger
from UM.Util import parseBool
import cura.CuraApplication
from . import Exceptions
@ -188,6 +190,12 @@ class GlobalStack(CuraContainerStack):
def getHeadAndFansCoordinates(self):
return self.getProperty("machine_head_with_fans_polygon", "value")
def getHasMaterials(self) -> bool:
return parseBool(self.getMetaDataEntry("has_materials", False))
def getHasVariants(self) -> bool:
return parseBool(self.getMetaDataEntry("has_variants", False))
## private:
global_stack_mime = MimeType(

View File

@ -85,14 +85,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
def __init__(self) -> None:
super().__init__()
MimeTypeDatabase.addMimeType(
MimeType(
name="application/x-curaproject+xml",
comment="Cura Project File",
suffixes=["curaproject.3mf"]
)
)
self._supported_extensions = [".3mf"]
self._dialog = WorkspaceDialog()
self._3mf_mesh_reader = None
@ -726,8 +718,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
nodes = []
base_file_name = os.path.basename(file_name)
if base_file_name.endswith(".curaproject.3mf"):
base_file_name = base_file_name[:base_file_name.rfind(".curaproject.3mf")]
self.setWorkspaceName(base_file_name)
return nodes

View File

@ -18,11 +18,7 @@ catalog = i18nCatalog("cura")
def getMetaData() -> Dict:
# Workaround for osx not supporting double file extensions correctly.
if Platform.isOSX():
workspace_extension = "3mf"
else:
workspace_extension = "curaproject.3mf"
metaData = {}
if "3MFReader.ThreeMFReader" in sys.modules:

View File

@ -15,11 +15,7 @@ from UM.Platform import Platform
i18n_catalog = i18nCatalog("uranium")
def getMetaData():
# Workarround for osx not supporting double file extensions correctly.
if Platform.isOSX():
workspace_extension = "3mf"
else:
workspace_extension = "curaproject.3mf"
metaData = {}
@ -36,7 +32,7 @@ def getMetaData():
"output": [{
"extension": workspace_extension,
"description": i18n_catalog.i18nc("@item:inlistbox", "Cura Project 3MF file"),
"mime_type": "application/x-curaproject+xml",
"mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
"mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode
}]
}

View File

@ -44,12 +44,11 @@ UM.PointingRectangle {
id: valueLabel
anchors {
left: parent.left
leftMargin: Math.round(UM.Theme.getSize("default_margin").width / 2)
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
}
width: maximumValue.toString().length * 12 * screenScaleFactor
width: (maximumValue.toString().length + 1) * 10 * screenScaleFactor
text: sliderLabelRoot.value + startFrom // the current handle value, add 1 because layers is an array
horizontalAlignment: TextInput.AlignRight

View File

@ -82,9 +82,16 @@ Item
}
spacing: Math.floor(UM.Theme.getSize("narrow_margin").height)
width: childrenRect.width
Label
{
text: catalog.i18nc("@label", "Contact") + ":"
text: catalog.i18nc("@label", "Website") + ":"
font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text_medium")
}
Label
{
text: catalog.i18nc("@label", "Email") + ":"
font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text_medium")
}
@ -100,18 +107,32 @@ Item
topMargin: UM.Theme.getSize("default_margin").height
}
spacing: Math.floor(UM.Theme.getSize("narrow_margin").height)
Label
{
text:
{
if (details.website)
{
return "<a href=\"" + details.website + "\">" + details.website + "</a>"
}
return ""
}
font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text")
linkColor: UM.Theme.getColor("text_link")
onLinkActivated: Qt.openUrlExternally(link)
}
Label
{
text:
{
if (details.email)
{
return "<a href=\"mailto:"+details.email+"\">"+details.name+"</a>"
}
else
{
return "<a href=\""+details.website+"\">"+details.name+"</a>"
return "<a href=\"mailto:" + details.email + "\">" + details.email + "</a>"
}
return ""
}
font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text")

View File

@ -8,7 +8,18 @@ import UM 1.1 as UM
Item
{
id: base
property var packageData
property var technicalDataSheetUrl: {
var link = undefined
if ("Technical Data Sheet" in packageData.links)
{
link = packageData.links["Technical Data Sheet"]
}
return link
}
anchors.topMargin: UM.Theme.getSize("default_margin").height
height: visible ? childrenRect.height : 0
visible: packageData.type == "material" && packageData.has_configs
@ -132,4 +143,25 @@ Item
width: Math.floor(table.width * 0.1)
}
}
Label
{
id: technical_data_sheet
anchors.top: table.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height / 2
visible: base.technicalDataSheetUrl !== undefined
text:
{
if (base.technicalDataSheetUrl !== undefined)
{
return "<a href='%1'>%2</a>".arg(base.technicalDataSheetUrl).arg("Technical Data Sheet")
}
return ""
}
font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text")
linkColor: UM.Theme.getColor("text_link")
onLinkActivated: Qt.openUrlExternally(link)
}
}

View File

@ -9,7 +9,7 @@ import UM 1.1 as UM
Item
{
property int packageCount: (toolbox.viewCategory == "material" && model.type === undefined) ? toolbox.getTotalNumberOfPackagesByAuthor(model.id) : 1
property int packageCount: (toolbox.viewCategory == "material" && model.type === undefined) ? toolbox.getTotalNumberOfMaterialPackagesByAuthor(model.id) : 1
property int installedPackages: (toolbox.viewCategory == "material" && model.type === undefined) ? toolbox.getNumberOfInstalledPackagesByAuthor(model.id) : (toolbox.isInstalled(model.id) ? 1 : 0)
height: childrenRect.height
Layout.alignment: Qt.AlignTop | Qt.AlignLeft

View File

@ -30,7 +30,7 @@ ScrollView
id: allPlugins
width: parent.width
heading: toolbox.viewCategory == "material" ? catalog.i18nc("@label", "Community Contributions") : catalog.i18nc("@label", "Community Plugins")
model: toolbox.viewCategory == "material" ? toolbox.authorsModel : toolbox.packagesModel
model: toolbox.viewCategory == "material" ? toolbox.materialsAvailableModel : toolbox.pluginsAvailableModel
}
ToolboxDownloadsGrid

View File

@ -9,7 +9,7 @@ import UM 1.1 as UM
Rectangle
{
property int packageCount: toolbox.viewCategory == "material" ? toolbox.getTotalNumberOfPackagesByAuthor(model.id) : 1
property int packageCount: toolbox.viewCategory == "material" ? toolbox.getTotalNumberOfMaterialPackagesByAuthor(model.id) : 1
property int installedPackages: toolbox.viewCategory == "material" ? toolbox.getNumberOfInstalledPackagesByAuthor(model.id) : (toolbox.isInstalled(model.id) ? 1 : 0)
id: tileBase
width: UM.Theme.getSize("toolbox_thumbnail_large").width + (2 * UM.Theme.getSize("default_lining").width)

View File

@ -33,6 +33,9 @@ class AuthorsModel(ListModel):
def _update(self):
items = []
if not self._metadata:
self.setItems([])
return
for author in self._metadata:
items.append({

View File

@ -5,9 +5,13 @@ import re
from typing import Dict
from PyQt5.QtCore import Qt, pyqtProperty
from UM.Logger import Logger
from UM.Qt.ListModel import ListModel
from .ConfigsModel import ConfigsModel
## Model that holds cura packages. By setting the filter property the instances held by this model can be changed.
class PackagesModel(ListModel):
def __init__(self, parent = None):
@ -34,6 +38,8 @@ class PackagesModel(ListModel):
self.addRoleName(Qt.UserRole + 17, "supported_configs")
self.addRoleName(Qt.UserRole + 18, "download_count")
self.addRoleName(Qt.UserRole + 19, "tags")
self.addRoleName(Qt.UserRole + 20, "links")
self.addRoleName(Qt.UserRole + 21, "website")
# List of filters for queries. The result is the union of the each list of results.
self._filter = {} # type: Dict[str, str]
@ -45,10 +51,16 @@ class PackagesModel(ListModel):
def _update(self):
items = []
for package in self._metadata:
if self._metadata is None:
Logger.logException("w", "Failed to load packages for Toolbox")
self.setItems(items)
return
for package in self._metadata:
has_configs = False
configs_model = None
links_dict = {}
if "data" in package:
if "supported_configs" in package["data"]:
if len(package["data"]["supported_configs"]) > 0:
@ -56,6 +68,11 @@ class PackagesModel(ListModel):
configs_model = ConfigsModel()
configs_model.setConfigs(package["data"]["supported_configs"])
# Links is a list of dictionaries with "title" and "url". Convert this list into a dict so it's easier
# to process.
link_list = package['data']['links'] if 'links' in package['data'] else []
links_dict = {d["title"]: d["url"] for d in link_list}
if "author_id" not in package["author"] or "display_name" not in package["author"]:
package["author"]["author_id"] = ""
package["author"]["display_name"] = ""
@ -80,17 +97,19 @@ class PackagesModel(ListModel):
"has_configs": has_configs,
"supported_configs": configs_model,
"download_count": package["download_count"] if "download_count" in package else 0,
"tags": package["tags"] if "tags" in package else []
"tags": package["tags"] if "tags" in package else [],
"links": links_dict,
"website": package["website"] if "website" in package else None,
})
# Filter on all the key-word arguments.
for key, value in self._filter.items():
if key is "tags":
key_filter = lambda item, value = value: value in item["tags"]
key_filter = lambda item, v = value: v in item["tags"]
elif "*" in value:
key_filter = lambda candidate, key = key, value = value: self._matchRegExp(candidate, key, value)
key_filter = lambda candidate, k = key, v = value: self._matchRegExp(candidate, k, v)
else:
key_filter = lambda candidate, key = key, value = value: self._matchString(candidate, key, value)
key_filter = lambda candidate, k = key, v = value: self._matchString(candidate, k, v)
items = filter(key_filter, items)
# Execute all filters.

View File

@ -83,7 +83,7 @@ class Toolbox(QObject, Extension):
"plugins_available": PackagesModel(self),
"plugins_installed": PackagesModel(self),
"materials_showcase": AuthorsModel(self),
"materials_available": PackagesModel(self),
"materials_available": AuthorsModel(self),
"materials_installed": PackagesModel(self),
"materials_generic": PackagesModel(self)
} # type: Dict[str, ListModel]
@ -514,10 +514,12 @@ class Toolbox(QObject, Extension):
count += 1
return count
# This slot is only used to get the number of material packages by author, not any other type of packages.
@pyqtSlot(str, result = int)
def getTotalNumberOfPackagesByAuthor(self, author_id: str) -> int:
def getTotalNumberOfMaterialPackagesByAuthor(self, author_id: str) -> int:
count = 0
for package in self._metadata["materials_available"]:
for package in self._metadata["packages"]:
if package["package_type"] == "material":
if package["author"]["author_id"] == author_id:
count += 1
return count
@ -606,8 +608,21 @@ class Toolbox(QObject, Extension):
self.resetDownload()
return
# HACK: These request are not handled independently at this moment, but together from the "packages" call
do_not_handle = [
"materials_available",
"materials_showcase",
"plugins_available",
"plugins_showcase",
]
if reply.operation() == QNetworkAccessManager.GetOperation:
for type, url in self._request_urls.items():
# HACK: Do nothing because we'll handle these from the "packages" call
if type in do_not_handle:
return
if reply.url() == url:
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 200:
try:
@ -624,17 +639,6 @@ class Toolbox(QObject, Extension):
Logger.log("e", "Could not find the %s model.", type)
break
# HACK: Eventually get rid of the code from here...
if type is "plugins_showcase" or type is "materials_showcase":
self._metadata["plugins_showcase"] = json_data["data"]["plugin"]["packages"]
self._models["plugins_showcase"].setMetadata(self._metadata["plugins_showcase"])
self._metadata["materials_showcase"] = json_data["data"]["material"]["authors"]
self._models["materials_showcase"].setMetadata(self._metadata["materials_showcase"])
else:
# ...until here.
# This hack arises for multiple reasons but the main
# one is because there are not separate API calls
# for different kinds of showcases.
self._metadata[type] = json_data["data"]
self._models[type].setMetadata(self._metadata[type])
@ -642,6 +646,8 @@ class Toolbox(QObject, Extension):
# TODO: Make multiple API calls in the future to handle this
if type is "packages":
self._models[type].setFilter({"type": "plugin"})
self.buildMaterialsModels()
self.buildPluginsModels()
if type is "authors":
self._models[type].setFilter({"package_types": "material"})
if type is "materials_generic":
@ -755,6 +761,10 @@ class Toolbox(QObject, Extension):
def pluginsShowcaseModel(self) -> PackagesModel:
return cast(PackagesModel, self._models["plugins_showcase"])
@pyqtProperty(QObject, notify = metadataChanged)
def pluginsAvailableModel(self) -> PackagesModel:
return cast(PackagesModel, self._models["plugins_available"])
@pyqtProperty(QObject, notify = metadataChanged)
def pluginsInstalledModel(self) -> PackagesModel:
return cast(PackagesModel, self._models["plugins_installed"])
@ -763,6 +773,10 @@ class Toolbox(QObject, Extension):
def materialsShowcaseModel(self) -> AuthorsModel:
return cast(AuthorsModel, self._models["materials_showcase"])
@pyqtProperty(QObject, notify = metadataChanged)
def materialsAvailableModel(self) -> AuthorsModel:
return cast(AuthorsModel, self._models["materials_available"])
@pyqtProperty(QObject, notify = metadataChanged)
def materialsInstalledModel(self) -> PackagesModel:
return cast(PackagesModel, self._models["materials_installed"])
@ -798,3 +812,46 @@ class Toolbox(QObject, Extension):
return
self._models[model_type].setFilter({})
self.filterChanged.emit()
# HACK(S):
# --------------------------------------------------------------------------
def buildMaterialsModels(self) -> None:
self._metadata["materials_showcase"] = []
self._metadata["materials_available"] = []
processed_authors = [] # type: List[str]
for item in self._metadata["packages"]:
if item["package_type"] == "material":
author = item["author"]
if author["author_id"] in processed_authors:
continue
if "showcase" in item["tags"]:
self._metadata["materials_showcase"].append(author)
else:
self._metadata["materials_available"].append(author)
processed_authors.append(author["author_id"])
self._models["materials_showcase"].setMetadata(self._metadata["materials_showcase"])
self._models["materials_available"].setMetadata(self._metadata["materials_available"])
def buildPluginsModels(self) -> None:
self._metadata["plugins_showcase"] = []
self._metadata["plugins_available"] = []
for item in self._metadata["packages"]:
if item["package_type"] == "plugin":
if "showcase" in item["tags"]:
self._metadata["plugins_showcase"].append(item)
else:
self._metadata["plugins_available"].append(item)
self._models["plugins_showcase"].setMetadata(self._metadata["plugins_showcase"])
self._models["plugins_available"].setMetadata(self._metadata["plugins_available"])

View File

@ -326,7 +326,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
if self._firmware_name is None:
self.sendCommand("M115")
if (b"ok " in line and b"T:" in line) or b"ok T:" in line or line.startswith(b"T:") or b"ok B:" in line or line.startswith(b"B:"): # Temperature message. 'T:' for extruder and 'B:' for bed
if (b"ok " in line and b"T:" in line) or line.startswith(b"T:") or b"ok B:" in line or line.startswith(b"B:"): # Temperature message. 'T:' for extruder and 'B:' for bed
extruder_temperature_matches = re.findall(b"T(\d*): ?([\d\.]+) ?\/?([\d\.]+)?", line)
# Update all temperature values
matched_extruder_nrs = []

View File

@ -17,8 +17,8 @@
"overrides": {
"machine_name": { "default_value": "BQ Hephestos 2" },
"machine_start_gcode": { "default_value": "; -- START GCODE --\nM104 S{material_print_temperature} ; Heat up extruder while leveling\nM800 ; Custom GCODE to fire start print procedure\nM109 S{material_print_temperature} ; Makes sure the temperature is correct before printing\n; -- end of START GCODE --" },
"machine_end_gcode": { "default_value": "; -- END GCODE --\nM801 ; Custom GCODE to fire end print procedure\n; -- end of END GCODE --" },
"machine_start_gcode": { "default_value": "; -- START GCODE --\nM104 S{material_print_temperature}\nG28 ; Zero-ing position\nG29 ; Auto bed-leveling\nG0 X4 Y297 Z15 F4000 ; Fast move to BQ's start position\nG90 ; Set to Absolute Positioning\nG92 E0 ; Reset extruder 0\nG1 F1800 ; Set default feedrate\nM109 S{material_print_temperature} ; Makes sure the temperature is correct before printing\n; -- end of START GCODE --" },
"machine_end_gcode": { "default_value": "; -- END GCODE --\nM801 ; Marlin G-CODE to fire end print procedure\n; -- end of END GCODE --" },
"machine_width": { "default_value": 210 },
"machine_depth": { "default_value": 297 },
"machine_height": { "default_value": 220 },

View File

@ -11,7 +11,6 @@
"has_machine_quality": true,
"has_materials": true,
"has_machine_materials": true,
"has_variant_materials": true,
"has_variants": true,
"variants_name": "Tool",

View File

@ -0,0 +1,92 @@
{
"name": "Creality Ender-3",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Sacha Telgenhof",
"manufacturer": "Creality3D",
"file_formats": "text/x-gcode",
"platform": "creality_ender3_platform.stl",
"preferred_quality_type": "draft"
},
"overrides": {
"machine_name": {
"default_value": "Creality Ender-3"
},
"machine_width": {
"default_value": 220
},
"machine_height": {
"default_value": 250
},
"machine_depth": {
"default_value": 220
},
"machine_heated_bed": {
"default_value": true
},
"gantry_height": {
"default_value": 30
},
"machine_head_polygon": {
"default_value": [
[-30, 34],
[-30, -32],
[30, -32],
[30, 34]
]
},
"material_diameter": {
"default_value": 1.75
},
"acceleration_enabled": {
"default_value": true
},
"acceleration_print": {
"default_value": 500
},
"acceleration_travel": {
"default_value": 500
},
"jerk_enabled": {
"default_value": true
},
"jerk_travel": {
"default_value": 20
},
"layer_height": {
"default_value": 0.15
},
"layer_height_0": {
"default_value": 0.2
},
"adhesion_type": {
"default_value": "skirt"
},
"top_bottom_thickness": {
"default_value": 0.6
},
"retraction_amount": {
"default_value": 5
},
"retraction_speed": {
"default_value": 40
},
"cool_min_layer_time": {
"default_value": 10
},
"skirt_line_count": {
"default_value": 4
},
"skirt_gap": {
"default_value": 5
},
"machine_start_gcode": {
"default_value": "; Ender 3 Custom Start G-code\nM104 S{material_print_temperature_layer_0} ; Set Extruder temperature\nM140 S{material_bed_temperature_layer_0} ; Set Heat Bed temperature\nM190 S{material_bed_temperature_layer_0} ; Wait for Heat Bed temperature\nM109 S{material_print_temperature_layer_0} ; Wait for Extruder temperature\nG28 ; Home all axes\nG92 E0 ; Reset Extruder\nG1 Z5.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position\nG1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z5.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed"
},
"machine_end_gcode": {
"default_value": "; Ender 3 Custom End G-code\nG4 ; Wait\nM220 S100 ; Reset Speed factor override percentage to default (100%)\nM221 S100 ; Reset Extrude factor override percentage to default (100%)\nG91 ; Set coordinates to relative\nG1 F1800 E-3 ; Retract filament 3 mm to prevent oozing\nG1 F3000 Z10 ; Move Z Axis up 10 mm to allow filament ooze freely\nG90 ; Set coordinates to absolute\nG1 X0 Y{machine_depth} F1000 ; Move Heat Bed to the front for easy print removal\nM104 S0 ; Turn off Extruder temperature\nM140 S0 ; Turn off Heat Bed\nM106 S0 ; Turn off Cooling Fan\nM107 ; Turn off Fan\nM84 ; Disable stepper motors"
}
}
}

View File

@ -1297,8 +1297,8 @@
"default_value": 0,
"type": "float",
"enabled": "travel_compensate_overlapping_walls_0_enabled or travel_compensate_overlapping_walls_x_enabled",
"settable_per_mesh": false,
"settable_per_extruder": true
"settable_per_mesh": true,
"settable_per_extruder": false
},
"wall_min_flow_retract":
{
@ -1307,8 +1307,8 @@
"type": "bool",
"default_value": false,
"enabled": "(travel_compensate_overlapping_walls_0_enabled or travel_compensate_overlapping_walls_x_enabled) and wall_min_flow > 0",
"settable_per_mesh": false,
"settable_per_extruder": true
"settable_per_mesh": true,
"settable_per_extruder": false
},
"fill_perimeter_gaps":
{
@ -3875,6 +3875,19 @@
}
}
},
"support_infill_angle":
{
"label": "Support Infill Line Direction",
"description": "Orientation of the infill pattern for supports. The support infill pattern is rotated in the horizontal plane.",
"unit": "°",
"type": "float",
"minimum_value": "-180",
"maximum_value": "180",
"default_value": 0,
"enabled": "support_enable and support_pattern != 'concentric' and support_infill_rate > 0",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"support_z_distance":
{
"label": "Support Z Distance",
@ -6483,6 +6496,30 @@
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"wall_overhang_angle":
{
"label": "Overhanging Wall Angle",
"description": "Walls that overhang more than this angle will be printed using overhanging wall settings. When the value is 90, no walls will be treated as overhanging.",
"unit": "°",
"type": "float",
"minimum_value": "0",
"minimum_value_warning": "2",
"maximum_value": "90",
"default_value": 90,
"settable_per_mesh": true
},
"wall_overhang_speed_factor":
{
"label": "Overhanging Wall Speed",
"description": "Overhanging walls will be printed at this percentage of their normal print speed.",
"unit": "%",
"type": "float",
"default_value": 100,
"minimum_value": "10",
"minimum_value_warning": "25",
"maximum_value": "100",
"settable_per_mesh": true
},
"bridge_settings_enabled":
{
"label": "Enable Bridge Settings",
@ -6502,8 +6539,8 @@
"minimum_value": "0",
"default_value": 5,
"enabled": "bridge_settings_enabled",
"settable_per_mesh": false,
"settable_per_extruder": true
"settable_per_mesh": true,
"settable_per_extruder": false
},
"bridge_skin_support_threshold":
{
@ -6517,18 +6554,6 @@
"enabled": "bridge_settings_enabled",
"settable_per_mesh": true
},
"bridge_wall_max_overhang":
{
"label": "Bridge Wall Max Overhang",
"description": "The maximum allowed width of the region of air below a wall line before the wall is printed using bridge settings. Expressed as a percentage of the wall line width. When the air gap is wider than this, the wall line is printed using the bridge settings. Otherwise, the wall line is printed using the normal settings. The lower the value, the more likely it is that overhung wall lines will be printed using bridge settings.",
"unit": "%",
"default_value": 100,
"type": "float",
"minimum_value": "0",
"maximum_value": "100",
"enabled": "bridge_settings_enabled",
"settable_per_mesh": true
},
"bridge_wall_coast":
{
"label": "Bridge Wall Coasting",
@ -6539,7 +6564,7 @@
"minimum_value": "0",
"maximum_value": "500",
"enabled": "bridge_settings_enabled",
"settable_per_mesh": false
"settable_per_mesh": true
},
"bridge_wall_speed":
{

View File

@ -13,7 +13,6 @@
"has_machine_quality": true,
"has_materials": true,
"has_machine_materials": true,
"has_variant_materials": true,
"has_variants": true,
"preferred_variant_name": "AA 0.4",
"preferred_quality_type": "normal",

View File

@ -13,7 +13,6 @@
"platform_offset": [0, 0, 0],
"has_machine_quality": true,
"has_machine_materials": true,
"has_variant_materials": true,
"has_materials": true,
"has_variants": true,
"preferred_variant_name": "AA 0.4",

View File

@ -15,7 +15,6 @@
"has_machine_quality": true,
"has_materials": true,
"has_machine_materials": true,
"has_variant_materials": true,
"has_variant_buildplates": true,
"has_variants": true,
"preferred_variant_name": "AA 0.4",

File diff suppressed because it is too large Load Diff

View File

@ -138,7 +138,7 @@ Item
Action
{
id: viewRightSideCameraAction;
text: catalog.i18nc("@action:inmenu menubar:view","Right Side View");
text: catalog.i18nc("@action:inmenu menubar:view","&Right Side View");
onTriggered: UM.Controller.rotateView("x", -90);
}
@ -236,16 +236,6 @@ Item
onTriggered: CuraActions.deleteSelection();
}
Action //Also add backspace as the same function as delete because on Macintosh keyboards the button called "delete" is actually a backspace, and the user expects it to function as a delete.
{
id: backspaceSelectionAction
text: catalog.i18ncp("@action:inmenu menubar:edit", "Delete Selected Model", "Delete Selected Models", UM.Selection.selectionCount)
enabled: UM.Controller.toolsEnabled && UM.Selection.hasSelection
iconName: "edit-delete"
shortcut: StandardKey.Backspace
onTriggered: CuraActions.deleteSelection()
}
Action
{
id: centerSelectionAction;
@ -338,7 +328,7 @@ Item
Action
{
id: deleteAllAction;
text: catalog.i18nc("@action:inmenu menubar:edit","&Clear Build Plate");
text: catalog.i18nc("@action:inmenu menubar:edit","Clear Build Plate");
enabled: UM.Controller.toolsEnabled;
iconName: "edit-delete";
shortcut: "Ctrl+D";
@ -348,7 +338,7 @@ Item
Action
{
id: reloadAllAction;
text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Models");
text: catalog.i18nc("@action:inmenu menubar:file","Reload All Models");
iconName: "document-revert";
shortcut: "F5"
onTriggered: CuraApplication.reloadAll();
@ -386,7 +376,7 @@ Item
Action
{
id: resetAllAction;
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Model Transformations");
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Model &Transformations");
onTriggered: CuraApplication.resetAll();
}

View File

@ -117,10 +117,10 @@ UM.MainWindow
MenuItem
{
id: saveWorkspaceMenu
text: catalog.i18nc("@title:menu menubar:file","Save...")
text: catalog.i18nc("@title:menu menubar:file","&Save...")
onTriggered:
{
var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetypes": "application/x-curaproject+xml" };
var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml" };
if(UM.Preferences.getValue("cura/dialog_on_project_save"))
{
saveWorkspaceDialog.args = args;

View File

@ -12,5 +12,5 @@ hardware_type = nozzle
machine_nozzle_size = 0.4
machine_nozzle_tip_outer_diameter = 1.05
speed_wall = =round(speed_print / 1.25, 1)
speed_wall_0 = =1 if speed_wall < 10 else (speed_wall - 10)
speed_wall_0 = =min(speed_wall - 10, 1)
speed_topbottom = =round(speed_print / 2.25, 1)