forked from Shinonome/dots-hyprland
wbar: add tooltip and stuff
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
import qs.modules.common.widgets
|
import qs.modules.common.widgets
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -13,15 +14,24 @@ Item {
|
|||||||
property real horizontalPadding: 10
|
property real horizontalPadding: 10
|
||||||
property real verticalPadding: 5
|
property real verticalPadding: 5
|
||||||
|
|
||||||
|
readonly property bool internalVisibleCondition: (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition
|
||||||
property var anchorEdges: Edges.Top
|
property var anchorEdges: Edges.Top
|
||||||
property var anchorGravity: anchorEdges
|
property var anchorGravity: anchorEdges
|
||||||
|
|
||||||
readonly property bool internalVisibleCondition: (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition
|
property Item contentItem: StyledToolTipContent {
|
||||||
|
id: contentItem
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: root.text
|
||||||
|
shown: false
|
||||||
|
Component.onCompleted: shown = true
|
||||||
|
horizontalPadding: root.horizontalPadding
|
||||||
|
verticalPadding: root.verticalPadding
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: tooltipLoader
|
id: tooltipLoader
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
active: internalVisibleCondition
|
active: root.internalVisibleCondition
|
||||||
sourceComponent: PopupWindow {
|
sourceComponent: PopupWindow {
|
||||||
visible: true
|
visible: true
|
||||||
anchor {
|
anchor {
|
||||||
@@ -35,18 +45,10 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
implicitWidth: contentItem.implicitWidth + root.horizontalPadding * 2
|
implicitWidth: root.contentItem.implicitWidth + root.horizontalPadding * 2
|
||||||
implicitHeight: contentItem.implicitHeight + root.verticalPadding * 2
|
implicitHeight: root.contentItem.implicitHeight + root.verticalPadding * 2
|
||||||
|
|
||||||
StyledToolTipContent {
|
data: [root.contentItem]
|
||||||
id: contentItem
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: root.text
|
|
||||||
shown: false
|
|
||||||
Component.onCompleted: shown = true
|
|
||||||
horizontalPadding: root.horizontalPadding
|
|
||||||
verticalPadding: root.verticalPadding
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@ ColumnLayout {
|
|||||||
Layout.fillHeight: false
|
Layout.fillHeight: false
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.bottomMargin: 6
|
Layout.bottomMargin: 6
|
||||||
model: root.devices.map(node => node.description)
|
model: root.devices.map(node => (node.nickname || node.description || Translation.tr("Unknown")))
|
||||||
currentIndex: root.devices.findIndex(item => {
|
currentIndex: root.devices.findIndex(item => {
|
||||||
if (root.isSink) {
|
if (root.isSink) {
|
||||||
return item.id === Pipewire.preferredDefaultAudioSink?.id
|
return item.id === Pipewire.preferredDefaultAudioSink?.id
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import Qt5Compat.GraphicalEffects
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
@@ -9,7 +10,9 @@ BarButton {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property string iconName
|
required property string iconName
|
||||||
|
property bool multiple: false
|
||||||
property bool separateLightDark: false
|
property bool separateLightDark: false
|
||||||
|
property alias tryCustomIcon: iconWidget.tryCustomIcon
|
||||||
leftInset: 2
|
leftInset: 2
|
||||||
rightInset: 2
|
rightInset: 2
|
||||||
implicitWidth: height - topInset - bottomInset + leftInset + rightInset
|
implicitWidth: height - topInset - bottomInset + leftInset + rightInset
|
||||||
@@ -20,9 +23,37 @@ BarButton {
|
|||||||
contentItem.scale = root.down ? 5/6 : 1 // If/When we do dragging, the scale is 1.25
|
contentItem.scale = root.down ? 5/6 : 1 // If/When we do dragging, the scale is 1.25
|
||||||
}
|
}
|
||||||
|
|
||||||
|
background: Item {
|
||||||
|
BackgroundAcrylicRectangle {
|
||||||
|
id: mainBgRect
|
||||||
|
anchors.fill: parent
|
||||||
|
layer.enabled: root.multiple
|
||||||
|
layer.effect: OpacityMask {
|
||||||
|
invert: true
|
||||||
|
maskSource: Item {
|
||||||
|
width: mainBgRect.width
|
||||||
|
height: mainBgRect.height
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.rightMargin: 3
|
||||||
|
radius: mainBgRect.radius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loader {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.rightMargin: 5
|
||||||
|
active: root.multiple
|
||||||
|
sourceComponent: BackgroundAcrylicRectangle {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
id: contentItem
|
id: contentItem
|
||||||
anchors.centerIn: root.background
|
anchors.centerIn: parent
|
||||||
|
|
||||||
implicitHeight: iconWidget.implicitHeight
|
implicitHeight: iconWidget.implicitHeight
|
||||||
implicitWidth: iconWidget.implicitWidth
|
implicitWidth: iconWidget.implicitWidth
|
||||||
@@ -41,4 +72,15 @@ BarButton {
|
|||||||
separateLightDark: root.separateLightDark
|
separateLightDark: root.separateLightDark
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component BackgroundAcrylicRectangle: AcrylicRectangle {
|
||||||
|
shiny: ((root.hovered && !root.down) || root.checked)
|
||||||
|
color: root.colBackground
|
||||||
|
border.width: 1
|
||||||
|
border.color: root.colBackgroundBorder
|
||||||
|
|
||||||
|
Behavior on border.color {
|
||||||
|
animation: Looks.transition.color.createObject(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ Kirigami.Icon {
|
|||||||
id: root
|
id: root
|
||||||
required property string iconName
|
required property string iconName
|
||||||
property bool separateLightDark: false
|
property bool separateLightDark: false
|
||||||
|
property bool tryCustomIcon: true
|
||||||
|
|
||||||
property real implicitSize: 26
|
property real implicitSize: 26
|
||||||
implicitWidth: implicitSize
|
implicitWidth: implicitSize
|
||||||
implicitHeight: implicitSize
|
implicitHeight: implicitSize
|
||||||
roundToIconSize: false
|
roundToIconSize: false
|
||||||
source: `${Looks.iconsPath}/${root.iconName}${!root.separateLightDark ? "" : Looks.dark ? "-dark" : "-light"}.svg`
|
|
||||||
fallback: root.iconName
|
fallback: root.iconName
|
||||||
|
source: tryCustomIcon ? `${Looks.iconsPath}/${root.iconName}${!root.separateLightDark ? "" : Looks.dark ? "-dark" : "-light"}.svg` : fallback
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,20 +8,70 @@ import qs.modules.waffle.looks
|
|||||||
Button {
|
Button {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
signal altAction()
|
||||||
|
signal middleClickAction()
|
||||||
|
|
||||||
|
property color colBackground
|
||||||
|
property color colBackgroundBorder
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
topInset: 4
|
topInset: 4
|
||||||
bottomInset: 4
|
bottomInset: 4
|
||||||
|
|
||||||
|
signal hoverTimedOut()
|
||||||
|
property bool shouldShowTooltip: false
|
||||||
|
property Timer hoverTimer: Timer {
|
||||||
|
id: hoverTimer
|
||||||
|
running: root.hovered
|
||||||
|
interval: 400
|
||||||
|
onTriggered: {
|
||||||
|
root.hoverTimedOut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onHoverTimedOut: {
|
||||||
|
root.shouldShowTooltip = true
|
||||||
|
}
|
||||||
|
onHoveredChanged: {
|
||||||
|
if (!root.hovered) {
|
||||||
|
root.shouldShowTooltip = false
|
||||||
|
root.hoverTimer.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
colBackground: {
|
||||||
|
if (root.down) {
|
||||||
|
return Looks.colors.bg1Active
|
||||||
|
} else if ((root.hovered && !root.down) || root.checked) {
|
||||||
|
return Looks.colors.bg1Hover
|
||||||
|
} else {
|
||||||
|
return ColorUtils.transparentize(Looks.colors.bg1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, root.checked ? Looks.contentTransparency : 1)
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
|
onPressed: (event) => {
|
||||||
|
root.down = true;
|
||||||
|
}
|
||||||
|
onReleased: (event) => {
|
||||||
|
root.down = false;
|
||||||
|
}
|
||||||
|
onClicked: (event) => {
|
||||||
|
if (event.button === Qt.LeftButton) root.clicked();
|
||||||
|
if (event.button === Qt.RightButton) root.altAction();
|
||||||
|
if (event.button === Qt.MiddleButton) root.middleClickAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
background: AcrylicRectangle {
|
background: AcrylicRectangle {
|
||||||
shiny: ((root.hovered && !root.down) || root.checked)
|
shiny: ((root.hovered && !root.down) || root.checked)
|
||||||
color: {
|
color: root.colBackground
|
||||||
if (root.down) {
|
border.width: 1
|
||||||
return Looks.colors.bg1Active
|
border.color: root.colBackgroundBorder
|
||||||
} else if ((root.hovered && !root.down) || root.checked) {
|
|
||||||
return Looks.colors.bg1Hover
|
Behavior on border.color {
|
||||||
} else {
|
animation: Looks.transition.color.createObject(this)
|
||||||
return ColorUtils.transparentize(Looks.colors.bg1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import qs.modules.common
|
||||||
|
import qs.modules.waffle.looks
|
||||||
|
|
||||||
|
WPopupToolTip {
|
||||||
|
anchorEdges: Config.options.waffles.bar.bottom ? Edges.Top : Edges.Bottom
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
import qs
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
import qs.modules.waffle.looks
|
import qs.modules.waffle.looks
|
||||||
@@ -10,4 +11,14 @@ AppButton {
|
|||||||
|
|
||||||
iconName: "system-search"
|
iconName: "system-search"
|
||||||
separateLightDark: true
|
separateLightDark: true
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now...
|
||||||
|
}
|
||||||
|
|
||||||
|
BarToolTip {
|
||||||
|
id: tooltip
|
||||||
|
text: Translation.tr("Search")
|
||||||
|
extraVisibleCondition: root.shouldShowTooltip
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
import qs
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
import qs.modules.waffle.looks
|
import qs.modules.waffle.looks
|
||||||
@@ -10,4 +11,14 @@ AppButton {
|
|||||||
|
|
||||||
leftInset: Config.options.waffles.bar.leftAlignApps ? 12 : 0
|
leftInset: Config.options.waffles.bar.leftAlignApps ? 12 : 0
|
||||||
iconName: "start-here"
|
iconName: "start-here"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now...
|
||||||
|
}
|
||||||
|
|
||||||
|
BarToolTip {
|
||||||
|
id: tooltip
|
||||||
|
text: Translation.tr("Start")
|
||||||
|
extraVisibleCondition: root.shouldShowTooltip
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import qs
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
import qs.modules.waffle.looks
|
import qs.modules.waffle.looks
|
||||||
@@ -7,35 +8,88 @@ import qs.modules.waffle.looks
|
|||||||
BarButton {
|
BarButton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// padding: 12
|
checked: GlobalStates.sidebarRightOpen
|
||||||
|
onClicked: {
|
||||||
|
GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; // For now...
|
||||||
|
}
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
anchors.centerIn: root.background
|
anchors.fill: parent
|
||||||
implicitHeight: column.implicitHeight
|
implicitHeight: column.implicitHeight
|
||||||
implicitWidth: column.implicitWidth
|
implicitWidth: column.implicitWidth
|
||||||
Row {
|
Row {
|
||||||
id: column
|
id: column
|
||||||
anchors.centerIn: parent
|
anchors {
|
||||||
spacing: 4
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
FluentIcon {
|
horizontalCenter: parent.horizontalCenter
|
||||||
icon: WIcons.internetIcon
|
|
||||||
}
|
}
|
||||||
|
spacing: 4
|
||||||
FluentIcon {
|
|
||||||
icon: {
|
IconHoverArea {
|
||||||
const muted = Audio.sink?.audio.muted ?? false;
|
id: internetHoverArea
|
||||||
const volume = Audio.sink?.audio.volume ?? 0;
|
iconItem: FluentIcon {
|
||||||
if (muted) return volume > 0 ? "speaker-off" : "speaker-none";
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
if (volume == 0) return "speaker-none";
|
icon: WIcons.internetIcon
|
||||||
if (volume < 0.5) return "speaker-1";
|
|
||||||
return "speaker";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FluentIcon {
|
IconHoverArea {
|
||||||
icon: WIcons.batteryIcon
|
id: volumeHoverArea
|
||||||
|
iconItem: FluentIcon {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
icon: {
|
||||||
|
const muted = Audio.sink?.audio.muted ?? false;
|
||||||
|
const volume = Audio.sink?.audio.volume ?? 0;
|
||||||
|
if (muted)
|
||||||
|
return volume > 0 ? "speaker-off" : "speaker-none";
|
||||||
|
if (volume == 0)
|
||||||
|
return "speaker-none";
|
||||||
|
if (volume < 0.5)
|
||||||
|
return "speaker-1";
|
||||||
|
return "speaker";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconHoverArea {
|
||||||
|
id: batteryHoverArea
|
||||||
|
iconItem: FluentIcon {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
icon: WIcons.batteryIcon
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component IconHoverArea: MouseArea {
|
||||||
|
id: hoverArea
|
||||||
|
required property var iconItem
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
hoverEnabled: true
|
||||||
|
implicitHeight: hoverArea.iconItem.implicitHeight
|
||||||
|
implicitWidth: hoverArea.iconItem.implicitWidth
|
||||||
|
|
||||||
|
onPressed: (event) => event.accepted = false; // Don't consume clicks
|
||||||
|
|
||||||
|
children: [iconItem]
|
||||||
|
}
|
||||||
|
|
||||||
|
BarToolTip {
|
||||||
|
extraVisibleCondition: root.shouldShowTooltip && internetHoverArea.containsMouse
|
||||||
|
text: Translation.tr("%1\nInternet access").arg(Network.ethernet ? Translation.tr("Network") : Network.networkName)
|
||||||
|
}
|
||||||
|
BarToolTip {
|
||||||
|
extraVisibleCondition: root.shouldShowTooltip && volumeHoverArea.containsMouse
|
||||||
|
text: Translation.tr("Speakers (%1): %2") //
|
||||||
|
.arg(Audio.sink?.nickname || Audio.sink?.description || Translation.tr("Unknown")) //
|
||||||
|
.arg(`${Math.round(Audio.sink?.audio.volume * 100) || 0}%`) //
|
||||||
|
}
|
||||||
|
BarToolTip {
|
||||||
|
extraVisibleCondition: root.shouldShowTooltip && batteryHoverArea.containsMouse
|
||||||
|
text: Translation.tr("Battery: %1").arg(`${Math.round(Battery.percentage * 100) || 0}%`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import qs.services
|
|
||||||
import qs.modules.common
|
|
||||||
import qs.modules.waffle.looks
|
|
||||||
import Quickshell
|
|
||||||
|
|
||||||
AppButton {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property var appEntry
|
|
||||||
readonly property bool isSeparator: appEntry.appId === "SEPARATOR"
|
|
||||||
readonly property var desktopEntry: DesktopEntries.heuristicLookup(appEntry.appId)
|
|
||||||
|
|
||||||
signal hoverPreviewRequested()
|
|
||||||
|
|
||||||
iconName: AppSearch.guessIcon(appEntry.appId)
|
|
||||||
Timer {
|
|
||||||
running: root.hovered
|
|
||||||
interval: 250
|
|
||||||
onTriggered: {
|
|
||||||
root.hoverPreviewRequested()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,4 +16,9 @@ AppButton {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
|
GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BarToolTip {
|
||||||
|
extraVisibleCondition: root.shouldShowTooltip
|
||||||
|
text: Translation.tr("Task View") // Should be a preview of workspaces, but we'll have this for now...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,4 +33,10 @@ BarButton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BarToolTip {
|
||||||
|
id: tooltip
|
||||||
|
extraVisibleCondition: root.shouldShowTooltip
|
||||||
|
text: `${Qt.locale().toString(DateTime.clock.date, "dddd, MMMM d, yyyy")}\n\n${Qt.locale().toString(DateTime.clock.date, "ddd hh:mm AP")}`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import QtQuick.Layouts
|
|||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
import qs.modules.common.widgets
|
import qs.modules.common.widgets
|
||||||
import qs.modules.waffle.looks
|
import qs.modules.waffle.looks
|
||||||
|
import qs.modules.waffle.bar.tasks
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|||||||
@@ -52,4 +52,9 @@ AppButton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BarToolTip {
|
||||||
|
extraVisibleCondition: root.shouldShowTooltip
|
||||||
|
text: Translation.tr("Widgets")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.services
|
||||||
|
import qs.modules.common
|
||||||
|
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"
|
||||||
|
readonly property var desktopEntry: DesktopEntries.heuristicLookup(appEntry.appId)
|
||||||
|
property bool active: root.appEntry.toplevels.some(t => t.activated)
|
||||||
|
property bool hasWindows: appEntry.toplevels.length > 0
|
||||||
|
|
||||||
|
signal hoverPreviewRequested()
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -70,7 +70,7 @@ PopupWindow {
|
|||||||
fill: contentItem
|
fill: contentItem
|
||||||
margins: -border.width
|
margins: -border.width
|
||||||
}
|
}
|
||||||
border.color: ColorUtils.transparentize(Looks.colors.bg0Border, Looks.contentTransparency)
|
border.color: ColorUtils.transparentize(Looks.colors.bg0Border, Looks.shadowTransparency)
|
||||||
border.width: 1
|
border.width: 1
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
radius: Looks.radius.large + border.width
|
radius: Looks.radius.large + border.width
|
||||||
+6
-2
@@ -13,6 +13,10 @@ MouseArea {
|
|||||||
implicitWidth: row.implicitWidth
|
implicitWidth: row.implicitWidth
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
|
function showPreviewPopup(appEntry, button) {
|
||||||
|
previewPopup.show(appEntry, button);
|
||||||
|
}
|
||||||
|
|
||||||
// Apps row
|
// Apps row
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: row
|
id: row
|
||||||
@@ -20,7 +24,7 @@ MouseArea {
|
|||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
// TODO: Include only apps (and windows) in current workspace only
|
// TODO: Include only apps (and windows) in current workspace only | wait, does that even make sense in a Hyprland workflow?
|
||||||
model: ScriptModel {
|
model: ScriptModel {
|
||||||
objectProp: "appId"
|
objectProp: "appId"
|
||||||
values: TaskbarApps.apps.filter(app => app.appId !== "SEPARATOR")
|
values: TaskbarApps.apps.filter(app => app.appId !== "SEPARATOR")
|
||||||
@@ -30,7 +34,7 @@ MouseArea {
|
|||||||
appEntry: modelData
|
appEntry: modelData
|
||||||
|
|
||||||
onHoverPreviewRequested: {
|
onHoverPreviewRequested: {
|
||||||
previewPopup.show(appEntry, this)
|
root.showPreviewPopup(appEntry, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
@@ -6,6 +6,7 @@ import qs.services
|
|||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
import qs.modules.common.functions
|
import qs.modules.common.functions
|
||||||
import qs.modules.waffle.looks
|
import qs.modules.waffle.looks
|
||||||
|
import qs.modules.waffle.bar
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ Singleton {
|
|||||||
|
|
||||||
property real backgroundTransparency: 0.17
|
property real backgroundTransparency: 0.17
|
||||||
property real contentTransparency: 0.25
|
property real contentTransparency: 0.25
|
||||||
|
property real shadowTransparency: 0.6
|
||||||
colors: QtObject {
|
colors: QtObject {
|
||||||
id: colors
|
id: colors
|
||||||
property color bg0: root.dark ? "#1C1C1C" : "#EEEEEE"
|
property color bg0: root.dark ? "#1C1C1C" : "#EEEEEE"
|
||||||
@@ -33,7 +34,9 @@ Singleton {
|
|||||||
property color fg1: root.dark ? "#D1D1D1" : "#626262"
|
property color fg1: root.dark ? "#D1D1D1" : "#626262"
|
||||||
property color danger: "#C42B1C"
|
property color danger: "#C42B1C"
|
||||||
property color dangerActive: "#B62D1F"
|
property color dangerActive: "#B62D1F"
|
||||||
property color brand: Appearance.m3colors.m3primary
|
// property color accent: root.dark ? "#A5C6D8" : "#5377A3"
|
||||||
|
property color accent: Appearance.m3colors.m3primary
|
||||||
|
property color accentUnfocused: root.dark ? "#989898" : "#848484"
|
||||||
}
|
}
|
||||||
|
|
||||||
radius: QtObject {
|
radius: QtObject {
|
||||||
@@ -106,7 +109,7 @@ Singleton {
|
|||||||
|
|
||||||
property Component move: Component {
|
property Component move: Component {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: 100
|
duration: 170
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
easing.bezierCurve: transition.easing.bezierCurve.easeInOut
|
easing.bezierCurve: transition.easing.bezierCurve.easeInOut
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import qs.modules.common
|
||||||
|
import qs.modules.common.functions
|
||||||
|
import qs.modules.common.widgets
|
||||||
|
import qs.modules.waffle.looks
|
||||||
|
|
||||||
|
PopupToolTip {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property real padding: 2
|
||||||
|
verticalPadding: padding
|
||||||
|
horizontalPadding: padding
|
||||||
|
|
||||||
|
contentItem: Item {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
implicitWidth: realContent.implicitWidth + root.verticalPadding * 2
|
||||||
|
implicitHeight: realContent.implicitHeight + root.horizontalPadding * 2
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: ambientShadow
|
||||||
|
z: 0
|
||||||
|
anchors {
|
||||||
|
fill: realContent
|
||||||
|
margins: -border.width
|
||||||
|
}
|
||||||
|
border.color: ColorUtils.transparentize(Looks.colors.bg0Border, Looks.shadowTransparency)
|
||||||
|
border.width: 1
|
||||||
|
color: "transparent"
|
||||||
|
radius: realContent.radius + border.width
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: realContent
|
||||||
|
z: 1
|
||||||
|
anchors.centerIn: parent
|
||||||
|
implicitWidth: tooltipText.implicitWidth + 10 * 2
|
||||||
|
implicitHeight: tooltipText.implicitHeight + 8 * 2
|
||||||
|
color: Looks.colors.bg1
|
||||||
|
radius: Looks.radius.medium
|
||||||
|
|
||||||
|
WText {
|
||||||
|
id: tooltipText
|
||||||
|
text: root.text
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -94,7 +94,7 @@ Singleton {
|
|||||||
if (!str || str.length == 0) return "image-missing";
|
if (!str || str.length == 0) return "image-missing";
|
||||||
|
|
||||||
// Quickshell's desktop entry lookup
|
// Quickshell's desktop entry lookup
|
||||||
const entry = DesktopEntries.heuristicLookup(str);
|
const entry = DesktopEntries.byId(str);
|
||||||
if (entry) return entry.icon;
|
if (entry) return entry.icon;
|
||||||
|
|
||||||
// Normal substitutions
|
// Normal substitutions
|
||||||
@@ -149,6 +149,9 @@ Singleton {
|
|||||||
if (iconExists(guess)) return guess;
|
if (iconExists(guess)) return guess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quickshell's desktop entry lookup
|
||||||
|
const heuristicEntry = DesktopEntries.heuristicLookup(str);
|
||||||
|
if (heuristicEntry) return heuristicEntry.icon;
|
||||||
|
|
||||||
// Give up
|
// Give up
|
||||||
return "application-x-executable";
|
return "application-x-executable";
|
||||||
|
|||||||
Reference in New Issue
Block a user