CURA-4525 solved merge conflicts

This commit is contained in:
Jack Ha 2018-01-03 13:52:55 +01:00
commit bfa33c721c
39 changed files with 11005 additions and 337 deletions

70
Jenkinsfile vendored
View file

@ -1,45 +1,47 @@
parallel_nodes(['linux && cura', 'windows && cura']) { timeout(time: 2, unit: "HOURS") {
// Prepare building parallel_nodes(['linux && cura', 'windows && cura']) {
stage('Prepare') { // Prepare building
// Ensure we start with a clean build directory. stage('Prepare') {
step([$class: 'WsCleanup']) // Ensure we start with a clean build directory.
step([$class: 'WsCleanup'])
// Checkout whatever sources are linked to this pipeline. // Checkout whatever sources are linked to this pipeline.
checkout scm checkout scm
} }
// If any error occurs during building, we want to catch it and continue with the "finale" stage. // If any error occurs during building, we want to catch it and continue with the "finale" stage.
catchError { catchError {
// Building and testing should happen in a subdirectory. // Building and testing should happen in a subdirectory.
dir('build') { dir('build') {
// Perform the "build". Since Uranium is Python code, this basically only ensures CMake is setup. // Perform the "build". Since Uranium is Python code, this basically only ensures CMake is setup.
stage('Build') { stage('Build') {
def branch = env.BRANCH_NAME def branch = env.BRANCH_NAME
if(!fileExists("${env.CURA_ENVIRONMENT_PATH}/${branch}")) { if(!fileExists("${env.CURA_ENVIRONMENT_PATH}/${branch}")) {
branch = "master" branch = "master"
}
// Ensure CMake is setup. Note that since this is Python code we do not really "build" it.
def uranium_dir = get_workspace_dir("Ultimaker/Uranium/${branch}")
cmake("..", "-DCMAKE_PREFIX_PATH=\"${env.CURA_ENVIRONMENT_PATH}/${branch}\" -DCMAKE_BUILD_TYPE=Release -DURANIUM_DIR=\"${uranium_dir}\"")
} }
// Ensure CMake is setup. Note that since this is Python code we do not really "build" it. // Try and run the unit tests. If this stage fails, we consider the build to be "unstable".
def uranium_dir = get_workspace_dir("Ultimaker/Uranium/${branch}") stage('Unit Test') {
cmake("..", "-DCMAKE_PREFIX_PATH=\"${env.CURA_ENVIRONMENT_PATH}/${branch}\" -DCMAKE_BUILD_TYPE=Release -DURANIUM_DIR=\"${uranium_dir}\"") try {
} make('test')
} catch(e) {
// Try and run the unit tests. If this stage fails, we consider the build to be "unstable". currentBuild.result = "UNSTABLE"
stage('Unit Test') { }
try {
make('test')
} catch(e) {
currentBuild.result = "UNSTABLE"
} }
} }
} }
}
// Perform any post-build actions like notification and publishing of unit tests. // Perform any post-build actions like notification and publishing of unit tests.
stage('Finalize') { stage('Finalize') {
// Publish the test results to Jenkins. // Publish the test results to Jenkins.
junit allowEmptyResults: true, testResults: 'build/junit*.xml' junit allowEmptyResults: true, testResults: 'build/junit*.xml'
notify_build_result(env.CURA_EMAIL_RECIPIENTS, '#cura-dev', ['master', '2.']) notify_build_result(env.CURA_EMAIL_RECIPIENTS, '#cura-dev', ['master', '2.'])
}
} }
} }

View file

@ -24,16 +24,23 @@ function(cura_add_test)
if(WIN32) if(WIN32)
string(REPLACE "|" "\\;" _PYTHONPATH ${_PYTHONPATH}) string(REPLACE "|" "\\;" _PYTHONPATH ${_PYTHONPATH})
set(_PYTHONPATH "${_PYTHONPATH}\\;$ENV{PYTHONPATH}")
else() else()
string(REPLACE "|" ":" _PYTHONPATH ${_PYTHONPATH}) string(REPLACE "|" ":" _PYTHONPATH ${_PYTHONPATH})
set(_PYTHONPATH "${_PYTHONPATH}:$ENV{PYTHONPATH}")
endif() endif()
add_test( get_test_property(${_NAME} ENVIRONMENT test_exists) #Find out if the test exists by getting a property from it that always exists (such as ENVIRONMENT because we set that ourselves).
NAME ${_NAME} if (NOT ${test_exists})
COMMAND ${PYTHON_EXECUTABLE} -m pytest --junitxml=${CMAKE_BINARY_DIR}/junit-${_NAME}.xml ${_DIRECTORY} add_test(
) NAME ${_NAME}
set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT LANG=C) COMMAND ${PYTHON_EXECUTABLE} -m pytest --junitxml=${CMAKE_BINARY_DIR}/junit-${_NAME}.xml ${_DIRECTORY}
set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT "PYTHONPATH=${_PYTHONPATH}") )
set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT LANG=C)
set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT "PYTHONPATH=${_PYTHONPATH}")
else()
message(WARNING "Duplicate test ${_NAME}!")
endif()
endfunction() endfunction()
cura_add_test(NAME pytest-main DIRECTORY ${CMAKE_SOURCE_DIR}/tests PYTHONPATH "${CMAKE_SOURCE_DIR}|${URANIUM_DIR}") cura_add_test(NAME pytest-main DIRECTORY ${CMAKE_SOURCE_DIR}/tests PYTHONPATH "${CMAKE_SOURCE_DIR}|${URANIUM_DIR}")

View file

@ -329,7 +329,7 @@ class CuraApplication(QtApplication):
preferences.addPreference("view/invert_zoom", False) preferences.addPreference("view/invert_zoom", False)
preferences.addPreference("view/filter_current_build_plate", False) preferences.addPreference("view/filter_current_build_plate", False)
preferences.addPreference("cura/sidebar_collapse", False) preferences.addPreference("cura/sidebar_collapsed", False)
self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement") self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement")
@ -422,6 +422,14 @@ class CuraApplication(QtApplication):
else: else:
self.exit(0) self.exit(0)
## Signal to connect preferences action in QML
showPreferencesWindow = pyqtSignal()
## Show the preferences window
@pyqtSlot()
def showPreferences(self):
self.showPreferencesWindow.emit()
## A reusable dialogbox ## A reusable dialogbox
# #
showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"]) showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"])
@ -703,7 +711,7 @@ class CuraApplication(QtApplication):
self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles))
run_without_gui = self.getCommandLineOption("headless", False) or self.getCommandLineOption("invisible", False) run_without_gui = self.getCommandLineOption("headless", False)
if not run_without_gui: if not run_without_gui:
self.initializeEngine() self.initializeEngine()
controller.setActiveStage("PrepareStage") controller.setActiveStage("PrepareStage")
@ -1449,7 +1457,7 @@ class CuraApplication(QtApplication):
if arrange_objects_on_load: if arrange_objects_on_load:
if node.callDecoration("isSliceable"): if node.callDecoration("isSliceable"):
# Only check position if it's not already blatantly obvious that it won't fit. # Only check position if it's not already blatantly obvious that it won't fit.
if node.getBoundingBox().width < self._volume.getBoundingBox().width or node.getBoundingBox().depth < self._volume.getBoundingBox().depth: if node.getBoundingBox() is None or self._volume.getBoundingBox() is None or node.getBoundingBox().width < self._volume.getBoundingBox().width or node.getBoundingBox().depth < self._volume.getBoundingBox().depth:
# Find node location # Find node location
offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(node, min_offset = min_offset) offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(node, min_offset = min_offset)

View file

@ -34,6 +34,7 @@ class PlatformPhysics:
self._change_timer.timeout.connect(self._onChangeTimerFinished) self._change_timer.timeout.connect(self._onChangeTimerFinished)
self._move_factor = 1.1 # By how much should we multiply overlap to calculate a new spot? self._move_factor = 1.1 # By how much should we multiply overlap to calculate a new spot?
self._max_overlap_checks = 10 # How many times should we try to find a new spot per tick? self._max_overlap_checks = 10 # How many times should we try to find a new spot per tick?
self._minimum_gap = 2 # It is a minimum distance between two models, applicable for small models
Preferences.getInstance().addPreference("physics/automatic_push_free", True) Preferences.getInstance().addPreference("physics/automatic_push_free", True)
Preferences.getInstance().addPreference("physics/automatic_drop_down", True) Preferences.getInstance().addPreference("physics/automatic_drop_down", True)
@ -77,7 +78,8 @@ class PlatformPhysics:
if not node.getDecorator(ConvexHullDecorator): if not node.getDecorator(ConvexHullDecorator):
node.addDecorator(ConvexHullDecorator()) node.addDecorator(ConvexHullDecorator())
if Preferences.getInstance().getValue("physics/automatic_push_free"): # only push away objects if this node is a printing mesh
if not node.callDecoration("isNonPrintingMesh") and Preferences.getInstance().getValue("physics/automatic_push_free"):
# Check for collisions between convex hulls # Check for collisions between convex hulls
for other_node in BreadthFirstIterator(root): for other_node in BreadthFirstIterator(root):
# Ignore root, ourselves and anything that is not a normal SceneNode. # Ignore root, ourselves and anything that is not a normal SceneNode.
@ -99,6 +101,9 @@ class PlatformPhysics:
if other_node in transformed_nodes: if other_node in transformed_nodes:
continue # Other node is already moving, wait for next pass. continue # Other node is already moving, wait for next pass.
if other_node.callDecoration("isNonPrintingMesh"):
continue
overlap = (0, 0) # Start loop with no overlap overlap = (0, 0) # Start loop with no overlap
current_overlap_checks = 0 current_overlap_checks = 0
# Continue to check the overlap until we no longer find one. # Continue to check the overlap until we no longer find one.
@ -113,26 +118,41 @@ class PlatformPhysics:
overlap = node.callDecoration("getConvexHull").translate(move_vector.x, move_vector.z).intersectsPolygon(other_head_hull) overlap = node.callDecoration("getConvexHull").translate(move_vector.x, move_vector.z).intersectsPolygon(other_head_hull)
if overlap: if overlap:
# Moving ensured that overlap was still there. Try anew! # Moving ensured that overlap was still there. Try anew!
move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor, move_vector = move_vector.set(x = move_vector.x + overlap[0] * self._move_factor,
z=move_vector.z + overlap[1] * self._move_factor) z = move_vector.z + overlap[1] * self._move_factor)
else: else:
# Moving ensured that overlap was still there. Try anew! # Moving ensured that overlap was still there. Try anew!
move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor, move_vector = move_vector.set(x = move_vector.x + overlap[0] * self._move_factor,
z=move_vector.z + overlap[1] * self._move_factor) z = move_vector.z + overlap[1] * self._move_factor)
else: else:
own_convex_hull = node.callDecoration("getConvexHull") own_convex_hull = node.callDecoration("getConvexHull")
other_convex_hull = other_node.callDecoration("getConvexHull") other_convex_hull = other_node.callDecoration("getConvexHull")
if own_convex_hull and other_convex_hull: if own_convex_hull and other_convex_hull:
overlap = own_convex_hull.translate(move_vector.x, move_vector.z).intersectsPolygon(other_convex_hull) overlap = own_convex_hull.translate(move_vector.x, move_vector.z).intersectsPolygon(other_convex_hull)
if overlap: # Moving ensured that overlap was still there. Try anew! if overlap: # Moving ensured that overlap was still there. Try anew!
move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor, temp_move_vector = move_vector.set(x = move_vector.x + overlap[0] * self._move_factor,
z=move_vector.z + overlap[1] * self._move_factor) z = move_vector.z + overlap[1] * self._move_factor)
# if the distance between two models less than 2mm then try to find a new factor
if abs(temp_move_vector.x - overlap[0]) < self._minimum_gap and abs(temp_move_vector.y - overlap[1]) < self._minimum_gap:
temp_scale_factor = self._move_factor
temp_x_factor = (abs(overlap[0]) + self._minimum_gap) / overlap[0] if overlap[0] != 0 else 0 # find x move_factor, like (3.4 + 2) / 3.4 = 1.58
temp_y_factor = (abs(overlap[1]) + self._minimum_gap) / overlap[1] if overlap[1] != 0 else 0 # find y move_factor
if abs(temp_x_factor) > abs(temp_y_factor):
temp_scale_factor = temp_x_factor
else:
temp_scale_factor = temp_y_factor
move_vector = move_vector.set(x = move_vector.x + overlap[0] * temp_scale_factor,
z = move_vector.z + overlap[1] * temp_scale_factor)
else:
move_vector = temp_move_vector
else: else:
# This can happen in some cases if the object is not yet done with being loaded. # This can happen in some cases if the object is not yet done with being loaded.
# Simply waiting for the next tick seems to resolve this correctly. # Simply waiting for the next tick seems to resolve this correctly.
overlap = None overlap = None
if not Vector.Null.equals(move_vector, epsilon=1e-5): if not Vector.Null.equals(move_vector, epsilon = 1e-5):
transformed_nodes.append(node) transformed_nodes.append(node)
op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector) op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector)
op.push() op.push()

View file

@ -14,6 +14,7 @@ from UM.Decorators import override
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.ContainerStack import ContainerStack from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.SettingInstance import SettingInstance
from UM.Application import Application from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
from UM.Message import Message from UM.Message import Message
@ -224,7 +225,7 @@ class CuraContainerRegistry(ContainerRegistry):
# This is assumed to be the global profile # This is assumed to be the global profile
profile_id = (global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_") profile_id = (global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_")
elif len(machine_extruders) > profile_index: elif profile_index < len(machine_extruders) + 1:
# This is assumed to be an extruder profile # This is assumed to be an extruder profile
extruder_id = Application.getInstance().getMachineManager().getQualityDefinitionId(machine_extruders[profile_index - 1].getBottom()) extruder_id = Application.getInstance().getMachineManager().getQualityDefinitionId(machine_extruders[profile_index - 1].getBottom())
if not profile.getMetaDataEntry("extruder"): if not profile.getMetaDataEntry("extruder"):
@ -430,11 +431,42 @@ class CuraContainerRegistry(ContainerRegistry):
extruder_stack.setDefinition(extruder_definition) extruder_stack.setDefinition(extruder_definition)
extruder_stack.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position")) extruder_stack.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position"))
from cura.CuraApplication import CuraApplication
# create a new definition_changes container for the extruder stack
definition_changes_id = self.uniqueName(extruder_stack.getId() + "_settings")
definition_changes_name = definition_changes_id
definition_changes = InstanceContainer(definition_changes_id)
definition_changes.setName(definition_changes_name)
definition_changes.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
definition_changes.addMetaDataEntry("type", "definition_changes")
definition_changes.addMetaDataEntry("definition", extruder_definition.getId())
# move definition_changes settings if exist
for setting_key in definition_changes.getAllKeys():
if machine.definition.getProperty(setting_key, "settable_per_extruder"):
setting_value = machine.definitionChanges.getProperty(setting_key, "value")
if setting_value is not None:
# move it to the extruder stack's definition_changes
setting_definition = machine.getSettingDefinition(setting_key)
new_instance = SettingInstance(setting_definition, definition_changes)
new_instance.setProperty("value", setting_value)
new_instance.resetState() # Ensure that the state is not seen as a user state.
definition_changes.addInstance(new_instance)
definition_changes.setDirty(True)
machine.definitionChanges.removeInstance(setting_key, postpone_emit = True)
self.addContainer(definition_changes)
extruder_stack.setDefinitionChanges(definition_changes)
# create empty user changes container otherwise # create empty user changes container otherwise
user_container = InstanceContainer(extruder_stack.id + "_user") user_container_id = self.uniqueName(extruder_stack.getId() + "_user")
user_container_name = user_container_id
user_container = InstanceContainer(user_container_id)
user_container.setName(user_container_name)
user_container.addMetaDataEntry("type", "user") user_container.addMetaDataEntry("type", "user")
user_container.addMetaDataEntry("machine", extruder_stack.getId()) user_container.addMetaDataEntry("machine", extruder_stack.getId())
from cura.CuraApplication import CuraApplication
user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion) user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
user_container.setDefinition(machine.definition.getId()) user_container.setDefinition(machine.definition.getId())
@ -444,7 +476,15 @@ class CuraContainerRegistry(ContainerRegistry):
for user_setting_key in machine.userChanges.getAllKeys(): for user_setting_key in machine.userChanges.getAllKeys():
settable_per_extruder = machine.getProperty(user_setting_key, "settable_per_extruder") settable_per_extruder = machine.getProperty(user_setting_key, "settable_per_extruder")
if settable_per_extruder: if settable_per_extruder:
user_container.addInstance(machine.userChanges.getInstance(user_setting_key)) setting_value = machine.getProperty(user_setting_key, "value")
setting_definition = machine.getSettingDefinition(user_setting_key)
new_instance = SettingInstance(setting_definition, definition_changes)
new_instance.setProperty("value", setting_value)
new_instance.resetState() # Ensure that the state is not seen as a user state.
user_container.addInstance(new_instance)
user_container.setDirty(True)
machine.userChanges.removeInstance(user_setting_key, postpone_emit = True) machine.userChanges.removeInstance(user_setting_key, postpone_emit = True)
self.addContainer(user_container) self.addContainer(user_container)

View file

