summaryrefslogtreecommitdiff
path: root/bar/ActiveWindow.qml
blob: 17d2322b5f12062d2928ca773ff10a2166f3cfb8 (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
        }
    }
}