summaryrefslogtreecommitdiff
path: root/bar/ActiveWindow.qml
blob: 0a6a54749427f9fea718604ab3e3ff24568fdfcd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import Quickshell.Widgets

import qs.components
import qs.services
import qs.config

// TODO use a item wrapping loader for opacity Behavior
IRect {
	id: root
	// hyprland toplevel isn't shown immediately...
	property var toplevel: ToplevelManager.activeToplevel
	property var icon: Quickshell.iconPath(AppSearch.guessIcon(toplevel?.appId), "image-missing")

	property var activated: toplevel?.activated || false

	implicitWidth: activated ? rowLayout.implicitWidth + General.rectMargin * 4 : 0
	implicitHeight: rowLayout.implicitHeight + General.rectMargin * 2 + Bar.topMargin * 2
	anchors.centerIn: parent

	color: Qt.rgba(Colors.background3.r, Colors.background3.g, Colors.background3.b, Bar.bgTransparency)
	// according to docs, null could happen but doesn't seem to happen in practice so..
	// hypr toplevel.activated is always true and doesn't change either so..
	opacity: activated ? 1 : 0

	bottomLeftRadius: Bar.moduleRadius
	bottomRightRadius: Bar.moduleRadius

	function strip(s) {
		var out = s;
		Bar.windowStrip.forEach(function (w) {
			out = out?.replace(new RegExp(w, "g"), "");
		});
		return out?.trim() || s;
	}

	RowLayout {
		id: rowLayout
		anchors.centerIn: parent
		spacing: Bar.resourceIconTextSpacing
		width: Math.min(implicitWidth, root.width)

		IconImage {
			id: icon
			source: root.icon
			implicitSize: General.appIconSize

			// sync animation
			opacity: root.activated ? 1 : 0
			Behavior on opacity {
				NumberAnimation {
					duration: General.animationDuration / 4
				}
			}
		}

		Item {
			Layout.fillWidth: true
			Layout.fillHeight: true
			implicitWidth: childrenRect.width
			IText {
				anchors.verticalCenter: parent.verticalCenter
				width: Math.min(implicitWidth, rowLayout.width - icon.implicitWidth)
				animate: true
				clip: true
				elide: Text.ElideRight
				font.pixelSize: General.fontSize
				text: strip(root?.toplevel?.title) || ""

				// sync animation
				opacity: root.activated ? 1 : 0
				Behavior on opacity {
					NumberAnimation {
						duration: General.animationDuration / 4
					}
				}
			}
		}
	}

	onIconChanged: fadeIcon.start()

	Behavior on opacity {
		NumberAnimation {
			duration: General.animationDuration / 4
		}
	}

	Behavior on width {
		ISpringAnimation {
			spring: General.springAnimationSpring * 2
			damping: General.springAnimationDamping * 1.3
		}
	}

	SequentialAnimation {
		id: fadeIcon
		running: false

		PropertyAnimation {
			target: icon
			property: "opacity"
			to: 0
			duration: General.animationDuration / 4
		}
		ScriptAction {
			script: icon.source = root.icon
		}
		PropertyAnimation {
			target: icon
			property: "opacity"
			to: 1
			duration: General.animationDuration / 4
		}
		ScriptAction {
			script: icon.source = root.icon
		}
	}
}