Lots of uncommitted changes
This commit is contained in:
parent
daace49bfc
commit
497ca48ada
27 changed files with 909 additions and 134 deletions
33
modules/user/modules/quickshell/shell/bar/Bar.qml
Normal file
33
modules/user/modules/quickshell/shell/bar/Bar.qml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import "systray" as SysTray
|
||||
|
||||
BarContainment {
|
||||
id: root
|
||||
ColumnLayout {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
SysTray.SysTray {
|
||||
bar: root
|
||||
Layout.fillWidth: true
|
||||
//width: 24
|
||||
}
|
||||
|
||||
ClockWidget {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
114
modules/user/modules/quickshell/shell/bar/BarContainment.qml
Normal file
114
modules/user/modules/quickshell/shell/bar/BarContainment.qml
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
default property list<QtObject> widgetSurfaceData;
|
||||
readonly property var widgetSurface: widgetSurface;
|
||||
property list<var> overlays: [];
|
||||
|
||||
anchors {
|
||||
left: true
|
||||
top: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
width: 70
|
||||
color: "transparent"
|
||||
WlrLayershell.namespace: "shell:bar"
|
||||
|
||||
Rectangle {
|
||||
id: barRect
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 10
|
||||
rightMargin: 5
|
||||
}
|
||||
|
||||
color: ShellGlobals.colors.bar
|
||||
radius: 5
|
||||
border.color: ShellGlobals.colors.barOutline
|
||||
border.width: 1
|
||||
|
||||
Item {
|
||||
id: containment
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// note: must be above the widgetSurface due to reload order
|
||||
PersistentProperties {
|
||||
id: persist
|
||||
reloadableId: "persist"
|
||||
|
||||
property bool visible: false
|
||||
}
|
||||
|
||||
onBackingWindowVisibleChanged: {
|
||||
persist.visible = Qt.binding(() => backingWindowVisible);
|
||||
}
|
||||
|
||||
PanelWindow {
|
||||
id: widgetSurface
|
||||
reloadableId: "widgetSurface"
|
||||
|
||||
visible: persist.visible
|
||||
anchors: root.anchors
|
||||
screen: root.screen
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.namespace: "shell:bar"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||
color: "transparent"
|
||||
|
||||
width: {
|
||||
const extents = overlays
|
||||
.filter(overlay => !overlay.fullyCollapsed)
|
||||
.map(overlay => overlayXOffset + overlay.expandedWidth);
|
||||
|
||||
return Math.max(root.width, ...extents);
|
||||
}
|
||||
|
||||
readonly property real overlayXOffset: root.width + 10;
|
||||
readonly property real tooltipXOffset: root.width + 2;
|
||||
|
||||
function overlayRect(targetY: real, size: rect): rect {
|
||||
const y = Math.max(barRect.y, Math.min((barRect.y + barRect.height) - size.height, targetY));
|
||||
return Qt.rect(overlayXOffset, y, size.width, size.height);
|
||||
}
|
||||
|
||||
function boundedY(targetY: real, height: real): real {
|
||||
return Math.max(0, Math.min(barRect.height - height, targetY))
|
||||
}
|
||||
|
||||
Item {
|
||||
id: contentArea
|
||||
data: widgetSurfaceData
|
||||
}
|
||||
|
||||
readonly property var tooltip: tooltip;
|
||||
Tooltip {
|
||||
id: tooltip
|
||||
bar: root
|
||||
}
|
||||
|
||||
function repositionContentArea() {
|
||||
// abusing the knowledge that both bars are in the same position onscreen
|
||||
const contentRect = containment.mapToItem(root.contentItem, 0, 0, containment.width, containment.height)
|
||||
|
||||
contentArea.x = contentRect.x
|
||||
contentArea.y = contentRect.y
|
||||
contentArea.width = contentRect.width
|
||||
contentArea.height = contentRect.height
|
||||
}
|
||||
}
|
||||
|
||||
onWindowTransformChanged: widgetSurface.repositionContentArea()
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import QtQuick
|
||||
import ".."
|
||||
|
||||
Rectangle {
|
||||
color: ShellGlobals.colors.widget
|
||||
radius: 5
|
||||
border.color: ShellGlobals.colors.widgetOutline
|
||||
border.width: 1
|
||||
}
|
||||
31
modules/user/modules/quickshell/shell/bar/BugTester.qml
Normal file
31
modules/user/modules/quickshell/shell/bar/BugTester.qml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import QtQuick
|
||||
|
||||
BarWidgetInner {
|
||||
implicitHeight: 50
|
||||
|
||||
SequentialAnimation on implicitHeight {
|
||||
loops: Animation.Infinite
|
||||
PropertyAnimation { to: 70; duration: 1000 }
|
||||
PropertyAnimation { to: 40; duration: 1000 }
|
||||
}
|
||||
|
||||
property int len: 1
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: `8${'='.repeat(len)}D`
|
||||
font.pointSize: 16
|
||||
color: "white"
|
||||
|
||||
PropertyAnimation on rotation {
|
||||
loops: Animation.Infinite
|
||||
to: 365
|
||||
duration: 1000
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: len += 1;
|
||||
}
|
||||
}
|
||||
41
modules/user/modules/quickshell/shell/bar/ClockWidget.qml
Normal file
41
modules/user/modules/quickshell/shell/bar/ClockWidget.qml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import ".."
|
||||
|
||||
OverlayWidget {
|
||||
expandedWidth: 600
|
||||
expandedHeight: 600
|
||||
|
||||
BarWidgetInner {
|
||||
implicitHeight: layout.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
spacing: 0
|
||||
|
||||
anchors {
|
||||
right: parent.right
|
||||
left: parent.left
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: ShellGlobals.time.getHours().toString().padStart(2, '0')
|
||||
font.pointSize: 18
|
||||
color: "#a0ffffff"
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: ShellGlobals.time.getMinutes().toString().padStart(2, '0')
|
||||
font.pointSize: 18
|
||||
color: "#a0ffffff"
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: expanded = !expanded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import QtQuick
|
||||
import Quickshell
|
||||
import ".."
|
||||
|
||||
Item {
|
||||
required property var bar;
|
||||
required property real expandedWidth;
|
||||
required property real expandedHeight;
|
||||
required default property Item widget;
|
||||
|
||||
property bool expanded: false;
|
||||
|
||||
onExpandedChanged: {
|
||||
animateTo(expanded ? 1.0 : 0.0)
|
||||
if (expanded) popupSurface.activeOverlay = this
|
||||
}
|
||||
|
||||
readonly property bool fullyCollapsed: animationProgress == 0.0;
|
||||
|
||||
onFullyCollapsedChanged: {
|
||||
if (fullyCollapsed && popupSurface.activeOverlay == this) {
|
||||
popupSurface.activeOverlay = null;
|
||||
}
|
||||
|
||||
/*if (fullyCollapsed) {
|
||||
widget.x = Qt.binding(() => this.x)
|
||||
}*/
|
||||
}
|
||||
|
||||
readonly property rect collapsedLayerRect: {
|
||||
void [barWindow.windowTransform, popupSurface.windowTransform, y, parent.y];
|
||||
return this.mapToItem(popupSurface.contentItem, 0, 0, width, height);
|
||||
}
|
||||
|
||||
onCollapsedLayerRectChanged: console.log(`clr: ${collapsedLayerRect}`)
|
||||
onLayerRectChanged: console.log(`lr: ${layerRect}`)
|
||||
onYChanged: console.log(`y: ${y}`)
|
||||
|
||||
readonly property rect expandedLayerRect: bar.widgetSurface.expandedPosition(this)
|
||||
|
||||
readonly property rect layerRect: {
|
||||
const [p, xCurve, yCurve] = [animationProgress, ShellGlobals.popoutXCurve, ShellGlobals.popoutYCurve];
|
||||
|
||||
return Qt.rect(
|
||||
xCurve.interpolate(p, collapsedLayerRect.x, expandedLayerRect.x),
|
||||
yCurve.interpolate(p, collapsedLayerRect.y, expandedLayerRect.y),
|
||||
xCurve.interpolate(p, collapsedLayerRect.width, expandedLayerRect.width),
|
||||
yCurve.interpolate(p, collapsedLayerRect.height, expandedLayerRect.height),
|
||||
);
|
||||
}
|
||||
|
||||
implicitWidth: widget.implicitWidth
|
||||
implicitHeight: widget.implicitHeight
|
||||
|
||||
Component.onCompleted: {
|
||||
popupSurface.connectOverlay(this);
|
||||
widget.x = Qt.binding(() => layerRect.x);
|
||||
widget.y = Qt.binding(() => layerRect.y);
|
||||
widget.width = Qt.binding(() => layerRect.width);
|
||||
widget.height = Qt.binding(() => layerRect.height);
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
popupSurface.disconnectOverlay(this)
|
||||
}
|
||||
|
||||
function animateTo(target: real) {
|
||||
animationProgressInternal = target * 1000
|
||||
}
|
||||
|
||||
property real animationProgress: animationProgressInternal * 0.001
|
||||
property real animationProgressInternal: 0.0 // animations seem to only have int precision
|
||||
|
||||
Behavior on animationProgressInternal {
|
||||
SmoothedAnimation { velocity: 3000 }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onPressed: expanded = false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
border.color: ShellGlobals.colors.widgetOutline
|
||||
border.width: 1
|
||||
radius: 5
|
||||
color: "transparent"
|
||||
opacity: mouseArea.containsMouse ? 1.0 : 0.0
|
||||
|
||||
Behavior on opacity {
|
||||
SmoothedAnimation { velocity: 4 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
modules/user/modules/quickshell/shell/bar/OverlayWidget.qml
Normal file
17
modules/user/modules/quickshell/shell/bar/OverlayWidget.qml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
|
||||
Item {
|
||||
default property Item item;
|
||||
property int expandedWidth;
|
||||
property int expandedHeight;
|
||||
|
||||
implicitHeight: item.implicitHeight
|
||||
implicitWidth: item.implicitWidth
|
||||
|
||||
Component.onCompleted: {
|
||||
item.width = Qt.binding(() => this.width)
|
||||
item.height = Qt.binding(() => this.height)
|
||||
}
|
||||
|
||||
children: [ item ]
|
||||
}
|
||||
127
modules/user/modules/quickshell/shell/bar/Tooltip.qml
Normal file
127
modules/user/modules/quickshell/shell/bar/Tooltip.qml
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
|
||||
Scope {
|
||||
id: root
|
||||
required property var bar;
|
||||
|
||||
property TooltipItem activeTooltip: null;
|
||||
property TooltipItem activeMenu: null;
|
||||
|
||||
readonly property TooltipItem activeItem: activeMenu ?? activeTooltip;
|
||||
property TooltipItem lastActiveItem: null;
|
||||
|
||||
onActiveItemChanged: {
|
||||
if (activeItem != null) activeItem.visible = true;
|
||||
if (lastActiveItem != null) lastActiveItem.visible = false;
|
||||
lastActiveItem = activeItem;
|
||||
}
|
||||
|
||||
function setItem(item: TooltipItem) {
|
||||
if (item.isMenu) {
|
||||
activeMenu = item;
|
||||
} else {
|
||||
activeTooltip = item;
|
||||
}
|
||||
}
|
||||
|
||||
function removeItem(item: TooltipItem) {
|
||||
if (item.isMenu && activeMenu == item) {
|
||||
activeMenu = null
|
||||
} else if (!item.isMenu && activeTooltip == item) {
|
||||
activeTooltip = null
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: popupLoader
|
||||
activeAsync: activeItem != null
|
||||
|
||||
PopupWindow {
|
||||
id: popup
|
||||
parentWindow: bar.widgetSurface
|
||||
relativeX: bar.widgetSurface.tooltipXOffset
|
||||
relativeY: 0
|
||||
height: bar.widgetSurface.height
|
||||
width: tooltipItem.width
|
||||
visible: true
|
||||
color: "transparent"
|
||||
|
||||
mask: Region {
|
||||
item: (activeItem?.isMenu ?? false) ? tooltipItem : null
|
||||
}
|
||||
|
||||
HyprlandFocusGrab {
|
||||
active: activeItem?.isMenu ?? false
|
||||
windows: [ popup, bar.widgetSurface ]
|
||||
onActiveChanged: {
|
||||
if (!active && activeItem?.isMenu) {
|
||||
activeMenu.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BarWidgetInner {
|
||||
id: tooltipItem
|
||||
|
||||
readonly property var targetWidth: activeItem?.implicitWidth ?? 10;
|
||||
readonly property var targetHeight: (activeItem?.implicitHeight ?? 0) + 10;
|
||||
|
||||
readonly property real targetY: {
|
||||
if (activeItem == null) return 0;
|
||||
const target = bar.widgetSurface.contentItem.mapFromItem(activeItem.owner, 0, activeItem.targetRelativeY).y;
|
||||
return bar.widgetSurface.boundedY(target, activeItem.implicitHeight / 2);
|
||||
}
|
||||
|
||||
width: targetWidth + 10
|
||||
|
||||
property var y1: -1
|
||||
property var y2: -1
|
||||
|
||||
y: y1
|
||||
height: y2 - y1
|
||||
|
||||
SmoothedAnimation {
|
||||
target: tooltipItem;
|
||||
property: "y1";
|
||||
to: tooltipItem.targetY - tooltipItem.targetHeight / 2;
|
||||
onToChanged: {
|
||||
if (tooltipItem.y1 == -1 || !(activeItem?.animateSize ?? true)) {
|
||||
stop();
|
||||
tooltipItem.y1 = to;
|
||||
} else {
|
||||
velocity = (Math.max(tooltipItem.y1, to) - Math.min(tooltipItem.y1, to)) * 5;
|
||||
restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmoothedAnimation {
|
||||
target: tooltipItem
|
||||
property: "y2"
|
||||
to: tooltipItem.targetY + tooltipItem.targetHeight / 2;
|
||||
onToChanged: {
|
||||
if (tooltipItem.y2 == -1 || !(activeItem?.animateSize ?? true)) {
|
||||
stop();
|
||||
tooltipItem.y2 = to;
|
||||
} else {
|
||||
velocity = (Math.max(tooltipItem.y2, to) - Math.min(tooltipItem.y2, to)) * 5;
|
||||
restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
clip: true
|
||||
children: [ activeItem ]
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
modules/user/modules/quickshell/shell/bar/TooltipItem.qml
Normal file
31
modules/user/modules/quickshell/shell/bar/TooltipItem.qml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Item {
|
||||
id: root
|
||||
required property var tooltip;
|
||||
required property Item owner;
|
||||
property bool isMenu: false;
|
||||
property bool animateSize: true;
|
||||
property bool show: false;
|
||||
|
||||
property real targetRelativeY: owner.height / 2;
|
||||
property real hangTime: isMenu ? 0 : 200;
|
||||
|
||||
signal close();
|
||||
|
||||
onShowChanged: {
|
||||
if (show) {
|
||||
hangTimer.stop();
|
||||
tooltip.setItem(this);
|
||||
} else if (hangTime == 0) {
|
||||
tooltip.removeItem(this);
|
||||
} else hangTimer.start();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: hangTimer
|
||||
interval: hangTime
|
||||
onTriggered: tooltip.removeItem(root);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import "../.."
|
||||
|
||||
Rectangle {
|
||||
property var checkState: Qt.Unchecked;
|
||||
implicitHeight: 18
|
||||
implicitWidth: 18
|
||||
radius: 3
|
||||
color: ShellGlobals.colors.widget
|
||||
|
||||
Shape {
|
||||
visible: checkState == Qt.Checked
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
layer.samples: 10
|
||||
|
||||
ShapePath {
|
||||
strokeWidth: 2
|
||||
capStyle: ShapePath.RoundCap
|
||||
joinStyle: ShapePath.RoundJoin
|
||||
fillColor: "transparent"
|
||||
|
||||
startX: start.x
|
||||
startY: start.y
|
||||
|
||||
PathLine {
|
||||
id: start
|
||||
x: width * 0.8
|
||||
y: height * 0.2
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: width * 0.35
|
||||
y: height * 0.8
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: width * 0.2
|
||||
y: height * 0.6
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import Quickshell
|
||||
|
||||
Item {
|
||||
property bool expanded: false;
|
||||
|
||||
readonly property bool open: progress != 0;
|
||||
readonly property bool animating: internalProgress != -1 && internalProgress != 101;
|
||||
|
||||
implicitHeight: 16
|
||||
implicitWidth: 16
|
||||
property var xStart: Math.round(width * 0.3)
|
||||
property var yStart: Math.round(height * 0.1)
|
||||
property var xEnd: Math.round(width * 0.7)
|
||||
property var yEnd: Math.round(height * 0.9)
|
||||
|
||||
property real internalProgress: expanded ? 101 : -1;
|
||||
Behavior on internalProgress { SmoothedAnimation { velocity: 300 } }
|
||||
|
||||
EasingCurve {
|
||||
id: curve
|
||||
curve.type: Easing.InOutQuad
|
||||
}
|
||||
|
||||
readonly property real progress: curve.valueAt(Math.min(100, Math.max(internalProgress, 0)) * 0.01)
|
||||
|
||||
rotation: progress * 90;
|
||||
|
||||
Shape {
|
||||
anchors.fill: parent
|
||||
|
||||
layer.enabled: true
|
||||
layer.samples: 3
|
||||
|
||||
ShapePath {
|
||||
strokeWidth: 2
|
||||
capStyle: ShapePath.RoundCap
|
||||
joinStyle: ShapePath.MiterJoin
|
||||
fillColor: "transparent"
|
||||
|
||||
startX: xStart
|
||||
startY: yStart
|
||||
|
||||
PathLine {
|
||||
x: xEnd
|
||||
y: height / 2
|
||||
}
|
||||
|
||||
PathLine {
|
||||
y: yEnd
|
||||
x: xStart
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
modules/user/modules/quickshell/shell/bar/systray/MenuItem.qml
Normal file
110
modules/user/modules/quickshell/shell/bar/systray/MenuItem.qml
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.DBusMenu
|
||||
import "../.."
|
||||
|
||||
MouseArea {
|
||||
id: root
|
||||
required property var entry;
|
||||
property alias expanded: childrenRevealer.expanded;
|
||||
property bool animating: childrenRevealer.animating || childrenList.animating;
|
||||
// appears it won't actually create the handler when only used from MenuItemList.
|
||||
onExpandedChanged: {}
|
||||
onAnimatingChanged: {}
|
||||
|
||||
signal close();
|
||||
|
||||
implicitWidth: row.implicitWidth + 4
|
||||
implicitHeight: row.implicitHeight + 4
|
||||
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
if (entry.hasChildren) childrenRevealer.expanded = !childrenRevealer.expanded
|
||||
else {
|
||||
entry.click();
|
||||
if (entry.toggleType == ToggleButtonType.None) close();
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: row
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
Item {
|
||||
implicitWidth: 22
|
||||
implicitHeight: 22
|
||||
|
||||
MenuCheckBox {
|
||||
anchors.centerIn: parent
|
||||
visible: entry.toggleType == ToggleButtonType.CheckBox
|
||||
checkState: entry.checkState
|
||||
}
|
||||
|
||||
MenuRadioButton {
|
||||
anchors.centerIn: parent
|
||||
visible: entry.toggleType == ToggleButtonType.RadioButton
|
||||
checkState: entry.checkState
|
||||
}
|
||||
|
||||
MenuChildrenRevealer {
|
||||
id: childrenRevealer
|
||||
anchors.centerIn: parent
|
||||
visible: entry.hasChildren
|
||||
onOpenChanged: entry.showChildren = open
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: entry.cleanLabel
|
||||
color: entry.enabled ? "white" : "#bbbbbb"
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
implicitWidth: 22
|
||||
implicitHeight: 22
|
||||
|
||||
Image {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: entry.icon != ""
|
||||
source: entry.icon
|
||||
sourceSize.height: parent.height
|
||||
sourceSize.width: parent.height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: childrenList.implicitHeight * childrenRevealer.progress
|
||||
clip: true
|
||||
|
||||
MenuItemList {
|
||||
id: childrenList
|
||||
items: entry.children
|
||||
onClose: root.close()
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
visible: root.containsMouse || childrenRevealer.expanded
|
||||
|
||||
color: ShellGlobals.colors.widget
|
||||
border.width: 1
|
||||
border.color: ShellGlobals.colors.widgetOutline
|
||||
radius: 5
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.DBusMenu
|
||||
import "../.."
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
required property var items;
|
||||
property Item animatingItem: null;
|
||||
property bool animating: animatingItem != null;
|
||||
|
||||
signal close();
|
||||
signal submenuExpanded(item: var);
|
||||
|
||||
spacing: 0
|
||||
|
||||
Repeater {
|
||||
model: items
|
||||
|
||||
Loader {
|
||||
required property var modelData;
|
||||
|
||||
property var item: Component {
|
||||
BoundComponent {
|
||||
id: itemComponent
|
||||
source: "MenuItem.qml"
|
||||
|
||||
property var entry: modelData
|
||||
|
||||
function onClose() {
|
||||
root.close()
|
||||
}
|
||||
|
||||
function onExpandedChanged() {
|
||||
if (item.expanded) root.submenuExpanded(item);
|
||||
}
|
||||
|
||||
function onAnimatingChanged() {
|
||||
if (item.animating) {
|
||||
root.animatingItem = this;
|
||||
} else if (root.animatingItem == this) {
|
||||
root.animatingItem = null;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
|
||||
function onSubmenuExpanded(expandedItem) {
|
||||
if (item != expandedItem) item.expanded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var separator: Component {
|
||||
Item {
|
||||
implicitHeight: seprect.height + 6
|
||||
|
||||
Rectangle {
|
||||
id: seprect
|
||||
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
color: ShellGlobals.colors.separator
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceComponent: modelData.isSeparator ? separator : item
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import QtQuick
|
||||
import "../.."
|
||||
|
||||
Rectangle {
|
||||
property var checkState: Qt.Unchecked;
|
||||
implicitHeight: 18
|
||||
implicitWidth: 18
|
||||
radius: width / 2
|
||||
color: ShellGlobals.colors.widget
|
||||
|
||||
Rectangle {
|
||||
x: parent.width * 0.25
|
||||
y: parent.height * 0.25
|
||||
visible: checkState == Qt.Checked
|
||||
width: parent.width * 0.5
|
||||
height: width
|
||||
radius: width / 2
|
||||
}
|
||||
}
|
||||
147
modules/user/modules/quickshell/shell/bar/systray/SysTray.qml
Normal file
147
modules/user/modules/quickshell/shell/bar/systray/SysTray.qml
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Services.SystemTray
|
||||
import ".."
|
||||
|
||||
OverlayWidget {
|
||||
id: root
|
||||
expandedWidth: 600
|
||||
expandedHeight: 800
|
||||
required property var bar;
|
||||
|
||||
BarWidgetInner {
|
||||
implicitHeight: column.implicitHeight + 10
|
||||
|
||||
ColumnLayout {
|
||||
id: column
|
||||
implicitHeight: childrenRect.height
|
||||
spacing: 5
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 5
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: SystemTray.items;
|
||||
|
||||
Item {
|
||||
required property var modelData;
|
||||
readonly property alias menu: menuWatcher.menu;
|
||||
|
||||
SystemTrayMenuWatcher {
|
||||
id: menuWatcher;
|
||||
trayItem: modelData;
|
||||
}
|
||||
|
||||
property bool targetMenuOpen: false;
|
||||
onTargetMenuOpenChanged: menu.showChildren = targetMenuOpen
|
||||
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: width
|
||||
Behavior on implicitHeight {
|
||||
SmoothedAnimation { velocity: 50 }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: height
|
||||
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
|
||||
Image {
|
||||
id: image
|
||||
anchors.fill: parent
|
||||
|
||||
anchors.margins: mouseArea.pressed || targetMenuOpen ? 3 : 0
|
||||
Behavior on anchors.margins { SmoothedAnimation { velocity: 30 } }
|
||||
|
||||
source: modelData.icon
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
cache: false
|
||||
visible: false
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
anchors.fill: image
|
||||
source: image
|
||||
|
||||
property real targetBrightness: mouseArea.pressed || targetMenuOpen ? -25 : mouseArea.containsMouse ? 75 : 0
|
||||
Behavior on targetBrightness { SmoothedAnimation { velocity: 600 } }
|
||||
brightness: targetBrightness / 1000
|
||||
}
|
||||
|
||||
onClicked: event => {
|
||||
event.accepted = true;
|
||||
|
||||
if (event.button == Qt.LeftButton) {
|
||||
modelData.activate();
|
||||
} else if (event.button == Qt.MiddleButton) {
|
||||
modelData.secondaryActivate();
|
||||
} else if (event.button == Qt.RightButton && menu != null) {
|
||||
targetMenuOpen = !targetMenuOpen;
|
||||
}
|
||||
}
|
||||
|
||||
onWheel: event => {
|
||||
event.accepted = true;
|
||||
const points = event.angleDelta.y / 120
|
||||
modelData.scroll(points, false);
|
||||
}
|
||||
|
||||
property var tooltip: TooltipItem {
|
||||
anchors.fill: parent
|
||||
tooltip: bar.widgetSurface.tooltip
|
||||
owner: image
|
||||
|
||||
show: mouseArea.containsMouse
|
||||
implicitWidth: tooltipText.implicitWidth
|
||||
implicitHeight: tooltipText.implicitHeight
|
||||
|
||||
Text {
|
||||
id: tooltipText
|
||||
anchors.fill: parent
|
||||
text: modelData.tooltipTitle != "" ? modelData.tooltipTitle : modelData.id
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
|
||||
property var rightclickMenu: TooltipItem {
|
||||
anchors.fill: parent
|
||||
tooltip: bar.widgetSurface.tooltip
|
||||
owner: image
|
||||
|
||||
isMenu: true
|
||||
show: targetMenuOpen && menu.showChildren
|
||||
animateSize: !rightclickItems.animating
|
||||
implicitHeight: rightclickItems.implicitHeight
|
||||
implicitWidth: rightclickItems.implicitWidth
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) targetMenuOpen = false;
|
||||
}
|
||||
|
||||
onClose: targetMenuOpen = false;
|
||||
|
||||
MenuItemList {
|
||||
id: rightclickItems
|
||||
anchors.fill: parent
|
||||
items: menu == null ? [] : menu.children
|
||||
onClose: targetMenuOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue