mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-12 16:28:59 +08:00
Merge branch 'master' of https://github.com/Ultimaker/Cura
This commit is contained in:
commit
6c30e1d107
@ -1 +1,48 @@
|
||||
|
||||
project(cura)
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository")
|
||||
|
||||
# Extract Strings
|
||||
add_custom_target(extract-messages ${URANIUM_SCRIPTS_DIR}/extract-messages ${CMAKE_SOURCE_DIR} cura)
|
||||
|
||||
# Build Translations
|
||||
find_package(Gettext)
|
||||
include(${URANIUM_SCRIPTS_DIR}/ECMPoQmTools.cmake)
|
||||
|
||||
if(GETTEXT_FOUND)
|
||||
# translations target will convert .po files into .mo and .qm as needed.
|
||||
# The files are checked for a _qt suffix and if it is found, converted to
|
||||
# qm, otherwise they are converted to .po.
|
||||
add_custom_target(translations)
|
||||
# copy-translations can be used to copy the built translation files from the
|
||||
# build directory to the source resources directory. This is mostly a convenience
|
||||
# during development, normally you want to simply use the install target to install
|
||||
# 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
|
||||
)
|
||||
foreach(lang ${languages})
|
||||
file(GLOB po_files resources/i18n/${lang}/*.po)
|
||||
foreach(file ${po_files})
|
||||
string(REGEX MATCH "qt\\.po$" match "${file}")
|
||||
if(match)
|
||||
ecm_process_po_files_as_qm(${lang} PO_FILES ${file})
|
||||
else()
|
||||
string(REGEX REPLACE ".*/(.*).po" "${lang}/\\1.mo" mofile ${file})
|
||||
add_custom_command(TARGET translations POST_BUILD COMMAND mkdir ARGS -p ${lang} COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ARGS ${file} -o ${mofile})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
file(GLOB qm_files ${CMAKE_BINARY_DIR}/${lang}/*.qm)
|
||||
file(GLOB mo_files ${CMAKE_BINARY_DIR}/${lang}/*.mo)
|
||||
foreach(file ${qm_files} ${mo_files})
|
||||
add_custom_command(TARGET copy-translations POST_BUILD COMMAND mkdir ARGS -p ${CMAKE_SOURCE_DIR}/resources/i18n/${lang}/LC_MESSAGES/ COMMAND cp ARGS ${file} ${CMAKE_SOURCE_DIR}/resources/i18n/${lang}/LC_MESSAGES/ COMMENT "Copying ${file}...")
|
||||
endforeach()
|
||||
endforeach()
|
||||
endif()
|
||||
|
6
cura.py
Executable file
6
cura.py
Executable file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from src.CuraApplication import CuraApplication
|
||||
|
||||
app = CuraApplication.getInstance()
|
||||
app.run()
|
@ -23,13 +23,13 @@ class CuraEngineBackend(Backend):
|
||||
super().__init__()
|
||||
|
||||
# Find out where the engine is located, and how it is called. This depends on how Cura is packaged and which OS we are running on.
|
||||
default_engine_location = '../PinkUnicornEngine/CuraEngine'
|
||||
if hasattr(sys, 'frozen'):
|
||||
default_engine_location = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), 'CuraEngine')
|
||||
if sys.platform == 'win32':
|
||||
default_engine_location += '.exe'
|
||||
default_engine_location = "../PinkUnicornEngine/CuraEngine"
|
||||
if hasattr(sys, "frozen"):
|
||||
default_engine_location = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "CuraEngine")
|
||||
if sys.platform == "win32":
|
||||
default_engine_location += ".exe"
|
||||
default_engine_location = os.path.abspath(default_engine_location)
|
||||
Preferences.getInstance().addPreference('backend/location', default_engine_location)
|
||||
Preferences.getInstance().addPreference("backend/location", default_engine_location)
|
||||
|
||||
self._scene = Application.getInstance().getController().getScene()
|
||||
self._scene.sceneChanged.connect(self._onSceneChanged)
|
||||
@ -59,7 +59,7 @@ class CuraEngineBackend(Backend):
|
||||
self.backendConnected.connect(self._onBackendConnected)
|
||||
|
||||
def getEngineCommand(self):
|
||||
return [Preferences.getInstance().getValue("backend/location"), '-j', Resources.getPath(Resources.SettingsLocation, 'fdmprinter.json'), '-vv', '--connect', "127.0.0.1:{0}".format(self._port)]
|
||||
return [Preferences.getInstance().getValue("backend/location"), "-j", Resources.getPath(Resources.SettingsLocation, "fdmprinter.json"), "-vv", "--connect", "127.0.0.1:{0}".format(self._port)]
|
||||
|
||||
## Emitted when we get a message containing print duration and material amount. This also implies the slicing has finished.
|
||||
# \param time The amount of time the print will take.
|
||||
@ -84,13 +84,13 @@ class CuraEngineBackend(Backend):
|
||||
# - report_progress: True if the slicing progress should be reported, False if not. Default is True.
|
||||
def slice(self, **kwargs):
|
||||
if self._slicing:
|
||||
if not kwargs.get('force_restart', True):
|
||||
if not kwargs.get("force_restart", True):
|
||||
return
|
||||
|
||||
self._slicing = False
|
||||
self._restart = True
|
||||
if self._process is not None:
|
||||
Logger.log('d', "Killing engine process")
|
||||
Logger.log("d", "Killing engine process")
|
||||
try:
|
||||
self._process.terminate()
|
||||
except: # terminating a process that is already terminating causes an exception, silently ignore this.
|
||||
@ -101,7 +101,7 @@ class CuraEngineBackend(Backend):
|
||||
objects = []
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
|
||||
if not getattr(node, '_outside_buildarea', False):
|
||||
if not getattr(node, "_outside_buildarea", False):
|
||||
objects.append(node)
|
||||
|
||||
if not objects:
|
||||
@ -110,22 +110,22 @@ class CuraEngineBackend(Backend):
|
||||
self._slicing = True
|
||||
self.slicingStarted.emit()
|
||||
|
||||
self._report_progress = kwargs.get('report_progress', True)
|
||||
self._report_progress = kwargs.get("report_progress", True)
|
||||
if self._report_progress:
|
||||
self.processingProgress.emit(0.0)
|
||||
|
||||
self._sendSettings(kwargs.get('settings', self._settings))
|
||||
self._sendSettings(kwargs.get("settings", self._settings))
|
||||
|
||||
self._scene.acquireLock()
|
||||
|
||||
# Set the gcode as an empty list. This will be filled with strings by GCodeLayer messages.
|
||||
# This is done so the gcode can be fragmented in memory and does not need a continues memory space.
|
||||
# (AKA. This prevents MemoryErrors)
|
||||
self._save_gcode = kwargs.get('save_gcode', True)
|
||||
self._save_gcode = kwargs.get("save_gcode", True)
|
||||
if self._save_gcode:
|
||||
setattr(self._scene, 'gcode_list', [])
|
||||
setattr(self._scene, "gcode_list", [])
|
||||
|
||||
self._save_polygons = kwargs.get('save_polygons', True)
|
||||
self._save_polygons = kwargs.get("save_polygons", True)
|
||||
|
||||
msg = Cura_pb2.ObjectList()
|
||||
|
||||
@ -194,7 +194,7 @@ class CuraEngineBackend(Backend):
|
||||
|
||||
def _onGCodePrefixMessage(self, message):
|
||||
if self._save_gcode:
|
||||
self._scene.gcode_list.insert(0, message.data.decode('utf-8', 'replace'))
|
||||
self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace"))
|
||||
|
||||
def _onObjectPrintTimeMessage(self, message):
|
||||
self.printDurationMessage.emit(message.time, message.material_amount)
|
||||
@ -221,7 +221,7 @@ class CuraEngineBackend(Backend):
|
||||
for setting in settings.getAllSettings(include_machine=True):
|
||||
s = msg.settings.add()
|
||||
s.name = setting.getKey()
|
||||
s.value = str(setting.getValue()).encode('utf-8')
|
||||
s.value = str(setting.getValue()).encode("utf-8")
|
||||
|
||||
self._socket.sendMessage(msg)
|
||||
|
||||
|
@ -10,4 +10,4 @@ class ProcessGCodeLayerJob(Job):
|
||||
self._message = message
|
||||
|
||||
def run(self):
|
||||
self._scene.gcode_list.append(self._message.data.decode('utf-8', 'replace'))
|
||||
self._scene.gcode_list.append(self._message.data.decode("utf-8", "replace"))
|
||||
|
@ -11,7 +11,7 @@ import struct
|
||||
|
||||
class ProcessSlicedObjectListJob(Job):
|
||||
def __init__(self, message):
|
||||
super().__init__(description = 'Processing sliced object')
|
||||
super().__init__()
|
||||
self._message = message
|
||||
self._scene = Application.getInstance().getController().getScene()
|
||||
|
||||
@ -27,7 +27,7 @@ class ProcessSlicedObjectListJob(Job):
|
||||
objectIdMap[id(node)] = node
|
||||
|
||||
settings = Application.getInstance().getActiveMachine()
|
||||
layerHeight = settings.getSettingValueByKey('layer_height')
|
||||
layerHeight = settings.getSettingValueByKey("layer_height")
|
||||
|
||||
for object in self._message.objects:
|
||||
try:
|
||||
@ -40,7 +40,7 @@ class ProcessSlicedObjectListJob(Job):
|
||||
layerData = LayerData.LayerData()
|
||||
for layer in object.layers:
|
||||
for polygon in layer.polygons:
|
||||
points = numpy.fromstring(polygon.points, dtype='i8') # Convert bytearray to numpy array
|
||||
points = numpy.fromstring(polygon.points, dtype="i8") # Convert bytearray to numpy array
|
||||
points = points.reshape((-1,2)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
|
||||
points = numpy.asarray(points, dtype=numpy.float32)
|
||||
points /= 1000
|
||||
@ -48,11 +48,11 @@ class ProcessSlicedObjectListJob(Job):
|
||||
|
||||
points[:,2] *= -1
|
||||
|
||||
if not settings.getSettingValueByKey('machine_center_is_zero'):
|
||||
center = [settings.getSettingValueByKey('machine_width') / 2, 0.0, -settings.getSettingValueByKey('machine_depth') / 2]
|
||||
if not settings.getSettingValueByKey("machine_center_is_zero"):
|
||||
center = [settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2]
|
||||
points -= numpy.array(center)
|
||||
|
||||
#points = numpy.pad(points, ((0,0), (0,1)), 'constant', constant_values=(0.0, 1.0))
|
||||
#points = numpy.pad(points, ((0,0), (0,1)), "constant", constant_values=(0.0, 1.0))
|
||||
#inverse = node.getWorldTransformation().getInverse().getData()
|
||||
#points = points.dot(inverse)
|
||||
#points = points[:,0:3]
|
||||
|
@ -2,15 +2,15 @@
|
||||
from . import CuraEngineBackend
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog('cura')
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
'type': 'backend',
|
||||
'plugin': {
|
||||
'name': "CuraEngine Backend",
|
||||
'author': 'Arjen Hiemstra',
|
||||
'description': catalog.i18nc('CuraEngine backend plugin description', 'Provides the link to the CuraEngine slicing backend')
|
||||
"type": "backend",
|
||||
"plugin": {
|
||||
"name": "CuraEngine Backend",
|
||||
"author": "Arjen Hiemstra",
|
||||
"description": catalog.i18nc("CuraEngine backend plugin description", "Provides the link to the CuraEngine slicing backend")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,12 @@ class GCodeWriter(MeshWriter):
|
||||
self._gcode = None
|
||||
|
||||
def write(self, file_name, storage_device, mesh_data):
|
||||
if 'gcode' in file_name:
|
||||
if "gcode" in file_name:
|
||||
scene = Application.getInstance().getController().getScene()
|
||||
gcode_list = getattr(scene, 'gcode_list')
|
||||
gcode_list = getattr(scene, "gcode_list")
|
||||
if gcode_list:
|
||||
f = storage_device.openFile(file_name, 'wt')
|
||||
Logger.log('d', "Writing GCode to file %s", file_name)
|
||||
f = storage_device.openFile(file_name, "wt")
|
||||
Logger.log("d", "Writing GCode to file %s", file_name)
|
||||
for gcode in gcode_list:
|
||||
f.write(gcode)
|
||||
storage_device.closeFile(f)
|
||||
|
@ -2,21 +2,21 @@ from . import GCodeWriter
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
|
||||
catalog = i18nCatalog('cura')
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
'type': 'mesh_writer',
|
||||
'plugin': {
|
||||
'name': 'GCode Writer',
|
||||
'author': 'Arjen Hiemstra',
|
||||
'version': '1.0',
|
||||
'description': catalog.i18nc('GCode Writer Plugin Description', 'Writes GCode to a file')
|
||||
"type": "mesh_writer",
|
||||
"plugin": {
|
||||
"name": "GCode Writer",
|
||||
"author": "Arjen Hiemstra",
|
||||
"version": "1.0",
|
||||
"description": catalog.i18nc("GCode Writer Plugin Description", "Writes GCode to a file")
|
||||
},
|
||||
|
||||
'mesh_writer': {
|
||||
'extension': 'gcode',
|
||||
'description': catalog.i18nc('GCode Writer File Description', 'GCode File')
|
||||
"mesh_writer": {
|
||||
"extension": "gcode",
|
||||
"description": catalog.i18nc("GCode Writer File Description", "GCode File")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ class LayerView(View):
|
||||
renderer.setRenderSelection(False)
|
||||
|
||||
if not self._material:
|
||||
self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, 'basic.vert'), Resources.getPath(Resources.ShadersLocation, 'vertexcolor.frag'))
|
||||
self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "vertexcolor.frag"))
|
||||
self._material.setUniformValue("u_color", [1.0, 0.0, 0.0, 1.0])
|
||||
|
||||
for node in DepthFirstIterator(scene.getRoot()):
|
||||
|
@ -1,17 +1,17 @@
|
||||
from . import LayerView
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog('cura')
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
'type': 'view',
|
||||
'plugin': {
|
||||
"type": "view",
|
||||
"plugin": {
|
||||
"name": "Layer View"
|
||||
},
|
||||
'view': {
|
||||
'name': catalog.i18nc('Layers View mode', 'Layers'),
|
||||
'view_panel': 'LayerView.qml'
|
||||
"view": {
|
||||
"name": catalog.i18nc("Layers View mode", "Layers"),
|
||||
"view_panel": "LayerView.qml"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ class PrinterConnection(SignalEmitter):
|
||||
hex_file = intelHex.readHex(self._firmware_file_name)
|
||||
|
||||
if len(hex_file) == 0:
|
||||
Logger.log('e', "Unable to read provided hex file. Could not update firmware")
|
||||
Logger.log("e", "Unable to read provided hex file. Could not update firmware")
|
||||
return
|
||||
|
||||
programmer = stk500v2.Stk500v2()
|
||||
@ -139,7 +139,7 @@ class PrinterConnection(SignalEmitter):
|
||||
time.sleep(1) # Give programmer some time to connect. Might need more in some cases, but this worked in all tested cases.
|
||||
|
||||
if not programmer.isConnected():
|
||||
Logger.log('e', "Unable to connect with serial. Could not update firmware")
|
||||
Logger.log("e", "Unable to connect with serial. Could not update firmware")
|
||||
return
|
||||
|
||||
self._updating_firmware = True
|
||||
@ -164,12 +164,12 @@ class PrinterConnection(SignalEmitter):
|
||||
self._is_connecting = True
|
||||
programmer = stk500v2.Stk500v2()
|
||||
try:
|
||||
programmer.connect(self._serial_port) # Connect with the serial, if this succeeds, it's an arduino based usb device.
|
||||
programmer.connect(self._serial_port) # Connect with the serial, if this succeeds, it"s an arduino based usb device.
|
||||
self._serial = programmer.leaveISP()
|
||||
except ispBase.IspError as e:
|
||||
Logger.log('i', "Could not establish connection on %s: %s. Device is not arduino based." %(self._serial_port,str(e)))
|
||||
Logger.log("i", "Could not establish connection on %s: %s. Device is not arduino based." %(self._serial_port,str(e)))
|
||||
except Exception as e:
|
||||
Logger.log('i', "Could not establish connection on %s, unknown reasons. Device is not arduino based." % self._serial_port)
|
||||
Logger.log("i", "Could not establish connection on %s, unknown reasons. Device is not arduino based." % self._serial_port)
|
||||
|
||||
# If the programmer connected, we know its an atmega based version. Not all that usefull, but it does give some debugging information.
|
||||
for baud_rate in self._getBaudrateList(): # Cycle all baud rates (auto detect)
|
||||
@ -178,7 +178,7 @@ class PrinterConnection(SignalEmitter):
|
||||
try:
|
||||
self._serial = serial.Serial(str(self._serial_port), baud_rate, timeout=3, writeTimeout=10000)
|
||||
except serial.SerialException:
|
||||
Logger.log('i', "Could not open port %s" % self._serial_port)
|
||||
Logger.log("i", "Could not open port %s" % self._serial_port)
|
||||
return
|
||||
else:
|
||||
if not self.setBaudRate(baud_rate):
|
||||
@ -187,7 +187,7 @@ class PrinterConnection(SignalEmitter):
|
||||
sucesfull_responses = 0
|
||||
timeout_time = time.time() + 5
|
||||
self._serial.write(b"\n")
|
||||
self._sendCommand("M105") # Request temperature, as this should (if baudrate is correct) result in a command with 'T:' in it
|
||||
self._sendCommand("M105") # Request temperature, as this should (if baudrate is correct) result in a command with "T:" in it
|
||||
while timeout_time > time.time():
|
||||
line = self._readline()
|
||||
if line is None:
|
||||
@ -202,7 +202,7 @@ class PrinterConnection(SignalEmitter):
|
||||
if sucesfull_responses >= self._required_responses_auto_baud:
|
||||
self._serial.timeout = 2 #Reset serial timeout
|
||||
self.setIsConnected(True)
|
||||
Logger.log('i', "Established printer connection on port %s" % self._serial_port)
|
||||
Logger.log("i", "Established printer connection on port %s" % self._serial_port)
|
||||
return
|
||||
self.close() # Unable to connect, wrap up.
|
||||
self.setIsConnected(False)
|
||||
@ -223,15 +223,15 @@ class PrinterConnection(SignalEmitter):
|
||||
if self._is_connected:
|
||||
self._listen_thread.start() #Start listening
|
||||
'''Application.getInstance().addOutputDevice(self._serial_port, {
|
||||
'id': self._serial_port,
|
||||
'function': self.printGCode,
|
||||
'description': 'Print with USB {0}'.format(self._serial_port),
|
||||
'icon': 'print_usb',
|
||||
'priority': 1
|
||||
"id": self._serial_port,
|
||||
"function": self.printGCode,
|
||||
"description": "Print with USB {0}".format(self._serial_port),
|
||||
"icon": "print_usb",
|
||||
"priority": 1
|
||||
})'''
|
||||
|
||||
else:
|
||||
Logger.log('w', "Printer connection state was not changed")
|
||||
Logger.log("w", "Printer connection state was not changed")
|
||||
|
||||
connectionStateChanged = Signal()
|
||||
|
||||
@ -254,37 +254,37 @@ class PrinterConnection(SignalEmitter):
|
||||
def _sendCommand(self, cmd):
|
||||
if self._serial is None:
|
||||
return
|
||||
if 'M109' in cmd or 'M190' in cmd:
|
||||
if "M109" in cmd or "M190" in cmd:
|
||||
self._heatup_wait_start_time = time.time()
|
||||
if 'M104' in cmd or 'M109' in cmd:
|
||||
if "M104" in cmd or "M109" in cmd:
|
||||
try:
|
||||
t = 0
|
||||
if 'T' in cmd:
|
||||
t = int(re.search('T([0-9]+)', cmd).group(1))
|
||||
self._target_extruder_temperatures[t] = float(re.search('S([0-9]+)', cmd).group(1))
|
||||
if "T" in cmd:
|
||||
t = int(re.search("T([0-9]+)", cmd).group(1))
|
||||
self._target_extruder_temperatures[t] = float(re.search("S([0-9]+)", cmd).group(1))
|
||||
except:
|
||||
pass
|
||||
if 'M140' in cmd or 'M190' in cmd:
|
||||
if "M140" in cmd or "M190" in cmd:
|
||||
try:
|
||||
self._target_bed_temperature = float(re.search('S([0-9]+)', cmd).group(1))
|
||||
self._target_bed_temperature = float(re.search("S([0-9]+)", cmd).group(1))
|
||||
except:
|
||||
pass
|
||||
#Logger.log('i','Sending: %s' % (cmd))
|
||||
#Logger.log("i","Sending: %s" % (cmd))
|
||||
try:
|
||||
command = (cmd + '\n').encode()
|
||||
#self._serial.write(b'\n')
|
||||
command = (cmd + "\n").encode()
|
||||
#self._serial.write(b"\n")
|
||||
self._serial.write(command)
|
||||
except serial.SerialTimeoutException:
|
||||
Logger.log("w","Serial timeout while writing to serial port, trying again.")
|
||||
try:
|
||||
time.sleep(0.5)
|
||||
self._serial.write((cmd + '\n').encode())
|
||||
self._serial.write((cmd + "\n").encode())
|
||||
except Exception as e:
|
||||
Logger.log("e","Unexpected error while writing serial port %s " % e)
|
||||
self._setErrorState("Unexpected error while writing serial port %s " % e)
|
||||
self.close()
|
||||
except Exception as e:
|
||||
Logger.log('e',"Unexpected error while writing serial port %s" % e)
|
||||
Logger.log("e","Unexpected error while writing serial port %s" % e)
|
||||
self._setErrorState("Unexpected error while writing serial port %s " % e)
|
||||
self.close()
|
||||
|
||||
@ -332,7 +332,7 @@ class PrinterConnection(SignalEmitter):
|
||||
|
||||
## Listen thread function.
|
||||
def _listen(self):
|
||||
Logger.log('i', "Printer connection listen thread started for %s" % self._serial_port)
|
||||
Logger.log("i", "Printer connection listen thread started for %s" % self._serial_port)
|
||||
temperature_request_timeout = time.time()
|
||||
ok_timeout = time.time()
|
||||
while self._is_connected:
|
||||
@ -341,24 +341,24 @@ class PrinterConnection(SignalEmitter):
|
||||
if line is None:
|
||||
break # None is only returned when something went wrong. Stop listening
|
||||
|
||||
if line.startswith(b'Error:'):
|
||||
if line.startswith(b"Error:"):
|
||||
# Oh YEAH, consistency.
|
||||
# Marlin reports an MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n"
|
||||
# But a bed temp error is reported as "Error: Temperature heated bed switched off. MAXTEMP triggered !!"
|
||||
# So we can have an extra newline in the most common case. Awesome work people.
|
||||
if re.match(b'Error:[0-9]\n', line):
|
||||
if re.match(b"Error:[0-9]\n", line):
|
||||
line = line.rstrip() + self._readline()
|
||||
|
||||
# Skip the communication errors, as those get corrected.
|
||||
if b'Extruder switched off' in line or b'Temperature heated bed switched off' in line or b'Something is wrong, please turn off the printer.' in line:
|
||||
if b"Extruder switched off" in line or b"Temperature heated bed switched off" in line or b"Something is wrong, please turn off the printer." in line:
|
||||
if not self.hasError():
|
||||
self._setErrorState(line[6:])
|
||||
elif b' T:' in line or line.startswith(b'T:'): #Temperature message
|
||||
elif b" T:" in line or line.startswith(b"T:"): #Temperature message
|
||||
try:
|
||||
self._setExtruderTemperature(self._temperature_requested_extruder_index,float(re.search(b"T: *([0-9\.]*)", line).group(1)))
|
||||
except:
|
||||
pass
|
||||
if b'B:' in line: # Check if it's a bed temperature
|
||||
if b"B:" in line: # Check if it"s a bed temperature
|
||||
try:
|
||||
self._setBedTemperature(float(re.search(b"B: *([0-9\.]*)", line).group(1)))
|
||||
except Exception as e:
|
||||
@ -374,16 +374,16 @@ class PrinterConnection(SignalEmitter):
|
||||
self.sendCommand("M105")
|
||||
temperature_request_timeout = time.time() + 5
|
||||
|
||||
if line == b'' and time.time() > ok_timeout:
|
||||
line = b'ok' # Force a timeout (basicly, send next command)
|
||||
if line == b"" and time.time() > ok_timeout:
|
||||
line = b"ok" # Force a timeout (basicly, send next command)
|
||||
|
||||
if b'ok' in line:
|
||||
if b"ok" in line:
|
||||
ok_timeout = time.time() + 5
|
||||
if not self._command_queue.empty():
|
||||
self._sendCommand(self._command_queue.get())
|
||||
else:
|
||||
self._sendNextGcodeLine()
|
||||
elif b"resend" in line.lower() or b"rs" in line: # Because a resend can be asked with 'resend' and 'rs'
|
||||
elif b"resend" in line.lower() or b"rs" in line: # Because a resend can be asked with "resend" and "rs"
|
||||
try:
|
||||
self._gcode_position = int(line.replace(b"N:",b" ").replace(b"N",b" ").replace(b":",b" ").split()[-1])
|
||||
except:
|
||||
@ -391,13 +391,13 @@ class PrinterConnection(SignalEmitter):
|
||||
self._gcode_position = int(line.split()[1])
|
||||
|
||||
else: # Request the temperature on comm timeout (every 2 seconds) when we are not printing.)
|
||||
if line == b'':
|
||||
if line == b"":
|
||||
if self._extruder_count > 0:
|
||||
self._temperature_requested_extruder_index = (self._temperature_requested_extruder_index + 1) % self._extruder_count
|
||||
self.sendCommand("M105 T%d" % self._temperature_requested_extruder_index)
|
||||
else:
|
||||
self.sendCommand("M105")
|
||||
Logger.log('i', "Printer connection listen thread stopped for %s" % self._serial_port)
|
||||
Logger.log("i", "Printer connection listen thread stopped for %s" % self._serial_port)
|
||||
|
||||
## Send next Gcode in the gcode list
|
||||
def _sendNextGcodeLine(self):
|
||||
@ -407,20 +407,20 @@ class PrinterConnection(SignalEmitter):
|
||||
self._print_start_time_100 = time.time()
|
||||
line = self._gcode[self._gcode_position]
|
||||
|
||||
if ';' in line:
|
||||
line = line[:line.find(';')]
|
||||
if ";" in line:
|
||||
line = line[:line.find(";")]
|
||||
line = line.strip()
|
||||
try:
|
||||
if line == 'M0' or line == 'M1':
|
||||
line = 'M105' #Don't send the M0 or M1 to the machine, as M0 and M1 are handled as an LCD menu pause.
|
||||
if ('G0' in line or 'G1' in line) and 'Z' in line:
|
||||
z = float(re.search('Z([0-9\.]*)', line).group(1))
|
||||
if line == "M0" or line == "M1":
|
||||
line = "M105" #Don"t send the M0 or M1 to the machine, as M0 and M1 are handled as an LCD menu pause.
|
||||
if ("G0" in line or "G1" in line) and "Z" in line:
|
||||
z = float(re.search("Z([0-9\.]*)", line).group(1))
|
||||
if self._current_z != z:
|
||||
self._current_z = z
|
||||
except Exception as e:
|
||||
Logger.log('e', "Unexpected error with printer connection: %s" % e)
|
||||
Logger.log("e", "Unexpected error with printer connection: %s" % e)
|
||||
self._setErrorState("Unexpected error: %s" %e)
|
||||
checksum = functools.reduce(lambda x,y: x^y, map(ord, 'N%d%s' % (self._gcode_position, line)))
|
||||
checksum = functools.reduce(lambda x,y: x^y, map(ord, "N%d%s" % (self._gcode_position, line)))
|
||||
|
||||
self._sendCommand("N%d%s*%d" % (self._gcode_position, line, checksum))
|
||||
self._gcode_position += 1
|
||||
@ -457,7 +457,7 @@ class PrinterConnection(SignalEmitter):
|
||||
try:
|
||||
ret = self._serial.readline()
|
||||
except Exception as e:
|
||||
Logger.log('e',"Unexpected error while reading serial port. %s" %e)
|
||||
Logger.log("e","Unexpected error while reading serial port. %s" %e)
|
||||
self._setErrorState("Printer has been disconnected")
|
||||
self.close()
|
||||
return None
|
||||
|
@ -17,7 +17,7 @@ from PyQt5.QtCore import QUrl, QObject, pyqtSlot, pyqtProperty, pyqtSignal
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
|
||||
i18n_catalog = i18nCatalog('plugins')
|
||||
i18n_catalog = i18nCatalog("plugins")
|
||||
|
||||
|
||||
class USBPrinterManager(QObject, SignalEmitter, Extension):
|
||||
@ -40,17 +40,17 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
|
||||
## Add menu item to top menu of the application.
|
||||
self.addMenuItem(i18n_catalog.i18n("Update firmware"), self.updateAllFirmware)
|
||||
|
||||
pyqtError = pyqtSignal(str, arguments = ['amount'])
|
||||
processingProgress = pyqtSignal(float, arguments = ['amount'])
|
||||
pyqtExtruderTemperature = pyqtSignal(float, arguments = ['amount'])
|
||||
pyqtBedTemperature = pyqtSignal(float, arguments = ['amount'])
|
||||
pyqtError = pyqtSignal(str, arguments = ["amount"])
|
||||
processingProgress = pyqtSignal(float, arguments = ["amount"])
|
||||
pyqtExtruderTemperature = pyqtSignal(float, arguments = ["amount"])
|
||||
pyqtBedTemperature = pyqtSignal(float, arguments = ["amount"])
|
||||
|
||||
## Show firmware interface.
|
||||
# This will create the view if its not already created.
|
||||
def spawnFirmwareInterface(self, serial_port):
|
||||
if self._firmware_view is None:
|
||||
self._firmware_view = QQuickView()
|
||||
self._firmware_view.engine().rootContext().setContextProperty('manager',self)
|
||||
self._firmware_view.engine().rootContext().setContextProperty("manager",self)
|
||||
self._firmware_view.setSource(QUrl("plugins/USBPrinting/FirmwareUpdateWindow.qml"))
|
||||
self._firmware_view.show()
|
||||
|
||||
@ -59,7 +59,7 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
|
||||
def spawnControlInterface(self,serial_port):
|
||||
if self._control_view is None:
|
||||
self._control_view = QQuickView()
|
||||
self._control_view.engine().rootContext().setContextProperty('manager',self)
|
||||
self._control_view.engine().rootContext().setContextProperty("manager",self)
|
||||
self._control_view.setSource(QUrl("plugins/USBPrinting/ControlWindow.qml"))
|
||||
self._control_view.show()
|
||||
|
||||
@ -105,7 +105,7 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
|
||||
if connection != None:
|
||||
self._printer_connections.remove(connection)
|
||||
connection.close()
|
||||
time.sleep(5) # Throttle, as we don't need this information to be updated every single second.
|
||||
time.sleep(5) # Throttle, as we don"t need this information to be updated every single second.
|
||||
|
||||
def updateAllFirmware(self):
|
||||
self.spawnFirmwareInterface("")
|
||||
@ -122,13 +122,13 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
|
||||
machine_type = Application.getInstance().getActiveMachine().getTypeID()
|
||||
firmware_name = ""
|
||||
baudrate = 250000
|
||||
if sys.platform.startswith('linux'):
|
||||
if sys.platform.startswith("linux"):
|
||||
baudrate = 115200
|
||||
if machine_type == "ultimaker_original":
|
||||
firmware_name = 'MarlinUltimaker'
|
||||
firmware_name += '-%d' % (baudrate)
|
||||
firmware_name = "MarlinUltimaker"
|
||||
firmware_name += "-%d" % (baudrate)
|
||||
elif machine_type == "ultimaker_original_plus":
|
||||
firmware_name = 'MarlinUltimaker-UMOP-%d' % (baudrate)
|
||||
firmware_name = "MarlinUltimaker-UMOP-%d" % (baudrate)
|
||||
elif machine_type == "Witbox":
|
||||
return "MarlinWitbox.hex"
|
||||
elif machine_type == "ultimaker2go":
|
||||
@ -220,22 +220,22 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
|
||||
connection = self.getConnectionByPort(serial_port)
|
||||
if connection.isConnected():
|
||||
Application.getInstance().addOutputDevice(serial_port, {
|
||||
'id': serial_port,
|
||||
'function': self.spawnControlInterface,
|
||||
'description': 'Write to USB {0}'.format(serial_port),
|
||||
'icon': 'print_usb',
|
||||
'priority': 1
|
||||
"id": serial_port,
|
||||
"function": self.spawnControlInterface,
|
||||
"description": "Write to USB {0}".format(serial_port),
|
||||
"icon": "print_usb",
|
||||
"priority": 1
|
||||
})
|
||||
else:
|
||||
Application.getInstance().removeOutputDevice(serial_port)
|
||||
|
||||
@pyqtSlot()
|
||||
def startPrint(self):
|
||||
gcode_list = getattr(Application.getInstance().getController().getScene(), 'gcode_list', None)
|
||||
gcode_list = getattr(Application.getInstance().getController().getScene(), "gcode_list", None)
|
||||
if gcode_list:
|
||||
final_list = []
|
||||
for gcode in gcode_list:
|
||||
final_list += gcode.split('\n')
|
||||
final_list += gcode.split("\n")
|
||||
self.sendGCodeToAllActive(gcode_list)
|
||||
|
||||
## Get a list of printer connection objects that are connected.
|
||||
@ -260,15 +260,15 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
|
||||
i = 0
|
||||
while True:
|
||||
values = winreg.EnumValue(key, i)
|
||||
if not base_list or 'USBSER' in values[0]:
|
||||
if not base_list or "USBSER" in values[0]:
|
||||
base_list += [values[1]]
|
||||
i += 1
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
if base_list:
|
||||
base_list = base_list + glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*') + glob.glob("/dev/cu.usb*")
|
||||
base_list = filter(lambda s: 'Bluetooth' not in s, base_list) # Filter because mac sometimes puts them in the list
|
||||
base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.usb*")
|
||||
base_list = filter(lambda s: "Bluetooth" not in s, base_list) # Filter because mac sometimes puts them in the list
|
||||
else:
|
||||
base_list = base_list + glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*') + glob.glob("/dev/cu.*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/rfcomm*") + glob.glob('/dev/serial/by-id/*')
|
||||
base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/rfcomm*") + glob.glob("/dev/serial/by-id/*")
|
||||
return base_list
|
@ -2,16 +2,16 @@ from . import USBPrinterManager
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
|
||||
i18n_catalog = i18nCatalog('cura')
|
||||
i18n_catalog = i18nCatalog("cura")
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
'type': 'extension',
|
||||
'plugin': {
|
||||
'name': 'USB printing',
|
||||
'author': 'Jaime van Kessel',
|
||||
'version': '1.0',
|
||||
'description': i18n_catalog.i18nc('usb printing description','Accepts G-Code and sends them to a printer. Plugin can also update firmware')
|
||||
"type": "extension",
|
||||
"plugin": {
|
||||
"name": "USB printing",
|
||||
"author": "Jaime van Kessel",
|
||||
"version": "1.0",
|
||||
"description": i18n_catalog.i18nc("usb printing description","Accepts G-Code and sends them to a printer. Plugin can also update firmware")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from src.PrinterApplication import PrinterApplication
|
||||
|
||||
app = PrinterApplication.getInstance()
|
||||
app.run()
|
BIN
resources/images/Ultimaker2backplate.png
Normal file
BIN
resources/images/Ultimaker2backplate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
resources/images/UltimakerPlusbackplate.png
Normal file
BIN
resources/images/UltimakerPlusbackplate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
resources/images/cura.png
Normal file
BIN
resources/images/cura.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
BIN
resources/meshes/UltimakerRobot_support.stl
Normal file
BIN
resources/meshes/UltimakerRobot_support.stl
Normal file
Binary file not shown.
15104
resources/meshes/ultimaker2_platform.obj
Normal file
15104
resources/meshes/ultimaker2_platform.obj
Normal file
File diff suppressed because it is too large
Load Diff
13812
resources/meshes/ultimaker2go_platform.obj
Normal file
13812
resources/meshes/ultimaker2go_platform.obj
Normal file
File diff suppressed because it is too large
Load Diff
BIN
resources/meshes/ultimaker_platform.stl
Normal file
BIN
resources/meshes/ultimaker_platform.stl
Normal file
Binary file not shown.
@ -8,15 +8,52 @@ import UM 1.0 as UM
|
||||
UM.Dialog {
|
||||
id: base
|
||||
|
||||
//: Add Printer dialog title
|
||||
//: About dialog title
|
||||
title: qsTr("About Cura");
|
||||
|
||||
Label {
|
||||
text: "Cura";
|
||||
ColumnLayout {
|
||||
anchors.fill: parent;
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true;
|
||||
Layout.fillHeight: true;
|
||||
}
|
||||
|
||||
Image {
|
||||
Layout.alignment: Qt.AlignHCenter;
|
||||
Layout.preferredWidth: parent.width * 0.75;
|
||||
Layout.preferredHeight: width * (1/4.25);
|
||||
|
||||
source: UM.Theme.images.logo;
|
||||
|
||||
sourceSize.width: width;
|
||||
sourceSize.height: height;
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignHCenter;
|
||||
|
||||
text: "Cura 15.06";
|
||||
font: UM.Theme.fonts.large;
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("End-to-end solution for fused filament 3D printing.")
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Cura has been developed by Ultimaker B.V. in cooperation with the community.")
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true;
|
||||
Layout.fillHeight: true;
|
||||
}
|
||||
}
|
||||
|
||||
rightButtons: Button {
|
||||
text: "Close";
|
||||
//: Close about dialog button
|
||||
text: qsTr("Close");
|
||||
|
||||
onClicked: base.visible = false;
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ UM.Dialog {
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent;
|
||||
anchors.margins: UM.Styles.defaultMargin;
|
||||
|
||||
Label {
|
||||
text: qsTr("Add Printer");
|
||||
|
@ -190,15 +190,11 @@ UM.MainWindow {
|
||||
source: UM.ActiveView.valid ? UM.ActiveView.activeViewPanel : "";
|
||||
}
|
||||
|
||||
DescriptionPane {
|
||||
id: descriptionPane;
|
||||
anchors.right: sidebar.left;
|
||||
}
|
||||
|
||||
PrinterButton {
|
||||
Button {
|
||||
id: openFileButton;
|
||||
|
||||
iconSource: UM.Theme.icons.open;
|
||||
style: UM.Theme.styles.tool_button;
|
||||
|
||||
anchors {
|
||||
top: parent.top;
|
||||
@ -225,7 +221,7 @@ UM.MainWindow {
|
||||
sourceSize.height: height;
|
||||
}
|
||||
|
||||
PrinterButton {
|
||||
Button {
|
||||
anchors {
|
||||
top: parent.top;
|
||||
topMargin: UM.Theme.sizes.window_margin.height;
|
||||
@ -237,6 +233,8 @@ UM.MainWindow {
|
||||
text: qsTr("View Mode");
|
||||
iconSource: UM.Theme.icons.viewmode;
|
||||
|
||||
style: UM.Theme.styles.tool_button;
|
||||
|
||||
menu: Menu {
|
||||
id: viewMenu;
|
||||
Instantiator {
|
||||
@ -256,7 +254,7 @@ UM.MainWindow {
|
||||
}
|
||||
}
|
||||
|
||||
PrinterToolbar {
|
||||
Toolbar {
|
||||
id: toolbar;
|
||||
|
||||
anchors {
|
||||
@ -273,11 +271,11 @@ UM.MainWindow {
|
||||
id: preferences
|
||||
|
||||
Component.onCompleted: {
|
||||
insertPage(1, qsTr('View'), 'view-preview', Qt.resolvedUrl('./ViewPage.qml'));
|
||||
insertPage(1, qsTr("View"), "view-preview", Qt.resolvedUrl("./ViewPage.qml"));
|
||||
}
|
||||
}
|
||||
|
||||
PrinterActions {
|
||||
Actions {
|
||||
id: actions;
|
||||
|
||||
open.onTriggered: openDialog.open();
|
@ -1,68 +0,0 @@
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.1
|
||||
|
||||
import UM 1.0 as UM
|
||||
|
||||
Rectangle {
|
||||
id: base
|
||||
|
||||
opacity: 0;
|
||||
|
||||
width: 300;
|
||||
height: label.height + label.anchors.topMargin + label.anchors.bottomMargin;
|
||||
|
||||
border.width: 1;
|
||||
|
||||
Label {
|
||||
id: label;
|
||||
|
||||
wrapMode: Text.WordWrap;
|
||||
horizontalAlignment: Text.AlignJustify;
|
||||
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 10;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 10;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: closeButton.height;
|
||||
anchors.bottomMargin: 10;
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
id: closeButton;
|
||||
anchors.right: parent.right;
|
||||
text: "Close";
|
||||
onClicked: closeAnimation.start();
|
||||
}
|
||||
|
||||
function show(text, x, y)
|
||||
{
|
||||
if(base.opacity > 0) {
|
||||
base._newText = text;
|
||||
base._newY = y;
|
||||
textChangeAnimation.start();
|
||||
} else {
|
||||
label.text = text;
|
||||
base.y = y;
|
||||
showAnimation.start();
|
||||
}
|
||||
}
|
||||
|
||||
property string _newText;
|
||||
property real _newY;
|
||||
|
||||
SequentialAnimation {
|
||||
id: textChangeAnimation;
|
||||
|
||||
NumberAnimation { target: base; property: "opacity"; to: 0; duration: 100; }
|
||||
PropertyAction { target: label; property: "text"; value: base._newText; }
|
||||
PropertyAction { target: base; property: "y"; value: base._newY; }
|
||||
NumberAnimation { target: base; property: "opacity"; to: 1; duration: 100; }
|
||||
}
|
||||
|
||||
NumberAnimation { id: showAnimation; target: base; property: "opacity"; to: 1; duration: 100; }
|
||||
NumberAnimation { id: closeAnimation; target: base; property: "opacity"; to: 0; duration: 100; }
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import UM 1.0 as UM
|
||||
|
||||
Rectangle {
|
||||
id: base;
|
||||
|
||||
signal requestOpenFile();
|
||||
signal openFile(url file);
|
||||
|
||||
function setDirectory(file)
|
||||
{
|
||||
UM.Models.directoryListModel.directory = file
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
acceptedButtons: Qt.AllButtons;
|
||||
|
||||
onWheel: {
|
||||
wheel.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent;
|
||||
anchors.margins: UM.Styles.defaultMargin;
|
||||
|
||||
//: Open file button
|
||||
Button { text: qsTr("Open File"); iconSource: UM.Resources.getIcon("open.png"); Layout.fillWidth: true; onClicked: base.requestOpenFile(); }
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true;
|
||||
Layout.fillHeight: true;
|
||||
border.width: 1;
|
||||
border.color: "#aaa";
|
||||
|
||||
ScrollView {
|
||||
anchors.fill: parent;
|
||||
anchors.margins: 1;
|
||||
|
||||
ListView {
|
||||
id: listView;
|
||||
model: UM.Models.directoryListModel;
|
||||
delegate: listDelegate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
iconSource: UM.Resources.getIcon('expand.png');
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: listDelegate;
|
||||
Rectangle {
|
||||
id: item;
|
||||
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
||||
height: 40;
|
||||
|
||||
color: mouseArea.pressed ? "#f00" : index % 2 ? "#eee" : "#fff";
|
||||
|
||||
Label {
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: UM.Styles.defaultMargin;
|
||||
|
||||
text: model.name;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea;
|
||||
anchors.fill: parent;
|
||||
|
||||
onClicked: base.openFile(model.url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import UM 1.0 as UM
|
||||
|
||||
Button {
|
||||
id: base;
|
||||
style: UM.Theme.styles.tool_button;
|
||||
}
|
@ -15,7 +15,7 @@ Button {
|
||||
|
||||
enabled: progress >= 0.95;
|
||||
|
||||
property string currentDevice: 'local_file'
|
||||
property string currentDevice: "local_file"
|
||||
property bool defaultOverride: false;
|
||||
property bool defaultAmbiguous: false;
|
||||
|
||||
|
@ -1,194 +0,0 @@
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import UM 1.0 as UM
|
||||
|
||||
Rectangle {
|
||||
id: base;
|
||||
|
||||
height: childrenRect.height;
|
||||
|
||||
property real expandedHeight: 500;
|
||||
|
||||
property bool collapsed: true;
|
||||
|
||||
signal showDescription(string text, real x, real y);
|
||||
|
||||
MouseArea {
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: contents.height;
|
||||
|
||||
acceptedButtons: Qt.AllButtons;
|
||||
|
||||
onWheel: {
|
||||
wheel.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: contents;
|
||||
spacing: UM.Styles.defaultMargin;
|
||||
|
||||
anchors {
|
||||
left: parent.left;
|
||||
leftMargin: UM.Styles.defaultMargin;
|
||||
right: parent.right;
|
||||
rightMargin: UM.Styles.defaultMargin;
|
||||
}
|
||||
|
||||
//: Print Settings panel title
|
||||
Label { text: qsTr("Print Settings"); width: parent.width; font.capitalization: Font.AllUppercase; font.pointSize: UM.Styles.smallTextSize; }
|
||||
|
||||
Item {
|
||||
width: parent.width;
|
||||
height: 24;
|
||||
|
||||
Row {
|
||||
anchors.fill: parent;
|
||||
spacing: UM.Styles.defaultMargin;
|
||||
|
||||
//: Material selection combo box label
|
||||
Label { text: qsTr("Material"); horizontalAlignment: Text.AlignRight; width: base.width * 0.5; }
|
||||
ComboBox {
|
||||
width: parent.width * 0.35;
|
||||
model: ListModel {
|
||||
ListElement { text: "PLA"; }
|
||||
ListElement { text: "ABS"; }
|
||||
}
|
||||
style: ComboBoxStyle { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width;
|
||||
height: 24;
|
||||
|
||||
Row {
|
||||
anchors.fill: parent;
|
||||
spacing: UM.Styles.defaultMargin;
|
||||
//: Time display label
|
||||
Label { text: qsTr("Time"); width: base.width * 0.5; horizontalAlignment: Text.AlignRight; }
|
||||
Label { text: Qt.formatTime(new Date(timeSlider.value * 60000)); width: base.width * 0.35; horizontalAlignment: Text.AlignLeft; }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { color: "black"; height: 1; width: parent.width; }
|
||||
|
||||
Item {
|
||||
id: speedSlider;
|
||||
|
||||
width: parent.width;
|
||||
height: 60;
|
||||
|
||||
Slider {
|
||||
id: timeSlider;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 20;
|
||||
|
||||
minimumValue: 60;
|
||||
maximumValue: 600;
|
||||
stepSize: 10;
|
||||
|
||||
style: SliderStyle {
|
||||
groove: Rectangle {
|
||||
height: 1;
|
||||
color: "black";
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
width: 1;
|
||||
height: control.height;
|
||||
color: "black";
|
||||
}
|
||||
Rectangle {
|
||||
anchors.right: parent.right;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
width: 1;
|
||||
height: control.height;
|
||||
color: "black";
|
||||
}
|
||||
}
|
||||
handle: Rectangle { width: 5; height: control.height; color: UM.Styles.primaryColor; }
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: parent.left;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
||||
Label { text: Qt.formatTime(new Date(timeSlider.minimumValue * 60000)); }
|
||||
//: Low quality display label
|
||||
Label { text: qsTr("Low Quality"); }
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.right: parent.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
||||
Label { text: Qt.formatTime(new Date(timeSlider.maximumValue * 60000)); anchors.right: parent.right; }
|
||||
//: High quality display label
|
||||
Label { text: qsTr("High Quality"); }
|
||||
}
|
||||
}
|
||||
|
||||
UM.SettingsView {
|
||||
id: settingsView;
|
||||
|
||||
width: parent.width;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
visible: false;
|
||||
|
||||
onShowDescription: base.showDescription(text, x, y);
|
||||
}
|
||||
|
||||
Rectangle { color: "black"; height: 1; width: parent.width; }
|
||||
|
||||
Item {
|
||||
Layout.columnSpan: 2;
|
||||
height: childrenRect.height;
|
||||
width: parent.width;
|
||||
|
||||
ToolButton {
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
iconSource: UM.Resources.getIcon('expand.png');
|
||||
onClicked: base.collapsed = !base.collapsed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: 'expanded';
|
||||
when: !base.collapsed;
|
||||
|
||||
PropertyChanges { target: speedSlider; opacity: 0; height: 0; visible: false; }
|
||||
PropertyChanges {
|
||||
target: settingsView;
|
||||
opacity: 1;
|
||||
height: Math.min(settingsView.listHeight, base.expandedHeight * 0.6);
|
||||
visible: true;
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
to: 'expanded';
|
||||
reversible: true;
|
||||
SequentialAnimation {
|
||||
NumberAnimation { target: speedSlider; property: 'opacity'; duration: 100; }
|
||||
PropertyAction { target: settingsView; property: 'visible'; }
|
||||
NumberAnimation { property: 'height'; duration: 200; }
|
||||
PropertyAction { target: speedSlider; property: 'visible'; }
|
||||
NumberAnimation { target: settingsView; property: 'opacity'; duration: 100; }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -50,13 +50,13 @@ UM.AngledCornerRectangle {
|
||||
modesModel: modesListModel;
|
||||
|
||||
currentModeIndex: {
|
||||
var index = parseInt(UM.Preferences.getValue('cura/active_mode'))
|
||||
var index = parseInt(UM.Preferences.getValue("cura/active_mode"))
|
||||
if(index) {
|
||||
return index;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
onCurrentModeIndexChanged: UM.Preferences.setValue('cura/active_mode', currentModeIndex);
|
||||
onCurrentModeIndexChanged: UM.Preferences.setValue("cura/active_mode", currentModeIndex);
|
||||
}
|
||||
|
||||
Loader {
|
||||
|
@ -102,8 +102,8 @@ Item {
|
||||
|
||||
style: UM.Theme.styles.checkbox;
|
||||
|
||||
checked: Printer.getSettingValue('support_enable');
|
||||
onCheckedChanged: Printer.setSettingValue('support_enable', checked);
|
||||
checked: Printer.getSettingValue("support_enable");
|
||||
onCheckedChanged: Printer.setSettingValue("support_enable", checked);
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true; Layout.fillHeight: true; }
|
||||
|
@ -24,7 +24,7 @@ Item {
|
||||
|
||||
model: UM.Models.toolModel
|
||||
|
||||
PrinterButton {
|
||||
Button {
|
||||
text: model.name;
|
||||
iconSource: UM.Theme.icons[model.icon];
|
||||
tooltip: model.description;
|
||||
@ -32,7 +32,9 @@ Item {
|
||||
checkable: true;
|
||||
checked: model.active;
|
||||
|
||||
//Workaround since using ToolButton's onClicked would break the binding of the checked property, instead
|
||||
style: UM.Theme.styles.tool_button;
|
||||
|
||||
//Workaround since using ToolButton"s onClicked would break the binding of the checked property, instead
|
||||
//just catch the click so we do not trigger that behaviour.
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
@ -10,15 +10,15 @@ UM.PreferencesPage {
|
||||
|
||||
function reset()
|
||||
{
|
||||
UM.Preferences.resetPreference('view/show_overhang');
|
||||
UM.Preferences.resetPreference("view/show_overhang");
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: 2;
|
||||
|
||||
CheckBox {
|
||||
checked: UM.Preferences.getValue('view/show_overhang');
|
||||
onCheckedChanged: UM.Preferences.setValue('view/show_overhang', checked)
|
||||
checked: UM.Preferences.getValue("view/show_overhang");
|
||||
onCheckedChanged: UM.Preferences.setValue("view/show_overhang", checked)
|
||||
|
||||
//: Display Overhang preference checkbox
|
||||
text: qsTr("Display Overhang");
|
||||
|
1319
resources/settings/fdmprinter.json
Normal file
1319
resources/settings/fdmprinter.json
Normal file
File diff suppressed because it is too large
Load Diff
3
resources/settings/profiles/high_quality.conf
Normal file
3
resources/settings/profiles/high_quality.conf
Normal file
@ -0,0 +1,3 @@
|
||||
[resolution]
|
||||
layer_height = 0.04
|
||||
fill_sparse_density = 25
|
3
resources/settings/profiles/low_quality.conf
Normal file
3
resources/settings/profiles/low_quality.conf
Normal file
@ -0,0 +1,3 @@
|
||||
[resolution]
|
||||
layer_height = 0.15
|
||||
fill_sparse_density = 10
|
44
resources/settings/ultimaker2.json
Normal file
44
resources/settings/ultimaker2.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"id": "ultimaker2",
|
||||
"name": "Ultimaker 2",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
"platform": "ultimaker2_platform.obj",
|
||||
"platform_texture": "Ultimaker2backplate.png",
|
||||
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"machine_settings": {
|
||||
"machine_width": { "default": 230 },
|
||||
"machine_depth": { "default": 225 },
|
||||
"machine_height": { "default": 205 },
|
||||
"machine_heated_bed": { "default": true },
|
||||
|
||||
"machine_center_is_zero": { "default": false },
|
||||
"machine_nozzle_size": { "default": 0.4 },
|
||||
"machine_head_shape_min_x": { "default": 40 },
|
||||
"machine_head_shape_min_y": { "default": 10 },
|
||||
"machine_head_shape_max_x": { "default": 60 },
|
||||
"machine_head_shape_max_y": { "default": 30 },
|
||||
"machine_nozzle_gantry_distance": { "default": 55 },
|
||||
"machine_nozzle_offset_x_1": { "default": 18.0 },
|
||||
"machine_nozzle_offset_y_1": { "default": 0.0 },
|
||||
"machine_gcode_flavor": { "default": "UltiGCode" },
|
||||
"machine_disallowed_areas": { "default": [
|
||||
[[-115.0, 112.5], [ -82.0, 112.5], [ -84.0, 104.5], [-115.0, 104.5]],
|
||||
[[ 115.0, 112.5], [ 115.0, 104.5], [ 110.0, 104.5], [ 108.0, 112.5]],
|
||||
[[-115.0, -112.5], [-115.0, -104.5], [ -84.0, -104.5], [ -82.0, -112.5]],
|
||||
[[ 115.0, -112.5], [ 108.0, -112.5], [ 110.0, -104.5], [ 115.0, -104.5]]
|
||||
]},
|
||||
"machine_platform_offset": { "default": [9.0, 0.0, 0.0] },
|
||||
|
||||
"machine_nozzle_tip_outer_diameter": { "default": 1.0 },
|
||||
"machine_nozzle_head_distance": { "default": 3.0 },
|
||||
"machine_nozzle_expansion_angle": { "default": 45 }
|
||||
},
|
||||
|
||||
"categories": {
|
||||
"material": {
|
||||
"visible": false
|
||||
}
|
||||
}
|
||||
}
|
15
resources/settings/ultimaker2extended.json
Normal file
15
resources/settings/ultimaker2extended.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "ultimaker2extended",
|
||||
"name": "Ultimaker 2 Extended",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
"platform": "ultimaker2_platform.obj",
|
||||
"platform_texture": "Ultimaker2backplate.png",
|
||||
|
||||
"inherits": "ultimaker2.json",
|
||||
|
||||
"machine_settings": {
|
||||
"machine_width": { "default": 230 },
|
||||
"machine_depth": { "default": 225 },
|
||||
"machine_height": { "default": 315 }
|
||||
}
|
||||
}
|
23
resources/settings/ultimaker2go.json
Normal file
23
resources/settings/ultimaker2go.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"id": "ultimaker2go",
|
||||
"name": "Ultimaker 2 Go",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
"platform": "ultimaker2go_platform.obj",
|
||||
"platform_texture": "Ultimaker2backplate.png",
|
||||
|
||||
"inherits": "ultimaker2.json",
|
||||
|
||||
"machine_settings": {
|
||||
"machine_width": { "default": 120 },
|
||||
"machine_depth": { "default": 120 },
|
||||
"machine_height": { "default": 115 },
|
||||
"machine_heated_bed": { "default": false },
|
||||
"machine_disallowed_areas": { "default": [
|
||||
[[-60.0, 60.0], [-33.0, 60.0], [-35.0, 52.0], [-60.0, 52.0]],
|
||||
[[ 60.0, 60.0], [ 60.0, 52.0], [ 35.0, 52.0], [ 33.0, 60.0]],
|
||||
[[-60.0, -60.0], [-60.0, -52.0], [-35.0, -52.0], [-33.0, -60.0]],
|
||||
[[ 60.0, -60.0], [ 33.0, -60.0], [ 35.0, -52.0], [ 60.0, -52.0]]
|
||||
]},
|
||||
"machine_platform_offset": { "default": [0.0, 0.0, 0.0] }
|
||||
}
|
||||
}
|
24
resources/settings/ultimaker_original.json
Normal file
24
resources/settings/ultimaker_original.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"id": "ultimaker_original",
|
||||
"name": "Ultimaker Original",
|
||||
"icon": "icon_ultimaker.png",
|
||||
"platform": "ultimaker_platform.stl",
|
||||
|
||||
"inherits": "fdmprinter.json",
|
||||
|
||||
"machine_settings": {
|
||||
"machine_width": { "default": 205 },
|
||||
"machine_height": { "default": 200 },
|
||||
"machine_depth": { "default": 205 },
|
||||
"machine_center_is_zero": { "default": false },
|
||||
"machine_nozzle_size": { "default": 0.4 },
|
||||
"machine_head_shape_min_x": { "default": 75 },
|
||||
"machine_head_shape_min_y": { "default": 18 },
|
||||
"machine_head_shape_max_x": { "default": 18 },
|
||||
"machine_head_shape_max_y": { "default": 35 },
|
||||
"machine_nozzle_gantry_distance": { "default": 55 },
|
||||
"machine_nozzle_offset_x_1": { "default": 18.0 },
|
||||
"machine_nozzle_offset_y_1": { "default": 0.0 },
|
||||
"machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" }
|
||||
}
|
||||
}
|
13
resources/settings/ultimaker_original_plus.json
Normal file
13
resources/settings/ultimaker_original_plus.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"id": "ultimaker_original_plus",
|
||||
"name": "Ultimaker Original Plus",
|
||||
"icon": "icon_ultimaker.png",
|
||||
"platform": "ultimaker2_platform.obj",
|
||||
"platform_texture": "UltimakerPlusbackplate.png",
|
||||
|
||||
"inherits": "ultimaker_original.json",
|
||||
|
||||
"machine_settings": {
|
||||
"machine_heated_bed": { "default": true }
|
||||
}
|
||||
}
|
56
setup.py
56
setup.py
@ -7,23 +7,23 @@ import re
|
||||
import shutil
|
||||
import site
|
||||
|
||||
includes = ['sip', 'ctypes', 'UM', 'PyQt5.QtNetwork', 'PyQt5._QOpenGLFunctions_2_0', 'serial', 'Arcus', 'google', 'google.protobuf', 'google.protobuf.descriptor', 'xml.etree', 'xml.etree.ElementTree', 'src']
|
||||
includes = ["sip", "ctypes", "UM", "PyQt5.QtNetwork", "PyQt5._QOpenGLFunctions_2_0", "serial", "Arcus", "google", "google.protobuf", "google.protobuf.descriptor", "xml.etree", "xml.etree.ElementTree", "src"]
|
||||
# Include all the UM modules in the includes. As py2exe fails to properly find all the dependencies due to the plugin architecture.
|
||||
for dirpath, dirnames, filenames in os.walk(os.path.dirname(UM.__file__)):
|
||||
if '__' in dirpath:
|
||||
if "__" in dirpath:
|
||||
continue
|
||||
module_path = dirpath.replace(os.path.dirname(UM.__file__), 'UM')
|
||||
module_path = dirpath.replace(os.path.dirname(UM.__file__), "UM")
|
||||
module_path = module_path.split(os.path.sep)
|
||||
module_name = '.'.join(module_path)
|
||||
if os.path.isfile(dirpath + '/__init__.py'):
|
||||
module_name = ".".join(module_path)
|
||||
if os.path.isfile(dirpath + "/__init__.py"):
|
||||
includes += [module_name]
|
||||
for filename in filenames:
|
||||
if '__' in filename or not filename.endswith('.py'):
|
||||
if "__" in filename or not filename.endswith(".py"):
|
||||
continue
|
||||
includes += [module_name + '.' + os.path.splitext(filename)[0]]
|
||||
includes += [module_name + "." + os.path.splitext(filename)[0]]
|
||||
|
||||
print('Removing previous distribution package')
|
||||
shutil.rmtree('dist', True)
|
||||
print("Removing previous distribution package")
|
||||
shutil.rmtree("dist", True)
|
||||
|
||||
setup(name="Cura",
|
||||
version="2.0",
|
||||
@ -36,24 +36,24 @@ setup(name="Cura",
|
||||
console=[{"script": "printer.py"}],
|
||||
options={"py2exe": {"skip_archive": False, "includes": includes}})
|
||||
|
||||
print('Coping Cura plugins.')
|
||||
shutil.copytree(os.path.dirname(UM.__file__) + '/../plugins', 'dist/plugins')
|
||||
for path in os.listdir('plugins'):
|
||||
shutil.copytree('plugins/' + path, 'dist/plugins/' + path)
|
||||
print('Coping resources.')
|
||||
shutil.copytree(os.path.dirname(UM.__file__) + '/../resources', 'dist/resources')
|
||||
shutil.copytree('resources/qml', 'dist/resources/qml')
|
||||
shutil.copytree('resources/themes', 'dist/resources/themes')
|
||||
print('Coping Uranium QML.')
|
||||
shutil.copytree(os.path.dirname(UM.__file__) + '/Qt/qml/UM', 'dist/qml/UM')
|
||||
print("Coping Cura plugins.")
|
||||
shutil.copytree(os.path.dirname(UM.__file__) + "/../plugins", "dist/plugins")
|
||||
for path in os.listdir("plugins"):
|
||||
shutil.copytree("plugins/" + path, "dist/plugins/" + path)
|
||||
print("Coping resources.")
|
||||
shutil.copytree(os.path.dirname(UM.__file__) + "/../resources", "dist/resources")
|
||||
shutil.copytree("resources/qml", "dist/resources/qml")
|
||||
shutil.copytree("resources/themes", "dist/resources/themes")
|
||||
print("Coping Uranium QML.")
|
||||
shutil.copytree(os.path.dirname(UM.__file__) + "/Qt/qml/UM", "dist/qml/UM")
|
||||
for site_package in site.getsitepackages():
|
||||
qt_origin_path = os.path.join(site_package, 'PyQt5')
|
||||
qt_origin_path = os.path.join(site_package, "PyQt5")
|
||||
if os.path.isdir(qt_origin_path):
|
||||
print('Coping PyQt5 plugins from: %s' % qt_origin_path)
|
||||
shutil.copytree(os.path.join(qt_origin_path, 'plugins'), 'dist/PyQt5/plugins')
|
||||
print('Coping PyQt5 QtQuick from: %s' % qt_origin_path)
|
||||
shutil.copytree(os.path.join(qt_origin_path, 'qml/QtQuick'), 'dist/qml/QtQuick')
|
||||
shutil.copytree(os.path.join(qt_origin_path, 'qml/QtQuick.2'), 'dist/qml/QtQuick.2')
|
||||
print('Coping PyQt5 svg library from: %s' % qt_origin_path)
|
||||
shutil.copy(os.path.join(qt_origin_path, 'Qt5Svg.dll'), 'dist/Qt5Svg.dll')
|
||||
os.rename('dist/printer.exe', 'dist/Cura.exe')
|
||||
print("Coping PyQt5 plugins from: %s" % qt_origin_path)
|
||||
shutil.copytree(os.path.join(qt_origin_path, "plugins"), "dist/PyQt5/plugins")
|
||||
print("Coping PyQt5 QtQuick from: %s" % qt_origin_path)
|
||||
shutil.copytree(os.path.join(qt_origin_path, "qml/QtQuick"), "dist/qml/QtQuick")
|
||||
shutil.copytree(os.path.join(qt_origin_path, "qml/QtQuick.2"), "dist/qml/QtQuick.2")
|
||||
print("Coping PyQt5 svg library from: %s" % qt_origin_path)
|
||||
shutil.copy(os.path.join(qt_origin_path, "Qt5Svg.dll"), "dist/Qt5Svg.dll")
|
||||
os.rename("dist/printer.exe", "dist/Cura.exe")
|
||||
|
@ -48,15 +48,15 @@ class BuildVolume(SceneNode):
|
||||
|
||||
if not self._material:
|
||||
self._material = renderer.createMaterial(
|
||||
Resources.getPath(Resources.ShadersLocation, 'basic.vert'),
|
||||
Resources.getPath(Resources.ShadersLocation, 'vertexcolor.frag')
|
||||
Resources.getPath(Resources.ShadersLocation, "basic.vert"),
|
||||
Resources.getPath(Resources.ShadersLocation, "vertexcolor.frag")
|
||||
)
|
||||
self._grid_material = renderer.createMaterial(
|
||||
Resources.getPath(Resources.ShadersLocation, 'basic.vert'),
|
||||
Resources.getPath(Resources.ShadersLocation, 'grid.frag')
|
||||
Resources.getPath(Resources.ShadersLocation, "basic.vert"),
|
||||
Resources.getPath(Resources.ShadersLocation, "grid.frag")
|
||||
)
|
||||
self._grid_material.setUniformValue('u_gridColor0', Color(245, 245, 245, 255))
|
||||
self._grid_material.setUniformValue('u_gridColor1', Color(205, 202, 201, 255))
|
||||
self._grid_material.setUniformValue("u_gridColor0", Color(245, 245, 245, 255))
|
||||
self._grid_material.setUniformValue("u_gridColor1", Color(205, 202, 201, 255))
|
||||
|
||||
renderer.queueNode(self, material = self._material, mode = Renderer.RenderLines)
|
||||
renderer.queueNode(self, mesh = self._grid_mesh, material = self._grid_material)
|
||||
|
@ -47,9 +47,9 @@ class ConvexHullNode(SceneNode):
|
||||
|
||||
def render(self, renderer):
|
||||
if not self._material:
|
||||
self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, 'basic.vert'), Resources.getPath(Resources.ShadersLocation, 'color.frag'))
|
||||
self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "color.frag"))
|
||||
|
||||
self._material.setUniformValue('u_color', Color(35, 35, 35, 128))
|
||||
self._material.setUniformValue("u_color", Color(35, 35, 35, 128))
|
||||
|
||||
renderer.queueNode(self, material = self._material, transparent = True)
|
||||
|
||||
|
@ -22,6 +22,8 @@ from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Operations.SetTransformOperation import SetTransformOperation
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
|
||||
from . import PlatformPhysics
|
||||
from . import BuildVolume
|
||||
from . import CameraAnimation
|
||||
@ -33,49 +35,42 @@ from PyQt5.QtGui import QColor
|
||||
import sys
|
||||
import os.path
|
||||
import numpy
|
||||
numpy.seterr(all='ignore')
|
||||
numpy.seterr(all="ignore")
|
||||
|
||||
class PrinterApplication(QtApplication):
|
||||
class CuraApplication(QtApplication):
|
||||
def __init__(self):
|
||||
super().__init__(name = 'cura', version = "14.2.1")
|
||||
if not hasattr(sys, "frozen"):
|
||||
Resources.addResourcePath(os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))
|
||||
|
||||
if not hasattr(sys, 'frozen'):
|
||||
Resources.addResourcePath(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..'))
|
||||
super().__init__(name = "cura", version = "master")
|
||||
|
||||
self.setRequiredPlugins([
|
||||
'CuraEngineBackend',
|
||||
'MeshView',
|
||||
'LayerView',
|
||||
'STLReader',
|
||||
'SelectionTool',
|
||||
'CameraTool',
|
||||
'GCodeWriter',
|
||||
'LocalFileStorage'
|
||||
"CuraEngineBackend",
|
||||
"MeshView",
|
||||
"LayerView",
|
||||
"STLReader",
|
||||
"SelectionTool",
|
||||
"CameraTool",
|
||||
"GCodeWriter",
|
||||
"LocalFileStorage"
|
||||
])
|
||||
self._physics = None
|
||||
self._volume = None
|
||||
self._platform = None
|
||||
self._output_devices = {
|
||||
'local_file': {
|
||||
'id': 'local_file',
|
||||
'function': self._writeToLocalFile,
|
||||
'description': 'Save to Disk',
|
||||
'icon': 'save',
|
||||
'priority': 0
|
||||
}
|
||||
}
|
||||
self._output_devices = {}
|
||||
self._print_information = None
|
||||
self._i18n_catalog = None
|
||||
|
||||
self.activeMachineChanged.connect(self._onActiveMachineChanged)
|
||||
|
||||
Preferences.getInstance().addPreference('cura/active_machine', '')
|
||||
Preferences.getInstance().addPreference('cura/active_mode', 'simple')
|
||||
Preferences.getInstance().addPreference("cura/active_machine", "")
|
||||
Preferences.getInstance().addPreference("cura/active_mode", "simple")
|
||||
|
||||
## Handle loading of all plugin types (and the backend explicitly)
|
||||
# \sa PluginRegistery
|
||||
def _loadPlugins(self):
|
||||
if not hasattr(sys, 'frozen'):
|
||||
self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..', 'plugins'))
|
||||
if not hasattr(sys, "frozen"):
|
||||
self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins"))
|
||||
|
||||
self._plugin_registry.loadPlugins({ "type": "logger"})
|
||||
self._plugin_registry.loadPlugins({ "type": "storage_device" })
|
||||
@ -85,10 +80,20 @@ class PrinterApplication(QtApplication):
|
||||
self._plugin_registry.loadPlugins({ "type": "tool" })
|
||||
self._plugin_registry.loadPlugins({ "type": "extension" })
|
||||
|
||||
self._plugin_registry.loadPlugin('CuraEngineBackend')
|
||||
self._plugin_registry.loadPlugin("CuraEngineBackend")
|
||||
|
||||
def run(self):
|
||||
self.showSplashMessage('Setting up scene...')
|
||||
self._i18n_catalog = i18nCatalog("cura");
|
||||
|
||||
self.addOutputDevice("local_file", {
|
||||
"id": "local_file",
|
||||
"function": self._writeToLocalFile,
|
||||
"description": self._i18n_catalog.i18nc("Save button tooltip", "Save to Disk"),
|
||||
"icon": "save",
|
||||
"priority": 0
|
||||
})
|
||||
|
||||
self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene..."))
|
||||
|
||||
controller = self.getController()
|
||||
|
||||
@ -96,7 +101,7 @@ class PrinterApplication(QtApplication):
|
||||
controller.setCameraTool("CameraTool")
|
||||
controller.setSelectionTool("SelectionTool")
|
||||
|
||||
t = controller.getTool('TranslateTool')
|
||||
t = controller.getTool("TranslateTool")
|
||||
if t:
|
||||
t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.ZAxis])
|
||||
|
||||
@ -112,25 +117,25 @@ class PrinterApplication(QtApplication):
|
||||
|
||||
self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume)
|
||||
|
||||
camera = Camera('3d', root)
|
||||
camera = Camera("3d", root)
|
||||
camera.setPosition(Vector(-150, 150, 300))
|
||||
camera.setPerspective(True)
|
||||
camera.lookAt(Vector(0, 0, 0))
|
||||
|
||||
self._camera_animation = CameraAnimation.CameraAnimation()
|
||||
self._camera_animation.setCameraTool(self.getController().getTool('CameraTool'))
|
||||
self._camera_animation.setCameraTool(self.getController().getTool("CameraTool"))
|
||||
|
||||
controller.getScene().setActiveCamera('3d')
|
||||
controller.getScene().setActiveCamera("3d")
|
||||
|
||||
self.showSplashMessage('Loading interface...')
|
||||
self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Loading interface..."))
|
||||
|
||||
self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Printer.qml"))
|
||||
self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml"))
|
||||
self.initializeEngine()
|
||||
|
||||
self.getStorageDevice('LocalFileStorage').removableDrivesChanged.connect(self._removableDrivesChanged)
|
||||
self.getStorageDevice("LocalFileStorage").removableDrivesChanged.connect(self._removableDrivesChanged)
|
||||
|
||||
if self.getMachines():
|
||||
active_machine_pref = Preferences.getInstance().getValue('cura/active_machine')
|
||||
active_machine_pref = Preferences.getInstance().getValue("cura/active_machine")
|
||||
if active_machine_pref:
|
||||
for machine in self.getMachines():
|
||||
if machine.getName() == active_machine_pref:
|
||||
@ -148,16 +153,16 @@ class PrinterApplication(QtApplication):
|
||||
self.exec_()
|
||||
|
||||
def registerObjects(self, engine):
|
||||
engine.rootContext().setContextProperty('Printer', self)
|
||||
engine.rootContext().setContextProperty("Printer", self)
|
||||
self._print_information = PrintInformation.PrintInformation()
|
||||
engine.rootContext().setContextProperty('PrintInformation', self._print_information)
|
||||
engine.rootContext().setContextProperty("PrintInformation", self._print_information)
|
||||
|
||||
def onSelectionChanged(self):
|
||||
if Selection.hasSelection():
|
||||
if not self.getController().getActiveTool():
|
||||
self.getController().setActiveTool('TranslateTool')
|
||||
self.getController().setActiveTool("TranslateTool")
|
||||
|
||||
self._camera_animation.setStart(self.getController().getTool('CameraTool').getOrigin())
|
||||
self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin())
|
||||
self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition())
|
||||
self._camera_animation.start()
|
||||
else:
|
||||
@ -167,7 +172,7 @@ class PrinterApplication(QtApplication):
|
||||
requestAddPrinter = pyqtSignal()
|
||||
|
||||
## Remove an object from the scene
|
||||
@pyqtSlot('quint64')
|
||||
@pyqtSlot("quint64")
|
||||
def deleteObject(self, object_id):
|
||||
object = self.getController().getScene().findObject(object_id)
|
||||
|
||||
@ -176,7 +181,7 @@ class PrinterApplication(QtApplication):
|
||||
op.push()
|
||||
|
||||
## Create a number of copies of existing object.
|
||||
@pyqtSlot('quint64', int)
|
||||
@pyqtSlot("quint64", int)
|
||||
def multiplyObject(self, object_id, count):
|
||||
node = self.getController().getScene().findObject(object_id)
|
||||
|
||||
@ -192,7 +197,7 @@ class PrinterApplication(QtApplication):
|
||||
op.push()
|
||||
|
||||
## Center object on platform.
|
||||
@pyqtSlot('quint64')
|
||||
@pyqtSlot("quint64")
|
||||
def centerObject(self, object_id):
|
||||
node = self.getController().getScene().findObject(object_id)
|
||||
|
||||
@ -286,15 +291,15 @@ class PrinterApplication(QtApplication):
|
||||
|
||||
outputDevicesChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty('QVariantMap', notify = outputDevicesChanged)
|
||||
@pyqtProperty("QVariantMap", notify = outputDevicesChanged)
|
||||
def outputDevices(self):
|
||||
return self._output_devices
|
||||
|
||||
@pyqtProperty('QStringList', notify = outputDevicesChanged)
|
||||
@pyqtProperty("QStringList", notify = outputDevicesChanged)
|
||||
def outputDeviceNames(self):
|
||||
return self._output_devices.keys()
|
||||
|
||||
@pyqtSlot(str, result = 'QVariant')
|
||||
@pyqtSlot(str, result = "QVariant")
|
||||
def getSettingValue(self, key):
|
||||
if not self.getActiveMachine():
|
||||
return None
|
||||
@ -302,7 +307,7 @@ class PrinterApplication(QtApplication):
|
||||
return self.getActiveMachine().getSettingValueByKey(key)
|
||||
|
||||
## Change setting by key value pair
|
||||
@pyqtSlot(str, 'QVariant')
|
||||
@pyqtSlot(str, "QVariant")
|
||||
def setSettingValue(self, key, value):
|
||||
if not self.getActiveMachine():
|
||||
return
|
||||
@ -332,7 +337,7 @@ class PrinterApplication(QtApplication):
|
||||
|
||||
@pyqtSlot(str)
|
||||
def writeToOutputDevice(self, device):
|
||||
self._output_devices[device]['function'](device)
|
||||
self._output_devices[device]["function"](device)
|
||||
|
||||
writeToLocalFileRequested = pyqtSignal()
|
||||
|
||||
@ -345,12 +350,12 @@ class PrinterApplication(QtApplication):
|
||||
continue
|
||||
|
||||
try:
|
||||
path = self.getStorageDevice('LocalFileStorage').getRemovableDrives()[device]
|
||||
path = self.getStorageDevice("LocalFileStorage").getRemovableDrives()[device]
|
||||
except KeyError:
|
||||
Logger.log('e', 'Tried to write to unknown SD card %s', device)
|
||||
Logger.log("e", "Tried to write to unknown SD card %s", device)
|
||||
return
|
||||
|
||||
filename = os.path.join(path, node.getName()[0:node.getName().rfind('.')] + '.gcode')
|
||||
filename = os.path.join(path, node.getName()[0:node.getName().rfind(".")] + ".gcode")
|
||||
|
||||
job = WriteMeshJob(filename, node.getMeshData())
|
||||
job._sdcard = device
|
||||
@ -359,21 +364,21 @@ class PrinterApplication(QtApplication):
|
||||
return
|
||||
|
||||
def _removableDrivesChanged(self):
|
||||
drives = self.getStorageDevice('LocalFileStorage').getRemovableDrives()
|
||||
drives = self.getStorageDevice("LocalFileStorage").getRemovableDrives()
|
||||
for drive in drives:
|
||||
if drive not in self._output_devices:
|
||||
self.addOutputDevice(drive, {
|
||||
'id': drive,
|
||||
'function': self._writeToSD,
|
||||
'description': 'Save to SD Card {0}'.format(drive),
|
||||
'icon': 'save_sd',
|
||||
'priority': 1
|
||||
"id": drive,
|
||||
"function": self._writeToSD,
|
||||
"description": self._i18n_catalog.i18nc("Save button tooltip. {0} is sd card name", "Save to SD Card {0}".format(drive)),
|
||||
"icon": "save_sd",
|
||||
"priority": 1
|
||||
})
|
||||
|
||||
drives_to_remove = []
|
||||
for device in self._output_devices:
|
||||
if device not in drives:
|
||||
if self._output_devices[device]['function'] == self._writeToSD:
|
||||
if self._output_devices[device]["function"] == self._writeToSD:
|
||||
drives_to_remove.append(device)
|
||||
|
||||
for drive in drives_to_remove:
|
||||
@ -382,13 +387,13 @@ class PrinterApplication(QtApplication):
|
||||
def _onActiveMachineChanged(self):
|
||||
machine = self.getActiveMachine()
|
||||
if machine:
|
||||
Preferences.getInstance().setValue('cura/active_machine', machine.getName())
|
||||
Preferences.getInstance().setValue("cura/active_machine", machine.getName())
|
||||
|
||||
self._volume.setWidth(machine.getSettingValueByKey('machine_width'))
|
||||
self._volume.setHeight(machine.getSettingValueByKey('machine_height'))
|
||||
self._volume.setDepth(machine.getSettingValueByKey('machine_depth'))
|
||||
self._volume.setWidth(machine.getSettingValueByKey("machine_width"))
|
||||
self._volume.setHeight(machine.getSettingValueByKey("machine_height"))
|
||||
self._volume.setDepth(machine.getSettingValueByKey("machine_depth"))
|
||||
|
||||
disallowed_areas = machine.getSettingValueByKey('machine_disallowed_areas')
|
||||
disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas")
|
||||
areas = []
|
||||
if disallowed_areas:
|
||||
|
||||
@ -403,22 +408,27 @@ class PrinterApplication(QtApplication):
|
||||
|
||||
self._volume.rebuild()
|
||||
|
||||
if self.getController().getTool('ScaleTool'):
|
||||
self.getController().getTool('ScaleTool').setMaximumBounds(self._volume.getBoundingBox())
|
||||
if self.getController().getTool("ScaleTool"):
|
||||
self.getController().getTool("ScaleTool").setMaximumBounds(self._volume.getBoundingBox())
|
||||
|
||||
offset = machine.getSettingValueByKey('machine_platform_offset')
|
||||
offset = machine.getSettingValueByKey("machine_platform_offset")
|
||||
if offset:
|
||||
self._platform.setPosition(Vector(offset[0], offset[1], offset[2]))
|
||||
else:
|
||||
self._platform.setPosition(Vector(0.0, 0.0, 0.0))
|
||||
|
||||
def _onWriteToSDFinished(self, job):
|
||||
message = Message("Saved to SD Card {0} as {1}".format(job._sdcard, job.getFileName()))
|
||||
message.addAction("Eject", "eject", "Eject SD Card {0}".format(job._sdcard))
|
||||
message = Message(self._i18n_catalog.i18nc("Saved to SD message, {0} is sdcard, {1} is filename", "Saved to SD Card {0} as {1}").format(job._sdcard, job.getFileName()))
|
||||
message.addAction(
|
||||
"eject",
|
||||
self._i18n_catalog.i18nc("Message action", "Eject"),
|
||||
"eject",
|
||||
self._i18n_catalog.i18nc("Message action tooltip, {0} is sdcard", "Eject SD Card {0}".format(job._sdcard))
|
||||
)
|
||||
message._sdcard = job._sdcard
|
||||
message.actionTriggered.connect(self._onMessageActionTriggered)
|
||||
message.show()
|
||||
|
||||
def _onMessageActionTriggered(self, message, action):
|
||||
if action == "Eject":
|
||||
if action == "eject":
|
||||
self.getStorageDevice("LocalFileStorage").ejectRemovableDrive(message._sdcard)
|
@ -52,8 +52,8 @@ class PlatformPhysics:
|
||||
move_vector.setY(-bbox.bottom)
|
||||
|
||||
# If there is no convex hull for the node, start calculating it and continue.
|
||||
if not hasattr(node, '_convex_hull'):
|
||||
if not hasattr(node, '_convex_hull_job'):
|
||||
if not hasattr(node, "_convex_hull"):
|
||||
if not hasattr(node, "_convex_hull_job"):
|
||||
job = ConvexHullJob.ConvexHullJob(node)
|
||||
job.start()
|
||||
node._convex_hull_job = job
|
||||
@ -65,7 +65,7 @@ class PlatformPhysics:
|
||||
continue
|
||||
|
||||
# Ignore nodes that do not have the right properties set.
|
||||
if not hasattr(other_node, '_convex_hull') or not other_node.getBoundingBox():
|
||||
if not hasattr(other_node, "_convex_hull") or not other_node.getBoundingBox():
|
||||
continue
|
||||
|
||||
# Check to see if the bounding boxes intersect. If not, we can ignore the node as there is no way the hull intersects.
|
||||
|
@ -27,4 +27,4 @@ class PlatformPhysicsOperation(Operation):
|
||||
return group
|
||||
|
||||
def __repr__(self):
|
||||
return 'PlatformPhysicsOperation(t = {0})'.format(self._position)
|
||||
return "PlatformPhysicsOperation(t = {0})".format(self._position)
|
||||
|
@ -168,27 +168,27 @@ class PrintInformation(QObject):
|
||||
|
||||
if not self._low_quality_settings:
|
||||
self._low_quality_settings = MachineSettings()
|
||||
self._low_quality_settings.loadSettingsFromFile(Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + '.json'))
|
||||
self._low_quality_settings.loadValuesFromFile(Resources.getPath(Resources.SettingsLocation, 'profiles', 'low_quality.conf'))
|
||||
self._low_quality_settings.loadSettingsFromFile(Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + ".json"))
|
||||
self._low_quality_settings.loadValuesFromFile(Resources.getPath(Resources.SettingsLocation, "profiles", "low_quality.conf"))
|
||||
|
||||
if not self._high_quality_settings:
|
||||
self._high_quality_settings = MachineSettings()
|
||||
self._high_quality_settings.loadSettingsFromFile(Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + '.json'))
|
||||
self._high_quality_settings.loadValuesFromFile(Resources.getPath(Resources.SettingsLocation, 'profiles', 'high_quality.conf'))
|
||||
self._high_quality_settings.loadSettingsFromFile(Resources.getPath(Resources.SettingsLocation, self._current_settings.getTypeID() + ".json"))
|
||||
self._high_quality_settings.loadValuesFromFile(Resources.getPath(Resources.SettingsLocation, "profiles", "high_quality.conf"))
|
||||
|
||||
for key, options in self._interpolation_settings.items():
|
||||
minimum_value = None
|
||||
if options['minimum'] == 'low':
|
||||
if options["minimum"] == "low":
|
||||
minimum_value = self._low_quality_settings.getSettingValueByKey(key)
|
||||
elif options['minimum'] == 'high':
|
||||
elif options["minimum"] == "high":
|
||||
minimum_value = self._high_quality_settings.getSettingValueByKey(key)
|
||||
else:
|
||||
continue
|
||||
|
||||
maximum_value = None
|
||||
if options['maximum'] == 'low':
|
||||
if options["maximum"] == "low":
|
||||
maximum_value = self._low_quality_settings.getSettingValueByKey(key)
|
||||
elif options['maximum'] == 'high':
|
||||
elif options["maximum"] == "high":
|
||||
maximum_value = self._high_quality_settings.getSettingValueByKey(key)
|
||||
else:
|
||||
continue
|
||||
|
Loading…
x
Reference in New Issue
Block a user