This commit is contained in:
Tim Kuipers 2015-08-24 12:05:49 +02:00
commit 7f15505f01
48 changed files with 783 additions and 314 deletions

View File

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

View File

@ -79,11 +79,13 @@ class CuraApplication(QtApplication):
self._platform_activity = False self._platform_activity = False
self.activeMachineChanged.connect(self._onActiveMachineChanged) self.activeMachineChanged.connect(self._onActiveMachineChanged)
self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity)
Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_machine", "")
Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/active_mode", "simple")
Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/recent_files", "")
Preferences.getInstance().addPreference("cura/categories_expanded", "") Preferences.getInstance().addPreference("cura/categories_expanded", "")
Preferences.getInstance().addPreference("view/center_on_select", True)
JobQueue.getInstance().jobFinished.connect(self._onJobFinished) JobQueue.getInstance().jobFinished.connect(self._onJobFinished)
@ -115,6 +117,11 @@ class CuraApplication(QtApplication):
def run(self): def run(self):
self._i18n_catalog = i18nCatalog("cura"); self._i18n_catalog = i18nCatalog("cura");
i18nCatalog.setTagReplacements({
"filename": "font color=\"black\"",
"message": "font color=UM.Theme.colors.message_text;",
})
self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene..."))
controller = self.getController() controller = self.getController()
@ -196,10 +203,10 @@ class CuraApplication(QtApplication):
self._previous_active_tool = None self._previous_active_tool = None
else: else:
self.getController().setActiveTool("TranslateTool") self.getController().setActiveTool("TranslateTool")
if Preferences.getInstance().getValue("view/center_on_select"):
self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin()) self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin())
self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition()) self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition())
self._camera_animation.start() self._camera_animation.start()
else: else:
if self.getController().getActiveTool(): if self.getController().getActiveTool():
self._previous_active_tool = self.getController().getActiveTool().getPluginId() self._previous_active_tool = self.getController().getActiveTool().getPluginId()
@ -214,24 +221,15 @@ class CuraApplication(QtApplication):
def getPlatformActivity(self): def getPlatformActivity(self):
return self._platform_activity return self._platform_activity
@pyqtSlot(bool) def updatePlatformActivity(self, node = None):
def setPlatformActivity(self, activity): count = 0
##Sets the _platform_activity variable on true or false depending on whether there is a mesh on the platform for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if activity == True: if type(node) is not SceneNode or not node.getMeshData():
self._platform_activity = activity continue
elif activity == False:
nodes = [] count += 1
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData(): self._platform_activity = True if count > 0 else False
continue
nodes.append(node)
i = 0
for node in nodes:
if not node.getMeshData():
continue
i += 1
if i <= 1: ## i == 0 when the meshes are removed using the deleteAll function; i == 1 when the last remaining mesh is removed using the deleteObject function
self._platform_activity = activity
self.activityChanged.emit() self.activityChanged.emit()
## Remove an object from the scene ## Remove an object from the scene
@ -252,8 +250,7 @@ class CuraApplication(QtApplication):
group_node = group_node.getParent() group_node = group_node.getParent()
op = RemoveSceneNodeOperation(group_node) op = RemoveSceneNodeOperation(group_node)
op.push() op.push()
self.setPlatformActivity(False)
## Create a number of copies of existing object. ## Create a number of copies of existing object.
@pyqtSlot("quint64", int) @pyqtSlot("quint64", int)
def multiplyObject(self, object_id, count): def multiplyObject(self, object_id, count):
@ -300,8 +297,7 @@ class CuraApplication(QtApplication):
op.addOperation(RemoveSceneNodeOperation(node)) op.addOperation(RemoveSceneNodeOperation(node))
op.push() op.push()
self.setPlatformActivity(False)
## Reset all translation on nodes with mesh data. ## Reset all translation on nodes with mesh data.
@pyqtSlot() @pyqtSlot()
def resetAllTranslation(self): def resetAllTranslation(self):

View File

@ -12,6 +12,8 @@ from UM.Math.Vector import Vector
from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Math.AxisAlignedBox import AxisAlignedBox
from UM.Application import Application from UM.Application import Application
from UM.Scene.Selection import Selection from UM.Scene.Selection import Selection
from UM.Preferences import Preferences
from cura.ConvexHullDecorator import ConvexHullDecorator from cura.ConvexHullDecorator import ConvexHullDecorator
from . import PlatformPhysicsOperation from . import PlatformPhysicsOperation
@ -37,6 +39,8 @@ class PlatformPhysics:
self._change_timer.setSingleShot(True) self._change_timer.setSingleShot(True)
self._change_timer.timeout.connect(self._onChangeTimerFinished) self._change_timer.timeout.connect(self._onChangeTimerFinished)
Preferences.getInstance().addPreference("physics/automatic_push_free", True)
def _onSceneChanged(self, source): def _onSceneChanged(self, source):
self._change_timer.start() self._change_timer.start()
@ -82,7 +86,7 @@ class PlatformPhysics:
elif Selection.isSelected(node): elif Selection.isSelected(node):
pass pass
else: elif Preferences.getInstance().getValue("physics/automatic_push_free"):
# Check for collisions between convex hulls # Check for collisions between convex hulls
for other_node in BreadthFirstIterator(root): for other_node in BreadthFirstIterator(root):
# Ignore root, ourselves and anything that is not a normal SceneNode. # Ignore root, ourselves and anything that is not a normal SceneNode.

View File

@ -15,16 +15,21 @@ import os
import struct import struct
import math import math
from os import listdir from os import listdir
import untangle
import zipfile import zipfile
import xml.etree.ElementTree as ET
## Base implementation for reading 3MF files. Has no support for textures. Only loads meshes! ## Base implementation for reading 3MF files. Has no support for textures. Only loads meshes!
class ThreeMFReader(MeshReader): class ThreeMFReader(MeshReader):
def __init__(self): def __init__(self):
super(ThreeMFReader, self).__init__() super(ThreeMFReader, self).__init__()
self._supported_extension = ".3mf" self._supported_extension = ".3mf"
self._namespaces = {
"3mf": "http://schemas.microsoft.com/3dmanufacturing/core/2015/02",
"cura": "http://software.ultimaker.com/xml/cura/3mf/2015/10"
}
def read(self, file_name): def read(self, file_name):
result = None result = None
extension = os.path.splitext(file_name)[1] extension = os.path.splitext(file_name)[1]
@ -33,32 +38,39 @@ class ThreeMFReader(MeshReader):
# The base object of 3mf is a zipped archive. # The base object of 3mf is a zipped archive.
archive = zipfile.ZipFile(file_name, 'r') archive = zipfile.ZipFile(file_name, 'r')
try: try:
# The model is always stored in this place. root = ET.parse(archive.open("3D/3dmodel.model"))
root = untangle.parse(archive.read("3D/3dmodel.model").decode("utf-8"))
for object in root.model.resources.object: # There can be multiple objects, try to load all of them. # There can be multiple objects, try to load all of them.
objects = root.findall("./3mf:resources/3mf:object", self._namespaces)
for object in objects:
mesh = MeshData() mesh = MeshData()
node = SceneNode() node = SceneNode()
vertex_list = [] vertex_list = []
for vertex in object.mesh.vertices.vertex: #for vertex in object.mesh.vertices.vertex:
vertex_list.append([vertex['x'],vertex['y'],vertex['z']]) for vertex in object.findall(".//3mf:vertex", self._namespaces):
vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
triangles = object.findall(".//3mf:triangle", self._namespaces)
mesh.reserveFaceCount(len(triangles))
mesh.reserveFaceCount(len(object.mesh.triangles.triangle)) #for triangle in object.mesh.triangles.triangle:
for triangle in triangles:
for triangle in object.mesh.triangles.triangle: v1 = int(triangle.get("v1"))
v1 = int(triangle["v1"]) v2 = int(triangle.get("v2"))
v2 = int(triangle["v2"]) v3 = int(triangle.get("v3"))
v3 = int(triangle["v3"])
mesh.addFace(vertex_list[v1][0],vertex_list[v1][1],vertex_list[v1][2],vertex_list[v2][0],vertex_list[v2][1],vertex_list[v2][2],vertex_list[v3][0],vertex_list[v3][1],vertex_list[v3][2]) mesh.addFace(vertex_list[v1][0],vertex_list[v1][1],vertex_list[v1][2],vertex_list[v2][0],vertex_list[v2][1],vertex_list[v2][2],vertex_list[v3][0],vertex_list[v3][1],vertex_list[v3][2])
#TODO: We currently do not check for normals and simply recalculate them. #TODO: We currently do not check for normals and simply recalculate them.
mesh.calculateNormals() mesh.calculateNormals()
node.setMeshData(mesh) node.setMeshData(mesh)
node.setSelectable(True) node.setSelectable(True)
# Magical python comprehension; looks for the matching transformation transformation = root.findall("./3mf:build/3mf:item[@objectid='{0}']".format(object.get("id")), self._namespaces)
transformation = next((x for x in root.model.build.item if x["objectid"] == object["id"]), None) if transformation:
transformation = transformation[0]
if transformation["transform"]:
splitted_transformation = transformation["transform"].split() if transformation.get("transform"):
splitted_transformation = transformation.get("transform").split()
## Transformation is saved as: ## Transformation is saved as:
## M00 M01 M02 0.0 ## M00 M01 M02 0.0
## M10 M11 M12 0.0 ## M10 M11 M12 0.0
@ -99,10 +111,10 @@ class ThreeMFReader(MeshReader):
rotation = Quaternion.fromAngleAxis(-0.5 * math.pi, Vector(1,0,0)) rotation = Quaternion.fromAngleAxis(-0.5 * math.pi, Vector(1,0,0))
node.rotate(rotation) node.rotate(rotation)
result.addChild(node) result.addChild(node)
# If there is more then one object, group them. #If there is more then one object, group them.
try: try:
if len(root.model.resources.object) > 1: if len(objects) > 1:
group_decorator = GroupDecorator() group_decorator = GroupDecorator()
result.addDecorator(group_decorator) result.addDecorator(group_decorator)
except: except:

