pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import ZShell.Blobs import qs.Components import ZShell.Config import qs.Services Item { id: root property bool acceptAllowed: true required property string acceptLabel required property Component content required property string header property int horizontalContentMargin property string icon required property string label property alias iconLabel: openButton.iconLabel property alias rowButton: openButton property string subtext: "" property bool open property real openHeight: Math.min(rootParent.height * 0.8, 600) property real openWidth: Math.min(rootParent.width * 0.8, 400) required property Item rootParent property bool separateContent required property string settingAnchor property bool first: false property bool last: false signal accepted signal cancelled function reparentWrapper(): void { const newParent = open ? rootParent : root; const pos = dialogWrapper.mapToItem(newParent, 0, 0); dialogWrapper.parent = newParent; dialogWrapper.x = pos.x; dialogWrapper.y = pos.y; } Layout.fillWidth: true implicitHeight: openButton.implicitHeight z: open || dialogTransition.running ? 2 : 0 BlobGroup { id: blobGroup color: root.open ? Colors.palette.m3surfaceContainerHighest : Colors.tPalette.m3surfaceContainer Behavior on color { CAnim {} } } MouseArea { id: backdrop anchors.fill: parent enabled: false hoverEnabled: enabled preventStealing: true parent: root.open ? root.rootParent : root onClicked: root.open = false } Item { id: dialogWrapper height: openButton.implicitHeight width: root.width z: 1 states: State { name: "open" when: root.open PropertyChanges { backdrop.enabled: true dialogBg.bottomLeftRadius: Tokens.rounding.largeIncreased dialogBg.bottomRightRadius: Tokens.rounding.largeIncreased dialogBg.topRightRadius: Tokens.rounding.largeIncreased dialogBg.topLeftRadius: Tokens.rounding.largeIncreased dialogContent.opacity: 1 dialogWrapper.height: root.openHeight dialogWrapper.width: root.openWidth dialogWrapper.x: (root.rootParent.width - root.openWidth) / 2 dialogWrapper.y: (root.rootParent.height - root.openHeight) / 2 elevation.opacity: 1 openButton.opacity: 0 } } transitions: Transition { id: dialogTransition SequentialAnimation { ScriptAction { script: root.reparentWrapper() } Anim { properties: "x,y" } } PropertyAction { property: "enabled" } Anim { properties: "opacity,topLeftRadius,topRightRadius,bottomLeftRadius,bottomRightRadius" type: Anim.DefaultEffects } Anim { properties: "width,height" } } Elevation { id: elevation anchors.fill: parent bottomLeftRadius: dialogBg.bottomLeftRadius bottomRightRadius: dialogBg.bottomRightRadius level: 4 opacity: 0 radius: dialogBg.radius transform: Matrix4x4 { matrix: dialogBg.deformMatrix } } BlobRect { id: dialogBg anchors.fill: parent bottomLeftRadius: root.last ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall bottomRightRadius: root.last ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall topRightRadius: root.first ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall topLeftRadius: root.first ? Tokens.rounding.largeIncreased : Tokens.rounding.extraSmall deformScale: 0 group: blobGroup opacity: blobGroup.color.a * (root.enabled ? 1 : 0.5) } RowButton { id: openButton anchors.left: parent.left anchors.right: parent.right color: "transparent" height: Math.min(implicitHeight, parent.height) icon: root.icon subtext: root.subtext last: root.last first: root.first text: root.label transform: Matrix4x4 { matrix: dialogBg.deformMatrix } onClicked: root.open = true } Loader { id: dialogContent active: opacity > 0 anchors.fill: parent asynchronous: true opacity: 0 sourceComponent: MouseArea { onWheel: event => event.accepted = true preventStealing: true ColumnLayout { anchors.bottomMargin: Tokens.padding.largeIncreased anchors.fill: parent anchors.margins: Tokens.padding.extraLarge spacing: 0 CustomText { font.pointSize: Tokens.font.size.large text: root.header } Loader { Layout.fillWidth: true Layout.topMargin: Tokens.spacing.medium active: root.separateContent sourceComponent: CustomRect { color: Colors.palette.m3outline implicitHeight: 1 } } Loader { Layout.fillHeight: true Layout.fillWidth: true Layout.leftMargin: root.horizontalContentMargin Layout.rightMargin: root.horizontalContentMargin sourceComponent: root.content } Loader { Layout.bottomMargin: Tokens.spacing.medium Layout.fillWidth: true active: root.separateContent sourceComponent: CustomRect { color: Colors.palette.m3outline implicitHeight: 1 } } RowLayout { Layout.alignment: Qt.AlignRight spacing: Tokens.spacing.extraSmall TextButton { horizontalPadding: Tokens.padding.largeIncreased isRound: true text: qsTr("Cancel") type: TextButton.Text verticalPadding: Tokens.padding.small stateLayer.preventStealing: true onClicked: { root.cancelled(); root.open = false; } } TextButton { enabled: root.acceptAllowed horizontalPadding: Tokens.padding.largeIncreased isRound: true text: root.acceptLabel type: TextButton.Text stateLayer.preventStealing: true verticalPadding: Tokens.padding.small onClicked: { root.accepted(); root.open = false; } } } } } transform: Matrix4x4 { matrix: dialogBg.deformMatrix } } } }