diff --git a/CMakeLists.txt b/CMakeLists.txt index 9296c4ce4e..96efd68a2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ endif() set(CURA_VERSION "master" CACHE STRING "Version name of Cura") set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'") +set(CURA_PACKAGES_VERSION "" CACHE STRING "Packages version of Cura") configure_file(${CMAKE_SOURCE_DIR}/cura.desktop.in ${CMAKE_BINARY_DIR}/cura.desktop @ONLY) configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 0493eb68af..e40efceeb3 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -537,7 +537,7 @@ class CuraApplication(QtApplication): ## A reusable dialogbox # - showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"]) + showMessageBox = pyqtSignal(str, str, str, str, str, int, int, arguments = ["title", "footer", "text", "informativeText", "detailedText", "buttons", "icon"]) def messageBox(self, title, text, informativeText = "", detailedText = "", buttons = QMessageBox.Ok, icon = QMessageBox.NoIcon, callback = None, callback_arguments = []): self._message_box_callback = callback diff --git a/cura/CuraPackageManager.py b/cura/CuraPackageManager.py index 6fe3840679..80e117277f 100644 --- a/cura/CuraPackageManager.py +++ b/cura/CuraPackageManager.py @@ -8,13 +8,14 @@ import shutil import zipfile import tempfile -from PyQt5.QtCore import pyqtSlot, QObject, pyqtSignal +from PyQt5.QtCore import pyqtSlot, QObject, pyqtSignal, QUrl from UM.Application import Application from UM.Logger import Logger from UM.Resources import Resources from UM.Version import Version + class CuraPackageManager(QObject): Version = 1 @@ -184,6 +185,12 @@ class CuraPackageManager(QObject): def isPackageInstalled(self, package_id: str) -> bool: return self.getInstalledPackageInfo(package_id) is not None + # This is called by drag-and-dropping curapackage files. + @pyqtSlot(QUrl) + def installPackageViaDragAndDrop(self, file_url: str) -> None: + filename = QUrl(file_url).toLocalFile() + return self.installPackage(filename) + # Schedules the given package file to be installed upon the next start. @pyqtSlot(str) def installPackage(self, filename: str) -> None: diff --git a/cura/CuraVersion.py.in b/cura/CuraVersion.py.in index c489485c2c..f45a24cae9 100644 --- a/cura/CuraVersion.py.in +++ b/cura/CuraVersion.py.in @@ -4,3 +4,4 @@ CuraVersion = "@CURA_VERSION@" CuraBuildType = "@CURA_BUILDTYPE@" CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False +CuraPackagesVersion = "@CURA_PACKAGES_VERSION@" diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index ad3c7f165f..8b74596667 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -76,10 +76,12 @@ class MaterialManager(QObject): def initialize(self): # Find all materials and put them in a matrix for quick search. - material_metadatas = {metadata["id"]: metadata for metadata in self._container_registry.findContainersMetadata(type = "material")} + material_metadatas = {metadata["id"]: metadata for metadata in + self._container_registry.findContainersMetadata(type = "material") if + metadata.get("GUID")} self._material_group_map = dict() - + # Map #1 # root_material_id -> MaterialGroup for material_id, material_metadata in material_metadatas.items(): @@ -93,7 +95,7 @@ class MaterialManager(QObject): self._material_group_map[root_material_id].is_read_only = self._container_registry.isReadOnly(root_material_id) group = self._material_group_map[root_material_id] - #Store this material in the group of the appropriate root material. + # Store this material in the group of the appropriate root material. if material_id != root_material_id: new_node = MaterialNode(material_metadata) group.derived_material_node_list.append(new_node) @@ -158,11 +160,11 @@ class MaterialManager(QObject): key_data.append(root_material_metadata.get(key)) key_data = tuple(key_data) - # If the key_data doesn't exist, no matter if the material is read only... + # If the key_data doesn't exist, it doesn't matter if the material is read only... if key_data not in material_group_dict: material_group_dict[key_data] = dict() else: - # ...but if key_data exists, we just overrite it if the material is read only, otherwise we skip it + # ...but if key_data exists, we just overwrite it if the material is read only, otherwise we skip it if not machine_node.is_read_only: continue approximate_diameter = root_material_metadata.get("approximate_diameter") diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index db28478597..6b539a4574 100755 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -35,7 +35,7 @@ class PlatformPhysics: self._max_overlap_checks = 10 # How many times should we try to find a new spot per tick? self._minimum_gap = 2 # It is a minimum distance (in mm) between two models, applicable for small models - Application.getInstance().getPreferences().addPreference("physics/automatic_push_free", True) + Application.getInstance().getPreferences().addPreference("physics/automatic_push_free", False) Application.getInstance().getPreferences().addPreference("physics/automatic_drop_down", True) def _onSceneChanged(self, source): diff --git a/cura/PreviewPass.py b/cura/PreviewPass.py index f6b963d141..4241a2f243 100644 --- a/cura/PreviewPass.py +++ b/cura/PreviewPass.py @@ -1,7 +1,6 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from UM.Application import Application -from UM.Math.Color import Color from UM.Resources import Resources from UM.View.RenderPass import RenderPass @@ -74,7 +73,6 @@ class PreviewPass(RenderPass): # Create batches to be rendered batch = RenderBatch(self._shader) - batch_non_printing = RenderBatch(self._non_printing_shader, type = RenderBatch.RenderType.Transparent) batch_support_mesh = RenderBatch(self._support_mesh_shader) # Fill up the batch with objects that can be sliced. ` @@ -83,7 +81,7 @@ class PreviewPass(RenderPass): per_mesh_stack = node.callDecoration("getStack") if node.callDecoration("isNonPrintingMesh"): # Non printing mesh - batch_non_printing.addItem(node.getWorldTransformation(), node.getMeshData(), uniforms = {}) + continue elif per_mesh_stack is not None and per_mesh_stack.getProperty("support_mesh", "value") == True: # Support mesh uniforms = {} @@ -112,7 +110,6 @@ class PreviewPass(RenderPass): batch.render(render_camera) batch_support_mesh.render(render_camera) - batch_non_printing.render(render_camera) self.release() diff --git a/cura/Snapshot.py b/cura/Snapshot.py index 1f2a24aecd..d1bfeea40f 100644 --- a/cura/Snapshot.py +++ b/cura/Snapshot.py @@ -6,13 +6,10 @@ from PyQt5 import QtCore from PyQt5.QtGui import QImage from cura.PreviewPass import PreviewPass -from cura.Scene import ConvexHullNode from UM.Application import Application -from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Math.Matrix import Matrix from UM.Math.Vector import Vector -from UM.Mesh.MeshData import transformVertices from UM.Scene.Camera import Camera from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator @@ -51,7 +48,7 @@ class Snapshot: # determine zoom and look at bbox = None for node in DepthFirstIterator(root): - if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible(): + if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible() and not node.callDecoration("isNonPrintingMesh"): if bbox is None: bbox = node.getBoundingBox() else: diff --git a/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml b/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml index da53fc94af..355fa5dece 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml @@ -9,7 +9,6 @@ import UM 1.1 as UM Item { id: tile - property bool installed: toolbox.isInstalled(model.id) width: detailList.width - UM.Theme.getSize("wide_margin").width height: normalData.height + compatibilityChart.height + 4 * UM.Theme.getSize("default_margin").height Item @@ -46,7 +45,7 @@ Item } } - Item + ToolboxDetailTileActions { id: controls anchors.right: tile.right @@ -54,28 +53,6 @@ Item width: childrenRect.width height: childrenRect.height - ToolboxProgressButton - { - id: installButton - active: toolbox.isDownloading && toolbox.activePackage == model - complete: tile.installed - readyAction: function() - { - toolbox.activePackage = model - toolbox.startDownload(model.download_url) - } - activeAction: function() - { - toolbox.cancelDownload() - } - completeAction: function() - { - toolbox.viewCategory = "installed" - } - // Don't allow installing while another download is running - enabled: installed || !(toolbox.isDownloading && toolbox.activePackage != model) - opacity: enabled ? 1.0 : 0.5 - } } ToolboxCompatibilityChart @@ -94,9 +71,4 @@ Item anchors.top: compatibilityChart.bottom anchors.topMargin: UM.Theme.getSize("default_margin").height + UM.Theme.getSize("wide_margin").height //Normal margin for spacing after chart, wide margin between items. } - Connections - { - target: toolbox - onInstallChanged: installed = toolbox.isInstalled(model.id) - } } diff --git a/plugins/Toolbox/resources/qml/ToolboxDetailTileActions.qml b/plugins/Toolbox/resources/qml/ToolboxDetailTileActions.qml new file mode 100644 index 0000000000..f82fb049d8 --- /dev/null +++ b/plugins/Toolbox/resources/qml/ToolboxDetailTileActions.qml @@ -0,0 +1,66 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Toolbox is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import UM 1.1 as UM + +Column +{ + property bool installed: toolbox.isInstalled(model.id) + property bool canUpdate: toolbox.canUpdate(model.id) + width: UM.Theme.getSize("toolbox_action_button").width + spacing: UM.Theme.getSize("narrow_margin").height + + ToolboxProgressButton + { + id: installButton + active: toolbox.isDownloading && toolbox.activePackage == model + complete: installed + readyAction: function() + { + toolbox.activePackage = model + toolbox.startDownload(model.download_url) + } + activeAction: function() + { + toolbox.cancelDownload() + } + completeAction: function() + { + toolbox.viewCategory = "installed" + } + // Don't allow installing while another download is running + enabled: installed || !(toolbox.isDownloading && toolbox.activePackage != model) + opacity: enabled ? 1.0 : 0.5 + } + + ToolboxProgressButton + { + id: updateButton + active: toolbox.isDownloading && toolbox.activePackage == model + readyLabel: catalog.i18nc("@action:button", "Update") + activeLabel: catalog.i18nc("@action:button", "Updating") + completeLabel: catalog.i18nc("@action:button", "Updated") + readyAction: function() + { + toolbox.activePackage = model + toolbox.update(model.id) + } + activeAction: function() + { + toolbox.cancelDownload() + } + // Don't allow installing while another download is running + enabled: !(toolbox.isDownloading && toolbox.activePackage != model) + opacity: enabled ? 1.0 : 0.5 + visible: installed && canUpdate + } + Connections + { + target: toolbox + onInstallChanged: installed = toolbox.isInstalled(model.id) + onMetadataChanged: canUpdate = toolbox.canUpdate(model.id) + } +} diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml index 5b9697eda2..e1ffc6326c 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml @@ -15,7 +15,7 @@ Column Label { id: heading - text: toolbox.viewCategory == "material" ? catalog.i18nc("@label", "Maker Choices") : catalog.i18nc("@label", "Community Plugins") + text: toolbox.viewCategory == "material" ? catalog.i18nc("@label", "Community contributions") : catalog.i18nc("@label", "Community plugins") width: parent.width color: UM.Theme.getColor("text_medium") font: UM.Theme.getFont("medium") diff --git a/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml b/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml index 435319b5e9..78c970659c 100644 --- a/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml @@ -10,7 +10,6 @@ Item { height: UM.Theme.getSize("toolbox_installed_tile").height width: parent.width - property bool canUpdate: false property bool isEnabled: true Rectangle @@ -109,7 +108,6 @@ Item { target: toolbox onEnabledChanged: isEnabled = toolbox.isEnabled(model.id) - onMetadataChanged: canUpdate = toolbox.canUpdate(model.id) } } } diff --git a/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml b/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml index 8bdec4da5f..0ae738b71d 100644 --- a/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml +++ b/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml @@ -8,6 +8,8 @@ import UM 1.1 as UM Column { + property bool canUpdate: false + property bool canDowngrade: false width: UM.Theme.getSize("toolbox_action_button").width spacing: UM.Theme.getSize("narrow_margin").height @@ -36,7 +38,7 @@ Column Button { id: removeButton - text: catalog.i18nc("@action:button", "Uninstall") + text: canDowngrade ? catalog.i18nc("@action:button", "Downgrade") : catalog.i18nc("@action:button", "Uninstall") visible: !model.is_bundled enabled: !toolbox.isDownloading style: ButtonStyle @@ -49,7 +51,17 @@ Column border { width: UM.Theme.getSize("default_lining").width - color: UM.Theme.getColor("lining") + color: + { + if (control.hovered) + { + return UM.Theme.getColor("primary_hover") + } + else + { + return UM.Theme.getColor("lining") + } + } } } label: Label @@ -58,8 +70,18 @@ Column color: UM.Theme.getColor("text") verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter + font: UM.Theme.getFont("default") } } onClicked: toolbox.uninstall(model.id) + Connections + { + target: toolbox + onMetadataChanged: + { + canUpdate = toolbox.canUpdate(model.id) + canDowngrade = toolbox.canDowngrade(model.id) + } + } } } diff --git a/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml b/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml index a977ef999b..b598bd96d0 100644 --- a/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml +++ b/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml @@ -68,7 +68,7 @@ Item { if (base.complete) { - return UM.Theme.getColor("action_button_disabled") + return "transparent" } else { @@ -82,6 +82,31 @@ Item } } } + border + { + width: + { + if (base.complete) + { + UM.Theme.getSize("default_lining").width + } + else + { + return 0 + } + } + color: + { + if (control.hovered) + { + return UM.Theme.getColor("primary_hover") + } + else + { + return UM.Theme.getColor("lining") + } + } + } } label: Label { @@ -90,7 +115,7 @@ Item { if (base.complete) { - return UM.Theme.getColor("action_button_disabled_text") + return UM.Theme.getColor("text") } else { @@ -106,7 +131,17 @@ Item } verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter - font: UM.Theme.getFont("default_bold") + font: + { + if (base.complete) + { + return UM.Theme.getFont("default") + } + else + { + return UM.Theme.getFont("default_bold") + } + } } } } diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index 622198666d..776f2a3870 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -300,6 +300,20 @@ class Toolbox(QObject, Extension): remote_version = Version(remote_package["package_version"]) return remote_version > local_version + @pyqtSlot(str, result=bool) + def canDowngrade(self, package_id: str) -> bool: + local_package = self._package_manager.getInstalledPackageInfo(package_id) + if local_package is None: + return False + + remote_package = self.getRemotePackage(package_id) + if remote_package is None: + return False + + local_version = Version(local_package["package_version"]) + remote_version = Version(remote_package["package_version"]) + return remote_version < local_version + @pyqtSlot(str, result = bool) def isInstalled(self, package_id: str) -> bool: return self._package_manager.isPackageInstalled(package_id) diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.py b/plugins/UM3NetworkPrinting/DiscoverUM3Action.py index 0b8d6e9f53..9b25de7f42 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.py +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.py @@ -45,6 +45,8 @@ class DiscoverUM3Action(MachineAction): @pyqtSlot() def reset(self): Logger.log("d", "Reset the list of found devices.") + if self._network_plugin: + self._network_plugin.resetLastManualDevice() self.discoveredDevicesChanged.emit() @pyqtSlot() @@ -83,15 +85,8 @@ class DiscoverUM3Action(MachineAction): @pyqtProperty("QVariantList", notify = discoveredDevicesChanged) def foundDevices(self): if self._network_plugin: - # TODO: Check if this needs to stay. - if Application.getInstance().getGlobalContainerStack(): - global_printer_type = Application.getInstance().getGlobalContainerStack().getBottom().getId() - else: - global_printer_type = "unknown" printers = list(self._network_plugin.getDiscoveredDevices().values()) - # TODO; There are still some testing printers that don't have a correct printer type, so don't filter out unkown ones just yet. - #printers = [printer for printer in printers if printer.printerType == global_printer_type or printer.printerType == "unknown"] printers.sort(key = lambda k: k.name) return printers else: @@ -138,7 +133,7 @@ class DiscoverUM3Action(MachineAction): self._network_plugin.reCheckConnections() @pyqtSlot(result = str) - def getStoredKey(self): + def getStoredKey(self) -> str: global_container_stack = Application.getInstance().getGlobalContainerStack() if global_container_stack: meta_data = global_container_stack.getMetaData() @@ -147,6 +142,12 @@ class DiscoverUM3Action(MachineAction): return "" + @pyqtSlot(result = str) + def getLastManualEntryKey(self) -> str: + if self._network_plugin: + return self._network_plugin.getLastManualDevice() + return "" + @pyqtSlot(str, result = bool) def existsKey(self, key) -> bool: return Application.getInstance().getMachineManager().existNetworkInstances(network_key = key) diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml index 72c956b8d7..3662fe291e 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml @@ -158,7 +158,10 @@ Cura.MachineAction model: manager.foundDevices onModelChanged: { - var selectedKey = manager.getStoredKey(); + var selectedKey = manager.getLastManualEntryKey() + // If there is no last manual entry key, then we select the stored key (if any) + if (selectedKey == "") + selectedKey = manager.getStoredKey() for(var i = 0; i < model.length; i++) { if(model[i].key == selectedKey) { @@ -354,12 +357,10 @@ Cura.MachineAction onShowDialog: { printerKey = key; - addressText = address; + manualPrinterDialog.show(); addressField.selectAll(); addressField.focus = true; - - manualPrinterDialog.show(); } onAccepted: diff --git a/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py b/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py index e53dc3e467..57b1e23c68 100644 --- a/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py +++ b/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py @@ -59,6 +59,9 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): self._manual_instances = self._preferences.getValue("um3networkprinting/manual_instances").split(",") + # Store the last manual entry key + self._last_manual_entry_key = "" # type: str + # The zero-conf service changed requests are handled in a separate thread, so we can re-schedule the requests # which fail to get detailed service info. # Any new or re-scheduled requests will be appended to the request queue, and the handling thread will pick @@ -71,6 +74,12 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): def getDiscoveredDevices(self): return self._discovered_devices + def getLastManualDevice(self) -> str: + return self._last_manual_entry_key + + def resetLastManualDevice(self) -> None: + self._last_manual_entry_key = "" + ## Start looking for devices on network. def start(self): self.startDiscovery() @@ -92,6 +101,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): for address in self._manual_instances: if address: self.addManualDevice(address) + self.resetLastManualDevice() def reCheckConnections(self): active_machine = Application.getInstance().getGlobalContainerStack() @@ -135,6 +145,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): if not address: address = self._discovered_devices[key].ipAddress self._onRemoveDevice(key) + self.resetLastManualDevice() if address in self._manual_instances: self._manual_instances.remove(address) @@ -156,6 +167,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): if instance_name not in self._discovered_devices: # Add a preliminary printer instance self._onAddDevice(instance_name, address, properties) + self._last_manual_entry_key = instance_name self._checkManualDevice(address) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 6dcd5a5ccc..70d07c1fc5 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -514,7 +514,7 @@ class XmlMaterialProfile(InstanceContainer): color = entry.find("./um:color", self.__namespaces) label = entry.find("./um:label", self.__namespaces) - if label is not None: + if label is not None and label.text is not None: meta_data["name"] = label.text else: meta_data["name"] = self._profile_name(material.text, color.text) @@ -805,7 +805,7 @@ class XmlMaterialProfile(InstanceContainer): color = entry.find("./um:color", cls.__namespaces) label = entry.find("./um:label", cls.__namespaces) - if label is not None: + if label is not None and label.text is not None: base_metadata["name"] = label.text else: base_metadata["name"] = cls._profile_name(material.text, color.text) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 5d7eed5c6d..fc8395a8dc 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -5772,6 +5772,27 @@ "limit_to_extruder": "infill_extruder_nr", "settable_per_mesh": true }, + "cross_infill_density_image": + { + "label": "Cross Infill Density Image", + "description": "The file location of an image of which the brightness values determine the minimal density at the corresponding location in the infill of the print.", + "type": "str", + "default_value": "", + "enabled": "infill_pattern == 'cross' or infill_pattern == 'cross_3d'", + "limit_to_extruder": "infill_extruder_nr", + "settable_per_mesh": true + }, + "cross_support_density_image": + { + "label": "Cross Fill Density Image for Support", + "description": "The file location of an image of which the brightness values determine the minimal density at the corresponding location in the support.", + "type": "str", + "default_value": "", + "enabled": "infill_pattern == 'cross' or infill_pattern == 'cross_3d'", + "limit_to_extruder": "support_infill_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + }, "spaghetti_infill_enabled": { "label": "Spaghetti Infill", diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index ac37cce10a..e1cc4f6e45 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -323,6 +323,21 @@ UM.MainWindow { if (drop.urls.length > 0) { + // As the drop area also supports plugins, first check if it's a plugin that was dropped. + if (drop.urls.length == 1) + { + var filename = drop.urls[0]; + if (filename.endsWith(".curapackage")) + { + // Try to install plugin & close. + CuraApplication.getCuraPackageManager().installPackageViaDragAndDrop(filename); + packageInstallDialog.text = catalog.i18nc("@label", "This package will be installed after restarting."); + packageInstallDialog.icon = StandardIcon.Information; + packageInstallDialog.open(); + return; + } + } + openDialog.handleOpenFileUrls(drop.urls); } } @@ -489,6 +504,7 @@ UM.MainWindow horizontalCenterOffset: -(Math.round(UM.Theme.getSize("sidebar").width / 2)) top: parent.verticalCenter; bottom: parent.bottom; + bottomMargin: UM.Theme.getSize("default_margin").height } } } @@ -789,6 +805,14 @@ UM.MainWindow } } + MessageDialog + { + id: packageInstallDialog + title: catalog.i18nc("@window:title", "Install Package"); + standardButtons: StandardButton.Ok + modality: Qt.ApplicationModal + } + MessageDialog { id: infoMultipleFilesWithGcodeDialog title: catalog.i18nc("@title:window", "Open File(s)") diff --git a/resources/qml/PrintMonitor.qml b/resources/qml/PrintMonitor.qml index ae74170004..b24bcb6d6c 100644 --- a/resources/qml/PrintMonitor.qml +++ b/resources/qml/PrintMonitor.qml @@ -67,7 +67,7 @@ Column HeatedBedBox { visible: { - if(activePrinter != null && activePrinter.bed_temperature != -1) + if(activePrinter != null && activePrinter.bedTemperature != -1) { return true } diff --git a/resources/qml/WorkspaceSummaryDialog.qml b/resources/qml/WorkspaceSummaryDialog.qml index 4d15860257..0869d7e698 100644 --- a/resources/qml/WorkspaceSummaryDialog.qml +++ b/resources/qml/WorkspaceSummaryDialog.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.1 @@ -61,237 +61,220 @@ UM.Dialog { id: palette } - - Column + Label { - anchors.fill: parent - spacing: 2 * screenScaleFactor - Label + id: mainHeading + width: parent.width + text: catalog.i18nc("@action:title", "Summary - Cura Project") + font.pointSize: 18 + anchors.top: parent.top + } + ScrollView + { + id: scroll + width: parent.width + anchors { - id: titleLabel - text: catalog.i18nc("@action:title", "Summary - Cura Project") - font.pointSize: 18 + top: mainHeading.bottom + topMargin: UM.Theme.getSize("default_margin").height + bottom: controls.top + bottomMargin: UM.Theme.getSize("default_margin").height } - Rectangle + style: UM.Theme.styles.scrollview + ColumnLayout { - id: separator - color: palette.text - width: parent.width - height: 1 - } - Item // Spacer - { - height: spacerHeight - width: height - } - - Label - { - text: catalog.i18nc("@action:label", "Printer settings") - font.bold: true - } - Row - { - width: parent.width - height: childrenRect.height - Label + spacing: UM.Theme.getSize("default_margin").height + Column { - text: catalog.i18nc("@action:label", "Type") - width: (parent.width / 3) | 0 - } - Label - { - text: (Cura.MachineManager.activeMachine == null) ? "" : Cura.MachineManager.activeMachine.definition.name - width: (parent.width / 3) | 0 - } - } - Row - { - width: parent.width - height: childrenRect.height - Label - { - text: catalog.i18nc("@action:label", Cura.MachineManager.activeMachineNetworkGroupName != "" ? "Printer Group" : "Name") - width: (parent.width / 3) | 0 - } - Label - { - text: Cura.MachineManager.activeMachineNetworkGroupName != "" ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName - width: (parent.width / 3) | 0 - } - } - Column - { - width: parent.width - visible: Cura.MachineManager.hasVariantBuildplates - Item // Spacer - { - height: spacerHeight - width: height - } - Row - { - width: parent.width - height: childrenRect.height Label { - text: catalog.i18nc("@action:label", "Build plate") - width: (parent.width / 3) | 0 + id: settingsHeading + text: catalog.i18nc("@action:label", "Printer settings") + font.bold: true } - Label - { - text: Cura.MachineManager.activeVariantBuildplateName - width: (parent.width / 3) | 0 - } - } - } - - Repeater - { - model: Cura.MachineManager.currentExtruderPositions - delegate: Column - { - Item // Spacer - { - height: spacerHeight - width: height - } - Label - { - text: catalog.i18nc("@action:label", "Extruder %1").arg(modelData) - } - height: childrenRect.height - width: parent.width Row { width: parent.width height: childrenRect.height Label { - text: catalog.i18nc("@action:label", "%1 & material").arg(Cura.MachineManager.activeDefinitionVariantsName) - width: (parent.width / 3) | 0 + text: catalog.i18nc("@action:label", "Type") + width: Math.floor(scroll.width / 3) | 0 } Label { - text: Cura.MachineManager.activeVariantNames[modelData] + ", " + Cura.MachineManager.getExtruder(modelData).material.name - width: (parent.width / 3) | 0 + text: (Cura.MachineManager.activeMachine == null) ? "" : Cura.MachineManager.activeMachine.definition.name + width: Math.floor(scroll.width / 3) | 0 + } + } + Row + { + width: parent.width + height: childrenRect.height + Label + { + text: catalog.i18nc("@action:label", Cura.MachineManager.activeMachineNetworkGroupName != "" ? "Printer Group" : "Name") + width: Math.floor(scroll.width / 3) | 0 + } + Label + { + text: Cura.MachineManager.activeMachineNetworkGroupName != "" ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName + width: Math.floor(scroll.width / 3) | 0 + } + } + } + Row + { + visible: Cura.MachineManager.hasVariantBuildplates + width: parent.width + height: childrenRect.height + Label + { + text: catalog.i18nc("@action:label", "Build plate") + width: Math.floor(scroll.width / 3) | 0 + } + Label + { + text: Cura.MachineManager.activeVariantBuildplateName + width: Math.floor(scroll.width / 3) | 0 + } + } + Repeater + { + width: parent.width + height: childrenRect.height + model: Cura.MachineManager.currentExtruderPositions + delegate: Column + { + height: childrenRect.height + width: parent.width + Label + { + text: catalog.i18nc("@action:label", "Extruder %1").arg(modelData) + font.bold: true + } + Row + { + width: parent.width + height: childrenRect.height + Label + { + text: catalog.i18nc("@action:label", "%1 & material").arg(Cura.MachineManager.activeDefinitionVariantsName) + width: Math.floor(scroll.width / 3) | 0 + } + Label + { + text: Cura.MachineManager.activeVariantNames[modelData] + ", " + Cura.MachineManager.getExtruder(modelData).material.name + width: Math.floor(scroll.width / 3) | 0 + } + } + } + } + Column + { + width: parent.width + height: childrenRect.height + Label + { + text: catalog.i18nc("@action:label", "Profile settings") + font.bold: true + } + Row + { + width: parent.width + Label + { + text: catalog.i18nc("@action:label", "Not in profile") + width: Math.floor(scroll.width / 3) | 0 + } + Label + { + text: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", Cura.MachineManager.numUserSettings).arg(Cura.MachineManager.numUserSettings) + width: Math.floor(scroll.width / 3) | 0 + } + visible: Cura.MachineManager.numUserSettings + } + Row + { + width: parent.width + height: childrenRect.height + Label + { + text: catalog.i18nc("@action:label", "Name") + width: Math.floor(scroll.width / 3) | 0 + } + Label + { + text: Cura.MachineManager.activeQualityOrQualityChangesName + width: Math.floor(scroll.width / 3) | 0 + } + + } + } + Column + { + width: parent.width + height: childrenRect.height + Label + { + text: catalog.i18nc("@action:label", "Setting visibility") + font.bold: true + } + Row + { + width: parent.width + height: childrenRect.height + Label + { + text: catalog.i18nc("@action:label", "Visible settings:") + width: Math.floor(scroll.width / 3) | 0 + } + Label + { + text: catalog.i18nc("@action:label", "%1 out of %2" ).arg(definitionsModel.visibleCount).arg(Cura.MachineManager.totalNumberOfSettings) + width: Math.floor(scroll.width / 3) | 0 } } } } - - Item // Spacer - { - height: spacerHeight - width: height - } - - Label - { - text: catalog.i18nc("@action:label", "Profile settings") - font.bold: true - } - Row - { - width: parent.width - Label - { - text: catalog.i18nc("@action:label", "Not in profile") - width: (parent.width / 3) | 0 - } - Label - { - text: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", Cura.MachineManager.numUserSettings).arg(Cura.MachineManager.numUserSettings) - width: (parent.width / 3) | 0 - } - visible: Cura.MachineManager.numUserSettings - } - Row - { - width: parent.width - height: childrenRect.height - Label - { - text: catalog.i18nc("@action:label", "Name") - width: (parent.width / 3) | 0 - } - Label - { - text: Cura.MachineManager.activeQualityOrQualityChangesName - width: (parent.width / 3) | 0 - } - - } - - Item // Spacer - { - height: spacerHeight - width: height - } - - Label - { - text: catalog.i18nc("@action:label", "Setting visibility") - font.bold: true - } - Row - { - width: parent.width - height: childrenRect.height - Label - { - text: catalog.i18nc("@action:label", "Visible settings:") - width: (parent.width / 3) | 0 - } - Label - { - text: catalog.i18nc("@action:label", "%1 out of %2" ).arg(definitionsModel.visibleCount).arg(Cura.MachineManager.totalNumberOfSettings) - width: (parent.width / 3) | 0 - } - } - - Item // Spacer - { - height: spacerHeight - width: height - } } - - CheckBox + Item { - id: dontShowAgainCheckbox - anchors.bottom: cancel_button.top - anchors.bottomMargin: UM.Theme.getSize("default_margin").height - anchors.left: parent.left - - text: catalog.i18nc("@action:label", "Don't show project summary on save again") - checked: dontShowAgain - } - - Button - { - id: cancel_button + id: controls + width: parent.width + height: childrenRect.height anchors.bottom: parent.bottom - anchors.right: ok_button.left - anchors.rightMargin: 2 - - text: catalog.i18nc("@action:button","Cancel"); - enabled: true - onClicked: close() - } - - Button - { - id: ok_button - anchors.bottom: parent.bottom - anchors.right: parent.right - - text: catalog.i18nc("@action:button","Save"); - enabled: true - onClicked: { - close() - yes() + CheckBox + { + id: dontShowAgainCheckbox + anchors.left: parent.left + text: catalog.i18nc("@action:label", "Don't show project summary on save again") + checked: dontShowAgain + } + Button + { + id: cancel_button + anchors + { + right: ok_button.left + rightMargin: UM.Theme.getSize("default_margin").width + } + text: catalog.i18nc("@action:button","Cancel"); + enabled: true + onClicked: close() + } + Button + { + id: ok_button + anchors.right: parent.right + text: catalog.i18nc("@action:button","Save"); + enabled: true + onClicked: + { + close() + yes() + } } } } -} +} \ No newline at end of file diff --git a/resources/shaders/camera_distance.shader b/resources/shaders/camera_distance.shader index e6e894a2f6..437aa39cc2 100644 --- a/resources/shaders/camera_distance.shader +++ b/resources/shaders/camera_distance.shader @@ -25,9 +25,9 @@ fragment = highp float distance_to_camera = distance(v_vertex, u_viewPosition) * 1000.; // distance in micron vec3 encoded; // encode float into 3 8-bit channels; this gives a precision of a micron at a range of up to ~16 meter - encoded.b = floor(distance_to_camera / 65536.0); - encoded.g = floor((distance_to_camera - encoded.b * 65536.0) / 256.0); - encoded.r = floor(distance_to_camera - encoded.b * 65536.0 - encoded.g * 256.0); + encoded.r = floor(distance_to_camera / 65536.0); + encoded.g = floor((distance_to_camera - encoded.r * 65536.0) / 256.0); + encoded.b = floor(distance_to_camera - encoded.r * 65536.0 - encoded.g * 256.0); gl_FragColor.rgb = encoded / 255.; gl_FragColor.a = 1.0;