View File

@ -130,6 +130,7 @@ class CuraEngineBackend(Backend):
if not getattr(node, "_outside_buildarea", False): if not getattr(node, "_outside_buildarea", False):
temp_list.append(node) temp_list.append(node)
if len(temp_list) == 0: if len(temp_list) == 0:
self.processingProgress.emit(0.0)
return return
object_groups.append(temp_list) object_groups.append(temp_list)
#for node in DepthFirstIterator(self._scene.getRoot()): #for node in DepthFirstIterator(self._scene.getRoot()):
@ -241,6 +242,10 @@ class CuraEngineBackend(Backend):
self._socket.registerMessageType(6, Cura_pb2.SettingList) self._socket.registerMessageType(6, Cura_pb2.SettingList)
self._socket.registerMessageType(7, Cura_pb2.GCodePrefix) self._socket.registerMessageType(7, Cura_pb2.GCodePrefix)
## Manually triggers a reslice
def forceSlice(self):
self._change_timer.start()
def _onChanged(self): def _onChanged(self):
if not self._settings: if not self._settings:
return return

View File

@ -28,7 +28,8 @@ class LayerData(MeshData):
self._layers[layer].polygons.append(p) self._layers[layer].polygons.append(p)
def getLayer(self, layer): def getLayer(self, layer):
return self._layers[layer] if layer in self._layers:
return self._layers[layer]
def getLayers(self): def getLayers(self):
return self._layers return self._layers

View File

