diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 511b66c46b..72cad13468 100644 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -452,7 +452,10 @@ class BuildVolume(SceneNode): if not used_extruders: # If no extruder is used, assume that the active extruder is used (else nothing is drawn) - used_extruders = [extruder_manager.getActiveExtruderStack()] + if extruder_manager.getActiveExtruderStack(): + used_extruders = [extruder_manager.getActiveExtruderStack()] + else: + used_extruders = [self._global_container_stack] result_areas = self._computeDisallowedAreasStatic(disallowed_border_size, used_extruders) #Normal machine disallowed areas can always be added. prime_areas = self._computeDisallowedAreasPrime(disallowed_border_size, used_extruders) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 6ed7759c34..4753955337 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -129,6 +129,7 @@ class CuraApplication(QtApplication): { ("quality", UM.Settings.InstanceContainer.Version): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"), ("machine_stack", UM.Settings.ContainerStack.Version): (self.ResourceTypes.MachineStack, "application/x-uranium-containerstack"), + ("extruder_train", UM.Settings.ContainerStack.Version): (self.ResourceTypes.ExtruderStack, "application/x-uranium-extruderstack"), ("preferences", UM.Preferences.Version): (Resources.Preferences, "application/x-uranium-preferences"), ("user", UM.Settings.InstanceContainer.Version): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer") } diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index 7e06b95100..af3cb62406 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -140,8 +140,6 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): for extruder in manager.getMachineExtruders(global_container_stack.getId()): extruder_name = extruder.getName() material = extruder.findContainer({ "type": "material" }) - if material and not self._simple_names: - extruder_name = "%s (%s)" % (material.getName(), extruder_name) position = extruder.getMetaDataEntry("position", default = "0") # Get the position try: position = int(position) diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index f7d2cc01f1..397a63c194 100644 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -187,10 +187,12 @@ class ThreeMFReader(MeshReader): build_item_node = self._createNodeFromObject(object, self._base_name + "_" + str(id)) # compensate for original center position, if object(s) is/are not around its zero position - extents = build_item_node.getMeshData().getExtents() - center_vector = Vector(extents.center.x, extents.center.y, extents.center.z) transform_matrix = Matrix() - transform_matrix.setByTranslation(center_vector) + mesh_data = build_item_node.getMeshData() + if mesh_data is not None: + extents = mesh_data.getExtents() + center_vector = Vector(extents.center.x, extents.center.y, extents.center.z) + transform_matrix.setByTranslation(center_vector) # offset with transform from 3mf transform = build_item.get("transform") diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index d50fe8c571..46806cf54d 100644 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -349,7 +349,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): global_stack = stack Job.yieldThread() except: - Logger.log("W", "We failed to serialize the stack. Trying to clean up.") + Logger.logException("w", "We failed to serialize the stack. Trying to clean up.") # Something went really wrong. Try to remove any data that we added. for container in containers_to_add: self._container_registry.getInstance().removeContainer(container.getId()) @@ -447,9 +447,17 @@ class ThreeMFWorkspaceReader(WorkspaceReader): def _getContainerIdListFromSerialized(self, serialized): parser = configparser.ConfigParser(interpolation=None, empty_lines_in_values=False) parser.read_string(serialized) - container_string = parser["general"].get("containers", "") - container_list = container_string.split(",") - return [container_id for container_id in container_list if container_id != ""] + + container_ids = [] + if "containers" in parser: + for index, container_id in parser.items("containers"): + container_ids.append(container_id) + elif parser.has_option("general", "containers"): + container_string = parser["general"].get("containers", "") + container_list = container_string.split(",") + container_ids = [container_id for container_id in container_list if container_id != ""] + + return container_ids def _getMachineNameFromSerializedStack(self, serialized): parser = configparser.ConfigParser(interpolation=None, empty_lines_in_values=False) @@ -461,4 +469,5 @@ class ThreeMFWorkspaceReader(WorkspaceReader): metadata = data.iterfind("./um:metadata/um:name/um:label", {"um": "http://www.ultimaker.com/material"}) for entry in metadata: return entry.text - pass \ No newline at end of file + pass + diff --git a/plugins/RemovableDriveOutputDevice/OSXRemovableDrivePlugin.py b/plugins/RemovableDriveOutputDevice/OSXRemovableDrivePlugin.py index c96bf8bacf..6d8b5021ae 100644 --- a/plugins/RemovableDriveOutputDevice/OSXRemovableDrivePlugin.py +++ b/plugins/RemovableDriveOutputDevice/OSXRemovableDrivePlugin.py @@ -17,41 +17,60 @@ class OSXRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin): drives = {} p = subprocess.Popen(["system_profiler", "SPUSBDataType", "-xml"], stdout = subprocess.PIPE) plist = plistlib.loads(p.communicate()[0]) - p.wait() - for entry in plist: - if "_items" in entry: - for item in entry["_items"]: - for dev in item["_items"]: - if "removable_media" in dev and dev["removable_media"] == "yes" and "volumes" in dev and len(dev["volumes"]) > 0: - for vol in dev["volumes"]: - if "mount_point" in vol: - volume = vol["mount_point"] - drives[volume] = os.path.basename(volume) + result = self._recursiveSearch(plist, "removable_media") p = subprocess.Popen(["system_profiler", "SPCardReaderDataType", "-xml"], stdout=subprocess.PIPE) plist = plistlib.loads(p.communicate()[0]) - p.wait() - for entry in plist: - if "_items" in entry: - for item in entry["_items"]: - for dev in item["_items"]: - if "removable_media" in dev and dev["removable_media"] == "yes" and "volumes" in dev and len(dev["volumes"]) > 0: - for vol in dev["volumes"]: - if "mount_point" in vol: - volume = vol["mount_point"] - drives[volume] = os.path.basename(volume) + result.extend(self._recursiveSearch(plist, "removable_media")) + + for drive in result: + # Ignore everything not explicitly marked as removable + if drive["removable_media"] != "yes": + continue + + # Ignore any removable device that does not have an actual volume + if "volumes" not in drive or not drive["volumes"]: + continue + + for volume in drive["volumes"]: + if not "mount_point" in volume: + continue + + mount_point = volume["mount_point"] + + if "_name" in volume: + drive_name = volume["_name"] + else: + drive_name = os.path.basename(mount_point) + + drives[mount_point] = drive_name return drives def performEjectDevice(self, device): p = subprocess.Popen(["diskutil", "eject", device.getId()], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE) output = p.communicate() - Logger.log("d", "umount returned: %s.", repr(output)) return_code = p.wait() if return_code != 0: return False else: - return True \ No newline at end of file + return True + + # Recursively search for key in a plist parsed by plistlib + def _recursiveSearch(self, plist, key): + result = [] + for entry in plist: + if key in entry: + result.append(entry) + continue + + if "_items" in entry: + result.extend(self._recursiveSearch(entry["_items"], key)) + + if "Media" in entry: + result.extend(self._recursiveSearch(entry["Media"], key)) + + return result diff --git a/plugins/VersionUpgrade/VersionUpgrade22to24/VersionUpgrade.py b/plugins/VersionUpgrade/VersionUpgrade22to24/VersionUpgrade.py new file mode 100644 index 0000000000..dce2b311bb --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade22to24/VersionUpgrade.py @@ -0,0 +1,120 @@ +# Copyright (c) 2016 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +import configparser #To get version numbers from config files. +import os +import os.path +import io + +from UM import Resources +from UM.VersionUpgrade import VersionUpgrade # Superclass of the plugin. + +class VersionUpgrade22to24(VersionUpgrade): + + def upgradeMachineInstance(self, serialised, filename): + # All of this is needed to upgrade custom variant machines from old Cura to 2.4 where + # `definition_changes` instance container has been introduced. Variant files which + # look like the the handy work of the old machine settings plugin are converted directly + # on disk. + + config = configparser.ConfigParser(interpolation = None) + config.read_string(serialised) # Read the input string as config file. + config.set("general", "version", "3") + + container_list = [] + if config.has_section("containers"): + for index, container_id in config.items("containers"): + container_list.append(container_id) + elif config.has_option("general", "containers"): + containers = config.get("general", "containers") + container_list = containers.split(",") + + user_variants = self.__getUserVariants() + name_path_dict = {} + for variant in user_variants: + name_path_dict[variant.get("name")] = variant.get("path") + + user_variant_names = set(container_list).intersection(name_path_dict.keys()) + if len(user_variant_names): + # One of the user defined variants appears in the list of containers in the stack. + + for variant_name in user_variant_names: # really there should just be one variant to convert. + config_name = self.__convertVariant(name_path_dict.get(variant_name)) + + # Change the name of variant and insert empty_variant into the stack. + new_container_list = [] + for item in container_list: + if item == variant_name: + new_container_list.append(config_name) + new_container_list.append("empty_variant") + else: + new_container_list.append(item) + + container_list = new_container_list + + if not config.has_section("containers"): + config.add_section("containers") + + config.remove_option("general", "containers") + + for index in range(len(container_list)): + config.set("containers", index, container_list[index]) + + output = io.StringIO() + config.write(output) + return [filename], [output.getvalue()] + + def __convertVariant(self, variant_path): + # Copy the variant to the machine_instances/*_settings.inst.cfg + variant_config = configparser.ConfigParser(interpolation=None) + with open(variant_path, "r") as fhandle: + variant_config.read_file(fhandle) + + if variant_config.has_section("general") and variant_config.has_option("general", "name"): + config_name = variant_config.get("general", "name") + if config_name.endswith("_variant"): + config_name = config_name[:-len("_variant")] + "_settings" + variant_config.set("general", "name", config_name) + + if not variant_config.has_section("metadata"): + variant_config.add_section("metadata") + variant_config.set("metadata", "type", "definition_changes") + + resource_path = Resources.getDataStoragePath() + machine_instances_dir = os.path.join(resource_path, "machine_instances") + + if variant_path.endswith("_variant.inst.cfg"): + variant_path = variant_path[:-len("_variant.inst.cfg")] + "_settings.inst.cfg" + + with open(os.path.join(machine_instances_dir, os.path.basename(variant_path)), "w") as fp: + variant_config.write(fp) + + return config_name + + def __getUserVariants(self): + resource_path = Resources.getDataStoragePath() + variants_dir = os.path.join(resource_path, "variants") + + result = [] + for entry in os.scandir(variants_dir): + if entry.name.endswith('.inst.cfg') and entry.is_file(): + config = configparser.ConfigParser(interpolation = None) + with open(entry.path, "r") as fhandle: + config.read_file(fhandle) + if config.has_section("general") and config.has_option("general", "name"): + result.append( { "path": entry.path, "name": config.get("general", "name") } ) + return result + + def upgradeExtruderTrain(self, serialised, filename): + config = configparser.ConfigParser(interpolation = None) + config.read_string(serialised) # Read the input string as config file. + config.set("general", "version", "3") # Just bump the version number. That is all we need for now. + + output = io.StringIO() + config.write(output) + return [filename], [output.getvalue()] + + def getCfgVersion(self, serialised): + parser = configparser.ConfigParser(interpolation = None) + parser.read_string(serialised) + return int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. diff --git a/plugins/VersionUpgrade/VersionUpgrade22to24/__init__.py b/plugins/VersionUpgrade/VersionUpgrade22to24/__init__.py new file mode 100644 index 0000000000..85d53199e4 --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade22to24/__init__.py @@ -0,0 +1,38 @@ +# Copyright (c) 2016 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +from . import VersionUpgrade + +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") + +upgrade = VersionUpgrade.VersionUpgrade22to24() + +def getMetaData(): + return { + "plugin": { + "name": catalog.i18nc("@label", "Version Upgrade 2.2 to 2.4"), + "author": "Ultimaker", + "version": "1.0", + "description": catalog.i18nc("@info:whatsthis", "Upgrades configurations from Cura 2.2 to Cura 2.4."), + "api": 3 + }, + "version_upgrade": { + # From To Upgrade function + ("machine_instance", 2): ("machine_stack", 3, upgrade.upgradeMachineInstance), + ("extruder_train", 2): ("extruder_train", 3, upgrade.upgradeExtruderTrain) + }, + "sources": { + "machine_stack": { + "get_version": upgrade.getCfgVersion, + "location": {"./machine_instances"} + }, + "extruder_train": { + "get_version": upgrade.getCfgVersion, + "location": {"./extruders"} + }, + } + } + +def register(app): + return { "version_upgrade": upgrade } diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index 71bbcccbdd..5e492bf531 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -106,6 +106,8 @@ "line_width": { "value": "machine_nozzle_size * 0.875" }, "machine_min_cool_heat_time_window": { "value": "15" }, "default_material_print_temperature": { "value": "200" }, + "material_bed_temperature": { "maximum_value": "115" }, + "material_bed_temperature_layer_0": { "maximum_value": "115" }, "material_standby_temperature": { "value": "100" }, "multiple_mesh_overlap": { "value": "0" }, "prime_tower_enable": { "value": "True" }, diff --git a/resources/extruders/ultimaker3_extended_extruder_left.def.json b/resources/extruders/ultimaker3_extended_extruder_left.def.json index 202272b096..3335e85ae3 100644 --- a/resources/extruders/ultimaker3_extended_extruder_left.def.json +++ b/resources/extruders/ultimaker3_extended_extruder_left.def.json @@ -1,7 +1,7 @@ { "id": "ultimaker3_extended_extruder_left", "version": 2, - "name": "Print core 1", + "name": "Extruder 1", "inherits": "fdmextruder", "metadata": { "machine": "ultimaker3_extended", diff --git a/resources/extruders/ultimaker3_extended_extruder_right.def.json b/resources/extruders/ultimaker3_extended_extruder_right.def.json index 0f85b2dd09..2e072753b1 100644 --- a/resources/extruders/ultimaker3_extended_extruder_right.def.json +++ b/resources/extruders/ultimaker3_extended_extruder_right.def.json @@ -1,7 +1,7 @@ { "id": "ultimaker3_extended_extruder_right", "version": 2, - "name": "Print core 2", + "name": "Extruder 2", "inherits": "fdmextruder", "metadata": { "machine": "ultimaker3_extended", diff --git a/resources/extruders/ultimaker3_extruder_left.def.json b/resources/extruders/ultimaker3_extruder_left.def.json index 83efa25dbb..141fd2f80c 100644 --- a/resources/extruders/ultimaker3_extruder_left.def.json +++ b/resources/extruders/ultimaker3_extruder_left.def.json @@ -1,7 +1,7 @@ { "id": "ultimaker3_extruder_left", "version": 2, - "name": "Print core 1", + "name": "Extruder 1", "inherits": "fdmextruder", "metadata": { "machine": "ultimaker3", diff --git a/resources/extruders/ultimaker3_extruder_right.def.json b/resources/extruders/ultimaker3_extruder_right.def.json index 4a75059c40..50a369e3ed 100644 --- a/resources/extruders/ultimaker3_extruder_right.def.json +++ b/resources/extruders/ultimaker3_extruder_right.def.json @@ -1,7 +1,7 @@ { "id": "ultimaker3_extruder_right", "version": 2, - "name": "Print core 2", + "name": "Extruder 2", "inherits": "fdmextruder", "metadata": { "machine": "ultimaker3", diff --git a/resources/extruders/ultimaker_original_dual_1st.def.json b/resources/extruders/ultimaker_original_dual_1st.def.json index 058dbf3028..62ec8479c9 100644 --- a/resources/extruders/ultimaker_original_dual_1st.def.json +++ b/resources/extruders/ultimaker_original_dual_1st.def.json @@ -1,7 +1,7 @@ { "id": "ultimaker_original_dual_1st", "version": 2, - "name": "1st Extruder", + "name": "Extruder 1", "inherits": "fdmextruder", "metadata": { "machine": "ultimaker_original_dual", diff --git a/resources/extruders/ultimaker_original_dual_2nd.def.json b/resources/extruders/ultimaker_original_dual_2nd.def.json index 4b600d0281..42a4da524b 100644 --- a/resources/extruders/ultimaker_original_dual_2nd.def.json +++ b/resources/extruders/ultimaker_original_dual_2nd.def.json @@ -1,7 +1,7 @@ { "id": "ultimaker_original_dual_2nd", "version": 2, - "name": "2nd Extruder", + "name": "Extruder 2", "inherits": "fdmextruder", "metadata": { "machine": "ultimaker_original_dual", diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 83f980bf86..70e3780707 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -127,7 +127,7 @@ UM.ManagementPage { text: catalog.i18nc("@action:button", "Activate"); iconName: "list-activate"; - enabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMaterialId + enabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMaterialId && Cura.MachineManager.hasMaterials onClicked: Cura.MachineManager.setActiveMaterial(base.currentItem.id) }, Button @@ -144,8 +144,10 @@ UM.ManagementPage { return } - - Cura.MachineManager.setActiveMaterial(material_id) + if(Cura.MachineManager.hasMaterials) + { + Cura.MachineManager.setActiveMaterial(material_id) + } } }, Button diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 5f20f92b20..6af3985527 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -84,7 +84,7 @@ Item onTextChanged: { - definitionsModel.filter = {"label": "*" + text}; + definitionsModel.filter = {"i18n_label": "*" + text}; findingSettings = (text.length > 0); if(findingSettings != lastFindingSettings) { diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index 77e82b5f92..f9c314d660 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -8,6 +8,7 @@ import QtQuick.Layouts 1.1 import UM 1.2 as UM import Cura 1.0 as Cura +import "Menus" Rectangle { @@ -30,9 +31,21 @@ Rectangle property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands - color: UM.Theme.getColor("sidebar"); + color: UM.Theme.getColor("sidebar") UM.I18nCatalog { id: catalog; name:"cura"} + Timer { + id: tooltipDelayTimer + interval: 500 + repeat: false + property var item + property string text + + onTriggered: + { + base.showTooltip(base, {x:1, y:item.y}, text); + } + } function showTooltip(item, position, text) { @@ -73,7 +86,7 @@ Rectangle } } - // Mode selection buttons for changing between Setting & Monitor print mode + // Printer selection and mode selection buttons for changing between Setting & Monitor print mode Rectangle { id: sidebarHeaderBar @@ -85,25 +98,90 @@ Rectangle Row { anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width; anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("default_margin").width + spacing: UM.Theme.getSize("default_margin").width + + ToolButton + { + id: machineSelection + text: Cura.MachineManager.activeMachineName + + width: parent.width - (showSettings.width + showMonitor.width + 2 * UM.Theme.getSize("default_margin").width) + height: UM.Theme.getSize("sidebar_header").height + tooltip: Cura.MachineManager.activeMachineName + + anchors.verticalCenter: parent.verticalCenter + style: ButtonStyle { + background: Rectangle { + color: control.hovered ? UM.Theme.getColor("button_hover") : + control.pressed ? UM.Theme.getColor("button_hover") : UM.Theme.getColor("sidebar_header_bar") + Behavior on color { ColorAnimation { duration: 50; } } + + UM.RecolorImage { + id: downArrow + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("default_margin").width + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + sourceSize.height: width + color: UM.Theme.getColor("text_reversed") + source: UM.Theme.getIcon("arrow_bottom") + } + Label { + id: sidebarComboBoxLabel + color: UM.Theme.getColor("text_reversed") + text: control.text; + elide: Text.ElideRight; + anchors.left: parent.left; + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.right: downArrow.left; + anchors.rightMargin: control.rightMargin; + anchors.verticalCenter: parent.verticalCenter; + font: UM.Theme.getFont("large") + } + } + label: Label{} + } + + menu: PrinterMenu { } + } + Button { id: showSettings - width: (parent.width - UM.Theme.getSize("default_margin").width) / 2 + width: height height: UM.Theme.getSize("sidebar_header").height onClicked: monitoringPrint = false iconSource: UM.Theme.getIcon("tab_settings"); checkable: true checked: !monitoringPrint exclusiveGroup: sidebarHeaderBarGroup + property string tooltipText: catalog.i18nc("@tooltip", "Print Setup

