waffles: overview: more proper anims and dragging functionality

ITS FUCKING WORKING AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
This commit is contained in:
end-4
2025-12-14 23:40:32 +01:00
parent f1fdb941e1
commit 663eb1896a
5 changed files with 168 additions and 43 deletions
@@ -16,29 +16,43 @@ Rectangle {
id: root
color: ColorUtils.transparentize(Looks.colors.bg1Base, 0.5)
property bool draggingWindow: false
property real openProgress: 0
property Item hoveredWorkspace: null
signal closed
Component.onCompleted: {
openAnim.start();
}
function close() {
closeAnim.start();
}
PropertyAnimation {
id: openAnim
target: root
property: "openProgress"
to: 1
duration: 200
duration: 250
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
}
PropertyAnimation {
SequentialAnimation {
id: closeAnim
target: root
property: "openProgress"
to: 0
duration: 200
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
PropertyAnimation {
target: root
property: "openProgress"
to: 0
duration: 200
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
}
ScriptAction {
script: {
root.closed();
}
}
}
// Windows
@@ -81,8 +95,18 @@ Rectangle {
return resultLayout;
}
MouseArea {
z: 0
anchors.fill: parent
onClicked: {
GlobalStates.overviewOpen = false;
}
}
// Windows
WListView {
id: windowListView
z: root.openProgress == 1 ? 2 : 1
anchors {
left: parent.left
right: parent.right
@@ -96,9 +120,8 @@ Rectangle {
rightMargin: root.padding
height: Math.min(contentHeight + topMargin + bottomMargin, root.height - (wsBorder.height + 16))
interactive: height < contentHeight
clip: true
interactive: (height < contentHeight) && !root.draggingWindow
clip: root.openProgress > 0.99 && !root.draggingWindow
model: ScriptModel {
values: root.arrangedToplevels
@@ -107,7 +130,7 @@ Rectangle {
id: clientRow
required property var modelData
spacing: root.spacing
anchors.horizontalCenter: parent.horizontalCenter
anchors.horizontalCenter: parent?.horizontalCenter ?? undefined
Repeater {
model: ScriptModel {
@@ -117,24 +140,61 @@ Rectangle {
id: clientGridArea
required property int index
required property var modelData
implicitWidth: windowItem.implicitWidth
implicitHeight: windowItem.implicitHeight
implicitWidth: windowItem.openedSize.width
implicitHeight: windowItem.openedSize.height + windowItem.titleBarImplicitHeight
TaskViewWindow {
id: windowItem
z: 9999
drag {
target: this
z: Drag.active ? 2 : 1
opacity: openAnim.running ? root.openProgress : 1
property int mappedX: {
// print("AAAWAWAAWAWWA: ", -(clientRow.x + clientGridArea.x + root.padding));
var rootPosToThis = -(clientRow.x + clientGridArea.x + root.padding);
return rootPosToThis + hyprlandClient.at[0];
}
property int mappedY: {
// print("AAAWAWAAWAWWA YYYY YUIUSDFOIU: ", clientRow.y + windowListView.y + root.padding + windowItem.titleBarImplicitHeight)
var rootPosToThis = -(clientRow.y + windowListView.y + root.padding + windowItem.titleBarImplicitHeight);
return rootPosToThis + hyprlandClient.at[1];
}
property int openedX: 0
property int openedY: 0
// property int openedX: Drag.active ? (dragHandler.xAxis.activeValue) : 0
// property int openedY: Drag.active ? (dragHandler.yAxis.activeValue) : 0
scaleSize: (root.openProgress > 0 && !closeAnim.running)
x: mappedX + (openedX - mappedX) * root.openProgress
y: mappedY + (openedY - mappedY) * root.openProgress
droppable: root.hoveredWorkspace !== null
Drag.active: dragHandler.active
Drag.hotSpot.x: mouseX
Drag.hotSpot.y: mouseY
DragHandler {
id: dragHandler
target: null
xAxis.onActiveValueChanged: {
windowItem.openedX = dragHandler.xAxis.activeValue;
}
yAxis.onActiveValueChanged: {
windowItem.openedY = dragHandler.yAxis.activeValue;
}
onActiveChanged: {
if (drag.active) {
parent = root;
if (active) {
root.draggingWindow = true;
} else {
parent = clientGridArea;
x = 0;
y = 0;
root.draggingWindow = false;
if (root.hoveredWorkspace !== null && root.hoveredWorkspace.workspace !== windowItem.hyprlandClient.workspace.id) {
Hyprland.dispatch(`movetoworkspacesilent ${root.hoveredWorkspace.workspace}, address:${windowItem.hyprlandClient.address}`);
} else {
windowItem.openedX = 0;
windowItem.openedY = 0;
}
}
}
}
Layout.alignment: Qt.AlignTop
maxHeight: root.maxWindowHeight
maxWidth: root.maxWindowWidth
@@ -148,6 +208,7 @@ Rectangle {
// Workspaces
Rectangle {
id: wsBorder
z: root.openProgress == 1 ? 1 : 2
property real sourceEdgeMargin: -(height + 8) + root.openProgress * (height + 16)
anchors {
left: parent.left
@@ -210,9 +271,29 @@ Rectangle {
}
}
delegate: TaskViewWorkspace {
id: workspaceItem
required property int index
workspace: index + 1
newWorkspace: index == workspaceIndexModel.count - 1
droppable: root.hoveredWorkspace === workspaceItem
DropArea {
anchors.fill: parent
onEntered: drag => {
root.hoveredWorkspace = workspaceItem;
}
onExited: {
if (root.hoveredWorkspace === workspaceItem) {
root.hoveredWorkspace = null;
}
}
}
onClicked: {
GlobalStates.overviewOpen = false;
root.closed(); // Close immediately to avoid weird animations
Hyprland.dispatch(`workspace ${workspaceItem.workspace}`);
}
}
}
}
@@ -25,47 +25,60 @@ WMouseAreaButton {
property string iconName: AppSearch.guessIcon(hyprlandClient?.class)
color: containsMouse ? Looks.colors.bg1Base : Looks.colors.bgPanelFooterBase
borderColor: Looks.colors.bg2Border
color: drag.active ? ColorUtils.transparentize(Looks.colors.bg1Base) : (containsMouse ? Looks.colors.bg1Base : Looks.colors.bgPanelFooterBase)
borderColor: ColorUtils.transparentize(Looks.colors.bg2Border, drag.active ? 1 : 0)
radius: Looks.radius.xLarge
property size size: WindowLayout.scaleWindow(hyprlandClient, maxWidth, maxHeight)
property real titleBarImplicitHeight: titleBar.implicitHeight
property bool scaleSize: true
property size openedSize: WindowLayout.scaleWindow(hyprlandClient, maxWidth, maxHeight);
property size fullSize: Qt.size(hyprlandClient?.size[0] ?? maxWidth, hyprlandClient?.size[1] ?? maxHeight)
property size size: scaleSize ? openedSize : fullSize
implicitWidth: Math.max(Math.round(contentItem.implicitWidth), 138)
implicitHeight: Math.round(contentItem.implicitHeight)
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
maskSource: Item {
width: root.background.width
height: root.background.height
radius: root.background.radius
Rectangle {
radius: root.background.radius
anchors {
fill: parent
topMargin: root.drag.active ? root.titleBarImplicitHeight : 0
}
}
}
}
scale: (root.pressedButtons & Qt.LeftButton) ? 0.95 : 1
property bool droppable: false
scale: (root.pressedButtons & Qt.LeftButton || root.Drag.active) ? (droppable ? 0.4 : 0.95) : 1
Behavior on scale {
NumberAnimation {
id: scaleAnim
duration: 300
duration: 200
easing.type: Easing.OutExpo
}
}
function closeWindow() {
Hyprland.dispatch(`closewindow address:${root.hyprlandClient?.address}`)
Hyprland.dispatch(`closewindow address:${root.hyprlandClient?.address}`);
}
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
onClicked: (event) => {
onClicked: event => {
if (event.button === Qt.LeftButton) {
GlobalStates.overviewOpen = false
Hyprland.dispatch(`focuswindow address:${root.hyprlandClient?.address}`)
GlobalStates.overviewOpen = false;
Hyprland.dispatch(`focuswindow address:${root.hyprlandClient?.address}`);
GlobalStates.overviewOpen = false;
} else if (event.button === Qt.MiddleButton) {
root.closeWindow();
event.accepted = true;
} else if (event.button === Qt.RightButton) {
if (!windowMenu.visible) windowMenu.popup();
else windowMenu.close();
if (!windowMenu.visible)
windowMenu.popup();
else
windowMenu.close();
}
}
@@ -77,6 +90,8 @@ WMouseAreaButton {
spacing: 0
RowLayout {
id: titleBar
opacity: root.drag.active ? 0 : 1
spacing: 8
WAppIcon {
Layout.leftMargin: 10
@@ -104,6 +119,14 @@ WMouseAreaButton {
Layout.alignment: Qt.AlignHCenter
implicitWidth: Math.round(root.size.width)
implicitHeight: Math.round(root.size.height)
constraintSize: Qt.size(Math.round(root.size.width), Math.round(root.size.height))
Behavior on implicitWidth {
animation: Looks.transition.enter.createObject(this)
}
Behavior on implicitHeight {
animation: Looks.transition.enter.createObject(this)
}
captureSource: root.toplevel ?? null
live: true
@@ -120,7 +143,7 @@ WMouseAreaButton {
icon.name: isPinned ? "checkmark" : "empty"
text: Translation.tr("Show this window on all desktops")
onTriggered: {
Hyprland.dispatch(`pin address:${root.hyprlandClient?.address}`)
Hyprland.dispatch(`pin address:${root.hyprlandClient?.address}`);
}
}
Action {
@@ -16,6 +16,7 @@ WMouseAreaButton {
required property int workspace
property bool newWorkspace: false
property bool droppable: false
readonly property bool isActiveWorkspace: HyprlandData.activeWorkspace?.id === root.workspace
readonly property real screenWidth: QsWindow.window?.width ?? 0
@@ -28,12 +29,7 @@ WMouseAreaButton {
height: ListView.view?.height ?? 100
implicitWidth: 244 // for now
onClicked: {
GlobalStates.overviewOpen = false;
Hyprland.dispatch(`workspace ${root.workspace}`);
}
colBackground: ColorUtils.transparentize(Looks.colors.bg2, isActiveWorkspace ? 0 : 1)
colBackground: ColorUtils.transparentize(Looks.colors.bg2, (isActiveWorkspace || droppable) ? 0 : 1)
Behavior on color {
animation: Looks.transition.color.createObject(this)
}
@@ -119,6 +115,14 @@ WMouseAreaButton {
icon: "add"
}
}
Rectangle {
z: 2
visible: root.droppable && !root.newWorkspace
anchors.fill: parent
color: Looks.colors.accent
opacity: 0.2
}
}
}
@@ -23,7 +23,14 @@ Scope {
Loader {
id: panelLoader
required property var modelData
active: GlobalStates.overviewOpen
active: false
Connections {
target: GlobalStates
function onOverviewOpenChanged() {
if (GlobalStates.overviewOpen)
panelLoader.active = true;
}
}
sourceComponent: PanelWindow {
id: root
property string searchingText: ""
@@ -44,7 +51,16 @@ Scope {
}
TaskViewContent {
id: taskViewContent
anchors.fill: parent
Connections {
target: GlobalStates
function onOverviewOpenChanged() {
if (!GlobalStates.overviewOpen) taskViewContent.close();
}
}
onClosed: panelLoader.active = false;
}
}
}
@@ -88,6 +88,7 @@ Singleton {
function onRawEvent(event) {
// console.log("Hyprland raw event:", event.name);
if (["openlayer", "closelayer", "screencast"].includes(event.name)) return;
updateAll()
}
}