@ -17,8 +17,8 @@ class RemovableDriveOutputDevice(OutputDevice):
super().__init__(device_id) super().__init__(device_id)
self.setName(device_name) self.setName(device_name)
self.setShortDescription(catalog.i18nc("", "Save to Removable Drive")) self.setShortDescription(catalog.i18nc("@action:button", "Save to Removable Drive"))
self.setDescription(catalog.i18nc("", "Save to Removable Drive {0}").format(device_name)) self.setDescription(catalog.i18nc("@info:tooltip", "Save to Removable Drive {0}").format(device_name))
self.setIconName("save_sd") self.setIconName("save_sd")
self.setPriority(1) self.setPriority(1)
@ -49,7 +49,7 @@ class RemovableDriveOutputDevice(OutputDevice):
job.progress.connect(self._onProgress) job.progress.connect(self._onProgress)
job.finished.connect(self._onFinished) job.finished.connect(self._onFinished)
message = Message(catalog.i18nc("", "Saving to Removable Drive {0}").format(self.getName()), 0, False, -1) message = Message(catalog.i18nc("@info:status", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1)
message.show() message.show()
job._message = message job._message = message

View File

@ -22,7 +22,7 @@ UM.Dialog
Column Column
{ {
anchors.fill: parent; anchors.fill: parent;
Text Text
{ {
anchors { anchors {

View File

@ -44,6 +44,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
self._connect_thread = threading.Thread(target = self._connect) self._connect_thread = threading.Thread(target = self._connect)
self._connect_thread.daemon = True self._connect_thread.daemon = True
self._end_stop_thread = threading.Thread(target = self._pollEndStop)
self._end_stop_thread.deamon = True
# Printer is connected # Printer is connected
self._is_connected = False self._is_connected = False
@ -52,7 +55,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
# The baud checking is done by sending a number of m105 commands to the printer and waiting for a readable # The baud checking is done by sending a number of m105 commands to the printer and waiting for a readable
# response. If the baudrate is correct, this should make sense, else we get giberish. # response. If the baudrate is correct, this should make sense, else we get giberish.
self._required_responses_auto_baud = 10 self._required_responses_auto_baud = 3
self._progress = 0 self._progress = 0
@ -60,8 +63,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
self._listen_thread.daemon = True self._listen_thread.daemon = True
self._update_firmware_thread = threading.Thread(target= self._updateFirmware) self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
self._update_firmware_thread.demon = True self._update_firmware_thread.deamon = True
self._heatup_wait_start_time = time.time() self._heatup_wait_start_time = time.time()
## Queue for commands that need to be send. Used when command is sent when a print is active. ## Queue for commands that need to be send. Used when command is sent when a print is active.
@ -97,6 +100,14 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
# Current Z stage location # Current Z stage location
self._current_z = 0 self._current_z = 0
self._x_min_endstop_pressed = False
self._y_min_endstop_pressed = False
self._z_min_endstop_pressed = False
self._x_max_endstop_pressed = False
self._y_max_endstop_pressed = False
self._z_max_endstop_pressed = False
# In order to keep the connection alive we request the temperature every so often from a different extruder. # In order to keep the connection alive we request the temperature every so often from a different extruder.
# This index is the extruder we requested data from the last time. # This index is the extruder we requested data from the last time.
self._temperature_requested_extruder_index = 0 self._temperature_requested_extruder_index = 0
@ -112,6 +123,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
extruderTemperatureChanged = pyqtSignal() extruderTemperatureChanged = pyqtSignal()
bedTemperatureChanged = pyqtSignal() bedTemperatureChanged = pyqtSignal()
endstopStateChanged = pyqtSignal(str ,bool, arguments = ["key","state"])
@pyqtProperty(float, notify = progressChanged) @pyqtProperty(float, notify = progressChanged)
def progress(self): def progress(self):
return self._progress return self._progress
@ -209,6 +222,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
self.setProgress(100, 100) self.setProgress(100, 100)
self.firmwareUpdateComplete.emit()
## Upload new firmware to machine ## Upload new firmware to machine
# \param filename full path of firmware file to be uploaded # \param filename full path of firmware file to be uploaded
def updateFirmware(self, file_name): def updateFirmware(self, file_name):
@ -216,6 +231,20 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
self._firmware_file_name = file_name self._firmware_file_name = file_name
self._update_firmware_thread.start() self._update_firmware_thread.start()
@pyqtSlot()
def startPollEndstop(self):
self._poll_endstop = True
self._end_stop_thread.start()
@pyqtSlot()
def stopPollEndstop(self):
self._poll_endstop = False
def _pollEndStop(self):
while self._is_connected and self._poll_endstop:
self.sendCommand("M119")
time.sleep(0.5)
## Private connect function run by thread. Can be started by calling connect. ## Private connect function run by thread. Can be started by calling connect.
def _connect(self): def _connect(self):
Logger.log("d", "Attempting to connect to %s", self._serial_port) Logger.log("d", "Attempting to connect to %s", self._serial_port)
@ -255,9 +284,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
if line is None: if line is None:
self.setIsConnected(False) # Something went wrong with reading, could be that close was called. self.setIsConnected(False) # Something went wrong with reading, could be that close was called.
return return
if b"T:" in line: if b"T:" in line:
self._serial.timeout = 0.5 self._serial.timeout = 0.5
self._sendCommand("M105")
sucesfull_responses += 1 sucesfull_responses += 1
if sucesfull_responses >= self._required_responses_auto_baud: if sucesfull_responses >= self._required_responses_auto_baud:
self._serial.timeout = 2 #Reset serial timeout self._serial.timeout = 2 #Reset serial timeout
@ -265,6 +294,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
Logger.log("i", "Established printer connection on port %s" % self._serial_port) Logger.log("i", "Established printer connection on port %s" % self._serial_port)
return return
self._sendCommand("M105") # Send M105 as long as we are listening, otherwise we end up in an undefined state
Logger.log("e", "Baud rate detection for %s failed", self._serial_port) Logger.log("e", "Baud rate detection for %s failed", self._serial_port)
self.close() # Unable to connect, wrap up. self.close() # Unable to connect, wrap up.
self.setIsConnected(False) self.setIsConnected(False)
@ -297,6 +328,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
except Exception as e: except Exception as e:
pass # This should work, but it does fail sometimes for some reason pass # This should work, but it does fail sometimes for some reason
self._connect_thread = threading.Thread(target=self._connect)
self._connect_thread.daemon = True
if self._serial is not None: if self._serial is not None:
self.setIsConnected(False) self.setIsConnected(False)
try: try:
@ -305,11 +339,30 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
pass pass
self._serial.close() self._serial.close()
self._listen_thread = threading.Thread(target=self._listen)
self._listen_thread.daemon = True
self._serial = None self._serial = None
def isConnected(self): def isConnected(self):
return self._is_connected return self._is_connected
@pyqtSlot(int)
def heatupNozzle(self, temperature):
self._sendCommand("M104 S%s" % temperature)
@pyqtSlot(int)
def heatupBed(self, temperature):
self._sendCommand("M140 S%s" % temperature)
@pyqtSlot("long", "long","long")
def moveHead(self, x, y, z):
print("Moving head" , x , " ", y , " " , z)
self._sendCommand("G0 X%s Y%s Z%s"%(x,y,z))
@pyqtSlot()
def homeHead(self):
self._sendCommand("G28")
## Directly send the command, withouth checking connection state (eg; printing). ## Directly send the command, withouth checking connection state (eg; printing).
# \param cmd string with g-code # \param cmd string with g-code
def _sendCommand(self, cmd): def _sendCommand(self, cmd):
@ -402,6 +455,20 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
def requestWrite(self, node): def requestWrite(self, node):
self.showControlInterface() self.showControlInterface()
def _setEndstopState(self, endstop_key, value):
if endstop_key == b'x_min':
if self._x_min_endstop_pressed != value:
self.endstopStateChanged.emit('x_min', value)
self._x_min_endstop_pressed = value
elif endstop_key == b'y_min':
if self._y_min_endstop_pressed != value:
self.endstopStateChanged.emit('y_min', value)
self._y_min_endstop_pressed = value
elif endstop_key == b'z_min':
if self._z_min_endstop_pressed != value:
self.endstopStateChanged.emit('z_min', value)
self._z_min_endstop_pressed = value
## Listen thread function. ## Listen thread function.
def _listen(self): def _listen(self):
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)
@ -413,6 +480,14 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
if line is None: if line is None:
break # None is only returned when something went wrong. Stop listening break # None is only returned when something went wrong. Stop listening
if time.time() > temperature_request_timeout:
if self._extruder_count > 0:
self._temperature_requested_extruder_index = (self._temperature_requested_extruder_index + 1) % self._extruder_count
self.sendCommand("M105 T%d" % (self._temperature_requested_extruder_index))
else:
self.sendCommand("M105")
temperature_request_timeout = time.time() + 5
if line.startswith(b"Error:"): if line.startswith(b"Error:"):
# Oh YEAH, consistency. # Oh YEAH, consistency.
# Marlin reports an MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n" # Marlin reports an MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n"
@ -437,16 +512,11 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
except Exception as e: except Exception as e:
pass pass
#TODO: temperature changed callback #TODO: temperature changed callback
elif b"_min" in line or b"_max" in line:
tag, value = line.split(b':', 1)
self._setEndstopState(tag,(b'H' in value or b'TRIGGERED' in value))
if self._is_printing: if self._is_printing:
if time.time() > temperature_request_timeout: # When printing, request temperature every 5 seconds.
if self._extruder_count > 0:
self._temperature_requested_extruder_index = (self._temperature_requested_extruder_index + 1) % self._extruder_count
self.sendCommand("M105 T%d" % (self._temperature_requested_extruder_index))
else:
self.sendCommand("M105")
temperature_request_timeout = time.time() + 5
if line == b"" and time.time() > ok_timeout: if line == b"" and time.time() > ok_timeout:
line = b"ok" # Force a timeout (basicly, send next command) line = b"ok" # Force a timeout (basicly, send next command)
@ -540,3 +610,10 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
def _getBaudrateList(self): def _getBaudrateList(self):
ret = [250000, 230400, 115200, 57600, 38400, 19200, 9600] ret = [250000, 230400, 115200, 57600, 38400, 19200, 9600]
return ret return ret
def _onFirmwareUpdateComplete(self):
self._update_firmware_thread.join()
self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
self._update_firmware_thread.deamon = True
self.connect()

View File

@ -10,6 +10,7 @@ from UM.Resources import Resources
from UM.Logger import Logger from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from UM.Qt.ListModel import ListModel
import threading import threading
import platform import platform
@ -35,6 +36,7 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
Extension.__init__(self) Extension.__init__(self)
self._serial_port_list = [] self._serial_port_list = []
self._printer_connections = {} self._printer_connections = {}
self._printer_connections_model = None
self._update_thread = threading.Thread(target = self._updateThread) self._update_thread = threading.Thread(target = self._updateThread)
self._update_thread.setDaemon(True) self._update_thread.setDaemon(True)
@ -49,6 +51,7 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
self.addConnectionSignal.connect(self.addConnection) #Because the model needs to be created in the same thread as the QMLEngine, we use a signal. self.addConnectionSignal.connect(self.addConnection) #Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
addConnectionSignal = Signal() addConnectionSignal = Signal()
printerConnectionStateChanged = pyqtSignal()
def start(self): def start(self):
self._check_updates = True self._check_updates = True
@ -84,15 +87,31 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
self.spawnFirmwareInterface("") self.spawnFirmwareInterface("")
for printer_connection in self._printer_connections: for printer_connection in self._printer_connections:
try: try:
printer_connection.updateFirmware(Resources.getPath(Resources.FirmwareLocation, self._getDefaultFirmwareName())) self._printer_connections[printer_connection].updateFirmware(Resources.getPath(Resources.FirmwareLocation, self._getDefaultFirmwareName()))
except FileNotFoundError: except FileNotFoundError:
continue continue
@pyqtSlot(str, result = bool)
def updateFirmwareBySerial(self, serial_port): def updateFirmwareBySerial(self, serial_port):
printer_connection = self.getConnectionByPort(serial_port) if serial_port in self._printer_connections:
if printer_connection is not None: self.spawnFirmwareInterface(self._printer_connections[serial_port].getSerialPort())
self.spawnFirmwareInterface(printer_connection.getSerialPort()) try:
printer_connection.updateFirmware(Resources.getPath(Resources.FirmwareLocation, self._getDefaultFirmwareName())) self._printer_connections[serial_port].updateFirmware(Resources.getPath(Resources.FirmwareLocation, self._getDefaultFirmwareName()))
except FileNotFoundError:
self._firmware_view.close()
Logger.log("e", "Could not find firmware required for this machine")
return False
return True
return False
## Return the singleton instance of the USBPrinterManager
@classmethod
def getInstance(cls, engine = None, script_engine = None):
# Note: Explicit use of class name to prevent issues with inheritance.
if USBPrinterManager._instance is None:
USBPrinterManager._instance = cls()
return USBPrinterManager._instance
def _getDefaultFirmwareName(self): def _getDefaultFirmwareName(self):
machine_type = Application.getInstance().getActiveMachine().getTypeID() machine_type = Application.getInstance().getActiveMachine().getTypeID()
@ -140,6 +159,17 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
self.getOutputDeviceManager().addOutputDevice(self._printer_connections[serial_port]) self.getOutputDeviceManager().addOutputDevice(self._printer_connections[serial_port])
else: else:
self.getOutputDeviceManager().removeOutputDevice(serial_port) self.getOutputDeviceManager().removeOutputDevice(serial_port)
self.printerConnectionStateChanged.emit()
@pyqtProperty(QObject , notify = printerConnectionStateChanged)
def connectedPrinterList(self):
self._printer_connections_model = ListModel()
self._printer_connections_model.addRoleName(Qt.UserRole + 1,"name")
self._printer_connections_model.addRoleName(Qt.UserRole + 2, "printer")
for connection in self._printer_connections:
if self._printer_connections[connection].isConnected():
self._printer_connections_model.appendItem({"name":connection, "printer": self._printer_connections[connection]})
return self._printer_connections_model
## Create a list of serial ports on the system. ## Create a list of serial ports on the system.
# \param only_list_usb If true, only usb ports are listed # \param only_list_usb If true, only usb ports are listed
@ -163,4 +193,6 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
base_list = filter(lambda s: "Bluetooth" not in s, base_list) # Filter because mac sometimes puts them in the list base_list = filter(lambda s: "Bluetooth" not in s, base_list) # Filter because mac sometimes puts them in the list
else: else:
base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/rfcomm*") + glob.glob("/dev/serial/by-id/*") base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/rfcomm*") + glob.glob("/dev/serial/by-id/*")
return list(base_list) return list(base_list)
_instance = None

View File

@ -2,7 +2,7 @@
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from . import USBPrinterManager from . import USBPrinterManager
from PyQt5.QtQml import qmlRegisterType, qmlRegisterSingletonType
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura") i18n_catalog = i18nCatalog("cura")
@ -19,4 +19,5 @@ def getMetaData():
} }
def register(app): def register(app):
return {"extension":USBPrinterManager.USBPrinterManager(),"output_device": USBPrinterManager.USBPrinterManager() } qmlRegisterSingletonType(USBPrinterManager.USBPrinterManager, "UM", 1, 0, "USBPrinterManager", USBPrinterManager.USBPrinterManager.getInstance)
return {"extension":USBPrinterManager.USBPrinterManager.getInstance(),"output_device": USBPrinterManager.USBPrinterManager.getInstance() }

View File

@ -40,10 +40,18 @@ Item {
property alias reportBug: reportBugAction; property alias reportBug: reportBugAction;
property alias about: aboutAction; property alias about: aboutAction;
property alias toggleFullScreen: toggleFullScreenAction;
Action
{
id:toggleFullScreenAction
shortcut: StandardKey.FullScreen;
}
Action { Action {
id: undoAction; id: undoAction;
//: Undo action //: Undo action
text: qsTr("&Undo"); text: qsTr("Undo");
iconName: "edit-undo"; iconName: "edit-undo";
shortcut: StandardKey.Undo; shortcut: StandardKey.Undo;
} }
@ -51,7 +59,7 @@ Item {
Action { Action {
id: redoAction; id: redoAction;
//: Redo action //: Redo action
text: qsTr("&Redo"); text: qsTr("Redo");
iconName: "edit-redo"; iconName: "edit-redo";
shortcut: StandardKey.Redo; shortcut: StandardKey.Redo;
} }
@ -59,7 +67,7 @@ Item {
Action { Action {
id: quitAction; id: quitAction;
//: Quit action //: Quit action
text: qsTr("&Quit"); text: qsTr("Quit");
iconName: "application-exit"; iconName: "application-exit";
shortcut: StandardKey.Quit; shortcut: StandardKey.Quit;
} }
@ -67,20 +75,20 @@ Item {
Action { Action {
id: preferencesAction; id: preferencesAction;
//: Preferences action //: Preferences action
text: qsTr("&Preferences..."); text: qsTr("Preferences...");
iconName: "configure"; iconName: "configure";
} }
Action { Action {
id: addMachineAction; id: addMachineAction;
//: Add Printer action //: Add Printer action
text: qsTr("&Add Printer..."); text: qsTr("Add Printer...");
} }
Action { Action {
id: settingsAction; id: settingsAction;
//: Configure Printers action //: Configure Printers action
text: qsTr("&Configure Printers"); text: qsTr("Configure Printers");
iconName: "configure"; iconName: "configure";
} }
@ -102,7 +110,7 @@ Item {
Action { Action {
id: aboutAction; id: aboutAction;
//: About action //: About action
text: qsTr("&About..."); text: qsTr("About...");
iconName: "help-about"; iconName: "help-about";
} }
@ -190,7 +198,7 @@ Item {
Action { Action {
id: openAction; id: openAction;
//: Open file action //: Open file action
text: qsTr("&Open..."); text: qsTr("Load file");
iconName: "document-open"; iconName: "document-open";
shortcut: StandardKey.Open; shortcut: StandardKey.Open;
} }
@ -198,7 +206,7 @@ Item {
Action { Action {
id: saveAction; id: saveAction;
//: Save file action //: Save file action
text: qsTr("&Save..."); text: qsTr("Save...");
iconName: "document-save"; iconName: "document-save";
shortcut: StandardKey.Save; shortcut: StandardKey.Save;
} }

View File

@ -12,7 +12,6 @@ import UM 1.1 as UM
UM.MainWindow { UM.MainWindow {
id: base id: base
visible: true visible: true
//: Cura application window title //: Cura application window title
title: qsTr("Cura"); title: qsTr("Cura");
@ -212,10 +211,8 @@ UM.MainWindow {
UM.MessageStack { UM.MessageStack {
anchors { anchors {
left: toolbar.right; horizontalCenter: parent.horizontalCenter
leftMargin: UM.Theme.sizes.window_margin.width; horizontalCenterOffset: -(UM.Theme.sizes.logo.width/ 2)
right: sidebar.left;
rightMargin: UM.Theme.sizes.window_margin.width;
top: parent.verticalCenter; top: parent.verticalCenter;
bottom: parent.bottom; bottom: parent.bottom;
} }
@ -242,17 +239,15 @@ UM.MainWindow {
Button { Button {
id: openFileButton; id: openFileButton;
//style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button;
iconSource: UM.Theme.icons.open; style: UM.Theme.styles.open_file_button
style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button;
tooltip: ''; tooltip: '';
anchors { anchors {
top: parent.top; top: parent.top;
topMargin: UM.Theme.sizes.window_margin.height; topMargin: UM.Theme.sizes.loadfile_margin.height
left: parent.left; left: parent.left;
leftMargin: UM.Theme.sizes.window_margin.width; leftMargin: UM.Theme.sizes.loadfile_margin.width
} }
action: actions.open; action: actions.open;
} }
@ -349,8 +344,15 @@ UM.MainWindow {
id: preferences id: preferences
Component.onCompleted: { Component.onCompleted: {
//; Remove & re-add the general page as we want to use our own instead of uranium standard.
removePage(0);
insertPage(0, qsTr("General") , "" , Qt.resolvedUrl("./GeneralPage.qml"));
//: View preferences page title //: View preferences page title
insertPage(1, qsTr("View"), "view-preview", Qt.resolvedUrl("./ViewPage.qml")); insertPage(1, qsTr("View"), "view-preview", Qt.resolvedUrl("./ViewPage.qml"));
//Force refresh
setPage(0)
} }
} }
@ -423,6 +425,8 @@ UM.MainWindow {
reportBug.onTriggered: CuraActions.openBugReportPage(); reportBug.onTriggered: CuraActions.openBugReportPage();
showEngineLog.onTriggered: engineLog.visible = true; showEngineLog.onTriggered: engineLog.visible = true;
about.onTriggered: aboutDialog.visible = true; about.onTriggered: aboutDialog.visible = true;
toggleFullScreen.onTriggered: base.toggleFullscreen()
} }
Menu { Menu {
@ -481,7 +485,6 @@ UM.MainWindow {
onAccepted: onAccepted:
{ {
UM.MeshFileHandler.readLocalFile(fileUrl) UM.MeshFileHandler.readLocalFile(fileUrl)
Printer.setPlatformActivity(true)
} }
} }

View File

@ -0,0 +1,130 @@
// Copyright (c) 2015 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM
UM.PreferencesPage
{
//: General configuration page title
title: qsTr("General");
function reset()
{
UM.Preferences.resetPreference("general/language")
UM.Preferences.resetPreference("physics/automatic_push_free")
}
GridLayout
{
columns: 2;
//: Language selection label
Label
{
id: languageLabel
text: qsTr("Language")
}
ComboBox
{
id: languageComboBox
model: ListModel
{
id: languageList
//: English language combo box option
ListElement { text: QT_TR_NOOP("English"); code: "en" }
//: German language combo box option
ListElement { text: QT_TR_NOOP("German"); code: "de" }
//: French language combo box option
// ListElement { text: QT_TR_NOOP("French"); code: "fr" }
//: Spanish language combo box option
ListElement { text: QT_TR_NOOP("Spanish"); code: "es" }
//: Italian language combo box option
// ListElement { text: QT_TR_NOOP("Italian"); code: "it" }
//: Finnish language combo box option
ListElement { text: QT_TR_NOOP("Finnish"); code: "fi" }
//: Russian language combo box option
ListElement { text: QT_TR_NOOP("Russian"); code: "ru" }
}
currentIndex:
{
var code = UM.Preferences.getValue("general/language");
for(var i = 0; i < languageList.count; ++i)
{
if(model.get(i).code == code)
{
return i
}
}
}
onActivated: UM.Preferences.setValue("general/language", model.get(index).code)
anchors.left: languageLabel.right
anchors.top: languageLabel.top
anchors.leftMargin: 20
Component.onCompleted:
{
// Because ListModel is stupid and does not allow using qsTr() for values.
for(var i = 0; i < languageList.count; ++i)
{
languageList.setProperty(i, "text", qsTr(languageList.get(i).text));
}
// Glorious hack time. ComboBox does not update the text properly after changing the
// model. So change the indices around to force it to update.
currentIndex += 1;
currentIndex -= 1;
}
}
Label
{
id: languageCaption;
Layout.columnSpan: 2
//: Language change warning
text: qsTr("You will need to restart the application for language changes to have effect.")
wrapMode: Text.WordWrap
font.italic: true
}
CheckBox
{
id: pushFreeCheckbox
checked: 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: qsTr("Automatic push free");
onClicked: pushFreeCheckbox.checked = !pushFreeCheckbox.checked
//: Display Overhang preference tooltip
tooltip: "Are objects on the platform automatically moved so they no longer intersect"
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

@ -19,7 +19,7 @@ Item {
anchors.bottom: parent.bottom; anchors.bottom: parent.bottom;
anchors.left: parent.left; anchors.left: parent.left;
spacing: 1 spacing: UM.Theme.sizes.default_lining.width
Repeater { Repeater {
id: repeat id: repeat
@ -67,6 +67,8 @@ Item {
Behavior on opacity { NumberAnimation { duration: 100 } } Behavior on opacity { NumberAnimation { duration: 100 } }
color: UM.Theme.colors.tool_panel_background; color: UM.Theme.colors.tool_panel_background;
border.width: UM.Theme.sizes.default_lining.width
border.color: UM.Theme.colors.button_lining
Loader { Loader {
id: panel id: panel

View File

@ -8,7 +8,8 @@ import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM import UM 1.0 as UM
UM.PreferencesPage { UM.PreferencesPage
{
id: preferencesPage id: preferencesPage
//: View configuration page title //: View configuration page title
@ -17,22 +18,26 @@ UM.PreferencesPage {
function reset() function reset()
{ {
UM.Preferences.resetPreference("view/show_overhang"); UM.Preferences.resetPreference("view/show_overhang");
UM.Preferences.resetPreferences("view/center_on_select");
} }
GridLayout { GridLayout
{
columns: 2; columns: 2;
CheckBox { CheckBox
id: viewCheckbox {
id: overhangCheckbox
checked: UM.Preferences.getValue("view/show_overhang") checked: UM.Preferences.getValue("view/show_overhang")
onCheckedChanged: UM.Preferences.setValue("view/show_overhang", checked) onCheckedChanged: UM.Preferences.setValue("view/show_overhang", checked)
} }
Button { Button
{
id: viewText //is a button so the user doesn't have te click inconvenientley precise to enable or disable the checkbox id: viewText //is a button so the user doesn't have te click inconvenientley precise to enable or disable the checkbox
//: Display Overhang preference checkbox //: Display Overhang preference checkbox
text: qsTr("Display Overhang"); text: qsTr("Display Overhang");
onClicked: viewCheckbox.checked = !viewCheckbox.checked onClicked: overhangCheckbox.checked = !overhangCheckbox.checked
//: Display Overhang preference tooltip //: Display Overhang preference tooltip
tooltip: "Highlight unsupported areas of the model in red. Without support these areas will nog print properly." tooltip: "Highlight unsupported areas of the model in red. Without support these areas will nog print properly."
@ -49,6 +54,39 @@ UM.PreferencesPage {
} }
} }
} }
CheckBox
{
id: centerCheckbox
checked: UM.Preferences.getValue("view/center_on_select")
onCheckedChanged: UM.Preferences.setValue("view/center_on_select", checked)
}
Button
{
id: centerText //is a button so the user doesn't have te click inconvenientley precise to enable or disable the checkbox
//: Display Overhang preference checkbox
text: qsTr("Center camera when item is selected");
onClicked: centerCheckbox.checked = !centerCheckbox.checked
//: Display Overhang preference tooltip
tooltip: "Moves the camera so the object is in the center of the view when an object is selected"
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 } Item { Layout.fillHeight: true; Layout.columnSpan: 2 }
} }
} }

View File

@ -252,6 +252,10 @@ ColumnLayout
UM.Models.availableMachinesModel.createMachine(machineList.currentIndex, machineName.text) UM.Models.availableMachinesModel.createMachine(machineList.currentIndex, machineName.text)
var pages = UM.Models.availableMachinesModel.getItem(machineList.currentIndex).pages var pages = UM.Models.availableMachinesModel.getItem(machineList.currentIndex).pages
var old_page_count = elementRoot.getPageCount() var old_page_count = elementRoot.getPageCount()
for(var i = 0; i < UM.Models.count; i++)
{
print(UM.Models.getItem(i))
}
// Delete old pages (if any) // Delete old pages (if any)
for (var i = old_page_count - 1; i > 0; i--) for (var i = old_page_count - 1; i > 0; i--)
{ {

View File

@ -8,62 +8,47 @@ import QtQuick.Window 2.1
import UM 1.0 as UM import UM 1.0 as UM
ColumnLayout { Column
{
id: wizardPage id: wizardPage
property string title property int leveling_state: 0
property int pageWidth property bool three_point_leveling: true
property int pageHeight property int platform_width: UM.Models.settingsModel.getMachineSetting("machine_width")
property int platform_height: UM.Models.settingsModel.getMachineSetting("machine_depth")
SystemPalette{id: palette} anchors.fill: parent;
//signal openFile(string fileName) property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
//signal closeWizard() Component.onCompleted: printer_connection.homeHead()
Label
width: wizardPage.pageWidth {
height: wizardPage.pageHeight text: ""
//Component.onCompleted:console.log(UM.Models.settingsModel.getMachineSetting("machine_width"))
Connections {
target: elementRoot
onResize: {
wizardPage.width = pageWidth
wizardPage.height = pageHeight
}
} }
Button
Label { {
text: parent.title text: "Move to next position"
font.pointSize: 18; onClicked:
} {
if(wizardPage.leveling_state == 0)
Label { {
//: Add Printer wizard page description printer_connection.moveHead(platform_width /2 , platform_height,0)
text: qsTr("Please select the type of printer:");
}
ScrollView {
Layout.fillWidth: true;
ListView {
id: machineList;
model: UM.Models.availableMachinesModel
delegate: RadioButton {
exclusiveGroup: printerGroup;
text: model.name;
onClicked: {
ListView.view.currentIndex = index;
}
} }
if(wizardPage.leveling_state == 1)
{
printer_connection.moveHead(platform_width , 0,0)
}
if(wizardPage.leveling_state == 2)
{
printer_connection.moveHead(0, 0 ,0)
}
wizardPage.leveling_state++
} }
} }
Label { function threePointLeveling(width, height)
//: Add Printer wizard field label {
text: qsTr("Printer Name:");
} }
TextField { id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name }
Item { Layout.fillWidth: true; Layout.fillHeight: true; }
ExclusiveGroup { id: printerGroup; }
} }

View File

@ -13,6 +13,16 @@ Column
id: wizardPage id: wizardPage
property string title property string title
anchors.fill: parent; anchors.fill: parent;
property bool x_min_pressed: false
property bool y_min_pressed: false
property bool z_min_pressed: false
property bool heater_works: false
property int extruder_target_temp: 0
property int bed_target_temp: 0
property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
Component.onCompleted: printer_connection.startPollEndstop()
Component.onDestruction: printer_connection.stopPollEndstop()
Label Label
{ {
@ -23,44 +33,144 @@ Column
Label Label
{ {
//: Add Printer wizard page description //: Add Printer wizard page description
text: qsTr("Please select the type of printer:"); text: qsTr("It's a good idea to do a few sanity checks on your Ultimaker. \n You can skip these if you know your machine is functional");
} }
ScrollView Row
{ {
height: parent.height - 50 Label
width: parent.width
ListView
{ {
id: machineList; text: qsTr("Connection: ")
model: UM.Models.availableMachinesModel }
delegate: RadioButton Label
{ {
exclusiveGroup: printerGroup; text: UM.USBPrinterManager.connectedPrinterList.count ? "Done":"Incomplete"
text: model.name; }
onClicked: }
{ Row
ListView.view.currentIndex = index; {
} Label
} {
text: qsTr("Min endstop X: ")
}
Label
{
text: x_min_pressed ? qsTr("Works") : qsTr("Not checked")
}
}
Row
{
Label
{
text: qsTr("Min endstop Y: ")
}
Label
{
text: y_min_pressed ? qsTr("Works") : qsTr("Not checked")
} }
} }
Label Row
{ {
//: Add Printer wizard field label Label
text: qsTr("Printer Name:"); {
text: qsTr("Min endstop Z: ")
}
Label
{
text: z_min_pressed ? qsTr("Works") : qsTr("Not checked")
}
} }
TextField Row
{ {
id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name Label
{
text: qsTr("Nozzle temperature check: ")
}
Label
{
text: printer_connection.extruderTemperature
}
Button
{
text: "Start heating"
onClicked:
{
heater_status_label.text = qsTr("Checking")
printer_connection.heatupNozzle(190)
wizardPage.extruder_target_temp = 190
}
}
Label
{
id: heater_status_label
text: qsTr("Not checked")
}
} }
Item Row
{ {
Layout.fillWidth: true; Label
Layout.fillHeight: true; {
text: qsTr("bed temperature check: ")
}
Label
{
text: printer_connection.bedTemperature
}
Button
{
text: "Start heating"
onClicked:
{
bed_status_label.text = qsTr("Checking")
printer_connection.printer.heatupBed(60)
wizardPage.bed_target_temp = 60
}
}
Label
{
id: bed_status_label
text: qsTr("Not checked")
}
}
Connections
{
target: printer_connection
onEndstopStateChanged:
{
if(key == "x_min")
{
x_min_pressed = true
}
if(key == "y_min")
{
y_min_pressed = true
}
if(key == "z_min")
{
z_min_pressed = true
}
}
onExtruderTemperatureChanged:
{
if(printer_connection.extruderTemperature > wizardPage.extruder_target_temp - 10 && printer_connection.extruderTemperature < wizardPage.extruder_target_temp + 10)
{
heater_status_label.text = qsTr("Works")
printer_connection.heatupNozzle(0)
}
}
onBedTemperatureChanged:
{
if(printer_connection.bedTemperature > wizardPage.bed_target_temp - 5 && printer_connection.bedTemperature < wizardPage.bed_target_temp + 5)
{
bed_status_label.text = qsTr("Works")
printer_connection.heatupBed(0)
}
}
} }
ExclusiveGroup ExclusiveGroup

View File

@ -13,19 +13,12 @@ Column
id: wizardPage id: wizardPage
property string title property string title
anchors.fill: parent; anchors.fill: parent;
Label Label
{ {
text: parent.title text: parent.title
font.pointSize: 18; font.pointSize: 18;
} }
Label
{
//: Add Printer wizard page description
text: qsTr("Please select the type of printer:");
}
ScrollView ScrollView
{ {
height: parent.height - 50 height: parent.height - 50
@ -33,14 +26,26 @@ Column
ListView ListView
{ {
id: machineList; id: machineList;
model: UM.Models.availableMachinesModel model: UM.USBPrinterManager.connectedPrinterList
delegate: RadioButton
delegate:Row
{ {
exclusiveGroup: printerGroup; id: derp
text: model.name; Text
onClicked:
{ {
ListView.view.currentIndex = index; id: text_area
text: model.name
}
Button
{
text: "Update";
onClicked:
{
if(!UM.USBPrinterManager.updateFirmwareBySerial(text_area.text))
{
status_text.text = "ERROR"
}
}
} }
} }
} }
@ -48,15 +53,10 @@ Column
Label Label
{ {
//: Add Printer wizard field label id: status_text
text: qsTr("Printer Name:"); text: ""
} }
TextField
{
id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name
}
Item Item
{ {
@ -64,8 +64,5 @@ Column
Layout.fillHeight: true; Layout.fillHeight: true;
} }
ExclusiveGroup
{
id: printerGroup;
}
} }

View File

@ -28,21 +28,6 @@
"machine_center_is_zero": { "machine_center_is_zero": {
"default": false "default": false
}, },
"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_extruder_count": { "machine_extruder_count": {
"default": 1 "default": 1
}, },
@ -67,20 +52,20 @@
"machine_head_polygon": { "machine_head_polygon": {
"default": [ "default": [
[ [
-10, -1,
10 1
], ],
[ [
10, -1,
10 -1
], ],
[ [
10, 1,
-10 -1
], ],
[ [
-10, 1,
-10 1
] ]
] ]
}, },

View File

@ -38,14 +38,30 @@
"machine_height": { "default": 205 }, "machine_height": { "default": 205 },
"machine_heated_bed": { "default": true }, "machine_heated_bed": { "default": true },
"machine_head_with_fans_polygon":
{
"default": [
[
-40,
30
],
[
-40,
-10
],
[
60,
-10
],
[
60,
30
]
]
},
"machine_center_is_zero": { "default": false }, "machine_center_is_zero": { "default": false },
"machine_nozzle_size": { "default": 0.4 }, "machine_nozzle_size": { "default": 0.4 },
"machine_head_shape_min_x": { "default": 40 }, "gantry_height": { "default": 55 },
"machine_head_shape_min_y": { "default": 10 },
"machine_head_shape_max_x": { "default": 60 },
"machine_head_shape_max_y": { "default": 30 },
"machine_nozzle_gantry_distance": { "default": 55 },
"machine_use_extruder_offset_to_offset_coords": { "default": true }, "machine_use_extruder_offset_to_offset_coords": { "default": true },
"machine_gcode_flavor": { "default": "UltiGCode" }, "machine_gcode_flavor": { "default": "UltiGCode" },
"machine_disallowed_areas": { "default": [ "machine_disallowed_areas": { "default": [

View File

@ -41,11 +41,28 @@
"machine_depth": { "default": 205 }, "machine_depth": { "default": 205 },
"machine_center_is_zero": { "default": false }, "machine_center_is_zero": { "default": false },
"machine_nozzle_size": { "default": 0.4 }, "machine_nozzle_size": { "default": 0.4 },
"machine_head_shape_min_x": { "default": 75 }, "machine_head_with_fans_polygon":
"machine_head_shape_min_y": { "default": 18 }, {
"machine_head_shape_max_x": { "default": 18 }, "default": [
"machine_head_shape_max_y": { "default": 35 }, [
"machine_nozzle_gantry_distance": { "default": 55 }, -75,
35
],
[
-75,
-18
],
[
18,
35
],
[
18,
-18
]
]
},
"gantry_height": { "default": 55 },
"machine_use_extruder_offset_to_offset_coords": { "default": true }, "machine_use_extruder_offset_to_offset_coords": { "default": true },
"machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" }, "machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" },

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -35,54 +35,26 @@ QtObject {
} }
} }
property Component open_file_button: Component { property Component open_file_button: Component {
ButtonStyle { ButtonStyle {
background: Item { background: Item{
implicitWidth: UM.Theme.sizes.button.width; implicitWidth: UM.Theme.sizes.loadfile_button.width
implicitHeight: UM.Theme.sizes.button.height; implicitHeight: UM.Theme.sizes.loadfile_button.height
Rectangle { Rectangle {
anchors.bottom: parent.verticalCenter; width: parent.width
width: parent.width; height: parent.height
height: control.hovered ? parent.height / 2 + label.height : 0; color: control.hovered ? UM.Theme.colors.load_save_button_hover : UM.Theme.colors.load_save_button
Behavior on height { NumberAnimation { duration: 100; } }
opacity: control.hovered ? 1.0 : 0.0;
Behavior on opacity { NumberAnimation { duration: 100; } }
Label {
id: label;
anchors.horizontalCenter: parent.horizontalCenter;
text: control.text.replace("&", "");
font: UM.Theme.fonts.button_tooltip;
color: UM.Theme.colors.button_tooltip_text;
}
}
UM.AngledCornerRectangle {
anchors.fill: parent;
color: {
if(control.hovered) {
return UM.Theme.colors.button_active_hover;
} else {
return UM.Theme.colors.button_active;
}
}
Behavior on color { ColorAnimation { duration: 50; } } Behavior on color { ColorAnimation { duration: 50; } }
cornerSize: UM.Theme.sizes.default_margin.width; }
Label {
anchors.centerIn: parent
text: control.text
color: UM.Theme.colors.load_save_button_text
font: UM.Theme.fonts.default
} }
} }
label: Label{
label: Item { visible: false
Image {
anchors.centerIn: parent;
source: control.iconSource;
width: UM.Theme.sizes.button_icon.width;
height: UM.Theme.sizes.button_icon.height;
sourceSize: UM.Theme.sizes.button_icon;
}
} }
} }
} }
@ -90,7 +62,6 @@ QtObject {
property Component tool_button: Component { property Component tool_button: Component {
ButtonStyle { ButtonStyle {
background: Item { background: Item {
///////////TODO CHANGE SIZES!!
implicitWidth: UM.Theme.sizes.button.width; implicitWidth: UM.Theme.sizes.button.width;
implicitHeight: UM.Theme.sizes.button.height; implicitHeight: UM.Theme.sizes.button.height;
@ -99,7 +70,6 @@ QtObject {
anchors.top: parent.verticalCenter; anchors.top: parent.verticalCenter;
width: parent.width; width: parent.width;
///////////TODO CHANGE LABELHEIGHT!!
height: control.hovered ? parent.height / 2 + label.height : 0; height: control.hovered ? parent.height / 2 + label.height : 0;
Behavior on height { NumberAnimation { duration: 100; } } Behavior on height { NumberAnimation { duration: 100; } }
@ -109,7 +79,7 @@ QtObject {
Label { Label {
id: label id: label
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
text: control.text.replace("&", ""); text: control.text
font: UM.Theme.fonts.button_tooltip; font: UM.Theme.fonts.button_tooltip;
color: UM.Theme.colors.button_tooltip_text; color: UM.Theme.colors.button_tooltip_text;
} }
@ -138,13 +108,14 @@ QtObject {
Behavior on color { ColorAnimation { duration: 50; } } Behavior on color { ColorAnimation { duration: 50; } }
Label { Label {
id: tool_button_arrow
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: UM.Theme.sizes.default_margin.width / 2; anchors.rightMargin: (UM.Theme.sizes.button.width - UM.Theme.sizes.button_icon.width - tool_button_arrow.width) / 2
anchors.verticalCenter: parent.verticalCenter; anchors.verticalCenter: parent.verticalCenter;
text: "▼"; text: "▼";
font: UM.Theme.fonts.small; font: UM.Theme.fonts.small;
visible: control.menu != null; visible: control.menu != null;
color: "white"; color: UM.Theme.colors.button_text
} }
} }
} }
@ -162,34 +133,98 @@ QtObject {
} }
} }
} }
property Component tool_button_panel: Component {
ButtonStyle {
background: Item {
implicitWidth: UM.Theme.sizes.button.width;
implicitHeight: UM.Theme.sizes.button.height;
Rectangle {
id: tool_button_background
anchors.top: parent.verticalCenter;
width: parent.width;
height: control.hovered ? parent.height / 2 + label.height : 0;
Behavior on height { NumberAnimation { duration: 100; } }
opacity: control.hovered ? 1.0 : 0.0;
Behavior on opacity { NumberAnimation { duration: 100; } }
Label {
id: label
anchors.bottom: parent.bottom
text: control.text
width: UM.Theme.sizes.button.width;
wrapMode: Text.WordWrap
font: UM.Theme.fonts.button_tooltip;
color: UM.Theme.colors.button_tooltip_text;
}
}
Rectangle {
id: buttonFace;
anchors.fill: parent;
property bool down: control.pressed || (control.checkable && control.checked);
color: {
if(!control.enabled) {
return UM.Theme.colors.button_disabled;
} else if(control.checkable && control.checked && control.hovered) {
return UM.Theme.colors.button_active_hover;
} else if(control.pressed || (control.checkable && control.checked)) {
return UM.Theme.colors.button_active;
} else if(control.hovered) {
return UM.Theme.colors.button_hover;
} else {
return UM.Theme.colors.button;
}
}
Behavior on color { ColorAnimation { duration: 50; } }
}
}
label: Item {
Image {
anchors.centerIn: parent;
source: control.iconSource;
width: UM.Theme.sizes.button_icon.width;
height: UM.Theme.sizes.button_icon.height;
sourceSize: UM.Theme.sizes.button_icon;
}
}
}
}
property Component progressbar: Component{ property Component progressbar: Component{
ProgressBarStyle { ProgressBarStyle {
background: UM.AngledCornerRectangle { background:Rectangle {
cornerSize: UM.Theme.sizes.progressbar_control.height implicitWidth: UM.Theme.sizes.message.width - (UM.Theme.sizes.default_margin.width * 2)
implicitWidth: UM.Theme.sizes.progressbar.width
implicitHeight: UM.Theme.sizes.progressbar.height implicitHeight: UM.Theme.sizes.progressbar.height
x: UM.Theme.sizes.default_margin.width
color: UM.Theme.colors.progressbar_background color: UM.Theme.colors.progressbar_background
} }
progress: UM.AngledCornerRectangle { progress: Rectangle {
cornerSize: UM.Theme.sizes.progressbar_control.height
color: control.indeterminate ? "transparent" : UM.Theme.colors.progressbar_control color: control.indeterminate ? "transparent" : UM.Theme.colors.progressbar_control
UM.AngledCornerRectangle { Rectangle{
cornerSize: UM.Theme.sizes.progressbar_control.height
color: UM.Theme.colors.progressbar_control color: UM.Theme.colors.progressbar_control
width: UM.Theme.sizes.progressbar_control.width width: UM.Theme.sizes.progressbar_control.width
height: UM.Theme.sizes.progressbar_control.height height: UM.Theme.sizes.progressbar_control.height
x: UM.Theme.sizes.default_margin.width
visible: control.indeterminate visible: control.indeterminate
SequentialAnimation on x { SequentialAnimation on x {
id: xAnim id: xAnim
property int animEndPoint: UM.Theme.sizes.progressbar.width - UM.Theme.sizes.progressbar_control.width property int animEndPoint: UM.Theme.sizes.message.width - UM.Theme.sizes.default_margin.width - UM.Theme.sizes.progressbar_control.width
running: control.indeterminate running: control.indeterminate
loops: Animation.Infinite loops: Animation.Infinite
NumberAnimation { from: 0; to: xAnim.animEndPoint; duration: 2000;} NumberAnimation { from: UM.Theme.sizes.default_margin.width; to: xAnim.animEndPoint; duration: 2000;}
NumberAnimation { from: xAnim.animEndPoint; to: 0; duration: 2000;} NumberAnimation { from: xAnim.animEndPoint; to: UM.Theme.sizes.default_margin.width; duration: 2000;}
} }
} }
} }

View File

@ -3,52 +3,52 @@
"large": { "large": {
"size": 1.5, "size": 1.5,
"bold": true, "bold": true,
"family": "Roboto" "family": "ProximaNova"
}, },
"default": { "default": {
"size": 1, "size": 1,
"family": "Roboto" "family": "ProximaNova"
}, },
"default_allcaps": { "default_allcaps": {
"size": 1, "size": 1,
"capitalize": true, "capitalize": true,
"family": "Roboto" "family": "ProximaNova"
}, },
"small": { "small": {
"size": 0.75, "size": 0.75,
"family": "Roboto" "family": "ProximaNova"
}, },
"tiny": { "tiny": {
"size": 0.5, "size": 0.5,
"family": "Roboto" "family": "ProximaNova"
}, },
"caption": { "caption": {
"size": 0.75, "size": 0.75,
"italic": true, "italic": true,
"family": "Roboto" "family": "ProximaNova"
}, },
"sidebar_header": { "sidebar_header": {
"size": 0.75, "size": 0.75,
"capitalize": true, "capitalize": true,
"family": "Roboto" "family": "ProximaNova"
}, },
"sidebar_save_to": { "sidebar_save_to": {
"size": 1.0, "size": 1.0,
"family": "Roboto" "family": "ProximaNova"
}, },
"timeslider_time": { "timeslider_time": {
"size": 1.0, "size": 1.0,
"bold": true, "bold": true,
"family": "Roboto" "family": "ProximaNova"
}, },
"button_tooltip": { "button_tooltip": {
"size": 0.75, "size": 0.75,
"capitalize": true, "capitalize": true,
"family": "Roboto" "family": "ProximaNova"
}, },
"setting_category": { "setting_category": {
"size": 1.5, "size": 1.5,
"family": "Roboto" "family": "ProximaNova"
} }
}, },
@ -66,15 +66,20 @@
"text_hover": [35, 35, 35, 255], "text_hover": [35, 35, 35, 255],
"text_pressed": [12, 169, 227, 255], "text_pressed": [12, 169, 227, 255],
"button": [160, 163, 171, 255], "button": [139, 143, 153, 255],
"button_hover": [140, 144, 154, 255], "button_hover": [116, 120, 127, 255],
"button_active": [12, 169, 227, 255], "button_active": [12, 169, 227, 255],
"button_active_hover": [34, 150, 199, 255], "button_active_hover": [77, 184, 226, 255],
"button_lining": [140, 144, 154, 255], "button_lining": [208, 210, 211, 255],
"button_text": [255, 255, 255, 255], "button_text": [255, 255, 255, 255],
"button_disabled": [245, 245, 245, 255], "button_disabled": [245, 245, 245, 255],
"button_tooltip_text": [35, 35, 35, 255], "button_tooltip_text": [35, 35, 35, 255],
"load_save_button": [0, 0, 0, 255],
"load_save_button_text": [255, 255, 255, 255],
"load_save_button_hover": [43, 45, 46, 255],
"load_save_button_active": [43, 45, 46, 255],
"scrollbar_background": [245, 245, 245, 255], "scrollbar_background": [245, 245, 245, 255],
"scrollbar_handle": [205, 202, 201, 255], "scrollbar_handle": [205, 202, 201, 255],
"scrollbar_handle_hover": [174, 174, 174, 255], "scrollbar_handle_hover": [174, 174, 174, 255],
@ -98,7 +103,7 @@
"setting_validation_warning": [255, 186, 15, 255], "setting_validation_warning": [255, 186, 15, 255],
"setting_validation_ok": [255, 255, 255, 255], "setting_validation_ok": [255, 255, 255, 255],
"progressbar_background": [245, 245, 245, 255], "progressbar_background": [208, 210, 211, 255],
"progressbar_control": [12, 169, 227, 255], "progressbar_control": [12, 169, 227, 255],
"slider_groove": [245, 245, 245, 255], "slider_groove": [245, 245, 245, 255],
@ -126,8 +131,8 @@
"save_button_printtime_text": [12, 169, 227, 255], "save_button_printtime_text": [12, 169, 227, 255],
"save_button_background": [249, 249, 249, 255], "save_button_background": [249, 249, 249, 255],
"message": [160, 163, 171, 255], "message_background": [255, 255, 255, 255],
"message_text": [35, 35, 35, 255], "message_text": [12, 169, 227, 255],
"tool_panel_background": [255, 255, 255, 255] "tool_panel_background": [255, 255, 255, 255]
}, },
@ -135,11 +140,15 @@
"sizes": { "sizes": {
"window_margin": [2.0, 2.0], "window_margin": [2.0, 2.0],
"default_margin": [1.0, 1.0], "default_margin": [1.0, 1.0],
"default_lining": [0.1, 0.1],
"panel": [22.0, 10.0], "panel": [22.0, 10.0],
"logo": [9.5, 2.0], "logo": [9.5, 2.0],
"toolbar_button": [2.0, 2.0], "toolbar_button": [2.0, 2.0],
"toolbar_spacing": [1.0, 1.0], "toolbar_spacing": [1.0, 1.0],
"loadfile_button": [11.0, 2.4],
"loadfile_margin": [0.8, 0.4],
"section": [22.0, 3.0], "section": [22.0, 3.0],
"section_icon": [2.14, 2.14], "section_icon": [2.14, 2.14],
"section_text_margin": [0.33, 0.33], "section_text_margin": [0.33, 0.33],
@ -153,11 +162,11 @@
"standard_list_lineheight": [1.5, 1.5], "standard_list_lineheight": [1.5, 1.5],
"standard_list_input": [20.0, 25.0], "standard_list_input": [20.0, 25.0],
"button": [4.25, 4.25], "button": [3.2, 3.2],
"button_icon": [2.9, 2.9], "button_icon": [2.5, 2.5],
"progressbar": [26.0, 0.5], "progressbar": [26.0, 0.8],
"progressbar_control": [8.0, 0.5], "progressbar_control": [8.0, 0.8],
"progressbar_padding": [0.0, 1.0], "progressbar_padding": [0.0, 1.0],
"scrollbar": [0.5, 0.5], "scrollbar": [0.5, 0.5],
@ -184,6 +193,7 @@
"wizard_progress": [10.0, 0.0], "wizard_progress": [10.0, 0.0],
"message": [30.0, 5.0], "message": [30.0, 5.0],
"message_close": [1.25, 1.25] "message_close": [1.25, 1.25],
"message_button": [6.0, 1.8]
} }
} }