diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 23fa4322..0ffe01c6 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -130,6 +130,15 @@ Singleton { property bool alwaysShowBatteryPercentage: false property real backgroundOpacity: 1.0 property list monitors: [] + + // Widget configuration for modular bar system + property JsonObject widgets + + widgets: JsonObject { + property list left: ["SystemMonitor", "ActiveWindow", "MediaMini"] + property list center: ["Workspace"] + property list right: ["ScreenRecorderIndicator", "Tray", "NotificationHistory", "WiFi", "Bluetooth", "Battery", "Volume", "Brightness", "Clock", "SidePanelToggle"] + } } // general diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index 6cc30a71..61e79400 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -47,7 +47,7 @@ Variants { layer.enabled: true } - // Left + // Left Section - Dynamic Widgets Row { id: leftSection @@ -57,14 +57,25 @@ Variants { anchors.verticalCenter: parent.verticalCenter spacing: Style.marginS * scaling - SystemMonitor {} - - ActiveWindow {} - - MediaMini {} + Repeater { + model: Settings.data.bar.widgets.left + 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}`) + } + } + } + } } - // Center + // Center Section - Dynamic Widgets Row { id: centerSection @@ -73,10 +84,25 @@ Variants { anchors.verticalCenter: parent.verticalCenter 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 { id: rightSection @@ -86,44 +112,43 @@ Variants { anchors.verticalCenter: bar.verticalCenter spacing: Style.marginS * scaling - ScreenRecorderIndicator { - anchors.verticalCenter: parent.verticalCenter + Repeater { + 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 + } + + + + } } diff --git a/Modules/Bar/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml similarity index 100% rename from Modules/Bar/ActiveWindow.qml rename to Modules/Bar/Widgets/ActiveWindow.qml diff --git a/Modules/Bar/Battery.qml b/Modules/Bar/Widgets/Battery.qml similarity index 100% rename from Modules/Bar/Battery.qml rename to Modules/Bar/Widgets/Battery.qml diff --git a/Modules/Bar/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml similarity index 87% rename from Modules/Bar/Bluetooth.qml rename to Modules/Bar/Widgets/Bluetooth.qml index adc76e0c..09c5c600 100644 --- a/Modules/Bar/Bluetooth.qml +++ b/Modules/Bar/Widgets/Bluetooth.qml @@ -10,9 +10,7 @@ import qs.Widgets NIconButton { id: root - readonly property bool bluetoothEnabled: Settings.data.network.bluetoothEnabled sizeMultiplier: 0.8 - visible: bluetoothEnabled colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface diff --git a/Modules/Bar/BluetoothPanel.qml b/Modules/Bar/Widgets/BluetoothPanel.qml similarity index 99% rename from Modules/Bar/BluetoothPanel.qml rename to Modules/Bar/Widgets/BluetoothPanel.qml index b583897b..eeb4c7fc 100644 --- a/Modules/Bar/BluetoothPanel.qml +++ b/Modules/Bar/Widgets/BluetoothPanel.qml @@ -118,7 +118,7 @@ NPanel { radius: Style.radiusM * scaling color: { if (availableDeviceArea.containsMouse && !isBusy) - return Color.mSecondary + return Color.mTertiary if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting) return Color.mPrimary diff --git a/Modules/Bar/Brightness.qml b/Modules/Bar/Widgets/Brightness.qml similarity index 96% rename from Modules/Bar/Brightness.qml rename to Modules/Bar/Widgets/Brightness.qml index 39c0fb8b..82bacb81 100644 --- a/Modules/Bar/Brightness.qml +++ b/Modules/Bar/Widgets/Brightness.qml @@ -10,7 +10,7 @@ Item { width: pill.width height: pill.height - visible: Settings.data.bar.showBrightness && firstBrightnessReceived && getMonitor() !== null + visible: firstBrightnessReceived && getMonitor() !== null // Used to avoid opening the pill on Quickshell startup property bool firstBrightnessReceived: false diff --git a/Modules/Bar/Clock.qml b/Modules/Bar/Widgets/Clock.qml similarity index 100% rename from Modules/Bar/Clock.qml rename to Modules/Bar/Widgets/Clock.qml diff --git a/Modules/Bar/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml similarity index 100% rename from Modules/Bar/MediaMini.qml rename to Modules/Bar/Widgets/MediaMini.qml diff --git a/Modules/Bar/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml similarity index 100% rename from Modules/Bar/NotificationHistory.qml rename to Modules/Bar/Widgets/NotificationHistory.qml diff --git a/Modules/Bar/ScreenRecorderIndicator.qml b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml similarity index 100% rename from Modules/Bar/ScreenRecorderIndicator.qml rename to Modules/Bar/Widgets/ScreenRecorderIndicator.qml diff --git a/Modules/Bar/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml similarity index 100% rename from Modules/Bar/SidePanelToggle.qml rename to Modules/Bar/Widgets/SidePanelToggle.qml diff --git a/Modules/Bar/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml similarity index 100% rename from Modules/Bar/SystemMonitor.qml rename to Modules/Bar/Widgets/SystemMonitor.qml diff --git a/Modules/Bar/Tray.qml b/Modules/Bar/Widgets/Tray.qml similarity index 100% rename from Modules/Bar/Tray.qml rename to Modules/Bar/Widgets/Tray.qml diff --git a/Modules/Bar/TrayMenu.qml b/Modules/Bar/Widgets/TrayMenu.qml similarity index 99% rename from Modules/Bar/TrayMenu.qml rename to Modules/Bar/Widgets/TrayMenu.qml index 699d8d10..a3a24fdc 100644 --- a/Modules/Bar/TrayMenu.qml +++ b/Modules/Bar/Widgets/TrayMenu.qml @@ -134,7 +134,7 @@ PopupWindow { Rectangle { anchors.fill: parent - color: mouseArea.containsMouse ? Color.mSecondary : Color.transparent + color: mouseArea.containsMouse ? Color.mTertiary : Color.transparent radius: Style.radiusS * scaling visible: !(modelData?.isSeparator ?? false) diff --git a/Modules/Bar/Volume.qml b/Modules/Bar/Widgets/Volume.qml similarity index 100% rename from Modules/Bar/Volume.qml rename to Modules/Bar/Widgets/Volume.qml diff --git a/Modules/Bar/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml similarity index 89% rename from Modules/Bar/WiFi.qml rename to Modules/Bar/Widgets/WiFi.qml index 6b9b9215..cdae9bef 100644 --- a/Modules/Bar/WiFi.qml +++ b/Modules/Bar/Widgets/WiFi.qml @@ -10,10 +10,7 @@ import qs.Widgets NIconButton { id: root - readonly property bool wifiEnabled: Settings.data.network.wifiEnabled - sizeMultiplier: 0.8 - visible: wifiEnabled colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface diff --git a/Modules/Bar/WiFiPanel.qml b/Modules/Bar/Widgets/WiFiPanel.qml similarity index 99% rename from Modules/Bar/WiFiPanel.qml rename to Modules/Bar/Widgets/WiFiPanel.qml index ce5acefa..8d88cd94 100644 --- a/Modules/Bar/WiFiPanel.qml +++ b/Modules/Bar/Widgets/WiFiPanel.qml @@ -147,7 +147,7 @@ NPanel { Layout.fillWidth: true Layout.preferredHeight: Style.baseWidgetSize * 1.5 * 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 { anchors.fill: parent diff --git a/Modules/Bar/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml similarity index 100% rename from Modules/Bar/Workspace.qml rename to Modules/Bar/Widgets/Workspace.qml diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml index 0224d897..b5667f97 100644 --- a/Modules/SettingsPanel/SettingsPanel.qml +++ b/Modules/SettingsPanel/SettingsPanel.qml @@ -47,6 +47,7 @@ NPanel { id: barTab Tabs.BarTab {} } + Component { id: audioTab Tabs.AudioTab {} @@ -202,7 +203,7 @@ NPanel { width: parent.width height: 32 * 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 property bool hovering: false property color tabTextColor: selected ? Color.mOnPrimary : (tabItem.hovering ? Color.mOnTertiary : Color.mOnSurface) @@ -265,7 +266,7 @@ NPanel { // Tab label on the main right side NText { text: root.tabsModel[currentTabIndex].label - font.pointSize: Style.fontSizeXL * scaling + font.pointSize: Style.fontSizeL * scaling font.weight: Style.fontWeightBold color: Color.mPrimary Layout.fillWidth: true diff --git a/Modules/SettingsPanel/Tabs/AboutTab.qml b/Modules/SettingsPanel/Tabs/AboutTab.qml index a7b7b3d3..405ed1b3 100644 --- a/Modules/SettingsPanel/Tabs/AboutTab.qml +++ b/Modules/SettingsPanel/Tabs/AboutTab.qml @@ -199,7 +199,7 @@ ColumnLayout { width: contributorsGrid.cellWidth - Style.marginL * scaling height: contributorsGrid.cellHeight - Style.marginXS * scaling radius: Style.radiusL * scaling - color: contributorArea.containsMouse ? Color.mSecondary : Color.transparent + color: contributorArea.containsMouse ? Color.mTertiary : Color.transparent RowLayout { anchors.fill: parent @@ -217,7 +217,7 @@ ColumnLayout { anchors.margins: Style.marginXS * scaling fallbackIcon: "person" borderColor: Color.mPrimary - borderWidth: Math.max(1, Style.borderL * scaling) + borderWidth: Math.max(1, Style.borderM * scaling) imageRadius: width * 0.5 } } diff --git a/Modules/SettingsPanel/Tabs/BarTab.qml b/Modules/SettingsPanel/Tabs/BarTab.qml index fe5cb42d..d03c3331 100644 --- a/Modules/SettingsPanel/Tabs/BarTab.qml +++ b/Modules/SettingsPanel/Tabs/BarTab.qml @@ -33,6 +33,13 @@ ColumnLayout { spacing: Style.marginL * scaling Layout.fillWidth: true + NText { + text: "Bar & Widgets" + font.pointSize: Style.fontSizeXXL * scaling + font.weight: Style.fontWeightBold + color: Color.mOnSurface + } + ColumnLayout { spacing: Style.marginXXS * scaling 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 { label: "Show Active Window's Icon" 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 { label: "Show Battery Percentage" 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 + } + } } diff --git a/Modules/SettingsPanel/Tabs/BrightnessTab.qml b/Modules/SettingsPanel/Tabs/BrightnessTab.qml index e4758c35..3b61e7b0 100644 --- a/Modules/SettingsPanel/Tabs/BrightnessTab.qml +++ b/Modules/SettingsPanel/Tabs/BrightnessTab.qml @@ -6,33 +6,34 @@ import qs.Commons import qs.Services import qs.Widgets -ColumnLayout { - id: root - spacing: 0 - +Item { + property real scaling: 1 readonly property string tabIcon: "brightness_6" readonly property string tabLabel: "Brightness" + Layout.fillWidth: true + Layout.fillHeight: true ScrollView { - id: scrollView - Layout.fillWidth: true - Layout.fillHeight: true - padding: Style.marginM * scaling + anchors.fill: parent clip: true - - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff ScrollBar.vertical.policy: ScrollBar.AsNeeded + ScrollBar.horizontal.policy: ScrollBar.AsNeeded + contentWidth: parent.width ColumnLayout { - width: scrollView.availableWidth - spacing: 0 - + width: parent.width ColumnLayout { - - width: scrollView.availableWidth spacing: Style.marginL * scaling + Layout.margins: Style.marginL * scaling Layout.fillWidth: true + NText { + text: "Brightness Settings" + font.pointSize: Style.fontSizeXXL * scaling + font.weight: Style.fontWeightBold + color: Color.mOnSurface + } + // Bar Visibility Section NToggle { label: "Show Bar Icon" diff --git a/Modules/SettingsPanel/Tabs/ColorSchemeTab.qml b/Modules/SettingsPanel/Tabs/ColorSchemeTab.qml index 80da36a2..c7343b6b 100644 --- a/Modules/SettingsPanel/Tabs/ColorSchemeTab.qml +++ b/Modules/SettingsPanel/Tabs/ColorSchemeTab.qml @@ -163,28 +163,22 @@ ColumnLayout { Layout.bottomMargin: Style.marginL * scaling } - NText { - text: "Predefined Color Schemes" - font.pointSize: Style.fontSizeXXL * scaling - font.weight: Style.fontWeightBold - color: Color.mOnSurface - } - ColumnLayout { spacing: Style.marginXXS * scaling Layout.fillWidth: true - // NText { - // text: "Predefined Color Schemes" - // font.pointSize: Style.fontSizeL * scaling - // font.weight: Style.fontWeightBold - // color: Color.mOnSurface - // Layout.fillWidth: true - // } + NText { + text: "Predefined Color Schemes" + font.pointSize: Style.fontSizeL * scaling + font.weight: Style.fontWeightBold + color: Color.mOnSurface + Layout.fillWidth: true + } + 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." font.pointSize: Style.fontSizeXS * scaling - color: Color.mOnSurfaceVariant + color: Color.mOnSurface Layout.fillWidth: true wrapMode: Text.WordWrap } diff --git a/Modules/SettingsPanel/Tabs/GeneralTab.qml b/Modules/SettingsPanel/Tabs/GeneralTab.qml index 19da93fb..1cb1878a 100644 --- a/Modules/SettingsPanel/Tabs/GeneralTab.qml +++ b/Modules/SettingsPanel/Tabs/GeneralTab.qml @@ -33,6 +33,13 @@ ColumnLayout { spacing: Style.marginL * scaling Layout.fillWidth: true + NText { + text: "General Settings" + font.pointSize: Style.fontSizeXXL * scaling + font.weight: Style.fontWeightBold + color: Color.mOnSurface + } + // Profile section ColumnLayout { spacing: Style.marginS * scaling diff --git a/Modules/SettingsPanel/Tabs/LauncherTab.qml b/Modules/SettingsPanel/Tabs/LauncherTab.qml index 5d9d6aa9..ae10ade5 100644 --- a/Modules/SettingsPanel/Tabs/LauncherTab.qml +++ b/Modules/SettingsPanel/Tabs/LauncherTab.qml @@ -34,7 +34,7 @@ ColumnLayout { Layout.fillWidth: true NText { - text: "Launcer Options" + text: "Launcher" font.pointSize: Style.fontSizeXXL * scaling font.weight: Style.fontWeightBold color: Color.mOnSurface @@ -56,7 +56,7 @@ ColumnLayout { } NText { - text: "Launcer Anchoring" + text: "Launcher Position" font.pointSize: Style.fontSizeXXL * scaling font.weight: Style.fontWeightBold color: Color.mOnSurface diff --git a/Modules/SettingsPanel/Tabs/NetworkTab.qml b/Modules/SettingsPanel/Tabs/NetworkTab.qml index f621f790..7029ecb5 100644 --- a/Modules/SettingsPanel/Tabs/NetworkTab.qml +++ b/Modules/SettingsPanel/Tabs/NetworkTab.qml @@ -34,6 +34,13 @@ ColumnLayout { spacing: Style.marginL * scaling Layout.fillWidth: true + NText { + text: "Interfaces" + font.pointSize: Style.fontSizeXXL * scaling + font.weight: Style.fontWeightBold + color: Color.mOnSurface + } + NToggle { label: "WiFi Enabled" description: "Enable WiFi connectivity." diff --git a/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml b/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml index a02b3a34..836ca6cf 100644 --- a/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml +++ b/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml @@ -33,6 +33,14 @@ ColumnLayout { spacing: Style.marginXS * scaling 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 ColumnLayout { spacing: Style.marginS * scaling diff --git a/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml b/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml index f3783a5d..4e7cd528 100644 --- a/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml +++ b/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml @@ -33,6 +33,14 @@ ColumnLayout { spacing: Style.marginXS * scaling 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 ColumnLayout { spacing: Style.marginM * scaling diff --git a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml index b3112e85..79b7fa29 100644 --- a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml +++ b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml @@ -31,7 +31,7 @@ Item { // Current wallpaper display NText { text: "Current Wallpaper" - font.pointSize: Style.fontSizeL * scaling + font.pointSize: Style.fontSizeXXL * scaling font.weight: Style.fontWeightBold color: Color.mOnSurface } diff --git a/Modules/SettingsPanel/Tabs/WallpaperTab.qml b/Modules/SettingsPanel/Tabs/WallpaperTab.qml index 8fe156de..f8da98d2 100644 --- a/Modules/SettingsPanel/Tabs/WallpaperTab.qml +++ b/Modules/SettingsPanel/Tabs/WallpaperTab.qml @@ -34,6 +34,14 @@ ColumnLayout { spacing: Style.marginL * scaling 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 ColumnLayout { spacing: Style.marginS * scaling