Merge pull request #13774 from Ultimaker/CURA-9424_update_loading_projects_design

Cura 9424 update loading projects design
This commit is contained in:
Casper Lamboo 2022-11-15 15:38:15 +01:00 committed by GitHub
commit 63b27d3ca8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 572 additions and 485 deletions

View File

@ -5,7 +5,7 @@
# online cloud connected printers are represented within this ListModel. Additional information such as the number of # online cloud connected printers are represented within this ListModel. Additional information such as the number of
# connected printers for each printer type is gathered. # connected printers for each printer type is gathered.
from typing import Optional from typing import Optional, List, cast
from PyQt6.QtCore import Qt, QTimer, QObject, pyqtSlot, pyqtProperty, pyqtSignal from PyQt6.QtCore import Qt, QTimer, QObject, pyqtSlot, pyqtProperty, pyqtSignal
@ -14,7 +14,6 @@ from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.Interfaces import ContainerInterface from UM.Settings.Interfaces import ContainerInterface
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from UM.Util import parseBool from UM.Util import parseBool
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
@ -29,11 +28,13 @@ class MachineListModel(ListModel):
MachineCountRole = Qt.ItemDataRole.UserRole + 6 MachineCountRole = Qt.ItemDataRole.UserRole + 6
IsAbstractMachineRole = Qt.ItemDataRole.UserRole + 7 IsAbstractMachineRole = Qt.ItemDataRole.UserRole + 7
ComponentTypeRole = Qt.ItemDataRole.UserRole + 8 ComponentTypeRole = Qt.ItemDataRole.UserRole + 8
IsNetworkedMachineRole = Qt.ItemDataRole.UserRole + 9
def __init__(self, parent: Optional[QObject] = None) -> None: def __init__(self, parent: Optional[QObject] = None, machines_filter: List[GlobalStack] = None, listenToChanges: bool = True) -> None:
super().__init__(parent) super().__init__(parent)
self._show_cloud_printers = False self._show_cloud_printers = False
self._machines_filter = machines_filter
self._catalog = i18nCatalog("cura") self._catalog = i18nCatalog("cura")
@ -45,17 +46,18 @@ class MachineListModel(ListModel):
self.addRoleName(self.MachineCountRole, "machineCount") self.addRoleName(self.MachineCountRole, "machineCount")
self.addRoleName(self.IsAbstractMachineRole, "isAbstractMachine") self.addRoleName(self.IsAbstractMachineRole, "isAbstractMachine")
self.addRoleName(self.ComponentTypeRole, "componentType") self.addRoleName(self.ComponentTypeRole, "componentType")
self.addRoleName(self.IsNetworkedMachineRole, "isNetworked")
self._change_timer = QTimer() self._change_timer = QTimer()
self._change_timer.setInterval(200) self._change_timer.setInterval(200)
self._change_timer.setSingleShot(True) self._change_timer.setSingleShot(True)
self._change_timer.timeout.connect(self._update) self._change_timer.timeout.connect(self._update)
# Listen to changes if listenToChanges:
CuraContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged) CuraContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged)
CuraContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged) CuraContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged)
CuraContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged) CuraContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged)
self._updateDelayed() self._updateDelayed()
showCloudPrintersChanged = pyqtSignal(bool) showCloudPrintersChanged = pyqtSignal(bool)
@ -79,17 +81,33 @@ class MachineListModel(ListModel):
def _updateDelayed(self) -> None: def _updateDelayed(self) -> None:
self._change_timer.start() self._change_timer.start()
def _getMachineStacks(self) -> List[ContainerStack]:
return CuraContainerRegistry.getInstance().findContainerStacks(type = "machine")
def _getAbstractMachineStacks(self) -> List[ContainerStack]:
return CuraContainerRegistry.getInstance().findContainerStacks(is_abstract_machine = "True")
def set_machines_filter(self, machines_filter: Optional[List[GlobalStack]]) -> None:
self._machines_filter = machines_filter
self._update()
def _update(self) -> None: def _update(self) -> None:
self.clear() self.clear()
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
machines_manager = CuraApplication.getInstance().getMachineManager() machines_manager = CuraApplication.getInstance().getMachineManager()
other_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type="machine") other_machine_stacks = self._getMachineStacks()
other_machine_stacks.sort(key = lambda machine: machine.getName().upper()) other_machine_stacks.sort(key = lambda machine: machine.getName().upper())
abstract_machine_stacks = CuraContainerRegistry.getInstance().findContainerStacks(is_abstract_machine = "True") abstract_machine_stacks = self._getAbstractMachineStacks()
abstract_machine_stacks.sort(key = lambda machine: machine.getName().upper(), reverse = True) abstract_machine_stacks.sort(key = lambda machine: machine.getName().upper(), reverse = True)
if self._machines_filter is not None:
filter_ids = [machine_filter.id for machine_filter in self._machines_filter]
other_machine_stacks = [machine for machine in other_machine_stacks if machine.id in filter_ids]
abstract_machine_stacks = [machine for machine in abstract_machine_stacks if machine.id in filter_ids]
for abstract_machine in abstract_machine_stacks: for abstract_machine in abstract_machine_stacks:
definition_id = abstract_machine.definition.getId() definition_id = abstract_machine.definition.getId()
online_machine_stacks = machines_manager.getMachinesWithDefinition(definition_id, online_only = True) online_machine_stacks = machines_manager.getMachinesWithDefinition(definition_id, online_only = True)
@ -113,18 +131,13 @@ class MachineListModel(ListModel):
other_machine_stacks.remove(stack) other_machine_stacks.remove(stack)
if len(abstract_machine_stacks) > 0: if len(abstract_machine_stacks) > 0:
if self._show_cloud_printers: self.appendItem({
self.appendItem({"componentType": "HIDE_BUTTON", "componentType": "HIDE_BUTTON" if self._show_cloud_printers else "SHOW_BUTTON",
"isOnline": True, "isOnline": True,
"isAbstractMachine": False, "isAbstractMachine": False,
"machineCount": 0 "machineCount": 0,
}) "catergory": "connected",
else: })
self.appendItem({"componentType": "SHOW_BUTTON",
"isOnline": True,
"isAbstractMachine": False,
"machineCount": 0
})
for stack in other_machine_stacks: for stack in other_machine_stacks:
self.addItem(stack, False) self.addItem(stack, False)
@ -134,11 +147,13 @@ class MachineListModel(ListModel):
return return
self.appendItem({ self.appendItem({
"componentType": "MACHINE", "componentType": "MACHINE",
"name": container_stack.getName(), "name": container_stack.getName(),
"id": container_stack.getId(), "id": container_stack.getId(),
"metadata": container_stack.getMetaData().copy(), "metadata": container_stack.getMetaData().copy(),
"isOnline": is_online, "isOnline": is_online,
"isAbstractMachine": parseBool(container_stack.getMetaDataEntry("is_abstract_machine", False)), "isAbstractMachine": parseBool(container_stack.getMetaDataEntry("is_abstract_machine", False)),
"machineCount": machine_count, "isNetworked": cast(GlobalStack, container_stack).hasNetworkedConnection() if isinstance(container_stack, GlobalStack) else False,
}) "machineCount": machine_count,
"catergory": "connected" if is_online else "other",
})