@ -8,6 +8,7 @@ from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
from UM.Settings.ContainerStack import ContainerStack from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext
from UM.Settings.SettingInstance import SettingInstance
from . import Exceptions from . import Exceptions
from .CuraContainerStack import CuraContainerStack from .CuraContainerStack import CuraContainerStack
@ -16,6 +17,11 @@ from .ExtruderManager import ExtruderManager
if TYPE_CHECKING: if TYPE_CHECKING:
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
_EXTRUDER_SPECIFIC_DEFINITION_CHANGES_SETTINGS = ["machine_nozzle_size",
"material_diameter"]
## Represents an Extruder and its related containers. ## Represents an Extruder and its related containers.
# #
# #
@ -39,6 +45,29 @@ class ExtruderStack(CuraContainerStack):
# For backward compatibility: Register the extruder with the Extruder Manager # For backward compatibility: Register the extruder with the Extruder Manager
ExtruderManager.getInstance().registerExtruder(self, stack.id) ExtruderManager.getInstance().registerExtruder(self, stack.id)
# Now each machine will have at least one extruder stack. If this is the first extruder, the extruder-specific
# settings such as nozzle size and material diameter should be moved from the machine's definition_changes to
# the this extruder's definition_changes.
#
# We do this here because it is tooooo expansive to do it in the version upgrade: During the version upgrade,
# when we are upgrading a definition_changes container file, there is NO guarantee that other files such as
# machine an extruder stack files are upgraded before this, so we cannot read those files assuming they are in
# the latest format.
if self.getMetaDataEntry("position") == "0":
for key in _EXTRUDER_SPECIFIC_DEFINITION_CHANGES_SETTINGS:
setting_value = stack.definitionChanges.getProperty(key, "value")
if setting_value is None:
continue
setting_definition = stack.getSettingDefinition(key)
new_instance = SettingInstance(setting_definition, self.definitionChanges)
new_instance.setProperty("value", setting_value)
new_instance.resetState() # Ensure that the state is not seen as a user state.
self.definitionChanges.addInstance(new_instance)
self.definitionChanges.setDirty(True)
stack.definitionChanges.removeInstance(key, postpone_emit = True)
@override(ContainerStack) @override(ContainerStack)
def getNextStack(self) -> Optional["GlobalStack"]: def getNextStack(self) -> Optional["GlobalStack"]:
return super().getNextStack() return super().getNextStack()

View file

@ -43,13 +43,12 @@ class ShapeArray:
transform_x = transform._data[0][3] transform_x = transform._data[0][3]
transform_y = transform._data[2][3] transform_y = transform._data[2][3]
hull_verts = node.callDecoration("getConvexHull") hull_verts = node.callDecoration("getConvexHull")
# If a model is too small then it will not contain any points
if hull_verts is None or not hull_verts.getPoints().any():
return None, None
# For one_at_a_time printing you need the convex hull head. # For one_at_a_time printing you need the convex hull head.
hull_head_verts = node.callDecoration("getConvexHullHead") or hull_verts hull_head_verts = node.callDecoration("getConvexHullHead") or hull_verts
# If a model is to small then it will not contain any points
if not hull_verts.getPoints().any():
return None, None
offset_verts = hull_head_verts.getMinkowskiHull(Polygon.approximatedCircle(min_offset)) offset_verts = hull_head_verts.getMinkowskiHull(Polygon.approximatedCircle(min_offset))
offset_points = copy.deepcopy(offset_verts._points) # x, y offset_points = copy.deepcopy(offset_verts._points) # x, y
offset_points[:, 0] = numpy.add(offset_points[:, 0], -transform_x) offset_points[:, 0] = numpy.add(offset_points[:, 0], -transform_x)

View file

@ -682,12 +682,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
file_name = global_stack_file) file_name = global_stack_file)
# Ensure a unique ID and name # Ensure a unique ID and name
stack._id = global_stack_id_new stack.setMetaDataEntry("id", global_stack_id_new)
# Extruder stacks are "bound" to a machine. If we add the machine as a new one, the id of the
# bound machine also needs to change.
if stack.getMetaDataEntry("machine", None):
stack.setMetaDataEntry("machine", global_stack_id_new)
# Only machines need a new name, stacks may be non-unique # Only machines need a new name, stacks may be non-unique
stack.setName(global_stack_name_new) stack.setName(global_stack_name_new)
@ -741,7 +736,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
stack.deserialize(extruder_file_content, file_name = extruder_stack_file) stack.deserialize(extruder_file_content, file_name = extruder_stack_file)
# Ensure a unique ID and name # Ensure a unique ID and name
stack._id = new_id stack.setMetaDataEntry("id", new_id)
self._container_registry.addContainer(stack) self._container_registry.addContainer(stack)
extruder_stacks_added.append(stack) extruder_stacks_added.append(stack)

View file

@ -153,10 +153,11 @@ class StartSliceJob(Job):
is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS)
if (node.callDecoration("getBuildPlateNumber") == self._build_plate_number): if (node.callDecoration("getBuildPlateNumber") == self._build_plate_number):
if not getattr(node, "_outside_buildarea", False) or not is_non_printing_mesh: if not getattr(node, "_outside_buildarea", False) or is_non_printing_mesh:
temp_list.append(node) temp_list.append(node)
if not is_non_printing_mesh: if not is_non_printing_mesh:
has_printing_mesh = True has_printing_mesh = True
Job.yieldThread() Job.yieldThread()
#If the list doesn't have any model with suitable settings then clean the list #If the list doesn't have any model with suitable settings then clean the list

View file

