feat: added widgets capture, music visualiser, bluetooth, notes
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: win
|
||||
|
||||
property var panel: null
|
||||
property string widgetId: ""
|
||||
property string title: ""
|
||||
property string icon: ""
|
||||
property real widgetWidth: 360
|
||||
property real widgetHeight: 320
|
||||
property real minimumY: 0
|
||||
property bool shown: false
|
||||
property Component contentComponent: null
|
||||
|
||||
readonly property real margin: panel ? panel.edgeMargin : 12
|
||||
readonly property real panelWidth: panel ? panel.width : 0
|
||||
readonly property real panelHeight: panel ? panel.height : 0
|
||||
readonly property string screenKey: panel ? panel.screenKey : ""
|
||||
// Which monitor the current x/y were resolved for; guards against saving a
|
||||
// position under a screen it was never arranged on.
|
||||
property string appliedKey: ""
|
||||
readonly property real maxX: Math.max(margin, (panel ? panel.width : width) - width - margin)
|
||||
readonly property real maxY: Math.max(minimumY, (panel ? panel.height : height) - height - margin)
|
||||
|
||||
function clampX(value) {
|
||||
return Math.max(margin, Math.min(maxX, value));
|
||||
}
|
||||
|
||||
function clampY(value) {
|
||||
return Math.max(minimumY, Math.min(maxY, value));
|
||||
}
|
||||
|
||||
// Each monitor keeps its own absolute arrangement, so moving between a 4K
|
||||
// and a 1440p screen restores what was arranged there rather than a scaled
|
||||
// copy of the other one.
|
||||
function applyStoredPosition() {
|
||||
if (!panel || panel.width <= 0 || panel.height <= 0)
|
||||
return;
|
||||
|
||||
const stored = panel.widgetPosition(win.widgetId);
|
||||
win.x = win.clampX(stored.x);
|
||||
win.y = win.clampY(stored.y);
|
||||
win.appliedKey = win.screenKey;
|
||||
}
|
||||
|
||||
function raise() {
|
||||
if (panel)
|
||||
win.z = panel.nextWindowZ();
|
||||
}
|
||||
|
||||
function storePosition() {
|
||||
if (!panel || panel.width <= 0 || panel.height <= 0)
|
||||
return;
|
||||
|
||||
// Mid-transition to another monitor: the position on screen does not
|
||||
// belong to the new screen yet.
|
||||
if (win.screenKey === "" || win.screenKey !== win.appliedKey)
|
||||
return;
|
||||
|
||||
panel.saveWidgetPosition(win.widgetId, win.x, win.y);
|
||||
}
|
||||
|
||||
width: widgetWidth
|
||||
height: widgetHeight
|
||||
visible: shown && opacity > 0
|
||||
opacity: shown ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: win.applyStoredPosition()
|
||||
onShownChanged: {
|
||||
if (shown) {
|
||||
win.applyStoredPosition();
|
||||
win.raise();
|
||||
}
|
||||
}
|
||||
// The panel has neither size nor a resolved screen while the delegate is
|
||||
// created, and the two settle independently - the screen can change without
|
||||
// a resize (same resolution) and vice versa, so react to both.
|
||||
onPanelWidthChanged: win.applyStoredPosition()
|
||||
onPanelHeightChanged: win.applyStoredPosition()
|
||||
onScreenKeyChanged: win.applyStoredPosition()
|
||||
|
||||
Rectangle {
|
||||
id: frame
|
||||
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius * 1.25
|
||||
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||
border.color: dragArea.pressed ? Theme.primary : Theme.outlineMedium
|
||||
border.width: dragArea.pressed ? 2 : Theme.layerOutlineWidth
|
||||
|
||||
Rectangle {
|
||||
id: titleBar
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 38
|
||||
radius: frame.radius
|
||||
color: dragArea.containsMouse ? Theme.surfaceContainerHigh : "transparent"
|
||||
|
||||
// Square off the bottom corners so the title bar blends into the body.
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: parent.radius
|
||||
color: parent.color
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: titleIcon
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: win.icon
|
||||
size: Theme.iconSize - 6
|
||||
color: Theme.primary
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.left: titleIcon.right
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.right: closeButton.left
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: win.title
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: closeButton
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
iconName: "close"
|
||||
buttonSize: 26
|
||||
iconSize: 15
|
||||
iconColor: Theme.surfaceVariantText
|
||||
onClicked: {
|
||||
if (win.panel)
|
||||
win.panel.toggleWidget(win.widgetId);
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: dragArea
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: closeButton.left
|
||||
hoverEnabled: true
|
||||
cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor
|
||||
drag.target: win
|
||||
drag.axis: Drag.XAndYAxis
|
||||
drag.minimumX: win.margin
|
||||
drag.maximumX: win.maxX
|
||||
drag.minimumY: win.minimumY
|
||||
drag.maximumY: win.maxY
|
||||
drag.threshold: 0
|
||||
onPressed: win.raise()
|
||||
onReleased: win.storePosition()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.AllButtons
|
||||
propagateComposedEvents: true
|
||||
z: -1
|
||||
onPressed: mouse => {
|
||||
win.raise();
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.top: titleBar.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.bottomMargin: Theme.spacingM
|
||||
active: win.shown
|
||||
sourceComponent: win.contentComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user