mirror of
https://github.com/end-4/dots-hyprland.git
synced 2026-06-05 23:09:26 -05:00
140 lines
4.3 KiB
QML
140 lines
4.3 KiB
QML
import QtQuick
|
|
import QtQuick.Layouts
|
|
import qs.services
|
|
import qs.modules.common
|
|
import qs.modules.common.functions
|
|
import qs.modules.waffle.looks
|
|
import qs.modules.waffle.bar
|
|
import Quickshell
|
|
|
|
AppButton {
|
|
id: root
|
|
|
|
required property var appEntry
|
|
readonly property bool isSeparator: appEntry.appId === "SEPARATOR"
|
|
property var desktopEntry: DesktopEntries.heuristicLookup(appEntry.appId)
|
|
|
|
Timer {
|
|
// Retry looking up the desktop entry if it failed (e.g. database not loaded yet)
|
|
property int retryCount: 5
|
|
interval: 1000
|
|
running: !root.isSeparator && root.desktopEntry === null && retryCount > 0
|
|
repeat: true
|
|
onTriggered: {
|
|
retryCount--;
|
|
root.desktopEntry = DesktopEntries.heuristicLookup(root.appEntry.appId);
|
|
}
|
|
}
|
|
|
|
property bool active: root.appEntry.toplevels.some(t => t.activated)
|
|
property bool hasWindows: appEntry.toplevels.length > 0
|
|
|
|
signal hoverPreviewRequested()
|
|
signal hoverPreviewDismissed()
|
|
|
|
multiple: appEntry.toplevels.length > 1
|
|
checked: active
|
|
iconName: AppSearch.guessIcon(appEntry.appId)
|
|
tryCustomIcon: false
|
|
|
|
onHoverTimedOut: {
|
|
root.hoverPreviewRequested()
|
|
}
|
|
|
|
onClicked: {
|
|
root.hoverTimer.stop() // Prevents preview showing up when clicking to focus
|
|
if (root.multiple) {
|
|
root.hoverPreviewRequested()
|
|
} else if (root.appEntry.toplevels.length === 1) {
|
|
root.appEntry.toplevels[0].activate()
|
|
} else {
|
|
root.desktopEntry.execute()
|
|
}
|
|
}
|
|
|
|
middleClickAction: () => {
|
|
if (root.desktopEntry) {
|
|
desktopEntry.execute()
|
|
}
|
|
}
|
|
|
|
altAction: () => {
|
|
root.hoverPreviewDismissed()
|
|
root.hoverTimer.stop()
|
|
contextMenu.active = true;
|
|
}
|
|
|
|
// Active indicator
|
|
Rectangle {
|
|
id: activeIndicator
|
|
opacity: root.hasWindows ? 1 : 0
|
|
anchors {
|
|
horizontalCenter: root.background.horizontalCenter
|
|
bottom: root.background.bottom
|
|
bottomMargin: 1
|
|
}
|
|
|
|
implicitWidth: root.active ? 16 : 6
|
|
implicitHeight: 3
|
|
radius: height / 2
|
|
|
|
color: root.active ? Looks.colors.accent : Looks.colors.accentUnfocused
|
|
|
|
Behavior on implicitWidth {
|
|
animation: Looks.transition.enter.createObject(this)
|
|
}
|
|
Behavior on color {
|
|
animation: Looks.transition.color.createObject(this)
|
|
}
|
|
Behavior on opacity {
|
|
animation: Looks.transition.opacity.createObject(this)
|
|
}
|
|
}
|
|
|
|
BarToolTip {
|
|
extraVisibleCondition: root.shouldShowTooltip && !root.hasWindows
|
|
text: desktopEntry ? desktopEntry.name : appEntry.appId
|
|
}
|
|
|
|
BarMenu {
|
|
id: contextMenu
|
|
noSmoothClosing: false // On the real thing this is always smooth
|
|
|
|
model: [
|
|
...((root.desktopEntry?.actions.length > 0) ? root.desktopEntry.actions.map(action =>({
|
|
iconName: action.icon,
|
|
text: action.name,
|
|
action: () => {
|
|
action.execute()
|
|
}
|
|
})).concat({ type: "separator" }) : []),
|
|
{
|
|
iconName: root.iconName,
|
|
text: root.desktopEntry ? root.desktopEntry.name : StringUtils.toTitleCase(appEntry.appId),
|
|
monochromeIcon: false,
|
|
action: () => {
|
|
if (root.desktopEntry) {
|
|
root.desktopEntry.execute()
|
|
}
|
|
}
|
|
},
|
|
{
|
|
iconName: root.appEntry.pinned ? "pin-off" : "pin",
|
|
text: root.appEntry.pinned ? Translation.tr("Unpin from taskbar") : Translation.tr("Pin to taskbar"),
|
|
action: () => {
|
|
TaskbarApps.togglePin(root.appEntry.appId);
|
|
}
|
|
},
|
|
...(root.appEntry.toplevels.length > 0 ? [{
|
|
iconName: "dismiss",
|
|
text: root.multiple ? Translation.tr("Close all windows") : Translation.tr("Close window"),
|
|
action: () => {
|
|
for (let toplevel of root.appEntry.toplevels) {
|
|
toplevel.close();
|
|
}
|
|
}
|
|
}] : []),
|
|
]
|
|
}
|
|
}
|