mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-16 00:04:01 -04:00
310 lines
12 KiB
QML
310 lines
12 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import qs.Common
|
|
import qs.Services
|
|
import qs.DCommon.Widgets
|
|
import qs.Modules.ControlCenter.Widgets
|
|
import qs.Modules.DDash.Overview
|
|
import qs.Modules.Settings.DesktopWidgetSettings
|
|
import qs.Modules.Settings.Widgets
|
|
import "../../DCommon/Common/FocusNavigation.js" as FocusNavigation
|
|
|
|
FocusScope {
|
|
id: root
|
|
|
|
required property WidgetEditLayer editLayer
|
|
readonly property bool lockScreen: editLayer.lockScreen
|
|
readonly property bool greeter: editLayer.greeter
|
|
property bool libraryOpen: false
|
|
readonly property real fabReserved: fabBar.reservedHeight
|
|
readonly property var singletonTypes: ["lockAuth", "greeterSession"]
|
|
readonly property var libraryWidgets: DesktopWidgetRegistry.getListWidgets(editLayer.listKey).filter(widget => {
|
|
if (!lockScreen)
|
|
return true;
|
|
return !singletonTypes.includes(widget.id) || !SettingsData.widgetInstanceOfType(editLayer.listKey, widget.id);
|
|
}).map(widget => ({
|
|
id: widget.id,
|
|
text: widget.name,
|
|
icon: widget.icon,
|
|
description: widget.description
|
|
}))
|
|
|
|
readonly property string surfaceLabel: {
|
|
if (greeter)
|
|
return SettingsData.greeterFollowLockScreen ? I18n.tr("Editing the login screen, shared with the lock screen", "widget editor banner") : I18n.tr("Editing the login screen", "widget editor banner");
|
|
if (!lockScreen || !GreeterService.available)
|
|
return "";
|
|
return SettingsData.greeterFollowLockScreen && GreeterService.slotState !== "" ? I18n.tr("Editing the lock screen, the login screen follows it", "widget editor banner") : I18n.tr("Editing the lock screen", "widget editor banner");
|
|
}
|
|
|
|
property string optionsInstanceId: ""
|
|
readonly property string selectedInstanceId: editLayer.selectedInstanceId
|
|
readonly property Item optionsTarget: optionsInstanceId !== "" && optionsInstanceId === selectedInstanceId ? editLayer.itemById(optionsInstanceId) : null
|
|
|
|
signal finished
|
|
|
|
onSelectedInstanceIdChanged: {
|
|
if (selectedInstanceId !== optionsInstanceId)
|
|
optionsInstanceId = "";
|
|
}
|
|
|
|
function closeLibrary() {
|
|
libraryOpen = false;
|
|
forceActiveFocus();
|
|
}
|
|
|
|
function showOptions(instanceId) {
|
|
if (optionsInstanceId === instanceId) {
|
|
closeOptions();
|
|
return;
|
|
}
|
|
optionsInstanceId = instanceId;
|
|
editLayer.selectedInstanceId = instanceId;
|
|
}
|
|
|
|
function closeOptions() {
|
|
const target = optionsTarget;
|
|
optionsInstanceId = "";
|
|
target?.forceActiveFocus();
|
|
}
|
|
|
|
function addWidget(widgetType) {
|
|
const def = DesktopWidgetRegistry.getWidget(widgetType);
|
|
const instance = SettingsData.createDesktopWidgetInstance(widgetType, def?.name ?? widgetType, DesktopWidgetRegistry.getDefaultConfig(widgetType), editLayer.listKey);
|
|
editLayer.pendingIds = editLayer.pendingIds.concat([instance.id]);
|
|
}
|
|
|
|
function resetLayout() {
|
|
if (greeter) {
|
|
SettingsData.resetGreeterWidgets();
|
|
return;
|
|
}
|
|
if (lockScreen) {
|
|
SettingsData.resetLockScreenWidgets();
|
|
return;
|
|
}
|
|
for (const instance of SettingsData.desktopWidgetInstances || [])
|
|
SessionData.resetDesktopWidgetInstanceGeometry(instance.id, ["x", "y", "width", "height"]);
|
|
}
|
|
|
|
function dismiss() {
|
|
if (optionsTarget) {
|
|
closeOptions();
|
|
return;
|
|
}
|
|
if (editControls.pendingAction !== "") {
|
|
editControls.cancelConfirmation();
|
|
return;
|
|
}
|
|
if (libraryOpen) {
|
|
closeLibrary();
|
|
return;
|
|
}
|
|
finished();
|
|
}
|
|
|
|
focus: true
|
|
Component.onCompleted: {
|
|
libraryOpen = DesktopWidgetRegistry.libraryScreen === editLayer.screenName;
|
|
forceActiveFocus();
|
|
if (!lockScreen && DesktopWidgetRegistry.optionsScreen === editLayer.screenName)
|
|
showOptions(DesktopWidgetRegistry.optionsInstanceId);
|
|
}
|
|
Keys.onEscapePressed: event => {
|
|
if (PopoutManager.screenshotActive) {
|
|
event.accepted = false;
|
|
return;
|
|
}
|
|
dismiss();
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
visible: root.libraryOpen
|
|
acceptedButtons: Qt.AllButtons
|
|
onClicked: root.closeLibrary()
|
|
}
|
|
|
|
Loader {
|
|
anchors.centerIn: parent
|
|
active: root.libraryOpen
|
|
|
|
sourceComponent: CcWidgetLibrary {
|
|
width: Math.min(implicitWidth, root.width - Theme.spacingL * 2)
|
|
height: Math.min(implicitHeight, root.height - Theme.spacingL * 2)
|
|
widgets: root.libraryWidgets
|
|
Component.onCompleted: reset()
|
|
onChosen: widgetId => {
|
|
root.addWidget(widgetId);
|
|
root.closeLibrary();
|
|
}
|
|
onDismissed: root.closeLibrary()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
visible: root.surfaceLabel !== "" && fabBar.shown
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: fabBar.reservedHeight + Theme.spacingL + (gridHint.visible ? gridHint.height + Theme.spacingS : 0)
|
|
width: surfaceRow.implicitWidth + Theme.spacingL * 2
|
|
height: Theme.buttonHeightM
|
|
radius: Theme.fullRadius(width, height)
|
|
color: Theme.readableSurface
|
|
border.width: Theme.layerOutlineWidth
|
|
border.color: Theme.outlineMedium
|
|
|
|
Row {
|
|
id: surfaceRow
|
|
anchors.centerIn: parent
|
|
spacing: Theme.spacingS
|
|
|
|
DIcon {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
name: root.greeter ? "login" : "lock"
|
|
size: Theme.iconSizeMedium
|
|
color: Theme.primary
|
|
}
|
|
|
|
StyledText {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: root.surfaceLabel
|
|
font.pixelSize: Theme.fontSizeMedium
|
|
font.weight: Theme.fontWeightMedium
|
|
color: Theme.surfaceText
|
|
}
|
|
}
|
|
}
|
|
|
|
DesktopWidgetGridHint {
|
|
id: gridHint
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: fabBar.reservedHeight + Theme.spacingL
|
|
visible: fabBar.shown && (root.editLayer.selectedInstanceId !== "" || root.editLayer.interactingItem !== null)
|
|
gridEnabled: root.editLayer.gridEnabled
|
|
gridSize: root.editLayer.gridSize
|
|
}
|
|
|
|
SettingsFabBar {
|
|
id: fabBar
|
|
shown: !root.libraryOpen
|
|
|
|
DashEditControls {
|
|
id: editControls
|
|
canClear: false
|
|
onAddRequested: {
|
|
root.optionsInstanceId = "";
|
|
root.libraryOpen = true;
|
|
}
|
|
onResetRequested: root.resetLayout()
|
|
onFinished: root.finished()
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
active: root.optionsTarget !== null
|
|
|
|
sourceComponent: FocusScope {
|
|
id: panel
|
|
|
|
readonly property Item target: root.optionsTarget
|
|
readonly property var instanceData: SettingsData.getDesktopWidgetInstance(root.optionsInstanceId)
|
|
readonly property var widgetDef: DesktopWidgetRegistry.getWidget(instanceData?.widgetType ?? "")
|
|
readonly property real margin: Theme.spacingL
|
|
readonly property real padding: PopoutMetrics.contentPadding
|
|
readonly property real focusPadding: SettingsMetrics.focusGutter
|
|
readonly property real bottomLimit: root.height - root.fabReserved - margin
|
|
readonly property real gap: (target?.chromeOutset ?? 0) + Theme.spacingS
|
|
readonly property real afterEdge: (target?.x ?? 0) + (target?.width ?? 0) + gap
|
|
readonly property real beforeEdge: (target?.x ?? 0) - gap
|
|
readonly property real afterRoom: root.width - margin - afterEdge
|
|
readonly property real beforeRoom: beforeEdge - margin
|
|
readonly property real maxWidth: Math.min(Theme.dialogMaxWidth, root.width - margin * 2)
|
|
readonly property real minWidth: Math.min(SettingsMetrics.windowMinWidth, maxWidth)
|
|
readonly property real firstRoom: I18n.isRtl ? beforeRoom : afterRoom
|
|
readonly property real secondRoom: I18n.isRtl ? afterRoom : beforeRoom
|
|
readonly property bool onAfter: (firstRoom >= minWidth || firstRoom >= secondRoom) !== I18n.isRtl
|
|
readonly property Item windowFocusItem: Window.activeFocusItem
|
|
|
|
x: Math.max(margin, Math.min(root.width - margin - width, onAfter ? afterEdge : beforeEdge - width))
|
|
y: Math.max(margin, Math.min(bottomLimit - height, target?.y ?? 0))
|
|
width: Math.min(maxWidth, Math.max(minWidth, onAfter ? afterRoom : beforeRoom))
|
|
height: Math.min(bottomLimit - margin, header.height + PopoutMetrics.contentGap + settings.implicitHeight + padding * 2)
|
|
focus: true
|
|
LayoutMirroring.enabled: I18n.isRtl
|
|
LayoutMirroring.childrenInherit: true
|
|
Accessible.role: Accessible.Dialog
|
|
Accessible.name: header.title
|
|
Component.onCompleted: forceActiveFocus()
|
|
|
|
onWindowFocusItemChanged: {
|
|
const item = windowFocusItem;
|
|
if (!item || !FocusNavigation.containsFocus(settings))
|
|
return;
|
|
const top = item.mapToItem(scroll.contentItem, 0, 0).y;
|
|
scroll.revealRange(top - focusPadding, top + item.height + focusPadding);
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
radius: Theme.windowRadius
|
|
color: Theme.cardSurface
|
|
border.width: Theme.layerOutlineWidth
|
|
border.color: Theme.outlineMedium
|
|
|
|
ElevationShadow {
|
|
anchors.fill: parent
|
|
z: -1
|
|
level: Theme.elevationLevel2
|
|
targetRadius: parent.radius
|
|
targetColor: "transparent"
|
|
shadowEnabled: Theme.elevationEnabled
|
|
}
|
|
|
|
// Presses and hover that miss a control would reach the widgets and the deselect area below.
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.AllButtons
|
|
hoverEnabled: true
|
|
cursorShape: Qt.ArrowCursor
|
|
}
|
|
}
|
|
|
|
DWindowHeader {
|
|
id: header
|
|
x: panel.padding
|
|
y: panel.padding
|
|
width: parent.width - panel.padding * 2
|
|
controls: null
|
|
horizontalPadding: 0
|
|
verticalPadding: 0
|
|
title: panel.instanceData?.name || panel.widgetDef?.name || ""
|
|
onCloseRequested: root.closeOptions()
|
|
}
|
|
|
|
DFlickable {
|
|
id: scroll
|
|
x: panel.padding - panel.focusPadding
|
|
y: header.y + header.height + PopoutMetrics.contentGap - panel.focusPadding
|
|
width: parent.width - x * 2
|
|
height: Math.max(0, parent.height - y - panel.padding + panel.focusPadding)
|
|
contentWidth: width
|
|
contentHeight: settings.implicitHeight + panel.focusPadding * 2
|
|
clip: true
|
|
|
|
DesktopWidgetTypeSettings {
|
|
id: settings
|
|
x: panel.focusPadding
|
|
y: panel.focusPadding
|
|
width: scroll.width - panel.focusPadding * 2
|
|
instanceId: root.optionsInstanceId
|
|
instanceData: panel.instanceData
|
|
widgetDef: panel.widgetDef
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|