Merge pull request #1 from Ultimaker/master

Updating my fork
This commit is contained in:
Thomas-Karl Pietrowski 2015-09-19 20:36:49 +02:00
commit 4bc81c0c6a
146 changed files with 100384 additions and 48366 deletions

View File

@ -2,6 +2,8 @@
project(cura) project(cura)
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 2.8.12)
include(GNUInstallDirs)
set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository") set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository")
if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "") if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
@ -10,13 +12,11 @@ if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
# Build Translations # Build Translations
find_package(Gettext) find_package(Gettext)
include(${URANIUM_SCRIPTS_DIR}/ECMPoQmTools.cmake)
if(GETTEXT_FOUND) if(GETTEXT_FOUND)
# translations target will convert .po files into .mo and .qm as needed. # translations target will convert .po files into .mo and .qm as needed.
# The files are checked for a _qt suffix and if it is found, converted to # The files are checked for a _qt suffix and if it is found, converted to
# qm, otherwise they are converted to .po. # qm, otherwise they are converted to .po.
add_custom_target(translations) add_custom_target(translations ALL)
# copy-translations can be used to copy the built translation files from the # copy-translations can be used to copy the built translation files from the
# build directory to the source resources directory. This is mostly a convenience # build directory to the source resources directory. This is mostly a convenience
# during development, normally you want to simply use the install target to install # during development, normally you want to simply use the install target to install
@ -33,29 +33,27 @@ if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
it it
es es
fi fi
pl
cs
bg
) )
foreach(lang ${languages}) foreach(lang ${languages})
file(GLOB po_files resources/i18n/${lang}/*.po) file(GLOB po_files resources/i18n/${lang}/*.po)
foreach(file ${po_files}) foreach(file ${po_files})
string(REGEX MATCH "qt\\.po$" match "${file}") string(REGEX REPLACE ".*/(.*).po" "${lang}/\\1.mo" mofile ${file})
if(match) add_custom_command(TARGET translations POST_BUILD COMMAND mkdir ARGS -p ${lang} COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ARGS ${file} -o ${mofile})
ecm_process_po_files_as_qm(${lang} PO_FILES ${file})
else()
string(REGEX REPLACE ".*/(.*).po" "${lang}/\\1.mo" mofile ${file})
add_custom_command(TARGET translations POST_BUILD COMMAND mkdir ARGS -p ${lang} COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ARGS ${file} -o ${mofile})
endif()
endforeach() endforeach()
file(GLOB qm_files ${CMAKE_BINARY_DIR}/${lang}/*.qm)
file(GLOB mo_files ${CMAKE_BINARY_DIR}/${lang}/*.mo) file(GLOB mo_files ${CMAKE_BINARY_DIR}/${lang}/*.mo)
foreach(file ${qm_files} ${mo_files}) foreach(file ${mo_files})
add_custom_command(TARGET copy-translations POST_BUILD COMMAND mkdir ARGS -p ${CMAKE_SOURCE_DIR}/resources/i18n/${lang}/LC_MESSAGES/ COMMAND cp ARGS ${file} ${CMAKE_SOURCE_DIR}/resources/i18n/${lang}/LC_MESSAGES/ COMMENT "Copying ${file}...") add_custom_command(TARGET copy-translations POST_BUILD COMMAND mkdir ARGS -p ${CMAKE_SOURCE_DIR}/resources/i18n/${lang}/LC_MESSAGES/ COMMAND cp ARGS ${file} ${CMAKE_SOURCE_DIR}/resources/i18n/${lang}/LC_MESSAGES/ COMMENT "Copying ${file}...")
endforeach() endforeach()
install(FILES ${mo_files} DESTINATION ${CMAKE_INSTALL_DATADIR}/uranium/resources/i18n/${lang}/LC_MESSAGES/)
endforeach() endforeach()
endif() endif()
endif() endif()
include(GNUInstallDirs)
find_package(PythonInterp 3.4.0 REQUIRED) find_package(PythonInterp 3.4.0 REQUIRED)
install(DIRECTORY resources DESTINATION ${CMAKE_INSTALL_DATADIR}/cura) install(DIRECTORY resources DESTINATION ${CMAKE_INSTALL_DATADIR}/cura)

View File

@ -39,7 +39,8 @@ Please checkout [cura-build](https://github.com/Ultimaker/cura-build)
Third party plugins Third party plugins
------------- -------------
[Print time calculator](https://github.com/nallath/PrintCostCalculator) * [Print time calculator](https://github.com/nallath/PrintCostCalculator)
* [Post processing plugin](https://github.com/nallath/PostProcessingPlugin)
Making profiles for other printers Making profiles for other printers
---------------------------------- ----------------------------------

View File

@ -5,7 +5,7 @@ GenericName=3D Printing Software
Comment= Comment=
Exec=/usr/bin/cura_app.py Exec=/usr/bin/cura_app.py
TryExec=/usr/bin/cura_app.py TryExec=/usr/bin/cura_app.py
Icon=/usr/share/cura/resources/images/cura_icon.png Icon=/usr/share/cura/resources/images/cura-icon.png
Terminal=false Terminal=false
Type=Application Type=Application
Categories=Graphics; Categories=Graphics;

View File

@ -10,6 +10,7 @@ from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Math.Vector import Vector from UM.Math.Vector import Vector
from UM.Math.Color import Color from UM.Math.Color import Color
from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Math.AxisAlignedBox import AxisAlignedBox
from UM.Math.Polygon import Polygon
import numpy import numpy
@ -33,15 +34,18 @@ class BuildVolume(SceneNode):
self.setCalculateBoundingBox(False) self.setCalculateBoundingBox(False)
self._active_instance = None
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveInstanceChanged)
self._onActiveInstanceChanged()
def setWidth(self, width): def setWidth(self, width):
self._width = width if width: self._width = width
def setHeight(self, height): def setHeight(self, height):
self._height = height if height: self._height = height
def setDepth(self, depth): def setDepth(self, depth):
self._depth = depth if depth: self._depth = depth
def getDisallowedAreas(self): def getDisallowedAreas(self):
return self._disallowed_areas return self._disallowed_areas
@ -55,12 +59,12 @@ class BuildVolume(SceneNode):
if not self._material: if not self._material:
self._material = renderer.createMaterial( self._material = renderer.createMaterial(
Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.Shaders, "basic.vert"),
Resources.getPath(Resources.ShadersLocation, "vertexcolor.frag") Resources.getPath(Resources.Shaders, "vertexcolor.frag")
) )
self._grid_material = renderer.createMaterial( self._grid_material = renderer.createMaterial(
Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.Shaders, "basic.vert"),
Resources.getPath(Resources.ShadersLocation, "grid.frag") Resources.getPath(Resources.Shaders, "grid.frag")
) )
self._grid_material.setUniformValue("u_gridColor0", Color(245, 245, 245, 255)) self._grid_material.setUniformValue("u_gridColor0", Color(245, 245, 245, 255))
self._grid_material.setUniformValue("u_gridColor1", Color(205, 202, 201, 255)) self._grid_material.setUniformValue("u_gridColor1", Color(205, 202, 201, 255))
@ -135,17 +139,18 @@ class BuildVolume(SceneNode):
self._aabb = AxisAlignedBox(minimum = Vector(minW, minH - 1.0, minD), maximum = Vector(maxW, maxH, maxD)) self._aabb = AxisAlignedBox(minimum = Vector(minW, minH - 1.0, minD), maximum = Vector(maxW, maxH, maxD))
settings = Application.getInstance().getActiveMachine()
skirt_size = 0.0 skirt_size = 0.0
if settings.getSettingValueByKey("adhesion_type") == "None":
skirt_size = settings.getSettingValueByKey("skirt_line_count") * settings.getSettingValueByKey("skirt_line_width") + settings.getSettingValueByKey("skirt_gap")
elif settings.getSettingValueByKey("adhesion_type") == "Brim":
skirt_size = settings.getSettingValueByKey("brim_line_count") * settings.getSettingValueByKey("skirt_line_width")
else:
skirt_size = settings.getSettingValueByKey("skirt_line_width")
skirt_size += settings.getSettingValueByKey("skirt_line_width") #profile = Application.getInstance().getMachineManager().getActiveProfile()
#if profile:
#if profile.getSettingValue("adhesion_type") == "skirt":
#skirt_size = profile.getSettingValue("skirt_line_count") * profile.getSettingValue("skirt_line_width") + profile.getSettingValue("skirt_gap")
#elif profile.getSettingValue("adhesion_type") == "brim":
#skirt_size = profile.getSettingValue("brim_line_count") * profile.getSettingValue("skirt_line_width")
#else:
#skirt_size = profile.getSettingValue("skirt_line_width")
#skirt_size += profile.getSettingValue("skirt_line_width")
scale_to_max_bounds = AxisAlignedBox( scale_to_max_bounds = AxisAlignedBox(
minimum = Vector(minW + skirt_size, minH, minD + skirt_size + disallowed_area_size), minimum = Vector(minW + skirt_size, minH, minD + skirt_size + disallowed_area_size),
@ -153,3 +158,21 @@ class BuildVolume(SceneNode):
) )
Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
def _onActiveInstanceChanged(self):
self._active_instance = Application.getInstance().getMachineManager().getActiveMachineInstance()
if self._active_instance:
self._width = self._active_instance.getMachineSettingValue("machine_width")
self._height = self._active_instance.getMachineSettingValue("machine_height")
self._depth = self._active_instance.getMachineSettingValue("machine_depth")
disallowed_areas = self._active_instance.getMachineSettingValue("machine_disallowed_areas")
areas = []
if disallowed_areas:
for area in disallowed_areas:
areas.append(Polygon(numpy.array(area, numpy.float32)))
self._disallowed_areas = areas
self.rebuild()

View File

@ -14,18 +14,10 @@ class ConvexHullDecorator(SceneNodeDecorator):
self._convex_hull_node = None self._convex_hull_node = None
self._convex_hull_job = None self._convex_hull_job = None
settings = Application.getInstance().getActiveMachine()
print_sequence_setting = settings.getSettingByKey("print_sequence")
if print_sequence_setting:
print_sequence_setting.valueChanged.connect(self._onPrintSequenceSettingChanged)
def _onPrintSequenceSettingChanged(self, setting): self._profile = None
if self._convex_hull_job: Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
self._convex_hull_job.cancel() self._onActiveProfileChanged()
self.setConvexHull(None)
if self._convex_hull_node:
self._convex_hull_node.setParent(None)
self._convex_hull_node = None
def getConvexHull(self): def getConvexHull(self):
return self._convex_hull return self._convex_hull
@ -61,4 +53,20 @@ class ConvexHullDecorator(SceneNodeDecorator):
def setConvexHullNode(self, node): def setConvexHullNode(self, node):
self._convex_hull_node = node self._convex_hull_node = node
def _onActiveProfileChanged(self):
if self._profile:
self._profile.settingValueChanged.disconnect(self._onSettingValueChanged)
self._profile = Application.getInstance().getMachineManager().getActiveProfile()
if self._profile:
self._profile.settingValueChanged.connect(self._onSettingValueChanged)
def _onSettingValueChanged(self, setting):
if setting == "print_sequence":
if self._convex_hull_job:
self._convex_hull_job.cancel()
self.setConvexHull(None)
if self._convex_hull_node:
self._convex_hull_node.setParent(None)
self._convex_hull_node = None

View File

@ -36,7 +36,8 @@ class ConvexHullJob(Job):
return return
mesh = self._node.getMeshData() mesh = self._node.getMeshData()
vertex_data = mesh.getTransformed(self._node.getWorldTransformation()).getVertices() vertex_data = mesh.getTransformed(self._node.getWorldTransformation()).getVertices()
# Don't use data below 0. TODO; We need a better check for this as this gives poor results for meshes with long edges.
vertex_data = vertex_data[vertex_data[:,1]>0]
hull = Polygon(numpy.rint(vertex_data[:, [0, 2]]).astype(int)) hull = Polygon(numpy.rint(vertex_data[:, [0, 2]]).astype(int))
# First, calculate the normal convex hull around the points # First, calculate the normal convex hull around the points
@ -45,14 +46,17 @@ class ConvexHullJob(Job):
# Then, do a Minkowski hull with a simple 1x1 quad to outset and round the normal convex hull. # Then, do a Minkowski hull with a simple 1x1 quad to outset and round the normal convex hull.
# This is done because of rounding errors. # This is done because of rounding errors.
hull = hull.getMinkowskiHull(Polygon(numpy.array([[-1, -1], [-1, 1], [1, 1], [1, -1]], numpy.float32))) hull = hull.getMinkowskiHull(Polygon(numpy.array([[-1, -1], [-1, 1], [1, 1], [1, -1]], numpy.float32)))
settings = Application.getInstance().getActiveMachine()
if settings.getSettingValueByKey("print_sequence") == "One at a time" and not self._node.getParent().callDecoration("isGroup"): profile = Application.getInstance().getMachineManager().getActiveProfile()
# Printing one at a time and it's not an object in a group if profile:
self._node.callDecoration("setConvexHullBoundary", copy.deepcopy(hull)) if profile.getSettingValue("print_sequence") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"):
head_hull = hull.getMinkowskiHull(Polygon(numpy.array(settings.getSettingValueByKey("machine_head_with_fans_polygon"),numpy.float32))) # Printing one at a time and it's not an object in a group
self._node.callDecoration("setConvexHullHead", head_hull) self._node.callDecoration("setConvexHullBoundary", copy.deepcopy(hull))
hull = hull.getMinkowskiHull(Polygon(numpy.array(settings.getSettingValueByKey("machine_head_polygon"),numpy.float32))) head_hull = hull.getMinkowskiHull(Polygon(numpy.array(profile.getSettingValue("machine_head_with_fans_polygon"),numpy.float32)))
self._node.callDecoration("setConvexHullHead", head_hull)
hull = hull.getMinkowskiHull(Polygon(numpy.array(profile.getSettingValue("machine_head_polygon"),numpy.float32)))
else:
self._node.callDecoration("setConvexHullHead", None)
hull_node = ConvexHullNode.ConvexHullNode(self._node, hull, Application.getInstance().getController().getScene().getRoot()) hull_node = ConvexHullNode.ConvexHullNode(self._node, hull, Application.getInstance().getController().getScene().getRoot())
self._node.callDecoration("setConvexHullNode", hull_node) self._node.callDecoration("setConvexHullNode", hull_node)
self._node.callDecoration("setConvexHull", hull) self._node.callDecoration("setConvexHull", hull)
@ -66,4 +70,3 @@ class ConvexHullJob(Job):
hull_node = self._node.getParent().callDecoration("getConvexHullNode") hull_node = self._node.getParent().callDecoration("getConvexHullNode")
if hull_node: if hull_node:
hull_node.setParent(None) hull_node.setParent(None)

View File

@ -22,22 +22,33 @@ class ConvexHullNode(SceneNode):
self._inherit_orientation = False self._inherit_orientation = False
self._inherit_scale = False self._inherit_scale = False
self._color = Color(35, 35, 35, 0.5)
self._node = node self._node = node
self._node.transformationChanged.connect(self._onNodePositionChanged) self._node.transformationChanged.connect(self._onNodePositionChanged)
self._node.parentChanged.connect(self._onNodeParentChanged) self._node.parentChanged.connect(self._onNodeParentChanged)
#self._onNodePositionChanged(self._node) self._node.decoratorsChanged.connect(self._onNodeDecoratorsChanged)
self._onNodeDecoratorsChanged(self._node)
self.convexHullHeadMesh = None
self._hull = hull self._hull = hull
hull_points = self._hull.getPoints() hull_points = self._hull.getPoints()
center = (hull_points.min(0) + hull_points.max(0)) / 2.0 hull_mesh = self.createHullMesh(self._hull.getPoints())
if hull_mesh:
self.setMeshData(hull_mesh)
convex_hull_head = self._node.callDecoration("getConvexHullHead")
if convex_hull_head:
self.convexHullHeadMesh = self.createHullMesh(convex_hull_head.getPoints())
def createHullMesh(self, hull_points):
mesh = MeshData() mesh = MeshData()
mesh.addVertex(center[0], 0.1, center[1]) if len(hull_points) > 3:
center = (hull_points.min(0) + hull_points.max(0)) / 2.0
mesh.addVertex(center[0], 0.1, center[1])
else:
return None
for point in hull_points: for point in hull_points:
mesh.addVertex(point[0], 0.1, point[1]) mesh.addVertex(point[0], 0.1, point[1])
indices = [] indices = []
for i in range(len(hull_points) - 1): for i in range(len(hull_points) - 1):
indices.append([0, i + 1, i + 2]) indices.append([0, i + 1, i + 2])
@ -45,35 +56,43 @@ class ConvexHullNode(SceneNode):
indices.append([0, mesh.getVertexCount() - 1, 1]) indices.append([0, mesh.getVertexCount() - 1, 1])
mesh.addIndices(numpy.array(indices, numpy.int32)) mesh.addIndices(numpy.array(indices, numpy.int32))
return mesh
self.setMeshData(mesh)
def getWatchedNode(self): def getWatchedNode(self):
return self._node return self._node
def render(self, renderer): def render(self, renderer):
if not self._material: if not self._material:
self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "color.frag")) self._material = renderer.createMaterial(Resources.getPath(Resources.Shaders, "basic.vert"), Resources.getPath(Resources.Shaders, "color.frag"))
self._material.setUniformValue("u_color", Color(35, 35, 35, 128))
if self.getParent(): if self.getParent():
self._material.setUniformValue("u_color", self._color)
renderer.queueNode(self, material = self._material, transparent = True) renderer.queueNode(self, material = self._material, transparent = True)
if self.convexHullHeadMesh:
renderer.queueNode(self, material = self._material,transparent = True, mesh = self.convexHullHeadMesh)
return True return True
def _onNodePositionChanged(self, node): def _onNodePositionChanged(self, node):
#self.setPosition(node.getWorldPosition())
if node.callDecoration("getConvexHull"): if node.callDecoration("getConvexHull"):
node.callDecoration("setConvexHull", None) node.callDecoration("setConvexHull", None)
node.callDecoration("setConvexHullNode", None) node.callDecoration("setConvexHullNode", None)
self.setParent(None) self.setParent(None)
#self._node.transformationChanged.disconnect(self._onNodePositionChanged)
#self._node.parentChanged.disconnect(self._onNodeParentChanged)
def _onNodeParentChanged(self, node): def _onNodeParentChanged(self, node):
if node.getParent(): if node.getParent():
self.setParent(self._original_parent) self.setParent(self._original_parent)
else: else:
self.setParent(None) self.setParent(None)
def _onNodeDecoratorsChanged(self, node):
self._color = Color(35, 35, 35, 0.5)
if not node:
return
if node.hasDecoration("getProfile"):
self._color.setR(0.75)
if node.hasDecoration("getSetting"):
self._color.setG(0.75)

View File

@ -3,18 +3,27 @@ import platform
import traceback import traceback
import webbrowser import webbrowser
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QCoreApplication
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
def show(type, value, tb):
if not hasattr(sys, "frozen"):
traceback.print_exception(type, value, tb)
application = QCoreApplication.instance()
if not application:
sys.exit(1)
def show():
dialog = QDialog() dialog = QDialog()
dialog.setWindowTitle("Oops!") dialog.setWindowTitle(catalog.i18nc("@title:window", "Oops!"))
layout = QVBoxLayout(dialog) layout = QVBoxLayout(dialog)
label = QLabel(dialog) label = QLabel(dialog)
layout.addWidget(label) layout.addWidget(label)
label.setText("<p>An uncaught exception has occurred!</p><p>Please use the information below to post a bug report at <a href=\"http://github.com/Ultimaker/Cura/issues\">http://github.com/Ultimaker/Cura/issues</a></p>") label.setText(catalog.i18nc("@label", "<p>An uncaught exception has occurred!</p><p>Please use the information below to post a bug report at <a href=\"http://github.com/Ultimaker/Cura/issues\">http://github.com/Ultimaker/Cura/issues</a></p>"))
textarea = QTextEdit(dialog) textarea = QTextEdit(dialog)
layout.addWidget(textarea) layout.addWidget(textarea)
@ -25,7 +34,7 @@ def show():
except: except:
version = "Unknown" version = "Unknown"
trace = "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) trace = "".join(traceback.format_exception(type, value, tb))
crash_info = "Version: {0}\nPlatform: {1}\nQt: {2}\nPyQt: {3}\n\nException:\n{4}" crash_info = "Version: {0}\nPlatform: {1}\nQt: {2}\nPyQt: {3}\n\nException:\n{4}"
crash_info = crash_info.format(version, platform.platform(), QT_VERSION_STR, PYQT_VERSION_STR, trace) crash_info = crash_info.format(version, platform.platform(), QT_VERSION_STR, PYQT_VERSION_STR, trace)
@ -34,8 +43,9 @@ def show():
buttons = QDialogButtonBox(QDialogButtonBox.Close, dialog) buttons = QDialogButtonBox(QDialogButtonBox.Close, dialog)
layout.addWidget(buttons) layout.addWidget(buttons)
buttons.addButton("Open Web Page", QDialogButtonBox.HelpRole) buttons.addButton(catalog.i18nc("@action:button", "Open Web Page"), QDialogButtonBox.HelpRole)
buttons.rejected.connect(lambda: dialog.close()) buttons.rejected.connect(lambda: dialog.close())
buttons.helpRequested.connect(lambda: webbrowser.open("http://github.com/Ultimaker/Cura/issues")) buttons.helpRequested.connect(lambda: webbrowser.open("http://github.com/Ultimaker/Cura/issues"))
dialog.exec_() dialog.exec_()
sys.exit(1)

View File

@ -1,6 +1,13 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
import platform
if platform.system() == "Linux": # Needed for platform.linux_distribution, which is not available on Windows and OSX
# For Ubuntu: https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
if platform.linux_distribution()[0] in ("Ubuntu", ): # Just in case it also happens on Debian, so it can be added
from OpenGL import GL
from UM.Qt.QtApplication import QtApplication from UM.Qt.QtApplication import QtApplication
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
from UM.Scene.Camera import Camera from UM.Scene.Camera import Camera
@ -38,26 +45,32 @@ from . import PrintInformation
from . import CuraActions from . import CuraActions
from . import MultiMaterialDecorator from . import MultiMaterialDecorator
from PyQt5.QtCore import pyqtSlot, QUrl, Qt, pyqtSignal, pyqtProperty from PyQt5.QtCore import pyqtSlot, QUrl, Qt, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
from PyQt5.QtGui import QColor, QIcon from PyQt5.QtGui import QColor, QIcon
from PyQt5.QtQml import qmlRegisterUncreatableType
import platform import platform
import sys import sys
import os import os
import os.path import os.path
import configparser
import numpy import numpy
import copy
numpy.seterr(all="ignore") numpy.seterr(all="ignore")
class CuraApplication(QtApplication): class CuraApplication(QtApplication):
class ResourceTypes:
QmlFiles = Resources.UserType + 1
Firmware = Resources.UserType + 2
Q_ENUMS(ResourceTypes)
def __init__(self): def __init__(self):
Resources.addResourcePath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura")) Resources.addSearchPath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura"))
if not hasattr(sys, "frozen"): if not hasattr(sys, "frozen"):
Resources.addResourcePath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))
super().__init__(name = "cura", version = "master") super().__init__(name = "cura", version = "15.09.82")
self.setWindowIcon(QIcon(Resources.getPath(Resources.ImagesLocation, "cura-icon.png"))) self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
self.setRequiredPlugins([ self.setRequiredPlugins([
"CuraEngineBackend", "CuraEngineBackend",
@ -78,12 +91,19 @@ class CuraApplication(QtApplication):
self._previous_active_tool = None self._previous_active_tool = None
self._platform_activity = False self._platform_activity = False
self.activeMachineChanged.connect(self._onActiveMachineChanged) self.getMachineManager().activeMachineInstanceChanged.connect(self._onActiveMachineChanged)
self.getMachineManager().addMachineRequested.connect(self._onAddMachineRequested)
self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity)
Resources.addType(self.ResourceTypes.QmlFiles, "qml")
Resources.addType(self.ResourceTypes.Firmware, "firmware")
Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_machine", "")
Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/active_mode", "simple")
Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/recent_files", "")
Preferences.getInstance().addPreference("cura/categories_expanded", "") Preferences.getInstance().addPreference("cura/categories_expanded", "")
Preferences.getInstance().addPreference("view/center_on_select", True)
Preferences.getInstance().addPreference("mesh/scale_to_fit", True)
JobQueue.getInstance().jobFinished.connect(self._onJobFinished) JobQueue.getInstance().jobFinished.connect(self._onJobFinished)
@ -115,7 +135,12 @@ class CuraApplication(QtApplication):
def run(self): def run(self):
self._i18n_catalog = i18nCatalog("cura"); self._i18n_catalog = i18nCatalog("cura");
self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) i18nCatalog.setTagReplacements({
"filename": "font color=\"black\"",
"message": "font color=UM.Theme.colors.message_text;",
})
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene..."))
controller = self.getController() controller = self.getController()
@ -125,7 +150,7 @@ class CuraApplication(QtApplication):
t = controller.getTool("TranslateTool") t = controller.getTool("TranslateTool")
if t: if t:
t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.ZAxis]) t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis,ToolHandle.ZAxis])
Selection.selectionChanged.connect(self.onSelectionChanged) Selection.selectionChanged.connect(self.onSelectionChanged)
@ -149,33 +174,34 @@ class CuraApplication(QtApplication):
controller.getScene().setActiveCamera("3d") controller.getScene().setActiveCamera("3d")
self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Loading interface...")) self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface..."))
self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml")) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
self.initializeEngine() self.initializeEngine()
if self.getMachines(): manager = self.getMachineManager()
active_machine_pref = Preferences.getInstance().getValue("cura/active_machine") if not self.getMachineManager().getMachineInstances():
if active_machine_pref:
for machine in self.getMachines():
if machine.getName() == active_machine_pref:
self.setActiveMachine(machine)
if not self.getActiveMachine():
self.setActiveMachine(self.getMachines()[0])
else:
self.requestAddPrinter.emit() self.requestAddPrinter.emit()
if self._engine.rootObjects: if self._engine.rootObjects:
self.closeSplash() self.closeSplash()
for file in self.getCommandLineOption("file", []): for file in self.getCommandLineOption("file", []):
job = ReadMeshJob(os.path.abspath(file)) self._openFile(file)
job.finished.connect(self._onFileLoaded)
job.start()
self.exec_() self.exec_()
# Handle Qt events
def event(self, event):
if event.type() == QEvent.FileOpen:
self._openFile(event.file())
return super().event(event)
def getPrintInformation(self):
return self._print_information
def registerObjects(self, engine): def registerObjects(self, engine):
engine.rootContext().setContextProperty("Printer", self) engine.rootContext().setContextProperty("Printer", self)
self._print_information = PrintInformation.PrintInformation() self._print_information = PrintInformation.PrintInformation()
@ -183,6 +209,8 @@ class CuraApplication(QtApplication):
self._cura_actions = CuraActions.CuraActions(self) self._cura_actions = CuraActions.CuraActions(self)
engine.rootContext().setContextProperty("CuraActions", self._cura_actions) engine.rootContext().setContextProperty("CuraActions", self._cura_actions)
qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type")
def onSelectionChanged(self): def onSelectionChanged(self):
if Selection.hasSelection(): if Selection.hasSelection():
if not self.getController().getActiveTool(): if not self.getController().getActiveTool():
@ -191,10 +219,10 @@ class CuraApplication(QtApplication):
self._previous_active_tool = None self._previous_active_tool = None
else: else:
self.getController().setActiveTool("TranslateTool") self.getController().setActiveTool("TranslateTool")
if Preferences.getInstance().getValue("view/center_on_select"):
self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin()) self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin())
self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition()) self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition())
self._camera_animation.start() self._camera_animation.start()
else: else:
if self.getController().getActiveTool(): if self.getController().getActiveTool():
self._previous_active_tool = self.getController().getActiveTool().getPluginId() self._previous_active_tool = self.getController().getActiveTool().getPluginId()
@ -209,24 +237,15 @@ class CuraApplication(QtApplication):
def getPlatformActivity(self): def getPlatformActivity(self):
return self._platform_activity return self._platform_activity
@pyqtSlot(bool) def updatePlatformActivity(self, node = None):
def setPlatformActivity(self, activity): count = 0
##Sets the _platform_activity variable on true or false depending on whether there is a mesh on the platform for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if activity == True: if type(node) is not SceneNode or not node.getMeshData():
self._platform_activity = activity continue
elif activity == False:
nodes = [] count += 1
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData(): self._platform_activity = True if count > 0 else False
continue
nodes.append(node)
i = 0
for node in nodes:
if not node.getMeshData():
continue
i += 1
if i <= 1: ## i == 0 when the meshes are removed using the deleteAll function; i == 1 when the last remaining mesh is removed using the deleteObject function
self._platform_activity = activity
self.activityChanged.emit() self.activityChanged.emit()
## Remove an object from the scene ## Remove an object from the scene
@ -247,7 +266,6 @@ class CuraApplication(QtApplication):
group_node = group_node.getParent() group_node = group_node.getParent()
op = RemoveSceneNodeOperation(group_node) op = RemoveSceneNodeOperation(group_node)
op.push() op.push()
self.setPlatformActivity(False)
## Create a number of copies of existing object. ## Create a number of copies of existing object.
@pyqtSlot("quint64", int) @pyqtSlot("quint64", int)
@ -260,22 +278,26 @@ class CuraApplication(QtApplication):
if node: if node:
op = GroupedOperation() op = GroupedOperation()
for i in range(count): for i in range(count):
new_node = SceneNode() if node.getParent() and node.getParent().callDecoration("isGroup"):
new_node.setMeshData(node.getMeshData()) new_node = copy.deepcopy(node.getParent()) #Copy the group node.
new_node.setScale(node.getScale()) new_node.callDecoration("setConvexHull",None)
new_node.translate(Vector((i + 1) * node.getBoundingBox().width, 0, 0))
new_node.setSelectable(True) op.addOperation(AddSceneNodeOperation(new_node,node.getParent().getParent()))
op.addOperation(AddSceneNodeOperation(new_node, node.getParent())) else:
new_node = copy.deepcopy(node)
new_node.callDecoration("setConvexHull", None)
op.addOperation(AddSceneNodeOperation(new_node, node.getParent()))
op.push() op.push()
## Center object on platform. ## Center object on platform.
@pyqtSlot("quint64") @pyqtSlot("quint64")
def centerObject(self, object_id): def centerObject(self, object_id):
node = self.getController().getScene().findObject(object_id) node = self.getController().getScene().findObject(object_id)
if node.getParent() and node.getParent().callDecoration("isGroup"):
node = node.getParent()
if not node and object_id != 0: #Workaround for tool handles overlapping the selected object if not node and object_id != 0: #Workaround for tool handles overlapping the selected object
node = Selection.getSelectedObject(0) node = Selection.getSelectedObject(0)
if node: if node:
op = SetTransformOperation(node, Vector()) op = SetTransformOperation(node, Vector())
op.push() op.push()
@ -285,8 +307,12 @@ class CuraApplication(QtApplication):
def deleteAll(self): def deleteAll(self):
nodes = [] nodes = []
for node in DepthFirstIterator(self.getController().getScene().getRoot()): for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData(): if type(node) is not SceneNode:
continue continue
if not node.getMeshData() and not node.callDecoration("isGroup"):
continue #Node that doesnt have a mesh and is not a group.
if node.getParent() and node.getParent().callDecoration("isGroup"):
continue #Grouped nodes don't need resetting as their parent (the group) is resetted)
nodes.append(node) nodes.append(node)
if nodes: if nodes:
op = GroupedOperation() op = GroupedOperation()
@ -295,22 +321,28 @@ class CuraApplication(QtApplication):
op.addOperation(RemoveSceneNodeOperation(node)) op.addOperation(RemoveSceneNodeOperation(node))
op.push() op.push()
self.setPlatformActivity(False)
## Reset all translation on nodes with mesh data. ## Reset all translation on nodes with mesh data.
@pyqtSlot() @pyqtSlot()
def resetAllTranslation(self): def resetAllTranslation(self):
nodes = [] nodes = []
for node in DepthFirstIterator(self.getController().getScene().getRoot()): for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData(): if type(node) is not SceneNode:
continue continue
nodes.append(node) if not node.getMeshData() and not node.callDecoration("isGroup"):
continue #Node that doesnt have a mesh and is not a group.
if node.getParent() and node.getParent().callDecoration("isGroup"):
continue #Grouped nodes don't need resetting as their parent (the group) is resetted)
nodes.append(node)
if nodes: if nodes:
op = GroupedOperation() op = GroupedOperation()
for node in nodes: for node in nodes:
op.addOperation(SetTransformOperation(node, Vector())) # Ensure that the object is above the build platform
move_distance = node.getBoundingBox().center.y
if move_distance <= 0:
move_distance = -node.getBoundingBox().bottom
op.addOperation(SetTransformOperation(node, Vector(0,move_distance,0)))
op.push() op.push()
@ -319,15 +351,23 @@ class CuraApplication(QtApplication):
def resetAll(self): def resetAll(self):
nodes = [] nodes = []
for node in DepthFirstIterator(self.getController().getScene().getRoot()): for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData(): if type(node) is not SceneNode:
continue continue
if not node.getMeshData() and not node.callDecoration("isGroup"):
continue #Node that doesnt have a mesh and is not a group.
if node.getParent() and node.getParent().callDecoration("isGroup"):
continue #Grouped nodes don't need resetting as their parent (the group) is resetted)
nodes.append(node) nodes.append(node)
if nodes: if nodes:
op = GroupedOperation() op = GroupedOperation()
for node in nodes: for node in nodes:
op.addOperation(SetTransformOperation(node, Vector(), Quaternion(), Vector(1, 1, 1))) # Ensure that the object is above the build platform
move_distance = node.getBoundingBox().center.y
if move_distance <= 0:
move_distance = -node.getBoundingBox().bottom
op.addOperation(SetTransformOperation(node, Vector(0,move_distance,0), Quaternion(), Vector(1, 1, 1)))
op.push() op.push()
@ -387,18 +427,18 @@ class CuraApplication(QtApplication):
@pyqtSlot(str, result = "QVariant") @pyqtSlot(str, result = "QVariant")
def getSettingValue(self, key): def getSettingValue(self, key):
if not self.getActiveMachine(): if not self.getMachineManager().getActiveProfile():
return None return None
return self.getMachineManager().getActiveProfile().getSettingValue(key)
return self.getActiveMachine().getSettingValueByKey(key) #return self.getActiveMachine().getSettingValueByKey(key)
## Change setting by key value pair ## Change setting by key value pair
@pyqtSlot(str, "QVariant") @pyqtSlot(str, "QVariant")
def setSettingValue(self, key, value): def setSettingValue(self, key, value):
if not self.getActiveMachine(): if not self.getMachineManager().getActiveProfile():
return return
self.getActiveMachine().setSettingValueByKey(key, value) self.getMachineManager().getActiveProfile().setSettingValue(key, value)
@pyqtSlot() @pyqtSlot()
def mergeSelected(self): def mergeSelected(self):
@ -412,7 +452,7 @@ class CuraApplication(QtApplication):
# Reset the position of each node # Reset the position of each node
for node in group_node.getChildren(): for node in group_node.getChildren():
new_position = node.getMeshData().getCenterPosition() new_position = node.getMeshData().getCenterPosition()
new_position.setY(0) new_position = new_position.scale(node.getScale())
node.setPosition(new_position) node.setPosition(new_position)
# Use the previously found center of the group bounding box as the new location of the group # Use the previously found center of the group bounding box as the new location of the group
@ -427,7 +467,9 @@ class CuraApplication(QtApplication):
for node in Selection.getAllSelectedObjects(): for node in Selection.getAllSelectedObjects():
node.setParent(group_node) node.setParent(group_node)
group_node.setCenterPosition(group_node.getBoundingBox().center)
#group_node.translate(Vector(0,group_node.getBoundingBox().center.y,0))
group_node.translate(group_node.getBoundingBox().center)
for node in group_node.getChildren(): for node in group_node.getChildren():
Selection.remove(node) Selection.remove(node)
@ -446,6 +488,12 @@ class CuraApplication(QtApplication):
for child in children_to_move: for child in children_to_move:
child.setParent(node.getParent()) child.setParent(node.getParent())
print(node.getPosition())
child.translate(node.getPosition())
child.setPosition(child.getPosition().scale(node.getScale()))
child.scale(node.getScale())
child.rotate(node.getOrientation())
Selection.add(child) Selection.add(child)
child.callDecoration("setConvexHull",None) child.callDecoration("setConvexHull",None)
node.setParent(None) node.setParent(None)
@ -454,37 +502,35 @@ class CuraApplication(QtApplication):
Selection.remove(node) Selection.remove(node)
def _onActiveMachineChanged(self): def _onActiveMachineChanged(self):
machine = self.getActiveMachine() machine = self.getMachineManager().getActiveMachineInstance()
if machine: if machine:
Preferences.getInstance().setValue("cura/active_machine", machine.getName()) pass
#Preferences.getInstance().setValue("cura/active_machine", machine.getName())
self._volume.setWidth(machine.getSettingValueByKey("machine_width")) #self._volume.setWidth(machine.getSettingValueByKey("machine_width"))
self._volume.setHeight(machine.getSettingValueByKey("machine_height")) #self._volume.setHeight(machine.getSettingValueByKey("machine_height"))
self._volume.setDepth(machine.getSettingValueByKey("machine_depth")) #self._volume.setDepth(machine.getSettingValueByKey("machine_depth"))
disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas") #disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas")
areas = [] #areas = []
if disallowed_areas: #if disallowed_areas:
for area in disallowed_areas: #for area in disallowed_areas:
areas.append(Polygon(numpy.array(area, numpy.float32))) #areas.append(Polygon(numpy.array(area, numpy.float32)))
self._volume.setDisallowedAreas(areas) #self._volume.setDisallowedAreas(areas)
self._volume.rebuild() #self._volume.rebuild()
offset = machine.getSettingValueByKey("machine_platform_offset") #offset = machine.getSettingValueByKey("machine_platform_offset")
if offset: #if offset:
self._platform.setPosition(Vector(offset[0], offset[1], offset[2])) #self._platform.setPosition(Vector(offset[0], offset[1], offset[2]))
else: #else:
self._platform.setPosition(Vector(0.0, 0.0, 0.0)) #self._platform.setPosition(Vector(0.0, 0.0, 0.0))
def _onFileLoaded(self, job): def _onFileLoaded(self, job):
mesh = job.getResult() node = job.getResult()
if mesh != None: if node != None:
node = SceneNode()
node.setSelectable(True) node.setSelectable(True)
node.setMeshData(mesh)
node.setName(os.path.basename(job.getFileName())) node.setName(os.path.basename(job.getFileName()))
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot()) op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
@ -510,4 +556,16 @@ class CuraApplication(QtApplication):
self.recentFilesChanged.emit() self.recentFilesChanged.emit()
def _reloadMeshFinished(self, job): def _reloadMeshFinished(self, job):
job._node.setMeshData(job.getResult()) # TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh!
job._node.setMeshData(job.getResult().getMeshData())
#job.getResult().setParent(self.getController().getScene().getRoot())
#job._node.setParent(self.getController().getScene().getRoot())
#job._node.meshDataChanged.emit(job._node)
def _openFile(self, file):
job = ReadMeshJob(os.path.abspath(file))
job.finished.connect(self._onFileLoaded)
job.start()
def _onAddMachineRequested(self):
self.requestAddPrinter.emit()

View File

@ -2,6 +2,7 @@
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from UM.Scene.Iterator import Iterator from UM.Scene.Iterator import Iterator
from UM.Scene.SceneNode import SceneNode
from functools import cmp_to_key from functools import cmp_to_key
from UM.Application import Application from UM.Application import Application
@ -10,14 +11,17 @@ from UM.Application import Application
# Take note that the list of nodes can have children (that may or may not contain mesh data) # Take note that the list of nodes can have children (that may or may not contain mesh data)
class OneAtATimeIterator(Iterator.Iterator): class OneAtATimeIterator(Iterator.Iterator):
def __init__(self, scene_node): def __init__(self, scene_node):
super(OneAtATimeIterator, self).__init__(scene_node) # Call super to make multiple inheritence work. super().__init__(scene_node) # Call super to make multiple inheritence work.
self._hit_map = [[]] self._hit_map = [[]]
self._original_node_list = [] self._original_node_list = []
def _fillStack(self): def _fillStack(self):
node_list = [] node_list = []
for node in self._scene_node.getChildren(): for node in self._scene_node.getChildren():
if node.getBoundingBox().height > Application.getInstance().getActiveMachine().getSettingValueByKey("gantry_height"): if not type(node) is SceneNode:
continue
if node.getBoundingBox().height > Application.getInstance().getMachineManager().getActiveProfile().getSettingValue("gantry_height"):
return return
if node.callDecoration("getConvexHull"): if node.callDecoration("getConvexHull"):
node_list.append(node) node_list.append(node)
@ -55,7 +59,7 @@ class OneAtATimeIterator(Iterator.Iterator):
# We have no more nodes to check, so quit looking. # We have no more nodes to check, so quit looking.
todo_node_list = None todo_node_list = None
self._node_stack = new_order self._node_stack = new_order
print(self._node_stack)
return return
todo_node_list.append(_objectOrder(new_order, new_todo_list)) todo_node_list.append(_objectOrder(new_order, new_todo_list))
self._node_stack = [] #No result found! self._node_stack = [] #No result found!

View File

@ -6,12 +6,13 @@ from PyQt5.QtCore import QTimer
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
from UM.Operations.TranslateOperation import TranslateOperation from UM.Operations.TranslateOperation import TranslateOperation
from UM.Operations.ScaleToBoundsOperation import ScaleToBoundsOperation
from UM.Math.Float import Float from UM.Math.Float import Float
from UM.Math.Vector import Vector from UM.Math.Vector import Vector
from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Math.AxisAlignedBox import AxisAlignedBox
from UM.Application import Application from UM.Application import Application
from UM.Scene.Selection import Selection from UM.Scene.Selection import Selection
from UM.Preferences import Preferences
from cura.ConvexHullDecorator import ConvexHullDecorator from cura.ConvexHullDecorator import ConvexHullDecorator
from . import PlatformPhysicsOperation from . import PlatformPhysicsOperation
@ -19,6 +20,7 @@ from . import ConvexHullJob
import time import time
import threading import threading
import copy
class PlatformPhysics: class PlatformPhysics:
def __init__(self, controller, volume): def __init__(self, controller, volume):
@ -36,6 +38,8 @@ class PlatformPhysics:
self._change_timer.setSingleShot(True) self._change_timer.setSingleShot(True)
self._change_timer.timeout.connect(self._onChangeTimerFinished) self._change_timer.timeout.connect(self._onChangeTimerFinished)
Preferences.getInstance().addPreference("physics/automatic_push_free", True)
def _onSceneChanged(self, source): def _onSceneChanged(self, source):
self._change_timer.start() self._change_timer.start()
@ -53,16 +57,22 @@ class PlatformPhysics:
self._change_timer.start() self._change_timer.start()
continue continue
build_volume_bounding_box = copy.deepcopy(self._build_volume.getBoundingBox())
build_volume_bounding_box.setBottom(-9001) # Ignore intersections with the bottom
# Mark the node as outside the build volume if the bounding box test fails. # Mark the node as outside the build volume if the bounding box test fails.
if self._build_volume.getBoundingBox().intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
node._outside_buildarea = True node._outside_buildarea = True
else: else:
node._outside_buildarea = False node._outside_buildarea = False
# Move the node upwards if the bottom is below the build platform. # Move it downwards if bottom is above platform
move_vector = Vector() move_vector = Vector()
if not Float.fuzzyCompare(bbox.bottom, 0.0): if not (node.getParent() and node.getParent().callDecoration("isGroup")): #If an object is grouped, don't move it down
move_vector.setY(-bbox.bottom) if bbox.bottom > 0:
move_vector.setY(-bbox.bottom)
#if not Float.fuzzyCompare(bbox.bottom, 0.0):
# pass#move_vector.setY(-bbox.bottom)
# If there is no convex hull for the node, start calculating it and continue. # If there is no convex hull for the node, start calculating it and continue.
if not node.getDecorator(ConvexHullDecorator): if not node.getDecorator(ConvexHullDecorator):
@ -76,7 +86,7 @@ class PlatformPhysics:
elif Selection.isSelected(node): elif Selection.isSelected(node):
pass pass
else: elif 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.
@ -88,27 +98,41 @@ class PlatformPhysics:
continue continue
# Ignore colissions within a group # Ignore colissions within a group
if other_node.getParent().callDecoration("isGroup") is not None: if other_node.getParent().callDecoration("isGroup") is not None or node.getParent().callDecoration("isGroup") is not None:
if node.getParent().callDecoration("isGroup") is other_node.getParent().callDecoration("isGroup"): continue
continue #if node.getParent().callDecoration("isGroup") is other_node.getParent().callDecoration("isGroup"):
# continue
# Ignore nodes that do not have the right properties set. # Ignore nodes that do not have the right properties set.
if not other_node.callDecoration("getConvexHull") or not other_node.getBoundingBox(): if not other_node.callDecoration("getConvexHull") or not other_node.getBoundingBox():
continue continue
# Check to see if the bounding boxes intersect. If not, we can ignore the node as there is no way the hull intersects. # Check to see if the bounding boxes intersect. If not, we can ignore the node as there is no way the hull intersects.
if node.getBoundingBox().intersectsBox(other_node.getBoundingBox()) == AxisAlignedBox.IntersectionResult.NoIntersection: #if node.getBoundingBox().intersectsBox(other_node.getBoundingBox()) == AxisAlignedBox.IntersectionResult.NoIntersection:
continue # continue
# Get the overlap distance for both convex hulls. If this returns None, there is no intersection. # Get the overlap distance for both convex hulls. If this returns None, there is no intersection.
overlap = node.callDecoration("getConvexHull").intersectsPolygon(other_node.callDecoration("getConvexHull")) try:
head_hull = node.callDecoration("getConvexHullHead")
if head_hull:
overlap = head_hull.intersectsPolygon(other_node.callDecoration("getConvexHull"))
if not overlap:
other_head_hull = other_node.callDecoration("getConvexHullHead")
if other_head_hull:
overlap = node.callDecoration("getConvexHull").intersectsPolygon(other_head_hull)
else:
overlap = node.callDecoration("getConvexHull").intersectsPolygon(other_node.callDecoration("getConvexHull"))
except:
overlap = None #It can sometimes occur that the caclulated convex hull has no size, in which case there is no overlap.
if overlap is None: if overlap is None:
continue continue
move_vector.setX(overlap[0] * 1.01)
move_vector.setX(overlap[0] * 1.1) move_vector.setZ(overlap[1] * 1.01)
move_vector.setZ(overlap[1] * 1.1)
convex_hull = node.callDecoration("getConvexHull") convex_hull = node.callDecoration("getConvexHull")
if convex_hull: if convex_hull:
if not convex_hull.isValid():
return
# Check for collisions between disallowed areas and the object # Check for collisions between disallowed areas and the object
for area in self._build_volume.getDisallowedAreas(): for area in self._build_volume.getDisallowedAreas():
overlap = convex_hull.intersectsPolygon(area) overlap = convex_hull.intersectsPolygon(area)

View File

@ -40,48 +40,13 @@ class PrintInformation(QObject):
def __init__(self, parent = None): def __init__(self, parent = None):
super().__init__(parent) super().__init__(parent)
self._enabled = False
self._minimum_print_time = Duration(None, self)
self._current_print_time = Duration(None, self) self._current_print_time = Duration(None, self)
self._maximum_print_time = Duration(None, self)
self._material_amount = -1 self._material_amount = -1
self._time_quality_value = 50
self._time_quality_changed_timer = QTimer()
self._time_quality_changed_timer.setInterval(500)
self._time_quality_changed_timer.setSingleShot(True)
self._time_quality_changed_timer.timeout.connect(self._updateTimeQualitySettings)
self._interpolation_settings = {
"layer_height": { "minimum": "low", "maximum": "high", "curve": "linear", "precision": 2 },
"fill_sparse_density": { "minimum": "low", "maximum": "high", "curve": "linear", "precision": 0 }
}
self._low_quality_settings = None
self._current_settings = None
self._high_quality_settings = None
self._slice_pass = None
self._slice_reason = None
Application.getInstance().activeMachineChanged.connect(self._onActiveMachineChanged)
self._onActiveMachineChanged()
Application.getInstance().getController().getScene().sceneChanged.connect(self._onSceneChanged)
self._backend = Application.getInstance().getBackend() self._backend = Application.getInstance().getBackend()
if self._backend: if self._backend:
self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._backend.printDurationMessage.connect(self._onPrintDurationMessage)
self._backend.slicingStarted.connect(self._onSlicingStarted)
self._backend.slicingCancelled.connect(self._onSlicingCancelled)
minimumPrintTimeChanged = pyqtSignal()
@pyqtProperty(Duration, notify = minimumPrintTimeChanged)
def minimumPrintTime(self):
return self._minimum_print_time
currentPrintTimeChanged = pyqtSignal() currentPrintTimeChanged = pyqtSignal()
@ -89,145 +54,18 @@ class PrintInformation(QObject):
def currentPrintTime(self): def currentPrintTime(self):
return self._current_print_time return self._current_print_time
maximumPrintTimeChanged = pyqtSignal()
@pyqtProperty(Duration, notify = maximumPrintTimeChanged)
def maximumPrintTime(self):
return self._maximum_print_time
materialAmountChanged = pyqtSignal() materialAmountChanged = pyqtSignal()
@pyqtProperty(float, notify = materialAmountChanged) @pyqtProperty(float, notify = materialAmountChanged)
def materialAmount(self): def materialAmount(self):
return self._material_amount return self._material_amount
timeQualityValueChanged = pyqtSignal()
@pyqtProperty(int, notify = timeQualityValueChanged)
def timeQualityValue(self):
return self._time_quality_value
def setEnabled(self, enabled):
if enabled != self._enabled:
self._enabled = enabled
if self._enabled:
self._updateTimeQualitySettings()
self._onSlicingStarted()
self.enabledChanged.emit()
enabledChanged = pyqtSignal()
@pyqtProperty(bool, fset = setEnabled, notify = enabledChanged)
def enabled(self):
return self._enabled
@pyqtSlot(int)
def setTimeQualityValue(self, value):
if value != self._time_quality_value:
self._time_quality_value = value
self.timeQualityValueChanged.emit()
self._time_quality_changed_timer.start()
def _onSlicingStarted(self):
if self._slice_pass is None:
self._slice_pass = self.SlicePass.CurrentSettings
if self._slice_reason is None:
self._slice_reason = self.SliceReason.Other
if self._slice_pass == self.SlicePass.CurrentSettings and self._slice_reason != self.SliceReason.SettingChanged:
self._minimum_print_time.setDuration(-1)
self.minimumPrintTimeChanged.emit()
self._maximum_print_time.setDuration(-1)
self.maximumPrintTimeChanged.emit()
def _onPrintDurationMessage(self, time, amount): def _onPrintDurationMessage(self, time, amount):
if self._slice_pass == self.SlicePass.CurrentSettings: #if self._slice_pass == self.SlicePass.CurrentSettings:
self._current_print_time.setDuration(time) self._current_print_time.setDuration(time)
self.currentPrintTimeChanged.emit() self.currentPrintTimeChanged.emit()
# Material amount is sent as an amount of mm^3, so calculate length from that # Material amount is sent as an amount of mm^3, so calculate length from that
r = self._current_settings.getSettingValueByKey("material_diameter") / 2 r = Application.getInstance().getMachineManager().getActiveProfile().getSettingValue("material_diameter") / 2
self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2) self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2)
self.materialAmountChanged.emit() self.materialAmountChanged.emit()
if not self._enabled:
return
if self._slice_reason != self.SliceReason.SettingChanged or not self._minimum_print_time.valid or not self._maximum_print_time.valid:
self._slice_pass = self.SlicePass.LowQualitySettings
self._backend.slice(settings = self._low_quality_settings, save_gcode = False, save_polygons = False, force_restart = False, report_progress = False)
else:
self._slice_pass = None
self._slice_reason = None
elif self._slice_pass == self.SlicePass.LowQualitySettings:
self._minimum_print_time.setDuration(time)
self.minimumPrintTimeChanged.emit()
self._slice_pass = self.SlicePass.HighQualitySettings
self._backend.slice(settings = self._high_quality_settings, save_gcode = False, save_polygons = False, force_restart = False, report_progress = False)
elif self._slice_pass == self.SlicePass.HighQualitySettings:
self._maximum_print_time.setDuration(time)
self.maximumPrintTimeChanged.emit()
self._slice_pass = None
self._slice_reason = None
def _onActiveMachineChanged(self):
if self._current_settings:
self._current_settings.settingChanged.disconnect(self._onSettingChanged)
self._current_settings = Application.getInstance().getActiveMachine()
if self._current_settings:
self._current_settings.settingChanged.connect(self._onSettingChanged)
self._low_quality_settings = None
self._high_quality_settings = None
self._updateTimeQualitySettings()
self._slice_reason = self.SliceReason.ActiveMachineChanged
def _updateTimeQualitySettings(self):
if not self._current_settings or not self._enabled:
return
if not self._low_quality_settings:
self._low_quality_settings = MachineSettings()
self._low_quality_settings.loadSettingsFromFile(Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + ".json"))
self._low_quality_settings.loadValuesFromFile(Resources.getPath(Resources.SettingsLocation, "profiles", "low_quality.conf"))
if not self._high_quality_settings:
self._high_quality_settings = MachineSettings()
self._high_quality_settings.loadSettingsFromFile(Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + ".json"))
self._high_quality_settings.loadValuesFromFile(Resources.getPath(Resources.SettingsLocation, "profiles", "high_quality.conf"))
for key, options in self._interpolation_settings.items():
minimum_value = None
if options["minimum"] == "low":
minimum_value = self._low_quality_settings.getSettingValueByKey(key)
elif options["minimum"] == "high":
minimum_value = self._high_quality_settings.getSettingValueByKey(key)
else:
continue
maximum_value = None
if options["maximum"] == "low":
maximum_value = self._low_quality_settings.getSettingValueByKey(key)
elif options["maximum"] == "high":
maximum_value = self._high_quality_settings.getSettingValueByKey(key)
else:
continue
setting_value = round(minimum_value + (maximum_value - minimum_value) * (self._time_quality_value / 100), options["precision"])
self._current_settings.setSettingValueByKey(key, setting_value)
def _onSceneChanged(self, source):
self._slice_reason = self.SliceReason.SceneChanged
def _onSettingChanged(self, source):
self._slice_reason = self.SliceReason.SettingChanged
def _onSlicingCancelled(self):
self._slice_pass = None

View File

@ -3,12 +3,15 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
try: import sys
import cura.CuraApplication
app = cura.CuraApplication.CuraApplication.getInstance() def exceptHook(type, value, traceback):
app.run()
except Exception as e:
import cura.CrashHandler import cura.CrashHandler
cura.CrashHandler.show() cura.CrashHandler.show(type, value, traceback)
sys.excepthook = exceptHook
import cura.CuraApplication
app = cura.CuraApplication.CuraApplication.getInstance()
app.run()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 625 B

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 361 KiB

View File

@ -1,5 +1,5 @@
!ifndef VERSION !ifndef VERSION
!define VERSION '15.05.97' !define VERSION '15.09.80'
!endif !endif
; The name of the installer ; The name of the installer
@ -45,7 +45,7 @@ SetCompressor /SOLID lzma
!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink" !define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink"
;Add an option to show release notes ;Add an option to show release notes
!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\release_notes.txt" !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\plugins\ChangeLogPlugin\changelog.txt"
; Pages ; Pages
;!insertmacro MUI_PAGE_WELCOME ;!insertmacro MUI_PAGE_WELCOME
@ -111,24 +111,24 @@ Section "Install Visual Studio 2010 Redistributable"
SectionEnd SectionEnd
;Section "Install Arduino Drivers" Section "Install Arduino Drivers"
; ; Set output path to the driver directory. ; Set output path to the driver directory.
; SetOutPath "$INSTDIR\drivers\" SetOutPath "$INSTDIR\drivers\"
; File /r "drivers\" File /r "drivers\"
;
; ${If} ${RunningX64} ${If} ${RunningX64}
; IfSilent +2 IfSilent +2
; ExecWait '"$INSTDIR\drivers\dpinst64.exe" /lm' ExecWait '"$INSTDIR\drivers\dpinst64.exe" /lm'
; ${Else} ${Else}
; IfSilent +2 IfSilent +2
; ExecWait '"$INSTDIR\drivers\dpinst32.exe" /lm' ExecWait '"$INSTDIR\drivers\dpinst32.exe" /lm'
; ${EndIf} ${EndIf}
;SectionEnd SectionEnd
Section "Open STL files with Cura" Section "Open STL files with Cura"
WriteRegStr HKCR .stl "" "Cura STL model file" WriteRegStr HKCR .stl "" "Cura STL model file"
DeleteRegValue HKCR .stl "Content Type" DeleteRegValue HKCR .stl "Content Type"
WriteRegStr HKCR "Cura STL model file\DefaultIcon" "" "$INSTDIR\resources\stl.ico,0" WriteRegStr HKCR "Cura STL model file\DefaultIcon" "" "$INSTDIR\Cura.exe,0"
WriteRegStr HKCR "Cura STL model file\shell" "" "open" WriteRegStr HKCR "Cura STL model file\shell" "" "open"
WriteRegStr HKCR "Cura STL model file\shell\open\command" "" '"$INSTDIR\Cura.exe" "%1"' WriteRegStr HKCR "Cura STL model file\shell\open\command" "" '"$INSTDIR\Cura.exe" "%1"'
SectionEnd SectionEnd
@ -136,7 +136,7 @@ SectionEnd
Section /o "Open OBJ files with Cura" Section /o "Open OBJ files with Cura"
WriteRegStr HKCR .obj "" "Cura OBJ model file" WriteRegStr HKCR .obj "" "Cura OBJ model file"
DeleteRegValue HKCR .obj "Content Type" DeleteRegValue HKCR .obj "Content Type"
WriteRegStr HKCR "Cura OBJ model file\DefaultIcon" "" "$INSTDIR\resources\stl.ico,0" WriteRegStr HKCR "Cura OBJ model file\DefaultIcon" "" "$INSTDIR\Cura.exe,0"
WriteRegStr HKCR "Cura OBJ model file\shell" "" "open" WriteRegStr HKCR "Cura OBJ model file\shell" "" "open"
WriteRegStr HKCR "Cura OBJ model file\shell\open\command" "" '"$INSTDIR\Cura.exe" "%1"' WriteRegStr HKCR "Cura OBJ model file\shell\open\command" "" '"$INSTDIR\Cura.exe" "%1"'
SectionEnd SectionEnd

View File

@ -0,0 +1,124 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.Mesh.MeshReader import MeshReader
from UM.Mesh.MeshData import MeshData
from UM.Logger import Logger
from UM.Math.Matrix import Matrix
from UM.Math.Vector import Vector
from UM.Scene.SceneNode import SceneNode
from UM.Scene.GroupDecorator import GroupDecorator
from UM.Math.Quaternion import Quaternion
import os
import struct
import math
from os import listdir
import zipfile
import xml.etree.ElementTree as ET
## Base implementation for reading 3MF files. Has no support for textures. Only loads meshes!
class ThreeMFReader(MeshReader):
def __init__(self):
super(ThreeMFReader, self).__init__()
self._supported_extension = ".3mf"
self._namespaces = {
"3mf": "http://schemas.microsoft.com/3dmanufacturing/core/2015/02",
"cura": "http://software.ultimaker.com/xml/cura/3mf/2015/10"
}
def read(self, file_name):
result = None
extension = os.path.splitext(file_name)[1]
if extension.lower() == self._supported_extension:
result = SceneNode()
# The base object of 3mf is a zipped archive.
archive = zipfile.ZipFile(file_name, 'r')
try:
root = ET.parse(archive.open("3D/3dmodel.model"))
# There can be multiple objects, try to load all of them.
objects = root.findall("./3mf:resources/3mf:object", self._namespaces)
for object in objects:
mesh = MeshData()
node = SceneNode()
vertex_list = []
#for vertex in object.mesh.vertices.vertex:
for vertex in object.findall(".//3mf:vertex", self._namespaces):
vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
triangles = object.findall(".//3mf:triangle", self._namespaces)
mesh.reserveFaceCount(len(triangles))
#for triangle in object.mesh.triangles.triangle:
for triangle in triangles:
v1 = int(triangle.get("v1"))
v2 = int(triangle.get("v2"))
v3 = int(triangle.get("v3"))
mesh.addFace(vertex_list[v1][0],vertex_list[v1][1],vertex_list[v1][2],vertex_list[v2][0],vertex_list[v2][1],vertex_list[v2][2],vertex_list[v3][0],vertex_list[v3][1],vertex_list[v3][2])
#TODO: We currently do not check for normals and simply recalculate them.
mesh.calculateNormals()
node.setMeshData(mesh)
node.setSelectable(True)
transformation = root.findall("./3mf:build/3mf:item[@objectid='{0}']".format(object.get("id")), self._namespaces)
if transformation:
transformation = transformation[0]
if transformation.get("transform"):
splitted_transformation = transformation.get("transform").split()
## Transformation is saved as:
## M00 M01 M02 0.0
## M10 M11 M12 0.0
## M20 M21 M22 0.0
## M30 M31 M32 1.0
## We switch the row & cols as that is how everyone else uses matrices!
temp_mat = Matrix()
# Rotation & Scale
temp_mat._data[0,0] = splitted_transformation[0]
temp_mat._data[1,0] = splitted_transformation[1]
temp_mat._data[2,0] = splitted_transformation[2]
temp_mat._data[0,1] = splitted_transformation[3]
temp_mat._data[1,1] = splitted_transformation[4]
temp_mat._data[2,1] = splitted_transformation[5]
temp_mat._data[0,2] = splitted_transformation[6]
temp_mat._data[1,2] = splitted_transformation[7]
temp_mat._data[2,2] = splitted_transformation[8]
# Translation
temp_mat._data[0,3] = splitted_transformation[9]
temp_mat._data[1,3] = splitted_transformation[10]
temp_mat._data[2,3] = splitted_transformation[11]
node.setPosition(Vector(temp_mat.at(0,3), temp_mat.at(1,3), temp_mat.at(2,3)))
temp_quaternion = Quaternion()
temp_quaternion.setByMatrix(temp_mat)
node.setOrientation(temp_quaternion)
# Magical scale extraction
S2 = temp_mat.getTransposed().multiply(temp_mat)
scale_x = math.sqrt(S2.at(0,0))
scale_y = math.sqrt(S2.at(1,1))
scale_z = math.sqrt(S2.at(2,2))
node.setScale(Vector(scale_x,scale_y,scale_z))
# We use a different coordinate frame, so rotate.
rotation = Quaternion.fromAngleAxis(-0.5 * math.pi, Vector(1,0,0))
node.rotate(rotation)
result.addChild(node)
#If there is more then one object, group them.
try:
if len(objects) > 1:
group_decorator = GroupDecorator()
result.addDecorator(group_decorator)
except:
pass
except Exception as e:
Logger.log("e" ,"exception occured in 3mf reader: %s" , e)
return result

View File

@ -0,0 +1,25 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
from . import ThreeMFReader
def getMetaData():
return {
"plugin": {
"name": catalog.i18nc("@label", "3MF Reader"),
"author": "Ultimaker",
"version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for reading 3MF files."),
"api": 2
},
"mesh_reader": {
"extension": "3mf",
"description": catalog.i18nc("@item:inlistbox", "3MF File")
}
}
def register(app):
return { "mesh_reader": ThreeMFReader.ThreeMFReader() }

View File

@ -0,0 +1,99 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.i18n import i18nCatalog
from UM.Extension import Extension
from UM.Preferences import Preferences
from UM.Application import Application
from UM.PluginRegistry import PluginRegistry
from UM.Version import Version
from PyQt5.QtQuick import QQuickView
from PyQt5.QtQml import QQmlComponent, QQmlContext
from PyQt5.QtCore import QUrl, pyqtSlot, QObject
import os.path
import collections
catalog = i18nCatalog("cura")
class ChangeLog(Extension, QObject,):
def __init__(self, parent = None):
QObject.__init__(self, parent)
Extension.__init__(self)
self._changelog_window = None
self._changelog_context = None
version_string = Application.getInstance().getVersion()
if version_string is not "master":
self._version = Version(version_string)
else:
self._version = None
self._change_logs = None
Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
Preferences.getInstance().addPreference("general/latest_version_changelog_shown", "15.05.90") #First version of CURA with uranium
#self.showChangelog()
def getChangeLogs(self):
if not self._change_logs:
self.loadChangeLogs()
return self._change_logs
@pyqtSlot(result = str)
def getChangeLogString(self):
logs = self.getChangeLogs()
latest_version = Version(Preferences.getInstance().getValue("general/latest_version_changelog_shown"))
result = ""
for version in logs:
result += "<h1>" + str(version) + "</h1><br>"
result += ""
for change in logs[version]:
result += "<b>" + str(change) + "</b><br>"
for line in logs[version][change]:
result += str(line) + "<br>"
result += "<br>"
pass
return result
def loadChangeLogs(self):
self._change_logs = collections.OrderedDict()
with open(os.path.join(PluginRegistry.getInstance().getPluginPath("ChangeLogPlugin"), "ChangeLog.txt"), 'r',-1, "utf-8") as f:
open_version = None
open_header = None
for line in f:
line = line.replace("\n","")
if "[" in line and "]" in line:
line = line.replace("[","")
line = line.replace("]","")
open_version = Version(line)
self._change_logs[Version(line)] = collections.OrderedDict()
elif line.startswith("*"):
open_header = line.replace("*","")
self._change_logs[open_version][open_header] = []
else:
if line != "":
self._change_logs[open_version][open_header].append(line)
def _onEngineCreated(self):
if not self._version:
return #We're on dev branch.
if self._version > Preferences.getInstance().getValue("general/latest_version_changelog_shown"):
self.showChangelog()
def showChangelog(self):
if not self._changelog_window:
self.createChangelogWindow()
self._changelog_window.show()
Preferences.getInstance().setValue("general/latest_version_changelog_shown", Application.getInstance().getVersion())
def hideChangelog(self):
if self._changelog_window:
self._changelog_window.hide()
def createChangelogWindow(self):
path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath("ChangeLogPlugin"), "ChangeLog.qml"))
component = QQmlComponent(Application.getInstance()._engine, path)
self._changelog_context = QQmlContext(Application.getInstance()._engine.rootContext())
self._changelog_context.setContextProperty("manager", self)
self._changelog_window = component.create(self._changelog_context)
#print(self._changelog_window)

View File

@ -0,0 +1,36 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import UM 1.1 as UM
UM.Dialog
{
id: base
width: 300 * Screen.devicePixelRatio;
height: 500 * Screen.devicePixelRatio;
title: "Changelog"
ScrollView
{
width: parent.width
height: parent.height - 25
Text
{
text: manager.getChangeLogString()
width:base.width - 35
wrapMode: Text.Wrap;
}
}
Button
{
anchors.bottom:parent.bottom
text: "close"
onClicked: base.hide()
anchors.horizontalCenter: parent.horizontalCenter
}
}

View File

@ -0,0 +1,44 @@
[15.10.0]
*All at Once/One at a Time
Curas default mode is set to All At Once. You can print multiple objects faster with the option print objects One At A Time. This can be changed in Advanced Settings. Please note that in One At A Time mode, grouped objects will still be printed as a single object.
*Setting Profiles
Now you can create preferred setting favourites and share them with others.
*Post-Processing Plugin
This plugin supports post-processing on the GCode generated by the engine allowing for custom scripts. For example, Pause At Height and Tweak At Z.
*Support for Bed Levelling and other wizards
We have restored the Bed Levelling function and several other wizards that were previously available for the Ultimaker Original. Additionally, these are ready to be used with machines from other vendors (BQ, Rep Rap neo).
*Third-Party Printer Profiles
We received printer profiles for third-party vendors (BQ, Rep Rap neo) from the community (thanks guys!). These have been included in this release.
*3MF File Loading Support (New)
Were happy to report we now support loading 3MF files. This is a new file format similar to AMF, but freely available.
*Output Device API for Developers (New)
The Storage Device API has now been replaced with the Output Device API for saving files. Its designed to make it easier for anyone that wants to write a plugin giving them some form of output device, whether its a printer or a web service.
*Improved Cut-Off Object Bottom (New)
Weve added a feature than allows you to move objects below the build plate. You can either correct a model with a rough bottom, or print only a part of an object. Please note that the implementation greatly differs from the old one where it was a setting.
*Improved File Saving (new)
Were happy to report that the way file saving is handled has received a huge overhaul. Now the default action is to save everything on the build plate to a file.
*Select Multiple Objects (New)
You now have the freedom to select and manipulate multiple objects at the same time.
*Grouping (New)
You can now group objects together to make it easier to manipulate multiple objects.
*Per-Object Settings (New)
You can now select different profiles for different objects and in advance mode override individual settings.
*64-bit Windows Builds (New)
Cura now allows 64-bit Windows builds in addition to the 32-bit builds. For users running the 64-bit version of Windows, you can now load models in more detail.
*Fuzzy skin mode (New)
A new engine feature that enables objects to be printed as if they have a fuzzy skin.
*Z-seam alignment (New)

View File

@ -0,0 +1,21 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from . import ChangeLog
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": catalog.i18nc("@label", "Change Log"),
"author": "Ultimaker",
"version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Shows changes since latest checked version"),
"api": 2
}
}
def register(app):
return {"extension": ChangeLog.ChangeLog()}

View File

@ -10,6 +10,8 @@ from UM.Math.Vector import Vector
from UM.Signal import Signal from UM.Signal import Signal
from UM.Logger import Logger from UM.Logger import Logger
from UM.Resources import Resources from UM.Resources import Resources
from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator
from UM.Message import Message
from cura.OneAtATimeIterator import OneAtATimeIterator from cura.OneAtATimeIterator import OneAtATimeIterator
from . import Cura_pb2 from . import Cura_pb2
@ -22,6 +24,9 @@ import numpy
from PyQt5.QtCore import QTimer from PyQt5.QtCore import QTimer
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
class CuraEngineBackend(Backend): class CuraEngineBackend(Backend):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -44,9 +49,10 @@ class CuraEngineBackend(Backend):
self._onActiveViewChanged() self._onActiveViewChanged()
self._stored_layer_data = None self._stored_layer_data = None
self._settings = None
Application.getInstance().activeMachineChanged.connect(self._onActiveMachineChanged) self._profile = None
self._onActiveMachineChanged() Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
self._onActiveProfileChanged()
self._change_timer = QTimer() self._change_timer = QTimer()
self._change_timer.setInterval(500) self._change_timer.setInterval(500)
@ -68,10 +74,15 @@ class CuraEngineBackend(Backend):
self._enabled = True self._enabled = True
self._message = None
self.backendConnected.connect(self._onBackendConnected) self.backendConnected.connect(self._onBackendConnected)
## Get the command that is used to call the engine.
# This is usefull for debugging and used to actually start the engine
# \return list of commands and args / parameters.
def getEngineCommand(self): def getEngineCommand(self):
return [Preferences.getInstance().getValue("backend/location"),"connect", "127.0.0.1:{0}".format(self._port), "-j", Resources.getPath(Resources.SettingsLocation, "fdmprinter.json"), "-vv"] return [Preferences.getInstance().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), "-j", Resources.getPath(Resources.MachineDefinitions, "fdmprinter.json"), "-vv"]
## Emitted when we get a message containing print duration and material amount. This also implies the slicing has finished. ## Emitted when we get a message containing print duration and material amount. This also implies the slicing has finished.
# \param time The amount of time the print will take. # \param time The amount of time the print will take.
@ -112,9 +123,9 @@ class CuraEngineBackend(Backend):
pass pass
self.slicingCancelled.emit() self.slicingCancelled.emit()
return return
Logger.log("d", "Preparing to send slice data to engine.")
object_groups = [] object_groups = []
if self._settings.getSettingValueByKey("print_sequence") == "One at a time": if self._profile.getSettingValue("print_sequence") == "one_at_a_time":
for node in OneAtATimeIterator(self._scene.getRoot()): for node in OneAtATimeIterator(self._scene.getRoot()):
temp_list = [] temp_list = []
children = node.getAllChildren() children = node.getAllChildren()
@ -130,6 +141,7 @@ class CuraEngineBackend(Backend):
if not getattr(node, "_outside_buildarea", False): if not getattr(node, "_outside_buildarea", False):
temp_list.append(node) temp_list.append(node)
if len(temp_list) == 0: if len(temp_list) == 0:
self.processingProgress.emit(0.0)
return return
object_groups.append(temp_list) object_groups.append(temp_list)
#for node in DepthFirstIterator(self._scene.getRoot()): #for node in DepthFirstIterator(self._scene.getRoot()):
@ -138,19 +150,39 @@ class CuraEngineBackend(Backend):
# objects.append(node) # objects.append(node)
if len(object_groups) == 0: if len(object_groups) == 0:
if self._message:
self._message.hide()
self._message = None
return #No point in slicing an empty build plate return #No point in slicing an empty build plate
if kwargs.get("settings", self._settings).hasErrorValue(): if kwargs.get("profile", self._profile).hasErrorValue():
Logger.log('w', "Profile has error values. Aborting slicing")
if self._message:
self._message.hide()
self._message = None
self._message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."))
self._message.show()
return #No slicing if we have error values since those are by definition illegal values. return #No slicing if we have error values since those are by definition illegal values.
# Remove existing layer data (if any)
for node in DepthFirstIterator(self._scene.getRoot()):
if type(node) is SceneNode and node.getMeshData():
if node.callDecoration("getLayerData"):
Application.getInstance().getController().getScene().getRoot().removeChild(node)
break
Application.getInstance().getController().getScene().gcode_list = None
self._slicing = True self._slicing = True
self.slicingStarted.emit() self.slicingStarted.emit()
self._report_progress = kwargs.get("report_progress", True) self._report_progress = kwargs.get("report_progress", True)
if self._report_progress: if self._report_progress:
self.processingProgress.emit(0.0) self.processingProgress.emit(0.0)
if not self._message:
self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
self._message.show()
else:
self._message.setProgress(-1)
self._sendSettings(kwargs.get("settings", self._settings)) self._sendSettings(kwargs.get("profile", self._profile))
self._scene.acquireLock() self._scene.acquireLock()
@ -178,7 +210,14 @@ class CuraEngineBackend(Backend):
verts[:,1] *= -1 verts[:,1] *= -1
obj.vertices = verts.tostring() obj.vertices = verts.tostring()
self._handlePerObjectSettings(object, obj)
# Hack to add per-object settings also to the "MeshGroup" in CuraEngine
# We really should come up with a better solution for this.
self._handlePerObjectSettings(group[0], group_message)
self._scene.releaseLock() self._scene.releaseLock()
Logger.log("d", "Sending data to engine for slicing.")
self._socket.sendMessage(slice_message) self._socket.sendMessage(slice_message)
def _onSceneChanged(self, source): def _onSceneChanged(self, source):
@ -190,13 +229,13 @@ class CuraEngineBackend(Backend):
self._onChanged() self._onChanged()
def _onActiveMachineChanged(self): def _onActiveProfileChanged(self):
if self._settings: if self._profile:
self._settings.settingChanged.disconnect(self._onSettingChanged) self._profile.settingValueChanged.disconnect(self._onSettingChanged)
self._settings = Application.getInstance().getActiveMachine() self._profile = Application.getInstance().getMachineManager().getActiveProfile()
if self._settings: if self._profile:
self._settings.settingChanged.connect(self._onSettingChanged) self._profile.settingValueChanged.connect(self._onSettingChanged)
self._onChanged() self._onChanged()
def _onSettingChanged(self, setting): def _onSettingChanged(self, setting):
@ -214,6 +253,14 @@ class CuraEngineBackend(Backend):
if message.amount >= 0.99: if message.amount >= 0.99:
self._slicing = False self._slicing = False
if self._message:
self._message.setProgress(100)
self._message.hide()
self._message = None
if self._message:
self._message.setProgress(round(message.amount * 100))
if self._report_progress: if self._report_progress:
self.processingProgress.emit(message.amount) self.processingProgress.emit(message.amount)
@ -241,18 +288,22 @@ class CuraEngineBackend(Backend):
self._socket.registerMessageType(6, Cura_pb2.SettingList) self._socket.registerMessageType(6, Cura_pb2.SettingList)
self._socket.registerMessageType(7, Cura_pb2.GCodePrefix) self._socket.registerMessageType(7, Cura_pb2.GCodePrefix)
## Manually triggers a reslice
def forceSlice(self):
self._change_timer.start()
def _onChanged(self): def _onChanged(self):
if not self._settings: if not self._profile:
return return
self._change_timer.start() self._change_timer.start()
def _sendSettings(self, settings): def _sendSettings(self, profile):
msg = Cura_pb2.SettingList() msg = Cura_pb2.SettingList()
for setting in settings.getAllSettings(include_machine=True): for key, value in profile.getAllSettingValues(include_machine = True).items():
s = msg.settings.add() s = msg.settings.add()
s.name = setting.getKey() s.name = key
s.value = str(setting.getValue()).encode("utf-8") s.value = str(value).encode("utf-8")
self._socket.sendMessage(msg) self._socket.sendMessage(msg)
@ -262,10 +313,10 @@ class CuraEngineBackend(Backend):
self._restart = False self._restart = False
def _onToolOperationStarted(self, tool): def _onToolOperationStarted(self, tool):
self._enabled = False self._enabled = False # Do not reslice when a tool is doing it's 'thing'
def _onToolOperationStopped(self, tool): def _onToolOperationStopped(self, tool):
self._enabled = True self._enabled = True # Tool stop, start listening for changes again.
self._onChanged() self._onChanged()
def _onActiveViewChanged(self): def _onActiveViewChanged(self):
@ -278,3 +329,20 @@ class CuraEngineBackend(Backend):
job.start() job.start()
else: else:
self._layer_view_active = False self._layer_view_active = False
def _handlePerObjectSettings(self, node, message):
profile = node.callDecoration("getProfile")
if profile:
for key, value in profile.getChangedSettingValues().items():
setting = message.settings.add()
setting.name = key
setting.value = str(value).encode()
object_settings = node.callDecoration("getAllSettingValues")
if not object_settings:
return
for key, value in object_settings.items():
setting = message.settings.add()
setting.name = key
setting.value = str(value).encode()

View File

@ -18,7 +18,7 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor.FileDescriptor(
name='Cura.proto', name='Cura.proto',
package='cura.proto', package='cura.proto',
serialized_pb=_b('\n\nCura.proto\x12\ncura.proto\"1\n\nObjectList\x12#\n\x07objects\x18\x01 \x03(\x0b\x32\x12.cura.proto.Object\"5\n\x05Slice\x12,\n\x0cobject_lists\x18\x01 \x03(\x0b\x32\x16.cura.proto.ObjectList\"o\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08vertices\x18\x02 \x01(\x0c\x12\x0f\n\x07normals\x18\x03 \x01(\x0c\x12\x0f\n\x07indices\x18\x04 \x01(\x0c\x12%\n\x08settings\x18\x05 \x03(\x0b\x32\x13.cura.proto.Setting\"\x1a\n\x08Progress\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x02\"=\n\x10SlicedObjectList\x12)\n\x07objects\x18\x01 \x03(\x0b\x32\x18.cura.proto.SlicedObject\"=\n\x0cSlicedObject\x12\n\n\x02id\x18\x01 \x01(\x03\x12!\n\x06layers\x18\x02 \x03(\x0b\x32\x11.cura.proto.Layer\"]\n\x05Layer\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x02\x12\x11\n\tthickness\x18\x03 \x01(\x02\x12%\n\x08polygons\x18\x04 \x03(\x0b\x32\x13.cura.proto.Polygon\"\xe1\x01\n\x07Polygon\x12&\n\x04type\x18\x01 \x01(\x0e\x32\x18.cura.proto.Polygon.Type\x12\x0e\n\x06points\x18\x02 \x01(\x0c\x12\x12\n\nline_width\x18\x03 \x01(\x02\"\x89\x01\n\x04Type\x12\x0c\n\x08NoneType\x10\x00\x12\x0e\n\nInset0Type\x10\x01\x12\x0e\n\nInsetXType\x10\x02\x12\x0c\n\x08SkinType\x10\x03\x12\x0f\n\x0bSupportType\x10\x04\x12\r\n\tSkirtType\x10\x05\x12\x0e\n\nInfillType\x10\x06\x12\x15\n\x11SupportInfillType\x10\x07\"&\n\nGCodeLayer\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"D\n\x0fObjectPrintTime\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04time\x18\x02 \x01(\x02\x12\x17\n\x0fmaterial_amount\x18\x03 \x01(\x02\"4\n\x0bSettingList\x12%\n\x08settings\x18\x01 \x03(\x0b\x32\x13.cura.proto.Setting\"&\n\x07Setting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x1b\n\x0bGCodePrefix\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x62\x06proto3') serialized_pb=_b('\n\nCura.proto\x12\ncura.proto\"X\n\nObjectList\x12#\n\x07objects\x18\x01 \x03(\x0b\x32\x12.cura.proto.Object\x12%\n\x08settings\x18\x02 \x03(\x0b\x32\x13.cura.proto.Setting\"5\n\x05Slice\x12,\n\x0cobject_lists\x18\x01 \x03(\x0b\x32\x16.cura.proto.ObjectList\"o\n\x06Object\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08vertices\x18\x02 \x01(\x0c\x12\x0f\n\x07normals\x18\x03 \x01(\x0c\x12\x0f\n\x07indices\x18\x04 \x01(\x0c\x12%\n\x08settings\x18\x05 \x03(\x0b\x32\x13.cura.proto.Setting\"\x1a\n\x08Progress\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x02\"=\n\x10SlicedObjectList\x12)\n\x07objects\x18\x01 \x03(\x0b\x32\x18.cura.proto.SlicedObject\"=\n\x0cSlicedObject\x12\n\n\x02id\x18\x01 \x01(\x03\x12!\n\x06layers\x18\x02 \x03(\x0b\x32\x11.cura.proto.Layer\"]\n\x05Layer\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x02\x12\x11\n\tthickness\x18\x03 \x01(\x02\x12%\n\x08polygons\x18\x04 \x03(\x0b\x32\x13.cura.proto.Polygon\"\xe1\x01\n\x07Polygon\x12&\n\x04type\x18\x01 \x01(\x0e\x32\x18.cura.proto.Polygon.Type\x12\x0e\n\x06points\x18\x02 \x01(\x0c\x12\x12\n\nline_width\x18\x03 \x01(\x02\"\x89\x01\n\x04Type\x12\x0c\n\x08NoneType\x10\x00\x12\x0e\n\nInset0Type\x10\x01\x12\x0e\n\nInsetXType\x10\x02\x12\x0c\n\x08SkinType\x10\x03\x12\x0f\n\x0bSupportType\x10\x04\x12\r\n\tSkirtType\x10\x05\x12\x0e\n\nInfillType\x10\x06\x12\x15\n\x11SupportInfillType\x10\x07\"&\n\nGCodeLayer\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"D\n\x0fObjectPrintTime\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04time\x18\x02 \x01(\x02\x12\x17\n\x0fmaterial_amount\x18\x03 \x01(\x02\"4\n\x0bSettingList\x12%\n\x08settings\x18\x01 \x03(\x0b\x32\x13.cura.proto.Setting\"&\n\x07Setting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x1b\n\x0bGCodePrefix\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x62\x06proto3')
) )
_sym_db.RegisterFileDescriptor(DESCRIPTOR) _sym_db.RegisterFileDescriptor(DESCRIPTOR)
@ -65,8 +65,8 @@ _POLYGON_TYPE = _descriptor.EnumDescriptor(
], ],
containing_type=None, containing_type=None,
options=None, options=None,
serialized_start=583, serialized_start=622,
serialized_end=720, serialized_end=759,
) )
_sym_db.RegisterEnumDescriptor(_POLYGON_TYPE) _sym_db.RegisterEnumDescriptor(_POLYGON_TYPE)
@ -85,6 +85,13 @@ _OBJECTLIST = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None, message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None, is_extension=False, extension_scope=None,
options=None), options=None),
_descriptor.FieldDescriptor(
name='settings', full_name='cura.proto.ObjectList.settings', index=1,
number=2, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
], ],
extensions=[ extensions=[
], ],
@ -97,7 +104,7 @@ _OBJECTLIST = _descriptor.Descriptor(
oneofs=[ oneofs=[
], ],
serialized_start=26, serialized_start=26,
serialized_end=75, serialized_end=114,
) )
@ -126,8 +133,8 @@ _SLICE = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=77, serialized_start=116,
serialized_end=130, serialized_end=169,
) )
@ -184,8 +191,8 @@ _OBJECT = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=132, serialized_start=171,
serialized_end=243, serialized_end=282,
) )
@ -214,8 +221,8 @@ _PROGRESS = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=245, serialized_start=284,
serialized_end=271, serialized_end=310,
) )
@ -244,8 +251,8 @@ _SLICEDOBJECTLIST = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=273, serialized_start=312,
serialized_end=334, serialized_end=373,
) )
@ -281,8 +288,8 @@ _SLICEDOBJECT = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=336, serialized_start=375,
serialized_end=397, serialized_end=436,
) )
@ -332,8 +339,8 @@ _LAYER = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=399, serialized_start=438,
serialized_end=492, serialized_end=531,
) )
@ -377,8 +384,8 @@ _POLYGON = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=495, serialized_start=534,
serialized_end=720, serialized_end=759,
) )
@ -414,8 +421,8 @@ _GCODELAYER = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=722, serialized_start=761,
serialized_end=760, serialized_end=799,
) )
@ -458,8 +465,8 @@ _OBJECTPRINTTIME = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=762, serialized_start=801,
serialized_end=830, serialized_end=869,
) )
@ -488,8 +495,8 @@ _SETTINGLIST = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=832, serialized_start=871,
serialized_end=884, serialized_end=923,
) )
@ -525,8 +532,8 @@ _SETTING = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=886, serialized_start=925,
serialized_end=924, serialized_end=963,
) )
@ -555,11 +562,12 @@ _GCODEPREFIX = _descriptor.Descriptor(
extension_ranges=[], extension_ranges=[],
oneofs=[ oneofs=[
], ],
serialized_start=926, serialized_start=965,
serialized_end=953, serialized_end=992,
) )
_OBJECTLIST.fields_by_name['objects'].message_type = _OBJECT _OBJECTLIST.fields_by_name['objects'].message_type = _OBJECT
_OBJECTLIST.fields_by_name['settings'].message_type = _SETTING
_SLICE.fields_by_name['object_lists'].message_type = _OBJECTLIST _SLICE.fields_by_name['object_lists'].message_type = _OBJECTLIST
_OBJECT.fields_by_name['settings'].message_type = _SETTING _OBJECT.fields_by_name['settings'].message_type = _SETTING
_SLICEDOBJECTLIST.fields_by_name['objects'].message_type = _SLICEDOBJECT _SLICEDOBJECTLIST.fields_by_name['objects'].message_type = _SLICEDOBJECT

View File

@ -28,7 +28,8 @@ class LayerData(MeshData):
self._layers[layer].polygons.append(p) self._layers[layer].polygons.append(p)
def getLayer(self, layer): def getLayer(self, layer):
return self._layers[layer] if layer in self._layers:
return self._layers[layer]
def getLayers(self): def getLayers(self):
return self._layers return self._layers
@ -216,7 +217,7 @@ class Polygon():
elif self._type == self.SkirtType: elif self._type == self.SkirtType:
return Color(0.0, 1.0, 1.0, 1.0) return Color(0.0, 1.0, 1.0, 1.0)
elif self._type == self.InfillType: elif self._type == self.InfillType:
return Color(1.0, 1.0, 0.0, 1.0) return Color(1.0, 0.74, 0.0, 1.0)
elif self._type == self.SupportInfillType: elif self._type == self.SupportInfillType:
return Color(0.0, 1.0, 1.0, 1.0) return Color(0.0, 1.0, 1.0, 1.0)
else: else:

View File

@ -1,5 +1,6 @@
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
## Simple decorator to indicate a scene node holds layer data.
class LayerDataDecorator(SceneNodeDecorator): class LayerDataDecorator(SceneNodeDecorator):
def __init__(self): def __init__(self):
super().__init__() super().__init__()

View File

@ -4,7 +4,6 @@
from UM.Job import Job from UM.Job import Job
from UM.Application import Application from UM.Application import Application
class ProcessGCodeLayerJob(Job): class ProcessGCodeLayerJob(Job):
def __init__(self, message): def __init__(self, message):
super().__init__() super().__init__()

View File

@ -27,7 +27,7 @@ class ProcessSlicedObjectListJob(Job):
def run(self): def run(self):
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView": if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
self._progress = Message(catalog.i18nc("Layers View mode", "Layers"), 0, False, 0) self._progress = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, -1)
self._progress.show() self._progress.show()
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged) Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
@ -43,18 +43,15 @@ class ProcessSlicedObjectListJob(Job):
else: else:
objectIdMap[id(node)] = node objectIdMap[id(node)] = node
settings = Application.getInstance().getActiveMachine() settings = Application.getInstance().getMachineManager().getActiveProfile()
layerHeight = settings.getSettingValueByKey("layer_height") layerHeight = settings.getSettingValue("layer_height")
center = None center = None
if not settings.getSettingValueByKey("machine_center_is_zero"): if not settings.getSettingValue("machine_center_is_zero"):
center = numpy.array([settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2]) center = numpy.array([settings.getSettingValue("machine_width") / 2, 0.0, -settings.getSettingValue("machine_depth") / 2])
else: else:
center = numpy.array([0.0, 0.0, 0.0]) center = numpy.array([0.0, 0.0, 0.0])
if self._progress:
self._progress.setProgress(2)
mesh = MeshData() mesh = MeshData()
layer_data = LayerData.LayerData() layer_data = LayerData.LayerData()
for object in self._message.objects: for object in self._message.objects:
@ -80,14 +77,10 @@ class ProcessSlicedObjectListJob(Job):
layer_data.addPolygon(layer.id, polygon.type, points, polygon.line_width) layer_data.addPolygon(layer.id, polygon.type, points, polygon.line_width)
if self._progress:
self._progress.setProgress(50)
# We are done processing all the layers we got from the engine, now create a mesh out of the data # We are done processing all the layers we got from the engine, now create a mesh out of the data
layer_data.build() layer_data.build()
if self._progress:
self._progress.setProgress(100)
#Add layerdata decorator to scene node to indicate that the node has layerdata #Add layerdata decorator to scene node to indicate that the node has layerdata
decorator = LayerDataDecorator.LayerDataDecorator() decorator = LayerDataDecorator.LayerDataDecorator()
@ -108,7 +101,7 @@ class ProcessSlicedObjectListJob(Job):
if self.isRunning(): if self.isRunning():
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView": if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
if not self._progress: if not self._progress:
self._progress = Message(catalog.i18nc("Layers View mode", "Layers"), 0, False, 0) self._progress = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, 0)
self._progress.show() self._progress.show()
else: else:
if self._progress: if self._progress:

View File

@ -10,9 +10,9 @@ catalog = i18nCatalog("cura")
def getMetaData(): def getMetaData():
return { return {
"plugin": { "plugin": {
"name": "CuraEngine Backend", "name": catalog.i18nc("@label", "CuraEngine Backend"),
"author": "Ultimaker", "author": "Ultimaker",
"description": catalog.i18nc("CuraEngine backend plugin description", "Provides the link to the CuraEngine slicing backend"), "description": catalog.i18nc("@info:whatsthis", "Provides the link to the CuraEngine slicing backend"),
"api": 2 "api": 2
} }
} }

View File

@ -9,17 +9,17 @@ catalog = i18nCatalog("cura")
def getMetaData(): def getMetaData():
return { return {
"plugin": { "plugin": {
"name": "GCode Writer", "name": catalog.i18nc("@label", "GCode Writer"),
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": catalog.i18nc("GCode Writer Plugin Description", "Writes GCode to a file"), "description": catalog.i18nc("@info:whatsthis", "Writes GCode to a file"),
"api": 2 "api": 2
}, },
"mesh_writer": { "mesh_writer": {
"output": [{ "output": [{
"extension": "gcode", "extension": "gcode",
"description": catalog.i18nc("GCode Writer File Description", "GCode File"), "description": catalog.i18nc("@item:inlistbox", "GCode File"),
"mime_type": "text/x-gcode", "mime_type": "text/x-gcode",
"mode": GCodeWriter.GCodeWriter.OutputMode.TextMode "mode": GCodeWriter.GCodeWriter.OutputMode.TextMode
}] }]

View File

@ -13,6 +13,8 @@ from UM.Mesh.MeshData import MeshData
from cura.ConvexHullNode import ConvexHullNode from cura.ConvexHullNode import ConvexHullNode
from PyQt5 import QtCore, QtWidgets
from . import LayerViewProxy from . import LayerViewProxy
## View used to display g-code paths. ## View used to display g-code paths.
@ -52,10 +54,10 @@ class LayerView(View):
renderer.setRenderSelection(False) renderer.setRenderSelection(False)
if not self._material: if not self._material:
self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "vertexcolor.frag")) self._material = renderer.createMaterial(Resources.getPath(Resources.Shaders, "basic.vert"), Resources.getPath(Resources.Shaders, "vertexcolor.frag"))
self._material.setUniformValue("u_color", [1.0, 0.0, 0.0, 1.0]) self._material.setUniformValue("u_color", [1.0, 0.0, 0.0, 1.0])
self._selection_material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "color.frag")) self._selection_material = renderer.createMaterial(Resources.getPath(Resources.Shaders, "basic.vert"), Resources.getPath(Resources.Shaders, "color.frag"))
self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128)) self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128))
for node in DepthFirstIterator(scene.getRoot()): for node in DepthFirstIterator(scene.getRoot()):
@ -92,9 +94,11 @@ class LayerView(View):
layer = self._current_layer_num - i layer = self._current_layer_num - i
if layer < 0: if layer < 0:
continue continue
try:
layer_mesh = layer_data.getLayer(layer).createMesh() layer_mesh = layer_data.getLayer(layer).createMesh()
if not layer_mesh or layer_mesh.getVertices() is None: if not layer_mesh or layer_mesh.getVertices() is None:
continue
except:
continue continue
self._current_layer_mesh.addVertices(layer_mesh.getVertices()) self._current_layer_mesh.addVertices(layer_mesh.getVertices())
@ -160,8 +164,12 @@ class LayerView(View):
pass pass
def event(self, event): def event(self, event):
if event.type == Event.KeyPressEvent: modifiers = QtWidgets.QApplication.keyboardModifiers()
ctrl_is_active = modifiers == QtCore.Qt.ControlModifier
if event.type == Event.KeyPressEvent and ctrl_is_active:
if event.key == KeyEvent.UpKey: if event.key == KeyEvent.UpKey:
self.setLayer(self._current_layer_num + 1) self.setLayer(self._current_layer_num + 1)
return True
if event.key == KeyEvent.DownKey: if event.key == KeyEvent.DownKey:
self.setLayer(self._current_layer_num - 1) self.setLayer(self._current_layer_num - 1)
return True

View File

@ -19,7 +19,7 @@ Item
width: 10 width: 10
height: 250 height: 250
anchors.right : parent.right anchors.right : parent.right
anchors.rightMargin: UM.Theme.sizes.slider_layerview_margin.width anchors.rightMargin: UM.Theme.sizes.slider_layerview_margin.width/2
orientation: Qt.Vertical orientation: Qt.Vertical
minimumValue: 0; minimumValue: 0;
maximumValue: UM.LayerView.numLayers; maximumValue: UM.LayerView.numLayers;
@ -38,14 +38,16 @@ Item
height: UM.Theme.sizes.slider_layerview_background_extension.height height: UM.Theme.sizes.slider_layerview_background_extension.height
color: UM.Theme.colors.slider_text_background color: UM.Theme.colors.slider_text_background
} }
UM.AngledCornerRectangle { Rectangle {
anchors.right : parent.right anchors.right : parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
z: slider.z - 1 z: slider.z - 1
cornerSize: UM.Theme.sizes.default_margin.width;
width: UM.Theme.sizes.slider_layerview_background.width width: UM.Theme.sizes.slider_layerview_background.width
height: slider.height + UM.Theme.sizes.default_margin.height * 2 height: slider.height + UM.Theme.sizes.default_margin.height * 2
color: UM.Theme.colors.slider_text_background color: UM.Theme.colors.tool_panel_background;
border.width: UM.Theme.sizes.default_lining.width
border.color: UM.Theme.colors.lining
MouseArea { MouseArea {
id: sliderMouseArea id: sliderMouseArea
property double manualStepSize: slider.maximumValue / 11 property double manualStepSize: slider.maximumValue / 11

View File

@ -16,13 +16,14 @@ class LayerViewProxy(QObject):
@pyqtProperty(bool, notify = activityChanged) @pyqtProperty(bool, notify = activityChanged)
def getLayerActivity(self): def getLayerActivity(self):
active_view = self._controller.getActiveView() active_view = self._controller.getActiveView()
return active_view.getActivity() if type(active_view) == LayerView.LayerView.LayerView:
return active_view.getActivity()
@pyqtProperty(int, notify = maxLayersChanged) @pyqtProperty(int, notify = maxLayersChanged)
def numLayers(self): def numLayers(self):
active_view = self._controller.getActiveView() active_view = self._controller.getActiveView()
#print("num max layers " , active_view.getMaxLayers()) if type(active_view) == LayerView.LayerView.LayerView:
return active_view.getMaxLayers() return active_view.getMaxLayers()
#return 100 #return 100
@pyqtProperty(int, notify = currentLayerChanged) @pyqtProperty(int, notify = currentLayerChanged)

View File

@ -10,14 +10,14 @@ catalog = i18nCatalog("cura")
def getMetaData(): def getMetaData():
return { return {
"plugin": { "plugin": {
"name": "Layer View", "name": catalog.i18nc("@label", "Layer View"),
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": catalog.i18nc("Layer View plugin description", "Provides the Layer view."), "description": catalog.i18nc("@info:whatsthis", "Provides the Layer view."),
"api": 2 "api": 2
}, },
"view": { "view": {
"name": catalog.i18nc("Layers View mode", "Layers"), "name": catalog.i18nc("@item:inlistbox", "Layers"),
"view_panel": "LayerView.qml" "view_panel": "LayerView.qml"
} }
} }

View File

@ -13,8 +13,8 @@ import os
import plistlib import plistlib
## Support for removable devices on Mac OSX ## Support for removable devices on Mac OSX
class OSXRemovableDrives(RemovableDrivePlugin.RemovableDrivePlugin): class OSXRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
def run(self): def checkRemovableDrives(self):
drives = {} drives = {}
p = subprocess.Popen(["system_profiler", "SPUSBDataType", "-xml"], stdout=subprocess.PIPE) p = subprocess.Popen(["system_profiler", "SPUSBDataType", "-xml"], stdout=subprocess.PIPE)
plist = plistlib.loads(p.communicate()[0]) plist = plistlib.loads(p.communicate()[0])
@ -41,6 +41,8 @@ class OSXRemovableDrives(RemovableDrivePlugin.RemovableDrivePlugin):
volume = vol["mount_point"] volume = vol["mount_point"]
drives[volume] = os.path.basename(volume) drives[volume] = os.path.basename(volume)
return drives
def performEjectDevice(self, device): def performEjectDevice(self, device):
p = subprocess.Popen(["diskutil", "eject", path], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p = subprocess.Popen(["diskutil", "eject", path], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = p.communicate() output = p.communicate()

View File

@ -10,15 +10,15 @@ from UM.OutputDevice.OutputDevice import OutputDevice
from UM.OutputDevice import OutputDeviceError from UM.OutputDevice import OutputDeviceError
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("uranium") catalog = i18nCatalog("cura")
class RemovableDriveOutputDevice(OutputDevice): class RemovableDriveOutputDevice(OutputDevice):
def __init__(self, device_id, device_name): def __init__(self, device_id, device_name):
super().__init__(device_id) super().__init__(device_id)
self.setName(device_name) self.setName(device_name)
self.setShortDescription(catalog.i18nc("", "Save to Removable Drive")) self.setShortDescription(catalog.i18nc("@action:button", "Save to Removable Drive"))
self.setDescription(catalog.i18nc("", "Save to Removable Drive {0}").format(device_name)) self.setDescription(catalog.i18nc("@item:inlistbox", "Save to Removable Drive {0}").format(device_name))
self.setIconName("save_sd") self.setIconName("save_sd")
self.setPriority(1) self.setPriority(1)
@ -49,7 +49,7 @@ class RemovableDriveOutputDevice(OutputDevice):
job.progress.connect(self._onProgress) job.progress.connect(self._onProgress)
job.finished.connect(self._onFinished) job.finished.connect(self._onFinished)
message = Message(catalog.i18nc("", "Saving to Removable Drive {0}").format(self.getName()), 0, False, -1) message = Message(catalog.i18nc("@info:progress", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1)
message.show() message.show()
job._message = message job._message = message
@ -70,13 +70,13 @@ class RemovableDriveOutputDevice(OutputDevice):
job._message = None job._message = None
self.writeFinished.emit(self) self.writeFinished.emit(self)
if job.getResult(): if job.getResult():
message = Message(catalog.i18nc("", "Saved to Removable Drive {0} as {1}").format(self.getName(), os.path.basename(job.getFileName()))) message = Message(catalog.i18nc("@info:status", "Saved to Removable Drive {0} as {1}").format(self.getName(), os.path.basename(job.getFileName())))
message.addAction("eject", catalog.i18nc("", "Eject"), "eject", catalog.i18nc("", "Eject removable device {0}").format(self.getName())) message.addAction("eject", catalog.i18nc("@action:button", "Eject"), "eject", catalog.i18nc("@action", "Eject removable device {0}").format(self.getName()))
message.actionTriggered.connect(self._onActionTriggered) message.actionTriggered.connect(self._onActionTriggered)
message.show() message.show()
self.writeSuccess.emit(self) self.writeSuccess.emit(self)
else: else:
message = Message(catalog.i18nc("", "Could not save to removable drive {0}: {1}").format(self.getName(), str(job.getError()))) message = Message(catalog.i18nc("@info:status", "Could not save to removable drive {0}: {1}").format(self.getName(), str(job.getError())))
message.show() message.show()
self.writeError.emit(self) self.writeError.emit(self)
job.getStream().close() job.getStream().close()

View File

@ -11,7 +11,7 @@ from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from . import RemovableDriveOutputDevice from . import RemovableDriveOutputDevice
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("uranium") catalog = i18nCatalog("cura")
class RemovableDrivePlugin(OutputDevicePlugin): class RemovableDrivePlugin(OutputDevicePlugin):
def __init__(self): def __init__(self):
@ -39,10 +39,10 @@ class RemovableDrivePlugin(OutputDevicePlugin):
def ejectDevice(self, device): def ejectDevice(self, device):
result = self.performEjectDevice(device) result = self.performEjectDevice(device)
if result: if result:
message = Message(catalog.i18n("Ejected {0}. You can now safely remove the drive.").format(device.getName())) message = Message(catalog.i18nc("@info:status", "Ejected {0}. You can now safely remove the drive.").format(device.getName()))
message.show() message.show()
else: else:
message = Message(catalog.i18n("Failed to eject {0}. Maybe it is still in use?").format(device.getName())) message = Message(catalog.i18nc("@info:status", "Failed to eject {0}. Maybe it is still in use?").format(device.getName()))
message.show() message.show()
def performEjectDevice(self, device): def performEjectDevice(self, device):

View File

@ -16,7 +16,7 @@ import os
import subprocess import subprocess
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("uranium") catalog = i18nCatalog("cura")
# WinAPI Constants that we need # WinAPI Constants that we need
# Hardcoded here due to stupid WinDLL stuff that does not give us access to these values. # Hardcoded here due to stupid WinDLL stuff that does not give us access to these values.
@ -55,7 +55,7 @@ class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
volume_name = name_buffer.value volume_name = name_buffer.value
if not volume_name: if not volume_name:
volume_name = catalog.i18nc("Default name for removable device", "Removable Drive") volume_name = catalog.i18nc("@item:intext", "Removable Drive")
# Certain readers will report themselves as a volume even when there is no card inserted, but will show an # Certain readers will report themselves as a volume even when there is no card inserted, but will show an
# "No volume in drive" warning when trying to call GetDiskFreeSpace. However, they will not report a valid # "No volume in drive" warning when trying to call GetDiskFreeSpace. However, they will not report a valid
@ -88,10 +88,13 @@ class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
result = None result = None
# Then, try and tell it to eject # Then, try and tell it to eject
if not windll.kernel32.DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, None, None, None, None, None, None): try:
if not windll.kernel32.DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, None, None, None, None, None, None):
result = False
else:
result = True
except Exception as e:
result = False result = False
else:
result = True
# Finally, close the handle # Finally, close the handle
windll.kernel32.CloseHandle(handle) windll.kernel32.CloseHandle(handle)

View File

@ -4,14 +4,14 @@
import platform import platform
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("uranium") catalog = i18nCatalog("cura")
def getMetaData(): def getMetaData():
return { return {
"plugin": { "plugin": {
"name": catalog.i18nc("Removable Drive Output Device Plugin name", "Removable Drive Output Device Plugin"), "name": catalog.i18nc("@label", "Removable Drive Output Device Plugin"),
"author": "Ultimaker B.V.", "author": "Ultimaker B.V.",
"description": catalog.i18nc("Removable Drive Output Device Plugin description", "Provides removable drive hotplugging and writing support"), "description": catalog.i18nc("@info:whatsthis", "Provides removable drive hotplugging and writing support"),
"version": "1.0", "version": "1.0",
"api": 2 "api": 2
} }

View File

@ -0,0 +1,121 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.Extension import Extension
from UM.Application import Application
from UM.Preferences import Preferences
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.Message import Message
from UM.i18n import i18nCatalog
import collections
import json
import os.path
import copy
import platform
import math
import urllib.request
import urllib.parse
catalog = i18nCatalog("cura")
## This Extension runs in the background and sends several bits of information to the Ultimaker servers.
# The data is only sent when the user in question gave permission to do so. All data is anonymous and
# no model files are being sent (Just a SHA256 hash of the model).
class SliceInfo(Extension):
def __init__(self):
super().__init__()
Application.getInstance().getOutputDeviceManager().writeStarted.connect(self._onWriteStarted)
Preferences.getInstance().addPreference("info/send_slice_info", True)
Preferences.getInstance().addPreference("info/asked_send_slice_info", False)
if not Preferences.getInstance().getValue("info/asked_send_slice_info"):
self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura automatically sends slice info. You can disable this in preferences"), lifetime = 0, dismissable = False)
self.send_slice_info_message.addAction("Dismiss", catalog.i18nc("@action:button", "Dismiss"), None, "")
self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered)
self.send_slice_info_message.show()
def messageActionTriggered(self, message_id, action_id):
self.send_slice_info_message.hide()
Preferences.getInstance().setValue("info/asked_send_slice_info", True)
def _onWriteStarted(self, output_device):
if not Preferences.getInstance().getValue("info/send_slice_info"):
return # Do nothing, user does not want to send data
settings = Application.getInstance().getMachineManager().getActiveProfile()
# Load all machine definitions and put them in machine_settings dict
#setting_file_name = Application.getInstance().getActiveMachineInstance().getMachineSettings()._json_file
machine_settings = {}
#with open(setting_file_name, "rt", -1, "utf-8") as f:
# data = json.load(f, object_pairs_hook = collections.OrderedDict)
#machine_settings[os.path.basename(setting_file_name)] = copy.deepcopy(data)
active_machine_definition= Application.getInstance().getMachineManager().getActiveMachineInstance().getMachineDefinition()
data = active_machine_definition._json_data
# Loop through inherited json files
setting_file_name = active_machine_definition._path
while True:
if "inherits" in data:
inherited_setting_file_name = os.path.dirname(setting_file_name) + "/" + data["inherits"]
with open(inherited_setting_file_name, "rt", -1, "utf-8") as f:
data = json.load(f, object_pairs_hook = collections.OrderedDict)
machine_settings[os.path.basename(inherited_setting_file_name)] = copy.deepcopy(data)
else:
break
profile_values = settings.getChangedSettings()
# Get total material used (in mm^3)
print_information = Application.getInstance().getPrintInformation()
material_radius = 0.5 * settings.getSettingValue("material_diameter")
material_used = math.pi * material_radius * material_radius * print_information.materialAmount #Volume of material used
# Get model information (bounding boxes, hashes and transformation matrix)
models_info = []
for node in DepthFirstIterator(Application.getInstance().getController().getScene().getRoot()):
if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
if not getattr(node, "_outside_buildarea", False):
model_info = {}
model_info["hash"] = node.getMeshData().getHash()
model_info["bounding_box"] = {}
model_info["bounding_box"]["minimum"] = {}
model_info["bounding_box"]["minimum"]["x"] = node.getBoundingBox().minimum.x
model_info["bounding_box"]["minimum"]["y"] = node.getBoundingBox().minimum.y
model_info["bounding_box"]["minimum"]["z"] = node.getBoundingBox().minimum.z
model_info["bounding_box"]["maximum"] = {}
model_info["bounding_box"]["maximum"]["x"] = node.getBoundingBox().maximum.x
model_info["bounding_box"]["maximum"]["y"] = node.getBoundingBox().maximum.y
model_info["bounding_box"]["maximum"]["z"] = node.getBoundingBox().maximum.z
model_info["transformation"] = str(node.getWorldTransformation().getData())
models_info.append(model_info)
# Bundle the collected data
submitted_data = {
"processor": platform.processor(),
"machine": platform.machine(),
"platform": platform.platform(),
"machine_settings": json.dumps(machine_settings),
"version": Application.getInstance().getVersion(),
"modelhash": "None",
"printtime": str(print_information.currentPrintTime),
"filament": material_used,
"language": Preferences.getInstance().getValue("general/language"),
"materials_profiles ": {}
}
# Convert data to bytes
submitted_data = urllib.parse.urlencode(submitted_data)
binary_data = submitted_data.encode('utf-8')
# Submit data
try:
f = urllib.request.urlopen("https://stats.youmagine.com/curastats/slice", data = binary_data, timeout = 1)
except Exception as e:
print("Exception occured", e)
f.close()

View File

@ -0,0 +1,19 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from . import SliceInfo
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": catalog.i18nc("@label", "Slice info"),
"author": "Ultimaker",
"version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Submits anonymous slice info. Can be disabled through preferences."),
"api": 2
}
}
def register(app):
return { "extension": SliceInfo.SliceInfo()}

View File

@ -6,13 +6,15 @@ import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Window 2.1 import QtQuick.Window 2.1
import UM 1.0 as UM import UM 1.1 as UM
UM.Dialog { UM.Dialog
{
width: 500 * Screen.devicePixelRatio; width: 500 * Screen.devicePixelRatio;
height: 100 * Screen.devicePixelRatio; height: 100 * Screen.devicePixelRatio;
modality: Qt.NonModal
title: "Print with USB" title: catalog.i18nc("@title:window", "Print with USB")
Column Column
{ {
@ -23,18 +25,20 @@ UM.Dialog {
Text Text
{ {
//: USB Printing dialog label, %1 is head temperature //: USB Printing dialog label, %1 is head temperature
text: qsTr("Extruder Temperature %1").arg(manager.extruderTemperature) text: catalog.i18nc("@label","Extruder Temperature %1").arg(manager.extruderTemperature)
} }
Text Text
{ {
//: USB Printing dialog label, %1 is bed temperature //: USB Printing dialog label, %1 is bed temperature
text: qsTr("Bed Temperature %1").arg(manager.bedTemperature) text: catalog.i18nc("@label","Bed Temperature %1").arg(manager.bedTemperature)
} }
Text Text
{ {
text: "" + manager.error text: "" + manager.error
} }
UM.I18nCatalog{id: catalog; name:"cura"}
} }
ProgressBar ProgressBar
@ -50,16 +54,17 @@ UM.Dialog {
} }
rightButtons: [ rightButtons: [
Button { Button
{
//: USB Printing dialog start print button //: USB Printing dialog start print button
text: qsTr("Print"); text: catalog.i18nc("@action:button","Print");
onClicked: { manager.startPrint() } onClicked: { manager.startPrint() }
enabled: manager.progress == 0 ? true : false enabled: manager.progress == 0 ? true : false
}, },
Button Button
{ {
//: USB Printing dialog cancel print button //: USB Printing dialog cancel print button
text: qsTr("Cancel"); text: catalog.i18nc("@action:button","Cancel");
onClicked: { manager.cancelPrint() } onClicked: { manager.cancelPrint() }
enabled: manager.progress == 0 ? false: true enabled: manager.progress == 0 ? false: true
} }

View File

@ -5,7 +5,7 @@ import QtQuick 2.2
import QtQuick.Window 2.2 import QtQuick.Window 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import UM 1.0 as UM import UM 1.1 as UM
UM.Dialog UM.Dialog
{ {
@ -17,15 +17,16 @@ UM.Dialog
visible: true; visible: true;
modality: Qt.ApplicationModal; modality: Qt.ApplicationModal;
title: "Firmware Update"; title: catalog.i18nc("@title:window","Firmware Update");
Column Column
{ {
anchors.fill: parent; anchors.fill: parent;
Text Label
{ {
anchors { anchors
{
left: parent.left; left: parent.left;
right: parent.right; right: parent.right;
} }
@ -34,17 +35,17 @@ UM.Dialog
if (manager.progress == 0) if (manager.progress == 0)
{ {
//: Firmware update status label //: Firmware update status label
return qsTr("Starting firmware update, this may take a while.") return catalog.i18nc("@label","Starting firmware update, this may take a while.")
} }
else if (manager.progress > 99) else if (manager.progress > 99)
{ {
//: Firmware update status label //: Firmware update status label
return qsTr("Firmware update completed.") return catalog.i18nc("@label","Firmware update completed.")
} }
else else
{ {
//: Firmware update status label //: Firmware update status label
return qsTr("Updating firmware.") return catalog.i18nc("@label","Updating firmware.")
} }
} }
@ -57,21 +58,26 @@ UM.Dialog
value: manager.progress value: manager.progress
minimumValue: 0; minimumValue: 0;
maximumValue: 100; maximumValue: 100;
anchors { anchors
{
left: parent.left; left: parent.left;
right: parent.right; right: parent.right;
} }
} }
SystemPalette { SystemPalette
{
id: palette; id: palette;
} }
UM.I18nCatalog { id: catalog; name: "cura"; }
} }
rightButtons: [ rightButtons: [
Button { Button
text: "Close"; {
text: catalog.i18nc("@action:button","Close");
enabled: manager.progress >= 100; enabled: manager.progress >= 100;
onClicked: base.visible = false; onClicked: base.visible = false;
} }

View File

@ -8,15 +8,34 @@ import time
import queue import queue
import re import re
import functools import functools
import os
import os.path
from UM.Application import Application from UM.Application import Application
from UM.Signal import Signal, SignalEmitter from UM.Signal import Signal, SignalEmitter
from UM.Resources import Resources from UM.Resources import Resources
from UM.Logger import Logger from UM.Logger import Logger
from UM.OutputDevice.OutputDevice import OutputDevice
from UM.OutputDevice import OutputDeviceError
from UM.PluginRegistry import PluginRegistry
class PrinterConnection(SignalEmitter): from PyQt5.QtQuick import QQuickView
def __init__(self, serial_port): from PyQt5.QtQml import QQmlComponent, QQmlContext
super().__init__() from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtProperty, pyqtSignal, Qt
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
class PrinterConnection(OutputDevice, QObject, SignalEmitter):
def __init__(self, serial_port, parent = None):
QObject.__init__(self, parent)
OutputDevice.__init__(self, serial_port)
SignalEmitter.__init__(self)
#super().__init__(serial_port)
self.setName(catalog.i18nc("@item:inmenu", "USB printing"))
self.setShortDescription(catalog.i18nc("@action:button", "Print with USB"))
self.setDescription(catalog.i18nc("@info:tooltip", "Print with USB"))
self.setIconName("print")
self._serial = None self._serial = None
self._serial_port = serial_port self._serial_port = serial_port
@ -25,6 +44,9 @@ class PrinterConnection(SignalEmitter):
self._connect_thread = threading.Thread(target = self._connect) self._connect_thread = threading.Thread(target = self._connect)
self._connect_thread.daemon = True self._connect_thread.daemon = True
self._end_stop_thread = threading.Thread(target = self._pollEndStop)
self._end_stop_thread.deamon = True
# Printer is connected # Printer is connected
self._is_connected = False self._is_connected = False
@ -33,7 +55,7 @@ class PrinterConnection(SignalEmitter):
# The baud checking is done by sending a number of m105 commands to the printer and waiting for a readable # The baud checking is done by sending a number of m105 commands to the printer and waiting for a readable
# response. If the baudrate is correct, this should make sense, else we get giberish. # response. If the baudrate is correct, this should make sense, else we get giberish.
self._required_responses_auto_baud = 10 self._required_responses_auto_baud = 3
self._progress = 0 self._progress = 0
@ -41,7 +63,7 @@ class PrinterConnection(SignalEmitter):
self._listen_thread.daemon = True self._listen_thread.daemon = True
self._update_firmware_thread = threading.Thread(target= self._updateFirmware) self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
self._update_firmware_thread.demon = True self._update_firmware_thread.deamon = True
self._heatup_wait_start_time = time.time() self._heatup_wait_start_time = time.time()
@ -78,6 +100,14 @@ class PrinterConnection(SignalEmitter):
# Current Z stage location # Current Z stage location
self._current_z = 0 self._current_z = 0
self._x_min_endstop_pressed = False
self._y_min_endstop_pressed = False
self._z_min_endstop_pressed = False
self._x_max_endstop_pressed = False
self._y_max_endstop_pressed = False
self._z_max_endstop_pressed = False
# In order to keep the connection alive we request the temperature every so often from a different extruder. # In order to keep the connection alive we request the temperature every so often from a different extruder.
# This index is the extruder we requested data from the last time. # This index is the extruder we requested data from the last time.
self._temperature_requested_extruder_index = 0 self._temperature_requested_extruder_index = 0
@ -86,6 +116,31 @@ class PrinterConnection(SignalEmitter):
self._firmware_file_name = None self._firmware_file_name = None
self._control_view = None
onError = pyqtSignal()
progressChanged = pyqtSignal()
extruderTemperatureChanged = pyqtSignal()
bedTemperatureChanged = pyqtSignal()
endstopStateChanged = pyqtSignal(str ,bool, arguments = ["key","state"])
@pyqtProperty(float, notify = progressChanged)
def progress(self):
return self._progress
@pyqtProperty(float, notify = extruderTemperatureChanged)
def extruderTemperature(self):
return self._extruder_temperatures[0]
@pyqtProperty(float, notify = bedTemperatureChanged)
def bedTemperature(self):
return self._bed_temperature
@pyqtProperty(str, notify = onError)
def error(self):
return self._error_state
# TODO: Might need to add check that extruders can not be changed when it started printing or loading these settings from settings object # TODO: Might need to add check that extruders can not be changed when it started printing or loading these settings from settings object
def setNumExtuders(self, num): def setNumExtuders(self, num):
self._extruder_count = num self._extruder_count = num
@ -98,11 +153,18 @@ class PrinterConnection(SignalEmitter):
return False return False
return self._is_printing return self._is_printing
@pyqtSlot()
def startPrint(self):
self.writeStarted.emit(self)
gcode_list = getattr( Application.getInstance().getController().getScene(), "gcode_list")
self.printGCode(gcode_list)
## Start a print based on a g-code. ## Start a print based on a g-code.
# \param gcode_list List with gcode (strings). # \param gcode_list List with gcode (strings).
def printGCode(self, gcode_list): def printGCode(self, gcode_list):
if self.isPrinting() or not self._is_connected: if self.isPrinting() or not self._is_connected:
Logger.log("d", "Printer is busy or not connected, aborting print") Logger.log("d", "Printer is busy or not connected, aborting print")
self.writeError.emit(self)
return return
self._gcode.clear() self._gcode.clear()
@ -119,6 +181,8 @@ class PrinterConnection(SignalEmitter):
for i in range(0, 4): #Push first 4 entries before accepting other inputs for i in range(0, 4): #Push first 4 entries before accepting other inputs
self._sendNextGcodeLine() self._sendNextGcodeLine()
self.writeFinished.emit(self)
## Get the serial port string of this connection. ## Get the serial port string of this connection.
# \return serial port # \return serial port
def getSerialPort(self): def getSerialPort(self):
@ -162,6 +226,8 @@ class PrinterConnection(SignalEmitter):
self.setProgress(100, 100) self.setProgress(100, 100)
self.firmwareUpdateComplete.emit()
## Upload new firmware to machine ## Upload new firmware to machine
# \param filename full path of firmware file to be uploaded # \param filename full path of firmware file to be uploaded
def updateFirmware(self, file_name): def updateFirmware(self, file_name):
@ -169,6 +235,20 @@ class PrinterConnection(SignalEmitter):
self._firmware_file_name = file_name self._firmware_file_name = file_name
self._update_firmware_thread.start() self._update_firmware_thread.start()
@pyqtSlot()
def startPollEndstop(self):
self._poll_endstop = True
self._end_stop_thread.start()
@pyqtSlot()
def stopPollEndstop(self):
self._poll_endstop = False
def _pollEndStop(self):
while self._is_connected and self._poll_endstop:
self.sendCommand("M119")
time.sleep(0.5)
## Private connect function run by thread. Can be started by calling connect. ## Private connect function run by thread. Can be started by calling connect.
def _connect(self): def _connect(self):
Logger.log("d", "Attempting to connect to %s", self._serial_port) Logger.log("d", "Attempting to connect to %s", self._serial_port)
@ -182,29 +262,24 @@ class PrinterConnection(SignalEmitter):
except Exception as e: except Exception as e:
Logger.log("i", "Could not establish connection on %s, unknown reasons. Device is not arduino based." % self._serial_port) Logger.log("i", "Could not establish connection on %s, unknown reasons. Device is not arduino based." % self._serial_port)
if not self._serial:
self._is_connecting = False
Logger.log("i", "Could not establish connection on %s, unknown reasons.", self._serial_port)
return
# If the programmer connected, we know its an atmega based version. Not all that usefull, but it does give some debugging information. # If the programmer connected, we know its an atmega based version. Not all that usefull, but it does give some debugging information.
for baud_rate in self._getBaudrateList(): # Cycle all baud rates (auto detect) for baud_rate in self._getBaudrateList(): # Cycle all baud rates (auto detect)
Logger.log("d","Attempting to connect to printer with serial %s on baud rate %s", self._serial_port, baud_rate)
if self._serial is None: if self._serial is None:
try: try:
self._serial = serial.Serial(str(self._serial_port), baud_rate, timeout=3, writeTimeout=10000) self._serial = serial.Serial(str(self._serial_port), baud_rate, timeout = 3, writeTimeout = 10000)
except serial.SerialException: except serial.SerialException:
Logger.log("i", "Could not open port %s" % self._serial_port) #Logger.log("i", "Could not open port %s" % self._serial_port)
return continue
else: else:
if not self.setBaudRate(baud_rate): if not self.setBaudRate(baud_rate):
continue # Could not set the baud rate, go to the next continue # Could not set the baud rate, go to the next
time.sleep(1.5) # Ensure that we are not talking to the bootloader. 1.5 sec seems to be the magic number time.sleep(1.5) # Ensure that we are not talking to the bootloader. 1.5 sec seems to be the magic number
sucesfull_responses = 0 sucesfull_responses = 0
timeout_time = time.time() + 15 timeout_time = time.time() + 5
self._serial.write(b"\n") self._serial.write(b"\n")
self._sendCommand("M105") # Request temperature, as this should (if baudrate is correct) result in a command with "T:" in it self._sendCommand("M105") # Request temperature, as this should (if baudrate is correct) result in a command with "T:" in it
while timeout_time > time.time(): while timeout_time > time.time():
line = self._readline() line = self._readline()
if line is None: if line is None:
@ -213,7 +288,6 @@ class PrinterConnection(SignalEmitter):
if b"T:" in line: if b"T:" in line:
self._serial.timeout = 0.5 self._serial.timeout = 0.5
self._sendCommand("M105")
sucesfull_responses += 1 sucesfull_responses += 1
if sucesfull_responses >= self._required_responses_auto_baud: if sucesfull_responses >= self._required_responses_auto_baud:
self._serial.timeout = 2 #Reset serial timeout self._serial.timeout = 2 #Reset serial timeout
@ -221,6 +295,8 @@ class PrinterConnection(SignalEmitter):
Logger.log("i", "Established printer connection on port %s" % self._serial_port) Logger.log("i", "Established printer connection on port %s" % self._serial_port)
return return
self._sendCommand("M105") # Send M105 as long as we are listening, otherwise we end up in an undefined state
Logger.log("e", "Baud rate detection for %s failed", self._serial_port) Logger.log("e", "Baud rate detection for %s failed", self._serial_port)
self.close() # Unable to connect, wrap up. self.close() # Unable to connect, wrap up.
self.setIsConnected(False) self.setIsConnected(False)
@ -240,15 +316,6 @@ class PrinterConnection(SignalEmitter):
self.connectionStateChanged.emit(self._serial_port) self.connectionStateChanged.emit(self._serial_port)
if self._is_connected: if self._is_connected:
self._listen_thread.start() #Start listening self._listen_thread.start() #Start listening
#Application.getInstance().addOutputDevice(self._serial_port, {
#"id": self._serial_port,
#"function": self.printGCode,
#"shortDescription": "Print with USB",
#"description": "Print with USB {0}".format(self._serial_port),
#"icon": "save",
#"priority": 1
#})
else: else:
Logger.log("w", "Printer connection state was not changed") Logger.log("w", "Printer connection state was not changed")
@ -262,6 +329,9 @@ class PrinterConnection(SignalEmitter):
except Exception as e: except Exception as e:
pass # This should work, but it does fail sometimes for some reason pass # This should work, but it does fail sometimes for some reason
self._connect_thread = threading.Thread(target=self._connect)
self._connect_thread.daemon = True
if self._serial is not None: if self._serial is not None:
self.setIsConnected(False) self.setIsConnected(False)
try: try:
@ -270,11 +340,32 @@ class PrinterConnection(SignalEmitter):
pass pass
self._serial.close() self._serial.close()
self._listen_thread = threading.Thread(target=self._listen)
self._listen_thread.daemon = True
self._serial = None self._serial = None
def isConnected(self): def isConnected(self):
return self._is_connected return self._is_connected
@pyqtSlot(int)
def heatupNozzle(self, temperature):
Logger.log("d", "Setting nozzle temperature to %s", temperature)
self._sendCommand("M104 S%s" % temperature)
@pyqtSlot(int)
def heatupBed(self, temperature):
Logger.log("d", "Setting bed temperature to %s", temperature)
self._sendCommand("M140 S%s" % temperature)
@pyqtSlot("long", "long","long")
def moveHead(self, x, y, z):
Logger.log("d","Moving head to %s, %s , %s", x, y, z)
self._sendCommand("G0 X%s Y%s Z%s"%(x,y,z))
@pyqtSlot()
def homeHead(self):
self._sendCommand("G28")
## Directly send the command, withouth checking connection state (eg; printing). ## Directly send the command, withouth checking connection state (eg; printing).
# \param cmd string with g-code # \param cmd string with g-code
def _sendCommand(self, cmd): def _sendCommand(self, cmd):
@ -296,10 +387,9 @@ class PrinterConnection(SignalEmitter):
self._target_bed_temperature = float(re.search("S([0-9]+)", cmd).group(1)) self._target_bed_temperature = float(re.search("S([0-9]+)", cmd).group(1))
except: except:
pass pass
#Logger.log("i","Sending: %s" % (cmd))
try: try:
command = (cmd + "\n").encode() command = (cmd + "\n").encode()
#self._serial.write(b"\n") self._serial.write(b"\n")
self._serial.write(command) self._serial.write(command)
except serial.SerialTimeoutException: except serial.SerialTimeoutException:
Logger.log("w","Serial timeout while writing to serial port, trying again.") Logger.log("w","Serial timeout while writing to serial port, trying again.")
@ -319,6 +409,21 @@ class PrinterConnection(SignalEmitter):
def __del__(self): def __del__(self):
self.close() self.close()
def createControlInterface(self):
if self._control_view is None:
path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath("USBPrinting"), "ControlWindow.qml"))
component = QQmlComponent(Application.getInstance()._engine, path)
self._control_context = QQmlContext(Application.getInstance()._engine.rootContext())
self._control_context.setContextProperty("manager", self)
self._control_view = component.create(self._control_context)
## Show control interface.
# This will create the view if its not already created.
def showControlInterface(self):
if self._control_view is None:
self.createControlInterface()
self._control_view.show()
## Send a command to printer. ## Send a command to printer.
# \param cmd string with g-code # \param cmd string with g-code
def sendCommand(self, cmd): def sendCommand(self, cmd):
@ -331,9 +436,7 @@ class PrinterConnection(SignalEmitter):
# \param error String with the error message. # \param error String with the error message.
def _setErrorState(self, error): def _setErrorState(self, error):
self._error_state = error self._error_state = error
self.onError.emit(error) self.onError.emit()
onError = Signal()
## Private function to set the temperature of an extruder ## Private function to set the temperature of an extruder
# \param index index of the extruder # \param index index of the extruder
@ -341,21 +444,33 @@ class PrinterConnection(SignalEmitter):
def _setExtruderTemperature(self, index, temperature): def _setExtruderTemperature(self, index, temperature):
try: try:
self._extruder_temperatures[index] = temperature self._extruder_temperatures[index] = temperature
self.onExtruderTemperatureChange.emit(self._serial_port, index, temperature) self.extruderTemperatureChanged.emit()
except Exception as e: except Exception as e:
pass pass
onExtruderTemperatureChange = Signal()
## Private function to set the temperature of the bed. ## Private function to set the temperature of the bed.
# As all printers (as of time of writing) only support a single heated bed, # As all printers (as of time of writing) only support a single heated bed,
# these are not indexed as with extruders. # these are not indexed as with extruders.
def _setBedTemperature(self, temperature): def _setBedTemperature(self, temperature):
self._bed_temperature = temperature self._bed_temperature = temperature
self.onBedTemperatureChange.emit(self._serial_port,temperature) self.bedTemperatureChanged.emit()
onBedTemperatureChange = Signal() def requestWrite(self, node):
self.showControlInterface()
def _setEndstopState(self, endstop_key, value):
if endstop_key == b'x_min':
if self._x_min_endstop_pressed != value:
self.endstopStateChanged.emit('x_min', value)
self._x_min_endstop_pressed = value
elif endstop_key == b'y_min':
if self._y_min_endstop_pressed != value:
self.endstopStateChanged.emit('y_min', value)
self._y_min_endstop_pressed = value
elif endstop_key == b'z_min':
if self._z_min_endstop_pressed != value:
self.endstopStateChanged.emit('z_min', value)
self._z_min_endstop_pressed = value
## Listen thread function. ## Listen thread function.
def _listen(self): def _listen(self):
@ -368,6 +483,14 @@ class PrinterConnection(SignalEmitter):
if line is None: if line is None:
break # None is only returned when something went wrong. Stop listening break # None is only returned when something went wrong. Stop listening
if time.time() > temperature_request_timeout:
if self._extruder_count > 0:
self._temperature_requested_extruder_index = (self._temperature_requested_extruder_index + 1) % self._extruder_count
self.sendCommand("M105 T%d" % (self._temperature_requested_extruder_index))
else:
self.sendCommand("M105")
temperature_request_timeout = time.time() + 5
if line.startswith(b"Error:"): if line.startswith(b"Error:"):
# Oh YEAH, consistency. # Oh YEAH, consistency.
# Marlin reports an MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n" # Marlin reports an MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n"
@ -392,16 +515,11 @@ class PrinterConnection(SignalEmitter):
except Exception as e: except Exception as e:
pass pass
#TODO: temperature changed callback #TODO: temperature changed callback
elif b"_min" in line or b"_max" in line:
tag, value = line.split(b':', 1)
self._setEndstopState(tag,(b'H' in value or b'TRIGGERED' in value))
if self._is_printing: if self._is_printing:
if time.time() > temperature_request_timeout: # When printing, request temperature every 5 seconds.
if self._extruder_count > 0:
self._temperature_requested_extruder_index = (self._temperature_requested_extruder_index + 1) % self._extruder_count
self.sendCommand("M105 T%d" % (self._temperature_requested_extruder_index))
else:
self.sendCommand("M105")
temperature_request_timeout = time.time() + 5
if line == b"" and time.time() > ok_timeout: if line == b"" and time.time() > ok_timeout:
line = b"ok" # Force a timeout (basicly, send next command) line = b"ok" # Force a timeout (basicly, send next command)
@ -453,17 +571,16 @@ class PrinterConnection(SignalEmitter):
self._sendCommand("N%d%s*%d" % (self._gcode_position, line, checksum)) self._sendCommand("N%d%s*%d" % (self._gcode_position, line, checksum))
self._gcode_position += 1 self._gcode_position += 1
self.setProgress(( self._gcode_position / len(self._gcode)) * 100) self.setProgress(( self._gcode_position / len(self._gcode)) * 100)
self.progressChanged.emit(self._progress, self._serial_port) self.progressChanged.emit()
progressChanged = Signal()
## Set the progress of the print. ## Set the progress of the print.
# It will be normalized (based on max_progress) to range 0 - 100 # It will be normalized (based on max_progress) to range 0 - 100
def setProgress(self, progress, max_progress = 100): def setProgress(self, progress, max_progress = 100):
self._progress = (progress / max_progress) * 100 #Convert to scale of 0-100 self._progress = (progress / max_progress) * 100 #Convert to scale of 0-100
self.progressChanged.emit(self._progress, self._serial_port) self.progressChanged.emit()
## Cancel the current print. Printer connection wil continue to listen. ## Cancel the current print. Printer connection wil continue to listen.
@pyqtSlot()
def cancelPrint(self): def cancelPrint(self):
self._gcode_position = 0 self._gcode_position = 0
self.setProgress(0) self.setProgress(0)
@ -494,5 +611,12 @@ class PrinterConnection(SignalEmitter):
## Create a list of baud rates at which we can communicate. ## Create a list of baud rates at which we can communicate.
# \return list of int # \return list of int
def _getBaudrateList(self): def _getBaudrateList(self):
ret = [250000, 230400, 115200, 57600, 38400, 19200, 9600] ret = [115200, 250000, 230400, 57600, 38400, 19200, 9600]
return ret return ret
def _onFirmwareUpdateComplete(self):
self._update_firmware_thread.join()
self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
self._update_firmware_thread.deamon = True
self.connect()

View File

@ -9,6 +9,10 @@ from UM.Scene.SceneNode import SceneNode
from UM.Resources import Resources from UM.Resources import Resources
from UM.Logger import Logger from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from UM.Qt.ListModel import ListModel
from cura.CuraApplication import CuraApplication
import threading import threading
import platform import platform
@ -22,37 +26,50 @@ from UM.Extension import Extension
from PyQt5.QtQuick import QQuickView from PyQt5.QtQuick import QQuickView
from PyQt5.QtQml import QQmlComponent, QQmlContext from PyQt5.QtQml import QQmlComponent, QQmlContext
from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtProperty, pyqtSignal, Qt from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtProperty, pyqtSignal, Qt
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura") i18n_catalog = i18nCatalog("cura")
class USBPrinterManager(QObject, SignalEmitter, Extension): class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
def __init__(self, parent = None): def __init__(self, parent = None):
super().__init__(parent) QObject.__init__(self, parent)
SignalEmitter.__init__(self)
OutputDevicePlugin.__init__(self)
Extension.__init__(self)
self._serial_port_list = [] self._serial_port_list = []
self._printer_connections = [] self._printer_connections = {}
self._check_ports_thread = threading.Thread(target = self._updateConnectionList) self._printer_connections_model = None
self._check_ports_thread.daemon = True self._update_thread = threading.Thread(target = self._updateThread)
self._check_ports_thread.start() self._update_thread.setDaemon(True)
self._progress = 0 self._check_updates = True
self._control_view = None
self._firmware_view = None self._firmware_view = None
self._extruder_temp = 0
self._bed_temp = 0
self._error_message = ""
## Add menu item to top menu of the application. ## Add menu item to top menu of the application.
self.setMenuName("Firmware") self.setMenuName(i18n_catalog.i18nc("@title:menu","Firmware"))
self.addMenuItem(i18n_catalog.i18n("Update Firmware"), self.updateAllFirmware) self.addMenuItem(i18n_catalog.i18nc("@item:inmenu", "Update Firmware"), self.updateAllFirmware)
Application.getInstance().applicationShuttingDown.connect(self._onApplicationShuttingDown) Application.getInstance().applicationShuttingDown.connect(self.stop)
self.addConnectionSignal.connect(self.addConnection) #Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
pyqtError = pyqtSignal(str, arguments = ["error"]) addConnectionSignal = Signal()
processingProgress = pyqtSignal(float, arguments = ["amount"]) printerConnectionStateChanged = pyqtSignal()
pyqtExtruderTemperature = pyqtSignal(float, arguments = ["amount"])
pyqtBedTemperature = pyqtSignal(float, arguments = ["amount"]) def start(self):
self._check_updates = True
self._update_thread.start()
def stop(self):
self._check_updates = False
try:
self._update_thread.join()
except RuntimeError:
pass
def _updateThread(self):
while self._check_updates:
result = self.getSerialPortList(only_list_usb = True)
self._addRemovePorts(result)
time.sleep(5)
## Show firmware interface. ## Show firmware interface.
# This will create the view if its not already created. # This will create the view if its not already created.
@ -67,80 +84,38 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
self._firmware_view.show() self._firmware_view.show()
## Show control interface.
# This will create the view if its not already created.
def spawnControlInterface(self,serial_port):
if self._control_view is None:
path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath("USBPrinting"), "ControlWindow.qml"))
component = QQmlComponent(Application.getInstance()._engine, path)
self._control_context = QQmlContext(Application.getInstance()._engine.rootContext())
self._control_context.setContextProperty("manager", self)
self._control_view = component.create(self._control_context)
self._control_view.show()
@pyqtProperty(float,notify = processingProgress)
def progress(self):
return self._progress
@pyqtProperty(float,notify = pyqtExtruderTemperature)
def extruderTemperature(self):
return self._extruder_temp
@pyqtProperty(float,notify = pyqtBedTemperature)
def bedTemperature(self):
return self._bed_temp
@pyqtProperty(str,notify = pyqtError)
def error(self):
return self._error_message
## Check all serial ports and create a PrinterConnection object for them.
# Note that this does not validate if the serial ports are actually usable!
# This (the validation) is only done when the connect function is called.
def _updateConnectionList(self):
while True:
temp_serial_port_list = self.getSerialPortList(only_list_usb = True)
if temp_serial_port_list != self._serial_port_list: # Something changed about the list since we last changed something.
disconnected_ports = [port for port in self._serial_port_list if port not in temp_serial_port_list ]
self._serial_port_list = temp_serial_port_list
for serial_port in self._serial_port_list:
if self.getConnectionByPort(serial_port) is None: # If it doesn't already exist, add it
if not os.path.islink(serial_port): # Only add the connection if it's a non symbolic link
connection = PrinterConnection.PrinterConnection(serial_port)
connection.connect()
connection.connectionStateChanged.connect(self.serialConectionStateCallback)
connection.progressChanged.connect(self.onProgress)
connection.onExtruderTemperatureChange.connect(self.onExtruderTemperature)
connection.onBedTemperatureChange.connect(self.onBedTemperature)
connection.onError.connect(self.onError)
self._printer_connections.append(connection)
for serial_port in disconnected_ports: # Close connections and remove them from list.
connection = self.getConnectionByPort(serial_port)
if connection != None:
self._printer_connections.remove(connection)
connection.close()
time.sleep(5) # Throttle, as we don"t need this information to be updated every single second.
def updateAllFirmware(self): def updateAllFirmware(self):
self.spawnFirmwareInterface("") self.spawnFirmwareInterface("")
for printer_connection in self._printer_connections: for printer_connection in self._printer_connections:
try: try:
printer_connection.updateFirmware(Resources.getPath(Resources.FirmwareLocation, self._getDefaultFirmwareName())) self._printer_connections[printer_connection].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName()))
except FileNotFoundError: except FileNotFoundError:
continue continue
@pyqtSlot(str, result = bool)
def updateFirmwareBySerial(self, serial_port): def updateFirmwareBySerial(self, serial_port):
printer_connection = self.getConnectionByPort(serial_port) if serial_port in self._printer_connections:
if printer_connection is not None: self.spawnFirmwareInterface(self._printer_connections[serial_port].getSerialPort())
self.spawnFirmwareInterface(printer_connection.getSerialPort()) try:
printer_connection.updateFirmware(Resources.getPath(Resources.FirmwareLocation, self._getDefaultFirmwareName())) self._printer_connections[serial_port].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName()))
except FileNotFoundError:
self._firmware_view.close()
Logger.log("e", "Could not find firmware required for this machine")
return False
return True
return False
## Return the singleton instance of the USBPrinterManager
@classmethod
def getInstance(cls, engine = None, script_engine = None):
# Note: Explicit use of class name to prevent issues with inheritance.
if USBPrinterManager._instance is None:
USBPrinterManager._instance = cls()
return USBPrinterManager._instance
def _getDefaultFirmwareName(self): def _getDefaultFirmwareName(self):
machine_type = Application.getInstance().getActiveMachine().getTypeID() machine_type = Application.getInstance().getMachineManager().getActiveMachineInstance().getMachineDefinition().getId()
firmware_name = "" firmware_name = ""
baudrate = 250000 baudrate = 250000
if sys.platform.startswith("linux"): if sys.platform.startswith("linux"):
@ -165,115 +140,41 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
firmware_name += ".hex" firmware_name += ".hex"
return firmware_name return firmware_name
## Callback for extruder temperature change def _addRemovePorts(self, serial_ports):
def onExtruderTemperature(self, serial_port, index, temperature): # First, find and add all new or changed keys
self._extruder_temp = temperature for serial_port in list(serial_ports):
self.pyqtExtruderTemperature.emit(temperature) if serial_port not in self._serial_port_list:
self.addConnectionSignal.emit(serial_port) #Hack to ensure its created in main thread
continue
self._serial_port_list = list(serial_ports)
## Callback for bed temperature change ## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
def onBedTemperature(self, serial_port,temperature): def addConnection(self, serial_port):
self._bed_temp = temperature connection = PrinterConnection.PrinterConnection(serial_port)
self.pyqtBedTemperature.emit(temperature) connection.connect()
connection.connectionStateChanged.connect(self._onPrinterConnectionStateChanged)
self._printer_connections[serial_port] = connection
## Callback for error def _onPrinterConnectionStateChanged(self, serial_port):
def onError(self, error): if self._printer_connections[serial_port].isConnected():
self._error_message = error if type(error) is str else error.decode("utf-8") self.getOutputDeviceManager().addOutputDevice(self._printer_connections[serial_port])
self.pyqtError.emit(self._error_message) else:
self.getOutputDeviceManager().removeOutputDevice(serial_port)
self.printerConnectionStateChanged.emit()
## Callback for progress change @pyqtProperty(QObject , notify = printerConnectionStateChanged)
def onProgress(self, progress, serial_port): def connectedPrinterList(self):
self._progress = progress self._printer_connections_model = ListModel()
self.processingProgress.emit(progress) self._printer_connections_model.addRoleName(Qt.UserRole + 1,"name")
self._printer_connections_model.addRoleName(Qt.UserRole + 2, "printer")
## Attempt to connect with all possible connections.
def connectAllConnections(self):
for connection in self._printer_connections: for connection in self._printer_connections:
connection.connect() if self._printer_connections[connection].isConnected():
self._printer_connections_model.appendItem({"name":connection, "printer": self._printer_connections[connection]})
## Send gcode to printer and start printing return self._printer_connections_model
def sendGCodeByPort(self, serial_port, gcode_list):
printer_connection = self.getConnectionByPort(serial_port)
if printer_connection is not None:
printer_connection.printGCode(gcode_list)
return True
return False
@pyqtSlot()
def cancelPrint(self):
for printer_connection in self.getActiveConnections():
printer_connection.cancelPrint()
## Send gcode to all active printers.
# \return True if there was at least one active connection.
def sendGCodeToAllActive(self, gcode_list):
for printer_connection in self.getActiveConnections():
printer_connection.printGCode(gcode_list)
if len(self.getActiveConnections()):
return True
else:
return False
## Send a command to a printer indentified by port
# \param serial port String indentifieing the port
# \param command String with the g-code command to send.
# \return True if connection was found, false otherwise
def sendCommandByPort(self, serial_port, command):
printer_connection = self.getConnectionByPort(serial_port)
if printer_connection is not None:
printer_connection.sendCommand(command)
return True
return False
## Send a command to all active (eg; connected) printers
# \param command String with the g-code command to send.
# \return True if at least one connection was found, false otherwise
def sendCommandToAllActive(self, command):
for printer_connection in self.getActiveConnections():
printer_connection.sendCommand(command)
if len(self.getActiveConnections()):
return True
else:
return False
## Callback if the connection state of a connection is changed.
# This adds or removes the connection as a possible output device.
def serialConectionStateCallback(self, serial_port):
connection = self.getConnectionByPort(serial_port)
if connection.isConnected():
Application.getInstance().addOutputDevice(serial_port, {
"id": serial_port,
"function": self.spawnControlInterface,
"description": "Print with USB {0}".format(serial_port),
"shortDescription": "Print with USB",
"icon": "save",
"priority": 1
})
else:
Application.getInstance().removeOutputDevice(serial_port)
@pyqtSlot()
def startPrint(self):
gcode_list = getattr(Application.getInstance().getController().getScene(), "gcode_list", None)
if gcode_list:
final_list = []
for gcode in gcode_list:
final_list += gcode.split("\n")
self.sendGCodeToAllActive(gcode_list)
## Get a list of printer connection objects that are connected.
def getActiveConnections(self):
return [connection for connection in self._printer_connections if connection.isConnected()]
## Get a printer connection object by serial port
def getConnectionByPort(self, serial_port):
for printer_connection in self._printer_connections:
if serial_port == printer_connection.getSerialPort():
return printer_connection
return None
## Create a list of serial ports on the system. ## Create a list of serial ports on the system.
# \param only_list_usb If true, only usb ports are listed # \param only_list_usb If true, only usb ports are listed
def getSerialPortList(self,only_list_usb=False): def getSerialPortList(self, only_list_usb = False):
base_list = [] base_list = []
if platform.system() == "Windows": if platform.system() == "Windows":
import winreg import winreg
@ -293,8 +194,6 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
base_list = filter(lambda s: "Bluetooth" not in s, base_list) # Filter because mac sometimes puts them in the list base_list = filter(lambda s: "Bluetooth" not in s, base_list) # Filter because mac sometimes puts them in the list
else: else:
base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/rfcomm*") + glob.glob("/dev/serial/by-id/*") base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/rfcomm*") + glob.glob("/dev/serial/by-id/*")
return base_list return list(base_list)
def _onApplicationShuttingDown(self): _instance = None
for connection in self._printer_connections:
connection.close()

View File

@ -2,7 +2,7 @@
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from . import USBPrinterManager from . import USBPrinterManager
from PyQt5.QtQml import qmlRegisterType, qmlRegisterSingletonType
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura") i18n_catalog = i18nCatalog("cura")
@ -10,12 +10,14 @@ def getMetaData():
return { return {
"type": "extension", "type": "extension",
"plugin": { "plugin": {
"name": "USB printing", "name": i18n_catalog.i18nc("@label", "USB printing"),
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": i18n_catalog.i18nc("USB Printing plugin description","Accepts G-Code and sends them to a printer. Plugin can also update firmware") "api": 2,
"description": i18n_catalog.i18nc("@info:whatsthis","Accepts G-Code and sends them to a printer. Plugin can also update firmware.")
} }
} }
def register(app): def register(app):
return {"extension":USBPrinterManager.USBPrinterManager()} qmlRegisterSingletonType(USBPrinterManager.USBPrinterManager, "UM", 1, 0, "USBPrinterManager", USBPrinterManager.USBPrinterManager.getInstance)
return {"extension":USBPrinterManager.USBPrinterManager.getInstance(),"output_device": USBPrinterManager.USBPrinterManager.getInstance() }

File diff suppressed because it is too large Load Diff

View File

@ -1,419 +0,0 @@
msgid ""
msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
#. About dialog title
#: ../resources/qml/AboutDialog.qml:12
msgctxt "AboutDialog|"
msgid "About Cura"
msgstr ""
#. About dialog application description
#: ../resources/qml/AboutDialog.qml:42
msgctxt "AboutDialog|"
msgid "End-to-end solution for fused filament 3D printing."
msgstr ""
#. About dialog application author note
#: ../resources/qml/AboutDialog.qml:47
msgctxt "AboutDialog|"
msgid ""
"Cura has been developed by Ultimaker B.V. in cooperation with the community."
msgstr ""
#. Close about dialog button
#: ../resources/qml/AboutDialog.qml:58
msgctxt "AboutDialog|"
msgid "Close"
msgstr ""
#. Undo action
#: ../resources/qml/Actions.qml:37
msgctxt "Actions|"
msgid "&Undo"
msgstr ""
#. Redo action
#: ../resources/qml/Actions.qml:45
msgctxt "Actions|"
msgid "&Redo"
msgstr ""
#. Quit action
#: ../resources/qml/Actions.qml:53
msgctxt "Actions|"
msgid "&Quit"
msgstr ""
#. Preferences action
#: ../resources/qml/Actions.qml:61
msgctxt "Actions|"
msgid "&Preferences..."
msgstr ""
#. Add Printer action
#: ../resources/qml/Actions.qml:68
msgctxt "Actions|"
msgid "&Add Printer..."
msgstr ""
#. Configure Printers action
#: ../resources/qml/Actions.qml:74
msgctxt "Actions|"
msgid "&Configure Printers"
msgstr ""
#. Show Online Documentation action
#: ../resources/qml/Actions.qml:81
msgctxt "Actions|"
msgid "Show Online &Documentation"
msgstr ""
#. Report a Bug Action
#: ../resources/qml/Actions.qml:89
msgctxt "Actions|"
msgid "Report a &Bug"
msgstr ""
#. About action
#: ../resources/qml/Actions.qml:96
msgctxt "Actions|"
msgid "&About..."
msgstr ""
#. Delete selection action
#: ../resources/qml/Actions.qml:103
msgctxt "Actions|"
msgid "Delete Selection"
msgstr ""
#. Delete object action
#: ../resources/qml/Actions.qml:111
msgctxt "Actions|"
msgid "Delete Object"
msgstr ""
#. Center object action
#: ../resources/qml/Actions.qml:118
msgctxt "Actions|"
msgid "Center Object on Platform"
msgstr ""
#. Duplicate object action
#: ../resources/qml/Actions.qml:124
msgctxt "Actions|"
msgid "Duplicate Object"
msgstr ""
#. Split object action
#: ../resources/qml/Actions.qml:130
msgctxt "Actions|"
msgid "Split Object into Parts"
msgstr ""
#. Clear build platform action
#: ../resources/qml/Actions.qml:137
msgctxt "Actions|"
msgid "Clear Build Platform"
msgstr ""
#. Reload all objects action
#: ../resources/qml/Actions.qml:144
msgctxt "Actions|"
msgid "Reload All Objects"
msgstr ""
#. Reset all positions action
#: ../resources/qml/Actions.qml:150
msgctxt "Actions|"
msgid "Reset All Object Positions"
msgstr ""
#. Reset all positions action
#: ../resources/qml/Actions.qml:156
msgctxt "Actions|"
msgid "Reset All Object Transformations"
msgstr ""
#. Open file action
#: ../resources/qml/Actions.qml:162
msgctxt "Actions|"
msgid "&Open..."
msgstr ""
#. Save file action
#: ../resources/qml/Actions.qml:170
msgctxt "Actions|"
msgid "&Save..."
msgstr ""
#. Show engine log action
#: ../resources/qml/Actions.qml:178
msgctxt "Actions|"
msgid "Show engine &log..."
msgstr ""
#. Add Printer dialog title
#. ----------
#. Add Printer wizard page title
#: ../resources/qml/AddMachineWizard.qml:12
#: ../resources/qml/AddMachineWizard.qml:19
msgctxt "AddMachineWizard|"
msgid "Add Printer"
msgstr ""
#. Add Printer wizard page description
#: ../resources/qml/AddMachineWizard.qml:25
msgctxt "AddMachineWizard|"
msgid "Please select the type of printer:"
msgstr ""
#. Add Printer wizard field label
#: ../resources/qml/AddMachineWizard.qml:40
msgctxt "AddMachineWizard|"
msgid "Printer Name:"
msgstr ""
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:53
msgctxt "AddMachineWizard|"
msgid "Next"
msgstr ""
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:63
msgctxt "AddMachineWizard|"
msgid "Cancel"
msgstr ""
#. USB Printing dialog label, %1 is head temperature
#: ../plugins/USBPrinting/ControlWindow.qml:15
#, qt-format
msgctxt "ControlWindow|"
msgid "Extruder Temperature %1"
msgstr ""
#. USB Printing dialog label, %1 is bed temperature
#: ../plugins/USBPrinting/ControlWindow.qml:20
#, qt-format
msgctxt "ControlWindow|"
msgid "Bed Temperature %1"
msgstr ""
#. USB Printing dialog start print button
#: ../plugins/USBPrinting/ControlWindow.qml:33
msgctxt "ControlWindow|"
msgid "Print"
msgstr ""
#. USB Printing dialog cancel print button
#: ../plugins/USBPrinting/ControlWindow.qml:40
msgctxt "ControlWindow|"
msgid "Cancel"
msgstr ""
#. Cura application window title
#: ../resources/qml/Cura.qml:14
msgctxt "Cura|"
msgid "Cura"
msgstr ""
#. File menu
#: ../resources/qml/Cura.qml:26
msgctxt "Cura|"
msgid "&File"
msgstr ""
#. Edit menu
#: ../resources/qml/Cura.qml:38
msgctxt "Cura|"
msgid "&Edit"
msgstr ""
#. Machine menu
#: ../resources/qml/Cura.qml:50
msgctxt "Cura|"
msgid "&Machine"
msgstr ""
#. Extensions menu
#: ../resources/qml/Cura.qml:76
msgctxt "Cura|"
msgid "E&xtensions"
msgstr ""
#. Settings menu
#: ../resources/qml/Cura.qml:107
msgctxt "Cura|"
msgid "&Settings"
msgstr ""
#. Help menu
#: ../resources/qml/Cura.qml:114
msgctxt "Cura|"
msgid "&Help"
msgstr ""
#. View Mode toolbar button
#: ../resources/qml/Cura.qml:231
msgctxt "Cura|"
msgid "View Mode"
msgstr ""
#. View preferences page title
#: ../resources/qml/Cura.qml:273
msgctxt "Cura|"
msgid "View"
msgstr ""
#. File open dialog title
#: ../resources/qml/Cura.qml:370
msgctxt "Cura|"
msgid "Open File"
msgstr ""
#. File save dialog title
#: ../resources/qml/Cura.qml:386
msgctxt "Cura|"
msgid "Save File"
msgstr ""
#. Engine Log dialog title
#: ../resources/qml/EngineLog.qml:11
msgctxt "EngineLog|"
msgid "Engine Log"
msgstr ""
#. Close engine log button
#: ../resources/qml/EngineLog.qml:30
msgctxt "EngineLog|"
msgid "Close"
msgstr ""
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:16
msgctxt "FirmwareUpdateWindow|"
msgid "Starting firmware update, this may take a while."
msgstr ""
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:21
msgctxt "FirmwareUpdateWindow|"
msgid "Firmware update completed."
msgstr ""
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:26
msgctxt "FirmwareUpdateWindow|"
msgid "Updating firmware."
msgstr ""
#. Print material amount save button label
#: ../resources/qml/SaveButton.qml:149
#, qt-format
msgctxt "SaveButton|"
msgid "%1m material"
msgstr ""
#. Save button label
#: ../resources/qml/SaveButton.qml:191
msgctxt "SaveButton|"
msgid "Please load a 3D model"
msgstr ""
#. Save button label
#: ../resources/qml/SaveButton.qml:194
msgctxt "SaveButton|"
msgid "Calculating Print-time"
msgstr ""
#. Save button label
#: ../resources/qml/SaveButton.qml:197
msgctxt "SaveButton|"
msgid "Estimated Print-time"
msgstr ""
#. Simple configuration mode option
#: ../resources/qml/Sidebar.qml:105
msgctxt "Sidebar|"
msgid "Simple"
msgstr ""
#. Advanced configuration mode option
#: ../resources/qml/Sidebar.qml:107
msgctxt "Sidebar|"
msgid "Advanced"
msgstr ""
#. Configuration mode label
#: ../resources/qml/SidebarHeader.qml:26
msgctxt "SidebarHeader|"
msgid "Mode:"
msgstr ""
#. Machine selection label
#: ../resources/qml/SidebarHeader.qml:70
msgctxt "SidebarHeader|"
msgid "Machine:"
msgstr ""
#. Sidebar header label
#: ../resources/qml/SidebarHeader.qml:117
msgctxt "SidebarHeader|"
msgid "Print Setup"
msgstr ""
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:40
msgctxt "SidebarSimple|"
msgid "No Model Loaded"
msgstr ""
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:45
msgctxt "SidebarSimple|"
msgid "Calculating..."
msgstr ""
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:50
msgctxt "SidebarSimple|"
msgid "Estimated Print Time"
msgstr ""
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:87
msgctxt "SidebarSimple|"
msgid ""
"Minimum\n"
"Draft"
msgstr ""
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:97
msgctxt "SidebarSimple|"
msgid ""
"Maximum\n"
"Quality"
msgstr ""
#. Setting checkbox
#: ../resources/qml/SidebarSimple.qml:109
msgctxt "SidebarSimple|"
msgid "Enable Support"
msgstr ""
#. View configuration page title
#: ../resources/qml/ViewPage.qml:9
msgctxt "ViewPage|"
msgid "View"
msgstr ""
#. Display Overhang preference checkbox
#: ../resources/qml/ViewPage.qml:24
msgctxt "ViewPage|"
msgid "Display Overhang"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@ -1,425 +0,0 @@
msgid ""
msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"X-Generator: Poedit 1.8\n"
"Language: cz\n"
#. About dialog title
#: ../resources/qml/AboutDialog.qml:12
msgctxt "AboutDialog|"
msgid "About Cura"
msgstr "Über Cura"
#. About dialog application description
#: ../resources/qml/AboutDialog.qml:42
msgctxt "AboutDialog|"
msgid "End-to-end solution for fused filament 3D printing."
msgstr "Komplettlösung für den 3D-Druck mit geschmolzenem Filament."
#. About dialog application author note
#: ../resources/qml/AboutDialog.qml:47
msgctxt "AboutDialog|"
msgid "Cura has been developed by Ultimaker B.V. in cooperation with the community."
msgstr "Cura wurde von Ultimaker B.V. in Zusammenarbeit mit der Gemeinschaft entwickelt."
#. Close about dialog button
#: ../resources/qml/AboutDialog.qml:58
msgctxt "AboutDialog|"
msgid "Close"
msgstr "Schließen"
#. Undo action
#: ../resources/qml/Actions.qml:37
msgctxt "Actions|"
msgid "&Undo"
msgstr "&Rückgängig machen"
#. Redo action
#: ../resources/qml/Actions.qml:45
msgctxt "Actions|"
msgid "&Redo"
msgstr "&Wiederholen"
#. Quit action
#: ../resources/qml/Actions.qml:53
msgctxt "Actions|"
msgid "&Quit"
msgstr "&Beenden"
#. Preferences action
#: ../resources/qml/Actions.qml:61
msgctxt "Actions|"
msgid "&Preferences..."
msgstr "&Einstellungen..."
#. Add Printer action
#: ../resources/qml/Actions.qml:68
msgctxt "Actions|"
msgid "&Add Printer..."
msgstr "&Drucker hinzufügen..."
#. Configure Printers action
#: ../resources/qml/Actions.qml:74
msgctxt "Actions|"
msgid "&Configure Printers"
msgstr "Drucker &konfigurieren"
#. Show Online Documentation action
#: ../resources/qml/Actions.qml:81
msgctxt "Actions|"
msgid "Show Online &Documentation"
msgstr "Online-&Dokumentation anzeigen"
#. Report a Bug Action
#: ../resources/qml/Actions.qml:89
msgctxt "Actions|"
msgid "Report a &Bug"
msgstr "&Fehler berichten"
#. About action
#: ../resources/qml/Actions.qml:96
msgctxt "Actions|"
msgid "&About..."
msgstr "&Über..."
#. Delete selection action
#: ../resources/qml/Actions.qml:103
msgctxt "Actions|"
msgid "Delete Selection"
msgstr "Auswahl löschen"
#. Delete object action
#: ../resources/qml/Actions.qml:111
msgctxt "Actions|"
msgid "Delete Object"
msgstr "Objekt löschen"
#. Center object action
#: ../resources/qml/Actions.qml:118
msgctxt "Actions|"
msgid "Center Object on Platform"
msgstr "Objekt auf Plattform zentrieren"
#. Duplicate object action
#: ../resources/qml/Actions.qml:124
msgctxt "Actions|"
msgid "Duplicate Object"
msgstr "Objekt duplizieren"
#. Split object action
#: ../resources/qml/Actions.qml:130
msgctxt "Actions|"
msgid "Split Object into Parts"
msgstr "Objekt teilen"
#. Clear build platform action
#: ../resources/qml/Actions.qml:137
msgctxt "Actions|"
msgid "Clear Build Platform"
msgstr "Druckplatte reinigen"
#. Reload all objects action
#: ../resources/qml/Actions.qml:144
msgctxt "Actions|"
msgid "Reload All Objects"
msgstr "Alle Objekte neu laden"
#. Reset all positions action
#: ../resources/qml/Actions.qml:150
msgctxt "Actions|"
msgid "Reset All Object Positions"
msgstr "Alle Objektpositionen zurücksetzen"
#. Reset all positions action
#: ../resources/qml/Actions.qml:156
msgctxt "Actions|"
msgid "Reset All Object Transformations"
msgstr "Alle Objektumwandlungen zurücksetzen"
#. Open file action
#: ../resources/qml/Actions.qml:162
msgctxt "Actions|"
msgid "&Open..."
msgstr "&Öffnen..."
#. Save file action
#: ../resources/qml/Actions.qml:170
msgctxt "Actions|"
msgid "&Save..."
msgstr "&Speichern..."
#. Show engine log action
#: ../resources/qml/Actions.qml:178
msgctxt "Actions|"
msgid "Show engine &log..."
msgstr "Engine-&Protokoll anzeigen..."
#. Add Printer dialog title
#. ----------
#. Add Printer wizard page title
#: ../resources/qml/AddMachineWizard.qml:12
#: ../resources/qml/AddMachineWizard.qml:19
msgctxt "AddMachineWizard|"
msgid "Add Printer"
msgstr "Drucker hinzufügen"
#. Add Printer wizard page description
#: ../resources/qml/AddMachineWizard.qml:25
msgctxt "AddMachineWizard|"
msgid "Please select the type of printer:"
msgstr "Wählen Sie den Druckertyp:"
#. Add Printer wizard field label
#: ../resources/qml/AddMachineWizard.qml:40
msgctxt "AddMachineWizard|"
msgid "Printer Name:"
msgstr "Druckername:"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:53
msgctxt "AddMachineWizard|"
msgid "Next"
msgstr "Weiter"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:63
msgctxt "AddMachineWizard|"
msgid "Cancel"
msgstr "Abbrechen"
#. USB Printing dialog label, %1 is head temperature
#: ../plugins/USBPrinting/ControlWindow.qml:15
#, qt-format
msgctxt "ControlWindow|"
msgid "Extruder Temperature %1"
msgstr "Extruder-Temperatur %1"
#. USB Printing dialog label, %1 is bed temperature
#: ../plugins/USBPrinting/ControlWindow.qml:20
#, qt-format
msgctxt "ControlWindow|"
msgid "Bed Temperature %1"
msgstr "Druckbett-Temperatur %1"
#. USB Printing dialog start print button
#: ../plugins/USBPrinting/ControlWindow.qml:33
msgctxt "ControlWindow|"
msgid "Print"
msgstr "Drucken"
#. USB Printing dialog cancel print button
#: ../plugins/USBPrinting/ControlWindow.qml:40
msgctxt "ControlWindow|"
msgid "Cancel"
msgstr "Abbrechen"
#. Cura application window title
#: ../resources/qml/Cura.qml:14
msgctxt "Cura|"
msgid "Cura"
msgstr "Cura"
#. File menu
#: ../resources/qml/Cura.qml:26
msgctxt "Cura|"
msgid "&File"
msgstr "&Datei"
#. Edit menu
#: ../resources/qml/Cura.qml:38
msgctxt "Cura|"
msgid "&Edit"
msgstr "&Bearbeiten"
#. Machine menu
#: ../resources/qml/Cura.qml:50
msgctxt "Cura|"
msgid "&Machine"
msgstr "&Maschine"
#. Extensions menu
#: ../resources/qml/Cura.qml:76
msgctxt "Cura|"
msgid "E&xtensions"
msgstr "Er&weiterungen"
#. Settings menu
#: ../resources/qml/Cura.qml:107
msgctxt "Cura|"
msgid "&Settings"
msgstr "&Einstellungen"
#. Help menu
#: ../resources/qml/Cura.qml:114
msgctxt "Cura|"
msgid "&Help"
msgstr "&Hilfe"
#. View Mode toolbar button
#: ../resources/qml/Cura.qml:231
msgctxt "Cura|"
msgid "View Mode"
msgstr "Ansichtsmodus"
#. View preferences page title
#: ../resources/qml/Cura.qml:273
msgctxt "Cura|"
msgid "View"
msgstr "Ansicht"
#. File open dialog title
#: ../resources/qml/Cura.qml:370
msgctxt "Cura|"
msgid "Open File"
msgstr "Datei öffnen"
#. File save dialog title
#: ../resources/qml/Cura.qml:386
msgctxt "Cura|"
msgid "Save File"
msgstr "Datei speichern"
#. Engine Log dialog title
#: ../resources/qml/EngineLog.qml:11
msgctxt "EngineLog|"
msgid "Engine Log"
msgstr "Engine-Protokoll"
#. Close engine log button
#: ../resources/qml/EngineLog.qml:30
msgctxt "EngineLog|"
msgid "Close"
msgstr "Schließen"
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:16
msgctxt "FirmwareUpdateWindow|"
msgid "Starting firmware update, this may take a while."
msgstr "Das Firmware-Update wird gestartet. Dies kann eine Weile dauern."
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:21
msgctxt "FirmwareUpdateWindow|"
msgid "Firmware update completed."
msgstr "Firmware-Update abgeschlossen."
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:26
msgctxt "FirmwareUpdateWindow|"
msgid "Updating firmware."
msgstr "Die Firmware wird aktualisiert."
#. Print material amount save button label
#: ../resources/qml/SaveButton.qml:149
#, qt-format
msgctxt "SaveButton|"
msgid "%1m material"
msgstr "%1m Material"
#. Save button label
#: ../resources/qml/SaveButton.qml:191
msgctxt "SaveButton|"
msgid "Please load a 3D model"
msgstr "Laden Sie ein 3D-Modell"
#. Save button label
#: ../resources/qml/SaveButton.qml:194
msgctxt "SaveButton|"
msgid "Calculating Print-time"
msgstr "Die Druck-Dauer wird berechnet"
#. Save button label
#: ../resources/qml/SaveButton.qml:197
msgctxt "SaveButton|"
msgid "Estimated Print-time"
msgstr "Geschätzte Druck-Dauer"
#. Simple configuration mode option
#: ../resources/qml/Sidebar.qml:105
msgctxt "Sidebar|"
msgid "Simple"
msgstr "Einfach"
#. Advanced configuration mode option
#: ../resources/qml/Sidebar.qml:107
msgctxt "Sidebar|"
msgid "Advanced"
msgstr "Erweitert"
#. Configuration mode label
#: ../resources/qml/SidebarHeader.qml:26
msgctxt "SidebarHeader|"
msgid "Mode:"
msgstr "Modus:"
#. Machine selection label
#: ../resources/qml/SidebarHeader.qml:70
msgctxt "SidebarHeader|"
msgid "Machine:"
msgstr "Maschine:"
#. Sidebar header label
#: ../resources/qml/SidebarHeader.qml:117
msgctxt "SidebarHeader|"
msgid "Print Setup"
msgstr "Druckkonfiguration"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:40
msgctxt "SidebarSimple|"
msgid "No Model Loaded"
msgstr "Kein Modell geladen"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:45
msgctxt "SidebarSimple|"
msgid "Calculating..."
msgstr "Die Berechnung läuft..."
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:50
msgctxt "SidebarSimple|"
msgid "Estimated Print Time"
msgstr "Geschätzte Druck-Dauer"
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:87
msgctxt "SidebarSimple|"
msgid ""
"Minimum\n"
"Draft"
msgstr "Minimal\nEntwurf"
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:97
msgctxt "SidebarSimple|"
msgid ""
"Maximum\n"
"Quality"
msgstr "Maximal\nQualität"
#. Setting checkbox
#: ../resources/qml/SidebarSimple.qml:109
msgctxt "SidebarSimple|"
msgid "Enable Support"
msgstr "Stützstruktur aktivieren"
#. View configuration page title
#: ../resources/qml/ViewPage.qml:9
msgctxt "ViewPage|"
msgid "View"
msgstr "Ansicht"
#. Display Overhang preference checkbox
#: ../resources/qml/ViewPage.qml:24
msgctxt "ViewPage|"
msgid "Display Overhang"
msgstr "Überhang anzeigen"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,434 +0,0 @@
msgid ""
msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Project-Id-Version: cura_0\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: Romain Di Vozzo <romaindivozzo@hotmail.com>\n"
"Language: es\n"
"X-Generator: Poedit 1.8.1\n"
#. About dialog title
#: ../resources/qml/AboutDialog.qml:12
msgctxt "AboutDialog|"
msgid "About Cura"
msgstr "Acerca de Cura"
#. About dialog application description
#: ../resources/qml/AboutDialog.qml:42
msgctxt "AboutDialog|"
msgid "End-to-end solution for fused filament 3D printing."
msgstr "Solución de extremo a extremo para impresion 3D. "
#. About dialog application author note
#: ../resources/qml/AboutDialog.qml:47
msgctxt "AboutDialog|"
msgid "Cura has been developed by Ultimaker B.V. in cooperation with the community."
msgstr "Cura ha sido desarrollado por Ultimaker B.V. en cooperación con la comunidad."
#. Close about dialog button
#: ../resources/qml/AboutDialog.qml:58
msgctxt "AboutDialog|"
msgid "Close"
msgstr "Cerrar"
#. Undo action
#: ../resources/qml/Actions.qml:37
msgctxt "Actions|"
msgid "&Undo"
msgstr "Deshacer"
#. Redo action
#: ../resources/qml/Actions.qml:45
msgctxt "Actions|"
msgid "&Redo"
msgstr "Rehacer"
#. Quit action
#: ../resources/qml/Actions.qml:53
msgctxt "Actions|"
msgid "&Quit"
msgstr "Salir"
#. Preferences action
#: ../resources/qml/Actions.qml:61
msgctxt "Actions|"
msgid "&Preferences..."
msgstr "Preferencias..."
#. Add Printer action
#: ../resources/qml/Actions.qml:68
msgctxt "Actions|"
msgid "&Add Printer..."
msgstr "Añadir una Impresora…"
#. Configure Printers action
#: ../resources/qml/Actions.qml:74
msgctxt "Actions|"
msgid "&Configure Printers"
msgstr "Configurar las Impresoras"
#. Show Online Documentation action
#: ../resources/qml/Actions.qml:81
msgctxt "Actions|"
msgid "Show Online &Documentation"
msgstr "Mostrar la Documentación en Línea"
#. Report a Bug Action
#: ../resources/qml/Actions.qml:89
msgctxt "Actions|"
msgid "Report a &Bug"
msgstr "Reportar un Error"
#. About action
#: ../resources/qml/Actions.qml:96
msgctxt "Actions|"
msgid "&About..."
msgstr "Acerca de..."
#. Delete selection action
#: ../resources/qml/Actions.qml:103
msgctxt "Actions|"
msgid "Delete Selection"
msgstr "Borrar la Selección"
#. Delete object action
#: ../resources/qml/Actions.qml:111
msgctxt "Actions|"
msgid "Delete Object"
msgstr "Borrar el Objeto"
#. Center object action
#: ../resources/qml/Actions.qml:118
msgctxt "Actions|"
msgid "Center Object on Platform"
msgstr "Centrar el Objeto en la Plataforma"
#. Duplicate object action
#: ../resources/qml/Actions.qml:124
msgctxt "Actions|"
msgid "Duplicate Object"
msgstr "Duplicar el Objeto"
#. Split object action
#: ../resources/qml/Actions.qml:130
msgctxt "Actions|"
msgid "Split Object into Parts"
msgstr "Separar el objeto en partes"
#. Clear build platform action
#: ../resources/qml/Actions.qml:137
msgctxt "Actions|"
msgid "Clear Build Platform"
msgstr "Vaciar la Plataforma"
#. Reload all objects action
#: ../resources/qml/Actions.qml:144
msgctxt "Actions|"
msgid "Reload All Objects"
msgstr "Recargar Todos los Objetos"
#. Reset all positions action
#: ../resources/qml/Actions.qml:150
msgctxt "Actions|"
msgid "Reset All Object Positions"
msgstr "Reiniciar la Posición de Todos los Objetos"
#. Reset all positions action
#: ../resources/qml/Actions.qml:156
msgctxt "Actions|"
msgid "Reset All Object Transformations"
msgstr "Reiniciar la Transformación de Todos los Objetos"
#. Open file action
#: ../resources/qml/Actions.qml:162
msgctxt "Actions|"
msgid "&Open..."
msgstr "Abrir..."
#. Save file action
#: ../resources/qml/Actions.qml:170
msgctxt "Actions|"
msgid "&Save..."
msgstr "Guardar..."
#. Show engine log action
#: ../resources/qml/Actions.qml:178
msgctxt "Actions|"
msgid "Show engine &log..."
msgstr "Mostrar el Registro del Motor de Cálculo "
#. Add Printer dialog title
#. ----------
#. Add Printer wizard page title
#: ../resources/qml/AddMachineWizard.qml:12
#: ../resources/qml/AddMachineWizard.qml:19
msgctxt "AddMachineWizard|"
msgid "Add Printer"
msgstr "Añadir una Impresora"
#. Add Printer wizard page description
#: ../resources/qml/AddMachineWizard.qml:25
msgctxt "AddMachineWizard|"
msgid "Please select the type of printer:"
msgstr "Seleccionar un Tipo de Impresora:"
#. Add Printer wizard field label
#: ../resources/qml/AddMachineWizard.qml:40
msgctxt "AddMachineWizard|"
msgid "Printer Name:"
msgstr "Nombre de la Impresora:"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:53
msgctxt "AddMachineWizard|"
msgid "Next"
msgstr "Siguiente"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:63
msgctxt "AddMachineWizard|"
msgid "Cancel"
msgstr "Cancelar"
# ?? -> %1
#. USB Printing dialog label, %1 is head temperature
#: ../plugins/USBPrinting/ControlWindow.qml:15
#, qt-format
msgctxt "ControlWindow|"
msgid "Extruder Temperature %1"
msgstr "Temperatura del Extrusor (%1)"
# ?? -> %1
#. USB Printing dialog label, %1 is bed temperature
#: ../plugins/USBPrinting/ControlWindow.qml:20
#, qt-format
msgctxt "ControlWindow|"
msgid "Bed Temperature %1"
msgstr "Temperatura de la Plataforma %1"
#. USB Printing dialog start print button
#: ../plugins/USBPrinting/ControlWindow.qml:33
msgctxt "ControlWindow|"
msgid "Print"
msgstr "Imprimir "
#. USB Printing dialog cancel print button
#: ../plugins/USBPrinting/ControlWindow.qml:40
msgctxt "ControlWindow|"
msgid "Cancel"
msgstr "Cancelar"
#. Cura application window title
#: ../resources/qml/Cura.qml:14
msgctxt "Cura|"
msgid "Cura"
msgstr "Cura"
#. File menu
#: ../resources/qml/Cura.qml:26
msgctxt "Cura|"
msgid "&File"
msgstr "Archivo"
#. Edit menu
#: ../resources/qml/Cura.qml:38
msgctxt "Cura|"
msgid "&Edit"
msgstr "Editar"
#. Machine menu
#: ../resources/qml/Cura.qml:50
msgctxt "Cura|"
msgid "&Machine"
msgstr "Maquina"
#. Extensions menu
#: ../resources/qml/Cura.qml:76
msgctxt "Cura|"
msgid "E&xtensions"
msgstr "Extensiones"
#. Settings menu
#: ../resources/qml/Cura.qml:107
msgctxt "Cura|"
msgid "&Settings"
msgstr "Ajustes"
#. Help menu
#: ../resources/qml/Cura.qml:114
msgctxt "Cura|"
msgid "&Help"
msgstr "Ayuda"
#. View Mode toolbar button
#: ../resources/qml/Cura.qml:231
msgctxt "Cura|"
msgid "View Mode"
msgstr "Modo de Visualización "
#. View preferences page title
#: ../resources/qml/Cura.qml:273
msgctxt "Cura|"
msgid "View"
msgstr "Visualización "
#. File open dialog title
#: ../resources/qml/Cura.qml:370
msgctxt "Cura|"
msgid "Open File"
msgstr "Abrir el Archivo"
#. File save dialog title
#: ../resources/qml/Cura.qml:386
msgctxt "Cura|"
msgid "Save File"
msgstr "Guardar el Archivo"
#. Engine Log dialog title
#: ../resources/qml/EngineLog.qml:11
msgctxt "EngineLog|"
msgid "Engine Log"
msgstr "Registro del Motor de Cálculo "
#. Close engine log button
#: ../resources/qml/EngineLog.qml:30
msgctxt "EngineLog|"
msgid "Close"
msgstr "Cerrar"
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:16
msgctxt "FirmwareUpdateWindow|"
msgid "Starting firmware update, this may take a while."
msgstr "Empezando la Actualización del Firmware, este proceso puede tardar un rato."
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:21
msgctxt "FirmwareUpdateWindow|"
msgid "Firmware update completed."
msgstr "Actualización de Firmware completada."
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:26
msgctxt "FirmwareUpdateWindow|"
msgid "Updating firmware."
msgstr "Actualizando el Firmware."
#. Print material amount save button label
#: ../resources/qml/SaveButton.qml:149
#, qt-format
msgctxt "SaveButton|"
msgid "%1m material"
msgstr "%1m de material"
#. Save button label
#: ../resources/qml/SaveButton.qml:191
msgctxt "SaveButton|"
msgid "Please load a 3D model"
msgstr "Cargar un Archivo 3D"
#. Save button label
#: ../resources/qml/SaveButton.qml:194
msgctxt "SaveButton|"
msgid "Calculating Print-time"
msgstr "Calculando la Duración de la Impresión "
#. Save button label
#: ../resources/qml/SaveButton.qml:197
msgctxt "SaveButton|"
msgid "Estimated Print-time"
msgstr "Duración Estimada de la Impresión"
#. Simple configuration mode option
#: ../resources/qml/Sidebar.qml:105
msgctxt "Sidebar|"
msgid "Simple"
msgstr "Simple"
#. Advanced configuration mode option
#: ../resources/qml/Sidebar.qml:107
msgctxt "Sidebar|"
msgid "Advanced"
msgstr "Avanzado"
#. Configuration mode label
#: ../resources/qml/SidebarHeader.qml:26
msgctxt "SidebarHeader|"
msgid "Mode:"
msgstr "Modo:"
#. Machine selection label
#: ../resources/qml/SidebarHeader.qml:70
msgctxt "SidebarHeader|"
msgid "Machine:"
msgstr "Máquina:"
#. Sidebar header label
#: ../resources/qml/SidebarHeader.qml:117
msgctxt "SidebarHeader|"
msgid "Print Setup"
msgstr "Configurar la Impresión"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:40
msgctxt "SidebarSimple|"
msgid "No Model Loaded"
msgstr "Ningún Modelo Cargado"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:45
msgctxt "SidebarSimple|"
msgid "Calculating..."
msgstr "Calculando..."
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:50
msgctxt "SidebarSimple|"
msgid "Estimated Print Time"
msgstr "Duración Estimada de la Impresión"
# a small doubt on the word "calado
# "...
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:87
msgctxt "SidebarSimple|"
msgid ""
"Minimum\n"
"Draft"
msgstr ""
"Calado\n"
"Mínimo "
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:97
msgctxt "SidebarSimple|"
msgid ""
"Maximum\n"
"Quality"
msgstr ""
"Calidad\n"
"Máxima"
#. Setting checkbox
#: ../resources/qml/SidebarSimple.qml:109
msgctxt "SidebarSimple|"
msgid "Enable Support"
msgstr "Habilitar Soporte"
#. View configuration page title
#: ../resources/qml/ViewPage.qml:9
msgctxt "ViewPage|"
msgid "View"
msgstr "Visualizar "
#. Display Overhang preference checkbox
#: ../resources/qml/ViewPage.qml:24
msgctxt "ViewPage|"
msgid "Display Overhang"
msgstr "Visualizar los Voladizos"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,426 +0,0 @@
msgid ""
msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: Tapio <info@tapimex.fi>\n"
"Language-Team: \n"
"Language: fi_FI\n"
"X-Generator: Poedit 1.8.1\n"
#. About dialog title
#: ../resources/qml/AboutDialog.qml:12
msgctxt "AboutDialog|"
msgid "About Cura"
msgstr "Tietoja Curasta"
#. About dialog application description
#: ../resources/qml/AboutDialog.qml:42
msgctxt "AboutDialog|"
msgid "End-to-end solution for fused filament 3D printing."
msgstr "Kokonaisvaltainen sulatettavan tulostuslangan 3D-tulostusratkaisu."
#. About dialog application author note
#: ../resources/qml/AboutDialog.qml:47
msgctxt "AboutDialog|"
msgid "Cura has been developed by Ultimaker B.V. in cooperation with the community."
msgstr "Cura-ohjelman on kehittänyt Ultimaker B.V. yhteistyössä yhteisön kanssa."
#. Close about dialog button
#: ../resources/qml/AboutDialog.qml:58
msgctxt "AboutDialog|"
msgid "Close"
msgstr "Sulje"
#. Undo action
#: ../resources/qml/Actions.qml:37
msgctxt "Actions|"
msgid "&Undo"
msgstr "&Kumoa"
#. Redo action
#: ../resources/qml/Actions.qml:45
msgctxt "Actions|"
msgid "&Redo"
msgstr "Tee &uudelleen"
#. Quit action
#: ../resources/qml/Actions.qml:53
msgctxt "Actions|"
msgid "&Quit"
msgstr "&Lopeta"
#. Preferences action
#: ../resources/qml/Actions.qml:61
msgctxt "Actions|"
msgid "&Preferences..."
msgstr "&Suosikkiasetukset..."
#. Add Printer action
#: ../resources/qml/Actions.qml:68
msgctxt "Actions|"
msgid "&Add Printer..."
msgstr "L&isää tulostin..."
#. Configure Printers action
#: ../resources/qml/Actions.qml:74
msgctxt "Actions|"
msgid "&Configure Printers"
msgstr "&Määritä tulostimet"
#. Show Online Documentation action
#: ../resources/qml/Actions.qml:81
msgctxt "Actions|"
msgid "Show Online &Documentation"
msgstr "Näytä sähköinen &dokumentaatio"
#. Report a Bug Action
#: ../resources/qml/Actions.qml:89
msgctxt "Actions|"
msgid "Report a &Bug"
msgstr "Ilmoita &virheestä"
#. About action
#: ../resources/qml/Actions.qml:96
msgctxt "Actions|"
msgid "&About..."
msgstr "Ti&etoja..."
#. Delete selection action
#: ../resources/qml/Actions.qml:103
msgctxt "Actions|"
msgid "Delete Selection"
msgstr "Poista valinta"
#. Delete object action
#: ../resources/qml/Actions.qml:111
msgctxt "Actions|"
msgid "Delete Object"
msgstr "Poista kohde"
#. Center object action
#: ../resources/qml/Actions.qml:118
msgctxt "Actions|"
msgid "Center Object on Platform"
msgstr "Keskitä kohde alustalle"
#. Duplicate object action
#: ../resources/qml/Actions.qml:124
msgctxt "Actions|"
msgid "Duplicate Object"
msgstr "Monista kohde"
#. Split object action
#: ../resources/qml/Actions.qml:130
msgctxt "Actions|"
msgid "Split Object into Parts"
msgstr "Jaa kohde osiin"
#. Clear build platform action
#: ../resources/qml/Actions.qml:137
msgctxt "Actions|"
msgid "Clear Build Platform"
msgstr "Tyhjennä alusta"
#. Reload all objects action
#: ../resources/qml/Actions.qml:144
msgctxt "Actions|"
msgid "Reload All Objects"
msgstr "Lataa kaikki kohteet uudelleen"
#. Reset all positions action
#: ../resources/qml/Actions.qml:150
msgctxt "Actions|"
msgid "Reset All Object Positions"
msgstr "Nollaa kaikki kohteiden sijainnit"
#. Reset all positions action
#: ../resources/qml/Actions.qml:156
msgctxt "Actions|"
msgid "Reset All Object Transformations"
msgstr "Nollaa kaikkien kohteiden muunnokset"
#. Open file action
#: ../resources/qml/Actions.qml:162
msgctxt "Actions|"
msgid "&Open..."
msgstr "&Avaa"
#. Save file action
#: ../resources/qml/Actions.qml:170
msgctxt "Actions|"
msgid "&Save..."
msgstr "&Tallenna"
#. Show engine log action
#: ../resources/qml/Actions.qml:178
msgctxt "Actions|"
msgid "Show engine &log..."
msgstr "Näytä moottorin l&oki"
#. Add Printer dialog title
#. ----------
#. Add Printer wizard page title
#: ../resources/qml/AddMachineWizard.qml:12
#: ../resources/qml/AddMachineWizard.qml:19
msgctxt "AddMachineWizard|"
msgid "Add Printer"
msgstr "Lisää tulostin"
#. Add Printer wizard page description
#: ../resources/qml/AddMachineWizard.qml:25
msgctxt "AddMachineWizard|"
msgid "Please select the type of printer:"
msgstr "Valitse tulostimen tyyppi:"
#. Add Printer wizard field label
#: ../resources/qml/AddMachineWizard.qml:40
msgctxt "AddMachineWizard|"
msgid "Printer Name:"
msgstr "Tulostimen nimi:"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:53
msgctxt "AddMachineWizard|"
msgid "Next"
msgstr "Seuraava"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:63
msgctxt "AddMachineWizard|"
msgid "Cancel"
msgstr "Peruuta"
#. USB Printing dialog label, %1 is head temperature
#: ../plugins/USBPrinting/ControlWindow.qml:15
#, qt-format
msgctxt "ControlWindow|"
msgid "Extruder Temperature %1"
msgstr "Suulakkeen lämpötila %1"
#. USB Printing dialog label, %1 is bed temperature
#: ../plugins/USBPrinting/ControlWindow.qml:20
#, qt-format
msgctxt "ControlWindow|"
msgid "Bed Temperature %1"
msgstr "Pöydän lämpötila %1"
#. USB Printing dialog start print button
#: ../plugins/USBPrinting/ControlWindow.qml:33
msgctxt "ControlWindow|"
msgid "Print"
msgstr "Tulosta"
#. USB Printing dialog cancel print button
#: ../plugins/USBPrinting/ControlWindow.qml:40
msgctxt "ControlWindow|"
msgid "Cancel"
msgstr "Peruuta"
#. Cura application window title
#: ../resources/qml/Cura.qml:14
msgctxt "Cura|"
msgid "Cura"
msgstr "Cura"
#. File menu
#: ../resources/qml/Cura.qml:26
msgctxt "Cura|"
msgid "&File"
msgstr "&Tiedosto"
#. Edit menu
#: ../resources/qml/Cura.qml:38
msgctxt "Cura|"
msgid "&Edit"
msgstr "&Muokkaa"
#. Machine menu
#: ../resources/qml/Cura.qml:50
msgctxt "Cura|"
msgid "&Machine"
msgstr "&Laite"
#. Extensions menu
#: ../resources/qml/Cura.qml:76
msgctxt "Cura|"
msgid "E&xtensions"
msgstr "Laa&jennukset"
#. Settings menu
#: ../resources/qml/Cura.qml:107
msgctxt "Cura|"
msgid "&Settings"
msgstr "&Asetukset"
#. Help menu
#: ../resources/qml/Cura.qml:114
msgctxt "Cura|"
msgid "&Help"
msgstr "&Ohje"
#. View Mode toolbar button
#: ../resources/qml/Cura.qml:231
msgctxt "Cura|"
msgid "View Mode"
msgstr "Näyttötapa"
#. View preferences page title
#: ../resources/qml/Cura.qml:273
msgctxt "Cura|"
msgid "View"
msgstr "Näytä"
#. File open dialog title
#: ../resources/qml/Cura.qml:370
msgctxt "Cura|"
msgid "Open File"
msgstr "Avaa tiedosto"
#. File save dialog title
#: ../resources/qml/Cura.qml:386
msgctxt "Cura|"
msgid "Save File"
msgstr "Tallenna tiedosto"
#. Engine Log dialog title
#: ../resources/qml/EngineLog.qml:11
msgctxt "EngineLog|"
msgid "Engine Log"
msgstr "Moottorin loki"
#. Close engine log button
#: ../resources/qml/EngineLog.qml:30
msgctxt "EngineLog|"
msgid "Close"
msgstr "Sulje"
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:16
msgctxt "FirmwareUpdateWindow|"
msgid "Starting firmware update, this may take a while."
msgstr "Käynnistetään laiteohjelmiston päivitystä, mikä voi kestää hetken."
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:21
msgctxt "FirmwareUpdateWindow|"
msgid "Firmware update completed."
msgstr "Laiteohjelmiston päivitys suoritettu."
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:26
msgctxt "FirmwareUpdateWindow|"
msgid "Updating firmware."
msgstr "Päivitetään laiteohjelmistoa."
#. Print material amount save button label
#: ../resources/qml/SaveButton.qml:149
#, qt-format
msgctxt "SaveButton|"
msgid "%1m material"
msgstr "%1m materiaali"
#. Save button label
#: ../resources/qml/SaveButton.qml:191
msgctxt "SaveButton|"
msgid "Please load a 3D model"
msgstr "Lataa 3D-malli"
#. Save button label
#: ../resources/qml/SaveButton.qml:194
msgctxt "SaveButton|"
msgid "Calculating Print-time"
msgstr "Lasketaan tulostusaikaa"
#. Save button label
#: ../resources/qml/SaveButton.qml:197
msgctxt "SaveButton|"
msgid "Estimated Print-time"
msgstr "Arvioitu tulostusaika"
#. Simple configuration mode option
#: ../resources/qml/Sidebar.qml:105
msgctxt "Sidebar|"
msgid "Simple"
msgstr "Perusasetukset"
#. Advanced configuration mode option
#: ../resources/qml/Sidebar.qml:107
msgctxt "Sidebar|"
msgid "Advanced"
msgstr "Lisäasetukset"
#. Configuration mode label
#: ../resources/qml/SidebarHeader.qml:26
msgctxt "SidebarHeader|"
msgid "Mode:"
msgstr "Tila:"
#. Machine selection label
#: ../resources/qml/SidebarHeader.qml:70
msgctxt "SidebarHeader|"
msgid "Machine:"
msgstr "Laite:"
#. Sidebar header label
#: ../resources/qml/SidebarHeader.qml:117
msgctxt "SidebarHeader|"
msgid "Print Setup"
msgstr "Tulostimen asennus"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:40
msgctxt "SidebarSimple|"
msgid "No Model Loaded"
msgstr "Ei ladattua mallia"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:45
msgctxt "SidebarSimple|"
msgid "Calculating..."
msgstr "Lasketaan..."
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:50
msgctxt "SidebarSimple|"
msgid "Estimated Print Time"
msgstr "Arvioitu tulostusaika"
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:87
msgctxt "SidebarSimple|"
msgid ""
"Minimum\n"
"Draft"
msgstr "Minimivedos"
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:97
msgctxt "SidebarSimple|"
msgid ""
"Maximum\n"
"Quality"
msgstr "Maksimilaatu"
#. Setting checkbox
#: ../resources/qml/SidebarSimple.qml:109
msgctxt "SidebarSimple|"
msgid "Enable Support"
msgstr "Ota tuki käyttöön"
#. View configuration page title
#: ../resources/qml/ViewPage.qml:9
msgctxt "ViewPage|"
msgid "View"
msgstr "Näytä"
#. Display Overhang preference checkbox
#: ../resources/qml/ViewPage.qml:24
msgctxt "ViewPage|"
msgid "Display Overhang"
msgstr "Näytä uloke"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,498 +0,0 @@
# ahiemstra <a.hiemstra@ultimaker.com>, 2015.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: 2015-06-30 10:35+0100\n"
"Last-Translator: ahiemstra <a.hiemstra@ultimaker.com>\n"
"Language-Team: English <kde-i18n-doc@kde.org>\n"
"Language: en_GB\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"X-Generator: Lokalize 2.0\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. About dialog title
#: ../resources/qml/AboutDialog.qml:12
msgctxt "AboutDialog|"
msgid "About Cura"
msgstr ""
#. About dialog application description
#: ../resources/qml/AboutDialog.qml:42
msgctxt "AboutDialog|"
msgid "End-to-end solution for fused filament 3D printing."
msgstr ""
#. About dialog application author note
#: ../resources/qml/AboutDialog.qml:47
msgctxt "AboutDialog|"
msgid ""
"Cura has been developed by Ultimaker B.V. in cooperation with the community."
msgstr ""
#. Close about dialog button
#: ../resources/qml/AboutDialog.qml:58
msgctxt "AboutDialog|"
msgid "Close"
msgstr ""
#. Undo action
#: ../resources/qml/Actions.qml:37
#, fuzzy
msgctxt "Actions|"
msgid "&Undo"
msgstr "Annuler"
#. Redo action
#: ../resources/qml/Actions.qml:45
#, fuzzy
msgctxt "Actions|"
msgid "&Redo"
msgstr "Rétablir"
#. Quit action
#: ../resources/qml/Actions.qml:53
#, fuzzy
msgctxt "Actions|"
msgid "&Quit"
msgstr "Quitter"
#. Preferences action
#: ../resources/qml/Actions.qml:61
#, fuzzy
msgctxt "Actions|"
msgid "&Preferences..."
msgstr "Préférences"
#. Add Printer action
#: ../resources/qml/Actions.qml:68
#, fuzzy
msgctxt "Actions|"
msgid "&Add Printer..."
msgstr "Ajouter une imprimante..."
#. Configure Printers action
#: ../resources/qml/Actions.qml:74
#, fuzzy
msgctxt "Actions|"
msgid "&Configure Printers"
msgstr "Configurer les imprimantes"
#. Show Online Documentation action
#: ../resources/qml/Actions.qml:81
msgctxt "Actions|"
msgid "Show Online &Documentation"
msgstr ""
#. Report a Bug Action
#: ../resources/qml/Actions.qml:89
msgctxt "Actions|"
msgid "Report a &Bug"
msgstr ""
#. About action
#: ../resources/qml/Actions.qml:96
#, fuzzy
msgctxt "Actions|"
msgid "&About..."
msgstr "À propos de..."
#. Delete selection action
#: ../resources/qml/Actions.qml:103
#, fuzzy
msgctxt "Actions|"
msgid "Delete Selection"
msgstr "Supprimer la sélection"
#. Delete object action
#: ../resources/qml/Actions.qml:111
#, fuzzy
msgctxt "Actions|"
msgid "Delete Object"
msgstr "Supprimer lobjet"
#. Center object action
#: ../resources/qml/Actions.qml:118
#, fuzzy
msgctxt "Actions|"
msgid "Center Object on Platform"
msgstr "Centrer lobjet sur le plateau"
#. Duplicate object action
#: ../resources/qml/Actions.qml:124
#, fuzzy
msgctxt "Actions|"
msgid "Duplicate Object"
msgstr "Dupliquer lobjet"
#. Split object action
#: ../resources/qml/Actions.qml:130
#, fuzzy
msgctxt "Actions|"
msgid "Split Object into Parts"
msgstr "Diviser lobjet en plusieurs parties"
#. Clear build platform action
#: ../resources/qml/Actions.qml:137
#, fuzzy
msgctxt "Actions|"
msgid "Clear Build Platform"
msgstr "Effacer les éléments du plateau dimpression"
#. Reload all objects action
#: ../resources/qml/Actions.qml:144
#, fuzzy
msgctxt "Actions|"
msgid "Reload All Objects"
msgstr "Recharger tous les objets"
#. Reset all positions action
#: ../resources/qml/Actions.qml:150
#, fuzzy
msgctxt "Actions|"
msgid "Reset All Object Positions"
msgstr "Réinitialiser toutes les positions de lobjet"
#. Reset all positions action
#: ../resources/qml/Actions.qml:156
#, fuzzy
msgctxt "Actions|"
msgid "Reset All Object Transformations"
msgstr "Réinitialiser toutes les transformations de lobjet"
#. Open file action
#: ../resources/qml/Actions.qml:162
#, fuzzy
msgctxt "Actions|"
msgid "&Open..."
msgstr "Ouvrir..."
#. Save file action
#: ../resources/qml/Actions.qml:170
#, fuzzy
msgctxt "Actions|"
msgid "&Save..."
msgstr "Enregistrer..."
#. Show engine log action
#: ../resources/qml/Actions.qml:178
msgctxt "Actions|"
msgid "Show engine &log..."
msgstr ""
#. Add Printer dialog title
#. ----------
#. Add Printer wizard page title
#: ../resources/qml/AddMachineWizard.qml:12
#: ../resources/qml/AddMachineWizard.qml:19
msgctxt "AddMachineWizard|"
msgid "Add Printer"
msgstr "Ajouter une imprimante"
#. Add Printer wizard page description
#: ../resources/qml/AddMachineWizard.qml:25
msgctxt "AddMachineWizard|"
msgid "Please select the type of printer:"
msgstr "Veuillez sélectionner le type dimprimante :"
#. Add Printer wizard field label
#: ../resources/qml/AddMachineWizard.qml:40
msgctxt "AddMachineWizard|"
msgid "Printer Name:"
msgstr "Nom de limprimante :"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:53
msgctxt "AddMachineWizard|"
msgid "Next"
msgstr "Suivant"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:63
msgctxt "AddMachineWizard|"
msgid "Cancel"
msgstr "Annuler"
#. USB Printing dialog label, %1 is head temperature
#: ../plugins/USBPrinting/ControlWindow.qml:15
#, qt-format
msgctxt "ControlWindow|"
msgid "Extruder Temperature %1"
msgstr ""
#. USB Printing dialog label, %1 is bed temperature
#: ../plugins/USBPrinting/ControlWindow.qml:20
#, qt-format
msgctxt "ControlWindow|"
msgid "Bed Temperature %1"
msgstr ""
#. USB Printing dialog start print button
#: ../plugins/USBPrinting/ControlWindow.qml:33
#, fuzzy
msgctxt "ControlWindow|"
msgid "Print"
msgstr "Ajouter une imprimante"
#. USB Printing dialog cancel print button
#: ../plugins/USBPrinting/ControlWindow.qml:40
#, fuzzy
msgctxt "ControlWindow|"
msgid "Cancel"
msgstr "Annuler"
#. Cura application window title
#: ../resources/qml/Cura.qml:14
#, fuzzy
msgctxt "Cura|"
msgid "Cura"
msgstr "Cura"
#. File menu
#: ../resources/qml/Cura.qml:26
#, fuzzy
msgctxt "Cura|"
msgid "&File"
msgstr "&Fichier"
#. Edit menu
#: ../resources/qml/Cura.qml:38
#, fuzzy
msgctxt "Cura|"
msgid "&Edit"
msgstr "M&odifier"
#. Machine menu
#: ../resources/qml/Cura.qml:50
#, fuzzy
msgctxt "Cura|"
msgid "&Machine"
msgstr "&Machine"
#. Extensions menu
#: ../resources/qml/Cura.qml:76
#, fuzzy
msgctxt "Cura|"
msgid "E&xtensions"
msgstr "&Extensions"
#. Settings menu
#: ../resources/qml/Cura.qml:107
#, fuzzy
msgctxt "Cura|"
msgid "&Settings"
msgstr "&Paramètres"
#. Help menu
#: ../resources/qml/Cura.qml:114
#, fuzzy
msgctxt "Cura|"
msgid "&Help"
msgstr "&Aide"
#. View Mode toolbar button
#: ../resources/qml/Cura.qml:231
#, fuzzy
msgctxt "Cura|"
msgid "View Mode"
msgstr "Mode daffichage"
#. View preferences page title
#: ../resources/qml/Cura.qml:273
#, fuzzy
msgctxt "Cura|"
msgid "View"
msgstr "Afficher"
#. File open dialog title
#: ../resources/qml/Cura.qml:370
#, fuzzy
msgctxt "Cura|"
msgid "Open File"
msgstr "Ouvrir un fichier"
#. File save dialog title
#: ../resources/qml/Cura.qml:386
#, fuzzy
msgctxt "Cura|"
msgid "Save File"
msgstr "Enregistrer un fichier"
#. Engine Log dialog title
#: ../resources/qml/EngineLog.qml:11
msgctxt "EngineLog|"
msgid "Engine Log"
msgstr ""
#. Close engine log button
#: ../resources/qml/EngineLog.qml:30
msgctxt "EngineLog|"
msgid "Close"
msgstr ""
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:16
msgctxt "FirmwareUpdateWindow|"
msgid "Starting firmware update, this may take a while."
msgstr ""
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:21
msgctxt "FirmwareUpdateWindow|"
msgid "Firmware update completed."
msgstr ""
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:26
msgctxt "FirmwareUpdateWindow|"
msgid "Updating firmware."
msgstr ""
#. Print material amount save button label
#: ../resources/qml/SaveButton.qml:149
#, qt-format
msgctxt "SaveButton|"
msgid "%1m material"
msgstr "%1m de matériel"
#. Save button label
#: ../resources/qml/SaveButton.qml:191
msgctxt "SaveButton|"
msgid "Please load a 3D model"
msgstr ""
#. Save button label
#: ../resources/qml/SaveButton.qml:194
msgctxt "SaveButton|"
msgid "Calculating Print-time"
msgstr ""
#. Save button label
#: ../resources/qml/SaveButton.qml:197
msgctxt "SaveButton|"
msgid "Estimated Print-time"
msgstr ""
#. Simple configuration mode option
#: ../resources/qml/Sidebar.qml:105
msgctxt "Sidebar|"
msgid "Simple"
msgstr ""
#. Advanced configuration mode option
#: ../resources/qml/Sidebar.qml:107
msgctxt "Sidebar|"
msgid "Advanced"
msgstr ""
#. Configuration mode label
#: ../resources/qml/SidebarHeader.qml:26
msgctxt "SidebarHeader|"
msgid "Mode:"
msgstr ""
#. Machine selection label
#: ../resources/qml/SidebarHeader.qml:70
#, fuzzy
msgctxt "SidebarHeader|"
msgid "Machine:"
msgstr "Machine"
#. Sidebar header label
#: ../resources/qml/SidebarHeader.qml:117
#, fuzzy
msgctxt "SidebarHeader|"
msgid "Print Setup"
msgstr "Paramètres dimpression"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:40
msgctxt "SidebarSimple|"
msgid "No Model Loaded"
msgstr ""
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:45
msgctxt "SidebarSimple|"
msgid "Calculating..."
msgstr ""
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:50
msgctxt "SidebarSimple|"
msgid "Estimated Print Time"
msgstr ""
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:87
msgctxt "SidebarSimple|"
msgid ""
"Minimum\n"
"Draft"
msgstr ""
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:97
msgctxt "SidebarSimple|"
msgid ""
"Maximum\n"
"Quality"
msgstr ""
#. Setting checkbox
#: ../resources/qml/SidebarSimple.qml:109
msgctxt "SidebarSimple|"
msgid "Enable Support"
msgstr ""
#. View configuration page title
#: ../resources/qml/ViewPage.qml:9
msgctxt "ViewPage|"
msgid "View"
msgstr "Afficher"
#. Display Overhang preference checkbox
#: ../resources/qml/ViewPage.qml:24
#, fuzzy
msgctxt "ViewPage|"
msgid "Display Overhang"
msgstr "Dépassement de laffichage"
#~ msgctxt "OutputGCodeButton|"
#~ msgid "Save"
#~ msgstr "Enregistrer"
#~ msgctxt "OutputGCodeButton|"
#~ msgid "Write to SD"
#~ msgstr "Enregistrer sur la carte SD"
#~ msgctxt "OutputGCodeButton|"
#~ msgid "Send over USB"
#~ msgstr "Transférer vers le périphérique USB"
#~ msgctxt "Printer|"
#~ msgid "No extensions loaded"
#~ msgstr "Aucune extension téléchargée"
#~ msgctxt "Printer|"
#~ msgid "Open File"
#~ msgstr "Ouvrir un fichier"
#~ msgctxt "PrinterActions|"
#~ msgid "Show Manual"
#~ msgstr "Afficher les instructions"
#~ msgctxt "SettingsPane|"
#~ msgid "Time"
#~ msgstr "Heure"
#~ msgctxt "SettingsPane|"
#~ msgid "Low Quality"
#~ msgstr "Basse qualité"
#~ msgctxt "SettingsPane|"
#~ msgid "High Quality"
#~ msgstr "Haute qualité"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,430 +0,0 @@
msgid ""
msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Qt-Contexts: true\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"Project-Id-Version: Cura\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: ru\n"
"X-Generator: Poedit 1.8.1\n"
#. About dialog title
#: ../resources/qml/AboutDialog.qml:12
msgctxt "AboutDialog|"
msgid "About Cura"
msgstr "О Кура"
#. About dialog application description
#: ../resources/qml/AboutDialog.qml:42
msgctxt "AboutDialog|"
msgid "End-to-end solution for fused filament 3D printing."
msgstr "Комплексное решение для 3D печати по технологии послойного накладывание пластика."
#. About dialog application author note
#: ../resources/qml/AboutDialog.qml:47
msgctxt "AboutDialog|"
msgid "Cura has been developed by Ultimaker B.V. in cooperation with the community."
msgstr "Кура была разработана компании Ultimaker BV в сотрудничестве с сообществом."
#. Close about dialog button
#: ../resources/qml/AboutDialog.qml:58
msgctxt "AboutDialog|"
msgid "Close"
msgstr "Закрыть окно"
#. Undo action
#: ../resources/qml/Actions.qml:37
msgctxt "Actions|"
msgid "&Undo"
msgstr "&Отмена"
#. Redo action
#: ../resources/qml/Actions.qml:45
msgctxt "Actions|"
msgid "&Redo"
msgstr "&Повтор"
#. Quit action
#: ../resources/qml/Actions.qml:53
msgctxt "Actions|"
msgid "&Quit"
msgstr "&Выход"
#. Preferences action
#: ../resources/qml/Actions.qml:61
msgctxt "Actions|"
msgid "&Preferences..."
msgstr "&Настройки программы..."
#. Add Printer action
#: ../resources/qml/Actions.qml:68
msgctxt "Actions|"
msgid "&Add Printer..."
msgstr "&Добавит новый принтер"
#. Configure Printers action
#: ../resources/qml/Actions.qml:74
msgctxt "Actions|"
msgid "&Configure Printers"
msgstr "&Настройки принтера"
#. Show Online Documentation action
#: ../resources/qml/Actions.qml:81
msgctxt "Actions|"
msgid "Show Online &Documentation"
msgstr "Показать онлайн &справку"
#. Report a Bug Action
#: ../resources/qml/Actions.qml:89
msgctxt "Actions|"
msgid "Report a &Bug"
msgstr "Сообщить о &проблеме"
#. About action
#: ../resources/qml/Actions.qml:96
msgctxt "Actions|"
msgid "&About..."
msgstr "&О Кура"
#. Delete selection action
#: ../resources/qml/Actions.qml:103
msgctxt "Actions|"
msgid "Delete Selection"
msgstr "Удалить выбранное"
#. Delete object action
#: ../resources/qml/Actions.qml:111
msgctxt "Actions|"
msgid "Delete Object"
msgstr "Удалить объект"
#. Center object action
#: ../resources/qml/Actions.qml:118
msgctxt "Actions|"
msgid "Center Object on Platform"
msgstr "Расположить объект по центру"
#. Duplicate object action
#: ../resources/qml/Actions.qml:124
msgctxt "Actions|"
msgid "Duplicate Object"
msgstr "Умножить объект"
#. Split object action
#: ../resources/qml/Actions.qml:130
msgctxt "Actions|"
msgid "Split Object into Parts"
msgstr "Разбить объект на частей"
#. Clear build platform action
#: ../resources/qml/Actions.qml:137
msgctxt "Actions|"
msgid "Clear Build Platform"
msgstr "Очистить печатающую платформу"
#. Reload all objects action
#: ../resources/qml/Actions.qml:144
msgctxt "Actions|"
msgid "Reload All Objects"
msgstr "Перезагрузить все объекты"
#. Reset all positions action
#: ../resources/qml/Actions.qml:150
msgctxt "Actions|"
msgid "Reset All Object Positions"
msgstr "Сбросить все позиции объектов"
#. Reset all positions action
#: ../resources/qml/Actions.qml:156
msgctxt "Actions|"
msgid "Reset All Object Transformations"
msgstr "Сбросить все преобразования объектов"
#. Open file action
#: ../resources/qml/Actions.qml:162
msgctxt "Actions|"
msgid "&Open..."
msgstr "&Открыть..."
#. Save file action
#: ../resources/qml/Actions.qml:170
msgctxt "Actions|"
msgid "&Save..."
msgstr "&Сохранить..."
#. Show engine log action
#: ../resources/qml/Actions.qml:178
msgctxt "Actions|"
msgid "Show engine &log..."
msgstr "Показать журнал &слайсера"
#. Add Printer dialog title
#. ----------
#. Add Printer wizard page title
#: ../resources/qml/AddMachineWizard.qml:12
#: ../resources/qml/AddMachineWizard.qml:19
msgctxt "AddMachineWizard|"
msgid "Add Printer"
msgstr "Добавить новый принтер"
#. Add Printer wizard page description
#: ../resources/qml/AddMachineWizard.qml:25
msgctxt "AddMachineWizard|"
msgid "Please select the type of printer:"
msgstr "Выберите тип принтера:"
#. Add Printer wizard field label
#: ../resources/qml/AddMachineWizard.qml:40
msgctxt "AddMachineWizard|"
msgid "Printer Name:"
msgstr "Название принтера:"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:53
msgctxt "AddMachineWizard|"
msgid "Next"
msgstr "Дальше"
#. Add Printer wizarad button
#: ../resources/qml/AddMachineWizard.qml:63
msgctxt "AddMachineWizard|"
msgid "Cancel"
msgstr "Отменить"
#. USB Printing dialog label, %1 is head temperature
#: ../plugins/USBPrinting/ControlWindow.qml:15
#, qt-format
msgctxt "ControlWindow|"
msgid "Extruder Temperature %1"
msgstr "Температура экструдера %1"
#. USB Printing dialog label, %1 is bed temperature
#: ../plugins/USBPrinting/ControlWindow.qml:20
#, qt-format
msgctxt "ControlWindow|"
msgid "Bed Temperature %1"
msgstr "Температура платформы %1"
#. USB Printing dialog start print button
#: ../plugins/USBPrinting/ControlWindow.qml:33
msgctxt "ControlWindow|"
msgid "Print"
msgstr "Печать"
#. USB Printing dialog cancel print button
#: ../plugins/USBPrinting/ControlWindow.qml:40
msgctxt "ControlWindow|"
msgid "Cancel"
msgstr "Отменить"
#. Cura application window title
#: ../resources/qml/Cura.qml:14
msgctxt "Cura|"
msgid "Cura"
msgstr "Кура"
#. File menu
#: ../resources/qml/Cura.qml:26
msgctxt "Cura|"
msgid "&File"
msgstr "&Файл"
#. Edit menu
#: ../resources/qml/Cura.qml:38
msgctxt "Cura|"
msgid "&Edit"
msgstr "&Изменить"
#. Machine menu
#: ../resources/qml/Cura.qml:50
msgctxt "Cura|"
msgid "&Machine"
msgstr "&Принтер"
#. Extensions menu
#: ../resources/qml/Cura.qml:76
msgctxt "Cura|"
msgid "E&xtensions"
msgstr "&Расширения"
#. Settings menu
#: ../resources/qml/Cura.qml:107
msgctxt "Cura|"
msgid "&Settings"
msgstr "&Настройки"
#. Help menu
#: ../resources/qml/Cura.qml:114
msgctxt "Cura|"
msgid "&Help"
msgstr "&Помощь"
#. View Mode toolbar button
#: ../resources/qml/Cura.qml:231
msgctxt "Cura|"
msgid "View Mode"
msgstr "Режим просмотра"
#. View preferences page title
#: ../resources/qml/Cura.qml:273
msgctxt "Cura|"
msgid "View"
msgstr "Просмотр"
#. File open dialog title
#: ../resources/qml/Cura.qml:370
msgctxt "Cura|"
msgid "Open File"
msgstr "Открыть файл"
#. File save dialog title
#: ../resources/qml/Cura.qml:386
msgctxt "Cura|"
msgid "Save File"
msgstr "Сохранить файл"
#. Engine Log dialog title
#: ../resources/qml/EngineLog.qml:11
msgctxt "EngineLog|"
msgid "Engine Log"
msgstr "Журнал слайсера"
#. Close engine log button
#: ../resources/qml/EngineLog.qml:30
msgctxt "EngineLog|"
msgid "Close"
msgstr "Закрыть"
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:16
msgctxt "FirmwareUpdateWindow|"
msgid "Starting firmware update, this may take a while."
msgstr "Начинается обновление прошивки, это может занять некоторое время."
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:21
msgctxt "FirmwareUpdateWindow|"
msgid "Firmware update completed."
msgstr "Обновление прошивки завершено."
#. Firmware update status label
#: ../plugins/USBPrinting/FirmwareUpdateWindow.qml:26
msgctxt "FirmwareUpdateWindow|"
msgid "Updating firmware."
msgstr "Обновление прошивки."
#. Print material amount save button label
#: ../resources/qml/SaveButton.qml:149
#, qt-format
msgctxt "SaveButton|"
msgid "%1m material"
msgstr "%1m материал"
#. Save button label
#: ../resources/qml/SaveButton.qml:191
msgctxt "SaveButton|"
msgid "Please load a 3D model"
msgstr "Пожалуйста, загрузите 3D модель"
#. Save button label
#: ../resources/qml/SaveButton.qml:194
msgctxt "SaveButton|"
msgid "Calculating Print-time"
msgstr "Вычисляется время печати"
#. Save button label
#: ../resources/qml/SaveButton.qml:197
msgctxt "SaveButton|"
msgid "Estimated Print-time"
msgstr "Расчетное время печати"
#. Simple configuration mode option
#: ../resources/qml/Sidebar.qml:105
msgctxt "Sidebar|"
msgid "Simple"
msgstr "Простой"
#. Advanced configuration mode option
#: ../resources/qml/Sidebar.qml:107
msgctxt "Sidebar|"
msgid "Advanced"
msgstr "Продвинутый"
#. Configuration mode label
#: ../resources/qml/SidebarHeader.qml:26
msgctxt "SidebarHeader|"
msgid "Mode:"
msgstr "Режим:"
#. Machine selection label
#: ../resources/qml/SidebarHeader.qml:70
msgctxt "SidebarHeader|"
msgid "Machine:"
msgstr "Принтер:"
#. Sidebar header label
#: ../resources/qml/SidebarHeader.qml:117
msgctxt "SidebarHeader|"
msgid "Print Setup"
msgstr "Настройка Печати"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:40
msgctxt "SidebarSimple|"
msgid "No Model Loaded"
msgstr "Модель не загружена"
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:45
msgctxt "SidebarSimple|"
msgid "Calculating..."
msgstr "Высчитывается..."
#. Sidebar configuration label
#: ../resources/qml/SidebarSimple.qml:50
msgctxt "SidebarSimple|"
msgid "Estimated Print Time"
msgstr "Расчетное время печати"
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:87
msgctxt "SidebarSimple|"
msgid ""
"Minimum\n"
"Draft"
msgstr ""
"Минимальная \n"
"тяга"
#. Quality slider label
#: ../resources/qml/SidebarSimple.qml:97
msgctxt "SidebarSimple|"
msgid ""
"Maximum\n"
"Quality"
msgstr ""
"Максимальное\n"
"Качество"
#. Setting checkbox
#: ../resources/qml/SidebarSimple.qml:109
msgctxt "SidebarSimple|"
msgid "Enable Support"
msgstr "Включить Поддержку"
#. View configuration page title
#: ../resources/qml/ViewPage.qml:9
msgctxt "ViewPage|"
msgid "View"
msgstr "Просмотр"
#. Display Overhang preference checkbox
#: ../resources/qml/ViewPage.qml:24
msgctxt "ViewPage|"
msgid "Display Overhang"
msgstr "Показать где есть нависающие части"

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -0,0 +1,60 @@
{
"id": "rigidbotbig",
"version": 1,
"name": "RigidBot",
"manufacturer": "Invent-A-Part",
"author": "RBC",
"platform": "rigidbot_platform.stl",
"inherits": "fdmprinter.json",
"machine_settings": {
"machine_width": { "default": 254 },
"machine_depth": { "default": 254 },
"machine_height": { "default": 254 },
"machine_heated_bed": { "default": true },
"machine_nozzle_size": { "default": 0.4,
"visible": true
},
"machine_head_shape_min_x": { "default": 0 },
"machine_head_shape_min_y": { "default": 0 },
"machine_head_shape_max_x": { "default": 0 },
"machine_head_shape_max_y": { "default": 0 },
"machine_nozzle_gantry_distance": { "default": 0 },
"machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": {
"default": ";Sliced at: {day} {date} {time}\n;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {infill_density}\n;Print time: {print_time}\n;Filament used: {filament_amount}m {filament_weight}g\n;Filament cost: {filament_cost}\n;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line\n;M109 S{print_temperature} ;Uncomment to add your own temperature line\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nM205 X8 ;X/Y Jerk settings\nG1 Z15.0 F{travel_speed} ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E7 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F{travel_speed}\n;Put printing message on LCD screen\nM117 Rigibot Printing..."
},
"machine_end_gcode": {
"default": ";End GCode\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+10 E-1 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nG1 Y230 F3000 ;move Y so the head is out of the way and Plate is moved forward\nM84 ;steppers off\nG90 ;absolute positioning\n;{profile_string}"
}
},
"overrides": {
"layer_height": { "default": 0.2 },
"shell_thickness": { "default": 0.8 },
"wall_thickness": { "default": 0.8 },
"top_bottom_thickness": { "default": 0.3, "visible": true },
"material_print_temperature": { "default": 195, "visible": true },
"material_bed_temperature": { "default": 60, "visible": true },
"material_diameter": { "default": 1.75, "visible": true },
"retraction_enable": { "default": true, "always_visible": true },
"retraction_speed": { "default": 50.0, "visible": false },
"retraction_amount": { "default": 0.8, "visible": false },
"retraction_hop": { "default": 0.075, "visible": false },
"speed_print": { "default": 60.0, "visible": true },
"speed_infill": { "default": 100.0, "visible": true },
"speed_topbottom": { "default": 15.0, "visible": true },
"speed_travel": { "default": 150.0, "visible": true },
"speed_layer_0": { "min_value": 0.1, "default": 15.0, "visible": true },
"infill_overlap": { "default": 10.0 },
"cool_fan_enabled": { "default": false, "visible": true },
"cool_fan_speed": { "default": 0.0, "visible": true },
"skirt_line_count": { "default": 3, "active_if": { "setting": "adhesion_type", "value": "None" } },
"skirt_gap": { "default": 4.0, "active_if": { "setting": "adhesion_type", "value": "None" } },
"skirt_minimal_length": { "default": 200.0, "active_if": { "setting": "adhesion_type", "value": "None" } }
}
}

View File

@ -0,0 +1,58 @@
{
"id": "rigidbotbig",
"version": 1,
"name": "RigidBotBig",
"manufacturer": "Invent-A-Part",
"author": "RBC",
"platform": "rigidbotbig_platform.stl",
"inherits": "fdmprinter.json",
"machine_settings": {
"machine_width": { "default": 400 },
"machine_depth": { "default": 300 },
"machine_height": { "default": 254 },
"machine_heated_bed": { "default": true },
"machine_nozzle_size": { "default": 0.4},
"machine_head_shape_min_x": { "default": 0 },
"machine_head_shape_min_y": { "default": 0 },
"machine_head_shape_max_x": { "default": 0 },
"machine_head_shape_max_y": { "default": 0 },
"machine_nozzle_gantry_distance": { "default": 0 },
"machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": {
"default": ";Sliced at: {day} {date} {time}\n;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {infill_density}\n;Print time: {print_time}\n;Filament used: {filament_amount}m {filament_weight}g\n;Filament cost: {filament_cost}\n;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line\n;M109 S{print_temperature} ;Uncomment to add your own temperature line\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nM205 X8 ;X/Y Jerk settings\nG1 Z15.0 F{travel_speed} ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E7 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F{travel_speed}\n;Put printing message on LCD screen\nM117 Rigibot Printing..."
},
"machine_end_gcode": {
"default": ";End GCode\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+10 E-1 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nG1 Y230 F3000 ;move Y so the head is out of the way and Plate is moved forward\nM84 ;steppers off\nG90 ;absolute positioning\n;{profile_string}"
}
},
"overrides": {
"layer_height": { "default": 0.2 },
"shell_thickness": { "default": 0.8},
"wall_thickness": { "default": 0.8 },
"top_bottom_thickness": { "default": 0.3, "visible": true },
"material_print_temperature": { "default": 195, "visible": true },
"material_bed_temperature": { "default": 60, "visible": true },
"material_diameter": { "default": 1.75, "visible": true },
"retraction_enable": { "default": true, "always_visible": true},
"retraction_speed": { "default": 50.0, "visible": false },
"retraction_amount": { "default": 0.8, "visible": false },
"retraction_hop": { "default": 0.075, "visible": false },
"speed_print": { "default": 60.0, "visible": true},
"speed_infill": { "default": 100.0, "visible": true },
"speed_topbottom": { "default": 15.0, "visible": true },
"speed_travel": { "default": 150.0, "visible": true },
"speed_layer_0": { "min_value": 0.1, "default": 15.0, "visible": true },
"infill_overlap": { "default": 10.0 },
"cool_fan_enabled": { "default": false, "visible": true},
"cool_fan_speed": { "default": 0.0, "visible": true },
"skirt_line_count": { "default": 3, "active_if": { "setting": "adhesion_type", "value": "None" } },
"skirt_gap": { "default": 4.0, "active_if": { "setting": "adhesion_type", "value": "None" } },
"skirt_minimal_length": { "default": 200.0, "active_if": { "setting": "adhesion_type", "value": "None" } }
}
}

View File

@ -0,0 +1,60 @@
{
"id": "bq_hephestos",
"version": 1,
"name": "BQ Prusa i3 Hephestos",
"manufacturer": "BQ",
"author": "BQ",
"platform": "hephestos_platform.stl",
"inherits": "fdmprinter.json",
"machine_settings": {
"machine_start_gcode": {
"default": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 X0 Y0 ;move to the X/Y origin (Home)\nG28 Z0 ;move to the Z origin (Home)\nG1 Z15.0 F1200 ;move Z to position 15.0 mm\nG92 E0 ;zero the extruded length\nG1 E20 F200 ;extrude 20mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F7200 ;set feedrate to 120 mm/sec\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default": "; -- END GCODE --\nM104 S0 ;set extruder temperature to zero (turned off)\nG91 ;set to relative positioning\nG1 E-20 F300 ;retract the filament a bit to release some of the pressure\nG1 Z10 ;move extruder up 10 mm\nG90 ;set to absolute positioning\nG1 X0 Y180 F1200 ;expose the platform\nM84 ;turn off steppers\n; -- end of END GCODE --"
},
"machine_width": {
"default": 215
},
"machine_depth": {
"default": 210
},
"machine_height": {
"default": 180
},
"machine_heated_bed": {
"default": false
},
"machine_center_is_zero": {
"default": false
},
"machine_gcode_flavor": {
"default": "RepRap"
},
"machine_platform_offset": {
"default": [0, 100, 0]
}
},
"overrides": {
"layer_height": { "default": 0.2 },
"layer_height_0": { "default": 0.2, "visible": false },
"shell_thickness": { "default": 1.0 },
"wall_thickness": { "default": 1.0, "visible": false },
"top_bottom_thickness": { "default": 1.0, "visible": false},
"bottom_thickness": { "default": 1.0, "visible": false },
"material_print_temperature": { "default": 220, "visible": true },
"material_bed_temperature": { "default": 0, "visible": false },
"material_diameter": { "default": 1.75, "visible": true },
"speed_print": { "default": 40.0},
"speed_infill": { "default": 40.0, "visible": true },
"speed_wall": { "default": 35.0, "visible": true},
"speed_topbottom": { "default": 35.0, "visible": true },
"speed_travel": { "default": 120.0 },
"speed_layer_0": { "default": 20.0, "visible": false },
"retraction_speed": { "default": 30.0, "visible": false},
"retraction_amount": { "default": 2.0, "visible": false },
"retraction_hop": { "default": 0.075, "visible": false },
"support_enable": { "default": true }
}
}

View File

@ -0,0 +1,60 @@
{
"id": "bq_hephestos_xl",
"version": 1,
"name": "BQ Prusa i3 Hephestos XL",
"manufacturer": "BQ",
"author": "BQ",
"platform": "hephestos_platform.stl",
"inherits": "fdmprinter.json",
"machine_settings": {
"machine_start_gcode": {
"default": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 X0 Y0 ;move to the X/Y origin (Home)\nG28 Z0 ;move to the Z origin (Home)\nG1 Z15.0 F1200 ;move Z to position 15.0 mm\nG92 E0 ;zero the extruded length\nG1 E20 F200 ;extrude 20mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F7200 ;set feedrate to 120 mm/sec\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default": "; -- END GCODE --\nM104 S0 ;set extruder temperature to zero (turned off)\nG91 ;set to relative positioning\nG1 E-20 F300 ;retract the filament a bit to release some of the pressure\nG1 Z10 ;move extruder up 10 mm\nG90 ;set to absolute positioning\nG1 X0 Y180 F1200 ;expose the platform\nM84 ;turn off steppers\n; -- end of END GCODE --"
},
"machine_width": {
"default": 200
},
"machine_depth": {
"default": 300
},
"machine_height": {
"default": 180
},
"machine_heated_bed": {
"default": false
},
"machine_center_is_zero": {
"default": false
},
"machine_gcode_flavor": {
"default": "RepRap"
},
"machine_platform_offset": {
"default": [0, 100, 0]
}
},
"overrides": {
"layer_height": { "default": 0.2 },
"layer_height_0": { "default": 0.2, "visible": false },
"shell_thickness": { "default": 1.0 },
"wall_thickness": { "default": 1.0, "visible": false },
"top_bottom_thickness": { "default": 1.0, "visible": false},
"bottom_thickness": { "default": 1.0, "visible": false },
"material_print_temperature": { "default": 220, "visible": true },
"material_bed_temperature": { "default": 0, "visible": false },
"material_diameter": { "default": 1.75, "visible": true },
"speed_print": { "default": 40.0},
"speed_infill": { "default": 40.0, "visible": true },
"speed_wall": { "default": 35.0, "visible": true},
"speed_topbottom": { "default": 35.0, "visible": true },
"speed_travel": { "default": 120.0 },
"speed_layer_0": { "default": 20.0, "visible": false },
"retraction_speed": { "default": 30.0, "visible": false},
"retraction_amount": { "default": 2.0, "visible": false },
"retraction_hop": { "default": 0.075, "visible": false },
"support_enable": { "default": true }
}
}

View File

@ -0,0 +1,60 @@
{
"id": "bq_witbox",
"version": 1,
"name": "BQ Witbox",
"manufacturer": "BQ",
"author": "BQ",
"platform": "witbox_platform.stl",
"inherits": "fdmprinter.json",
"machine_settings": {
"machine_start_gcode": {
"default": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 X0 Y0 ;move to the X/Y origin (Home)\nG28 Z0 ;move to the Z origin (Home)\nG1 Z15.0 F1200 ;move Z to position 15.0 mm\nG92 E0 ;zero the extruded length\nG1 E20 F200 ;extrude 20mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F7200 ;set feedrate to 120 mm/sec\n; -- end of START GCODE --"
},
"machine_end_gcode": {
"default": "; -- END GCODE --\nM104 S0 ;set extruder temperature to zero (turned off)\nG91 ;set to relative positioning\nG1 E-20 F300 ;retract the filament a bit to release some of the pressure\nG90 ;set to absolute positioning\nG1 Z200 ;move the platform to the bottom\nG28 X0 Y0 ;move to the X/Y origin (Home)\nM84 ;turn off steppers\n; -- end of END GCODE --"
},
"machine_width": {
"default": 297
},
"machine_depth": {
"default": 210
},
"machine_height": {
"default": 200
},
"machine_heated_bed": {
"default": false
},
"machine_center_is_zero": {
"default": false
},
"machine_gcode_flavor": {
"default": "RepRap"
},
"machine_platform_offset": {
"default": [0, -145, -38]
}
},
"overrides": {
"layer_height": { "default": 0.2 },
"layer_height_0": { "default": 0.2, "visible": false },
"shell_thickness": { "default": 1.0 },
"wall_thickness": { "default": 1.0, "visible": false },
"top_bottom_thickness": { "default": 1.0, "visible": false},
"bottom_thickness": { "default": 1.0, "visible": false },
"material_print_temperature": { "default": 220, "visible": true },
"material_bed_temperature": { "default": 0, "visible": false },
"material_diameter": { "default": 1.75, "visible": true },
"speed_print": { "default": 40.0},
"speed_infill": { "default": 40.0, "visible": true },
"speed_wall": { "default": 35.0, "visible": true},
"speed_topbottom": { "default": 35.0, "visible": true },
"speed_travel": { "default": 120.0 },
"speed_layer_0": { "default": 20.0, "visible": false },
"retraction_speed": { "default": 30.0, "visible": false},
"retraction_amount": { "default": 2.0, "visible": false },
"retraction_hop": { "default": 0.075, "visible": false },
"support_enable": { "default": true }
}
}

View File

@ -2,7 +2,7 @@
"id": "grr_neo", "id": "grr_neo",
"version": 1, "version": 1,
"name": "German RepRap Neo", "name": "German RepRap Neo",
"manufacturer": "German RepRap", "manufacturer": "Other",
"author": "other", "author": "other",
"icon": "icon_ultimaker.png", "icon": "icon_ultimaker.png",
"platform": "grr_neo_platform.stl", "platform": "grr_neo_platform.stl",
@ -21,8 +21,6 @@
"machine_head_shape_max_x": { "default": 18 }, "machine_head_shape_max_x": { "default": 18 },
"machine_head_shape_max_y": { "default": 35 }, "machine_head_shape_max_y": { "default": 35 },
"machine_nozzle_gantry_distance": { "default": 55 }, "machine_nozzle_gantry_distance": { "default": 55 },
"machine_nozzle_offset_x_1": { "default": 18.0 },
"machine_nozzle_offset_y_1": { "default": 0.0 },
"machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" }, "machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": { "machine_start_gcode": {
@ -33,13 +31,7 @@
} }
}, },
"categories": { "overrides": {
"material": { "material_bed_temperature": { "visible": false }
"settings": {
"material_bed_temperature": {
"visible": false
}
}
}
} }
} }

View File

@ -0,0 +1,82 @@
{
"id": "maker_starter",
"version": 1,
"name": "3DMaker Starter",
"manufacturer": "Other",
"author": "Other",
"icon": "icon_ultimaker2.png",
"platform": "makerstarter_platform.stl",
"inherits": "fdmprinter.json",
"machine_settings": {
"machine_width": { "default": 210 },
"machine_depth": { "default": 185 },
"machine_height": { "default": 200 },
"machine_heated_bed": { "default": false },
"machine_center_is_zero": { "default": false },
"machine_nozzle_size": { "default": 0.4 },
"machine_head_shape_min_x": { "default": 0 },
"machine_head_shape_min_y": { "default": 0 },
"machine_head_shape_max_x": { "default": 0 },
"machine_head_shape_max_y": { "default": 0 },
"machine_nozzle_gantry_distance": { "default": 55 },
"machine_gcode_flavor": { "default": "RepRap" },
"machine_disallowed_areas": { "default": []},
"machine_platform_offset": { "default": [0.0, 0.0, 0.0] },
"machine_nozzle_tip_outer_diameter": { "default": 1.0 },
"machine_nozzle_head_distance": { "default": 3.0 },
"machine_nozzle_expansion_angle": { "default": 45 }
},
"overrides": {
"layer_height": { "default": 0.2 },
"layer_height_0": { "default": 0.2, "visible": false },
"wall_line_count": { "default": 2, "visible": true },
"top_layers": { "default": 4, "visible": true },
"bottom_layers": { "default": 4, "visible": true },
"material_print_temperature": { "visible": false },
"material_bed_temperature": { "visible": false },
"material_diameter": { "default": 1.75, "visible": false },
"material_flow": { "visible": false },
"retraction_hop": { "default": 0.2 },
"speed_print": { "default": 50.0 },
"speed_wall": { "default": 30.0 },
"speed_wall_0": { "default": 30.0 },
"speed_wall_x": { "default": 30.0 },
"speed_topbottom": { "default": 50.0 },
"speed_support": { "default": 50.0 },
"speed_travel": { "default": 120.0 },
"speed_layer_0": { "default": 20.0 },
"skirt_speed": { "default": 15.0 },
"speed_slowdown_layers": { "default": 4 },
"infill_sparse_density": { "default": 20.0 },
"cool_fan_speed_min": { "default": 50.0 },
"cool_fan_speed_max": { "default": 100.0 },
"cool_fan_full_layer": { "default": 4, "visible": true },
"cool_min_layer_time": { "default": 5.0 },
"cool_min_layer_time_fan_speed_max": { "default": 10.0 },
"support_type": { "default": "Everywhere" },
"support_angle": { "default": 45.0, "visible": true },
"support_xy_distance": { "default": 1 },
"support_z_distance": { "default": 0.2 },
"support_top_distance": { "default": 0.2 },
"support_bottom_distance": { "default": 0.24 },
"support_pattern": { "default": "ZigZag" },
"support_infill_rate": { "default": 15, "visible": true },
"adhesion_type": { "default": "Raft" },
"skirt_minimal_length": { "default": 100.0 },
"raft_base_line_spacing": { "default": 2.0 },
"raft_base_thickness": { "default": 0.3 },
"raft_base_line_width": { "default": 2.0 },
"raft_base_speed": { "default": 15.0 },
"raft_interface_thickness": { "default": 0.24 },
"raft_interface_line_width": { "default": 0.6 },
"raft_airgap": { "default": 0.2 },
"raft_surface_layers": { "default": 2 }
}
}

View File

@ -20,8 +20,6 @@
"machine_head_shape_max_x": { "default": 18 }, "machine_head_shape_max_x": { "default": 18 },
"machine_head_shape_max_y": { "default": 35 }, "machine_head_shape_max_y": { "default": 35 },
"machine_nozzle_gantry_distance": { "default": 55 }, "machine_nozzle_gantry_distance": { "default": 55 },
"machine_nozzle_offset_x_1": { "default": 0.0 },
"machine_nozzle_offset_y_1": { "default": 0.0 },
"machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" }, "machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": { "machine_start_gcode": {
@ -32,13 +30,7 @@
} }
}, },
"categories": { "overrides": {
"material": { "material_bed_temperature": { "visible": true }
"settings": {
"material_bed_temperature": {
"visible": true
}
}
}
} }
} }

View File

@ -10,6 +10,26 @@
"inherits": "fdmprinter.json", "inherits": "fdmprinter.json",
"machine_extruder_trains": [
{
"machine_nozzle_size": {
"default": 0.4
},
"machine_nozzle_tip_outer_diameter": {
"default": 1
},
"machine_nozzle_head_distance": {
"default": 3
},
"machine_nozzle_expansion_angle": {
"default": 45
},
"machine_heat_zone_length": {
"default": 16
}
}
],
"machine_settings": { "machine_settings": {
"machine_start_gcode" : { "default": "" }, "machine_start_gcode" : { "default": "" },
"machine_end_gcode" : { "default": "" }, "machine_end_gcode" : { "default": "" },
@ -18,15 +38,31 @@
"machine_height": { "default": 205 }, "machine_height": { "default": 205 },
"machine_heated_bed": { "default": true }, "machine_heated_bed": { "default": true },
"machine_head_with_fans_polygon":
{
"default": [
[
-40,
30
],
[
-40,
-10
],
[
60,
-10
],
[
60,
30
]
]
},
"machine_center_is_zero": { "default": false }, "machine_center_is_zero": { "default": false },
"machine_nozzle_size": { "default": 0.4 }, "machine_nozzle_size": { "default": 0.4 },
"machine_head_shape_min_x": { "default": 40 }, "gantry_height": { "default": 55 },
"machine_head_shape_min_y": { "default": 10 }, "machine_use_extruder_offset_to_offset_coords": { "default": true },
"machine_head_shape_max_x": { "default": 60 },
"machine_head_shape_max_y": { "default": 30 },
"machine_nozzle_gantry_distance": { "default": 55 },
"machine_nozzle_offset_x_1": { "default": 18.0 },
"machine_nozzle_offset_y_1": { "default": 0.0 },
"machine_gcode_flavor": { "default": "UltiGCode" }, "machine_gcode_flavor": { "default": "UltiGCode" },
"machine_disallowed_areas": { "default": [ "machine_disallowed_areas": { "default": [
[[-115.0, 112.5], [ -82.0, 112.5], [ -84.0, 104.5], [-115.0, 104.5]], [[-115.0, 112.5], [ -82.0, 112.5], [ -84.0, 104.5], [-115.0, 104.5]],
@ -41,22 +77,10 @@
"machine_nozzle_expansion_angle": { "default": 45 } "machine_nozzle_expansion_angle": { "default": 45 }
}, },
"categories": { "overrides": {
"material": { "material_print_temperature": { "enabled": "False" },
"settings": { "material_bed_temperature": { "enabled": "False" },
"material_print_temperature": { "material_diameter": { "enabled": "False" },
"visible": false "material_flow": { "enabled": "False" }
},
"material_bed_temperature": {
"visible": false
},
"material_diameter": {
"visible": false
},
"material_flow": {
"visible": false
}
}
}
} }
} }

View File

@ -6,7 +6,7 @@
"author": "Ultimaker", "author": "Ultimaker",
"icon": "icon_ultimaker2.png", "icon": "icon_ultimaker2.png",
"platform": "ultimaker2_platform.obj", "platform": "ultimaker2_platform.obj",
"platform_texture": "Ultimaker2backplate.png", "platform_texture": "Ultimaker2Extendedbackplate.png",
"inherits": "ultimaker2.json", "inherits": "ultimaker2.json",

View File

@ -6,7 +6,7 @@
"author": "Ultimaker", "author": "Ultimaker",
"icon": "icon_ultimaker2.png", "icon": "icon_ultimaker2.png",
"platform": "ultimaker2go_platform.obj", "platform": "ultimaker2go_platform.obj",
"platform_texture": "Ultimaker2backplate.png", "platform_texture": "Ultimaker2Gobackplate.png",
"inherits": "ultimaker2.json", "inherits": "ultimaker2.json",

View File

@ -9,43 +9,72 @@
"inherits": "fdmprinter.json", "inherits": "fdmprinter.json",
"add_pages": [ "pages": [
{"page": "SelectUpgradedParts", "title": "Select Upgraded Parts"}, "SelectUpgradedParts",
{"page": "UpgradeFirmware", "title": "Upgrade Ultimaker Firmware"}, "UpgradeFirmware",
{"page": "UltimakerCheckup", "title": "Ultimaker Checkup"}, "UltimakerCheckup",
{"page": "Bedleveling", "title": "Bedleveling Wizard"} "BedLeveling"
], ],
"machine_extruder_trains": [
{
"machine_nozzle_size": {
"default": 0.4
},
"machine_nozzle_tip_outer_diameter": {
"default": 1
},
"machine_nozzle_head_distance": {
"default": 3
},
"machine_nozzle_expansion_angle": {
"default": 45
},
"machine_heat_zone_length": {
"default": 16
}
}
],
"machine_settings": { "machine_settings": {
"machine_width": { "default": 205 }, "machine_width": { "default": 205 },
"machine_height": { "default": 200 }, "machine_height": { "default": 200 },
"machine_depth": { "default": 205 }, "machine_depth": { "default": 205 },
"machine_center_is_zero": { "default": false }, "machine_center_is_zero": { "default": false },
"machine_nozzle_size": { "default": 0.4 }, "machine_nozzle_size": { "default": 0.4 },
"machine_head_shape_min_x": { "default": 75 }, "machine_head_with_fans_polygon":
"machine_head_shape_min_y": { "default": 18 }, {
"machine_head_shape_max_x": { "default": 18 }, "default": [
"machine_head_shape_max_y": { "default": 35 }, [
"machine_nozzle_gantry_distance": { "default": 55 }, -75,
"machine_nozzle_offset_x_1": { "default": 18.0 }, 35
"machine_nozzle_offset_y_1": { "default": 0.0 }, ],
[
-75,
-18
],
[
18,
35
],
[
18,
-18
]
]
},
"gantry_height": { "default": 55 },
"machine_use_extruder_offset_to_offset_coords": { "default": true },
"machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" }, "machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": { "machine_start_gcode": {
"default": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E3 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." "default": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E6 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..."
}, },
"machine_end_gcode": { "machine_end_gcode": {
"default": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning" "default": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
} }
}, },
"categories": { "overrides": {
"material": { "material_bed_temperature": { "visible": false }
"settings": {
"material_bed_temperature": {
"visible": false
}
}
}
} }
} }

View File

@ -10,6 +10,12 @@
"inherits": "ultimaker_original.json", "inherits": "ultimaker_original.json",
"pages": [
"UpgradeFirmware",
"UltimakerCheckup",
"BedLeveling"
],
"machine_settings": { "machine_settings": {
"machine_heated_bed": { "default": true } "machine_heated_bed": { "default": true }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,6 @@
[general]
version = 1
name = High Quality
[settings]
layer_height = 0.06

View File

@ -0,0 +1,6 @@
[general]
version = 1
name = Normal Quality
[settings]
layer_height = 0.1

View File

@ -5,17 +5,21 @@ import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Window 2.1 import QtQuick.Window 2.1
import UM 1.0 as UM import UM 1.1 as UM
UM.Dialog { UM.Dialog
{
id: base id: base
//: About dialog title //: About dialog title
title: qsTr("About Cura") title: catalog.i18nc("@title:window","About Cura")
minimumWidth: 400 minimumWidth: 400
minimumHeight: 300 minimumHeight: 300;
//UM.I18nCatalog { id: catalog; }
Image {
Image
{
id: logo id: logo
width: parent.width * 0.75 width: parent.width * 0.75
height: width * (1/4.25) height: width * (1/4.25)
@ -26,9 +30,11 @@ UM.Dialog {
sourceSize.height: height sourceSize.height: height
anchors.centerIn: parent anchors.centerIn: parent
anchors.verticalCenterOffset : -(height * 0.5) anchors.verticalCenterOffset : -(height * 0.5)
UM.I18nCatalog{id: catalog; name:"cura"}
} }
Label { Label
{
id: version id: version
text: "Cura %1".arg(UM.Application.version) text: "Cura %1".arg(UM.Application.version)
@ -39,30 +45,33 @@ UM.Dialog {
anchors.topMargin : 5 anchors.topMargin : 5
} }
Label { Label
{
id: description id: description
width: parent.width width: parent.width
//: About dialog application description //: About dialog application description
text: qsTr("End-to-end solution for fused filament 3D printing.") text: catalog.i18nc("@label","End-to-end solution for fused filament 3D printing.")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
anchors.top: version.bottom anchors.top: version.bottom
anchors.topMargin : 10 anchors.topMargin : 10
} }
Label { Label
{
id: author_note id: author_note
width: parent.width width: parent.width
//: About dialog application author note //: About dialog application author note
text: qsTr("Cura has been developed by Ultimaker B.V. in cooperation with the community.") text: catalog.i18nc("@info:credit","Cura has been developed by Ultimaker B.V. in cooperation with the community.")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
anchors.top: description.bottom anchors.top: description.bottom
} }
rightButtons: Button { rightButtons: Button
{
//: Close about dialog button //: Close about dialog button
text: qsTr("Close"); text: catalog.i18nc("@action:button","Close");
onClicked: base.visible = false; onClicked: base.visible = false;
} }

View File

@ -3,11 +3,11 @@
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import UM 1.0 as UM import UM 1.1 as UM
Item { Item
{
property alias open: openAction; property alias open: openAction;
property alias save: saveAction;
property alias quit: quitAction; property alias quit: quitAction;
property alias undo: undoAction; property alias undo: undoAction;
@ -23,7 +23,6 @@ Item {
//property alias unMergeObjects: unMergeObjectsAction; //property alias unMergeObjects: unMergeObjectsAction;
property alias multiplyObject: multiplyObjectAction; property alias multiplyObject: multiplyObjectAction;
property alias splitObject: splitObjectAction;
property alias deleteAll: deleteAllAction; property alias deleteAll: deleteAllAction;
property alias reloadAll: reloadAllAction; property alias reloadAll: reloadAllAction;
@ -32,6 +31,7 @@ Item {
property alias addMachine: addMachineAction; property alias addMachine: addMachineAction;
property alias configureMachines: settingsAction; property alias configureMachines: settingsAction;
property alias manageProfiles: manageProfilesAction;
property alias preferences: preferencesAction; property alias preferences: preferencesAction;
@ -40,172 +40,181 @@ Item {
property alias reportBug: reportBugAction; property alias reportBug: reportBugAction;
property alias about: aboutAction; property alias about: aboutAction;
Action { property alias toggleFullScreen: toggleFullScreenAction;
UM.I18nCatalog{id: catalog; name:"cura"}
Action
{
id:toggleFullScreenAction
shortcut: StandardKey.FullScreen;
text: catalog.i18nc("@action:inmenu","Toggle Fu&ll Screen");
iconName: "view-fullscreen";
}
Action
{
id: undoAction; id: undoAction;
//: Undo action text: catalog.i18nc("@action:inmenu","&Undo");
text: qsTr("&Undo");
iconName: "edit-undo"; iconName: "edit-undo";
shortcut: StandardKey.Undo; shortcut: StandardKey.Undo;
} }
Action { Action
{
id: redoAction; id: redoAction;
//: Redo action text: catalog.i18nc("@action:inmenu","&Redo");
text: qsTr("&Redo");
iconName: "edit-redo"; iconName: "edit-redo";
shortcut: StandardKey.Redo; shortcut: StandardKey.Redo;
} }
Action { Action
{
id: quitAction; id: quitAction;
//: Quit action text: catalog.i18nc("@action:inmenu","&Quit");
text: qsTr("&Quit");
iconName: "application-exit"; iconName: "application-exit";
shortcut: StandardKey.Quit; shortcut: StandardKey.Quit;
} }
Action { Action
{
id: preferencesAction; id: preferencesAction;
//: Preferences action text: catalog.i18nc("@action:inmenu","&Preferences...");
text: qsTr("&Preferences...");
iconName: "configure"; iconName: "configure";
} }
Action { Action
{
id: addMachineAction; id: addMachineAction;
//: Add Printer action text: catalog.i18nc("@action:inmenu","&Add Printer...");
text: qsTr("&Add Printer...");
} }
Action { Action
{
id: settingsAction; id: settingsAction;
//: Configure Printers action text: catalog.i18nc("@action:inmenu","Manage Pr&inters...");
text: qsTr("&Configure Printers");
iconName: "configure"; iconName: "configure";
} }
Action { Action
{
id: manageProfilesAction;
text: catalog.i18nc("@action:inmenu","Manage Profiles...");
iconName: "configure";
}
Action
{
id: documentationAction; id: documentationAction;
//: Show Online Documentation action text: catalog.i18nc("@action:inmenu","Show Online &Documentation");
text: qsTr("Show Online &Documentation");
iconName: "help-contents"; iconName: "help-contents";
shortcut: StandardKey.Help; shortcut: StandardKey.Help;
} }
Action { Action {
id: reportBugAction; id: reportBugAction;
//: Report a Bug Action text: catalog.i18nc("@action:inmenu","Report a &Bug");
text: qsTr("Report a &Bug");
iconName: "tools-report-bug"; iconName: "tools-report-bug";
} }
Action { Action
{
id: aboutAction; id: aboutAction;
//: About action text: catalog.i18nc("@action:inmenu","&About...");
text: qsTr("&About...");
iconName: "help-about"; iconName: "help-about";
} }
Action { Action
{
id: deleteSelectionAction; id: deleteSelectionAction;
//: Delete selection action text: catalog.i18nc("@action:inmenu","Delete &Selection");
text: qsTr("Delete Selection");
iconName: "edit-delete"; iconName: "edit-delete";
shortcut: StandardKey.Delete; shortcut: StandardKey.Delete;
} }
Action { Action
{
id: deleteObjectAction; id: deleteObjectAction;
//: Delete object action text: catalog.i18nc("@action:inmenu","Delete Object");
text: qsTr("Delete Object");
iconName: "edit-delete"; iconName: "edit-delete";
shortcut: StandardKey.Backspace;
} }
Action { Action
{
id: centerObjectAction; id: centerObjectAction;
//: Center object action text: catalog.i18nc("@action:inmenu","Ce&nter Object on Platform");
text: qsTr("Center Object on Platform");
} }
Action Action
{ {
id: groupObjectsAction id: groupObjectsAction
text: qsTr("Group objects"); text: catalog.i18nc("@action:inmenu","&Group Objects");
enabled: UM.Scene.numObjectsSelected > 1 ? true: false enabled: UM.Scene.numObjectsSelected > 1 ? true: false
iconName: "object-group"
} }
Action Action
{ {
id: unGroupObjectsAction id: unGroupObjectsAction
text: qsTr("Ungroup objects"); text: catalog.i18nc("@action:inmenu","Ungroup Objects");
enabled: UM.Scene.isGroupSelected enabled: UM.Scene.isGroupSelected
iconName: "object-ungroup"
} }
Action Action
{ {
id: mergeObjectsAction id: mergeObjectsAction
text: qsTr("Merge objects"); text: catalog.i18nc("@action:inmenu","&Merge Objects");
enabled: UM.Scene.numObjectsSelected > 1 ? true: false enabled: UM.Scene.numObjectsSelected > 1 ? true: false
iconName: "merge";
} }
Action { Action
{
id: multiplyObjectAction; id: multiplyObjectAction;
//: Duplicate object action text: catalog.i18nc("@action:inmenu","&Duplicate Object");
text: qsTr("Duplicate Object"); iconName: "edit-duplicate"
} }
Action { Action
id: splitObjectAction; {
//: Split object action
text: qsTr("Split Object into Parts");
enabled: false;
}
Action {
id: deleteAllAction; id: deleteAllAction;
//: Clear build platform action text: catalog.i18nc("@action:inmenu","&Clear Build Platform");
text: qsTr("Clear Build Platform"); iconName: "edit-delete";
iconName: "edit-clear";
} }
Action { Action
{
id: reloadAllAction; id: reloadAllAction;
//: Reload all objects action text: catalog.i18nc("@action:inmenu","Re&load All Objects");
text: qsTr("Reload All Objects"); iconName: "document-revert";
} }
Action { Action
{
id: resetAllTranslationAction; id: resetAllTranslationAction;
//: Reset all positions action text: catalog.i18nc("@action:inmenu","Reset All Object Positions");
text: qsTr("Reset All Object Positions");
} }
Action { Action
{
id: resetAllAction; id: resetAllAction;
//: Reset all positions action text: catalog.i18nc("@action:inmenu","Reset All Object &Transformations");
text: qsTr("Reset All Object Transformations");
} }
Action { Action
{
id: openAction; id: openAction;
//: Open file action text: catalog.i18nc("@action:inmenu","&Open File...");
text: qsTr("&Open...");
iconName: "document-open"; iconName: "document-open";
shortcut: StandardKey.Open; shortcut: StandardKey.Open;
} }
Action { Action
id: saveAction; {
//: Save file action
text: qsTr("&Save...");
iconName: "document-save";
shortcut: StandardKey.Save;
}
Action {
id: showEngineLogAction; id: showEngineLogAction;
//: Show engine log action text: catalog.i18nc("@action:inmenu","Show Engine &Log...");
text: qsTr("Show engine &log...");
iconName: "view-list-text"; iconName: "view-list-text";
} }
} }

View File

@ -6,11 +6,27 @@ import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Window 2.1 import QtQuick.Window 2.1
import UM 1.0 as UM import UM 1.1 as UM
import Cura 1.0 as Cura
UM.Wizard{ import "WizardPages"
id: base
property bool printer: true UM.Wizard
file: "ultimaker2.json" {
firstRun: printer ? false : true id: base;
title: catalog.i18nc("@title:window", "Add Printer")
// This part is optional
// This part checks whether there is a printer -> if not: some of the functions (delete for example) are disabled
firstRun: false
Component.onCompleted: {
base.appendPage(Qt.resolvedUrl("WizardPages/AddMachine.qml"), catalog.i18nc("@title", "Add Printer"));
base.currentPage = 0;
}
Item {
UM.I18nCatalog { id: catalog; name: "cura"; }
}
} }

View File

@ -9,43 +9,56 @@ import QtQuick.Dialogs 1.1
import UM 1.1 as UM import UM 1.1 as UM
UM.MainWindow { UM.MainWindow
{
id: base id: base
visible: true
//: Cura application window title //: Cura application window title
title: qsTr("Cura"); title: catalog.i18nc("@title:window","Cura");
Item { viewportRect: Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0)
Item
{
id: backgroundItem; id: backgroundItem;
anchors.fill: parent; anchors.fill: parent;
UM.I18nCatalog{id: catalog; name:"cura"}
UM.ApplicationMenu { UM.ApplicationMenu
{
id: menu id: menu
window: base window: base
Menu { Menu
{
id: fileMenu id: fileMenu
//: File menu //: File menu
title: qsTr("&File"); title: catalog.i18nc("@title:menu","&File");
MenuItem { action: actions.open; } MenuItem {
action: actions.open;
}
Menu { Menu
{
id: recentFilesMenu; id: recentFilesMenu;
title: "Open Recent" title: catalog.i18nc("@title:menu", "Open &Recent")
iconName: "document-open-recent"; iconName: "document-open-recent";
enabled: Printer.recentFiles.length > 0; enabled: Printer.recentFiles.length > 0;
Instantiator { Instantiator
{
model: Printer.recentFiles model: Printer.recentFiles
MenuItem { MenuItem
text: { {
text:
{
var path = modelData.toString() var path = modelData.toString()
return (index + 1) + ". " + path.slice(path.lastIndexOf("/") + 1); return (index + 1) + ". " + path.slice(path.lastIndexOf("/") + 1);
} }
onTriggered: UM.MeshFileHandler.readLocalFile(modelData); onTriggered: {
UM.MeshFileHandler.readLocalFile(modelData);
openDialog.sendMeshName(modelData.toString())
}
} }
onObjectAdded: recentFilesMenu.insertItem(index, object) onObjectAdded: recentFilesMenu.insertItem(index, object)
onObjectRemoved: recentFilesMenu.removeItem(object) onObjectRemoved: recentFilesMenu.removeItem(object)
@ -54,52 +67,66 @@ UM.MainWindow {
MenuSeparator { } MenuSeparator { }
MenuItem { MenuItem
text: "Save Selection to File"; {
text: catalog.i18nc("@action:inmenu", "&Save Selection to File");
enabled: UM.Selection.hasSelection; enabled: UM.Selection.hasSelection;
iconName: "document-save-as"; iconName: "document-save-as";
onTriggered: devicesModel.requestWriteSelectionToDevice("local_file"); onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file");
} }
Menu { Menu
{
id: saveAllMenu id: saveAllMenu
title: "Save All" title: catalog.i18nc("@title:menu","Save &All")
iconName: "document-save"; iconName: "document-save-all";
enabled: devicesModel.count > 0 && UM.Backend.progress > 0.99; enabled: devicesModel.rowCount() > 0 && UM.Backend.progress > 0.99;
Instantiator { Instantiator
{
model: UM.OutputDevicesModel { id: devicesModel; } model: UM.OutputDevicesModel { id: devicesModel; }
MenuItem { MenuItem
text: model.description {
onTriggered: devicesModel.requestWriteToDevice(model.id); text: model.description;
onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id);
} }
onObjectAdded: saveAllMenu.insertItem(index, object) onObjectAdded: saveAllMenu.insertItem(index, object)
onObjectRemoved: saveAllMenu.removeItem(object) onObjectRemoved: saveAllMenu.removeItem(object)
} }
} }
MenuItem { action: actions.reloadAll; }
MenuSeparator { } MenuSeparator { }
MenuItem { action: actions.quit; } MenuItem { action: actions.quit; }
} }
Menu { Menu
{
//: Edit menu //: Edit menu
title: qsTr("&Edit"); title: catalog.i18nc("@title:menu","&Edit");
MenuItem { action: actions.undo; } MenuItem { action: actions.undo; }
MenuItem { action: actions.redo; } MenuItem { action: actions.redo; }
MenuSeparator { } MenuSeparator { }
MenuItem { action: actions.deleteSelection; } MenuItem { action: actions.deleteSelection; }
MenuItem { action: actions.deleteAll; } MenuItem { action: actions.deleteAll; }
MenuItem { action: actions.resetAllTranslation; }
MenuItem { action: actions.resetAll; }
MenuSeparator { }
MenuItem { action: actions.groupObjects;}
MenuItem { action: actions.mergeObjects;}
MenuItem { action: actions.unGroupObjects;}
} }
Menu Menu
{ {
title: qsTr("&View"); title: catalog.i18nc("@title:menu","&View");
id: top_view_menu id: top_view_menu
Instantiator Instantiator
{ {
model: UM.Models.viewModel model: UM.ViewModel { }
MenuItem MenuItem
{ {
text: model.name; text: model.name;
@ -112,20 +139,27 @@ UM.MainWindow {
onObjectRemoved: top_view_menu.removeItem(object) onObjectRemoved: top_view_menu.removeItem(object)
} }
ExclusiveGroup { id: view_menu_top_group; } ExclusiveGroup { id: view_menu_top_group; }
MenuSeparator { }
MenuItem { action: actions.toggleFullScreen; }
} }
Menu { Menu
{
id: machineMenu; id: machineMenu;
//: Machine menu //: Machine menu
title: qsTr("&Machine"); title: catalog.i18nc("@title:menu","&Machine");
Instantiator { Instantiator
model: UM.Models.machinesModel {
MenuItem { model: UM.MachineInstancesModel { }
MenuItem
{
text: model.name; text: model.name;
checkable: true; checkable: true;
checked: model.active; checked: model.active;
exclusiveGroup: machineMenuGroup; exclusiveGroup: machineMenuGroup;
onTriggered: UM.Models.machinesModel.setActive(index) onTriggered: UM.MachineManager.setActiveMachineInstance(model.name)
} }
onObjectAdded: machineMenu.insertItem(index, object) onObjectAdded: machineMenu.insertItem(index, object)
onObjectRemoved: machineMenu.removeItem(object) onObjectRemoved: machineMenu.removeItem(object)
@ -135,14 +169,59 @@ UM.MainWindow {
MenuSeparator { } MenuSeparator { }
Instantiator
{
model: UM.MachineVariantsModel { }
MenuItem {
text: model.name;
checkable: true;
checked: model.active;
exclusiveGroup: machineVariantsGroup;
onTriggered: UM.MachineManager.setActiveMachineVariant(model.name)
}
onObjectAdded: machineMenu.insertItem(index, object)
onObjectRemoved: machineMenu.removeItem(object)
}
ExclusiveGroup { id: machineVariantsGroup; }
MenuSeparator { visible: UM.MachineManager.hasVariants; }
MenuItem { action: actions.addMachine; } MenuItem { action: actions.addMachine; }
MenuItem { action: actions.configureMachines; } MenuItem { action: actions.configureMachines; }
} }
Menu { Menu
{
id: profileMenu
title: catalog.i18nc("@title:menu", "&Profile")
Instantiator
{
model: UM.ProfilesModel { }
MenuItem {
text: model.name;
checkable: true;
checked: model.active;
exclusiveGroup: profileMenuGroup;
onTriggered: UM.MachineManager.setActiveProfile(model.name)
}
onObjectAdded: profileMenu.insertItem(index, object)
onObjectRemoved: profileMenu.removeItem(object)
}
ExclusiveGroup { id: profileMenuGroup; }
MenuSeparator { }
MenuItem { action: actions.manageProfiles; }
}
Menu
{
id: extension_menu id: extension_menu
//: Extensions menu //: Extensions menu
title: qsTr("E&xtensions"); title: catalog.i18nc("@title:menu","E&xtensions");
Instantiator Instantiator
{ {
@ -152,7 +231,8 @@ UM.MainWindow {
{ {
id: sub_menu id: sub_menu
title: model.name; title: model.name;
visible: actions != null
enabled:actions != null
Instantiator Instantiator
{ {
model: actions model: actions
@ -171,16 +251,18 @@ UM.MainWindow {
} }
} }
Menu { Menu
{
//: Settings menu //: Settings menu
title: qsTr("&Settings"); title: catalog.i18nc("@title:menu","&Settings");
MenuItem { action: actions.preferences; } MenuItem { action: actions.preferences; }
} }
Menu { Menu
{
//: Help menu //: Help menu
title: qsTr("&Help"); title: catalog.i18nc("@title:menu","&Help");
MenuItem { action: actions.showEngineLog; } MenuItem { action: actions.showEngineLog; }
MenuItem { action: actions.documentation; } MenuItem { action: actions.documentation; }
@ -190,7 +272,8 @@ UM.MainWindow {
} }
} }
Item { Item
{
id: contentItem; id: contentItem;
y: menu.height y: menu.height
@ -199,23 +282,31 @@ UM.MainWindow {
Keys.forwardTo: menu Keys.forwardTo: menu
DropArea { DropArea
{
anchors.fill: parent; anchors.fill: parent;
onDropped: { onDropped:
if(drop.urls.length > 0) { {
for(var i in drop.urls) { if(drop.urls.length > 0)
{
for(var i in drop.urls)
{
UM.MeshFileHandler.readLocalFile(drop.urls[i]); UM.MeshFileHandler.readLocalFile(drop.urls[i]);
if (i == drop.urls.length - 1)
{
openDialog.sendMeshName(drop.urls[i].toString())
}
} }
} }
} }
} }
UM.MessageStack { UM.MessageStack
anchors { {
left: toolbar.right; anchors
leftMargin: UM.Theme.sizes.window_margin.width; {
right: sidebar.left; horizontalCenter: parent.horizontalCenter
rightMargin: UM.Theme.sizes.window_margin.width; horizontalCenterOffset: -(UM.Theme.sizes.logo.width/ 2)
top: parent.verticalCenter; top: parent.verticalCenter;
bottom: parent.bottom; bottom: parent.bottom;
} }
@ -240,27 +331,34 @@ UM.MainWindow {
source: UM.ActiveView.valid ? UM.ActiveView.activeViewPanel : ""; source: UM.ActiveView.valid ? UM.ActiveView.activeViewPanel : "";
} }
Button { Button
{
id: openFileButton; id: openFileButton;
//style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button;
iconSource: UM.Theme.icons.open; //style: UM.Theme.styles.open_file_button
style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button; text: catalog.i18nc("@action:button","Open File");
iconSource: UM.Theme.icons.load
style: UM.Theme.styles.open_file_button
tooltip: ''; tooltip: '';
anchors { anchors
{
top: parent.top; top: parent.top;
topMargin: UM.Theme.sizes.window_margin.height; //topMargin: UM.Theme.sizes.loadfile_margin.height
left: parent.left; left: parent.left;
leftMargin: UM.Theme.sizes.window_margin.width; //leftMargin: UM.Theme.sizes.loadfile_margin.width
} }
action: actions.open; action: actions.open;
} }
Image { Image
anchors { {
verticalCenter: openFileButton.verticalCenter; id: logo
left: openFileButton.right; anchors
leftMargin: UM.Theme.sizes.window_margin.width; {
left: parent.left
leftMargin: UM.Theme.sizes.default_margin.width;
bottom: parent.bottom
bottomMargin: UM.Theme.sizes.default_margin.height;
} }
source: UM.Theme.images.logo; source: UM.Theme.images.logo;
@ -271,25 +369,29 @@ UM.MainWindow {
sourceSize.height: height; sourceSize.height: height;
} }
Button { Button
anchors { {
id: viewModeButton
property bool verticalTooltip: true
anchors
{
top: parent.top; top: parent.top;
topMargin: UM.Theme.sizes.window_margin.height;
right: sidebar.left; right: sidebar.left;
rightMargin: UM.Theme.sizes.window_margin.width; rightMargin: UM.Theme.sizes.window_margin.width;
} }
id: viewModeButton text: catalog.i18nc("@action:button","View Mode");
//: View Mode toolbar button
text: qsTr("View Mode");
iconSource: UM.Theme.icons.viewmode; iconSource: UM.Theme.icons.viewmode;
style: UM.Theme.styles.tool_button; style: UM.Theme.styles.tool_button;
tooltip: ''; tooltip: '';
menu: Menu { menu: Menu
{
id: viewMenu; id: viewMenu;
Instantiator { Instantiator
model: UM.Models.viewModel; {
MenuItem { model: UM.ViewModel { }
MenuItem
{
text: model.name; text: model.name;
checkable: true; checkable: true;
checked: model.active; checked: model.active;
@ -304,39 +406,47 @@ UM.MainWindow {
} }
} }
Toolbar { Toolbar
{
id: toolbar; id: toolbar;
anchors { anchors {
left: parent.left; left: parent.left
leftMargin: UM.Theme.sizes.window_margin.width; top: parent.top
bottom: parent.bottom; topMargin: 74
bottomMargin: UM.Theme.sizes.window_margin.height; //horizontalCenter: parent.horizontalCenter
//horizontalCenterOffset: -(UM.Theme.sizes.sidebar.width / 2)
//top: parent.top;
} }
} }
Sidebar { Sidebar
{
id: sidebar; id: sidebar;
anchors { anchors
{
top: parent.top; top: parent.top;
bottom: parent.bottom; bottom: parent.bottom;
right: parent.right; right: parent.right;
} }
width: UM.Theme.sizes.panel.width; width: UM.Theme.sizes.sidebar.width;
addMachineAction: actions.addMachine; addMachineAction: actions.addMachine;
configureMachinesAction: actions.configureMachines; configureMachinesAction: actions.configureMachines;
manageProfilesAction: actions.manageProfiles;
} }
Rectangle { Rectangle
{
x: base.mouseX + UM.Theme.sizes.default_margin.width; x: base.mouseX + UM.Theme.sizes.default_margin.width;
y: base.mouseY + UM.Theme.sizes.default_margin.height; y: base.mouseY + UM.Theme.sizes.default_margin.height;
width: childrenRect.width; width: childrenRect.width;
height: childrenRect.height; height: childrenRect.height;
Label { Label
{
text: UM.ActiveTool.properties.Rotation != undefined ? "%1°".arg(UM.ActiveTool.properties.Rotation) : ""; text: UM.ActiveTool.properties.Rotation != undefined ? "%1°".arg(UM.ActiveTool.properties.Rotation) : "";
} }
@ -345,20 +455,29 @@ UM.MainWindow {
} }
} }
UM.PreferencesDialog { UM.PreferencesDialog
{
id: preferences id: preferences
Component.onCompleted: { Component.onCompleted:
{
//; Remove & re-add the general page as we want to use our own instead of uranium standard.
removePage(0);
insertPage(0, catalog.i18nc("@title:tab","General") , "" , Qt.resolvedUrl("./GeneralPage.qml"));
//: View preferences page title //: View preferences page title
insertPage(1, qsTr("View"), "view-preview", Qt.resolvedUrl("./ViewPage.qml")); insertPage(1, catalog.i18nc("@title:tab","View"), "view-preview", Qt.resolvedUrl("./ViewPage.qml"));
//Force refresh
setPage(0)
} }
} }
Actions { Actions
{
id: actions; id: actions;
open.onTriggered: openDialog.open(); open.onTriggered: openDialog.open();
save.onTriggered: saveDialog.open();
quit.onTriggered: base.visible = false; quit.onTriggered: base.visible = false;
@ -367,28 +486,36 @@ UM.MainWindow {
redo.onTriggered: UM.OperationStack.redo(); redo.onTriggered: UM.OperationStack.redo();
redo.enabled: UM.OperationStack.canRedo; redo.enabled: UM.OperationStack.canRedo;
deleteSelection.onTriggered: { deleteSelection.onTriggered:
if(objectContextMenu.objectId != 0) { {
if(objectContextMenu.objectId != 0)
{
Printer.deleteObject(objectContextMenu.objectId); Printer.deleteObject(objectContextMenu.objectId);
} }
} }
deleteObject.onTriggered: { deleteObject.onTriggered:
if(objectContextMenu.objectId != 0) { {
if(objectContextMenu.objectId != 0)
{
Printer.deleteObject(objectContextMenu.objectId); Printer.deleteObject(objectContextMenu.objectId);
objectContextMenu.objectId = 0; objectContextMenu.objectId = 0;
} }
} }
multiplyObject.onTriggered: { multiplyObject.onTriggered:
if(objectContextMenu.objectId != 0) { {
if(objectContextMenu.objectId != 0)
{
Printer.multiplyObject(objectContextMenu.objectId, 1); Printer.multiplyObject(objectContextMenu.objectId, 1);
objectContextMenu.objectId = 0; objectContextMenu.objectId = 0;
} }
} }
centerObject.onTriggered: { centerObject.onTriggered:
if(objectContextMenu.objectId != 0) { {
if(objectContextMenu.objectId != 0)
{
Printer.centerObject(objectContextMenu.objectId); Printer.centerObject(objectContextMenu.objectId);
objectContextMenu.objectId = 0; objectContextMenu.objectId = 0;
} }
@ -418,94 +545,117 @@ UM.MainWindow {
preferences.onTriggered: preferences.visible = true; preferences.onTriggered: preferences.visible = true;
configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(2); } configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(2); }
manageProfiles.onTriggered: { preferences.visible = true; preferences.setPage(4); }
documentation.onTriggered: CuraActions.openDocumentation(); documentation.onTriggered: CuraActions.openDocumentation();
reportBug.onTriggered: CuraActions.openBugReportPage(); reportBug.onTriggered: CuraActions.openBugReportPage();
showEngineLog.onTriggered: engineLog.visible = true; showEngineLog.onTriggered: engineLog.visible = true;
about.onTriggered: aboutDialog.visible = true; about.onTriggered: aboutDialog.visible = true;
toggleFullScreen.onTriggered: base.toggleFullscreen()
} }
Menu { Menu
{
id: objectContextMenu; id: objectContextMenu;
property variant objectId: -1; property variant objectId: -1;
MenuItem { action: actions.centerObject; } MenuItem { action: actions.centerObject; }
MenuItem { action: actions.deleteObject; } MenuItem { action: actions.deleteObject; }
MenuItem { action: actions.multiplyObject; } MenuItem { action: actions.multiplyObject; }
MenuItem { action: actions.splitObject; }
MenuSeparator { } MenuSeparator { }
MenuItem { action: actions.deleteAll; } MenuItem { action: actions.deleteAll; }
MenuItem { action: actions.reloadAll; } MenuItem { action: actions.reloadAll; }
MenuItem { action: actions.resetAllTranslation; } MenuItem { action: actions.resetAllTranslation; }
MenuItem { action: actions.resetAll; } MenuItem { action: actions.resetAll; }
MenuItem { action: actions.groupObjects;} MenuItem { action: actions.groupObjects;}
MenuItem { action: actions.unGroupObjects;}
MenuItem { action: actions.mergeObjects;} MenuItem { action: actions.mergeObjects;}
MenuItem { action: actions.unGroupObjects;}
} }
Menu { Menu
{
id: contextMenu; id: contextMenu;
MenuItem { action: actions.deleteAll; } MenuItem { action: actions.deleteAll; }
MenuItem { action: actions.reloadAll; } MenuItem { action: actions.reloadAll; }
MenuItem { action: actions.resetAllTranslation; } MenuItem { action: actions.resetAllTranslation; }
MenuItem { action: actions.resetAll; } MenuItem { action: actions.resetAll; }
MenuItem { action: actions.groupObjects;} MenuItem { action: actions.groupObjects;}
MenuItem { action: actions.unGroupObjects;}
MenuItem { action: actions.mergeObjects;} MenuItem { action: actions.mergeObjects;}
MenuItem { action: actions.unGroupObjects;}
} }
Connections { Connections
{
target: UM.Controller target: UM.Controller
onContextMenuRequested: { onContextMenuRequested:
if(objectId == 0) { {
if(objectId == 0)
{
contextMenu.popup(); contextMenu.popup();
} else { } else
{
objectContextMenu.objectId = objectId; objectContextMenu.objectId = objectId;
objectContextMenu.popup(); objectContextMenu.popup();
} }
} }
} }
FileDialog { FileDialog
{
id: openDialog; id: openDialog;
//: File open dialog title //: File open dialog title
title: qsTr("Open File") title: catalog.i18nc("@title:window","Open File")
modality: UM.Application.platform == "linux" ? Qt.NonModal : Qt.WindowModal; modality: UM.Application.platform == "linux" ? Qt.NonModal : Qt.WindowModal;
//TODO: Support multiple file selection, workaround bug in KDE file dialog //TODO: Support multiple file selection, workaround bug in KDE file dialog
//selectMultiple: true //selectMultiple: true
signal hasMesh(string name)
function sendMeshName(path){
var fileName = path.slice(path.lastIndexOf("/") + 1)
var fileBase = fileName.slice(0, fileName.lastIndexOf("."))
openDialog.hasMesh(fileBase)
}
nameFilters: UM.MeshFileHandler.supportedReadFileTypes; nameFilters: UM.MeshFileHandler.supportedReadFileTypes;
onAccepted: onAccepted:
{ {
UM.MeshFileHandler.readLocalFile(fileUrl) UM.MeshFileHandler.readLocalFile(fileUrl)
Printer.setPlatformActivity(true) openDialog.sendMeshName(fileUrl.toString())
} }
} }
EngineLog { EngineLog
{
id: engineLog; id: engineLog;
} }
AddMachineWizard { AddMachineWizard
{
id: addMachineWizard id: addMachineWizard
} }
AboutDialog { AboutDialog
{
id: aboutDialog id: aboutDialog
} }
Connections { Connections
{
target: Printer target: Printer
onRequestAddPrinter: { onRequestAddPrinter:
{
addMachineWizard.visible = true addMachineWizard.visible = true
addMachineWizard.printer = false addMachineWizard.firstRun = true
} }
} }
Component.onCompleted: UM.Theme.load(UM.Resources.getPath(UM.Resources.ThemesLocation, "cura")) Component.onCompleted:
{
UM.Theme.load(UM.Resources.getPath(UM.Resources.Themes, "cura"))
base.visible = true;
}
} }

View File

@ -5,40 +5,48 @@ import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import UM 1.0 as UM import UM 1.1 as UM
UM.Dialog { UM.Dialog
{
id: dialog; id: dialog;
//: Engine Log dialog title //: Engine Log dialog title
title: qsTr("Engine Log"); title: catalog.i18nc("@title:window","Engine Log");
modality: Qt.NonModal; modality: Qt.NonModal;
TextArea { TextArea
{
id: textArea id: textArea
anchors.fill: parent; anchors.fill: parent;
Timer { Timer
{
id: updateTimer; id: updateTimer;
interval: 1000; interval: 1000;
running: false; running: false;
repeat: true; repeat: true;
onTriggered: textArea.text = Printer.getEngineLog(); onTriggered: textArea.text = Printer.getEngineLog();
} }
UM.I18nCatalog{id: catalog; name:"cura"}
} }
rightButtons: Button { rightButtons: Button
{
//: Close engine log button //: Close engine log button
text: qsTr("Close"); text: catalog.i18nc("@action:button","Close");
onClicked: dialog.visible = false; onClicked: dialog.visible = false;
} }
onVisibleChanged: { onVisibleChanged:
if(visible) { {
if(visible)
{
textArea.text = Printer.getEngineLog(); textArea.text = Printer.getEngineLog();
updateTimer.start(); updateTimer.start();
} else { } else
{
updateTimer.stop(); updateTimer.stop();
} }
} }

View File

@ -0,0 +1,202 @@
// Copyright (c) 2015 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.1 as UM
UM.PreferencesPage
{
//: General configuration page title
title: catalog.i18nc("@title:tab","General");
function reset()
{
UM.Preferences.resetPreference("general/language")
UM.Preferences.resetPreference("physics/automatic_push_free")
UM.Preferences.resetPreference("mesh/scale_to_fit")
UM.Preferences.resetPreference("info/send_slice_info")
pushFreeCheckbox.checked = boolCheck(UM.Preferences.getValue("physics/automatic_push_free"))
sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info"))
scaleToFitCheckbox.checked = boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
languageComboBox.currentIndex = 0
}
GridLayout
{
columns: 2;
//: Language selection label
UM.I18nCatalog{id: catalog; name:"cura"}
Label
{
id: languageLabel
text: catalog.i18nc("@label","Language")
}
ComboBox
{
id: languageComboBox
model: ListModel
{
id: languageList
Component.onCompleted: {
append({ text: catalog.i18nc("@item:inlistbox", "Bulgarian"), code: "bg" })
append({ text: catalog.i18nc("@item:inlistbox", "Czech"), code: "cs" })
append({ text: catalog.i18nc("@item:inlistbox", "English"), code: "en" })
append({ text: catalog.i18nc("@item:inlistbox", "Finnish"), code: "fi" })
append({ text: catalog.i18nc("@item:inlistbox", "French"), code: "fr" })
append({ text: catalog.i18nc("@item:inlistbox", "German"), code: "de" })
append({ text: catalog.i18nc("@item:inlistbox", "Italian"), code: "it" })
append({ text: catalog.i18nc("@item:inlistbox", "Polish"), code: "pl" })
append({ text: catalog.i18nc("@item:inlistbox", "Russian"), code: "ru" })
append({ text: catalog.i18nc("@item:inlistbox", "Spanish"), code: "es" })
}
}
currentIndex:
{
var code = UM.Preferences.getValue("general/language");
for(var i = 0; i < languageList.count; ++i)
{
if(model.get(i).code == code)
{
return i
}
}
}
onActivated: UM.Preferences.setValue("general/language", model.get(index).code)
anchors.left: languageLabel.right
anchors.top: languageLabel.top
anchors.leftMargin: 20
Component.onCompleted:
{
// Because ListModel is stupid and does not allow using qsTr() for values.
for(var i = 0; i < languageList.count; ++i)
{
languageList.setProperty(i, "text", catalog.i18n(languageList.get(i).text));
}
// Glorious hack time. ComboBox does not update the text properly after changing the
// model. So change the indices around to force it to update.
currentIndex += 1;
currentIndex -= 1;
}
}
Label
{
id: languageCaption;
Layout.columnSpan: 2
//: Language change warning
text: catalog.i18nc("@label", "You will need to restart the application for language changes to have effect.")
wrapMode: Text.WordWrap
font.italic: true
}
CheckBox
{
id: pushFreeCheckbox
checked: boolCheck(UM.Preferences.getValue("physics/automatic_push_free"))
onCheckedChanged: UM.Preferences.setValue("physics/automatic_push_free", checked)
}
Button
{
id: pushFreeText //is a button so the user doesn't have te click inconvenientley precise to enable or disable the checkbox
//: Display Overhang preference checkbox
text: catalog.i18nc("@option:check", "Ensure objects are kept apart");
onClicked: pushFreeCheckbox.checked = !pushFreeCheckbox.checked
//: Display Overhang preference tooltip
tooltip: catalog.i18nc("@info:tooltip", "Should objects on the platform be moved so that they no longer intersect.")
style: ButtonStyle
{
background: Rectangle
{
border.width: 0
color: "transparent"
}
label: Text
{
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignLeft
text: control.text
}
}
}
CheckBox
{
id: sendDataCheckbox
checked: boolCheck(UM.Preferences.getValue("info/send_slice_info"))
onCheckedChanged: UM.Preferences.setValue("info/send_slice_info", checked)
}
Button
{
id: sendDataText //is a button so the user doesn't have te click inconvenientley precise to enable or disable the checkbox
//: Display Overhang preference checkbox
text: catalog.i18nc("@option:check","Send (Anonymous) Print Information");
onClicked: sendDataCheckbox.checked = !sendDataCheckbox.checked
//: Display Overhang preference tooltip
tooltip: catalog.i18nc("@info:tooltip","Should anonymous data about your print be sent to Ultimaker? Note, no models, IP addresses or other personally identifiable information is sent or stored.")
style: ButtonStyle
{
background: Rectangle
{
border.width: 0
color: "transparent"
}
label: Text
{
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignLeft
text: control.text
}
}
}
CheckBox
{
id: scaleToFitCheckbox
checked: boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
onCheckedChanged: UM.Preferences.setValue("mesh/scale_to_fit", checked)
}
Button
{
id: scaleToFitText //is a button so the user doesn't have te click inconvenientley precise to enable or disable the checkbox
//: Display Overhang preference checkbox
text: catalog.i18nc("@option:check","Scale Too Large Files");
onClicked: scaleToFitCheckbox.checked = !scaleToFitCheckbox.checked
//: Display Overhang preference tooltip
tooltip: catalog.i18nc("@info:tooltip","Should opened files be scaled to the build volume when they are too large?")
style: ButtonStyle
{
background: Rectangle
{
border.width: 0
color: "transparent"
}
label: Text
{
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignLeft
text: control.text
}
}
}
Item { Layout.fillHeight: true; Layout.columnSpan: 2 }
}
}

View File

@ -0,0 +1,155 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.1 as UM
Column{
id: base;
UM.I18nCatalog { id: catalog; name:"cura"}
property int totalHeightProfileSetup: childrenRect.height
property Action manageProfilesAction
spacing: 0
Rectangle{
id: variantItem;
height: UM.Theme.sizes.sidebar_setup.height
width: base.width
visible: UM.MachineManager.hasVariants;
Rectangle {
id: variantRow
width: base.width
height: parent.heigth
Label{
id: variantLabel
text: catalog.i18nc("@label","Variant:");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
anchors.verticalCenter: parent.verticalCenter
width: parent.width/100*45
font: UM.Theme.fonts.default;
}
ToolButton {
id: variantSelection
text: UM.MachineManager.activeMachineVariant
width: parent.width/100*55
height: UM.Theme.sizes.setting_control.height
tooltip: UM.MachineManager.activeMachineInstance;
anchors.right: parent.right
anchors.rightMargin: UM.Theme.sizes.default_margin.width
anchors.verticalCenter: parent.verticalCenter
style: UM.Theme.styles.sidebar_header_button
menu: Menu
{
id: variantsSelectionMenu
Instantiator
{
model: UM.MachineVariantsModel { }
MenuItem
{
text: model.name;
checkable: true;
checked: model.active;
exclusiveGroup: variantSelectionMenuGroup;
onTriggered: UM.MachineManager.setActiveMachineVariant(model.getItem(index).name)
}
}
ExclusiveGroup { id: variantSelectionMenuGroup; }
}
}
}
}
Rectangle{
id: globalProfileRow;
height: UM.Theme.sizes.sidebar_setup.height
width: base.width
Label{
id: globalProfileLabel
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
anchors.verticalCenter: parent.verticalCenter
text: catalog.i18nc("@label","Global Profile:");
width: parent.width/100*45
font: UM.Theme.fonts.default;
}
ToolButton {
id: globalProfileSelection
text: UM.MachineManager.activeProfile
width: parent.width/100*55
height: UM.Theme.sizes.setting_control.height
anchors.right: parent.right
anchors.rightMargin: UM.Theme.sizes.default_margin.width
anchors.verticalCenter: parent.verticalCenter
tooltip: UM.MachineManager.activeProfile
style: UM.Theme.styles.sidebar_header_button
menu: Menu
{
id: profileSelectionMenu
Instantiator
{
model: UM.ProfilesModel { }
MenuItem
{
text: model.name
checkable: true;
checked: model.active;
exclusiveGroup: profileSelectionMenuGroup;
onTriggered: UM.MachineManager.setActiveProfile(model.name)
}
onObjectAdded: profileSelectionMenu.insertItem(index, object)
onObjectRemoved: profileSelectionMenu.removeItem(object)
}
ExclusiveGroup { id: profileSelectionMenuGroup; }
MenuSeparator { }
MenuItem {
action: base.manageProfilesAction;
}
}
// Button {
// id: saveProfileButton
// visible: true
// anchors.top: parent.top
// x: globalProfileSelection.width + 2
// width: parent.width/100*25
// text: catalog.i18nc("@action:button", "Save");
// height: parent.height
//
// style: ButtonStyle {
// background: Rectangle {
// color: control.hovered ? UM.Theme.colors.load_save_button_hover : UM.Theme.colors.load_save_button
// Behavior on color { ColorAnimation { duration: 50; } }
// width: actualLabel.width + UM.Theme.sizes.default_margin.width
// Label {
// id: actualLabel
// anchors.centerIn: parent
// color: UM.Theme.colors.load_save_button_text
// font: UM.Theme.fonts.default
// text: control.text;
// }
// }
// label: Item { }
// }
// }
}
}
Rectangle{
width: base.width
height: UM.Theme.sizes.default_margin.width/2
}
}

View File

@ -14,171 +14,249 @@ Rectangle {
property real progress: UM.Backend.progress; property real progress: UM.Backend.progress;
property bool activity: Printer.getPlatformActivity; property bool activity: Printer.getPlatformActivity;
Behavior on progress { NumberAnimation { duration: 250; } } Behavior on progress { NumberAnimation { duration: 250; } }
property int totalHeight: childrenRect.height
property string fileBaseName
property variant activeMachineInstance: UM.MachineManager.activeMachineInstance
onActiveMachineInstanceChanged:
{
base.createFileName()
}
UM.I18nCatalog { id: catalog; name:"cura"}
property variant printDuration: PrintInformation.currentPrintTime; property variant printDuration: PrintInformation.currentPrintTime;
property real printMaterialAmount: PrintInformation.materialAmount; property real printMaterialAmount: PrintInformation.materialAmount;
Rectangle{ function createFileName(){
id: background var splitMachineName = UM.MachineManager.activeMachineInstance.split(" ")
implicitWidth: base.width; var abbrMachine = ''
implicitHeight: parent.height; for (var i = 0; i < splitMachineName.length; i++){
color: UM.Theme.colors.save_button_background; if (splitMachineName[i].search(/ultimaker/i) != -1){
border.width: UM.Theme.sizes.save_button_border.width abbrMachine += 'UM'
border.color: UM.Theme.colors.save_button_border }
else{
if (splitMachineName[i].charAt(0).search(/[0-9]/g) == -1)
abbrMachine += splitMachineName[i].charAt(0)
}
var regExpAdditives = /[0-9\+]/g;
var resultAdditives = splitMachineName[i].match(regExpAdditives);
if (resultAdditives != null){
for (var j = 0; j < resultAdditives.length; j++){
abbrMachine += resultAdditives[j]
Rectangle {
id: infoBox
width: parent.width - UM.Theme.sizes.default_margin.width * 2;
height: UM.Theme.sizes.save_button_slicing_bar.height
anchors.top: parent.top
anchors.topMargin: UM.Theme.sizes.default_margin.height;
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
border.width: UM.Theme.sizes.save_button_border.width
border.color: UM.Theme.colors.save_button_border
color: UM.Theme.colors.save_button_estimated_text_background;
Label {
id: label;
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width;
visible: base.progress >= 0 && base.progress < 0.99 ? false : true
color: UM.Theme.colors.save_button_estimated_text;
font: UM.Theme.fonts.small;
text: {
if(base.activity == false) {
//: Save button label
return qsTr("Please load a 3D model");
} else if (base.progress < 0.99) {
//: Save button label
return qsTr("Calculating Print-time");
} else if (base.printDuration.days > 0 || base.progress == null){
return qsTr("");
} }
else if (base.progress > 0.99){
//: Save button label
return qsTr("Estimated Print-time");
}
return "";
} }
} }
Label { printJobTextfield.text = abbrMachine + '_' + base.fileBaseName
id: printDurationLabel }
anchors.verticalCenter: parent.verticalCenter
anchors.left: label.right; Connections {
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width; target: openDialog
color: UM.Theme.colors.save_button_printtime_text; onHasMesh: {
font: UM.Theme.fonts.small; base.fileBaseName = name
visible: base.activity == false || base.progress < 0.99 ? false : true base.createFileName()
text: (!base.printDuration || !base.printDuration.valid) ? "" : base.printDuration.getDisplayString(UM.DurationFormat.Long); }
}
Rectangle{
id: printJobRow
implicitWidth: base.width;
implicitHeight: UM.Theme.sizes.sidebar_header.height
anchors.top: parent.top
color: UM.Theme.colors.sidebar_header_bar
Label{
id: printJobTextfieldLabel
text: catalog.i18nc("@label:textbox", "Printjob Name");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
anchors.verticalCenter: parent.verticalCenter
font: UM.Theme.fonts.default;
color: UM.Theme.colors.text_white
}
TextField {
id: printJobTextfield
anchors.right: parent.right
anchors.rightMargin: UM.Theme.sizes.default_margin.width;
anchors.verticalCenter: parent.verticalCenter
width: parent.width/100*55
height: UM.Theme.sizes.sidebar_inputFields.height
property int unremovableSpacing: 5
text: ''
onEditingFinished: {
if (printJobTextfield.text != ''){
printJobTextfield.focus = false
}
} }
Label { validator: RegExpValidator {
id: printMaterialLabel regExp: /^[^\\ \/ \.]*$/
anchors.verticalCenter: parent.verticalCenter }
anchors.left: printDurationLabel.right; style: TextFieldStyle{
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width; textColor: UM.Theme.colors.setting_control_text;
color: base.printDuration.days > 0 ? UM.Theme.colors.save_button_estimated_text : UM.Theme.colors.save_button_printtime_text; font: UM.Theme.fonts.default;
font: UM.Theme.fonts.small; background: Rectangle {
property bool mediumLengthDuration: base.printDuration.hours > 9 && base.printMaterialAmount > 9.99 && base.printDuration.days == 0 radius: 0
width: mediumLengthDuration ? 50 : undefined implicitWidth: parent.width
elide: mediumLengthDuration ? Text.ElideRight : Text.ElideNone implicitHeight: parent.height
visible: base.activity == false || base.progress < 0.99 ? false : true border.width: 1;
//: Print material amount save button label border.color: UM.Theme.colors.slider_groove_border;
text: base.printMaterialAmount < 0 ? "" : qsTr("%1m of Material").arg(base.printMaterialAmount); }
} }
} }
Rectangle { }
id: infoBoxOverlay
anchors { Rectangle {
left: infoBox.left; id: specsRow
top: infoBox.top; implicitWidth: base.width
bottom: infoBox.bottom; implicitHeight: UM.Theme.sizes.sidebar_specs_bar.height
anchors.top: printJobRow.bottom
Item{
id: time
width: childrenRect.width;
height: parent.height
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width
anchors.top: parent.top
visible: base.printMaterialAmount > 0 ? true : false
UM.RecolorImage {
id: timeIcon
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
width: UM.Theme.sizes.save_button_specs_icons.width
height: UM.Theme.sizes.save_button_specs_icons.height
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.colors.text_hover
source: UM.Theme.icons.print_time;
}
Label{
id: timeSpec
anchors.verticalCenter: parent.verticalCenter
anchors.left: timeIcon.right
anchors.leftMargin: UM.Theme.sizes.default_margin.width/2
font: UM.Theme.fonts.default
color: UM.Theme.colors.text
text: (!base.printDuration || !base.printDuration.valid) ? "" : base.printDuration.getDisplayString(UM.DurationFormat.Short)
} }
width: Math.max(infoBox.width * base.progress);
color: UM.Theme.colors.save_button_active
visible: progress > 0.99 ? false : true
} }
Item{
width: parent.width / 100 * 55
height: parent.height
anchors.left: time.right
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
anchors.top: parent.top
visible: base.printMaterialAmount > 0 ? true : false
UM.RecolorImage {
id: lengthIcon
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
width: UM.Theme.sizes.save_button_specs_icons.width
height: UM.Theme.sizes.save_button_specs_icons.height
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.colors.text_hover
source: UM.Theme.icons.category_material;
}
Label{
id: lengthSpec
anchors.verticalCenter: parent.verticalCenter
anchors.left: lengthIcon.right
anchors.leftMargin: UM.Theme.sizes.default_margin.width/2
font: UM.Theme.fonts.default
color: UM.Theme.colors.text
text: base.printMaterialAmount <= 0 ? "" : catalog.i18nc("@label %1 is length of filament","%1 m").arg(base.printMaterialAmount)
}
}
}
Rectangle{
id: saveRow
width: base.width
height: saveToButton.height + (UM.Theme.sizes.default_margin.height / 2) // height + bottomMargin
anchors.top: specsRow.bottom
anchors.left: parent.left
Button { Button {
id: saveToButton id: saveToButton
anchors.top: infoBox.bottom property int resizedWidth
anchors.topMargin: UM.Theme.sizes.save_button_text_margin.height; x: base.width - saveToButton.resizedWidth - UM.Theme.sizes.default_margin.width - UM.Theme.sizes.save_button_save_to_button.height
anchors.left: parent.left tooltip: UM.OutputDeviceManager.activeDeviceDescription;
anchors.leftMargin: UM.Theme.sizes.default_margin.width; enabled: base.progress > 0.99 && base.activity == true
tooltip: devicesModel.activeDevice.description;
enabled: progress > 0.99 && base.activity == true
width: infoBox.width/6*4.5
height: UM.Theme.sizes.save_button_save_to_button.height height: UM.Theme.sizes.save_button_save_to_button.height
width: 150
text: devicesModel.activeDevice.short_description; anchors.top:parent.top
text: UM.OutputDeviceManager.activeDeviceShortDescription
onClicked:
{
UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice)
}
style: ButtonStyle { style: ButtonStyle {
background: Rectangle { background: Rectangle {
color: !control.enabled ? UM.Theme.colors.save_button_inactive : control.hovered ? UM.Theme.colors.save_button_active_hover : UM.Theme.colors.save_button_active; color: control.hovered ? UM.Theme.colors.load_save_button_hover : UM.Theme.colors.load_save_button
Behavior on color { ColorAnimation { duration: 50; } }
width: {
var w = 0;
if (base.width*0.55 > actualLabel.width + (UM.Theme.sizes.default_margin.width * 2)){
saveToButton.resizedWidth = base.width*0.55
w = base.width*0.55
}
else {
saveToButton.resizedWidth = actualLabel.width + (UM.Theme.sizes.default_margin.width * 2)
w = actualLabel.width + (UM.Theme.sizes.default_margin.width * 2)
}
if(w < base.width * 0.55) {
w = base.width * 0.55;
}
return w;
}
Label { Label {
id: actualLabel
anchors.centerIn: parent anchors.centerIn: parent
color: UM.Theme.colors.save_button_safe_to_text; color: UM.Theme.colors.load_save_button_text
font: UM.Theme.fonts.sidebar_save_to; font: UM.Theme.fonts.default
text: control.text; text: control.text;
} }
} }
label: Item { } label: Item { }
} }
onClicked: devicesModel.requestWriteToDevice(devicesModel.activeDevice.id)
} }
Button { Button {
id: deviceSelectionMenu; id: deviceSelectionMenu
anchors.top: infoBox.bottom tooltip: catalog.i18nc("@info:tooltip","Select the active output device");
anchors.topMargin: UM.Theme.sizes.save_button_text_margin.height anchors.top:parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: UM.Theme.sizes.default_margin.width; anchors.rightMargin: UM.Theme.sizes.default_margin.width
width: UM.Theme.sizes.save_button_save_to_button.height
tooltip: qsTr("Select the active output device");
width: infoBox.width/6*1.3 - UM.Theme.sizes.save_button_text_margin.height;
height: UM.Theme.sizes.save_button_save_to_button.height height: UM.Theme.sizes.save_button_save_to_button.height
//iconSource: UM.Theme.icons[UM.OutputDeviceManager.activeDeviceIconName];
iconSource: UM.Theme.icons[devicesModel.activeDevice.icon_name];
style: ButtonStyle { style: ButtonStyle {
background: Rectangle { background: Rectangle {
color: UM.Theme.colors.save_button_background; id: deviceSelectionIcon
border.width: control.hovered ? UM.Theme.sizes.save_button_border.width : 0 color: control.hovered ? UM.Theme.colors.load_save_button_hover : UM.Theme.colors.load_save_button
border.color: UM.Theme.colors.save_button_border Behavior on color { ColorAnimation { duration: 50; } }
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width / 2;
width: parent.height
height: parent.height
Rectangle { UM.RecolorImage {
id: deviceSelectionIcon id: lengthIcon
color: UM.Theme.colors.save_button_background; anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.horizontalCenter: parent.horizontalCenter
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width / 2; width: UM.Theme.sizes.standard_arrow.width
anchors.verticalCenter: parent.verticalCenter; height: UM.Theme.sizes.standard_arrow.height
width: parent.height - UM.Theme.sizes.save_button_text_margin.width ; sourceSize.width: width
height: parent.height - UM.Theme.sizes.save_button_text_margin.width; sourceSize.height: width
color: UM.Theme.colors.load_save_button_text
UM.RecolorImage { source: UM.Theme.icons.arrow_bottom
anchors.fill: parent;
sourceSize.width: width;
sourceSize.height: height;
color: UM.Theme.colors.save_button_active
source: control.iconSource;
}
}
Label {
id: deviceSelectionArrow
anchors.right: parent.right;
anchors.rightMargin: UM.Theme.sizes.save_button_text_margin.height
anchors.verticalCenter: parent.verticalCenter;
text: "▼";
font: UM.Theme.fonts.tiny;
color: UM.Theme.colors.save_button_active;
} }
} }
label: Item { } label: Label{ }
} }
menu: Menu { menu: Menu {
@ -188,10 +266,10 @@ Rectangle {
MenuItem { MenuItem {
text: model.description text: model.description
checkable: true; checkable: true;
checked: model.id == devicesModel.activeDevice.id; checked: model.id == UM.OutputDeviceManager.activeDevice;
exclusiveGroup: devicesMenuGroup; exclusiveGroup: devicesMenuGroup;
onTriggered: { onTriggered: {
devicesModel.setActiveDevice(model.id); UM.OutputDeviceManager.setActiveDevice(model.id);
} }
} }
onObjectAdded: devicesMenu.insertItem(index, object) onObjectAdded: devicesMenu.insertItem(index, object)
@ -200,9 +278,6 @@ Rectangle {
ExclusiveGroup { id: devicesMenuGroup; } ExclusiveGroup { id: devicesMenuGroup; }
} }
} }
} UM.OutputDevicesModel { id: devicesModel; }
UM.OutputDevicesModel {
id: devicesModel;
} }
} }

View File

@ -6,110 +6,122 @@ import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import UM 1.0 as UM import UM 1.1 as UM
Rectangle { Rectangle
{
id: base; id: base;
property Action addMachineAction; property Action addMachineAction;
property Action configureMachinesAction; property Action configureMachinesAction;
property Action manageProfilesAction;
color: UM.Theme.colors.sidebar; color: UM.Theme.colors.sidebar;
UM.I18nCatalog { id: catalog; name:"cura"}
function showTooltip(item, position, text) { function showTooltip(item, position, text)
{
tooltip.text = text; tooltip.text = text;
position = item.mapToItem(base, position.x, position.y / 2); position = item.mapToItem(base, position.x, position.y / 2);
tooltip.show(position); tooltip.show(position);
} }
function hideTooltip() { function hideTooltip()
{
tooltip.hide(); tooltip.hide();
} }
MouseArea { MouseArea
{
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.AllButtons; acceptedButtons: Qt.AllButtons;
onWheel: { onWheel:
{
wheel.accepted = true; wheel.accepted = true;
} }
} }
ColumnLayout { SidebarHeader {
anchors.fill: parent; id: header
anchors.topMargin: UM.Theme.sizes.default_margin.height; width: parent.width
height: totalHeightHeader
spacing: UM.Theme.sizes.default_margin.height; addMachineAction: base.addMachineAction;
configureMachinesAction: base.configureMachinesAction;
modesModel: modesListModel;
SidebarHeader { currentModeIndex:
id: header; {
var index = parseInt(UM.Preferences.getValue("cura/active_mode"))
Layout.fillWidth: true; if(index)
addMachineAction: base.addMachineAction;
configureMachinesAction: base.configureMachinesAction;
modesModel: modesListModel;
currentModeIndex: {
var index = parseInt(UM.Preferences.getValue("cura/active_mode"))
if(index) {
return index;
}
return 0;
}
onCurrentModeIndexChanged: UM.Preferences.setValue("cura/active_mode", currentModeIndex);
}
Loader {
id: sidebarContents;
Layout.fillWidth: true;
Layout.fillHeight: true;
source: modesListModel.get(header.currentModeIndex).file;
property Item sidebar: base;
onLoaded:
{ {
if(item) return index;
}
return 0;
}
onCurrentModeIndexChanged: UM.Preferences.setValue("cura/active_mode", currentModeIndex);
}
ProfileSetup {
id: profileItem
manageProfilesAction: base.manageProfilesAction
anchors.top: header.bottom
width: parent.width
height: totalHeightProfileSetup
}
Loader
{
id: sidebarContents;
anchors.bottom: saveButton.top
anchors.top: profileItem.bottom
anchors.left: base.left
anchors.right: base.right
source: modesListModel.count > header.currentModeIndex ? modesListModel.get(header.currentModeIndex).file : "";
property Item sidebar: base;
onLoaded:
{
if(item)
{
item.configureSettings = base.configureMachinesAction;
if(item.onShowTooltip != undefined)
{ {
item.configureSettings = base.configureMachinesAction; item.showTooltip.connect(base.showTooltip)
if(item.onShowTooltip != undefined) }
{ if(item.onHideTooltip != undefined)
item.showTooltip.connect(base.showTooltip) {
} item.hideTooltip.connect(base.hideTooltip)
if(item.onHideTooltip != undefined)
{
item.hideTooltip.connect(base.hideTooltip)
}
} }
} }
} }
SaveButton {
id: saveButton;
implicitWidth: base.width
implicitHeight: UM.Theme.sizes.save_button_text_margin.height * 2 + UM.Theme.sizes.save_button_slicing_bar.height + UM.Theme.sizes.save_button_save_to_button.height + UM.Theme.sizes.default_margin.height
}
} }
SidebarTooltip { SaveButton
{
id: saveButton;
implicitWidth: base.width
implicitHeight: totalHeight
anchors.bottom: parent.bottom
}
SidebarTooltip
{
id: tooltip; id: tooltip;
} }
ListModel { ListModel
{
id: modesListModel; id: modesListModel;
//: Simple configuration mode option
ListElement { text: QT_TR_NOOP("Simple"); file: "SidebarSimple.qml" }
//: Advanced configuration mode option
ListElement { text: QT_TR_NOOP("Advanced"); file: "SidebarAdvanced.qml" }
} }
Component.onCompleted: { Component.onCompleted:
for(var i = 0; i < modesListModel.count; ++i) {
{ modesListModel.append({ text: catalog.i18nc("@title:tab", "Simple"), file: "SidebarSimple.qml" })
modesListModel.setProperty(i, "text", qsTr(modesListModel.get(i).text)); modesListModel.append({ text: catalog.i18nc("@title:tab", "Advanced"), file: "SidebarAdvanced.qml" })
} sidebarContents.setSource(modesListModel.get(header.currentModeIndex).file)
} }
} }

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