Warning, /plasma/plasma-workspace/components/containmentlayoutmanager/qml/BasicAppletContainer.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org> 0003 SPDX-FileCopyrightText: 2022 ivan tkachenko <me@ratijas.tk> 0004 SPDX-FileCopyrightText: 2022 Niccolò Venerandi <niccolo@venerandi.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 import QtQuick 2.15 0010 import QtQuick.Layouts 1.15 0011 import QtQuick.Window 2.15 0012 import Qt5Compat.GraphicalEffects 0013 0014 import org.kde.plasma.plasmoid 2.0 0015 import org.kde.plasma.core as PlasmaCore 0016 import org.kde.ksvg 1.0 as KSvg 0017 import org.kde.plasma.components 3.0 as PlasmaComponents 0018 import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager 0019 import org.kde.kirigami 2.11 as Kirigami 0020 0021 ContainmentLayoutManager.AppletContainer { 0022 id: appletContainer 0023 editModeCondition: Plasmoid.immutable 0024 ? ContainmentLayoutManager.ItemContainer.Manual 0025 : ContainmentLayoutManager.ItemContainer.AfterPressAndHold 0026 0027 Kirigami.Theme.inherit: false 0028 Kirigami.Theme.colorSet: (applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.ShadowBackground) 0029 && !(applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.StandardBackground) 0030 && !(applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.TranslucentBackground) 0031 ? Kirigami.Theme.Complementary 0032 : Kirigami.Theme.Window 0033 0034 onFocusChanged: { 0035 if (!focus && !dragActive) { 0036 editMode = false; 0037 } 0038 } 0039 Layout.minimumWidth: { 0040 if (!applet) { 0041 return leftPadding + rightPadding; 0042 } 0043 0044 if (applet.preferredRepresentation !== applet.fullRepresentation 0045 && applet.compactRepresentationItem 0046 ) { 0047 return applet.compactRepresentationItem.Layout.minimumWidth + leftPadding + rightPadding; 0048 } else { 0049 return applet.Layout.minimumWidth + leftPadding + rightPadding; 0050 } 0051 } 0052 Layout.minimumHeight: { 0053 if (!applet) { 0054 return topPadding + bottomPadding; 0055 } 0056 0057 if (applet.preferredRepresentation !== applet.fullRepresentation 0058 && applet.compactRepresentationItem 0059 ) { 0060 return applet.compactRepresentationItem.Layout.minimumHeight + topPadding + bottomPadding; 0061 } else { 0062 return applet.Layout.minimumHeight + topPadding + bottomPadding; 0063 } 0064 } 0065 0066 Layout.preferredWidth: Math.max(applet.Layout.minimumWidth, applet.Layout.preferredWidth) 0067 Layout.preferredHeight: Math.max(applet.Layout.minimumHeight, applet.Layout.preferredHeight) 0068 0069 Layout.maximumWidth: applet.Layout.maximumWidth 0070 Layout.maximumHeight: applet.Layout.maximumHeight 0071 0072 leftPadding: background.margins.left 0073 topPadding: background.margins.top 0074 rightPadding: background.margins.right 0075 bottomPadding: background.margins.bottom 0076 0077 // render via a layer if we're at an angle 0078 // resize handles are rendered outside this item, so also disable when they're showing to avoid clipping 0079 layer.enabled: (rotation % 90 !== 0) && !(configOverlayItem && configOverlayItem.visible) 0080 layer.smooth: true 0081 0082 initialSize.width: applet.switchWidth + leftPadding + rightPadding 0083 initialSize.height: applet.switchHeight + topPadding + bottomPadding 0084 0085 background: KSvg.FrameSvgItem { 0086 id: background 0087 0088 property bool blurEnabled: false 0089 property Item maskItem: null 0090 0091 prefix: blurEnabled ? "blurred" : "" 0092 0093 imagePath: { 0094 if (!appletContainer.applet) { 0095 return ""; 0096 } 0097 if (appletContainer.applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.TranslucentBackground) { 0098 return "widgets/translucentbackground"; 0099 } else if (appletContainer.applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.StandardBackground) { 0100 return "widgets/background"; 0101 } else { 0102 return ""; 0103 } 0104 } 0105 0106 function bindBlurEnabled() { 0107 // bind to api and hints automatically, refresh non-observable prefix manually 0108 blurEnabled = Qt.binding(() => 0109 GraphicsInfo.api !== GraphicsInfo.Software 0110 && (appletContainer.applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.StandardBackground) 0111 && hasElementPrefix("blurred") 0112 ); 0113 } 0114 0115 Component.onCompleted: bindBlurEnabled() 0116 onRepaintNeeded: bindBlurEnabled() 0117 0118 onBlurEnabledChanged: { 0119 if (blurEnabled) { 0120 if (maskItem === null) { 0121 maskItem = maskComponent.createObject(this); 0122 } 0123 } else { 0124 if (maskItem !== null) { 0125 maskItem.destroy(); 0126 maskItem = null; 0127 } 0128 } 0129 } 0130 0131 DropShadow { 0132 anchors { 0133 fill: parent 0134 leftMargin: appletContainer.leftPadding 0135 topMargin: appletContainer.topPadding 0136 rightMargin: appletContainer.rightPadding 0137 bottomMargin: appletContainer.bottomPadding 0138 } 0139 z: -1 0140 horizontalOffset: 0 0141 verticalOffset: 1 0142 0143 radius: 4 0144 samples: 9 0145 spread: 0.35 0146 0147 color: Qt.rgba(0, 0, 0, 0.5) 0148 opacity: 1 0149 0150 source: appletContainer.applet && appletContainer.applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.ShadowBackground 0151 ? appletContainer.applet : null 0152 visible: source !== null 0153 } 0154 } 0155 0156 Component { 0157 id: maskComponent 0158 0159 OpacityMask { 0160 id: mask 0161 0162 readonly property rect appletContainerScreenRect: { 0163 const win = appletContainer.Window.window; 0164 let sceneSize = Qt.size(appletContainer.width, appletContainer.height) 0165 if (win) { 0166 sceneSize = Qt.size(win.width, win.height) 0167 } 0168 const position = appletContainer.Kirigami.ScenePosition; 0169 return clipRect( 0170 boundsForTransformedRect( 0171 Qt.rect( 0172 position.x, 0173 position.y, 0174 appletContainer.width, 0175 appletContainer.height), 0176 appletContainer.rotation, 0177 appletContainer.scale), 0178 sceneSize); 0179 } 0180 0181 /** Apply geometry transformations, and return a bounding rectangle for a resulting shape. */ 0182 // Note: It's basically a custom QMatrix::mapRect implementation, and for 0183 // simplicity's sake should be replaced when/if mapRect becomes available in QML. 0184 function boundsForTransformedRect(rect: rect, angle: real, scale: real): rect { 0185 if (angle === 0 && scale === 1) { 0186 return rect; // hot path optimization 0187 } 0188 let cosa = Math.abs(Math.cos(angle * (Math.PI / 180))) * scale; 0189 let sina = Math.abs(Math.sin(angle * (Math.PI / 180))) * scale; 0190 let newSize = Qt.size( 0191 rect.width * cosa + rect.height * sina, 0192 rect.width * sina + rect.height * cosa); 0193 return Qt.rect( 0194 rect.left + (rect.width - newSize.width) / 2, 0195 rect.top + (rect.height - newSize.height) / 2, 0196 newSize.width, 0197 newSize.height); 0198 } 0199 0200 /** Clip given rectangle to the bounds of given size, assuming bounds position {0,0}. 0201 * This is a pure library function, similar to QRect::intersected, 0202 * which Qt should've exposed in QML stdlib. 0203 */ 0204 function clipRect(rect: rect, bounds: size): rect { 0205 return Qt.rect( 0206 Math.max(0, Math.min(bounds.width, rect.x)), 0207 Math.max(0, Math.min(bounds.height, rect.y)), 0208 Math.max(0, rect.width 0209 + Math.min(0, rect.x) 0210 + Math.min(0, bounds.width - (rect.x + rect.width))), 0211 Math.max(0, rect.height 0212 + Math.min(0, rect.y) 0213 + Math.min(0, bounds.height - (rect.y + rect.height))), 0214 ); 0215 } 0216 0217 parent: appletContainer.layout.containmentItem 0218 x: appletContainerScreenRect.x 0219 y: appletContainerScreenRect.y 0220 width: appletContainerScreenRect.width 0221 height: appletContainerScreenRect.height 0222 0223 z: -2 0224 maskSource: Item { 0225 // optimized (clipped) blurred-mask 0226 0227 width: mask.appletContainerScreenRect.width 0228 height: mask.appletContainerScreenRect.height 0229 0230 clip: true 0231 0232 KSvg.FrameSvgItem { 0233 imagePath: "widgets/background" 0234 prefix: "blurred-mask" 0235 0236 x: appletContainer.Kirigami.ScenePosition.x - mask.appletContainerScreenRect.x 0237 y: appletContainer.Kirigami.ScenePosition.y - mask.appletContainerScreenRect.y 0238 0239 width: background.width 0240 height: background.height 0241 0242 rotation: appletContainer.rotation 0243 scale: appletContainer.scale 0244 } 0245 } 0246 0247 source: FastBlur { 0248 width: mask.appletContainerScreenRect.width 0249 height: mask.appletContainerScreenRect.height 0250 0251 radius: 128 0252 0253 source: ShaderEffectSource { 0254 width: mask.appletContainerScreenRect.width 0255 height: mask.appletContainerScreenRect.height 0256 sourceRect: mask.appletContainerScreenRect 0257 sourceItem: appletContainer.layout.containmentItem.wallpaper 0258 } 0259 } 0260 } 0261 } 0262 0263 busyIndicatorComponent: PlasmaComponents.BusyIndicator { 0264 anchors.centerIn: parent 0265 visible: applet.plasmoid.busy 0266 running: visible 0267 } 0268 configurationRequiredComponent: PlasmaComponents.Button { 0269 anchors.centerIn: parent 0270 text: i18n("Configure…") 0271 icon.name: "configure" 0272 visible: applet.plasmoid.configurationRequired 0273 onClicked: applet.plasmoid.internalAction("configure").trigger(); 0274 } 0275 }