View File

@ -9,6 +9,7 @@ from typing import cast, Dict, List, Optional, Tuple, Any, Set
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from UM.Util import parseBool
from UM.Workspace.WorkspaceReader import WorkspaceReader from UM.Workspace.WorkspaceReader import WorkspaceReader
from UM.Application import Application from UM.Application import Application
@ -600,6 +601,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._dialog.setActiveMode(active_mode) self._dialog.setActiveMode(active_mode)
self._dialog.setUpdatableMachines(updatable_machines) self._dialog.setUpdatableMachines(updatable_machines)
self._dialog.setMachineName(machine_name) self._dialog.setMachineName(machine_name)
self._dialog.setIsNetworkedMachine(existing_global_stack.hasNetworkedConnection())
self._dialog.setIsAbstractMachine(parseBool(existing_global_stack.getMetaDataEntry("is_abstract_machine", False)))
self._dialog.setMachineToOverride(global_stack_id)
self._dialog.setMaterialLabels(material_labels) self._dialog.setMaterialLabels(material_labels)
self._dialog.setMachineType(machine_type) self._dialog.setMachineType(machine_type)
self._dialog.setExtruders(extruders) self._dialog.setExtruders(extruders)

View File

@ -1,43 +0,0 @@
# Copyright (c) 2020 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Dict, List
from PyQt6.QtCore import Qt
from UM.Qt.ListModel import ListModel
from cura.Settings.GlobalStack import GlobalStack
create_new_list_item = {
"id": "new",
"name": "Create new",
"displayName": "Create new",
"type": "default_option" # to make sure we are not mixing the "Create new" option with a printer with id "new"
} # type: Dict[str, str]
class UpdatableMachinesModel(ListModel):
"""Model that holds cura packages.
By setting the filter property the instances held by this model can be changed.
"""
def __init__(self, parent = None) -> None:
super().__init__(parent)
self.addRoleName(Qt.ItemDataRole.UserRole + 1, "id")
self.addRoleName(Qt.ItemDataRole.UserRole + 2, "name")
self.addRoleName(Qt.ItemDataRole.UserRole + 3, "displayName")
self.addRoleName(Qt.ItemDataRole.UserRole + 4, "type") # Either "default_option" or "machine"
def update(self, machines: List[GlobalStack]) -> None:
items = [create_new_list_item] # type: List[Dict[str, str]]
for machine in sorted(machines, key = lambda printer: printer.name):
items.append({
"id": machine.id,
"name": machine.name,
"displayName": "Update " + machine.name,
"type": "machine"
})
self.setItems(items)

View File

