WIP - modular bar (need to fix brightness & tray)

This commit is contained in:
Ly-sec 2025-08-22 16:37:45 +02:00
parent 8f951946ea
commit 8e562e0701
31 changed files with 785 additions and 136 deletions

View file

@ -130,6 +130,15 @@ Singleton {
property bool alwaysShowBatteryPercentage: false property bool alwaysShowBatteryPercentage: false
property real backgroundOpacity: 1.0 property real backgroundOpacity: 1.0
property list<string> monitors: [] property list<string> monitors: []
// Widget configuration for modular bar system
property JsonObject widgets
widgets: JsonObject {
property list<string> left: ["SystemMonitor", "ActiveWindow", "MediaMini"]
property list<string> center: ["Workspace"]
property list<string> right: ["ScreenRecorderIndicator", "Tray", "NotificationHistory", "WiFi", "Bluetooth", "Battery", "Volume", "Brightness", "Clock", "SidePanelToggle"]
}
} }
// general // general

View file

@ -47,7 +47,7 @@ Variants {
layer.enabled: true layer.enabled: true
} }
// Left // Left Section - Dynamic Widgets
Row { Row {
id: leftSection id: leftSection
@ -57,14 +57,25 @@ Variants {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS * scaling spacing: Style.marginS * scaling
SystemMonitor {} Repeater {
model: Settings.data.bar.widgets.left
ActiveWindow {} delegate: Loader {
id: widgetLoader
MediaMini {} sourceComponent: getWidgetComponent(modelData)
active: true
anchors.verticalCenter: parent.verticalCenter
onStatusChanged: {
if (status === Loader.Error) {
console.warn(`Failed to load widget: ${modelData}`)
} else if (status === Loader.Ready) {
console.log(`Successfully loaded widget: ${modelData}`)
}
}
}
}
} }
// Center // Center Section - Dynamic Widgets
Row { Row {
id: centerSection id: centerSection
@ -73,10 +84,25 @@ Variants {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginS * scaling spacing: Style.marginS * scaling
Workspace {} Repeater {
model: Settings.data.bar.widgets.center
delegate: Loader {
id: widgetLoader
sourceComponent: getWidgetComponent(modelData)
active: true
anchors.verticalCenter: parent.verticalCenter
onStatusChanged: {
if (status === Loader.Error) {
console.warn(`Failed to load widget: ${modelData}`)
} else if (status === Loader.Ready) {
console.log(`Successfully loaded widget: ${modelData}`)
}
}
}
}
} }
// Right // Right Section - Dynamic Widgets
Row { Row {
id: rightSection id: rightSection
@ -86,44 +112,43 @@ Variants {
anchors.verticalCenter: bar.verticalCenter anchors.verticalCenter: bar.verticalCenter
spacing: Style.marginS * scaling spacing: Style.marginS * scaling
ScreenRecorderIndicator { Repeater {
anchors.verticalCenter: parent.verticalCenter model: Settings.data.bar.widgets.right
delegate: Loader {
id: widgetLoader
sourceComponent: getWidgetComponent(modelData)
active: true
anchors.verticalCenter: parent.verticalCenter
onStatusChanged: {
if (status === Loader.Error) {
console.warn(`Failed to load widget: ${modelData}`)
} else if (status === Loader.Ready) {
console.log(`Successfully loaded widget: ${modelData}`)
}
}
}
} }
Tray {
anchors.verticalCenter: parent.verticalCenter
}
NotificationHistory {
anchors.verticalCenter: parent.verticalCenter
}
WiFi {
anchors.verticalCenter: parent.verticalCenter
}
Bluetooth {
anchors.verticalCenter: parent.verticalCenter
}
Battery {
anchors.verticalCenter: parent.verticalCenter
}
Volume {
anchors.verticalCenter: parent.verticalCenter
}
Brightness {
anchors.verticalCenter: parent.verticalCenter
}
Clock {
anchors.verticalCenter: parent.verticalCenter
}
SidePanelToggle {}
} }
} }
// Auto-discover widget components
function getWidgetComponent(widgetName) {
if (!widgetName || widgetName.trim() === "") {
return null
}
// Try to load the widget directly from file
const component = Qt.createComponent(`../Bar/Widgets/${widgetName}.qml`)
if (component.status === Component.Ready) {
return component
}
console.warn(`Failed to load widget: ${widgetName}.qml`)
return null
}
} }
} }

View file

@ -10,9 +10,7 @@ import qs.Widgets
NIconButton { NIconButton {
id: root id: root
readonly property bool bluetoothEnabled: Settings.data.network.bluetoothEnabled
sizeMultiplier: 0.8 sizeMultiplier: 0.8
visible: bluetoothEnabled
colorBg: Color.mSurfaceVariant colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface colorFg: Color.mOnSurface

View file

@ -118,7 +118,7 @@ NPanel {
radius: Style.radiusM * scaling radius: Style.radiusM * scaling
color: { color: {
if (availableDeviceArea.containsMouse && !isBusy) if (availableDeviceArea.containsMouse && !isBusy)
return Color.mSecondary return Color.mTertiary
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting) if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
return Color.mPrimary return Color.mPrimary

View file

@ -10,7 +10,7 @@ Item {
width: pill.width width: pill.width
height: pill.height height: pill.height
visible: Settings.data.bar.showBrightness && firstBrightnessReceived && getMonitor() !== null visible: firstBrightnessReceived && getMonitor() !== null
// Used to avoid opening the pill on Quickshell startup // Used to avoid opening the pill on Quickshell startup
property bool firstBrightnessReceived: false property bool firstBrightnessReceived: false

View file

@ -134,7 +134,7 @@ PopupWindow {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: mouseArea.containsMouse ? Color.mSecondary : Color.transparent color: mouseArea.containsMouse ? Color.mTertiary : Color.transparent
radius: Style.radiusS * scaling radius: Style.radiusS * scaling
visible: !(modelData?.isSeparator ?? false) visible: !(modelData?.isSeparator ?? false)

View file

@ -10,10 +10,7 @@ import qs.Widgets
NIconButton { NIconButton {
id: root id: root
readonly property bool wifiEnabled: Settings.data.network.wifiEnabled
sizeMultiplier: 0.8 sizeMultiplier: 0.8
visible: wifiEnabled
colorBg: Color.mSurfaceVariant colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface colorFg: Color.mOnSurface

View file

@ -147,7 +147,7 @@ NPanel {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: Style.baseWidgetSize * 1.5 * scaling Layout.preferredHeight: Style.baseWidgetSize * 1.5 * scaling
radius: Style.radiusS * scaling radius: Style.radiusS * scaling
color: modelData.connected ? Color.mPrimary : (networkMouseArea.containsMouse ? Color.mSecondary : Color.transparent) color: modelData.connected ? Color.mPrimary : (networkMouseArea.containsMouse ? Color.mTertiary : Color.transparent)
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent

View file

@ -47,6 +47,7 @@ NPanel {
id: barTab id: barTab
Tabs.BarTab {} Tabs.BarTab {}
} }
Component { Component {
id: audioTab id: audioTab
Tabs.AudioTab {} Tabs.AudioTab {}
@ -202,7 +203,7 @@ NPanel {
width: parent.width width: parent.width
height: 32 * scaling height: 32 * scaling
radius: Style.radiusS * scaling radius: Style.radiusS * scaling
color: selected ? Color.mPrimary : (tabItem.hovering ? Color.mSecondary : Color.transparent) color: selected ? Color.mPrimary : (tabItem.hovering ? Color.mTertiary : Color.transparent)
readonly property bool selected: index === currentTabIndex readonly property bool selected: index === currentTabIndex
property bool hovering: false property bool hovering: false
property color tabTextColor: selected ? Color.mOnPrimary : (tabItem.hovering ? Color.mOnTertiary : Color.mOnSurface) property color tabTextColor: selected ? Color.mOnPrimary : (tabItem.hovering ? Color.mOnTertiary : Color.mOnSurface)
@ -265,7 +266,7 @@ NPanel {
// Tab label on the main right side // Tab label on the main right side
NText { NText {
text: root.tabsModel[currentTabIndex].label text: root.tabsModel[currentTabIndex].label
font.pointSize: Style.fontSizeXL * scaling font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mPrimary color: Color.mPrimary
Layout.fillWidth: true Layout.fillWidth: true

View file

@ -199,7 +199,7 @@ ColumnLayout {
width: contributorsGrid.cellWidth - Style.marginL * scaling width: contributorsGrid.cellWidth - Style.marginL * scaling
height: contributorsGrid.cellHeight - Style.marginXS * scaling height: contributorsGrid.cellHeight - Style.marginXS * scaling
radius: Style.radiusL * scaling radius: Style.radiusL * scaling
color: contributorArea.containsMouse ? Color.mSecondary : Color.transparent color: contributorArea.containsMouse ? Color.mTertiary : Color.transparent
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
@ -217,7 +217,7 @@ ColumnLayout {
anchors.margins: Style.marginXS * scaling anchors.margins: Style.marginXS * scaling
fallbackIcon: "person" fallbackIcon: "person"
borderColor: Color.mPrimary borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderL * scaling) borderWidth: Math.max(1, Style.borderM * scaling)
imageRadius: width * 0.5 imageRadius: width * 0.5
} }
} }

View file

@ -33,6 +33,13 @@ ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText {
text: "Bar & Widgets"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
ColumnLayout { ColumnLayout {
spacing: Style.marginXXS * scaling spacing: Style.marginXXS * scaling
Layout.fillWidth: true Layout.fillWidth: true
@ -71,15 +78,6 @@ ColumnLayout {
} }
} }
NToggle {
label: "Show Active Window"
description: "Display the title of the currently focused window."
checked: Settings.data.bar.showActiveWindow
onToggled: checked => {
Settings.data.bar.showActiveWindow = checked
}
}
NToggle { NToggle {
label: "Show Active Window's Icon" label: "Show Active Window's Icon"
description: "Display the app icon next to the title of the currently focused window." description: "Display the app icon next to the title of the currently focused window."
@ -89,42 +87,6 @@ ColumnLayout {
} }
} }
NToggle {
label: "Show System Info"
description: "Display system statistics (CPU, RAM, Temperature)."
checked: Settings.data.bar.showSystemInfo
onToggled: checked => {
Settings.data.bar.showSystemInfo = checked
}
}
NToggle {
label: "Show Media"
description: "Display media controls and information."
checked: Settings.data.bar.showMedia
onToggled: checked => {
Settings.data.bar.showMedia = checked
}
}
NToggle {
label: "Show Notifications History"
description: "Display a shortcut to the notifications history."
checked: Settings.data.bar.showNotificationsHistory
onToggled: checked => {
Settings.data.bar.showNotificationsHistory = checked
}
}
NToggle {
label: "Show Applications Tray"
description: "Display the applications tray."
checked: Settings.data.bar.showTray
onToggled: checked => {
Settings.data.bar.showTray = checked
}
}
NToggle { NToggle {
label: "Show Battery Percentage" label: "Show Battery Percentage"
description: "Show battery percentage at all times." description: "Show battery percentage at all times."
@ -172,7 +134,631 @@ ColumnLayout {
} }
} }
} }
// Widget Management Section
ColumnLayout {
spacing: Style.marginXXS * scaling
Layout.fillWidth: true
NText {
text: "Widget Management"
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: "Configure which widgets appear in each section of the bar. Use the arrow buttons to reorder widgets, or the add/remove buttons to manage them."
font.pointSize: Style.fontSizeXS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
// Bar Sections
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: Style.marginM * scaling
// Left Section
NCard {
Layout.fillWidth: true
Layout.minimumHeight: {
var widgetCount = Settings.data.bar.widgets.left.length
if (widgetCount === 0) return 120 * scaling
var availableWidth = scrollView.availableWidth - (Style.marginM * scaling * 2) // Card margins
var avgWidgetWidth = 150 * scaling // Estimated widget width including spacing
var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth))
var rows = Math.ceil(widgetCount / widgetsPerRow)
// Header (40) + spacing (16) + (rows * widget height) + (rows-1 * spacing) + bottom margin (16)
return (40 + 16 + (rows * 48) + ((rows - 1) * Style.marginS) + 16) * scaling
}
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginM * scaling
spacing: Style.marginM * scaling
RowLayout {
Layout.fillWidth: true
NText {
text: "Left Section"
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
Item { Layout.fillWidth: true }
Rectangle {
width: 32 * scaling
height: 32 * scaling
radius: width * 0.5
color: Color.mPrimary
border.color: Color.mPrimaryContainer
border.width: 2 * scaling
NIcon {
anchors.centerIn: parent
text: "add"
color: Color.mOnPrimary
font.pointSize: Style.fontSizeM * scaling
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
addWidgetDialog.show("left")
}
}
}
}
Flow {
id: leftWidgetsFlow
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 52 * scaling
spacing: Style.marginS * scaling
flow: Flow.LeftToRight
Repeater {
model: Settings.data.bar.widgets.left
delegate: Rectangle {
width: widgetContent.implicitWidth + 16 * scaling
height: 48 * scaling
radius: Style.radiusS * scaling
color: Color.mPrimary
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
RowLayout {
id: widgetContent
anchors.centerIn: parent
spacing: Style.marginXS * scaling
NIconButton {
icon: "chevron_left"
size: 20 * scaling
colorBg: Color.applyOpacity(Color.mOnPrimary, "20")
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
enabled: index > 0
onClicked: {
if (index > 0) {
reorderWidgetInSection("left", index, index - 1)
}
}
}
NText {
text: modelData
font.pointSize: Style.fontSizeS * scaling
color: Color.mOnPrimary
horizontalAlignment: Text.AlignHCenter
}
NIconButton {
icon: "chevron_right"
size: 20 * scaling
colorBg: Color.applyOpacity(Color.mOnPrimary, "20")
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
enabled: index < Settings.data.bar.widgets.left.length - 1
onClicked: {
if (index < Settings.data.bar.widgets.left.length - 1) {
reorderWidgetInSection("left", index, index + 1)
}
}
}
NIconButton {
icon: "close"
size: 20 * scaling
colorBg: Color.applyOpacity(Color.mOnPrimary, "20")
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
onClicked: {
removeWidgetFromSection("left", index)
}
}
}
}
}
}
}
}
// Center Section
NCard {
Layout.fillWidth: true
Layout.minimumHeight: {
var widgetCount = Settings.data.bar.widgets.center.length
if (widgetCount === 0) return 120 * scaling
var availableWidth = scrollView.availableWidth - (Style.marginM * scaling * 2) // Card margins
var avgWidgetWidth = 150 * scaling // Estimated widget width including spacing
var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth))
var rows = Math.ceil(widgetCount / widgetsPerRow)
// Header (40) + spacing (16) + (rows * widget height) + (rows-1 * spacing) + bottom margin (16)
return (40 + 16 + (rows * 48) + ((rows - 1) * Style.marginS) + 16) * scaling
}
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginM * scaling
spacing: Style.marginM * scaling
RowLayout {
Layout.fillWidth: true
NText {
text: "Center Section"
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
Item { Layout.fillWidth: true }
Rectangle {
width: 32 * scaling
height: 32 * scaling
radius: width * 0.5
color: Color.mPrimary
border.color: Color.mPrimaryContainer
border.width: 2 * scaling
NIcon {
anchors.centerIn: parent
text: "add"
color: Color.mOnPrimary
font.pointSize: Style.fontSizeM * scaling
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
addWidgetDialog.show("center")
}
}
}
}
Flow {
id: centerWidgetsFlow
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 52 * scaling
spacing: Style.marginS * scaling
flow: Flow.LeftToRight
Repeater {
model: Settings.data.bar.widgets.center
delegate: Rectangle {
width: widgetContent.implicitWidth + 16 * scaling
height: 48 * scaling
radius: Style.radiusS * scaling
color: Color.mPrimary
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
RowLayout {
id: widgetContent
anchors.centerIn: parent
spacing: Style.marginXS * scaling
NIconButton {
icon: "chevron_left"
size: 20 * scaling
colorBg: Color.applyOpacity(Color.mOnPrimary, "20")
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
enabled: index > 0
onClicked: {
if (index > 0) {
reorderWidgetInSection("center", index, index - 1)
}
}
}
NText {
text: modelData
font.pointSize: Style.fontSizeS * scaling
color: Color.mOnPrimary
horizontalAlignment: Text.AlignHCenter
}
NIconButton {
icon: "chevron_right"
size: 20 * scaling
colorBg: Color.applyOpacity(Color.mOnPrimary, "20")
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
enabled: index < Settings.data.bar.widgets.center.length - 1
onClicked: {
if (index < Settings.data.bar.widgets.center.length - 1) {
reorderWidgetInSection("center", index, index + 1)
}
}
}
NIconButton {
icon: "close"
size: 20 * scaling
colorBg: Color.applyOpacity(Color.mOnPrimary, "20")
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
onClicked: {
removeWidgetFromSection("center", index)
}
}
}
}
}
}
}
}
// Right Section
NCard {
Layout.fillWidth: true
Layout.minimumHeight: {
var widgetCount = Settings.data.bar.widgets.right.length
if (widgetCount === 0) return 120 * scaling
var availableWidth = scrollView.availableWidth - (Style.marginM * scaling * 2) // Card margins
var avgWidgetWidth = 150 * scaling // Estimated widget width including spacing
var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth))
var rows = Math.ceil(widgetCount / widgetsPerRow)
// Header (40) + spacing (16) + (rows * widget height) + (rows-1 * spacing) + bottom margin (16)
return (40 + 16 + (rows * 48) + ((rows - 1) * Style.marginS) + 16) * scaling
}
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginM * scaling
spacing: Style.marginM * scaling
RowLayout {
Layout.fillWidth: true
NText {
text: "Right Section"
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
Item { Layout.fillWidth: true }
Rectangle {
width: 32 * scaling
height: 32 * scaling
radius: width * 0.5
color: Color.mPrimary
border.color: Color.mPrimaryContainer
border.width: 2 * scaling
NIcon {
anchors.centerIn: parent
text: "add"
color: Color.mOnPrimary
font.pointSize: Style.fontSizeM * scaling
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
addWidgetDialog.show("right")
}
}
}
}
Flow {
id: rightWidgetsFlow
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 52 * scaling
spacing: Style.marginS * scaling
flow: Flow.LeftToRight
Repeater {
model: Settings.data.bar.widgets.right
delegate: Rectangle {
width: widgetContent.implicitWidth + 16 * scaling
height: 48 * scaling
radius: Style.radiusS * scaling
color: Color.mPrimary
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
RowLayout {
id: widgetContent
anchors.centerIn: parent
spacing: Style.marginXS * scaling
NIconButton {
icon: "chevron_left"
size: 20 * scaling
colorBg: Color.applyOpacity(Color.mOnPrimary, "20")
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
enabled: index > 0
onClicked: {
if (index > 0) {
reorderWidgetInSection("right", index, index - 1)
}
}
}
NText {
text: modelData
font.pointSize: Style.fontSizeS * scaling
color: Color.mOnPrimary
horizontalAlignment: Text.AlignHCenter
}
NIconButton {
icon: "chevron_right"
size: 20 * scaling
colorBg: Color.applyOpacity(Color.mOnPrimary, "20")
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
enabled: index < Settings.data.bar.widgets.right.length - 1
onClicked: {
if (index < Settings.data.bar.widgets.right.length - 1) {
reorderWidgetInSection("right", index, index + 1)
}
}
}
NIconButton {
icon: "close"
size: 20 * scaling
colorBg: Color.applyOpacity(Color.mOnPrimary, "20")
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
onClicked: {
removeWidgetFromSection("right", index)
}
}
}
}
}
}
}
}
}
}
} }
} }
} }
// Add Widget Dialog
Rectangle {
id: addWidgetDialog
anchors.fill: parent
color: Color.applyOpacity(Color.mShadow, "80")
visible: false
z: 1000
property string targetSection: ""
function show(section) {
targetSection = section
visible = true
}
function hide() {
visible = false
targetSection = ""
}
MouseArea {
anchors.fill: parent
onClicked: addWidgetDialog.hide()
}
Rectangle {
anchors.centerIn: parent
width: 400 * scaling
height: 500 * scaling
radius: Style.radiusL * scaling
color: Color.mSurface
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginL * scaling
spacing: Style.marginM * scaling
NText {
text: "Add Widget to " + (addWidgetDialog.targetSection === "left" ? "Left" :
addWidgetDialog.targetSection === "center" ? "Center" : "Right") + " Section"
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.fillWidth: true
}
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
spacing: Style.marginXS * scaling
model: ListModel {
ListElement { name: "SystemMonitor"; icon: "memory"; description: "System statistics" }
ListElement { name: "ActiveWindow"; icon: "web_asset"; description: "Active window title" }
ListElement { name: "MediaMini"; icon: "music_note"; description: "Media controls" }
ListElement { name: "Workspace"; icon: "dashboard"; description: "Workspace switcher" }
ListElement { name: "ScreenRecorderIndicator"; icon: "videocam"; description: "Recording indicator" }
ListElement { name: "Tray"; icon: "apps"; description: "System tray" }
ListElement { name: "NotificationHistory"; icon: "notifications"; description: "Notification history" }
ListElement { name: "WiFi"; icon: "wifi"; description: "WiFi status" }
ListElement { name: "Bluetooth"; icon: "bluetooth"; description: "Bluetooth status" }
ListElement { name: "Battery"; icon: "battery_full"; description: "Battery status" }
ListElement { name: "Volume"; icon: "volume_up"; description: "Volume control" }
ListElement { name: "Brightness"; icon: "brightness_6"; description: "Brightness control" }
ListElement { name: "Clock"; icon: "schedule"; description: "Clock" }
ListElement { name: "SidePanelToggle"; icon: "widgets"; description: "Side panel toggle" }
}
delegate: Rectangle {
width: ListView.view.width
height: 48 * scaling
radius: Style.radiusS * scaling
color: mouseArea.containsMouse ? Color.mTertiary : Color.mSurfaceVariant
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
RowLayout {
anchors.fill: parent
anchors.margins: Style.marginS * scaling
spacing: Style.marginS * scaling
NIcon {
text: model.icon
color: Color.mOnSurface
font.pointSize: Style.fontSizeM * scaling
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
NText {
text: model.name
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: model.description
font.pointSize: Style.fontSizeXS * scaling
color: Color.mOnSurfaceVariant
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
addWidgetToSection(model.name, addWidgetDialog.targetSection)
addWidgetDialog.hide()
}
}
}
}
RowLayout {
Layout.fillWidth: true
Item { Layout.fillWidth: true }
NIconButton {
icon: "close"
size: 20 * scaling
color: Color.mOnSurface
onClicked: addWidgetDialog.hide()
}
}
}
}
}
// Helper functions
function addWidgetToSection(widgetName, section) {
console.log("Adding widget", widgetName, "to section", section)
var sectionArray = Settings.data.bar.widgets[section]
if (sectionArray) {
// Create a new array to avoid modifying the original
var newArray = sectionArray.slice()
newArray.push(widgetName)
console.log("Widget added. New array:", JSON.stringify(newArray))
// Assign the new array
Settings.data.bar.widgets[section] = newArray
}
}
function removeWidgetFromSection(section, index) {
console.log("Removing widget from section", section, "at index", index)
var sectionArray = Settings.data.bar.widgets[section]
if (sectionArray && index >= 0 && index < sectionArray.length) {
// Create a new array to avoid modifying the original
var newArray = sectionArray.slice()
newArray.splice(index, 1)
console.log("Widget removed. New array:", JSON.stringify(newArray))
// Assign the new array
Settings.data.bar.widgets[section] = newArray
}
}
function reorderWidgetInSection(section, fromIndex, toIndex) {
console.log("Reordering widget in section", section, "from", fromIndex, "to", toIndex)
var sectionArray = Settings.data.bar.widgets[section]
if (sectionArray && fromIndex >= 0 && fromIndex < sectionArray.length &&
toIndex >= 0 && toIndex < sectionArray.length) {
// Create a new array to avoid modifying the original
var newArray = sectionArray.slice()
var item = newArray[fromIndex]
newArray.splice(fromIndex, 1)
newArray.splice(toIndex, 0, item)
console.log("Widget reordered. New array:", JSON.stringify(newArray))
// Assign the new array
Settings.data.bar.widgets[section] = newArray
}
}
} }

