diff --git a/README.md b/README.md index 2fb2d6f682..f118fa66d5 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,8 @@ Please checkout [cura-build](https://github.com/Ultimaker/cura-build) Third party plugins ------------- -[Print time calculator](https://github.com/nallath/PrintCostCalculator) +* [Print time calculator](https://github.com/nallath/PrintCostCalculator) +* [Post processing plugin](https://github.com/nallath/PostProcessingPlugin) Making profiles for other printers ---------------------------------- diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index e2908c9f97..1584eaa9ab 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -79,11 +79,13 @@ class CuraApplication(QtApplication): self._platform_activity = False self.activeMachineChanged.connect(self._onActiveMachineChanged) + self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity) Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") + Preferences.getInstance().addPreference("view/center_on_select", True) JobQueue.getInstance().jobFinished.connect(self._onJobFinished) @@ -115,6 +117,11 @@ class CuraApplication(QtApplication): def run(self): 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...")) controller = self.getController() @@ -196,10 +203,10 @@ class CuraApplication(QtApplication): self._previous_active_tool = None else: self.getController().setActiveTool("TranslateTool") - - self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin()) - self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition()) - self._camera_animation.start() + if Preferences.getInstance().getValue("view/center_on_select"): + self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin()) + self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition()) + self._camera_animation.start() else: if self.getController().getActiveTool(): self._previous_active_tool = self.getController().getActiveTool().getPluginId() @@ -214,24 +221,15 @@ class CuraApplication(QtApplication): def getPlatformActivity(self): return self._platform_activity - @pyqtSlot(bool) - def setPlatformActivity(self, activity): - ##Sets the _platform_activity variable on true or false depending on whether there is a mesh on the platform - if activity == True: - self._platform_activity = activity - elif activity == False: - nodes = [] - for node in DepthFirstIterator(self.getController().getScene().getRoot()): - if type(node) is not SceneNode or not node.getMeshData(): - continue - nodes.append(node) - i = 0 - for node in nodes: - if not node.getMeshData(): - continue - i += 1 - if i <= 1: ## i == 0 when the meshes are removed using the deleteAll function; i == 1 when the last remaining mesh is removed using the deleteObject function - self._platform_activity = activity + def updatePlatformActivity(self, node = None): + count = 0 + for node in DepthFirstIterator(self.getController().getScene().getRoot()): + if type(node) is not SceneNode or not node.getMeshData(): + continue + + count += 1 + + self._platform_activity = True if count > 0 else False self.activityChanged.emit() ## Remove an object from the scene @@ -252,8 +250,7 @@ class CuraApplication(QtApplication): group_node = group_node.getParent() op = RemoveSceneNodeOperation(group_node) op.push() - self.setPlatformActivity(False) - + ## Create a number of copies of existing object. @pyqtSlot("quint64", int) def multiplyObject(self, object_id, count): @@ -300,8 +297,7 @@ class CuraApplication(QtApplication): op.addOperation(RemoveSceneNodeOperation(node)) op.push() - self.setPlatformActivity(False) - + ## Reset all translation on nodes with mesh data. @pyqtSlot() def resetAllTranslation(self): diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index ee6e39f03b..f96c81abce 100644 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -12,6 +12,8 @@ from UM.Math.Vector import Vector from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Application import Application from UM.Scene.Selection import Selection +from UM.Preferences import Preferences + from cura.ConvexHullDecorator import ConvexHullDecorator from . import PlatformPhysicsOperation @@ -37,6 +39,8 @@ class PlatformPhysics: self._change_timer.setSingleShot(True) self._change_timer.timeout.connect(self._onChangeTimerFinished) + Preferences.getInstance().addPreference("physics/automatic_push_free", True) + def _onSceneChanged(self, source): self._change_timer.start() @@ -82,7 +86,7 @@ class PlatformPhysics: elif Selection.isSelected(node): pass - else: + elif Preferences.getInstance().getValue("physics/automatic_push_free"): # Check for collisions between convex hulls for other_node in BreadthFirstIterator(root): # Ignore root, ourselves and anything that is not a normal SceneNode. diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 993f15c42a..ca3904bc4e 100644 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -15,16 +15,21 @@ import os import struct import math from os import listdir -import untangle import zipfile +import xml.etree.ElementTree as ET ## Base implementation for reading 3MF files. Has no support for textures. Only loads meshes! class ThreeMFReader(MeshReader): def __init__(self): super(ThreeMFReader, self).__init__() self._supported_extension = ".3mf" - + + self._namespaces = { + "3mf": "http://schemas.microsoft.com/3dmanufacturing/core/2015/02", + "cura": "http://software.ultimaker.com/xml/cura/3mf/2015/10" + } + def read(self, file_name): result = None extension = os.path.splitext(file_name)[1] @@ -33,32 +38,39 @@ class ThreeMFReader(MeshReader): # The base object of 3mf is a zipped archive. archive = zipfile.ZipFile(file_name, 'r') try: - # The model is always stored in this place. - 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. + root = ET.parse(archive.open("3D/3dmodel.model")) + + # There can be multiple objects, try to load all of them. + objects = root.findall("./3mf:resources/3mf:object", self._namespaces) + for object in objects: mesh = MeshData() node = SceneNode() vertex_list = [] - for vertex in object.mesh.vertices.vertex: - vertex_list.append([vertex['x'],vertex['y'],vertex['z']]) + #for vertex in object.mesh.vertices.vertex: + for vertex in object.findall(".//3mf:vertex", self._namespaces): + vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")]) + + triangles = object.findall(".//3mf:triangle", self._namespaces) + + mesh.reserveFaceCount(len(triangles)) - mesh.reserveFaceCount(len(object.mesh.triangles.triangle)) - - for triangle in object.mesh.triangles.triangle: - v1 = int(triangle["v1"]) - v2 = int(triangle["v2"]) - v3 = int(triangle["v3"]) + #for triangle in object.mesh.triangles.triangle: + for triangle in triangles: + v1 = int(triangle.get("v1")) + v2 = int(triangle.get("v2")) + v3 = int(triangle.get("v3")) mesh.addFace(vertex_list[v1][0],vertex_list[v1][1],vertex_list[v1][2],vertex_list[v2][0],vertex_list[v2][1],vertex_list[v2][2],vertex_list[v3][0],vertex_list[v3][1],vertex_list[v3][2]) #TODO: We currently do not check for normals and simply recalculate them. mesh.calculateNormals() node.setMeshData(mesh) node.setSelectable(True) - # Magical python comprehension; looks for the matching transformation - transformation = next((x for x in root.model.build.item if x["objectid"] == object["id"]), None) - - if transformation["transform"]: - splitted_transformation = transformation["transform"].split() + transformation = root.findall("./3mf:build/3mf:item[@objectid='{0}']".format(object.get("id")), self._namespaces) + if transformation: + transformation = transformation[0] + + if transformation.get("transform"): + splitted_transformation = transformation.get("transform").split() ## Transformation is saved as: ## M00 M01 M02 0.0 ## M10 M11 M12 0.0 @@ -99,10 +111,10 @@ class ThreeMFReader(MeshReader): rotation = Quaternion.fromAngleAxis(-0.5 * math.pi, Vector(1,0,0)) node.rotate(rotation) result.addChild(node) - - # If there is more then one object, group them. + + #If there is more then one object, group them. try: - if len(root.model.resources.object) > 1: + if len(objects) > 1: group_decorator = GroupDecorator() result.addDecorator(group_decorator) except: diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index f6b56b9386..26c4488857 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -130,6 +130,7 @@ class CuraEngineBackend(Backend): if not getattr(node, "_outside_buildarea", False): temp_list.append(node) if len(temp_list) == 0: + self.processingProgress.emit(0.0) return object_groups.append(temp_list) #for node in DepthFirstIterator(self._scene.getRoot()): @@ -241,6 +242,10 @@ class CuraEngineBackend(Backend): self._socket.registerMessageType(6, Cura_pb2.SettingList) self._socket.registerMessageType(7, Cura_pb2.GCodePrefix) + ## Manually triggers a reslice + def forceSlice(self): + self._change_timer.start() + def _onChanged(self): if not self._settings: return diff --git a/plugins/CuraEngineBackend/LayerData.py b/plugins/CuraEngineBackend/LayerData.py index c793c17504..597839ea39 100644 --- a/plugins/CuraEngineBackend/LayerData.py +++ b/plugins/CuraEngineBackend/LayerData.py @@ -28,7 +28,8 @@ class LayerData(MeshData): self._layers[layer].polygons.append(p) def getLayer(self, layer): - return self._layers[layer] + if layer in self._layers: + return self._layers[layer] def getLayers(self): return self._layers diff --git a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py index 2728dfd90b..9c9afa4246 100644 --- a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py +++ b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py @@ -17,8 +17,8 @@ class RemovableDriveOutputDevice(OutputDevice): super().__init__(device_id) self.setName(device_name) - self.setShortDescription(catalog.i18nc("", "Save to Removable Drive")) - self.setDescription(catalog.i18nc("", "Save to Removable Drive {0}").format(device_name)) + self.setShortDescription(catalog.i18nc("@action:button", "Save to Removable Drive")) + self.setDescription(catalog.i18nc("@info:tooltip", "Save to Removable Drive {0}").format(device_name)) self.setIconName("save_sd") self.setPriority(1) @@ -49,7 +49,7 @@ class RemovableDriveOutputDevice(OutputDevice): job.progress.connect(self._onProgress) job.finished.connect(self._onFinished) - message = Message(catalog.i18nc("", "Saving to Removable Drive {0}").format(self.getName()), 0, False, -1) + message = Message(catalog.i18nc("@info:status", "Saving to Removable Drive {0}").format(self.getName()), 0, False, -1) message.show() job._message = message diff --git a/plugins/USBPrinting/FirmwareUpdateWindow.qml b/plugins/USBPrinting/FirmwareUpdateWindow.qml index 5217e59aa1..12f4931697 100644 --- a/plugins/USBPrinting/FirmwareUpdateWindow.qml +++ b/plugins/USBPrinting/FirmwareUpdateWindow.qml @@ -22,7 +22,7 @@ UM.Dialog Column { anchors.fill: parent; - + Text { anchors { diff --git a/plugins/USBPrinting/PrinterConnection.py b/plugins/USBPrinting/PrinterConnection.py index d19e5d2f19..1ac1cb1b89 100644 --- a/plugins/USBPrinting/PrinterConnection.py +++ b/plugins/USBPrinting/PrinterConnection.py @@ -44,6 +44,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): self._connect_thread = threading.Thread(target = self._connect) self._connect_thread.daemon = True + self._end_stop_thread = threading.Thread(target = self._pollEndStop) + self._end_stop_thread.deamon = True + # Printer is connected self._is_connected = False @@ -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 # 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 @@ -60,8 +63,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): self._listen_thread.daemon = True self._update_firmware_thread = threading.Thread(target= self._updateFirmware) - self._update_firmware_thread.demon = True - + self._update_firmware_thread.deamon = True + self._heatup_wait_start_time = time.time() ## 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 self._current_z = 0 + self._x_min_endstop_pressed = False + self._y_min_endstop_pressed = False + self._z_min_endstop_pressed = False + + self._x_max_endstop_pressed = False + self._y_max_endstop_pressed = False + self._z_max_endstop_pressed = False + # In order to keep the connection alive we request the temperature every so often from a different extruder. # This index is the extruder we requested data from the last time. self._temperature_requested_extruder_index = 0 @@ -112,6 +123,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): extruderTemperatureChanged = pyqtSignal() bedTemperatureChanged = pyqtSignal() + endstopStateChanged = pyqtSignal(str ,bool, arguments = ["key","state"]) + @pyqtProperty(float, notify = progressChanged) def progress(self): return self._progress @@ -209,6 +222,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): self.setProgress(100, 100) + self.firmwareUpdateComplete.emit() + ## Upload new firmware to machine # \param filename full path of firmware file to be uploaded def updateFirmware(self, file_name): @@ -216,6 +231,20 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): self._firmware_file_name = file_name self._update_firmware_thread.start() + @pyqtSlot() + def startPollEndstop(self): + self._poll_endstop = True + self._end_stop_thread.start() + + @pyqtSlot() + def stopPollEndstop(self): + self._poll_endstop = False + + def _pollEndStop(self): + while self._is_connected and self._poll_endstop: + self.sendCommand("M119") + time.sleep(0.5) + ## Private connect function run by thread. Can be started by calling connect. def _connect(self): Logger.log("d", "Attempting to connect to %s", self._serial_port) @@ -255,9 +284,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): if line is None: self.setIsConnected(False) # Something went wrong with reading, could be that close was called. return + if b"T:" in line: self._serial.timeout = 0.5 - self._sendCommand("M105") sucesfull_responses += 1 if sucesfull_responses >= self._required_responses_auto_baud: self._serial.timeout = 2 #Reset serial timeout @@ -265,6 +294,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): Logger.log("i", "Established printer connection on port %s" % self._serial_port) return + self._sendCommand("M105") # Send M105 as long as we are listening, otherwise we end up in an undefined state + Logger.log("e", "Baud rate detection for %s failed", self._serial_port) self.close() # Unable to connect, wrap up. self.setIsConnected(False) @@ -297,6 +328,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): except Exception as e: pass # This should work, but it does fail sometimes for some reason + self._connect_thread = threading.Thread(target=self._connect) + self._connect_thread.daemon = True + if self._serial is not None: self.setIsConnected(False) try: @@ -305,11 +339,30 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): pass self._serial.close() + self._listen_thread = threading.Thread(target=self._listen) + self._listen_thread.daemon = True self._serial = None def isConnected(self): return self._is_connected + @pyqtSlot(int) + def heatupNozzle(self, temperature): + 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). # \param cmd string with g-code def _sendCommand(self, cmd): @@ -402,6 +455,20 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): def requestWrite(self, node): self.showControlInterface() + def _setEndstopState(self, endstop_key, value): + if endstop_key == b'x_min': + if self._x_min_endstop_pressed != value: + self.endstopStateChanged.emit('x_min', value) + self._x_min_endstop_pressed = value + elif endstop_key == b'y_min': + if self._y_min_endstop_pressed != value: + self.endstopStateChanged.emit('y_min', value) + self._y_min_endstop_pressed = value + elif endstop_key == b'z_min': + if self._z_min_endstop_pressed != value: + self.endstopStateChanged.emit('z_min', value) + self._z_min_endstop_pressed = value + ## Listen thread function. def _listen(self): 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: break # None is only returned when something went wrong. Stop listening + if time.time() > temperature_request_timeout: + if self._extruder_count > 0: + self._temperature_requested_extruder_index = (self._temperature_requested_extruder_index + 1) % self._extruder_count + self.sendCommand("M105 T%d" % (self._temperature_requested_extruder_index)) + else: + self.sendCommand("M105") + temperature_request_timeout = time.time() + 5 + if line.startswith(b"Error:"): # Oh YEAH, consistency. # Marlin reports an MIN/MAX temp error as "Error:x\n: Extruder switched off. MAXTEMP triggered !\n" @@ -437,16 +512,11 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): except Exception as e: pass #TODO: temperature changed callback + elif b"_min" in line or b"_max" in line: + tag, value = line.split(b':', 1) + self._setEndstopState(tag,(b'H' in value or b'TRIGGERED' in value)) if self._is_printing: - if time.time() > temperature_request_timeout: # When printing, request temperature every 5 seconds. - if self._extruder_count > 0: - self._temperature_requested_extruder_index = (self._temperature_requested_extruder_index + 1) % self._extruder_count - self.sendCommand("M105 T%d" % (self._temperature_requested_extruder_index)) - else: - self.sendCommand("M105") - temperature_request_timeout = time.time() + 5 - if line == b"" and time.time() > ok_timeout: line = b"ok" # Force a timeout (basicly, send next command) @@ -540,3 +610,10 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter): def _getBaudrateList(self): ret = [250000, 230400, 115200, 57600, 38400, 19200, 9600] return ret + + def _onFirmwareUpdateComplete(self): + self._update_firmware_thread.join() + self._update_firmware_thread = threading.Thread(target= self._updateFirmware) + self._update_firmware_thread.deamon = True + + self.connect() diff --git a/plugins/USBPrinting/USBPrinterManager.py b/plugins/USBPrinting/USBPrinterManager.py index 4363883b2b..bae5099610 100644 --- a/plugins/USBPrinting/USBPrinterManager.py +++ b/plugins/USBPrinting/USBPrinterManager.py @@ -10,6 +10,7 @@ from UM.Resources import Resources from UM.Logger import Logger from UM.PluginRegistry import PluginRegistry from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin +from UM.Qt.ListModel import ListModel import threading import platform @@ -35,6 +36,7 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension): Extension.__init__(self) self._serial_port_list = [] self._printer_connections = {} + self._printer_connections_model = None self._update_thread = threading.Thread(target = self._updateThread) 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. addConnectionSignal = Signal() + printerConnectionStateChanged = pyqtSignal() def start(self): self._check_updates = True @@ -84,15 +87,31 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension): self.spawnFirmwareInterface("") for printer_connection in self._printer_connections: try: - printer_connection.updateFirmware(Resources.getPath(Resources.FirmwareLocation, self._getDefaultFirmwareName())) + self._printer_connections[printer_connection].updateFirmware(Resources.getPath(Resources.FirmwareLocation, self._getDefaultFirmwareName())) except FileNotFoundError: continue + @pyqtSlot(str, result = bool) def updateFirmwareBySerial(self, serial_port): - printer_connection = self.getConnectionByPort(serial_port) - if printer_connection is not None: - self.spawnFirmwareInterface(printer_connection.getSerialPort()) - printer_connection.updateFirmware(Resources.getPath(Resources.FirmwareLocation, self._getDefaultFirmwareName())) + if serial_port in self._printer_connections: + self.spawnFirmwareInterface(self._printer_connections[serial_port].getSerialPort()) + try: + self._printer_connections[serial_port].updateFirmware(Resources.getPath(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): machine_type = Application.getInstance().getActiveMachine().getTypeID() @@ -140,6 +159,17 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension): self.getOutputDeviceManager().addOutputDevice(self._printer_connections[serial_port]) else: 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. # \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 else: base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/rfcomm*") + glob.glob("/dev/serial/by-id/*") - return list(base_list) \ No newline at end of file + return list(base_list) + + _instance = None \ No newline at end of file diff --git a/plugins/USBPrinting/__init__.py b/plugins/USBPrinting/__init__.py index baf4ec6eb4..7ee8290e12 100644 --- a/plugins/USBPrinting/__init__.py +++ b/plugins/USBPrinting/__init__.py @@ -2,7 +2,7 @@ # Cura is released under the terms of the AGPLv3 or higher. from . import USBPrinterManager - +from PyQt5.QtQml import qmlRegisterType, qmlRegisterSingletonType from UM.i18n import i18nCatalog i18n_catalog = i18nCatalog("cura") @@ -19,4 +19,5 @@ def getMetaData(): } 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() } diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 8d5b8337f0..29bd573d12 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -40,10 +40,18 @@ Item { property alias reportBug: reportBugAction; property alias about: aboutAction; + property alias toggleFullScreen: toggleFullScreenAction; + + Action + { + id:toggleFullScreenAction + shortcut: StandardKey.FullScreen; + } + Action { id: undoAction; //: Undo action - text: qsTr("&Undo"); + text: qsTr("Undo"); iconName: "edit-undo"; shortcut: StandardKey.Undo; } @@ -51,7 +59,7 @@ Item { Action { id: redoAction; //: Redo action - text: qsTr("&Redo"); + text: qsTr("Redo"); iconName: "edit-redo"; shortcut: StandardKey.Redo; } @@ -59,7 +67,7 @@ Item { Action { id: quitAction; //: Quit action - text: qsTr("&Quit"); + text: qsTr("Quit"); iconName: "application-exit"; shortcut: StandardKey.Quit; } @@ -67,20 +75,20 @@ Item { Action { id: preferencesAction; //: Preferences action - text: qsTr("&Preferences..."); + text: qsTr("Preferences..."); iconName: "configure"; } Action { id: addMachineAction; //: Add Printer action - text: qsTr("&Add Printer..."); + text: qsTr("Add Printer..."); } Action { id: settingsAction; //: Configure Printers action - text: qsTr("&Configure Printers"); + text: qsTr("Configure Printers"); iconName: "configure"; } @@ -102,7 +110,7 @@ Item { Action { id: aboutAction; //: About action - text: qsTr("&About..."); + text: qsTr("About..."); iconName: "help-about"; } @@ -190,7 +198,7 @@ Item { Action { id: openAction; //: Open file action - text: qsTr("&Open..."); + text: qsTr("Load file"); iconName: "document-open"; shortcut: StandardKey.Open; } @@ -198,7 +206,7 @@ Item { Action { id: saveAction; //: Save file action - text: qsTr("&Save..."); + text: qsTr("Save..."); iconName: "document-save"; shortcut: StandardKey.Save; } diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 0bdc9586bd..e54a00d9d0 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -12,7 +12,6 @@ import UM 1.1 as UM UM.MainWindow { id: base visible: true - //: Cura application window title title: qsTr("Cura"); @@ -212,10 +211,8 @@ UM.MainWindow { UM.MessageStack { anchors { - left: toolbar.right; - leftMargin: UM.Theme.sizes.window_margin.width; - right: sidebar.left; - rightMargin: UM.Theme.sizes.window_margin.width; + horizontalCenter: parent.horizontalCenter + horizontalCenterOffset: -(UM.Theme.sizes.logo.width/ 2) top: parent.verticalCenter; bottom: parent.bottom; } @@ -242,17 +239,15 @@ UM.MainWindow { Button { id: openFileButton; - - iconSource: UM.Theme.icons.open; - style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button; + //style: UM.Backend.progress < 0 ? UM.Theme.styles.open_file_button : UM.Theme.styles.tool_button; + style: UM.Theme.styles.open_file_button tooltip: ''; anchors { top: parent.top; - topMargin: UM.Theme.sizes.window_margin.height; + topMargin: UM.Theme.sizes.loadfile_margin.height left: parent.left; - leftMargin: UM.Theme.sizes.window_margin.width; + leftMargin: UM.Theme.sizes.loadfile_margin.width } - action: actions.open; } @@ -349,8 +344,15 @@ UM.MainWindow { id: preferences 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 insertPage(1, qsTr("View"), "view-preview", Qt.resolvedUrl("./ViewPage.qml")); + + //Force refresh + setPage(0) } } @@ -423,6 +425,8 @@ UM.MainWindow { reportBug.onTriggered: CuraActions.openBugReportPage(); showEngineLog.onTriggered: engineLog.visible = true; about.onTriggered: aboutDialog.visible = true; + toggleFullScreen.onTriggered: base.toggleFullscreen() + } Menu { @@ -481,7 +485,6 @@ UM.MainWindow { onAccepted: { UM.MeshFileHandler.readLocalFile(fileUrl) - Printer.setPlatformActivity(true) } } diff --git a/resources/qml/GeneralPage.qml b/resources/qml/GeneralPage.qml new file mode 100644 index 0000000000..9f7203702f --- /dev/null +++ b/resources/qml/GeneralPage.qml @@ -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 } + } +} diff --git a/resources/qml/Toolbar.qml b/resources/qml/Toolbar.qml index 5d4400bfda..e14dfdc99d 100644 --- a/resources/qml/Toolbar.qml +++ b/resources/qml/Toolbar.qml @@ -19,7 +19,7 @@ Item { anchors.bottom: parent.bottom; anchors.left: parent.left; - spacing: 1 + spacing: UM.Theme.sizes.default_lining.width Repeater { id: repeat @@ -67,6 +67,8 @@ Item { Behavior on opacity { NumberAnimation { duration: 100 } } color: UM.Theme.colors.tool_panel_background; + border.width: UM.Theme.sizes.default_lining.width + border.color: UM.Theme.colors.button_lining Loader { id: panel diff --git a/resources/qml/ViewPage.qml b/resources/qml/ViewPage.qml index 172ddad8d8..ed00eacca0 100644 --- a/resources/qml/ViewPage.qml +++ b/resources/qml/ViewPage.qml @@ -8,7 +8,8 @@ import QtQuick.Controls.Styles 1.1 import UM 1.0 as UM -UM.PreferencesPage { +UM.PreferencesPage +{ id: preferencesPage //: View configuration page title @@ -17,22 +18,26 @@ UM.PreferencesPage { function reset() { UM.Preferences.resetPreference("view/show_overhang"); + UM.Preferences.resetPreferences("view/center_on_select"); } - GridLayout { + GridLayout + { columns: 2; - CheckBox { - id: viewCheckbox + CheckBox + { + id: overhangCheckbox checked: UM.Preferences.getValue("view/show_overhang") 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 //: Display Overhang preference checkbox text: qsTr("Display Overhang"); - onClicked: viewCheckbox.checked = !viewCheckbox.checked + onClicked: overhangCheckbox.checked = !overhangCheckbox.checked //: Display Overhang preference tooltip 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 } } } diff --git a/resources/qml/WizardPages/AddMachine.qml b/resources/qml/WizardPages/AddMachine.qml index 081c6b65bf..39dfd2414d 100644 --- a/resources/qml/WizardPages/AddMachine.qml +++ b/resources/qml/WizardPages/AddMachine.qml @@ -252,6 +252,10 @@ ColumnLayout UM.Models.availableMachinesModel.createMachine(machineList.currentIndex, machineName.text) var pages = UM.Models.availableMachinesModel.getItem(machineList.currentIndex).pages 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) for (var i = old_page_count - 1; i > 0; i--) { diff --git a/resources/qml/WizardPages/Bedleveling.qml b/resources/qml/WizardPages/Bedleveling.qml index 218624263a..3c1dcea552 100644 --- a/resources/qml/WizardPages/Bedleveling.qml +++ b/resources/qml/WizardPages/Bedleveling.qml @@ -8,62 +8,47 @@ import QtQuick.Window 2.1 import UM 1.0 as UM -ColumnLayout { +Column +{ id: wizardPage - property string title - property int pageWidth - property int pageHeight - - SystemPalette{id: palette} - //signal openFile(string fileName) - //signal closeWizard() - - width: wizardPage.pageWidth - height: wizardPage.pageHeight - - Connections { - target: elementRoot - onResize: { - wizardPage.width = pageWidth - wizardPage.height = pageHeight - } + property int leveling_state: 0 + property bool three_point_leveling: true + property int platform_width: UM.Models.settingsModel.getMachineSetting("machine_width") + property int platform_height: UM.Models.settingsModel.getMachineSetting("machine_depth") + anchors.fill: parent; + property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer + Component.onCompleted: printer_connection.homeHead() + Label + { + text: "" + //Component.onCompleted:console.log(UM.Models.settingsModel.getMachineSetting("machine_width")) } - - Label { - text: parent.title - font.pointSize: 18; - } - - Label { - //: Add Printer wizard page description - 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; - - } + Button + { + text: "Move to next position" + onClicked: + { + if(wizardPage.leveling_state == 0) + { + printer_connection.moveHead(platform_width /2 , platform_height,0) } + 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 { - //: Add Printer wizard field label - text: qsTr("Printer Name:"); + function threePointLeveling(width, height) + { } - TextField { id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name } - Item { Layout.fillWidth: true; Layout.fillHeight: true; } - - ExclusiveGroup { id: printerGroup; } } \ No newline at end of file diff --git a/resources/qml/WizardPages/UltimakerCheckup.qml b/resources/qml/WizardPages/UltimakerCheckup.qml index f67694e03a..acfe288e14 100644 --- a/resources/qml/WizardPages/UltimakerCheckup.qml +++ b/resources/qml/WizardPages/UltimakerCheckup.qml @@ -13,6 +13,16 @@ Column id: wizardPage property string title 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 { @@ -23,44 +33,144 @@ Column Label { //: 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 - width: parent.width - ListView + Label { - id: machineList; - model: UM.Models.availableMachinesModel - delegate: RadioButton - { - exclusiveGroup: printerGroup; - text: model.name; - onClicked: - { - ListView.view.currentIndex = index; - } - } + text: qsTr("Connection: ") + } + Label + { + text: UM.USBPrinterManager.connectedPrinterList.count ? "Done":"Incomplete" + } + } + Row + { + 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 - text: qsTr("Printer Name:"); + Label + { + 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; - Layout.fillHeight: true; + Label + { + 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 diff --git a/resources/qml/WizardPages/UpgradeFirmware.qml b/resources/qml/WizardPages/UpgradeFirmware.qml index b980681662..9bb7152931 100644 --- a/resources/qml/WizardPages/UpgradeFirmware.qml +++ b/resources/qml/WizardPages/UpgradeFirmware.qml @@ -13,19 +13,12 @@ Column id: wizardPage property string title anchors.fill: parent; - Label { text: parent.title font.pointSize: 18; } - Label - { - //: Add Printer wizard page description - text: qsTr("Please select the type of printer:"); - } - ScrollView { height: parent.height - 50 @@ -33,14 +26,26 @@ Column ListView { id: machineList; - model: UM.Models.availableMachinesModel - delegate: RadioButton + model: UM.USBPrinterManager.connectedPrinterList + + delegate:Row { - exclusiveGroup: printerGroup; - text: model.name; - onClicked: + id: derp + Text { - 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 { - //: Add Printer wizard field label - text: qsTr("Printer Name:"); + id: status_text + text: "" } - TextField - { - id: machineName; Layout.fillWidth: true; text: machineList.model.getItem(machineList.currentIndex).name - - } Item { @@ -64,8 +64,5 @@ Column Layout.fillHeight: true; } - ExclusiveGroup - { - id: printerGroup; - } + } \ No newline at end of file diff --git a/resources/settings/fdmprinter.json b/resources/settings/fdmprinter.json index c46d92b9a4..6a91a43eab 100644 --- a/resources/settings/fdmprinter.json +++ b/resources/settings/fdmprinter.json @@ -28,21 +28,6 @@ "machine_center_is_zero": { "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": { "default": 1 }, @@ -67,20 +52,20 @@ "machine_head_polygon": { "default": [ [ - -10, - 10 + -1, + 1 ], [ - 10, - 10 + -1, + -1 ], [ - 10, - -10 + 1, + -1 ], [ - -10, - -10 + 1, + 1 ] ] }, diff --git a/resources/settings/ultimaker2.json b/resources/settings/ultimaker2.json index 64c008c5d4..30814fe859 100644 --- a/resources/settings/ultimaker2.json +++ b/resources/settings/ultimaker2.json @@ -38,14 +38,30 @@ "machine_height": { "default": 205 }, "machine_heated_bed": { "default": true }, - + "machine_head_with_fans_polygon": + { + "default": [ + [ + -40, + 30 + ], + [ + -40, + -10 + ], + [ + 60, + -10 + ], + [ + 60, + 30 + ] + ] + }, "machine_center_is_zero": { "default": false }, "machine_nozzle_size": { "default": 0.4 }, - "machine_head_shape_min_x": { "default": 40 }, - "machine_head_shape_min_y": { "default": 10 }, - "machine_head_shape_max_x": { "default": 60 }, - "machine_head_shape_max_y": { "default": 30 }, - "machine_nozzle_gantry_distance": { "default": 55 }, + "gantry_height": { "default": 55 }, "machine_use_extruder_offset_to_offset_coords": { "default": true }, "machine_gcode_flavor": { "default": "UltiGCode" }, "machine_disallowed_areas": { "default": [ diff --git a/resources/settings/ultimaker_original.json b/resources/settings/ultimaker_original.json index 84849abb83..555c7e7363 100644 --- a/resources/settings/ultimaker_original.json +++ b/resources/settings/ultimaker_original.json @@ -41,11 +41,28 @@ "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_head_with_fans_polygon": + { + "default": [ + [ + -75, + 35 + ], + [ + -75, + -18 + ], + [ + 18, + 35 + ], + [ + 18, + -18 + ] + ] + }, + "gantry_height": { "default": 55 }, "machine_use_extruder_offset_to_offset_coords": { "default": true }, "machine_gcode_flavor": { "default": "RepRap (Marlin/Sprinter)" }, diff --git a/resources/themes/cura/fonts/ProximaNova-Black.otf b/resources/themes/cura/fonts/ProximaNova-Black.otf new file mode 100644 index 0000000000..ec4d45f178 Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNova-Black.otf differ diff --git a/resources/themes/cura/fonts/ProximaNova-Bold.otf b/resources/themes/cura/fonts/ProximaNova-Bold.otf new file mode 100644 index 0000000000..4df9e17140 Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNova-Bold.otf differ diff --git a/resources/themes/cura/fonts/ProximaNova-BoldIt.otf b/resources/themes/cura/fonts/ProximaNova-BoldIt.otf new file mode 100644 index 0000000000..60188efbff Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNova-BoldIt.otf differ diff --git a/resources/themes/cura/fonts/ProximaNova-Extrabold.otf b/resources/themes/cura/fonts/ProximaNova-Extrabold.otf new file mode 100644 index 0000000000..bd8e650ff9 Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNova-Extrabold.otf differ diff --git a/resources/themes/cura/fonts/ProximaNova-Light.otf b/resources/themes/cura/fonts/ProximaNova-Light.otf new file mode 100644 index 0000000000..d8f5338d21 Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNova-Light.otf differ diff --git a/resources/themes/cura/fonts/ProximaNova-LightItalic.otf b/resources/themes/cura/fonts/ProximaNova-LightItalic.otf new file mode 100644 index 0000000000..f779115b97 Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNova-LightItalic.otf differ diff --git a/resources/themes/cura/fonts/ProximaNova-Regular.otf b/resources/themes/cura/fonts/ProximaNova-Regular.otf new file mode 100644 index 0000000000..27c8d8f7bf Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNova-Regular.otf differ diff --git a/resources/themes/cura/fonts/ProximaNova-RegularItalic.otf b/resources/themes/cura/fonts/ProximaNova-RegularItalic.otf new file mode 100644 index 0000000000..20ffc1fcdd Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNova-RegularItalic.otf differ diff --git a/resources/themes/cura/fonts/ProximaNovaCond-Light.otf b/resources/themes/cura/fonts/ProximaNovaCond-Light.otf new file mode 100644 index 0000000000..0b27849cd0 Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNovaCond-Light.otf differ diff --git a/resources/themes/cura/fonts/ProximaNovaCond-LightIt.otf b/resources/themes/cura/fonts/ProximaNovaCond-LightIt.otf new file mode 100644 index 0000000000..a7dd085cf1 Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNovaCond-LightIt.otf differ diff --git a/resources/themes/cura/fonts/ProximaNovaCond-Regular.otf b/resources/themes/cura/fonts/ProximaNovaCond-Regular.otf new file mode 100644 index 0000000000..7356c3b88b Binary files /dev/null and b/resources/themes/cura/fonts/ProximaNovaCond-Regular.otf differ diff --git a/resources/themes/cura/fonts/Roboto-Black.ttf b/resources/themes/cura/fonts/Roboto-Black.ttf deleted file mode 100644 index 9002aab5d4..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-Black.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-BlackItalic.ttf b/resources/themes/cura/fonts/Roboto-BlackItalic.ttf deleted file mode 100644 index b87e025dff..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-BlackItalic.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-Bold.ttf b/resources/themes/cura/fonts/Roboto-Bold.ttf deleted file mode 100644 index 072b842925..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-Bold.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-BoldItalic.ttf b/resources/themes/cura/fonts/Roboto-BoldItalic.ttf deleted file mode 100644 index 74919ff649..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-BoldItalic.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-Italic.ttf b/resources/themes/cura/fonts/Roboto-Italic.ttf deleted file mode 100644 index bd57775e44..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-Italic.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-Light.ttf b/resources/themes/cura/fonts/Roboto-Light.ttf deleted file mode 100644 index 13bf13af00..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-Light.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-LightItalic.ttf b/resources/themes/cura/fonts/Roboto-LightItalic.ttf deleted file mode 100644 index 130672a907..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-LightItalic.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-Medium.ttf b/resources/themes/cura/fonts/Roboto-Medium.ttf deleted file mode 100644 index d0f6e2b64f..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-Medium.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-MediumItalic.ttf b/resources/themes/cura/fonts/Roboto-MediumItalic.ttf deleted file mode 100644 index 6153d48b49..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-MediumItalic.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-Regular.ttf b/resources/themes/cura/fonts/Roboto-Regular.ttf deleted file mode 100644 index 0ba95c98c4..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-Regular.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-Thin.ttf b/resources/themes/cura/fonts/Roboto-Thin.ttf deleted file mode 100644 index 309c22d358..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-Thin.ttf and /dev/null differ diff --git a/resources/themes/cura/fonts/Roboto-ThinItalic.ttf b/resources/themes/cura/fonts/Roboto-ThinItalic.ttf deleted file mode 100644 index 0b53ba4d38..0000000000 Binary files a/resources/themes/cura/fonts/Roboto-ThinItalic.ttf and /dev/null differ diff --git a/resources/themes/cura/styles.qml b/resources/themes/cura/styles.qml index 77b1d2852e..0810989304 100644 --- a/resources/themes/cura/styles.qml +++ b/resources/themes/cura/styles.qml @@ -35,54 +35,26 @@ QtObject { } } - property Component open_file_button: Component { + property Component open_file_button: Component { ButtonStyle { - background: Item { - implicitWidth: UM.Theme.sizes.button.width; - implicitHeight: UM.Theme.sizes.button.height; - + background: Item{ + implicitWidth: UM.Theme.sizes.loadfile_button.width + implicitHeight: UM.Theme.sizes.loadfile_button.height Rectangle { - anchors.bottom: 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.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; - } - } + width: parent.width + height: parent.height + color: control.hovered ? UM.Theme.colors.load_save_button_hover : UM.Theme.colors.load_save_button 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: 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; - } + label: Label{ + visible: false } } } @@ -90,7 +62,6 @@ QtObject { property Component tool_button: Component { ButtonStyle { background: Item { - ///////////TODO CHANGE SIZES!! implicitWidth: UM.Theme.sizes.button.width; implicitHeight: UM.Theme.sizes.button.height; @@ -99,7 +70,6 @@ QtObject { anchors.top: parent.verticalCenter; width: parent.width; - ///////////TODO CHANGE LABELHEIGHT!! height: control.hovered ? parent.height / 2 + label.height : 0; Behavior on height { NumberAnimation { duration: 100; } } @@ -109,7 +79,7 @@ QtObject { Label { id: label anchors.bottom: parent.bottom - text: control.text.replace("&", ""); + text: control.text font: UM.Theme.fonts.button_tooltip; color: UM.Theme.colors.button_tooltip_text; } @@ -138,13 +108,14 @@ QtObject { Behavior on color { ColorAnimation { duration: 50; } } Label { + id: tool_button_arrow 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; text: "▼"; font: UM.Theme.fonts.small; 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{ ProgressBarStyle { - background: UM.AngledCornerRectangle { - cornerSize: UM.Theme.sizes.progressbar_control.height - implicitWidth: UM.Theme.sizes.progressbar.width + background:Rectangle { + implicitWidth: UM.Theme.sizes.message.width - (UM.Theme.sizes.default_margin.width * 2) implicitHeight: UM.Theme.sizes.progressbar.height + x: UM.Theme.sizes.default_margin.width color: UM.Theme.colors.progressbar_background } - progress: UM.AngledCornerRectangle { - cornerSize: UM.Theme.sizes.progressbar_control.height + progress: Rectangle { color: control.indeterminate ? "transparent" : UM.Theme.colors.progressbar_control - UM.AngledCornerRectangle { - cornerSize: UM.Theme.sizes.progressbar_control.height + Rectangle{ color: UM.Theme.colors.progressbar_control width: UM.Theme.sizes.progressbar_control.width height: UM.Theme.sizes.progressbar_control.height + x: UM.Theme.sizes.default_margin.width visible: control.indeterminate SequentialAnimation on x { 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 loops: Animation.Infinite - NumberAnimation { from: 0; to: xAnim.animEndPoint; duration: 2000;} - NumberAnimation { from: xAnim.animEndPoint; to: 0; duration: 2000;} + NumberAnimation { from: UM.Theme.sizes.default_margin.width; to: xAnim.animEndPoint; duration: 2000;} + NumberAnimation { from: xAnim.animEndPoint; to: UM.Theme.sizes.default_margin.width; duration: 2000;} } } } diff --git a/resources/themes/cura/theme.json b/resources/themes/cura/theme.json index b600db1c2c..413a653d3c 100644 --- a/resources/themes/cura/theme.json +++ b/resources/themes/cura/theme.json @@ -3,52 +3,52 @@ "large": { "size": 1.5, "bold": true, - "family": "Roboto" + "family": "ProximaNova" }, "default": { "size": 1, - "family": "Roboto" + "family": "ProximaNova" }, "default_allcaps": { "size": 1, "capitalize": true, - "family": "Roboto" + "family": "ProximaNova" }, "small": { "size": 0.75, - "family": "Roboto" + "family": "ProximaNova" }, "tiny": { "size": 0.5, - "family": "Roboto" + "family": "ProximaNova" }, "caption": { "size": 0.75, "italic": true, - "family": "Roboto" + "family": "ProximaNova" }, "sidebar_header": { "size": 0.75, "capitalize": true, - "family": "Roboto" + "family": "ProximaNova" }, "sidebar_save_to": { "size": 1.0, - "family": "Roboto" + "family": "ProximaNova" }, "timeslider_time": { "size": 1.0, "bold": true, - "family": "Roboto" + "family": "ProximaNova" }, "button_tooltip": { "size": 0.75, "capitalize": true, - "family": "Roboto" + "family": "ProximaNova" }, "setting_category": { "size": 1.5, - "family": "Roboto" + "family": "ProximaNova" } }, @@ -66,15 +66,20 @@ "text_hover": [35, 35, 35, 255], "text_pressed": [12, 169, 227, 255], - "button": [160, 163, 171, 255], - "button_hover": [140, 144, 154, 255], + "button": [139, 143, 153, 255], + "button_hover": [116, 120, 127, 255], "button_active": [12, 169, 227, 255], - "button_active_hover": [34, 150, 199, 255], - "button_lining": [140, 144, 154, 255], + "button_active_hover": [77, 184, 226, 255], + "button_lining": [208, 210, 211, 255], "button_text": [255, 255, 255, 255], "button_disabled": [245, 245, 245, 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_handle": [205, 202, 201, 255], "scrollbar_handle_hover": [174, 174, 174, 255], @@ -98,7 +103,7 @@ "setting_validation_warning": [255, 186, 15, 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], "slider_groove": [245, 245, 245, 255], @@ -126,8 +131,8 @@ "save_button_printtime_text": [12, 169, 227, 255], "save_button_background": [249, 249, 249, 255], - "message": [160, 163, 171, 255], - "message_text": [35, 35, 35, 255], + "message_background": [255, 255, 255, 255], + "message_text": [12, 169, 227, 255], "tool_panel_background": [255, 255, 255, 255] }, @@ -135,11 +140,15 @@ "sizes": { "window_margin": [2.0, 2.0], "default_margin": [1.0, 1.0], + "default_lining": [0.1, 0.1], "panel": [22.0, 10.0], "logo": [9.5, 2.0], "toolbar_button": [2.0, 2.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_icon": [2.14, 2.14], "section_text_margin": [0.33, 0.33], @@ -153,11 +162,11 @@ "standard_list_lineheight": [1.5, 1.5], "standard_list_input": [20.0, 25.0], - "button": [4.25, 4.25], - "button_icon": [2.9, 2.9], + "button": [3.2, 3.2], + "button_icon": [2.5, 2.5], - "progressbar": [26.0, 0.5], - "progressbar_control": [8.0, 0.5], + "progressbar": [26.0, 0.8], + "progressbar_control": [8.0, 0.8], "progressbar_padding": [0.0, 1.0], "scrollbar": [0.5, 0.5], @@ -184,6 +193,7 @@ "wizard_progress": [10.0, 0.0], "message": [30.0, 5.0], - "message_close": [1.25, 1.25] + "message_close": [1.25, 1.25], + "message_button": [6.0, 1.8] } }