1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-07 14:05:38 -05:00
Files
DankMaterialShell/Widgets/DankModal.qml
2025-07-22 23:00:09 -04:00

214 lines
5.7 KiB
QML

import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Wayland
import qs.Common
import qs.Widgets
PanelWindow {
id: root
// Core properties
property alias content: contentLoader.sourceComponent
// Sizing
property real width: 400
property real height: 300
// Background behavior
property bool showBackground: true
property real backgroundOpacity: 0.5
// Positioning
property string positioning: "center" // "center", "top-right", "custom"
property point customPosition: Qt.point(0, 0)
// Focus management
property string keyboardFocus: "ondemand" // "ondemand", "exclusive", "none"
property bool closeOnEscapeKey: true
property bool closeOnBackgroundClick: true
// Animation
property string animationType: "scale" // "scale", "slide", "fade"
property int animationDuration: Theme.mediumDuration
property var animationEasing: Theme.emphasizedEasing
// Styling
property color backgroundColor: Theme.surfaceContainer
property color borderColor: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
property real borderWidth: 1
property real cornerRadius: Theme.cornerRadiusLarge
property bool enableShadow: false
// Signals
signal opened()
signal dialogClosed()
signal backgroundClicked()
// PanelWindow configuration
// visible property is inherited from PanelWindow
color: "transparent"
anchors {
top: true
left: true
right: true
bottom: true
}
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: {
switch (root.keyboardFocus) {
case "exclusive": return WlrKeyboardFocus.Exclusive
case "none": return WlrKeyboardFocus.None
default: return WlrKeyboardFocus.OnDemand
}
}
onVisibleChanged: {
if (root.visible) {
opened()
} else {
dialogClosed()
}
}
// Background overlay
Rectangle {
id: background
anchors.fill: parent
color: "black"
opacity: root.showBackground ? (root.visible ? root.backgroundOpacity : 0) : 0
visible: root.showBackground
Behavior on opacity {
NumberAnimation {
duration: root.animationDuration
easing.type: root.animationEasing
}
}
MouseArea {
anchors.fill: parent
enabled: root.closeOnBackgroundClick
onClicked: (mouse) => {
var localPos = mapToItem(contentContainer, mouse.x, mouse.y)
if (localPos.x < 0 || localPos.x > contentContainer.width ||
localPos.y < 0 || localPos.y > contentContainer.height) {
root.backgroundClicked()
}
}
}
}
// Main content container
Rectangle {
id: contentContainer
width: root.width
height: root.height
// Positioning
anchors.centerIn: positioning === "center" ? parent : undefined
x: {
if (positioning === "top-right") {
return Math.max(Theme.spacingL, parent.width - width - Theme.spacingL)
} else if (positioning === "custom") {
return root.customPosition.x
}
return 0 // Will be overridden by anchors.centerIn when positioning === "center"
}
y: {
if (positioning === "top-right") {
return Theme.barHeight + Theme.spacingXS
} else if (positioning === "custom") {
return root.customPosition.y
}
return 0 // Will be overridden by anchors.centerIn when positioning === "center"
}
color: root.backgroundColor
radius: root.cornerRadius
border.color: root.borderColor
border.width: root.borderWidth
layer.enabled: root.enableShadow
// Animation properties
opacity: root.visible ? 1 : 0
scale: {
if (root.animationType === "scale") {
return root.visible ? 1 : 0.9
}
return 1
}
// Transform for slide animation
transform: root.animationType === "slide" ? slideTransform : null
Translate {
id: slideTransform
x: root.visible ? 0 : 15
y: root.visible ? 0 : -30
}
// Content area
Loader {
id: contentLoader
anchors.fill: parent
active: true
asynchronous: false
}
// Animations
Behavior on opacity {
NumberAnimation {
duration: root.animationDuration
easing.type: root.animationEasing
}
}
Behavior on scale {
enabled: root.animationType === "scale"
NumberAnimation {
duration: root.animationDuration
easing.type: root.animationEasing
}
}
// Shadow effect
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 8
shadowBlur: 1
shadowColor: Qt.rgba(0, 0, 0, 0.3)
shadowOpacity: 0.3
}
}
// Keyboard handling
FocusScope {
anchors.fill: parent
focus: visible && root.closeOnEscapeKey
Keys.onEscapePressed: {
if (root.closeOnEscapeKey) {
visible = false
}
}
}
// Convenience functions
function open() {
visible = true
}
function close() {
visible = false
}
function toggle() {
visible = !visible
}
}