Warning, /plasma/plasma-mobile/lookandfeel/contents/systemdialog/SystemDialog.qml is written in an unsupported language. File is not indexed.
0001 /*
0002 * SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
0003 *
0004 * SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006
0007 import QtQuick 2.15
0008 import QtQuick.Controls 2.15
0009 import QtQuick.Layouts 1.15
0010 import QtQuick.Window 2.15
0011 import Qt5Compat.GraphicalEffects
0012 import org.kde.kirigami 2.18 as Kirigami
0013 import "private" as Private
0014
0015 Item {
0016 id: root
0017
0018 default property Item mainItem
0019
0020 /**
0021 * Title of the dialog.
0022 */
0023 property string mainText: ""
0024
0025 /**
0026 * Subtitle of the dialog.
0027 */
0028 property string subtitle: ""
0029
0030 /**
0031 * This property holds the default padding of the content.
0032 */
0033 property real padding: Kirigami.Units.smallSpacing
0034
0035 /**
0036 * This property holds the left padding of the content. If not specified, it uses `padding`.
0037 */
0038 property real leftPadding: padding
0039
0040 /**
0041 * This property holds the right padding of the content. If not specified, it uses `padding`.
0042 */
0043 property real rightPadding: padding
0044
0045 /**
0046 * This property holds the top padding of the content. If not specified, it uses `padding`.
0047 */
0048 property real topPadding: padding
0049
0050 /**
0051 * This property holds the bottom padding of the content. If not specified, it uses `padding`.
0052 */
0053 property real bottomPadding: padding
0054 property alias standardButtons: footerButtonBox.standardButtons
0055
0056 readonly property int flags: Qt.FramelessWindowHint | Qt.Dialog
0057 readonly property real dialogCornerRadius: Kirigami.Units.smallSpacing * 2
0058 property list<Kirigami.Action> actions
0059 property string iconName
0060
0061 implicitWidth: loader.implicitWidth
0062 implicitHeight: loader.implicitHeight
0063
0064 readonly property real minimumHeight: implicitWidth
0065 readonly property real minimumWidth: implicitHeight
0066
0067 required property Kirigami.AbstractApplicationWindow window
0068
0069 function present() {
0070 root.window.showFullScreen()
0071 }
0072
0073 onWindowChanged: {
0074 window.color = Qt.binding(() => {
0075 return Qt.rgba(0, 0, 0, 0.5)
0076 })
0077 }
0078
0079 // load in async to speed up load times (especially on embedded devices)
0080 Loader {
0081 id: loader
0082 anchors.centerIn: parent
0083 asynchronous: true
0084
0085 sourceComponent: Item {
0086 // margins for shadow
0087 implicitWidth: Math.min(Screen.width, control.implicitWidth + 2 * Kirigami.Units.gridUnit)
0088 implicitHeight: Math.min(Screen.height, control.implicitHeight + 2 * Kirigami.Units.gridUnit)
0089
0090 // shadow
0091 RectangularGlow {
0092 id: glow
0093 anchors.topMargin: 1
0094 anchors.fill: control
0095 cached: true
0096 glowRadius: 2
0097 cornerRadius: Kirigami.Units.gridUnit
0098 spread: 0.1
0099 color: Qt.rgba(0, 0, 0, 0.4)
0100 }
0101
0102 // actual window
0103 Control {
0104 id: control
0105 anchors.fill: parent
0106 anchors.margins: glow.cornerRadius
0107 topPadding: 0
0108 bottomPadding: 0
0109 rightPadding: 0
0110 leftPadding: 0
0111
0112 background: Item {
0113 Rectangle { // border
0114 anchors.fill: parent
0115 anchors.margins: -1
0116 radius: dialogCornerRadius + 1
0117 color: Qt.darker(Kirigami.Theme.backgroundColor, 1.5)
0118 }
0119 Rectangle { // background colour
0120 anchors.fill: parent
0121 radius: dialogCornerRadius
0122 color: Kirigami.Theme.backgroundColor
0123 }
0124 }
0125
0126 contentItem: column
0127 }
0128 }
0129 }
0130
0131 readonly property var contents: ColumnLayout {
0132 id: column
0133 spacing: 0
0134
0135 // header
0136 Control {
0137 id: headerControl
0138
0139 Layout.fillWidth: true
0140 Layout.maximumWidth: root.window.maximumWidth
0141
0142 topPadding: 0
0143 leftPadding: 0
0144 rightPadding: 0
0145 bottomPadding: 0
0146
0147 background: Item {}
0148
0149 contentItem: RowLayout {
0150 Kirigami.Heading {
0151 Layout.fillWidth: true
0152 Layout.topMargin: Kirigami.Units.largeSpacing
0153 Layout.bottomMargin: Kirigami.Units.largeSpacing
0154 Layout.leftMargin: Kirigami.Units.largeSpacing
0155 Layout.rightMargin: Kirigami.Units.largeSpacing
0156 Layout.alignment: Qt.AlignVCenter
0157 level: 2
0158 text: root.mainText
0159 wrapMode: Text.Wrap
0160 elide: Text.ElideRight
0161 horizontalAlignment: Text.AlignHCenter
0162 }
0163 }
0164 }
0165
0166 // content
0167 Control {
0168 id: content
0169
0170 Layout.fillHeight: true
0171 Layout.fillWidth: true
0172 Layout.maximumWidth: root.window.maximumWidth
0173
0174 leftPadding: 0
0175 rightPadding: 0
0176 topPadding: 0
0177 bottomPadding: 0
0178
0179 background: Item {}
0180 contentItem: ColumnLayout {
0181 spacing: 0
0182 clip: true
0183
0184 Label {
0185 id: subtitleLabel
0186 Layout.fillWidth: true
0187 Layout.topMargin: Kirigami.Units.largeSpacing
0188 Layout.bottomMargin: Kirigami.Units.largeSpacing
0189 Layout.leftMargin: Kirigami.Units.gridUnit * 3
0190 Layout.rightMargin: Kirigami.Units.gridUnit * 3
0191 visible: root.subtitle !== ""
0192 horizontalAlignment: Text.AlignHCenter
0193 text: root.subtitle
0194 wrapMode: Label.Wrap
0195 }
0196
0197 // separator when scrolling
0198 Kirigami.Separator {
0199 Layout.fillWidth: true
0200 opacity: root.mainItem && contentControl.flickableItem && contentControl.flickableItem.contentY !== 0 ? 1 : 0 // always maintain same height (as opposed to visible)
0201 }
0202
0203 // mainItem is in scrollview, in case of overflow
0204 Private.ScrollView {
0205 id: contentControl
0206 clip: true
0207
0208 // we cannot have contentItem inside a sub control (allowing for content padding within the scroll area),
0209 // because if the contentItem is a Flickable (ex. ListView), the ScrollView needs it to be top level in order
0210 // to decorate it
0211 contentItem: root.mainItem
0212 canFlickWithMouse: true
0213
0214 // ensure window colour scheme, and background color
0215 Kirigami.Theme.inherit: false
0216 Kirigami.Theme.colorSet: Kirigami.Theme.Window
0217
0218 // needs to explicitly be set for each side to work
0219 leftPadding: root.leftPadding; topPadding: root.topPadding
0220 rightPadding: root.rightPadding; bottomPadding: root.bottomPadding
0221
0222 // height of everything else in the dialog other than the content
0223 property real otherHeights: headerControl.height + subtitleLabel.height + footerButtonBox.height + root.topPadding + root.bottomPadding;
0224
0225 property real calculatedMaximumWidth: root.window.maximumWidth > root.absoluteMaximumWidth ? root.absoluteMaximumWidth : root.window.maximumWidth
0226 property real calculatedMaximumHeight: root.window.maximumHeight > root.absoluteMaximumHeight ? root.absoluteMaximumHeight : root.window.maximumHeight
0227 property real calculatedImplicitWidth: root.mainItem ? (root.mainItem.implicitWidth ? root.mainItem.implicitWidth : root.mainItem.width) + root.leftPadding + root.rightPadding : 0
0228 property real calculatedImplicitHeight: root.mainItem ? (root.mainItem.implicitHeight ? root.mainItem.implicitHeight : root.mainItem.height) + root.topPadding + root.bottomPadding : 0
0229
0230 // don't enforce preferred width and height if not set
0231 Layout.preferredWidth: root.preferredWidth >= 0 ? root.preferredWidth : calculatedImplicitWidth + contentControl.rightSpacing
0232 Layout.preferredHeight: root.preferredHeight >= 0 ? root.preferredHeight - otherHeights : calculatedImplicitHeight + contentControl.bottomSpacing
0233
0234 Layout.fillWidth: true
0235 Layout.fillHeight: true
0236 Layout.maximumWidth: calculatedMaximumWidth
0237 Layout.maximumHeight: calculatedMaximumHeight >= otherHeights ? calculatedMaximumHeight - otherHeights : 0 // we enforce maximum height solely from the content
0238
0239 // give an implied width and height to the contentItem so that features like word wrapping/eliding work
0240 // cannot placed directly in contentControl as a child, so we must use a property
0241 property var widthHint: Binding {
0242 target: root.mainItem
0243 property: "width"
0244 // we want to avoid horizontal scrolling, so we apply maximumWidth as a hint if necessary
0245 property real preferredWidthHint: contentControl.width - root.leftPadding - root.rightPadding - contentControl.rightSpacing
0246 property real maximumWidthHint: contentControl.calculatedMaximumWidth - root.leftPadding - root.rightPadding - contentControl.rightSpacing
0247 value: maximumWidthHint < preferredWidthHint ? maximumWidthHint : preferredWidthHint
0248 }
0249 property var heightHint: Binding {
0250 target: root.mainItem
0251 property: "height"
0252 // we are okay with overflow, if it exceeds maximumHeight we will allow scrolling
0253 value: contentControl.Layout.preferredHeight - root.topPadding - root.bottomPadding - contentControl.bottomSpacing
0254 }
0255
0256 // give explicit warnings since the maximumHeight is ignored when negative, so developers aren't confused
0257 Component.onCompleted: {
0258 if (contentControl.Layout.maximumHeight < 0 || contentControl.Layout.maximumHeight === Infinity) {
0259 console.log("Dialog Warning: the calculated maximumHeight for the content is " + contentControl.Layout.maximumHeight + ", ignoring...");
0260 }
0261 }
0262 }
0263 }
0264 }
0265 Control {
0266 Layout.fillWidth: true
0267
0268 leftPadding: 0
0269 rightPadding: 0
0270 topPadding: 0
0271 bottomPadding: 0
0272 contentItem: footerButtonBox
0273 }
0274 }
0275
0276 readonly property DialogButtonBox dialogButtonBox: DialogButtonBox {
0277 //We want to report the same width on all so the button area is split equally
0278 id: footerButtonBox
0279 Layout.fillWidth: true
0280 onAccepted: root.window.accept()
0281 onRejected: root.window.reject()
0282 implicitHeight: contentItem.implicitHeight
0283 alignment: undefined
0284
0285 readonly property real sameWidth: 50
0286 delegate: Private.MobileSystemDialogButton {
0287 Layout.fillWidth: true
0288 Layout.preferredWidth: footerButtonBox.sameWidth
0289
0290 readonly property point globalPos: root.window.visible ? mapToItem(footerButtonBox, Qt.point(x, y)) : Qt.point(0, 0)
0291 verticalSeparator: globalPos.x > 0 && root.window.layout === Qt.Horizontal
0292 horizontalSeparator: true
0293 corners.bottomLeftRadius: verticalSeparator ? 0 : root.dialogCornerRadius
0294 corners.bottomRightRadius: globalPos.x >= footerButtonBox.width ? root.dialogCornerRadius : 0
0295 }
0296
0297 leftPadding: 0
0298 rightPadding: 0
0299 topPadding: 0
0300 bottomPadding: 0
0301
0302 contentItem: GridLayout {
0303 Layout.fillWidth: true
0304
0305 rowSpacing: 0
0306 columnSpacing: 0
0307 rows: root.window.layout === Qt.Vertical ? Number.MAX_VALUE : 1
0308 columns: root.window.layout !== Qt.Vertical ? Number.MAX_VALUE : 1
0309
0310 Repeater {
0311 model: root.actions
0312 delegate: Private.MobileSystemDialogButton {
0313 Layout.fillWidth: true
0314 Layout.preferredWidth: footerButtonBox.sameWidth
0315 readonly property point globalPos: root.window.visible ? mapToItem(footerButtonBox, Qt.point(x, y)) : Qt.point(0, 0)
0316 verticalSeparator: globalPos.x > 0 && root.window.layout === Qt.Horizontal
0317 horizontalSeparator: true
0318 corners.bottomLeftRadius: model.index === root.actions.length - 1 ? root.dialogCornerRadius : 0
0319 corners.bottomRightRadius: model.index === root.actions.length - 1 && footerButtonBox.standardButtons === 0 ? root.dialogCornerRadius : 0
0320 action: modelData
0321 }
0322 }
0323 }
0324 }
0325 }