@ -7,14 +7,11 @@ from UM.FlameProfiler import pyqtSlot
from cura.MachineAction import MachineAction from cura.MachineAction import MachineAction
from UM.Application import Application from UM.Application import Application
from UM.Preferences import Preferences
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.DefinitionContainer import DefinitionContainer from UM.Settings.DefinitionContainer import DefinitionContainer
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Logger import Logger from UM.Logger import Logger
from cura.CuraApplication import CuraApplication
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
from cura.Settings.CuraStackBuilder import CuraStackBuilder from cura.Settings.CuraStackBuilder import CuraStackBuilder
@ -36,7 +33,6 @@ class MachineSettingsAction(MachineAction):
self._container_registry.containerAdded.connect(self._onContainerAdded) self._container_registry.containerAdded.connect(self._onContainerAdded)
self._container_registry.containerRemoved.connect(self._onContainerRemoved) self._container_registry.containerRemoved.connect(self._onContainerRemoved)
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
self._empty_container = self._container_registry.getEmptyInstanceContainer() self._empty_container = self._container_registry.getEmptyInstanceContainer()
@ -67,7 +63,9 @@ class MachineSettingsAction(MachineAction):
self._global_container_stack, self._global_container_stack.getName() + "_settings") self._global_container_stack, self._global_container_stack.getName() + "_settings")
# Notify the UI in which container to store the machine settings data # Notify the UI in which container to store the machine settings data
container_index = self._global_container_stack.getContainerIndex(definition_changes_container) from cura.Settings.CuraContainerStack import CuraContainerStack, _ContainerIndexes
container_index = _ContainerIndexes.DefinitionChanges
if container_index != self._container_index: if container_index != self._container_index:
self._container_index = container_index self._container_index = container_index
self.containerIndexChanged.emit() self.containerIndexChanged.emit()
@ -82,17 +80,6 @@ class MachineSettingsAction(MachineAction):
if self._backend and self._backend.determineAutoSlicing(): if self._backend and self._backend.determineAutoSlicing():
self._backend.tickle() self._backend.tickle()
def _onActiveExtruderStackChanged(self):
extruder_container_stack = ExtruderManager.getInstance().getActiveExtruderStack()
if not self._global_container_stack or not extruder_container_stack:
return
# Make sure there is a definition_changes container to store the machine settings
definition_changes_container = extruder_container_stack.definitionChanges
if definition_changes_container == self._empty_container:
definition_changes_container = CuraStackBuilder.createDefinitionChangesContainer(
extruder_container_stack, extruder_container_stack.getId() + "_settings")
containerIndexChanged = pyqtSignal() containerIndexChanged = pyqtSignal()
@pyqtProperty(int, notify = containerIndexChanged) @pyqtProperty(int, notify = containerIndexChanged)
@ -217,8 +204,8 @@ class MachineSettingsAction(MachineAction):
Application.getInstance().globalContainerStackChanged.emit() Application.getInstance().globalContainerStackChanged.emit()
@pyqtSlot() @pyqtSlot(int)
def updateMaterialForDiameter(self): def updateMaterialForDiameter(self, extruder_position: int):
# Updates the material container to a material that matches the material diameter set for the printer # Updates the material container to a material that matches the material diameter set for the printer
if not self._global_container_stack: if not self._global_container_stack:
return return
@ -226,24 +213,22 @@ class MachineSettingsAction(MachineAction):
if not self._global_container_stack.getMetaDataEntry("has_materials", False): if not self._global_container_stack.getMetaDataEntry("has_materials", False):
return return
material = ExtruderManager.getInstance().getActiveExtruderStack().material extruder_stack = self._global_container_stack.extruders[str(extruder_position)]
material_diameter = material.getProperty("material_diameter", "value")
material_diameter = extruder_stack.material.getProperty("material_diameter", "value")
if not material_diameter: if not material_diameter:
# in case of "empty" material # in case of "empty" material
material_diameter = 0 material_diameter = 0
material_approximate_diameter = str(round(material_diameter)) material_approximate_diameter = str(round(material_diameter))
definition_changes = self._global_container_stack.definitionChanges machine_diameter = extruder_stack.definitionChanges.getProperty("material_diameter", "value")
machine_diameter = definition_changes.getProperty("material_diameter", "value")
if not machine_diameter: if not machine_diameter:
machine_diameter = self._global_container_stack.definition.getProperty("material_diameter", "value") machine_diameter = extruder_stack.definition.getProperty("material_diameter", "value")
machine_approximate_diameter = str(round(machine_diameter)) machine_approximate_diameter = str(round(machine_diameter))
if material_approximate_diameter != machine_approximate_diameter: if material_approximate_diameter != machine_approximate_diameter:
Logger.log("i", "The the currently active material(s) do not match the diameter set for the printer. Finding alternatives.") Logger.log("i", "The the currently active material(s) do not match the diameter set for the printer. Finding alternatives.")
stacks = ExtruderManager.getInstance().getExtruderStacks()
if self._global_container_stack.getMetaDataEntry("has_machine_materials", False): if self._global_container_stack.getMetaDataEntry("has_machine_materials", False):
materials_definition = self._global_container_stack.definition.getId() materials_definition = self._global_container_stack.definition.getId()
has_material_variants = self._global_container_stack.getMetaDataEntry("has_variants", False) has_material_variants = self._global_container_stack.getMetaDataEntry("has_variants", False)
@ -251,45 +236,44 @@ class MachineSettingsAction(MachineAction):
materials_definition = "fdmprinter" materials_definition = "fdmprinter"
has_material_variants = False has_material_variants = False
for stack in stacks: old_material = extruder_stack.material
old_material = stack.material search_criteria = {
search_criteria = { "type": "material",
"type": "material", "approximate_diameter": machine_approximate_diameter,
"approximate_diameter": machine_approximate_diameter, "material": old_material.getMetaDataEntry("material", "value"),
"material": old_material.getMetaDataEntry("material", "value"), "supplier": old_material.getMetaDataEntry("supplier", "value"),
"supplier": old_material.getMetaDataEntry("supplier", "value"), "color_name": old_material.getMetaDataEntry("color_name", "value"),
"color_name": old_material.getMetaDataEntry("color_name", "value"), "definition": materials_definition
"definition": materials_definition }
} if has_material_variants:
if has_material_variants: search_criteria["variant"] = extruder_stack.variant.getId()
search_criteria["variant"] = stack.variant.getId()
if old_material == self._empty_container: if old_material == self._empty_container:
search_criteria.pop("material", None) search_criteria.pop("material", None)
search_criteria.pop("supplier", None) search_criteria.pop("supplier", None)
search_criteria.pop("definition", None) search_criteria.pop("definition", None)
search_criteria["id"] = stack.getMetaDataEntry("preferred_material") search_criteria["id"] = extruder_stack.getMetaDataEntry("preferred_material")
materials = self._container_registry.findInstanceContainers(**search_criteria)
if not materials:
# Same material with new diameter is not found, search for generic version of the same material type
search_criteria.pop("supplier", None)
search_criteria["color_name"] = "Generic"
materials = self._container_registry.findInstanceContainers(**search_criteria) materials = self._container_registry.findInstanceContainers(**search_criteria)
if not materials: if not materials:
# Same material with new diameter is not found, search for generic version of the same material type # Generic material with new diameter is not found, search for preferred material
search_criteria.pop("supplier", None) search_criteria.pop("color_name", None)
search_criteria["color_name"] = "Generic" search_criteria.pop("material", None)
materials = self._container_registry.findInstanceContainers(**search_criteria) search_criteria["id"] = extruder_stack.getMetaDataEntry("preferred_material")
if not materials: materials = self._container_registry.findInstanceContainers(**search_criteria)
# Generic material with new diameter is not found, search for preferred material if not materials:
search_criteria.pop("color_name", None) # Preferred material with new diameter is not found, search for any material
search_criteria.pop("material", None) search_criteria.pop("id", None)
search_criteria["id"] = stack.getMetaDataEntry("preferred_material") materials = self._container_registry.findInstanceContainers(**search_criteria)
materials = self._container_registry.findInstanceContainers(**search_criteria) if not materials:
if not materials: # Just use empty material as a final fallback
# Preferred material with new diameter is not found, search for any material materials = [self._empty_container]
search_criteria.pop("id", None)
materials = self._container_registry.findInstanceContainers(**search_criteria)
if not materials:
# Just use empty material as a final fallback
materials = [self._empty_container]
Logger.log("i", "Selecting new material: %s" % materials[0].getId()) Logger.log("i", "Selecting new material: %s" % materials[0].getId())
stack.material = materials[0] extruder_stack.material = materials[0]

View file

@ -292,18 +292,6 @@ Cura.MachineAction
} }
} }
} }
Loader
{
id: materialDiameterField
visible: Cura.MachineManager.hasMaterials
sourceComponent: numericTextFieldWithUnit
property string settingKey: "material_diameter"
property string unit: catalog.i18nc("@label", "mm")
property string tooltip: catalog.i18nc("@tooltip", "The nominal diameter of filament supported by the printer. The exact diameter will be overridden by the material and/or the profile.")
property var afterOnEditingFinished: manager.updateMaterialForDiameter
property string label: catalog.i18nc("@label", "Material diameter")
}
} }
} }
@ -360,7 +348,6 @@ Cura.MachineAction
if(currentIndex > 0) if(currentIndex > 0)
{ {
contentItem.forceActiveFocus(); contentItem.forceActiveFocus();
Cura.ExtruderManager.setActiveExtruderIndex(currentIndex - 1);
} }
} }
@ -397,6 +384,25 @@ Cura.MachineAction
property bool isExtruderSetting: true property bool isExtruderSetting: true
} }
Loader
{
id: materialDiameterField
visible: Cura.MachineManager.hasMaterials
sourceComponent: numericTextFieldWithUnit
property string settingKey: "material_diameter"
property string label: catalog.i18nc("@label", "Material diameter")
property string unit: catalog.i18nc("@label", "mm")
property string tooltip: catalog.i18nc("@tooltip", "The nominal diameter of filament supported by the printer. The exact diameter will be overridden by the material and/or the profile.")
property var afterOnEditingFinished:
{
if (settingsTabs.currentIndex > 0)
{
manager.updateMaterialForDiameter(settingsTabs.currentIndex - 1);
}
}
property bool isExtruderSetting: true
}
Loader Loader
{ {
id: extruderOffsetXField id: extruderOffsetXField
@ -495,7 +501,7 @@ Cura.MachineAction
{ {
if(settingsTabs.currentIndex > 0) if(settingsTabs.currentIndex > 0)
{ {
return Cura.MachineManager.activeStackId; return Cura.ExtruderManager.extruderIds[String(settingsTabs.currentIndex - 1)];
} }
return ""; return "";
} }
@ -513,11 +519,11 @@ Cura.MachineAction
checked: String(propertyProvider.properties.value).toLowerCase() != 'false' checked: String(propertyProvider.properties.value).toLowerCase() != 'false'
onClicked: onClicked:
{ {
propertyProvider.setPropertyValue("value", checked); propertyProvider.setPropertyValue("value", checked);
if(_forceUpdateOnChange) if(_forceUpdateOnChange)
{ {
manager.forceUpdate(); manager.forceUpdate();
} }
} }
} }
} }
@ -548,7 +554,7 @@ Cura.MachineAction
{ {
if(settingsTabs.currentIndex > 0) if(settingsTabs.currentIndex > 0)
{ {
return Cura.MachineManager.activeStackId; return Cura.ExtruderManager.extruderIds[String(settingsTabs.currentIndex - 1)];
} }
return ""; return "";
} }
@ -581,7 +587,10 @@ Cura.MachineAction
TextField TextField
{ {
id: textField id: textField
text: (propertyProvider.properties.value) ? propertyProvider.properties.value : "" text: {
const value = propertyProvider.properties.value;
return value ? value : "";
}
validator: RegExpValidator { regExp: _allowNegative ? /-?[0-9\.]{0,6}/ : /[0-9\.]{0,6}/ } validator: RegExpValidator { regExp: _allowNegative ? /-?[0-9\.]{0,6}/ : /[0-9\.]{0,6}/ }
onEditingFinished: onEditingFinished:
{ {
@ -590,12 +599,7 @@ Cura.MachineAction
propertyProvider.setPropertyValue("value", text); propertyProvider.setPropertyValue("value", text);
if(_forceUpdateOnChange) if(_forceUpdateOnChange)
{ {
var extruderIndex = Cura.ExtruderManager.activeExtruderIndex;
manager.forceUpdate(); manager.forceUpdate();
if(Cura.ExtruderManager.activeExtruderIndex != extruderIndex)
{
Cura.ExtruderManager.setActiveExtruderIndex(extruderIndex)
}
} }
if(_afterOnEditingFinished) if(_afterOnEditingFinished)
{ {
@ -641,7 +645,7 @@ Cura.MachineAction
{ {
if(settingsTabs.currentIndex > 0) if(settingsTabs.currentIndex > 0)
{ {
return Cura.MachineManager.activeStackId; return Cura.ExtruderManager.extruderIds[String(settingsTabs.currentIndex - 1)];
} }
return ""; return "";
} }

View file

@ -4,6 +4,7 @@
import sys import sys
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QOpenGLContext
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from UM.Application import Application from UM.Application import Application
@ -13,6 +14,7 @@ from UM.Logger import Logger
from UM.Math.Color import Color from UM.Math.Color import Color
from UM.Mesh.MeshBuilder import MeshBuilder from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Message import Message from UM.Message import Message
from UM.Platform import Platform
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.Preferences import Preferences from UM.Preferences import Preferences
from UM.Resources import Resources from UM.Resources import Resources
@ -24,6 +26,7 @@ from UM.View.GL.OpenGLContext import OpenGLContext
from UM.View.View import View from UM.View.View import View
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from cura.ConvexHullNode import ConvexHullNode from cura.ConvexHullNode import ConvexHullNode
from cura.CuraApplication import CuraApplication
from .NozzleNode import NozzleNode from .NozzleNode import NozzleNode
from .SimulationPass import SimulationPass from .SimulationPass import SimulationPass
@ -414,6 +417,23 @@ class SimulationView(View):
return True return True
if event.type == Event.ViewActivateEvent: if event.type == Event.ViewActivateEvent:
# FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching.
# This can happen when you do the following steps:
# 1. Start Cura
# 2. Load a model
# 3. Switch to Custom mode
# 4. Select the model and click on the per-object tool icon
# 5. Switch view to Layer view or X-Ray
# 6. Cura will very likely crash
# It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why.
# This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL
# context is None.
if Platform.isOSX():
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
# Make sure the SimulationPass is created # Make sure the SimulationPass is created
layer_pass = self.getSimulationPass() layer_pass = self.getSimulationPass()
self.getRenderer().addRenderPass(layer_pass) self.getRenderer().addRenderPass(layer_pass)

View file

@ -187,7 +187,7 @@ geometry41core =
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert)); myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert)); myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head + g_vertex_offset_vert)); myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head + g_vertex_offset_vert));
//And reverse so that the line is also visible from the back side. //And reverse so that the line is also visible from the back side.
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert)); myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert)); myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert)); myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
@ -212,17 +212,17 @@ geometry41core =
EndPrimitive(); EndPrimitive();
// left side // left side
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz)); myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert)); myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head)); myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head));
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz)); myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
EndPrimitive(); EndPrimitive();
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz)); myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert)); myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head)); myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head));
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz)); myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
EndPrimitive(); EndPrimitive();

View file

@ -39,19 +39,26 @@ class SliceInfo(Extension):
Preferences.getInstance().addPreference("info/send_slice_info", True) Preferences.getInstance().addPreference("info/send_slice_info", True)
Preferences.getInstance().addPreference("info/asked_send_slice_info", False) Preferences.getInstance().addPreference("info/asked_send_slice_info", False)
if not Preferences.getInstance().getValue("info/asked_send_slice_info") and Preferences.getInstance().getValue("info/send_slice_info"): if not Preferences.getInstance().getValue("info/asked_send_slice_info"):
self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura collects anonymised slicing statistics. You can disable this in the preferences."), self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura collects anonymized usage statistics."),
lifetime = 0, lifetime = 0,
dismissable = False, dismissable = False,
title = catalog.i18nc("@info:title", "Collecting Data")) title = catalog.i18nc("@info:title", "Collecting Data"))
self.send_slice_info_message.addAction("Dismiss", catalog.i18nc("@action:button", "Dismiss"), None, "") 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."))
self.send_slice_info_message.addAction("Disable", name = catalog.i18nc("@action:button", "Disable"), icon = None,
description = catalog.i18nc("@action:tooltip", "Don't allow Cura to send anonymized usage statistics. You can enable it again in the preferences."), button_style = Message.ActionButtonStyle.LINK)
self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered) self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered)
self.send_slice_info_message.show() self.send_slice_info_message.show()
## Perform action based on user input.
# Note that clicking "Disable" won't actually disable the data sending, but rather take the user to preferences where they can disable it.
def messageActionTriggered(self, message_id, action_id): def messageActionTriggered(self, message_id, action_id):
self.send_slice_info_message.hide()
Preferences.getInstance().setValue("info/asked_send_slice_info", True) Preferences.getInstance().setValue("info/asked_send_slice_info", True)
if action_id == "Disable":
CuraApplication.getInstance().showPreferences()
self.send_slice_info_message.hide()
def _onWriteStarted(self, output_device): def _onWriteStarted(self, output_device):
try: try:

View file

@ -122,26 +122,6 @@ class VersionUpgrade30to31(VersionUpgrade):
if len(all_quality_changes) <= 1 and not parser.has_option("metadata", "extruder"): if len(all_quality_changes) <= 1 and not parser.has_option("metadata", "extruder"):
self._createExtruderQualityChangesForSingleExtrusionMachine(filename, parser) self._createExtruderQualityChangesForSingleExtrusionMachine(filename, parser)
if parser["metadata"]["type"] == "definition_changes":
if parser["general"]["definition"] == "custom":
# We are only interested in machine_nozzle_size
if parser.has_option("values", "machine_nozzle_size"):
machine_nozzle_size = parser["values"]["machine_nozzle_size"]
machine_extruder_count = '1' # by default it is 1 and the value cannot be stored in the global stack
if parser.has_option("values", "machine_extruder_count"):
machine_extruder_count = parser["values"]["machine_extruder_count"]
if machine_extruder_count == '1':
definition_name = parser["general"]["name"]
machine_extruders = self._getSingleExtrusionMachineExtruders(definition_name)
# For single extruder machine we need only first extruder
if len(machine_extruders) !=0:
self._updateSingleExtruderDefinitionFile(machine_extruders, machine_nozzle_size)
parser.remove_option("values", "machine_nozzle_size")
# Update version numbers # Update version numbers
parser["general"]["version"] = "2" parser["general"]["version"] = "2"
parser["metadata"]["setting_version"] = "4" parser["metadata"]["setting_version"] = "4"
@ -220,123 +200,6 @@ class VersionUpgrade30to31(VersionUpgrade):
return quality_changes_containers return quality_changes_containers
def _getSingleExtrusionMachineExtruders(self, definition_name):
machine_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.MachineStack)
machine_instance_id = None
# Find machine instances
for item in os.listdir(machine_instances_dir):
file_path = os.path.join(machine_instances_dir, item)
if not os.path.isfile(file_path):
continue
parser = configparser.ConfigParser(interpolation=None)
try:
parser.read([file_path])
except:
# skip, it is not a valid stack file
continue
if not parser.has_option("metadata", "type"):
continue
if "machine" != parser["metadata"]["type"]:
continue
if not parser.has_option("general", "id"):
continue
id = parser["general"]["id"]
if id + "_settings" != definition_name:
continue
else:
machine_instance_id = id
break
if machine_instance_id is not None:
extruders_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.ExtruderStack)
#"machine",[extruders]
extruder_instances = []
# Find all custom extruders for found machines
for item in os.listdir(extruders_instances_dir):
file_path = os.path.join(extruders_instances_dir, item)
if not os.path.isfile(file_path):
continue
parser = configparser.ConfigParser(interpolation=None)
try:
parser.read([file_path])
except:
# skip, it is not a valid stack file
continue
if not parser.has_option("metadata", "type"):
continue
if "extruder_train" != parser["metadata"]["type"]:
continue
if not parser.has_option("metadata", "machine"):
continue
if not parser.has_option("metadata", "position"):
continue
if machine_instance_id != parser["metadata"]["machine"]:
continue
extruder_instances.append(parser)
return extruder_instances
# Find extruder definition at index 0 and update its values
def _updateSingleExtruderDefinitionFile(self, extruder_instances_per_machine, machine_nozzle_size):
defintion_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.DefinitionChangesContainer)
for item in os.listdir(defintion_instances_dir):
file_path = os.path.join(defintion_instances_dir, item)
if not os.path.isfile(file_path):
continue
parser = configparser.ConfigParser(interpolation=None)
try:
parser.read([file_path])
except:
# skip, it is not a valid stack file
continue
if not parser.has_option("general", "name"):
continue
name = parser["general"]["name"]
custom_extruder_at_0_position = None
for extruder_instance in extruder_instances_per_machine:
definition_position = extruder_instance["metadata"]["position"]
if definition_position == "0":
custom_extruder_at_0_position = extruder_instance
break
# If not null, then parsed file is for first extuder and then can be updated. I need to update only
# first, because this update for single extuder machine
if custom_extruder_at_0_position is not None:
#Add new value
parser["values"]["machine_nozzle_size"] = machine_nozzle_size
definition_output = io.StringIO()
parser.write(definition_output)
with open(file_path, "w") as f:
f.write(definition_output.getvalue())
return True
return False
def _createExtruderQualityChangesForSingleExtrusionMachine(self, filename, global_quality_changes): def _createExtruderQualityChangesForSingleExtrusionMachine(self, filename, global_quality_changes):
suffix = "_" + quote_plus(global_quality_changes["general"]["name"].lower()) suffix = "_" + quote_plus(global_quality_changes["general"]["name"].lower())
machine_name = os.path.os.path.basename(filename).replace(".inst.cfg", "").replace(suffix, "") machine_name = os.path.os.path.basename(filename).replace(".inst.cfg", "").replace(suffix, "")
@ -369,4 +232,4 @@ class VersionUpgrade30to31(VersionUpgrade):
quality_changes_dir = Resources.getPath(CuraApplication.ResourceTypes.QualityInstanceContainer) quality_changes_dir = Resources.getPath(CuraApplication.ResourceTypes.QualityInstanceContainer)
with open(os.path.join(quality_changes_dir, extruder_quality_changes_filename), "w") as f: with open(os.path.join(quality_changes_dir, extruder_quality_changes_filename), "w") as f:
f.write(extruder_quality_changes_output.getvalue()) f.write(extruder_quality_changes_output.getvalue())

View file

@ -185,7 +185,7 @@ class X3DReader(MeshReader):
got_center = (center.x != 0 or center.y != 0 or center.z != 0) got_center = (center.x != 0 or center.y != 0 or center.z != 0)
T = self.transform T = self.transform
if trans.x != 0 or trans.y != 0 or trans.z !=0: if trans.x != 0 or trans.y != 0 or trans.z != 0:
T.translate(trans) T.translate(trans)
if got_center: if got_center:
T.translate(center) T.translate(center)

View file

@ -2,10 +2,13 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import os.path import os.path
from PyQt5.QtGui import QOpenGLContext
from UM.Application import Application from UM.Application import Application
from UM.Logger import Logger
from UM.Math.Color import Color from UM.Math.Color import Color
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.Platform import Platform
from UM.Event import Event from UM.Event import Event
from UM.View.View import View from UM.View.View import View
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
@ -13,6 +16,8 @@ from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
from UM.View.RenderBatch import RenderBatch from UM.View.RenderBatch import RenderBatch
from UM.View.GL.OpenGL import OpenGL from UM.View.GL.OpenGL import OpenGL
from cura.CuraApplication import CuraApplication
from . import XRayPass from . import XRayPass
## View used to display a see-through version of objects with errors highlighted. ## View used to display a see-through version of objects with errors highlighted.
@ -52,6 +57,23 @@ class XRayView(View):
def event(self, event): def event(self, event):
if event.type == Event.ViewActivateEvent: if event.type == Event.ViewActivateEvent:
# FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching.
# This can happen when you do the following steps:
# 1. Start Cura
# 2. Load a model
# 3. Switch to Custom mode
# 4. Select the model and click on the per-object tool icon
# 5. Switch view to Layer view or X-Ray
# 6. Cura will very likely crash
# It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why.
# This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL
# context is None.
if Platform.isOSX():
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
if not self._xray_pass: if not self._xray_pass:
# Currently the RenderPass constructor requires a size > 0 # Currently the RenderPass constructor requires a size > 0
# This should be fixed in RenderPass's constructor. # This should be fixed in RenderPass's constructor.

View file

@ -1,5 +1,4 @@
{ {
"id": "builder_premium_large",
"version": 2, "version": 2,
"name": "Builder Premium Large", "name": "Builder Premium Large",
"inherits": "fdmprinter", "inherits": "fdmprinter",

View file

@ -1,5 +1,4 @@
{ {
"id": "builder_premium_medium",
"version": 2, "version": 2,
"name": "Builder Premium Medium", "name": "Builder Premium Medium",
"inherits": "fdmprinter", "inherits": "fdmprinter",

View file

@ -1,5 +1,4 @@
{ {
"id": "builder_premium_small",
"version": 2, "version": 2,
"name": "Builder Premium Small", "name": "Builder Premium Small",
"inherits": "fdmprinter", "inherits": "fdmprinter",

View file

@ -1,5 +1,4 @@
{ {
"id": "deltacomb",
"version": 2, "version": 2,
"name": "Deltacomb 3D", "name": "Deltacomb 3D",
"inherits": "fdmprinter", "inherits": "fdmprinter",

View file

@ -181,6 +181,27 @@
} }
} }
}, },
"material": {
"label": "Material",
"icon": "category_material",
"description": "Material",
"type": "category",
"children": {
"material_diameter": {
"label": "Diameter",
"description": "Adjusts the diameter of the filament used. Match this value with the diameter of the used filament.",
"unit": "mm",
"type": "float",
"default_value": 2.85,
"minimum_value": "0.0001",
"minimum_value_warning": "0.4",
"maximum_value_warning": "3.5",
"enabled": "machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false,
"settable_per_extruder": true
}
}
},
"platform_adhesion": "platform_adhesion":
{ {
"label": "Build Plate Adhesion", "label": "Build Plate Adhesion",

View file

@ -1614,7 +1614,7 @@
"infill_overlap": "infill_overlap":
{ {
"label": "Infill Overlap Percentage", "label": "Infill Overlap Percentage",
"description": "The amount of overlap between the infill and the walls. A slight overlap allows the walls to connect firmly to the infill.", "description": "The amount of overlap between the infill and the walls as a percentage of the infill line width. A slight overlap allows the walls to connect firmly to the infill.",
"unit": "%", "unit": "%",
"type": "float", "type": "float",
"default_value": 10, "default_value": 10,
@ -1635,7 +1635,7 @@
"default_value": 0.04, "default_value": 0.04,
"minimum_value_warning": "-0.5 * machine_nozzle_size", "minimum_value_warning": "-0.5 * machine_nozzle_size",
"maximum_value_warning": "machine_nozzle_size", "maximum_value_warning": "machine_nozzle_size",
"value": "0.5 * ( infill_line_width + (wall_line_width_x if wall_line_count > 1 else wall_line_width_0) ) * infill_overlap / 100 if infill_sparse_density < 95 and infill_pattern != 'concentric' else 0", "value": "0.5 * (infill_line_width + (wall_line_width_x if wall_line_count > 1 else wall_line_width_0)) * infill_overlap / 100 if infill_sparse_density < 95 and infill_pattern != 'concentric' else 0",
"enabled": "infill_sparse_density > 0 and infill_pattern != 'concentric'", "enabled": "infill_sparse_density > 0 and infill_pattern != 'concentric'",
"settable_per_mesh": true "settable_per_mesh": true
} }
@ -1644,7 +1644,7 @@
"skin_overlap": "skin_overlap":
{ {
"label": "Skin Overlap Percentage", "label": "Skin Overlap Percentage",
"description": "The amount of overlap between the skin and the walls as a percentage of the line width. A slight overlap allows the walls to connect firmly to the skin. This is a percentage of the average line widths of the skin lines and the innermost wall.", "description": "The amount of overlap between the skin and the walls as a percentage of the skin line width. A slight overlap allows the walls to connect firmly to the skin. This is a percentage of the average line widths of the skin lines and the innermost wall.",
"unit": "%", "unit": "%",
"type": "float", "type": "float",
"default_value": 5, "default_value": 5,
@ -1665,7 +1665,7 @@
"default_value": 0.02, "default_value": 0.02,
"minimum_value_warning": "-0.5 * machine_nozzle_size", "minimum_value_warning": "-0.5 * machine_nozzle_size",
"maximum_value_warning": "machine_nozzle_size", "maximum_value_warning": "machine_nozzle_size",
"value": "0.5 * ( skin_line_width + (wall_line_width_x if wall_line_count > 1 else wall_line_width_0) ) * skin_overlap / 100 if top_bottom_pattern != 'concentric' else 0", "value": "0.5 * (skin_line_width + (wall_line_width_x if wall_line_count > 1 else wall_line_width_0)) * skin_overlap / 100 if top_bottom_pattern != 'concentric' else 0",
"enabled": "top_bottom_pattern != 'concentric'", "enabled": "top_bottom_pattern != 'concentric'",
"settable_per_mesh": true "settable_per_mesh": true
} }

4595
resources/i18n/pt_PT/cura.po Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,210 @@
# Cura JSON setting files
# Copyright (C) 2017 Ultimaker
# This file is distributed under the same license as the Cura package.
# Ruben Dulek <r.dulek@ultimaker.com>, 2017.
#
msgid ""
msgstr ""
"Project-Id-Version: Cura 3.1\n"
"Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n"
"POT-Creation-Date: 2017-08-02 16:53+0000\n"
"PO-Revision-Date: 2017-12-07 13:41+0100\n"
"Last-Translator: Bothof <info@bothof.nl>\n"
"Language-Team: Bothof\n"
"Language: pt_PT\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: fdmextruder.def.json
msgctxt "machine_settings label"
msgid "Machine"
msgstr "Máquina"
#: fdmextruder.def.json
msgctxt "machine_settings description"
msgid "Machine specific settings"
msgstr "Definições específicas da máquina"
#: fdmextruder.def.json
msgctxt "extruder_nr label"
msgid "Extruder"
msgstr "Extrusora"
#: fdmextruder.def.json
msgctxt "extruder_nr description"
msgid "The extruder train used for printing. This is used in multi-extrusion."
msgstr "A máquina extrusora utilizada para imprimir. Esta é utilizada em extrusões múltiplas."
#: fdmextruder.def.json
msgctxt "machine_nozzle_id label"
msgid "Nozzle ID"
msgstr "ID do bocal"
#: fdmextruder.def.json
msgctxt "machine_nozzle_id description"
msgid "The nozzle ID for an extruder train, such as \"AA 0.4\" and \"BB 0.8\"."
msgstr "A ID do bocal para uma máquina de extrusão, tal como \"AA 0.4\" e \"BB 0.8\"."
#: fdmextruder.def.json
msgctxt "machine_nozzle_size label"
msgid "Nozzle Diameter"
msgstr "Diâmetro do bocal"
#: fdmextruder.def.json
msgctxt "machine_nozzle_size description"
msgid ""
"The inner diameter of the nozzle. Change this setting when using a non-"
"standard nozzle size."
msgstr "O diâmetro interno do bocal. Altere esta definição ao utilizar um tamanho de bocal não convencional."
#: fdmextruder.def.json
msgctxt "machine_nozzle_offset_x label"
msgid "Nozzle X Offset"
msgstr "Desvio X do bocal"
#: fdmextruder.def.json
msgctxt "machine_nozzle_offset_x description"
msgid "The x-coordinate of the offset of the nozzle."
msgstr "A coordenada X do desvio do bocal."
#: fdmextruder.def.json
msgctxt "machine_nozzle_offset_y label"
msgid "Nozzle Y Offset"
msgstr "Desvio Y do bocal"
#: fdmextruder.def.json
msgctxt "machine_nozzle_offset_y description"
msgid "The y-coordinate of the offset of the nozzle."
msgstr "A coordenada Y do desvio do bocal."
#: fdmextruder.def.json
msgctxt "machine_extruder_start_code label"
msgid "Extruder Start G-Code"
msgstr "G-Code inicial da extrusora"
#: fdmextruder.def.json
msgctxt "machine_extruder_start_code description"
msgid "Start g-code to execute whenever turning the extruder on."
msgstr "G-Code inicial a ser executado sempre que a extrusora for ligada."
#: fdmextruder.def.json
msgctxt "machine_extruder_start_pos_abs label"
msgid "Extruder Start Position Absolute"
msgstr "Posição inicial absoluta da extrusora"
#: fdmextruder.def.json
msgctxt "machine_extruder_start_pos_abs description"
msgid ""
"Make the extruder starting position absolute rather than relative to the "
"last-known location of the head."
msgstr "Torne a posição inicial da extrusora absoluta em vez de relativa à última posição conhecida da cabeça."
#: fdmextruder.def.json
msgctxt "machine_extruder_start_pos_x label"
msgid "Extruder Start Position X"
msgstr "X da posição inicial da extrusora"
#: fdmextruder.def.json
msgctxt "machine_extruder_start_pos_x description"
msgid "The x-coordinate of the starting position when turning the extruder on."
msgstr "A coordenada X da posição inicial ao ligar a extrusora."
#: fdmextruder.def.json
msgctxt "machine_extruder_start_pos_y label"
msgid "Extruder Start Position Y"
msgstr "Y da posição inicial da extrusora"
#: fdmextruder.def.json
msgctxt "machine_extruder_start_pos_y description"
msgid "The y-coordinate of the starting position when turning the extruder on."
msgstr "A coordenada Y da posição inicial ao ligar a extrusora."
#: fdmextruder.def.json
msgctxt "machine_extruder_end_code label"
msgid "Extruder End G-Code"
msgstr "G-Code final da extrusora"
#: fdmextruder.def.json
msgctxt "machine_extruder_end_code description"
msgid "End g-code to execute whenever turning the extruder off."
msgstr "G-Code final a ser executado sempre que a extrusora for desligada."
#: fdmextruder.def.json
msgctxt "machine_extruder_end_pos_abs label"
msgid "Extruder End Position Absolute"
msgstr "Posição final absoluta da extrusora"
#: fdmextruder.def.json
msgctxt "machine_extruder_end_pos_abs description"
msgid ""
"Make the extruder ending position absolute rather than relative to the last-"
"known location of the head."
msgstr "Torne a posição final da extrusora absoluta em vez de relativa à última localização conhecida da cabeça."
#: fdmextruder.def.json
msgctxt "machine_extruder_end_pos_x label"
msgid "Extruder End Position X"
msgstr "X da posição final da extrusora"
#: fdmextruder.def.json
msgctxt "machine_extruder_end_pos_x description"
msgid "The x-coordinate of the ending position when turning the extruder off."
msgstr "A coordenada X da posição final ao desligar a extrusora."
#: fdmextruder.def.json
msgctxt "machine_extruder_end_pos_y label"
msgid "Extruder End Position Y"
msgstr "Y da posição final da extrusora"
#: fdmextruder.def.json
msgctxt "machine_extruder_end_pos_y description"
msgid "The y-coordinate of the ending position when turning the extruder off."
msgstr "A coordenada Y da posição final ao desligar a extrusora."
#: fdmextruder.def.json
msgctxt "extruder_prime_pos_z label"
msgid "Extruder Prime Z Position"
msgstr "Posição Z de preparação da extrusora"
#: fdmextruder.def.json
msgctxt "extruder_prime_pos_z description"
msgid ""
"The Z coordinate of the position where the nozzle primes at the start of "
"printing."
msgstr "A coordenada Z da posição de preparação do bocal ao iniciar a impressão."
#: fdmextruder.def.json
msgctxt "platform_adhesion label"
msgid "Build Plate Adhesion"
msgstr "Aderência à placa de construção"
#: fdmextruder.def.json
msgctxt "platform_adhesion description"
msgid "Adhesion"
msgstr "Aderência"
#: fdmextruder.def.json
msgctxt "extruder_prime_pos_x label"
msgid "Extruder Prime X Position"
msgstr "Posição X de preparação da extrusora"
#: fdmextruder.def.json
msgctxt "extruder_prime_pos_x description"
msgid ""
"The X coordinate of the position where the nozzle primes at the start of "
"printing."
msgstr "A coordenada X da posição de preparação do bocal ao iniciar a impressão."
#: fdmextruder.def.json
msgctxt "extruder_prime_pos_y label"
msgid "Extruder Prime Y Position"
msgstr "Posição Y de preparação da extrusora"
#: fdmextruder.def.json
msgctxt "extruder_prime_pos_y description"
msgid ""
"The Y coordinate of the position where the nozzle primes at the start of "
"printing."
msgstr "A coordenada Y da posição de preparação do bocal ao iniciar a impressão."

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
// Copyright (c) 2016 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
@ -25,6 +25,15 @@ UM.Dialog
width: minimumWidth width: minimumWidth
height: minimumHeight height: minimumHeight
flags: {
var window_flags = Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint;
if (Cura.MachineManager.activeDefinitionId !== "") //Disallow closing the window if we have no active printer yet. You MUST add a printer.
{
window_flags |= Qt.WindowCloseButtonHint;
}
return window_flags;
}
onVisibilityChanged: onVisibilityChanged:
{ {
// Reset selection and machine name // Reset selection and machine name

View file

@ -413,7 +413,7 @@ UM.MainWindow
collapseSidebarAnimation.start(); collapseSidebarAnimation.start();
} }
collapsed = !collapsed; collapsed = !collapsed;
UM.Preferences.setValue("cura/sidebar_collapse", collapsed); UM.Preferences.setValue("cura/sidebar_collapsed", collapsed);
} }
anchors anchors
@ -444,9 +444,10 @@ UM.MainWindow
Component.onCompleted: Component.onCompleted:
{ {
var sidebarCollapsed = UM.Preferences.getValue("cura/sidebar_collapse"); var sidebar_collapsed = UM.Preferences.getValue("cura/sidebar_collapsed");
if (sidebarCollapsed) { if (sidebar_collapsed)
{
sidebar.collapsed = true; sidebar.collapsed = true;
viewportRect = Qt.rect(0, 0, 1, 1.0) viewportRect = Qt.rect(0, 0, 1, 1.0)
collapseSidebarAnimation.start(); collapseSidebarAnimation.start();
@ -540,6 +541,12 @@ UM.MainWindow
onTriggered: preferences.visible = true onTriggered: preferences.visible = true
} }
Connections
{
target: CuraApplication
onShowPreferencesWindow: preferences.visible = true
}
MessageDialog MessageDialog
{ {
id: newProjectDialog id: newProjectDialog

View file

@ -1,4 +1,4 @@
// Copyright (c) 2017 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
@ -33,9 +33,10 @@ Menu
{ {
id: materialDiameterProvider id: materialDiameterProvider
containerStackId: Cura.MachineManager.activeMachineId containerStackId: Cura.ExtruderManager.activeExtruderStackId
key: "material_diameter" key: "material_diameter"
watchedProperties: [ "value" ] watchedProperties: [ "value" ]
storeIndex: 5
} }
MenuItem MenuItem
@ -207,8 +208,8 @@ Menu
// Add to top section // Add to top section
var materialId = items[i].id; var materialId = items[i].id;
genericMaterialsModel.append({ genericMaterialsModel.append({
id:materialId, id: materialId,
name:items[i].name name: items[i].name
}); });
} }
else else

View file

@ -199,12 +199,12 @@ Item
} }
Component.onCompleted: { Component.onCompleted: {
updateAdditionalComponents("monitorButtons") buttonsRow.updateAdditionalComponents("monitorButtons")
} }
Connections { Connections {
target: CuraApplication target: CuraApplication
onAdditionalComponentsChanged: updateAdditionalComponents onAdditionalComponentsChanged: buttonsRow.updateAdditionalComponents("monitorButtons")
} }
function updateAdditionalComponents (areaId) { function updateAdditionalComponents (areaId) {

View file

@ -159,6 +159,7 @@ UM.PreferencesPage
append({ text: "Nederlands", code: "nl_NL" }) append({ text: "Nederlands", code: "nl_NL" })
append({ text: "Polski", code: "pl_PL" }) append({ text: "Polski", code: "pl_PL" })
append({ text: "Português do Brasil", code: "pt_BR" }) append({ text: "Português do Brasil", code: "pt_BR" })
append({ text: "Português", code: "pt_PT" })
append({ text: "Русский", code: "ru_RU" }) append({ text: "Русский", code: "ru_RU" })
append({ text: "Türkçe", code: "tr_TR" }) append({ text: "Türkçe", code: "tr_TR" })
append({ text: "简体中文", code: "zh_CN" }) append({ text: "简体中文", code: "zh_CN" })

View file

@ -387,9 +387,10 @@ UM.ManagementPage
{ {
id: materialDiameterProvider id: materialDiameterProvider
containerStackId: Cura.MachineManager.activeMachineId containerStackId: Cura.ExtruderManager.activeExtruderStackId
key: "material_diameter" key: "material_diameter"
watchedProperties: [ "value" ] watchedProperties: [ "value" ]
storeIndex: 5
} }
UM.I18nCatalog { id: catalog; name: "cura"; } UM.I18nCatalog { id: catalog; name: "cura"; }

View file

@ -138,12 +138,12 @@ Item {
} }
Component.onCompleted: { Component.onCompleted: {
addAdditionalComponents("saveButton") saveRow.addAdditionalComponents("saveButton")
} }
Connections { Connections {
target: CuraApplication target: CuraApplication
onAdditionalComponentsChanged: addAdditionalComponents onAdditionalComponentsChanged: saveRow.addAdditionalComponents("saveButton")
} }
function addAdditionalComponents (areaId) { function addAdditionalComponents (areaId) {

View file

@ -1,5 +1,5 @@
// Copyright (c) 2015 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
// Uranium is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
@ -31,13 +31,17 @@ Button {
onClicked: onClicked:
{ {
forceActiveFocus();
if(definition.expanded) if(definition.expanded)
{ {
settingDefinitionsModel.collapse(definition.key); settingDefinitionsModel.collapse(definition.key);
} else { }
else
{
settingDefinitionsModel.expandAll(definition.key); settingDefinitionsModel.expandAll(definition.key);
} }
//Set focus so that tab navigation continues from this point on.
//NB: This must be set AFTER collapsing/expanding the category so that the scroll position is correct.
forceActiveFocus();
} }
onActiveFocusChanged: onActiveFocusChanged:
{ {

View file

@ -1,5 +1,5 @@
// Copyright (c) 2015 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
// Uranium is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.1 import QtQuick 2.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
@ -154,7 +154,7 @@ Item {
onEntered: { onEntered: {
hoverTimer.stop(); hoverTimer.stop();
var tooltipText = catalog.i18nc("@label", "This setting is always shared between all extruders. Changing it here will change the value for all extruders") + "."; var tooltipText = catalog.i18nc("@label", "This setting is always shared between all extruders. Changing it here will change the value for all extruders.");
if ((resolve != "None") && (stackLevel != 0)) { if ((resolve != "None") && (stackLevel != 0)) {
// We come here if a setting has a resolve and the setting is not manually edited. // We come here if a setting has a resolve and the setting is not manually edited.
tooltipText += " " + catalog.i18nc("@label", "The value is resolved from per-extruder values ") + "[" + Cura.ExtruderManager.getInstanceExtruderValues(definition.key) + "]."; tooltipText += " " + catalog.i18nc("@label", "The value is resolved from per-extruder values ") + "[" + Cura.ExtruderManager.getInstanceExtruderValues(definition.key) + "].";

View file

@ -372,7 +372,7 @@ Item
{ {
id: provider id: provider
containerStackId: Cura.MachineManager.activeMachineId containerStackId: Cura.ExtruderManager.activeExtruderStackId
key: model.key ? model.key : "" key: model.key ? model.key : ""
watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ] watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ]
storeIndex: 0 storeIndex: 0

View file

@ -340,6 +340,8 @@ Item
text: catalog.i18nc("@label", "Print Speed") text: catalog.i18nc("@label", "Print Speed")
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
width: parseInt(UM.Theme.getSize("sidebar").width * 0.35)
elide: Text.ElideRight
} }
Label Label

View file

@ -25,9 +25,12 @@ Rectangle
property int allItemsWidth: 0; property int allItemsWidth: 0;
function updateMarginsAndSizes() { function updateMarginsAndSizes() {
if (UM.Preferences.getValue("cura/sidebar_collapse")) { if (UM.Preferences.getValue("cura/sidebar_collapsed"))
{
rightMargin = UM.Theme.getSize("default_margin").width; rightMargin = UM.Theme.getSize("default_margin").width;
} else { }
else
{
rightMargin = UM.Theme.getSize("sidebar").width + UM.Theme.getSize("default_margin").width; rightMargin = UM.Theme.getSize("sidebar").width + UM.Theme.getSize("default_margin").width;
} }
allItemsWidth = ( allItemsWidth = (

View file

@ -202,9 +202,8 @@ QtObject {
height: Theme.getSize("topbar_button_icon").height height: Theme.getSize("topbar_button_icon").height
Label Label
{ {
id: button_label
text: control.text; text: control.text;
anchors.right: (icon.visible || overlayIcon.visible) ? icon.left : parent.right
anchors.rightMargin: (icon.visible || overlayIcon.visible) ? Theme.getSize("default_margin").width : 0
anchors.verticalCenter: parent.verticalCenter; anchors.verticalCenter: parent.verticalCenter;
font: control.checked ? UM.Theme.getFont("large") : UM.Theme.getFont("large_nonbold") font: control.checked ? UM.Theme.getFont("large") : UM.Theme.getFont("large_nonbold")
color: color:
@ -227,6 +226,8 @@ QtObject {
{ {
visible: control.iconSource != "" visible: control.iconSource != ""
id: icon id: icon
anchors.left: button_label.right
anchors.leftMargin: (icon.visible || overlayIcon.visible) ? Theme.getSize("default_margin").width : 0
color: UM.Theme.getColor("text_emphasis") color: UM.Theme.getColor("text_emphasis")
opacity: !control.enabled ? 0.2 : 1.0 opacity: !control.enabled ? 0.2 : 1.0
source: control.iconSource source: control.iconSource
@ -238,6 +239,8 @@ QtObject {
UM.RecolorImage UM.RecolorImage
{ {
id: overlayIcon id: overlayIcon
anchors.left: button_label.right
anchors.leftMargin: (icon.visible || overlayIcon.visible) ? Theme.getSize("default_margin").width : 0
visible: control.overlayIconSource != "" && control.iconSource != "" visible: control.overlayIconSource != "" && control.iconSource != ""
color: control.overlayColor color: control.overlayColor
opacity: !control.enabled ? 0.2 : 1.0 opacity: !control.enabled ? 0.2 : 1.0