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",
|
"label": "Position",
|
||||||
"description": "Choose where the Control Center panel appears when opened."
|
"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": {
|
"audio": {
|
||||||
@@ -1241,6 +1259,10 @@
|
|||||||
"bottom_right": "Bottom right",
|
"bottom_right": "Bottom right",
|
||||||
"bottom_center": "Bottom center",
|
"bottom_center": "Bottom center",
|
||||||
"top_center": "Top center"
|
"top_center": "Top center"
|
||||||
|
},
|
||||||
|
"quickSettingsStyle": {
|
||||||
|
"modern": "Modern Cards",
|
||||||
|
"classic": "Classic Icons"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"osd": {
|
"osd": {
|
||||||
|
|||||||
@@ -112,7 +112,36 @@
|
|||||||
"terminalCommand": "xterm -e"
|
"terminalCommand": "xterm -e"
|
||||||
},
|
},
|
||||||
"controlCenter": {
|
"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": {
|
"dock": {
|
||||||
"displayMode": "always_visible",
|
"displayMode": "always_visible",
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ Singleton {
|
|||||||
property JsonObject controlCenter: JsonObject {
|
property JsonObject controlCenter: JsonObject {
|
||||||
// Position: close_to_bar_button, center, top_left, top_right, bottom_left, bottom_right, bottom_center, top_center
|
// 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 position: "close_to_bar_button"
|
||||||
|
property string quickSettingsStyle: "modern" // "modern" or "classic"
|
||||||
property JsonObject widgets
|
property JsonObject widgets
|
||||||
widgets: JsonObject {
|
widgets: JsonObject {
|
||||||
property list<var> quickSettings: [{
|
property list<var> quickSettings: [{
|
||||||
|
|||||||
@@ -106,8 +106,8 @@ NBox {
|
|||||||
id: grid
|
id: grid
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
columns: 3
|
columns: 3
|
||||||
columnSpacing: Style.marginL * scaling
|
columnSpacing: Style.marginM * scaling
|
||||||
rowSpacing: Style.marginM * scaling
|
rowSpacing: Style.marginS * scaling
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: Settings.data.controlCenter.widgets.quickSettings
|
model: Settings.data.controlCenter.widgets.quickSettings
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ import qs.Commons
|
|||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
NButton {
|
NQuickSetting {
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property real scaling: 1.0
|
property real scaling: 1.0
|
||||||
|
|
||||||
outlined: true
|
|
||||||
text: "Bluetooth"
|
text: "Bluetooth"
|
||||||
fontSize: Style.fontSizeS * scaling
|
fontSize: Style.fontSizeS * scaling
|
||||||
fontWeight: Style.fontWeightRegular
|
fontWeight: Style.fontWeightMedium
|
||||||
icon: BluetoothService.enabled ? "bluetooth" : "bluetooth-off"
|
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)
|
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ import qs.Commons
|
|||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
NButton {
|
NQuickSetting {
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property real scaling: 1.0
|
property real scaling: 1.0
|
||||||
|
|
||||||
outlined: true
|
|
||||||
text: "Do not Disturb"
|
text: "Do not Disturb"
|
||||||
fontSize: Style.fontSizeS * scaling
|
fontSize: Style.fontSizeS * scaling
|
||||||
fontWeight: Style.fontWeightRegular
|
fontWeight: Style.fontWeightMedium
|
||||||
icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell"
|
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
|
onClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ import qs.Commons
|
|||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
NButton {
|
NQuickSetting {
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property real scaling: 1.0
|
property real scaling: 1.0
|
||||||
|
|
||||||
outlined: true
|
text: "Keep-awake"
|
||||||
text: IdleInhibitorService.isInhibited ? "Keep-awake" : "Keep-awake"
|
|
||||||
fontSize: Style.fontSizeS * scaling
|
fontSize: Style.fontSizeS * scaling
|
||||||
fontWeight: Style.fontWeightRegular
|
fontWeight: Style.fontWeightMedium
|
||||||
icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off"
|
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()
|
onClicked: IdleInhibitorService.manualToggle()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,27 @@ import qs.Commons
|
|||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
NButton {
|
NQuickSetting {
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property real scaling: 1.0
|
property real scaling: 1.0
|
||||||
|
|
||||||
outlined: true
|
|
||||||
enabled: ProgramCheckerService.wlsunsetAvailable
|
enabled: ProgramCheckerService.wlsunsetAvailable
|
||||||
text: "Night Light"
|
text: "Night Light"
|
||||||
fontSize: Style.fontSizeS * scaling
|
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"
|
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: {
|
onClicked: {
|
||||||
if (!Settings.data.nightLight.enabled) {
|
if (!Settings.data.nightLight.enabled) {
|
||||||
Settings.data.nightLight.enabled = true
|
Settings.data.nightLight.enabled = true
|
||||||
@@ -25,6 +36,7 @@ NButton {
|
|||||||
Settings.data.nightLight.forced = false
|
Settings.data.nightLight.forced = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRightClicked: {
|
onRightClicked: {
|
||||||
var settingsPanel = PanelService.getPanel("settingsPanel")
|
var settingsPanel = PanelService.getPanel("settingsPanel")
|
||||||
settingsPanel.requestedTab = SettingsPanel.Tab.Display
|
settingsPanel.requestedTab = SettingsPanel.Tab.Display
|
||||||
|
|||||||
@@ -6,17 +6,20 @@ import qs.Services
|
|||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
// Performance
|
// Performance
|
||||||
NButton {
|
NQuickSetting {
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property real scaling: 1.0
|
property real scaling: 1.0
|
||||||
readonly property bool hasPP: PowerProfileService.available
|
readonly property bool hasPP: PowerProfileService.available
|
||||||
|
|
||||||
enabled: hasPP
|
enabled: hasPP
|
||||||
outlined: true
|
|
||||||
text: PowerProfileService.getName()
|
text: PowerProfileService.getName()
|
||||||
fontSize: Style.fontSizeS * scaling
|
fontSize: Style.fontSizeS * scaling
|
||||||
fontWeight: Style.fontWeightRegular
|
fontWeight: Style.fontWeightMedium
|
||||||
icon: PowerProfileService.getIcon()
|
icon: PowerProfileService.getIcon()
|
||||||
|
active: hasPP
|
||||||
|
tooltipText: hasPP ? "Current: " + PowerProfileService.getName() : "Power profiles not available"
|
||||||
|
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
PowerProfileService.cycleProfile()
|
PowerProfileService.cycleProfile()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,19 @@ import qs.Commons
|
|||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
NButton {
|
NQuickSetting {
|
||||||
|
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property real scaling: 1.0
|
property real scaling: 1.0
|
||||||
|
|
||||||
enabled: ProgramCheckerService.gpuScreenRecorderAvailable
|
enabled: ProgramCheckerService.gpuScreenRecorderAvailable
|
||||||
outlined: true
|
|
||||||
icon: "camera-video"
|
icon: "camera-video"
|
||||||
text: "Screen Rec."
|
text: "Screen Rec."
|
||||||
fontSize: Style.fontSizeS * scaling
|
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: {
|
onClicked: {
|
||||||
ScreenRecorderService.toggleRecording()
|
ScreenRecorderService.toggleRecording()
|
||||||
if (!ScreenRecorderService.isRecording) {
|
if (!ScreenRecorderService.isRecording) {
|
||||||
|
|||||||
@@ -4,17 +4,19 @@ import qs.Commons
|
|||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
NButton {
|
NQuickSetting {
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property real scaling: 1.0
|
property real scaling: 1.0
|
||||||
|
|
||||||
|
|
||||||
enabled: Settings.data.wallpaper.enabled
|
enabled: Settings.data.wallpaper.enabled
|
||||||
outlined: true
|
|
||||||
icon: "wallpaper-selector"
|
icon: "wallpaper-selector"
|
||||||
text: "Wallpaper"
|
text: "Wallpaper"
|
||||||
fontSize: Style.fontSizeS * scaling
|
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)
|
onClicked: PanelService.getPanel("wallpaperPanel")?.toggle(this)
|
||||||
onRightClicked: WallpaperService.setRandomWallpaper()
|
onRightClicked: WallpaperService.setRandomWallpaper()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,10 @@ import qs.Commons
|
|||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
NButton {
|
NQuickSetting {
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property real scaling: 1.0
|
property real scaling: 1.0
|
||||||
|
|
||||||
|
|
||||||
outlined: true
|
|
||||||
icon: {
|
icon: {
|
||||||
try {
|
try {
|
||||||
if (NetworkService.ethernetConnected) {
|
if (NetworkService.ethernetConnected) {
|
||||||
@@ -30,13 +28,47 @@ NButton {
|
|||||||
return "signal_wifi_bad"
|
return "signal_wifi_bad"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
text: {
|
text: {
|
||||||
if (NetworkService.ethernetConnected) {
|
if (NetworkService.ethernetConnected) {
|
||||||
return "Network"
|
return "Network"
|
||||||
}
|
}
|
||||||
return "Wi-Fi"
|
return "Wi-Fi"
|
||||||
}
|
}
|
||||||
|
|
||||||
fontSize: Style.fontSizeS * scaling
|
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)
|
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
|
// Widgets Management Section
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
spacing: Style.marginXXS * scaling
|
spacing: Style.marginXXS * scaling
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ Rectangle {
|
|||||||
property int fontWeight: Style.fontWeightBold
|
property int fontWeight: Style.fontWeightBold
|
||||||
property real iconSize: Style.fontSizeL * scaling
|
property real iconSize: Style.fontSizeL * scaling
|
||||||
property bool outlined: false
|
property bool outlined: false
|
||||||
property int horizontalAlignment: Qt.AlignHCenter
|
property int horizontalAlignment: Qt.AlignHCenter
|
||||||
|
|
||||||
// Signals
|
// Signals
|
||||||
signal clicked
|
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