Edit or review the settings for the active print job.") + + onHoveredChanged: { + if (hovered) + { + tooltipDelayTimer.item = showSettings + tooltipDelayTimer.text = tooltipText + tooltipDelayTimer.start(); + } + else + { + tooltipDelayTimer.stop(); + base.hideTooltip(); + } + } style: UM.Theme.styles.sidebar_header_tab } + Button { id: showMonitor - width: (parent.width - UM.Theme.getSize("default_margin").width) / 2 + width: height height: UM.Theme.getSize("sidebar_header").height onClicked: monitoringPrint = true iconSource: { @@ -139,6 +217,21 @@ Rectangle checkable: true checked: monitoringPrint exclusiveGroup: sidebarHeaderBarGroup + property string tooltipText: catalog.i18nc("@tooltip", "Print Monitor

Monitor the state of the connected printer and the print job in progress.") + + onHoveredChanged: { + if (hovered) + { + tooltipDelayTimer.item = showMonitor + tooltipDelayTimer.text = tooltipText + tooltipDelayTimer.start(); + } + else + { + tooltipDelayTimer.stop(); + base.hideTooltip(); + } + } style: UM.Theme.styles.sidebar_header_tab } @@ -151,7 +244,6 @@ Rectangle width: parent.width anchors.top: sidebarHeaderBar.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height onShowTooltip: base.showTooltip(item, location, text) onHideTooltip: base.hideTooltip() @@ -160,10 +252,11 @@ Rectangle Rectangle { id: headerSeparator width: parent.width - height: UM.Theme.getSize("sidebar_lining").height + visible: !monitoringPrint + height: visible ? UM.Theme.getSize("sidebar_lining").height : 0 color: UM.Theme.getColor("sidebar_lining") anchors.top: header.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height + anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0 } onCurrentModeIndexChanged: @@ -212,6 +305,20 @@ Rectangle checked: base.currentModeIndex == index onClicked: base.currentModeIndex = index + onHoveredChanged: { + if (hovered) + { + tooltipDelayTimer.item = settingsModeSelection + tooltipDelayTimer.text = model.tooltipText + tooltipDelayTimer.start(); + } + else + { + tooltipDelayTimer.stop(); + base.hideTooltip(); + } + } + style: ButtonStyle { background: Rectangle { border.width: UM.Theme.getSize("default_lining").width @@ -408,8 +515,18 @@ Rectangle Component.onCompleted: { - modesListModel.append({ text: catalog.i18nc("@title:tab", "Recommended"), item: sidebarSimple, showFilterButton: false }) - modesListModel.append({ text: catalog.i18nc("@title:tab", "Custom"), item: sidebarAdvanced, showFilterButton: true }) + modesListModel.append({ + text: catalog.i18nc("@title:tab", "Recommended"), + tooltipText: catalog.i18nc("@tooltip", "Recommended Print Setup

Print with the recommended settings for the selected printer, material and quality."), + item: sidebarSimple, + showFilterButton: false + }) + modesListModel.append({ + text: catalog.i18nc("@title:tab", "Custom"), + tooltipText: catalog.i18nc("@tooltip", "Custom Print Setup

Print with finegrained control over every last bit of the slicing process."), + item: sidebarAdvanced, + showFilterButton: true + }) sidebarContents.push({ "item": modesListModel.get(base.currentModeIndex).item, "immediate": true }); var index = parseInt(UM.Preferences.getValue("cura/active_mode")) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index e894392b06..78bde0c437 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -21,145 +21,142 @@ Column signal showTooltip(Item item, point location, string text) signal hideTooltip() - Row + Item { - id: machineSelectionRow - height: UM.Theme.getSize("sidebar_setup").height + id: extruderSelectionRow + width: parent.width + height: UM.Theme.getSize("sidebar_tabs").height + visible: machineExtruderCount.properties.value > 1 && !sidebar.monitoringPrint - anchors + Rectangle { - left: parent.left - leftMargin: UM.Theme.getSize("default_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("default_margin").width + id: extruderSeparator + visible: machineExtruderCount.properties.value > 1 && !sidebar.monitoringPrint + + width: parent.width + height: parent.height + color: UM.Theme.getColor("sidebar_lining") + + anchors.top: extruderSelectionRow.top } - Label + ListView { - id: machineSelectionLabel - text: catalog.i18nc("@label:listbox", "Printer:"); - anchors.verticalCenter: parent.verticalCenter - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); + id: extrudersList + property var index: 0 - width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width - } + height: UM.Theme.getSize("sidebar_header_mode_tabs").height + width: parent.width + boundsBehavior: Flickable.StopAtBounds - ToolButton - { - id: machineSelection - text: Cura.MachineManager.activeMachineName; + anchors + { + left: parent.left + right: parent.right + bottom: extruderSelectionRow.bottom + } - height: UM.Theme.getSize("setting_control").height - tooltip: Cura.MachineManager.activeMachineName - anchors.verticalCenter: parent.verticalCenter - style: UM.Theme.styles.sidebar_header_button + ExclusiveGroup { id: extruderMenuGroup; } - width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width + orientation: ListView.Horizontal - menu: PrinterMenu { } + model: Cura.ExtrudersModel { id: extrudersModel; addGlobal: false } + + Connections + { + target: Cura.MachineManager + onGlobalContainerChanged: + { + forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values. + var extruder_index = (machineExtruderCount.properties.value == 1) ? -1 : 0 + ExtruderManager.setActiveExtruderIndex(extruder_index); + } + } + + delegate: Button + { + height: ListView.view.height + width: ListView.view.width / extrudersModel.rowCount() + + text: model.name + tooltip: model.name + exclusiveGroup: extruderMenuGroup + checked: base.currentExtruderIndex == index + + onClicked: + { + forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values. + ExtruderManager.setActiveExtruderIndex(index); + } + + style: ButtonStyle + { + background: Rectangle + { + border.width: UM.Theme.getSize("default_lining").width + border.color: control.checked ? UM.Theme.getColor("tab_checked_border") : + control.pressed ? UM.Theme.getColor("tab_active_border") : + control.hovered ? UM.Theme.getColor("tab_hovered_border") : UM.Theme.getColor("tab_unchecked_border") + color: control.checked ? UM.Theme.getColor("tab_checked") : + control.pressed ? UM.Theme.getColor("tab_active") : + control.hovered ? UM.Theme.getColor("tab_hovered") : UM.Theme.getColor("tab_unchecked") + Behavior on color { ColorAnimation { duration: 50; } } + + Rectangle + { + id: highlight + visible: control.checked + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + height: UM.Theme.getSize("sidebar_header_highlight").height + color: UM.Theme.getColor("sidebar_header_bar") + } + + Rectangle + { + id: swatch + visible: index > -1 + height: UM.Theme.getSize("setting_control").height / 2 + width: height + anchors.left: parent.left + anchors.leftMargin: (parent.height - height) / 2 + anchors.verticalCenter: parent.verticalCenter + + color: model.color + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("setting_control_border") + } + + Label + { + anchors.verticalCenter: parent.verticalCenter + anchors.left: swatch.visible ? swatch.right : parent.left + anchors.leftMargin: swatch.visible ? UM.Theme.getSize("default_margin").width / 2 : UM.Theme.getSize("default_margin").width + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("default_margin").width / 2 + + color: control.checked ? UM.Theme.getColor("tab_checked_text") : + control.pressed ? UM.Theme.getColor("tab_active_text") : + control.hovered ? UM.Theme.getColor("tab_hovered_text") : UM.Theme.getColor("tab_unchecked_text") + + font: UM.Theme.getFont("default") + text: control.text + elide: Text.ElideRight + } + } + label: Item { } + } + } } } - ListView + Item { - id: extrudersList - property var index: 0 - - visible: machineExtruderCount.properties.value > 1 && !sidebar.monitoringPrint - height: UM.Theme.getSize("sidebar_header_mode_toggle").height - - boundsBehavior: Flickable.StopAtBounds - - anchors - { - left: parent.left - leftMargin: UM.Theme.getSize("default_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("default_margin").width - } - - ExclusiveGroup { id: extruderMenuGroup; } - - orientation: ListView.Horizontal - - model: Cura.ExtrudersModel { id: extrudersModel; addGlobal: false } - - Connections - { - target: Cura.MachineManager - onGlobalContainerChanged: - { - forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values. - var extruder_index = (machineExtruderCount.properties.value == 1) ? -1 : 0 - ExtruderManager.setActiveExtruderIndex(extruder_index); - } - } - - delegate: Button - { - height: ListView.view.height - width: ListView.view.width / extrudersModel.rowCount() - - text: model.name - tooltip: model.name - exclusiveGroup: extruderMenuGroup - checked: base.currentExtruderIndex == index - - onClicked: - { - forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values. - ExtruderManager.setActiveExtruderIndex(index); - } - - style: ButtonStyle - { - background: Rectangle - { - border.width: UM.Theme.getSize("default_lining").width - border.color: control.checked ? UM.Theme.getColor("toggle_checked_border") : - control.pressed ? UM.Theme.getColor("toggle_active_border") : - control.hovered ? UM.Theme.getColor("toggle_hovered_border") : UM.Theme.getColor("toggle_unchecked_border") - color: control.checked ? UM.Theme.getColor("toggle_checked") : - control.pressed ? UM.Theme.getColor("toggle_active") : - control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked") - Behavior on color { ColorAnimation { duration: 50; } } - - Rectangle - { - id: swatch - visible: index > -1 - height: UM.Theme.getSize("setting_control").height / 2 - width: height - anchors.left: parent.left - anchors.leftMargin: (parent.height - height) / 2 - anchors.verticalCenter: parent.verticalCenter - - color: model.color - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("toggle_checked") - } - - Label - { - anchors.verticalCenter: parent.verticalCenter - anchors.left: swatch.visible ? swatch.right : parent.left - anchors.leftMargin: swatch.visible ? UM.Theme.getSize("default_margin").width / 2 : UM.Theme.getSize("default_margin").width - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width / 2 - - color: control.checked ? UM.Theme.getColor("toggle_checked_text") : - control.pressed ? UM.Theme.getColor("toggle_active_text") : - control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text") - - font: UM.Theme.getFont("default") - text: control.text - elide: Text.ElideRight - } - } - label: Item { } - } - } + id: variantRowSpacer + height: UM.Theme.getSize("default_margin").height / 4 + width: height + visible: !extruderSelectionRow.visible } Row diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index c7da237648..499125a6f9 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -30,7 +30,7 @@ Item id: infillCellLeft anchors.top: parent.top anchors.left: parent.left - width: base.width / 100 * 35 - UM.Theme.getSize("default_margin").width + width: base.width * .45 - UM.Theme.getSize("default_margin").width height: childrenRect.height Label @@ -52,7 +52,7 @@ Item id: infillCellRight height: childrenRect.height; - width: base.width / 100 * 65 + width: base.width * .55 spacing: UM.Theme.getSize("default_margin").width anchors.left: infillCellLeft.right @@ -231,7 +231,7 @@ Item anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: enableSupportCheckBox.verticalCenter - width: parent.width / 100 * 45 - 3 * UM.Theme.getSize("default_margin").width + width: parent.width * .45 - 3 * UM.Theme.getSize("default_margin").width text: catalog.i18nc("@label", "Enable Support"); font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); @@ -279,7 +279,7 @@ Item anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: supportExtruderCombobox.verticalCenter - width: parent.width / 100 * 45 - 3 * UM.Theme.getSize("default_margin").width + width: parent.width * .45 - 3 * UM.Theme.getSize("default_margin").width text: catalog.i18nc("@label", "Support Extruder"); font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); @@ -319,7 +319,7 @@ Item } anchors.left: supportExtruderLabel.right anchors.leftMargin: UM.Theme.getSize("default_margin").width - width: parent.width / 100 * 55 + width: parent.width * .55 height: { if ((supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1)) @@ -332,6 +332,7 @@ Item return 0; } } + Behavior on height { NumberAnimation { duration: 100 } } style: UM.Theme.styles.combobox_color enabled: base.settingsEnabled @@ -377,7 +378,7 @@ Item anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: adhesionCheckBox.verticalCenter - width: parent.width / 100 * 45 - 3 * UM.Theme.getSize("default_margin").width + width: parent.width * .45 - 3 * UM.Theme.getSize("default_margin").width text: catalog.i18nc("@label", "Build Plate Adhesion"); font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); diff --git a/resources/qml/SidebarTooltip.qml b/resources/qml/SidebarTooltip.qml index 5cb7ff1f0b..7344834c7e 100644 --- a/resources/qml/SidebarTooltip.qml +++ b/resources/qml/SidebarTooltip.qml @@ -29,6 +29,11 @@ UM.PointingRectangle { } else { x = position.x - base.width; y = position.y - UM.Theme.getSize("tooltip_arrow_margins").height; + if(y < 0) + { + position.y += -y; + y = 0; + } } base.opacity = 1; target = Qt.point(40 , position.y + UM.Theme.getSize("tooltip_arrow_margins").height / 2) diff --git a/resources/themes/cura/theme.json b/resources/themes/cura/theme.json index a29aefa143..d5a95a7104 100644 --- a/resources/themes/cura/theme.json +++ b/resources/themes/cura/theme.json @@ -91,7 +91,21 @@ "toggle_hovered_text": [24, 41, 77, 255], "toggle_active": [32, 166, 219, 255], "toggle_active_border": [32, 166, 219, 255], - "toggle_active_text": [255, 255, 255, 255], + "toggle_active_text": [24, 41, 77, 255], + + "tab_checked": [255, 255, 255, 255], + "tab_checked_border": [255, 255, 255, 255], + "tab_checked_text": [24, 41, 77, 255], + "tab_unchecked": [245, 245, 245, 255], + "tab_unchecked_border": [245, 245, 245, 255], + "tab_unchecked_text": [127, 127, 127, 255], + "tab_hovered": [245, 245, 245, 255], + "tab_hovered_border": [245, 245, 245, 255], + "tab_hovered_text": [32, 166, 219, 255], + "tab_active": [255, 255, 255, 255], + "tab_active_border": [255, 255, 255, 255], + "tab_active_text": [24, 41, 77, 255], + "tab_background": [245, 245, 245, 255], "action_button": [255, 255, 255, 255], "action_button_text": [24, 41, 77, 255], @@ -191,10 +205,12 @@ "sidebar": [35.0, 10.0], "sidebar_header": [0.0, 4.0], - "sidebar_header_highlight": [0.5, 0.5], + "sidebar_header_highlight": [0.25, 0.25], "sidebar_header_mode_toggle": [0.0, 2.0], + "sidebar_header_mode_tabs": [0.0, 3.0], "sidebar_lining": [0.5, 0.5], "sidebar_setup": [0.0, 2.0], + "sidebar_tabs": [0.0, 3.5], "sidebar_inputfields": [0.0, 2.0], "simple_mode_infill_caption": [0.0, 5.0], "simple_mode_infill_height": [0.0, 8.0],