130 lines
4.2 KiB
QML
130 lines
4.2 KiB
QML
// One global place to set windows aside. Empty, it is a quiet drop target;
|
|
// populated, it expands into a compact row of restorable window cards.
|
|
|
|
import QtQuick
|
|
import qs.config
|
|
|
|
Item {
|
|
id: root
|
|
|
|
required property var workspace
|
|
property int refreshToken: 0
|
|
|
|
signal windowDropped(var toplevel)
|
|
signal restoreRequested(var toplevel)
|
|
signal closeRequested(var toplevel)
|
|
|
|
readonly property var windows: root.workspace?.toplevels?.values ?? []
|
|
readonly property bool populated: root.windows.length > 0
|
|
|
|
implicitHeight: root.populated ? 112 : 42
|
|
|
|
Rectangle {
|
|
id: surface
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.bottom: parent.bottom
|
|
width: root.populated
|
|
? Math.min(parent.width, Math.max(360, root.windows.length * 198 + 28))
|
|
: 292
|
|
height: root.populated ? 112 : 42
|
|
radius: root.populated ? Theme.popoverRadius : Theme.pillRadius
|
|
border.width: 1
|
|
border.color: dropArea.containsDrag ? Theme.ok : Theme.alpha(Theme.fg, root.populated ? 0.1 : 0.08)
|
|
color: Theme.alpha(Theme.bgPopover, root.populated ? 0.76 : 0.42)
|
|
|
|
Behavior on width {
|
|
NumberAnimation { duration: Theme.durNormal; easing.type: Easing.OutCubic }
|
|
}
|
|
Behavior on height {
|
|
NumberAnimation { duration: Theme.durNormal; easing.type: Easing.OutCubic }
|
|
}
|
|
Behavior on border.color {
|
|
ColorAnimation { duration: Theme.durFast }
|
|
}
|
|
|
|
Row {
|
|
anchors.centerIn: parent
|
|
visible: !root.populated
|
|
spacing: 8
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: dropArea.containsDrag ? "\u{F04E7}" : "\u{F02D4}"
|
|
color: dropArea.containsDrag ? Theme.ok : Theme.fgDim
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 15
|
|
}
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: dropArea.containsDrag ? "Release to set aside" : "Drop to Scratchpad"
|
|
color: dropArea.containsDrag ? Theme.fg : Theme.fgDim
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSize
|
|
font.weight: Font.Medium
|
|
}
|
|
}
|
|
|
|
Text {
|
|
id: heading
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 14
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 9
|
|
visible: root.populated
|
|
text: "Scratchpad · " + root.windows.length
|
|
color: Theme.fgDim
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.weight: Font.DemiBold
|
|
}
|
|
|
|
Flickable {
|
|
id: windowStrip
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
anchors.leftMargin: 12
|
|
anchors.rightMargin: 12
|
|
anchors.bottomMargin: 8
|
|
height: 76
|
|
visible: root.populated
|
|
clip: true
|
|
contentWidth: Math.max(width, cards.implicitWidth)
|
|
contentHeight: height
|
|
boundsBehavior: Flickable.StopAtBounds
|
|
|
|
Row {
|
|
id: cards
|
|
spacing: Theme.itemSpacing
|
|
|
|
Repeater {
|
|
model: root.windows
|
|
|
|
WindowThumbnail {
|
|
required property var modelData
|
|
toplevel: modelData
|
|
refreshToken: root.refreshToken
|
|
width: 190
|
|
height: 76
|
|
onActivated: root.restoreRequested(modelData)
|
|
onCloseRequested: root.closeRequested(modelData)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DropArea {
|
|
id: dropArea
|
|
anchors.fill: parent
|
|
z: 5
|
|
onDropped: drop => {
|
|
if (!drop.source?.toplevel)
|
|
return;
|
|
root.windowDropped(drop.source.toplevel);
|
|
drop.acceptProposedAction();
|
|
}
|
|
}
|
|
}
|
|
}
|