WIP - modular bar (need to fix brightness & tray)
This commit is contained in:
parent
8f951946ea
commit
8e562e0701
31 changed files with 785 additions and 136 deletions
|
|
@ -130,6 +130,15 @@ Singleton {
|
|||
property bool alwaysShowBatteryPercentage: false
|
||||
property real backgroundOpacity: 1.0
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue