mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-23 22:54:01 -06:00
Merge branch 'master' of https://github.com/Ultimaker/Cura into clean_print_job_info_block
This commit is contained in:
commit
9caeddf824
128 changed files with 3074 additions and 2239 deletions
|
@ -934,7 +934,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||
root_material_id)
|
||||
|
||||
if material_node is not None and material_node.getContainer() is not None:
|
||||
extruder_stack.material = material_node.getContainer()
|
||||
extruder_stack.material = material_node.getContainer() # type: InstanceContainer
|
||||
|
||||
def _applyChangesToMachine(self, global_stack, extruder_stack_dict):
|
||||
# Clear all first
|
||||
|
|
|
@ -29,6 +29,7 @@ message Object
|
|||
bytes normals = 3; //An array of 3 floats.
|
||||
bytes indices = 4; //An array of ints.
|
||||
repeated Setting settings = 5; // Setting override per object, overruling the global settings.
|
||||
string name = 6;
|
||||
}
|
||||
|
||||
message Progress
|
||||
|
|
|
@ -179,8 +179,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
# This is useful for debugging and used to actually start the engine.
|
||||
# \return list of commands and args / parameters.
|
||||
def getEngineCommand(self) -> List[str]:
|
||||
json_path = Resources.getPath(Resources.DefinitionContainers, "fdmprinter.def.json")
|
||||
command = [self._application.getPreferences().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), "-j", json_path, ""]
|
||||
command = [self._application.getPreferences().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), ""]
|
||||
|
||||
parser = argparse.ArgumentParser(prog = "cura", add_help = False)
|
||||
parser.add_argument("--debug", action = "store_true", default = False, help = "Turn on the debug mode by setting this option.")
|
||||
|
|
|
@ -270,7 +270,7 @@ class StartSliceJob(Job):
|
|||
|
||||
obj = group_message.addRepeatedMessage("objects")
|
||||
obj.id = id(object)
|
||||
|
||||
obj.name = object.getName()
|
||||
indices = mesh_data.getIndices()
|
||||
if indices is not None:
|
||||
flat_verts = numpy.take(verts, indices.flatten(), axis=0)
|
||||
|
@ -440,8 +440,7 @@ class StartSliceJob(Job):
|
|||
Job.yieldThread()
|
||||
|
||||
# Ensure that the engine is aware what the build extruder is.
|
||||
if stack.getProperty("machine_extruder_count", "value") > 1:
|
||||
changed_setting_keys.add("extruder_nr")
|
||||
changed_setting_keys.add("extruder_nr")
|
||||
|
||||
# Get values for all changed settings
|
||||
for key in changed_setting_keys:
|
||||
|
|
|
@ -4,15 +4,22 @@
|
|||
import gzip
|
||||
|
||||
from UM.Mesh.MeshReader import MeshReader #The class we're extending/implementing.
|
||||
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType #To add the .gcode.gz files to the MIME type database.
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
|
||||
|
||||
## A file reader that reads gzipped g-code.
|
||||
#
|
||||
# If you're zipping g-code, you might as well use gzip!
|
||||
class GCodeGzReader(MeshReader):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
MimeTypeDatabase.addMimeType(
|
||||
MimeType(
|
||||
name = "application/x-cura-compressed-gcode-file",
|
||||
comment = "Cura Compressed GCode File",
|
||||
suffixes = ["gcode.gz"]
|
||||
)
|
||||
)
|
||||
self._supported_extensions = [".gcode.gz"]
|
||||
|
||||
def _read(self, file_name):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright (c) 2017 Aleph Objects, Inc.
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from UM.FileHandler.FileReader import FileReader
|
||||
|
@ -11,13 +12,7 @@ catalog = i18nCatalog("cura")
|
|||
from . import MarlinFlavorParser, RepRapFlavorParser
|
||||
|
||||
|
||||
MimeTypeDatabase.addMimeType(
|
||||
MimeType(
|
||||
name = "application/x-cura-gcode-file",
|
||||
comment = "Cura GCode File",
|
||||
suffixes = ["gcode", "gcode.gz"]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
# Class for loading and parsing G-code files
|
||||
|
@ -29,7 +24,15 @@ class GCodeReader(MeshReader):
|
|||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
MimeTypeDatabase.addMimeType(
|
||||
MimeType(
|
||||
name = "application/x-cura-gcode-file",
|
||||
comment = "Cura GCode File",
|
||||
suffixes = ["gcode"]
|
||||
)
|
||||
)
|
||||
self._supported_extensions = [".gcode", ".g"]
|
||||
|
||||
self._flavor_reader = None
|
||||
|
||||
Application.getInstance().getPreferences().addPreference("gcodereader/show_caution", True)
|
||||
|
|
|
@ -70,7 +70,7 @@ class GCodeWriter(MeshWriter):
|
|||
active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate
|
||||
scene = Application.getInstance().getController().getScene()
|
||||
if not hasattr(scene, "gcode_dict"):
|
||||
self.setInformation(catalog.i18nc("@warning:status", "Please generate G-code before saving."))
|
||||
self.setInformation(catalog.i18nc("@warning:status", "Please prepare G-code before exporting."))
|
||||
return False
|
||||
gcode_dict = getattr(scene, "gcode_dict")
|
||||
gcode_list = gcode_dict.get(active_build_plate, None)
|
||||
|
@ -86,7 +86,7 @@ class GCodeWriter(MeshWriter):
|
|||
stream.write(settings)
|
||||
return True
|
||||
|
||||
self.setInformation(catalog.i18nc("@warning:status", "Please generate G-code before saving."))
|
||||
self.setInformation(catalog.i18nc("@warning:status", "Please prepare G-code before exporting."))
|
||||
return False
|
||||
|
||||
## Create a new container with container 2 as base and container 1 written over it.
|
||||
|
|
|
@ -185,6 +185,12 @@ Item {
|
|||
{
|
||||
selectedObjectId: UM.ActiveTool.properties.getValue("SelectedObjectId")
|
||||
}
|
||||
|
||||
// For some reason the model object is updated after removing him from the memory and
|
||||
// it happens only on Windows. For this reason, set the destroyed value manually.
|
||||
Component.onDestruction: {
|
||||
setDestroyed(true);
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Row
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
# Cura PostProcessingPlugin
|
||||
# Author: Amanda de Castilho
|
||||
# Date: August 28, 2018
|
||||
|
||||
# Description: This plugin inserts a line at the start of each layer,
|
||||
# M117 - displays the filename and layer height to the LCD
|
||||
# Alternatively, user can override the filename to display alt text + layer height
|
||||
|
||||
from ..Script import Script
|
||||
from UM.Application import Application
|
||||
|
||||
class DisplayFilenameAndLayerOnLCD(Script):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Display filename and layer on LCD",
|
||||
"key": "DisplayFilenameAndLayerOnLCD",
|
||||
"metadata": {},
|
||||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"name":
|
||||
{
|
||||
"label": "text to display:",
|
||||
"description": "By default the current filename will be displayed on the LCD. Enter text here to override the filename and display something else.",
|
||||
"type": "str",
|
||||
"default_value": ""
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
def execute(self, data):
|
||||
if self.getSettingValueByKey("name") != "":
|
||||
name = self.getSettingValueByKey("name")
|
||||
else:
|
||||
name = Application.getInstance().getPrintInformation().jobName
|
||||
lcd_text = "M117 " + name + " layer: "
|
||||
i = 0
|
||||
for layer in data:
|
||||
display_text = lcd_text + str(i)
|
||||
layer_index = data.index(layer)
|
||||
lines = layer.split("\n")
|
||||
for line in lines:
|
||||
if line.startswith(";LAYER:"):
|
||||
line_index = lines.index(line)
|
||||
lines.insert(line_index + 1, display_text)
|
||||
i += 1
|
||||
final_lines = "\n".join(lines)
|
||||
data[layer_index] = final_lines
|
||||
|
||||
return data
|
|
@ -0,0 +1,51 @@
|
|||
from ..Script import Script
|
||||
|
||||
class PauseAtHeightRepRapFirmwareDuet(Script):
|
||||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Pause at height for RepRapFirmware DuetWifi / Duet Ethernet / Duet Maestro",
|
||||
"key": "PauseAtHeightRepRapFirmwareDuet",
|
||||
"metadata": {},
|
||||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"pause_height":
|
||||
{
|
||||
"label": "Pause height",
|
||||
"description": "At what height should the pause occur",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 5.0
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
def execute(self, data):
|
||||
current_z = 0.
|
||||
pause_z = self.getSettingValueByKey("pause_height")
|
||||
|
||||
layers_started = False
|
||||
for layer_number, layer in enumerate(data):
|
||||
lines = layer.split("\n")
|
||||
for line in lines:
|
||||
if ";LAYER:0" in line:
|
||||
layers_started = True
|
||||
continue
|
||||
|
||||
if not layers_started:
|
||||
continue
|
||||
|
||||
if self.getValue(line, 'G') == 1 or self.getValue(line, 'G') == 0:
|
||||
current_z = self.getValue(line, 'Z')
|
||||
if current_z != None:
|
||||
if current_z >= pause_z:
|
||||
prepend_gcode = ";TYPE:CUSTOM\n"
|
||||
prepend_gcode += "; -- Pause at height (%.2f mm) --\n" % pause_z
|
||||
prepend_gcode += self.putValue(M = 226) + "\n"
|
||||
layer = prepend_gcode + layer
|
||||
|
||||
data[layer_number] = layer # Override the data of this layer with the modified data
|
||||
return data
|
||||
break
|
||||
return data
|
|
@ -18,10 +18,13 @@ from UM.Platform import Platform
|
|||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.Resources import Resources
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Signal import Signal
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
from UM.View.GL.OpenGLContext import OpenGLContext
|
||||
|
||||
|
||||
from UM.View.View import View
|
||||
from UM.i18n import i18nCatalog
|
||||
from cura.Scene.ConvexHullNode import ConvexHullNode
|
||||
|
@ -30,11 +33,20 @@ from cura.CuraApplication import CuraApplication
|
|||
from .NozzleNode import NozzleNode
|
||||
from .SimulationPass import SimulationPass
|
||||
from .SimulationViewProxy import SimulationViewProxy
|
||||
import numpy
|
||||
import os.path
|
||||
|
||||
from typing import Optional, TYPE_CHECKING, List
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Scene.Scene import Scene
|
||||
from UM.View.GL.ShaderProgram import ShaderProgram
|
||||
from UM.View.RenderPass import RenderPass
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
import numpy
|
||||
import os.path
|
||||
|
||||
## View used to display g-code paths.
|
||||
class SimulationView(View):
|
||||
|
@ -44,7 +56,7 @@ class SimulationView(View):
|
|||
LAYER_VIEW_TYPE_FEEDRATE = 2
|
||||
LAYER_VIEW_TYPE_THICKNESS = 3
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
self._max_layers = 0
|
||||
|
@ -64,21 +76,21 @@ class SimulationView(View):
|
|||
self._busy = False
|
||||
self._simulation_running = False
|
||||
|
||||
self._ghost_shader = None
|
||||
self._layer_pass = None
|
||||
self._composite_pass = None
|
||||
self._ghost_shader = None # type: Optional["ShaderProgram"]
|
||||
self._layer_pass = None # type: Optional[SimulationPass]
|
||||
self._composite_pass = None # type: Optional[RenderPass]
|
||||
self._old_layer_bindings = None
|
||||
self._simulationview_composite_shader = None
|
||||
self._simulationview_composite_shader = None # type: Optional["ShaderProgram"]
|
||||
self._old_composite_shader = None
|
||||
|
||||
self._global_container_stack = None
|
||||
self._global_container_stack = None # type: Optional[ContainerStack]
|
||||
self._proxy = SimulationViewProxy()
|
||||
self._controller.getScene().getRoot().childrenChanged.connect(self._onSceneChanged)
|
||||
|
||||
self._resetSettings()
|
||||
self._legend_items = None
|
||||
self._show_travel_moves = False
|
||||
self._nozzle_node = None
|
||||
self._nozzle_node = None # type: Optional[NozzleNode]
|
||||
|
||||
Application.getInstance().getPreferences().addPreference("view/top_layer_count", 5)
|
||||
Application.getInstance().getPreferences().addPreference("view/only_show_top_layers", False)
|
||||
|
@ -102,29 +114,29 @@ class SimulationView(View):
|
|||
self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled"),
|
||||
title = catalog.i18nc("@info:title", "Simulation View"))
|
||||
|
||||
def _evaluateCompatibilityMode(self):
|
||||
def _evaluateCompatibilityMode(self) -> bool:
|
||||
return OpenGLContext.isLegacyOpenGL() or bool(Application.getInstance().getPreferences().getValue("view/force_layer_view_compatibility_mode"))
|
||||
|
||||
def _resetSettings(self):
|
||||
self._layer_view_type = 0 # 0 is material color, 1 is color by linetype, 2 is speed, 3 is layer thickness
|
||||
def _resetSettings(self) -> None:
|
||||
self._layer_view_type = 0 # type: int # 0 is material color, 1 is color by linetype, 2 is speed, 3 is layer thickness
|
||||
self._extruder_count = 0
|
||||
self._extruder_opacity = [1.0, 1.0, 1.0, 1.0]
|
||||
self._show_travel_moves = 0
|
||||
self._show_helpers = 1
|
||||
self._show_skin = 1
|
||||
self._show_infill = 1
|
||||
self._show_travel_moves = False
|
||||
self._show_helpers = True
|
||||
self._show_skin = True
|
||||
self._show_infill = True
|
||||
self.resetLayerData()
|
||||
|
||||
def getActivity(self):
|
||||
def getActivity(self) -> bool:
|
||||
return self._activity
|
||||
|
||||
def setActivity(self, activity):
|
||||
def setActivity(self, activity: bool) -> None:
|
||||
if self._activity == activity:
|
||||
return
|
||||
self._activity = activity
|
||||
self.activityChanged.emit()
|
||||
|
||||
def getSimulationPass(self):
|
||||
def getSimulationPass(self) -> SimulationPass:
|
||||
if not self._layer_pass:
|
||||
# Currently the RenderPass constructor requires a size > 0
|
||||
# This should be fixed in RenderPass's constructor.
|
||||
|
@ -133,30 +145,30 @@ class SimulationView(View):
|
|||
self._layer_pass.setSimulationView(self)
|
||||
return self._layer_pass
|
||||
|
||||
def getCurrentLayer(self):
|
||||
def getCurrentLayer(self) -> int:
|
||||
return self._current_layer_num
|
||||
|
||||
def getMinimumLayer(self):
|
||||
def getMinimumLayer(self) -> int:
|
||||
return self._minimum_layer_num
|
||||
|
||||
def getMaxLayers(self):
|
||||
def getMaxLayers(self) -> int:
|
||||
return self._max_layers
|
||||
|
||||
def getCurrentPath(self):
|
||||
def getCurrentPath(self) -> int:
|
||||
return self._current_path_num
|
||||
|
||||
def getMinimumPath(self):
|
||||
def getMinimumPath(self) -> int:
|
||||
return self._minimum_path_num
|
||||
|
||||
def getMaxPaths(self):
|
||||
def getMaxPaths(self) -> int:
|
||||
return self._max_paths
|
||||
|
||||
def getNozzleNode(self):
|
||||
def getNozzleNode(self) -> NozzleNode:
|
||||
if not self._nozzle_node:
|
||||
self._nozzle_node = NozzleNode()
|
||||
return self._nozzle_node
|
||||
|
||||
def _onSceneChanged(self, node):
|
||||
def _onSceneChanged(self, node: "SceneNode") -> None:
|
||||
if node.getMeshData() is None:
|
||||
self.resetLayerData()
|
||||
|
||||
|
@ -164,21 +176,21 @@ class SimulationView(View):
|
|||
self.calculateMaxLayers()
|
||||
self.calculateMaxPathsOnLayer(self._current_layer_num)
|
||||
|
||||
def isBusy(self):
|
||||
def isBusy(self) -> bool:
|
||||
return self._busy
|
||||
|
||||
def setBusy(self, busy):
|
||||
def setBusy(self, busy: bool) -> None:
|
||||
if busy != self._busy:
|
||||
self._busy = busy
|
||||
self.busyChanged.emit()
|
||||
|
||||
def isSimulationRunning(self):
|
||||
def isSimulationRunning(self) -> bool:
|
||||
return self._simulation_running
|
||||
|
||||
def setSimulationRunning(self, running):
|
||||
def setSimulationRunning(self, running: bool) -> None:
|
||||
self._simulation_running = running
|
||||
|
||||
def resetLayerData(self):
|
||||
def resetLayerData(self) -> None:
|
||||
self._current_layer_mesh = None
|
||||
self._current_layer_jumps = None
|
||||
self._max_feedrate = sys.float_info.min
|
||||
|
@ -186,7 +198,7 @@ class SimulationView(View):
|
|||
self._max_thickness = sys.float_info.min
|
||||
self._min_thickness = sys.float_info.max
|
||||
|
||||
def beginRendering(self):
|
||||
def beginRendering(self) -> None:
|
||||
scene = self.getController().getScene()
|
||||
renderer = self.getRenderer()
|
||||
|
||||
|
@ -204,7 +216,7 @@ class SimulationView(View):
|
|||
if (node.getMeshData()) and node.isVisible():
|
||||
renderer.queueNode(node, transparent = True, shader = self._ghost_shader)
|
||||
|
||||
def setLayer(self, value):
|
||||
def setLayer(self, value: int) -> None:
|
||||
if self._current_layer_num != value:
|
||||
self._current_layer_num = value
|
||||
if self._current_layer_num < 0:
|
||||
|
@ -218,7 +230,7 @@ class SimulationView(View):
|
|||
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
def setMinimumLayer(self, value):
|
||||
def setMinimumLayer(self, value: int) -> None:
|
||||
if self._minimum_layer_num != value:
|
||||
self._minimum_layer_num = value
|
||||
if self._minimum_layer_num < 0:
|
||||
|
@ -232,7 +244,7 @@ class SimulationView(View):
|
|||
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
def setPath(self, value):
|
||||
def setPath(self, value: int) -> None:
|
||||
if self._current_path_num != value:
|
||||
self._current_path_num = value
|
||||
if self._current_path_num < 0:
|
||||
|
@ -246,7 +258,7 @@ class SimulationView(View):
|
|||
|
||||
self.currentPathNumChanged.emit()
|
||||
|
||||
def setMinimumPath(self, value):
|
||||
def setMinimumPath(self, value: int) -> None:
|
||||
if self._minimum_path_num != value:
|
||||
self._minimum_path_num = value
|
||||
if self._minimum_path_num < 0:
|
||||
|
@ -263,24 +275,24 @@ class SimulationView(View):
|
|||
## Set the layer view type
|
||||
#
|
||||
# \param layer_view_type integer as in SimulationView.qml and this class
|
||||
def setSimulationViewType(self, layer_view_type):
|
||||
def setSimulationViewType(self, layer_view_type: int) -> None:
|
||||
self._layer_view_type = layer_view_type
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
## Return the layer view type, integer as in SimulationView.qml and this class
|
||||
def getSimulationViewType(self):
|
||||
def getSimulationViewType(self) -> int:
|
||||
return self._layer_view_type
|
||||
|
||||
## Set the extruder opacity
|
||||
#
|
||||
# \param extruder_nr 0..3
|
||||
# \param opacity 0.0 .. 1.0
|
||||
def setExtruderOpacity(self, extruder_nr, opacity):
|
||||
def setExtruderOpacity(self, extruder_nr: int, opacity: float) -> None:
|
||||
if 0 <= extruder_nr <= 3:
|
||||
self._extruder_opacity[extruder_nr] = opacity
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
def getExtruderOpacities(self):
|
||||
def getExtruderOpacities(self)-> List[float]:
|
||||
return self._extruder_opacity
|
||||
|
||||
def setShowTravelMoves(self, show):
|
||||
|
@ -290,46 +302,46 @@ class SimulationView(View):
|
|||
def getShowTravelMoves(self):
|
||||
return self._show_travel_moves
|
||||
|
||||
def setShowHelpers(self, show):
|
||||
def setShowHelpers(self, show: bool) -> None:
|
||||
self._show_helpers = show
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
def getShowHelpers(self):
|
||||
def getShowHelpers(self) -> bool:
|
||||
return self._show_helpers
|
||||
|
||||
def setShowSkin(self, show):
|
||||
def setShowSkin(self, show: bool) -> None:
|
||||
self._show_skin = show
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
def getShowSkin(self):
|
||||
def getShowSkin(self) -> bool:
|
||||
return self._show_skin
|
||||
|
||||
def setShowInfill(self, show):
|
||||
def setShowInfill(self, show: bool) -> None:
|
||||
self._show_infill = show
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
def getShowInfill(self):
|
||||
def getShowInfill(self) -> bool:
|
||||
return self._show_infill
|
||||
|
||||
def getCompatibilityMode(self):
|
||||
def getCompatibilityMode(self) -> bool:
|
||||
return self._compatibility_mode
|
||||
|
||||
def getExtruderCount(self):
|
||||
def getExtruderCount(self) -> int:
|
||||
return self._extruder_count
|
||||
|
||||
def getMinFeedrate(self):
|
||||
def getMinFeedrate(self) -> float:
|
||||
return self._min_feedrate
|
||||
|
||||
def getMaxFeedrate(self):
|
||||
def getMaxFeedrate(self) -> float:
|
||||
return self._max_feedrate
|
||||
|
||||
def getMinThickness(self):
|
||||
def getMinThickness(self) -> float:
|
||||
return self._min_thickness
|
||||
|
||||
def getMaxThickness(self):
|
||||
def getMaxThickness(self) -> float:
|
||||
return self._max_thickness
|
||||
|
||||
def calculateMaxLayers(self):
|
||||
def calculateMaxLayers(self) -> None:
|
||||
scene = self.getController().getScene()
|
||||
|
||||
self._old_max_layers = self._max_layers
|
||||
|
@ -383,7 +395,7 @@ class SimulationView(View):
|
|||
self.maxLayersChanged.emit()
|
||||
self._startUpdateTopLayers()
|
||||
|
||||
def calculateMaxPathsOnLayer(self, layer_num):
|
||||
def calculateMaxPathsOnLayer(self, layer_num: int) -> None:
|
||||
# Update the currentPath
|
||||
scene = self.getController().getScene()
|
||||
for node in DepthFirstIterator(scene.getRoot()):
|
||||
|
@ -415,10 +427,10 @@ class SimulationView(View):
|
|||
def getProxy(self, engine, script_engine):
|
||||
return self._proxy
|
||||
|
||||
def endRendering(self):
|
||||
def endRendering(self) -> None:
|
||||
pass
|
||||
|
||||
def event(self, event):
|
||||
def event(self, event) -> bool:
|
||||
modifiers = QApplication.keyboardModifiers()
|
||||
ctrl_is_active = modifiers & Qt.ControlModifier
|
||||
shift_is_active = modifiers & Qt.ShiftModifier
|
||||
|
@ -447,7 +459,7 @@ class SimulationView(View):
|
|||
if QOpenGLContext.currentContext() is None:
|
||||
Logger.log("d", "current context of OpenGL is empty on Mac OS X, will try to create shaders later")
|
||||
CuraApplication.getInstance().callLater(lambda e=event: self.event(e))
|
||||
return
|
||||
return False
|
||||
|
||||
# Make sure the SimulationPass is created
|
||||
layer_pass = self.getSimulationPass()
|
||||
|
@ -480,11 +492,14 @@ class SimulationView(View):
|
|||
Application.getInstance().globalContainerStackChanged.disconnect(self._onGlobalStackChanged)
|
||||
if self._global_container_stack:
|
||||
self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
|
||||
|
||||
self._nozzle_node.setParent(None)
|
||||
if self._nozzle_node:
|
||||
self._nozzle_node.setParent(None)
|
||||
self.getRenderer().removeRenderPass(self._layer_pass)
|
||||
self._composite_pass.setLayerBindings(self._old_layer_bindings)
|
||||
self._composite_pass.setCompositeShader(self._old_composite_shader)
|
||||
if self._composite_pass:
|
||||
self._composite_pass.setLayerBindings(self._old_layer_bindings)
|
||||
self._composite_pass.setCompositeShader(self._old_composite_shader)
|
||||
|
||||
return False
|
||||
|
||||
def getCurrentLayerMesh(self):
|
||||
return self._current_layer_mesh
|
||||
|
@ -492,7 +507,7 @@ class SimulationView(View):
|
|||
def getCurrentLayerJumps(self):
|
||||
return self._current_layer_jumps
|
||||
|
||||
def _onGlobalStackChanged(self):
|
||||
def _onGlobalStackChanged(self) -> None:
|
||||
if self._global_container_stack:
|
||||
self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
|
||||
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
|
@ -504,17 +519,17 @@ class SimulationView(View):
|
|||
else:
|
||||
self._wireprint_warning_message.hide()
|
||||
|
||||
def _onPropertyChanged(self, key, property_name):
|
||||
def _onPropertyChanged(self, key: str, property_name: str) -> None:
|
||||
if key == "wireframe_enabled" and property_name == "value":
|
||||
if self._global_container_stack.getProperty("wireframe_enabled", "value"):
|
||||
if self._global_container_stack and self._global_container_stack.getProperty("wireframe_enabled", "value"):
|
||||
self._wireprint_warning_message.show()
|
||||
else:
|
||||
self._wireprint_warning_message.hide()
|
||||
|
||||
def _onCurrentLayerNumChanged(self):
|
||||
def _onCurrentLayerNumChanged(self) -> None:
|
||||
self.calculateMaxPathsOnLayer(self._current_layer_num)
|
||||
|
||||
def _startUpdateTopLayers(self):
|
||||
def _startUpdateTopLayers(self) -> None:
|
||||
if not self._compatibility_mode:
|
||||
return
|
||||
|
||||
|
@ -525,10 +540,10 @@ class SimulationView(View):
|
|||
self.setBusy(True)
|
||||
|
||||
self._top_layers_job = _CreateTopLayersJob(self._controller.getScene(), self._current_layer_num, self._solid_layers)
|
||||
self._top_layers_job.finished.connect(self._updateCurrentLayerMesh)
|
||||
self._top_layers_job.start()
|
||||
self._top_layers_job.finished.connect(self._updateCurrentLayerMesh) # type: ignore # mypy doesn't understand the whole private class thing that's going on here.
|
||||
self._top_layers_job.start() # type: ignore
|
||||
|
||||
def _updateCurrentLayerMesh(self, job):
|
||||
def _updateCurrentLayerMesh(self, job: "_CreateTopLayersJob") -> None:
|
||||
self.setBusy(False)
|
||||
|
||||
if not job.getResult():
|
||||
|
@ -539,9 +554,9 @@ class SimulationView(View):
|
|||
self._current_layer_jumps = job.getResult().get("jumps")
|
||||
self._controller.getScene().sceneChanged.emit(self._controller.getScene().getRoot())
|
||||
|
||||
self._top_layers_job = None
|
||||
self._top_layers_job = None # type: Optional["_CreateTopLayersJob"]
|
||||
|
||||
def _updateWithPreferences(self):
|
||||
def _updateWithPreferences(self) -> None:
|
||||
self._solid_layers = int(Application.getInstance().getPreferences().getValue("view/top_layer_count"))
|
||||
self._only_show_top_layers = bool(Application.getInstance().getPreferences().getValue("view/only_show_top_layers"))
|
||||
self._compatibility_mode = self._evaluateCompatibilityMode()
|
||||
|
@ -563,7 +578,7 @@ class SimulationView(View):
|
|||
self._startUpdateTopLayers()
|
||||
self.preferencesChanged.emit()
|
||||
|
||||
def _onPreferencesChanged(self, preference):
|
||||
def _onPreferencesChanged(self, preference: str) -> None:
|
||||
if preference not in {
|
||||
"view/top_layer_count",
|
||||
"view/only_show_top_layers",
|
||||
|
@ -581,7 +596,7 @@ class SimulationView(View):
|
|||
|
||||
|
||||
class _CreateTopLayersJob(Job):
|
||||
def __init__(self, scene, layer_number, solid_layers):
|
||||
def __init__(self, scene: "Scene", layer_number: int, solid_layers: int) -> None:
|
||||
super().__init__()
|
||||
|
||||
self._scene = scene
|
||||
|
@ -589,7 +604,7 @@ class _CreateTopLayersJob(Job):
|
|||
self._solid_layers = solid_layers
|
||||
self._cancel = False
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
layer_data = None
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
layer_data = node.callDecoration("getLayerData")
|
||||
|
@ -638,6 +653,6 @@ class _CreateTopLayersJob(Job):
|
|||
|
||||
self.setResult({"layers": layer_mesh.build(), "jumps": jump_mesh})
|
||||
|
||||
def cancel(self):
|
||||
def cancel(self) -> None:
|
||||
self._cancel = True
|
||||
super().cancel()
|
||||
|
|
|
@ -256,6 +256,7 @@ fragment41core =
|
|||
out vec4 frag_color;
|
||||
|
||||
uniform mediump vec4 u_ambientColor;
|
||||
uniform mediump vec4 u_minimumAlbedo;
|
||||
uniform highp vec3 u_lightPosition;
|
||||
|
||||
void main()
|
||||
|
@ -263,7 +264,7 @@ fragment41core =
|
|||
mediump vec4 finalColor = vec4(0.0);
|
||||
float alpha = f_color.a;
|
||||
|
||||
finalColor.rgb += f_color.rgb * 0.3;
|
||||
finalColor.rgb += f_color.rgb * 0.2 + u_minimumAlbedo.rgb;
|
||||
|
||||
highp vec3 normal = normalize(f_normal);
|
||||
highp vec3 light_dir = normalize(u_lightPosition - f_vertex);
|
||||
|
@ -285,6 +286,7 @@ u_extruder_opacity = [1.0, 1.0, 1.0, 1.0]
|
|||
u_specularColor = [0.4, 0.4, 0.4, 1.0]
|
||||
u_ambientColor = [0.3, 0.3, 0.3, 0.0]
|
||||
u_diffuseColor = [1.0, 0.79, 0.14, 1.0]
|
||||
u_minimumAlbedo = [0.1, 0.1, 0.1, 1.0]
|
||||
u_shininess = 20.0
|
||||
|
||||
u_show_travel_moves = 0
|
||||
|
|
|
@ -33,30 +33,35 @@ class SliceInfo(QObject, Extension):
|
|||
def __init__(self, parent = None):
|
||||
QObject.__init__(self, parent)
|
||||
Extension.__init__(self)
|
||||
Application.getInstance().getOutputDeviceManager().writeStarted.connect(self._onWriteStarted)
|
||||
Application.getInstance().getPreferences().addPreference("info/send_slice_info", True)
|
||||
Application.getInstance().getPreferences().addPreference("info/asked_send_slice_info", False)
|
||||
|
||||
self._application = Application.getInstance()
|
||||
|
||||
self._application.getOutputDeviceManager().writeStarted.connect(self._onWriteStarted)
|
||||
self._application.getPreferences().addPreference("info/send_slice_info", True)
|
||||
self._application.getPreferences().addPreference("info/asked_send_slice_info", False)
|
||||
|
||||
self._more_info_dialog = None
|
||||
self._example_data_content = None
|
||||
|
||||
if not Application.getInstance().getPreferences().getValue("info/asked_send_slice_info"):
|
||||
self._application.initializationFinished.connect(self._onAppInitialized)
|
||||
|
||||
def _onAppInitialized(self):
|
||||
# DO NOT read any preferences values in the constructor because at the time plugins are created, no version
|
||||
# upgrade has been performed yet because version upgrades are plugins too!
|
||||
if not self._application.getPreferences().getValue("info/asked_send_slice_info"):
|
||||
self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura collects anonymized usage statistics."),
|
||||
lifetime = 0,
|
||||
dismissable = False,
|
||||
title = catalog.i18nc("@info:title", "Collecting Data"))
|
||||
|
||||
self.send_slice_info_message.addAction("MoreInfo", name = catalog.i18nc("@action:button", "More info"), icon = None,
|
||||
description = catalog.i18nc("@action:tooltip", "See more information on what data Cura sends."), button_style = Message.ActionButtonStyle.LINK)
|
||||
description = catalog.i18nc("@action:tooltip", "See more information on what data Cura sends."), button_style = Message.ActionButtonStyle.LINK)
|
||||
|
||||
self.send_slice_info_message.addAction("Dismiss", name = catalog.i18nc("@action:button", "Allow"), icon = None,
|
||||
description = catalog.i18nc("@action:tooltip", "Allow Cura to send anonymized usage statistics to help prioritize future improvements to Cura. Some of your preferences and settings are sent, the Cura version and a hash of the models you're slicing."))
|
||||
description = catalog.i18nc("@action:tooltip", "Allow Cura to send anonymized usage statistics to help prioritize future improvements to Cura. Some of your preferences and settings are sent, the Cura version and a hash of the models you're slicing."))
|
||||
self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered)
|
||||
self.send_slice_info_message.show()
|
||||
|
||||
Application.getInstance().initializationFinished.connect(self._onAppInitialized)
|
||||
|
||||
def _onAppInitialized(self):
|
||||
if self._more_info_dialog is None:
|
||||
self._more_info_dialog = self._createDialog("MoreInfoWindow.qml")
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ Window
|
|||
{
|
||||
id: header
|
||||
}
|
||||
|
||||
Item
|
||||
{
|
||||
id: mainView
|
||||
|
@ -75,6 +76,7 @@ Window
|
|||
visible: toolbox.viewCategory == "installed"
|
||||
}
|
||||
}
|
||||
|
||||
ToolboxFooter
|
||||
{
|
||||
id: footer
|
||||
|
|
|
@ -15,7 +15,7 @@ Item
|
|||
{
|
||||
id: sidebar
|
||||
}
|
||||
Rectangle
|
||||
Item
|
||||
{
|
||||
id: header
|
||||
anchors
|
||||
|
|
|
@ -23,6 +23,7 @@ Item
|
|||
{
|
||||
id: button
|
||||
text: catalog.i18nc("@action:button", "Back")
|
||||
enabled: !toolbox.isDownloading
|
||||
UM.RecolorImage
|
||||
{
|
||||
id: backArrow
|
||||
|
@ -39,7 +40,7 @@ Item
|
|||
width: width
|
||||
height: height
|
||||
}
|
||||
color: button.hovered ? UM.Theme.getColor("primary") : UM.Theme.getColor("text")
|
||||
color: button.enabled ? (button.hovered ? UM.Theme.getColor("primary") : UM.Theme.getColor("text")) : UM.Theme.getColor("text_inactive")
|
||||
source: UM.Theme.getIcon("arrow_left")
|
||||
}
|
||||
width: UM.Theme.getSize("toolbox_back_button").width
|
||||
|
@ -59,7 +60,7 @@ Item
|
|||
{
|
||||
id: labelStyle
|
||||
text: control.text
|
||||
color: control.hovered ? UM.Theme.getColor("primary") : UM.Theme.getColor("text")
|
||||
color: control.enabled ? (control.hovered ? UM.Theme.getColor("primary") : UM.Theme.getColor("text")) : UM.Theme.getColor("text_inactive")
|
||||
font: UM.Theme.getFont("default_bold")
|
||||
horizontalAlignment: Text.AlignRight
|
||||
width: control.width
|
||||
|
|
|
@ -9,9 +9,8 @@ import UM 1.1 as UM
|
|||
Item
|
||||
{
|
||||
id: page
|
||||
property var details: base.selection
|
||||
property var details: base.selection || {}
|
||||
anchors.fill: parent
|
||||
width: parent.width
|
||||
ToolboxBackColumn
|
||||
{
|
||||
id: sidebar
|
||||
|
|
|
@ -9,6 +9,7 @@ import UM 1.1 as UM
|
|||
|
||||
Item
|
||||
{
|
||||
id: toolboxDownloadsGridTile
|
||||
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
|
||||
|
|
|
@ -21,11 +21,13 @@ Item
|
|||
left: parent.left
|
||||
leftMargin: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
|
||||
ToolboxTabButton
|
||||
{
|
||||
id: pluginsTabButton
|
||||
text: catalog.i18nc("@title:tab", "Plugins")
|
||||
active: toolbox.viewCategory == "plugin" && enabled
|
||||
enabled: toolbox.viewPage != "loading" && toolbox.viewPage != "errored"
|
||||
enabled: !toolbox.isDownloading && toolbox.viewPage != "loading" && toolbox.viewPage != "errored"
|
||||
onClicked:
|
||||
{
|
||||
toolbox.filterModelByProp("packages", "type", "plugin")
|
||||
|
@ -34,12 +36,12 @@ Item
|
|||
}
|
||||
}
|
||||
|
||||
/* // NOTE: Remember to re-enable for v3.6!
|
||||
ToolboxTabButton
|
||||
{
|
||||
id: materialsTabButton
|
||||
text: catalog.i18nc("@title:tab", "Materials")
|
||||
active: toolbox.viewCategory == "material" && enabled
|
||||
enabled: toolbox.viewPage != "loading" && toolbox.viewPage != "errored"
|
||||
enabled: !toolbox.isDownloading && toolbox.viewPage != "loading" && toolbox.viewPage != "errored"
|
||||
onClicked:
|
||||
{
|
||||
toolbox.filterModelByProp("authors", "package_types", "material")
|
||||
|
@ -47,12 +49,13 @@ Item
|
|||
toolbox.viewPage = "overview"
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
ToolboxTabButton
|
||||
{
|
||||
id: installedTabButton
|
||||
text: catalog.i18nc("@title:tab", "Installed")
|
||||
active: toolbox.viewCategory == "installed"
|
||||
enabled: !toolbox.isDownloading
|
||||
anchors
|
||||
{
|
||||
right: parent.right
|
||||
|
|
|
@ -603,7 +603,7 @@ class Toolbox(QObject, Extension):
|
|||
|
||||
@pyqtSlot()
|
||||
def cancelDownload(self) -> None:
|
||||
Logger.log("i", "Toolbox: User cancelled the download of a plugin.")
|
||||
Logger.log("i", "Toolbox: User cancelled the download of a package.")
|
||||
self.resetDownload()
|
||||
|
||||
def resetDownload(self) -> None:
|
||||
|
@ -755,6 +755,7 @@ class Toolbox(QObject, Extension):
|
|||
self._active_package = package
|
||||
self.activePackageChanged.emit()
|
||||
|
||||
## The active package is the package that is currently being downloaded
|
||||
@pyqtProperty(QObject, fset = setActivePackage, notify = activePackageChanged)
|
||||
def activePackage(self) -> Optional[Dict[str, Any]]:
|
||||
return self._active_package
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#Copyright (c) 2018 Ultimaker B.V.
|
||||
#Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from typing import cast
|
||||
|
||||
from Charon.VirtualFile import VirtualFile #To open UFP files.
|
||||
|
@ -9,6 +10,7 @@ from io import StringIO #For converting g-code to bytes.
|
|||
from UM.Application import Application
|
||||
from UM.Logger import Logger
|
||||
from UM.Mesh.MeshWriter import MeshWriter #The writer we need to implement.
|
||||
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
|
||||
from UM.PluginRegistry import PluginRegistry #To get the g-code writer.
|
||||
from PyQt5.QtCore import QBuffer
|
||||
|
||||
|
@ -22,6 +24,15 @@ catalog = i18nCatalog("cura")
|
|||
class UFPWriter(MeshWriter):
|
||||
def __init__(self):
|
||||
super().__init__(add_to_recent_files = False)
|
||||
|
||||
MimeTypeDatabase.addMimeType(
|
||||
MimeType(
|
||||
name = "application/x-cura-stl-file",
|
||||
comment = "Cura UFP File",
|
||||
suffixes = ["ufp"]
|
||||
)
|
||||
)
|
||||
|
||||
self._snapshot = None
|
||||
Application.getInstance().getOutputDeviceManager().writeStarted.connect(self._createSnapshot)
|
||||
|
||||
|
|
|
@ -11,16 +11,6 @@ except ImportError:
|
|||
|
||||
from UM.i18n import i18nCatalog #To translate the file format description.
|
||||
from UM.Mesh.MeshWriter import MeshWriter #For the binary mode flag.
|
||||
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
|
||||
|
||||
|
||||
MimeTypeDatabase.addMimeType(
|
||||
MimeType(
|
||||
name = "application/x-cura-stl-file",
|
||||
comment = "Cura UFP File",
|
||||
suffixes = ["ufp"]
|
||||
)
|
||||
)
|
||||
|
||||
i18n_catalog = i18nCatalog("cura")
|
||||
|
||||
|
|
|
@ -260,6 +260,19 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
|
|||
# or "Legacy" UM3 device.
|
||||
cluster_size = int(properties.get(b"cluster_size", -1))
|
||||
|
||||
printer_type = properties.get(b"machine", b"").decode("utf-8")
|
||||
printer_type_identifiers = {
|
||||
"9066": "ultimaker3",
|
||||
"9511": "ultimaker3_extended",
|
||||
"9051": "ultimaker_s5"
|
||||
}
|
||||
|
||||
for key, value in printer_type_identifiers.items():
|
||||
if printer_type.startswith(key):
|
||||
properties[b"printer_type"] = bytes(value, encoding="utf8")
|
||||
break
|
||||
else:
|
||||
properties[b"printer_type"] = b"Unknown"
|
||||
if cluster_size >= 0:
|
||||
device = ClusterUM3OutputDevice.ClusterUM3OutputDevice(name, address, properties)
|
||||
else:
|
||||
|
|
|
@ -86,6 +86,12 @@ class VersionUpgrade34to35(VersionUpgrade):
|
|||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(serialized)
|
||||
|
||||
# Need to show the data collection agreement again because the data Cura collects has been changed.
|
||||
if parser.has_option("info", "asked_send_slice_info"):
|
||||
parser.set("info", "asked_send_slice_info", "False")
|
||||
if parser.has_option("info", "send_slice_info"):
|
||||
parser.set("info", "send_slice_info", "True")
|
||||
|
||||
# Update version number.
|
||||
parser["general"]["version"] = "6"
|
||||
if "metadata" not in parser:
|
||||
|
|
|
@ -17,6 +17,10 @@ test_upgrade_version_nr_data = [
|
|||
version = 5
|
||||
[metadata]
|
||||
setting_version = 4
|
||||
|
||||
[info]
|
||||
asked_send_slice_info = True
|
||||
send_slice_info = True
|
||||
"""
|
||||
)
|
||||
]
|
||||
|
@ -32,4 +36,8 @@ def test_upgradeVersionNr(test_name, file_data, upgrader):
|
|||
|
||||
#Check the new version.
|
||||
assert parser["general"]["version"] == "6"
|
||||
assert parser["metadata"]["setting_version"] == "5"
|
||||
assert parser["metadata"]["setting_version"] == "5"
|
||||
|
||||
# Check if the data collection values have been reset to their defaults
|
||||
assert parser.get("info", "asked_send_slice_info") == "False"
|
||||
assert parser.get("info", "send_slice_info") == "True"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue