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)
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")
if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
@ -10,13 +12,11 @@ if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
# Build Translations
find_package(Gettext)
include(${URANIUM_SCRIPTS_DIR}/ECMPoQmTools.cmake)
if(GETTEXT_FOUND)
# 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
# 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
# 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
@ -33,29 +33,27 @@ if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
it
es
fi
pl
cs
bg
)
foreach(lang ${languages})
file(GLOB po_files resources/i18n/${lang}/*.po)
foreach(file ${po_files})
string(REGEX MATCH "qt\\.po$" match "${file}")
if(match)
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()
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})
endforeach()
file(GLOB qm_files ${CMAKE_BINARY_DIR}/${lang}/*.qm)
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}...")
endforeach()
install(FILES ${mo_files} DESTINATION ${CMAKE_INSTALL_DATADIR}/uranium/resources/i18n/${lang}/LC_MESSAGES/)
endforeach()
endif()
endif()
include(GNUInstallDirs)
find_package(PythonInterp 3.4.0 REQUIRED)
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
-------------
[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
----------------------------------

View File

@ -5,7 +5,7 @@ GenericName=3D Printing Software
Comment=
Exec=/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
Type=Application
Categories=Graphics;

View File

@ -10,6 +10,7 @@ from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Math.Vector import Vector
from UM.Math.Color import Color
from UM.Math.AxisAlignedBox import AxisAlignedBox
from UM.Math.Polygon import Polygon
import numpy
@ -33,15 +34,18 @@ class BuildVolume(SceneNode):
self.setCalculateBoundingBox(False)
self._active_instance = None
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveInstanceChanged)
self._onActiveInstanceChanged()
def setWidth(self, width):
self._width = width
if width: self._width = width
def setHeight(self, height):
self._height = height
if height: self._height = height
def setDepth(self, depth):
self._depth = depth
if depth: self._depth = depth
def getDisallowedAreas(self):
return self._disallowed_areas
@ -55,12 +59,12 @@ class BuildVolume(SceneNode):
if not self._material:
self._material = renderer.createMaterial(
Resources.getPath(Resources.ShadersLocation, "basic.vert"),
Resources.getPath(Resources.ShadersLocation, "vertexcolor.frag")
Resources.getPath(Resources.Shaders, "basic.vert"),
Resources.getPath(Resources.Shaders, "vertexcolor.frag")
)
self._grid_material = renderer.createMaterial(
Resources.getPath(Resources.ShadersLocation, "basic.vert"),
Resources.getPath(Resources.ShadersLocation, "grid.frag")
Resources.getPath(Resources.Shaders, "basic.vert"),
Resources.getPath(Resources.Shaders, "grid.frag")
)
self._grid_material.setUniformValue("u_gridColor0", Color(245, 245, 245, 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))
settings = Application.getInstance().getActiveMachine()
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(
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
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_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):
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
self._profile = None
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
self._onActiveProfileChanged()
def getConvexHull(self):
return self._convex_hull
@ -61,4 +53,20 @@ class ConvexHullDecorator(SceneNodeDecorator):
def setConvexHullNode(self, 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
mesh = self._node.getMeshData()
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))
# 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.
# This is done because of rounding errors.
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"):
# Printing one at a time and it's not an object in a group
self._node.callDecoration("setConvexHullBoundary", copy.deepcopy(hull))
head_hull = hull.getMinkowskiHull(Polygon(numpy.array(settings.getSettingValueByKey("machine_head_with_fans_polygon"),numpy.float32)))
self._node.callDecoration("setConvexHullHead", head_hull)
hull = hull.getMinkowskiHull(Polygon(numpy.array(settings.getSettingValueByKey("machine_head_polygon"),numpy.float32)))
profile = Application.getInstance().getMachineManager().getActiveProfile()
if profile:
if profile.getSettingValue("print_sequence") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"):
# Printing one at a time and it's not an object in a group
self._node.callDecoration("setConvexHullBoundary", copy.deepcopy(hull))
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())
self._node.callDecoration("setConvexHullNode", hull_node)
self._node.callDecoration("setConvexHull", hull)
@ -66,4 +70,3 @@ class ConvexHullJob(Job):
hull_node = self._node.getParent().callDecoration("getConvexHullNode")
if hull_node:
hull_node.setParent(None)

View File

@ -22,22 +22,33 @@ class ConvexHullNode(SceneNode):
self._inherit_orientation = False
self._inherit_scale = False
self._color = Color(35, 35, 35, 0.5)
self._node = node
self._node.transformationChanged.connect(self._onNodePositionChanged)
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
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.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:
mesh.addVertex(point[0], 0.1, point[1])
indices = []
for i in range(len(hull_points) - 1):
indices.append([0, i + 1, i + 2])
@ -45,35 +56,43 @@ class ConvexHullNode(SceneNode):
indices.append([0, mesh.getVertexCount() - 1, 1])
mesh.addIndices(numpy.array(indices, numpy.int32))
self.setMeshData(mesh)
return mesh
def getWatchedNode(self):
return self._node
def render(self, renderer):
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():
self._material.setUniformValue("u_color", self._color)
renderer.queueNode(self, material = self._material, transparent = True)
if self.convexHullHeadMesh:
renderer.queueNode(self, material = self._material,transparent = True, mesh = self.convexHullHeadMesh)
return True
def _onNodePositionChanged(self, node):
#self.setPosition(node.getWorldPosition())
if node.callDecoration("getConvexHull"):
node.callDecoration("setConvexHull", None)
node.callDecoration("setConvexHullNode", None)
self.setParent(None)
#self._node.transformationChanged.disconnect(self._onNodePositionChanged)
#self._node.parentChanged.disconnect(self._onNodeParentChanged)
def _onNodeParentChanged(self, node):
if node.getParent():
self.setParent(self._original_parent)
else:
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 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 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.setWindowTitle("Oops!")
dialog.setWindowTitle(catalog.i18nc("@title:window", "Oops!"))
layout = QVBoxLayout(dialog)
label = QLabel(dialog)
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)
layout.addWidget(textarea)
@ -25,7 +34,7 @@ def show():
except:
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 = crash_info.format(version, platform.platform(), QT_VERSION_STR, PYQT_VERSION_STR, trace)
@ -34,8 +43,9 @@ def show():
buttons = QDialogButtonBox(QDialogButtonBox.Close, dialog)
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.helpRequested.connect(lambda: webbrowser.open("http://github.com/Ultimaker/Cura/issues"))
dialog.exec_()
sys.exit(1)

View File

@ -1,6 +1,13 @@
# Copyright (c) 2015 Ultimaker B.V.
# 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.Scene.SceneNode import SceneNode
from UM.Scene.Camera import Camera
@ -38,26 +45,32 @@ from . import PrintInformation
from . import CuraActions
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.QtQml import qmlRegisterUncreatableType
import platform
import sys
import os
import os.path
import configparser
import numpy
import copy
numpy.seterr(all="ignore")
class CuraApplication(QtApplication):
class ResourceTypes:
QmlFiles = Resources.UserType + 1
Firmware = Resources.UserType + 2
Q_ENUMS(ResourceTypes)
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"):
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([
"CuraEngineBackend",
@ -78,12 +91,19 @@ class CuraApplication(QtApplication):
self._previous_active_tool = None
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_mode", "simple")
Preferences.getInstance().addPreference("cura/recent_files", "")
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)
@ -115,7 +135,12 @@ class CuraApplication(QtApplication):
def run(self):
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()
@ -125,7 +150,7 @@ class CuraApplication(QtApplication):
t = controller.getTool("TranslateTool")
if t:
t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.ZAxis])
t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis,ToolHandle.ZAxis])
Selection.selectionChanged.connect(self.onSelectionChanged)
@ -149,33 +174,34 @@ class CuraApplication(QtApplication):
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()
if self.getMachines():
active_machine_pref = Preferences.getInstance().getValue("cura/active_machine")
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:
manager = self.getMachineManager()
if not self.getMachineManager().getMachineInstances():
self.requestAddPrinter.emit()
if self._engine.rootObjects:
self.closeSplash()
for file in self.getCommandLineOption("file", []):
job = ReadMeshJob(os.path.abspath(file))
job.finished.connect(self._onFileLoaded)
job.start()
self._openFile(file)
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):
engine.rootContext().setContextProperty("Printer", self)
self._print_information = PrintInformation.PrintInformation()
@ -183,6 +209,8 @@ class CuraApplication(QtApplication):
self._cura_actions = CuraActions.CuraActions(self)
engine.rootContext().setContextProperty("CuraActions", self._cura_actions)
qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type")
def onSelectionChanged(self):
if Selection.hasSelection():
if not self.getController().getActiveTool():
@ -191,10 +219,10 @@ class CuraApplication(QtApplication):
self._previous_active_tool = None
else:
self.getController().setActiveTool("TranslateTool")
self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin())
self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition())
self._camera_animation.start()
if Preferences.getInstance().getValue("view/center_on_select"):
self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin())
self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition())
self._camera_animation.start()
else:
if self.getController().getActiveTool():
self._previous_active_tool = self.getController().getActiveTool().getPluginId()
@ -209,24 +237,15 @@ class CuraApplication(QtApplication):
def getPlatformActivity(self):
return self._platform_activity
@pyqtSlot(bool)
def setPlatformActivity(self, activity):
##Sets the _platform_activity variable on true or false depending on whether there is a mesh on the platform
if activity == True:
self._platform_activity = activity
elif activity == False:
nodes = []
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData():
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
def updatePlatformActivity(self, node = None):
count = 0
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData():
continue
count += 1
self._platform_activity = True if count > 0 else False
self.activityChanged.emit()
## Remove an object from the scene
@ -247,7 +266,6 @@ class CuraApplication(QtApplication):
group_node = group_node.getParent()
op = RemoveSceneNodeOperation(group_node)
op.push()
self.setPlatformActivity(False)
## Create a number of copies of existing object.
@pyqtSlot("quint64", int)
@ -260,22 +278,26 @@ class CuraApplication(QtApplication):
if node:
op = GroupedOperation()
for i in range(count):
new_node = SceneNode()
new_node.setMeshData(node.getMeshData())
new_node.setScale(node.getScale())
new_node.translate(Vector((i + 1) * node.getBoundingBox().width, 0, 0))
new_node.setSelectable(True)
op.addOperation(AddSceneNodeOperation(new_node, node.getParent()))
if node.getParent() and node.getParent().callDecoration("isGroup"):
new_node = copy.deepcopy(node.getParent()) #Copy the group node.
new_node.callDecoration("setConvexHull",None)
op.addOperation(AddSceneNodeOperation(new_node,node.getParent().getParent()))
else:
new_node = copy.deepcopy(node)
new_node.callDecoration("setConvexHull", None)
op.addOperation(AddSceneNodeOperation(new_node, node.getParent()))
op.push()
## Center object on platform.
@pyqtSlot("quint64")
def centerObject(self, 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
node = Selection.getSelectedObject(0)
if node:
op = SetTransformOperation(node, Vector())
op.push()
@ -285,8 +307,12 @@ class CuraApplication(QtApplication):
def deleteAll(self):
nodes = []
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
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:
op = GroupedOperation()
@ -295,22 +321,28 @@ class CuraApplication(QtApplication):
op.addOperation(RemoveSceneNodeOperation(node))
op.push()
self.setPlatformActivity(False)
## Reset all translation on nodes with mesh data.
@pyqtSlot()
def resetAllTranslation(self):
nodes = []
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
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:
op = GroupedOperation()
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()
@ -319,15 +351,23 @@ class CuraApplication(QtApplication):
def resetAll(self):
nodes = []
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
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:
op = GroupedOperation()
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()
@ -387,18 +427,18 @@ class CuraApplication(QtApplication):
@pyqtSlot(str, result = "QVariant")
def getSettingValue(self, key):
if not self.getActiveMachine():
if not self.getMachineManager().getActiveProfile():
return None
return self.getActiveMachine().getSettingValueByKey(key)
return self.getMachineManager().getActiveProfile().getSettingValue(key)
#return self.getActiveMachine().getSettingValueByKey(key)
## Change setting by key value pair
@pyqtSlot(str, "QVariant")
def setSettingValue(self, key, value):
if not self.getActiveMachine():
if not self.getMachineManager().getActiveProfile():
return
self.getActiveMachine().setSettingValueByKey(key, value)
self.getMachineManager().getActiveProfile().setSettingValue(key, value)
@pyqtSlot()
def mergeSelected(self):
@ -412,7 +452,7 @@ class CuraApplication(QtApplication):
# Reset the position of each node
for node in group_node.getChildren():
new_position = node.getMeshData().getCenterPosition()
new_position.setY(0)
new_position = new_position.scale(node.getScale())
node.setPosition(new_position)
# 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():
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():
Selection.remove(node)
@ -446,6 +488,12 @@ class CuraApplication(QtApplication):
for child in children_to_move:
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)
child.callDecoration("setConvexHull",None)
node.setParent(None)
@ -454,37 +502,35 @@ class CuraApplication(QtApplication):
Selection.remove(node)
def _onActiveMachineChanged(self):
machine = self.getActiveMachine()
machine = self.getMachineManager().getActiveMachineInstance()
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.setHeight(machine.getSettingValueByKey("machine_height"))
self._volume.setDepth(machine.getSettingValueByKey("machine_depth"))
#self._volume.setWidth(machine.getSettingValueByKey("machine_width"))
#self._volume.setHeight(machine.getSettingValueByKey("machine_height"))
#self._volume.setDepth(machine.getSettingValueByKey("machine_depth"))
disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas")
areas = []
if disallowed_areas:
for area in disallowed_areas:
areas.append(Polygon(numpy.array(area, numpy.float32)))
#disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas")
#areas = []
#if disallowed_areas:
#for area in disallowed_areas:
#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")
if offset:
self._platform.setPosition(Vector(offset[0], offset[1], offset[2]))
else:
self._platform.setPosition(Vector(0.0, 0.0, 0.0))
#offset = machine.getSettingValueByKey("machine_platform_offset")
#if offset:
#self._platform.setPosition(Vector(offset[0], offset[1], offset[2]))
#else:
#self._platform.setPosition(Vector(0.0, 0.0, 0.0))
def _onFileLoaded(self, job):
mesh = job.getResult()
if mesh != None:
node = SceneNode()
node = job.getResult()
if node != None:
node.setSelectable(True)
node.setMeshData(mesh)
node.setName(os.path.basename(job.getFileName()))
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
@ -510,4 +556,16 @@ class CuraApplication(QtApplication):
self.recentFilesChanged.emit()
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.
from UM.Scene.Iterator import Iterator
from UM.Scene.SceneNode import SceneNode
from functools import cmp_to_key
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)
class OneAtATimeIterator(Iterator.Iterator):
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._original_node_list = []
def _fillStack(self):
node_list = []
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
if node.callDecoration("getConvexHull"):
node_list.append(node)
@ -55,7 +59,7 @@ class OneAtATimeIterator(Iterator.Iterator):
# We have no more nodes to check, so quit looking.
todo_node_list = None
self._node_stack = new_order
print(self._node_stack)
return
todo_node_list.append(_objectOrder(new_order, new_todo_list))
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.Iterator.BreadthFirstIterator import BreadthFirstIterator
from UM.Operations.TranslateOperation import TranslateOperation
from UM.Operations.ScaleToBoundsOperation import ScaleToBoundsOperation
from UM.Math.Float import Float
from UM.Math.Vector import Vector
from UM.Math.AxisAlignedBox import AxisAlignedBox
from UM.Application import Application
from UM.Scene.Selection import Selection
from UM.Preferences import Preferences
from cura.ConvexHullDecorator import ConvexHullDecorator
from . import PlatformPhysicsOperation
@ -19,6 +20,7 @@ from . import ConvexHullJob
import time
import threading
import copy
class PlatformPhysics:
def __init__(self, controller, volume):
@ -36,6 +38,8 @@ class PlatformPhysics:
self._change_timer.setSingleShot(True)
self._change_timer.timeout.connect(self._onChangeTimerFinished)
Preferences.getInstance().addPreference("physics/automatic_push_free", True)
def _onSceneChanged(self, source):
self._change_timer.start()
@ -53,16 +57,22 @@ class PlatformPhysics:
self._change_timer.start()
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.
if self._build_volume.getBoundingBox().intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
node._outside_buildarea = True
else:
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()
if not Float.fuzzyCompare(bbox.bottom, 0.0):
move_vector.setY(-bbox.bottom)
if not (node.getParent() and node.getParent().callDecoration("isGroup")): #If an object is grouped, don't move it down
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 not node.getDecorator(ConvexHullDecorator):
@ -76,7 +86,7 @@ class PlatformPhysics:
elif Selection.isSelected(node):
pass
else:
elif Preferences.getInstance().getValue("physics/automatic_push_free"):
# Check for collisions between convex hulls
for other_node in BreadthFirstIterator(root):
# Ignore root, ourselves and anything that is not a normal SceneNode.
@ -88,27 +98,41 @@ class PlatformPhysics:
continue
# Ignore colissions within a group
if other_node.getParent().callDecoration("isGroup") is not None:
if node.getParent().callDecoration("isGroup") is other_node.getParent().callDecoration("isGroup"):
continue
if other_node.getParent().callDecoration("isGroup") is not None or node.getParent().callDecoration("isGroup") is not None:
continue
#if node.getParent().callDecoration("isGroup") is other_node.getParent().callDecoration("isGroup"):
# continue
# Ignore nodes that do not have the right properties set.
if not other_node.callDecoration("getConvexHull") or not other_node.getBoundingBox():
continue
# 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:
continue
#if node.getBoundingBox().intersectsBox(other_node.getBoundingBox()) == AxisAlignedBox.IntersectionResult.NoIntersection:
# continue
# 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:
continue
move_vector.setX(overlap[0] * 1.1)
move_vector.setZ(overlap[1] * 1.1)
move_vector.setX(overlap[0] * 1.01)
move_vector.setZ(overlap[1] * 1.01)
convex_hull = node.callDecoration("getConvexHull")
if convex_hull:
if not convex_hull.isValid():
return
# Check for collisions between disallowed areas and the object
for area in self._build_volume.getDisallowedAreas():
overlap = convex_hull.intersectsPolygon(area)

View File

@ -40,48 +40,13 @@ class PrintInformation(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self._enabled = False
self._minimum_print_time = Duration(None, self)
self._current_print_time = Duration(None, self)
self._maximum_print_time = Duration(None, self)
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()
if self._backend:
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()
@ -89,145 +54,18 @@ class PrintInformation(QObject):
def currentPrintTime(self):
return self._current_print_time
maximumPrintTimeChanged = pyqtSignal()
@pyqtProperty(Duration, notify = maximumPrintTimeChanged)
def maximumPrintTime(self):
return self._maximum_print_time
materialAmountChanged = pyqtSignal()
@pyqtProperty(float, notify = materialAmountChanged)
def materialAmount(self):
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):
if self._slice_pass == self.SlicePass.CurrentSettings:
self._current_print_time.setDuration(time)
self.currentPrintTimeChanged.emit()
#if self._slice_pass == self.SlicePass.CurrentSettings:
self._current_print_time.setDuration(time)
self.currentPrintTimeChanged.emit()
# Material amount is sent as an amount of mm^3, so calculate length from that
r = self._current_settings.getSettingValueByKey("material_diameter") / 2
self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2)
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
# Material amount is sent as an amount of mm^3, so calculate length from that
r = Application.getInstance().getMachineManager().getActiveProfile().getSettingValue("material_diameter") / 2
self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2)
self.materialAmountChanged.emit()

View File

@ -3,12 +3,15 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
try:
import cura.CuraApplication
import sys
app = cura.CuraApplication.CuraApplication.getInstance()
app.run()
except Exception as e:
def exceptHook(type, value, traceback):
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
!define VERSION '15.05.97'
!define VERSION '15.09.80'
!endif
; The name of the installer
@ -45,7 +45,7 @@ SetCompressor /SOLID lzma
!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink"
;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
;!insertmacro MUI_PAGE_WELCOME
@ -111,24 +111,24 @@ Section "Install Visual Studio 2010 Redistributable"
SectionEnd
;Section "Install Arduino Drivers"
; ; Set output path to the driver directory.
; SetOutPath "$INSTDIR\drivers\"
; File /r "drivers\"
;
; ${If} ${RunningX64}
; IfSilent +2
; ExecWait '"$INSTDIR\drivers\dpinst64.exe" /lm'
; ${Else}
; IfSilent +2
; ExecWait '"$INSTDIR\drivers\dpinst32.exe" /lm'
; ${EndIf}
;SectionEnd
Section "Install Arduino Drivers"
; Set output path to the driver directory.
SetOutPath "$INSTDIR\drivers\"
File /r "drivers\"
${If} ${RunningX64}
IfSilent +2
ExecWait '"$INSTDIR\drivers\dpinst64.exe" /lm'
${Else}
IfSilent +2
ExecWait '"$INSTDIR\drivers\dpinst32.exe" /lm'
${EndIf}
SectionEnd
Section "Open STL files with Cura"
WriteRegStr HKCR .stl "" "Cura STL model file"
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\command" "" '"$INSTDIR\Cura.exe" "%1"'
SectionEnd
@ -136,7 +136,7 @@ SectionEnd
Section /o "Open OBJ files with Cura"
WriteRegStr HKCR .obj "" "Cura OBJ model file"
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\command" "" '"$INSTDIR\Cura.exe" "%1"'
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.Logger import Logger
from UM.Resources import Resources
from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator
from UM.Message import Message
from cura.OneAtATimeIterator import OneAtATimeIterator
from . import Cura_pb2
@ -22,6 +24,9 @@ import numpy
from PyQt5.QtCore import QTimer
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
class CuraEngineBackend(Backend):
def __init__(self):
super().__init__()
@ -44,9 +49,10 @@ class CuraEngineBackend(Backend):
self._onActiveViewChanged()
self._stored_layer_data = None
self._settings = None
Application.getInstance().activeMachineChanged.connect(self._onActiveMachineChanged)
self._onActiveMachineChanged()
self._profile = None
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
self._onActiveProfileChanged()
self._change_timer = QTimer()
self._change_timer.setInterval(500)
@ -68,10 +74,15 @@ class CuraEngineBackend(Backend):
self._enabled = True
self._message = None
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):
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.
# \param time The amount of time the print will take.
@ -112,9 +123,9 @@ class CuraEngineBackend(Backend):
pass
self.slicingCancelled.emit()
return
Logger.log("d", "Preparing to send slice data to engine.")
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()):
temp_list = []
children = node.getAllChildren()
@ -130,6 +141,7 @@ class CuraEngineBackend(Backend):
if not getattr(node, "_outside_buildarea", False):
temp_list.append(node)
if len(temp_list) == 0:
self.processingProgress.emit(0.0)
return
object_groups.append(temp_list)
#for node in DepthFirstIterator(self._scene.getRoot()):
@ -138,19 +150,39 @@ class CuraEngineBackend(Backend):
# objects.append(node)
if len(object_groups) == 0:
if self._message:
self._message.hide()
self._message = None
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.
# 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.slicingStarted.emit()
self._report_progress = kwargs.get("report_progress", True)
if self._report_progress:
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()
@ -178,7 +210,14 @@ class CuraEngineBackend(Backend):
verts[:,1] *= -1
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()
Logger.log("d", "Sending data to engine for slicing.")
self._socket.sendMessage(slice_message)
def _onSceneChanged(self, source):
@ -190,13 +229,13 @@ class CuraEngineBackend(Backend):
self._onChanged()
def _onActiveMachineChanged(self):
if self._settings:
self._settings.settingChanged.disconnect(self._onSettingChanged)
def _onActiveProfileChanged(self):
if self._profile:
self._profile.settingValueChanged.disconnect(self._onSettingChanged)
self._settings = Application.getInstance().getActiveMachine()
if self._settings:
self._settings.settingChanged.connect(self._onSettingChanged)
self._profile = Application.getInstance().getMachineManager().getActiveProfile()
if self._profile:
self._profile.settingValueChanged.connect(self._onSettingChanged)
self._onChanged()
def _onSettingChanged(self, setting):
@ -214,6 +253,14 @@ class CuraEngineBackend(Backend):
if message.amount >= 0.99:
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:
self.processingProgress.emit(message.amount)
@ -241,18 +288,22 @@ class CuraEngineBackend(Backend):
self._socket.registerMessageType(6, Cura_pb2.SettingList)
self._socket.registerMessageType(7, Cura_pb2.GCodePrefix)
## Manually triggers a reslice
def forceSlice(self):
self._change_timer.start()
def _onChanged(self):
if not self._settings:
if not self._profile:
return
self._change_timer.start()
def _sendSettings(self, settings):
def _sendSettings(self, profile):
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.name = setting.getKey()
s.value = str(setting.getValue()).encode("utf-8")
s.name = key
s.value = str(value).encode("utf-8")
self._socket.sendMessage(msg)
@ -262,10 +313,10 @@ class CuraEngineBackend(Backend):
self._restart = False
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):
self._enabled = True
self._enabled = True # Tool stop, start listening for changes again.
self._onChanged()
def _onActiveViewChanged(self):
@ -278,3 +329,20 @@ class CuraEngineBackend(Backend):
job.start()
else:
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(
name='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)
@ -65,8 +65,8 @@ _POLYGON_TYPE = _descriptor.EnumDescriptor(
],
containing_type=None,
options=None,
serialized_start=583,
serialized_end=720,
serialized_start=622,
serialized_end=759,
)
_sym_db.RegisterEnumDescriptor(_POLYGON_TYPE)
@ -85,6 +85,13 @@ _OBJECTLIST = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=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=[
],
@ -97,7 +104,7 @@ _OBJECTLIST = _descriptor.Descriptor(
oneofs=[
],
serialized_start=26,
serialized_end=75,
serialized_end=114,
)
@ -126,8 +133,8 @@ _SLICE = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=77,
serialized_end=130,
serialized_start=116,
serialized_end=169,
)
@ -184,8 +191,8 @@ _OBJECT = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=132,
serialized_end=243,
serialized_start=171,
serialized_end=282,
)
@ -214,8 +221,8 @@ _PROGRESS = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=245,
serialized_end=271,
serialized_start=284,
serialized_end=310,
)
@ -244,8 +251,8 @@ _SLICEDOBJECTLIST = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=273,
serialized_end=334,
serialized_start=312,
serialized_end=373,
)
@ -281,8 +288,8 @@ _SLICEDOBJECT = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=336,
serialized_end=397,
serialized_start=375,
serialized_end=436,
)
@ -332,8 +339,8 @@ _LAYER = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=399,
serialized_end=492,
serialized_start=438,
serialized_end=531,
)
@ -377,8 +384,8 @@ _POLYGON = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=495,
serialized_end=720,
serialized_start=534,
serialized_end=759,
)
@ -414,8 +421,8 @@ _GCODELAYER = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=722,
serialized_end=760,
serialized_start=761,
serialized_end=799,
)
@ -458,8 +465,8 @@ _OBJECTPRINTTIME = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=762,
serialized_end=830,
serialized_start=801,
serialized_end=869,
)
@ -488,8 +495,8 @@ _SETTINGLIST = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=832,
serialized_end=884,
serialized_start=871,
serialized_end=923,
)
@ -525,8 +532,8 @@ _SETTING = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=886,
serialized_end=924,
serialized_start=925,
serialized_end=963,
)
@ -555,11 +562,12 @@ _GCODEPREFIX = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=926,
serialized_end=953,
serialized_start=965,
serialized_end=992,
)
_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
_OBJECT.fields_by_name['settings'].message_type = _SETTING
_SLICEDOBJECTLIST.fields_by_name['objects'].message_type = _SLICEDOBJECT

View File

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

View File

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

View File

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

View File

@ -27,7 +27,7 @@ class ProcessSlicedObjectListJob(Job):
def run(self):
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()
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
@ -43,18 +43,15 @@ class ProcessSlicedObjectListJob(Job):
else:
objectIdMap[id(node)] = node
settings = Application.getInstance().getActiveMachine()
layerHeight = settings.getSettingValueByKey("layer_height")
settings = Application.getInstance().getMachineManager().getActiveProfile()
layerHeight = settings.getSettingValue("layer_height")
center = None
if not settings.getSettingValueByKey("machine_center_is_zero"):
center = numpy.array([settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2])
if not settings.getSettingValue("machine_center_is_zero"):
center = numpy.array([settings.getSettingValue("machine_width") / 2, 0.0, -settings.getSettingValue("machine_depth") / 2])
else:
center = numpy.array([0.0, 0.0, 0.0])
if self._progress:
self._progress.setProgress(2)
mesh = MeshData()
layer_data = LayerData.LayerData()
for object in self._message.objects:
@ -80,14 +77,10 @@ class ProcessSlicedObjectListJob(Job):
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
layer_data.build()
if self._progress:
self._progress.setProgress(100)
#Add layerdata decorator to scene node to indicate that the node has layerdata
decorator = LayerDataDecorator.LayerDataDecorator()
@ -108,7 +101,7 @@ class ProcessSlicedObjectListJob(Job):
if self.isRunning():
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
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()
else:
if self._progress:

View File

@ -10,9 +10,9 @@ catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": "CuraEngine Backend",
"name": catalog.i18nc("@label", "CuraEngine Backend"),
"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
}
}

View File

@ -9,17 +9,17 @@ catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": "GCode Writer",
"name": catalog.i18nc("@label", "GCode Writer"),
"author": "Ultimaker",
"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
},
"mesh_writer": {
"output": [{
"extension": "gcode",
"description": catalog.i18nc("GCode Writer File Description", "GCode File"),
"description": catalog.i18nc("@item:inlistbox", "GCode File"),
"mime_type": "text/x-gcode",
"mode": GCodeWriter.GCodeWriter.OutputMode.TextMode
}]

View File

@ -13,6 +13,8 @@ from UM.Mesh.MeshData import MeshData
from cura.ConvexHullNode import ConvexHullNode
from PyQt5 import QtCore, QtWidgets
from . import LayerViewProxy
## View used to display g-code paths.
@ -52,10 +54,10 @@ class LayerView(View):
renderer.setRenderSelection(False)
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._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))
for node in DepthFirstIterator(scene.getRoot()):
@ -92,9 +94,11 @@ class LayerView(View):
layer = self._current_layer_num - i
if layer < 0:
continue
layer_mesh = layer_data.getLayer(layer).createMesh()
if not layer_mesh or layer_mesh.getVertices() is None:
try:
layer_mesh = layer_data.getLayer(layer).createMesh()
if not layer_mesh or layer_mesh.getVertices() is None:
continue
except:
continue
self._current_layer_mesh.addVertices(layer_mesh.getVertices())
@ -160,8 +164,12 @@ class LayerView(View):
pass
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:
self.setLayer(self._current_layer_num + 1)
return True
if event.key == KeyEvent.DownKey:
self.setLayer(self._current_layer_num - 1)
return True

View File

@ -19,7 +19,7 @@ Item
width: 10
height: 250
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
minimumValue: 0;
maximumValue: UM.LayerView.numLayers;
@ -38,14 +38,16 @@ Item
height: UM.Theme.sizes.slider_layerview_background_extension.height
color: UM.Theme.colors.slider_text_background
}
UM.AngledCornerRectangle {
Rectangle {
anchors.right : parent.right
anchors.verticalCenter: parent.verticalCenter
z: slider.z - 1
cornerSize: UM.Theme.sizes.default_margin.width;
width: UM.Theme.sizes.slider_layerview_background.width
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 {
id: sliderMouseArea
property double manualStepSize: slider.maximumValue / 11

View File

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

View File

@ -10,14 +10,14 @@ catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": "Layer View",
"name": catalog.i18nc("@label", "Layer View"),
"author": "Ultimaker",
"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
},
"view": {
"name": catalog.i18nc("Layers View mode", "Layers"),
"name": catalog.i18nc("@item:inlistbox", "Layers"),
"view_panel": "LayerView.qml"
}
}

View File

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

View File

@ -10,15 +10,15 @@ from UM.OutputDevice.OutputDevice import OutputDevice
from UM.OutputDevice import OutputDeviceError
from UM.i18n import i18nCatalog
catalog = i18nCatalog("uranium")
catalog = i18nCatalog("cura")
class RemovableDriveOutputDevice(OutputDevice):
def __init__(self, device_id, device_name):
super().__init__(device_id)
self.setName(device_name)
self.setShortDescription(catalog.i18nc("", "Save to Removable Drive"))
self.setDescription(catalog.i18nc("", "Save to Removable Drive {0}").format(device_name))
self.setShortDescription(catalog.i18nc("@action:button", "Save to Removable Drive"))
self.setDescription(catalog.i18nc("@item:inlistbox", "Save to Removable Drive {0}").format(device_name))
self.setIconName("save_sd")
self.setPriority(1)
@ -49,7 +49,7 @@ class RemovableDriveOutputDevice(OutputDevice):
job.progress.connect(self._onProgress)
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()
job._message = message
@ -70,13 +70,13 @@ class RemovableDriveOutputDevice(OutputDevice):
job._message = None
self.writeFinished.emit(self)
if job.getResult():
message = Message(catalog.i18nc("", "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 = 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("@action:button", "Eject"), "eject", catalog.i18nc("@action", "Eject removable device {0}").format(self.getName()))
message.actionTriggered.connect(self._onActionTriggered)
message.show()
self.writeSuccess.emit(self)
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()
self.writeError.emit(self)
job.getStream().close()

View File

@ -11,7 +11,7 @@ from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from . import RemovableDriveOutputDevice
from UM.i18n import i18nCatalog
catalog = i18nCatalog("uranium")
catalog = i18nCatalog("cura")
class RemovableDrivePlugin(OutputDevicePlugin):
def __init__(self):
@ -39,10 +39,10 @@ class RemovableDrivePlugin(OutputDevicePlugin):
def ejectDevice(self, device):
result = self.performEjectDevice(device)
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()
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()
def performEjectDevice(self, device):

View File

@ -16,7 +16,7 @@ import os
import subprocess
from UM.i18n import i18nCatalog
catalog = i18nCatalog("uranium")
catalog = i18nCatalog("cura")
# WinAPI Constants that we need
# 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
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
# "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
# 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
else:
result = True
# Finally, close the handle
windll.kernel32.CloseHandle(handle)

View File

@ -4,14 +4,14 @@
import platform
from UM.i18n import i18nCatalog
catalog = i18nCatalog("uranium")
catalog = i18nCatalog("cura")
def getMetaData():
return {
"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.",
"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",
"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.Window 2.1
import UM 1.0 as UM
import UM 1.1 as UM
UM.Dialog {
UM.Dialog
{
width: 500 * Screen.devicePixelRatio;
height: 100 * Screen.devicePixelRatio;
modality: Qt.NonModal
title: "Print with USB"
title: catalog.i18nc("@title:window", "Print with USB")
Column
{
@ -23,18 +25,20 @@ UM.Dialog {
Text
{
//: 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
{
//: 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: "" + manager.error
}
UM.I18nCatalog{id: catalog; name:"cura"}
}
ProgressBar
@ -50,16 +54,17 @@ UM.Dialog {
}
rightButtons: [
Button {
Button
{
//: USB Printing dialog start print button
text: qsTr("Print");
text: catalog.i18nc("@action:button","Print");
onClicked: { manager.startPrint() }
enabled: manager.progress == 0 ? true : false
},
Button
{
//: USB Printing dialog cancel print button
text: qsTr("Cancel");
text: catalog.i18nc("@action:button","Cancel");
onClicked: { manager.cancelPrint() }
enabled: manager.progress == 0 ? false: true
}

View File

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

View File

@ -8,15 +8,34 @@ import time
import queue
import re
import functools
import os
import os.path
from UM.Application import Application
from UM.Signal import Signal, SignalEmitter
from UM.Resources import Resources
from UM.Logger import Logger
from UM.OutputDevice.OutputDevice import OutputDevice
from UM.OutputDevice import OutputDeviceError
from UM.PluginRegistry import PluginRegistry
class PrinterConnection(SignalEmitter):
def __init__(self, serial_port):
super().__init__()
from PyQt5.QtQuick import QQuickView
from PyQt5.QtQml import QQmlComponent, QQmlContext
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_port = serial_port
@ -25,6 +44,9 @@ class PrinterConnection(SignalEmitter):
self._connect_thread = threading.Thread(target = self._connect)
self._connect_thread.daemon = True
self._end_stop_thread = threading.Thread(target = self._pollEndStop)
self._end_stop_thread.deamon = True
# Printer is connected
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
# 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
@ -41,7 +63,7 @@ class PrinterConnection(SignalEmitter):
self._listen_thread.daemon = True
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()
@ -78,6 +100,14 @@ class PrinterConnection(SignalEmitter):
# Current Z stage location
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.
# This index is the extruder we requested data from the last time.
self._temperature_requested_extruder_index = 0
@ -86,6 +116,31 @@ class PrinterConnection(SignalEmitter):
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
def setNumExtuders(self, num):
self._extruder_count = num
@ -98,11 +153,18 @@ class PrinterConnection(SignalEmitter):
return False
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.
# \param gcode_list List with gcode (strings).
def printGCode(self, gcode_list):
if self.isPrinting() or not self._is_connected:
Logger.log("d", "Printer is busy or not connected, aborting print")
self.writeError.emit(self)
return
self._gcode.clear()
@ -119,6 +181,8 @@ class PrinterConnection(SignalEmitter):
for i in range(0, 4): #Push first 4 entries before accepting other inputs
self._sendNextGcodeLine()
self.writeFinished.emit(self)
## Get the serial port string of this connection.
# \return serial port
def getSerialPort(self):
@ -162,6 +226,8 @@ class PrinterConnection(SignalEmitter):
self.setProgress(100, 100)
self.firmwareUpdateComplete.emit()
## Upload new firmware to machine
# \param filename full path of firmware file to be uploaded
def updateFirmware(self, file_name):
@ -169,6 +235,20 @@ class PrinterConnection(SignalEmitter):
self._firmware_file_name = file_name
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.
def _connect(self):
Logger.log("d", "Attempting to connect to %s", self._serial_port)
@ -182,29 +262,24 @@ class PrinterConnection(SignalEmitter):
except Exception as e:
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.
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:
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:
Logger.log("i", "Could not open port %s" % self._serial_port)
return
#Logger.log("i", "Could not open port %s" % self._serial_port)
continue
else:
if not self.setBaudRate(baud_rate):
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
sucesfull_responses = 0
timeout_time = time.time() + 15
timeout_time = time.time() + 5
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
while timeout_time > time.time():
line = self._readline()
if line is None:
@ -213,7 +288,6 @@ class PrinterConnection(SignalEmitter):
if b"T:" in line:
self._serial.timeout = 0.5
self._sendCommand("M105")
sucesfull_responses += 1
if sucesfull_responses >= self._required_responses_auto_baud:
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)
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)
self.close() # Unable to connect, wrap up.
self.setIsConnected(False)
@ -240,15 +316,6 @@ class PrinterConnection(SignalEmitter):
self.connectionStateChanged.emit(self._serial_port)
if self._is_connected:
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:
Logger.log("w", "Printer connection state was not changed")
@ -262,6 +329,9 @@ class PrinterConnection(SignalEmitter):
except Exception as e:
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:
self.setIsConnected(False)
try:
@ -270,11 +340,32 @@ class PrinterConnection(SignalEmitter):
pass
self._serial.close()
self._listen_thread = threading.Thread(target=self._listen)
self._listen_thread.daemon = True
self._serial = None
def isConnected(self):
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).
# \param cmd string with g-code
def _sendCommand(self, cmd):
@ -296,10 +387,9 @@ class PrinterConnection(SignalEmitter):
self._target_bed_temperature = float(re.search("S([0-9]+)", cmd).group(1))
except:
pass
#Logger.log("i","Sending: %s" % (cmd))
try:
command = (cmd + "\n").encode()
#self._serial.write(b"\n")
self._serial.write(b"\n")
self._serial.write(command)
except serial.SerialTimeoutException:
Logger.log("w","Serial timeout while writing to serial port, trying again.")
@ -319,6 +409,21 @@ class PrinterConnection(SignalEmitter):
def __del__(self):
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.
# \param cmd string with g-code
def sendCommand(self, cmd):
@ -331,9 +436,7 @@ class PrinterConnection(SignalEmitter):
# \param error String with the error message.
def _setErrorState(self, error):
self._error_state = error
self.onError.emit(error)
onError = Signal()
self.onError.emit()
## Private function to set the temperature of an extruder
# \param index index of the extruder
@ -341,21 +444,33 @@ class PrinterConnection(SignalEmitter):
def _setExtruderTemperature(self, index, temperature):
try:
self._extruder_temperatures[index] = temperature
self.onExtruderTemperatureChange.emit(self._serial_port, index, temperature)
self.extruderTemperatureChanged.emit()
except Exception as e:
pass
onExtruderTemperatureChange = Signal()
## Private function to set the temperature of the bed.
# As all printers (as of time of writing) only support a single heated bed,
# these are not indexed as with extruders.
def _setBedTemperature(self, 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.
def _listen(self):
@ -368,6 +483,14 @@ class PrinterConnection(SignalEmitter):
if line is None:
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:"):
# Oh YEAH, consistency.
# 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:
pass
#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 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:
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._gcode_position += 1
self.setProgress(( self._gcode_position / len(self._gcode)) * 100)
self.progressChanged.emit(self._progress, self._serial_port)
progressChanged = Signal()
self.progressChanged.emit()
## Set the progress of the print.
# It will be normalized (based on max_progress) to range 0 - 100
def setProgress(self, progress, max_progress = 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.
@pyqtSlot()
def cancelPrint(self):
self._gcode_position = 0
self.setProgress(0)
@ -494,5 +611,12 @@ class PrinterConnection(SignalEmitter):
## Create a list of baud rates at which we can communicate.
# \return list of int
def _getBaudrateList(self):
ret = [250000, 230400, 115200, 57600, 38400, 19200, 9600]
ret = [115200, 250000, 230400, 57600, 38400, 19200, 9600]
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.Logger import Logger
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 platform
@ -22,37 +26,50 @@ from UM.Extension import Extension
from PyQt5.QtQuick import QQuickView
from PyQt5.QtQml import QQmlComponent, QQmlContext
from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtProperty, pyqtSignal, Qt
from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura")
class USBPrinterManager(QObject, SignalEmitter, Extension):
class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
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._printer_connections = []
self._check_ports_thread = threading.Thread(target = self._updateConnectionList)
self._check_ports_thread.daemon = True
self._check_ports_thread.start()
self._printer_connections = {}
self._printer_connections_model = None
self._update_thread = threading.Thread(target = self._updateThread)
self._update_thread.setDaemon(True)
self._progress = 0
self._control_view = None
self._check_updates = True
self._firmware_view = None
self._extruder_temp = 0
self._bed_temp = 0
self._error_message = ""
## Add menu item to top menu of the application.
self.setMenuName("Firmware")
self.addMenuItem(i18n_catalog.i18n("Update Firmware"), self.updateAllFirmware)
self.setMenuName(i18n_catalog.i18nc("@title:menu","Firmware"))
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"])
processingProgress = pyqtSignal(float, arguments = ["amount"])
pyqtExtruderTemperature = pyqtSignal(float, arguments = ["amount"])
pyqtBedTemperature = pyqtSignal(float, arguments = ["amount"])
addConnectionSignal = Signal()
printerConnectionStateChanged = pyqtSignal()
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.
# This will create the view if its not already created.
@ -67,80 +84,38 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
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):
self.spawnFirmwareInterface("")
for printer_connection in self._printer_connections:
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:
continue
@pyqtSlot(str, result = bool)
def updateFirmwareBySerial(self, serial_port):
printer_connection = self.getConnectionByPort(serial_port)
if printer_connection is not None:
self.spawnFirmwareInterface(printer_connection.getSerialPort())
printer_connection.updateFirmware(Resources.getPath(Resources.FirmwareLocation, self._getDefaultFirmwareName()))
if serial_port in self._printer_connections:
self.spawnFirmwareInterface(self._printer_connections[serial_port].getSerialPort())
try:
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):
machine_type = Application.getInstance().getActiveMachine().getTypeID()
machine_type = Application.getInstance().getMachineManager().getActiveMachineInstance().getMachineDefinition().getId()
firmware_name = ""
baudrate = 250000
if sys.platform.startswith("linux"):
@ -165,115 +140,41 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
firmware_name += ".hex"
return firmware_name
## Callback for extruder temperature change
def onExtruderTemperature(self, serial_port, index, temperature):
self._extruder_temp = temperature
self.pyqtExtruderTemperature.emit(temperature)
def _addRemovePorts(self, serial_ports):
# First, find and add all new or changed keys
for serial_port in list(serial_ports):
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
def onBedTemperature(self, serial_port,temperature):
self._bed_temp = temperature
self.pyqtBedTemperature.emit(temperature)
## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
def addConnection(self, serial_port):
connection = PrinterConnection.PrinterConnection(serial_port)
connection.connect()
connection.connectionStateChanged.connect(self._onPrinterConnectionStateChanged)
self._printer_connections[serial_port] = connection
## Callback for error
def onError(self, error):
self._error_message = error if type(error) is str else error.decode("utf-8")
self.pyqtError.emit(self._error_message)
def _onPrinterConnectionStateChanged(self, serial_port):
if self._printer_connections[serial_port].isConnected():
self.getOutputDeviceManager().addOutputDevice(self._printer_connections[serial_port])
else:
self.getOutputDeviceManager().removeOutputDevice(serial_port)
self.printerConnectionStateChanged.emit()
## Callback for progress change
def onProgress(self, progress, serial_port):
self._progress = progress
self.processingProgress.emit(progress)
## Attempt to connect with all possible connections.
def connectAllConnections(self):
@pyqtProperty(QObject , notify = printerConnectionStateChanged)
def connectedPrinterList(self):
self._printer_connections_model = ListModel()
self._printer_connections_model.addRoleName(Qt.UserRole + 1,"name")
self._printer_connections_model.addRoleName(Qt.UserRole + 2, "printer")
for connection in self._printer_connections:
connection.connect()
## Send gcode to printer and start printing
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
if self._printer_connections[connection].isConnected():
self._printer_connections_model.appendItem({"name":connection, "printer": self._printer_connections[connection]})
return self._printer_connections_model
## Create a list of serial ports on the system.
# \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 = []
if platform.system() == "Windows":
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
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/*")
return base_list
return list(base_list)
def _onApplicationShuttingDown(self):
for connection in self._printer_connections:
connection.close()
_instance = None

View File

@ -2,7 +2,7 @@
# Cura is released under the terms of the AGPLv3 or higher.
from . import USBPrinterManager
from PyQt5.QtQml import qmlRegisterType, qmlRegisterSingletonType
from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura")
@ -10,12 +10,14 @@ def getMetaData():
return {
"type": "extension",
"plugin": {
"name": "USB printing",
"name": i18n_catalog.i18nc("@label", "USB printing"),
"author": "Ultimaker",
"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):
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",
"version": 1,
"name": "German RepRap Neo",
"manufacturer": "German RepRap",
"manufacturer": "Other",
"author": "other",
"icon": "icon_ultimaker.png",
"platform": "grr_neo_platform.stl",
@ -21,8 +21,6 @@
"machine_head_shape_max_x": { "default": 18 },
"machine_head_shape_max_y": { "default": 35 },
"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_start_gcode": {
@ -33,13 +31,7 @@
}
},
"categories": {
"material": {
"settings": {
"material_bed_temperature": {
"visible": false
}
}
}
"overrides": {
"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_y": { "default": 35 },
"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_start_gcode": {
@ -32,13 +30,7 @@
}
},
"categories": {
"material": {
"settings": {
"material_bed_temperature": {
"visible": true
}
}
}
"overrides": {
"material_bed_temperature": { "visible": true }
}
}

View File

@ -10,6 +10,26 @@
"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_start_gcode" : { "default": "" },
"machine_end_gcode" : { "default": "" },
@ -18,15 +38,31 @@
"machine_height": { "default": 205 },
"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_nozzle_size": { "default": 0.4 },
"machine_head_shape_min_x": { "default": 40 },
"machine_head_shape_min_y": { "default": 10 },
"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 },
"gantry_height": { "default": 55 },
"machine_use_extruder_offset_to_offset_coords": { "default": true },
"machine_gcode_flavor": { "default": "UltiGCode" },
"machine_disallowed_areas": { "default": [
[[-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 }
},
"categories": {
"material": {
"settings": {
"material_print_temperature": {
"visible": false
},
"material_bed_temperature": {
"visible": false
},
"material_diameter": {
"visible": false
},
"material_flow": {
"visible": false
}
}
}
"overrides": {
"material_print_temperature": { "enabled": "False" },
"material_bed_temperature": { "enabled": "False" },
"material_diameter": { "enabled": "False" },
"material_flow": { "enabled": "False" }
}
}

View File

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

View File

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

View File

@ -9,43 +9,72 @@
"inherits": "fdmprinter.json",
"add_pages": [
{"page": "SelectUpgradedParts", "title": "Select Upgraded Parts"},
{"page": "UpgradeFirmware", "title": "Upgrade Ultimaker Firmware"},
{"page": "UltimakerCheckup", "title": "Ultimaker Checkup"},
{"page": "Bedleveling", "title": "Bedleveling Wizard"}
"pages": [
"SelectUpgradedParts",
"UpgradeFirmware",
"UltimakerCheckup",
"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_width": { "default": 205 },
"machine_height": { "default": 200 },
"machine_depth": { "default": 205 },
"machine_center_is_zero": { "default": false },
"machine_nozzle_size": { "default": 0.4 },
"machine_head_shape_min_x": { "default": 75 },
"machine_head_shape_min_y": { "default": 18 },
"machine_head_shape_max_x": { "default": 18 },
"machine_head_shape_max_y": { "default": 35 },
"machine_nozzle_gantry_distance": { "default": 55 },
"machine_nozzle_offset_x_1": { "default": 18.0 },
"machine_nozzle_offset_y_1": { "default": 0.0 },
"machine_head_with_fans_polygon":
{
"default": [
[
-75,
35
],
[
-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_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": {
"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": {
"material": {
"settings": {
"material_bed_temperature": {
"visible": false
}
}
}
"overrides": {
"material_bed_temperature": { "visible": false }
}
}

View File

@ -10,6 +10,12 @@
"inherits": "ultimaker_original.json",
"pages": [
"UpgradeFirmware",
"UltimakerCheckup",
"BedLeveling"
],
"machine_settings": {
"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.Window 2.1
import UM 1.0 as UM
import UM 1.1 as UM
UM.Dialog {
UM.Dialog
{
id: base
//: About dialog title
title: qsTr("About Cura")
title: catalog.i18nc("@title:window","About Cura")
minimumWidth: 400
minimumHeight: 300
minimumHeight: 300;
//UM.I18nCatalog { id: catalog; }
Image {
Image
{
id: logo
width: parent.width * 0.75
height: width * (1/4.25)
@ -26,9 +30,11 @@ UM.Dialog {
sourceSize.height: height
anchors.centerIn: parent
anchors.verticalCenterOffset : -(height * 0.5)
UM.I18nCatalog{id: catalog; name:"cura"}
}
Label {
Label
{
id: version
text: "Cura %1".arg(UM.Application.version)
@ -39,30 +45,33 @@ UM.Dialog {
anchors.topMargin : 5
}
Label {
Label
{
id: description
width: parent.width
//: 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
anchors.top: version.bottom
anchors.topMargin : 10
}
Label {
Label
{
id: author_note
width: parent.width
//: 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
anchors.top: description.bottom
}
rightButtons: Button {
rightButtons: Button
{
//: Close about dialog button
text: qsTr("Close");
text: catalog.i18nc("@action:button","Close");
onClicked: base.visible = false;
}

View File

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

View File

@ -6,11 +6,27 @@ import QtQuick.Controls 1.1
import QtQuick.Layouts 1.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{
id: base
property bool printer: true
file: "ultimaker2.json"
firstRun: printer ? false : true
import "WizardPages"
UM.Wizard
{
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
UM.MainWindow {
UM.MainWindow
{
id: base
visible: true
//: 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;
anchors.fill: parent;
UM.ApplicationMenu {
UM.I18nCatalog{id: catalog; name:"cura"}
UM.ApplicationMenu
{
id: menu
window: base
Menu {
Menu
{
id: fileMenu
//: File menu
title: qsTr("&File");
title: catalog.i18nc("@title:menu","&File");
MenuItem { action: actions.open; }
MenuItem {
action: actions.open;
}
Menu {
Menu
{
id: recentFilesMenu;
title: "Open Recent"
title: catalog.i18nc("@title:menu", "Open &Recent")
iconName: "document-open-recent";
enabled: Printer.recentFiles.length > 0;
Instantiator {
Instantiator
{
model: Printer.recentFiles
MenuItem {
text: {
MenuItem
{
text:
{
var path = modelData.toString()
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)
onObjectRemoved: recentFilesMenu.removeItem(object)
@ -54,52 +67,66 @@ UM.MainWindow {
MenuSeparator { }
MenuItem {
text: "Save Selection to File";
MenuItem
{
text: catalog.i18nc("@action:inmenu", "&Save Selection to File");
enabled: UM.Selection.hasSelection;
iconName: "document-save-as";
onTriggered: devicesModel.requestWriteSelectionToDevice("local_file");
onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file");
}
Menu {
Menu
{
id: saveAllMenu
title: "Save All"
iconName: "document-save";
enabled: devicesModel.count > 0 && UM.Backend.progress > 0.99;
title: catalog.i18nc("@title:menu","Save &All")
iconName: "document-save-all";
enabled: devicesModel.rowCount() > 0 && UM.Backend.progress > 0.99;
Instantiator {
Instantiator
{
model: UM.OutputDevicesModel { id: devicesModel; }
MenuItem {
text: model.description
onTriggered: devicesModel.requestWriteToDevice(model.id);
MenuItem
{
text: model.description;
onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id);
}
onObjectAdded: saveAllMenu.insertItem(index, object)
onObjectRemoved: saveAllMenu.removeItem(object)
}
}
MenuItem { action: actions.reloadAll; }
MenuSeparator { }
MenuItem { action: actions.quit; }
}
Menu {
Menu
{
//: Edit menu
title: qsTr("&Edit");
title: catalog.i18nc("@title:menu","&Edit");
MenuItem { action: actions.undo; }
MenuItem { action: actions.redo; }
MenuSeparator { }
MenuItem { action: actions.deleteSelection; }
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
{
title: qsTr("&View");
title: catalog.i18nc("@title:menu","&View");
id: top_view_menu
Instantiator
{
model: UM.Models.viewModel
model: UM.ViewModel { }
MenuItem
{
text: model.name;
@ -112,20 +139,27 @@ UM.MainWindow {
onObjectRemoved: top_view_menu.removeItem(object)
}
ExclusiveGroup { id: view_menu_top_group; }
MenuSeparator { }
MenuItem { action: actions.toggleFullScreen; }
}
Menu {
Menu
{
id: machineMenu;
//: Machine menu
title: qsTr("&Machine");
title: catalog.i18nc("@title:menu","&Machine");
Instantiator {
model: UM.Models.machinesModel
MenuItem {
Instantiator
{
model: UM.MachineInstancesModel { }
MenuItem
{
text: model.name;
checkable: true;
checked: model.active;
exclusiveGroup: machineMenuGroup;
onTriggered: UM.Models.machinesModel.setActive(index)
onTriggered: UM.MachineManager.setActiveMachineInstance(model.name)
}
onObjectAdded: machineMenu.insertItem(index, object)
onObjectRemoved: machineMenu.removeItem(object)
@ -135,14 +169,59 @@ UM.MainWindow {
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.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
//: Extensions menu
title: qsTr("E&xtensions");
title: catalog.i18nc("@title:menu","E&xtensions");
Instantiator
{
@ -152,7 +231,8 @@ UM.MainWindow {
{
id: sub_menu
title: model.name;
visible: actions != null
enabled:actions != null
Instantiator
{
model: actions
@ -171,16 +251,18 @@ UM.MainWindow {
}
}
Menu {
Menu
{
//: Settings menu
title: qsTr("&Settings");
title: catalog.i18nc("@title:menu","&Settings");
MenuItem { action: actions.preferences; }
}
Menu {
Menu
{
//: Help menu
title: qsTr("&Help");
title: catalog.i18nc("@title:menu","&Help");
MenuItem { action: actions.showEngineLog; }
MenuItem { action: actions.documentation; }
@ -190,7 +272,8 @@ UM.MainWindow {
}
}
Item {
Item
{
id: contentItem;
y: menu.height
@ -199,23 +282,31 @@ UM.MainWindow {
Keys.forwardTo: menu
DropArea {
DropArea
{
anchors.fill: parent;
onDropped: {
if(drop.urls.length > 0) {
for(var i in drop.urls) {
onDropped:
{
if(drop.urls.length > 0)
{
for(var i in drop.urls)
{
UM.MeshFileHandler.readLocalFile(drop.urls[i]);
if (i == drop.urls.length - 1)
{
openDialog.sendMeshName(drop.urls[i].toString())
}
}
}
}
}
UM.MessageStack {
anchors {
left: toolbar.right;
leftMargin: UM.Theme.sizes.window_margin.width;
right: sidebar.left;
rightMargin: UM.Theme.sizes.window_margin.width;
UM.MessageStack
{
anchors
{
horizontalCenter: parent.horizontalCenter
horizontalCenterOffset: -(UM.Theme.sizes.logo.width/ 2)
top: parent.verticalCenter;
bottom: parent.bottom;
}
@ -240,27 +331,34 @@ UM.MainWindow {
source: UM.ActiveView.valid ? UM.ActiveView.activeViewPanel : "";
}
Button {
Button
{
id: openFileButton;
iconSource: UM.Theme.icons.open;
style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button;
//style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button;
//style: UM.Theme.styles.open_file_button
text: catalog.i18nc("@action:button","Open File");
iconSource: UM.Theme.icons.load
style: UM.Theme.styles.open_file_button
tooltip: '';
anchors {
anchors
{
top: parent.top;
topMargin: UM.Theme.sizes.window_margin.height;
//topMargin: UM.Theme.sizes.loadfile_margin.height
left: parent.left;
leftMargin: UM.Theme.sizes.window_margin.width;
//leftMargin: UM.Theme.sizes.loadfile_margin.width
}
action: actions.open;
}
Image {
anchors {
verticalCenter: openFileButton.verticalCenter;
left: openFileButton.right;
leftMargin: UM.Theme.sizes.window_margin.width;
Image
{
id: logo
anchors
{
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;
@ -271,25 +369,29 @@ UM.MainWindow {
sourceSize.height: height;
}
Button {
anchors {
Button
{
id: viewModeButton
property bool verticalTooltip: true
anchors
{
top: parent.top;
topMargin: UM.Theme.sizes.window_margin.height;
right: sidebar.left;
rightMargin: UM.Theme.sizes.window_margin.width;
}
id: viewModeButton
//: View Mode toolbar button
text: qsTr("View Mode");
text: catalog.i18nc("@action:button","View Mode");
iconSource: UM.Theme.icons.viewmode;
style: UM.Theme.styles.tool_button;
tooltip: '';
menu: Menu {
menu: Menu
{
id: viewMenu;
Instantiator {
model: UM.Models.viewModel;
MenuItem {
Instantiator
{
model: UM.ViewModel { }
MenuItem
{
text: model.name;
checkable: true;
checked: model.active;
@ -304,39 +406,47 @@ UM.MainWindow {
}
}
Toolbar {
Toolbar
{
id: toolbar;
anchors {
left: parent.left;
leftMargin: UM.Theme.sizes.window_margin.width;
bottom: parent.bottom;
bottomMargin: UM.Theme.sizes.window_margin.height;
left: parent.left
top: parent.top
topMargin: 74
//horizontalCenter: parent.horizontalCenter
//horizontalCenterOffset: -(UM.Theme.sizes.sidebar.width / 2)
//top: parent.top;
}
}
Sidebar {
Sidebar
{
id: sidebar;
anchors {
anchors
{
top: parent.top;
bottom: parent.bottom;
right: parent.right;
}
width: UM.Theme.sizes.panel.width;
width: UM.Theme.sizes.sidebar.width;
addMachineAction: actions.addMachine;
configureMachinesAction: actions.configureMachines;
manageProfilesAction: actions.manageProfiles;
}
Rectangle {
Rectangle
{
x: base.mouseX + UM.Theme.sizes.default_margin.width;
y: base.mouseY + UM.Theme.sizes.default_margin.height;
width: childrenRect.width;
height: childrenRect.height;
Label {
Label
{
text: UM.ActiveTool.properties.Rotation != undefined ? "%1°".arg(UM.ActiveTool.properties.Rotation) : "";
}
@ -345,20 +455,29 @@ UM.MainWindow {
}
}
UM.PreferencesDialog {
UM.PreferencesDialog
{
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
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;
open.onTriggered: openDialog.open();
save.onTriggered: saveDialog.open();
quit.onTriggered: base.visible = false;
@ -367,28 +486,36 @@ UM.MainWindow {
redo.onTriggered: UM.OperationStack.redo();
redo.enabled: UM.OperationStack.canRedo;
deleteSelection.onTriggered: {
if(objectContextMenu.objectId != 0) {
deleteSelection.onTriggered:
{
if(objectContextMenu.objectId != 0)
{
Printer.deleteObject(objectContextMenu.objectId);
}
}
deleteObject.onTriggered: {
if(objectContextMenu.objectId != 0) {
deleteObject.onTriggered:
{
if(objectContextMenu.objectId != 0)
{
Printer.deleteObject(objectContextMenu.objectId);
objectContextMenu.objectId = 0;
}
}
multiplyObject.onTriggered: {
if(objectContextMenu.objectId != 0) {
multiplyObject.onTriggered:
{
if(objectContextMenu.objectId != 0)
{
Printer.multiplyObject(objectContextMenu.objectId, 1);
objectContextMenu.objectId = 0;
}
}
centerObject.onTriggered: {
if(objectContextMenu.objectId != 0) {
centerObject.onTriggered:
{
if(objectContextMenu.objectId != 0)
{
Printer.centerObject(objectContextMenu.objectId);
objectContextMenu.objectId = 0;
}
@ -418,94 +545,117 @@ UM.MainWindow {
preferences.onTriggered: preferences.visible = true;
configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(2); }
manageProfiles.onTriggered: { preferences.visible = true; preferences.setPage(4); }
documentation.onTriggered: CuraActions.openDocumentation();
reportBug.onTriggered: CuraActions.openBugReportPage();
showEngineLog.onTriggered: engineLog.visible = true;
about.onTriggered: aboutDialog.visible = true;
toggleFullScreen.onTriggered: base.toggleFullscreen()
}
Menu {
Menu
{
id: objectContextMenu;
property variant objectId: -1;
MenuItem { action: actions.centerObject; }
MenuItem { action: actions.deleteObject; }
MenuItem { action: actions.multiplyObject; }
MenuItem { action: actions.splitObject; }
MenuSeparator { }
MenuItem { action: actions.deleteAll; }
MenuItem { action: actions.reloadAll; }
MenuItem { action: actions.resetAllTranslation; }
MenuItem { action: actions.resetAll; }
MenuItem { action: actions.groupObjects;}
MenuItem { action: actions.unGroupObjects;}
MenuItem { action: actions.mergeObjects;}
MenuItem { action: actions.unGroupObjects;}
}
Menu {
Menu
{
id: contextMenu;
MenuItem { action: actions.deleteAll; }
MenuItem { action: actions.reloadAll; }
MenuItem { action: actions.resetAllTranslation; }
MenuItem { action: actions.resetAll; }
MenuItem { action: actions.groupObjects;}
MenuItem { action: actions.unGroupObjects;}
MenuItem { action: actions.mergeObjects;}
MenuItem { action: actions.unGroupObjects;}
}
Connections {
Connections
{
target: UM.Controller
onContextMenuRequested: {
if(objectId == 0) {
onContextMenuRequested:
{
if(objectId == 0)
{
contextMenu.popup();
} else {
} else
{
objectContextMenu.objectId = objectId;
objectContextMenu.popup();
}
}
}
FileDialog {
FileDialog
{
id: openDialog;
//: File open dialog title
title: qsTr("Open File")
title: catalog.i18nc("@title:window","Open File")
modality: UM.Application.platform == "linux" ? Qt.NonModal : Qt.WindowModal;
//TODO: Support multiple file selection, workaround bug in KDE file dialog
//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;
onAccepted:
{
UM.MeshFileHandler.readLocalFile(fileUrl)
Printer.setPlatformActivity(true)
openDialog.sendMeshName(fileUrl.toString())
}
}
EngineLog {
EngineLog
{
id: engineLog;
}
AddMachineWizard {
AddMachineWizard
{
id: addMachineWizard
}
AboutDialog {
AboutDialog
{
id: aboutDialog
}
Connections {
Connections
{
target: Printer
onRequestAddPrinter: {
onRequestAddPrinter:
{
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.Layouts 1.1
import UM 1.0 as UM
import UM 1.1 as UM
UM.Dialog {
UM.Dialog
{
id: dialog;
//: Engine Log dialog title
title: qsTr("Engine Log");
title: catalog.i18nc("@title:window","Engine Log");
modality: Qt.NonModal;
TextArea {
TextArea
{
id: textArea
anchors.fill: parent;
Timer {
Timer
{
id: updateTimer;
interval: 1000;
running: false;
repeat: true;
onTriggered: textArea.text = Printer.getEngineLog();
}
UM.I18nCatalog{id: catalog; name:"cura"}
}
rightButtons: Button {
rightButtons: Button
{
//: Close engine log button
text: qsTr("Close");
text: catalog.i18nc("@action:button","Close");
onClicked: dialog.visible = false;
}
onVisibleChanged: {
if(visible) {
onVisibleChanged:
{
if(visible)
{
textArea.text = Printer.getEngineLog();
updateTimer.start();
} else {
} else
{
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 bool activity: Printer.getPlatformActivity;
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 real printMaterialAmount: PrintInformation.materialAmount;
Rectangle{
id: background
implicitWidth: base.width;
implicitHeight: parent.height;
color: UM.Theme.colors.save_button_background;
border.width: UM.Theme.sizes.save_button_border.width
border.color: UM.Theme.colors.save_button_border
function createFileName(){
var splitMachineName = UM.MachineManager.activeMachineInstance.split(" ")
var abbrMachine = ''
for (var i = 0; i < splitMachineName.length; i++){
if (splitMachineName[i].search(/ultimaker/i) != -1){
abbrMachine += 'UM'
}
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 {
id: printDurationLabel
anchors.verticalCenter: parent.verticalCenter
anchors.left: label.right;
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width;
color: UM.Theme.colors.save_button_printtime_text;
font: UM.Theme.fonts.small;
visible: base.activity == false || base.progress < 0.99 ? false : true
text: (!base.printDuration || !base.printDuration.valid) ? "" : base.printDuration.getDisplayString(UM.DurationFormat.Long);
printJobTextfield.text = abbrMachine + '_' + base.fileBaseName
}
Connections {
target: openDialog
onHasMesh: {
base.fileBaseName = name
base.createFileName()
}
}
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 {
id: printMaterialLabel
anchors.verticalCenter: parent.verticalCenter
anchors.left: printDurationLabel.right;
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width;
color: base.printDuration.days > 0 ? UM.Theme.colors.save_button_estimated_text : UM.Theme.colors.save_button_printtime_text;
font: UM.Theme.fonts.small;
property bool mediumLengthDuration: base.printDuration.hours > 9 && base.printMaterialAmount > 9.99 && base.printDuration.days == 0
width: mediumLengthDuration ? 50 : undefined
elide: mediumLengthDuration ? Text.ElideRight : Text.ElideNone
visible: base.activity == false || base.progress < 0.99 ? false : true
//: Print material amount save button label
text: base.printMaterialAmount < 0 ? "" : qsTr("%1m of Material").arg(base.printMaterialAmount);
validator: RegExpValidator {
regExp: /^[^\\ \/ \.]*$/
}
style: TextFieldStyle{
textColor: UM.Theme.colors.setting_control_text;
font: UM.Theme.fonts.default;
background: Rectangle {
radius: 0
implicitWidth: parent.width
implicitHeight: parent.height
border.width: 1;
border.color: UM.Theme.colors.slider_groove_border;
}
}
}
Rectangle {
id: infoBoxOverlay
anchors {
left: infoBox.left;
top: infoBox.top;
bottom: infoBox.bottom;
}
Rectangle {
id: specsRow
implicitWidth: base.width
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 {
id: saveToButton
anchors.top: infoBox.bottom
anchors.topMargin: UM.Theme.sizes.save_button_text_margin.height;
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
tooltip: devicesModel.activeDevice.description;
enabled: progress > 0.99 && base.activity == true
width: infoBox.width/6*4.5
property int resizedWidth
x: base.width - saveToButton.resizedWidth - UM.Theme.sizes.default_margin.width - UM.Theme.sizes.save_button_save_to_button.height
tooltip: UM.OutputDeviceManager.activeDeviceDescription;
enabled: base.progress > 0.99 && base.activity == true
height: UM.Theme.sizes.save_button_save_to_button.height
text: devicesModel.activeDevice.short_description;
width: 150
anchors.top:parent.top
text: UM.OutputDeviceManager.activeDeviceShortDescription
onClicked:
{
UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice)
}
style: ButtonStyle {
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 {
id: actualLabel
anchors.centerIn: parent
color: UM.Theme.colors.save_button_safe_to_text;
font: UM.Theme.fonts.sidebar_save_to;
color: UM.Theme.colors.load_save_button_text
font: UM.Theme.fonts.default
text: control.text;
}
}
label: Item { }
label: Item { }
}
onClicked: devicesModel.requestWriteToDevice(devicesModel.activeDevice.id)
}
Button {
id: deviceSelectionMenu;
anchors.top: infoBox.bottom
anchors.topMargin: UM.Theme.sizes.save_button_text_margin.height
id: deviceSelectionMenu
tooltip: catalog.i18nc("@info:tooltip","Select the active output device");
anchors.top:parent.top
anchors.right: parent.right
anchors.rightMargin: UM.Theme.sizes.default_margin.width;
tooltip: qsTr("Select the active output device");
width: infoBox.width/6*1.3 - UM.Theme.sizes.save_button_text_margin.height;
anchors.rightMargin: UM.Theme.sizes.default_margin.width
width: UM.Theme.sizes.save_button_save_to_button.height
height: UM.Theme.sizes.save_button_save_to_button.height
iconSource: UM.Theme.icons[devicesModel.activeDevice.icon_name];
//iconSource: UM.Theme.icons[UM.OutputDeviceManager.activeDeviceIconName];
style: ButtonStyle {
background: Rectangle {
color: UM.Theme.colors.save_button_background;
border.width: control.hovered ? UM.Theme.sizes.save_button_border.width : 0
border.color: UM.Theme.colors.save_button_border
id: deviceSelectionIcon
color: control.hovered ? UM.Theme.colors.load_save_button_hover : UM.Theme.colors.load_save_button
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 {
id: deviceSelectionIcon
color: UM.Theme.colors.save_button_background;
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width / 2;
anchors.verticalCenter: parent.verticalCenter;
width: parent.height - UM.Theme.sizes.save_button_text_margin.width ;
height: parent.height - UM.Theme.sizes.save_button_text_margin.width;
UM.RecolorImage {
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;
UM.RecolorImage {
id: lengthIcon
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
width: UM.Theme.sizes.standard_arrow.width
height: UM.Theme.sizes.standard_arrow.height
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.colors.load_save_button_text
source: UM.Theme.icons.arrow_bottom
}
}
label: Item { }
label: Label{ }
}
menu: Menu {
@ -188,10 +266,10 @@ Rectangle {
MenuItem {
text: model.description
checkable: true;
checked: model.id == devicesModel.activeDevice.id;
checked: model.id == UM.OutputDeviceManager.activeDevice;
exclusiveGroup: devicesMenuGroup;
onTriggered: {
devicesModel.setActiveDevice(model.id);
UM.OutputDeviceManager.setActiveDevice(model.id);
}
}
onObjectAdded: devicesMenu.insertItem(index, object)
@ -200,9 +278,6 @@ Rectangle {
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.Layouts 1.1
import UM 1.0 as UM
import UM 1.1 as UM
Rectangle {
Rectangle
{
id: base;
property Action addMachineAction;
property Action configureMachinesAction;
property Action manageProfilesAction;
color: UM.Theme.colors.sidebar;
UM.I18nCatalog { id: catalog; name:"cura"}
function showTooltip(item, position, text) {
function showTooltip(item, position, text)
{
tooltip.text = text;
position = item.mapToItem(base, position.x, position.y / 2);
tooltip.show(position);
}
function hideTooltip() {
function hideTooltip()
{
tooltip.hide();
}
MouseArea {
MouseArea
{
anchors.fill: parent
acceptedButtons: Qt.AllButtons;
onWheel: {
onWheel:
{
wheel.accepted = true;
}
}
ColumnLayout {
anchors.fill: parent;
anchors.topMargin: UM.Theme.sizes.default_margin.height;
SidebarHeader {
id: header
width: parent.width
height: totalHeightHeader
spacing: UM.Theme.sizes.default_margin.height;
addMachineAction: base.addMachineAction;
configureMachinesAction: base.configureMachinesAction;
modesModel: modesListModel;
SidebarHeader {
id: header;
Layout.fillWidth: true;
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:
currentModeIndex:
{
var index = parseInt(UM.Preferences.getValue("cura/active_mode"))
if(index)
{
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;
if(item.onShowTooltip != undefined)
{
item.showTooltip.connect(base.showTooltip)
}
if(item.onHideTooltip != undefined)
{
item.hideTooltip.connect(base.hideTooltip)
}
item.showTooltip.connect(base.showTooltip)
}
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;
}
ListModel {
ListModel
{
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: {
for(var i = 0; i < modesListModel.count; ++i)
{
modesListModel.setProperty(i, "text", qsTr(modesListModel.get(i).text));
}
Component.onCompleted:
{
modesListModel.append({ text: catalog.i18nc("@title:tab", "Simple"), file: "SidebarSimple.qml" })
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