mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2026-08-15 18:43:59 +00:00
QuickSettings: customization!?
This commit is contained in:
@@ -95,6 +95,24 @@
|
||||
"label": "Position",
|
||||
"description": "Choose where the Control Center panel appears when opened."
|
||||
}
|
||||
},
|
||||
"controlCenter": {
|
||||
"quickSettingsStyle": {
|
||||
"section": {
|
||||
"label": "Quick Settings Style",
|
||||
"description": "Choose the visual style for quick settings buttons."
|
||||
},
|
||||
"style": {
|
||||
"label": "Display Style",
|
||||
"description": "Select between modern card-style buttons or classic icon buttons."
|
||||
}
|
||||
},
|
||||
"widgets": {
|
||||
"section": {
|
||||
"label": "Widgets",
|
||||
"description": "Manage and configure Control Center widgets."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"audio": {
|
||||
@@ -1241,6 +1259,10 @@
|
||||
"bottom_right": "Bottom right",
|
||||
"bottom_center": "Bottom center",
|
||||
"top_center": "Top center"
|
||||
},
|
||||
"quickSettingsStyle": {
|
||||
"modern": "Modern Cards",
|
||||
"classic": "Classic Icons"
|
||||
}
|
||||
},
|
||||
"osd": {
|
||||
|
||||
@@ -112,7 +112,36 @@
|
||||
"terminalCommand": "xterm -e"
|
||||
},
|
||||
"controlCenter": {
|
||||
"position": "close_to_bar_button"
|
||||
"position": "close_to_bar_button",
|
||||
"quickSettingsStyle": "modern",
|
||||
"widgets": {
|
||||
"quickSettings": [
|
||||
{
|
||||
"id": "WiFi"
|
||||
},
|
||||
{
|
||||
"id": "Bluetooth"
|
||||
},
|
||||
{
|
||||
"id": "DoNotDisturb"
|
||||
},
|
||||
{
|
||||
"id": "NightLight"
|
||||
},
|
||||
{
|
||||
"id": "KeepAwake"
|
||||
},
|
||||
{
|
||||
"id": "PowerProfile"
|
||||
},
|
||||
{
|
||||
"id": "ScreenRecorder"
|
||||
},
|
||||
{
|
||||
"id": "WallpaperSelector"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dock": {
|
||||
"displayMode": "always_visible",
|
||||
|
||||
@@ -246,6 +246,7 @@ Singleton {
|
||||
property JsonObject controlCenter: JsonObject {
|
||||
// Position: close_to_bar_button, center, top_left, top_right, bottom_left, bottom_right, bottom_center, top_center
|
||||
property string position: "close_to_bar_button"
|
||||
property string quickSettingsStyle: "modern" // "modern" or "classic"
|
||||
property JsonObject widgets
|
||||
widgets: JsonObject {
|
||||
property list<var> quickSettings: [{
|
||||
|
||||
@@ -106,8 +106,8 @@ NBox {
|
||||
id: grid
|
||||
Layout.fillWidth: true
|
||||
columns: 3
|
||||
columnSpacing: Style.marginL * scaling
|
||||
rowSpacing: Style.marginM * scaling
|
||||
columnSpacing: Style.marginM * scaling
|
||||
rowSpacing: Style.marginS * scaling
|
||||
|
||||
Repeater {
|
||||
model: Settings.data.controlCenter.widgets.quickSettings
|
||||
|
||||
@@ -4,14 +4,17 @@ import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NButton {
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
outlined: true
|
||||
text: "Bluetooth"
|
||||
fontSize: Style.fontSizeS * scaling
|
||||
fontWeight: Style.fontWeightRegular
|
||||
fontWeight: Style.fontWeightMedium
|
||||
icon: BluetoothService.enabled ? "bluetooth" : "bluetooth-off"
|
||||
active: BluetoothService.enabled
|
||||
tooltipText: BluetoothService.enabled ? "Bluetooth enabled" : "Bluetooth disabled"
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this)
|
||||
}
|
||||
|
||||
@@ -4,14 +4,17 @@ import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NButton {
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
outlined: true
|
||||
text: "Do not Disturb"
|
||||
fontSize: Style.fontSizeS * scaling
|
||||
fontWeight: Style.fontWeightRegular
|
||||
icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell"
|
||||
fontWeight: Style.fontWeightMedium
|
||||
icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell"
|
||||
active: Settings.data.notifications.doNotDisturb
|
||||
tooltipText: Settings.data.notifications.doNotDisturb ? "Turn off Do Not Disturb" : "Turn on Do Not Disturb"
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
onClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
|
||||
}
|
||||
|
||||
@@ -4,14 +4,17 @@ import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NButton {
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
outlined: true
|
||||
text: IdleInhibitorService.isInhibited ? "Keep-awake" : "Keep-awake"
|
||||
text: "Keep-awake"
|
||||
fontSize: Style.fontSizeS * scaling
|
||||
fontWeight: Style.fontWeightRegular
|
||||
fontWeight: Style.fontWeightMedium
|
||||
icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off"
|
||||
active: IdleInhibitorService.isInhibited
|
||||
tooltipText: IdleInhibitorService.isInhibited ? "Disable keep-awake" : "Enable keep-awake"
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
onClicked: IdleInhibitorService.manualToggle()
|
||||
}
|
||||
|
||||
@@ -4,16 +4,27 @@ import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NButton {
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
outlined: true
|
||||
enabled: ProgramCheckerService.wlsunsetAvailable
|
||||
text: "Night Light"
|
||||
fontSize: Style.fontSizeS * scaling
|
||||
fontWeight: Style.fontWeightRegular
|
||||
fontWeight: Style.fontWeightMedium
|
||||
icon: Settings.data.nightLight.enabled ? (Settings.data.nightLight.forced ? "nightlight-forced" : "nightlight-on") : "nightlight-off"
|
||||
active: Settings.data.nightLight.enabled
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
tooltipText: {
|
||||
if (!Settings.data.nightLight.enabled) {
|
||||
return "Turn on Night Light"
|
||||
} else if (Settings.data.nightLight.forced) {
|
||||
return "Night Light forced on"
|
||||
} else {
|
||||
return "Turn off Night Light"
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (!Settings.data.nightLight.enabled) {
|
||||
Settings.data.nightLight.enabled = true
|
||||
@@ -25,6 +36,7 @@ NButton {
|
||||
Settings.data.nightLight.forced = false
|
||||
}
|
||||
}
|
||||
|
||||
onRightClicked: {
|
||||
var settingsPanel = PanelService.getPanel("settingsPanel")
|
||||
settingsPanel.requestedTab = SettingsPanel.Tab.Display
|
||||
|
||||
@@ -6,17 +6,20 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
// Performance
|
||||
NButton {
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
readonly property bool hasPP: PowerProfileService.available
|
||||
|
||||
enabled: hasPP
|
||||
outlined: true
|
||||
text: PowerProfileService.getName()
|
||||
fontSize: Style.fontSizeS * scaling
|
||||
fontWeight: Style.fontWeightRegular
|
||||
fontWeight: Style.fontWeightMedium
|
||||
icon: PowerProfileService.getIcon()
|
||||
active: hasPP
|
||||
tooltipText: hasPP ? "Current: " + PowerProfileService.getName() : "Power profiles not available"
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
onClicked: {
|
||||
PowerProfileService.cycleProfile()
|
||||
}
|
||||
|
||||
@@ -4,17 +4,19 @@ import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NButton {
|
||||
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
enabled: ProgramCheckerService.gpuScreenRecorderAvailable
|
||||
outlined: true
|
||||
icon: "camera-video"
|
||||
text: "Screen Rec."
|
||||
fontSize: Style.fontSizeS * scaling
|
||||
fontWeight: Style.fontWeightRegular
|
||||
fontWeight: Style.fontWeightMedium
|
||||
active: ScreenRecorderService.isRecording
|
||||
tooltipText: ScreenRecorderService.isRecording ? "Stop recording" : "Start screen recording"
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
onClicked: {
|
||||
ScreenRecorderService.toggleRecording()
|
||||
if (!ScreenRecorderService.isRecording) {
|
||||
|
||||
@@ -4,17 +4,19 @@ import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NButton {
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
|
||||
enabled: Settings.data.wallpaper.enabled
|
||||
outlined: true
|
||||
icon: "wallpaper-selector"
|
||||
text: "Wallpaper"
|
||||
fontSize: Style.fontSizeS * scaling
|
||||
fontWeight: Style.fontWeightRegular
|
||||
fontWeight: Style.fontWeightMedium
|
||||
active: Settings.data.wallpaper.enabled
|
||||
tooltipText: "Open wallpaper selector"
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
onClicked: PanelService.getPanel("wallpaperPanel")?.toggle(this)
|
||||
onRightClicked: WallpaperService.setRandomWallpaper()
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@ import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NButton {
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
|
||||
outlined: true
|
||||
icon: {
|
||||
try {
|
||||
if (NetworkService.ethernetConnected) {
|
||||
@@ -30,13 +28,47 @@ NButton {
|
||||
return "signal_wifi_bad"
|
||||
}
|
||||
}
|
||||
|
||||
text: {
|
||||
if (NetworkService.ethernetConnected) {
|
||||
return "Network"
|
||||
}
|
||||
return "Wi-Fi"
|
||||
}
|
||||
|
||||
fontSize: Style.fontSizeS * scaling
|
||||
fontWeight: Style.fontWeightRegular
|
||||
fontWeight: Style.fontWeightMedium
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
active: {
|
||||
if (NetworkService.ethernetConnected) {
|
||||
return true
|
||||
}
|
||||
try {
|
||||
for (const net in NetworkService.networks) {
|
||||
if (NetworkService.networks[net].connected) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
tooltipText: {
|
||||
if (NetworkService.ethernetConnected) {
|
||||
return "Ethernet connected"
|
||||
}
|
||||
let connected = false
|
||||
for (const net in NetworkService.networks) {
|
||||
if (NetworkService.networks[net].connected) {
|
||||
connected = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return connected ? "Wi-Fi connected" : "Wi-Fi disconnected"
|
||||
}
|
||||
|
||||
onClicked: PanelService.getPanel("wifiPanel")?.toggle(this)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,41 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
// Quick Settings Style Section
|
||||
ColumnLayout {
|
||||
spacing: Style.marginL * scaling
|
||||
Layout.fillWidth: true
|
||||
|
||||
NHeader {
|
||||
label: I18n.tr("settings.controlCenter.quickSettingsStyle.section.label")
|
||||
description: I18n.tr("settings.controlCenter.quickSettingsStyle.section.description")
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
id: quickSettingsStyle
|
||||
label: I18n.tr("settings.controlCenter.quickSettingsStyle.style.label")
|
||||
description: I18n.tr("settings.controlCenter.quickSettingsStyle.style.description")
|
||||
Layout.fillWidth: true
|
||||
model: [{
|
||||
"key": "modern",
|
||||
"name": I18n.tr("options.controlCenter.quickSettingsStyle.modern")
|
||||
}, {
|
||||
"key": "classic",
|
||||
"name": I18n.tr("options.controlCenter.quickSettingsStyle.classic")
|
||||
}]
|
||||
currentKey: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
onSelected: function (key) {
|
||||
Settings.data.controlCenter.quickSettingsStyle = key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginXL * scaling
|
||||
Layout.bottomMargin: Style.marginXL * scaling
|
||||
}
|
||||
|
||||
// Widgets Management Section
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXXS * scaling
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ Rectangle {
|
||||
property int fontWeight: Style.fontWeightBold
|
||||
property real iconSize: Style.fontSizeL * scaling
|
||||
property bool outlined: false
|
||||
property int horizontalAlignment: Qt.AlignHCenter
|
||||
property int horizontalAlignment: Qt.AlignHCenter
|
||||
|
||||
// Signals
|
||||
signal clicked
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Effects
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
// Public properties
|
||||
property string text: ""
|
||||
property string icon: ""
|
||||
property string tooltipText: ""
|
||||
property bool enabled: true
|
||||
property bool active: false
|
||||
property bool compact: false
|
||||
property string style: "modern" // "modern" or "classic"
|
||||
|
||||
// Styling properties
|
||||
property real fontSize: Style.fontSizeS * scaling
|
||||
property int fontWeight: Style.fontWeightMedium
|
||||
property real iconSize: Style.fontSizeL * scaling
|
||||
property real cornerRadius: Style.radiusM * scaling
|
||||
|
||||
// Colors - Style-dependent colors
|
||||
property color backgroundColor: style === "classic" ? Color.mSurfaceVariant : Color.mSurface
|
||||
property color textColor: Color.mOnSurface
|
||||
property color iconColor: style === "classic" ? Color.mPrimary : (active ? Color.mPrimary : Color.mOnSurface)
|
||||
property color borderColor: Color.mOutline
|
||||
property color hoverColor: style === "classic" ? Color.mTertiary : Color.mPrimary
|
||||
property color pressedColor: style === "classic" ? Color.mTertiary : Qt.darker(Color.mPrimary, 1.1)
|
||||
property color hoverTextColor: Color.mOnPrimary
|
||||
property color hoverIconColor: style === "classic" ? Color.mOnTertiary : Color.mOnPrimary
|
||||
|
||||
// Signals
|
||||
signal clicked
|
||||
signal rightClicked
|
||||
signal middleClicked
|
||||
|
||||
// Internal properties
|
||||
property bool hovered: false
|
||||
property bool pressed: false
|
||||
property real scaling: 1.0
|
||||
|
||||
// Dimensions - Style-dependent sizing
|
||||
implicitWidth: {
|
||||
if (style === "classic") {
|
||||
return Style.baseWidgetSize * scaling
|
||||
}
|
||||
return compact ? Math.max(100 * scaling, contentRow.implicitWidth + (Style.marginL * scaling)) : Math.max(120 * scaling, contentRow.implicitWidth + (Style.marginL * scaling))
|
||||
}
|
||||
implicitHeight: {
|
||||
if (style === "classic") {
|
||||
return Style.baseWidgetSize * scaling
|
||||
}
|
||||
return compact ? Math.max(48 * scaling, contentRow.implicitHeight + (Style.marginM * scaling)) : Math.max(56 * scaling, contentRow.implicitHeight + (Style.marginL * scaling))
|
||||
}
|
||||
|
||||
// Appearance - Style-dependent styling
|
||||
radius: style === "classic" ? width * 0.5 : cornerRadius
|
||||
color: {
|
||||
if (!enabled)
|
||||
return Qt.lighter(Color.mSurface, 1.1)
|
||||
if (pressed)
|
||||
return pressedColor
|
||||
if (hovered)
|
||||
return hoverColor
|
||||
return backgroundColor
|
||||
}
|
||||
|
||||
border.width: style === "classic" ? Math.max(1, Style.borderS * scaling) : 0
|
||||
border.color: style === "classic" ? borderColor : "transparent"
|
||||
|
||||
opacity: enabled ? (style === "classic" ? Style.opacityFull : 1.0) : (style === "classic" ? Style.opacityMedium : 0.6)
|
||||
|
||||
// Smooth animations
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: style === "classic" ? Style.animationNormal : Style.animationFast
|
||||
easing.type: style === "classic" ? Easing.InOutQuad : Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
duration: style === "classic" ? Style.animationNormal : Style.animationFast
|
||||
easing.type: style === "classic" ? Easing.InOutQuad : Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
// Hover scale effect
|
||||
scale: hovered ? 1.02 : 1.0
|
||||
|
||||
// Subtle shadow/elevation effect
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
color: Qt.rgba(0, 0, 0, 0.1)
|
||||
visible: active
|
||||
z: -1
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modern style - icon above text
|
||||
ColumnLayout {
|
||||
id: contentRow
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginXXS * scaling
|
||||
visible: root.style !== "classic"
|
||||
|
||||
// Icon
|
||||
NIcon {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
visible: root.icon !== ""
|
||||
icon: root.icon
|
||||
pointSize: root.iconSize
|
||||
color: {
|
||||
if (!root.enabled)
|
||||
return Color.mOnSurfaceVariant
|
||||
if (root.hovered)
|
||||
return root.hoverIconColor
|
||||
return root.iconColor
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Text content
|
||||
NText {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
visible: root.text !== "" && !compact
|
||||
text: root.text
|
||||
pointSize: root.fontSize
|
||||
font.weight: root.fontWeight
|
||||
color: {
|
||||
if (!root.enabled)
|
||||
return Color.mOnSurfaceVariant
|
||||
if (root.hovered)
|
||||
return root.hoverTextColor
|
||||
return root.textColor
|
||||
}
|
||||
elide: Text.ElideRight
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Classic style - EXACTLY like NIconButton (icon + text)
|
||||
RowLayout {
|
||||
anchors.centerIn: parent
|
||||
visible: root.style === "classic"
|
||||
spacing: Style.marginXS * scaling
|
||||
|
||||
NIcon {
|
||||
visible: root.icon !== ""
|
||||
icon: root.icon
|
||||
pointSize: Style.fontSizeM * scaling
|
||||
color: {
|
||||
if (!root.enabled)
|
||||
return Color.mOnSurfaceVariant
|
||||
if (root.hovered)
|
||||
return root.hoverIconColor
|
||||
return root.iconColor
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
visible: root.text !== ""
|
||||
text: root.text
|
||||
pointSize: root.fontSize
|
||||
font.weight: root.fontWeight
|
||||
color: {
|
||||
if (!root.enabled)
|
||||
return Color.mOnSurfaceVariant
|
||||
if (root.hovered)
|
||||
return root.hoverTextColor
|
||||
return root.textColor
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse interaction with enhanced feedback
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
enabled: root.enabled
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
|
||||
onEntered: {
|
||||
root.hovered = true
|
||||
if (tooltipText) {
|
||||
TooltipService.show(Screen, root, root.tooltipText)
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
root.hovered = false
|
||||
if (tooltipText) {
|
||||
TooltipService.hide()
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: mouse => {
|
||||
root.pressed = true
|
||||
root.scale = 0.95
|
||||
if (tooltipText) {
|
||||
TooltipService.hide()
|
||||
}
|
||||
}
|
||||
|
||||
onReleased: mouse => {
|
||||
root.pressed = false
|
||||
root.scale = 1.0
|
||||
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
root.clicked()
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
root.rightClicked()
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
root.middleClicked()
|
||||
}
|
||||
}
|
||||
|
||||
onCanceled: {
|
||||
root.hovered = false
|
||||
root.pressed = false
|
||||
root.scale = 1.0
|
||||
if (tooltipText) {
|
||||
TooltipService.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ripple effect for M3-style interaction feedback
|
||||
Rectangle {
|
||||
id: ripple
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
color: Qt.rgba(1, 1, 1, 0.2)
|
||||
scale: 0
|
||||
opacity: 0
|
||||
visible: false
|
||||
|
||||
SequentialAnimation {
|
||||
id: rippleAnimation
|
||||
running: false
|
||||
|
||||
ParallelAnimation {
|
||||
NumberAnimation {
|
||||
target: ripple
|
||||
property: "scale"
|
||||
from: 0
|
||||
to: 1.2
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
target: ripple
|
||||
property: "opacity"
|
||||
from: 0.6
|
||||
to: 0
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger ripple effect on click
|
||||
Connections {
|
||||
target: root
|
||||
function onClicked() {
|
||||
ripple.visible = true
|
||||
rippleAnimation.start()
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up ripple after animation
|
||||
Connections {
|
||||
target: rippleAnimation
|
||||
function onFinished() {
|
||||
ripple.visible = false
|
||||
ripple.scale = 0
|
||||
ripple.opacity = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user