Merge branch '2.1'

This commit is contained in:
Tim Kuipers 2016-01-28 15:25:18 +01:00
commit 8a48791a0b
83 changed files with 14784 additions and 9510 deletions

1
.gitignore vendored
View file

@ -1,5 +1,6 @@
*.pyc
*kdev*
*.kate-swp
__pycache__
docs/html
*.lprof

View file

@ -9,6 +9,20 @@ set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY
set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY)
# Macro needed to list all sub-directory of a directory.
# There is no function in cmake as far as I know.
# Found at: http://stackoverflow.com/a/7788165
MACRO(SUBDIRLIST result curdir)
FILE(GLOB children RELATIVE ${curdir} ${curdir}/*)
SET(dirlist "")
FOREACH(child ${children})
IF(IS_DIRECTORY ${curdir}/${child})
LIST(APPEND dirlist ${child})
ENDIF()
ENDFOREACH()
SET(${result} ${dirlist})
ENDMACRO()
if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
# Extract Strings
add_custom_target(extract-messages ${URANIUM_SCRIPTS_DIR}/extract-messages ${CMAKE_SOURCE_DIR} cura)
@ -24,36 +38,16 @@ if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
# build directory to the source resources directory. This is mostly a convenience
# during development, normally you want to simply use the install target to install
# the files along side the rest of the application.
add_custom_target(copy-translations)
#TODO: Properly install the built files. This should be done after we move the applications out of the Uranium repo.
set(languages
en
x-test
ru
fr
de
it
es
fi
pl
cs
bg
)
SUBDIRLIST(languages ${CMAKE_SOURCE_DIR}/resources/i18n/)
foreach(lang ${languages})
file(GLOB po_files resources/i18n/${lang}/*.po)
foreach(file ${po_files})
string(REGEX REPLACE ".*/(.*).po" "${lang}/\\1.mo" mofile ${file})
add_custom_command(TARGET translations POST_BUILD COMMAND mkdir ARGS -p ${lang} COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ARGS ${file} -o ${mofile})
file(GLOB po_files ${CMAKE_SOURCE_DIR}/resources/i18n/${lang}/*.po)
foreach(po_file ${po_files})
string(REGEX REPLACE ".*/(.*).po" "${CMAKE_BINARY_DIR}/resources/i18n/${lang}/LC_MESSAGES/\\1.mo" mo_file ${po_file})
add_custom_command(TARGET translations POST_BUILD COMMAND mkdir ARGS -p ${CMAKE_BINARY_DIR}/resources/i18n/${lang}/LC_MESSAGES/ COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ARGS ${po_file} -o ${mo_file})
endforeach()
file(GLOB mo_files ${CMAKE_BINARY_DIR}/${lang}/*.mo)
foreach(file ${mo_files})
add_custom_command(TARGET copy-translations POST_BUILD COMMAND mkdir ARGS -p ${CMAKE_SOURCE_DIR}/resources/i18n/${lang}/LC_MESSAGES/ COMMAND cp ARGS ${file} ${CMAKE_SOURCE_DIR}/resources/i18n/${lang}/LC_MESSAGES/ COMMENT "Copying ${file}...")
endforeach()
install(FILES ${mo_files} DESTINATION ${CMAKE_INSTALL_DATADIR}/uranium/resources/i18n/${lang}/LC_MESSAGES/)
endforeach()
install(DIRECTORY ${CMAKE_BINARY_DIR}/resources DESTINATION ${CMAKE_INSTALL_DATADIR}/cura)
endif()
endif()

View file

@ -1,13 +1,15 @@
[Desktop Entry]
Version=15.06.01
Name=Cura
Name[de]=Cura
GenericName=3D Printing Software
GenericName[de]=3D-Druck-Software
Comment=
Exec=/usr/bin/cura_app.py
TryExec=/usr/bin/cura_app.py
Icon=/usr/share/cura/resources/images/cura-icon.png
Terminal=false
Type=Application
MimeType=application/sla
MimeType=application/sla;image/bmp;image/gif;image/jpeg;image/png
Categories=Graphics;
Keywords=3D;Printing;

View file

@ -129,9 +129,13 @@ class BuildVolume(SceneNode):
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
# Find the largest disallowed area to exclude it from the maximum scale bounds.
# This is a very nasty hack. This pretty much only works for UM machines. This disallowed area_size needs
# A -lot- of rework at some point in the future: TODO
if numpy.min(points[:, 1]) >= 0: # This filters out all areas that have points to the left of the centre. This is done to filter the skirt area.
size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
else:
size = 0
disallowed_area_size = max(size, disallowed_area_size)
self._disallowed_area_mesh = mb.getData()
@ -146,9 +150,12 @@ class BuildVolume(SceneNode):
if profile:
skirt_size = self._getSkirtSize(profile)
# As this works better for UM machines, we only add the dissallowed_area_size for the z direction.
# This is probably wrong in all other cases. TODO!
# The +1 and -1 is added as there is always a bit of extra room required to work properly.
scale_to_max_bounds = AxisAlignedBox(
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)
minimum = Vector(min_w + skirt_size + 1, min_h, min_d + disallowed_area_size - skirt_size + 1),
maximum = Vector(max_w - skirt_size - 1, max_h, max_d - disallowed_area_size + skirt_size - 1)
)
Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
@ -192,6 +199,7 @@ class BuildVolume(SceneNode):
skirt_size = self._getSkirtSize(self._active_profile)
if disallowed_areas:
# Extend every area already in the disallowed_areas with the skirt size.
for area in disallowed_areas:
poly = Polygon(numpy.array(area, numpy.float32))
poly = poly.getMinkowskiHull(Polygon(numpy.array([
@ -207,6 +215,7 @@ class BuildVolume(SceneNode):
areas.append(poly)
# Add the skirt areas arround the borders of the build plate.
if skirt_size > 0:
half_machine_width = self._active_instance.getMachineSettingValue("machine_width") / 2
half_machine_depth = self._active_instance.getMachineSettingValue("machine_depth") / 2
@ -257,6 +266,7 @@ class BuildVolume(SceneNode):
if profile.getSettingValue("draft_shield_enabled"):
skirt_size += profile.getSettingValue("draft_shield_dist")
if profile.getSettingValue("xy_offset"):
skirt_size += profile.getSettingValue("xy_offset")
return skirt_size

View file

@ -19,6 +19,11 @@ class ConvexHullDecorator(SceneNodeDecorator):
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
self._onActiveProfileChanged()
## Force that a new (empty) object is created upon copy.
def __deepcopy__(self, memo):
copy = ConvexHullDecorator()
return copy
def getConvexHull(self):
return self._convex_hull

View file

@ -54,7 +54,12 @@ class ConvexHullJob(Job):
if profile.getSettingValue("print_sequence") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"):
# Printing one at a time and it's not an object in a group
self._node.callDecoration("setConvexHullBoundary", copy.deepcopy(hull))
head_hull = hull.getMinkowskiHull(Polygon(numpy.array(profile.getSettingValue("machine_head_with_fans_polygon"),numpy.float32)))
head_and_fans = Polygon(numpy.array(profile.getSettingValue("machine_head_with_fans_polygon"), numpy.float32))
mirrored = copy.deepcopy(head_and_fans)
mirrored.mirror([0, 0], [0, 1]) #Mirror horizontally.
mirrored.mirror([0, 0], [1, 0]) #Mirror vertically.
head_and_fans = head_and_fans.intersectionConvexHulls(mirrored)
head_hull = hull.getMinkowskiHull(head_and_fans)
self._node.callDecoration("setConvexHullHead", head_hull)
hull = hull.getMinkowskiHull(Polygon(numpy.array(profile.getSettingValue("machine_head_polygon"),numpy.float32)))
else:

View file

@ -5,7 +5,7 @@ from UM.Scene.SceneNode import SceneNode
from UM.Resources import Resources
from UM.Math.Color import Color
from UM.Math.Vector import Vector
from UM.Mesh.MeshData import MeshData
from UM.Mesh.MeshBuilder import MeshBuilder #To create a mesh to display the convex hull with.
from UM.View.GL.OpenGL import OpenGL
@ -25,6 +25,7 @@ class ConvexHullNode(SceneNode):
self._inherit_scale = False
self._color = Color(35, 35, 35, 128)
self._mesh_height = 0.1 #The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting.
self._node = node
self._node.transformationChanged.connect(self._onNodePositionChanged)
@ -43,22 +44,19 @@ class ConvexHullNode(SceneNode):
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])
else:
#Input checking.
if len(hull_points) < 3:
return None
for point in hull_points:
mesh.addVertex(point[0], -0.1, point[1])
indices = []
for i in range(len(hull_points) - 1):
indices.append([0, i + 1, i + 2])
indices.append([0, mesh.getVertexCount() - 1, 1])
mesh_builder = MeshBuilder()
point_first = Vector(hull_points[0][0], self._mesh_height, hull_points[0][1])
point_previous = Vector(hull_points[1][0], self._mesh_height, hull_points[1][1])
for point in hull_points[2:]: #Add the faces in the order of a triangle fan.
point_new = Vector(point[0], self._mesh_height, point[1])
mesh_builder.addFace(point_first, point_previous, point_new, color = self._color)
point_previous = point_new #Prepare point_previous for the next triangle.
mesh.addIndices(numpy.array(indices, numpy.int32))
return mesh
return mesh_builder.getData()
def getWatchedNode(self):
return self._node

View file

@ -114,6 +114,7 @@ class CuraApplication(QtApplication):
Preferences.getInstance().addPreference("cura/categories_expanded", "")
Preferences.getInstance().addPreference("view/center_on_select", True)
Preferences.getInstance().addPreference("mesh/scale_to_fit", True)
Preferences.getInstance().setDefault("local_file/last_used_type", "text/x-gcode")
JobQueue.getInstance().jobFinished.connect(self._onJobFinished)
@ -132,6 +133,7 @@ class CuraApplication(QtApplication):
if not hasattr(sys, "frozen"):
self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins"))
self._plugin_registry.loadPlugin("ConsoleLogger")
self._plugin_registry.loadPlugin("CuraEngineBackend")
self._plugin_registry.loadPlugins()
@ -249,18 +251,24 @@ class CuraApplication(QtApplication):
@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())
return self._i18n_catalog.i18nc("@info", "%(width).1f x %(depth).1f x %(height).1f mm") % {'width' : self._scene_boundingbox.width.item(), 'depth': self._scene_boundingbox.depth.item(), 'height' : self._scene_boundingbox.height.item()}
def updatePlatformActivity(self, node = None):
count = 0
scene_boundingbox = AxisAlignedBox()
scene_boundingbox = None
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData():
continue
count += 1
if not scene_boundingbox:
scene_boundingbox = node.getBoundingBox()
else:
scene_boundingbox += node.getBoundingBox()
if not scene_boundingbox:
scene_boundingbox = AxisAlignedBox()
if repr(self._scene_boundingbox) != repr(scene_boundingbox):
self._scene_boundingbox = scene_boundingbox
self.sceneBoundingBoxChanged.emit()
@ -270,6 +278,7 @@ class CuraApplication(QtApplication):
@pyqtSlot(str)
def setJobName(self, name):
name = os.path.splitext(name)[0] #when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its extension. This cuts the extension off if nescessary.
if self._job_name != name:
self._job_name = name
self.jobNameChanged.emit()
@ -280,9 +289,28 @@ class CuraApplication(QtApplication):
def jobName(self):
return self._job_name
## Remove an object from the scene
# Remove all selected objects from the scene.
@pyqtSlot()
def deleteSelection(self):
if not self.getController().getToolsEnabled():
return
op = GroupedOperation()
nodes = Selection.getAllSelectedObjects()
for node in nodes:
op.addOperation(RemoveSceneNodeOperation(node))
op.push()
pass
## Remove an object from the scene.
# Note that this only removes an object if it is selected.
@pyqtSlot("quint64")
def deleteObject(self, object_id):
if not self.getController().getToolsEnabled():
return
node = self.getController().getScene().findObject(object_id)
if not node and object_id != 0: #Workaround for tool handles overlapping the selected object
@ -342,6 +370,9 @@ class CuraApplication(QtApplication):
## Delete all mesh data on the scene.
@pyqtSlot()
def deleteAll(self):
if not self.getController().getToolsEnabled():
return
nodes = []
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode:
@ -570,9 +601,9 @@ class CuraApplication(QtApplication):
def _onFileLoaded(self, job):
node = job.getResult()
if node != None:
self.setJobName(os.path.basename(job.getFileName()))
node.setSelectable(True)
node.setName(os.path.basename(job.getFileName()))
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
op.push()

View file

@ -1,8 +1,8 @@
# 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.QtCore import Qt, QCoreApplication
from PyQt5.QtGui import QPixmap, QColor, QFont, QFontMetrics
from PyQt5.QtWidgets import QSplashScreen
from UM.Resources import Resources
@ -11,7 +11,10 @@ from UM.Application import Application
class CuraSplashScreen(QSplashScreen):
def __init__(self):
super().__init__()
self.setPixmap(QPixmap(Resources.getPath(Resources.Images, "cura.png")))
self._scale = round(QFontMetrics(QCoreApplication.instance().font()).ascent() / 12)
splash_image = QPixmap(Resources.getPath(Resources.Images, "cura.png"))
self.setPixmap(splash_image.scaled(splash_image.size() * self._scale))
def drawContents(self, painter):
painter.save()
@ -19,11 +22,11 @@ class CuraSplashScreen(QSplashScreen):
version = Application.getInstance().getVersion().split("-")
painter.setFont(QFont("Proxima Nova Rg", 20))
painter.drawText(0, 0, 203, 230, Qt.AlignRight | Qt.AlignBottom, version[0])
painter.setFont(QFont("Proxima Nova Rg", 20 ))
painter.drawText(0, 0, 330 * self._scale, 230 * self._scale, Qt.AlignHCenter | 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.setFont(QFont("Proxima Nova Rg", 12 ))
painter.drawText(0, 0, 330 * self._scale, 255 * self._scale, Qt.AlignHCenter | Qt.AlignBottom, version[1])
painter.restore()
super().drawContents(painter)

View file

@ -24,7 +24,7 @@ import xml.etree.ElementTree as ET
class ThreeMFReader(MeshReader):
def __init__(self):
super(ThreeMFReader, self).__init__()
self._supported_extension = ".3mf"
self._supported_extensions = [".3mf"]
self._namespaces = {
"3mf": "http://schemas.microsoft.com/3dmanufacturing/core/2015/02",
@ -33,8 +33,7 @@ class ThreeMFReader(MeshReader):
def read(self, file_name):
result = None
extension = os.path.splitext(file_name)[1]
if extension.lower() == self._supported_extension:
result = SceneNode()
# The base object of 3mf is a zipped archive.
archive = zipfile.ZipFile(file_name, "r")
@ -131,4 +130,5 @@ class ThreeMFReader(MeshReader):
pass
except Exception as e:
Logger.log("e" ,"exception occured in 3mf reader: %s" , e)
return result

View file

@ -15,10 +15,12 @@ def getMetaData():
"description": catalog.i18nc("@info:whatsthis", "Provides support for reading 3MF files."),
"api": 2
},
"mesh_reader": {
"mesh_reader": [
{
"extension": "3mf",
"description": catalog.i18nc("@item:inlistbox", "3MF File")
}
]
}
def register(app):

View file

@ -0,0 +1,80 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import QTimer
from UM.Extension import Extension
from UM.Preferences import Preferences
from UM.Application import Application
from UM.Resources import Resources
from UM.Logger import Logger
class AutoSave(Extension):
def __init__(self):
super().__init__()
Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged)
machine_manager = Application.getInstance().getMachineManager()
self._profile = None
machine_manager.activeProfileChanged.connect(self._onActiveProfileChanged)
machine_manager.profileNameChanged.connect(self._onProfilesChanged)
machine_manager.profilesChanged.connect(self._onProfilesChanged)
machine_manager.machineInstanceNameChanged.connect(self._onInstanceNameChanged)
machine_manager.machineInstancesChanged.connect(self._onInstancesChanged)
Application
self._onActiveProfileChanged()
self._change_timer = QTimer()
self._change_timer.setInterval(1000 * 60)
self._change_timer.setSingleShot(True)
self._change_timer.timeout.connect(self._onTimeout)
self._save_preferences = False
self._save_profiles = False
self._save_instances = False
def _onPreferenceChanged(self, preference):
self._save_preferences = True
self._change_timer.start()
def _onSettingValueChanged(self, setting):
self._save_profiles = True
self._change_timer.start()
def _onActiveProfileChanged(self):
if self._profile:
self._profile.settingValueChanged.disconnect(self._onSettingValueChanged)
self._profile = Application.getInstance().getMachineManager().getActiveProfile()
if self._profile:
self._profile.settingValueChanged.connect(self._onSettingValueChanged)
def _onProfilesChanged(self):
self._save_profiles = True
self._change_timer.start()
def _onInstanceNameChanged(self, name):
self._onInstancesChanged()
def _onInstancesChanged(self):
self._save_instances = True
self._change_timer.start()
def _onTimeout(self):
Logger.log("d", "Autosaving preferences, instances and profiles")
if self._save_preferences:
Preferences.getInstance().writeToFile(Resources.getStoragePath(Resources.Preferences, Application.getInstance().getApplicationName() + ".cfg"))
if self._save_instances:
Application.getInstance().getMachineManager().saveMachineInstances()
if self._save_profiles:
Application.getInstance().getMachineManager().saveProfiles()
self._save_preferences = False
self._save_instances = False
self._save_profiles = False

View file

@ -0,0 +1,21 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from . import AutoSave
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": catalog.i18nc("@label", "Auto Save"),
"author": "Ultimaker",
"version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Automatically saves Preferences, Machines and Profiles after changes."),
"api": 2
},
}
def register(app):
return { "extension": AutoSave.AutoSave() }

View file

@ -107,15 +107,7 @@ class CuraEngineBackend(Backend):
return
if self._slicing:
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._terminate()
if self._message:
self._message.hide()
@ -142,11 +134,23 @@ class CuraEngineBackend(Backend):
self._scene.gcode_list = []
self._slicing = True
self.slicingStarted.emit()
job = StartSliceJob.StartSliceJob(self._profile, self._socket)
job.start()
job.finished.connect(self._onStartSliceCompleted)
def _terminate(self):
self._slicing = False
self._restart = True
self.slicingCancelled.emit()
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
def _onStartSliceCompleted(self, job):
if job.getError() or job.getResult() != True:
if self._message:
@ -245,6 +249,7 @@ class CuraEngineBackend(Backend):
self._restart = False
def _onToolOperationStarted(self, tool):
self._terminate() # Do not continue slicing once a tool has started
self._enabled = False # Do not reslice when a tool is doing it's 'thing'
def _onToolOperationStopped(self, tool):
@ -256,7 +261,9 @@ class CuraEngineBackend(Backend):
view = Application.getInstance().getController().getActiveView()
if view.getPluginId() == "LayerView":
self._layer_view_active = True
if self._stored_layer_data:
# There is data and we're not slicing at the moment
# if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment.
if self._stored_layer_data and not self._slicing:
job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(self._stored_layer_data)
job.start()
self._stored_layer_data = None
@ -265,12 +272,5 @@ class CuraEngineBackend(Backend):
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._terminate()
self.slicingCancelled.emit()

View file

@ -1,6 +1,8 @@
# 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
@ -17,7 +19,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
name='Cura.proto',
package='cura.proto',
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'
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\"\x11\n\x0fSlicingFinishedb\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
@ -164,21 +166,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),
@ -375,7 +377,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),
@ -421,7 +423,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),
@ -528,14 +530,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),
@ -566,7 +568,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),
@ -586,6 +588,30 @@ _GCODEPREFIX = _descriptor.Descriptor(
serialized_end=1037,
)
_SLICINGFINISHED = _descriptor.Descriptor(
name='SlicingFinished',
full_name='cura.proto.SlicingFinished',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=1039,
serialized_end=1056,
)
_OBJECTLIST.fields_by_name['objects'].message_type = _OBJECT
_OBJECTLIST.fields_by_name['settings'].message_type = _SETTING
_SLICE.fields_by_name['object_lists'].message_type = _OBJECTLIST
@ -609,6 +635,7 @@ DESCRIPTOR.message_types_by_name['ObjectPrintTime'] = _OBJECTPRINTTIME
DESCRIPTOR.message_types_by_name['SettingList'] = _SETTINGLIST
DESCRIPTOR.message_types_by_name['Setting'] = _SETTING
DESCRIPTOR.message_types_by_name['GCodePrefix'] = _GCODEPREFIX
DESCRIPTOR.message_types_by_name['SlicingFinished'] = _SLICINGFINISHED
ObjectList = _reflection.GeneratedProtocolMessageType('ObjectList', (_message.Message,), dict(
DESCRIPTOR = _OBJECTLIST,
@ -701,5 +728,12 @@ GCodePrefix = _reflection.GeneratedProtocolMessageType('GCodePrefix', (_message.
))
_sym_db.RegisterMessage(GCodePrefix)
SlicingFinished = _reflection.GeneratedProtocolMessageType('SlicingFinished', (_message.Message,), dict(
DESCRIPTOR = _SLICINGFINISHED,
__module__ = 'Cura_pb2'
# @@protoc_insertion_point(class_scope:cura.proto.SlicingFinished)
))
_sym_db.RegisterMessage(SlicingFinished)
# @@protoc_insertion_point(module_scope)

View file

@ -29,6 +29,7 @@ class ProcessSlicedObjectListJob(Job):
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
self._progress = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, -1)
self._progress.show()
Job.yieldThread()
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)

View file

@ -0,0 +1,39 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.Application import Application #To get the machine manager to create the new profile in.
from UM.Settings.Profile import Profile
from UM.Settings.ProfileReader import ProfileReader
## A plugin that reads profile data from Cura profile files.
#
# It reads a profile from a .curaprofile file, and returns it as a profile
# instance.
class CuraProfileReader(ProfileReader):
## Initialises the cura profile reader.
#
# This does nothing since the only other function is basically stateless.
def __init__(self):
super().__init__()
## Reads a cura profile from a file and returns it.
#
# \param file_name The file to read the cura profile from.
# \return The cura profile that was in the file, if any. If the file could
# not be read or didn't contain a valid profile, \code None \endcode is
# returned.
def read(self, file_name):
profile = Profile(machine_manager = Application.getInstance().getMachineManager(), read_only = False) #Create an empty profile.
serialised = ""
try:
with open(file_name) as f: #Open file for reading.
serialised = f.read()
except IOError as e:
Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e))
return None
try:
profile.unserialise(serialised)
except Exception as e: #Parsing error. This is not a (valid) Cura profile then.
return None
return profile

View file

@ -0,0 +1,27 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from . import CuraProfileReader
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": catalog.i18nc("@label", "Cura Profile Reader"),
"author": "Ultimaker",
"version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for importing Cura profiles."),
"api": 2
},
"profile_reader": [
{
"extension": "curaprofile",
"description": catalog.i18nc("@item:inlistbox", "Cura Profile")
}
]
}
def register(app):
return { "profile_reader": CuraProfileReader.CuraProfileReader() }

View file

@ -0,0 +1,26 @@
# Copyright (c) 2015 Ultimaker B.V.
# Copyright (c) 2013 David Braam
# Uranium is released under the terms of the AGPLv3 or higher.
from UM.Logger import Logger
from UM.SaveFile import SaveFile
from UM.Settings.Profile import Profile
from UM.Settings.ProfileWriter import ProfileWriter
## Writes profiles to Cura's own profile format with config files.
class CuraProfileWriter(ProfileWriter):
## Writes a profile to the specified file path.
#
# \param path \type{string} The file to output to.
# \param profile \type{Profile} The profile to write to that file.
# \return \code True \endcode if the writing was successful, or \code
# False \endcode if it wasn't.
def write(self, path, profile):
serialised = profile.serialise()
try:
with SaveFile(path, "wt", -1, "utf-8") as f: #Open the specified file.
f.write(serialised)
except Exception as e:
Logger.log("e", "Failed to write profile to %s: %s", path, str(e))
return False
return True

View file

@ -0,0 +1,27 @@
# Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.
from . import CuraProfileWriter
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": catalog.i18nc("@label", "Cura Profile Writer"),
"author": "Ultimaker",
"version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for exporting Cura profiles."),
"api": 2
},
"profile_writer": [
{
"extension": "curaprofile",
"description": catalog.i18nc("@item:inlistbox", "Cura Profile")
}
]
}
def register(app):
return { "profile_writer": CuraProfileWriter.CuraProfileWriter() }

View file

@ -0,0 +1,67 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.Application import Application #To get the machine manager to create the new profile in.
from UM.Settings.Profile import Profile
from UM.Settings.ProfileReader import ProfileReader
import re #Regular expressions for parsing escape characters in the settings.
## A class that reads profile data from g-code files.
#
# It reads the profile data from g-code files and stores it in a new profile.
# This class currently does not process the rest of the g-code in any way.
class GCodeProfileReader(ProfileReader):
## The file format version of the serialised g-code.
#
# It can only read settings with the same version as the version it was
# written with. If the file format is changed in a way that breaks reverse
# compatibility, increment this version number!
version = 1
## Dictionary that defines how characters are escaped when embedded in
# g-code.
#
# Note that the keys of this dictionary are regex strings. The values are
# not.
escape_characters = {
re.escape("\\\\"): "\\", #The escape character.
re.escape("\\n"): "\n", #Newlines. They break off the comment.
re.escape("\\r"): "\r" #Carriage return. Windows users may need this for visualisation in their editors.
}
## Initialises the g-code reader as a profile reader.
def __init__(self):
super().__init__()
## Reads a g-code file, loading the profile from it.
#
# \param file_name The name of the file to read the profile from.
# \return The profile that was in the specified file, if any. If the
# specified file was no g-code or contained no parsable profile, \code
# None \endcode is returned.
def read(self, file_name):
prefix = ";SETTING_" + str(GCodeProfileReader.version) + " "
prefix_length = len(prefix)
#Loading all settings from the file. They are all at the end, but Python has no reverse seek any more since Python3. TODO: Consider moving settings to the start?
serialised = "" #Will be filled with the serialised profile.
try:
with open(file_name) as f:
for line in f:
if line.startswith(prefix):
serialised += line[prefix_length : -1] #Remove the prefix and the newline from the line, and add it to the rest.
except IOError as e:
Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e))
return None
#Unescape the serialised profile.
pattern = re.compile("|".join(GCodeProfileReader.escape_characters.keys()))
serialised = pattern.sub(lambda m: GCodeProfileReader.escape_characters[re.escape(m.group(0))], serialised) #Perform the replacement with a regular expression.
#Apply the changes to the current profile.
profile = Profile(machine_manager = Application.getInstance().getMachineManager(), read_only = False)
try:
profile.unserialise(serialised)
except Exception as e: #Not a valid g-code file.
return None
return profile

View file

@ -0,0 +1,27 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from . import GCodeProfileReader
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": catalog.i18nc("@label", "GCode Profile Reader"),
"author": "Ultimaker",
"version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for importing profiles from g-code files."),
"api": 2
},
"profile_reader": [
{
"extension": "gcode",
"description": catalog.i18nc("@item:inlistbox", "G-code File")
}
]
}
def register(app):
return { "profile_reader": GCodeProfileReader.GCodeProfileReader() }

View file

@ -1,110 +0,0 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.Mesh.MeshReader import MeshReader
from UM.Application import Application
from UM.Scene.SceneNode import SceneNode
from UM.Mesh.MeshData import MeshData
from cura.LayerData import LayerData
from cura.LayerDataDecorator import LayerDataDecorator
import os
import numpy
class GCodeReader(MeshReader):
def __init__(self):
super().__init__()
self._supported_extension = ".gcode"
self._scene = Application.getInstance().getController().getScene()
def read(self, file_name):
extension = os.path.splitext(file_name)[1]
if extension.lower() == self._supported_extension:
layer_data = LayerData()
with open (file_name,"rt") as f:
layer = ""
current_path_type = ""
current_layer_nr = 0
poly_list = []
old_position = [0,0,0]
current_z = 0
for line in f:
if line.startswith(';TYPE:'):
current_path_type = line[6:].strip()
#layer_data.addPolygon(current_layer_nr,3 ,None ,5 )
elif line.startswith(';LAYER:'):
current_layer_nr = int(line[7:].strip())
layer_data.addLayer(int(line[7:].strip()))
elif line.startswith(';'):
pass # Ignore comments
else:
command_type = self.getCodeInt(line, 'G')
if command_type == 0 or command_type == 1: #Move command
x = self.getCodeFloat(line, 'X')
y = self.getCodeFloat(line, 'Y')
z = self.getCodeFloat(line, 'Z')
if z:
current_z = z
if x and y:
polygon_data = numpy.zeros((4,3)) #Square :)
polygon_data[0,:] = old_position
polygon_data[1,:] = old_position
polygon_data[2,:] = [x,current_z,y]
polygon_data[3,:] = [x,current_z,y]
old_position = [x,current_z,y]
if current_path_type == "SKIRT":
layer_data.addPolygon(current_layer_nr,5 ,polygon_data ,5 )
elif current_path_type == "WALL-INNER":
layer_data.addPolygon(current_layer_nr,3 ,polygon_data ,5 )
elif current_path_type == "WALL-OUTER":
layer_data.addPolygon(current_layer_nr,1 ,polygon_data ,5 )
else:
layer_data.addPolygon(current_layer_nr,2 ,polygon_data ,5 )
#e = self.getCodeFloat(line, 'E')
#print(x , " ", y , " ", z, " " , e)
pass
layer_data.build()
decorator = LayerDataDecorator()
decorator.setLayerData(layer_data)
new_node = SceneNode()
new_node.setMeshData(MeshData())
new_node.addDecorator(decorator)
new_node.setParent(self._scene.getRoot())
## Gets the value after the 'code' as int
# example: line = "G50" and code is "G" this function will return 50
# \param line string containing g-code.
# \param code string Letter to look for.
# \sa getCodeFloat
# \returns int
def getCodeInt(self, line, code):
n = line.find(code) + 1
if n < 1:
return None
m = line.find(' ', n)
try:
if m < 0:
return int(line[n:])
return int(line[n:m])
except:
return None
## Gets the value after the 'code' as float
# example: line = "G50" and code is "G" this function will return 50
# \param line string containing g-code.
# \param code string Letter to look for.
# \sa getCodeInt
# \returns float
def getCodeFloat(self, line, code):
n = line.find(code) + 1
if n < 1:
return None
m = line.find(' ', n)
try:
if m < 0:
return float(line[n:])
return float(line[n:m])
except:
return None

View file

@ -1,25 +0,0 @@
# 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() }

View file

@ -5,9 +5,28 @@ from UM.Mesh.MeshWriter import MeshWriter
from UM.Logger import Logger
from UM.Application import Application
import io
import re #For escaping characters in the settings.
class GCodeWriter(MeshWriter):
## The file format version of the serialised g-code.
#
# It can only read settings with the same version as the version it was
# written with. If the file format is changed in a way that breaks reverse
# compatibility, increment this version number!
version = 1
## Dictionary that defines how characters are escaped when embedded in
# g-code.
#
# Note that the keys of this dictionary are regex strings. The values are
# not.
escape_characters = {
re.escape("\\"): "\\\\", #The escape character.
re.escape("\n"): "\\n", #Newlines. They break off the comment.
re.escape("\r"): "\\r" #Carriage return. Windows users may need this for visualisation in their editors.
}
def __init__(self):
super().__init__()
@ -21,6 +40,33 @@ class GCodeWriter(MeshWriter):
if gcode_list:
for gcode in gcode_list:
stream.write(gcode)
profile = self._serialiseProfile(Application.getInstance().getMachineManager().getActiveProfile()) #Serialise the profile and put them at the end of the file.
stream.write(profile)
return True
return False
## Serialises the profile to prepare it for saving in the g-code.
#
# The profile are serialised, and special characters (including newline)
# are escaped.
#
# \param profile The profile to serialise.
# \return A serialised string of the profile.
def _serialiseProfile(self, profile):
prefix = ";SETTING_" + str(GCodeWriter.version) + " " #The prefix to put before each line.
prefix_length = len(prefix)
serialised = profile.serialise()
#Escape characters that have a special meaning in g-code comments.
pattern = re.compile("|".join(GCodeWriter.escape_characters.keys()))
serialised = pattern.sub(lambda m: GCodeWriter.escape_characters[re.escape(m.group(0))], serialised) #Perform the replacement with a regular expression.
#Introduce line breaks so that each comment is no longer than 80 characters. Prepend each line with the prefix.
result = ""
for pos in range(0, len(serialised), 80 - prefix_length): #Lines have 80 characters, so the payload of each line is 80 - prefix.
result += prefix + serialised[pos : pos + 80 - prefix_length] + "\n"
serialised = result
return serialised

View file

@ -0,0 +1,205 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import UM 1.1 as UM
UM.Dialog
{
width: 350*Screen.devicePixelRatio;
minimumWidth: 350*Screen.devicePixelRatio;
maximumWidth: 350*Screen.devicePixelRatio;
height: 220*Screen.devicePixelRatio;
minimumHeight: 220*Screen.devicePixelRatio;
maximumHeight: 220*Screen.devicePixelRatio;
modality: Qt.Modal
title: catalog.i18nc("@title:window", "Convert Image...")
GridLayout
{
UM.I18nCatalog{id: catalog; name:"cura"}
anchors.fill: parent;
Layout.fillWidth: true
columnSpacing: 16
rowSpacing: 4
columns: 1
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","The maximum distance of each pixel from \"Base.\"")
Row {
width: parent.width
height: childrenRect.height
Text {
text: catalog.i18nc("@action:label","Height (mm)")
width: 150
anchors.verticalCenter: parent.verticalCenter
}
TextField {
id: peak_height
objectName: "Peak_Height"
validator: DoubleValidator {notation: DoubleValidator.StandardNotation; bottom: -500; top: 500;}
width: 180
onTextChanged: { manager.onPeakHeightChanged(text) }
}
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","The base height from the build plate in millimeters.")
Row {
width: parent.width
height: childrenRect.height
Text {
text: catalog.i18nc("@action:label","Base (mm)")
width: 150
anchors.verticalCenter: parent.verticalCenter
}
TextField {
id: base_height
objectName: "Base_Height"
validator: DoubleValidator {notation: DoubleValidator.StandardNotation; bottom: 0; top: 500;}
width: 180
onTextChanged: { manager.onBaseHeightChanged(text) }
}
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","The width in millimeters on the build plate.")
Row {
width: parent.width
height: childrenRect.height
Text {
text: catalog.i18nc("@action:label","Width (mm)")
width: 150
anchors.verticalCenter: parent.verticalCenter
}
TextField {
id: width
objectName: "Width"
focus: true
validator: DoubleValidator {notation: DoubleValidator.StandardNotation; bottom: 1; top: 500;}
width: 180
onTextChanged: { manager.onWidthChanged(text) }
}
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","The depth in millimeters on the build plate")
Row {
width: parent.width
height: childrenRect.height
Text {
text: catalog.i18nc("@action:label","Depth (mm)")
width: 150
anchors.verticalCenter: parent.verticalCenter
}
TextField {
id: depth
objectName: "Depth"
focus: true
validator: DoubleValidator {notation: DoubleValidator.StandardNotation; bottom: 1; top: 500;}
width: 180
onTextChanged: { manager.onDepthChanged(text) }
}
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","By default, white pixels represent high points on the mesh and black pixels represent low points on the mesh. Change this option to reverse the behavior such that black pixels represent high points on the mesh and white pixels represent low points on the mesh.")
Row {
width: parent.width
height: childrenRect.height
//Empty label so 2 column layout works.
Text {
text: ""
width: 150
anchors.verticalCenter: parent.verticalCenter
}
ComboBox {
id: image_color_invert
objectName: "Image_Color_Invert"
model: [ catalog.i18nc("@item:inlistbox","Lighter is higher"), catalog.i18nc("@item:inlistbox","Darker is higher") ]
width: 180
onCurrentIndexChanged: { manager.onImageColorInvertChanged(currentIndex) }
}
}
}
UM.TooltipArea {
Layout.fillWidth:true
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","The amount of smoothing to apply to the image.")
Row {
width: parent.width
height: childrenRect.height
Text {
text: catalog.i18nc("@action:label","Smoothing")
width: 150
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
width: 180
height: 20
Layout.fillWidth:true
color: "transparent"
Slider {
id: smoothing
objectName: "Smoothing"
maximumValue: 100.0
stepSize: 1.0
width: 180
onValueChanged: { manager.onSmoothingChanged(value) }
}
}
}
}
}
rightButtons: [
Button
{
id:ok_button
text: catalog.i18nc("@action:button","OK");
onClicked: { manager.onOkButtonClicked() }
enabled: true
},
Button
{
id:cancel_button
text: catalog.i18nc("@action:button","Cancel");
onClicked: { manager.onCancelButtonClicked() }
enabled: true
}
]
}

View file

@ -0,0 +1,216 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import os
import numpy
from PyQt5.QtGui import QImage, qRed, qGreen, qBlue
from PyQt5.QtCore import Qt
from UM.Mesh.MeshReader import MeshReader
from UM.Mesh.MeshData import MeshData
from UM.Scene.SceneNode import SceneNode
from UM.Math.Vector import Vector
from UM.Job import Job
from UM.Logger import Logger
from .ImageReaderUI import ImageReaderUI
class ImageReader(MeshReader):
def __init__(self):
super(ImageReader, self).__init__()
self._supported_extensions = [".jpg", ".jpeg", ".bmp", ".gif", ".png"]
self._ui = ImageReaderUI(self)
def preRead(self, file_name):
img = QImage(file_name)
if img.isNull():
Logger.log("e", "Image is corrupt.")
return MeshReader.PreReadResult.failed
width = img.width()
depth = img.height()
largest = max(width, depth)
width = width / largest * self._ui.defaultWidth
depth = depth / largest * self._ui.defaultDepth
self._ui.setWidthAndDepth(width, depth)
self._ui.showConfigUI()
self._ui.waitForUIToClose()
if self._ui.getCancelled():
return MeshReader.PreReadResult.cancelled
return MeshReader.PreReadResult.accepted
def read(self, file_name):
size = max(self._ui.getWidth(), self._ui.getDepth())
return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.image_color_invert)
def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, image_color_invert):
mesh = None
scene_node = None
scene_node = SceneNode()
mesh = MeshData()
scene_node.setMeshData(mesh)
img = QImage(file_name)
if img.isNull():
Logger.log("e", "Image is corrupt.")
return None
width = max(img.width(), 2)
height = max(img.height(), 2)
aspect = height / width
if img.width() < 2 or img.height() < 2:
img = img.scaled(width, height, Qt.IgnoreAspectRatio)
base_height = max(base_height, 0)
peak_height = max(peak_height, -base_height)
xz_size = max(xz_size, 1)
scale_vector = Vector(xz_size, peak_height, xz_size)
if width > height:
scale_vector.setZ(scale_vector.z * aspect)
elif height > width:
scale_vector.setX(scale_vector.x / aspect)
if width > max_size or height > max_size:
scale_factor = max_size / width
if height > width:
scale_factor = max_size / height
width = int(max(round(width * scale_factor), 2))
height = int(max(round(height * scale_factor), 2))
img = img.scaled(width, height, Qt.IgnoreAspectRatio)
width_minus_one = width - 1
height_minus_one = height - 1
Job.yieldThread()
texel_width = 1.0 / (width_minus_one) * scale_vector.x
texel_height = 1.0 / (height_minus_one) * scale_vector.z
height_data = numpy.zeros((height, width), dtype=numpy.float32)
for x in range(0, width):
for y in range(0, height):
qrgb = img.pixel(x, y)
avg = float(qRed(qrgb) + qGreen(qrgb) + qBlue(qrgb)) / (3 * 255)
height_data[y, x] = avg
Job.yieldThread()
if image_color_invert:
height_data = 1 - height_data
for i in range(0, blur_iterations):
copy = numpy.pad(height_data, ((1, 1), (1, 1)), mode='edge')
height_data += copy[1:-1, 2:]
height_data += copy[1:-1, :-2]
height_data += copy[2:, 1:-1]
height_data += copy[:-2, 1:-1]
height_data += copy[2:, 2:]
height_data += copy[:-2, 2:]
height_data += copy[2:, :-2]
height_data += copy[:-2, :-2]
height_data /= 9
Job.yieldThread()
height_data *= scale_vector.y
height_data += base_height
heightmap_face_count = 2 * height_minus_one * width_minus_one
total_face_count = heightmap_face_count + (width_minus_one * 2) * (height_minus_one * 2) + 2
mesh.reserveFaceCount(total_face_count)
# initialize to texel space vertex offsets.
# 6 is for 6 vertices for each texel quad.
heightmap_vertices = numpy.zeros((width_minus_one * height_minus_one, 6, 3), dtype=numpy.float32)
heightmap_vertices = heightmap_vertices + numpy.array([[
[0, base_height, 0],
[0, base_height, texel_height],
[texel_width, base_height, texel_height],
[texel_width, base_height, texel_height],
[texel_width, base_height, 0],
[0, base_height, 0]
]], dtype=numpy.float32)
offsetsz, offsetsx = numpy.mgrid[0:height_minus_one, 0:width-1]
offsetsx = numpy.array(offsetsx, numpy.float32).reshape(-1, 1) * texel_width
offsetsz = numpy.array(offsetsz, numpy.float32).reshape(-1, 1) * texel_height
# offsets for each texel quad
heightmap_vertex_offsets = numpy.concatenate([offsetsx, numpy.zeros((offsetsx.shape[0], offsetsx.shape[1]), dtype=numpy.float32), offsetsz], 1)
heightmap_vertices += heightmap_vertex_offsets.repeat(6, 0).reshape(-1, 6, 3)
# apply height data to y values
heightmap_vertices[:, 0, 1] = heightmap_vertices[:, 5, 1] = height_data[:-1, :-1].reshape(-1)
heightmap_vertices[:, 1, 1] = height_data[1:, :-1].reshape(-1)
heightmap_vertices[:, 2, 1] = heightmap_vertices[:, 3, 1] = height_data[1:, 1:].reshape(-1)
heightmap_vertices[:, 4, 1] = height_data[:-1, 1:].reshape(-1)
heightmap_indices = numpy.array(numpy.mgrid[0:heightmap_face_count * 3], dtype=numpy.int32).reshape(-1, 3)
mesh._vertices[0:(heightmap_vertices.size // 3), :] = heightmap_vertices.reshape(-1, 3)
mesh._indices[0:(heightmap_indices.size // 3), :] = heightmap_indices
mesh._vertex_count = heightmap_vertices.size // 3
mesh._face_count = heightmap_indices.size // 3
geo_width = width_minus_one * texel_width
geo_height = height_minus_one * texel_height
# bottom
mesh.addFace(0, 0, 0, 0, 0, geo_height, geo_width, 0, geo_height)
mesh.addFace(geo_width, 0, geo_height, geo_width, 0, 0, 0, 0, 0)
# north and south walls
for n in range(0, width_minus_one):
x = n * texel_width
nx = (n + 1) * texel_width
hn0 = height_data[0, n]
hn1 = height_data[0, n + 1]
hs0 = height_data[height_minus_one, n]
hs1 = height_data[height_minus_one, n + 1]
mesh.addFace(x, 0, 0, nx, 0, 0, nx, hn1, 0)
mesh.addFace(nx, hn1, 0, x, hn0, 0, x, 0, 0)
mesh.addFace(x, 0, geo_height, nx, 0, geo_height, nx, hs1, geo_height)
mesh.addFace(nx, hs1, geo_height, x, hs0, geo_height, x, 0, geo_height)
# west and east walls
for n in range(0, height_minus_one):
y = n * texel_height
ny = (n + 1) * texel_height
hw0 = height_data[n, 0]
hw1 = height_data[n + 1, 0]
he0 = height_data[n, width_minus_one]
he1 = height_data[n + 1, width_minus_one]
mesh.addFace(0, 0, y, 0, 0, ny, 0, hw1, ny)
mesh.addFace(0, hw1, ny, 0, hw0, y, 0, 0, y)
mesh.addFace(geo_width, 0, y, geo_width, 0, ny, geo_width, he1, ny)
mesh.addFace(geo_width, he1, ny, geo_width, he0, y, geo_width, 0, y)
mesh.calculateNormals(fast=True)
return scene_node

View file

@ -0,0 +1,155 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import os
import threading
from PyQt5.QtCore import Qt, QUrl, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtQml import QQmlComponent, QQmlContext
from UM.Application import Application
from UM.PluginRegistry import PluginRegistry
from UM.Logger import Logger
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
class ImageReaderUI(QObject):
show_config_ui_trigger = pyqtSignal()
def __init__(self, image_reader):
super(ImageReaderUI, self).__init__()
self.image_reader = image_reader
self._ui_view = None
self.show_config_ui_trigger.connect(self._actualShowConfigUI)
self.defaultWidth = 120
self.defaultDepth = 120
self._aspect = 1
self._width = self.defaultWidth
self._depth = self.defaultDepth
self.base_height = 1
self.peak_height = 10
self.smoothing = 1
self.image_color_invert = False;
self._ui_lock = threading.Lock()
self._cancelled = False
self._disable_size_callbacks = False
def setWidthAndDepth(self, width, depth):
self._aspect = width / depth
self._width = width
self._depth = depth
def getWidth(self):
return self._width
def getDepth(self):
return self._depth
def getCancelled(self):
return self._cancelled
def waitForUIToClose(self):
self._ui_lock.acquire()
self._ui_lock.release()
def showConfigUI(self):
self._ui_lock.acquire()
self._cancelled = False
self.show_config_ui_trigger.emit()
def _actualShowConfigUI(self):
self._disable_size_callbacks = True
if self._ui_view is None:
self._createConfigUI()
self._ui_view.show()
self._ui_view.findChild(QObject, "Width").setProperty("text", str(self._width))
self._ui_view.findChild(QObject, "Depth").setProperty("text", str(self._depth))
self._disable_size_callbacks = False
self._ui_view.findChild(QObject, "Base_Height").setProperty("text", str(self.base_height))
self._ui_view.findChild(QObject, "Peak_Height").setProperty("text", str(self.peak_height))
self._ui_view.findChild(QObject, "Smoothing").setProperty("value", self.smoothing)
def _createConfigUI(self):
if self._ui_view is None:
Logger.log("d", "Creating ImageReader config UI")
path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath("ImageReader"), "ConfigUI.qml"))
component = QQmlComponent(Application.getInstance()._engine, path)
self._ui_context = QQmlContext(Application.getInstance()._engine.rootContext())
self._ui_context.setContextProperty("manager", self)
self._ui_view = component.create(self._ui_context)
self._ui_view.setFlags(self._ui_view.flags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowMinimizeButtonHint & ~Qt.WindowMaximizeButtonHint);
self._disable_size_callbacks = False
@pyqtSlot()
def onOkButtonClicked(self):
self._cancelled = False
self._ui_view.close()
self._ui_lock.release()
@pyqtSlot()
def onCancelButtonClicked(self):
self._cancelled = True
self._ui_view.close()
self._ui_lock.release()
@pyqtSlot(str)
def onWidthChanged(self, value):
if self._ui_view and not self._disable_size_callbacks:
if len(value) > 0:
self._width = float(value)
else:
self._width = 0
self._depth = self._width / self._aspect
self._disable_size_callbacks = True
self._ui_view.findChild(QObject, "Depth").setProperty("text", str(self._depth))
self._disable_size_callbacks = False
@pyqtSlot(str)
def onDepthChanged(self, value):
if self._ui_view and not self._disable_size_callbacks:
if len(value) > 0:
self._depth = float(value)
else:
self._depth = 0
self._width = self._depth * self._aspect
self._disable_size_callbacks = True
self._ui_view.findChild(QObject, "Width").setProperty("text", str(self._width))
self._disable_size_callbacks = False
@pyqtSlot(str)
def onBaseHeightChanged(self, value):
if (len(value) > 0):
self.base_height = float(value)
else:
self.base_height = 0
@pyqtSlot(str)
def onPeakHeightChanged(self, value):
if (len(value) > 0):
self.peak_height = float(value)
else:
self.peak_height = 0
@pyqtSlot(float)
def onSmoothingChanged(self, value):
self.smoothing = int(value)
@pyqtSlot(int)
def onImageColorInvertChanged(self, value):
if (value == 1):
self.image_color_invert = True
else:
self.image_color_invert = False

View file

@ -0,0 +1,43 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from . import ImageReader
from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": i18n_catalog.i18nc("@label", "Image Reader"),
"author": "Ultimaker",
"version": "1.0",
"description": i18n_catalog.i18nc("@info:whatsthis", "Enables ability to generate printable geometry from 2D image files."),
"api": 2
},
"mesh_reader": [
{
"extension": "jpg",
"description": i18n_catalog.i18nc("@item:inlistbox", "JPG Image")
},
{
"extension": "jpeg",
"description": i18n_catalog.i18nc("@item:inlistbox", "JPEG Image")
},
{
"extension": "png",
"description": i18n_catalog.i18nc("@item:inlistbox", "PNG Image")
},
{
"extension": "bmp",
"description": i18n_catalog.i18nc("@item:inlistbox", "BMP Image")
},
{
"extension": "gif",
"description": i18n_catalog.i18nc("@item:inlistbox", "GIF Image")
}
]
}
def register(app):
return { "mesh_reader": ImageReader.ImageReader() }

View file

@ -59,7 +59,7 @@ class LayerView(View):
renderer = self.getRenderer()
if not self._selection_shader:
self._selection_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader"))
self._selection_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader"))
self._selection_shader.setUniformValue("u_color", Color(32, 32, 32, 128))
for node in DepthFirstIterator(scene.getRoot()):

View file

@ -18,7 +18,8 @@ def getMetaData():
},
"view": {
"name": catalog.i18nc("@item:inlistbox", "Layers"),
"view_panel": "LayerView.qml"
"view_panel": "LayerView.qml",
"weight": 2
}
}

View file

@ -0,0 +1,157 @@
{
"source_version": "15.04",
"target_version": 1,
"translation": {
"machine_nozzle_size": "nozzle_size",
"line_width": "wall_thickness if (spiralize == \"True\" or simple_mode == \"True\") else (nozzle_size if (float(wall_thickness) < 0.01) else (wall_thickness if (float(wall_thickness) < float(nozzle_size)) else (nozzle_size if ((int(float(wall_thickness) / (float(nozzle_size) - 0.0001))) == 0) else ((float(wall_thickness) / ((int(float(wall_thickness) / (float(nozzle_size) - 0.0001))) + 1)) if ((float(wall_thickness) / (int(float(wall_thickness) / (float(nozzle_size) - 0.0001)))) > float(nozzle_size) * 1.5) else ((float(wall_thickness) / (int(float(wall_thickness) / (float(nozzle_size) - 0.0001)))))))))",
"layer_height": "layer_height",
"layer_height_0": "bottom_thickness",
"wall_thickness": "wall_thickness",
"top_bottom_thickness": "solid_layer_thickness",
"top_thickness": "0 if (solid_top == \"False\") else solid_layer_thickness",
"bottom_thickness": "0 if (solid_bottom == \"False\") else solid_layer_thickness",
"infill_sparse_density": "fill_density",
"infill_overlap": "fill_overlap",
"infill_before_walls": "False if (perimeter_before_infill == \"True\") else True",
"material_print_temperature": "print_temperature",
"material_bed_temperature": "print_bed_temperature",
"material_diameter": "filament_diameter",
"material_flow": "filament_flow",
"retraction_enable": "retraction_enable",
"retraction_amount": "retraction_amount",
"retraction_speed": "retraction_speed",
"retraction_min_travel": "retraction_min_travel",
"retraction_hop": "retraction_hop",
"speed_print": "print_speed",
"speed_infill": "infill_speed if (float(infill_speed) != 0) else print_speed",
"speed_wall_0": "inset0_speed if (float(inset0_speed) != 0) else print_speed",
"speed_wall_x": "insetx_speed if (float(insetx_speed) != 0) else print_speed",
"speed_topbottom": "solidarea_speed if (float(solidarea_speed) != 0) else print_speed",
"speed_travel": "travel_speed if (float(travel_speed) != 0) else travel_speed",
"speed_layer_0": "bottom_layer_speed",
"retraction_combing": "True if (retraction_combing == \"All\" or retraction_combing == \"No Skin\") else False",
"cool_fan_enabled": "fan_enabled",
"cool_fan_speed_min": "fan_speed",
"cool_fan_speed_max": "fan_speed_max",
"cool_fan_full_at_height": "fan_full_height",
"cool_min_layer_time": "cool_min_layer_time",
"cool_min_speed": "cool_min_feedrate",
"cool_lift_head": "cool_head_lift",
"support_enable": "False if (support == \"None\") else True",
"support_type": "\"buildplate\" if (support == \"Touching buildplate\") else \"everywhere\"",
"support_angle": "support_angle",
"support_xy_distance": "support_xy_distance",
"support_z_distance": "support_z_distance",
"support_pattern": "support_type.lower()",
"support_infill_rate": "support_fill_rate",
"adhesion_type": "\"skirt\" if (platform_adhesion == \"None\") else platform_adhesion.lower()",
"skirt_line_count": "skirt_line_count",
"skirt_gap": "skirt_gap",
"skirt_minimal_length": "skirt_minimal_length",
"brim_line_count": "brim_line_count",
"raft_margin": "raft_margin",
"raft_airgap": "raft_airgap_all",
"raft_surface_layers": "raft_surface_layers",
"raft_surface_thickness": "raft_surface_thickness",
"raft_surface_line_width": "raft_surface_linewidth",
"raft_surface_line_spacing": "raft_line_spacing",
"raft_interface_thickness": "raft_interface_thickness",
"raft_interface_line_width": "raft_interface_linewidth",
"raft_interface_line_spacing": "raft_line_spacing",
"raft_base_thickness": "raft_base_thickness",
"raft_base_line_width": "raft_base_linewidth",
"raft_base_line_spacing": "raft_line_spacing",
"meshfix_union_all": "fix_horrible_union_all_type_a",
"meshfix_union_all_remove_holes": "fix_horrible_union_all_type_b",
"meshfix_extensive_stitching": "fix_horrible_extensive_stitching",
"meshfix_keep_open_polygons": "fix_horrible_use_open_bits",
"magic_mesh_surface_mode": "simple_mode",
"magic_spiralize": "spiralize",
"prime_tower_enable": "wipe_tower",
"prime_tower_size": "math.sqrt(float(wipe_tower_volume) / float(layer_height))",
"ooze_shield_enabled": "ooze_shield"
},
"defaults": {
"bottom_layer_speed": "20",
"bottom_thickness": "0.3",
"brim_line_count": "20",
"cool_head_lift": "False",
"cool_min_feedrate": "10",
"cool_min_layer_time": "5",
"fan_enabled": "True",
"fan_full_height": "0.5",
"fan_speed": "100",
"fan_speed_max": "100",
"filament_diameter": "2.85",
"filament_diameter2": "0",
"filament_diameter3": "0",
"filament_diameter4": "0",
"filament_diameter5": "0",
"filament_flow": "100.0",
"fill_density": "20",
"fill_overlap": "15",
"fix_horrible_extensive_stitching": "False",
"fix_horrible_union_all_type_a": "True",
"fix_horrible_union_all_type_b": "False",
"fix_horrible_use_open_bits": "False",
"infill_speed": "0.0",
"inset0_speed": "0.0",
"insetx_speed": "0.0",
"layer_height": "0.1",
"layer0_width_factor": "100",
"nozzle_size": "0.4",
"object_sink": "0.0",
"ooze_shield": "False",
"overlap_dual": "0.15",
"perimeter_before_infill": "False",
"platform_adhesion": "None",
"print_bed_temperature": "70",
"print_speed": "50",
"print_temperature": "210",
"print_temperature2": "0",
"print_temperature3": "0",
"print_temperature4": "0",
"print_temperature5": "0",
"raft_airgap": "0.22",
"raft_airgap_all": "0.0",
"raft_base_linewidth": "1.0",
"raft_base_thickness": "0.3",
"raft_interface_linewidth": "0.4",
"raft_interface_thickness": "0.27",
"raft_line_spacing": "3.0",
"raft_margin": "5.0",
"raft_surface_layers": "2",
"raft_surface_linewidth": "0.4",
"raft_surface_thickness": "0.27",
"retraction_amount": "4.5",
"retraction_combing": "All",
"retraction_dual_amount": "16.5",
"retraction_enable": "True",
"retraction_hop": "0.0",
"retraction_min_travel": "1.5",
"retraction_minimal_extrusion": "0.02",
"retraction_speed": "40.0",
"simple_mode": "False",
"skirt_gap": "3.0",
"skirt_line_count": "1",
"skirt_minimal_length": "150.0",
"solid_bottom": "True",
"solid_layer_thickness": "0.6",
"solid_top": "True",
"solidarea_speed": "0.0",
"spiralize": "False",
"support": "None",
"support_angle": "60",
"support_dual_extrusion": "Both",
"support_fill_rate": "15",
"support_type": "Lines",
"support_xy_distance": "0.7",
"support_z_distance": "0.15",
"travel_speed": "150.0",
"wall_thickness": "0.8",
"wipe_tower": "False",
"wipe_tower_volume": "15"
}
}

View file

@ -0,0 +1,127 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import configparser #For reading the legacy profile INI files.
import json #For reading the Dictionary of Doom.
import math #For mathematical operations included in the Dictionary of Doom.
import os.path #For concatenating the path to the plugin and the relative path to the Dictionary of Doom.
from UM.Application import Application #To get the machine manager to create the new profile in.
from UM.Logger import Logger #Logging errors.
from UM.PluginRegistry import PluginRegistry #For getting the path to this plugin's directory.
from UM.Settings.Profile import Profile
from UM.Settings.ProfileReader import ProfileReader
## A plugin that reads profile data from legacy Cura versions.
#
# It reads a profile from an .ini file, and performs some translations on it.
# Not all translations are correct, mind you, but it is a best effort.
class LegacyProfileReader(ProfileReader):
## Initialises the legacy profile reader.
#
# This does nothing since the only other function is basically stateless.
def __init__(self):
super().__init__()
## Prepares the default values of all legacy settings.
#
# These are loaded from the Dictionary of Doom.
#
# \param json The JSON file to load the default setting values from. This
# should not be a URL but a pre-loaded JSON handle.
# \return A dictionary of the default values of the legacy Cura version.
def prepareDefaults(self, json):
defaults = {}
for key in json["defaults"]: #We have to copy over all defaults from the JSON handle to a normal dict.
defaults[key] = json["defaults"][key]
return defaults
## Prepares the local variables that can be used in evaluation of computing
# new setting values from the old ones.
#
# This fills a dictionary with all settings from the legacy Cura version
# and their values, so that they can be used in evaluating the new setting
# values as Python code.
#
# \param config_parser The ConfigParser that finds the settings in the
# legacy profile.
# \param config_section The section in the profile where the settings
# should be found.
# \param defaults The default values for all settings in the legacy Cura.
# \return A set of local variables, one for each setting in the legacy
# profile.
def prepareLocals(self, config_parser, config_section, defaults):
locals = defaults.copy() #Don't edit the original!
for option in config_parser.options(config_section):
locals[option] = config_parser.get(config_section, option)
return locals
## Reads a legacy Cura profile from a file and returns it.
#
# \param file_name The file to read the legacy Cura profile from.
# \return The legacy Cura profile that was in the file, if any. If the
# file could not be read or didn't contain a valid profile, \code None
# \endcode is returned.
def read(self, file_name):
Logger.log("i", "Importing legacy profile from file " + file_name + ".")
profile = Profile(machine_manager = Application.getInstance().getMachineManager(), read_only = False) #Create an empty profile.
profile.setName("Imported Legacy Profile")
parser = configparser.ConfigParser(interpolation = None)
try:
with open(file_name) as f:
parser.readfp(f) #Parse the INI file.
except Exception as e:
Logger.log("e", "Unable to open legacy profile %s: %s", file_name, str(e))
return None
#Legacy Cura saved the profile under the section "profile_N" where N is the ID of a machine, except when you export in which case it saves it in the section "profile".
#Since importing multiple machine profiles is out of scope, just import the first section we find.
section = ""
for found_section in parser.sections():
if found_section.startswith("profile"):
section = found_section
break
if not section: #No section starting with "profile" was found. Probably not a proper INI file.
return None
try:
with open(os.path.join(PluginRegistry.getInstance().getPluginPath("LegacyProfileReader"), "DictionaryOfDoom.json"), "r", -1, "utf-8") as f:
dict_of_doom = json.load(f) #Parse the Dictionary of Doom.
except IOError as e:
Logger.log("e", "Could not open DictionaryOfDoom.json for reading: %s", str(e))
return None
except Exception as e:
Logger.log("e", "Could not parse DictionaryOfDoom.json: %s", str(e))
return None
defaults = self.prepareDefaults(dict_of_doom)
legacy_settings = self.prepareLocals(parser, section, defaults) #Gets the settings from the legacy profile.
#Check the target version in the Dictionary of Doom with this application version.
if "target_version" not in dict_of_doom:
Logger.log("e", "Dictionary of Doom has no target version. Is it the correct JSON file?")
return None
if Profile.ProfileVersion != dict_of_doom["target_version"]:
Logger.log("e", "Dictionary of Doom of legacy profile reader (version %s) is not in sync with the profile version (version %s)!", dict_of_doom["target_version"], str(Profile.ProfileVersion))
return None
if "translation" not in dict_of_doom:
Logger.log("e", "Dictionary of Doom has no translation. Is it the correct JSON file?")
return None
for new_setting in dict_of_doom["translation"]: #Evaluate all new settings that would get a value from the translations.
old_setting_expression = dict_of_doom["translation"][new_setting]
compiled = compile(old_setting_expression, new_setting, "eval")
try:
new_value = eval(compiled, {"math": math}, legacy_settings) #Pass the legacy settings as local variables to allow access to in the evaluation.
value_using_defaults = eval(compiled, {"math": math}, defaults) #Evaluate again using only the default values to try to see if they are default.
except Exception as e: #Probably some setting name that was missing or something else that went wrong in the ini file.
Logger.log("w", "Setting " + new_setting + " could not be set because the evaluation failed. Something is probably missing from the imported legacy profile.")
continue
if new_value != value_using_defaults and profile.getSettingValue(new_setting) != new_value: #Not equal to the default in the new Cura OR the default in the legacy Cura.
profile.setSettingValue(new_setting, new_value) #Store the setting in the profile!
if len(profile.getChangedSettings()) == 0:
Logger.log("i", "A legacy profile was imported but everything evaluates to the defaults, creating an empty profile.")
return profile

View file

@ -0,0 +1,27 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from . import LegacyProfileReader
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": catalog.i18nc("@label", "Legacy Cura Profile Reader"),
"author": "Ultimaker",
"version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for importing profiles from legacy Cura versions."),
"api": 2
},
"profile_reader": [
{
"extension": "ini",
"description": catalog.i18nc("@item:inlistbox", "Cura 15.04 profiles")
}
]
}
def register(app):
return { "profile_reader": LegacyProfileReader.LegacyProfileReader() }

View file

@ -13,6 +13,8 @@ Item {
property int currentIndex: UM.ActiveTool.properties.SelectedIndex;
property string printSequence: UM.ActiveTool.properties.PrintSequence;
UM.I18nCatalog { id: catalog; name: "cura"; }
width: childrenRect.width;
height: childrenRect.height;
@ -104,7 +106,7 @@ Item {
height: parent.height/2
sourceSize.width: width
sourceSize.height: width
color: UM.Theme.colors.setting_control_revert
color: control.hovered ? UM.Theme.colors.setting_control_button_hover : UM.Theme.colors.setting_control_button
source: UM.Theme.icons.cross1
}
}
@ -157,7 +159,6 @@ Item {
}
}
UM.I18nCatalog { id: catalog; name: "uranium"; }
UM.Dialog {
id: settingPickDialog

View file

@ -4,7 +4,7 @@
from . import PerObjectSettingsTool
from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("uranium")
i18n_catalog = i18nCatalog("cura")
def getMetaData():
return {

View file

@ -8,6 +8,7 @@ from UM.Mesh.MeshWriter import MeshWriter
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
from UM.OutputDevice.OutputDevice import OutputDevice
from UM.OutputDevice import OutputDeviceError
from UM.Preferences import Preferences
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
@ -22,15 +23,18 @@ class RemovableDriveOutputDevice(OutputDevice):
self.setIconName("save_sd")
self.setPriority(1)
Preferences.getInstance().addPreference("removable_drive/file_type", "text/x-gcode") #Add a preference that says in what file type we should store the file.
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")
file_type = Preferences.getInstance().getValue("removable_drive/file_type")
gcode_writer = Application.getInstance().getMeshFileHandler().getWriterByMimeType(file_type)
if not gcode_writer:
Logger.log("e", "Could not find GCode writer, not writing to removable drive %s", self.getName())
Logger.log("e", "Could not find writer for MIME type %s, not writing to removable drive %s", file_type, self.getName())
raise OutputDeviceError.WriteRequestFailedError()
if file_name == None:

View file

@ -16,7 +16,8 @@ def getMetaData():
"api": 2
},
"view": {
"name": i18n_catalog.i18nc("@item:inmenu", "Solid")
"name": i18n_catalog.i18nc("@item:inmenu", "Solid"),
"weight": 0
}
}

View file

@ -98,7 +98,7 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
@pyqtSlot()
def updateAllFirmware(self):
if not self._printer_connections:
Message("Cannot update firmware, there were no connected printers found.").show()
Message(i18n_catalog.i18nc("@info","Cannot update firmware, there were no connected printers found.")).show()
return
self.spawnFirmwareInterface("")

View file

@ -16,7 +16,8 @@ def getMetaData():
"api": 2
},
"view": {
"name": catalog.i18nc("@item:inlistbox", "X-Ray")
"name": catalog.i18nc("@item:inlistbox", "X-Ray"),
"weight": 1
}
}

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

1373
resources/i18n/en/cura.po Normal file

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Uranium json setting files\n"
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
"POT-Creation-Date: 2015-09-12 20:10+0000\n"
"POT-Creation-Date: 2016-01-18 11:54+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE\n"
@ -11,6 +11,21 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: fdmprinter.json
msgctxt "machine label"
msgid "Machine"
msgstr ""
#: fdmprinter.json
msgctxt "machine_nozzle_size label"
msgid "Nozzle Diameter"
msgstr ""
#: fdmprinter.json
msgctxt "machine_nozzle_size description"
msgid "The inner diameter of the nozzle."
msgstr ""
#: fdmprinter.json
msgctxt "resolution label"
msgid "Quality"
@ -184,8 +199,8 @@ msgstr ""
#: fdmprinter.json
msgctxt "wall_line_count description"
msgid ""
"Number of shell lines. This these lines are called perimeter lines in other "
"tools and impact the strength and structural integrity of your print."
"Number of shell lines. These lines are called perimeter lines in other tools "
"and impact the strength and structural integrity of your print."
msgstr ""
#: fdmprinter.json
@ -209,9 +224,9 @@ msgstr ""
#: fdmprinter.json
msgctxt "top_bottom_thickness description"
msgid ""
"This controls the thickness of the bottom and top layers, the amount of "
"solid layers put down is calculated by the layer thickness and this value. "
"Having this value a multiple of the layer thickness makes sense. And keep it "
"This controls the thickness of the bottom and top layers. The number of "
"solid layers put down is calculated from the layer thickness and this value. "
"Having this value a multiple of the layer thickness makes sense. Keep it "
"near your wall thickness to make an evenly strong part."
msgstr ""
@ -225,8 +240,8 @@ msgctxt "top_thickness description"
msgid ""
"This controls the thickness of the top layers. The number of solid layers "
"printed is calculated from the layer thickness and this value. Having this "
"value be a multiple of the layer thickness makes sense. And keep it nearto "
"your wall thickness to make an evenly strong part."
"value be a multiple of the layer thickness makes sense. Keep it near your "
"wall thickness to make an evenly strong part."
msgstr ""
#: fdmprinter.json
@ -236,7 +251,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "top_layers description"
msgid "This controls the amount of top layers."
msgid "This controls the number of top layers."
msgstr ""
#: fdmprinter.json
@ -351,7 +366,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "top_bottom_pattern description"
msgid ""
"Pattern of the top/bottom solid fill. This normally is done with lines to "
"Pattern of the top/bottom solid fill. This is normally done with lines to "
"get the best possible finish, but in some cases a concentric fill gives a "
"nicer end result."
msgstr ""
@ -373,13 +388,13 @@ msgstr ""
#: fdmprinter.json
msgctxt "skin_no_small_gaps_heuristic label"
msgid "Ingore small Z gaps"
msgid "Ignore small Z gaps"
msgstr ""
#: fdmprinter.json
msgctxt "skin_no_small_gaps_heuristic description"
msgid ""
"When the model has small vertical gaps about 5% extra computation time can "
"When the model has small vertical gaps, about 5% extra computation time can "
"be spent on generating top and bottom skin in these narrow spaces. In such a "
"case set this setting to false."
msgstr ""
@ -394,19 +409,19 @@ msgctxt "skin_alternate_rotation description"
msgid ""
"Alternate between diagonal skin fill and horizontal + vertical skin fill. "
"Although the diagonal directions can print quicker, this option can improve "
"on the printing quality by reducing the pillowing effect."
"the printing quality by reducing the pillowing effect."
msgstr ""
#: fdmprinter.json
msgctxt "skin_outline_count label"
msgid "Skin Perimeter Line Count"
msgid "Extra Skin Wall Count"
msgstr ""
#: fdmprinter.json
msgctxt "skin_outline_count description"
msgid ""
"Number of lines around skin regions. Using one or two skin perimeter lines "
"can greatly improve on roofs which would start in the middle of infill cells."
"can greatly improve roofs which would start in the middle of infill cells."
msgstr ""
#: fdmprinter.json
@ -417,7 +432,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "xy_offset description"
msgid ""
"Amount of offset applied all polygons in each layer. Positive values can "
"Amount of offset applied to all polygons in each layer. Positive values can "
"compensate for too big holes; negative values can compensate for too small "
"holes."
msgstr ""
@ -430,11 +445,11 @@ msgstr ""
#: fdmprinter.json
msgctxt "z_seam_type description"
msgid ""
"Starting point of each part in a layer. When parts in consecutive layers "
"Starting point of each path in a layer. When paths in consecutive layers "
"start at the same point a vertical seam may show on the print. When aligning "
"these at the back, the seam is easiest to remove. When placed randomly the "
"inaccuracies at the part start will be less noticable. When taking the "
"shortest path the print will be more quick."
"inaccuracies at the paths' start will be less noticeable. When taking the "
"shortest path the print will be quicker."
msgstr ""
#: fdmprinter.json
@ -466,8 +481,8 @@ msgstr ""
msgctxt "infill_sparse_density description"
msgid ""
"This controls how densely filled the insides of your print will be. For a "
"solid part use 100%, for an hollow part use 0%. A value around 20% is "
"usually enough. This won't affect the outside of the print and only adjusts "
"solid part use 100%, for a hollow part use 0%. A value around 20% is usually "
"enough. This setting won't affect the outside of the print and only adjusts "
"how strong the part becomes."
msgstr ""
@ -489,7 +504,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "infill_pattern description"
msgid ""
"Cura defaults to switching between grid and line infill. But with this "
"Cura defaults to switching between grid and line infill, but with this "
"setting visible you can control this yourself. The line infill swaps "
"direction on alternate layers of infill, while the grid prints the full "
"cross-hatching on each layer of infill."
@ -505,6 +520,11 @@ msgctxt "infill_pattern option lines"
msgid "Lines"
msgstr ""
#: fdmprinter.json
msgctxt "infill_pattern option triangles"
msgid "Triangles"
msgstr ""
#: fdmprinter.json
msgctxt "infill_pattern option concentric"
msgid "Concentric"
@ -536,7 +556,7 @@ msgstr ""
msgctxt "infill_wipe_dist description"
msgid ""
"Distance of a travel move inserted after every infill line, to make the "
"infill stick to the walls better. This option is imilar to infill overlap, "
"infill stick to the walls better. This option is similar to infill overlap, "
"but without extrusion and only on one end of the infill line."
msgstr ""
@ -553,16 +573,6 @@ msgid ""
"save printing time."
msgstr ""
#: fdmprinter.json
msgctxt "infill_sparse_combine label"
msgid "Infill Layers"
msgstr ""
#: fdmprinter.json
msgctxt "infill_sparse_combine description"
msgid "Amount of layers that are combined together to form sparse infill."
msgstr ""
#: fdmprinter.json
msgctxt "infill_before_walls label"
msgid "Infill Before Walls"
@ -582,6 +592,18 @@ msgctxt "material label"
msgid "Material"
msgstr ""
#: fdmprinter.json
msgctxt "material_flow_dependent_temperature label"
msgid "Auto Temperature"
msgstr ""
#: fdmprinter.json
msgctxt "material_flow_dependent_temperature description"
msgid ""
"Change the temperature for each layer automatically with the average flow "
"speed of that layer."
msgstr ""
#: fdmprinter.json
msgctxt "material_print_temperature label"
msgid "Printing Temperature"
@ -595,6 +617,42 @@ msgid ""
"For ABS a value of 230C or higher is required."
msgstr ""
#: fdmprinter.json
msgctxt "material_flow_temp_graph label"
msgid "Flow Temperature Graph"
msgstr ""
#: fdmprinter.json
msgctxt "material_flow_temp_graph description"
msgid ""
"Data linking material flow (in mm3 per second) to temperature (degrees "
"Celsius)."
msgstr ""
#: fdmprinter.json
msgctxt "material_standby_temperature label"
msgid "Standby Temperature"
msgstr ""
#: fdmprinter.json
msgctxt "material_standby_temperature description"
msgid ""
"The temperature of the nozzle when another nozzle is currently used for "
"printing."
msgstr ""
#: fdmprinter.json
msgctxt "material_extrusion_cool_down_speed label"
msgid "Extrusion Cool Down Speed Modifier"
msgstr ""
#: fdmprinter.json
msgctxt "material_extrusion_cool_down_speed description"
msgid ""
"The extra speed by which the nozzle cools while extruding. The same value is "
"used to signify the heat up speed lost when heating up while extruding."
msgstr ""
#: fdmprinter.json
msgctxt "material_bed_temperature label"
msgid "Bed Temperature"
@ -617,7 +675,7 @@ msgctxt "material_diameter description"
msgid ""
"The diameter of your filament needs to be measured as accurately as "
"possible.\n"
"If you cannot measure this value you will have to calibrate it, a higher "
"If you cannot measure this value you will have to calibrate it; a higher "
"number means less extrusion, a smaller number generates more extrusion."
msgstr ""
@ -654,7 +712,7 @@ msgstr ""
msgctxt "retraction_amount description"
msgid ""
"The amount of retraction: Set at 0 for no retraction at all. A value of "
"4.5mm seems to generate good results for 3mm filament in Bowden-tube fed "
"4.5mm seems to generate good results for 3mm filament in bowden tube fed "
"printers."
msgstr ""
@ -700,8 +758,8 @@ msgstr ""
#: fdmprinter.json
msgctxt "retraction_extra_prime_amount description"
msgid ""
"The amount of material extruded after unretracting. During a retracted "
"travel material might get lost and so we need to compensate for this."
"The amount of material extruded after a retraction. During a travel move, "
"some material might get lost and so we need to compensate for this."
msgstr ""
#: fdmprinter.json
@ -713,33 +771,33 @@ msgstr ""
msgctxt "retraction_min_travel description"
msgid ""
"The minimum distance of travel needed for a retraction to happen at all. "
"This helps ensure you do not get a lot of retractions in a small area."
"This helps to get fewer retractions in a small area."
msgstr ""
#: fdmprinter.json
msgctxt "retraction_count_max label"
msgid "Maximal Retraction Count"
msgid "Maximum Retraction Count"
msgstr ""
#: fdmprinter.json
msgctxt "retraction_count_max description"
msgid ""
"This settings limits the number of retractions occuring within the Minimal "
"This setting limits the number of retractions occurring within the Minimum "
"Extrusion Distance Window. Further retractions within this window will be "
"ignored. This avoids retracting repeatedly on the same piece of filament as "
"ignored. This avoids retracting repeatedly on the same piece of filament, as "
"that can flatten the filament and cause grinding issues."
msgstr ""
#: fdmprinter.json
msgctxt "retraction_extrusion_window label"
msgid "Minimal Extrusion Distance Window"
msgid "Minimum Extrusion Distance Window"
msgstr ""
#: fdmprinter.json
msgctxt "retraction_extrusion_window description"
msgid ""
"The window in which the Maximal Retraction Count is enforced. This window "
"should be approximately the size of the Retraction distance, so that "
"The window in which the Maximum Retraction Count is enforced. This value "
"should be approximately the same as the Retraction distance, so that "
"effectively the number of times a retraction passes the same patch of "
"material is limited."
msgstr ""
@ -753,7 +811,7 @@ msgstr ""
msgctxt "retraction_hop description"
msgid ""
"Whenever a retraction is done, the head is lifted by this amount to travel "
"over the print. A value of 0.075 works well. This feature has a lot of "
"over the print. A value of 0.075 works well. This feature has a large "
"positive effect on delta towers."
msgstr ""
@ -796,7 +854,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "speed_wall description"
msgid ""
"The speed at which shell is printed. Printing the outer shell at a lower "
"The speed at which the shell is printed. Printing the outer shell at a lower "
"speed improves the final skin quality."
msgstr ""
@ -808,7 +866,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "speed_wall_0 description"
msgid ""
"The speed at which outer shell is printed. Printing the outer shell at a "
"The speed at which the outer shell is printed. Printing the outer shell at a "
"lower speed improves the final skin quality. However, having a large "
"difference between the inner shell speed and the outer shell speed will "
"effect quality in a negative way."
@ -823,7 +881,7 @@ msgstr ""
msgctxt "speed_wall_x description"
msgid ""
"The speed at which all inner shells are printed. Printing the inner shell "
"fasster than the outer shell will reduce printing time. It is good to set "
"faster than the outer shell will reduce printing time. It works well to set "
"this in between the outer shell speed and the infill speed."
msgstr ""
@ -849,8 +907,9 @@ msgstr ""
msgctxt "speed_support description"
msgid ""
"The speed at which exterior support is printed. Printing exterior supports "
"at higher speeds can greatly improve printing time. And the surface quality "
"of exterior support is usually not important, so higher speeds can be used."
"at higher speeds can greatly improve printing time. The surface quality of "
"exterior support is usually not important anyway, so higher speeds can be "
"used."
msgstr ""
#: fdmprinter.json
@ -862,7 +921,7 @@ msgstr ""
msgctxt "speed_support_lines description"
msgid ""
"The speed at which the walls of exterior support are printed. Printing the "
"walls at higher speeds can improve on the overall duration. "
"walls at higher speeds can improve the overall duration."
msgstr ""
#: fdmprinter.json
@ -874,7 +933,7 @@ msgstr ""
msgctxt "speed_support_roof description"
msgid ""
"The speed at which the roofs of exterior support are printed. Printing the "
"support roof at lower speeds can improve on overhang quality. "
"support roof at lower speeds can improve overhang quality."
msgstr ""
#: fdmprinter.json
@ -886,7 +945,7 @@ msgstr ""
msgctxt "speed_travel description"
msgid ""
"The speed at which travel moves are done. A well-built Ultimaker can reach "
"speeds of 250mm/s. But some machines might have misaligned layers then."
"speeds of 250mm/s, but some machines might have misaligned layers then."
msgstr ""
#: fdmprinter.json
@ -898,7 +957,7 @@ msgstr ""
msgctxt "speed_layer_0 description"
msgid ""
"The print speed for the bottom layer: You want to print the first layer "
"slower so it sticks to the printer bed better."
"slower so it sticks better to the printer bed."
msgstr ""
#: fdmprinter.json
@ -910,19 +969,19 @@ msgstr ""
msgctxt "skirt_speed description"
msgid ""
"The speed at which the skirt and brim are printed. Normally this is done at "
"the initial layer speed. But sometimes you want to print the skirt at a "
"different speed."
"the initial layer speed, but sometimes you might want to print the skirt at "
"a different speed."
msgstr ""
#: fdmprinter.json
msgctxt "speed_slowdown_layers label"
msgid "Amount of Slower Layers"
msgid "Number of Slower Layers"
msgstr ""
#: fdmprinter.json
msgctxt "speed_slowdown_layers description"
msgid ""
"The first few layers are printed slower then the rest of the object, this to "
"The first few layers are printed slower than the rest of the object, this to "
"get better adhesion to the printer bed and improve the overall success rate "
"of prints. The speed is gradually increased over these layers. 4 layers of "
"speed-up is generally right for most materials and printers."
@ -942,8 +1001,8 @@ msgstr ""
msgctxt "retraction_combing description"
msgid ""
"Combing keeps the head within the interior of the print whenever possible "
"when traveling from one part of the print to another, and does not use "
"retraction. If combing is disabled the printer head moves straight from the "
"when traveling from one part of the print to another and does not use "
"retraction. If combing is disabled, the print head moves straight from the "
"start point to the end point and it will always retract."
msgstr ""
@ -992,26 +1051,6 @@ msgid ""
"nozzle diameter cubed."
msgstr ""
#: fdmprinter.json
msgctxt "coasting_volume_retract label"
msgid "Retract-Coasting Volume"
msgstr ""
#: fdmprinter.json
msgctxt "coasting_volume_retract description"
msgid "The volume otherwise oozed in a travel move with retraction."
msgstr ""
#: fdmprinter.json
msgctxt "coasting_volume_move label"
msgid "Move-Coasting Volume"
msgstr ""
#: fdmprinter.json
msgctxt "coasting_volume_move description"
msgid "The volume otherwise oozed in a travel move without retraction."
msgstr ""
#: fdmprinter.json
msgctxt "coasting_min_volume label"
msgid "Minimal Volume Before Coasting"
@ -1022,31 +1061,8 @@ msgctxt "coasting_min_volume description"
msgid ""
"The least volume an extrusion path should have to coast the full amount. For "
"smaller extrusion paths, less pressure has been built up in the bowden tube "
"and so the coasted volume is scaled linearly."
msgstr ""
#: fdmprinter.json
msgctxt "coasting_min_volume_retract label"
msgid "Min Volume Retract-Coasting"
msgstr ""
#: fdmprinter.json
msgctxt "coasting_min_volume_retract description"
msgid ""
"The minimal volume an extrusion path must have in order to coast the full "
"amount before doing a retraction."
msgstr ""
#: fdmprinter.json
msgctxt "coasting_min_volume_move label"
msgid "Min Volume Move-Coasting"
msgstr ""
#: fdmprinter.json
msgctxt "coasting_min_volume_move description"
msgid ""
"The minimal volume an extrusion path must have in order to coast the full "
"amount before doing a travel move without retraction."
"and so the coasted volume is scaled linearly. This value should always be "
"larger than the Coasting Volume."
msgstr ""
#: fdmprinter.json
@ -1059,31 +1075,7 @@ msgctxt "coasting_speed description"
msgid ""
"The speed by which to move during coasting, relative to the speed of the "
"extrusion path. A value slightly under 100% is advised, since during the "
"coasting move, the pressure in the bowden tube drops."
msgstr ""
#: fdmprinter.json
msgctxt "coasting_speed_retract label"
msgid "Retract-Coasting Speed"
msgstr ""
#: fdmprinter.json
msgctxt "coasting_speed_retract description"
msgid ""
"The speed by which to move during coasting before a retraction, relative to "
"the speed of the extrusion path."
msgstr ""
#: fdmprinter.json
msgctxt "coasting_speed_move label"
msgid "Move-Coasting Speed"
msgstr ""
#: fdmprinter.json
msgctxt "coasting_speed_move description"
msgid ""
"The speed by which to move during coasting before a travel move without "
"retraction, relative to the speed of the extrusion path."
"coasting move the pressure in the bowden tube drops."
msgstr ""
#: fdmprinter.json
@ -1166,7 +1158,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "cool_min_layer_time label"
msgid "Minimal Layer Time"
msgid "Minimum Layer Time"
msgstr ""
#: fdmprinter.json
@ -1180,16 +1172,16 @@ msgstr ""
#: fdmprinter.json
msgctxt "cool_min_layer_time_fan_speed_max label"
msgid "Minimal Layer Time Full Fan Speed"
msgid "Minimum Layer Time Full Fan Speed"
msgstr ""
#: fdmprinter.json
msgctxt "cool_min_layer_time_fan_speed_max description"
msgid ""
"The minimum time spent in a layer which will cause the fan to be at maximum "
"speed. The fan speed increases linearly from minimal fan speed for layers "
"taking minimal layer time to maximum fan speed for layers taking the time "
"specified here."
"speed. The fan speed increases linearly from minimum fan speed for layers "
"taking the minimum layer time to maximum fan speed for layers taking the "
"time specified here."
msgstr ""
#: fdmprinter.json
@ -1243,7 +1235,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_type description"
msgid ""
"Where to place support structures. The placement can be restricted such that "
"Where to place support structures. The placement can be restricted so that "
"the support structures won't rest on the model, which could otherwise cause "
"scarring."
msgstr ""
@ -1279,7 +1271,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_xy_distance description"
msgid ""
"Distance of the support structure from the print, in the X/Y directions. "
"Distance of the support structure from the print in the X/Y directions. "
"0.7mm typically gives a nice distance from the print so the support does not "
"stick to the surface."
msgstr ""
@ -1352,7 +1344,7 @@ msgstr ""
msgctxt "support_conical_min_width description"
msgid ""
"Minimal width to which conical support reduces the support areas. Small "
"widths can cause the base of the support to not act well as fundament for "
"widths can cause the base of the support to not act well as foundation for "
"support above."
msgstr ""
@ -1377,8 +1369,8 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_join_distance description"
msgid ""
"The maximum distance between support blocks, in the X/Y directions, such "
"that the blocks will merge into a single block."
"The maximum distance between support blocks in the X/Y directions, so that "
"the blocks will merge into a single block."
msgstr ""
#: fdmprinter.json
@ -1401,7 +1393,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_area_smoothing description"
msgid ""
"Maximal distance in the X/Y directions of a line segment which is to be "
"Maximum distance in the X/Y directions of a line segment which is to be "
"smoothed out. Ragged lines are introduced by the join distance and support "
"bridge, which cause the machine to resonate. Smoothing the support areas "
"won't cause them to break with the constraints, except it might change the "
@ -1426,7 +1418,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_roof_height description"
msgid "The height of the support roofs. "
msgid "The height of the support roofs."
msgstr ""
#: fdmprinter.json
@ -1438,7 +1430,8 @@ msgstr ""
msgctxt "support_roof_density description"
msgid ""
"This controls how densely filled the roofs of the support will be. A higher "
"percentage results in better overhangs, which are more difficult to remove."
"percentage results in better overhangs, but makes the support more difficult "
"to remove."
msgstr ""
#: fdmprinter.json
@ -1488,7 +1481,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_use_towers label"
msgid "Use towers."
msgid "Use towers"
msgstr ""
#: fdmprinter.json
@ -1501,14 +1494,14 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_minimal_diameter label"
msgid "Minimal Diameter"
msgid "Minimum Diameter"
msgstr ""
#: fdmprinter.json
msgctxt "support_minimal_diameter description"
msgid ""
"Maximal diameter in the X/Y directions of a small area which is to be "
"supported by a specialized support tower. "
"Minimum diameter in the X/Y directions of a small area which is to be "
"supported by a specialized support tower."
msgstr ""
#: fdmprinter.json
@ -1518,7 +1511,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_tower_diameter description"
msgid "The diameter of a special tower. "
msgid "The diameter of a special tower."
msgstr ""
#: fdmprinter.json
@ -1529,7 +1522,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_tower_roof_angle description"
msgid ""
"The angle of the rooftop of a tower. Larger angles mean more pointy towers. "
"The angle of the rooftop of a tower. Larger angles mean more pointy towers."
msgstr ""
#: fdmprinter.json
@ -1540,11 +1533,11 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_pattern description"
msgid ""
"Cura supports 3 distinct types of support structure. First is a grid based "
"support structure which is quite solid and can be removed as 1 piece. The "
"second is a line based support structure which has to be peeled off line by "
"line. The third is a structure in between the other two; it consists of "
"lines which are connected in an accordeon fashion."
"Cura can generate 3 distinct types of support structure. First is a grid "
"based support structure which is quite solid and can be removed in one "
"piece. The second is a line based support structure which has to be peeled "
"off line by line. The third is a structure in between the other two; it "
"consists of lines which are connected in an accordion fashion."
msgstr ""
#: fdmprinter.json
@ -1592,7 +1585,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "support_infill_rate description"
msgid ""
"The amount of infill structure in the support, less infill gives weaker "
"The amount of infill structure in the support; less infill gives weaker "
"support which is easier to remove."
msgstr ""
@ -1619,11 +1612,14 @@ msgstr ""
#: fdmprinter.json
msgctxt "adhesion_type description"
msgid ""
"Different options that help in preventing corners from lifting due to "
"warping. Brim adds a single-layer-thick flat area around your object which "
"is easy to cut off afterwards, and it is the recommended option. Raft adds a "
"thick grid below the object and a thin interface between this and your "
"object. (Note that enabling the brim or raft disables the skirt.)"
"Different options that help to improve priming your extrusion.\n"
"Brim and Raft help in preventing corners from lifting due to warping. Brim "
"adds a single-layer-thick flat area around your object which is easy to cut "
"off afterwards, and it is the recommended option.\n"
"Raft adds a thick grid below the object and a thin interface between this "
"and your object.\n"
"The skirt is a line drawn around the first layer of the print, this helps to "
"prime your extrusion and to see if the object fits on your platform."
msgstr ""
#: fdmprinter.json
@ -1649,10 +1645,8 @@ msgstr ""
#: fdmprinter.json
msgctxt "skirt_line_count description"
msgid ""
"The skirt is a line drawn around the first layer of the. This helps to prime "
"your extruder, and to see if the object fits on your platform. Setting this "
"to 0 will disable the skirt. Multiple skirt lines can help to prime your "
"extruder better for small objects."
"Multiple skirt lines help to prime your extrusion better for small objects. "
"Setting this to 0 will disable the skirt."
msgstr ""
#: fdmprinter.json
@ -1681,6 +1675,19 @@ msgid ""
"count is set to 0 this is ignored."
msgstr ""
#: fdmprinter.json
msgctxt "brim_width label"
msgid "Brim Width"
msgstr ""
#: fdmprinter.json
msgctxt "brim_width description"
msgid ""
"The distance from the model to the end of the brim. A larger brim sticks "
"better to the build platform, but also makes your effective print area "
"smaller."
msgstr ""
#: fdmprinter.json
msgctxt "brim_line_count label"
msgid "Brim Line Count"
@ -1689,8 +1696,9 @@ msgstr ""
#: fdmprinter.json
msgctxt "brim_line_count description"
msgid ""
"The amount of lines used for a brim: More lines means a larger brim which "
"sticks better, but this also makes your effective print area smaller."
"The number of lines used for a brim. More lines means a larger brim which "
"sticks better to the build plate, but this also makes your effective print "
"area smaller."
msgstr ""
#: fdmprinter.json
@ -1721,84 +1729,84 @@ msgstr ""
#: fdmprinter.json
msgctxt "raft_surface_layers label"
msgid "Raft Surface Layers"
msgid "Raft Top Layers"
msgstr ""
#: fdmprinter.json
msgctxt "raft_surface_layers description"
msgid ""
"The number of surface layers on top of the 2nd raft layer. These are fully "
"filled layers that the object sits on. 2 layers usually works fine."
"The number of top layers on top of the 2nd raft layer. These are fully "
"filled layers that the object sits on. 2 layers result in a smoother top "
"surface than 1."
msgstr ""
#: fdmprinter.json
msgctxt "raft_surface_thickness label"
msgid "Raft Surface Thickness"
msgid "Raft Top Layer Thickness"
msgstr ""
#: fdmprinter.json
msgctxt "raft_surface_thickness description"
msgid "Layer thickness of the surface raft layers."
msgid "Layer thickness of the top raft layers."
msgstr ""
#: fdmprinter.json
msgctxt "raft_surface_line_width label"
msgid "Raft Surface Line Width"
msgid "Raft Top Line Width"
msgstr ""
#: fdmprinter.json
msgctxt "raft_surface_line_width description"
msgid ""
"Width of the lines in the surface raft layers. These can be thin lines so "
"that the top of the raft becomes smooth."
"Width of the lines in the top surface of the raft. These can be thin lines "
"so that the top of the raft becomes smooth."
msgstr ""
#: fdmprinter.json
msgctxt "raft_surface_line_spacing label"
msgid "Raft Surface Spacing"
msgid "Raft Top Spacing"
msgstr ""
#: fdmprinter.json
msgctxt "raft_surface_line_spacing description"
msgid ""
"The distance between the raft lines for the surface raft layers. The spacing "
"of the interface should be equal to the line width, so that the surface is "
"solid."
"The distance between the raft lines for the top raft layers. The spacing "
"should be equal to the line width, so that the surface is solid."
msgstr ""
#: fdmprinter.json
msgctxt "raft_interface_thickness label"
msgid "Raft Interface Thickness"
msgid "Raft Middle Thickness"
msgstr ""
#: fdmprinter.json
msgctxt "raft_interface_thickness description"
msgid "Layer thickness of the interface raft layer."
msgid "Layer thickness of the middle raft layer."
msgstr ""
#: fdmprinter.json
msgctxt "raft_interface_line_width label"
msgid "Raft Interface Line Width"
msgid "Raft Middle Line Width"
msgstr ""
#: fdmprinter.json
msgctxt "raft_interface_line_width description"
msgid ""
"Width of the lines in the interface raft layer. Making the second layer "
"extrude more causes the lines to stick to the bed."
"Width of the lines in the middle raft layer. Making the second layer extrude "
"more causes the lines to stick to the bed."
msgstr ""
#: fdmprinter.json
msgctxt "raft_interface_line_spacing label"
msgid "Raft Interface Spacing"
msgid "Raft Middle Spacing"
msgstr ""
#: fdmprinter.json
msgctxt "raft_interface_line_spacing description"
msgid ""
"The distance between the raft lines for the interface raft layer. The "
"spacing of the interface should be quite wide, while being dense enough to "
"support the surface raft layers."
"The distance between the raft lines for the middle raft layer. The spacing "
"of the middle should be quite wide, while being dense enough to support the "
"top raft layers."
msgstr ""
#: fdmprinter.json
@ -1855,7 +1863,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "raft_surface_speed description"
msgid ""
"The speed at which the surface raft layers are printed. This should be "
"The speed at which the surface raft layers are printed. These should be "
"printed a bit slower, so that the nozzle can slowly smooth out adjacent "
"surface lines."
msgstr ""
@ -1869,7 +1877,7 @@ msgstr ""
msgctxt "raft_interface_speed description"
msgid ""
"The speed at which the interface raft layer is printed. This should be "
"printed quite slowly, as the amount of material coming out of the nozzle is "
"printed quite slowly, as the volume of material coming out of the nozzle is "
"quite high."
msgstr ""
@ -1882,7 +1890,7 @@ msgstr ""
msgctxt "raft_base_speed description"
msgid ""
"The speed at which the base raft layer is printed. This should be printed "
"quite slowly, as the amount of material coming out of the nozzle is quite "
"quite slowly, as the volume of material coming out of the nozzle is quite "
"high."
msgstr ""
@ -1956,7 +1964,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "draft_shield_height_limitation description"
msgid "Whether to limit the height of the draft shield"
msgid "Whether or not to limit the height of the draft shield."
msgstr ""
#: fdmprinter.json
@ -1995,7 +2003,7 @@ msgstr ""
msgctxt "meshfix_union_all description"
msgid ""
"Ignore the internal geometry arising from overlapping volumes and print the "
"volumes as one. This may cause internal cavaties to disappear."
"volumes as one. This may cause internal cavities to disappear."
msgstr ""
#: fdmprinter.json
@ -2034,8 +2042,8 @@ msgctxt "meshfix_keep_open_polygons description"
msgid ""
"Normally Cura tries to stitch up small holes in the mesh and remove parts of "
"a layer with big holes. Enabling this option keeps those parts which cannot "
"be stitched. This option should be used as a last resort option when all "
"else doesn produce proper GCode."
"be stitched. This option should be used as a last resort option when "
"everything else fails to produce proper GCode."
msgstr ""
#: fdmprinter.json
@ -2053,9 +2061,9 @@ msgctxt "print_sequence description"
msgid ""
"Whether to print all objects one layer at a time or to wait for one object "
"to finish, before moving on to the next. One at a time mode is only possible "
"if all models are separated such that the whole print head can move between "
"and all models are lower than the distance between the nozzle and the X/Y "
"axles."
"if all models are separated in such a way that the whole print head can move "
"in between and all models are lower than the distance between the nozzle and "
"the X/Y axes."
msgstr ""
#: fdmprinter.json
@ -2108,7 +2116,7 @@ msgid ""
"Spiralize smooths out the Z move of the outer edge. This will create a "
"steady Z increase over the whole print. This feature turns a solid object "
"into a single walled print with a solid bottom. This feature used to be "
"called Joris in older versions."
"called Joris in older versions."
msgstr ""
#: fdmprinter.json
@ -2311,9 +2319,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "wireframe_bottom_delay description"
msgid ""
"Delay time after a downward move. Only applies to Wire Printing. Only "
"applies to Wire Printing."
msgid "Delay time after a downward move. Only applies to Wire Printing."
msgstr ""
#: fdmprinter.json
@ -2326,7 +2332,7 @@ msgctxt "wireframe_flat_delay description"
msgid ""
"Delay time between two horizontal segments. Introducing such a delay can "
"cause better adhesion to previous layers at the connection points, while too "
"large delay times cause sagging. Only applies to Wire Printing."
"long delays cause sagging. Only applies to Wire Printing."
msgstr ""
#: fdmprinter.json
@ -2391,10 +2397,10 @@ msgid ""
"Strategy for making sure two consecutive layers connect at each connection "
"point. Retraction lets the upward lines harden in the right position, but "
"may cause filament grinding. A knot can be made at the end of an upward line "
"to heighten the chance of connecting to it and to let the line cool; however "
"it may require slow printing speeds. Another strategy is to compensate for "
"the sagging of the top of an upward line; however, the lines won't always "
"fall down as predicted."
"to heighten the chance of connecting to it and to let the line cool; "
"however, it may require slow printing speeds. Another strategy is to "
"compensate for the sagging of the top of an upward line; however, the lines "
"won't always fall down as predicted."
msgstr ""
#: fdmprinter.json
@ -2459,7 +2465,7 @@ msgstr ""
#: fdmprinter.json
msgctxt "wireframe_roof_outer_delay description"
msgid ""
"Time spent at the outer perimeters of hole which is to become a roof. Larger "
"Time spent at the outer perimeters of hole which is to become a roof. Longer "
"times can ensure a better connection. Only applies to Wire Printing."
msgstr ""

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.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -33,7 +33,7 @@
"default": "RepRap"
},
"machine_platform_offset": {
"default": [-6, 1320, 0]
"default": [6, 1320, 0]
}
"material_print_temperature": { "default": 210.0, "visible": true },
"material_bed_temperature": { "default": 0 },

View file

@ -153,6 +153,8 @@
"type": "float",
"unit": "mm",
"default": 200,
"min_value_warning": "-1000",
"max_value_warning": "1000",
"enabled": "prime_tower_enable"
},
"prime_tower_position_y": {
@ -162,6 +164,8 @@
"type": "float",
"unit": "mm",
"default": 200,
"min_value_warning": "-1000",
"max_value_warning": "1000",
"enabled": "prime_tower_enable"
},
"prime_tower_flow": {
@ -231,6 +235,8 @@
"unit": "mm",
"type": "float",
"default": 16,
"min_value_warning": "0",
"max_value_warning": "100",
"visible": false,
"inherit_function": "machine_heat_zone_length",
"enabled": "retraction_enable"
@ -241,6 +247,8 @@
"unit": "mm/s",
"type": "float",
"default": 20,
"min_value": "0.1",
"max_value_warning": "300",
"visible": false,
"inherit": false,
"enabled": "retraction_enable",
@ -251,6 +259,8 @@
"unit": "mm/s",
"type": "float",
"default": 20,
"min_value": "0.1",
"max_value_warning": "300",
"visible": false,
"enabled": "retraction_enable"
},
@ -260,6 +270,8 @@
"unit": "mm/s",
"type": "float",
"default": 20,
"min_value": "0.1",
"max_value_warning": "300",
"visible": false,
"enabled": "retraction_enable"
}

View file

@ -158,6 +158,7 @@
"type": "float",
"default": 0.4,
"min_value": "0.001",
"max_value_warning": "10",
"visible": false
}
}
@ -286,6 +287,8 @@
"description": "Width of a single support roof line, used to fill the top of the support.",
"unit": "mm",
"default": 0.4,
"min_value": "0.0001",
"max_value_warning": "machine_nozzle_size * 2",
"type": "float",
"visible": false,
"enabled": "support_roof_enable"
@ -323,8 +326,8 @@
"wall_line_count": {
"label": "Wall Line Count",
"description": "Number of shell lines. These lines are called perimeter lines in other tools and impact the strength and structural integrity of your print.",
"min_value": "0",
"default": 2,
"min_value": "0",
"type": "int",
"visible": false,
"inherit_function": "max(1, round((wall_thickness - wall_line_width_0) / wall_line_width_x) + 1)"
@ -354,16 +357,18 @@
"label": "Top Thickness",
"description": "This controls the thickness of the top layers. The number of solid layers printed is calculated from the layer thickness and this value. Having this value be a multiple of the layer thickness makes sense. Keep it near your wall thickness to make an evenly strong part.",
"unit": "mm",
"min_value": "0",
"default": 0.8,
"min_value": "0",
"max_value_warning": "100",
"type": "float",
"visible": false,
"children": {
"top_layers": {
"label": "Top Layers",
"description": "This controls the number of top layers.",
"min_value": "0",
"default": 8,
"min_value": "0",
"max_value_warning": "100",
"type": "int",
"visible": false,
"inherit_function": "0 if infill_sparse_density == 100 else math.ceil(parent_value / layer_height)"
@ -374,8 +379,8 @@
"label": "Bottom Thickness",
"description": "This controls the thickness of the bottom layers. The number of solid layers printed is calculated from the layer thickness and this value. Having this value be a multiple of the layer thickness makes sense. And keep it near to your wall thickness to make an evenly strong part.",
"unit": "mm",
"min_value": "0",
"default": 0.6,
"min_value": "0",
"type": "float",
"visible": false,
"children": {
@ -469,6 +474,8 @@
"label": "Extra Skin Wall Count",
"description": "Number of lines around skin regions. Using one or two skin perimeter lines can greatly improve roofs which would start in the middle of infill cells.",
"default": 0,
"min_value": "0",
"max_value_warning": "10",
"type": "int",
"visible": false
},
@ -477,6 +484,8 @@
"description": "Amount of offset applied to all polygons in each layer. Positive values can compensate for too big holes; negative values can compensate for too small holes.",
"unit": "mm",
"type": "float",
"min_value_warning": "-10",
"max_value_warning": "10",
"default": 0,
"visible": false
},
@ -506,7 +515,7 @@
"type": "float",
"default": 20,
"min_value": "0",
"max_value": "100",
"max_value_warning": "100",
"children": {
"infill_line_distance": {
"label": "Line distance",
@ -514,6 +523,7 @@
"unit": "mm",
"type": "float",
"default": 2,
"min_value": "0",
"visible": false,
"inherit_function": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density"
}
@ -541,7 +551,7 @@
"type": "float",
"default": 10,
"min_value": "0",
"max_value": "100",
"max_value_warning": "100",
"inherit_function": "10 if infill_sparse_density < 95 else 0",
"visible": false
},
@ -551,6 +561,8 @@
"unit": "mm",
"type": "float",
"default": 0.04,
"min_value_warning": "0",
"max_value_warning": "machine_nozzle_size",
"visible": false
},
"infill_sparse_thickness": {
@ -559,6 +571,8 @@
"unit": "mm",
"type": "float",
"default": 0.1,
"min_value": "0.0001",
"max_value_warning": "0.32",
"visible": false,
"inherit_function": "layer_height"
},
@ -595,7 +609,7 @@
},
"material_flow_temp_graph": {
"label": "Flow Temperature Graph",
"description": "Data linking material flow (in mm³/s) to temperature (°C).",
"description": "Data linking material flow (in mm3 per second) to temperature (degrees Celsius).",
"unit": "",
"type": "string",
"default": "[[3.5,200],[7.0,240]]",
@ -635,6 +649,7 @@
"unit": "mm",
"type": "float",
"default": 2.85,
"min_value": "0.0001",
"min_value_warning": "0.4",
"max_value_warning": "3.5"
},
@ -661,6 +676,8 @@
"unit": "mm",
"type": "float",
"default": 4.5,
"min_value_warning": "-0.0001",
"max_value_warning": "10.0",
"visible": false,
"inherit": false,
"enabled": "retraction_enable"
@ -671,6 +688,8 @@
"unit": "mm/s",
"type": "float",
"default": 25,
"min_value": "0",
"max_value_warning": "100",
"visible": false,
"inherit": false,
"enabled": "retraction_enable",
@ -681,6 +700,8 @@
"unit": "mm/s",
"type": "float",
"default": 25,
"min_value": "0",
"max_value_warning": "100",
"visible": false,
"enabled": "retraction_enable"
},
@ -690,6 +711,8 @@
"unit": "mm/s",
"type": "float",
"default": 25,
"min_value": "0",
"max_value_warning": "100",
"visible": false,
"enabled": "retraction_enable"
}
@ -701,6 +724,8 @@
"unit": "mm³",
"type": "float",
"default": 0,
"min_value_warning": "-0.0001",
"max_value_warning": "5.0",
"visible": false,
"inherit": false,
"enabled": "retraction_enable"
@ -711,6 +736,8 @@
"unit": "mm",
"type": "float",
"default": 1.5,
"min_value": "0",
"max_value_warning": "10",
"visible": false,
"inherit": false,
"enabled": "retraction_enable"
@ -719,6 +746,8 @@
"label": "Maximum Retraction Count",
"description": "This setting limits the number of retractions occurring within the Minimum Extrusion Distance Window. Further retractions within this window will be ignored. This avoids retracting repeatedly on the same piece of filament, as that can flatten the filament and cause grinding issues.",
"default": 8,
"min_value": "0",
"max_value_warning": "20",
"type": "int",
"min_value": "1",
"visible": false,
@ -732,6 +761,7 @@
"type": "float",
"default": 4.5,
"min_value": "0.0",
"max_value_warning": "retraction_amount * 2",
"visible": false,
"inherit_function": "retraction_amount",
"enabled": "retraction_enable"
@ -742,6 +772,8 @@
"unit": "mm",
"type": "float",
"default": 0,
"min_value_warning": "-0.0001",
"max_value_warning": "10",
"visible": false,
"inherit": false,
"enabled": "retraction_enable"
@ -835,6 +867,8 @@
"unit": "mm/s",
"type": "float",
"default": 60,
"min_value": "0.1",
"max_value_warning": "150",
"visible": false,
"inherit": true,
"enabled": "support_roof_enable"
@ -845,6 +879,8 @@
"unit": "mm/s",
"type": "float",
"default": 40,
"min_value": "0.1",
"max_value_warning": "150",
"visible": false,
"inherit": false,
"enabled": "support_roof_enable",
@ -859,9 +895,9 @@
"description": "The speed at which travel moves are done. A well-built Ultimaker can reach speeds of 250mm/s, but some machines might have misaligned layers then.",
"unit": "mm/s",
"type": "float",
"default": 120,
"min_value": "0.1",
"max_value_warning": "300",
"default": 120,
"inherit_function": "speed_print if magic_spiralize else 120"
},
"speed_layer_0": {
@ -869,8 +905,9 @@
"description": "The print speed for the bottom layer: You want to print the first layer slower so it sticks better to the printer bed.",
"unit": "mm/s",
"type": "float",
"min_value": "0.1",
"default": 30,
"min_value": "0.1",
"max_value_warning": "300",
"visible": false
},
"skirt_speed": {
@ -878,8 +915,9 @@
"description": "The speed at which the skirt and brim are printed. Normally this is done at the initial layer speed, but sometimes you might want to print the skirt at a different speed.",
"unit": "mm/s",
"type": "float",
"min_value": "0.1",
"default": 30,
"min_value": "0.1",
"max_value_warning": "300",
"visible": false,
"inherit_function": "speed_layer_0"
},
@ -887,8 +925,9 @@
"label": "Number of Slower Layers",
"description": "The first few layers are printed slower than the rest of the object, this to get better adhesion to the printer bed and improve the overall success rate of prints. The speed is gradually increased over these layers. 4 layers of speed-up is generally right for most materials and printers.",
"type": "int",
"min_value": "0",
"default": 4,
"min_value": "0",
"max_value_warning": "300",
"visible": false
}
}
@ -919,6 +958,8 @@
"unit": "mm",
"type": "float",
"default": 1.5,
"min_value": "0",
"max_value_warning": "machine_nozzle_tip_outer_diameter * 5",
"visible": false,
"inherit": false,
"enabled": "retraction_combing"
@ -938,6 +979,8 @@
"unit": "mm³",
"type": "float",
"default": 0.064,
"min_value": "0",
"max_value_warning": "2.0",
"visible": false,
"inherit": false,
"enabled": "coasting_enable"
@ -949,6 +992,7 @@
"type": "float",
"default": 0.8,
"min_value": "0",
"max_value_warning": "10.0",
"visible": false,
"enabled": "coasting_enable"
},
@ -958,6 +1002,8 @@
"unit": "%",
"type": "float",
"default": 90,
"min_value": "0.0001",
"max_value_warning": "100",
"visible": false,
"inherit": false,
"enabled": "coasting_enable"
@ -1015,16 +1061,18 @@
"description": "The height at which the fan is turned on completely. For the layers below this the fan speed is scaled linearly with the fan off for the first layer.",
"unit": "mm",
"type": "float",
"min_value": "0",
"default": 0.5,
"min_value": "0",
"max_value_warning": "10.0",
"visible": false,
"children": {
"cool_fan_full_layer": {
"label": "Fan Full on at Layer",
"description": "The layer number at which the fan is turned on completely. For the layers below this the fan speed is scaled linearly with the fan off for the first layer.",
"type": "int",
"min_value": "0",
"default": 4,
"min_value": "0",
"max_value_warning": "100",
"visible": false,
"inherit_function": "int((parent_value - layer_height_0 + 0.001) / layer_height)"
}
@ -1035,8 +1083,9 @@
"description": "The minimum time spent in a layer: Gives the layer time to cool down before the next one is put on top. If a layer would print in less time, then the printer will slow down to make sure it has spent at least this many seconds printing the layer.",
"unit": "sec",
"type": "float",
"min_value": "0",
"default": 5,
"min_value": "0",
"max_value_warning": "600",
"visible": false
},
"cool_min_layer_time_fan_speed_max": {
@ -1044,8 +1093,9 @@
"description": "The minimum time spent in a layer which will cause the fan to be at maximum speed. The fan speed increases linearly from minimum fan speed for layers taking the minimum layer time to maximum fan speed for layers taking the time specified here.",
"unit": "sec",
"type": "float",
"min_value": "0",
"default": 10,
"min_value": "cool_min_layer_time",
"max_value_warning": "600",
"visible": false
},
"cool_min_speed": {
@ -1054,6 +1104,8 @@
"unit": "mm/s",
"type": "float",
"default": 10,
"min_value": "0",
"max_value_warning": "100",
"visible": false
},
"cool_lift_head": {
@ -1062,6 +1114,47 @@
"type": "boolean",
"default": false,
"visible": false
},
"draft_shield_enabled": {
"label": "Enable Draft Shield",
"description": "Enable exterior draft shield. This will create a wall around the object which traps (hot) air and shields against gusts of wind. Especially useful for materials which warp easily.",
"type": "boolean",
"default": false
},
"draft_shield_dist": {
"label": "Draft Shield X/Y Distance",
"description": "Distance of the draft shield from the print, in the X/Y directions.",
"unit": "mm",
"type": "float",
"min_value": "0",
"max_value_warning": "100",
"default": 10,
"visible": false,
"enabled": "draft_shield_enabled"
},
"draft_shield_height_limitation": {
"label": "Draft Shield Limitation",
"description": "Whether or not to limit the height of the draft shield.",
"type": "enum",
"options": {
"full": "Full",
"limited": "Limited"
},
"default": "full",
"visible": false,
"enabled": "draft_shield_enabled"
},
"draft_shield_height": {
"label": "Draft Shield Height",
"description": "Height limitation on the draft shield. Above this height no draft shield will be printed.",
"unit": "mm",
"type": "float",
"min_value": "0",
"max_value_warning": "30",
"default": 0,
"inherit_function": "9999 if draft_shield_height_limitation == 'full' and draft_shield_enabled else 0.0",
"visible": false,
"enabled": "draft_shield_height_limitation == \"limited\""
}
}
},
@ -1162,14 +1255,16 @@
"max_value": "90",
"default": 30,
"visible": false,
"enabled": "support_enable"
"enabled": "support_conical_enabled and support_enable"
},
"support_conical_min_width": {
"label": "Minimal Width",
"description": "Minimal width to which conical support reduces the support areas. Small widths can cause the base of the support to not act well as foundation for support above.",
"unit": "mm",
"min_value": "0",
"default": 3.0,
"min_value": "0",
"min_value_warning": "machine_nozzle_size * 3",
"max_value_warning": "100.0",
"type": "float",
"visible": false,
"enabled": "support_enable"
@ -1180,6 +1275,8 @@
"unit": "mm",
"type": "float",
"default": 0.3,
"min_value": "0",
"max_value_warning": "1.0",
"visible": false,
"enabled": "support_enable"
},
@ -1188,7 +1285,9 @@
"description": "The maximum distance between support blocks in the X/Y directions, so that the blocks will merge into a single block.",
"unit": "mm",
"type": "float",
"default": 2,
"default": 2.0,
"min_value_warning": "0",
"max_value_warning": "10",
"visible": false,
"enabled": "support_enable"
},
@ -1198,6 +1297,8 @@
"unit": "mm",
"type": "float",
"default": 0.2,
"min_value_warning": "-0.5",
"max_value_warning": "5.0",
"visible": false,
"enabled": "support_enable"
},
@ -1207,6 +1308,8 @@
"unit": "mm",
"type": "float",
"default": 0.6,
"min_value": "0",
"max_value_warning": "1.0",
"visible": false,
"enabled": "support_enable"
},
@ -1224,6 +1327,8 @@
"unit": "mm",
"type": "float",
"default": 1,
"min_value": "0",
"max_value_warning": "10",
"visible": false,
"enabled": "support_roof_enable"
},
@ -1233,6 +1338,8 @@
"unit": "%",
"type": "float",
"default": 100,
"min_value": "0",
"max_value_warning": "100",
"enabled":"support_roof_enable",
"children": {
"support_roof_line_distance": {
@ -1241,6 +1348,7 @@
"unit": "mm",
"type": "float",
"default": 0.4,
"min_value": "0",
"visible": false,
"inherit_function": "0 if parent_value == 0 else (support_roof_line_width * 100) / parent_value",
"enabled": "support_roof_enable"
@ -1276,6 +1384,8 @@
"unit": "mm",
"type": "float",
"default": 1,
"min_value": "0",
"max_value_warning": "10",
"visible": false,
"enabled": "support_enable"
},
@ -1285,6 +1395,9 @@
"unit": "mm",
"type": "float",
"default": 1,
"min_value": "0",
"min_value_warning": "support_minimal_diameter",
"max_value_warning": "10",
"visible": false,
"enabled": "support_enable"
},
@ -1328,7 +1441,7 @@
"unit": "%",
"type": "float",
"min_value": "0",
"max_value": "100",
"max_value_warning": "100",
"default": 15,
"visible": false,
"enabled": "support_enable",
@ -1370,6 +1483,8 @@
"description": "Multiple skirt lines help to prime your extrusion better for small objects. Setting this to 0 will disable the skirt.",
"type": "int",
"default": 1,
"min_value": "0",
"max_value_warning": "10",
"enabled": "adhesion_type == \"skirt\""
},
"skirt_gap": {
@ -1378,6 +1493,8 @@
"unit": "mm",
"type": "float",
"default": 3,
"min_value_warning": "0",
"max_value_warning": "100",
"enabled": "adhesion_type == \"skirt\""
},
"skirt_minimal_length": {
@ -1386,6 +1503,9 @@
"unit": "mm",
"type": "float",
"default": 250,
"min_value": "0",
"min_value_warning": "25",
"max_value_warning": "2500",
"enabled": "adhesion_type == \"skirt\""
},
"brim_width": {
@ -1394,6 +1514,8 @@
"type": "float",
"unit": "mm",
"default": 5.0,
"min_value": "0.0",
"max_value_warning": "100.0",
"enabled": "adhesion_type == \"brim\"",
"children": {
"brim_line_count": {
@ -1401,6 +1523,8 @@
"description": "The number of lines used for a brim. More lines means a larger brim which sticks better to the build plate, but this also makes your effective print area smaller.",
"type": "int",
"default": 13,
"min_value": "0",
"max_value_warning": "300",
"inherit_function": "math.ceil(parent_value / skirt_line_width)",
"enabled": "adhesion_type == \"brim\""
}
@ -1412,6 +1536,8 @@
"unit": "mm",
"type": "float",
"default": 5,
"min_value_warning": "0",
"max_value_warning": "10",
"enabled": "adhesion_type == \"raft\""
},
"raft_airgap": {
@ -1420,6 +1546,8 @@
"unit": "mm",
"type": "float",
"default": 0.35,
"min_value": "0",
"max_value_warning": "1.0",
"enabled": "adhesion_type == \"raft\""
},
"raft_surface_layers": {
@ -1427,6 +1555,8 @@
"description": "The number of top layers on top of the 2nd raft layer. These are fully filled layers that the object sits on. 2 layers result in a smoother top surface than 1.",
"type": "int",
"default": 2,
"min_value": "0",
"max_value_warning": "20",
"enabled": "adhesion_type == \"raft\""
},
"raft_surface_thickness": {
@ -1435,6 +1565,8 @@
"unit": "mm",
"type": "float",
"default": 0.1,
"min_value": "0",
"max_value_warning": "2.0",
"enabled": "adhesion_type == \"raft\""
},
"raft_surface_line_width": {
@ -1443,6 +1575,8 @@
"unit": "mm",
"type": "float",
"default": 0.3,
"min_value": "0.0001",
"max_value_warning": "machine_nozzle_size * 2",
"enabled": "adhesion_type == \"raft\""
},
"raft_surface_line_spacing": {
@ -1451,6 +1585,8 @@
"unit": "mm",
"type": "float",
"default": 0.3,
"min_value": "0.0001",
"max_value_warning": "5.0",
"enabled": "adhesion_type == \"raft\"",
"inherit_function": "raft_surface_line_width"
},
@ -1460,6 +1596,8 @@
"unit": "mm",
"type": "float",
"default": 0.27,
"min_value": "0",
"max_value_warning": "5.0",
"enabled": "adhesion_type == \"raft\""
},
"raft_interface_line_width": {
@ -1468,6 +1606,8 @@
"unit": "mm",
"type": "float",
"default": 1,
"min_value": "0.0001",
"max_value_warning": "machine_nozzle_size * 2",
"enabled": "adhesion_type == \"raft\""
},
"raft_interface_line_spacing": {
@ -1476,6 +1616,8 @@
"unit": "mm",
"type": "float",
"default": 1.0,
"min_value": "0",
"max_value_warning": "15.0",
"enabled": "adhesion_type == \"raft\""
},
"raft_base_thickness": {
@ -1484,6 +1626,8 @@
"unit": "mm",
"type": "float",
"default": 0.3,
"min_value": "0",
"max_value_warning": "5.0",
"enabled": "adhesion_type == \"raft\""
},
"raft_base_line_width": {
@ -1492,6 +1636,8 @@
"unit": "mm",
"type": "float",
"default": 1,
"min_value": "0.0001",
"max_value_warning": "machine_nozzle_size * 2",
"enabled": "adhesion_type == \"raft\""
},
"raft_base_line_spacing": {
@ -1500,6 +1646,8 @@
"unit": "mm",
"type": "float",
"default": 3.0,
"min_value": "0.0001",
"max_value_warning": "100",
"enabled": "adhesion_type == \"raft\""
},
"raft_speed": {
@ -1508,6 +1656,8 @@
"unit": "mm/s",
"type": "float",
"default": 30,
"min_value": "0.1",
"max_value_warning": "200",
"enabled": "adhesion_type == \"raft\"",
"inherit_function": "speed_print / 60 * 30",
"children": {
@ -1517,6 +1667,8 @@
"unit": "mm/s",
"type": "float",
"default": 30,
"min_value": "0.1",
"max_value_warning": "100",
"enabled": "adhesion_type == \"raft\"",
"inherit_function": "parent_value"
},
@ -1526,6 +1678,8 @@
"unit": "mm/s",
"type": "float",
"default": 15,
"min_value": "0.1",
"max_value_warning": "150",
"enabled": "adhesion_type == \"raft\"",
"inherit_function": "0.5 * parent_value"
},
@ -1535,6 +1689,8 @@
"unit": "mm/s",
"type": "float",
"default": 15,
"min_value": "0.1",
"max_value_warning": "200",
"enabled": "adhesion_type == \"raft\"",
"inherit_function": "0.5 * parent_value"
}
@ -1588,47 +1744,6 @@
"enabled": "adhesion_type == \"raft\""
}
}
},
"draft_shield_enabled": {
"label": "Enable Draft Shield",
"description": "Enable exterior draft shield. This will create a wall around the object which traps (hot) air and shields against gusts of wind. Especially useful for materials which warp easily.",
"type": "boolean",
"default": false
},
"draft_shield_dist": {
"label": "Draft Shield X/Y Distance",
"description": "Distance of the draft shield from the print, in the X/Y directions.",
"unit": "mm",
"type": "float",
"min_value": "0",
"max_value_warning": "100",
"default": 10,
"visible": false,
"enabled": "draft_shield_enabled"
},
"draft_shield_height_limitation": {
"label": "Draft Shield Limitation",
"description": "Whether or not to limit the height of the draft shield.",
"type": "enum",
"options": {
"full": "Full",
"limited": "Limited"
},
"default": "full",
"visible": false,
"enabled": "draft_shield_enabled"
},
"draft_shield_height": {
"label": "Draft Shield Height",
"description": "Height limitation on the draft shield. Above this height no draft shield will be printed.",
"unit": "mm",
"type": "float",
"min_value": "0",
"max_value_warning": "30",
"default": 0,
"inherit_function": "9999 if draft_shield_height_limitation == 'full' and draft_shield_enabled else 0.0",
"visible": false,
"enabled": "draft_shield_height_limitation == \"limited\""
}
}
},
@ -1698,7 +1813,7 @@
},
"magic_spiralize": {
"label": "Spiralize Outer Contour",
"description": "Spiralize smooths out the Z move of the outer edge. This will create a steady Z increase over the whole print. This feature turns a solid object into a single walled print with a solid bottom. This feature used to be called Joris in older versions.",
"description": "Spiralize smooths out the Z move of the outer edge. This will create a steady Z increase over the whole print. This feature turns a solid object into a single walled print with a solid bottom. This feature used to be called Joris in older versions.",
"type": "boolean",
"default": false,
"visible": false
@ -1716,6 +1831,8 @@
"type": "float",
"unit": "mm",
"default": 0.3,
"min_value": "0",
"max_value_warning": "wall_line_width_0",
"visible": false,
"enabled": "magic_fuzzy_skin_enabled"
},
@ -1725,6 +1842,9 @@
"type": "float",
"unit": "1/mm",
"default": 1.25,
"min_value_warning": "0.1",
"max_value_warning": "10",
"max_value": "10000",
"visible": false,
"enabled": "magic_fuzzy_skin_enabled",
"children": {
@ -1734,6 +1854,8 @@
"type": "float",
"unit": "mm",
"default": 0.8,
"min_value_warning": "0.0001",
"max_value_warning": "10",
"inherit_function": "1/parent_value",
"visible": false,
"enabled": "magic_fuzzy_skin_enabled"
@ -1753,6 +1875,8 @@
"type": "float",
"unit": "mm",
"default": 3,
"min_value": "0.0001",
"max_value_warning": "20",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1762,6 +1886,9 @@
"type": "float",
"unit": "mm",
"default": 3,
"min_value": "0",
"min_value_warning": "machine_nozzle_size",
"max_value_warning": "20",
"visible": false,
"enabled": "wireframe_enabled",
"inherit_function": "wireframe_height"
@ -1772,6 +1899,8 @@
"unit": "mm/s",
"type": "float",
"default": 5,
"min_value": "0.1",
"max_value_warning": "50",
"visible": false,
"enabled": "wireframe_enabled",
"children": {
@ -1781,6 +1910,8 @@
"unit": "mm/s",
"type": "float",
"default": 5,
"min_value": "0.1",
"max_value_warning": "50",
"visible": false,
"inherit": true,
"enabled": "wireframe_enabled"
@ -1791,6 +1922,8 @@
"unit": "mm/s",
"type": "float",
"default": 5,
"min_value": "0.1",
"max_value_warning": "50",
"visible": false,
"inherit": true,
"enabled": "wireframe_enabled"
@ -1801,6 +1934,8 @@
"unit": "mm/s",
"type": "float",
"default": 5,
"min_value": "0.1",
"max_value_warning": "50",
"visible": false,
"inherit": true,
"enabled": "wireframe_enabled"
@ -1811,6 +1946,8 @@
"unit": "mm/s",
"type": "float",
"default": 5,
"min_value": "0.1",
"max_value_warning": "100",
"visible": false,
"inherit": true,
"enabled": "wireframe_enabled"
@ -1823,7 +1960,7 @@
"unit": "%",
"default": 100,
"min_value": "0",
"max_value": "100",
"max_value_warning": "100",
"type": "float",
"visible": false,
"enabled": "wireframe_enabled",
@ -1833,6 +1970,8 @@
"description": "Flow compensation when going up or down. Only applies to Wire Printing.",
"unit": "%",
"default": 100,
"min_value": "0",
"max_value_warning": "100",
"type": "float",
"visible": false,
"enabled": "wireframe_enabled"
@ -1842,6 +1981,8 @@
"description": "Flow compensation when printing flat lines. Only applies to Wire Printing.",
"unit": "%",
"default": 100,
"min_value": "0",
"max_value_warning": "100",
"type": "float",
"visible": false,
"enabled": "wireframe_enabled"
@ -1854,6 +1995,8 @@
"unit": "sec",
"type": "float",
"default": 0,
"min_value": "0",
"max_value_warning": "1",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1863,6 +2006,8 @@
"unit": "sec",
"type": "float",
"default": 0,
"min_value": "0",
"max_value_warning": "1",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1872,6 +2017,8 @@
"unit": "sec",
"type": "float",
"default": 0.1,
"min_value": "0",
"max_value_warning": "0.5",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1881,6 +2028,8 @@
"type": "float",
"unit": "mm",
"default": 0.3,
"min_value": "0",
"max_value_warning": "5.0",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1890,6 +2039,8 @@
"type": "float",
"unit": "mm",
"default": 0.6,
"min_value": "0",
"max_value_warning": "2.0",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1899,6 +2050,8 @@
"type": "float",
"unit": "mm",
"default": 0.5,
"min_value": "0",
"max_value_warning": "wireframe_height",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1908,6 +2061,8 @@
"type": "float",
"unit": "mm",
"default": 0.6,
"min_value": "0",
"max_value_warning": "wireframe_height",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1929,9 +2084,9 @@
"description": "Percentage of a diagonally downward line which is covered by a horizontal line piece. This can prevent sagging of the top most point of upward lines. Only applies to Wire Printing.",
"type": "float",
"unit": "%",
"default": 20,
"min_value": "0",
"max_value": "100",
"default": 20,
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1941,6 +2096,8 @@
"type": "float",
"unit": "mm",
"default": 2,
"min_value_warning": "0",
"max_value_warning": "wireframe_roof_inset",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1950,6 +2107,8 @@
"type": "float",
"unit": "mm",
"default": 0.8,
"min_value": "0",
"max_value_warning": "10",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1959,6 +2118,8 @@
"type": "float",
"unit": "sec",
"default": 0.2,
"min_value": "0",
"max_value_warning": "2.0",
"visible": false,
"enabled": "wireframe_enabled"
},
@ -1968,6 +2129,8 @@
"type": "float",
"unit": "mm",
"default": 1,
"min_value_warning": "0",
"max_value_warning": "10.0",
"visible": false,
"enabled": "wireframe_enabled"
}

View file

@ -0,0 +1,38 @@
{
"id": "m180",
"version": 1,
"name": "Malyan M180",
"manufacturer": "Other",
"icon": "icon_ultimaker.png",
"platform": "",
"inherits": "fdmprinter.json",
"machine_settings": {
"machine_width": { "default": 230 },
"machine_height": { "default": 165 },
"machine_depth": { "default": 145 },
"machine_center_is_zero": { "default": true },
"machine_nozzle_size": { "default": 0.4, "min_value": "0.001" },
"machine_head_with_fans_polygon": {
"default": [
[ -75, 35 ],
[ -75, -18 ],
[ 18, -18 ],
[ 18, 35 ]
]
},
"gantry_height": { "default": 55 },
"machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": { "default": "M136\nM73 P0\nM103\nG21\nG90\nM320\n;(**** begin homing ****)\nG162 X Y F4000\nG161 Z F3500\nG92 Z-5\nG1 Z0.0\nG161 Z F100\nM132 X Y Z A B\n;(**** end homing ****)\nG92 X147 Y66 Z5\nG1 X105 Y-60 Z10 F4000.0\nG130 X127 Y127 A127 B127\nG0 X105 Y-60\nG1 Z0.3 F300\nG92 E0\nG1 X100 E10 F300\nG92 E0\nG1 Z0.0 F300\nM320" },
"machine_end_gcode": { "default": "G92 Z0\nG1 Z10 F400\nM18\nM109 S0 T0\nM104 S0 T0\nM73 P100 (end build progress)\nG162 X Y F3000\nM18" }
},
"overrides": {
"material_bed_temperature": { "visible": "True" },
"material_diameter": {
"default": 1.75,
"min_value_warning": "1.5",
"max_value_warning": "2.0"
}
}
}

View file

@ -0,0 +1,19 @@
{
"id": "ultimaker2_extended_plus_base",
"version": 1,
"name": "Ultimaker 2 Extended+",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"platform": "ultimaker2_platform.obj",
"platform_texture": "ultimaker2plus_backplate.png",
"visible": false,
"inherits": "ultimaker2plus.json",
"machine_settings": {
"machine_width": { "default": 230 },
"machine_depth": { "default": 225 },
"machine_height": { "default": 310 },
"machine_show_variants": { "default": true },
"gantry_height": { "default": 50 }
}
}

View file

@ -0,0 +1,14 @@
{
"id": "ultimaker2_extended_plus",
"version": 1,
"name": "Ultimaker 2 Extended+",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"platform": "ultimaker2_platform.obj",
"platform_texture": "ultimaker2plus_backplate.png",
"inherits": "ultimaker2_extended_plus.json",
"variant": "0.25mm Nozzle",
"machine_settings": {
"machine_nozzle_size": { "default": 0.25 }
}
}

View file

@ -0,0 +1,14 @@
{
"id": "ultimaker2_extended_plus",
"version": 1,
"name": "Ultimaker 2 Extended+",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"platform": "ultimaker2_platform.obj",
"platform_texture": "ultimaker2plus_backplate.png",
"inherits": "ultimaker2_extended_plus.json",
"variant": "0.40mm Nozzle",
"machine_settings": {
"machine_nozzle_size": { "default": 0.40 }
}
}

View file

@ -0,0 +1,14 @@
{
"id": "ultimaker2_extended_plus",
"version": 1,
"name": "Ultimaker 2 Extended+",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"platform": "ultimaker2_platform.obj",
"platform_texture": "ultimaker2plus_backplate.png",
"inherits": "ultimaker2_extended_plus.json",
"variant": "0.60mm Nozzle",
"machine_settings": {
"machine_nozzle_size": { "default": 0.60 }
}
}

View file

@ -0,0 +1,14 @@
{
"id": "ultimaker2_extended_plus",
"version": 1,
"name": "Ultimaker 2 Extended+",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"platform": "ultimaker2_platform.obj",
"platform_texture": "ultimaker2plus_backplate.png",
"inherits": "ultimaker2_extended_plus.json",
"variant": "0.80mm Nozzle",
"machine_settings": {
"machine_nozzle_size": { "default": 0.80 }
}
}

View file

@ -0,0 +1,46 @@
{
"id": "ultimaker2plus_base",
"version": 1,
"name": "Ultimaker 2+",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"platform": "ultimaker2_platform.obj",
"platform_texture": "ultimaker2plus_backplate.png",
"visible": false,
"inherits": "ultimaker2.json",
"machine_settings": {
"machine_width": { "default": 230 },
"machine_depth": { "default": 225 },
"machine_height": { "default": 200 },
"machine_show_variants": { "default": true },
"gantry_height": { "default": 50 }
},
"overrides": {
"shell_thickness": { "default": 1.2 },
"top_bottom_thickness": { "inherit_function": "(parent_value / 3) * 2" },
"travel_compensate_overlapping_walls_enabled": { "default": true },
"skin_alternate_rotation": { "default": true },
"skin_outline_count": { "default": 2 },
"infill_sparse_density": { "default": 10 },
"infill_overlap": { "default": 14, "inherit_function": "14 if infill_sparse_density < 95 else 0" },
"infill_wipe_dist": { "default": 0.35, "inherit_function": "wall_line_width_0" },
"retraction_amount": { "default": 6 },
"retraction_min_travel": { "default": 4.5 },
"retraction_count_max": { "default": 6 },
"retraction_extrusion_window": { "default": 6.0 },
"speed_print": { "default": 50 },
"speed_wall": { "inherit_function": "parent_value / 50 * 30" },
"speed_wall_x": { "inherit_function": "speed_print / 50 * 40" },
"speed_topbottom": { "inherit_function": "parent_value / 50 * 20" },
"speed_layer_0": { "default": 20 },
"skirt_speed": { "default": 20 },
"travel_avoid_distance": { "default": 1.0 },
"coasting_enable": { "default": true },
"coasting_volume": { "default": 0.4 },
"support_angle": { "default": 50 },
"adhesion_type": { "default": "brim" }
}
}

View file

@ -0,0 +1,31 @@
{
"id": "ultimaker2plus",
"version": 1,
"name": "Ultimaker 2+",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"platform": "ultimaker2_platform.obj",
"platform_texture": "ultimaker2plus_backplate.png",
"inherits": "ultimaker2plus.json",
"variant": "0.25mm Nozzle",
"machine_settings": {
"machine_nozzle_size": { "default": 0.25 }
},
"overrides": {
"layer_height": { "default": 0.06 },
"layer_height_0": { "default": 0.15 },
"infill_sparse_density": { "default": 12 },
"speed_print": { "default": 30 },
"speed_wall": { "inherit_function": "parent_value / 30 * 20" },
"speed_wall_x": { "inherit_function": "speed_print / 30 * 25" },
"speed_topbottom": { "inherit_function": "parent_value / 30 * 20" },
"coasting_volume": { "default": 0.1 },
"coasting_min_volume": { "default": 0.17 }
}
}

View file

@ -0,0 +1,22 @@
{
"id": "ultimaker2plus",
"version": 1,
"name": "Ultimaker 2+",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"platform": "ultimaker2_platform.obj",
"platform_texture": "ultimaker2plus_backplate.png",
"inherits": "ultimaker2plus.json",
"variant": "0.40mm Nozzle",
"machine_settings": {
"machine_nozzle_size": { "default": 0.40 }
},
"overrides": {
"wall_line_width_0": { "inherit_function": "parent_value * 0.875" },
"skin_line_width": { "inherit_function": "parent_value * 0.875" }
}
}

View file

@ -0,0 +1,32 @@
{
"id": "ultimaker2plus",
"version": 1,
"name": "Ultimaker 2+",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"platform": "ultimaker2_platform.obj",
"platform_texture": "ultimaker2plus_backplate.png",
"inherits": "ultimaker2plus.json",
"variant": "0.60mm Nozzle",
"machine_settings": {
"machine_nozzle_size": { "default": 0.60 }
},
"overrides": {
"layer_height": { "default": 0.15 },
"layer_height_0": { "default": 0.4 },
"shell_thickness": { "default": 1.8 },
"infill_sparse_density": { "default": 15 },
"speed_print": { "default": 55 },
"speed_wall": { "inherit_function": "parent_value / 55 * 25" },
"speed_wall_x": { "inherit_function": "speed_print / 55 * 40" },
"speed_topbottom": { "inherit_function": "parent_value / 55 * 20" },
"coasting_volume": { "default": 1.36 }
}
}

View file

@ -0,0 +1,33 @@
{
"id": "ultimaker2plus",
"version": 1,
"name": "Ultimaker 2+",
"manufacturer": "Ultimaker",
"author": "Ultimaker",
"platform": "ultimaker2_platform.obj",
"platform_texture": "ultimaker2plus_backplate.png",
"inherits": "ultimaker2plus.json",
"variant": "0.80mm Nozzle",
"machine_settings": {
"machine_nozzle_size": { "default": 0.80 }
},
"overrides": {
"layer_height": { "default": 0.2 },
"layer_height_0": { "default": 0.5 },
"shell_thickness": { "default": 2.4 },
"top_bottom_thickness": { "inherit_function": "parent_value / 2" },
"infill_sparse_density": { "default": 16 },
"speed_print": { "default": 40 },
"speed_wall": { "inherit_function": "parent_value / 40 * 20" },
"speed_wall_x": { "inherit_function": "speed_print / 40 * 30" },
"speed_topbottom": { "inherit_function": "parent_value / 40 * 20" },
"coasting_volume": { "default": 3.22 }
}
}

View file

@ -54,7 +54,7 @@ Item
Action
{
id: undoAction;
text: catalog.i18nc("@action:inmenu","&Undo");
text: catalog.i18nc("@action:inmenu menubar:edit","&Undo");
iconName: "edit-undo";
shortcut: StandardKey.Undo;
}
@ -62,7 +62,7 @@ Item
Action
{
id: redoAction;
text: catalog.i18nc("@action:inmenu","&Redo");
text: catalog.i18nc("@action:inmenu menubar:edit","&Redo");
iconName: "edit-redo";
shortcut: StandardKey.Redo;
}
@ -70,7 +70,7 @@ Item
Action
{
id: quitAction;
text: catalog.i18nc("@action:inmenu","&Quit");
text: catalog.i18nc("@action:inmenu menubar:file","&Quit");
iconName: "application-exit";
shortcut: StandardKey.Quit;
}
@ -78,55 +78,56 @@ Item
Action
{
id: preferencesAction;
text: catalog.i18nc("@action:inmenu","&Preferences...");
text: catalog.i18nc("@action:inmenu menubar:settings","&Preferences...");
iconName: "configure";
}
Action
{
id: addMachineAction;
text: catalog.i18nc("@action:inmenu","&Add Printer...");
text: catalog.i18nc("@action:inmenu menubar:printer","&Add Printer...");
}
Action
{
id: settingsAction;
text: catalog.i18nc("@action:inmenu","Manage Pr&inters...");
text: catalog.i18nc("@action:inmenu menubar:printer","Manage Pr&inters...");
iconName: "configure";
}
Action
{
id: manageProfilesAction;
text: catalog.i18nc("@action:inmenu","Manage Profiles...");
text: catalog.i18nc("@action:inmenu menubar:profile","Manage Profiles...");
iconName: "configure";
}
Action
{
id: documentationAction;
text: catalog.i18nc("@action:inmenu","Show Online &Documentation");
text: catalog.i18nc("@action:inmenu menubar:help","Show Online &Documentation");
iconName: "help-contents";
shortcut: StandardKey.Help;
}
Action {
id: reportBugAction;
text: catalog.i18nc("@action:inmenu","Report a &Bug");
text: catalog.i18nc("@action:inmenu menubar:help","Report a &Bug");
iconName: "tools-report-bug";
}
Action
{
id: aboutAction;
text: catalog.i18nc("@action:inmenu","&About...");
text: catalog.i18nc("@action:inmenu menubar:help","&About...");
iconName: "help-about";
}
Action
{
id: deleteSelectionAction;
text: catalog.i18nc("@action:inmenu","Delete &Selection");
text: catalog.i18nc("@action:inmenu menubar:edit","Delete &Selection");
enabled: UM.Controller.toolsEnabled;
iconName: "edit-delete";
shortcut: StandardKey.Delete;
}
@ -135,6 +136,7 @@ Item
{
id: deleteObjectAction;
text: catalog.i18nc("@action:inmenu","Delete Object");
enabled: UM.Controller.toolsEnabled;
iconName: "edit-delete";
}
@ -147,7 +149,7 @@ Item
Action
{
id: groupObjectsAction
text: catalog.i18nc("@action:inmenu","&Group Objects");
text: catalog.i18nc("@action:inmenu menubar:edit","&Group Objects");
enabled: UM.Scene.numObjectsSelected > 1 ? true: false
iconName: "object-group"
}
@ -155,7 +157,7 @@ Item
Action
{
id: unGroupObjectsAction
text: catalog.i18nc("@action:inmenu","Ungroup Objects");
text: catalog.i18nc("@action:inmenu menubar:edit","Ungroup Objects");
enabled: UM.Scene.isGroupSelected
iconName: "object-ungroup"
}
@ -163,7 +165,7 @@ Item
Action
{
id: mergeObjectsAction
text: catalog.i18nc("@action:inmenu","&Merge Objects");
text: catalog.i18nc("@action:inmenu menubar:edit","&Merge Objects");
enabled: UM.Scene.numObjectsSelected > 1 ? true: false
iconName: "merge";
}
@ -178,7 +180,8 @@ Item
Action
{
id: deleteAllAction;
text: catalog.i18nc("@action:inmenu","&Clear Build Platform");
text: catalog.i18nc("@action:inmenu menubar:edit","&Clear Build Platform");
enabled: UM.Controller.toolsEnabled;
iconName: "edit-delete";
shortcut: "Ctrl+D";
}
@ -186,26 +189,26 @@ Item
Action
{
id: reloadAllAction;
text: catalog.i18nc("@action:inmenu","Re&load All Objects");
text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Objects");
iconName: "document-revert";
}
Action
{
id: resetAllTranslationAction;
text: catalog.i18nc("@action:inmenu","Reset All Object Positions");
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Object Positions");
}
Action
{
id: resetAllAction;
text: catalog.i18nc("@action:inmenu","Reset All Object &Transformations");
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Object &Transformations");
}
Action
{
id: openAction;
text: catalog.i18nc("@action:inmenu","&Open File...");
text: catalog.i18nc("@action:inmenu menubar:file","&Open File...");
iconName: "document-open";
shortcut: StandardKey.Open;
}
@ -213,7 +216,7 @@ Item
Action
{
id: showEngineLogAction;
text: catalog.i18nc("@action:inmenu","Show Engine &Log...");
text: catalog.i18nc("@action:inmenu menubar:help","Show Engine &Log...");
iconName: "view-list-text";
shortcut: StandardKey.WhatsThis;
}

View file

@ -14,7 +14,6 @@ UM.MainWindow
id: base
//: Cura application window title
title: catalog.i18nc("@title:window","Cura");
viewportRect: Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0)
Item
@ -23,6 +22,14 @@ UM.MainWindow
anchors.fill: parent;
UM.I18nCatalog{id: catalog; name:"cura"}
signal hasMesh(string name) //this signal sends the filebase name so it can be used for the JobSpecs.qml
function getMeshName(path){
//takes the path the complete path of the meshname and returns only the filebase
var fileName = path.slice(path.lastIndexOf("/") + 1)
var fileBase = fileName.slice(0, fileName.lastIndexOf("."))
return fileBase
}
//DeleteSelection on the keypress backspace event
Keys.onPressed: {
if (event.key == Qt.Key_Backspace)
@ -34,7 +41,6 @@ UM.MainWindow
}
}
UM.ApplicationMenu
{
id: menu
@ -44,7 +50,7 @@ UM.MainWindow
{
id: fileMenu
//: File menu
title: catalog.i18nc("@title:menu","&File");
title: catalog.i18nc("@title:menu menubar:toplevel","&File");
MenuItem {
action: actions.open;
@ -53,7 +59,7 @@ UM.MainWindow
Menu
{
id: recentFilesMenu;
title: catalog.i18nc("@title:menu", "Open &Recent")
title: catalog.i18nc("@title:menu menubar:file", "Open &Recent")
iconName: "document-open-recent";
enabled: Printer.recentFiles.length > 0;
@ -70,7 +76,8 @@ UM.MainWindow
}
onTriggered: {
UM.MeshFileHandler.readLocalFile(modelData);
openDialog.sendMeshName(modelData.toString())
var meshName = backgroundItem.getMeshName(modelData.toString())
backgroundItem.hasMesh(meshName)
}
}
onObjectAdded: recentFilesMenu.insertItem(index, object)
@ -82,7 +89,7 @@ UM.MainWindow
MenuItem
{
text: catalog.i18nc("@action:inmenu", "&Save Selection to File");
text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File");
enabled: UM.Selection.hasSelection;
iconName: "document-save-as";
onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", Printer.jobName);
@ -90,7 +97,7 @@ UM.MainWindow
Menu
{
id: saveAllMenu
title: catalog.i18nc("@title:menu","Save &All")
title: catalog.i18nc("@title:menu menubar:file","Save &All")
iconName: "document-save-all";
enabled: devicesModel.rowCount() > 0 && UM.Backend.progress > 0.99;
@ -118,7 +125,7 @@ UM.MainWindow
Menu
{
//: Edit menu
title: catalog.i18nc("@title:menu","&Edit");
title: catalog.i18nc("@title:menu menubar:toplevel","&Edit");
MenuItem { action: actions.undo; }
MenuItem { action: actions.redo; }
@ -135,7 +142,7 @@ UM.MainWindow
Menu
{
title: catalog.i18nc("@title:menu","&View");
title: catalog.i18nc("@title:menu menubar:toplevel","&View");
id: top_view_menu
Instantiator
{
@ -157,7 +164,7 @@ UM.MainWindow
{
id: machineMenu;
//: Machine menu
title: catalog.i18nc("@title:menu","&Machine");
title: catalog.i18nc("@title:menu menubar:toplevel","&Printer");
Instantiator
{
@ -203,7 +210,7 @@ UM.MainWindow
Menu
{
id: profileMenu
title: catalog.i18nc("@title:menu", "&Profile")
title: catalog.i18nc("@title:menu menubar:toplevel", "P&rofile")
Instantiator
{
@ -230,7 +237,7 @@ UM.MainWindow
{
id: extension_menu
//: Extensions menu
title: catalog.i18nc("@title:menu","E&xtensions");
title: catalog.i18nc("@title:menu menubar:toplevel","E&xtensions");
Instantiator
{
@ -263,7 +270,7 @@ UM.MainWindow
Menu
{
//: Settings menu
title: catalog.i18nc("@title:menu","&Settings");
title: catalog.i18nc("@title:menu menubar:toplevel","&Settings");
MenuItem { action: actions.preferences; }
}
@ -271,7 +278,7 @@ UM.MainWindow
Menu
{
//: Help menu
title: catalog.i18nc("@title:menu","&Help");
title: catalog.i18nc("@title:menu menubar:toplevel","&Help");
MenuItem { action: actions.showEngineLog; }
MenuItem { action: actions.documentation; }
@ -303,7 +310,8 @@ UM.MainWindow
UM.MeshFileHandler.readLocalFile(drop.urls[i]);
if (i == drop.urls.length - 1)
{
openDialog.sendMeshName(drop.urls[i].toString())
var meshName = backgroundItem.getMeshName(drop.urls[i].toString())
backgroundItem.hasMesh(meshName)
}
}
}
@ -312,6 +320,7 @@ UM.MainWindow
JobSpecs
{
id: jobSpecs
anchors
{
bottom: parent.bottom;
@ -327,7 +336,8 @@ UM.MainWindow
{
horizontalCenter: parent.horizontalCenter
horizontalCenterOffset: -(UM.Theme.sizes.sidebar.width/ 2)
verticalCenter: parent.verticalCenter;
top: parent.verticalCenter;
bottom: parent.bottom;
}
}
@ -517,10 +527,7 @@ UM.MainWindow
deleteSelection.onTriggered:
{
if(objectContextMenu.objectId != 0)
{
Printer.deleteObject(objectContextMenu.objectId);
}
Printer.deleteSelection()
}
deleteObject.onTriggered:
@ -638,14 +645,6 @@ UM.MainWindow
modality: UM.Application.platform == "linux" ? Qt.NonModal : Qt.WindowModal;
//TODO: Support multiple file selection, workaround bug in KDE file dialog
//selectMultiple: true
signal hasMesh(string name)
function sendMeshName(path){
var fileName = path.slice(path.lastIndexOf("/") + 1)
var fileBase = fileName.slice(0, fileName.lastIndexOf("."))
openDialog.hasMesh(fileBase)
}
nameFilters: UM.MeshFileHandler.supportedReadFileTypes;
onAccepted:
@ -656,7 +655,8 @@ UM.MainWindow
folder = f;
UM.MeshFileHandler.readLocalFile(fileUrl)
openDialog.sendMeshName(fileUrl.toString())
var meshName = backgroundItem.getMeshName(fileUrl.toString())
backgroundItem.hasMesh(meshName)
}
}

View file

@ -11,7 +11,7 @@ import UM 1.1 as UM
UM.PreferencesPage
{
//: General configuration page title
title: catalog.i18nc("@title:tab","General");
title: catalog.i18nc("@title:tab","General")
function setDefaultLanguage(languageCode)
{
@ -38,15 +38,17 @@ UM.PreferencesPage
setDefaultLanguage(defaultLanguage)
}
GridLayout
ColumnLayout
{
columns: 2;
//: Language selection label
UM.I18nCatalog{id: catalog; name:"cura"}
RowLayout
{
Label
{
id: languageLabel
text: catalog.i18nc("@label","Language")
text: catalog.i18nc("@label","Language:")
}
ComboBox
@ -83,10 +85,6 @@ UM.PreferencesPage
}
onActivated: UM.Preferences.setValue("general/language", model.get(index).code)
anchors.left: languageLabel.right
anchors.top: languageLabel.top
anchors.leftMargin: 20
Component.onCompleted:
{
// Because ListModel is stupid and does not allow using qsTr() for values.
@ -101,11 +99,11 @@ UM.PreferencesPage
currentIndex -= 1;
}
}
}
Label
{
id: languageCaption;
Layout.columnSpan: 2
id: languageCaption
//: Language change warning
text: catalog.i18nc("@label", "You will need to restart the application for language changes to have effect.")
@ -113,103 +111,46 @@ UM.PreferencesPage
font.italic: true
}
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip", "Should objects on the platform be moved so that they no longer intersect.")
CheckBox
{
id: pushFreeCheckbox
text: catalog.i18nc("@option:check", "Ensure objects are kept apart")
checked: boolCheck(UM.Preferences.getValue("physics/automatic_push_free"))
onCheckedChanged: UM.Preferences.setValue("physics/automatic_push_free", checked)
}
Button
{
id: pushFreeText //is a button so the user doesn't have te click inconvenientley precise to enable or disable the checkbox
}
//: Display Overhang preference checkbox
text: catalog.i18nc("@option:check", "Ensure objects are kept apart");
onClicked: pushFreeCheckbox.checked = !pushFreeCheckbox.checked
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","Should opened files be scaled to the build volume if they are too large?")
//: Display Overhang preference tooltip
tooltip: catalog.i18nc("@info:tooltip", "Should objects on the platform be moved so that they no longer intersect.")
CheckBox
{
id: scaleToFitCheckbox
text: catalog.i18nc("@option:check","Scale large files")
checked: boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
onCheckedChanged: UM.Preferences.setValue("mesh/scale_to_fit", checked)
}
}
style: ButtonStyle
{
background: Rectangle
{
border.width: 0
color: "transparent"
}
label: Text
{
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignLeft
text: control.text
}
}
}
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","Should anonymous data about your print be sent to Ultimaker? Note, no models, IP addresses or other personally identifiable information is sent or stored.")
CheckBox
{
id: sendDataCheckbox
text: catalog.i18nc("@option:check","Send (anonymous) print information")
checked: boolCheck(UM.Preferences.getValue("info/send_slice_info"))
onCheckedChanged: UM.Preferences.setValue("info/send_slice_info", checked)
}
Button
{
id: sendDataText //is a button so the user doesn't have te click inconvenientley precise to enable or disable the checkbox
//: Display Overhang preference checkbox
text: catalog.i18nc("@option:check","Send (Anonymous) Print Information");
onClicked: sendDataCheckbox.checked = !sendDataCheckbox.checked
//: Display Overhang preference tooltip
tooltip: catalog.i18nc("@info:tooltip","Should anonymous data about your print be sent to Ultimaker? Note, no models, IP addresses or other personally identifiable information is sent or stored.")
style: ButtonStyle
{
background: Rectangle
{
border.width: 0
color: "transparent"
}
label: Text
{
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignLeft
text: control.text
}
}
}
CheckBox
{
id: scaleToFitCheckbox
checked: boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
onCheckedChanged: UM.Preferences.setValue("mesh/scale_to_fit", checked)
}
Button
{
id: scaleToFitText //is a button so the user doesn't have te click inconvenientley precise to enable or disable the checkbox
//: Display Overhang preference checkbox
text: catalog.i18nc("@option:check","Scale Too Large Files");
onClicked: scaleToFitCheckbox.checked = !scaleToFitCheckbox.checked
//: Display Overhang preference tooltip
tooltip: catalog.i18nc("@info:tooltip","Should opened files be scaled to the build volume when they are too large?")
style: ButtonStyle
{
background: Rectangle
{
border.width: 0
color: "transparent"
}
label: Text
{
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignLeft
text: control.text
}
}
}
Item { Layout.fillHeight: true; Layout.columnSpan: 2 }
}
}

View file

@ -53,33 +53,88 @@ Rectangle {
}
Connections {
target: openDialog
target: backgroundItem
onHasMesh: {
if(base.fileBaseName == ''){
base.fileBaseName = name
base.createFileName()
}
}
}
onActivityChanged: {
if (activity == false){
base.fileBaseName = ''
if (activity == true && base.fileBaseName == ''){
//this only runs when you open a file from the terminal (or something that works the same way; for example when you drag a file on the icon in MacOS or use 'open with' on Windows)
base.fileBaseName = Printer.jobName //it gets the fileBaseName from CuraApplication.py because this saves the filebase when the file is opened using the terminal (or something alike)
base.createFileName()
}
if (activity == true && base.fileBaseName != ''){
//this runs in all other cases where there is a mesh on the buildplate (activity == true). It uses the fileBaseName from the hasMesh signal
base.createFileName()
}
if (activity == false){
//When there is no mesh in the buildplate; the printJobTextField is set to an empty string so it doesn't set an empty string as a jobName (which is later used for saving the file)
printJobTextfield.text = ''
}
}
TextField {
id: printJobTextfield
Rectangle
{
id: jobNameRow
anchors.top: parent.top
anchors.right: parent.right
height: UM.Theme.sizes.jobspecs_line.height
visible: base.activity
Item
{
width: parent.width
height: parent.height
Button
{
id: printJobPencilIcon
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: UM.Theme.sizes.save_button_specs_icons.width
height: UM.Theme.sizes.save_button_specs_icons.height
onClicked:
{
printJobTextfield.selectAll()
printJobTextfield.focus = true
}
style: ButtonStyle
{
background: Rectangle
{
color: "transparent"
UM.RecolorImage
{
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: control.hovered ? UM.Theme.colors.setting_control_button_hover : UM.Theme.colors.text
source: UM.Theme.icons.pencil;
}
}
}
}
TextField
{
id: printJobTextfield
anchors.right: printJobPencilIcon.left
anchors.rightMargin: UM.Theme.sizes.default_margin.width/2
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
onTextChanged: {
if(text != ''){
//this prevent that is sets an empty string as jobname
Printer.setJobName(text)
}
}
onEditingFinished: {
if (printJobTextfield.text != ''){
printJobTextfield.focus = false
@ -90,17 +145,19 @@ Rectangle {
}
style: TextFieldStyle{
textColor: UM.Theme.colors.setting_control_text;
font: UM.Theme.fonts.default;
font: UM.Theme.fonts.default_bold;
background: Rectangle {
opacity: 0
border.width: 0
}
}
}
}
}
Label{
id: boundingSpec
anchors.top: printJobTextfield.bottom
anchors.top: jobNameRow.bottom
anchors.right: parent.right
height: UM.Theme.sizes.jobspecs_line.height
verticalAlignment: Text.AlignVCenter
@ -138,7 +195,7 @@ Rectangle {
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)
text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short)
}
UM.RecolorImage {
id: lengthIcon
@ -158,7 +215,7 @@ Rectangle {
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)
text: base.printMaterialAmount <= 0 ? catalog.i18nc("@label", "0.0 m") : catalog.i18nc("@label", "%1 m").arg(base.printMaterialAmount)
}
}
}

View file

@ -0,0 +1,64 @@
// 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.Window 2.1
import UM 1.1 as UM
UM.Dialog
{
id: base
//: About dialog title
title: catalog.i18nc("@title:window","Load profile")
width: 400
height: childrenRect.height
Label
{
id: body
//: About dialog application description
text: catalog.i18nc("@label","Selecting this profile overwrites some of your customised settings. Do you want to merge the new settings into your current profile or do you want to load a clean copy of the profile?")
wrapMode: Text.WordWrap
width: parent.width
anchors.top: parent.top
anchors.margins: UM.Theme.sizes.default_margin.height
UM.I18nCatalog { id: catalog; name: "cura"; }
}
Label
{
id: show_details
//: About dialog application author note
text: catalog.i18nc("@label","Show details.")
wrapMode: Text.WordWrap
anchors.top: body.bottom
anchors.topMargin: UM.Theme.sizes.default_margin.height
}
rightButtons: Row
{
spacing: UM.Theme.sizes.default_margin.width
Button
{
text: catalog.i18nc("@action:button","Merge settings");
}
Button
{
text: catalog.i18nc("@action:button","Reset profile");
}
Button
{
text: catalog.i18nc("@action:button","Cancel");
onClicked: base.visible = false;
}
}
}

View file

@ -14,62 +14,9 @@ Item{
property int totalHeightProfileSetup: childrenRect.height
property Action manageProfilesAction
Rectangle {
id: variantRow
anchors.top: base.top
width: base.width
height: UM.Theme.sizes.sidebar_setup.height
//visible: UM.MachineManager.hasVariants;
visible: true
Label{
id: variantLabel
text: catalog.i18nc("@label","Variant:");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
anchors.verticalCenter: parent.verticalCenter
width: parent.width/100*45
font: UM.Theme.fonts.default;
}
ToolButton {
id: variantSelection
text: UM.MachineManager.activeMachineVariant
width: parent.width/100*55
height: UM.Theme.sizes.setting_control.height
tooltip: UM.MachineManager.activeMachineInstance;
anchors.right: parent.right
anchors.rightMargin: UM.Theme.sizes.default_margin.width
anchors.verticalCenter: parent.verticalCenter
style: UM.Theme.styles.sidebar_header_button
menu: Menu
{
id: variantsSelectionMenu
Instantiator
{
model: UM.MachineVariantsModel { id: variantsModel }
MenuItem
{
text: model.name;
checkable: true;
checked: model.active;
exclusiveGroup: variantSelectionMenuGroup;
onTriggered: UM.MachineManager.setActiveMachineVariant(variantsModel.getItem(index).name)
}
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
id: globalProfileRow
anchors.top: base.top
height: UM.Theme.sizes.sidebar_setup.height
width: base.width
@ -78,7 +25,7 @@ Item{
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
anchors.verticalCenter: parent.verticalCenter
text: catalog.i18nc("@label","Global Profile:");
text: catalog.i18nc("@label","Profile:");
width: parent.width/100*45
font: UM.Theme.fonts.default;
color: UM.Theme.colors.text;

View file

@ -74,7 +74,7 @@ Rectangle {
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 + 3
x: base.width - saveToButton.resizedWidth - UM.Theme.sizes.default_margin.width - UM.Theme.sizes.save_button_save_to_button.height + UM.Theme.sizes.save_button_save_to_button.width
tooltip: UM.OutputDeviceManager.activeDeviceDescription;
enabled: base.progress > 0.99 && base.activity == true
height: UM.Theme.sizes.save_button_save_to_button.height
@ -90,6 +90,7 @@ Rectangle {
background: Rectangle {
//opacity: control.enabled ? 1.0 : 0.5
//Behavior on opacity { NumberAnimation { duration: 50; } }
border.width: UM.Theme.sizes.default_lining.width
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
@ -130,6 +131,7 @@ Rectangle {
style: ButtonStyle {
background: Rectangle {
id: deviceSelectionIcon
border.width: UM.Theme.sizes.default_lining.width
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

View file

@ -120,6 +120,7 @@ Rectangle
style: ButtonStyle {
background: Rectangle {
border.width: UM.Theme.sizes.default_lining.width
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

View file

@ -17,7 +17,7 @@ Item
property int totalHeightHeader: childrenRect.height
Rectangle {
id: settingsModeRow
id: sidebarTabRow
width: base.width
height: 0
anchors.top: parent.top
@ -29,7 +29,7 @@ Item
text: catalog.i18nc("@label:listbox","Print Job");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width;
anchors.top: settingsModeRow.bottom
anchors.top: sidebarTabRow.bottom
anchors.topMargin: UM.Theme.sizes.default_margin.height
width: parent.width/100*45
font: UM.Theme.fonts.large;
@ -47,7 +47,7 @@ Item
Label{
id: machineSelectionLabel
//: Machine selection label
text: catalog.i18nc("@label:listbox","Machine:");
text: catalog.i18nc("@label:listbox","Printer:");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width
anchors.verticalCenter: parent.verticalCenter
@ -93,4 +93,57 @@ Item
}
}
}
Rectangle {
id: variantRow
anchors.top: machineSelectionRow.bottom
anchors.topMargin: UM.MachineManager.hasVariants ? UM.Theme.sizes.default_margin.height : 0
width: base.width
height: UM.MachineManager.hasVariants ? UM.Theme.sizes.sidebar_setup.height : 0
visible: UM.MachineManager.hasVariants
Label{
id: variantLabel
text: catalog.i18nc("@label","Nozzle:");
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;
}
ToolButton {
id: variantSelection
text: UM.MachineManager.activeMachineVariant
width: parent.width/100*55
height: UM.Theme.sizes.setting_control.height
tooltip: UM.MachineManager.activeMachineVariant;
anchors.right: parent.right
anchors.rightMargin: UM.Theme.sizes.default_margin.width
anchors.verticalCenter: parent.verticalCenter
style: UM.Theme.styles.sidebar_header_button
menu: Menu
{
id: variantsSelectionMenu
Instantiator
{
model: UM.MachineVariantsModel { id: variantsModel }
MenuItem
{
text: model.name;
checkable: true;
checked: model.active;
exclusiveGroup: variantSelectionMenuGroup;
onTriggered: UM.MachineManager.setActiveMachineVariant(variantsModel.getItem(index).name)
}
onObjectAdded: variantsSelectionMenu.insertItem(index, object)
onObjectRemoved: variantsSelectionMenu.removeItem(object)
}
ExclusiveGroup { id: variantSelectionMenuGroup; }
}
}
}
}

View file

@ -127,7 +127,7 @@ Item
anchors.top: parent.top
anchors.left: parent.left
width: base.width/100* 35 - UM.Theme.sizes.default_margin.width
height: childrenRect.height < UM.Theme.sizes.simple_mode_infill_caption.height ? UM.Theme.sizes.simple_mode_infill_caption.height : childrenRect.height
height: childrenRect.height
Label{
id: infillLabel
@ -140,17 +140,6 @@ Item
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width
}
/* Label{
id: infillCaption
width: infillCellLeft.width - UM.Theme.sizes.default_margin.width * 2
text: infillModel.count > 0 && infillListView.activeIndex != -1 ? infillModel.get(infillListView.activeIndex).text : ""
font: UM.Theme.fonts.caption
wrapMode: Text.Wrap
color: UM.Theme.colors.text_subtext
anchors.top: infillLabel.bottom
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width
} */
}
Flow {
@ -162,7 +151,6 @@ Item
anchors.left: infillCellLeft.right
anchors.top: infillCellLeft.top
anchors.topMargin: UM.Theme.sizes.default_margin.height
Repeater {
id: infillListView
@ -335,7 +323,7 @@ Item
property bool hovered_ex: false
anchors.top: brimCheckBox.bottom
anchors.topMargin: UM.Theme.sizes.default_lining.height
anchors.topMargin: UM.Theme.sizes.default_margin.height
anchors.left: parent.left
//: Setting enable support checkbox

View file

@ -33,7 +33,7 @@ Item {
checkable: true;
checked: model.active;
enabled: UM.Selection.hasSelection;
enabled: UM.Selection.hasSelection && UM.Controller.toolsEnabled;
style: UM.Theme.styles.tool_button;
@ -97,6 +97,7 @@ Item {
y: UM.Theme.sizes.default_margin.height;
source: UM.ActiveTool.valid ? UM.ActiveTool.activeToolPanel : "";
enabled: UM.Controller.toolsEnabled;
}
}
}

View file

@ -39,7 +39,7 @@ UM.PreferencesPage
checked: boolCheck(UM.Preferences.getValue("view/show_overhang"))
onClicked: UM.Preferences.setValue("view/show_overhang", checked)
text: catalog.i18nc("@option:check","Display Overhang");
text: catalog.i18nc("@option:check","Display overhang");
}
}

View file

@ -129,30 +129,31 @@ Item
section.property: "manufacturer"
section.delegate: Button {
text: section + " "
text: section
style: ButtonStyle {
background: Rectangle {
id: manufacturerBackground
opacity: 0.3
border.width: 0
color: control.hovered ? palette.light : "transparent";
color: "transparent";
height: UM.Theme.sizes.standard_list_lineheight.height
width: machineList.width
}
label: Text {
horizontalAlignment: Text.AlignLeft
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.standard_arrow.width + UM.Theme.sizes.default_margin.width
text: control.text
color: palette.windowText
font.bold: true
UM.RecolorImage {
id: downArrow
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.right
anchors.right: parent.left
anchors.rightMargin: UM.Theme.sizes.default_margin.width
width: UM.Theme.sizes.standard_arrow.width
height: UM.Theme.sizes.standard_arrow.height
sourceSize.width: width
sourceSize.height: width
color: palette.windowText
source: base,activeManufacturer == section ? UM.Theme.icons.arrow_bottom : UM.Theme.icons.arrow_right
source: base.activeManufacturer == section ? UM.Theme.icons.arrow_bottom : UM.Theme.icons.arrow_right
}
}
}
@ -184,18 +185,6 @@ Item
machineName.text = getMachineName()
}
Label
{
id: author
text: model.author;
anchors.left: machineButton.right
anchors.leftMargin: UM.Theme.sizes.standard_list_lineheight.height/2
anchors.verticalCenter: machineButton.verticalCenter
anchors.verticalCenterOffset: UM.Theme.sizes.standard_list_lineheight.height / 4
font: UM.Theme.fonts.caption;
color: palette.mid
}
states: State {
name: "collapsed";
when: base.activeManufacturer != model.manufacturer;

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" viewBox="0 -256 1792 1792" id="svg3001" version="1.1" inkscape:version="0.48.3.1 r9886" width="100%" height="100%" sodipodi:docname="pencil_font_awesome.svg">
<metadata id="metadata3011">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
</cc:Work>
</rdf:RDF>
</metadata>
<defs id="defs3009"/>
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="640" inkscape:window-height="480" id="namedview3007" showgrid="false" inkscape:zoom="0.13169643" inkscape:cx="896" inkscape:cy="896" inkscape:window-x="0" inkscape:window-y="25" inkscape:window-maximized="0" inkscape:current-layer="svg3001"/>
<g transform="matrix(1,0,0,-1,121.49153,1270.2373)" id="g3003">
<path d="M 363,0 454,91 219,326 128,235 V 128 H 256 V 0 h 107 z m 523,928 q 0,22 -22,22 -10,0 -17,-7 L 305,401 q -7,-7 -7,-17 0,-22 22,-22 10,0 17,7 l 542,542 q 7,7 7,17 z M 832,1120 1248,704 416,-128 H 0 v 416 z m 683,-96 q 0,-53 -37,-90 l -166,-166 -416,416 166,165 q 36,38 90,38 53,0 91,-38 l 235,-234 q 37,-39 37,-91 z" id="path3005" inkscape:connector-curvature="0" style="fill:currentColor"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -12,7 +12,7 @@ QtObject {
ButtonStyle {
background: Rectangle {
color: UM.Theme.colors.setting_control
border.width: 1
border.width: UM.Theme.sizes.default_lining.width
border.color: control.hovered ? UM.Theme.colors.setting_control_border_highlight : UM.Theme.colors.setting_control_border
UM.RecolorImage {
id: downArrow
@ -331,7 +331,8 @@ QtObject {
width: UM.Theme.sizes.section_icon_column.width
UM.RecolorImage {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
anchors.left: parent.left
anchors.leftMargin: UM.Theme.sizes.default_margin.width
color: UM.Theme.colors.setting_category_text
source: control.iconSource;
width: UM.Theme.sizes.section_icon.width;
@ -344,6 +345,7 @@ QtObject {
Label {
anchors {
left: icon.right;
leftMargin: UM.Theme.sizes.default_lining.width;
right: parent.right;
verticalCenter: parent.verticalCenter;
}
@ -493,7 +495,7 @@ QtObject {
radius: width/2;
color: UM.Theme.colors.slider_groove;
border.width: UM.Theme.sizes.default_lining;
border.width: UM.Theme.sizes.default_lining.width;
border.color: UM.Theme.colors.slider_groove_border;
Rectangle {
anchors {
@ -515,26 +517,24 @@ QtObject {
TextField {
id: valueLabel
property string maxValue: control.maximumValue + 1
placeholderText: control.value + 1
text: control.value + 1
horizontalAlignment: TextInput.AlignHCenter
onEditingFinished: {
if (valueLabel.text != ''){
control.value = valueLabel.text - 1
valueLabel.text = ''
valueLabel.focus = false
}
}
validator: IntValidator {bottom: 1; top: control.maximumValue + 1;}
visible: UM.LayerView.getLayerActivity && Printer.getPlatformActivity ? true : false
anchors.top: layerSliderControl.bottom
anchors.topMargin: UM.Theme.sizes.default_margin.width
anchors.topMargin: width/2 - UM.Theme.sizes.default_margin.width/2
anchors.horizontalCenter: layerSliderControl.horizontalCenter
rotation: 90
style: TextFieldStyle{
textColor: UM.Theme.colors.setting_control_text;
font: UM.Theme.fonts.default;
background: Rectangle {
implicitWidth: control.maxValue.length * valueLabel.font.pixelSize
implicitWidth: control.maxValue.length * valueLabel.font.pixelSize + UM.Theme.sizes.default_margin.width
implicitHeight: UM.Theme.sizes.slider_handle.height + UM.Theme.sizes.default_margin.width
border.width: UM.Theme.sizes.default_lining.width;
border.color: UM.Theme.colors.slider_groove_border;

View file

@ -9,10 +9,19 @@
"size": 1.15,
"family": "Proxima Nova Rg"
},
"default_bold": {
"size": 1.15,
"bold": true,
"family": "Proxima Nova Rg"
},
"small": {
"size": 1.0,
"family": "Proxima Nova Rg"
},
"very_small": {
"size": 0.75,
"family": "Proxima Nova Rg"
},
"caption": {
"size": 1.0,
"family": "Proxima Nova Rg"
@ -55,7 +64,7 @@
"text": [24, 41, 77, 255],
"text_inactive": [174, 174, 174, 255],
"text_hover": [35, 35, 35, 255],
"text_hover": [70, 84, 113, 255],
"text_pressed": [12, 169, 227, 255],
"text_white": [255, 255, 255, 255],
"text_subtext": [127, 127, 127, 255],
@ -100,24 +109,24 @@
"action_button_active_border": [12, 169, 227, 255],
"action_button_disabled": [245, 245, 245, 255],
"action_button_disabled_text": [127, 127, 127, 255],
"action_button_disabled_border": [127, 127, 127, 255],
"action_button_disabled_border": [245, 245, 245, 255],
"scrollbar_background": [255, 255, 255, 255],
"scrollbar_handle": [24, 41, 77, 255],
"scrollbar_handle_hover": [12, 159, 227, 255],
"scrollbar_handle_down": [12, 159, 227, 255],
"setting_category": [255, 255, 255, 255],
"setting_category": [245, 245, 245, 255],
"setting_category_disabled": [255, 255, 255, 255],
"setting_category_hover": [245, 245, 245, 255],
"setting_category_active": [255, 255, 255, 255],
"setting_category_active": [245, 245, 245, 255],
"setting_category_active_hover": [245, 245, 245, 255],
"setting_category_text": [24, 41, 77, 255],
"setting_category_border": [127, 127, 127, 255],
"setting_category_disabled_border": [127, 127, 127, 255],
"setting_category_border": [245, 245, 245, 255],
"setting_category_disabled_border": [245, 245, 245, 255],
"setting_category_hover_border": [12, 159, 227, 255],
"setting_category_active_border": [245, 245, 245, 255],
"setting_category_active_hover_border": [245, 245, 245, 255],
"setting_category_active_hover_border": [12, 159, 227, 255],
"setting_control": [255, 255, 255, 255],
"setting_control_selected": [24, 41, 77, 255],
@ -126,7 +135,8 @@
"setting_control_border_highlight": [12, 169, 227, 255],
"setting_control_text": [24, 41, 77, 255],
"setting_control_depth_line": [127, 127, 127, 255],
"setting_control_revert": [127, 127, 127, 255],
"setting_control_button": [127, 127, 127, 255],
"setting_control_button_hover": [70, 84, 113, 255],
"setting_unit": [127, 127, 127, 255],
"setting_validation_error": [255, 57, 14, 255],
"setting_validation_warning": [255, 186, 15, 255],
@ -227,7 +237,7 @@
"save_button_save_to_button": [0.3, 2.7],
"save_button_specs_icons": [1.4, 1.4],
"modal_window_minimum": [30.0, 30.0],
"modal_window_minimum": [60.0, 45],
"wizard_progress": [10.0, 0.0],
"message": [30.0, 5.0],