mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-06 05:23:58 -06:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
fb18cec049
123 changed files with 20817 additions and 15793 deletions
|
@ -6,6 +6,9 @@ include(GNUInstallDirs)
|
|||
|
||||
set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository")
|
||||
|
||||
set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
|
||||
configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY)
|
||||
|
||||
if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
|
||||
# Extract Strings
|
||||
add_custom_target(extract-messages ${URANIUM_SCRIPTS_DIR}/extract-messages ${CMAKE_SOURCE_DIR} cura)
|
||||
|
@ -60,9 +63,12 @@ install(DIRECTORY resources DESTINATION ${CMAKE_INSTALL_DATADIR}/cura)
|
|||
install(DIRECTORY plugins DESTINATION lib/cura)
|
||||
install(FILES cura_app.py DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
if(NOT APPLE AND NOT WIN32)
|
||||
install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages)
|
||||
install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages FILES_MATCHING PATTERN *.py)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/CuraVersion.py DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages/cura)
|
||||
install(FILES cura.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
||||
else()
|
||||
install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages)
|
||||
install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages FILES_MATCHING PATTERN *.py)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/CuraVersion.py DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages/cura)
|
||||
endif()
|
||||
|
||||
include(CPackConfig.cmake)
|
||||
|
|
16
CPackConfig.cmake
Normal file
16
CPackConfig.cmake
Normal file
|
@ -0,0 +1,16 @@
|
|||
set(CPACK_PACKAGE_VENDOR "Ultimaker B.V.")
|
||||
set(CPACK_PACKAGE_CONTACT "Arjen Hiemstra <a.hiemstra@ultimaker.com>")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Cura application to drive the CuraEngine")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 15)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 05)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 90)
|
||||
set(CPACK_PACKAGE_VERSION_REVISION 1)
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
|
||||
set(DEB_DEPENDS
|
||||
"uranium (>= 15.05.93)"
|
||||
)
|
||||
string(REPLACE ";" ", " DEB_DEPENDS "${DEB_DEPENDS}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS ${DEB_DEPENDS})
|
||||
|
||||
include(CPack)
|
|
@ -13,7 +13,7 @@ Use [this](https://github.com/Ultimaker/Uranium/wiki/Bug-Reporting-Template) tem
|
|||
For crashes and similar issues, please attach the following information:
|
||||
|
||||
* (On Windows) The log as produced by dxdiag (start -> run -> dxdiag -> save output)
|
||||
* The Cura GUI log file, located at (Windows) $User/AppData/Local/cura/cura.log, (OSX) $User/.cura/cura.log
|
||||
* The Cura GUI log file, located at (Windows) $User/AppData/Local/cura/cura.log, (OSX) $User/.cura/cura.log, (Ubuntu) $USER/.local/share/cura
|
||||
* The Cura Engine log, using Help -> Show Engine Log
|
||||
|
||||
Dependencies
|
||||
|
@ -41,6 +41,7 @@ Third party plugins
|
|||
-------------
|
||||
* [Print time calculator](https://github.com/nallath/PrintCostCalculator)
|
||||
* [Post processing plugin](https://github.com/nallath/PostProcessingPlugin)
|
||||
* [Barbarian Plugin](https://github.com/nallath/BarbarianPlugin) Simple scale tool for imperial to metric.
|
||||
|
||||
Making profiles for other printers
|
||||
----------------------------------
|
||||
|
|
|
@ -8,5 +8,6 @@ TryExec=/usr/bin/cura_app.py
|
|||
Icon=/usr/share/cura/resources/images/cura-icon.png
|
||||
Terminal=false
|
||||
Type=Application
|
||||
MimeType=application/sla
|
||||
Categories=Graphics;
|
||||
Keywords=3D;Printing;
|
||||
|
|
|
@ -12,6 +12,9 @@ from UM.Math.Color import Color
|
|||
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||
from UM.Math.Polygon import Polygon
|
||||
|
||||
from UM.View.RenderBatch import RenderBatch
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
import numpy
|
||||
|
||||
class BuildVolume(SceneNode):
|
||||
|
@ -24,20 +27,24 @@ class BuildVolume(SceneNode):
|
|||
self._height = 0
|
||||
self._depth = 0
|
||||
|
||||
self._material = None
|
||||
self._shader = None
|
||||
|
||||
self._grid_mesh = None
|
||||
self._grid_material = None
|
||||
self._grid_shader = None
|
||||
|
||||
self._disallowed_areas = []
|
||||
self._disallowed_area_mesh = None
|
||||
|
||||
self.setCalculateBoundingBox(False)
|
||||
|
||||
self._active_profile = None
|
||||
self._active_instance = None
|
||||
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveInstanceChanged)
|
||||
self._onActiveInstanceChanged()
|
||||
|
||||
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
|
||||
self._onActiveProfileChanged()
|
||||
|
||||
def setWidth(self, width):
|
||||
if width: self._width = width
|
||||
|
||||
|
@ -57,78 +64,72 @@ class BuildVolume(SceneNode):
|
|||
if not self.getMeshData():
|
||||
return True
|
||||
|
||||
if not self._material:
|
||||
self._material = renderer.createMaterial(
|
||||
Resources.getPath(Resources.Shaders, "basic.vert"),
|
||||
Resources.getPath(Resources.Shaders, "vertexcolor.frag")
|
||||
)
|
||||
self._grid_material = renderer.createMaterial(
|
||||
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))
|
||||
if not self._shader:
|
||||
self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader"))
|
||||
self._grid_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "grid.shader"))
|
||||
|
||||
renderer.queueNode(self, material = self._material, mode = Renderer.RenderLines)
|
||||
renderer.queueNode(self, mesh = self._grid_mesh, material = self._grid_material, force_single_sided = True)
|
||||
renderer.queueNode(self, mode = RenderBatch.RenderMode.Lines)
|
||||
renderer.queueNode(self, mesh = self._grid_mesh, shader = self._grid_shader, backface_cull = True)
|
||||
if self._disallowed_area_mesh:
|
||||
renderer.queueNode(self, mesh = self._disallowed_area_mesh, material = self._material)
|
||||
renderer.queueNode(self, mesh = self._disallowed_area_mesh, shader = self._shader, transparent = True, backface_cull = True, sort = -9)
|
||||
return True
|
||||
|
||||
def rebuild(self):
|
||||
if self._width == 0 or self._height == 0 or self._depth == 0:
|
||||
return
|
||||
|
||||
minW = -self._width / 2
|
||||
maxW = self._width / 2
|
||||
minH = 0.0
|
||||
maxH = self._height
|
||||
minD = -self._depth / 2
|
||||
maxD = self._depth / 2
|
||||
min_w = -self._width / 2
|
||||
max_w = self._width / 2
|
||||
min_h = 0.0
|
||||
max_h = self._height
|
||||
min_d = -self._depth / 2
|
||||
max_d = self._depth / 2
|
||||
|
||||
mb = MeshBuilder()
|
||||
|
||||
mb.addLine(Vector(minW, minH, minD), Vector(maxW, minH, minD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(minW, minH, minD), Vector(minW, maxH, minD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(minW, maxH, minD), Vector(maxW, maxH, minD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(maxW, minH, minD), Vector(maxW, maxH, minD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
|
||||
|
||||
mb.addLine(Vector(minW, minH, maxD), Vector(maxW, minH, maxD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(minW, minH, maxD), Vector(minW, maxH, maxD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(minW, maxH, maxD), Vector(maxW, maxH, maxD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(maxW, minH, maxD), Vector(maxW, maxH, maxD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
|
||||
|
||||
mb.addLine(Vector(minW, minH, minD), Vector(minW, minH, maxD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(maxW, minH, minD), Vector(maxW, minH, maxD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(minW, maxH, minD), Vector(minW, maxH, maxD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(maxW, maxH, minD), Vector(maxW, maxH, maxD), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor)
|
||||
mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
|
||||
|
||||
self.setMeshData(mb.getData())
|
||||
|
||||
mb = MeshBuilder()
|
||||
mb.addQuad(
|
||||
Vector(minW, minH, minD),
|
||||
Vector(maxW, minH, minD),
|
||||
Vector(maxW, minH, maxD),
|
||||
Vector(minW, minH, maxD)
|
||||
Vector(min_w, min_h - 0.2, min_d),
|
||||
Vector(max_w, min_h - 0.2, min_d),
|
||||
Vector(max_w, min_h - 0.2, max_d),
|
||||
Vector(min_w, min_h - 0.2, max_d)
|
||||
)
|
||||
self._grid_mesh = mb.getData()
|
||||
for n in range(0, 6):
|
||||
v = self._grid_mesh.getVertex(n)
|
||||
self._grid_mesh.setVertexUVCoordinates(n, v[0], v[2])
|
||||
|
||||
disallowed_area_height = 0.1
|
||||
disallowed_area_size = 0
|
||||
if self._disallowed_areas:
|
||||
mb = MeshBuilder()
|
||||
color = Color(0.0, 0.0, 0.0, 0.15)
|
||||
for polygon in self._disallowed_areas:
|
||||
points = polygon.getPoints()
|
||||
mb.addQuad(
|
||||
Vector(points[0, 0], 0.1, points[0, 1]),
|
||||
Vector(points[1, 0], 0.1, points[1, 1]),
|
||||
Vector(points[2, 0], 0.1, points[2, 1]),
|
||||
Vector(points[3, 0], 0.1, points[3, 1]),
|
||||
color = Color(174, 174, 174, 255)
|
||||
)
|
||||
first = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d))
|
||||
previous_point = Vector(self._clamp(points[0][0], min_w, max_w), disallowed_area_height, self._clamp(points[0][1], min_d, max_d))
|
||||
for point in points:
|
||||
new_point = Vector(self._clamp(point[0], min_w, max_w), disallowed_area_height, self._clamp(point[1], min_d, max_d))
|
||||
mb.addFace(first, previous_point, new_point, color = color)
|
||||
previous_point = new_point
|
||||
|
||||
# Find the largest disallowed area to exclude it from the maximum scale bounds
|
||||
size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
|
||||
disallowed_area_size = max(size, disallowed_area_size)
|
||||
|
@ -137,24 +138,17 @@ class BuildVolume(SceneNode):
|
|||
else:
|
||||
self._disallowed_area_mesh = None
|
||||
|
||||
self._aabb = AxisAlignedBox(minimum = Vector(minW, minH - 1.0, minD), maximum = Vector(maxW, maxH, maxD))
|
||||
self._aabb = AxisAlignedBox(minimum = Vector(min_w, min_h - 1.0, min_d), maximum = Vector(max_w, max_h, max_d))
|
||||
|
||||
skirt_size = 0.0
|
||||
|
||||
#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")
|
||||
profile = Application.getInstance().getMachineManager().getActiveProfile()
|
||||
if profile:
|
||||
skirt_size = self._getSkirtSize(profile)
|
||||
|
||||
scale_to_max_bounds = AxisAlignedBox(
|
||||
minimum = Vector(minW + skirt_size, minH, minD + skirt_size + disallowed_area_size),
|
||||
maximum = Vector(maxW - skirt_size, maxH, maxD - skirt_size - disallowed_area_size)
|
||||
minimum = Vector(min_w + skirt_size, min_h, min_d + skirt_size + disallowed_area_size),
|
||||
maximum = Vector(max_w - skirt_size, max_h, max_d - skirt_size - disallowed_area_size)
|
||||
)
|
||||
|
||||
Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
|
||||
|
@ -167,12 +161,107 @@ class BuildVolume(SceneNode):
|
|||
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._updateDisallowedAreas()
|
||||
|
||||
self.rebuild()
|
||||
|
||||
def _onActiveProfileChanged(self):
|
||||
if self._active_profile:
|
||||
self._active_profile.settingValueChanged.disconnect(self._onSettingValueChanged)
|
||||
|
||||
self._active_profile = Application.getInstance().getMachineManager().getActiveProfile()
|
||||
if self._active_profile:
|
||||
self._active_profile.settingValueChanged.connect(self._onSettingValueChanged)
|
||||
self._updateDisallowedAreas()
|
||||
self.rebuild()
|
||||
|
||||
def _onSettingValueChanged(self, setting):
|
||||
if setting in self._skirt_settings:
|
||||
self._updateDisallowedAreas()
|
||||
self.rebuild()
|
||||
|
||||
def _updateDisallowedAreas(self):
|
||||
if not self._active_instance or not self._active_profile:
|
||||
return
|
||||
|
||||
disallowed_areas = self._active_instance.getMachineSettingValue("machine_disallowed_areas")
|
||||
areas = []
|
||||
|
||||
skirt_size = 0.0
|
||||
if self._active_profile:
|
||||
skirt_size = self._getSkirtSize(self._active_profile)
|
||||
|
||||
if disallowed_areas:
|
||||
for area in disallowed_areas:
|
||||
poly = Polygon(numpy.array(area, numpy.float32))
|
||||
poly = poly.getMinkowskiHull(Polygon(numpy.array([
|
||||
[-skirt_size, 0],
|
||||
[-skirt_size * 0.707, skirt_size * 0.707],
|
||||
[0, skirt_size],
|
||||
[skirt_size * 0.707, skirt_size * 0.707],
|
||||
[skirt_size, 0],
|
||||
[skirt_size * 0.707, -skirt_size * 0.707],
|
||||
[0, -skirt_size],
|
||||
[-skirt_size * 0.707, -skirt_size * 0.707]
|
||||
], numpy.float32)))
|
||||
|
||||
areas.append(poly)
|
||||
|
||||
if skirt_size > 0:
|
||||
half_machine_width = self._active_instance.getMachineSettingValue("machine_width") / 2
|
||||
half_machine_depth = self._active_instance.getMachineSettingValue("machine_depth") / 2
|
||||
|
||||
areas.append(Polygon(numpy.array([
|
||||
[-half_machine_width, -half_machine_depth],
|
||||
[-half_machine_width, half_machine_depth],
|
||||
[-half_machine_width + skirt_size, half_machine_depth - skirt_size],
|
||||
[-half_machine_width + skirt_size, -half_machine_depth + skirt_size]
|
||||
], numpy.float32)))
|
||||
|
||||
areas.append(Polygon(numpy.array([
|
||||
[half_machine_width, half_machine_depth],
|
||||
[half_machine_width, -half_machine_depth],
|
||||
[half_machine_width - skirt_size, -half_machine_depth + skirt_size],
|
||||
[half_machine_width - skirt_size, half_machine_depth - skirt_size]
|
||||
], numpy.float32)))
|
||||
|
||||
areas.append(Polygon(numpy.array([
|
||||
[-half_machine_width, half_machine_depth],
|
||||
[half_machine_width, half_machine_depth],
|
||||
[half_machine_width - skirt_size, half_machine_depth - skirt_size],
|
||||
[-half_machine_width + skirt_size, half_machine_depth - skirt_size]
|
||||
], numpy.float32)))
|
||||
|
||||
areas.append(Polygon(numpy.array([
|
||||
[half_machine_width, -half_machine_depth],
|
||||
[-half_machine_width, -half_machine_depth],
|
||||
[-half_machine_width + skirt_size, -half_machine_depth + skirt_size],
|
||||
[half_machine_width - skirt_size, -half_machine_depth + skirt_size]
|
||||
], numpy.float32)))
|
||||
|
||||
self._disallowed_areas = areas
|
||||
|
||||
def _getSkirtSize(self, profile):
|
||||
skirt_size = 0.0
|
||||
|
||||
adhesion_type = profile.getSettingValue("adhesion_type")
|
||||
if adhesion_type == "skirt":
|
||||
skirt_distance = profile.getSettingValue("skirt_gap")
|
||||
skirt_line_count = profile.getSettingValue("skirt_line_count")
|
||||
skirt_size = skirt_distance + (skirt_line_count * profile.getSettingValue("skirt_line_width"))
|
||||
elif adhesion_type == "brim":
|
||||
skirt_size = profile.getSettingValue("brim_width")
|
||||
elif adhesion_type == "raft":
|
||||
skirt_size = profile.getSettingValue("raft_margin")
|
||||
|
||||
if profile.getSettingValue("draft_shield_enabled"):
|
||||
skirt_size += profile.getSettingValue("draft_shield_dist")
|
||||
|
||||
skirt_size += profile.getSettingValue("xy_offset")
|
||||
|
||||
return skirt_size
|
||||
|
||||
def _clamp(self, value, min_value, max_value):
|
||||
return max(min(value, max_value), min_value)
|
||||
|
||||
_skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_line_width", "brim_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist", "xy_offset"]
|
||||
|
|
|
@ -31,6 +31,8 @@ class ConvexHullJob(Job):
|
|||
self._node.callDecoration("setConvexHullJob", None)
|
||||
return
|
||||
|
||||
Job.yieldThread()
|
||||
|
||||
else:
|
||||
if not self._node.getMeshData():
|
||||
return
|
||||
|
|
|
@ -7,6 +7,8 @@ from UM.Math.Color import Color
|
|||
from UM.Math.Vector import Vector
|
||||
from UM.Mesh.MeshData import MeshData
|
||||
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
import numpy
|
||||
|
||||
class ConvexHullNode(SceneNode):
|
||||
|
@ -15,21 +17,21 @@ class ConvexHullNode(SceneNode):
|
|||
|
||||
self.setCalculateBoundingBox(False)
|
||||
|
||||
self._material = None
|
||||
self._shader = None
|
||||
|
||||
self._original_parent = parent
|
||||
|
||||
self._inherit_orientation = False
|
||||
self._inherit_scale = False
|
||||
|
||||
self._color = Color(35, 35, 35, 0.5)
|
||||
self._color = Color(35, 35, 35, 128)
|
||||
|
||||
self._node = node
|
||||
self._node.transformationChanged.connect(self._onNodePositionChanged)
|
||||
self._node.parentChanged.connect(self._onNodeParentChanged)
|
||||
self._node.decoratorsChanged.connect(self._onNodeDecoratorsChanged)
|
||||
self._onNodeDecoratorsChanged(self._node)
|
||||
self.convexHullHeadMesh = None
|
||||
self._convex_hull_head_mesh = None
|
||||
self._hull = hull
|
||||
|
||||
hull_points = self._hull.getPoints()
|
||||
|
@ -38,17 +40,17 @@ class ConvexHullNode(SceneNode):
|
|||
self.setMeshData(hull_mesh)
|
||||
convex_hull_head = self._node.callDecoration("getConvexHullHead")
|
||||
if convex_hull_head:
|
||||
self.convexHullHeadMesh = self.createHullMesh(convex_hull_head.getPoints())
|
||||
self._convex_hull_head_mesh = self.createHullMesh(convex_hull_head.getPoints())
|
||||
|
||||
def createHullMesh(self, hull_points):
|
||||
mesh = MeshData()
|
||||
if len(hull_points) > 3:
|
||||
center = (hull_points.min(0) + hull_points.max(0)) / 2.0
|
||||
mesh.addVertex(center[0], 0.1, center[1])
|
||||
mesh.addVertex(center[0], -0.1, center[1])
|
||||
else:
|
||||
return None
|
||||
for point in hull_points:
|
||||
mesh.addVertex(point[0], 0.1, point[1])
|
||||
mesh.addVertex(point[0], -0.1, point[1])
|
||||
indices = []
|
||||
for i in range(len(hull_points) - 1):
|
||||
indices.append([0, i + 1, i + 2])
|
||||
|
@ -62,14 +64,14 @@ class ConvexHullNode(SceneNode):
|
|||
return self._node
|
||||
|
||||
def render(self, renderer):
|
||||
if not self._material:
|
||||
self._material = renderer.createMaterial(Resources.getPath(Resources.Shaders, "basic.vert"), Resources.getPath(Resources.Shaders, "color.frag"))
|
||||
if not self._shader:
|
||||
self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader"))
|
||||
self._shader.setUniformValue("u_color", self._color)
|
||||
|
||||
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)
|
||||
renderer.queueNode(self, transparent = True, shader = self._shader, backface_cull = True, sort = -8)
|
||||
if self._convex_hull_head_mesh:
|
||||
renderer.queueNode(self, shader = self._shader, transparent = True, mesh = self._convex_hull_head_mesh, backface_cull = True, sort = -8)
|
||||
|
||||
return True
|
||||
|
||||
|
|
|
@ -8,9 +8,15 @@ from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTex
|
|||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
def show(type, value, tb):
|
||||
if not hasattr(sys, "frozen"):
|
||||
traceback.print_exception(type, value, tb)
|
||||
def show(exception_type, value, tb):
|
||||
debug_mode = False
|
||||
if QCoreApplication.instance():
|
||||
debug_mode = QCoreApplication.instance().getCommandLineOption("debug-mode", False)
|
||||
|
||||
traceback.print_exception(exception_type, value, tb)
|
||||
|
||||
if not debug_mode:
|
||||
return
|
||||
|
||||
application = QCoreApplication.instance()
|
||||
if not application:
|
||||
|
@ -34,7 +40,7 @@ def show(type, value, tb):
|
|||
except:
|
||||
version = "Unknown"
|
||||
|
||||
trace = "".join(traceback.format_exception(type, value, tb))
|
||||
trace = "".join(traceback.format_exception(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)
|
||||
|
@ -44,7 +50,7 @@ def show(type, value, tb):
|
|||
buttons = QDialogButtonBox(QDialogButtonBox.Close, dialog)
|
||||
layout.addWidget(buttons)
|
||||
buttons.addButton(catalog.i18nc("@action:button", "Open Web Page"), QDialogButtonBox.HelpRole)
|
||||
buttons.rejected.connect(lambda: dialog.close())
|
||||
buttons.rejected.connect(dialog.close)
|
||||
buttons.helpRequested.connect(lambda: webbrowser.open("http://github.com/Ultimaker/Cura/issues"))
|
||||
|
||||
dialog.exec_()
|
||||
|
|
|
@ -3,11 +3,6 @@
|
|||
|
||||
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
|
||||
|
@ -15,6 +10,7 @@ from UM.Scene.Platform import Platform
|
|||
from UM.Math.Vector import Vector
|
||||
from UM.Math.Matrix import Matrix
|
||||
from UM.Math.Quaternion import Quaternion
|
||||
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||
from UM.Resources import Resources
|
||||
from UM.Scene.ToolHandle import ToolHandle
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
|
@ -44,6 +40,8 @@ from . import CameraAnimation
|
|||
from . import PrintInformation
|
||||
from . import CuraActions
|
||||
from . import MultiMaterialDecorator
|
||||
from . import ZOffsetDecorator
|
||||
from . import CuraSplashScreen
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot, QUrl, Qt, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
|
||||
from PyQt5.QtGui import QColor, QIcon
|
||||
|
@ -57,6 +55,16 @@ import numpy
|
|||
import copy
|
||||
numpy.seterr(all="ignore")
|
||||
|
||||
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
|
||||
|
||||
try:
|
||||
from cura.CuraVersion import CuraVersion
|
||||
except ImportError:
|
||||
CuraVersion = "master" # [CodeStyle: Reflecting imported value]
|
||||
|
||||
class CuraApplication(QtApplication):
|
||||
class ResourceTypes:
|
||||
QmlFiles = Resources.UserType + 1
|
||||
|
@ -68,7 +76,7 @@ class CuraApplication(QtApplication):
|
|||
if not hasattr(sys, "frozen"):
|
||||
Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))
|
||||
|
||||
super().__init__(name = "cura", version = "15.09.82")
|
||||
super().__init__(name = "cura", version = CuraVersion)
|
||||
|
||||
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
|
||||
|
||||
|
@ -90,6 +98,8 @@ class CuraApplication(QtApplication):
|
|||
self._i18n_catalog = None
|
||||
self._previous_active_tool = None
|
||||
self._platform_activity = False
|
||||
self._scene_boundingbox = AxisAlignedBox()
|
||||
self._job_name = None
|
||||
|
||||
self.getMachineManager().activeMachineInstanceChanged.connect(self._onActiveMachineChanged)
|
||||
self.getMachineManager().addMachineRequested.connect(self._onAddMachineRequested)
|
||||
|
@ -131,8 +141,12 @@ class CuraApplication(QtApplication):
|
|||
def addCommandLineOptions(self, parser):
|
||||
super().addCommandLineOptions(parser)
|
||||
parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
|
||||
parser.add_argument("--debug", dest="debug-mode", action="store_true", default=False, help="Enable detailed crash reports.")
|
||||
|
||||
def run(self):
|
||||
if "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION" not in os.environ or os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] != "cpp":
|
||||
Logger.log("w", "Using Python implementation of Protobuf, expect bad performance!")
|
||||
|
||||
self._i18n_catalog = i18nCatalog("cura");
|
||||
|
||||
i18nCatalog.setTagReplacements({
|
||||
|
@ -144,7 +158,7 @@ class CuraApplication(QtApplication):
|
|||
|
||||
controller = self.getController()
|
||||
|
||||
controller.setActiveView("MeshView")
|
||||
controller.setActiveView("SolidView")
|
||||
controller.setCameraTool("CameraTool")
|
||||
controller.setSelectionTool("SelectionTool")
|
||||
|
||||
|
@ -159,31 +173,26 @@ class CuraApplication(QtApplication):
|
|||
|
||||
self._volume = BuildVolume.BuildVolume(root)
|
||||
|
||||
self.getRenderer().setLightPosition(Vector(0, 150, 0))
|
||||
self.getRenderer().setBackgroundColor(QColor(245, 245, 245))
|
||||
|
||||
self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume)
|
||||
|
||||
camera = Camera("3d", root)
|
||||
camera.setPosition(Vector(-150, 150, 300))
|
||||
camera.setPosition(Vector(-80, 250, 700))
|
||||
camera.setPerspective(True)
|
||||
camera.lookAt(Vector(0, 0, 0))
|
||||
controller.getScene().setActiveCamera("3d")
|
||||
|
||||
self.getController().getTool("CameraTool").setOrigin(Vector(0, 100, 0))
|
||||
|
||||
self._camera_animation = CameraAnimation.CameraAnimation()
|
||||
self._camera_animation.setCameraTool(self.getController().getTool("CameraTool"))
|
||||
|
||||
controller.getScene().setActiveCamera("3d")
|
||||
|
||||
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface..."))
|
||||
|
||||
self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
|
||||
self.initializeEngine()
|
||||
|
||||
manager = self.getMachineManager()
|
||||
if not self.getMachineManager().getMachineInstances():
|
||||
self.requestAddPrinter.emit()
|
||||
|
||||
|
||||
if self._engine.rootObjects:
|
||||
self.closeSplash()
|
||||
|
||||
|
@ -232,35 +241,58 @@ class CuraApplication(QtApplication):
|
|||
|
||||
requestAddPrinter = pyqtSignal()
|
||||
activityChanged = pyqtSignal()
|
||||
sceneBoundingBoxChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty(bool, notify = activityChanged)
|
||||
def getPlatformActivity(self):
|
||||
return self._platform_activity
|
||||
|
||||
@pyqtProperty(str, notify = sceneBoundingBoxChanged)
|
||||
def getSceneBoundingBoxString(self):
|
||||
return self._i18n_catalog.i18nc("@info", "%.1f x %.1f x %.1f mm") % (self._scene_boundingbox.width.item(), self._scene_boundingbox.depth.item(), self._scene_boundingbox.height.item())
|
||||
|
||||
def updatePlatformActivity(self, node = None):
|
||||
count = 0
|
||||
scene_boundingbox = AxisAlignedBox()
|
||||
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
|
||||
if type(node) is not SceneNode or not node.getMeshData():
|
||||
continue
|
||||
|
||||
count += 1
|
||||
scene_boundingbox += node.getBoundingBox()
|
||||
|
||||
if repr(self._scene_boundingbox) != repr(scene_boundingbox):
|
||||
self._scene_boundingbox = scene_boundingbox
|
||||
self.sceneBoundingBoxChanged.emit()
|
||||
|
||||
self._platform_activity = True if count > 0 else False
|
||||
self.activityChanged.emit()
|
||||
|
||||
@pyqtSlot(str)
|
||||
def setJobName(self, name):
|
||||
if self._job_name != name:
|
||||
self._job_name = name
|
||||
self.jobNameChanged.emit()
|
||||
|
||||
jobNameChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty(str, notify = jobNameChanged)
|
||||
def jobName(self):
|
||||
return self._job_name
|
||||
|
||||
## Remove an object from the scene
|
||||
@pyqtSlot("quint64")
|
||||
def deleteObject(self, object_id):
|
||||
object = self.getController().getScene().findObject(object_id)
|
||||
node = self.getController().getScene().findObject(object_id)
|
||||
|
||||
if not object and object_id != 0: #Workaround for tool handles overlapping the selected object
|
||||
object = Selection.getSelectedObject(0)
|
||||
|
||||
if object:
|
||||
if object.getParent():
|
||||
group_node = object.getParent()
|
||||
if not node and object_id != 0: #Workaround for tool handles overlapping the selected object
|
||||
node = Selection.getSelectedObject(0)
|
||||
|
||||
if node:
|
||||
if node.getParent():
|
||||
group_node = node.getParent()
|
||||
if not group_node.callDecoration("isGroup"):
|
||||
op = RemoveSceneNodeOperation(object)
|
||||
op = RemoveSceneNodeOperation(node)
|
||||
else:
|
||||
while group_node.getParent().callDecoration("isGroup"):
|
||||
group_node = group_node.getParent()
|
||||
|
@ -294,10 +326,15 @@ class CuraApplication(QtApplication):
|
|||
@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 not node:
|
||||
return
|
||||
|
||||
if node.getParent() and node.getParent().callDecoration("isGroup"):
|
||||
node = node.getParent()
|
||||
|
||||
if node:
|
||||
op = SetTransformOperation(node, Vector())
|
||||
op.push()
|
||||
|
@ -335,14 +372,12 @@ class CuraApplication(QtApplication):
|
|||
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:
|
||||
# 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)))
|
||||
node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
|
||||
op.addOperation(SetTransformOperation(node, Vector(0,0,0)))
|
||||
|
||||
op.push()
|
||||
|
||||
|
@ -364,10 +399,8 @@ class CuraApplication(QtApplication):
|
|||
|
||||
for node in nodes:
|
||||
# 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)))
|
||||
node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
|
||||
op.addOperation(SetTransformOperation(node, Vector(0,0,0), Quaternion(), Vector(1, 1, 1)))
|
||||
|
||||
op.push()
|
||||
|
||||
|
@ -407,6 +440,7 @@ class CuraApplication(QtApplication):
|
|||
return log
|
||||
|
||||
recentFilesChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty("QVariantList", notify = recentFilesChanged)
|
||||
def recentFiles(self):
|
||||
return self._recent_files
|
||||
|
@ -421,6 +455,7 @@ class CuraApplication(QtApplication):
|
|||
self.expandedCategoriesChanged.emit()
|
||||
|
||||
expandedCategoriesChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty("QStringList", notify = expandedCategoriesChanged)
|
||||
def expandedCategories(self):
|
||||
return Preferences.getInstance().getValue("cura/categories_expanded").split(";")
|
||||
|
@ -464,17 +499,20 @@ class CuraApplication(QtApplication):
|
|||
group_decorator = GroupDecorator()
|
||||
group_node.addDecorator(group_decorator)
|
||||
group_node.setParent(self.getController().getScene().getRoot())
|
||||
|
||||
center = Selection.getSelectionCenter()
|
||||
group_node.setPosition(center)
|
||||
group_node.setCenterPosition(center)
|
||||
|
||||
for node in Selection.getAllSelectedObjects():
|
||||
world = node.getWorldPosition()
|
||||
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)
|
||||
node.setPosition(world - center)
|
||||
|
||||
for node in group_node.getChildren():
|
||||
Selection.remove(node)
|
||||
|
||||
|
||||
Selection.add(group_node)
|
||||
|
||||
|
||||
@pyqtSlot()
|
||||
def ungroupSelected(self):
|
||||
ungrouped_nodes = []
|
||||
|
@ -485,12 +523,11 @@ class CuraApplication(QtApplication):
|
|||
for child in node.getChildren():
|
||||
if type(child) is SceneNode:
|
||||
children_to_move.append(child)
|
||||
|
||||
|
||||
for child in children_to_move:
|
||||
position = child.getWorldPosition()
|
||||
child.setParent(node.getParent())
|
||||
print(node.getPosition())
|
||||
child.translate(node.getPosition())
|
||||
child.setPosition(child.getPosition().scale(node.getScale()))
|
||||
child.setPosition(position - node.getParent().getWorldPosition())
|
||||
child.scale(node.getScale())
|
||||
child.rotate(node.getOrientation())
|
||||
|
||||
|
@ -501,6 +538,9 @@ class CuraApplication(QtApplication):
|
|||
for node in ungrouped_nodes:
|
||||
Selection.remove(node)
|
||||
|
||||
def _createSplashScreen(self):
|
||||
return CuraSplashScreen.CuraSplashScreen()
|
||||
|
||||
def _onActiveMachineChanged(self):
|
||||
machine = self.getMachineManager().getActiveMachineInstance()
|
||||
if machine:
|
||||
|
@ -536,6 +576,8 @@ class CuraApplication(QtApplication):
|
|||
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
|
||||
op.push()
|
||||
|
||||
self.getController().getScene().sceneChanged.emit(node) #Force scene change.
|
||||
|
||||
def _onJobFinished(self, job):
|
||||
if type(job) is not ReadMeshJob or not job.getResult():
|
||||
return
|
||||
|
|
29
cura/CuraSplashScreen.py
Normal file
29
cura/CuraSplashScreen.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QPixmap, QColor, QFont
|
||||
from PyQt5.QtWidgets import QSplashScreen
|
||||
|
||||
from UM.Resources import Resources
|
||||
from UM.Application import Application
|
||||
|
||||
class CuraSplashScreen(QSplashScreen):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setPixmap(QPixmap(Resources.getPath(Resources.Images, "cura.png")))
|
||||
|
||||
def drawContents(self, painter):
|
||||
painter.save()
|
||||
painter.setPen(QColor(0, 0, 0, 255))
|
||||
|
||||
version = Application.getInstance().getVersion().split("-")
|
||||
|
||||
painter.setFont(QFont("Proxima Nova Rg", 20))
|
||||
painter.drawText(0, 0, 203, 230, Qt.AlignRight | Qt.AlignBottom, version[0])
|
||||
if len(version) > 1:
|
||||
painter.setFont(QFont("Proxima Nova Rg", 12))
|
||||
painter.drawText(0, 0, 203, 255, Qt.AlignRight | Qt.AlignBottom, version[1])
|
||||
|
||||
painter.restore()
|
||||
super().drawContents(painter)
|
4
cura/CuraVersion.py.in
Normal file
4
cura/CuraVersion.py.in
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
CuraVersion = "@CURA_VERSION@"
|
|
@ -63,6 +63,7 @@ class LayerData(MeshData):
|
|||
offset = data.build(offset, vertices, colors, indices)
|
||||
self._element_counts[layer] = data.elementCount
|
||||
|
||||
self.clear()
|
||||
self.addVertices(vertices)
|
||||
self.addColors(colors)
|
||||
self.addIndices(indices.flatten())
|
||||
|
@ -107,7 +108,7 @@ class Layer():
|
|||
def build(self, offset, vertices, colors, indices):
|
||||
result = offset
|
||||
for polygon in self._polygons:
|
||||
if polygon._type == Polygon.InfillType or polygon._type == Polygon.SupportInfillType:
|
||||
if polygon.type == Polygon.InfillType or polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType:
|
||||
continue
|
||||
|
||||
polygon.build(result, vertices, colors, indices)
|
||||
|
@ -117,14 +118,27 @@ class Layer():
|
|||
return result
|
||||
|
||||
def createMesh(self):
|
||||
return self.createMeshOrJumps(True)
|
||||
|
||||
def createJumps(self):
|
||||
return self.createMeshOrJumps(False)
|
||||
|
||||
def createMeshOrJumps(self, make_mesh):
|
||||
builder = MeshBuilder()
|
||||
|
||||
for polygon in self._polygons:
|
||||
if make_mesh and (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType):
|
||||
continue
|
||||
if not make_mesh and not (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType):
|
||||
continue
|
||||
|
||||
poly_color = polygon.getColor()
|
||||
|
||||
points = numpy.copy(polygon.data)
|
||||
if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType:
|
||||
points[:,1] -= 0.01
|
||||
if polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType:
|
||||
points[:,1] += 0.01
|
||||
|
||||
# Calculate normals for the entire polygon using numpy.
|
||||
normals = numpy.copy(points)
|
||||
|
@ -175,6 +189,8 @@ class Polygon():
|
|||
SkirtType = 5
|
||||
InfillType = 6
|
||||
SupportInfillType = 7
|
||||
MoveCombingType = 8
|
||||
MoveRetractionType = 9
|
||||
|
||||
def __init__(self, mesh, type, data, line_width):
|
||||
super().__init__()
|
||||
|
@ -185,18 +201,14 @@ class Polygon():
|
|||
|
||||
def build(self, offset, vertices, colors, indices):
|
||||
self._begin = offset
|
||||
self._end = self._begin + len(self._data) - 1
|
||||
|
||||
color = self.getColor()
|
||||
color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)
|
||||
color = numpy.array([color.r, color.g, color.b, color.a], numpy.float32)
|
||||
|
||||
for i in range(len(self._data)):
|
||||
vertices[offset + i, :] = self._data[i, :]
|
||||
colors[offset + i, 0] = color.r
|
||||
colors[offset + i, 1] = color.g
|
||||
colors[offset + i, 2] = color.b
|
||||
colors[offset + i, 3] = color.a
|
||||
|
||||
self._end = self._begin + len(self._data) - 1
|
||||
vertices[self._begin:self._end + 1, :] = self._data[:, :]
|
||||
colors[self._begin:self._end + 1, :] = color
|
||||
|
||||
for i in range(self._begin, self._end):
|
||||
indices[i, 0] = i
|
||||
|
@ -220,6 +232,10 @@ class Polygon():
|
|||
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)
|
||||
elif self._type == self.MoveCombingType:
|
||||
return Color(0.0, 0.0, 1.0, 1.0)
|
||||
elif self._type == self.MoveRetractionType:
|
||||
return Color(0.5, 0.5, 1.0, 1.0)
|
||||
else:
|
||||
return Color(1.0, 1.0, 1.0, 1.0)
|
||||
|
|
@ -45,7 +45,7 @@ class OneAtATimeIterator(Iterator.Iterator):
|
|||
# This does not decrease the worst case running time, but should improve it in most cases.
|
||||
sorted(node_list, key = cmp_to_key(self._calculateScore))
|
||||
|
||||
todo_node_list = [_objectOrder([], node_list)]
|
||||
todo_node_list = [_ObjectOrder([], node_list)]
|
||||
while len(todo_node_list) > 0:
|
||||
current = todo_node_list.pop()
|
||||
for node in current.todo:
|
||||
|
@ -61,7 +61,7 @@ class OneAtATimeIterator(Iterator.Iterator):
|
|||
self._node_stack = new_order
|
||||
|
||||
return
|
||||
todo_node_list.append(_objectOrder(new_order, new_todo_list))
|
||||
todo_node_list.append(_ObjectOrder(new_order, new_todo_list))
|
||||
self._node_stack = [] #No result found!
|
||||
|
||||
|
||||
|
@ -99,7 +99,7 @@ class OneAtATimeIterator(Iterator.Iterator):
|
|||
|
||||
|
||||
## Internal object used to keep track of a possible order in which to print objects.
|
||||
class _objectOrder():
|
||||
class _ObjectOrder():
|
||||
def __init__(self, order, todo):
|
||||
"""
|
||||
:param order: List of indexes in which to print objects, ordered by printing order.
|
||||
|
|
|
@ -17,6 +17,7 @@ from cura.ConvexHullDecorator import ConvexHullDecorator
|
|||
|
||||
from . import PlatformPhysicsOperation
|
||||
from . import ConvexHullJob
|
||||
from . import ZOffsetDecorator
|
||||
|
||||
import time
|
||||
import threading
|
||||
|
@ -69,8 +70,12 @@ class PlatformPhysics:
|
|||
# Move it downwards if bottom is above platform
|
||||
move_vector = Vector()
|
||||
if not (node.getParent() and node.getParent().callDecoration("isGroup")): #If an object is grouped, don't move it down
|
||||
z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0
|
||||
if bbox.bottom > 0:
|
||||
move_vector.setY(-bbox.bottom)
|
||||
move_vector.setY(-bbox.bottom + z_offset)
|
||||
elif bbox.bottom < z_offset:
|
||||
move_vector.setY((-bbox.bottom) - z_offset)
|
||||
|
||||
#if not Float.fuzzyCompare(bbox.bottom, 0.0):
|
||||
# pass#move_vector.setY(-bbox.bottom)
|
||||
|
||||
|
@ -127,8 +132,8 @@ class PlatformPhysics:
|
|||
|
||||
if overlap is None:
|
||||
continue
|
||||
move_vector.setX(overlap[0] * 1.01)
|
||||
move_vector.setZ(overlap[1] * 1.01)
|
||||
move_vector.setX(overlap[0] * 1.1)
|
||||
move_vector.setZ(overlap[1] * 1.1)
|
||||
convex_hull = node.callDecoration("getConvexHull")
|
||||
if convex_hull:
|
||||
if not convex_hull.isValid():
|
||||
|
@ -149,5 +154,16 @@ class PlatformPhysics:
|
|||
self._enabled = False
|
||||
|
||||
def _onToolOperationStopped(self, tool):
|
||||
if tool.getPluginId() == "TranslateTool":
|
||||
for node in Selection.getAllSelectedObjects():
|
||||
if node.getBoundingBox().bottom < 0:
|
||||
if not node.getDecorator(ZOffsetDecorator.ZOffsetDecorator):
|
||||
node.addDecorator(ZOffsetDecorator.ZOffsetDecorator())
|
||||
|
||||
node.callDecoration("setZOffset", node.getBoundingBox().bottom)
|
||||
else:
|
||||
if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator):
|
||||
node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
|
||||
|
||||
self._enabled = True
|
||||
self._onChangeTimerFinished()
|
||||
|
|
13
cura/ZOffsetDecorator.py
Normal file
13
cura/ZOffsetDecorator.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
|
||||
|
||||
## A decorator that stores the amount an object has been moved below the platform.
|
||||
class ZOffsetDecorator(SceneNodeDecorator):
|
||||
def __init__(self):
|
||||
self._z_offset = 0
|
||||
|
||||
def setZOffset(self, offset):
|
||||
print("setZOffset", offset)
|
||||
self._z_offset = offset
|
||||
|
||||
def getZOffset(self):
|
||||
return self._z_offset
|
18
cura_app.py
18
cura_app.py
|
@ -4,6 +4,7 @@
|
|||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
def exceptHook(type, value, traceback):
|
||||
import cura.CrashHandler
|
||||
|
@ -11,7 +12,22 @@ def exceptHook(type, value, traceback):
|
|||
|
||||
sys.excepthook = exceptHook
|
||||
|
||||
import cura.CuraApplication
|
||||
try:
|
||||
from google.protobuf.pyext import _message
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "cpp"
|
||||
|
||||
if True: # To make the code style checker stop complaining
|
||||
import cura.CuraApplication
|
||||
|
||||
if sys.platform == "win32" and hasattr(sys, "frozen"):
|
||||
import os
|
||||
dirpath = os.path.expanduser("~/AppData/Local/cura/")
|
||||
os.makedirs(dirpath, exist_ok = True)
|
||||
sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w")
|
||||
sys.stderr = open(os.path.join(dirpath, "stderr.log"), "w")
|
||||
|
||||
app = cura.CuraApplication.CuraApplication.getInstance()
|
||||
app.run()
|
||||
|
|
|
@ -10,6 +10,7 @@ from UM.Scene.SceneNode import SceneNode
|
|||
from UM.Scene.GroupDecorator import GroupDecorator
|
||||
from UM.Math.Quaternion import Quaternion
|
||||
|
||||
from UM.Job import Job
|
||||
|
||||
import os
|
||||
import struct
|
||||
|
@ -36,12 +37,16 @@ class ThreeMFReader(MeshReader):
|
|||
if extension.lower() == self._supported_extension:
|
||||
result = SceneNode()
|
||||
# The base object of 3mf is a zipped archive.
|
||||
archive = zipfile.ZipFile(file_name, 'r')
|
||||
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)
|
||||
if len(objects) == 0:
|
||||
Logger.log("w", "No objects found in 3MF file %s, either the file is corrupt or you are using an outdated format", file_name)
|
||||
return None
|
||||
|
||||
for object in objects:
|
||||
mesh = MeshData()
|
||||
node = SceneNode()
|
||||
|
@ -49,22 +54,25 @@ class ThreeMFReader(MeshReader):
|
|||
#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")])
|
||||
Job.yieldThread()
|
||||
|
||||
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.
|
||||
Job.yieldThread()
|
||||
|
||||
#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]
|
||||
|
@ -88,30 +96,32 @@ class ThreeMFReader(MeshReader):
|
|||
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))
|
||||
scale = temp_mat.getTransposed().multiply(temp_mat)
|
||||
scale_x = math.sqrt(scale.at(0,0))
|
||||
scale_y = math.sqrt(scale.at(1,1))
|
||||
scale_z = math.sqrt(scale.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)
|
||||
#rotation = Quaternion.fromAngleAxis(-0.5 * math.pi, Vector(1,0,0))
|
||||
#node.rotate(rotation)
|
||||
result.addChild(node)
|
||||
|
||||
Job.yieldThread()
|
||||
|
||||
#If there is more then one object, group them.
|
||||
try:
|
||||
if len(objects) > 1:
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from . import ThreeMFReader
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
from . import ThreeMFReader
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
"plugin": {
|
||||
|
|
|
@ -31,6 +31,7 @@ class ChangeLog(Extension, QObject,):
|
|||
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.addMenuItem(catalog.i18nc("@item:inmenu", "Show Changelog"), self.showChangelog)
|
||||
#self.showChangelog()
|
||||
|
||||
def getChangeLogs(self):
|
||||
|
@ -57,7 +58,7 @@ class ChangeLog(Extension, QObject,):
|
|||
|
||||
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:
|
||||
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:
|
||||
|
@ -77,8 +78,8 @@ class ChangeLog(Extension, QObject,):
|
|||
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()
|
||||
#if self._version > Preferences.getInstance().getValue("general/latest_version_changelog_shown"):
|
||||
#self.showChangelog()
|
||||
|
||||
def showChangelog(self):
|
||||
if not self._changelog_window:
|
||||
|
|
|
@ -11,8 +11,8 @@ import UM 1.1 as UM
|
|||
UM.Dialog
|
||||
{
|
||||
id: base
|
||||
width: 300 * Screen.devicePixelRatio;
|
||||
height: 500 * Screen.devicePixelRatio;
|
||||
minimumWidth: 400
|
||||
minimumHeight: 300;
|
||||
title: "Changelog"
|
||||
|
||||
ScrollView
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
[15.10.0]
|
||||
[2.0.0]
|
||||
|
||||
*Naming changes
|
||||
Infill prints after perimeters → Infill Before Walls
|
||||
Initial layer thickness → Initial Layer Height
|
||||
Structure type → Pattern
|
||||
Cool head lift → Lift Head
|
||||
Combine everything (Type-A) → Union Overlapping Volumes
|
||||
Combine everything (Type-B) → Remove All Holes
|
||||
Keep open faces Keep Disconnected → Faces
|
||||
Only follow mesh surface → Surface Mode
|
||||
|
||||
*All at Once/One at a Time
|
||||
Cura’s 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.
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ catalog = i18nCatalog("cura")
|
|||
def getMetaData():
|
||||
return {
|
||||
"plugin": {
|
||||
"name": catalog.i18nc("@label", "Change Log"),
|
||||
"name": catalog.i18nc("@label", "Changelog"),
|
||||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"description": catalog.i18nc("@info:whatsthis", "Shows changes since latest checked version"),
|
||||
|
|
|
@ -17,6 +17,7 @@ from cura.OneAtATimeIterator import OneAtATimeIterator
|
|||
from . import Cura_pb2
|
||||
from . import ProcessSlicedObjectListJob
|
||||
from . import ProcessGCodeJob
|
||||
from . import StartSliceJob
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
@ -49,6 +50,7 @@ class CuraEngineBackend(Backend):
|
|||
self._onActiveViewChanged()
|
||||
self._stored_layer_data = None
|
||||
|
||||
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onChanged)
|
||||
|
||||
self._profile = None
|
||||
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
|
||||
|
@ -67,22 +69,26 @@ class CuraEngineBackend(Backend):
|
|||
|
||||
self._slicing = False
|
||||
self._restart = False
|
||||
|
||||
self._save_gcode = True
|
||||
self._save_polygons = True
|
||||
self._report_progress = True
|
||||
|
||||
self._enabled = True
|
||||
self._always_restart = True
|
||||
|
||||
self._message = None
|
||||
|
||||
self.backendConnected.connect(self._onBackendConnected)
|
||||
Application.getInstance().getController().toolOperationStarted.connect(self._onToolOperationStarted)
|
||||
Application.getInstance().getController().toolOperationStopped.connect(self._onToolOperationStopped)
|
||||
|
||||
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onInstanceChanged)
|
||||
|
||||
## 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.MachineDefinitions, "fdmprinter.json"), "-vv"]
|
||||
active_machine = Application.getInstance().getMachineManager().getActiveMachineInstance()
|
||||
if not active_machine:
|
||||
return None
|
||||
|
||||
return [Preferences.getInstance().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), "-j", active_machine.getMachineDefinition().getPath(), "-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.
|
||||
|
@ -95,24 +101,12 @@ class CuraEngineBackend(Backend):
|
|||
## Emitted whne the slicing process is aborted forcefully.
|
||||
slicingCancelled = Signal()
|
||||
|
||||
## Perform a slice of the scene with the given set of settings.
|
||||
#
|
||||
# \param kwargs Keyword arguments.
|
||||
# Valid values are:
|
||||
# - settings: The settings to use for the slice. The default is the active machine.
|
||||
# - save_gcode: True if the generated gcode should be saved, False if not. True by default.
|
||||
# - save_polygons: True if the generated polygon data should be saved, False if not. True by default.
|
||||
# - force_restart: True if the slicing process should be forcefully restarted if it is already slicing.
|
||||
# If False, this method will do nothing when already slicing. True by default.
|
||||
# - report_progress: True if the slicing progress should be reported, False if not. Default is True.
|
||||
def slice(self, **kwargs):
|
||||
## Perform a slice of the scene.
|
||||
def slice(self):
|
||||
if not self._enabled:
|
||||
return
|
||||
|
||||
if self._slicing:
|
||||
if not kwargs.get("force_restart", True):
|
||||
return
|
||||
|
||||
self._slicing = False
|
||||
self._restart = True
|
||||
if self._process is not None:
|
||||
|
@ -121,110 +115,56 @@ class CuraEngineBackend(Backend):
|
|||
self._process.terminate()
|
||||
except: # terminating a process that is already terminating causes an exception, silently ignore this.
|
||||
pass
|
||||
self.slicingCancelled.emit()
|
||||
return
|
||||
Logger.log("d", "Preparing to send slice data to engine.")
|
||||
object_groups = []
|
||||
if self._profile.getSettingValue("print_sequence") == "one_at_a_time":
|
||||
for node in OneAtATimeIterator(self._scene.getRoot()):
|
||||
temp_list = []
|
||||
children = node.getAllChildren()
|
||||
children.append(node)
|
||||
for child_node in children:
|
||||
if type(child_node) is SceneNode and child_node.getMeshData() and child_node.getMeshData().getVertices() is not None:
|
||||
temp_list.append(child_node)
|
||||
object_groups.append(temp_list)
|
||||
else:
|
||||
temp_list = []
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
|
||||
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()):
|
||||
# if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
|
||||
# if not getattr(node, "_outside_buildarea", False):
|
||||
# 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("profile", self._profile).hasErrorValue():
|
||||
Logger.log('w', "Profile has error values. Aborting slicing")
|
||||
self.slicingCancelled.emit()
|
||||
return
|
||||
|
||||
if 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.processingProgress.emit(0.0)
|
||||
if self._message:
|
||||
self._message.setProgress(-1)
|
||||
#else:
|
||||
# self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
|
||||
# self._message.show()
|
||||
|
||||
self._scene.gcode_list = []
|
||||
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)
|
||||
job = StartSliceJob.StartSliceJob(self._profile, self._socket)
|
||||
job.start()
|
||||
job.finished.connect(self._onStartSliceCompleted)
|
||||
|
||||
self._sendSettings(kwargs.get("profile", self._profile))
|
||||
|
||||
self._scene.acquireLock()
|
||||
|
||||
# Set the gcode as an empty list. This will be filled with strings by GCodeLayer messages.
|
||||
# This is done so the gcode can be fragmented in memory and does not need a continues memory space.
|
||||
# (AKA. This prevents MemoryErrors)
|
||||
self._save_gcode = kwargs.get("save_gcode", True)
|
||||
if self._save_gcode:
|
||||
setattr(self._scene, "gcode_list", [])
|
||||
|
||||
self._save_polygons = kwargs.get("save_polygons", True)
|
||||
|
||||
slice_message = Cura_pb2.Slice()
|
||||
|
||||
for group in object_groups:
|
||||
group_message = slice_message.object_lists.add()
|
||||
for object in group:
|
||||
mesh_data = object.getMeshData().getTransformed(object.getWorldTransformation())
|
||||
|
||||
obj = group_message.objects.add()
|
||||
obj.id = id(object)
|
||||
|
||||
verts = numpy.array(mesh_data.getVertices())
|
||||
verts[:,[1,2]] = verts[:,[2,1]]
|
||||
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):
|
||||
if (type(source) is not SceneNode) or (source is self._scene.getRoot()) or (source.getMeshData() is None):
|
||||
def _onStartSliceCompleted(self, job):
|
||||
if job.getError() or job.getResult() != True:
|
||||
if self._message:
|
||||
self._message.hide()
|
||||
self._message = None
|
||||
return
|
||||
|
||||
if(source.getMeshData().getVertices() is None):
|
||||
def _onSceneChanged(self, source):
|
||||
if type(source) is not SceneNode:
|
||||
return
|
||||
|
||||
if source is self._scene.getRoot():
|
||||
return
|
||||
|
||||
if source.getMeshData() is None:
|
||||
return
|
||||
|
||||
if source.getMeshData().getVertices() is None:
|
||||
return
|
||||
|
||||
self._onChanged()
|
||||
|
@ -242,41 +182,42 @@ class CuraEngineBackend(Backend):
|
|||
self._onChanged()
|
||||
|
||||
def _onSlicedObjectListMessage(self, message):
|
||||
if self._save_polygons:
|
||||
if self._layer_view_active:
|
||||
job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message)
|
||||
job.start()
|
||||
else :
|
||||
self._stored_layer_data = message
|
||||
if self._layer_view_active:
|
||||
job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message)
|
||||
job.start()
|
||||
else :
|
||||
self._stored_layer_data = message
|
||||
|
||||
def _onProgressMessage(self, message):
|
||||
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)
|
||||
self.processingProgress.emit(message.amount)
|
||||
|
||||
def _onGCodeLayerMessage(self, message):
|
||||
if self._save_gcode:
|
||||
job = ProcessGCodeJob.ProcessGCodeLayerJob(message)
|
||||
job.start()
|
||||
self._scene.gcode_list.append(message.data.decode("utf-8", "replace"))
|
||||
|
||||
def _onGCodePrefixMessage(self, message):
|
||||
if self._save_gcode:
|
||||
self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace"))
|
||||
self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace"))
|
||||
|
||||
def _onObjectPrintTimeMessage(self, message):
|
||||
self.printDurationMessage.emit(message.time, message.material_amount)
|
||||
self.processingProgress.emit(1.0)
|
||||
|
||||
self._slicing = False
|
||||
|
||||
if self._message:
|
||||
self._message.setProgress(100)
|
||||
self._message.hide()
|
||||
self._message = None
|
||||
|
||||
if self._always_restart:
|
||||
try:
|
||||
self._process.terminate()
|
||||
self._createSocket()
|
||||
except: # terminating a process that is already terminating causes an exception, silently ignore this.
|
||||
pass
|
||||
|
||||
def _createSocket(self):
|
||||
super()._createSocket()
|
||||
|
||||
|
@ -298,15 +239,6 @@ class CuraEngineBackend(Backend):
|
|||
|
||||
self._change_timer.start()
|
||||
|
||||
def _sendSettings(self, profile):
|
||||
msg = Cura_pb2.SettingList()
|
||||
for key, value in profile.getAllSettingValues(include_machine = True).items():
|
||||
s = msg.settings.add()
|
||||
s.name = key
|
||||
s.value = str(value).encode("utf-8")
|
||||
|
||||
self._socket.sendMessage(msg)
|
||||
|
||||
def _onBackendConnected(self):
|
||||
if self._restart:
|
||||
self._onChanged()
|
||||
|
@ -327,22 +259,18 @@ class CuraEngineBackend(Backend):
|
|||
if self._stored_layer_data:
|
||||
job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(self._stored_layer_data)
|
||||
job.start()
|
||||
self._stored_layer_data = None
|
||||
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()
|
||||
def _onInstanceChanged(self):
|
||||
self._slicing = False
|
||||
self._restart = True
|
||||
if self._process is not None:
|
||||
Logger.log("d", "Killing engine process")
|
||||
try:
|
||||
self._process.terminate()
|
||||
except: # terminating a process that is already terminating causes an exception, silently ignore this.
|
||||
pass
|
||||
self.slicingCancelled.emit()
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: Cura.proto
|
||||
|
||||
import sys
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
|
@ -18,7 +16,8 @@ _sym_db = _symbol_database.Default()
|
|||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='Cura.proto',
|
||||
package='cura.proto',
|
||||
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')
|
||||
syntax='proto3',
|
||||
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\"\x8e\x02\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\"\xb6\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\x12\x13\n\x0fMoveCombingType\x10\x08\x12\x16\n\x12MoveRetractionType\x10\t\"&\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)
|
||||
|
||||
|
@ -62,11 +61,19 @@ _POLYGON_TYPE = _descriptor.EnumDescriptor(
|
|||
name='SupportInfillType', index=7, number=7,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='MoveCombingType', index=8, number=8,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='MoveRetractionType', index=9, number=9,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=622,
|
||||
serialized_end=759,
|
||||
serialized_end=804,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_POLYGON_TYPE)
|
||||
|
||||
|
@ -100,6 +107,7 @@ _OBJECTLIST = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
|
@ -130,6 +138,7 @@ _SLICE = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
|
@ -155,21 +164,21 @@ _OBJECT = _descriptor.Descriptor(
|
|||
_descriptor.FieldDescriptor(
|
||||
name='vertices', full_name='cura.proto.Object.vertices', index=1,
|
||||
number=2, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=b"",
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='normals', full_name='cura.proto.Object.normals', index=2,
|
||||
number=3, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=b"",
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='indices', full_name='cura.proto.Object.indices', index=3,
|
||||
number=4, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=b"",
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
|
@ -188,6 +197,7 @@ _OBJECT = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
|
@ -218,6 +228,7 @@ _PROGRESS = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
|
@ -248,6 +259,7 @@ _SLICEDOBJECTLIST = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
|
@ -285,6 +297,7 @@ _SLICEDOBJECT = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
|
@ -336,6 +349,7 @@ _LAYER = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
|
@ -361,7 +375,7 @@ _POLYGON = _descriptor.Descriptor(
|
|||
_descriptor.FieldDescriptor(
|
||||
name='points', full_name='cura.proto.Polygon.points', index=1,
|
||||
number=2, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=b"",
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
|
@ -381,11 +395,12 @@ _POLYGON = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=534,
|
||||
serialized_end=759,
|
||||
serialized_end=804,
|
||||
)
|
||||
|
||||
|
||||
|
@ -406,7 +421,7 @@ _GCODELAYER = _descriptor.Descriptor(
|
|||
_descriptor.FieldDescriptor(
|
||||
name='data', full_name='cura.proto.GCodeLayer.data', index=1,
|
||||
number=2, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=b"",
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
|
@ -418,11 +433,12 @@ _GCODELAYER = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=761,
|
||||
serialized_end=799,
|
||||
serialized_start=806,
|
||||
serialized_end=844,
|
||||
)
|
||||
|
||||
|
||||
|
@ -462,11 +478,12 @@ _OBJECTPRINTTIME = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=801,
|
||||
serialized_end=869,
|
||||
serialized_start=846,
|
||||
serialized_end=914,
|
||||
)
|
||||
|
||||
|
||||
|
@ -492,11 +509,12 @@ _SETTINGLIST = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=871,
|
||||
serialized_end=923,
|
||||
serialized_start=916,
|
||||
serialized_end=968,
|
||||
)
|
||||
|
||||
|
||||
|
@ -510,14 +528,14 @@ _SETTING = _descriptor.Descriptor(
|
|||
_descriptor.FieldDescriptor(
|
||||
name='name', full_name='cura.proto.Setting.name', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value', full_name='cura.proto.Setting.value', index=1,
|
||||
number=2, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=b"",
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
|
@ -529,11 +547,12 @@ _SETTING = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=925,
|
||||
serialized_end=963,
|
||||
serialized_start=970,
|
||||
serialized_end=1008,
|
||||
)
|
||||
|
||||
|
||||
|
@ -547,7 +566,7 @@ _GCODEPREFIX = _descriptor.Descriptor(
|
|||
_descriptor.FieldDescriptor(
|
||||
name='data', full_name='cura.proto.GCodePrefix.data', index=0,
|
||||
number=2, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
has_default_value=False, default_value=b"",
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
|
@ -559,11 +578,12 @@ _GCODEPREFIX = _descriptor.Descriptor(
|
|||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=965,
|
||||
serialized_end=992,
|
||||
serialized_start=1010,
|
||||
serialized_end=1037,
|
||||
)
|
||||
|
||||
_OBJECTLIST.fields_by_name['objects'].message_type = _OBJECT
|
||||
|
|
|
@ -10,8 +10,8 @@ from UM.Mesh.MeshData import MeshData
|
|||
from UM.Message import Message
|
||||
from UM.i18n import i18nCatalog
|
||||
|
||||
from . import LayerData
|
||||
from . import LayerDataDecorator
|
||||
from cura import LayerData
|
||||
from cura import LayerDataDecorator
|
||||
|
||||
import numpy
|
||||
import struct
|
||||
|
@ -32,19 +32,18 @@ class ProcessSlicedObjectListJob(Job):
|
|||
|
||||
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
|
||||
|
||||
objectIdMap = {}
|
||||
object_id_map = {}
|
||||
new_node = SceneNode()
|
||||
## Put all nodes in a dict identified by ID
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if type(node) is SceneNode and node.getMeshData():
|
||||
if node.callDecoration("getLayerData"):
|
||||
#if hasattr(node.getMeshData(), "layerData"):
|
||||
self._scene.getRoot().removeChild(node)
|
||||
else:
|
||||
objectIdMap[id(node)] = node
|
||||
object_id_map[id(node)] = node
|
||||
Job.yieldThread()
|
||||
|
||||
settings = Application.getInstance().getMachineManager().getActiveProfile()
|
||||
layerHeight = settings.getSettingValue("layer_height")
|
||||
|
||||
center = None
|
||||
if not settings.getSettingValue("machine_center_is_zero"):
|
||||
|
@ -54,9 +53,15 @@ class ProcessSlicedObjectListJob(Job):
|
|||
|
||||
mesh = MeshData()
|
||||
layer_data = LayerData.LayerData()
|
||||
|
||||
layer_count = 0
|
||||
for object in self._message.objects:
|
||||
layer_count += len(object.layers)
|
||||
|
||||
current_layer = 0
|
||||
for object in self._message.objects:
|
||||
try:
|
||||
node = objectIdMap[object.id]
|
||||
node = object_id_map[object.id]
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
|
@ -73,23 +78,34 @@ class ProcessSlicedObjectListJob(Job):
|
|||
|
||||
points[:,2] *= -1
|
||||
|
||||
points -= numpy.array(center)
|
||||
points -= center
|
||||
|
||||
layer_data.addPolygon(layer.id, polygon.type, points, polygon.line_width)
|
||||
|
||||
Job.yieldThread()
|
||||
|
||||
current_layer += 1
|
||||
progress = (current_layer / layer_count) * 100
|
||||
# TODO: Rebuild the layer data mesh once the layer has been processed.
|
||||
# This needs some work in LayerData so we can add the new layers instead of recreating the entire mesh.
|
||||
|
||||
if self._progress:
|
||||
self._progress.setProgress(progress)
|
||||
|
||||
# We are done processing all the layers we got from the engine, now create a mesh out of the data
|
||||
layer_data.build()
|
||||
|
||||
|
||||
#Add layerdata decorator to scene node to indicate that the node has layerdata
|
||||
decorator = LayerDataDecorator.LayerDataDecorator()
|
||||
decorator.setLayerData(layer_data)
|
||||
new_node.addDecorator(decorator)
|
||||
|
||||
|
||||
new_node.setMeshData(mesh)
|
||||
new_node.setParent(self._scene.getRoot())
|
||||
|
||||
|
||||
if self._progress:
|
||||
self._progress.setProgress(100)
|
||||
|
||||
view = Application.getInstance().getController().getActiveView()
|
||||
if view.getPluginId() == "LayerView":
|
||||
view.resetLayerData()
|
||||
|
|
152
plugins/CuraEngineBackend/StartSliceJob.py
Normal file
152
plugins/CuraEngineBackend/StartSliceJob.py
Normal file
|
@ -0,0 +1,152 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import numpy
|
||||
from string import Formatter
|
||||
import traceback
|
||||
|
||||
from UM.Job import Job
|
||||
from UM.Application import Application
|
||||
from UM.Logger import Logger
|
||||
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
|
||||
from cura.OneAtATimeIterator import OneAtATimeIterator
|
||||
|
||||
from . import Cura_pb2
|
||||
|
||||
## Formatter class that handles token expansion in start/end gcod
|
||||
class GcodeStartEndFormatter(Formatter):
|
||||
def get_value(self, key, args, kwargs): # [CodeStyle: get_value is an overridden function from the Formatter class]
|
||||
if isinstance(key, str):
|
||||
try:
|
||||
return kwargs[key]
|
||||
except KeyError:
|
||||
Logger.log("w", "Unable to replace '%s' placeholder in start/end gcode", key)
|
||||
return "{" + key + "}"
|
||||
else:
|
||||
Logger.log("w", "Incorrectly formatted placeholder '%s' in start/end gcode", key)
|
||||
return "{" + str(key) + "}"
|
||||
|
||||
## Job class that handles sending the current scene data to CuraEngine
|
||||
class StartSliceJob(Job):
|
||||
def __init__(self, profile, socket):
|
||||
super().__init__()
|
||||
|
||||
self._scene = Application.getInstance().getController().getScene()
|
||||
self._profile = profile
|
||||
self._socket = socket
|
||||
|
||||
def run(self):
|
||||
self._scene.acquireLock()
|
||||
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if node.callDecoration("getLayerData"):
|
||||
node.getParent().removeChild(node)
|
||||
break
|
||||
|
||||
object_groups = []
|
||||
if self._profile.getSettingValue("print_sequence") == "one_at_a_time":
|
||||
for node in OneAtATimeIterator(self._scene.getRoot()):
|
||||
temp_list = []
|
||||
|
||||
if getattr(node, "_outside_buildarea", False):
|
||||
continue
|
||||
|
||||
children = node.getAllChildren()
|
||||
children.append(node)
|
||||
for child_node in children:
|
||||
if type(child_node) is SceneNode and child_node.getMeshData() and child_node.getMeshData().getVertices() is not None:
|
||||
temp_list.append(child_node)
|
||||
|
||||
if temp_list:
|
||||
object_groups.append(temp_list)
|
||||
Job.yieldThread()
|
||||
else:
|
||||
temp_list = []
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
|
||||
if not getattr(node, "_outside_buildarea", False):
|
||||
temp_list.append(node)
|
||||
Job.yieldThread()
|
||||
|
||||
if temp_list:
|
||||
object_groups.append(temp_list)
|
||||
|
||||
self._scene.releaseLock()
|
||||
|
||||
if not object_groups:
|
||||
return
|
||||
|
||||
self._sendSettings(self._profile)
|
||||
|
||||
slice_message = Cura_pb2.Slice()
|
||||
|
||||
for group in object_groups:
|
||||
group_message = slice_message.object_lists.add()
|
||||
for object in group:
|
||||
mesh_data = object.getMeshData().getTransformed(object.getWorldTransformation())
|
||||
|
||||
obj = group_message.objects.add()
|
||||
obj.id = id(object)
|
||||
|
||||
verts = numpy.array(mesh_data.getVertices())
|
||||
verts[:,[1,2]] = verts[:,[2,1]]
|
||||
verts[:,1] *= -1
|
||||
obj.vertices = verts.tostring()
|
||||
|
||||
self._handlePerObjectSettings(object, obj)
|
||||
|
||||
Job.yieldThread()
|
||||
|
||||
Logger.log("d", "Sending data to engine for slicing.")
|
||||
self._socket.sendMessage(slice_message)
|
||||
|
||||
self.setResult(True)
|
||||
|
||||
def _expandGcodeTokens(self, key, value, settings):
|
||||
try:
|
||||
# any setting can be used as a token
|
||||
fmt = GcodeStartEndFormatter()
|
||||
return str(fmt.format(value, **settings)).encode("utf-8")
|
||||
except:
|
||||
Logger.log("w", "Unabled to do token replacement on start/end gcode %s", traceback.format_exc())
|
||||
return str(value).encode("utf-8")
|
||||
|
||||
def _sendSettings(self, profile):
|
||||
msg = Cura_pb2.SettingList()
|
||||
settings = profile.getAllSettingValues(include_machine = True)
|
||||
start_gcode = settings["machine_start_gcode"]
|
||||
settings["material_bed_temp_prepend"] = "{material_bed_temperature}" not in start_gcode
|
||||
settings["material_print_temp_prepend"] = "{material_print_temperature}" not in start_gcode
|
||||
for key, value in settings.items():
|
||||
s = msg.settings.add()
|
||||
s.name = key
|
||||
if key == "machine_start_gcode" or key == "machine_end_gcode":
|
||||
s.value = self._expandGcodeTokens(key, value, settings)
|
||||
else:
|
||||
s.value = str(value).encode("utf-8")
|
||||
|
||||
self._socket.sendMessage(msg)
|
||||
|
||||
def _handlePerObjectSettings(self, node, message):
|
||||
profile = node.callDecoration("getProfile")
|
||||
if profile:
|
||||
for key, value in profile.getAllSettingValues().items():
|
||||
setting = message.settings.add()
|
||||
setting.name = key
|
||||
setting.value = str(value).encode()
|
||||
|
||||
Job.yieldThread()
|
||||
|
||||
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()
|
||||
|
||||
Job.yieldThread()
|
8
plugins/GCodeReader/GCodeReader.py
Normal file
8
plugins/GCodeReader/GCodeReader.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from UM.Mesh.MeshReader import MeshReader
|
||||
|
||||
class GCodeReader(MeshReader):
|
||||
def read(self, file_name):
|
||||
pass
|
25
plugins/GCodeReader/__init__.py
Normal file
25
plugins/GCodeReader/__init__.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from . import GCodeReader
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
"plugin": {
|
||||
"name": catalog.i18nc("@label", "GCode Reader"),
|
||||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"description": catalog.i18nc("@info:whatsthis", "Provides support for reading GCode files."),
|
||||
"api": 2
|
||||
},
|
||||
"mesh_reader": {
|
||||
"extension": "gcode",
|
||||
"description": catalog.i18nc("@item:inlistbox", "Gcode File")
|
||||
}
|
||||
}
|
||||
|
||||
def register(app):
|
||||
return { "mesh_reader": GCodeReader.GCodeReader() }
|
|
@ -11,6 +11,9 @@ from UM.Scene.Selection import Selection
|
|||
from UM.Math.Color import Color
|
||||
from UM.Mesh.MeshData import MeshData
|
||||
|
||||
from UM.View.RenderBatch import RenderBatch
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
from cura.ConvexHullNode import ConvexHullNode
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
@ -21,7 +24,8 @@ from . import LayerViewProxy
|
|||
class LayerView(View):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._material = None
|
||||
self._shader = None
|
||||
self._selection_shader = None
|
||||
self._num_layers = 0
|
||||
self._layer_percentage = 0 # what percentage of layers need to be shown (SLider gives value between 0 - 100)
|
||||
self._proxy = LayerViewProxy.LayerViewProxy()
|
||||
|
@ -29,6 +33,7 @@ class LayerView(View):
|
|||
self._max_layers = 10
|
||||
self._current_layer_num = 10
|
||||
self._current_layer_mesh = None
|
||||
self._current_layer_jumps = None
|
||||
self._activity = False
|
||||
|
||||
self._solid_layers = 5
|
||||
|
@ -47,18 +52,15 @@ class LayerView(View):
|
|||
|
||||
def resetLayerData(self):
|
||||
self._current_layer_mesh = None
|
||||
self._current_layer_jumps = None
|
||||
|
||||
def beginRendering(self):
|
||||
scene = self.getController().getScene()
|
||||
renderer = self.getRenderer()
|
||||
renderer.setRenderSelection(False)
|
||||
|
||||
if not self._material:
|
||||
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.Shaders, "basic.vert"), Resources.getPath(Resources.Shaders, "color.frag"))
|
||||
self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128))
|
||||
if not self._selection_shader:
|
||||
self._selection_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader"))
|
||||
self._selection_shader.setUniformValue("u_color", Color(32, 32, 32, 128))
|
||||
|
||||
for node in DepthFirstIterator(scene.getRoot()):
|
||||
# We do not want to render ConvexHullNode as it conflicts with the bottom layers.
|
||||
|
@ -69,7 +71,7 @@ class LayerView(View):
|
|||
if not node.render(renderer):
|
||||
if node.getMeshData() and node.isVisible():
|
||||
if Selection.isSelected(node):
|
||||
renderer.queueNode(node, material = self._selection_material, transparent = True)
|
||||
renderer.queueNode(node, transparent = True, shader = self._selection_shader)
|
||||
layer_data = node.callDecoration("getLayerData")
|
||||
if not layer_data:
|
||||
continue
|
||||
|
@ -85,7 +87,7 @@ class LayerView(View):
|
|||
end += counts
|
||||
|
||||
# This uses glDrawRangeElements internally to only draw a certain range of lines.
|
||||
renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end)
|
||||
renderer.queueNode(node, mesh = layer_data, mode = RenderBatch.RenderMode.Lines, range = (start, end))
|
||||
|
||||
# We currently recreate the current "solid" layers every time a
|
||||
if not self._current_layer_mesh:
|
||||
|
@ -100,15 +102,38 @@ class LayerView(View):
|
|||
continue
|
||||
except:
|
||||
continue
|
||||
|
||||
self._current_layer_mesh.addVertices(layer_mesh.getVertices())
|
||||
if self._current_layer_mesh: #Threading thing; Switching between views can cause the current layer mesh to be deleted.
|
||||
self._current_layer_mesh.addVertices(layer_mesh.getVertices())
|
||||
|
||||
# Scale layer color by a brightness factor based on the current layer number
|
||||
# This will result in a range of 0.5 - 1.0 to multiply colors by.
|
||||
brightness = (2.0 - (i / self._solid_layers)) / 2.0
|
||||
self._current_layer_mesh.addColors(layer_mesh.getColors() * brightness)
|
||||
if self._current_layer_mesh:
|
||||
self._current_layer_mesh.addColors(layer_mesh.getColors() * brightness)
|
||||
if self._current_layer_mesh:
|
||||
renderer.queueNode(node, mesh = self._current_layer_mesh)
|
||||
|
||||
renderer.queueNode(node, mesh = self._current_layer_mesh, material = self._material)
|
||||
if not self._current_layer_jumps:
|
||||
self._current_layer_jumps = MeshData()
|
||||
for i in range(1):
|
||||
layer = self._current_layer_num - i
|
||||
if layer < 0:
|
||||
continue
|
||||
try:
|
||||
layer_mesh = layer_data.getLayer(layer).createJumps()
|
||||
if not layer_mesh or layer_mesh.getVertices() is None:
|
||||
continue
|
||||
except:
|
||||
continue
|
||||
|
||||
self._current_layer_jumps.addVertices(layer_mesh.getVertices())
|
||||
|
||||
# Scale layer color by a brightness factor based on the current layer number
|
||||
# This will result in a range of 0.5 - 1.0 to multiply colors by.
|
||||
brightness = (2.0 - (i / self._solid_layers)) / 2.0
|
||||
self._current_layer_jumps.addColors(layer_mesh.getColors() * brightness)
|
||||
|
||||
renderer.queueNode(node, mesh = self._current_layer_jumps)
|
||||
|
||||
def setLayer(self, value):
|
||||
if self._current_layer_num != value:
|
||||
|
@ -119,6 +144,7 @@ class LayerView(View):
|
|||
self._current_layer_num = self._max_layers
|
||||
|
||||
self._current_layer_mesh = None
|
||||
self._current_layer_jumps = None
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
currentLayerNumChanged = Signal()
|
||||
|
@ -126,31 +152,27 @@ class LayerView(View):
|
|||
def calculateMaxLayers(self):
|
||||
scene = self.getController().getScene()
|
||||
renderer = self.getRenderer()
|
||||
if renderer and self._material:
|
||||
self._activity = True
|
||||
renderer.setRenderSelection(False)
|
||||
self._old_max_layers = self._max_layers
|
||||
## Recalculate num max layers
|
||||
new_max_layers = 0
|
||||
for node in DepthFirstIterator(scene.getRoot()):
|
||||
if not node.render(renderer):
|
||||
if node.getMeshData() and node.isVisible():
|
||||
|
||||
layer_data = node.callDecoration("getLayerData")
|
||||
if not layer_data:
|
||||
continue
|
||||
self._activity = True
|
||||
|
||||
if new_max_layers < len(layer_data.getLayers()):
|
||||
new_max_layers = len(layer_data.getLayers()) - 1
|
||||
self._old_max_layers = self._max_layers
|
||||
## Recalculate num max layers
|
||||
new_max_layers = 0
|
||||
for node in DepthFirstIterator(scene.getRoot()):
|
||||
layer_data = node.callDecoration("getLayerData")
|
||||
if not layer_data:
|
||||
continue
|
||||
|
||||
if new_max_layers > 0 and new_max_layers != self._old_max_layers:
|
||||
self._max_layers = new_max_layers
|
||||
self.maxLayersChanged.emit()
|
||||
self._current_layer_num = self._max_layers
|
||||
if new_max_layers < len(layer_data.getLayers()):
|
||||
new_max_layers = len(layer_data.getLayers()) - 1
|
||||
|
||||
# This makes sure we update the current layer
|
||||
self.setLayer(int(self._max_layers))
|
||||
self.currentLayerNumChanged.emit()
|
||||
if new_max_layers > 0 and new_max_layers != self._old_max_layers:
|
||||
self._max_layers = new_max_layers
|
||||
self.maxLayersChanged.emit()
|
||||
self._current_layer_num = self._max_layers
|
||||
|
||||
# This makes sure we update the current layer
|
||||
self.setLayer(int(self._max_layers))
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
maxLayersChanged = Signal()
|
||||
currentLayerNumChanged = Signal()
|
||||
|
|
|
@ -10,16 +10,16 @@ import UM 1.0 as UM
|
|||
|
||||
Item
|
||||
{
|
||||
width: 250
|
||||
height: 250
|
||||
width: UM.Theme.sizes.button.width
|
||||
height: UM.Theme.sizes.slider_layerview_size.height
|
||||
|
||||
Slider
|
||||
{
|
||||
id: slider
|
||||
width: 10
|
||||
height: 250
|
||||
anchors.right : parent.right
|
||||
anchors.rightMargin: UM.Theme.sizes.slider_layerview_margin.width/2
|
||||
width: UM.Theme.sizes.slider_layerview_size.width
|
||||
height: UM.Theme.sizes.slider_layerview_size.height
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: UM.Theme.sizes.slider_layerview_margin.width/2
|
||||
orientation: Qt.Vertical
|
||||
minimumValue: 0;
|
||||
maximumValue: UM.LayerView.numLayers;
|
||||
|
@ -31,15 +31,7 @@ Item
|
|||
style: UM.Theme.styles.layerViewSlider
|
||||
}
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
y: -UM.Theme.sizes.slider_layerview_background_extension.height
|
||||
z: slider.z - 1
|
||||
width: UM.Theme.sizes.button.width
|
||||
height: UM.Theme.sizes.slider_layerview_background_extension.height
|
||||
color: UM.Theme.colors.slider_text_background
|
||||
}
|
||||
Rectangle {
|
||||
anchors.right : parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
z: slider.z - 1
|
||||
width: UM.Theme.sizes.slider_layerview_background.width
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty
|
||||
from UM.Application import Application
|
||||
|
||||
import LayerView
|
||||
|
||||
class LayerViewProxy(QObject):
|
||||
def __init__(self, parent = None):
|
||||
super().__init__(parent)
|
||||
|
@ -52,4 +54,4 @@ class LayerViewProxy(QObject):
|
|||
active_view = self._controller.getActiveView()
|
||||
if type(active_view) == LayerView.LayerView.LayerView:
|
||||
active_view.currentLayerNumChanged.connect(self._onLayerChanged)
|
||||
active_view.maxLayersChanged.connect(self._onMaxLayersChanged)
|
||||
active_view.maxLayersChanged.connect(self._onMaxLayersChanged)
|
||||
|
|
109
plugins/PerObjectSettingsTool/PerObjectSettingsModel.py
Normal file
109
plugins/PerObjectSettingsTool/PerObjectSettingsModel.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSlot, QUrl
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Qt.ListModel import ListModel
|
||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator
|
||||
from UM.Settings.ProfileOverrideDecorator import ProfileOverrideDecorator
|
||||
|
||||
from . import SettingOverrideModel
|
||||
|
||||
class PerObjectSettingsModel(ListModel):
|
||||
IdRole = Qt.UserRole + 1
|
||||
XRole = Qt.UserRole + 2
|
||||
YRole = Qt.UserRole + 3
|
||||
MaterialRole = Qt.UserRole + 4
|
||||
ProfileRole = Qt.UserRole + 5
|
||||
SettingsRole = Qt.UserRole + 6
|
||||
|
||||
def __init__(self, parent = None):
|
||||
super().__init__(parent)
|
||||
self._scene = Application.getInstance().getController().getScene()
|
||||
self._root = self._scene.getRoot()
|
||||
self._root.transformationChanged.connect(self._updatePositions)
|
||||
self._root.childrenChanged.connect(self._updateNodes)
|
||||
self._updateNodes(None)
|
||||
|
||||
self.addRoleName(self.IdRole,"id")
|
||||
self.addRoleName(self.XRole,"x")
|
||||
self.addRoleName(self.YRole,"y")
|
||||
self.addRoleName(self.MaterialRole, "material")
|
||||
self.addRoleName(self.ProfileRole, "profile")
|
||||
self.addRoleName(self.SettingsRole, "settings")
|
||||
|
||||
@pyqtSlot("quint64", str)
|
||||
def setObjectProfile(self, object_id, profile_name):
|
||||
self.setProperty(self.find("id", object_id), "profile", profile_name)
|
||||
|
||||
profile = None
|
||||
if profile_name != "global":
|
||||
profile = Application.getInstance().getMachineManager().findProfile(profile_name)
|
||||
|
||||
node = self._scene.findObject(object_id)
|
||||
if profile:
|
||||
if not node.getDecorator(ProfileOverrideDecorator):
|
||||
node.addDecorator(ProfileOverrideDecorator())
|
||||
node.callDecoration("setProfile", profile)
|
||||
else:
|
||||
if node.getDecorator(ProfileOverrideDecorator):
|
||||
node.removeDecorator(ProfileOverrideDecorator)
|
||||
|
||||
@pyqtSlot("quint64", str)
|
||||
def addSettingOverride(self, object_id, key):
|
||||
machine = Application.getInstance().getMachineManager().getActiveMachineInstance()
|
||||
if not machine:
|
||||
return
|
||||
|
||||
node = self._scene.findObject(object_id)
|
||||
if not node.getDecorator(SettingOverrideDecorator):
|
||||
node.addDecorator(SettingOverrideDecorator())
|
||||
|
||||
node.callDecoration("addSetting", key)
|
||||
|
||||
@pyqtSlot("quint64", str)
|
||||
def removeSettingOverride(self, object_id, key):
|
||||
node = self._scene.findObject(object_id)
|
||||
node.callDecoration("removeSetting", key)
|
||||
|
||||
if len(node.callDecoration("getAllSettings")) == 0:
|
||||
node.removeDecorator(SettingOverrideDecorator)
|
||||
|
||||
def _updatePositions(self, source):
|
||||
camera = Application.getInstance().getController().getScene().getActiveCamera()
|
||||
for node in BreadthFirstIterator(self._root):
|
||||
if type(node) is not SceneNode or not node.getMeshData():
|
||||
continue
|
||||
|
||||
projected_position = camera.project(node.getWorldPosition())
|
||||
|
||||
index = self.find("id", id(node))
|
||||
self.setProperty(index, "x", float(projected_position[0]))
|
||||
self.setProperty(index, "y", float(projected_position[1]))
|
||||
|
||||
def _updateNodes(self, source):
|
||||
self.clear()
|
||||
camera = Application.getInstance().getController().getScene().getActiveCamera()
|
||||
for node in BreadthFirstIterator(self._root):
|
||||
if type(node) is not SceneNode or not node.getMeshData() or not node.isSelectable():
|
||||
continue
|
||||
|
||||
projected_position = camera.project(node.getWorldPosition())
|
||||
|
||||
node_profile = node.callDecoration("getProfile")
|
||||
if not node_profile:
|
||||
node_profile = "global"
|
||||
else:
|
||||
node_profile = node_profile.getName()
|
||||
|
||||
self.appendItem({
|
||||
"id": id(node),
|
||||
"x": float(projected_position[0]),
|
||||
"y": float(projected_position[1]),
|
||||
"material": "",
|
||||
"profile": node_profile,
|
||||
"settings": SettingOverrideModel.SettingOverrideModel(node)
|
||||
})
|
311
plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml
Normal file
311
plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml
Normal file
|
@ -0,0 +1,311 @@
|
|||
// Copyright (c) 2015 Ultimaker B.V.
|
||||
// Uranium is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Controls.Styles 1.2
|
||||
import QtQuick.Window 2.2
|
||||
|
||||
import UM 1.1 as UM
|
||||
|
||||
Item {
|
||||
id: base;
|
||||
property int currentIndex: UM.ActiveTool.properties.SelectedIndex;
|
||||
property string printSequence: UM.ActiveTool.properties.PrintSequence;
|
||||
|
||||
width: childrenRect.width;
|
||||
height: childrenRect.height;
|
||||
|
||||
Column {
|
||||
id: items
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
|
||||
spacing: UM.Theme.sizes.default_margin.height;
|
||||
|
||||
Label {
|
||||
width: UM.Theme.sizes.setting.width;
|
||||
wrapMode: Text.Wrap;
|
||||
text: catalog.i18nc("@label", "Per Object Settings behavior may be unexpected when 'Print sequence' is set to 'All at Once'.")
|
||||
color: UM.Theme.colors.text;
|
||||
visible: base.printSequence == "all_at_once"
|
||||
}
|
||||
|
||||
UM.SettingItem {
|
||||
id: profileSelection
|
||||
|
||||
width: UM.Theme.sizes.setting.width;
|
||||
height: UM.Theme.sizes.setting.height;
|
||||
|
||||
name: catalog.i18nc("@label", "Object profile")
|
||||
type: "enum"
|
||||
indent: false
|
||||
|
||||
style: UM.Theme.styles.setting_item;
|
||||
|
||||
options: UM.ProfilesModel { addUseGlobal: true }
|
||||
|
||||
value: UM.ActiveTool.properties.Model.getItem(base.currentIndex).profile
|
||||
|
||||
onItemValueChanged: {
|
||||
var item = UM.ActiveTool.properties.Model.getItem(base.currentIndex);
|
||||
UM.ActiveTool.properties.Model.setObjectProfile(item.id, value)
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: customisedSettings
|
||||
spacing: UM.Theme.sizes.default_lining.height;
|
||||
width: UM.Theme.sizes.setting.width + UM.Theme.sizes.setting.height/2;
|
||||
|
||||
Repeater {
|
||||
id: settings;
|
||||
|
||||
model: UM.ActiveTool.properties.Model.getItem(base.currentIndex).settings
|
||||
|
||||
UM.SettingItem {
|
||||
width: UM.Theme.sizes.setting.width;
|
||||
height: UM.Theme.sizes.setting.height;
|
||||
|
||||
name: model.label;
|
||||
type: model.type;
|
||||
value: model.value;
|
||||
description: model.description;
|
||||
unit: model.unit;
|
||||
valid: model.valid;
|
||||
options: model.options
|
||||
indent: false
|
||||
|
||||
style: UM.Theme.styles.setting_item;
|
||||
|
||||
onItemValueChanged: {
|
||||
settings.model.setSettingValue(model.key, value)
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
anchors.left: parent.right;
|
||||
|
||||
width: UM.Theme.sizes.setting.height;
|
||||
height: UM.Theme.sizes.setting.height;
|
||||
|
||||
onClicked: UM.ActiveTool.properties.Model.removeSettingOverride(UM.ActiveTool.properties.Model.getItem(base.currentIndex).id, model.key)
|
||||
|
||||
style: ButtonStyle
|
||||
{
|
||||
background: Rectangle
|
||||
{
|
||||
color: control.hovered ? control.parent.style.controlHighlightColor : control.parent.style.controlColor;
|
||||
UM.RecolorImage
|
||||
{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width/2
|
||||
height: parent.height/2
|
||||
sourceSize.width: width
|
||||
sourceSize.height: width
|
||||
color: UM.Theme.colors.setting_control_revert
|
||||
source: UM.Theme.icons.cross1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
id: customise_settings_button;
|
||||
anchors.right: profileSelection.right;
|
||||
height: UM.Theme.sizes.setting.height;
|
||||
visible: parseInt(UM.Preferences.getValue("cura/active_mode")) == 1
|
||||
|
||||
text: catalog.i18nc("@action:button", "Add Setting");
|
||||
|
||||
style: ButtonStyle
|
||||
{
|
||||
background: Rectangle
|
||||
{
|
||||
width: control.width;
|
||||
height: control.height;
|
||||
border.width: UM.Theme.sizes.default_lining.width;
|
||||
border.color: control.pressed ? UM.Theme.colors.action_button_active_border :
|
||||
control.hovered ? UM.Theme.colors.action_button_hovered_border : UM.Theme.colors.action_button_border
|
||||
color: control.pressed ? UM.Theme.colors.action_button_active :
|
||||
control.hovered ? UM.Theme.colors.action_button_hovered : UM.Theme.colors.action_button
|
||||
}
|
||||
label: Label
|
||||
{
|
||||
text: control.text;
|
||||
color: UM.Theme.colors.setting_control_text;
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: settingPickDialog.visible = true;
|
||||
|
||||
Connections
|
||||
{
|
||||
target: UM.Preferences;
|
||||
|
||||
onPreferenceChanged:
|
||||
{
|
||||
customise_settings_button.visible = parseInt(UM.Preferences.getValue("cura/active_mode"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UM.I18nCatalog { id: catalog; name: "uranium"; }
|
||||
|
||||
UM.Dialog {
|
||||
id: settingPickDialog
|
||||
|
||||
title: catalog.i18nc("@title:window", "Pick a Setting to Customize")
|
||||
|
||||
TextField {
|
||||
id: filter;
|
||||
|
||||
anchors {
|
||||
top: parent.top;
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
}
|
||||
|
||||
placeholderText: catalog.i18nc("@label:textbox", "Filter...");
|
||||
|
||||
onTextChanged: settingCategoriesModel.filter(text);
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: view;
|
||||
anchors {
|
||||
top: filter.bottom;
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
bottom: parent.bottom;
|
||||
}
|
||||
|
||||
Column {
|
||||
width: view.width - UM.Theme.sizes.default_margin.width * 2;
|
||||
height: childrenRect.height;
|
||||
|
||||
Repeater {
|
||||
id: settingList;
|
||||
|
||||
model: UM.SettingCategoriesModel { id: settingCategoriesModel; }
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem;
|
||||
|
||||
width: parent.width;
|
||||
height: childrenRect.height;
|
||||
|
||||
ToolButton {
|
||||
id: categoryHeader;
|
||||
text: model.name;
|
||||
checkable: true;
|
||||
width: parent.width;
|
||||
onCheckedChanged: settingsColumn.state != "" ? settingsColumn.state = "" : settingsColumn.state = "collapsed";
|
||||
|
||||
style: ButtonStyle {
|
||||
background: Rectangle
|
||||
{
|
||||
width: control.width;
|
||||
height: control.height;
|
||||
color: control.hovered ? palette.highlight : "transparent";
|
||||
}
|
||||
label: Row
|
||||
{
|
||||
spacing: UM.Theme.sizes.default_margin.width;
|
||||
Image
|
||||
{
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
source: control.checked ? UM.Theme.icons.arrow_right : UM.Theme.icons.arrow_bottom;
|
||||
}
|
||||
Label
|
||||
{
|
||||
text: control.text;
|
||||
font.bold: true;
|
||||
color: control.hovered ? palette.highlightedText : palette.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property variant settingsModel: model.settings;
|
||||
|
||||
visible: model.visible;
|
||||
|
||||
Column {
|
||||
id: settingsColumn;
|
||||
|
||||
anchors.top: categoryHeader.bottom;
|
||||
|
||||
property real childrenHeight:
|
||||
{
|
||||
var h = 0.0;
|
||||
for(var i in children)
|
||||
{
|
||||
var item = children[i];
|
||||
h += children[i].height;
|
||||
if(item.settingVisible)
|
||||
{
|
||||
if(i > 0)
|
||||
{
|
||||
h += spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
width: childrenRect.width;
|
||||
height: childrenHeight;
|
||||
Repeater {
|
||||
model: delegateItem.settingsModel;
|
||||
|
||||
delegate: ToolButton {
|
||||
id: button;
|
||||
x: model.depth * UM.Theme.sizes.default_margin.width;
|
||||
text: model.name;
|
||||
tooltip: model.description;
|
||||
|
||||
onClicked: {
|
||||
var object_id = UM.ActiveTool.properties.Model.getItem(base.currentIndex).id;
|
||||
UM.ActiveTool.properties.Model.addSettingOverride(object_id, model.key);
|
||||
settingPickDialog.visible = false;
|
||||
}
|
||||
|
||||
states: State {
|
||||
name: "filtered"
|
||||
when: model.filtered || !model.visible || !model.enabled
|
||||
PropertyChanges { target: button; height: 0; opacity: 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
states: State {
|
||||
name: "collapsed";
|
||||
|
||||
PropertyChanges { target: settingsColumn; opacity: 0; height: 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rightButtons: [
|
||||
Button {
|
||||
text: catalog.i18nc("@action:button", "Cancel");
|
||||
onClicked: {
|
||||
settingPickDialog.visible = false;
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
SystemPalette { id: palette; }
|
||||
}
|
29
plugins/PerObjectSettingsTool/PerObjectSettingsTool.py
Normal file
29
plugins/PerObjectSettingsTool/PerObjectSettingsTool.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from UM.Tool import Tool
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Application import Application
|
||||
|
||||
from . import PerObjectSettingsModel
|
||||
|
||||
class PerObjectSettingsTool(Tool):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.setExposedProperties("Model", "SelectedIndex", "PrintSequence")
|
||||
|
||||
def event(self, event):
|
||||
return False
|
||||
|
||||
def getModel(self):
|
||||
return PerObjectSettingsModel.PerObjectSettingsModel()
|
||||
|
||||
def getSelectedIndex(self):
|
||||
selected_object_id = id(Selection.getSelectedObject(0))
|
||||
index = self.getModel().find("id", selected_object_id)
|
||||
return index
|
||||
|
||||
def getPrintSequence(self):
|
||||
settings = Application.getInstance().getMachineManager().getActiveProfile()
|
||||
return settings.getSettingValue("print_sequence")
|
100
plugins/PerObjectSettingsTool/SettingOverrideModel.py
Normal file
100
plugins/PerObjectSettingsTool/SettingOverrideModel.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSlot, QUrl
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Qt.ListModel import ListModel
|
||||
from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator
|
||||
|
||||
class SettingOverrideModel(ListModel):
|
||||
KeyRole = Qt.UserRole + 1
|
||||
LabelRole = Qt.UserRole + 2
|
||||
DescriptionRole = Qt.UserRole + 3
|
||||
ValueRole = Qt.UserRole + 4
|
||||
TypeRole = Qt.UserRole + 5
|
||||
UnitRole = Qt.UserRole + 6
|
||||
ValidRole = Qt.UserRole + 7
|
||||
OptionsRole = Qt.UserRole + 8
|
||||
WarningDescriptionRole = Qt.UserRole + 9
|
||||
ErrorDescriptionRole = Qt.UserRole + 10
|
||||
|
||||
def __init__(self, node, parent = None):
|
||||
super().__init__(parent)
|
||||
|
||||
self._ignore_setting_change = None
|
||||
|
||||
self._node = node
|
||||
self._node.decoratorsChanged.connect(self._onDecoratorsChanged)
|
||||
self._onDecoratorsChanged(None)
|
||||
|
||||
self.addRoleName(self.KeyRole, "key")
|
||||
self.addRoleName(self.LabelRole, "label")
|
||||
self.addRoleName(self.DescriptionRole, "description")
|
||||
self.addRoleName(self.ValueRole,"value")
|
||||
self.addRoleName(self.TypeRole, "type")
|
||||
self.addRoleName(self.UnitRole, "unit")
|
||||
self.addRoleName(self.ValidRole, "valid")
|
||||
self.addRoleName(self.OptionsRole, "options")
|
||||
self.addRoleName(self.WarningDescriptionRole, "warning_description")
|
||||
self.addRoleName(self.ErrorDescriptionRole, "error_description")
|
||||
|
||||
@pyqtSlot(str, "QVariant")
|
||||
def setSettingValue(self, key, value):
|
||||
if not self._decorator:
|
||||
return
|
||||
|
||||
self._decorator.setSettingValue(key, value)
|
||||
|
||||
def _onDecoratorsChanged(self, node):
|
||||
if not self._node.getDecorator(SettingOverrideDecorator):
|
||||
self.clear()
|
||||
return
|
||||
|
||||
self._decorator = self._node.getDecorator(SettingOverrideDecorator)
|
||||
self._decorator.settingAdded.connect(self._onSettingsChanged)
|
||||
self._decorator.settingRemoved.connect(self._onSettingsChanged)
|
||||
self._decorator.settingValueChanged.connect(self._onSettingValueChanged)
|
||||
self._onSettingsChanged()
|
||||
|
||||
def _createOptionsModel(self, options):
|
||||
if not options:
|
||||
return None
|
||||
|
||||
model = ListModel()
|
||||
model.addRoleName(Qt.UserRole + 1, "value")
|
||||
model.addRoleName(Qt.UserRole + 2, "name")
|
||||
for value, name in options.items():
|
||||
model.appendItem({"value": str(value), "name": str(name)})
|
||||
return model
|
||||
|
||||
def _onSettingsChanged(self):
|
||||
self.clear()
|
||||
|
||||
items = []
|
||||
for key, setting in self._decorator.getAllSettings().items():
|
||||
value = self._decorator.getSettingValue(key)
|
||||
items.append({
|
||||
"key": key,
|
||||
"label": setting.getLabel(),
|
||||
"description": setting.getDescription(),
|
||||
"value": str(value),
|
||||
"type": setting.getType(),
|
||||
"unit": setting.getUnit(),
|
||||
"valid": setting.validate(value),
|
||||
"options": self._createOptionsModel(setting.getOptions()),
|
||||
"warning_description": setting.getWarningDescription(),
|
||||
"error_description": setting.getErrorDescription()
|
||||
})
|
||||
|
||||
items.sort(key = lambda i: i["key"])
|
||||
|
||||
for item in items:
|
||||
self.appendItem(item)
|
||||
|
||||
def _onSettingValueChanged(self, setting):
|
||||
index = self.find("key", setting.getKey())
|
||||
value = self._decorator.getSettingValue(setting.getKey())
|
||||
if index != -1:
|
||||
self.setProperty(index, "value", str(value))
|
||||
self.setProperty(index, "valid", setting.validate(value))
|
28
plugins/PerObjectSettingsTool/__init__.py
Normal file
28
plugins/PerObjectSettingsTool/__init__.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from . import PerObjectSettingsTool
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
i18n_catalog = i18nCatalog("uranium")
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
"plugin": {
|
||||
"name": i18n_catalog.i18nc("@label", "Per Object Settings Tool"),
|
||||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"description": i18n_catalog.i18nc("@info:whatsthis", "Provides the Per Object Settings."),
|
||||
"api": 2
|
||||
},
|
||||
"tool": {
|
||||
"name": i18n_catalog.i18nc("@label", "Per Object Settings"),
|
||||
"description": i18n_catalog.i18nc("@info:tooltip", "Configure Per Object Settings"),
|
||||
"icon": "setting_per_object",
|
||||
"tool_panel": "PerObjectSettingsPanel.qml",
|
||||
"weight": 3
|
||||
},
|
||||
}
|
||||
|
||||
def register(app):
|
||||
return { "tool": PerObjectSettingsTool.PerObjectSettingsTool() }
|
|
@ -22,18 +22,23 @@ class RemovableDriveOutputDevice(OutputDevice):
|
|||
self.setIconName("save_sd")
|
||||
self.setPriority(1)
|
||||
|
||||
def requestWrite(self, node):
|
||||
self._writing = False
|
||||
|
||||
def requestWrite(self, node, file_name = None):
|
||||
if self._writing:
|
||||
raise OutputDeviceError.DeviceBusyError()
|
||||
|
||||
gcode_writer = Application.getInstance().getMeshFileHandler().getWriterByMimeType("text/x-gcode")
|
||||
if not gcode_writer:
|
||||
Logger.log("e", "Could not find GCode writer, not writing to removable drive %s", self.getName())
|
||||
raise OutputDeviceError.WriteRequestFailedError()
|
||||
|
||||
file_name = None
|
||||
for n in BreadthFirstIterator(node):
|
||||
if n.getMeshData():
|
||||
file_name = n.getName()
|
||||
if file_name:
|
||||
break
|
||||
if file_name == None:
|
||||
for n in BreadthFirstIterator(node):
|
||||
if n.getMeshData():
|
||||
file_name = n.getName()
|
||||
if file_name:
|
||||
break
|
||||
|
||||
if not file_name:
|
||||
Logger.log("e", "Could not determine a proper file name when trying to write to %s, aborting", self.getName())
|
||||
|
@ -52,11 +57,16 @@ class RemovableDriveOutputDevice(OutputDevice):
|
|||
message = Message(catalog.i18nc("@info:progress", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1)
|
||||
message.show()
|
||||
|
||||
self.writeStarted.emit(self)
|
||||
|
||||
job._message = message
|
||||
self._writing = True
|
||||
job.start()
|
||||
except PermissionError as e:
|
||||
Logger.log("e", "Permission denied when trying to write to %s: %s", file_name, str(e))
|
||||
raise OutputDeviceError.PermissionDeniedError() from e
|
||||
except OSError as e:
|
||||
Logger.log("e", "Operating system would not let us write to %s: %s", file_name, str(e))
|
||||
raise OutputDeviceError.WriteRequestFailedError() from e
|
||||
|
||||
def _onProgress(self, job, progress):
|
||||
|
@ -68,6 +78,8 @@ class RemovableDriveOutputDevice(OutputDevice):
|
|||
if hasattr(job, "_message"):
|
||||
job._message.hide()
|
||||
job._message = None
|
||||
|
||||
self._writing = False
|
||||
self.writeFinished.emit(self)
|
||||
if job.getResult():
|
||||
message = Message(catalog.i18nc("@info:status", "Saved to Removable Drive {0} as {1}").format(self.getName(), os.path.basename(job.getFileName())))
|
||||
|
|
|
@ -37,7 +37,11 @@ class RemovableDrivePlugin(OutputDevicePlugin):
|
|||
raise NotImplementedError()
|
||||
|
||||
def ejectDevice(self, device):
|
||||
result = self.performEjectDevice(device)
|
||||
try:
|
||||
result = self.performEjectDevice(device)
|
||||
except Exception as e:
|
||||
result = False
|
||||
|
||||
if result:
|
||||
message = Message(catalog.i18nc("@info:status", "Ejected {0}. You can now safely remove the drive.").format(device.getName()))
|
||||
message.show()
|
||||
|
|
|
@ -20,17 +20,17 @@ catalog = i18nCatalog("cura")
|
|||
|
||||
# WinAPI Constants that we need
|
||||
# Hardcoded here due to stupid WinDLL stuff that does not give us access to these values.
|
||||
DRIVE_REMOVABLE = 2
|
||||
DRIVE_REMOVABLE = 2 # [CodeStyle: Windows Enum value]
|
||||
|
||||
GENERIC_READ = 2147483648
|
||||
GENERIC_WRITE = 1073741824
|
||||
GENERIC_READ = 2147483648 # [CodeStyle: Windows Enum value]
|
||||
GENERIC_WRITE = 1073741824 # [CodeStyle: Windows Enum value]
|
||||
|
||||
FILE_SHARE_READ = 1
|
||||
FILE_SHARE_WRITE = 2
|
||||
FILE_SHARE_READ = 1 # [CodeStyle: Windows Enum value]
|
||||
FILE_SHARE_WRITE = 2 # [CodeStyle: Windows Enum value]
|
||||
|
||||
IOCTL_STORAGE_EJECT_MEDIA = 2967560
|
||||
IOCTL_STORAGE_EJECT_MEDIA = 2967560 # [CodeStyle: Windows Enum value]
|
||||
|
||||
OPEN_EXISTING = 3
|
||||
OPEN_EXISTING = 3 # [CodeStyle: Windows Enum value]
|
||||
|
||||
## Removable drive support for windows
|
||||
class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
|
||||
|
@ -65,11 +65,11 @@ class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
|
|||
continue
|
||||
|
||||
# Check for the free space. Some card readers show up as a drive with 0 space free when there is no card inserted.
|
||||
freeBytes = ctypes.c_longlong(0)
|
||||
if windll.kernel32.GetDiskFreeSpaceExA(drive.encode("ascii"), ctypes.byref(freeBytes), None, None) == 0:
|
||||
free_bytes = ctypes.c_longlong(0)
|
||||
if windll.kernel32.GetDiskFreeSpaceExA(drive.encode("ascii"), ctypes.byref(free_bytes), None, None) == 0:
|
||||
continue
|
||||
|
||||
if freeBytes.value < 1:
|
||||
if free_bytes.value < 1:
|
||||
continue
|
||||
|
||||
drives[drive] = "{0} ({1}:)".format(volume_name, letter)
|
||||
|
@ -88,13 +88,10 @@ class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
|
|||
|
||||
result = None
|
||||
# Then, try and tell it to eject
|
||||
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:
|
||||
if not windll.kernel32.DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, None, None, None, None, None, None):
|
||||
result = False
|
||||
else:
|
||||
result = True
|
||||
|
||||
# Finally, close the handle
|
||||
windll.kernel32.CloseHandle(handle)
|
||||
|
|
|
@ -110,7 +110,7 @@ class SliceInfo(Extension):
|
|||
|
||||
# Convert data to bytes
|
||||
submitted_data = urllib.parse.urlencode(submitted_data)
|
||||
binary_data = submitted_data.encode('utf-8')
|
||||
binary_data = submitted_data.encode("utf-8")
|
||||
|
||||
# Submit data
|
||||
try:
|
||||
|
|
68
plugins/SolidView/SolidView.py
Normal file
68
plugins/SolidView/SolidView.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from UM.View.View import View
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
from UM.Resources import Resources
|
||||
from UM.Application import Application
|
||||
from UM.Math.Color import Color
|
||||
from UM.Preferences import Preferences
|
||||
from UM.View.Renderer import Renderer
|
||||
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
import math
|
||||
|
||||
## Standard view for mesh models.
|
||||
class SolidView(View):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
Preferences.getInstance().addPreference("view/show_overhang", True)
|
||||
|
||||
self._enabled_shader = None
|
||||
self._disabled_shader = None
|
||||
|
||||
def beginRendering(self):
|
||||
scene = self.getController().getScene()
|
||||
renderer = self.getRenderer()
|
||||
|
||||
if not self._enabled_shader:
|
||||
self._enabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader"))
|
||||
|
||||
if not self._disabled_shader:
|
||||
self._disabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader"))
|
||||
self._disabled_shader.setUniformValue("u_diffuseColor", [0.68, 0.68, 0.68, 1.0])
|
||||
|
||||
if Application.getInstance().getMachineManager().getActiveProfile():
|
||||
profile = Application.getInstance().getMachineManager().getActiveProfile()
|
||||
|
||||
if profile.getSettingValue("support_enable") or not Preferences.getInstance().getValue("view/show_overhang"):
|
||||
angle = profile.getSettingValue("support_angle")
|
||||
if angle != None:
|
||||
self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(90 - angle)))
|
||||
else:
|
||||
self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0)))
|
||||
|
||||
for node in DepthFirstIterator(scene.getRoot()):
|
||||
if not node.render(renderer):
|
||||
if node.getMeshData() and node.isVisible():
|
||||
# TODO: Find a better way to handle this
|
||||
#if node.getBoundingBoxMesh():
|
||||
# renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(),mode = Renderer.RenderLines)
|
||||
if hasattr(node, "_outside_buildarea"):
|
||||
if node._outside_buildarea:
|
||||
renderer.queueNode(node, shader = self._disabled_shader)
|
||||
else:
|
||||
renderer.queueNode(node, shader = self._enabled_shader)
|
||||
else:
|
||||
renderer.queueNode(node, material = self._enabled_shader)
|
||||
if node.callDecoration("isGroup"):
|
||||
renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(),mode = Renderer.RenderLines)
|
||||
|
||||
def endRendering(self):
|
||||
pass
|
||||
|
||||
#def _onPreferenceChanged(self, preference):
|
||||
#if preference == "view/show_overhang": ## Todo: This a printer only setting. Should be removed from Uranium.
|
||||
#self._enabled_material = None
|
24
plugins/SolidView/__init__.py
Normal file
24
plugins/SolidView/__init__.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from . import SolidView
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
i18n_catalog = i18nCatalog("cura")
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
"plugin": {
|
||||
"name": i18n_catalog.i18nc("@label", "Solid View"),
|
||||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"decription": i18n_catalog.i18nc("@info:whatsthis", "Provides a normal solid mesh view."),
|
||||
"api": 2
|
||||
},
|
||||
"view": {
|
||||
"name": i18n_catalog.i18nc("@item:inmenu", "Solid")
|
||||
}
|
||||
}
|
||||
|
||||
def register(app):
|
||||
return { "view": SolidView.SolidView() }
|
|
@ -45,7 +45,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
self._connect_thread.daemon = True
|
||||
|
||||
self._end_stop_thread = threading.Thread(target = self._pollEndStop)
|
||||
self._end_stop_thread.deamon = True
|
||||
self._end_stop_thread.daemon = True
|
||||
self._poll_endstop = -1
|
||||
|
||||
# Printer is connected
|
||||
self._is_connected = False
|
||||
|
@ -63,7 +64,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
self._listen_thread.daemon = True
|
||||
|
||||
self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
|
||||
self._update_firmware_thread.deamon = True
|
||||
self._update_firmware_thread.daemon = True
|
||||
self.firmwareUpdateComplete.connect(self._onFirmwareUpdateComplete)
|
||||
|
||||
self._heatup_wait_start_time = time.time()
|
||||
|
||||
|
@ -122,6 +124,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
progressChanged = pyqtSignal()
|
||||
extruderTemperatureChanged = pyqtSignal()
|
||||
bedTemperatureChanged = pyqtSignal()
|
||||
firmwareUpdateComplete = pyqtSignal()
|
||||
|
||||
endstopStateChanged = pyqtSignal(str ,bool, arguments = ["key","state"])
|
||||
|
||||
|
@ -195,6 +198,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
|
||||
## Private fuction (threaded) that actually uploads the firmware.
|
||||
def _updateFirmware(self):
|
||||
self.setProgress(0, 100)
|
||||
|
||||
if self._is_connecting or self._is_connected:
|
||||
self.close()
|
||||
hex_file = intelHex.readHex(self._firmware_file_name)
|
||||
|
@ -205,7 +210,11 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
|
||||
programmer = stk500v2.Stk500v2()
|
||||
programmer.progressCallback = self.setProgress
|
||||
programmer.connect(self._serial_port)
|
||||
|
||||
try:
|
||||
programmer.connect(self._serial_port)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
time.sleep(1) # Give programmer some time to connect. Might need more in some cases, but this worked in all tested cases.
|
||||
|
||||
|
@ -237,8 +246,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
|
||||
@pyqtSlot()
|
||||
def startPollEndstop(self):
|
||||
self._poll_endstop = True
|
||||
self._end_stop_thread.start()
|
||||
if self._poll_endstop == -1:
|
||||
self._poll_endstop = True
|
||||
self._end_stop_thread.start()
|
||||
|
||||
@pyqtSlot()
|
||||
def stopPollEndstop(self):
|
||||
|
@ -323,6 +333,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
|
||||
## Close the printer connection
|
||||
def close(self):
|
||||
Logger.log("d", "Closing the printer connection.")
|
||||
if self._connect_thread.isAlive():
|
||||
try:
|
||||
self._connect_thread.join()
|
||||
|
@ -332,8 +343,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
self._connect_thread = threading.Thread(target=self._connect)
|
||||
self._connect_thread.daemon = True
|
||||
|
||||
self.setIsConnected(False)
|
||||
if self._serial is not None:
|
||||
self.setIsConnected(False)
|
||||
try:
|
||||
self._listen_thread.join()
|
||||
except:
|
||||
|
@ -345,7 +356,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
self._serial = None
|
||||
|
||||
def isConnected(self):
|
||||
return self._is_connected
|
||||
return self._is_connected
|
||||
|
||||
@pyqtSlot(int)
|
||||
def heatupNozzle(self, temperature):
|
||||
|
@ -411,6 +422,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
|
||||
def createControlInterface(self):
|
||||
if self._control_view is None:
|
||||
Logger.log("d", "Creating control interface for printer connection")
|
||||
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())
|
||||
|
@ -455,21 +467,21 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
self._bed_temperature = temperature
|
||||
self.bedTemperatureChanged.emit()
|
||||
|
||||
def requestWrite(self, node):
|
||||
def requestWrite(self, node, file_name = None):
|
||||
self.showControlInterface()
|
||||
|
||||
def _setEndstopState(self, endstop_key, value):
|
||||
if endstop_key == b'x_min':
|
||||
if endstop_key == b"x_min":
|
||||
if self._x_min_endstop_pressed != value:
|
||||
self.endstopStateChanged.emit('x_min', value)
|
||||
self.endstopStateChanged.emit("x_min", value)
|
||||
self._x_min_endstop_pressed = value
|
||||
elif endstop_key == b'y_min':
|
||||
elif endstop_key == b"y_min":
|
||||
if self._y_min_endstop_pressed != value:
|
||||
self.endstopStateChanged.emit('y_min', value)
|
||||
self.endstopStateChanged.emit("y_min", value)
|
||||
self._y_min_endstop_pressed = value
|
||||
elif endstop_key == b'z_min':
|
||||
elif endstop_key == b"z_min":
|
||||
if self._z_min_endstop_pressed != value:
|
||||
self.endstopStateChanged.emit('z_min', value)
|
||||
self.endstopStateChanged.emit("z_min", value)
|
||||
self._z_min_endstop_pressed = value
|
||||
|
||||
## Listen thread function.
|
||||
|
@ -516,8 +528,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
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))
|
||||
tag, value = line.split(b":", 1)
|
||||
self._setEndstopState(tag,(b"H" in value or b"TRIGGERED" in value))
|
||||
|
||||
if self._is_printing:
|
||||
if line == b"" and time.time() > ok_timeout:
|
||||
|
@ -617,6 +629,6 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
def _onFirmwareUpdateComplete(self):
|
||||
self._update_firmware_thread.join()
|
||||
self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
|
||||
self._update_firmware_thread.deamon = True
|
||||
self._update_firmware_thread.daemon = True
|
||||
|
||||
self.connect()
|
||||
|
|
|
@ -11,6 +11,7 @@ from UM.Logger import Logger
|
|||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
|
||||
from UM.Qt.ListModel import ListModel
|
||||
from UM.Message import Message
|
||||
|
||||
from cura.CuraApplication import CuraApplication
|
||||
|
||||
|
@ -54,6 +55,16 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
|
|||
addConnectionSignal = Signal()
|
||||
printerConnectionStateChanged = pyqtSignal()
|
||||
|
||||
progressChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty(float, notify = progressChanged)
|
||||
def progress(self):
|
||||
progress = 0
|
||||
for name, connection in self._printer_connections.items():
|
||||
progress += connection.progress
|
||||
|
||||
return progress / len(self._printer_connections)
|
||||
|
||||
def start(self):
|
||||
self._check_updates = True
|
||||
self._update_thread.start()
|
||||
|
@ -84,12 +95,18 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
|
|||
|
||||
self._firmware_view.show()
|
||||
|
||||
@pyqtSlot()
|
||||
def updateAllFirmware(self):
|
||||
if not self._printer_connections:
|
||||
Message("Cannot update firmware, there were no connected printers found.").show()
|
||||
return
|
||||
|
||||
self.spawnFirmwareInterface("")
|
||||
for printer_connection in self._printer_connections:
|
||||
try:
|
||||
self._printer_connections[printer_connection].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName()))
|
||||
except FileNotFoundError:
|
||||
Logger.log("w", "No firmware found for printer %s", printer_connection)
|
||||
continue
|
||||
|
||||
@pyqtSlot(str, result = bool)
|
||||
|
@ -148,11 +165,22 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
|
|||
continue
|
||||
self._serial_port_list = list(serial_ports)
|
||||
|
||||
connections_to_remove = []
|
||||
for port, connection in self._printer_connections.items():
|
||||
if port not in self._serial_port_list:
|
||||
connection.close()
|
||||
connections_to_remove.append(port)
|
||||
|
||||
for port in connections_to_remove:
|
||||
del self._printer_connections[port]
|
||||
|
||||
|
||||
## 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)
|
||||
connection.progressChanged.connect(self.progressChanged)
|
||||
self._printer_connections[serial_port] = connection
|
||||
|
||||
def _onPrinterConnectionStateChanged(self, serial_port):
|
||||
|
@ -196,4 +224,4 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
|
|||
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 list(base_list)
|
||||
|
||||
_instance = None
|
||||
_instance = None
|
||||
|
|
|
@ -4,22 +4,22 @@ To support more chips add the relevant data to the avrChipDB list.
|
|||
This is a python 3 conversion of the code created by David Braam for the Cura project.
|
||||
"""
|
||||
|
||||
avrChipDB = {
|
||||
'ATMega1280': {
|
||||
'signature': [0x1E, 0x97, 0x03],
|
||||
'pageSize': 128,
|
||||
'pageCount': 512,
|
||||
avr_chip_db = {
|
||||
"ATMega1280": {
|
||||
"signature": [0x1E, 0x97, 0x03],
|
||||
"pageSize": 128,
|
||||
"pageCount": 512,
|
||||
},
|
||||
'ATMega2560': {
|
||||
'signature': [0x1E, 0x98, 0x01],
|
||||
'pageSize': 128,
|
||||
'pageCount': 1024,
|
||||
"ATMega2560": {
|
||||
"signature": [0x1E, 0x98, 0x01],
|
||||
"pageSize": 128,
|
||||
"pageCount": 1024,
|
||||
},
|
||||
}
|
||||
|
||||
def getChipFromDB(sig):
|
||||
for chip in avrChipDB.values():
|
||||
if chip['signature'] == sig:
|
||||
for chip in avr_chip_db.values():
|
||||
if chip["signature"] == sig:
|
||||
return chip
|
||||
return False
|
||||
|
||||
|
|
|
@ -11,36 +11,36 @@ def readHex(filename):
|
|||
Read an verify an intel hex file. Return the data as an list of bytes.
|
||||
"""
|
||||
data = []
|
||||
extraAddr = 0
|
||||
extra_addr = 0
|
||||
f = io.open(filename, "r")
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if len(line) < 1:
|
||||
continue
|
||||
if line[0] != ':':
|
||||
if line[0] != ":":
|
||||
raise Exception("Hex file has a line not starting with ':'")
|
||||
recLen = int(line[1:3], 16)
|
||||
addr = int(line[3:7], 16) + extraAddr
|
||||
recType = int(line[7:9], 16)
|
||||
if len(line) != recLen * 2 + 11:
|
||||
rec_len = int(line[1:3], 16)
|
||||
addr = int(line[3:7], 16) + extra_addr
|
||||
rec_type = int(line[7:9], 16)
|
||||
if len(line) != rec_len * 2 + 11:
|
||||
raise Exception("Error in hex file: " + line)
|
||||
checkSum = 0
|
||||
for i in range(0, recLen + 5):
|
||||
checkSum += int(line[i*2+1:i*2+3], 16)
|
||||
checkSum &= 0xFF
|
||||
if checkSum != 0:
|
||||
check_sum = 0
|
||||
for i in range(0, rec_len + 5):
|
||||
check_sum += int(line[i*2+1:i*2+3], 16)
|
||||
check_sum &= 0xFF
|
||||
if check_sum != 0:
|
||||
raise Exception("Checksum error in hex file: " + line)
|
||||
|
||||
if recType == 0:#Data record
|
||||
while len(data) < addr + recLen:
|
||||
if rec_type == 0:#Data record
|
||||
while len(data) < addr + rec_len:
|
||||
data.append(0)
|
||||
for i in range(0, recLen):
|
||||
for i in range(0, rec_len):
|
||||
data[addr + i] = int(line[i*2+9:i*2+11], 16)
|
||||
elif recType == 1: #End Of File record
|
||||
elif rec_type == 1: #End Of File record
|
||||
pass
|
||||
elif recType == 2: #Extended Segment Address Record
|
||||
extraAddr = int(line[9:13], 16) * 16
|
||||
elif rec_type == 2: #Extended Segment Address Record
|
||||
extra_addr = int(line[9:13], 16) * 16
|
||||
else:
|
||||
print(recType, recLen, addr, checkSum, line)
|
||||
print(rec_type, rec_len, addr, check_sum, line)
|
||||
f.close()
|
||||
return data
|
||||
|
|
|
@ -14,18 +14,18 @@ class IspBase():
|
|||
Base class for ISP based AVR programmers.
|
||||
Functions in this class raise an IspError when something goes wrong.
|
||||
"""
|
||||
def programChip(self, flashData):
|
||||
def programChip(self, flash_data):
|
||||
""" Program a chip with the given flash data. """
|
||||
self.curExtAddr = -1
|
||||
self.cur_ext_addr = -1
|
||||
self.chip = chipDB.getChipFromDB(self.getSignature())
|
||||
if not self.chip:
|
||||
raise IspError("Chip with signature: " + str(self.getSignature()) + "not found")
|
||||
self.chipErase()
|
||||
|
||||
print("Flashing %i bytes" % len(flashData))
|
||||
self.writeFlash(flashData)
|
||||
print("Verifying %i bytes" % len(flashData))
|
||||
self.verifyFlash(flashData)
|
||||
print("Flashing %i bytes" % len(flash_data))
|
||||
self.writeFlash(flash_data)
|
||||
print("Verifying %i bytes" % len(flash_data))
|
||||
self.verifyFlash(flash_data)
|
||||
print("Completed")
|
||||
|
||||
def getSignature(self):
|
||||
|
@ -45,20 +45,20 @@ class IspBase():
|
|||
"""
|
||||
self.sendISP([0xAC, 0x80, 0x00, 0x00])
|
||||
|
||||
def writeFlash(self, flashData):
|
||||
def writeFlash(self, flash_data):
|
||||
"""
|
||||
Write the flash data, needs to be implemented in a subclass.
|
||||
"""
|
||||
raise IspError("Called undefined writeFlash")
|
||||
|
||||
def verifyFlash(self, flashData):
|
||||
def verifyFlash(self, flash_data):
|
||||
"""
|
||||
Verify the flash data, needs to be implemented in a subclass.
|
||||
"""
|
||||
raise IspError("Called undefined verifyFlash")
|
||||
|
||||
|
||||
class IspError(BaseException):
|
||||
class IspError(Exception):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
|
|
|
@ -19,10 +19,10 @@ class Stk500v2(ispBase.IspBase):
|
|||
def __init__(self):
|
||||
self.serial = None
|
||||
self.seq = 1
|
||||
self.lastAddr = -1
|
||||
self.progressCallback = None
|
||||
self.last_addr = -1
|
||||
self.progress_callback = None
|
||||
|
||||
def connect(self, port = 'COM22', speed = 115200):
|
||||
def connect(self, port = "COM22", speed = 115200):
|
||||
if self.serial is not None:
|
||||
self.close()
|
||||
try:
|
||||
|
@ -82,49 +82,49 @@ class Stk500v2(ispBase.IspBase):
|
|||
|
||||
def writeFlash(self, flash_data):
|
||||
#Set load addr to 0, in case we have more then 64k flash we need to enable the address extension
|
||||
page_size = self.chip['pageSize'] * 2
|
||||
flashSize = page_size * self.chip['pageCount']
|
||||
page_size = self.chip["pageSize"] * 2
|
||||
flash_size = page_size * self.chip["pageCount"]
|
||||
print("Writing flash")
|
||||
if flashSize > 0xFFFF:
|
||||
if flash_size > 0xFFFF:
|
||||
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
|
||||
else:
|
||||
self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00])
|
||||
load_count = (len(flash_data) + page_size - 1) / page_size
|
||||
for i in range(0, int(load_count)):
|
||||
recv = self.sendMessage([0x13, page_size >> 8, page_size & 0xFF, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00] + flash_data[(i * page_size):(i * page_size + page_size)])
|
||||
if self.progressCallback is not None:
|
||||
if self.progress_callback is not None:
|
||||
if self._has_checksum:
|
||||
self.progressCallback(i + 1, load_count)
|
||||
self.progress_callback(i + 1, load_count)
|
||||
else:
|
||||
self.progressCallback(i + 1, load_count*2)
|
||||
self.progress_callback(i + 1, load_count*2)
|
||||
|
||||
def verifyFlash(self, flashData):
|
||||
def verifyFlash(self, flash_data):
|
||||
if self._has_checksum:
|
||||
self.sendMessage([0x06, 0x00, (len(flashData) >> 17) & 0xFF, (len(flashData) >> 9) & 0xFF, (len(flashData) >> 1) & 0xFF])
|
||||
self.sendMessage([0x06, 0x00, (len(flash_data) >> 17) & 0xFF, (len(flash_data) >> 9) & 0xFF, (len(flash_data) >> 1) & 0xFF])
|
||||
res = self.sendMessage([0xEE])
|
||||
checksum_recv = res[2] | (res[3] << 8)
|
||||
checksum = 0
|
||||
for d in flashData:
|
||||
for d in flash_data:
|
||||
checksum += d
|
||||
checksum &= 0xFFFF
|
||||
if hex(checksum) != hex(checksum_recv):
|
||||
raise ispBase.IspError('Verify checksum mismatch: 0x%x != 0x%x' % (checksum & 0xFFFF, checksum_recv))
|
||||
raise ispBase.IspError("Verify checksum mismatch: 0x%x != 0x%x" % (checksum & 0xFFFF, checksum_recv))
|
||||
else:
|
||||
#Set load addr to 0, in case we have more then 64k flash we need to enable the address extension
|
||||
flashSize = self.chip['pageSize'] * 2 * self.chip['pageCount']
|
||||
if flashSize > 0xFFFF:
|
||||
flash_size = self.chip["pageSize"] * 2 * self.chip["pageCount"]
|
||||
if flash_size > 0xFFFF:
|
||||
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
|
||||
else:
|
||||
self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00])
|
||||
|
||||
loadCount = (len(flashData) + 0xFF) / 0x100
|
||||
for i in range(0, int(loadCount)):
|
||||
load_count = (len(flash_data) + 0xFF) / 0x100
|
||||
for i in range(0, int(load_count)):
|
||||
recv = self.sendMessage([0x14, 0x01, 0x00, 0x20])[2:0x102]
|
||||
if self.progressCallback is not None:
|
||||
self.progressCallback(loadCount + i + 1, loadCount*2)
|
||||
if self.progress_callback is not None:
|
||||
self.progress_callback(load_count + i + 1, load_count*2)
|
||||
for j in range(0, 0x100):
|
||||
if i * 0x100 + j < len(flashData) and flashData[i * 0x100 + j] != recv[j]:
|
||||
raise ispBase.IspError('Verify error at: 0x%x' % (i * 0x100 + j))
|
||||
if i * 0x100 + j < len(flash_data) and flash_data[i * 0x100 + j] != recv[j]:
|
||||
raise ispBase.IspError("Verify error at: 0x%x" % (i * 0x100 + j))
|
||||
|
||||
def sendMessage(self, data):
|
||||
message = struct.pack(">BBHB", 0x1B, self.seq, len(data), 0x0E)
|
||||
|
@ -138,12 +138,12 @@ class Stk500v2(ispBase.IspBase):
|
|||
self.serial.write(message)
|
||||
self.serial.flush()
|
||||
except SerialTimeoutException:
|
||||
raise ispBase.IspError('Serial send timeout')
|
||||
raise ispBase.IspError("Serial send timeout")
|
||||
self.seq = (self.seq + 1) & 0xFF
|
||||
return self.recvMessage()
|
||||
|
||||
def recvMessage(self):
|
||||
state = 'Start'
|
||||
state = "Start"
|
||||
checksum = 0
|
||||
while True:
|
||||
s = self.serial.read()
|
||||
|
@ -152,31 +152,31 @@ class Stk500v2(ispBase.IspBase):
|
|||
b = struct.unpack(">B", s)[0]
|
||||
checksum ^= b
|
||||
#print(hex(b))
|
||||
if state == 'Start':
|
||||
if state == "Start":
|
||||
if b == 0x1B:
|
||||
state = 'GetSeq'
|
||||
state = "GetSeq"
|
||||
checksum = 0x1B
|
||||
elif state == 'GetSeq':
|
||||
state = 'MsgSize1'
|
||||
elif state == 'MsgSize1':
|
||||
msgSize = b << 8
|
||||
state = 'MsgSize2'
|
||||
elif state == 'MsgSize2':
|
||||
msgSize |= b
|
||||
state = 'Token'
|
||||
elif state == 'Token':
|
||||
elif state == "GetSeq":
|
||||
state = "MsgSize1"
|
||||
elif state == "MsgSize1":
|
||||
msg_size = b << 8
|
||||
state = "MsgSize2"
|
||||
elif state == "MsgSize2":
|
||||
msg_size |= b
|
||||
state = "Token"
|
||||
elif state == "Token":
|
||||
if b != 0x0E:
|
||||
state = 'Start'
|
||||
state = "Start"
|
||||
else:
|
||||
state = 'Data'
|
||||
state = "Data"
|
||||
data = []
|
||||
elif state == 'Data':
|
||||
elif state == "Data":
|
||||
data.append(b)
|
||||
if len(data) == msgSize:
|
||||
state = 'Checksum'
|
||||
elif state == 'Checksum':
|
||||
if len(data) == msg_size:
|
||||
state = "Checksum"
|
||||
elif state == "Checksum":
|
||||
if checksum != 0:
|
||||
state = 'Start'
|
||||
state = "Start"
|
||||
else:
|
||||
return data
|
||||
|
||||
|
@ -190,7 +190,7 @@ def portList():
|
|||
values = _winreg.EnumValue(key, i)
|
||||
except:
|
||||
return ret
|
||||
if 'USBSER' in values[0]:
|
||||
if "USBSER" in values[0]:
|
||||
ret.append(values[1])
|
||||
i+=1
|
||||
return ret
|
||||
|
@ -205,7 +205,7 @@ def runProgrammer(port, filename):
|
|||
def main():
|
||||
""" Entry point to call the stk500v2 programmer from the commandline. """
|
||||
import threading
|
||||
if sys.argv[1] == 'AUTO':
|
||||
if sys.argv[1] == "AUTO":
|
||||
print(portList())
|
||||
for port in portList():
|
||||
threading.Thread(target=runProgrammer, args=(port,sys.argv[2])).start()
|
||||
|
@ -216,5 +216,5 @@ def main():
|
|||
programmer.programChip(intelHex.readHex(sys.argv[2]))
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
39
plugins/XRayView/XRayPass.py
Normal file
39
plugins/XRayView/XRayPass.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import os.path
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
|
||||
from UM.View.RenderPass import RenderPass
|
||||
from UM.View.RenderBatch import RenderBatch
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
|
||||
class XRayPass(RenderPass):
|
||||
def __init__(self, width, height):
|
||||
super().__init__("xray", width, height)
|
||||
|
||||
self._shader = None
|
||||
self._gl = OpenGL.getInstance().getBindingsObject()
|
||||
self._scene = Application.getInstance().getController().getScene()
|
||||
|
||||
def render(self):
|
||||
if not self._shader:
|
||||
self._shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("XRayView"), "xray.shader"))
|
||||
|
||||
batch = RenderBatch(self._shader, type = RenderBatch.RenderType.NoType, backface_cull = False, blend_mode = RenderBatch.BlendMode.Additive)
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if type(node) is SceneNode and node.getMeshData() and node.isVisible():
|
||||
batch.addItem(node.getWorldTransformation(), node.getMeshData())
|
||||
|
||||
self.bind()
|
||||
|
||||
self._gl.glDisable(self._gl.GL_DEPTH_TEST)
|
||||
batch.render(self._scene.getActiveCamera())
|
||||
self._gl.glEnable(self._gl.GL_DEPTH_TEST)
|
||||
|
||||
self.release()
|
72
plugins/XRayView/XRayView.py
Normal file
72
plugins/XRayView/XRayView.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import os.path
|
||||
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.Event import Event
|
||||
from UM.View.View import View
|
||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||
|
||||
from UM.View.RenderBatch import RenderBatch
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
from . import XRayPass
|
||||
|
||||
## View used to display a see-through version of objects with errors highlighted.
|
||||
class XRayView(View):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self._xray_shader = None
|
||||
self._xray_pass = None
|
||||
self._xray_composite_shader = None
|
||||
self._composite_pass = None
|
||||
self._old_composite_shader = None
|
||||
self._old_layer_bindings = None
|
||||
|
||||
def beginRendering(self):
|
||||
scene = self.getController().getScene()
|
||||
renderer = self.getRenderer()
|
||||
|
||||
if not self._xray_shader:
|
||||
self._xray_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("XRayView"), "xray.shader"))
|
||||
self._xray_shader.setUniformValue("u_color", [0.1, 0.1, 0.2, 1.0])
|
||||
|
||||
for node in BreadthFirstIterator(scene.getRoot()):
|
||||
if not node.render(renderer):
|
||||
if node.getMeshData() and node.isVisible():
|
||||
renderer.queueNode(node,
|
||||
shader = self._xray_shader,
|
||||
type = RenderBatch.RenderType.Solid,
|
||||
blend_mode = RenderBatch.BlendMode.Additive,
|
||||
sort = -10,
|
||||
state_setup_callback = lambda gl: gl.glDepthFunc(gl.GL_ALWAYS),
|
||||
state_teardown_callback = lambda gl: gl.glDepthFunc(gl.GL_LESS)
|
||||
)
|
||||
|
||||
def endRendering(self):
|
||||
pass
|
||||
|
||||
def event(self, event):
|
||||
if event.type == Event.ViewActivateEvent:
|
||||
if not self._xray_pass:
|
||||
# Currently the RenderPass constructor requires a size > 0
|
||||
# This should be fixed in RenderPass's constructor.
|
||||
self._xray_pass = XRayPass.XRayPass(1, 1)
|
||||
self.getRenderer().addRenderPass(self._xray_pass)
|
||||
|
||||
if not self._xray_composite_shader:
|
||||
self._xray_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("XRayView"), "xray_composite.shader"))
|
||||
|
||||
if not self._composite_pass:
|
||||
self._composite_pass = self.getRenderer().getRenderPass("composite")
|
||||
|
||||
self._old_layer_bindings = self._composite_pass.getLayerBindings()
|
||||
self._composite_pass.setLayerBindings(["default", "selection", "xray"])
|
||||
self._old_composite_shader = self._composite_pass.getCompositeShader()
|
||||
self._composite_pass.setCompositeShader(self._xray_composite_shader)
|
||||
|
||||
if event.type == Event.ViewDeactivateEvent:
|
||||
self._composite_pass.setLayerBindings(self._old_layer_bindings)
|
||||
self._composite_pass.setCompositeShader(self._old_composite_shader)
|
24
plugins/XRayView/__init__.py
Normal file
24
plugins/XRayView/__init__.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from . import XRayView
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
"plugin": {
|
||||
"name": catalog.i18nc("@label", "X-Ray View"),
|
||||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"description": catalog.i18nc("@info:whatsthis", "Provides the X-Ray view."),
|
||||
"api": 2
|
||||
},
|
||||
"view": {
|
||||
"name": catalog.i18nc("@item:inlistbox", "X-Ray")
|
||||
}
|
||||
}
|
||||
|
||||
def register(app):
|
||||
return { "view": XRayView.XRayView() }
|
27
plugins/XRayView/xray.shader
Normal file
27
plugins/XRayView/xray.shader
Normal file
|
@ -0,0 +1,27 @@
|
|||
[shaders]
|
||||
vertex =
|
||||
uniform highp mat4 u_modelViewProjectionMatrix;
|
||||
|
||||
attribute highp vec4 a_vertex;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_modelViewProjectionMatrix * a_vertex;
|
||||
}
|
||||
|
||||
fragment =
|
||||
uniform lowp vec4 u_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = u_color;
|
||||
}
|
||||
|
||||
[defaults]
|
||||
u_color = [0.02, 0.02, 0.02, 1.0]
|
||||
|
||||
[bindings]
|
||||
u_modelViewProjectionMatrix = model_view_projection_matrix
|
||||
|
||||
[attributes]
|
||||
a_vertex = vertex
|
75
plugins/XRayView/xray_composite.shader
Normal file
75
plugins/XRayView/xray_composite.shader
Normal file
|
@ -0,0 +1,75 @@
|
|||
[shaders]
|
||||
vertex =
|
||||
uniform highp mat4 u_modelViewProjectionMatrix;
|
||||
attribute highp vec4 a_vertex;
|
||||
attribute highp vec2 a_uvs;
|
||||
|
||||
varying highp vec2 v_uvs;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = u_modelViewProjectionMatrix * a_vertex;
|
||||
v_uvs = a_uvs;
|
||||
}
|
||||
|
||||
fragment =
|
||||
uniform sampler2D u_layer0;
|
||||
uniform sampler2D u_layer1;
|
||||
uniform sampler2D u_layer2;
|
||||
uniform sampler2D u_layer3;
|
||||
|
||||
uniform float u_imageWidth;
|
||||
uniform float u_imageHeight;
|
||||
|
||||
uniform vec2 u_offset[9];
|
||||
|
||||
uniform float u_outline_strength;
|
||||
uniform vec4 u_outline_color;
|
||||
uniform vec4 u_error_color;
|
||||
|
||||
varying vec2 v_uvs;
|
||||
|
||||
float kernel[9];
|
||||
|
||||
void main()
|
||||
{
|
||||
kernel[0] = 0.0; kernel[1] = 1.0; kernel[2] = 0.0;
|
||||
kernel[3] = 1.0; kernel[4] = -4.0; kernel[5] = 1.0;
|
||||
kernel[6] = 0.0; kernel[7] = 1.0; kernel[8] = 0.0;
|
||||
|
||||
vec4 result = vec4(0.965, 0.965, 0.965, 1.0);
|
||||
vec4 layer0 = texture2D(u_layer0, v_uvs);
|
||||
|
||||
result = layer0 * layer0.a + result * (1.0 - layer0.a);
|
||||
|
||||
float intersection_count = (texture2D(u_layer2, v_uvs).r * 255.0) / 5.0;
|
||||
if(mod(intersection_count, 2.0) == 1.0)
|
||||
{
|
||||
result = u_error_color;
|
||||
}
|
||||
|
||||
vec4 sum = vec4(0.0);
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
vec4 color = vec4(texture2D(u_layer1, v_uvs.xy + u_offset[i]).a);
|
||||
sum += color * (kernel[i] / u_outline_strength);
|
||||
}
|
||||
|
||||
gl_FragColor = mix(result, vec4(abs(sum.a)) * u_outline_color, abs(sum.a));
|
||||
}
|
||||
|
||||
[defaults]
|
||||
u_layer0 = 0
|
||||
u_layer1 = 1
|
||||
u_layer2 = 2
|
||||
u_layer3 = 3
|
||||
u_outline_strength = 1.0
|
||||
u_outline_color = [0.05, 0.66, 0.89, 1.0]
|
||||
u_error_color = [1.0, 0.0, 0.0, 1.0]
|
||||
|
||||
[bindings]
|
||||
|
||||
[attributes]
|
||||
a_vertex = vertex
|
||||
a_uvs = uv
|
||||
|
2130
resources/i18n/de/cura.po
Normal file → Executable file
2130
resources/i18n/de/cura.po
Normal file → Executable file
File diff suppressed because it is too large
Load diff
5649
resources/i18n/de/fdmprinter.json.po
Normal file → Executable file
5649
resources/i18n/de/fdmprinter.json.po
Normal file → Executable file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
325
resources/i18n/fi/cura.po
Normal file → Executable file
325
resources/i18n/fi/cura.po
Normal file → Executable file
|
@ -8,20 +8,20 @@ msgstr ""
|
|||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-09-12 20:10+0200\n"
|
||||
"PO-Revision-Date: 2015-06-30 18:02+0300\n"
|
||||
"PO-Revision-Date: 2015-09-28 14:08+0300\n"
|
||||
"Last-Translator: Tapio <info@tapimex.fi>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: fi_FI\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.8.2\n"
|
||||
"X-Generator: Poedit 1.8.5\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/cura/CrashHandler.py:20
|
||||
msgctxt "@title:window"
|
||||
msgid "Oops!"
|
||||
msgstr ""
|
||||
msgstr "Hups!"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/cura/CrashHandler.py:26
|
||||
msgctxt "@label"
|
||||
|
@ -30,11 +30,14 @@ msgid ""
|
|||
"below to post a bug report at <a href=\"http://github.com/Ultimaker/Cura/"
|
||||
"issues\">http://github.com/Ultimaker/Cura/issues</a></p>"
|
||||
msgstr ""
|
||||
"<p>Tapahtui epätavallinen poikkeus!</p><p>Lähetä virheraportti alla olevin "
|
||||
"tiedoin osoitteella <a href=\"http://github.com/Ultimaker/Cura/issues"
|
||||
"\">http://github.com/Ultimaker/Cura/issues</a></p>"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/cura/CrashHandler.py:46
|
||||
msgctxt "@action:button"
|
||||
msgid "Open Web Page"
|
||||
msgstr ""
|
||||
msgstr "Avaa verkkosivu"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/cura/CuraApplication.py:135
|
||||
#, fuzzy
|
||||
|
@ -51,34 +54,32 @@ msgstr "Ladataan käyttöliittymää..."
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/3MFReader/__init__.py:12
|
||||
msgctxt "@label"
|
||||
msgid "3MF Reader"
|
||||
msgstr ""
|
||||
msgstr "3MF Reader"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/3MFReader/__init__.py:15
|
||||
msgctxt "@info:whatsthis"
|
||||
msgid "Provides support for reading 3MF files."
|
||||
msgstr ""
|
||||
msgstr "Tukee 3MF-tiedostojen lukemista."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/3MFReader/__init__.py:20
|
||||
#, fuzzy
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "3MF File"
|
||||
msgstr "&Tiedosto"
|
||||
msgstr "3MF-tiedosto"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/ChangeLogPlugin/__init__.py:12
|
||||
#, fuzzy
|
||||
msgctxt "@label"
|
||||
msgid "Change Log"
|
||||
msgstr "Moottorin loki"
|
||||
msgstr "Muutosloki"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/ChangeLogPlugin/__init__.py:15
|
||||
msgctxt "@info:whatsthis"
|
||||
msgid "Shows changes since latest checked version"
|
||||
msgstr ""
|
||||
msgstr "Näyttää viimeisimmän tarkistetun version jälkeen tapahtuneet muutokset"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/CuraEngineBackend/__init__.py:13
|
||||
msgctxt "@label"
|
||||
msgid "CuraEngine Backend"
|
||||
msgstr ""
|
||||
msgstr "CuraEngine-taustaosa"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/CuraEngineBackend/__init__.py:15
|
||||
#, fuzzy
|
||||
|
@ -90,25 +91,22 @@ msgstr "Linkki CuraEngine-viipalointiin taustalla"
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py:111
|
||||
msgctxt "@info:status"
|
||||
msgid "Processing Layers"
|
||||
msgstr ""
|
||||
msgstr "Käsitellään kerroksia"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/CuraEngineBackend/CuraEngineBackend.py:169
|
||||
#, fuzzy
|
||||
msgctxt "@info:status"
|
||||
msgid "Slicing..."
|
||||
msgstr "Lasketaan..."
|
||||
msgstr "Viipaloidaan..."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/GCodeWriter/__init__.py:12
|
||||
#, fuzzy
|
||||
msgctxt "@label"
|
||||
msgid "GCode Writer"
|
||||
msgstr "GCode-tiedosto"
|
||||
msgstr "GCode Writer"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/GCodeWriter/__init__.py:15
|
||||
#, fuzzy
|
||||
msgctxt "@info:whatsthis"
|
||||
msgid "Writes GCode to a file"
|
||||
msgstr "Kirjoittaa GCoden tiedostoon"
|
||||
msgstr "Kirjoittaa GCodea tiedostoon"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/GCodeWriter/__init__.py:22
|
||||
#, fuzzy
|
||||
|
@ -117,19 +115,16 @@ msgid "GCode File"
|
|||
msgstr "GCode-tiedosto"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/LayerView/__init__.py:13
|
||||
#, fuzzy
|
||||
msgctxt "@label"
|
||||
msgid "Layer View"
|
||||
msgstr "Kerrokset"
|
||||
msgstr "Kerrosnäkymä"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/LayerView/__init__.py:16
|
||||
#, fuzzy
|
||||
msgctxt "@info:whatsthis"
|
||||
msgid "Provides the Layer view."
|
||||
msgstr "Kerrosnäkymä."
|
||||
msgstr "Näyttää kerrosnäkymän."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/LayerView/__init__.py:20
|
||||
#, fuzzy
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "Layers"
|
||||
msgstr "Kerrokset"
|
||||
|
@ -137,28 +132,27 @@ msgstr "Kerrokset"
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:20
|
||||
msgctxt "@action:button"
|
||||
msgid "Save to Removable Drive"
|
||||
msgstr ""
|
||||
msgstr "Tallenna siirrettävälle asemalle"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:21
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "Save to Removable Drive {0}"
|
||||
msgstr "Tallenna SD-kortille {0}"
|
||||
msgstr "Tallenna siirrettävälle asemalle {0}"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:52
|
||||
#, python-brace-format
|
||||
msgctxt "@info:progress"
|
||||
msgid "Saving to Removable Drive <filename>{0}</filename>"
|
||||
msgstr ""
|
||||
msgstr "Tallennetaan siirrettävälle asemalle <filename>{0}</filename>"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:73
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgctxt "@info:status"
|
||||
msgid "Saved to Removable Drive {0} as {1}"
|
||||
msgstr "Tallennettu SD-kortille {0} nimellä {1}"
|
||||
msgstr "Tallennettu siirrettävälle asemalle {0} nimellä {1}"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:74
|
||||
#, fuzzy
|
||||
msgctxt "@action:button"
|
||||
msgid "Eject"
|
||||
msgstr "Poista"
|
||||
|
@ -167,96 +161,98 @@ msgstr "Poista"
|
|||
#, python-brace-format
|
||||
msgctxt "@action"
|
||||
msgid "Eject removable device {0}"
|
||||
msgstr ""
|
||||
msgstr "Poista siirrettävä asema {0}"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:79
|
||||
#, python-brace-format
|
||||
msgctxt "@info:status"
|
||||
msgid "Could not save to removable drive {0}: {1}"
|
||||
msgstr ""
|
||||
msgstr "Ei voitu tallentaa siirrettävälle asemalle {0}: {1}"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/WindowsRemovableDrivePlugin.py:58
|
||||
msgctxt "@item:intext"
|
||||
msgid "Removable Drive"
|
||||
msgstr ""
|
||||
msgstr "Siirrettävä asema"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/RemovableDrivePlugin.py:42
|
||||
#, python-brace-format
|
||||
msgctxt "@info:status"
|
||||
msgid "Ejected {0}. You can now safely remove the drive."
|
||||
msgstr ""
|
||||
msgstr "Poistettu {0}. Voit nyt poistaa aseman turvallisesti."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/RemovableDrivePlugin.py:45
|
||||
#, python-brace-format
|
||||
msgctxt "@info:status"
|
||||
msgid "Failed to eject {0}. Maybe it is still in use?"
|
||||
msgstr ""
|
||||
msgstr "{0} poisto epäonnistui. Onko se vielä käytössä?"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/__init__.py:12
|
||||
msgctxt "@label"
|
||||
msgid "Removable Drive Output Device Plugin"
|
||||
msgstr ""
|
||||
msgstr "Irrotettavan aseman lisäosa"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/RemovableDriveOutputDevice/__init__.py:14
|
||||
msgctxt "@info:whatsthis"
|
||||
msgid "Provides removable drive hotplugging and writing support"
|
||||
msgstr ""
|
||||
msgstr "Tukee irrotettavan aseman kytkemistä lennossa ja sille kirjoittamista"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/SliceInfoPlugin/__init__.py:10
|
||||
msgctxt "@label"
|
||||
msgid "Slice info"
|
||||
msgstr ""
|
||||
msgstr "Viipalointitiedot"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/SliceInfoPlugin/__init__.py:13
|
||||
msgctxt "@info:whatsthis"
|
||||
msgid "Submits anonymous slice info. Can be disabled through preferences."
|
||||
msgstr ""
|
||||
"Lähettää anonyymiä viipalointitietoa. Voidaan lisäasetuksista kytkeä pois "
|
||||
"käytöstä."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/SliceInfoPlugin/SliceInfo.py:35
|
||||
msgctxt "@info"
|
||||
msgid ""
|
||||
"Cura automatically sends slice info. You can disable this in preferences"
|
||||
msgstr ""
|
||||
"Cura lähettää automaattisesti viipalointitietoa. Voit lisäasetuksista kytkeä "
|
||||
"sen pois käytöstä"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/SliceInfoPlugin/SliceInfo.py:36
|
||||
msgctxt "@action:button"
|
||||
msgid "Dismiss"
|
||||
msgstr ""
|
||||
msgstr "Ohita"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/PrinterConnection.py:35
|
||||
msgctxt "@item:inmenu"
|
||||
msgid "USB printing"
|
||||
msgstr ""
|
||||
msgstr "USB-tulostus"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/PrinterConnection.py:36
|
||||
msgctxt "@action:button"
|
||||
msgid "Print with USB"
|
||||
msgstr ""
|
||||
msgstr "Tulosta USB:llä"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/PrinterConnection.py:37
|
||||
msgctxt "@info:tooltip"
|
||||
msgid "Print with USB"
|
||||
msgstr ""
|
||||
msgstr "Tulostus USB:n kautta"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/__init__.py:13
|
||||
msgctxt "@label"
|
||||
msgid "USB printing"
|
||||
msgstr ""
|
||||
msgstr "USB-tulostus"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/__init__.py:17
|
||||
#, fuzzy
|
||||
msgctxt "@info:whatsthis"
|
||||
msgid ""
|
||||
"Accepts G-Code and sends them to a printer. Plugin can also update firmware."
|
||||
msgstr ""
|
||||
"Hyväksyy G-Coden ja lähettää ne tulostimeen. Lisäosa voi myös päivittää "
|
||||
"laiteohjelmiston"
|
||||
"Hyväksyy G-Code-määrittelyt ja lähettää ne tulostimeen. Lisäosa voi myös "
|
||||
"päivittää laiteohjelmiston."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/USBPrinterManager.py:46
|
||||
#, fuzzy
|
||||
msgctxt "@title:menu"
|
||||
msgid "Firmware"
|
||||
msgstr "Päivitä laiteohjelmisto"
|
||||
msgstr "Laiteohjelmisto"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/USBPrinterManager.py:47
|
||||
#, fuzzy
|
||||
|
@ -267,7 +263,7 @@ msgstr "Päivitä laiteohjelmisto"
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/ControlWindow.qml:17
|
||||
msgctxt "@title:window"
|
||||
msgid "Print with USB"
|
||||
msgstr ""
|
||||
msgstr "Tulostus USB:n kautta"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/ControlWindow.qml:28
|
||||
#, fuzzy
|
||||
|
@ -294,10 +290,9 @@ msgid "Cancel"
|
|||
msgstr "Peruuta"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/FirmwareUpdateWindow.qml:20
|
||||
#, fuzzy
|
||||
msgctxt "@title:window"
|
||||
msgid "Firmware Update"
|
||||
msgstr "Laiteohjelmiston päivitys suoritettu."
|
||||
msgstr "Laiteohjelmiston päivitys"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/plugins/USBPrinting/FirmwareUpdateWindow.qml:38
|
||||
#, fuzzy
|
||||
|
@ -347,12 +342,12 @@ msgstr "Moottorin loki"
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/ProfileSetup.qml:31
|
||||
msgctxt "@label"
|
||||
msgid "Variant:"
|
||||
msgstr ""
|
||||
msgstr "Variantti:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/ProfileSetup.qml:82
|
||||
msgctxt "@label"
|
||||
msgid "Global Profile:"
|
||||
msgstr ""
|
||||
msgstr "Yleisprofiili:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/AddMachine.qml:60
|
||||
#, fuzzy
|
||||
|
@ -370,31 +365,29 @@ msgstr "Tulostimen nimi:"
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/SelectUpgradedParts.qml:29
|
||||
msgctxt "@title"
|
||||
msgid "Select Upgraded Parts"
|
||||
msgstr ""
|
||||
msgstr "Valitse päivitettävät osat"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/AddMachine.qml:214
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UpgradeFirmware.qml:29
|
||||
#, fuzzy
|
||||
msgctxt "@title"
|
||||
msgid "Upgrade Firmware"
|
||||
msgstr "Päivitä laiteohjelmisto"
|
||||
msgstr "Laiteohjelmiston päivitys"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/AddMachine.qml:217
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:37
|
||||
#, fuzzy
|
||||
msgctxt "@title"
|
||||
msgid "Check Printer"
|
||||
msgstr "Lisää tulostin"
|
||||
msgstr "Tarkista tulostin"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/AddMachine.qml:220
|
||||
msgctxt "@title"
|
||||
msgid "Bed Levelling"
|
||||
msgstr ""
|
||||
msgstr "Pöydän tasaaminen"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/Bedleveling.qml:25
|
||||
msgctxt "@title"
|
||||
msgid "Bed Leveling"
|
||||
msgstr ""
|
||||
msgstr "Pöydän tasaaminen"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/Bedleveling.qml:34
|
||||
msgctxt "@label"
|
||||
|
@ -403,6 +396,8 @@ msgid ""
|
|||
"buildplate. When you click 'Move to Next Position' the nozzle will move to "
|
||||
"the different positions that can be adjusted."
|
||||
msgstr ""
|
||||
"Voit säätää alustaa, jotta tulosteista tulisi hyviä. Kun napsautat 'Siirry "
|
||||
"seuraavaan positioon', suutin siirtyy eri positioihin, joita voidaan säätää."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/Bedleveling.qml:40
|
||||
msgctxt "@label"
|
||||
|
@ -411,16 +406,19 @@ msgid ""
|
|||
"print bed height. The print bed height is right when the paper is slightly "
|
||||
"gripped by the tip of the nozzle."
|
||||
msgstr ""
|
||||
"Laita paperinpala kussakin positiossa suuttimen alle ja säädä tulostuspöydän "
|
||||
"korkeus. Tulostuspöydän korkeus on oikea, kun suuttimen kärki juuri ja juuri "
|
||||
"osuu paperiin."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/Bedleveling.qml:44
|
||||
msgctxt "@action:button"
|
||||
msgid "Move to Next Position"
|
||||
msgstr ""
|
||||
msgstr "Siirry seuraavaan positioon"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/Bedleveling.qml:66
|
||||
msgctxt "@action:button"
|
||||
msgid "Skip Bedleveling"
|
||||
msgstr ""
|
||||
msgstr "Ohita pöydän tasaus"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/SelectUpgradedParts.qml:39
|
||||
msgctxt "@label"
|
||||
|
@ -428,27 +426,28 @@ msgid ""
|
|||
"To assist you in having better default settings for your Ultimaker. Cura "
|
||||
"would like to know which upgrades you have in your machine:"
|
||||
msgstr ""
|
||||
"Saat paremmat oletusasetukset Ultimakeriin. Cura haluaisi tietää, mitä "
|
||||
"päivityksiä laitteessasi on:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/SelectUpgradedParts.qml:49
|
||||
#, fuzzy
|
||||
msgctxt "@option:check"
|
||||
msgid "Extruder driver ugrades"
|
||||
msgstr "Suulakkeen lämpötila %1"
|
||||
msgstr "Suulakekäytön päivitykset"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/SelectUpgradedParts.qml:54
|
||||
msgctxt "@option:check"
|
||||
msgid "Heated printer bed (standard kit)"
|
||||
msgstr ""
|
||||
msgstr "Lämmitetty tulostinpöytä (normaali sarja)"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/SelectUpgradedParts.qml:58
|
||||
msgctxt "@option:check"
|
||||
msgid "Heated printer bed (self built)"
|
||||
msgstr ""
|
||||
msgstr "Lämmitetty tulostinpöytä (itse rakennettu)"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/SelectUpgradedParts.qml:62
|
||||
msgctxt "@option:check"
|
||||
msgid "Dual extrusion (experimental)"
|
||||
msgstr ""
|
||||
msgstr "Kaksoispursotus (kokeellinen)"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/SelectUpgradedParts.qml:70
|
||||
msgctxt "@label"
|
||||
|
@ -458,6 +457,11 @@ msgid ""
|
|||
"improve reliability. This upgrade can be bought from the Ultimaker webshop "
|
||||
"or found on thingiverse as thing:26094"
|
||||
msgstr ""
|
||||
"Jos olet hankkinut Ultimakerin lokakuun 2012 jälkeen, sinulla on "
|
||||
"suulakekäytön päivityspaketti (Extruder drive). Ellei sinulla ole tätä "
|
||||
"päivitystä, sitä suositellaan kovasti luotettavuuden parantamiseksi. Tämä "
|
||||
"päivityspaketti voidaan ostaa Ultimakerin verkkokaupasta tai se löytyy "
|
||||
"thingiverse-sivustolta numerolla: 26094"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:44
|
||||
msgctxt "@label"
|
||||
|
@ -465,36 +469,38 @@ msgid ""
|
|||
"It's a good idea to do a few sanity checks on your Ultimaker. You can skip "
|
||||
"this step if you know your machine is functional"
|
||||
msgstr ""
|
||||
"Ultimakerille on hyvä tehdä muutamia toimintatarkastuksia. Voit jättää tämän "
|
||||
"vaiheen väliin, jos tiedät laitteesi olevan toimintakunnossa"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:49
|
||||
msgctxt "@action:button"
|
||||
msgid "Start Printer Check"
|
||||
msgstr ""
|
||||
msgstr "Aloita tulostintarkistus"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:56
|
||||
msgctxt "@action:button"
|
||||
msgid "Skip Printer Check"
|
||||
msgstr ""
|
||||
msgstr "Ohita tulostintarkistus"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:65
|
||||
msgctxt "@label"
|
||||
msgid "Connection: "
|
||||
msgstr ""
|
||||
msgstr "Yhteys:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:69
|
||||
msgctxt "@info:status"
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
msgstr "Valmis"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:69
|
||||
msgctxt "@info:status"
|
||||
msgid "Incomplete"
|
||||
msgstr ""
|
||||
msgstr "Kesken"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:76
|
||||
msgctxt "@label"
|
||||
msgid "Min endstop X: "
|
||||
msgstr ""
|
||||
msgstr "Min. päätyraja X:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:80
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:91
|
||||
|
@ -503,7 +509,7 @@ msgstr ""
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:201
|
||||
msgctxt "@info:status"
|
||||
msgid "Works"
|
||||
msgstr ""
|
||||
msgstr "Toimii"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:80
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:91
|
||||
|
@ -512,40 +518,39 @@ msgstr ""
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:163
|
||||
msgctxt "@info:status"
|
||||
msgid "Not checked"
|
||||
msgstr ""
|
||||
msgstr "Ei tarkistettu"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:87
|
||||
msgctxt "@label"
|
||||
msgid "Min endstop Y: "
|
||||
msgstr ""
|
||||
msgstr "Min. päätyraja Y:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:99
|
||||
msgctxt "@label"
|
||||
msgid "Min endstop Z: "
|
||||
msgstr ""
|
||||
msgstr "Min. päätyraja Z:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:111
|
||||
msgctxt "@label"
|
||||
msgid "Nozzle temperature check: "
|
||||
msgstr ""
|
||||
msgstr "Suuttimen lämpötilatarkistus:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:119
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:149
|
||||
msgctxt "@action:button"
|
||||
msgid "Start Heating"
|
||||
msgstr ""
|
||||
msgstr "Aloita lämmitys"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:124
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:154
|
||||
msgctxt "@info:progress"
|
||||
msgid "Checking"
|
||||
msgstr ""
|
||||
msgstr "Tarkistetaan"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UltimakerCheckup.qml:141
|
||||
#, fuzzy
|
||||
msgctxt "@label"
|
||||
msgid "bed temperature check:"
|
||||
msgstr "Pöydän lämpötila %1"
|
||||
msgstr "Pöydän lämpötilan tarkistus:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UpgradeFirmware.qml:38
|
||||
msgctxt "@label"
|
||||
|
@ -554,6 +559,9 @@ msgid ""
|
|||
"firmware controls the step motors, regulates the temperature and ultimately "
|
||||
"makes your printer work."
|
||||
msgstr ""
|
||||
"Laiteohjelmisto on suoraan 3D-tulostimessa toimiva ohjelma. Laiteohjelmisto "
|
||||
"ohjaa askelmoottoreita, säätää lämpötilaa ja loppujen lopuksi saa tulostimen "
|
||||
"toimimaan."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UpgradeFirmware.qml:45
|
||||
msgctxt "@label"
|
||||
|
@ -561,6 +569,8 @@ msgid ""
|
|||
"The firmware shipping with new Ultimakers works, but upgrades have been made "
|
||||
"to make better prints, and make calibration easier."
|
||||
msgstr ""
|
||||
"Uusien Ultimakerien mukana toimitettu laiteohjelmisto toimii, mutta "
|
||||
"päivityksillä saadaan parempia tulosteita ja kalibrointi helpottuu."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UpgradeFirmware.qml:52
|
||||
msgctxt "@label"
|
||||
|
@ -568,37 +578,36 @@ msgid ""
|
|||
"Cura requires these new features and thus your firmware will most likely "
|
||||
"need to be upgraded. You can do so now."
|
||||
msgstr ""
|
||||
"Cura tarvitsee näitä uusia ominaisuuksia ja siten laiteohjelmisto on "
|
||||
"todennäköisesti päivitettävä. Voit tehdä sen nyt."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UpgradeFirmware.qml:55
|
||||
#, fuzzy
|
||||
msgctxt "@action:button"
|
||||
msgid "Upgrade to Marlin Firmware"
|
||||
msgstr "Päivitä laiteohjelmisto"
|
||||
msgstr "Päivitä Marlin-laiteohjelmistoon"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/WizardPages/UpgradeFirmware.qml:58
|
||||
msgctxt "@action:button"
|
||||
msgid "Skip Upgrade"
|
||||
msgstr ""
|
||||
msgstr "Ohita päivitys"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/AboutDialog.qml:15
|
||||
#, fuzzy
|
||||
msgctxt "@title:window"
|
||||
msgid "About Cura"
|
||||
msgstr "Tietoja Curasta"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/AboutDialog.qml:54
|
||||
#, fuzzy
|
||||
msgctxt "@label"
|
||||
msgid "End-to-end solution for fused filament 3D printing."
|
||||
msgstr "Kokonaisvaltainen sulatettavan tulostuslangan 3D-tulostusratkaisu."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/AboutDialog.qml:66
|
||||
#, fuzzy
|
||||
msgctxt "@info:credit"
|
||||
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."
|
||||
"Cura-ohjelman on kehittänyt Ultimaker B.V. yhteistyössä käyttäjäyhteisön "
|
||||
"kanssa."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/ViewPage.qml:16
|
||||
#, fuzzy
|
||||
|
@ -618,11 +627,13 @@ msgid ""
|
|||
"Highlight unsupported areas of the model in red. Without support these areas "
|
||||
"will nog print properly."
|
||||
msgstr ""
|
||||
"Korostaa mallin vailla tukea olevat alueet punaisella. Ilman tukea nämä "
|
||||
"alueet eivät tulostu kunnolla."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/ViewPage.qml:74
|
||||
msgctxt "@action:button"
|
||||
msgid "Center camera when item is selected"
|
||||
msgstr ""
|
||||
msgstr "Keskitä kamera kun kohde on valittu"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/ViewPage.qml:78
|
||||
msgctxt "@info:tooltip"
|
||||
|
@ -630,11 +641,13 @@ msgid ""
|
|||
"Moves the camera so the object is in the center of the view when an object "
|
||||
"is selected"
|
||||
msgstr ""
|
||||
"Siirtää kameraa siten, että kappale on näkymän keskellä, kun kappale on "
|
||||
"valittu"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:51
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Toggle Fu&ll Screen"
|
||||
msgstr ""
|
||||
msgstr "Vaihda &koko näyttöön"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:58
|
||||
#, fuzzy
|
||||
|
@ -655,10 +668,9 @@ msgid "&Quit"
|
|||
msgstr "&Lopeta"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:82
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "&Preferences..."
|
||||
msgstr "&Suosikkiasetukset..."
|
||||
msgstr "&Lisäasetukset..."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:89
|
||||
#, fuzzy
|
||||
|
@ -667,15 +679,14 @@ msgid "&Add Printer..."
|
|||
msgstr "L&isää tulostin..."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:95
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Manage Pr&inters..."
|
||||
msgstr "L&isää tulostin..."
|
||||
msgstr "Tulostinten &hallinta..."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:102
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Manage Profiles..."
|
||||
msgstr ""
|
||||
msgstr "Profiilien hallinta..."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:109
|
||||
#, fuzzy
|
||||
|
@ -696,74 +707,64 @@ msgid "&About..."
|
|||
msgstr "Ti&etoja..."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:130
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Delete &Selection"
|
||||
msgstr "Poista valinta"
|
||||
msgstr "&Poista valinta"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:138
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Delete Object"
|
||||
msgstr "Poista kohde"
|
||||
msgstr "Poista kappale"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:146
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Ce&nter Object on Platform"
|
||||
msgstr "Keskitä kohde alustalle"
|
||||
msgstr "K&eskitä kappale alustalle"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:152
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "&Group Objects"
|
||||
msgstr ""
|
||||
msgstr "&Ryhmitä kappaleet"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:160
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Ungroup Objects"
|
||||
msgstr ""
|
||||
msgstr "Pura kappaleiden ryhmitys"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:168
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "&Merge Objects"
|
||||
msgstr "Poista kohde"
|
||||
msgstr "&Yhdistä kappaleet"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:176
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "&Duplicate Object"
|
||||
msgstr "Monista kohde"
|
||||
msgstr "&Monista kappale"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:183
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "&Clear Build Platform"
|
||||
msgstr "Tyhjennä alusta"
|
||||
msgstr "&Tyhjennä alusta"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:190
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Re&load All Objects"
|
||||
msgstr "Lataa kaikki kohteet uudelleen"
|
||||
msgstr "&Lataa kaikki kappaleet uudelleen"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:197
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Reset All Object Positions"
|
||||
msgstr "Nollaa kaikki kohteiden sijainnit"
|
||||
msgstr "Nollaa kaikkien kappaleiden sijainnit"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:203
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "Reset All Object &Transformations"
|
||||
msgstr "Nollaa kaikkien kohteiden muunnokset"
|
||||
msgstr "Nollaa kaikkien kappaleiden m&uunnokset"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:209
|
||||
#, fuzzy
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "&Open File..."
|
||||
msgstr "Avaa tiedosto"
|
||||
msgstr "&Avaa tiedosto..."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Actions.qml:217
|
||||
#, fuzzy
|
||||
|
@ -775,84 +776,87 @@ msgstr "Näytä moottorin l&oki"
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Cura.qml:461
|
||||
msgctxt "@title:tab"
|
||||
msgid "General"
|
||||
msgstr ""
|
||||
msgstr "Yleiset"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:36
|
||||
msgctxt "@label"
|
||||
msgid "Language"
|
||||
msgstr ""
|
||||
msgstr "Kieli"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:47
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "Bulgarian"
|
||||
msgstr ""
|
||||
msgstr "bulgaria"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:48
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "Czech"
|
||||
msgstr ""
|
||||
msgstr "tsekki"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:49
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "English"
|
||||
msgstr ""
|
||||
msgstr "englanti"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:50
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "Finnish"
|
||||
msgstr ""
|
||||
msgstr "suomi"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:51
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "French"
|
||||
msgstr ""
|
||||
msgstr "ranska"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:52
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "German"
|
||||
msgstr ""
|
||||
msgstr "saksa"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:53
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "Italian"
|
||||
msgstr ""
|
||||
msgstr "italia"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:54
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "Polish"
|
||||
msgstr ""
|
||||
msgstr "puola"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:55
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "Russian"
|
||||
msgstr ""
|
||||
msgstr "venäjä"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:56
|
||||
msgctxt "@item:inlistbox"
|
||||
msgid "Spanish"
|
||||
msgstr ""
|
||||
msgstr "espanja"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:98
|
||||
msgctxt "@label"
|
||||
msgid ""
|
||||
"You will need to restart the application for language changes to have effect."
|
||||
msgstr ""
|
||||
"Sovellus on käynnistettävä uudelleen, jotta kielimuutokset tulevat voimaan."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:114
|
||||
msgctxt "@option:check"
|
||||
msgid "Ensure objects are kept apart"
|
||||
msgstr ""
|
||||
msgstr "Pidä kappaleet erillään"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:118
|
||||
msgctxt "@info:tooltip"
|
||||
msgid ""
|
||||
"Should objects on the platform be moved so that they no longer intersect."
|
||||
msgstr ""
|
||||
"Pitäisikö kappaleita alustalla siirtää niin, etteivät ne enää leikkaa "
|
||||
"toisiaan?"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:147
|
||||
msgctxt "@option:check"
|
||||
msgid "Send (Anonymous) Print Information"
|
||||
msgstr ""
|
||||
msgstr "Lähetä (anonyymit) tulostustiedot"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:151
|
||||
msgctxt "@info:tooltip"
|
||||
|
@ -861,103 +865,102 @@ msgid ""
|
|||
"models, IP addresses or other personally identifiable information is sent or "
|
||||
"stored."
|
||||
msgstr ""
|
||||
"Pitäisikö anonyymejä tietoja tulosteesta lähettää Ultimakerille? Huomaa, "
|
||||
"että malleja, IP-osoitteita tai muita henkilökohtaisia tietoja ei lähetetä "
|
||||
"eikä tallenneta."
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:179
|
||||
msgctxt "@option:check"
|
||||
msgid "Scale Too Large Files"
|
||||
msgstr ""
|
||||
msgstr "Skaalaa liian isot tiedostot"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/GeneralPage.qml:183
|
||||
msgctxt "@info:tooltip"
|
||||
msgid ""
|
||||
"Should opened files be scaled to the build volume when they are too large?"
|
||||
msgstr ""
|
||||
"Pitäisikö avoimia tiedostoja skaalata rakennustilavuuteen, jos ne ovat liian "
|
||||
"isoja?"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SaveButton.qml:70
|
||||
#, fuzzy
|
||||
msgctxt "@label:textbox"
|
||||
msgid "Printjob Name"
|
||||
msgstr "Tulostimen nimi:"
|
||||
msgstr "Tulostustyön nimi"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SaveButton.qml:167
|
||||
msgctxt "@label %1 is length of filament"
|
||||
msgid "%1 m"
|
||||
msgstr ""
|
||||
msgstr "%1 m"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SaveButton.qml:229
|
||||
msgctxt "@info:tooltip"
|
||||
msgid "Select the active output device"
|
||||
msgstr ""
|
||||
msgstr "Valitse aktiivinen oheislaite"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarSimple.qml:34
|
||||
msgctxt "@label"
|
||||
msgid "Infill:"
|
||||
msgstr ""
|
||||
msgstr "Täyttö:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarSimple.qml:119
|
||||
msgctxt "@label"
|
||||
msgid "Sparse"
|
||||
msgstr ""
|
||||
msgstr "Harva"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarSimple.qml:121
|
||||
msgctxt "@label"
|
||||
msgid "Sparse (20%) infill will give your model an average strength"
|
||||
msgstr ""
|
||||
msgstr "Harva (20 %) täyttö antaa mallille keskimääräistä lujuutta"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarSimple.qml:125
|
||||
msgctxt "@label"
|
||||
msgid "Dense"
|
||||
msgstr ""
|
||||
msgstr "Tiheä"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarSimple.qml:127
|
||||
msgctxt "@label"
|
||||
msgid "Dense (50%) infill will give your model an above average strength"
|
||||
msgstr ""
|
||||
msgstr "Tiheä (50 %) täyttö antaa mallille keskimääräistä paremman lujuuden"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarSimple.qml:131
|
||||
msgctxt "@label"
|
||||
msgid "Solid"
|
||||
msgstr ""
|
||||
msgstr "Kiinteä"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarSimple.qml:133
|
||||
msgctxt "@label"
|
||||
msgid "Solid (100%) infill will make your model completely solid"
|
||||
msgstr ""
|
||||
msgstr "Kiinteä (100 %) täyttö tekee mallista täysin umpinaisen"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarSimple.qml:151
|
||||
#, fuzzy
|
||||
msgctxt "@label:listbox"
|
||||
msgid "Helpers:"
|
||||
msgstr "&Ohje"
|
||||
msgstr "Avustimet:"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarSimple.qml:169
|
||||
msgctxt "@option:check"
|
||||
msgid "Enable Skirt Adhesion"
|
||||
msgstr ""
|
||||
msgstr "Ota helman tarttuvuus käyttöön"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarSimple.qml:187
|
||||
#, fuzzy
|
||||
msgctxt "@option:check"
|
||||
msgid "Enable Support"
|
||||
msgstr "Ota tuki käyttöön"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Sidebar.qml:123
|
||||
#, fuzzy
|
||||
msgctxt "@title:tab"
|
||||
msgid "Simple"
|
||||
msgstr "Perusasetukset"
|
||||
msgstr "Suppea"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Sidebar.qml:124
|
||||
#, fuzzy
|
||||
msgctxt "@title:tab"
|
||||
msgid "Advanced"
|
||||
msgstr "Lisäasetukset"
|
||||
msgstr "Laajennettu"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarHeader.qml:30
|
||||
#, fuzzy
|
||||
msgctxt "@label:listbox"
|
||||
msgid "Print Setup"
|
||||
msgstr "Tulostimen asennus"
|
||||
msgstr "Tulostusasetukset"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/SidebarHeader.qml:100
|
||||
#, fuzzy
|
||||
|
@ -980,18 +983,17 @@ msgstr "&Tiedosto"
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Cura.qml:43
|
||||
msgctxt "@title:menu"
|
||||
msgid "Open &Recent"
|
||||
msgstr ""
|
||||
msgstr "Avaa &viimeisin"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Cura.qml:72
|
||||
msgctxt "@action:inmenu"
|
||||
msgid "&Save Selection to File"
|
||||
msgstr ""
|
||||
msgstr "&Tallenna valinta tiedostoon"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Cura.qml:80
|
||||
#, fuzzy
|
||||
msgctxt "@title:menu"
|
||||
msgid "Save &All"
|
||||
msgstr "Tallenna tiedosto"
|
||||
msgstr "Tallenna &kaikki"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Cura.qml:108
|
||||
#, fuzzy
|
||||
|
@ -1000,10 +1002,9 @@ msgid "&Edit"
|
|||
msgstr "&Muokkaa"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Cura.qml:125
|
||||
#, fuzzy
|
||||
msgctxt "@title:menu"
|
||||
msgid "&View"
|
||||
msgstr "Näytä"
|
||||
msgstr "&Näytä"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Cura.qml:151
|
||||
#, fuzzy
|
||||
|
@ -1014,7 +1015,7 @@ msgstr "&Laite"
|
|||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Cura.qml:197
|
||||
msgctxt "@title:menu"
|
||||
msgid "&Profile"
|
||||
msgstr ""
|
||||
msgstr "&Profiili"
|
||||
|
||||
#: /home/ahiemstra/dev/15.10/src/cura/resources/qml/Cura.qml:224
|
||||
#, fuzzy
|
||||
|
|
1771
resources/i18n/fi/fdmprinter.json.po
Normal file → Executable file
1771
resources/i18n/fi/fdmprinter.json.po
Normal file → Executable file
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
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
Binary file not shown.
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 20 KiB |
|
@ -2,13 +2,13 @@
|
|||
"id": "rigidbotbig",
|
||||
"version": 1,
|
||||
"name": "RigidBot",
|
||||
"manufacturer": "Invent-A-Part",
|
||||
"manufacturer": "Other",
|
||||
"author": "RBC",
|
||||
"platform": "rigidbot_platform.stl",
|
||||
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
|
||||
"machine_width": { "default": 254 },
|
||||
"machine_depth": { "default": 254 },
|
||||
|
@ -18,6 +18,8 @@
|
|||
"machine_nozzle_size": { "default": 0.4,
|
||||
"visible": true
|
||||
},
|
||||
"machine_nozzle_heat_up_speed": { "default": 2.0 },
|
||||
"machine_nozzle_cool_down_speed": { "default": 2.0 },
|
||||
"machine_head_shape_min_x": { "default": 0 },
|
||||
"machine_head_shape_min_y": { "default": 0 },
|
||||
"machine_head_shape_max_x": { "default": 0 },
|
||||
|
@ -26,14 +28,12 @@
|
|||
"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..."
|
||||
"default": ";Sliced at: {day} {date} {time}\n;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {infill_sparse_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 },
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
"id": "rigidbotbig",
|
||||
"version": 1,
|
||||
"name": "RigidBotBig",
|
||||
"manufacturer": "Invent-A-Part",
|
||||
"manufacturer": "Other",
|
||||
"author": "RBC",
|
||||
"platform": "rigidbotbig_platform.stl",
|
||||
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
|
||||
"machine_width": { "default": 400 },
|
||||
"machine_depth": { "default": 300 },
|
||||
|
@ -16,6 +16,8 @@
|
|||
"machine_heated_bed": { "default": true },
|
||||
|
||||
"machine_nozzle_size": { "default": 0.4},
|
||||
"machine_nozzle_heat_up_speed": { "default": 2.0 },
|
||||
"machine_nozzle_cool_down_speed": { "default": 2.0 },
|
||||
"machine_head_shape_min_x": { "default": 0 },
|
||||
"machine_head_shape_min_y": { "default": 0 },
|
||||
"machine_head_shape_max_x": { "default": 0 },
|
||||
|
@ -24,14 +26,12 @@
|
|||
"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..."
|
||||
"default": ";Sliced at: {day} {date} {time}\n;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {infill_sparse_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 },
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
"id": "bq_hephestos",
|
||||
"version": 1,
|
||||
"name": "BQ Prusa i3 Hephestos",
|
||||
"manufacturer": "BQ",
|
||||
"manufacturer": "Other",
|
||||
"author": "BQ",
|
||||
"platform": "hephestos_platform.stl",
|
||||
"platform": "bq_hephestos_platform.stl",
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
"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 --"
|
||||
},
|
||||
|
@ -33,10 +33,8 @@
|
|||
"default": "RepRap"
|
||||
},
|
||||
"machine_platform_offset": {
|
||||
"default": [0, 100, 0]
|
||||
}
|
||||
},
|
||||
"overrides": {
|
||||
"default": [0, -82, 0]
|
||||
},
|
||||
"layer_height": { "default": 0.2 },
|
||||
"layer_height_0": { "default": 0.2, "visible": false },
|
||||
"shell_thickness": { "default": 1.0 },
|
||||
|
|
65
resources/machines/bq_hephestos_2.json
Normal file
65
resources/machines/bq_hephestos_2.json
Normal file
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"id": "bq_hephestos_2",
|
||||
"version": 1,
|
||||
"name": "BQ Hephestos 2",
|
||||
"manufacturer": "Other",
|
||||
"author": "BQ",
|
||||
"platform": "bq_hephestos_2_platform.stl",
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"overrides": {
|
||||
"machine_start_gcode": {
|
||||
"default": "; -- START GCODE --\nM800 ; Custom GCODE to fire start print procedure\n; -- end of START GCODE --"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default": "; -- END GCODE --\nM801 ; Custom GCODE to fire end print procedure\n; -- end of END GCODE --"
|
||||
},
|
||||
"machine_width": {
|
||||
"default": 210
|
||||
},
|
||||
"machine_depth": {
|
||||
"default": 297
|
||||
},
|
||||
"machine_height": {
|
||||
"default": 220
|
||||
},
|
||||
"machine_heated_bed": {
|
||||
"default": false
|
||||
},
|
||||
"machine_center_is_zero": {
|
||||
"default": false
|
||||
},
|
||||
"machine_gcode_flavor": {
|
||||
"default": "RepRap"
|
||||
},
|
||||
"machine_platform_offset": {
|
||||
"default": [-6, 1320, 0]
|
||||
}
|
||||
"material_print_temperature": { "default": 210.0, "visible": true },
|
||||
"material_bed_temperature": { "default": 0 },
|
||||
"material_diameter": { "default": 1.75 },
|
||||
"layer_height": { "default": 0.2 },
|
||||
"layer_height_0": { "default": 0.2, "visible": true },
|
||||
"shell_thickness": { "default": 1.2 },
|
||||
"wall_line_count": { "default": 3, "visible": false },
|
||||
"wall_thickness": { "default": 1.2, "visible": false },
|
||||
"top_bottom_thickness": { "default": 1.2, "visible": false },
|
||||
"infill_sparse_density": { "default": 20.0 },
|
||||
"infill_overlap": { "default": 15.0, "visible": false },
|
||||
"speed_print": { "default": 60.0 },
|
||||
"speed_travel": { "default": 160.0 },
|
||||
"speed_layer_0": { "default": 30.0, "visible": true },
|
||||
"speed_wall_x": { "default": 35.0, "visible": false },
|
||||
"speed_wall_0": { "default": 30.0, "visible": false },
|
||||
"speed_infill": { "default": 80.0, "visible": true },
|
||||
"speed_topbottom": { "default": 35.0, "visible": false },
|
||||
"skirt_speed": { "default": 35.0, "visible": false },
|
||||
"retraction_amount": { "default": 2.0, "visible": false },
|
||||
"retraction_speed": { "default": 45.0, "visible": false },
|
||||
"skirt_line_count": { "default": 4 },
|
||||
"skirt_minimal_length": { "default": 30.0, "visible": false },
|
||||
"skirt_gap": { "default": 6.0 },
|
||||
"cool_fan_full_at_height": { "default": 0.4, "visible": false },
|
||||
"support_enable": { "default": false }
|
||||
}
|
||||
}
|
|
@ -2,12 +2,12 @@
|
|||
"id": "bq_hephestos_xl",
|
||||
"version": 1,
|
||||
"name": "BQ Prusa i3 Hephestos XL",
|
||||
"manufacturer": "BQ",
|
||||
"manufacturer": "Other",
|
||||
"author": "BQ",
|
||||
"platform": "hephestos_platform.stl",
|
||||
"platform": "bq_hephestos_platform.stl",
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
"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 --"
|
||||
},
|
||||
|
@ -33,10 +33,8 @@
|
|||
"default": "RepRap"
|
||||
},
|
||||
"machine_platform_offset": {
|
||||
"default": [0, 100, 0]
|
||||
}
|
||||
},
|
||||
"overrides": {
|
||||
"default": [0, -82, 0]
|
||||
},
|
||||
"layer_height": { "default": 0.2 },
|
||||
"layer_height_0": { "default": 0.2, "visible": false },
|
||||
"shell_thickness": { "default": 1.0 },
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
"id": "bq_witbox",
|
||||
"version": 1,
|
||||
"name": "BQ Witbox",
|
||||
"manufacturer": "BQ",
|
||||
"manufacturer": "Other",
|
||||
"author": "BQ",
|
||||
"platform": "witbox_platform.stl",
|
||||
"platform": "bq_witbox_platform.stl",
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
"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 --"
|
||||
},
|
||||
|
@ -34,9 +34,7 @@
|
|||
},
|
||||
"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 },
|
||||
|
|
65
resources/machines/bq_witbox_2.json
Normal file
65
resources/machines/bq_witbox_2.json
Normal file
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"id": "bq_witbox_2",
|
||||
"version": 1,
|
||||
"name": "BQ Witbox 2",
|
||||
"manufacturer": "Other",
|
||||
"author": "BQ",
|
||||
"platform": "bq_witbox_platform.stl",
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"overrides": {
|
||||
"machine_start_gcode": {
|
||||
"default": "; -- START GCODE --\nM800 ; Custom GCODE to fire start print procedure\n; -- end of START GCODE --"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default": "; -- END GCODE --\nM801 ; Custom GCODE to fire end print procedure\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]
|
||||
},
|
||||
"material_print_temperature": { "default": 210.0, "visible": true },
|
||||
"material_bed_temperature": { "default": 0 },
|
||||
"material_diameter": { "default": 1.75 },
|
||||
"layer_height": { "default": 0.2 },
|
||||
"layer_height_0": { "default": 0.2, "visible": true },
|
||||
"shell_thickness": { "default": 1.2 },
|
||||
"wall_line_count": { "default": 3, "visible": false },
|
||||
"wall_thickness": { "default": 1.2, "visible": false },
|
||||
"top_bottom_thickness": { "default": 1.2, "visible": false },
|
||||
"infill_sparse_density": { "default": 20.0 },
|
||||
"infill_overlap": { "default": 15.0, "visible": false },
|
||||
"speed_print": { "default": 60.0 },
|
||||
"speed_travel": { "default": 160.0 },
|
||||
"speed_layer_0": { "default": 30.0, "visible": true },
|
||||
"speed_wall_x": { "default": 35.0, "visible": false },
|
||||
"speed_wall_0": { "default": 30.0, "visible": false },
|
||||
"speed_infill": { "default": 80.0, "visible": true },
|
||||
"speed_topbottom": { "default": 35.0, "visible": false },
|
||||
"skirt_speed": { "default": 35.0, "visible": false },
|
||||
"retraction_amount": { "default": 2.0, "visible": false },
|
||||
"retraction_speed": { "default": 45.0, "visible": false },
|
||||
"skirt_line_count": { "default": 4 },
|
||||
"skirt_minimal_length": { "default": 30.0, "visible": false },
|
||||
"skirt_gap": { "default": 6.0 },
|
||||
"cool_fan_full_at_height": { "default": 0.4, "visible": false },
|
||||
"support_enable": { "default": false }
|
||||
}
|
||||
}
|
271
resources/machines/dual_extrusion_printer.json
Normal file
271
resources/machines/dual_extrusion_printer.json
Normal file
|
@ -0,0 +1,271 @@
|
|||
{
|
||||
"version": 1,
|
||||
"id": "dual_extrusion",
|
||||
"name": "Dual Extrusion Base File",
|
||||
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"visible": false,
|
||||
|
||||
|
||||
"machine_extruder_trains": {
|
||||
"0": {
|
||||
"extruder_nr": { "default": 0 },
|
||||
"machine_nozzle_offset_x": { "default": 0.0 },
|
||||
"machine_nozzle_offset_y": { "default": 0.0 }
|
||||
},
|
||||
"1": {
|
||||
"extruder_nr": { "default": 1 }
|
||||
}
|
||||
},
|
||||
|
||||
"machine_settings": {
|
||||
"machine_use_extruder_offset_to_offset_coords": { "default": false },
|
||||
|
||||
"machine_nozzle_offset_x": { "default": 0, "SEE_machine_extruder_trains": true },
|
||||
"machine_nozzle_offset_y": { "default": 0, "SEE_machine_extruder_trains": true },
|
||||
"machine_extruder_start_code": { "default": "", "SEE_machine_extruder_trains": true },
|
||||
"machine_extruder_start_pos_abs": { "default": false, "SEE_machine_extruder_trains": true },
|
||||
"machine_extruder_start_pos_x": { "default": 0, "SEE_machine_extruder_trains": true },
|
||||
"machine_extruder_start_pos_y": { "default": 0, "SEE_machine_extruder_trains": true },
|
||||
"machine_extruder_end_pos_abs": { "default": false, "SEE_machine_extruder_trains": true },
|
||||
"machine_extruder_end_pos_x": { "default": 0, "SEE_machine_extruder_trains": true },
|
||||
"machine_extruder_end_pos_y": { "default": 0, "SEE_machine_extruder_trains": true },
|
||||
"machine_extruder_end_code": { "default": "", "SEE_machine_extruder_trains": true }
|
||||
},
|
||||
"overrides": {
|
||||
"speed_print": {
|
||||
"children": {
|
||||
"speed_prime_tower": {
|
||||
"label": "Prime Tower Speed",
|
||||
"description": "The speed at which the prime tower is printed. Printing the prime tower slower can make it more stable when the adhesion between the different filaments is suboptimal.",
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"min_value": "0.1",
|
||||
"max_value_warning": "150",
|
||||
"default": 60,
|
||||
"visible": false,
|
||||
"enabled": "prime_tower_enable"
|
||||
}
|
||||
}
|
||||
},
|
||||
"line_width": {
|
||||
"children": {
|
||||
"prime_tower_line_width": {
|
||||
"label": "Prime Tower Line Width",
|
||||
"description": "Width of a single prime tower line.",
|
||||
"unit": "mm",
|
||||
"min_value": "0.0001",
|
||||
"min_value_warning": "0.2",
|
||||
"max_value_warning": "5",
|
||||
"default": 0.4,
|
||||
"type": "float",
|
||||
"visible": false,
|
||||
"enabled": "prime_tower_enable"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"categories": {
|
||||
"dual": {
|
||||
"label": "Dual Extrusion",
|
||||
"visible": true,
|
||||
"icon": "category_dual",
|
||||
"settings": {
|
||||
"extruder_nr": {
|
||||
"label": "Extruder",
|
||||
"description": "The extruder train used for printing. This is used in multi-extrusion.",
|
||||
"type": "int",
|
||||
"default": 0,
|
||||
"min_value": "0",
|
||||
"max_value": "16",
|
||||
"always_visible": true,
|
||||
|
||||
"children": {
|
||||
"adhesion_extruder_nr": {
|
||||
"label": "Platform Adhesion Extruder",
|
||||
"description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.",
|
||||
"type": "int",
|
||||
"default": 0,
|
||||
"min_value": "0",
|
||||
"max_value": "16"
|
||||
},
|
||||
"support_extruder_nr": {
|
||||
"label": "Support Extruder",
|
||||
"description": "The extruder train to use for printing the support. This is used in multi-extrusion.",
|
||||
"type": "int",
|
||||
"default": 0,
|
||||
"min_value": "0",
|
||||
"max_value": "16",
|
||||
"children": {
|
||||
"support_infill_extruder_nr": {
|
||||
"label": "Support Infill Extruder",
|
||||
"description": "The extruder train to use for printing the infill of the support. This is used in multi-extrusion.",
|
||||
"type": "int",
|
||||
"default": 0,
|
||||
"min_value": "0",
|
||||
"max_value": "16"
|
||||
},
|
||||
"support_extruder_nr_layer_0": {
|
||||
"label": "First Layer Support Extruder",
|
||||
"description": "The extruder train to use for printing the first layer of support infill. This is used in multi-extrusion.",
|
||||
"type": "int",
|
||||
"default": 0,
|
||||
"min_value": "0",
|
||||
"max_value": "16"
|
||||
},
|
||||
"support_roof_extruder_nr": {
|
||||
"label": "Support Roof Extruder",
|
||||
"description": "The extruder train to use for printing the roof of the support. This is used in multi-extrusion.",
|
||||
"type": "int",
|
||||
"default": 0,
|
||||
"min_value": "0",
|
||||
"max_value": "16",
|
||||
"enabled": "support_roof_enable"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"prime_tower_enable": {
|
||||
"label": "Enable Prime Tower",
|
||||
"description": "Print a tower next to the print which serves to prime the material after each nozzle switch.",
|
||||
"type": "boolean",
|
||||
"visible": true,
|
||||
"default": false
|
||||
},
|
||||
"prime_tower_size": {
|
||||
"label": "Prime Tower Size",
|
||||
"description": "The width of the prime tower.",
|
||||
"visible": false,
|
||||
"type": "float",
|
||||
"unit": "mm",
|
||||
"default": 15,
|
||||
"min_value": "0",
|
||||
"max_value_warning": "20",
|
||||
"inherit_function": "15 if prime_tower_enable else 0",
|
||||
"enabled": "prime_tower_enable"
|
||||
},
|
||||
"prime_tower_position_x": {
|
||||
"label": "Prime Tower X Position",
|
||||
"description": "The x position of the prime tower.",
|
||||
"visible": false,
|
||||
"type": "float",
|
||||
"unit": "mm",
|
||||
"default": 200,
|
||||
"enabled": "prime_tower_enable"
|
||||
},
|
||||
"prime_tower_position_y": {
|
||||
"label": "Prime Tower Y Position",
|
||||
"description": "The y position of the prime tower.",
|
||||
"visible": false,
|
||||
"type": "float",
|
||||
"unit": "mm",
|
||||
"default": 200,
|
||||
"enabled": "prime_tower_enable"
|
||||
},
|
||||
"prime_tower_flow": {
|
||||
"label": "Prime Tower Flow",
|
||||
"description": "Flow compensation: the amount of material extruded is multiplied by this value.",
|
||||
"visible": false,
|
||||
"unit": "%",
|
||||
"default": 100,
|
||||
"type": "float",
|
||||
"min_value": "5",
|
||||
"min_value_warning": "50",
|
||||
"max_value_warning": "150",
|
||||
"enabled": "prime_tower_enable"
|
||||
},
|
||||
"prime_tower_wipe_enabled": {
|
||||
"label": "Wipe Nozzle on Prime tower",
|
||||
"description": "After printing the prime tower with the one nozzle, wipe the oozed material from the other nozzle off on the prime tower.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"enabled": "prime_tower_enable"
|
||||
},
|
||||
"multiple_mesh_overlap": {
|
||||
"label": "Dual Extrusion Overlap",
|
||||
"description": "Make the objects printed with different extruder trains overlap a bit. This makes the different materials bond together better.",
|
||||
"visible": false,
|
||||
"type": "float",
|
||||
"unit": "mm",
|
||||
"default": 0.15,
|
||||
"min_value": "0",
|
||||
"max_value_warning": "1.0"
|
||||
},
|
||||
"ooze_shield_enabled": {
|
||||
"label": "Enable Ooze Shield",
|
||||
"description": "Enable exterior ooze shield. This will create a shell around the object which is likely to wipe a second nozzle if it's at the same height as the first nozzle.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"ooze_shield_angle": {
|
||||
"label": "Ooze Shield Angle",
|
||||
"description": "The maximum angle a part in the ooze shield will have. With 0 degrees being vertical, and 90 degrees being horizontal. A smaller angle leads to less failed ooze shields, but more material.",
|
||||
"unit": "°",
|
||||
"type": "float",
|
||||
"min_value": "0",
|
||||
"max_value": "90",
|
||||
"default": 60,
|
||||
"visible": false,
|
||||
"enabled": "ooze_shield_enabled"
|
||||
},
|
||||
"ooze_shield_dist": {
|
||||
"label": "Ooze Shields Distance",
|
||||
"description": "Distance of the ooze shield from the print, in the X/Y directions.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"min_value": "0",
|
||||
"max_value_warning": "30",
|
||||
"default": 2,
|
||||
"visible": false,
|
||||
"enabled": "ooze_shield_enabled"
|
||||
}
|
||||
}
|
||||
},
|
||||
"material": {
|
||||
"settings": {
|
||||
"switch_extruder_retraction_amount": {
|
||||
"label": "Nozzle Switch Retraction Distance",
|
||||
"description": "The amount of retraction: Set at 0 for no retraction at all. This should generally be the same as the length of the heat zone.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default": 16,
|
||||
"visible": false,
|
||||
"inherit_function": "machine_heat_zone_length",
|
||||
"enabled": "retraction_enable"
|
||||
},
|
||||
"switch_extruder_retraction_speeds": {
|
||||
"label": "Nozzle Switch Retraction Speed",
|
||||
"description": "The speed at which the filament is retracted. A higher retraction speed works better, but a very high retraction speed can lead to filament grinding.",
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"default": 20,
|
||||
"visible": false,
|
||||
"inherit": false,
|
||||
"enabled": "retraction_enable",
|
||||
"children": {
|
||||
"switch_extruder_retraction_speed": {
|
||||
"label": "Nozzle Switch Retract Speed",
|
||||
"description": "The speed at which the filament is retracted during a nozzle switch retract. ",
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"default": 20,
|
||||
"visible": false,
|
||||
"enabled": "retraction_enable"
|
||||
},
|
||||
"switch_extruder_prime_speed": {
|
||||
"label": "Nozzle Switch Prime Speed",
|
||||
"description": "The speed at which the filament is pushed back after a nozzle switch retraction.",
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"default": 20,
|
||||
"visible": false,
|
||||
"enabled": "retraction_enable"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -3,19 +3,21 @@
|
|||
"version": 1,
|
||||
"name": "German RepRap Neo",
|
||||
"manufacturer": "Other",
|
||||
"author": "other",
|
||||
"author": "Other",
|
||||
"icon": "icon_ultimaker.png",
|
||||
"platform": "grr_neo_platform.stl",
|
||||
|
||||
"inherits": "fdmprinter.json",
|
||||
"visible": "true",
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
"machine_width": { "default": 150 },
|
||||
"machine_height": { "default": 150 },
|
||||
"machine_depth": { "default": 150 },
|
||||
"machine_center_is_zero": { "default": false },
|
||||
"machine_nozzle_size": { "default": 0.5 },
|
||||
"machine_nozzle_heat_up_speed": { "default": 2.0 },
|
||||
"machine_nozzle_cool_down_speed": { "default": 2.0 },
|
||||
"machine_head_shape_min_x": { "default": 75 },
|
||||
"machine_head_shape_min_y": { "default": 18 },
|
||||
"machine_head_shape_max_x": { "default": 18 },
|
||||
|
@ -28,10 +30,8 @@
|
|||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"material_bed_temperature": { "visible": false }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
"machine_width": { "default": 210 },
|
||||
"machine_depth": { "default": 185 },
|
||||
"machine_height": { "default": 200 },
|
||||
|
@ -17,6 +17,8 @@
|
|||
|
||||
"machine_center_is_zero": { "default": false },
|
||||
"machine_nozzle_size": { "default": 0.4 },
|
||||
"machine_nozzle_heat_up_speed": { "default": 2.0 },
|
||||
"machine_nozzle_cool_down_speed": { "default": 2.0 },
|
||||
"machine_head_shape_min_x": { "default": 0 },
|
||||
"machine_head_shape_min_y": { "default": 0 },
|
||||
"machine_head_shape_max_x": { "default": 0 },
|
||||
|
@ -28,10 +30,8 @@
|
|||
|
||||
"machine_nozzle_tip_outer_diameter": { "default": 1.0 },
|
||||
"machine_nozzle_head_distance": { "default": 3.0 },
|
||||
"machine_nozzle_expansion_angle": { "default": 45 }
|
||||
},
|
||||
"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 },
|
||||
|
|
|
@ -2,19 +2,22 @@
|
|||
"id": "prusa_i3",
|
||||
"version": 1,
|
||||
"name": "Prusa i3",
|
||||
"manufacturer": "Prusa",
|
||||
"author": "other",
|
||||
"manufacturer": "Other",
|
||||
"author": "Other",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
"platform": "prusai3_platform.stl",
|
||||
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
"machine_heated_bed": { "default": true },
|
||||
"machine_width": { "default": 200 },
|
||||
"machine_height": { "default": 200 },
|
||||
"machine_depth": { "default": 200 },
|
||||
"machine_center_is_zero": { "default": false },
|
||||
"machine_nozzle_size": { "default": 0.4 },
|
||||
"machine_nozzle_heat_up_speed": { "default": 2.0 },
|
||||
"machine_nozzle_cool_down_speed": { "default": 2.0 },
|
||||
"machine_head_shape_min_x": { "default": 75 },
|
||||
"machine_head_shape_min_y": { "default": 18 },
|
||||
"machine_head_shape_max_x": { "default": 18 },
|
||||
|
@ -28,9 +31,5 @@
|
|||
"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"
|
||||
}
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"material_bed_temperature": { "visible": true }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,13 @@
|
|||
"inherits": "fdmprinter.json",
|
||||
|
||||
|
||||
"machine_extruder_trains": [
|
||||
{
|
||||
"machine_nozzle_size": {
|
||||
"default": 0.4
|
||||
"machine_extruder_trains": {
|
||||
"0": {
|
||||
"machine_nozzle_heat_up_speed": {
|
||||
"default": 2.0
|
||||
},
|
||||
"machine_nozzle_cool_down_speed": {
|
||||
"default": 2.0
|
||||
},
|
||||
"machine_nozzle_tip_outer_diameter": {
|
||||
"default": 1
|
||||
|
@ -29,8 +32,8 @@
|
|||
"default": 16
|
||||
}
|
||||
}
|
||||
],
|
||||
"machine_settings": {
|
||||
},
|
||||
"overrides": {
|
||||
"machine_start_gcode" : { "default": "" },
|
||||
"machine_end_gcode" : { "default": "" },
|
||||
"machine_width": { "default": 230 },
|
||||
|
@ -42,25 +45,27 @@
|
|||
{
|
||||
"default": [
|
||||
[
|
||||
-40,
|
||||
30
|
||||
-42,
|
||||
12
|
||||
],
|
||||
[
|
||||
-40,
|
||||
-10
|
||||
-42,
|
||||
-32
|
||||
],
|
||||
[
|
||||
60,
|
||||
-10
|
||||
62,
|
||||
12
|
||||
],
|
||||
[
|
||||
60,
|
||||
30
|
||||
62,
|
||||
-32
|
||||
]
|
||||
]
|
||||
},
|
||||
"machine_center_is_zero": { "default": false },
|
||||
"machine_nozzle_size": { "default": 0.4 },
|
||||
"machine_nozzle_size": { "default": 0.4, "description": "The inner diameter of the hole in the nozzle. If you are using an Olsson Block with a non-standard nozzle then set this field to the nozzle size you are using." },
|
||||
"machine_nozzle_heat_up_speed": { "default": 2.0 },
|
||||
"machine_nozzle_cool_down_speed": { "default": 2.0 },
|
||||
"gantry_height": { "default": 55 },
|
||||
"machine_use_extruder_offset_to_offset_coords": { "default": true },
|
||||
"machine_gcode_flavor": { "default": "UltiGCode" },
|
||||
|
@ -74,10 +79,8 @@
|
|||
|
||||
"machine_nozzle_tip_outer_diameter": { "default": 1.0 },
|
||||
"machine_nozzle_head_distance": { "default": 3.0 },
|
||||
"machine_nozzle_expansion_angle": { "default": 45 }
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_nozzle_expansion_angle": { "default": 45 },
|
||||
|
||||
"material_print_temperature": { "enabled": "False" },
|
||||
"material_bed_temperature": { "enabled": "False" },
|
||||
"material_diameter": { "enabled": "False" },
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
"inherits": "ultimaker2.json",
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
"machine_width": { "default": 230 },
|
||||
"machine_depth": { "default": 225 },
|
||||
"machine_height": { "default": 315 }
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
"inherits": "ultimaker2.json",
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
"machine_width": { "default": 120 },
|
||||
"machine_depth": { "default": 120 },
|
||||
"machine_height": { "default": 115 },
|
||||
|
|
|
@ -16,10 +16,13 @@
|
|||
"BedLeveling"
|
||||
],
|
||||
|
||||
"machine_extruder_trains": [
|
||||
{
|
||||
"machine_nozzle_size": {
|
||||
"default": 0.4
|
||||
"machine_extruder_trains": {
|
||||
"0": {
|
||||
"machine_nozzle_heat_up_speed": {
|
||||
"default": 2.0
|
||||
},
|
||||
"machine_nozzle_cool_down_speed": {
|
||||
"default": 2.0
|
||||
},
|
||||
"machine_nozzle_tip_outer_diameter": {
|
||||
"default": 1
|
||||
|
@ -34,13 +37,15 @@
|
|||
"default": 16
|
||||
}
|
||||
}
|
||||
],
|
||||
"machine_settings": {
|
||||
},
|
||||
"overrides": {
|
||||
"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_nozzle_heat_up_speed": { "default": 2.0 },
|
||||
"machine_nozzle_cool_down_speed": { "default": 2.0 },
|
||||
"machine_head_with_fans_polygon":
|
||||
{
|
||||
"default": [
|
||||
|
@ -71,10 +76,8 @@
|
|||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"material_bed_temperature": { "visible": false }
|
||||
"machine_extruder_drive_upgrade": { "default": false }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"BedLeveling"
|
||||
],
|
||||
|
||||
"machine_settings": {
|
||||
"overrides": {
|
||||
"machine_heated_bed": { "default": true }
|
||||
}
|
||||
}
|
||||
|
|
BIN
resources/meshes/bq_hephestos_2_platform.stl
Normal file
BIN
resources/meshes/bq_hephestos_2_platform.stl
Normal file
Binary file not shown.
BIN
resources/meshes/bq_hephestos_platform.stl
Normal file
BIN
resources/meshes/bq_hephestos_platform.stl
Normal file
Binary file not shown.
Binary file not shown.
BIN
resources/meshes/inventor_platform.STL
Normal file
BIN
resources/meshes/inventor_platform.STL
Normal file
Binary file not shown.
|
@ -4,3 +4,5 @@ name = High Quality
|
|||
|
||||
[settings]
|
||||
layer_height = 0.06
|
||||
infill_sparse_density = 12
|
||||
|
||||
|
|
15
resources/profiles/Low+Quality.cfg
Normal file
15
resources/profiles/Low+Quality.cfg
Normal file
|
@ -0,0 +1,15 @@
|
|||
[general]
|
||||
version = 1
|
||||
name = Low Quality
|
||||
|
||||
[settings]
|
||||
layer_height = 0.15
|
||||
shell_thickness = 0.8
|
||||
infill_sparse_density = 8
|
||||
speed_print = 60
|
||||
speed_wall_0 = 40
|
||||
speed_wall_x = 50
|
||||
speed_topbottom = 30
|
||||
speed_travel = 150
|
||||
speed_layer_0 = 30
|
||||
skirt_speed = 30
|
|
@ -3,4 +3,3 @@ version = 1
|
|||
name = Normal Quality
|
||||
|
||||
[settings]
|
||||
layer_height = 0.1
|
||||
|
|
9
resources/profiles/Ulti+Quality.cfg
Normal file
9
resources/profiles/Ulti+Quality.cfg
Normal file
|
@ -0,0 +1,9 @@
|
|||
[general]
|
||||
version = 1
|
||||
name = Ulti Quality
|
||||
|
||||
[settings]
|
||||
layer_height = 0.04
|
||||
shell_thickness = 1.6
|
||||
top_bottom_thickness = 0.8
|
||||
infill_sparse_density = 14
|
|
@ -47,7 +47,6 @@ Item
|
|||
Action
|
||||
{
|
||||
id:toggleFullScreenAction
|
||||
shortcut: StandardKey.FullScreen;
|
||||
text: catalog.i18nc("@action:inmenu","Toggle Fu&ll Screen");
|
||||
iconName: "view-fullscreen";
|
||||
}
|
||||
|
@ -137,7 +136,6 @@ Item
|
|||
id: deleteObjectAction;
|
||||
text: catalog.i18nc("@action:inmenu","Delete Object");
|
||||
iconName: "edit-delete";
|
||||
shortcut: StandardKey.Backspace;
|
||||
}
|
||||
|
||||
Action
|
||||
|
@ -182,6 +180,7 @@ Item
|
|||
id: deleteAllAction;
|
||||
text: catalog.i18nc("@action:inmenu","&Clear Build Platform");
|
||||
iconName: "edit-delete";
|
||||
shortcut: "Ctrl+D";
|
||||
}
|
||||
|
||||
Action
|
||||
|
@ -216,5 +215,6 @@ Item
|
|||
id: showEngineLogAction;
|
||||
text: catalog.i18nc("@action:inmenu","Show Engine &Log...");
|
||||
iconName: "view-list-text";
|
||||
shortcut: StandardKey.WhatsThis;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,19 @@ UM.MainWindow
|
|||
id: backgroundItem;
|
||||
anchors.fill: parent;
|
||||
UM.I18nCatalog{id: catalog; name:"cura"}
|
||||
|
||||
//DeleteSelection on the keypress backspace event
|
||||
Keys.onPressed: {
|
||||
if (event.key == Qt.Key_Backspace)
|
||||
{
|
||||
if(objectContextMenu.objectId != 0)
|
||||
{
|
||||
Printer.deleteObject(objectContextMenu.objectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UM.ApplicationMenu
|
||||
{
|
||||
id: menu
|
||||
|
@ -72,7 +85,7 @@ UM.MainWindow
|
|||
text: catalog.i18nc("@action:inmenu", "&Save Selection to File");
|
||||
enabled: UM.Selection.hasSelection;
|
||||
iconName: "document-save-as";
|
||||
onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file");
|
||||
onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", Printer.jobName);
|
||||
}
|
||||
Menu
|
||||
{
|
||||
|
@ -88,7 +101,7 @@ UM.MainWindow
|
|||
MenuItem
|
||||
{
|
||||
text: model.description;
|
||||
onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id);
|
||||
onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id, Printer.jobName);
|
||||
}
|
||||
onObjectAdded: saveAllMenu.insertItem(index, object)
|
||||
onObjectRemoved: saveAllMenu.removeItem(object)
|
||||
|
@ -139,10 +152,6 @@ UM.MainWindow
|
|||
onObjectRemoved: top_view_menu.removeItem(object)
|
||||
}
|
||||
ExclusiveGroup { id: view_menu_top_group; }
|
||||
|
||||
MenuSeparator { }
|
||||
|
||||
MenuItem { action: actions.toggleFullScreen; }
|
||||
}
|
||||
Menu
|
||||
{
|
||||
|
@ -301,14 +310,24 @@ UM.MainWindow
|
|||
}
|
||||
}
|
||||
|
||||
JobSpecs
|
||||
{
|
||||
anchors
|
||||
{
|
||||
bottom: parent.bottom;
|
||||
right: sidebar.left;
|
||||
bottomMargin: UM.Theme.sizes.default_margin.height;
|
||||
rightMargin: UM.Theme.sizes.default_margin.width;
|
||||
}
|
||||
}
|
||||
|
||||
UM.MessageStack
|
||||
{
|
||||
anchors
|
||||
{
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
horizontalCenterOffset: -(UM.Theme.sizes.logo.width/ 2)
|
||||
top: parent.verticalCenter;
|
||||
bottom: parent.bottom;
|
||||
horizontalCenterOffset: -(UM.Theme.sizes.sidebar.width/ 2)
|
||||
verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,8 +340,7 @@ UM.MainWindow
|
|||
//anchors.bottom: parent.bottom
|
||||
anchors.top: viewModeButton.bottom
|
||||
anchors.topMargin: UM.Theme.sizes.default_margin.height;
|
||||
anchors.right: sidebar.left;
|
||||
anchors.rightMargin: UM.Theme.sizes.window_margin.width;
|
||||
anchors.left: viewModeButton.left;
|
||||
//anchors.bottom: buttons.top;
|
||||
//anchors.bottomMargin: UM.Theme.sizes.default_margin.height;
|
||||
|
||||
|
@ -335,10 +353,9 @@ UM.MainWindow
|
|||
{
|
||||
id: openFileButton;
|
||||
//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
|
||||
style: UM.Theme.styles.tool_button
|
||||
tooltip: '';
|
||||
anchors
|
||||
{
|
||||
|
@ -364,6 +381,7 @@ UM.MainWindow
|
|||
source: UM.Theme.images.logo;
|
||||
width: UM.Theme.sizes.logo.width;
|
||||
height: UM.Theme.sizes.logo.height;
|
||||
z: -1;
|
||||
|
||||
sourceSize.width: width;
|
||||
sourceSize.height: height;
|
||||
|
@ -372,12 +390,12 @@ UM.MainWindow
|
|||
Button
|
||||
{
|
||||
id: viewModeButton
|
||||
property bool verticalTooltip: true
|
||||
|
||||
anchors
|
||||
{
|
||||
top: parent.top;
|
||||
right: sidebar.left;
|
||||
rightMargin: UM.Theme.sizes.window_margin.width;
|
||||
top: toolbar.bottom;
|
||||
topMargin: UM.Theme.sizes.window_margin.height;
|
||||
left: parent.left;
|
||||
}
|
||||
text: catalog.i18nc("@action:button","View Mode");
|
||||
iconSource: UM.Theme.icons.viewmode;
|
||||
|
@ -389,12 +407,13 @@ UM.MainWindow
|
|||
id: viewMenu;
|
||||
Instantiator
|
||||
{
|
||||
id: viewMenuInstantiator
|
||||
model: UM.ViewModel { }
|
||||
MenuItem
|
||||
{
|
||||
text: model.name;
|
||||
text: model.name
|
||||
checkable: true;
|
||||
checked: model.active;
|
||||
checked: model.active
|
||||
exclusiveGroup: viewMenuGroup;
|
||||
onTriggered: UM.Controller.setActiveView(model.id);
|
||||
}
|
||||
|
@ -411,12 +430,9 @@ UM.MainWindow
|
|||
id: toolbar;
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
topMargin: 74
|
||||
//horizontalCenter: parent.horizontalCenter
|
||||
//horizontalCenterOffset: -(UM.Theme.sizes.sidebar.width / 2)
|
||||
//top: parent.top;
|
||||
top: openFileButton.bottom;
|
||||
topMargin: UM.Theme.sizes.window_margin.height;
|
||||
left: parent.left;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,14 +479,27 @@ UM.MainWindow
|
|||
{
|
||||
//; 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"));
|
||||
insertPage(0, catalog.i18nc("@title:tab","General"), generalPage);
|
||||
|
||||
//: View preferences page title
|
||||
insertPage(1, catalog.i18nc("@title:tab","View"), "view-preview", Qt.resolvedUrl("./ViewPage.qml"));
|
||||
insertPage(1, catalog.i18nc("@title:tab","View"), viewPage);
|
||||
|
||||
//Force refresh
|
||||
setPage(0)
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: false
|
||||
GeneralPage
|
||||
{
|
||||
id: generalPage
|
||||
}
|
||||
|
||||
ViewPage
|
||||
{
|
||||
id: viewPage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Actions
|
||||
|
@ -543,8 +572,8 @@ UM.MainWindow
|
|||
|
||||
addMachine.onTriggered: addMachineWizard.visible = true;
|
||||
|
||||
preferences.onTriggered: preferences.visible = true;
|
||||
configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(2); }
|
||||
preferences.onTriggered: { preferences.visible = true; preferences.setPage(0); }
|
||||
configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(3); }
|
||||
manageProfiles.onTriggered: { preferences.visible = true; preferences.setPage(4); }
|
||||
|
||||
documentation.onTriggered: CuraActions.openDocumentation();
|
||||
|
@ -605,7 +634,7 @@ UM.MainWindow
|
|||
id: openDialog;
|
||||
|
||||
//: File open dialog title
|
||||
title: catalog.i18nc("@title:window","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
|
||||
|
@ -621,6 +650,11 @@ UM.MainWindow
|
|||
|
||||
onAccepted:
|
||||
{
|
||||
//Because several implementations of the file dialog only update the folder
|
||||
//when it is explicitly set.
|
||||
var f = folder;
|
||||
folder = f;
|
||||
|
||||
UM.MeshFileHandler.readLocalFile(fileUrl)
|
||||
openDialog.sendMeshName(fileUrl.toString())
|
||||
}
|
||||
|
@ -648,14 +682,34 @@ UM.MainWindow
|
|||
onRequestAddPrinter:
|
||||
{
|
||||
addMachineWizard.visible = true
|
||||
addMachineWizard.firstRun = true
|
||||
addMachineWizard.firstRun = false
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted:
|
||||
{
|
||||
UM.Theme.load(UM.Resources.getPath(UM.Resources.Themes, "cura"))
|
||||
base.visible = true;
|
||||
}
|
||||
|
||||
Timer
|
||||
{
|
||||
id: startupTimer;
|
||||
interval: 100;
|
||||
repeat: false;
|
||||
running: true;
|
||||
onTriggered:
|
||||
{
|
||||
if(!base.visible)
|
||||
{
|
||||
base.visible = true;
|
||||
restart();
|
||||
}
|
||||
else if(UM.MachineManager.activeMachineInstance == "")
|
||||
{
|
||||
addMachineWizard.firstRun = true;
|
||||
addMachineWizard.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,18 @@ UM.PreferencesPage
|
|||
//: General configuration page title
|
||||
title: catalog.i18nc("@title:tab","General");
|
||||
|
||||
function setDefaultLanguage(languageCode)
|
||||
{
|
||||
//loops trough the languageList and sets the language using the languageCode
|
||||
for(var i = 0; i < languageList.count; i++)
|
||||
{
|
||||
if (languageComboBox.model.get(i).code == languageCode)
|
||||
{
|
||||
languageComboBox.currentIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reset()
|
||||
{
|
||||
UM.Preferences.resetPreference("general/language")
|
||||
|
@ -22,7 +34,8 @@ UM.PreferencesPage
|
|||
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
|
||||
var defaultLanguage = UM.Preferences.getValue("general/language")
|
||||
setDefaultLanguage(defaultLanguage)
|
||||
}
|
||||
|
||||
GridLayout
|
||||
|
@ -44,16 +57,16 @@ UM.PreferencesPage
|
|||
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", "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", "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" })
|
||||
// append({ text: catalog.i18nc("@item:inlistbox", "Russian"), code: "ru" })
|
||||
// append({ text: catalog.i18nc("@item:inlistbox", "Spanish"), code: "es" })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
165
resources/qml/JobSpecs.qml
Normal file
165
resources/qml/JobSpecs.qml
Normal file
|
@ -0,0 +1,165 @@
|
|||
// 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
|
||||
|
||||
Rectangle {
|
||||
id: base;
|
||||
|
||||
property bool activity: Printer.getPlatformActivity;
|
||||
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;
|
||||
|
||||
width: UM.Theme.sizes.jobspecs.width
|
||||
height: childrenRect.height
|
||||
color: "transparent"
|
||||
|
||||
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]
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
printJobTextfield.text = abbrMachine + '_' + base.fileBaseName
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: openDialog
|
||||
onHasMesh: {
|
||||
if(base.fileBaseName == ''){
|
||||
base.fileBaseName = name
|
||||
base.createFileName()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onActivityChanged: {
|
||||
if (activity == false){
|
||||
base.fileBaseName = ''
|
||||
base.createFileName()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TextField {
|
||||
id: printJobTextfield
|
||||
anchors.right: parent.right
|
||||
height: UM.Theme.sizes.jobspecs_line.height
|
||||
width: base.width
|
||||
property int unremovableSpacing: 5
|
||||
text: ''
|
||||
horizontalAlignment: TextInput.AlignRight
|
||||
onTextChanged: Printer.setJobName(text)
|
||||
visible: base.activity
|
||||
onEditingFinished: {
|
||||
if (printJobTextfield.text != ''){
|
||||
printJobTextfield.focus = false
|
||||
}
|
||||
}
|
||||
validator: RegExpValidator {
|
||||
regExp: /^[^\\ \/ \.]*$/
|
||||
}
|
||||
style: TextFieldStyle{
|
||||
textColor: UM.Theme.colors.setting_control_text;
|
||||
font: UM.Theme.fonts.default;
|
||||
background: Rectangle {
|
||||
opacity: 0
|
||||
border.width: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label{
|
||||
id: boundingSpec
|
||||
anchors.top: printJobTextfield.bottom
|
||||
anchors.right: parent.right
|
||||
height: UM.Theme.sizes.jobspecs_line.height
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font: UM.Theme.fonts.small
|
||||
color: UM.Theme.colors.text_subtext
|
||||
text: Printer.getSceneBoundingBoxString
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: specsRow
|
||||
anchors.top: boundingSpec.bottom
|
||||
anchors.right: parent.right
|
||||
height: UM.Theme.sizes.jobspecs_line.height
|
||||
|
||||
Item{
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
UM.RecolorImage {
|
||||
id: timeIcon
|
||||
anchors.right: timeSpec.left
|
||||
anchors.rightMargin: UM.Theme.sizes.default_margin.width/2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
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_subtext
|
||||
source: UM.Theme.icons.print_time;
|
||||
}
|
||||
Label{
|
||||
id: timeSpec
|
||||
anchors.right: lengthIcon.left
|
||||
anchors.rightMargin: UM.Theme.sizes.default_margin.width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: UM.Theme.fonts.small
|
||||
color: UM.Theme.colors.text_subtext
|
||||
text: (!base.printDuration || !base.printDuration.valid) ? "00h 00min" : base.printDuration.getDisplayString(UM.DurationFormat.Short)
|
||||
}
|
||||
UM.RecolorImage {
|
||||
id: lengthIcon
|
||||
anchors.right: lengthSpec.left
|
||||
anchors.rightMargin: UM.Theme.sizes.default_margin.width/2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
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_subtext
|
||||
source: UM.Theme.icons.category_material;
|
||||
}
|
||||
Label{
|
||||
id: lengthSpec
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: UM.Theme.fonts.small
|
||||
color: UM.Theme.colors.text_subtext
|
||||
text: base.printMaterialAmount <= 0 ? "0.0 m" : catalog.i18nc("@label %1 is length of filament","%1 m").arg(base.printMaterialAmount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,69 +8,68 @@ import QtQuick.Layouts 1.1
|
|||
|
||||
import UM 1.1 as UM
|
||||
|
||||
Column{
|
||||
Item{
|
||||
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
|
||||
Rectangle {
|
||||
id: variantRow
|
||||
anchors.top: base.top
|
||||
width: base.width
|
||||
visible: UM.MachineManager.hasVariants;
|
||||
height: UM.Theme.sizes.sidebar_setup.height
|
||||
//visible: UM.MachineManager.hasVariants;
|
||||
visible: true
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
menu: Menu
|
||||
{
|
||||
id: variantsSelectionMenu
|
||||
Instantiator
|
||||
{
|
||||
id: variantsSelectionMenu
|
||||
Instantiator
|
||||
model: UM.MachineVariantsModel { id: variantsModel }
|
||||
MenuItem
|
||||
{
|
||||
model: UM.MachineVariantsModel { }
|
||||
MenuItem
|
||||
{
|
||||
text: model.name;
|
||||
checkable: true;
|
||||
checked: model.active;
|
||||
exclusiveGroup: variantSelectionMenuGroup;
|
||||
onTriggered: UM.MachineManager.setActiveMachineVariant(model.getItem(index).name)
|
||||
}
|
||||
text: model.name;
|
||||
checkable: true;
|
||||
checked: model.active;
|
||||
exclusiveGroup: variantSelectionMenuGroup;
|
||||
onTriggered: UM.MachineManager.setActiveMachineVariant(variantsModel.getItem(index).name)
|
||||
}
|
||||
|
||||
ExclusiveGroup { id: variantSelectionMenuGroup; }
|
||||
onObjectAdded: variantsSelectionMenu.insertItem(index, object)
|
||||
onObjectRemoved: variantsSelectionMenu.removeItem(object)
|
||||
}
|
||||
|
||||
ExclusiveGroup { id: variantSelectionMenuGroup; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
id: globalProfileRow;
|
||||
anchors.top: UM.MachineManager.hasVariants ? variantRow.bottom : base.top
|
||||
//anchors.top: variantRow.bottom
|
||||
height: UM.Theme.sizes.sidebar_setup.height
|
||||
width: base.width
|
||||
|
||||
|
@ -82,6 +81,7 @@ Column{
|
|||
text: catalog.i18nc("@label","Global Profile:");
|
||||
width: parent.width/100*45
|
||||
font: UM.Theme.fonts.default;
|
||||
color: UM.Theme.colors.text;
|
||||
}
|
||||
|
||||
|
||||
|
@ -148,8 +148,4 @@ Column{
|
|||
// }
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
width: base.width
|
||||
height: UM.Theme.sizes.default_margin.width/2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,176 +10,71 @@ import UM 1.1 as UM
|
|||
|
||||
Rectangle {
|
||||
id: base;
|
||||
UM.I18nCatalog { id: catalog; name:"cura"}
|
||||
|
||||
property real progress: UM.Backend.progress;
|
||||
property bool activity: Printer.getPlatformActivity;
|
||||
Behavior on progress { NumberAnimation { duration: 250; } }
|
||||
property int totalHeight: childrenRect.height
|
||||
//Behavior on progress { NumberAnimation { duration: 250; } }
|
||||
property int totalHeight: childrenRect.height + UM.Theme.sizes.default_margin.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;
|
||||
|
||||
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]
|
||||
|
||||
}
|
||||
}
|
||||
property string statusText: {
|
||||
if(progress == 0) {
|
||||
if(!activity) {
|
||||
return catalog.i18nc("@label:PrintjobStatus","Please load a 3d model");
|
||||
} else {
|
||||
return catalog.i18nc("@label:PrintjobStatus","Preparing to slice...");
|
||||
}
|
||||
printJobTextfield.text = abbrMachine + '_' + base.fileBaseName
|
||||
} else if(base.progress < 0.99) {
|
||||
return catalog.i18nc("@label:PrintjobStatus","Slicing...");
|
||||
} else {
|
||||
return catalog.i18nc("@label:PrintjobStatus","Ready to ") + UM.OutputDeviceManager.activeDeviceShortDescription;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: openDialog
|
||||
onHasMesh: {
|
||||
base.fileBaseName = name
|
||||
base.createFileName()
|
||||
}
|
||||
Label {
|
||||
id: statusLabel
|
||||
width: parent.width - 2 * UM.Theme.sizes.default_margin.width
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: UM.Theme.sizes.default_margin.width
|
||||
|
||||
color: UM.Theme.colors.text
|
||||
font: UM.Theme.fonts.large
|
||||
text: statusText;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
id: progressBar
|
||||
width: parent.width - 2 * UM.Theme.sizes.default_margin.width
|
||||
height: UM.Theme.sizes.progressbar.height
|
||||
anchors.top: statusLabel.bottom
|
||||
anchors.topMargin: UM.Theme.sizes.default_margin.height/4
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: UM.Theme.sizes.default_margin.width
|
||||
radius: UM.Theme.sizes.progressbar_radius.width
|
||||
color: UM.Theme.colors.progressbar_background
|
||||
|
||||
Rectangle {
|
||||
id: specsRow
|
||||
implicitWidth: base.width
|
||||
implicitHeight: UM.Theme.sizes.sidebar_specs_bar.height
|
||||
anchors.top: printJobRow.bottom
|
||||
Item{
|
||||
id: time
|
||||
width: childrenRect.width;
|
||||
Rectangle{
|
||||
width: Math.max(parent.width * base.progress)
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
color: UM.Theme.colors.progressbar_control
|
||||
radius: UM.Theme.sizes.progressbar_radius.width
|
||||
visible: base.progress > 0.99 ? false : true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
id: saveRow
|
||||
width: base.width
|
||||
height: saveToButton.height + (UM.Theme.sizes.default_margin.height / 2) // height + bottomMargin
|
||||
anchors.top: specsRow.bottom
|
||||
height: saveToButton.height
|
||||
anchors.top: progressBar.bottom
|
||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||
anchors.left: parent.left
|
||||
|
||||
Button {
|
||||
id: saveToButton
|
||||
property int resizedWidth
|
||||
x: base.width - saveToButton.resizedWidth - UM.Theme.sizes.default_margin.width - UM.Theme.sizes.save_button_save_to_button.height
|
||||
x: base.width - saveToButton.resizedWidth - UM.Theme.sizes.default_margin.width - UM.Theme.sizes.save_button_save_to_button.height + 3
|
||||
tooltip: UM.OutputDeviceManager.activeDeviceDescription;
|
||||
enabled: base.progress > 0.99 && base.activity == true
|
||||
height: UM.Theme.sizes.save_button_save_to_button.height
|
||||
|
@ -188,35 +83,32 @@ Rectangle {
|
|||
text: UM.OutputDeviceManager.activeDeviceShortDescription
|
||||
onClicked:
|
||||
{
|
||||
UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice)
|
||||
UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, Printer.jobName)
|
||||
}
|
||||
|
||||
style: ButtonStyle {
|
||||
background: Rectangle {
|
||||
color: control.hovered ? UM.Theme.colors.load_save_button_hover : UM.Theme.colors.load_save_button
|
||||
//opacity: control.enabled ? 1.0 : 0.5
|
||||
//Behavior on opacity { NumberAnimation { duration: 50; } }
|
||||
border.color: !control.enabled ? UM.Theme.colors.action_button_disabled_border :
|
||||
control.pressed ? UM.Theme.colors.action_button_active_border :
|
||||
control.hovered ? UM.Theme.colors.action_button_hovered_border : UM.Theme.colors.action_button_border
|
||||
color: !control.enabled ? UM.Theme.colors.action_button_disabled :
|
||||
control.pressed ? UM.Theme.colors.action_button_active :
|
||||
control.hovered ? UM.Theme.colors.action_button_hovered : UM.Theme.colors.action_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;
|
||||
saveToButton.resizedWidth = actualLabel.width + (UM.Theme.sizes.default_margin.width * 2)
|
||||
return saveToButton.resizedWidth
|
||||
}
|
||||
Label {
|
||||
id: actualLabel
|
||||
//Behavior on opacity { NumberAnimation { duration: 50; } }
|
||||
anchors.centerIn: parent
|
||||
color: UM.Theme.colors.load_save_button_text
|
||||
font: UM.Theme.fonts.default
|
||||
color: !control.enabled ? UM.Theme.colors.action_button_disabled_text :
|
||||
control.pressed ? UM.Theme.colors.action_button_active_text :
|
||||
control.hovered ? UM.Theme.colors.action_button_hovered_text : UM.Theme.colors.action_button_text
|
||||
font: UM.Theme.fonts.action_button
|
||||
text: control.text;
|
||||
}
|
||||
}
|
||||
|
@ -232,12 +124,18 @@ Rectangle {
|
|||
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
|
||||
enabled: base.progress > 0.99 && base.activity == true
|
||||
//iconSource: UM.Theme.icons[UM.OutputDeviceManager.activeDeviceIconName];
|
||||
|
||||
style: ButtonStyle {
|
||||
background: Rectangle {
|
||||
id: deviceSelectionIcon
|
||||
color: control.hovered ? UM.Theme.colors.load_save_button_hover : UM.Theme.colors.load_save_button
|
||||
border.color: !control.enabled ? UM.Theme.colors.action_button_disabled_border :
|
||||
control.pressed ? UM.Theme.colors.action_button_active_border :
|
||||
control.hovered ? UM.Theme.colors.action_button_hovered_border : UM.Theme.colors.action_button_border
|
||||
color: !control.enabled ? UM.Theme.colors.action_button_disabled :
|
||||
control.pressed ? UM.Theme.colors.action_button_active :
|
||||
control.hovered ? UM.Theme.colors.action_button_hovered : UM.Theme.colors.action_button
|
||||
Behavior on color { ColorAnimation { duration: 50; } }
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: UM.Theme.sizes.save_button_text_margin.width / 2;
|
||||
|
@ -245,15 +143,16 @@ Rectangle {
|
|||
height: parent.height
|
||||
|
||||
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
|
||||
sourceSize.height: height
|
||||
color: !control.enabled ? UM.Theme.colors.action_button_disabled_text :
|
||||
control.pressed ? UM.Theme.colors.action_button_active_text :
|
||||
control.hovered ? UM.Theme.colors.action_button_hovered_text : UM.Theme.colors.action_button_text;
|
||||
source: UM.Theme.icons.arrow_bottom;
|
||||
}
|
||||
}
|
||||
label: Label{ }
|
||||
|
|
|
@ -15,6 +15,7 @@ Rectangle
|
|||
property Action addMachineAction;
|
||||
property Action configureMachinesAction;
|
||||
property Action manageProfilesAction;
|
||||
property int currentModeIndex;
|
||||
|
||||
color: UM.Theme.colors.sidebar;
|
||||
UM.I18nCatalog { id: catalog; name:"cura"}
|
||||
|
@ -49,37 +50,118 @@ Rectangle
|
|||
|
||||
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);
|
||||
Rectangle {
|
||||
id: headerSeparator
|
||||
width: parent.width
|
||||
height: UM.Theme.sizes.sidebar_lining.height
|
||||
color: UM.Theme.colors.sidebar_lining
|
||||
anchors.top: header.bottom
|
||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||
}
|
||||
|
||||
ProfileSetup {
|
||||
id: profileItem
|
||||
manageProfilesAction: base.manageProfilesAction
|
||||
anchors.top: header.bottom
|
||||
anchors.top: settingsModeSelection.bottom
|
||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||
width: parent.width
|
||||
height: totalHeightProfileSetup
|
||||
}
|
||||
|
||||
currentModeIndex:
|
||||
{
|
||||
var index = parseInt(UM.Preferences.getValue("cura/active_mode"))
|
||||
if(index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
onCurrentModeIndexChanged:
|
||||
{
|
||||
UM.Preferences.setValue("cura/active_mode", currentModeIndex);
|
||||
}
|
||||
|
||||
Label {
|
||||
id: settingsModeLabel
|
||||
text: catalog.i18nc("@label:listbox","Setup");
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
|
||||
anchors.top: headerSeparator.bottom
|
||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||
width: parent.width/100*45
|
||||
font: UM.Theme.fonts.large;
|
||||
color: UM.Theme.colors.text
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: settingsModeSelection
|
||||
width: parent.width/100*55
|
||||
height: UM.Theme.sizes.sidebar_header_mode_toggle.height
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: UM.Theme.sizes.default_margin.width
|
||||
anchors.top: headerSeparator.bottom
|
||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||
Component{
|
||||
id: wizardDelegate
|
||||
Button {
|
||||
height: settingsModeSelection.height
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: model.index * (settingsModeSelection.width / 2)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width / 2
|
||||
text: model.text
|
||||
exclusiveGroup: modeMenuGroup;
|
||||
checkable: true;
|
||||
checked: base.currentModeIndex == index
|
||||
onClicked: base.currentModeIndex = index
|
||||
|
||||
style: ButtonStyle {
|
||||
background: Rectangle {
|
||||
border.color: control.checked ? UM.Theme.colors.toggle_checked_border :
|
||||
control.pressed ? UM.Theme.colors.toggle_active_border :
|
||||
control.hovered ? UM.Theme.colors.toggle_hovered_border : UM.Theme.colors.toggle_unchecked_border
|
||||
color: control.checked ? UM.Theme.colors.toggle_checked :
|
||||
control.pressed ? UM.Theme.colors.toggle_active :
|
||||
control.hovered ? UM.Theme.colors.toggle_hovered : UM.Theme.colors.toggle_unchecked
|
||||
Behavior on color { ColorAnimation { duration: 50; } }
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
color: control.checked ? UM.Theme.colors.toggle_checked_text :
|
||||
control.pressed ? UM.Theme.colors.toggle_active_text :
|
||||
control.hovered ? UM.Theme.colors.toggle_hovered_text : UM.Theme.colors.toggle_unchecked_text
|
||||
font: UM.Theme.fonts.default
|
||||
text: control.text;
|
||||
}
|
||||
}
|
||||
label: Item { }
|
||||
}
|
||||
}
|
||||
}
|
||||
ExclusiveGroup { id: modeMenuGroup; }
|
||||
ListView{
|
||||
id: modesList
|
||||
property var index: 0
|
||||
model: modesListModel
|
||||
delegate: wizardDelegate
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
|
||||
Loader
|
||||
{
|
||||
id: sidebarContents;
|
||||
anchors.bottom: saveButton.top
|
||||
anchors.bottom: footerSeparator.top
|
||||
anchors.top: profileItem.bottom
|
||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||
anchors.left: base.left
|
||||
anchors.right: base.right
|
||||
|
||||
source: modesListModel.count > header.currentModeIndex ? modesListModel.get(header.currentModeIndex).file : "";
|
||||
source: modesListModel.count > base.currentModeIndex ? modesListModel.get(base.currentModeIndex).file : "";
|
||||
|
||||
property Item sidebar: base;
|
||||
|
||||
|
@ -100,6 +182,15 @@ Rectangle
|
|||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: footerSeparator
|
||||
width: parent.width
|
||||
height: UM.Theme.sizes.sidebar_lining.height
|
||||
color: UM.Theme.colors.sidebar_lining
|
||||
anchors.bottom: saveButton.top
|
||||
anchors.bottomMargin: UM.Theme.sizes.default_margin.height
|
||||
}
|
||||
|
||||
SaveButton
|
||||
{
|
||||
id: saveButton;
|
||||
|
@ -122,6 +213,6 @@ Rectangle
|
|||
{
|
||||
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)
|
||||
sidebarContents.setSource(modesListModel.get(base.currentModeIndex).file)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,6 @@ Item
|
|||
{
|
||||
id: base;
|
||||
// Machine Setup
|
||||
property variant modesModel;
|
||||
property int currentModeIndex: 0;
|
||||
property Action addMachineAction;
|
||||
property Action configureMachinesAction;
|
||||
UM.I18nCatalog { id: catalog; name:"cura"}
|
||||
|
@ -21,77 +19,29 @@ Item
|
|||
Rectangle {
|
||||
id: settingsModeRow
|
||||
width: base.width
|
||||
height: UM.Theme.sizes.sidebar_header.height
|
||||
height: 0
|
||||
anchors.top: parent.top
|
||||
color: UM.Theme.colors.sidebar_header_bar
|
||||
}
|
||||
|
||||
Label{
|
||||
id: settingsModeLabel
|
||||
text: catalog.i18nc("@label:listbox","Print Setup");
|
||||
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;
|
||||
color: UM.Theme.colors.text_white
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
id: settingsModeSelection
|
||||
width: parent.width/100*55
|
||||
height: childrenRect.height - UM.Theme.sizes.default_margin.width;
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: UM.Theme.sizes.default_margin.width;
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Component{
|
||||
id: wizardDelegate
|
||||
Button {
|
||||
id: simpleModeButton
|
||||
height: settingsModeSelection.height
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: model.index * (settingsModeSelection.width / 2)
|
||||
anchors.top: parent.top
|
||||
width: parent.width / 2
|
||||
text: model.text
|
||||
exclusiveGroup: modeMenuGroup;
|
||||
checkable: true;
|
||||
checked: base.currentModeIndex == index
|
||||
onClicked: base.currentModeIndex = index
|
||||
style: ButtonStyle {
|
||||
background: Rectangle {
|
||||
color: control.checked ? UM.Theme.colors.toggle_active : UM.Theme.colors.toggle_disabled
|
||||
Behavior on color { ColorAnimation { duration: 50; } }
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
color: control.checked ? UM.Theme.colors.toggle_active_text : UM.Theme.colors.toggle_disabled_text
|
||||
font: UM.Theme.fonts.default
|
||||
text: control.text;
|
||||
}
|
||||
}
|
||||
label: Item { }
|
||||
}
|
||||
}
|
||||
}
|
||||
ExclusiveGroup { id: modeMenuGroup; }
|
||||
ListView{
|
||||
id: modesList
|
||||
property var index: 0
|
||||
model: base.modesModel
|
||||
delegate: wizardDelegate
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
width: parent.width
|
||||
height: UM.Theme.sizes.sidebar_header.height
|
||||
currentIndex: base.currentIndex;
|
||||
}
|
||||
}
|
||||
Label{
|
||||
id: printjobTabLabel
|
||||
text: catalog.i18nc("@label:listbox","Print Job");
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
|
||||
anchors.top: settingsModeRow.bottom
|
||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||
width: parent.width/100*45
|
||||
font: UM.Theme.fonts.large;
|
||||
color: UM.Theme.colors.text
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: machineSelectionRow
|
||||
width: base.width
|
||||
height: UM.Theme.sizes.sidebar_header.height
|
||||
anchors.top: settingsModeRow.bottom
|
||||
height: UM.Theme.sizes.sidebar_setup.height
|
||||
anchors.top: printjobTabLabel.bottom
|
||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Label{
|
||||
|
@ -102,6 +52,7 @@ Item
|
|||
anchors.leftMargin: UM.Theme.sizes.default_margin.width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font: UM.Theme.fonts.default;
|
||||
color: UM.Theme.colors.text;
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
|
@ -110,7 +61,6 @@ Item
|
|||
width: parent.width/100*55
|
||||
height: UM.Theme.sizes.setting_control.height
|
||||
tooltip: UM.MachineManager.activeMachineInstance;
|
||||
//style: UM.Theme.styles.sidebar_header_button;
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: UM.Theme.sizes.default_margin.width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue