mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-07 06:12:08 -04:00
animations/ripple: clean up effect and apply more universally
This commit is contained in:
@@ -30,6 +30,12 @@ Rectangle {
|
||||
return mouseArea.containsMouse ? Theme.primaryHoverLight : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency);
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: rippleLayer
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: indexBadge
|
||||
anchors.left: parent.left
|
||||
@@ -138,6 +144,10 @@ Rectangle {
|
||||
anchors.rightMargin: 80
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => {
|
||||
const pos = mouseArea.mapToItem(root, mouse.x, mouse.y);
|
||||
rippleLayer.trigger(pos.x, pos.y);
|
||||
}
|
||||
onClicked: copyRequested()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,12 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : "transparent"
|
||||
|
||||
DankRipple {
|
||||
id: rippleLayer
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
@@ -99,6 +105,10 @@ Rectangle {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
onPressed: mouse => {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
rippleLayer.trigger(mouse.x, mouse.y);
|
||||
}
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
var scenePos = mapToItem(null, mouse.x, mouse.y);
|
||||
|
||||
@@ -475,6 +475,12 @@ Popup {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: menuItemRipple
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: itemMouseArea
|
||||
anchors.fill: parent
|
||||
@@ -484,6 +490,7 @@ Popup {
|
||||
root.keyboardNavigation = false;
|
||||
root.selectedMenuIndex = menuItemDelegate.itemIndex;
|
||||
}
|
||||
onPressed: mouse => menuItemRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
var menuItem = menuItemDelegate.modelData;
|
||||
if (menuItem.action)
|
||||
|
||||
@@ -53,6 +53,12 @@ Rectangle {
|
||||
color: isSelected ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : "transparent"
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
DankRipple {
|
||||
id: rippleLayer
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: itemArea
|
||||
z: 1
|
||||
@@ -62,6 +68,10 @@ Rectangle {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
onPressed: mouse => {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
rippleLayer.trigger(mouse.x, mouse.y);
|
||||
}
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
var scenePos = mapToItem(null, mouse.x, mouse.y);
|
||||
|
||||
@@ -82,6 +82,12 @@ Rectangle {
|
||||
return ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp"].indexOf(ext) >= 0;
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: rippleLayer
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 4
|
||||
@@ -193,6 +199,10 @@ Rectangle {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
onPressed: mouse => {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
rippleLayer.trigger(mouse.x, mouse.y);
|
||||
}
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
var scenePos = mapToItem(null, mouse.x, mouse.y);
|
||||
|
||||
@@ -239,7 +239,6 @@ Rectangle {
|
||||
"icon": "computer",
|
||||
"collapsedByDefault": true,
|
||||
"children": [
|
||||
|
||||
{
|
||||
"id": "audio",
|
||||
"text": I18n.tr("Audio"),
|
||||
@@ -702,6 +701,12 @@ Rectangle {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: resultRipple
|
||||
rippleColor: root.searchSelectedIndex === resultDelegate.index ? Theme.buttonText : Theme.surfaceText
|
||||
cornerRadius: resultDelegate.radius
|
||||
}
|
||||
|
||||
Row {
|
||||
id: resultContent
|
||||
anchors.left: parent.left
|
||||
@@ -749,6 +754,7 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => resultRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.selectSearchResult(resultDelegate.modelData)
|
||||
}
|
||||
|
||||
@@ -825,6 +831,12 @@ Rectangle {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: categoryRipple
|
||||
rippleColor: categoryRow.isActive ? Theme.buttonText : Theme.surfaceText
|
||||
cornerRadius: categoryRow.radius
|
||||
}
|
||||
|
||||
Row {
|
||||
id: categoryRowContent
|
||||
anchors.left: parent.left
|
||||
@@ -864,6 +876,7 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => categoryRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
root.keyboardHighlightIndex = -1;
|
||||
if (categoryDelegate.modelData.children) {
|
||||
@@ -915,6 +928,12 @@ Rectangle {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: childRipple
|
||||
rippleColor: childDelegate.isActive ? Theme.buttonText : Theme.surfaceText
|
||||
cornerRadius: childDelegate.radius
|
||||
}
|
||||
|
||||
Row {
|
||||
id: childRowContent
|
||||
anchors.left: parent.left
|
||||
@@ -943,6 +962,7 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => childRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
root.keyboardHighlightIndex = -1;
|
||||
root.tabChangeRequested(childDelegate.modelData.tabIndex);
|
||||
|
||||
@@ -101,12 +101,18 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: ripple
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: root.enabled
|
||||
onPressed: mouse => ripple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
|
||||
|
||||
@@ -11,19 +11,11 @@ Rectangle {
|
||||
property string iconName: ""
|
||||
property string text: ""
|
||||
|
||||
signal pressed()
|
||||
signal pressed
|
||||
|
||||
height: 34
|
||||
radius: Theme.cornerRadius
|
||||
color: mouseArea.containsMouse ? Qt.rgba(
|
||||
Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.12) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.5)
|
||||
color: mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5)
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
@@ -44,12 +36,20 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: ripple
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: root.pressed()
|
||||
onPressed: mouse => {
|
||||
ripple.trigger(mouse.x, mouse.y);
|
||||
root.pressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,11 +61,17 @@ Rectangle {
|
||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
DankRipple {
|
||||
id: iconRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (AudioService.source && AudioService.source.audio) {
|
||||
AudioService.source.audio.muted = !AudioService.source.audio.muted;
|
||||
@@ -126,15 +132,15 @@ Rectangle {
|
||||
|
||||
function normalizePinList(value) {
|
||||
if (Array.isArray(value))
|
||||
return value.filter(v => v)
|
||||
return value.filter(v => v);
|
||||
if (typeof value === "string" && value.length > 0)
|
||||
return [value]
|
||||
return []
|
||||
return [value];
|
||||
return [];
|
||||
}
|
||||
|
||||
function getPinnedInputs() {
|
||||
const pins = SettingsData.audioInputDevicePins || {}
|
||||
return normalizePinList(pins["preferredInput"])
|
||||
const pins = SettingsData.audioInputDevicePins || {};
|
||||
return normalizePinList(pins["preferredInput"]);
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -153,14 +159,14 @@ Rectangle {
|
||||
let sorted = [...nodes];
|
||||
sorted.sort((a, b) => {
|
||||
// Pinned device first
|
||||
const aPinnedIndex = pinnedList.indexOf(a.name)
|
||||
const bPinnedIndex = pinnedList.indexOf(b.name)
|
||||
const aPinnedIndex = pinnedList.indexOf(a.name);
|
||||
const bPinnedIndex = pinnedList.indexOf(b.name);
|
||||
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
|
||||
if (aPinnedIndex === -1)
|
||||
return 1
|
||||
return 1;
|
||||
if (bPinnedIndex === -1)
|
||||
return -1
|
||||
return aPinnedIndex - bPinnedIndex
|
||||
return -1;
|
||||
return aPinnedIndex - bPinnedIndex;
|
||||
}
|
||||
// Then active device
|
||||
if (a === AudioService.source && b !== AudioService.source)
|
||||
@@ -276,38 +282,53 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: pinRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {}))
|
||||
let pinnedList = audioContent.normalizePinList(pins["preferredInput"])
|
||||
const pinIndex = pinnedList.indexOf(modelData.name)
|
||||
const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {}));
|
||||
let pinnedList = audioContent.normalizePinList(pins["preferredInput"]);
|
||||
const pinIndex = pinnedList.indexOf(modelData.name);
|
||||
|
||||
if (pinIndex !== -1) {
|
||||
pinnedList.splice(pinIndex, 1)
|
||||
pinnedList.splice(pinIndex, 1);
|
||||
} else {
|
||||
pinnedList.unshift(modelData.name)
|
||||
pinnedList.unshift(modelData.name);
|
||||
if (pinnedList.length > audioContent.maxPinnedInputs)
|
||||
pinnedList = pinnedList.slice(0, audioContent.maxPinnedInputs)
|
||||
pinnedList = pinnedList.slice(0, audioContent.maxPinnedInputs);
|
||||
}
|
||||
|
||||
if (pinnedList.length > 0)
|
||||
pins["preferredInput"] = pinnedList
|
||||
pins["preferredInput"] = pinnedList;
|
||||
else
|
||||
delete pins["preferredInput"]
|
||||
delete pins["preferredInput"];
|
||||
|
||||
SettingsData.set("audioInputDevicePins", pins)
|
||||
SettingsData.set("audioInputDevicePins", pins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: deviceRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: deviceMouseArea
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: pinInputRow.width + Theme.spacingS * 4
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => {
|
||||
let mapped = mapToItem(parent, mouse.x, mouse.y);
|
||||
deviceRipple.trigger(mapped.x, mapped.y);
|
||||
}
|
||||
onClicked: {
|
||||
if (modelData) {
|
||||
Pipewire.preferredDefaultAudioSource = modelData;
|
||||
|
||||
@@ -61,11 +61,17 @@ Rectangle {
|
||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
DankRipple {
|
||||
id: muteRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => muteRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (AudioService.sink && AudioService.sink.audio) {
|
||||
AudioService.sink.audio.muted = !AudioService.sink.audio.muted;
|
||||
@@ -184,6 +190,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
id: outputDelegate
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
@@ -194,6 +201,11 @@ Rectangle {
|
||||
border.color: modelData === AudioService.sink ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: 0
|
||||
|
||||
DankRipple {
|
||||
id: deviceRipple
|
||||
cornerRadius: outputDelegate.radius
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -288,9 +300,15 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: pinRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {}));
|
||||
let pinnedList = audioContent.normalizePinList(pins["preferredOutput"]);
|
||||
@@ -320,6 +338,10 @@ Rectangle {
|
||||
anchors.rightMargin: pinOutputRow.width + Theme.spacingS * 4
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => {
|
||||
let mapped = deviceMouseArea.mapToItem(outputDelegate, mouse.x, mouse.y);
|
||||
deviceRipple.trigger(mapped.x, mapped.y);
|
||||
}
|
||||
onClicked: {
|
||||
if (modelData) {
|
||||
Pipewire.preferredDefaultAudioSink = modelData;
|
||||
@@ -428,12 +450,18 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: appIconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||
|
||||
DankRipple {
|
||||
id: appMuteRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: appIconArea
|
||||
anchors.fill: parent
|
||||
visible: modelData !== null
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => appMuteRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (modelData) {
|
||||
SessionData.suppressOSDTemporarily();
|
||||
|
||||
@@ -293,6 +293,11 @@ Item {
|
||||
visible: modelData.name === currentCodec
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: codecRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: codecMouseArea
|
||||
|
||||
@@ -300,6 +305,7 @@ Item {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: modelData.name !== currentCodec && !isLoading
|
||||
onPressed: mouse => codecRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
selectCodec(modelData.profile);
|
||||
}
|
||||
|
||||
@@ -139,12 +139,18 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: scanRipple
|
||||
cornerRadius: scanButton.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: scanMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
enabled: scanButton.adapterEnabled
|
||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
onPressed: mouse => scanRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (!BluetoothService.adapter)
|
||||
return;
|
||||
@@ -399,12 +405,21 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: deviceRipple
|
||||
cornerRadius: pairedDelegate.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: deviceMouseArea
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: pairedOptionsButton.width + Theme.spacingM + pinBluetoothRow.width + Theme.spacingS * 4
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => {
|
||||
const pos = mapToItem(pairedDelegate, mouse.x, mouse.y);
|
||||
deviceRipple.trigger(pos.x, pos.y);
|
||||
}
|
||||
onClicked: {
|
||||
if (pairedDelegate.isConnected) {
|
||||
pairedDelegate.modelData.disconnect();
|
||||
@@ -547,12 +562,18 @@ Rectangle {
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: availableRipple
|
||||
cornerRadius: availableDelegate.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: availableMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: availableDelegate.isInteractive ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
enabled: availableDelegate.isInteractive
|
||||
onPressed: mouse => availableRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.handlePairDevice(availableDelegate.modelData)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,9 +211,15 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: pinRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.togglePinToScreen()
|
||||
}
|
||||
}
|
||||
@@ -443,9 +449,15 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: expToggleRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => expToggleRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
const currentState = SessionData.getBrightnessExponential(modelData.name);
|
||||
SessionData.setBrightnessExponential(modelData.name, !currentState);
|
||||
@@ -454,12 +466,18 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: deviceRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.bottomMargin: 28
|
||||
anchors.rightMargin: SessionData.getBrightnessExponential(modelData.name) ? 145 : 0
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => deviceRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
const pinKey = root.getScreenPinKey();
|
||||
if (pinKey.length > 0 && modelData.name !== currentDeviceName) {
|
||||
|
||||
@@ -155,10 +155,16 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: mountRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => mountRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
currentMountPath = modelData.mount;
|
||||
mountPathChanged(modelData.mount);
|
||||
|
||||
@@ -344,12 +344,18 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: wiredRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wiredNetworkMouseArea
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: wiredOptionsButton.width + Theme.spacingS
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => wiredRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: function (event) {
|
||||
if (modelData.uuid !== NetworkService.ethernetConnectionUuid) {
|
||||
NetworkService.connectToSpecificWiredConfig(modelData.uuid);
|
||||
@@ -467,15 +473,15 @@ Rectangle {
|
||||
|
||||
function normalizePinList(value) {
|
||||
if (Array.isArray(value))
|
||||
return value.filter(v => v)
|
||||
return value.filter(v => v);
|
||||
if (typeof value === "string" && value.length > 0)
|
||||
return [value]
|
||||
return []
|
||||
return [value];
|
||||
return [];
|
||||
}
|
||||
|
||||
function getPinnedNetworks() {
|
||||
const pins = SettingsData.wifiNetworkPins || {}
|
||||
return normalizePinList(pins["preferredWifi"])
|
||||
const pins = SettingsData.wifiNetworkPins || {};
|
||||
return normalizePinList(pins["preferredWifi"]);
|
||||
}
|
||||
|
||||
property var frozenNetworks: []
|
||||
@@ -483,18 +489,18 @@ Rectangle {
|
||||
property var sortedNetworks: {
|
||||
const ssid = NetworkService.currentWifiSSID;
|
||||
const networks = NetworkService.wifiNetworks;
|
||||
const pinnedList = getPinnedNetworks()
|
||||
const pinnedList = getPinnedNetworks();
|
||||
|
||||
let sorted = [...networks];
|
||||
sorted.sort((a, b) => {
|
||||
const aPinnedIndex = pinnedList.indexOf(a.ssid)
|
||||
const bPinnedIndex = pinnedList.indexOf(b.ssid)
|
||||
const aPinnedIndex = pinnedList.indexOf(a.ssid);
|
||||
const bPinnedIndex = pinnedList.indexOf(b.ssid);
|
||||
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
|
||||
if (aPinnedIndex === -1)
|
||||
return 1
|
||||
return 1;
|
||||
if (bPinnedIndex === -1)
|
||||
return -1
|
||||
return aPinnedIndex - bPinnedIndex
|
||||
return -1;
|
||||
return aPinnedIndex - bPinnedIndex;
|
||||
}
|
||||
if (a.ssid === ssid)
|
||||
return -1;
|
||||
@@ -677,38 +683,50 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: pinRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}))
|
||||
let pinnedList = wifiContent.normalizePinList(pins["preferredWifi"])
|
||||
const pinIndex = pinnedList.indexOf(modelData.ssid)
|
||||
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}));
|
||||
let pinnedList = wifiContent.normalizePinList(pins["preferredWifi"]);
|
||||
const pinIndex = pinnedList.indexOf(modelData.ssid);
|
||||
|
||||
if (pinIndex !== -1) {
|
||||
pinnedList.splice(pinIndex, 1)
|
||||
pinnedList.splice(pinIndex, 1);
|
||||
} else {
|
||||
pinnedList.unshift(modelData.ssid)
|
||||
pinnedList.unshift(modelData.ssid);
|
||||
if (pinnedList.length > wifiContent.maxPinnedNetworks)
|
||||
pinnedList = pinnedList.slice(0, wifiContent.maxPinnedNetworks)
|
||||
pinnedList = pinnedList.slice(0, wifiContent.maxPinnedNetworks);
|
||||
}
|
||||
|
||||
if (pinnedList.length > 0)
|
||||
pins["preferredWifi"] = pinnedList
|
||||
pins["preferredWifi"] = pinnedList;
|
||||
else
|
||||
delete pins["preferredWifi"]
|
||||
delete pins["preferredWifi"];
|
||||
|
||||
SettingsData.set("wifiNetworkPins", pins)
|
||||
SettingsData.set("wifiNetworkPins", pins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: wifiRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: networkMouseArea
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: optionsButton.width + Theme.spacingM + Theme.spacingS + pinWifiRow.width + Theme.spacingS * 4
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => wifiRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: function (event) {
|
||||
if (modelData.ssid !== NetworkService.currentWifiSSID) {
|
||||
if (modelData.secured && !modelData.saved) {
|
||||
|
||||
@@ -22,12 +22,18 @@ Row {
|
||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||
|
||||
DankRipple {
|
||||
id: iconRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
anchors.fill: parent
|
||||
visible: defaultSink !== null
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (defaultSink) {
|
||||
SessionData.suppressOSDTemporarily();
|
||||
|
||||
@@ -91,12 +91,18 @@ Row {
|
||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||
|
||||
DankRipple {
|
||||
id: iconRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: DisplayService.devices && DisplayService.devices.length > 1 ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
|
||||
onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (DisplayService.devices && DisplayService.devices.length > 1) {
|
||||
root.iconClicked();
|
||||
|
||||
@@ -72,6 +72,11 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: bodyRipple
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row
|
||||
anchors.fill: parent
|
||||
@@ -112,11 +117,17 @@ Rectangle {
|
||||
color: isActive ? _tileIconActive : _tileIconInactive
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: tileRipple
|
||||
cornerRadius: _tileRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: tileMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => tileRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.toggled()
|
||||
}
|
||||
}
|
||||
@@ -167,7 +178,11 @@ Rectangle {
|
||||
rightHoverOverlay.opacity = 0.0;
|
||||
rightHoverOverlay.visible = false;
|
||||
}
|
||||
onPressed: rightHoverOverlay.opacity = 0.16
|
||||
onPressed: mouse => {
|
||||
const pos = mapToItem(root, mouse.x, mouse.y);
|
||||
bodyRipple.trigger(pos.x, pos.y);
|
||||
rightHoverOverlay.opacity = 0.16;
|
||||
}
|
||||
onReleased: rightHoverOverlay.opacity = containsMouse ? 0.08 : 0.0
|
||||
onClicked: root.expandClicked()
|
||||
onWheel: function (ev) {
|
||||
|
||||
@@ -22,12 +22,18 @@ Row {
|
||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||
|
||||
DankRipple {
|
||||
id: iconRipple
|
||||
cornerRadius: parent.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
anchors.fill: parent
|
||||
visible: defaultSource !== null
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => iconRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (defaultSource) {
|
||||
SessionData.suppressOSDTemporarily();
|
||||
|
||||
@@ -89,12 +89,18 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: ripple
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: root.enabled
|
||||
onPressed: mouse => ripple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
|
||||
|
||||
@@ -105,12 +105,18 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: ripple
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: root.enabled
|
||||
onPressed: mouse => ripple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
|
||||
|
||||
@@ -66,12 +66,18 @@ Rectangle {
|
||||
onRotationCompleted: root.iconRotationCompleted()
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: ripple
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: root.enabled
|
||||
onPressed: mouse => ripple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
|
||||
|
||||
@@ -110,12 +110,18 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: ripple
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: root.enabled
|
||||
onPressed: mouse => ripple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
BasePill {
|
||||
id: root
|
||||
|
||||
enableBackgroundHover: false
|
||||
enableCursor: false
|
||||
section: "left"
|
||||
|
||||
property var widgetData: null
|
||||
property var barConfig: null
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property string section: "left"
|
||||
property var parentScreen
|
||||
property var hoveredItem: null
|
||||
property var topBar: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
property real barSpacing: 4
|
||||
property bool isAutoHideBar: false
|
||||
readonly property real horizontalPadding: (barConfig?.noBackground ?? false) ? 2 : Theme.spacingS
|
||||
property Item windowRoot: (Window.window ? Window.window.contentItem : null)
|
||||
|
||||
property int draggedIndex: -1
|
||||
@@ -66,7 +60,7 @@ Item {
|
||||
readonly property real barY: barBounds.y
|
||||
|
||||
readonly property real minTooltipY: {
|
||||
if (!parentScreen || !isVertical) {
|
||||
if (!parentScreen || !isVerticalOrientation) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -322,7 +316,9 @@ Item {
|
||||
}
|
||||
|
||||
function applyOverflow(baseResult) {
|
||||
const { items } = baseResult;
|
||||
const {
|
||||
items
|
||||
} = baseResult;
|
||||
const maxPinned = root.maxVisibleApps;
|
||||
const maxRunning = root.maxVisibleRunningApps;
|
||||
|
||||
@@ -403,110 +399,19 @@ Item {
|
||||
|
||||
Component.onCompleted: updateModel()
|
||||
|
||||
readonly property int calculatedSize: {
|
||||
const count = dockItems.length;
|
||||
if (count === 0)
|
||||
return 0;
|
||||
|
||||
if (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) {
|
||||
return count * 24 + (count - 1) * Theme.spacingXS + horizontalPadding * 2;
|
||||
} else {
|
||||
return count * (24 + Theme.spacingXS + 120) + (count - 1) * Theme.spacingXS + horizontalPadding * 2;
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real realCalculatedSize: {
|
||||
let total = horizontalPadding * 2;
|
||||
const compact = (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode);
|
||||
|
||||
for (let i = 0; i < dockItems.length; i++) {
|
||||
const item = dockItems[i];
|
||||
const isInOverflow = item.isInOverflow === true;
|
||||
if (isInOverflow && !root.overflowExpanded)
|
||||
continue;
|
||||
|
||||
let itemSize = 0;
|
||||
if (item.type === "separator") {
|
||||
itemSize = 8;
|
||||
} else {
|
||||
itemSize = compact ? 24 : (24 + Theme.spacingXS + 120);
|
||||
}
|
||||
|
||||
total += itemSize;
|
||||
if (i < dockItems.length - 1)
|
||||
total += Theme.spacingXS;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
width: dockItems.length > 0 ? (isVertical ? barThickness : realCalculatedSize) : 0
|
||||
height: dockItems.length > 0 ? (isVertical ? realCalculatedSize : barThickness) : 0
|
||||
visible: dockItems.length > 0
|
||||
|
||||
Item {
|
||||
id: visualBackground
|
||||
width: root.isVertical ? root.widgetThickness : root.realCalculatedSize
|
||||
height: root.isVertical ? root.realCalculatedSize : root.widgetThickness
|
||||
anchors.centerIn: parent
|
||||
clip: false
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0
|
||||
implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0
|
||||
|
||||
Rectangle {
|
||||
id: outline
|
||||
anchors.centerIn: parent
|
||||
width: {
|
||||
const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
||||
return parent.width + borderWidth * 2;
|
||||
}
|
||||
height: {
|
||||
const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
||||
return parent.height + borderWidth * 2;
|
||||
}
|
||||
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
|
||||
color: "transparent"
|
||||
border.width: (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0
|
||||
border.color: {
|
||||
if (!(barConfig?.widgetOutlineEnabled ?? false)) {
|
||||
return "transparent";
|
||||
}
|
||||
const colorOption = barConfig?.widgetOutlineColor || "primary";
|
||||
const opacity = barConfig?.widgetOutlineOpacity ?? 1.0;
|
||||
switch (colorOption) {
|
||||
case "surfaceText":
|
||||
return Theme.withAlpha(Theme.surfaceText, opacity);
|
||||
case "secondary":
|
||||
return Theme.withAlpha(Theme.secondary, opacity);
|
||||
case "primary":
|
||||
return Theme.withAlpha(Theme.primary, opacity);
|
||||
default:
|
||||
return Theme.withAlpha(Theme.primary, opacity);
|
||||
}
|
||||
Loader {
|
||||
id: layoutLoader
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: root.isVerticalOrientation ? columnLayout : rowLayout
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (dockItems.length === 0)
|
||||
return "transparent";
|
||||
if ((barConfig?.noBackground ?? false))
|
||||
return "transparent";
|
||||
|
||||
const baseColor = Theme.widgetBaseBackgroundColor;
|
||||
const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0;
|
||||
if (Theme.widgetBackgroundHasAlpha) {
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * transparency);
|
||||
}
|
||||
return Theme.withAlpha(baseColor, transparency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: layoutLoader
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: root.isVertical ? columnLayout : rowLayout
|
||||
}
|
||||
|
||||
Component {
|
||||
@@ -556,8 +461,8 @@ Item {
|
||||
readonly property bool isInOverflow: modelData.isInOverflow === true
|
||||
|
||||
readonly property real visualSize: isSeparator ? 8 : ((widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? 24 : (24 + Theme.spacingXS + 120))
|
||||
readonly property real visualWidth: root.isVertical ? root.barThickness : visualSize
|
||||
readonly property real visualHeight: root.isVertical ? visualSize : root.barThickness
|
||||
readonly property real visualWidth: root.isVerticalOrientation ? root.barThickness : visualSize
|
||||
readonly property real visualHeight: root.isVerticalOrientation ? visualSize : root.barThickness
|
||||
|
||||
visible: !isInOverflow || root.overflowExpanded
|
||||
opacity: (isInOverflow && !root.overflowExpanded) ? 0 : 1
|
||||
@@ -604,8 +509,8 @@ Item {
|
||||
}
|
||||
|
||||
transform: Translate {
|
||||
x: root.isVertical ? 0 : delegateItem.shiftOffset
|
||||
y: root.isVertical ? delegateItem.shiftOffset : 0
|
||||
x: root.isVerticalOrientation ? 0 : delegateItem.shiftOffset
|
||||
y: root.isVerticalOrientation ? delegateItem.shiftOffset : 0
|
||||
|
||||
Behavior on x {
|
||||
enabled: !root.suppressShiftAnimation
|
||||
@@ -625,8 +530,8 @@ Item {
|
||||
|
||||
Rectangle {
|
||||
visible: isSeparator
|
||||
width: root.isVertical ? root.barThickness * 0.6 : 2
|
||||
height: root.isVertical ? 2 : root.barThickness * 0.6
|
||||
width: root.isVerticalOrientation ? root.barThickness * 0.6 : 2
|
||||
height: root.isVerticalOrientation ? 2 : root.barThickness * 0.6
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
radius: 1
|
||||
anchors.centerIn: parent
|
||||
@@ -640,7 +545,7 @@ Item {
|
||||
iconSize: 24
|
||||
overflowCount: modelData.overflowCount || 0
|
||||
overflowExpanded: root.overflowExpanded
|
||||
isVertical: root.isVertical
|
||||
isVertical: root.isVerticalOrientation
|
||||
showBadge: root.showOverflowBadge
|
||||
z: 10
|
||||
onClicked: {
|
||||
@@ -709,14 +614,14 @@ Item {
|
||||
}
|
||||
|
||||
transform: Translate {
|
||||
x: (dragHandler.dragging && !root.isVertical) ? dragHandler.dragAxisOffset : 0
|
||||
y: (dragHandler.dragging && root.isVertical) ? dragHandler.dragAxisOffset : 0
|
||||
x: (dragHandler.dragging && !root.isVerticalOrientation) ? dragHandler.dragAxisOffset : 0
|
||||
y: (dragHandler.dragging && root.isVerticalOrientation) ? dragHandler.dragAxisOffset : 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: visualContent
|
||||
width: root.isVertical ? 24 : delegateItem.visualSize
|
||||
height: root.isVertical ? delegateItem.visualSize : 24
|
||||
width: root.isVerticalOrientation ? 24 : delegateItem.visualSize
|
||||
height: root.isVerticalOrientation ? delegateItem.visualSize : 24
|
||||
anchors.centerIn: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
@@ -735,11 +640,11 @@ Item {
|
||||
AppIconRenderer {
|
||||
id: coreIcon
|
||||
readonly property bool isCompact: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode)
|
||||
anchors.left: (root.isVertical || isCompact) ? undefined : parent.left
|
||||
anchors.leftMargin: (root.isVertical || isCompact) ? 0 : Theme.spacingXS
|
||||
anchors.top: (root.isVertical && !isCompact) ? parent.top : undefined
|
||||
anchors.topMargin: (root.isVertical && !isCompact) ? Theme.spacingXS : 0
|
||||
anchors.centerIn: (root.isVertical || isCompact) ? parent : undefined
|
||||
anchors.left: (root.isVerticalOrientation || isCompact) ? undefined : parent.left
|
||||
anchors.leftMargin: (root.isVerticalOrientation || isCompact) ? 0 : Theme.spacingXS
|
||||
anchors.top: (root.isVerticalOrientation && !isCompact) ? parent.top : undefined
|
||||
anchors.topMargin: (root.isVerticalOrientation && !isCompact) ? Theme.spacingXS : 0
|
||||
anchors.centerIn: (root.isVerticalOrientation || isCompact) ? parent : undefined
|
||||
|
||||
iconSize: appItem.effectiveIconSize
|
||||
materialIconSizeAdjustment: 0
|
||||
@@ -770,11 +675,11 @@ Item {
|
||||
IconImage {
|
||||
id: iconImg
|
||||
readonly property bool isCompact: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode)
|
||||
anchors.left: (root.isVertical || isCompact) ? undefined : parent.left
|
||||
anchors.leftMargin: (root.isVertical || isCompact) ? 0 : Theme.spacingXS
|
||||
anchors.top: (root.isVertical && !isCompact) ? parent.top : undefined
|
||||
anchors.topMargin: (root.isVertical && !isCompact) ? Theme.spacingXS : 0
|
||||
anchors.centerIn: (root.isVertical || isCompact) ? parent : undefined
|
||||
anchors.left: (root.isVerticalOrientation || isCompact) ? undefined : parent.left
|
||||
anchors.leftMargin: (root.isVerticalOrientation || isCompact) ? 0 : Theme.spacingXS
|
||||
anchors.top: (root.isVerticalOrientation && !isCompact) ? parent.top : undefined
|
||||
anchors.topMargin: (root.isVerticalOrientation && !isCompact) ? Theme.spacingXS : 0
|
||||
anchors.centerIn: (root.isVerticalOrientation || isCompact) ? parent : undefined
|
||||
|
||||
width: appItem.effectiveIconSize
|
||||
height: appItem.effectiveIconSize
|
||||
@@ -815,11 +720,11 @@ Item {
|
||||
|
||||
DankIcon {
|
||||
readonly property bool isCompact: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode)
|
||||
anchors.left: (root.isVertical || isCompact) ? undefined : parent.left
|
||||
anchors.leftMargin: (root.isVertical || isCompact) ? 0 : Theme.spacingXS
|
||||
anchors.top: (root.isVertical && !isCompact) ? parent.top : undefined
|
||||
anchors.topMargin: (root.isVertical && !isCompact) ? Theme.spacingXS : 0
|
||||
anchors.centerIn: (root.isVertical || isCompact) ? parent : undefined
|
||||
anchors.left: (root.isVerticalOrientation || isCompact) ? undefined : parent.left
|
||||
anchors.leftMargin: (root.isVerticalOrientation || isCompact) ? 0 : Theme.spacingXS
|
||||
anchors.top: (root.isVerticalOrientation && !isCompact) ? parent.top : undefined
|
||||
anchors.topMargin: (root.isVerticalOrientation && !isCompact) ? Theme.spacingXS : 0
|
||||
anchors.centerIn: (root.isVerticalOrientation || isCompact) ? parent : undefined
|
||||
|
||||
size: appItem.effectiveIconSize
|
||||
name: "sports_esports"
|
||||
@@ -882,7 +787,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
visible: !root.isVertical && !(widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode)
|
||||
visible: !root.isVerticalOrientation && !(widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode)
|
||||
anchors.left: iconImg.right
|
||||
anchors.leftMargin: Theme.spacingXS
|
||||
anchors.right: parent.right
|
||||
@@ -897,16 +802,16 @@ Item {
|
||||
|
||||
Rectangle {
|
||||
visible: modelData.isRunning && !(widgetData?.appsDockHideIndicators !== undefined ? widgetData.appsDockHideIndicators : SettingsData.appsDockHideIndicators)
|
||||
width: root.isVertical ? 2 : 20
|
||||
height: root.isVertical ? 20 : 2
|
||||
width: root.isVerticalOrientation ? 2 : 20
|
||||
height: root.isVerticalOrientation ? 20 : 2
|
||||
radius: 1
|
||||
color: appItem.isFocused ? Theme.primary : Theme.surfaceText
|
||||
opacity: appItem.isFocused ? 1 : 0.5
|
||||
|
||||
anchors.bottom: root.isVertical ? undefined : parent.bottom
|
||||
anchors.right: root.isVertical ? parent.right : undefined
|
||||
anchors.horizontalCenter: root.isVertical ? undefined : parent.horizontalCenter
|
||||
anchors.verticalCenter: root.isVertical ? parent.verticalCenter : undefined
|
||||
anchors.bottom: root.isVerticalOrientation ? undefined : parent.bottom
|
||||
anchors.right: root.isVerticalOrientation ? parent.right : undefined
|
||||
anchors.horizontalCenter: root.isVerticalOrientation ? undefined : parent.horizontalCenter
|
||||
anchors.verticalCenter: root.isVerticalOrientation ? parent.verticalCenter : undefined
|
||||
|
||||
anchors.margins: 0
|
||||
z: 5
|
||||
@@ -1009,10 +914,10 @@ Item {
|
||||
if (!dragHandler.dragging)
|
||||
return;
|
||||
|
||||
const axisOffset = root.isVertical ? (mouse.y - dragHandler.dragStartPos.y) : (mouse.x - dragHandler.dragStartPos.x);
|
||||
const axisOffset = root.isVerticalOrientation ? (mouse.y - dragHandler.dragStartPos.y) : (mouse.x - dragHandler.dragStartPos.x);
|
||||
dragHandler.dragAxisOffset = axisOffset;
|
||||
|
||||
const itemSize = (root.isVertical ? delegateItem.height : delegateItem.width) + Theme.spacingXS;
|
||||
const itemSize = (root.isVerticalOrientation ? delegateItem.height : delegateItem.width) + Theme.spacingXS;
|
||||
const slotOffset = Math.round(axisOffset / itemSize);
|
||||
const newTargetIndex = Math.max(0, Math.min(root.pinnedAppCount - 1, index + slotOffset));
|
||||
|
||||
@@ -1028,7 +933,7 @@ Item {
|
||||
|
||||
tooltipLoader.active = true;
|
||||
if (tooltipLoader.item) {
|
||||
if (root.isVertical) {
|
||||
if (root.isVerticalOrientation) {
|
||||
const globalPos = delegateItem.mapToGlobal(0, delegateItem.height / 2);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
@@ -213,12 +212,19 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: windowRipple
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: windowArea
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 24
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => windowRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (modelData && modelData.activate) {
|
||||
modelData.activate();
|
||||
@@ -285,11 +291,18 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: actionRipple
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: actionArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => actionRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (modelData) {
|
||||
SessionService.launchDesktopAction(root.desktopEntry, modelData);
|
||||
@@ -333,11 +346,18 @@ PanelWindow {
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: pinRipple
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: pinArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (!root.appData) {
|
||||
return;
|
||||
@@ -386,11 +406,18 @@ PanelWindow {
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: nvidiaRipple
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: nvidiaArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => nvidiaRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (root.desktopEntry) {
|
||||
SessionService.launchDesktopEntry(root.desktopEntry, true);
|
||||
@@ -426,11 +453,18 @@ PanelWindow {
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: closeRipple
|
||||
rippleColor: Theme.error
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => closeRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (root.appData?.type === "window") {
|
||||
root.appData?.toplevel?.close();
|
||||
|
||||
@@ -115,7 +115,8 @@ BasePill {
|
||||
height: battery.height + battery.topMargin + battery.bottomMargin
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
onPressed: mouse => {
|
||||
battery.triggerRipple(this, mouse.x, mouse.y);
|
||||
toggleBatteryPopup();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ BasePill {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => root.triggerRipple(this, mouse.x, mouse.y)
|
||||
onClicked: function (mouse) {
|
||||
switch (mouse.button) {
|
||||
case Qt.RightButton:
|
||||
|
||||
@@ -11,6 +11,8 @@ BasePill {
|
||||
property bool compactMode: false
|
||||
signal clockClicked
|
||||
|
||||
onClicked: clockClicked()
|
||||
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : clockRow.implicitWidth
|
||||
@@ -326,15 +328,4 @@ BasePill {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
x: -root.leftMargin
|
||||
y: -root.topMargin
|
||||
width: root.width + root.leftMargin + root.rightMargin
|
||||
height: root.height + root.topMargin + root.bottomMargin
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
root.clockClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ BasePill {
|
||||
z: 1
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
root.colorPickerRequested();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,8 @@ BasePill {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
DgopService.setSortBy("cpu");
|
||||
cpuClicked();
|
||||
}
|
||||
|
||||
@@ -138,7 +138,8 @@ BasePill {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
DgopService.setSortBy("cpu");
|
||||
cpuTempClicked();
|
||||
}
|
||||
|
||||
@@ -206,7 +206,8 @@ BasePill {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
DgopService.setSortBy("cpu");
|
||||
gpuTempClicked();
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ BasePill {
|
||||
z: 1
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
}
|
||||
onClicked: {
|
||||
SessionService.toggleIdleInhibit();
|
||||
}
|
||||
|
||||
@@ -12,31 +12,101 @@ BasePill {
|
||||
property var widgetData: null
|
||||
property bool compactMode: widgetData?.keyboardLayoutNameCompactMode !== undefined ? widgetData.keyboardLayoutNameCompactMode : SettingsData.keyboardLayoutNameCompactMode
|
||||
readonly property var langCodes: ({
|
||||
"afrikaans": "af", "albanian": "sq", "amharic": "am", "arabic": "ar",
|
||||
"armenian": "hy", "azerbaijani": "az", "basque": "eu", "belarusian": "be",
|
||||
"bengali": "bn", "bosnian": "bs", "bulgarian": "bg", "burmese": "my",
|
||||
"catalan": "ca", "chinese": "zh", "croatian": "hr", "czech": "cs",
|
||||
"danish": "da", "dutch": "nl", "english": "en", "esperanto": "eo",
|
||||
"estonian": "et", "filipino": "fil", "finnish": "fi", "french": "fr",
|
||||
"galician": "gl", "georgian": "ka", "german": "de", "greek": "el",
|
||||
"gujarati": "gu", "hausa": "ha", "hebrew": "he", "hindi": "hi",
|
||||
"hungarian": "hu", "icelandic": "is", "igbo": "ig", "indonesian": "id",
|
||||
"irish": "ga", "italian": "it", "japanese": "ja", "javanese": "jv",
|
||||
"kannada": "kn", "kazakh": "kk", "khmer": "km", "korean": "ko",
|
||||
"kurdish": "ku", "kyrgyz": "ky", "lao": "lo", "latvian": "lv",
|
||||
"lithuanian": "lt", "luxembourgish": "lb", "macedonian": "mk", "malay": "ms",
|
||||
"malayalam": "ml", "maltese": "mt", "maori": "mi", "marathi": "mr",
|
||||
"mongolian": "mn", "nepali": "ne", "norwegian": "no", "pashto": "ps",
|
||||
"persian": "fa", "iranian": "fa", "farsi": "fa", "polish": "pl",
|
||||
"portuguese": "pt", "punjabi": "pa", "romanian": "ro", "russian": "ru",
|
||||
"serbian": "sr", "sindhi": "sd", "sinhala": "si", "slovak": "sk",
|
||||
"slovenian": "sl", "somali": "so", "spanish": "es", "swahili": "sw",
|
||||
"swedish": "sv", "tajik": "tg", "tamil": "ta", "tatar": "tt",
|
||||
"telugu": "te", "thai": "th", "tibetan": "bo", "turkish": "tr",
|
||||
"turkmen": "tk", "ukrainian": "uk", "urdu": "ur", "uyghur": "ug",
|
||||
"uzbek": "uz", "vietnamese": "vi", "welsh": "cy", "yiddish": "yi",
|
||||
"yoruba": "yo", "zulu": "zu"
|
||||
})
|
||||
"afrikaans": "af",
|
||||
"albanian": "sq",
|
||||
"amharic": "am",
|
||||
"arabic": "ar",
|
||||
"armenian": "hy",
|
||||
"azerbaijani": "az",
|
||||
"basque": "eu",
|
||||
"belarusian": "be",
|
||||
"bengali": "bn",
|
||||
"bosnian": "bs",
|
||||
"bulgarian": "bg",
|
||||
"burmese": "my",
|
||||
"catalan": "ca",
|
||||
"chinese": "zh",
|
||||
"croatian": "hr",
|
||||
"czech": "cs",
|
||||
"danish": "da",
|
||||
"dutch": "nl",
|
||||
"english": "en",
|
||||
"esperanto": "eo",
|
||||
"estonian": "et",
|
||||
"filipino": "fil",
|
||||
"finnish": "fi",
|
||||
"french": "fr",
|
||||
"galician": "gl",
|
||||
"georgian": "ka",
|
||||
"german": "de",
|
||||
"greek": "el",
|
||||
"gujarati": "gu",
|
||||
"hausa": "ha",
|
||||
"hebrew": "he",
|
||||
"hindi": "hi",
|
||||
"hungarian": "hu",
|
||||
"icelandic": "is",
|
||||
"igbo": "ig",
|
||||
"indonesian": "id",
|
||||
"irish": "ga",
|
||||
"italian": "it",
|
||||
"japanese": "ja",
|
||||
"javanese": "jv",
|
||||
"kannada": "kn",
|
||||
"kazakh": "kk",
|
||||
"khmer": "km",
|
||||
"korean": "ko",
|
||||
"kurdish": "ku",
|
||||
"kyrgyz": "ky",
|
||||
"lao": "lo",
|
||||
"latvian": "lv",
|
||||
"lithuanian": "lt",
|
||||
"luxembourgish": "lb",
|
||||
"macedonian": "mk",
|
||||
"malay": "ms",
|
||||
"malayalam": "ml",
|
||||
"maltese": "mt",
|
||||
"maori": "mi",
|
||||
"marathi": "mr",
|
||||
"mongolian": "mn",
|
||||
"nepali": "ne",
|
||||
"norwegian": "no",
|
||||
"pashto": "ps",
|
||||
"persian": "fa",
|
||||
"iranian": "fa",
|
||||
"farsi": "fa",
|
||||
"polish": "pl",
|
||||
"portuguese": "pt",
|
||||
"punjabi": "pa",
|
||||
"romanian": "ro",
|
||||
"russian": "ru",
|
||||
"serbian": "sr",
|
||||
"sindhi": "sd",
|
||||
"sinhala": "si",
|
||||
"slovak": "sk",
|
||||
"slovenian": "sl",
|
||||
"somali": "so",
|
||||
"spanish": "es",
|
||||
"swahili": "sw",
|
||||
"swedish": "sv",
|
||||
"tajik": "tg",
|
||||
"tamil": "ta",
|
||||
"tatar": "tt",
|
||||
"telugu": "te",
|
||||
"thai": "th",
|
||||
"tibetan": "bo",
|
||||
"turkish": "tr",
|
||||
"turkmen": "tk",
|
||||
"ukrainian": "uk",
|
||||
"urdu": "ur",
|
||||
"uyghur": "ug",
|
||||
"uzbek": "uz",
|
||||
"vietnamese": "vi",
|
||||
"welsh": "cy",
|
||||
"yiddish": "yi",
|
||||
"yoruba": "yo",
|
||||
"zulu": "zu"
|
||||
})
|
||||
readonly property var validVariants: ["US", "UK", "GB", "AZERTY", "QWERTY", "Dvorak", "Colemak", "Mac", "Intl", "International"]
|
||||
property string currentLayout: {
|
||||
if (CompositorService.isNiri) {
|
||||
@@ -119,6 +189,9 @@ BasePill {
|
||||
z: 1
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
}
|
||||
onClicked: {
|
||||
if (CompositorService.isNiri) {
|
||||
NiriService.cycleKeyboardLayout();
|
||||
|
||||
@@ -171,6 +171,9 @@ BasePill {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
}
|
||||
onClicked: {
|
||||
if (root.popoutTarget && root.popoutTarget.setTriggerPosition) {
|
||||
const globalPos = parent.mapToItem(null, 0, 0);
|
||||
@@ -326,7 +329,8 @@ BasePill {
|
||||
anchors.fill: parent
|
||||
enabled: root.playerAvailable
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
if (root.popoutTarget && root.popoutTarget.setTriggerPosition) {
|
||||
const globalPos = mapToItem(null, 0, 0);
|
||||
const currentScreen = root.parentScreen || Screen;
|
||||
|
||||
@@ -130,6 +130,9 @@ BasePill {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
}
|
||||
onClicked: function (mouse) {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
openContextMenu();
|
||||
|
||||
@@ -1,247 +1,171 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
BasePill {
|
||||
id: root
|
||||
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property string section: "right"
|
||||
property var popupTarget: null
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
property var barConfig: null
|
||||
section: "right"
|
||||
|
||||
property bool showMicIcon: SettingsData.privacyShowMicIcon
|
||||
property bool showCameraIcon: SettingsData.privacyShowCameraIcon
|
||||
property bool showScreenSharingIcon: SettingsData.privacyShowScreenShareIcon
|
||||
|
||||
readonly property real horizontalPadding: (barConfig?.noBackground ?? false) ? 2 : Theme.spacingS
|
||||
readonly property bool hasActivePrivacy: showMicIcon || showCameraIcon || showScreenSharingIcon || PrivacyService.anyPrivacyActive
|
||||
readonly property int activeCount: (showMicIcon ? 1 : PrivacyService.microphoneActive) + (showCameraIcon ? 1 : PrivacyService.cameraActive) + (showScreenSharingIcon ? 1 : PrivacyService.screensharingActive)
|
||||
readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
|
||||
readonly property real contentHeight: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
|
||||
readonly property real visualWidth: isVertical ? widgetThickness : (hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0)
|
||||
readonly property real visualHeight: isVertical ? (hasActivePrivacy ? (contentHeight + horizontalPadding * 2) : 0) : widgetThickness
|
||||
|
||||
width: isVertical ? barThickness : visualWidth
|
||||
height: isVertical ? visualHeight : barThickness
|
||||
visible: hasActivePrivacy
|
||||
opacity: hasActivePrivacy ? 1 : 0
|
||||
enabled: hasActivePrivacy
|
||||
|
||||
Item {
|
||||
id: visualContent
|
||||
width: root.visualWidth
|
||||
height: root.visualHeight
|
||||
anchors.centerIn: parent
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: root.hasActivePrivacy ? root.contentWidth : 0
|
||||
implicitHeight: root.hasActivePrivacy ? root.contentHeight : 0
|
||||
|
||||
Rectangle {
|
||||
id: outline
|
||||
anchors.centerIn: parent
|
||||
width: {
|
||||
const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
||||
return parent.width + borderWidth * 2;
|
||||
}
|
||||
height: {
|
||||
const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
||||
return parent.height + borderWidth * 2;
|
||||
}
|
||||
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
|
||||
color: "transparent"
|
||||
border.width: {
|
||||
if (barConfig?.widgetOutlineEnabled ?? false) {
|
||||
return barConfig?.widgetOutlineThickness ?? 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
border.color: {
|
||||
if (!(barConfig?.widgetOutlineEnabled ?? false)) {
|
||||
return "transparent";
|
||||
}
|
||||
const colorOption = barConfig?.widgetOutlineColor || "primary";
|
||||
const opacity = barConfig?.widgetOutlineOpacity ?? 1.0;
|
||||
switch (colorOption) {
|
||||
case "surfaceText":
|
||||
return Theme.withAlpha(Theme.surfaceText, opacity);
|
||||
case "secondary":
|
||||
return Theme.withAlpha(Theme.secondary, opacity);
|
||||
case "primary":
|
||||
return Theme.withAlpha(Theme.primary, opacity);
|
||||
default:
|
||||
return Theme.withAlpha(Theme.primary, opacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
visible: root.isVerticalOrientation && root.hasActivePrivacy
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (barConfig?.noBackground ?? false) {
|
||||
return "transparent";
|
||||
}
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: PrivacyService.microphoneActive
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
const rawTransparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0;
|
||||
const isHovered = privacyArea.containsMouse;
|
||||
const transparency = isHovered ? Math.max(0.3, rawTransparency) : rawTransparency;
|
||||
const baseColor = isHovered ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
|
||||
return Theme.withAlpha(baseColor, transparency);
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
visible: root.isVertical && root.hasActivePrivacy
|
||||
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: PrivacyService.microphoneActive
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
DankIcon {
|
||||
name: {
|
||||
const sourceAudio = AudioService.source?.audio;
|
||||
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0;
|
||||
if (muted)
|
||||
return "mic_off";
|
||||
return "mic";
|
||||
DankIcon {
|
||||
name: {
|
||||
const sourceAudio = AudioService.source?.audio;
|
||||
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0;
|
||||
if (muted)
|
||||
return "mic_off";
|
||||
return "mic";
|
||||
}
|
||||
size: Theme.iconSizeSmall
|
||||
color: Theme.error
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
size: Theme.iconSizeSmall
|
||||
color: Theme.error
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: PrivacyService.cameraActive
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "camera_video"
|
||||
size: Theme.iconSizeSmall
|
||||
color: Theme.widgetTextColor
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 6
|
||||
height: 6
|
||||
radius: 3
|
||||
color: Theme.error
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: -2
|
||||
anchors.topMargin: -1
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: PrivacyService.screensharingActive
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "screen_share"
|
||||
size: Theme.iconSizeSmall
|
||||
color: Theme.warning
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
visible: !root.isVertical && root.hasActivePrivacy
|
||||
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: showMicIcon || PrivacyService.microphoneActive
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: {
|
||||
const sourceAudio = AudioService.source?.audio;
|
||||
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0;
|
||||
if (muted)
|
||||
return "mic_off";
|
||||
return "mic";
|
||||
}
|
||||
size: Theme.iconSizeSmall
|
||||
color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: showCameraIcon || PrivacyService.cameraActive
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "camera_video"
|
||||
size: Theme.iconSizeSmall
|
||||
color: PrivacyService.cameraActive ? Theme.error : Theme.surfaceText
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 6
|
||||
height: 6
|
||||
radius: 3
|
||||
color: Theme.error
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: -2
|
||||
anchors.topMargin: -1
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: PrivacyService.cameraActive
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "camera_video"
|
||||
size: Theme.iconSizeSmall
|
||||
color: Theme.widgetTextColor
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 6
|
||||
height: 6
|
||||
radius: 3
|
||||
color: Theme.error
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: -2
|
||||
anchors.topMargin: -1
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: PrivacyService.screensharingActive
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "screen_share"
|
||||
size: Theme.iconSizeSmall
|
||||
color: Theme.warning
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: showScreenSharingIcon || PrivacyService.screensharingActive
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
visible: !root.isVerticalOrientation && root.hasActivePrivacy
|
||||
|
||||
DankIcon {
|
||||
name: "screen_share"
|
||||
size: Theme.iconSizeSmall
|
||||
color: PrivacyService.screensharingActive ? Theme.warning : Theme.surfaceText
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: root.showMicIcon || PrivacyService.microphoneActive
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: {
|
||||
const sourceAudio = AudioService.source?.audio;
|
||||
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0;
|
||||
if (muted)
|
||||
return "mic_off";
|
||||
return "mic";
|
||||
}
|
||||
size: Theme.iconSizeSmall
|
||||
color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: root.showCameraIcon || PrivacyService.cameraActive
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "camera_video"
|
||||
size: Theme.iconSizeSmall
|
||||
color: PrivacyService.cameraActive ? Theme.error : Theme.surfaceText
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 6
|
||||
height: 6
|
||||
radius: 3
|
||||
color: Theme.error
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: -2
|
||||
anchors.topMargin: -1
|
||||
visible: PrivacyService.cameraActive
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 18
|
||||
height: 18
|
||||
visible: root.showScreenSharingIcon || PrivacyService.screensharingActive
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "screen_share"
|
||||
size: Theme.iconSizeSmall
|
||||
color: PrivacyService.screensharingActive ? Theme.warning : Theme.surfaceText
|
||||
filled: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: privacyArea
|
||||
z: -1
|
||||
anchors.fill: parent
|
||||
hoverEnabled: hasActivePrivacy
|
||||
enabled: hasActivePrivacy
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: tooltip
|
||||
width: tooltipText.contentWidth + Theme.spacingM * 2
|
||||
@@ -251,7 +175,7 @@ Item {
|
||||
border.color: Theme.outlineMedium
|
||||
border.width: 1
|
||||
visible: false
|
||||
opacity: privacyArea.containsMouse && hasActivePrivacy ? 1 : 0
|
||||
opacity: root.isMouseHovered && hasActivePrivacy ? 1 : 0
|
||||
z: 100
|
||||
x: (parent.width - width) / 2
|
||||
y: -height - Theme.spacingXS
|
||||
@@ -287,7 +211,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
enabled: hasActivePrivacy && visible && !isVertical
|
||||
enabled: hasActivePrivacy && visible && !isVerticalOrientation
|
||||
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
@@ -296,7 +220,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
enabled: hasActivePrivacy && visible && isVertical
|
||||
enabled: hasActivePrivacy && visible && isVerticalOrientation
|
||||
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
|
||||
@@ -161,7 +161,8 @@ BasePill {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
DgopService.setSortBy("memory");
|
||||
ramClicked();
|
||||
}
|
||||
|
||||
@@ -5,25 +5,21 @@ import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
BasePill {
|
||||
id: root
|
||||
|
||||
enableBackgroundHover: false
|
||||
enableCursor: false
|
||||
section: "left"
|
||||
|
||||
property var widgetData: null
|
||||
property var barConfig: null
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property string section: "left"
|
||||
property var parentScreen
|
||||
property var hoveredItem: null
|
||||
property var topBar: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
property real barSpacing: 4
|
||||
property bool isAutoHideBar: false
|
||||
readonly property real horizontalPadding: (barConfig?.noBackground ?? false) ? 2 : Theme.spacingS
|
||||
property Item windowRoot: (Window.window ? Window.window.contentItem : null)
|
||||
|
||||
readonly property real effectiveBarThickness: {
|
||||
@@ -52,7 +48,7 @@ Item {
|
||||
readonly property real barY: barBounds.y
|
||||
|
||||
readonly property real minTooltipY: {
|
||||
if (!parentScreen || !isVertical) {
|
||||
if (!parentScreen || !isVerticalOrientation) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -139,108 +135,42 @@ Item {
|
||||
}
|
||||
}
|
||||
readonly property int windowCount: _groupByApp ? (groupedWindows?.length || 0) : (sortedToplevels?.length || 0)
|
||||
readonly property int calculatedSize: {
|
||||
if (windowCount === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) {
|
||||
return windowCount * 24 + (windowCount - 1) * Theme.spacingXS + horizontalPadding * 2;
|
||||
} else {
|
||||
return windowCount * (24 + Theme.spacingXS + 120) + (windowCount - 1) * Theme.spacingXS + horizontalPadding * 2;
|
||||
}
|
||||
}
|
||||
|
||||
width: windowCount > 0 ? (isVertical ? barThickness : calculatedSize) : 0
|
||||
height: windowCount > 0 ? (isVertical ? calculatedSize : barThickness) : 0
|
||||
visible: windowCount > 0
|
||||
|
||||
Item {
|
||||
id: visualBackground
|
||||
width: root.isVertical ? root.widgetThickness : root.calculatedSize
|
||||
height: root.isVertical ? root.calculatedSize : root.widgetThickness
|
||||
anchors.centerIn: parent
|
||||
clip: false
|
||||
property real scrollAccumulator: 0
|
||||
property real touchpadThreshold: 500
|
||||
|
||||
Rectangle {
|
||||
id: outline
|
||||
anchors.centerIn: parent
|
||||
width: {
|
||||
const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
||||
return parent.width + borderWidth * 2;
|
||||
}
|
||||
height: {
|
||||
const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
||||
return parent.height + borderWidth * 2;
|
||||
}
|
||||
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
|
||||
color: "transparent"
|
||||
border.width: {
|
||||
if (barConfig?.widgetOutlineEnabled ?? false) {
|
||||
return barConfig?.widgetOutlineThickness ?? 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
border.color: {
|
||||
if (!(barConfig?.widgetOutlineEnabled ?? false)) {
|
||||
return "transparent";
|
||||
}
|
||||
const colorOption = barConfig?.widgetOutlineColor || "primary";
|
||||
const opacity = barConfig?.widgetOutlineOpacity ?? 1.0;
|
||||
switch (colorOption) {
|
||||
case "surfaceText":
|
||||
return Theme.withAlpha(Theme.surfaceText, opacity);
|
||||
case "secondary":
|
||||
return Theme.withAlpha(Theme.secondary, opacity);
|
||||
case "primary":
|
||||
return Theme.withAlpha(Theme.primary, opacity);
|
||||
default:
|
||||
return Theme.withAlpha(Theme.primary, opacity);
|
||||
onWheel: function (wheelEvent) {
|
||||
const deltaY = wheelEvent.angleDelta.y;
|
||||
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0;
|
||||
|
||||
const windows = root.sortedToplevels;
|
||||
if (windows.length < 2)
|
||||
return;
|
||||
|
||||
if (isMouseWheel) {
|
||||
let currentIndex = -1;
|
||||
for (var i = 0; i < windows.length; i++) {
|
||||
if (windows[i].activated) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (windowCount === 0) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
if ((barConfig?.noBackground ?? false)) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
const baseColor = Theme.widgetBaseBackgroundColor;
|
||||
const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0;
|
||||
if (Theme.widgetBackgroundHasAlpha) {
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * transparency);
|
||||
}
|
||||
return Theme.withAlpha(baseColor, transparency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
|
||||
property real scrollAccumulator: 0
|
||||
property real touchpadThreshold: 500
|
||||
|
||||
onWheel: wheel => {
|
||||
const deltaY = wheel.angleDelta.y;
|
||||
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0;
|
||||
|
||||
const windows = root.sortedToplevels;
|
||||
if (windows.length < 2) {
|
||||
return;
|
||||
let nextIndex;
|
||||
if (deltaY < 0) {
|
||||
nextIndex = currentIndex === -1 ? 0 : Math.min(currentIndex + 1, windows.length - 1);
|
||||
} else {
|
||||
nextIndex = currentIndex === -1 ? windows.length - 1 : Math.max(currentIndex - 1, 0);
|
||||
}
|
||||
|
||||
if (isMouseWheel) {
|
||||
// Direct mouse wheel action
|
||||
const nextWindow = windows[nextIndex];
|
||||
if (nextWindow)
|
||||
nextWindow.activate();
|
||||
} else {
|
||||
scrollAccumulator += deltaY;
|
||||
|
||||
if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
|
||||
let currentIndex = -1;
|
||||
for (var i = 0; i < windows.length; i++) {
|
||||
if (windows[i].activated) {
|
||||
@@ -250,69 +180,32 @@ Item {
|
||||
}
|
||||
|
||||
let nextIndex;
|
||||
if (deltaY < 0) {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0;
|
||||
} else {
|
||||
nextIndex = Math.min(currentIndex + 1, windows.length - 1);
|
||||
}
|
||||
if (scrollAccumulator < 0) {
|
||||
nextIndex = currentIndex === -1 ? 0 : Math.min(currentIndex + 1, windows.length - 1);
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length - 1;
|
||||
} else {
|
||||
nextIndex = Math.max(currentIndex - 1, 0);
|
||||
}
|
||||
nextIndex = currentIndex === -1 ? windows.length - 1 : Math.max(currentIndex - 1, 0);
|
||||
}
|
||||
|
||||
const nextWindow = windows[nextIndex];
|
||||
if (nextWindow) {
|
||||
if (nextWindow)
|
||||
nextWindow.activate();
|
||||
}
|
||||
} else {
|
||||
// Touchpad - accumulate small deltas
|
||||
scrollAccumulator += deltaY;
|
||||
|
||||
if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
|
||||
let currentIndex = -1;
|
||||
for (var i = 0; i < windows.length; i++) {
|
||||
if (windows[i].activated) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let nextIndex;
|
||||
if (scrollAccumulator < 0) {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0;
|
||||
} else {
|
||||
nextIndex = Math.min(currentIndex + 1, windows.length - 1);
|
||||
}
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length - 1;
|
||||
} else {
|
||||
nextIndex = Math.max(currentIndex - 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const nextWindow = windows[nextIndex];
|
||||
if (nextWindow) {
|
||||
nextWindow.activate();
|
||||
}
|
||||
|
||||
scrollAccumulator = 0;
|
||||
}
|
||||
scrollAccumulator = 0;
|
||||
}
|
||||
|
||||
wheel.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: layoutLoader
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: root.isVertical ? columnLayout : rowLayout
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0
|
||||
implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0
|
||||
|
||||
Loader {
|
||||
id: layoutLoader
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: root.isVerticalOrientation ? columnLayout : rowLayout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
@@ -466,6 +359,7 @@ Item {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onPressed: mouse => root.triggerRipple(this, mouse.x, mouse.y)
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (isGrouped && windowCount > 1) {
|
||||
@@ -495,7 +389,7 @@ Item {
|
||||
windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1));
|
||||
windowContextMenuLoader.item.triggerBarThickness = root.barThickness;
|
||||
windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing;
|
||||
if (root.isVertical) {
|
||||
if (root.isVerticalOrientation) {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||
@@ -526,7 +420,7 @@ Item {
|
||||
root.hoveredItem = delegateItem;
|
||||
tooltipLoader.active = true;
|
||||
if (tooltipLoader.item) {
|
||||
if (root.isVertical) {
|
||||
if (root.isVerticalOrientation) {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||
@@ -711,6 +605,7 @@ Item {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onPressed: mouse => root.triggerRipple(this, mouse.x, mouse.y)
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (isGrouped && windowCount > 1) {
|
||||
@@ -740,7 +635,7 @@ Item {
|
||||
windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1));
|
||||
windowContextMenuLoader.item.triggerBarThickness = root.barThickness;
|
||||
windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing;
|
||||
if (root.isVertical) {
|
||||
if (root.isVerticalOrientation) {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||
@@ -765,7 +660,7 @@ Item {
|
||||
root.hoveredItem = delegateItem;
|
||||
tooltipLoader.active = true;
|
||||
if (tooltipLoader.item) {
|
||||
if (root.isVertical) {
|
||||
if (root.isVerticalOrientation) {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||
|
||||
@@ -6,23 +6,19 @@ import Quickshell.Services.SystemTray
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
BasePill {
|
||||
id: root
|
||||
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
enableBackgroundHover: false
|
||||
enableCursor: false
|
||||
|
||||
property var parentWindow: null
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
property real barSpacing: 4
|
||||
property bool isAtBottom: false
|
||||
property var barConfig: null
|
||||
property bool isAutoHideBar: false
|
||||
readonly property real horizontalPadding: (barConfig?.noBackground ?? false) ? 2 : Theme.spacingS
|
||||
readonly property var hiddenTrayIds: {
|
||||
const envValue = Quickshell.env("DMS_HIDE_TRAYIDS") || "";
|
||||
return envValue ? envValue.split(",").map(id => id.trim().toLowerCase()) : [];
|
||||
@@ -102,21 +98,10 @@ Item {
|
||||
property int dropTargetIndex: -1
|
||||
property bool suppressShiftAnimation: false
|
||||
readonly property bool hasHiddenItems: allTrayItems.length > mainBarItems.length
|
||||
readonly property int calculatedSize: {
|
||||
if (allTrayItems.length === 0)
|
||||
return 0;
|
||||
const itemCount = mainBarItems.length + (hasHiddenItems ? 1 : 0);
|
||||
return itemCount * 24 + horizontalPadding * 2;
|
||||
}
|
||||
readonly property real visualWidth: isVertical ? widgetThickness : calculatedSize
|
||||
readonly property real visualHeight: isVertical ? calculatedSize : widgetThickness
|
||||
|
||||
width: isVertical ? barThickness : visualWidth
|
||||
height: isVertical ? visualHeight : barThickness
|
||||
visible: allTrayItems.length > 0
|
||||
|
||||
readonly property real minTooltipY: {
|
||||
if (!parentScreen || !isVertical) {
|
||||
if (!parentScreen || !isVerticalOrientation) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -135,77 +120,17 @@ Item {
|
||||
property bool menuOpen: false
|
||||
property var currentTrayMenu: null
|
||||
|
||||
Item {
|
||||
id: visualBackground
|
||||
width: root.visualWidth
|
||||
height: root.visualHeight
|
||||
anchors.centerIn: parent
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0
|
||||
implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0
|
||||
|
||||
Rectangle {
|
||||
id: outline
|
||||
anchors.centerIn: parent
|
||||
width: {
|
||||
const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
||||
return parent.width + borderWidth * 2;
|
||||
}
|
||||
height: {
|
||||
const borderWidth = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
||||
return parent.height + borderWidth * 2;
|
||||
}
|
||||
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
|
||||
color: "transparent"
|
||||
border.width: {
|
||||
if (barConfig?.widgetOutlineEnabled ?? false) {
|
||||
return barConfig?.widgetOutlineThickness ?? 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
border.color: {
|
||||
if (!(barConfig?.widgetOutlineEnabled ?? false)) {
|
||||
return "transparent";
|
||||
}
|
||||
const colorOption = barConfig?.widgetOutlineColor || "primary";
|
||||
const opacity = barConfig?.widgetOutlineOpacity ?? 1.0;
|
||||
switch (colorOption) {
|
||||
case "surfaceText":
|
||||
return Theme.withAlpha(Theme.surfaceText, opacity);
|
||||
case "secondary":
|
||||
return Theme.withAlpha(Theme.secondary, opacity);
|
||||
case "primary":
|
||||
return Theme.withAlpha(Theme.primary, opacity);
|
||||
default:
|
||||
return Theme.withAlpha(Theme.primary, opacity);
|
||||
}
|
||||
Loader {
|
||||
id: layoutLoader
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: root.isVerticalOrientation ? columnComp : rowComp
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (allTrayItems.length === 0) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
if ((barConfig?.noBackground ?? false)) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
const baseColor = Theme.widgetBaseBackgroundColor;
|
||||
const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0;
|
||||
if (Theme.widgetBackgroundHasAlpha) {
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * transparency);
|
||||
}
|
||||
return Theme.withAlpha(baseColor, transparency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: layoutLoader
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: root.isVertical ? columnComp : rowComp
|
||||
}
|
||||
|
||||
Component {
|
||||
@@ -334,6 +259,11 @@ Item {
|
||||
font.pixelSize: 10
|
||||
color: Theme.widgetTextColor
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: itemRipple
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -344,6 +274,8 @@ Item {
|
||||
cursorShape: dragHandler.longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor
|
||||
|
||||
onPressed: mouse => {
|
||||
const pos = mapToItem(visualContent, mouse.x, mouse.y);
|
||||
itemRipple.trigger(pos.x, pos.y);
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
dragHandler.dragStartPos = Qt.point(mouse.x, mouse.y);
|
||||
longPressTimer.start();
|
||||
@@ -379,7 +311,7 @@ Item {
|
||||
if (!delegateRoot.trayItem.hasMenu)
|
||||
return;
|
||||
root.menuOpen = false;
|
||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
|
||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
||||
}
|
||||
|
||||
onPositionChanged: mouse => {
|
||||
@@ -412,7 +344,7 @@ Item {
|
||||
if (!delegateRoot.trayItem?.hasMenu)
|
||||
return;
|
||||
root.menuOpen = false;
|
||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
|
||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -438,11 +370,19 @@ Item {
|
||||
color: Theme.widgetTextColor
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: caretRipple
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: caretArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => {
|
||||
caretRipple.trigger(mouse.x, mouse.y);
|
||||
}
|
||||
onClicked: root.menuOpen = !root.menuOpen
|
||||
}
|
||||
}
|
||||
@@ -576,6 +516,11 @@ Item {
|
||||
font.pixelSize: 10
|
||||
color: Theme.widgetTextColor
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: itemRipple
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -586,6 +531,8 @@ Item {
|
||||
cursorShape: dragHandler.longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor
|
||||
|
||||
onPressed: mouse => {
|
||||
const pos = mapToItem(visualContent, mouse.x, mouse.y);
|
||||
itemRipple.trigger(pos.x, pos.y);
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
dragHandler.dragStartPos = Qt.point(mouse.x, mouse.y);
|
||||
longPressTimer.start();
|
||||
@@ -621,7 +568,7 @@ Item {
|
||||
if (!delegateRoot.trayItem.hasMenu)
|
||||
return;
|
||||
root.menuOpen = false;
|
||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
|
||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
||||
}
|
||||
|
||||
onPositionChanged: mouse => {
|
||||
@@ -654,7 +601,7 @@ Item {
|
||||
if (!delegateRoot.trayItem?.hasMenu)
|
||||
return;
|
||||
root.menuOpen = false;
|
||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
|
||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -687,11 +634,19 @@ Item {
|
||||
color: Theme.widgetTextColor
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: caretRippleVert
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: caretAreaVert
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => {
|
||||
caretRippleVert.trigger(mouse.x, mouse.y);
|
||||
}
|
||||
onClicked: root.menuOpen = !root.menuOpen
|
||||
}
|
||||
}
|
||||
@@ -862,7 +817,7 @@ Item {
|
||||
const relativeX = globalPos.x - screenX;
|
||||
const relativeY = globalPos.y - screenY;
|
||||
|
||||
if (root.isVertical) {
|
||||
if (root.isVerticalOrientation) {
|
||||
const edge = root.axis?.edge;
|
||||
let targetX = edge === "left" ? root.barThickness + root.barSpacing + Theme.popupDistance : screen.width - (root.barThickness + root.barSpacing + Theme.popupDistance);
|
||||
const adjustedY = relativeY + root.height / 2 + root.minTooltipY;
|
||||
@@ -900,7 +855,7 @@ Item {
|
||||
height: alignedHeight
|
||||
|
||||
x: Theme.snap((() => {
|
||||
if (root.isVertical) {
|
||||
if (root.isVerticalOrientation) {
|
||||
const edge = root.axis?.edge;
|
||||
if (edge === "left") {
|
||||
const targetX = overflowMenu.anchorPos.x;
|
||||
@@ -918,7 +873,7 @@ Item {
|
||||
})(), overflowMenu.dpr)
|
||||
|
||||
y: Theme.snap((() => {
|
||||
if (root.isVertical) {
|
||||
if (root.isVerticalOrientation) {
|
||||
const top = Math.max(overflowMenu.barY, 10);
|
||||
const bottom = overflowMenu.height - alignedHeight - 10;
|
||||
const want = overflowMenu.anchorPos.y - alignedHeight / 2;
|
||||
@@ -1074,7 +1029,7 @@ Item {
|
||||
|
||||
if (!trayItem.hasMenu)
|
||||
return;
|
||||
root.showForTrayItem(trayItem, menuContainer, parentScreen, root.isAtBottom, root.isVertical, root.axis);
|
||||
root.showForTrayItem(trayItem, menuContainer, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,8 @@ BasePill {
|
||||
z: 1
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
onPressed: mouse => {
|
||||
root.triggerRipple(this, mouse.x, mouse.y);
|
||||
if (popoutTarget && popoutTarget.setTriggerPosition) {
|
||||
const globalPos = root.visualContent.mapToItem(null, 0, 0);
|
||||
const currentScreen = parentScreen || Screen;
|
||||
|
||||
@@ -71,6 +71,7 @@ BasePill {
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
enabled: !DMSNetworkService.isBusy
|
||||
onPressed: event => {
|
||||
root.triggerRipple(this, event.x, event.y);
|
||||
switch (event.button) {
|
||||
case Qt.RightButton:
|
||||
DMSNetworkService.toggleVpn();
|
||||
|
||||
@@ -268,12 +268,19 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: windowRipple
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: windowArea
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 24
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => windowRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (modelData && modelData.activate) {
|
||||
modelData.activate();
|
||||
@@ -340,11 +347,18 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: actionRipple
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: actionArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => actionRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (modelData) {
|
||||
SessionService.launchDesktopAction(root.desktopEntry, modelData);
|
||||
@@ -388,11 +402,18 @@ PanelWindow {
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: pinRipple
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: pinArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => pinRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (!root.appData)
|
||||
return;
|
||||
@@ -441,11 +462,18 @@ PanelWindow {
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: nvidiaRipple
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: nvidiaArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => nvidiaRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (root.desktopEntry) {
|
||||
SessionService.launchDesktopEntry(root.desktopEntry, true);
|
||||
@@ -481,11 +509,18 @@ PanelWindow {
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: closeRipple
|
||||
rippleColor: Theme.error
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => closeRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (root.appData?.type === "window") {
|
||||
root.appData?.toplevel?.close();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@@ -18,6 +19,9 @@ Item {
|
||||
property bool isFirst: false
|
||||
property bool isLast: false
|
||||
property real sectionSpacing: 0
|
||||
property bool enableBackgroundHover: true
|
||||
property bool enableCursor: true
|
||||
readonly property bool isMouseHovered: mouseArea.containsMouse
|
||||
property bool isLeftBarEdge: false
|
||||
property bool isRightBarEdge: false
|
||||
property bool isTopBarEdge: false
|
||||
@@ -38,6 +42,11 @@ Item {
|
||||
signal rightClicked(real rootX, real rootY)
|
||||
signal wheel(var wheelEvent)
|
||||
|
||||
function triggerRipple(sourceItem, mouseX, mouseY) {
|
||||
const pos = sourceItem.mapToItem(visualContent, mouseX, mouseY);
|
||||
rippleLayer.trigger(pos.x, pos.y);
|
||||
}
|
||||
|
||||
width: isVerticalOrientation ? barThickness : visualWidth
|
||||
height: isVerticalOrientation ? visualHeight : barThickness
|
||||
|
||||
@@ -95,7 +104,7 @@ Item {
|
||||
}
|
||||
|
||||
const rawTransparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0;
|
||||
const isHovered = mouseArea.containsMouse || (root.isHovered || false);
|
||||
const isHovered = root.enableBackgroundHover && (mouseArea.containsMouse || (root.isHovered || false));
|
||||
const transparency = isHovered ? Math.max(0.3, rawTransparency) : rawTransparency;
|
||||
const baseColor = isHovered ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
|
||||
|
||||
@@ -106,6 +115,12 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: rippleLayer
|
||||
rippleColor: Theme.surfaceText
|
||||
cornerRadius: background.radius
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: contentLoader
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -121,7 +136,7 @@ Item {
|
||||
width: root.width + root.leftMargin + root.rightMargin
|
||||
height: root.height + root.topMargin + root.bottomMargin
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
cursorShape: root.enableCursor ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onPressed: function (mouse) {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
@@ -129,6 +144,8 @@ Item {
|
||||
root.rightClicked(rPos.x, rPos.y);
|
||||
return;
|
||||
}
|
||||
const ripplePos = mouseArea.mapToItem(visualContent, mouse.x, mouse.y);
|
||||
rippleLayer.trigger(ripplePos.x, ripplePos.y);
|
||||
if (popoutTarget) {
|
||||
// Ensure bar context is set first if supported
|
||||
if (popoutTarget.setBarContext) {
|
||||
|
||||
@@ -313,6 +313,12 @@ Popup {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: menuItemRipple
|
||||
rippleColor: modelData.dangerous ? Theme.error : Theme.surfaceText
|
||||
cornerRadius: menuItem.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: menuItemArea
|
||||
anchors.fill: parent
|
||||
@@ -323,6 +329,7 @@ Popup {
|
||||
keyboardNavigation = false;
|
||||
selectedIndex = index;
|
||||
}
|
||||
onPressed: mouse => menuItemRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: modelData.action()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ Rectangle {
|
||||
property int buttonHeight: 40
|
||||
property int horizontalPadding: Theme.spacingL
|
||||
property bool enableScaleAnimation: false
|
||||
property bool enableRipple: false
|
||||
property bool enableRipple: typeof SettingsData !== "undefined" ? (SettingsData.enableRippleEffects ?? true) : true
|
||||
|
||||
signal clicked
|
||||
|
||||
@@ -55,6 +55,13 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: rippleLayer
|
||||
rippleColor: root.textColor
|
||||
cornerRadius: root.radius
|
||||
enableRipple: root.enableRipple
|
||||
}
|
||||
|
||||
Row {
|
||||
id: contentRow
|
||||
anchors.centerIn: parent
|
||||
@@ -83,6 +90,10 @@ Rectangle {
|
||||
hoverEnabled: true
|
||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
enabled: root.enabled
|
||||
onPressed: mouse => {
|
||||
if (root.enableRipple)
|
||||
rippleLayer.trigger(mouse.x, mouse.y);
|
||||
}
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +169,12 @@ Flow {
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: segmentRipple
|
||||
cornerRadius: Theme.cornerRadius
|
||||
rippleColor: segment.selected ? Theme.buttonText : Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
Item {
|
||||
id: contentItem
|
||||
anchors.centerIn: parent
|
||||
@@ -222,6 +228,7 @@ Flow {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => segmentRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.selectItem(index)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import qs.Common
|
||||
|
||||
// Material Design 3 ripple effect component
|
||||
MouseArea {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property color rippleColor: Theme.primary
|
||||
@@ -11,10 +11,10 @@ MouseArea {
|
||||
|
||||
property real _rippleX: 0
|
||||
property real _rippleY: 0
|
||||
property real _rippleRadius: 0
|
||||
property real _rippleSize: 0
|
||||
readonly property alias animating: rippleAnim.running
|
||||
|
||||
enabled: false
|
||||
hoverEnabled: false
|
||||
anchors.fill: parent
|
||||
|
||||
function trigger(x, y) {
|
||||
if (!enableRipple || Theme.currentAnimationSpeed === SettingsData.AnimationSpeed.None)
|
||||
@@ -24,7 +24,7 @@ MouseArea {
|
||||
_rippleY = y;
|
||||
|
||||
const dist = (ox, oy) => ox * ox + oy * oy;
|
||||
_rippleRadius = Math.sqrt(Math.max(dist(x, y), dist(x, height - y), dist(width - x, y), dist(width - x, height - y)));
|
||||
_rippleSize = Math.sqrt(Math.max(dist(x, y), dist(x, height - y), dist(width - x, y), dist(width - x, height - y))) * 2;
|
||||
|
||||
rippleAnim.restart();
|
||||
}
|
||||
@@ -42,10 +42,20 @@ MouseArea {
|
||||
property: "y"
|
||||
value: root._rippleY
|
||||
}
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "implicitWidth"
|
||||
value: 0
|
||||
}
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "implicitHeight"
|
||||
value: 0
|
||||
}
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "opacity"
|
||||
value: 0.08
|
||||
value: 0.10
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
@@ -53,39 +63,74 @@ MouseArea {
|
||||
target: ripple
|
||||
property: "implicitWidth"
|
||||
from: 0
|
||||
to: root._rippleRadius * 2
|
||||
duration: Theme.expressiveDurations.expressiveEffects
|
||||
to: root._rippleSize
|
||||
duration: Theme.expressiveDurations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Theme.expressiveCurves.standardDecel
|
||||
}
|
||||
DankAnim {
|
||||
target: ripple
|
||||
property: "implicitHeight"
|
||||
from: 0
|
||||
to: root._rippleRadius * 2
|
||||
duration: Theme.expressiveDurations.expressiveEffects
|
||||
to: root._rippleSize
|
||||
duration: Theme.expressiveDurations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Theme.expressiveCurves.standardDecel
|
||||
}
|
||||
}
|
||||
|
||||
DankAnim {
|
||||
target: ripple
|
||||
property: "opacity"
|
||||
to: 0
|
||||
duration: Theme.expressiveDurations.expressiveEffects
|
||||
easing.bezierCurve: Theme.expressiveCurves.standard
|
||||
SequentialAnimation {
|
||||
PauseAnimation {
|
||||
duration: Math.round(Theme.expressiveDurations.expressiveDefaultSpatial * 0.6)
|
||||
}
|
||||
DankAnim {
|
||||
target: ripple
|
||||
property: "opacity"
|
||||
to: 0
|
||||
duration: Theme.expressiveDurations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Theme.expressiveCurves.standard
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: ripple
|
||||
Item {
|
||||
id: rippleContainer
|
||||
anchors.fill: parent
|
||||
visible: root.cornerRadius <= 0
|
||||
|
||||
radius: Math.min(width, height) / 2
|
||||
color: root.rippleColor
|
||||
opacity: 0
|
||||
Rectangle {
|
||||
id: ripple
|
||||
|
||||
transform: Translate {
|
||||
x: -ripple.width / 2
|
||||
y: -ripple.height / 2
|
||||
radius: Math.min(width, height) / 2
|
||||
color: root.rippleColor
|
||||
opacity: 0
|
||||
|
||||
transform: Translate {
|
||||
x: -ripple.width / 2
|
||||
y: -ripple.height / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: rippleMask
|
||||
anchors.fill: parent
|
||||
layer.enabled: root.cornerRadius > 0
|
||||
layer.smooth: true
|
||||
visible: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: root.cornerRadius
|
||||
color: "black"
|
||||
antialiasing: true
|
||||
}
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
anchors.fill: parent
|
||||
source: rippleContainer
|
||||
maskEnabled: true
|
||||
maskSource: rippleMask
|
||||
maskThresholdMin: 0.5
|
||||
maskSpreadAtMin: 1.0
|
||||
visible: root.cornerRadius > 0 && rippleAnim.running
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,81 +27,80 @@ FocusScope {
|
||||
KeyNavigation.backtab: previousFocusTarget
|
||||
KeyNavigation.up: previousFocusTarget
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
Keys.onPressed: event => {
|
||||
if (!tabBar.activeFocus || tabRepeater.count === 0)
|
||||
return
|
||||
|
||||
return;
|
||||
function findSelectableIndex(startIndex, step) {
|
||||
let idx = startIndex
|
||||
let idx = startIndex;
|
||||
for (let i = 0; i < tabRepeater.count; i++) {
|
||||
idx = (idx + step + tabRepeater.count) % tabRepeater.count
|
||||
const item = tabRepeater.itemAt(idx)
|
||||
idx = (idx + step + tabRepeater.count) % tabRepeater.count;
|
||||
const item = tabRepeater.itemAt(idx);
|
||||
if (item && !item.isAction)
|
||||
return idx
|
||||
return idx;
|
||||
}
|
||||
return -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
const goToIndex = (nextIndex) => {
|
||||
const goToIndex = nextIndex => {
|
||||
if (nextIndex >= 0 && nextIndex !== tabBar.currentIndex) {
|
||||
tabBar.currentIndex = nextIndex
|
||||
tabBar.tabClicked(nextIndex)
|
||||
tabBar.currentIndex = nextIndex;
|
||||
tabBar.tabClicked(nextIndex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const resolveTarget = (item) => {
|
||||
const resolveTarget = item => {
|
||||
if (!item)
|
||||
return null
|
||||
return null;
|
||||
|
||||
if (item.focusTarget)
|
||||
return resolveTarget(item.focusTarget)
|
||||
return resolveTarget(item.focusTarget);
|
||||
|
||||
return item
|
||||
}
|
||||
return item;
|
||||
};
|
||||
|
||||
const focusItem = (item) => {
|
||||
const target = resolveTarget(item)
|
||||
const focusItem = item => {
|
||||
const target = resolveTarget(item);
|
||||
if (!target)
|
||||
return false
|
||||
return false;
|
||||
|
||||
if (target.requestFocus) {
|
||||
Qt.callLater(() => target.requestFocus())
|
||||
return true
|
||||
Qt.callLater(() => target.requestFocus());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target.forceActiveFocus) {
|
||||
Qt.callLater(() => target.forceActiveFocus())
|
||||
return true
|
||||
Qt.callLater(() => target.forceActiveFocus());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (event.key === Qt.Key_Right && tabBar.enableArrowNavigation) {
|
||||
const baseIndex = (tabBar.currentIndex >= 0 && tabBar.currentIndex < tabRepeater.count) ? tabBar.currentIndex : -1
|
||||
const nextIndex = findSelectableIndex(baseIndex, 1)
|
||||
const baseIndex = (tabBar.currentIndex >= 0 && tabBar.currentIndex < tabRepeater.count) ? tabBar.currentIndex : -1;
|
||||
const nextIndex = findSelectableIndex(baseIndex, 1);
|
||||
if (nextIndex >= 0) {
|
||||
goToIndex(nextIndex)
|
||||
event.accepted = true
|
||||
goToIndex(nextIndex);
|
||||
event.accepted = true;
|
||||
}
|
||||
} else if (event.key === Qt.Key_Left && tabBar.enableArrowNavigation) {
|
||||
const baseIndex = (tabBar.currentIndex >= 0 && tabBar.currentIndex < tabRepeater.count) ? tabBar.currentIndex : 0
|
||||
const nextIndex = findSelectableIndex(baseIndex, -1)
|
||||
const baseIndex = (tabBar.currentIndex >= 0 && tabBar.currentIndex < tabRepeater.count) ? tabBar.currentIndex : 0;
|
||||
const nextIndex = findSelectableIndex(baseIndex, -1);
|
||||
if (nextIndex >= 0) {
|
||||
goToIndex(nextIndex)
|
||||
event.accepted = true
|
||||
goToIndex(nextIndex);
|
||||
event.accepted = true;
|
||||
}
|
||||
} else if (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier)) {
|
||||
if (focusItem(tabBar.previousFocusTarget)) {
|
||||
event.accepted = true
|
||||
event.accepted = true;
|
||||
}
|
||||
} else if (event.key === Qt.Key_Tab || event.key === Qt.Key_Down) {
|
||||
if (focusItem(tabBar.nextFocusTarget)) {
|
||||
event.accepted = true
|
||||
event.accepted = true;
|
||||
}
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
if (focusItem(tabBar.previousFocusTarget)) {
|
||||
event.accepted = true
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,7 +141,7 @@ FocusScope {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: tabItem.isActive ? Theme.primary : Theme.surfaceText
|
||||
font.weight: tabItem.isActive ? Font.Medium : Font.Normal
|
||||
font.weight: Font.Medium
|
||||
visible: hasText
|
||||
}
|
||||
}
|
||||
@@ -154,7 +153,17 @@ FocusScope {
|
||||
opacity: tabArea.pressed ? 0.12 : (tabArea.containsMouse ? 0.08 : 0)
|
||||
visible: opacity > 0
|
||||
radius: Theme.cornerRadius
|
||||
Behavior on opacity { NumberAnimation { duration: Theme.shortDuration; easing.type: Theme.standardEasing } }
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: tabRipple
|
||||
cornerRadius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -162,15 +171,15 @@ FocusScope {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: mouse => tabRipple.trigger(mouse.x, mouse.y)
|
||||
onClicked: {
|
||||
if (tabItem.isAction) {
|
||||
tabBar.actionTriggered(index)
|
||||
tabBar.actionTriggered(index);
|
||||
} else {
|
||||
tabBar.tabClicked(index)
|
||||
tabBar.tabClicked(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,39 +225,39 @@ FocusScope {
|
||||
|
||||
function updateIndicator() {
|
||||
if (tabRepeater.count === 0 || currentIndex < 0 || currentIndex >= tabRepeater.count) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const item = tabRepeater.itemAt(currentIndex)
|
||||
const item = tabRepeater.itemAt(currentIndex);
|
||||
if (!item || item.isAction) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const tabPos = item.mapToItem(tabBar, 0, 0)
|
||||
const tabCenterX = tabPos.x + item.width / 2
|
||||
const indicatorWidth = 60
|
||||
const tabPos = item.mapToItem(tabBar, 0, 0);
|
||||
const tabCenterX = tabPos.x + item.width / 2;
|
||||
const indicatorWidth = 60;
|
||||
|
||||
if (tabPos.x < 10 && currentIndex > 0) {
|
||||
Qt.callLater(updateIndicator)
|
||||
return
|
||||
Qt.callLater(updateIndicator);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!indicator.initialSetupComplete) {
|
||||
indicator.animationEnabled = false
|
||||
indicator.width = indicatorWidth
|
||||
indicator.x = tabCenterX - indicatorWidth / 2
|
||||
indicator.visible = true
|
||||
indicator.initialSetupComplete = true
|
||||
indicator.animationEnabled = true
|
||||
indicator.animationEnabled = false;
|
||||
indicator.width = indicatorWidth;
|
||||
indicator.x = tabCenterX - indicatorWidth / 2;
|
||||
indicator.visible = true;
|
||||
indicator.initialSetupComplete = true;
|
||||
indicator.animationEnabled = true;
|
||||
} else {
|
||||
indicator.width = indicatorWidth
|
||||
indicator.x = tabCenterX - indicatorWidth / 2
|
||||
indicator.visible = true
|
||||
indicator.width = indicatorWidth;
|
||||
indicator.x = tabCenterX - indicatorWidth / 2;
|
||||
indicator.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
Qt.callLater(updateIndicator)
|
||||
Qt.callLater(updateIndicator);
|
||||
}
|
||||
onWidthChanged: Qt.callLater(updateIndicator)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user