@ -5,6 +5,7 @@ from PyQt6.QtCore import pyqtSignal, QObject, pyqtProperty, QCoreApplication, QU
from PyQt6.QtGui import QDesktopServices from PyQt6.QtGui import QDesktopServices
from typing import List, Optional, Dict, cast from typing import List, Optional, Dict, cast
from cura.Machines.Models.MachineListModel import MachineListModel
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
from UM.Application import Application from UM.Application import Application
from UM.FlameProfiler import pyqtSlot from UM.FlameProfiler import pyqtSlot
@ -14,8 +15,6 @@ from UM.Message import Message
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from .UpdatableMachinesModel import UpdatableMachinesModel
import os import os
import threading import threading
import time import time
@ -63,10 +62,12 @@ class WorkspaceDialog(QObject):
self._extruders = [] self._extruders = []
self._objects_on_plate = False self._objects_on_plate = False
self._is_printer_group = False self._is_printer_group = False
self._updatable_machines_model = UpdatableMachinesModel(self) self._updatable_machines_model = MachineListModel(self, listenToChanges=False)
self._missing_package_metadata: List[Dict[str, str]] = [] self._missing_package_metadata: List[Dict[str, str]] = []
self._plugin_registry: PluginRegistry = CuraApplication.getInstance().getPluginRegistry() self._plugin_registry: PluginRegistry = CuraApplication.getInstance().getPluginRegistry()
self._install_missing_package_dialog: Optional[QObject] = None self._install_missing_package_dialog: Optional[QObject] = None
self._is_abstract_machine = False
self._is_networked_machine = False
machineConflictChanged = pyqtSignal() machineConflictChanged = pyqtSignal()
qualityChangesConflictChanged = pyqtSignal() qualityChangesConflictChanged = pyqtSignal()
@ -80,6 +81,8 @@ class WorkspaceDialog(QObject):
intentNameChanged = pyqtSignal() intentNameChanged = pyqtSignal()
machineNameChanged = pyqtSignal() machineNameChanged = pyqtSignal()
updatableMachinesChanged = pyqtSignal() updatableMachinesChanged = pyqtSignal()
isAbstractMachineChanged = pyqtSignal()
isNetworkedChanged = pyqtSignal()
materialLabelsChanged = pyqtSignal() materialLabelsChanged = pyqtSignal()
objectsOnPlateChanged = pyqtSignal() objectsOnPlateChanged = pyqtSignal()
numUserSettingsChanged = pyqtSignal() numUserSettingsChanged = pyqtSignal()
@ -161,13 +164,31 @@ class WorkspaceDialog(QObject):
self.machineNameChanged.emit() self.machineNameChanged.emit()
@pyqtProperty(QObject, notify = updatableMachinesChanged) @pyqtProperty(QObject, notify = updatableMachinesChanged)
def updatableMachinesModel(self) -> UpdatableMachinesModel: def updatableMachinesModel(self) -> MachineListModel:
return cast(UpdatableMachinesModel, self._updatable_machines_model) return cast(MachineListModel, self._updatable_machines_model)
def setUpdatableMachines(self, updatable_machines: List[GlobalStack]) -> None: def setUpdatableMachines(self, updatable_machines: List[GlobalStack]) -> None:
self._updatable_machines_model.update(updatable_machines) self._updatable_machines_model.set_machines_filter(updatable_machines)
self.updatableMachinesChanged.emit() self.updatableMachinesChanged.emit()
@pyqtProperty(bool, notify = isAbstractMachineChanged)
def isAbstractMachine(self) -> bool:
return self._is_abstract_machine
@pyqtSlot(bool)
def setIsAbstractMachine(self, is_abstract_machine: bool) -> None:
self._is_abstract_machine = is_abstract_machine
self.isAbstractMachineChanged.emit()
@pyqtProperty(bool, notify = isNetworkedChanged)
def isNetworked(self) -> bool:
return self._is_networked_machine
@pyqtSlot(bool)
def setIsNetworkedMachine(self, is_networked_machine: bool) -> None:
self._is_networked_machine = is_networked_machine
self.isNetworkedChanged.emit()
@pyqtProperty(str, notify=qualityTypeChanged) @pyqtProperty(str, notify=qualityTypeChanged)
def qualityType(self) -> str: def qualityType(self) -> str:
return self._quality_type return self._quality_type

View File

@ -1,4 +1,4 @@
// Copyright (c) 2020 Ultimaker B.V. // Copyright (c) 2022 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10 import QtQuick 2.10
@ -11,47 +11,48 @@ import Cura 1.1 as Cura
UM.Dialog UM.Dialog
{ {
id: base id: workspaceDialog
title: catalog.i18nc("@title:window", "Open Project") title: catalog.i18nc("@title:window", "Open Project")
minimumWidth: UM.Theme.getSize("popup_dialog").width
minimumHeight: UM.Theme.getSize("popup_dialog").height
width: minimumWidth
backgroundColor: UM.Theme.getColor("main_background")
margin: UM.Theme.getSize("default_margin").width margin: UM.Theme.getSize("default_margin").width
property int comboboxHeight: UM.Theme.getSize("default_margin").height minimumWidth: UM.Theme.getSize("modal_window_minimum").width
minimumHeight: UM.Theme.getSize("modal_window_minimum").height
onClosing: manager.notifyClosed() backgroundColor: UM.Theme.getColor("detail_background")
onVisibleChanged:
headerComponent: Rectangle
{ {
if (visible) height: childrenRect.height + 2 * UM.Theme.getSize("default_margin").height
color: UM.Theme.getColor("main_background")
UM.Label
{ {
machineResolveComboBox.currentIndex = 0 id: titleLabel
qualityChangesResolveComboBox.currentIndex = 0 text: catalog.i18nc("@action:title", "Summary - Cura Project")
materialResolveComboBox.currentIndex = 0 font: UM.Theme.getFont("large")
anchors.top: parent.top
anchors.left: parent.left
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.leftMargin: UM.Theme.getSize("default_margin").height
} }
} }
Flickable Rectangle
{ {
clip: true anchors.fill: parent
width: parent.width UM.I18nCatalog { id: catalog; name: "cura" }
height: parent.height color: UM.Theme.getColor("main_background")
contentHeight: dialogSummaryItem.height
ScrollBar.vertical: UM.ScrollBar { id: verticalScrollBar }
Item Flickable
{ {
id: dialogSummaryItem id: dialogSummaryItem
width: verticalScrollBar.visible ? parent.width - verticalScrollBar.width - UM.Theme.getSize("default_margin").width : parent.width width: parent.width
height: childrenRect.height height: parent.height
anchors.margins: 10 * screenScaleFactor
UM.I18nCatalog clip: true
{
id: catalog contentHeight: contentColumn.height
name: "cura" ScrollBar.vertical: UM.ScrollBar { id: scrollbar }
}
ListModel ListModel
{ {
@ -68,373 +69,224 @@ UM.Dialog
Column Column
{ {
width: parent.width id: contentColumn
width: parent.width - scrollbar.width - UM.Theme.getSize("default_margin").width
height: childrenRect.height height: childrenRect.height
spacing: UM.Theme.getSize("default_margin").height spacing: UM.Theme.getSize("default_margin").height
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
Column WorkspaceSection
{ {
width: parent.width id: printerSection
height: childrenRect.height title: catalog.i18nc("@action:label", "Printer settings")
iconSource: UM.Theme.getIcon("Printer")
UM.Label content: Column
{ {
id: titleLabel spacing: UM.Theme.getSize("default_margin").height
text: catalog.i18nc("@action:title", "Summary - Cura Project") leftPadding: UM.Theme.getSize("medium_button_icon").width + UM.Theme.getSize("default_margin").width
font: UM.Theme.getFont("large")
}
Rectangle WorkspaceRow
{
id: separator
color: UM.Theme.getColor("text")
width: parent.width
height: UM.Theme.getSize("default_lining").height
}
}
Item
{
width: parent.width
height: childrenRect.height
UM.TooltipArea
{
id: machineResolveStrategyTooltip
anchors.top: parent.top
anchors.right: parent.right
width: (parent.width / 3) | 0
height: visible ? comboboxHeight : 0
visible: base.visible && machineResolveComboBox.model.count > 1
text: catalog.i18nc("@info:tooltip", "How should the conflict in the machine be resolved?")
Cura.ComboBox
{ {
id: machineResolveComboBox leftLabelText: catalog.i18nc("@action:label", "Type")
model: manager.updatableMachinesModel rightLabelText: manager.machineType
visible: machineResolveStrategyTooltip.visible }
textRole: "displayName"
width: parent.width WorkspaceRow
height: UM.Theme.getSize("button").height {
onCurrentIndexChanged: leftLabelText: catalog.i18nc("@action:label", manager.isPrinterGroup ? "Printer Group" : "Printer Name")
rightLabelText: manager.machineName
}
}
comboboxTitle: catalog.i18nc("@action:label", "Open With")
comboboxTooltipText: catalog.i18nc("@info:tooltip", "Printer settings will be updated to match the settings saved with the project.")
comboboxVisible: workspaceDialog.visible && manager.updatableMachinesModel.count > 1
combobox: Cura.MachineSelector
{
id: machineSelector
headerCornerSide: Cura.RoundedRectangle.Direction.All
width: parent.width
height: parent.height
machineListModel: manager.updatableMachinesModel
machineName: manager.machineName
isConnectedCloudPrinter: false
isCloudRegistered: false
isNetworkPrinter: manager.isNetworked
isGroup: manager.isAbstractMachine
connectionStatus: ""
minDropDownWidth: machineSelector.width
buttons: [
Cura.SecondaryButton
{ {
if (model.getItem(currentIndex).id == "new" id: createNewPrinter
&& model.getItem(currentIndex).type == "default_option") text: catalog.i18nc("@button", "Create new")
fixedWidthMode: true
width: parent.width - leftPadding * 1.5
onClicked:
{ {
machineSelector.machineName = catalog.i18nc("@button", "Create new")
manager.setIsAbstractMachine(false)
manager.setIsNetworkedMachine(false)
toggleContent()
manager.setResolveStrategy("machine", "new") manager.setResolveStrategy("machine", "new")
} }
else
{
manager.setResolveStrategy("machine", "override")
manager.setMachineToOverride(model.getItem(currentIndex).id)
}
} }
]
onVisibleChanged: onSelectPrinter: function(machine)
{
if (!visible) {return}
currentIndex = 0
// If the project printer exists in Cura, set it as the default dropdown menu option.
// No need to check object 0, which is the "Create new" option
for (var i = 1; i < model.count; i++)
{
if (model.getItem(i).name == manager.machineName)
{
currentIndex = i
break
}
}
// The project printer does not exist in Cura. If there is at least one printer of the same
// type, select the first one, else set the index to "Create new"
if (currentIndex == 0 && model.count > 1)
{
currentIndex = 1
}
}
}
}
Column
{
width: parent.width
height: childrenRect.height
UM.Label
{ {
id: printer_settings_label toggleContent();
text: catalog.i18nc("@action:label", "Printer settings") manager.setResolveStrategy("machine", "override")
font: UM.Theme.getFont("default_bold") manager.setMachineToOverride(machine.id)
} manager.setIsAbstractMachine(machine.isAbstractMachine)
manager.setIsNetworkedMachine(machine.isNetworked)
Row machineSelector.machineName = machine.name
{
width: parent.width
height: childrenRect.height
UM.Label
{
text: catalog.i18nc("@action:label", "Type")
width: (parent.width / 3) | 0
}
UM.Label
{
text: manager.machineType
width: (parent.width / 3) | 0
}
}
Row
{
width: parent.width
height: childrenRect.height
UM.Label
{
text: catalog.i18nc("@action:label", manager.isPrinterGroup ? "Printer Group" : "Printer Name")
width: (parent.width / 3) | 0
}
UM.Label
{
text: manager.machineName
width: (parent.width / 3) | 0
wrapMode: Text.WordWrap
}
} }
} }
} }
Item WorkspaceSection
{ {
width: parent.width id: profileSection
height: childrenRect.height title: catalog.i18nc("@action:label", "Profile settings")
iconSource: UM.Theme.getIcon("Sliders")
UM.TooltipArea content: Column
{ {
anchors.right: parent.right id: profileSettingsValuesTable
anchors.top: parent.top spacing: UM.Theme.getSize("default_margin").height
width: (parent.width / 3) | 0 leftPadding: UM.Theme.getSize("medium_button_icon").width + UM.Theme.getSize("default_margin").width
height: visible ? comboboxHeight : 0
WorkspaceRow
{
leftLabelText: catalog.i18nc("@action:label", "Name")
rightLabelText: manager.qualityName
}
WorkspaceRow
{
leftLabelText: catalog.i18nc("@action:label", "Intent")
rightLabelText: manager.intentName
}
WorkspaceRow
{
leftLabelText: catalog.i18nc("@action:label", "Not in profile")
rightLabelText: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", manager.numUserSettings).arg(manager.numUserSettings)
visible: manager.numUserSettings != 0
}
WorkspaceRow
{
leftLabelText: catalog.i18nc("@action:label", "Derivative from")
rightLabelText: catalog.i18ncp("@action:label", "%1, %2 override", "%1, %2 overrides", manager.numSettingsOverridenByQualityChanges).arg(manager.qualityType).arg(manager.numSettingsOverridenByQualityChanges)
visible: manager.numSettingsOverridenByQualityChanges != 0
}
}
comboboxVisible: manager.qualityChangesConflict
combobox: Cura.ComboBox
{
id: qualityChangesResolveComboBox
model: resolveStrategiesModel
textRole: "label"
visible: manager.qualityChangesConflict visible: manager.qualityChangesConflict
text: catalog.i18nc("@info:tooltip", "How should the conflict in the profile be resolved?")
Cura.ComboBox
{
model: resolveStrategiesModel
textRole: "label"
id: qualityChangesResolveComboBox
width: parent.width
height: UM.Theme.getSize("button").height
onActivated:
{
manager.setResolveStrategy("quality_changes", resolveStrategiesModel.get(index).key)
}
}
}
Column // This is a hack. This will trigger onCurrentIndexChanged and set the index when this component in loaded
{ currentIndex:
width: parent.width
height: childrenRect.height
UM.Label
{ {
text: catalog.i18nc("@action:label", "Profile settings") currentIndex = 0
font: UM.Theme.getFont("default_bold")
} }
Row onCurrentIndexChanged:
{ {
width: parent.width manager.setResolveStrategy("quality_changes", resolveStrategiesModel.get(currentIndex).key)
height: childrenRect.height
UM.Label
{
text: catalog.i18nc("@action:label", "Name")
width: (parent.width / 3) | 0
}
UM.Label
{
text: manager.qualityName
width: (parent.width / 3) | 0
wrapMode: Text.WordWrap
}
}
Row
{
width: parent.width
height: childrenRect.height
UM.Label
{
text: catalog.i18nc("@action:label", "Intent")
width: (parent.width / 3) | 0
}
UM.Label
{
text: manager.intentName
width: (parent.width / 3) | 0
wrapMode: Text.WordWrap
}
}
Row
{
width: parent.width
height: childrenRect.height
UM.Label
{
text: catalog.i18nc("@action:label", "Not in profile")
visible: manager.numUserSettings != 0
width: (parent.width / 3) | 0
}
UM.Label
{
text: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", manager.numUserSettings).arg(manager.numUserSettings)
visible: manager.numUserSettings != 0
width: (parent.width / 3) | 0
}
}
Row
{
width: parent.width
height: childrenRect.height
UM.Label
{
text: catalog.i18nc("@action:label", "Derivative from")
visible: manager.numSettingsOverridenByQualityChanges != 0
width: (parent.width / 3) | 0
}
UM.Label
{
text: catalog.i18ncp("@action:label", "%1, %2 override", "%1, %2 overrides", manager.numSettingsOverridenByQualityChanges).arg(manager.qualityType).arg(manager.numSettingsOverridenByQualityChanges)
width: (parent.width / 3) | 0
visible: manager.numSettingsOverridenByQualityChanges != 0
wrapMode: Text.WordWrap
}
} }
} }
} }
Item WorkspaceSection
{ {
width: parent.width id: materialSection
height: childrenRect.height title: catalog.i18nc("@action:label", "Material settings")
iconSource: UM.Theme.getIcon("Spool")
UM.TooltipArea content: Column
{ {
id: materialResolveTooltip spacing: UM.Theme.getSize("default_margin").height
anchors.right: parent.right leftPadding: UM.Theme.getSize("medium_button_icon").width + UM.Theme.getSize("default_margin").width
anchors.top: parent.top
width: (parent.width / 3) | 0
height: visible ? comboboxHeight : 0
visible: manager.materialConflict
text: catalog.i18nc("@info:tooltip", "How should the conflict in the material be resolved?")
Cura.ComboBox
{
model: resolveStrategiesModel
textRole: "label"
id: materialResolveComboBox
width: parent.width
height: UM.Theme.getSize("button").height
onActivated:
{
manager.setResolveStrategy("material", resolveStrategiesModel.get(index).key)
}
}
}
Column
{
width: parent.width
height: childrenRect.height
Row
{
height: childrenRect.height
width: parent.width
spacing: UM.Theme.getSize("narrow_margin").width
UM.Label
{
text: catalog.i18nc("@action:label", "Material settings")
font: UM.Theme.getFont("default_bold")
width: (parent.width / 3) | 0
}
}
Repeater Repeater
{ {
model: manager.materialLabels model: manager.materialLabels
delegate: Row delegate: WorkspaceRow
{ {
width: parent.width leftLabelText: catalog.i18nc("@action:label", "Name")
height: childrenRect.height rightLabelText: modelData
UM.Label
{
text: catalog.i18nc("@action:label", "Name")
width: (parent.width / 3) | 0
}
UM.Label
{
text: modelData
width: (parent.width / 3) | 0
wrapMode: Text.WordWrap
}
} }
} }
} }
comboboxVisible: manager.materialConflict
combobox: Cura.ComboBox
{
id: materialResolveComboBox
model: resolveStrategiesModel
textRole: "label"
visible: manager.materialConflict
// This is a hack. This will trigger onCurrentIndexChanged and set the index when this component in loaded
currentIndex:
{
currentIndex = 0
}
onCurrentIndexChanged:
{
manager.setResolveStrategy("material", resolveStrategiesModel.get(currentIndex).key)
}
}
} }
Column WorkspaceSection
{ {
width: parent.width id: visibilitySection
height: childrenRect.height title: catalog.i18nc("@action:label", "Setting visibility")
iconSource: UM.Theme.getIcon("Eye")
content: Column
{
spacing: UM.Theme.getSize("default_margin").height
leftPadding: UM.Theme.getSize("medium_button_icon").width + UM.Theme.getSize("default_margin").width
bottomPadding: UM.Theme.getSize("narrow_margin").height
UM.Label WorkspaceRow
{
text: catalog.i18nc("@action:label", "Setting visibility")
font: UM.Theme.getFont("default_bold")
}
Row
{
width: parent.width
height: childrenRect.height
UM.Label
{ {
text: catalog.i18nc("@action:label", "Mode") leftLabelText: catalog.i18nc("@action:label", "Mode")
width: (parent.width / 3) | 0 rightLabelText: manager.activeMode
} }
UM.Label
WorkspaceRow
{ {
text: manager.activeMode leftLabelText: catalog.i18nc("@action:label", "%1 out of %2" ).arg(manager.numVisibleSettings).arg(manager.totalNumberOfSettings)
width: (parent.width / 3) | 0 rightLabelText: manager.activeMode
} visible: manager.hasVisibleSettingsField
}
Row
{
width: parent.width
height: childrenRect.height
visible: manager.hasVisibleSettingsField
UM.Label
{
text: catalog.i18nc("@action:label", "Visible settings:")
width: (parent.width / 3) | 0
}
UM.Label
{
text: catalog.i18nc("@action:label", "%1 out of %2" ).arg(manager.numVisibleSettings).arg(manager.totalNumberOfSettings)
width: (parent.width / 3) | 0
} }
} }
} }
Row Row
{ {
id: clearBuildPlateWarning
width: parent.width width: parent.width
height: childrenRect.height height: childrenRect.height
spacing: UM.Theme.getSize("default_margin").width
visible: manager.hasObjectsOnPlate visible: manager.hasObjectsOnPlate
UM.ColorImage UM.ColorImage
{ {
width: warningLabel.height width: warningLabel.height
@ -459,14 +311,18 @@ UM.Dialog
color: warning ? UM.Theme.getColor("warning") : "transparent" color: warning ? UM.Theme.getColor("warning") : "transparent"
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: parent.width width: parent.width
height: childrenRect.height + 2 * base.margin height: childrenRect.height + (warning ? 2 * workspaceDialog.margin : workspaceDialog.margin)
Column Column
{ {
height: childrenRect.height height: childrenRect.height
spacing: base.margin spacing: workspaceDialog.margin
anchors.leftMargin: workspaceDialog.margin
anchors.rightMargin: workspaceDialog.margin
anchors.bottomMargin: workspaceDialog.margin
anchors.topMargin: warning ? workspaceDialog.margin : 0
anchors.margins: base.margin
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
@ -476,7 +332,7 @@ UM.Dialog
id: warningRow id: warningRow
height: childrenRect.height height: childrenRect.height
visible: warning visible: warning
spacing: base.margin spacing: workspaceDialog.margin
UM.ColorImage UM.ColorImage
{ {
width: UM.Theme.getSize("extruder_icon").width width: UM.Theme.getSize("extruder_icon").width
@ -500,7 +356,7 @@ UM.Dialog
} }
} }
buttonSpacing: UM.Theme.getSize("default_margin").width buttonSpacing: UM.Theme.getSize("wide_margin").width
rightButtons: [ rightButtons: [
Cura.TertiaryButton Cura.TertiaryButton
@ -532,6 +388,19 @@ UM.Dialog
} }
] ]
onClosing: manager.notifyClosed()
onRejected: manager.onCancelButtonClicked() onRejected: manager.onCancelButtonClicked()
onAccepted: manager.onOkButtonClicked() onAccepted: manager.onOkButtonClicked()
onVisibleChanged:
{
if (visible)
{
// Force relead the comboboxes
// Since this dialog is only created once the first time you open it, these comboxes need to be reloaded
// each time it is shown after the first time so that the indexes will update correctly.
materialSection.reloadValues()
profileSection.reloadValues()
printerSection.reloadValues()
}
}
} }

View File

@ -0,0 +1,34 @@
// Copyright (c) 2022 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import QtQuick.Window 2.2
import UM 1.5 as UM
import Cura 1.1 as Cura
Row
{
property alias leftLabelText: leftLabel.text
property alias rightLabelText: rightLabel.text
width: parent.width
height: visible ? childrenRect.height : 0
UM.Label
{
id: leftLabel
text: catalog.i18nc("@action:label", "Type")
width: Math.round(parent.width / 4)
wrapMode: Text.WordWrap
}
UM.Label
{
id: rightLabel
text: manager.machineType
width: Math.round(parent.width / 3)
wrapMode: Text.WordWrap
}
}

View File

@ -0,0 +1,126 @@
// Copyright (c) 2022 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import UM 1.5 as UM
Item
{
property alias title: sectionTitle.text
property alias iconSource: sectionTitleIcon.source
property Component content: Item { visible: false }
property alias comboboxTitle: comboboxLabel.text
property Component combobox: Item { visible: false }
property string comboboxTooltipText: ""
property bool comboboxVisible: false
width: parent.width
height: childrenRect.height
anchors.leftMargin: UM.Theme.getSize("default_margin").width
Row
{
id: sectionTitleRow
anchors.top: parent.top
bottomPadding: UM.Theme.getSize("default_margin").height
spacing: UM.Theme.getSize("default_margin").width
UM.ColorImage
{
id: sectionTitleIcon
anchors.verticalCenter: parent.verticalCenter
source: ""
height: UM.Theme.getSize("medium_button_icon").height
width: height
}
UM.Label
{
id: sectionTitle
text: ""
anchors.verticalCenter: parent.verticalCenter
font: UM.Theme.getFont("default_bold")
}
}
Item
{
id: comboboxTooltip
width: Math.round(parent.width / 2.5)
height: visible ? UM.Theme.getSize("default_margin").height : 0
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
visible: comboboxVisible
UM.Label
{
id: comboboxLabel
anchors.top: parent.top
anchors.left: parent.left
anchors.topMargin: UM.Theme.getSize("default_margin").height
visible: comboboxVisible && text != ""
text: ""
font: UM.Theme.getFont("default_bold")
}
Loader
{
id: comboboxLoader
width: parent.width
height: UM.Theme.getSize("button").height
anchors.top: comboboxLabel.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: parent.left
sourceComponent: combobox
}
MouseArea
{
id: helpIconMouseArea
anchors.right: parent.right
anchors.verticalCenter: comboboxLabel.verticalCenter
width: childrenRect.width
height: childrenRect.height
hoverEnabled: true
UM.ColorImage
{
width: UM.Theme.getSize("section_icon").width
height: width
visible: comboboxTooltipText != ""
source: UM.Theme.getIcon("Help")
UM.ToolTip
{
text: comboboxTooltipText
visible: helpIconMouseArea.containsMouse
targetPoint: Qt.point(parent.x + Math.round(parent.width / 2), parent.y)
x: 0
y: parent.y + parent.height + UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("tooltip").width
}
}
}
}
Loader
{
width: parent.width
height: content.height
anchors.top: sectionTitleRow.bottom
sourceComponent: content
}
function reloadValues()
{
comboboxLoader.sourceComponent = null
comboboxLoader.sourceComponent = combobox
}
}

View File

@ -19,5 +19,7 @@ Item
width: UM.Theme.getSize("machine_selector_widget").width width: UM.Theme.getSize("machine_selector_widget").width
height: parent.height height: parent.height
anchors.centerIn: parent anchors.centerIn: parent
machineListModel: Cura.MachineListModel {}
} }
} }

View File

@ -150,6 +150,7 @@ Item
width: parent.width / 2 - UM.Theme.getSize("default_margin").width width: parent.width / 2 - UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("setting_control").height height: UM.Theme.getSize("setting_control").height
textRole: "text" textRole: "text"
forceHighlight: base.hovered
model: ListModel model: ListModel
{ {

View File

@ -55,6 +55,50 @@ Item
Layout.preferredWidth: parent.machineSelectorWidth Layout.preferredWidth: parent.machineSelectorWidth
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
machineManager: Cura.MachineManager
onSelectPrinter: function(machine)
{
toggleContent();
Cura.MachineManager.setActiveMachine(machine.id);
}
machineListModel: Cura.MachineListModel {}
buttons: [
Cura.SecondaryButton
{
id: addPrinterButton
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@button", "Add printer")
// The maximum width of the button is half of the total space, minus the padding of the parent, the left
// padding of the component and half the spacing because of the space between buttons.
fixedWidthMode: true
width: Math.round(parent.width / 2 - leftPadding * 1.5)
onClicked:
{
machineSelection.toggleContent()
Cura.Actions.addMachine.trigger()
}
},
Cura.SecondaryButton
{
id: managePrinterButton
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@button", "Manage printers")
fixedWidthMode: true
// The maximum width of the button is half of the total space, minus the padding of the parent, the right
// padding of the component and half the spacing because of the space between buttons.
width: Math.round(parent.width / 2 - rightPadding * 1.5)
onClicked:
{
machineSelection.toggleContent()
Cura.Actions.configureMachines.trigger()
}
}
]
} }
Cura.ConfigurationMenu Cura.ConfigurationMenu

View File

@ -11,12 +11,29 @@ Cura.ExpandablePopup
{ {
id: machineSelector id: machineSelector
property bool isNetworkPrinter: Cura.MachineManager.activeMachineHasNetworkConnection property Cura.MachineManager machineManager
property bool isConnectedCloudPrinter: Cura.MachineManager.activeMachineHasCloudConnection property bool isNetworkPrinter: machineManager.activeMachineHasNetworkConnection
property bool isCloudRegistered: Cura.MachineManager.activeMachineHasCloudRegistration property bool isConnectedCloudPrinter: machineManager.activeMachineHasCloudConnection
property bool isGroup: Cura.MachineManager.activeMachineIsGroup property bool isCloudRegistered: machineManager.activeMachineHasCloudRegistration
property bool isGroup: machineManager.activeMachineIsGroup
property string machineName: {
if (isNetworkPrinter && machineManager.activeMachineNetworkGroupName != "")
{
return machineManager.activeMachineNetworkGroupName
}
if (machineManager.activeMachine != null)
{
return machineManager.activeMachine.name
}
return ""
}
readonly property string connectionStatus: { property alias machineListModel: machineSelectorList.model
property alias onSelectPrinter: machineSelectorList.onSelectPrinter
property list<Item> buttons
property string connectionStatus: {
if (isNetworkPrinter) if (isNetworkPrinter)
{ {
return "printer_connected" return "printer_connected"
@ -42,7 +59,7 @@ Cura.ExpandablePopup
{ {
if (Cura.API.account.isLoggedIn) if (Cura.API.account.isLoggedIn)
{ {
if (Cura.MachineManager.activeMachineIsLinkedToCurrentAccount) if (machineManager.activeMachineIsLinkedToCurrentAccount)
{ {
return catalog.i18nc("@status", "The cloud printer is offline. Please check if the printer is turned on and connected to the internet.") return catalog.i18nc("@status", "The cloud printer is offline. Please check if the printer is turned on and connected to the internet.")
} }
@ -55,7 +72,8 @@ Cura.ExpandablePopup
{ {
return catalog.i18nc("@status", "The cloud connection is currently unavailable. Please sign in to connect to the cloud printer.") return catalog.i18nc("@status", "The cloud connection is currently unavailable. Please sign in to connect to the cloud printer.")
} }
} else }
else
{ {
return catalog.i18nc("@status", "The cloud connection is currently unavailable. Please check your internet connection.") return catalog.i18nc("@status", "The cloud connection is currently unavailable. Please check your internet connection.")
} }
@ -77,18 +95,8 @@ Cura.ExpandablePopup
headerItem: Cura.IconWithText headerItem: Cura.IconWithText
{ {
text: text: machineName
{
if (isNetworkPrinter && Cura.MachineManager.activeMachineNetworkGroupName != "")
{
return Cura.MachineManager.activeMachineNetworkGroupName
}
if(Cura.MachineManager.activeMachine != null)
{
return Cura.MachineManager.activeMachine.name
}
return ""
}
source: source:
{ {
if (isGroup) if (isGroup)
@ -140,7 +148,7 @@ Cura.ExpandablePopup
color: connectionStatus == "printer_cloud_not_available" ? UM.Theme.getColor("cloud_unavailable") : UM.Theme.getColor("primary") color: connectionStatus == "printer_cloud_not_available" ? UM.Theme.getColor("cloud_unavailable") : UM.Theme.getColor("primary")
visible: isNetworkPrinter || isCloudRegistered visible: (isNetworkPrinter || isCloudRegistered) && source != ""
// Make a themable circle in the background so we can change it in other themes // Make a themable circle in the background so we can change it in other themes
Rectangle Rectangle
@ -156,7 +164,8 @@ Cura.ExpandablePopup
} }
MouseArea // Connection status tooltip hover area // Connection status tooltip hover area
MouseArea
{ {
id: connectionStatusTooltipHoverArea id: connectionStatusTooltipHoverArea
anchors.fill: parent anchors.fill: parent
@ -189,11 +198,14 @@ Cura.ExpandablePopup
} }
} }
property int minDropDownWidth: UM.Theme.getSize("machine_selector_widget_content").width
property int maxDropDownHeight: UM.Theme.getSize("machine_selector_widget_content").height
contentItem: Item contentItem: Item
{ {
id: popup id: popup
implicitWidth: Math.max(machineSelector.width, UM.Theme.getSize("machine_selector_widget_content").width) implicitWidth: Math.max(machineSelector.width, minDropDownWidth)
implicitHeight: Math.min(machineSelectorList.contentHeight + separator.height + buttonRow.height, UM.Theme.getSize("machine_selector_widget_content").height) //Maximum height is the theme entry. implicitHeight: Math.min(machineSelectorList.contentHeight + separator.height + buttonRow.height, maxDropDownHeight) //Maximum height is the theme entry.
MachineSelectorList MachineSelectorList
{ {
id: machineSelectorList id: machineSelectorList
@ -229,39 +241,25 @@ Cura.ExpandablePopup
padding: UM.Theme.getSize("default_margin").width padding: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("default_margin").width
Cura.SecondaryButton children: buttons
{
id: addPrinterButton
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@button", "Add printer")
// The maximum width of the button is half of the total space, minus the padding of the parent, the left
// padding of the component and half the spacing because of the space between buttons.
fixedWidthMode: true
width: buttonRow.width / 2 - leftPadding * 1.5
onClicked:
{
toggleContent()
Cura.Actions.addMachine.trigger()
}
}
Cura.SecondaryButton
{
id: managePrinterButton
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@button", "Manage printers")
fixedWidthMode: true
// The maximum width of the button is half of the total space, minus the padding of the parent, the right
// padding of the component and half the spacing because of the space between buttons.
width: buttonRow.width / 2 - rightPadding * 1.5
onClicked:
{
toggleContent()
Cura.Actions.configureMachines.trigger()
}
}
} }
states: [
State {
name: "noButtons"
when: !buttons || buttons.length == 0
PropertyChanges
{
target: buttonRow
height: 0
padding: 0
}
PropertyChanges
{
target: separator
height: 0
}
}
]
} }
} }

View File

@ -10,9 +10,9 @@ import Cura 1.0 as Cura
ListView ListView
{ {
id: listView id: listView
model: Cura.MachineListModel {} section.property: "category"
section.property: "isOnline"
property real contentHeight: childrenRect.height property real contentHeight: childrenRect.height
property var onSelectPrinter
ScrollBar.vertical: UM.ScrollBar ScrollBar.vertical: UM.ScrollBar
{ {
@ -21,7 +21,17 @@ ListView
section.delegate: UM.Label section.delegate: UM.Label
{ {
text: section == "true" ? catalog.i18nc("@label", "Connected printers") : catalog.i18nc("@label", "Other printers") text: {
switch (section)
{
case "connected":
return catalog.i18nc("@label", "Connected printers");
case "other":
return catalog.i18nc("@label", "Other printers");
default:
return catalog.i18nc("@label", "Other printers");
}
}
height: UM.Theme.getSize("action_button").height height: UM.Theme.getSize("action_button").height
width: parent.width - scrollBar.width width: parent.width - scrollBar.width
leftPadding: UM.Theme.getSize("default_margin").width leftPadding: UM.Theme.getSize("default_margin").width
@ -43,8 +53,7 @@ ListView
listView.model.setShowCloudPrinters(true); listView.model.setShowCloudPrinters(true);
break; break;
case "MACHINE": case "MACHINE":
toggleContent() if (typeof onSelectPrinter === "function") onSelectPrinter(model);
Cura.MachineManager.setActiveMachine(model.id)
break; break;
default: default:
} }

View File

@ -18,6 +18,7 @@ SettingItem
model: definition.options model: definition.options
textRole: "value" textRole: "value"
forceHighlight: base.hovered
anchors.fill: parent anchors.fill: parent

View File

@ -17,6 +17,8 @@ SettingItem
id: control id: control
anchors.fill: parent anchors.fill: parent
forceHighlight: base.hovered
property var extrudersModel: CuraApplication.getExtrudersModel() property var extrudersModel: CuraApplication.getExtrudersModel()
model: extrudersModel model: extrudersModel

View File

@ -23,6 +23,7 @@ SettingItem
{ {
id: control id: control
anchors.fill: parent anchors.fill: parent
forceHighlight: base.hovered
model: base.extrudersWithOptionalModel model: base.extrudersWithOptionalModel

View File

@ -18,6 +18,8 @@ ComboBox
property var defaultTextOnEmptyModel: catalog.i18nc("@label", "No items to select from") // Text displayed in the combobox when the model is empty property var defaultTextOnEmptyModel: catalog.i18nc("@label", "No items to select from") // Text displayed in the combobox when the model is empty
property var defaultTextOnEmptyIndex: "" // Text displayed in the combobox when the model has items but no item is selected property var defaultTextOnEmptyIndex: "" // Text displayed in the combobox when the model has items but no item is selected
property alias textFormat: contentLabel.textFormat property alias textFormat: contentLabel.textFormat
property alias backgroundColor: background.color
property bool forceHighlight: false
enabled: delegateModel.count > 0 enabled: delegateModel.count > 0
@ -45,7 +47,7 @@ ComboBox
State State
{ {
name: "highlighted" name: "highlighted"
when: (base.hovered || control.hovered) && !control.activeFocus when: (control.hovered && !control.activeFocus) || forceHighlight
PropertyChanges PropertyChanges
{ {
target: background target: background
@ -56,6 +58,7 @@ ComboBox
background: UM.UnderlineBackground background: UM.UnderlineBackground
{ {
id: background
// Rectangle for highlighting when this combobox needs to pulse. // Rectangle for highlighting when this combobox needs to pulse.
Rectangle Rectangle
{ {