View file

@ -6,33 +6,34 @@ import qs.Commons
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { Item {
id: root property real scaling: 1
spacing: 0
readonly property string tabIcon: "brightness_6" readonly property string tabIcon: "brightness_6"
readonly property string tabLabel: "Brightness" readonly property string tabLabel: "Brightness"
Layout.fillWidth: true
Layout.fillHeight: true
ScrollView { ScrollView {
id: scrollView anchors.fill: parent
Layout.fillWidth: true
Layout.fillHeight: true
padding: Style.marginM * scaling
clip: true clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
contentWidth: parent.width
ColumnLayout { ColumnLayout {
width: scrollView.availableWidth width: parent.width
spacing: 0
ColumnLayout { ColumnLayout {
width: scrollView.availableWidth
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.margins: Style.marginL * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText {
text: "Brightness Settings"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
// Bar Visibility Section // Bar Visibility Section
NToggle { NToggle {
label: "Show Bar Icon" label: "Show Bar Icon"

View file

@ -163,28 +163,22 @@ ColumnLayout {
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginL * scaling
} }
NText {
text: "Predefined Color Schemes"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
ColumnLayout { ColumnLayout {
spacing: Style.marginXXS * scaling spacing: Style.marginXXS * scaling
Layout.fillWidth: true Layout.fillWidth: true
// NText { NText {
// text: "Predefined Color Schemes" text: "Predefined Color Schemes"
// font.pointSize: Style.fontSizeL * scaling font.pointSize: Style.fontSizeL * scaling
// font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
// color: Color.mOnSurface color: Color.mOnSurface
// Layout.fillWidth: true Layout.fillWidth: true
// } }
NText { NText {
text: "These color schemes only apply when 'Use Matugen' is disabled. When enabled, Matugen will generate colors based on your wallpaper instead. You can toggle between light and dark themes when using Matugen." text: "These color schemes only apply when 'Use Matugen' is disabled. When enabled, Matugen will generate colors based on your wallpaper instead. You can toggle between light and dark themes when using Matugen."
font.pointSize: Style.fontSizeXS * scaling font.pointSize: Style.fontSizeXS * scaling
color: Color.mOnSurfaceVariant color: Color.mOnSurface
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }

View file

@ -33,6 +33,13 @@ ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText {
text: "General Settings"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
// Profile section // Profile section
ColumnLayout { ColumnLayout {
spacing: Style.marginS * scaling spacing: Style.marginS * scaling

View file

@ -34,7 +34,7 @@ ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
NText { NText {
text: "Launcer Options" text: "Launcher"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mOnSurface
@ -56,7 +56,7 @@ ColumnLayout {
} }
NText { NText {
text: "Launcer Anchoring" text: "Launcher Position"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mOnSurface

View file

@ -34,6 +34,13 @@ ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText {
text: "Interfaces"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NToggle { NToggle {
label: "WiFi Enabled" label: "WiFi Enabled"
description: "Enable WiFi connectivity." description: "Enable WiFi connectivity."

View file

@ -33,6 +33,14 @@ ColumnLayout {
spacing: Style.marginXS * scaling spacing: Style.marginXS * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText {
text: "Recordings"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.bottomMargin: Style.marginS * scaling
}
// Output Directory // Output Directory
ColumnLayout { ColumnLayout {
spacing: Style.marginS * scaling spacing: Style.marginS * scaling

View file

@ -33,6 +33,14 @@ ColumnLayout {
spacing: Style.marginXS * scaling spacing: Style.marginXS * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText {
text: "Location"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.bottomMargin: Style.marginS * scaling
}
// Location section // Location section
ColumnLayout { ColumnLayout {
spacing: Style.marginM * scaling spacing: Style.marginM * scaling

View file

@ -31,7 +31,7 @@ Item {
// Current wallpaper display // Current wallpaper display
NText { NText {
text: "Current Wallpaper" text: "Current Wallpaper"
font.pointSize: Style.fontSizeL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mOnSurface
} }

View file

@ -34,6 +34,14 @@ ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText {
text: "Directory"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.bottomMargin: Style.marginS * scaling
}
// Wallpaper Settings Category // Wallpaper Settings Category
ColumnLayout { ColumnLayout {
spacing: Style.marginS * scaling spacing: Style.marginS * scaling