diff --git a/.config/konsolerc b/.config/konsolerc new file mode 100644 index 000000000..31a3b7571 --- /dev/null +++ b/.config/konsolerc @@ -0,0 +1,11 @@ +[Desktop Entry] +DefaultProfile=Profile 1.profile + +[General] +ConfigVersion=1 + +[KonsoleWindow] +UseSingleInstance=true + +[UiSettings] +ColorScheme= diff --git a/.config/quickshell/ii/modules/background/Background.qml b/.config/quickshell/ii/modules/background/Background.qml index 5cffaa9f3..54224244f 100644 --- a/.config/quickshell/ii/modules/background/Background.qml +++ b/.config/quickshell/ii/modules/background/Background.qml @@ -12,278 +12,276 @@ import Quickshell.Io import Quickshell.Wayland import Quickshell.Hyprland -Scope { + +Variants { id: root readonly property bool fixedClockPosition: Config.options.background.fixedClockPosition readonly property real fixedClockX: Config.options.background.clockX readonly property real fixedClockY: Config.options.background.clockY + model: Quickshell.screens - Variants { - model: Quickshell.screens + PanelWindow { + id: bgRoot - PanelWindow { - id: bgRoot + required property var modelData - required property var modelData + // Hide when fullscreen + readonly property Toplevel activeWindow: ToplevelManager.activeToplevel + property bool focusingThisMonitor: HyprlandData.activeWorkspace?.monitor == monitor?.name + visible: !(activeWindow?.fullscreen && activeWindow?.activated && focusingThisMonitor) - // Hide when fullscreen - readonly property Toplevel activeWindow: ToplevelManager.activeToplevel - property bool focusingThisMonitor: HyprlandData.activeWorkspace?.monitor == monitor?.name - visible: !(activeWindow?.fullscreen && activeWindow?.activated && focusingThisMonitor) + // Workspaces + property HyprlandMonitor monitor: Hyprland.monitorFor(modelData) + property list relevantWindows: HyprlandData.windowList.filter(win => win.monitor == monitor?.id && win.workspace.id >= 0).sort((a, b) => a.workspace.id - b.workspace.id) + property int firstWorkspaceId: relevantWindows[0]?.workspace.id || 1 + property int lastWorkspaceId: relevantWindows[relevantWindows.length - 1]?.workspace.id || 10 + // Wallpaper + property bool wallpaperIsVideo: Config.options.background.wallpaperPath.endsWith(".mp4") + || Config.options.background.wallpaperPath.endsWith(".webm") + || Config.options.background.wallpaperPath.endsWith(".mkv") + || Config.options.background.wallpaperPath.endsWith(".avi") + || Config.options.background.wallpaperPath.endsWith(".mov") + property string wallpaperPath: wallpaperIsVideo ? Config.options.background.thumbnailPath : Config.options.background.wallpaperPath + property real preferredWallpaperScale: Config.options.background.parallax.workspaceZoom + property real effectiveWallpaperScale: 1 // Some reasonable init value, to be updated + property int wallpaperWidth: modelData.width // Some reasonable init value, to be updated + property int wallpaperHeight: modelData.height // Some reasonable init value, to be updated + property real movableXSpace: (Math.min(wallpaperWidth * effectiveWallpaperScale, screen.width * preferredWallpaperScale) - screen.width) / 2 + property real movableYSpace: (Math.min(wallpaperHeight * effectiveWallpaperScale, screen.height * preferredWallpaperScale) - screen.height) / 2 + // Position + property real clockX: (modelData.width / 2) + ((Math.random() < 0.5 ? -1 : 1) * modelData.width) + property real clockY: (modelData.height / 2) + ((Math.random() < 0.5 ? -1 : 1) * modelData.height) + property var textHorizontalAlignment: clockX < screen.width / 3 ? Text.AlignLeft : + (clockX > screen.width * 2 / 3 ? Text.AlignRight : Text.AlignHCenter) + // Colors + property color dominantColor: Appearance.colors.colPrimary + property bool dominantColorIsDark: dominantColor.hslLightness < 0.5 + property color colText: CF.ColorUtils.colorWithLightness(Appearance.colors.colPrimary, (dominantColorIsDark ? 0.8 : 0.12)) - // Workspaces - property HyprlandMonitor monitor: Hyprland.monitorFor(modelData) - property list relevantWindows: HyprlandData.windowList.filter(win => win.monitor == monitor?.id && win.workspace.id >= 0).sort((a, b) => a.workspace.id - b.workspace.id) - property int firstWorkspaceId: relevantWindows[0]?.workspace.id || 1 - property int lastWorkspaceId: relevantWindows[relevantWindows.length - 1]?.workspace.id || 10 - // Wallpaper - property bool wallpaperIsVideo: Config.options.background.wallpaperPath.endsWith(".mp4") - || Config.options.background.wallpaperPath.endsWith(".webm") - || Config.options.background.wallpaperPath.endsWith(".mkv") - || Config.options.background.wallpaperPath.endsWith(".avi") - || Config.options.background.wallpaperPath.endsWith(".mov") - property string wallpaperPath: wallpaperIsVideo ? Config.options.background.thumbnailPath : Config.options.background.wallpaperPath - property real preferredWallpaperScale: Config.options.background.parallax.workspaceZoom - property real effectiveWallpaperScale: 1 // Some reasonable init value, to be updated - property int wallpaperWidth: modelData.width // Some reasonable init value, to be updated - property int wallpaperHeight: modelData.height // Some reasonable init value, to be updated - property real movableXSpace: (Math.min(wallpaperWidth * effectiveWallpaperScale, screen.width * preferredWallpaperScale) - screen.width) / 2 - property real movableYSpace: (Math.min(wallpaperHeight * effectiveWallpaperScale, screen.height * preferredWallpaperScale) - screen.height) / 2 - // Position - property real clockX: (modelData.width / 2) + ((Math.random() < 0.5 ? -1 : 1) * modelData.width) - property real clockY: (modelData.height / 2) + ((Math.random() < 0.5 ? -1 : 1) * modelData.height) - property var textHorizontalAlignment: clockX < screen.width / 3 ? Text.AlignLeft : - (clockX > screen.width * 2 / 3 ? Text.AlignRight : Text.AlignHCenter) - // Colors - property color dominantColor: Appearance.colors.colPrimary - property bool dominantColorIsDark: dominantColor.hslLightness < 0.5 - property color colText: CF.ColorUtils.colorWithLightness(Appearance.colors.colPrimary, (dominantColorIsDark ? 0.8 : 0.12)) + // Layer props + screen: modelData + exclusionMode: ExclusionMode.Ignore + WlrLayershell.layer: GlobalStates.screenLocked ? WlrLayer.Top : WlrLayer.Bottom + // WlrLayershell.layer: WlrLayer.Bottom + WlrLayershell.namespace: "quickshell:background" + anchors { + top: true + bottom: true + left: true + right: true + } + color: "transparent" - // Layer props - screen: modelData - exclusionMode: ExclusionMode.Ignore - WlrLayershell.layer: GlobalStates.screenLocked ? WlrLayer.Top : WlrLayer.Bottom - // WlrLayershell.layer: WlrLayer.Bottom - WlrLayershell.namespace: "quickshell:background" + onWallpaperPathChanged: { + bgRoot.updateZoomScale() + // Clock position gets updated after zoom scale is updated + } + + // Wallpaper zoom scale + function updateZoomScale() { + getWallpaperSizeProc.path = bgRoot.wallpaperPath + getWallpaperSizeProc.running = true; + } + Process { + id: getWallpaperSizeProc + property string path: bgRoot.wallpaperPath + command: [ "magick", "identify", "-format", "%w %h", path ] + stdout: StdioCollector { + id: wallpaperSizeOutputCollector + onStreamFinished: { + const output = wallpaperSizeOutputCollector.text + const [width, height] = output.split(" ").map(Number); + bgRoot.wallpaperWidth = width + bgRoot.wallpaperHeight = height + bgRoot.effectiveWallpaperScale = Math.max(1, Math.min( + bgRoot.preferredWallpaperScale, + width / bgRoot.screen.width, + height / bgRoot.screen.height + )); + + bgRoot.updateClockPosition() + } + } + } + + // Clock positioning + function updateClockPosition() { + // Somehow all this manual setting is needed to make the proc correctly use the new values + leastBusyRegionProc.path = bgRoot.wallpaperPath + leastBusyRegionProc.contentWidth = clock.implicitWidth + leastBusyRegionProc.contentHeight = clock.implicitHeight + leastBusyRegionProc.horizontalPadding = (effectiveWallpaperScale - 1) / 2 * screen.width + 100 + leastBusyRegionProc.verticalPadding = (effectiveWallpaperScale - 1) / 2 * screen.height + 100 + leastBusyRegionProc.running = false; + leastBusyRegionProc.running = true; + } + Process { + id: leastBusyRegionProc + property string path: bgRoot.wallpaperPath + property int contentWidth: 300 + property int contentHeight: 300 + property int horizontalPadding: bgRoot.movableXSpace + property int verticalPadding: bgRoot.movableYSpace + command: [Quickshell.shellPath("scripts/images/least_busy_region.py"), + "--screen-width", bgRoot.screen.width, + "--screen-height", bgRoot.screen.height, + "--width", contentWidth, + "--height", contentHeight, + "--horizontal-padding", horizontalPadding, + "--vertical-padding", verticalPadding, + path + ] + stdout: StdioCollector { + id: leastBusyRegionOutputCollector + onStreamFinished: { + const output = leastBusyRegionOutputCollector.text + // console.log("[Background] Least busy region output:", output) + if (output.length === 0) return; + const parsedContent = JSON.parse(output) + bgRoot.clockX = parsedContent.center_x + bgRoot.clockY = parsedContent.center_y + bgRoot.dominantColor = parsedContent.dominant_color || Appearance.colors.colPrimary + } + } + } + + // Wallpaper + Image { + id: wallpaper + visible: !bgRoot.wallpaperIsVideo + property real value // 0 to 1, for offset + value: { + // Range = groups that workspaces span on + const chunkSize = Config?.options.bar.workspaces.shown ?? 10; + const lower = Math.floor(bgRoot.firstWorkspaceId / chunkSize) * chunkSize; + const upper = Math.ceil(bgRoot.lastWorkspaceId / chunkSize) * chunkSize; + const range = upper - lower; + return (Config.options.background.parallax.enableWorkspace ? ((bgRoot.monitor.activeWorkspace?.id - lower) / range) : 0.5) + + (0.15 * GlobalStates.sidebarRightOpen * Config.options.background.parallax.enableSidebar) + - (0.15 * GlobalStates.sidebarLeftOpen * Config.options.background.parallax.enableSidebar) + } + property real effectiveValue: Math.max(0, Math.min(1, value)) + x: -(bgRoot.movableXSpace) - (effectiveValue - 0.5) * 2 * bgRoot.movableXSpace + y: -(bgRoot.movableYSpace) + source: bgRoot.wallpaperPath + fillMode: Image.PreserveAspectCrop + Behavior on x { + NumberAnimation { + duration: 600 + easing.type: Easing.OutCubic + } + } + sourceSize { + width: bgRoot.screen.width * bgRoot.effectiveWallpaperScale + height: bgRoot.screen.height * bgRoot.effectiveWallpaperScale + } + } + + // The clock + Item { + id: clock anchors { - top: true - bottom: true - left: true - right: true - } - color: "transparent" - - onWallpaperPathChanged: { - bgRoot.updateZoomScale() - // Clock position gets updated after zoom scale is updated + left: wallpaper.left + top: wallpaper.top + leftMargin: ((root.fixedClockPosition ? root.fixedClockX : bgRoot.clockX * bgRoot.effectiveWallpaperScale) - implicitWidth / 2) - (wallpaper.effectiveValue * bgRoot.movableXSpace) + topMargin: ((root.fixedClockPosition ? root.fixedClockY : bgRoot.clockY * bgRoot.effectiveWallpaperScale) - implicitHeight / 2) + Behavior on leftMargin { + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } + Behavior on topMargin { + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } } - // Wallpaper zoom scale - function updateZoomScale() { - getWallpaperSizeProc.path = bgRoot.wallpaperPath - getWallpaperSizeProc.running = true; - } - Process { - id: getWallpaperSizeProc - property string path: bgRoot.wallpaperPath - command: [ "magick", "identify", "-format", "%w %h", path ] - stdout: StdioCollector { - id: wallpaperSizeOutputCollector - onStreamFinished: { - const output = wallpaperSizeOutputCollector.text - const [width, height] = output.split(" ").map(Number); - bgRoot.wallpaperWidth = width - bgRoot.wallpaperHeight = height - bgRoot.effectiveWallpaperScale = Math.max(1, Math.min( - bgRoot.preferredWallpaperScale, - width / bgRoot.screen.width, - height / bgRoot.screen.height - )); + implicitWidth: clockColumn.implicitWidth + implicitHeight: clockColumn.implicitHeight - bgRoot.updateClockPosition() + ColumnLayout { + id: clockColumn + anchors.centerIn: parent + spacing: 0 + + StyledText { + Layout.fillWidth: true + horizontalAlignment: bgRoot.textHorizontalAlignment + font { + family: Appearance.font.family.expressive + pixelSize: 90 + weight: Font.Bold } + color: bgRoot.colText + style: Text.Raised + styleColor: Appearance.colors.colShadow + text: DateTime.time } - } - - // Clock positioning - function updateClockPosition() { - // Somehow all this manual setting is needed to make the proc correctly use the new values - leastBusyRegionProc.path = bgRoot.wallpaperPath - leastBusyRegionProc.contentWidth = clock.implicitWidth - leastBusyRegionProc.contentHeight = clock.implicitHeight - leastBusyRegionProc.horizontalPadding = (effectiveWallpaperScale - 1) / 2 * screen.width + 100 - leastBusyRegionProc.verticalPadding = (effectiveWallpaperScale - 1) / 2 * screen.height + 100 - leastBusyRegionProc.running = false; - leastBusyRegionProc.running = true; - } - Process { - id: leastBusyRegionProc - property string path: bgRoot.wallpaperPath - property int contentWidth: 300 - property int contentHeight: 300 - property int horizontalPadding: bgRoot.movableXSpace - property int verticalPadding: bgRoot.movableYSpace - command: [Quickshell.shellPath("scripts/images/least_busy_region.py"), - "--screen-width", bgRoot.screen.width, - "--screen-height", bgRoot.screen.height, - "--width", contentWidth, - "--height", contentHeight, - "--horizontal-padding", horizontalPadding, - "--vertical-padding", verticalPadding, - path - ] - stdout: StdioCollector { - id: leastBusyRegionOutputCollector - onStreamFinished: { - const output = leastBusyRegionOutputCollector.text - // console.log("[Background] Least busy region output:", output) - if (output.length === 0) return; - const parsedContent = JSON.parse(output) - bgRoot.clockX = parsedContent.center_x - bgRoot.clockY = parsedContent.center_y - bgRoot.dominantColor = parsedContent.dominant_color || Appearance.colors.colPrimary + StyledText { + Layout.fillWidth: true + Layout.topMargin: -5 + horizontalAlignment: bgRoot.textHorizontalAlignment + font { + family: Appearance.font.family.expressive + pixelSize: 20 + weight: Font.DemiBold } + color: bgRoot.colText + style: Text.Raised + styleColor: Appearance.colors.colShadow + text: DateTime.date } } - // Wallpaper - Image { - id: wallpaper - visible: !bgRoot.wallpaperIsVideo - property real value // 0 to 1, for offset - value: { - // Range = groups that workspaces span on - const chunkSize = Config?.options.bar.workspaces.shown ?? 10; - const lower = Math.floor(bgRoot.firstWorkspaceId / chunkSize) * chunkSize; - const upper = Math.ceil(bgRoot.lastWorkspaceId / chunkSize) * chunkSize; - const range = upper - lower; - return (Config.options.background.parallax.enableWorkspace ? ((bgRoot.monitor?.activeWorkspace?.id ?? 1 - lower) / range) : 0.5) - + (0.15 * GlobalStates.sidebarRightOpen * Config.options.background.parallax.enableSidebar) - - (0.15 * GlobalStates.sidebarLeftOpen * Config.options.background.parallax.enableSidebar) - } - property real effectiveValue: Math.max(0, Math.min(1, value)) - x: -(bgRoot.movableXSpace) - (effectiveValue - 0.5) * 2 * bgRoot.movableXSpace - y: -(bgRoot.movableYSpace) - source: bgRoot.wallpaperPath - fillMode: Image.PreserveAspectCrop - Behavior on x { - NumberAnimation { - duration: 600 - easing.type: Easing.OutCubic - } - } - sourceSize { - width: bgRoot.screen.width * bgRoot.effectiveWallpaperScale - height: bgRoot.screen.height * bgRoot.effectiveWallpaperScale - } - } - - // The clock - Item { - id: clock + RowLayout { anchors { - left: wallpaper.left - top: wallpaper.top - leftMargin: ((root.fixedClockPosition ? root.fixedClockX : bgRoot.clockX * bgRoot.effectiveWallpaperScale) - implicitWidth / 2) - (wallpaper.effectiveValue * bgRoot.movableXSpace) - topMargin: ((root.fixedClockPosition ? root.fixedClockY : bgRoot.clockY * bgRoot.effectiveWallpaperScale) - implicitHeight / 2) - Behavior on leftMargin { - animation: Appearance.animation.elementMove.numberAnimation.createObject(this) - } - Behavior on topMargin { - animation: Appearance.animation.elementMove.numberAnimation.createObject(this) - } + top: clockColumn.bottom + left: bgRoot.textHorizontalAlignment === Text.AlignLeft ? clockColumn.left : undefined + right: bgRoot.textHorizontalAlignment === Text.AlignRight ? clockColumn.right : undefined + horizontalCenter: bgRoot.textHorizontalAlignment === Text.AlignHCenter ? clockColumn.horizontalCenter : undefined + topMargin: 5 + leftMargin: -5 + rightMargin: -5 } - - implicitWidth: clockColumn.implicitWidth - implicitHeight: clockColumn.implicitHeight - - ColumnLayout { - id: clockColumn - anchors.centerIn: parent - spacing: 0 - - StyledText { - Layout.fillWidth: true - horizontalAlignment: bgRoot.textHorizontalAlignment - font { - family: Appearance.font.family.expressive - pixelSize: 90 - weight: Font.Bold - } - color: bgRoot.colText - style: Text.Raised - styleColor: Appearance.colors.colShadow - text: DateTime.time - } - StyledText { - Layout.fillWidth: true - Layout.topMargin: -5 - horizontalAlignment: bgRoot.textHorizontalAlignment - font { - family: Appearance.font.family.expressive - pixelSize: 20 - weight: Font.DemiBold - } - color: bgRoot.colText - style: Text.Raised - styleColor: Appearance.colors.colShadow - text: DateTime.date - } - } - - RowLayout { - anchors { - top: clockColumn.bottom - left: bgRoot.textHorizontalAlignment === Text.AlignLeft ? clockColumn.left : undefined - right: bgRoot.textHorizontalAlignment === Text.AlignRight ? clockColumn.right : undefined - horizontalCenter: bgRoot.textHorizontalAlignment === Text.AlignHCenter ? clockColumn.horizontalCenter : undefined - topMargin: 5 - leftMargin: -5 - rightMargin: -5 - } - opacity: GlobalStates.screenLocked ? 1 : 0 - visible: opacity > 0 - Behavior on opacity { - animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) - } - Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft; implicitWidth: 1 } - MaterialSymbol { - text: "lock" - Layout.fillWidth: false - iconSize: Appearance.font.pixelSize.huge - color: bgRoot.colText - } - StyledText { - Layout.fillWidth: false - text: "Locked" - color: bgRoot.colText - font { - pixelSize: Appearance.font.pixelSize.larger - } - } - Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignRight; implicitWidth: 1 } - - } - } - - // Password prompt - StyledText { - anchors { - horizontalCenter: parent.horizontalCenter - bottom: parent.bottom - bottomMargin: 30 - } - opacity: (GlobalStates.screenLocked && !GlobalStates.screenLockContainsCharacters) ? 1 : 0 - scale: opacity + opacity: GlobalStates.screenLocked ? 1 : 0 visible: opacity > 0 Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } - text: "Enter password" - color: CF.ColorUtils.transparentize(bgRoot.colText, 0.3) - font { - pixelSize: Appearance.font.pixelSize.normal + Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft; implicitWidth: 1 } + MaterialSymbol { + text: "lock" + Layout.fillWidth: false + iconSize: Appearance.font.pixelSize.huge + color: bgRoot.colText } + StyledText { + Layout.fillWidth: false + text: "Locked" + color: bgRoot.colText + font { + pixelSize: Appearance.font.pixelSize.larger + } + } + Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignRight; implicitWidth: 1 } + + } + } + + // Password prompt + StyledText { + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + bottomMargin: 30 + } + opacity: (GlobalStates.screenLocked && !GlobalStates.screenLockContainsCharacters) ? 1 : 0 + scale: opacity + visible: opacity > 0 + Behavior on opacity { + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) + } + text: "Enter password" + color: CF.ColorUtils.transparentize(bgRoot.colText, 0.3) + font { + pixelSize: Appearance.font.pixelSize.normal } } } diff --git a/.config/quickshell/ii/modules/bar/ActiveWindow.qml b/.config/quickshell/ii/modules/bar/ActiveWindow.qml index bb2b59e5f..9e7eeba1f 100644 --- a/.config/quickshell/ii/modules/bar/ActiveWindow.qml +++ b/.config/quickshell/ii/modules/bar/ActiveWindow.qml @@ -4,13 +4,13 @@ import qs.modules.common.widgets import qs import QtQuick import QtQuick.Layouts +import Quickshell import Quickshell.Wayland import Quickshell.Hyprland Item { id: root - required property var bar - readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen) + readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.QsWindow.window?.screen) readonly property Toplevel activeWindow: ToplevelManager.activeToplevel property string activeWindowAddress: `0x${activeWindow?.HyprlandToplevel?.address}` diff --git a/.config/quickshell/ii/modules/bar/Bar.qml b/.config/quickshell/ii/modules/bar/Bar.qml index 7fe8668e1..c08133ad6 100644 --- a/.config/quickshell/ii/modules/bar/Bar.qml +++ b/.config/quickshell/ii/modules/bar/Bar.qml @@ -18,14 +18,6 @@ Scope { readonly property int osdHideMouseMoveThreshold: 20 property bool showBarBackground: Config.options.bar.showBackground - component VerticalBarSeparator: Rectangle { - Layout.topMargin: Appearance.sizes.baseBarHeight / 3 - Layout.bottomMargin: Appearance.sizes.baseBarHeight / 3 - Layout.fillHeight: true - implicitWidth: 1 - color: Appearance.colors.colOutlineVariant - } - Variants { // For each monitor model: { @@ -63,8 +55,9 @@ Scope { right: true } - Item { // Bar content region + BarContent { id: barContent + anchors { right: parent.right left: parent.left @@ -72,7 +65,6 @@ Scope { bottom: undefined } implicitHeight: Appearance.sizes.barHeight - height: Appearance.sizes.barHeight states: State { name: "bottom" @@ -87,427 +79,6 @@ Scope { } } } - - // Background shadow - Loader { - active: showBarBackground && Config.options.bar.cornerStyle === 1 - anchors.fill: barBackground - sourceComponent: StyledRectangularShadow { - anchors.fill: undefined // The loader's anchors act on this, and this should not have any anchor - target: barBackground - } - } - // Background - Rectangle { - id: barBackground - anchors { - fill: parent - margins: Config.options.bar.cornerStyle === 1 ? (Appearance.sizes.hyprlandGapsOut) : 0 // idk why but +1 is needed - } - color: showBarBackground ? Appearance.colors.colLayer0 : "transparent" - radius: Config.options.bar.cornerStyle === 1 ? Appearance.rounding.windowRounding : 0 - border.width: Config.options.bar.cornerStyle === 1 ? 1 : 0 - border.color: Appearance.colors.colLayer0Border - } - - MouseArea { // Left side | scroll to change brightness - id: barLeftSideMouseArea - anchors.left: parent.left - implicitHeight: Appearance.sizes.baseBarHeight - height: Appearance.sizes.barHeight - width: (barRoot.width - middleSection.width) / 2 - property bool hovered: false - property real lastScrollX: 0 - property real lastScrollY: 0 - property bool trackingScroll: false - acceptedButtons: Qt.LeftButton - hoverEnabled: true - propagateComposedEvents: true - onEntered: event => { - barLeftSideMouseArea.hovered = true; - } - onExited: event => { - barLeftSideMouseArea.hovered = false; - barLeftSideMouseArea.trackingScroll = false; - } - onPressed: event => { - if (event.button === Qt.LeftButton) { - GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen; - } - } - // Scroll to change brightness - WheelHandler { - onWheel: event => { - if (event.angleDelta.y < 0) - barRoot.brightnessMonitor.setBrightness(barRoot.brightnessMonitor.brightness - 0.05); - else if (event.angleDelta.y > 0) - barRoot.brightnessMonitor.setBrightness(barRoot.brightnessMonitor.brightness + 0.05); - // Store the mouse position and start tracking - barLeftSideMouseArea.lastScrollX = event.x; - barLeftSideMouseArea.lastScrollY = event.y; - barLeftSideMouseArea.trackingScroll = true; - } - acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad - } - onPositionChanged: mouse => { - if (barLeftSideMouseArea.trackingScroll) { - const dx = mouse.x - barLeftSideMouseArea.lastScrollX; - const dy = mouse.y - barLeftSideMouseArea.lastScrollY; - if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) { - GlobalStates.osdBrightnessOpen = false; - barLeftSideMouseArea.trackingScroll = false; - } - } - } - Item { - // Left section - anchors.fill: parent - implicitHeight: leftSectionRowLayout.implicitHeight - implicitWidth: leftSectionRowLayout.implicitWidth - - ScrollHint { - reveal: barLeftSideMouseArea.hovered - icon: "light_mode" - tooltipText: Translation.tr("Scroll to change brightness") - side: "left" - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - } - - RowLayout { // Content - id: leftSectionRowLayout - anchors.fill: parent - spacing: 10 - - RippleButton { - // Left sidebar button - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - Layout.leftMargin: Appearance.rounding.screenRounding - Layout.fillWidth: false - property real buttonPadding: 5 - implicitWidth: distroIcon.width + buttonPadding * 2 - implicitHeight: distroIcon.height + buttonPadding * 2 - - buttonRadius: Appearance.rounding.full - colBackground: barLeftSideMouseArea.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1) - colBackgroundHover: Appearance.colors.colLayer1Hover - colRipple: Appearance.colors.colLayer1Active - colBackgroundToggled: Appearance.colors.colSecondaryContainer - colBackgroundToggledHover: Appearance.colors.colSecondaryContainerHover - colRippleToggled: Appearance.colors.colSecondaryContainerActive - toggled: GlobalStates.sidebarLeftOpen - property color colText: toggled ? Appearance.m3colors.m3onSecondaryContainer : Appearance.colors.colOnLayer0 - - onPressed: { - GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen; - } - - CustomIcon { - id: distroIcon - anchors.centerIn: parent - width: 19.5 - height: 19.5 - source: Config.options.bar.topLeftIcon == 'distro' ? SystemInfo.distroIcon : "spark-symbolic" - colorize: true - color: Appearance.colors.colOnLayer0 - } - } - - ActiveWindow { - visible: barRoot.useShortenedForm === 0 - Layout.rightMargin: Appearance.rounding.screenRounding - Layout.fillWidth: true - Layout.fillHeight: true - bar: barRoot - } - } - } - } - - RowLayout { // Middle section - id: middleSection - anchors.centerIn: parent - spacing: Config.options?.bar.borderless ? 4 : 8 - - BarGroup { - id: leftCenterGroup - Layout.preferredWidth: barRoot.centerSideModuleWidth - Layout.fillHeight: true - - Resources { - alwaysShowAllResources: barRoot.useShortenedForm === 2 - Layout.fillWidth: barRoot.useShortenedForm === 2 - } - - Media { - visible: barRoot.useShortenedForm < 2 - Layout.fillWidth: true - } - } - - VerticalBarSeparator { - visible: Config.options?.bar.borderless - } - - BarGroup { - id: middleCenterGroup - padding: workspacesWidget.widgetPadding - Layout.fillHeight: true - - Workspaces { - id: workspacesWidget - bar: barRoot - Layout.fillHeight: true - MouseArea { - // Right-click to toggle overview - anchors.fill: parent - acceptedButtons: Qt.RightButton - - onPressed: event => { - if (event.button === Qt.RightButton) { - GlobalStates.overviewOpen = !GlobalStates.overviewOpen; - } - } - } - } - } - - VerticalBarSeparator { - visible: Config.options?.bar.borderless - } - - MouseArea { - id: rightCenterGroup - implicitWidth: rightCenterGroupContent.implicitWidth - implicitHeight: rightCenterGroupContent.implicitHeight - Layout.preferredWidth: barRoot.centerSideModuleWidth - Layout.fillHeight: true - - onPressed: { - GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; - } - - BarGroup { - id: rightCenterGroupContent - anchors.fill: parent - - ClockWidget { - showDate: (Config.options.bar.verbose && barRoot.useShortenedForm < 2) - Layout.alignment: Qt.AlignVCenter - Layout.fillWidth: true - } - - UtilButtons { - visible: (Config.options.bar.verbose && barRoot.useShortenedForm === 0) - Layout.alignment: Qt.AlignVCenter - } - - BatteryIndicator { - visible: (barRoot.useShortenedForm < 2 && UPower.displayDevice.isLaptopBattery) - Layout.alignment: Qt.AlignVCenter - } - } - } - - VerticalBarSeparator { - visible: Config.options.bar.borderless && Config.options.bar.weather.enable - } - } - - MouseArea { // Right side | scroll to change volume - id: barRightSideMouseArea - - anchors.right: parent.right - implicitHeight: Appearance.sizes.baseBarHeight - height: Appearance.sizes.barHeight - width: (barRoot.width - middleSection.width) / 2 - - property bool hovered: false - property real lastScrollX: 0 - property real lastScrollY: 0 - property bool trackingScroll: false - - acceptedButtons: Qt.LeftButton - hoverEnabled: true - propagateComposedEvents: true - onEntered: event => { - barRightSideMouseArea.hovered = true; - } - onExited: event => { - barRightSideMouseArea.hovered = false; - barRightSideMouseArea.trackingScroll = false; - } - onPressed: event => { - if (event.button === Qt.LeftButton) { - GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; - } else if (event.button === Qt.RightButton) { - MprisController.activePlayer.next(); - } - } - // Scroll to change volume - WheelHandler { - onWheel: event => { - const currentVolume = Audio.value; - const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2; - if (event.angleDelta.y < 0) - Audio.sink.audio.volume -= step; - else if (event.angleDelta.y > 0) - Audio.sink.audio.volume = Math.min(1, Audio.sink.audio.volume + step); - // Store the mouse position and start tracking - barRightSideMouseArea.lastScrollX = event.x; - barRightSideMouseArea.lastScrollY = event.y; - barRightSideMouseArea.trackingScroll = true; - } - acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad - } - onPositionChanged: mouse => { - if (barRightSideMouseArea.trackingScroll) { - const dx = mouse.x - barRightSideMouseArea.lastScrollX; - const dy = mouse.y - barRightSideMouseArea.lastScrollY; - if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) { - GlobalStates.osdVolumeOpen = false; - barRightSideMouseArea.trackingScroll = false; - } - } - } - - Item { - anchors.fill: parent - implicitHeight: rightSectionRowLayout.implicitHeight - implicitWidth: rightSectionRowLayout.implicitWidth - - ScrollHint { - reveal: barRightSideMouseArea.hovered - icon: "volume_up" - tooltipText: Translation.tr("Scroll to change volume") - side: "right" - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - } - - RowLayout { - id: rightSectionRowLayout - anchors.fill: parent - spacing: 5 - layoutDirection: Qt.RightToLeft - - RippleButton { // Right sidebar button - id: rightSidebarButton - - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - Layout.rightMargin: Appearance.rounding.screenRounding - Layout.fillWidth: false - - implicitWidth: indicatorsRowLayout.implicitWidth + 10 * 2 - implicitHeight: indicatorsRowLayout.implicitHeight + 5 * 2 - - buttonRadius: Appearance.rounding.full - colBackground: barRightSideMouseArea.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1) - colBackgroundHover: Appearance.colors.colLayer1Hover - colRipple: Appearance.colors.colLayer1Active - colBackgroundToggled: Appearance.colors.colSecondaryContainer - colBackgroundToggledHover: Appearance.colors.colSecondaryContainerHover - colRippleToggled: Appearance.colors.colSecondaryContainerActive - toggled: GlobalStates.sidebarRightOpen - property color colText: toggled ? Appearance.m3colors.m3onSecondaryContainer : Appearance.colors.colOnLayer0 - - Behavior on colText { - animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) - } - - onPressed: { - GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; - } - - RowLayout { - id: indicatorsRowLayout - anchors.centerIn: parent - property real realSpacing: 15 - spacing: 0 - - Revealer { - reveal: Audio.sink?.audio?.muted ?? false - Layout.fillHeight: true - Layout.rightMargin: reveal ? indicatorsRowLayout.realSpacing : 0 - Behavior on Layout.rightMargin { - NumberAnimation { - duration: Appearance.animation.elementMoveFast.duration - easing.type: Appearance.animation.elementMoveFast.type - easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve - } - } - MaterialSymbol { - text: "volume_off" - iconSize: Appearance.font.pixelSize.larger - color: rightSidebarButton.colText - } - } - Revealer { - reveal: Audio.source?.audio?.muted ?? false - Layout.fillHeight: true - Layout.rightMargin: reveal ? indicatorsRowLayout.realSpacing : 0 - Behavior on Layout.rightMargin { - NumberAnimation { - duration: Appearance.animation.elementMoveFast.duration - easing.type: Appearance.animation.elementMoveFast.type - easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve - } - } - MaterialSymbol { - text: "mic_off" - iconSize: Appearance.font.pixelSize.larger - color: rightSidebarButton.colText - } - } - Loader { - active: HyprlandXkb.layoutCodes.length > 1 - visible: active - Layout.rightMargin: indicatorsRowLayout.realSpacing - sourceComponent: StyledText { - text: HyprlandXkb.currentLayoutCode - font.pixelSize: Appearance.font.pixelSize.small - color: rightSidebarButton.colText - } - } - MaterialSymbol { - Layout.rightMargin: indicatorsRowLayout.realSpacing - text: Network.materialSymbol - iconSize: Appearance.font.pixelSize.larger - color: rightSidebarButton.colText - } - MaterialSymbol { - text: Bluetooth.bluetoothConnected ? "bluetooth_connected" : Bluetooth.bluetoothEnabled ? "bluetooth" : "bluetooth_disabled" - iconSize: Appearance.font.pixelSize.larger - color: rightSidebarButton.colText - } - } - } - - SysTray { - bar: barRoot - visible: barRoot.useShortenedForm === 0 - Layout.fillWidth: false - Layout.fillHeight: true - } - - Item { - Layout.fillWidth: true - Layout.fillHeight: true - } - - // Weather - Loader { - Layout.leftMargin: 8 - Layout.fillHeight: true - active: Config.options.bar.weather.enable - sourceComponent: BarGroup { - implicitHeight: Appearance.sizes.baseBarHeight - WeatherBar {} - } - } - } - } - } } // Round decorators @@ -540,7 +111,7 @@ Scope { left: parent.left } - size: Appearance.rounding.screenRounding + implicitSize: Appearance.rounding.screenRounding color: showBarBackground ? Appearance.colors.colLayer0 : "transparent" corner: RoundCorner.CornerEnum.TopLeft @@ -559,7 +130,7 @@ Scope { top: !Config.options.bar.bottom ? parent.top : undefined bottom: Config.options.bar.bottom ? parent.bottom : undefined } - size: Appearance.rounding.screenRounding + implicitSize: Appearance.rounding.screenRounding color: showBarBackground ? Appearance.colors.colLayer0 : "transparent" corner: RoundCorner.CornerEnum.TopRight diff --git a/.config/quickshell/ii/modules/bar/BarContent.qml b/.config/quickshell/ii/modules/bar/BarContent.qml new file mode 100644 index 000000000..616918197 --- /dev/null +++ b/.config/quickshell/ii/modules/bar/BarContent.qml @@ -0,0 +1,448 @@ +import "./weather" +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Hyprland +import Quickshell.Services.UPower +import qs +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.functions + +Item { // Bar content region + id: root + + property var screen: root.QsWindow.window?.screen + property var brightnessMonitor: Brightness.getMonitorForScreen(screen) + property real useShortenedForm: (Appearance.sizes.barHellaShortenScreenWidthThreshold >= screen?.width) ? 2 : (Appearance.sizes.barShortenScreenWidthThreshold >= screen?.width) ? 1 : 0 + readonly property int centerSideModuleWidth: (useShortenedForm == 2) ? Appearance.sizes.barCenterSideModuleWidthHellaShortened : (useShortenedForm == 1) ? Appearance.sizes.barCenterSideModuleWidthShortened : Appearance.sizes.barCenterSideModuleWidth + + component VerticalBarSeparator: Rectangle { + Layout.topMargin: Appearance.sizes.baseBarHeight / 3 + Layout.bottomMargin: Appearance.sizes.baseBarHeight / 3 + Layout.fillHeight: true + implicitWidth: 1 + color: Appearance.colors.colOutlineVariant + } + + // Background shadow + Loader { + active: Config.options.bar.showBackground && Config.options.bar.cornerStyle === 1 + anchors.fill: barBackground + sourceComponent: StyledRectangularShadow { + anchors.fill: undefined // The loader's anchors act on this, and this should not have any anchor + target: barBackground + } + } + // Background + Rectangle { + id: barBackground + anchors { + fill: parent + margins: Config.options.bar.cornerStyle === 1 ? (Appearance.sizes.hyprlandGapsOut) : 0 // idk why but +1 is needed + } + color: Config.options.bar.showBackground ? Appearance.colors.colLayer0 : "transparent" + radius: Config.options.bar.cornerStyle === 1 ? Appearance.rounding.windowRounding : 0 + border.width: Config.options.bar.cornerStyle === 1 ? 1 : 0 + border.color: Appearance.colors.colLayer0Border + } + + MouseArea { // Left side | scroll to change brightness + id: barLeftSideMouseArea + anchors.left: parent.left + implicitHeight: Appearance.sizes.baseBarHeight + height: Appearance.sizes.barHeight + width: (root.width - middleSection.width) / 2 + property bool hovered: false + property real lastScrollX: 0 + property real lastScrollY: 0 + property bool trackingScroll: false + acceptedButtons: Qt.LeftButton + hoverEnabled: true + propagateComposedEvents: true + onEntered: event => { + barLeftSideMouseArea.hovered = true; + } + onExited: event => { + barLeftSideMouseArea.hovered = false; + barLeftSideMouseArea.trackingScroll = false; + } + onPressed: event => { + if (event.button === Qt.LeftButton) { + GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen; + } + } + // Scroll to change brightness + WheelHandler { + onWheel: event => { + if (event.angleDelta.y < 0) + root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness - 0.05); + else if (event.angleDelta.y > 0) + root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness + 0.05); + // Store the mouse position and start tracking + barLeftSideMouseArea.lastScrollX = event.x; + barLeftSideMouseArea.lastScrollY = event.y; + barLeftSideMouseArea.trackingScroll = true; + } + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + } + onPositionChanged: mouse => { + if (barLeftSideMouseArea.trackingScroll) { + const dx = mouse.x - barLeftSideMouseArea.lastScrollX; + const dy = mouse.y - barLeftSideMouseArea.lastScrollY; + if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) { + GlobalStates.osdBrightnessOpen = false; + barLeftSideMouseArea.trackingScroll = false; + } + } + } + Item { + // Left section + anchors.fill: parent + implicitHeight: leftSectionRowLayout.implicitHeight + implicitWidth: leftSectionRowLayout.implicitWidth + + ScrollHint { + reveal: barLeftSideMouseArea.hovered + icon: "light_mode" + tooltipText: Translation.tr("Scroll to change brightness") + side: "left" + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + } + + RowLayout { // Content + id: leftSectionRowLayout + anchors.fill: parent + spacing: 10 + + RippleButton { + // Left sidebar button + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.leftMargin: Appearance.rounding.screenRounding + Layout.fillWidth: false + property real buttonPadding: 5 + implicitWidth: distroIcon.width + buttonPadding * 2 + implicitHeight: distroIcon.height + buttonPadding * 2 + + buttonRadius: Appearance.rounding.full + colBackground: barLeftSideMouseArea.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1) + colBackgroundHover: Appearance.colors.colLayer1Hover + colRipple: Appearance.colors.colLayer1Active + colBackgroundToggled: Appearance.colors.colSecondaryContainer + colBackgroundToggledHover: Appearance.colors.colSecondaryContainerHover + colRippleToggled: Appearance.colors.colSecondaryContainerActive + toggled: GlobalStates.sidebarLeftOpen + property color colText: toggled ? Appearance.m3colors.m3onSecondaryContainer : Appearance.colors.colOnLayer0 + + onPressed: { + GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen; + } + + CustomIcon { + id: distroIcon + anchors.centerIn: parent + width: 19.5 + height: 19.5 + source: Config.options.bar.topLeftIcon == 'distro' ? SystemInfo.distroIcon : "spark-symbolic" + colorize: true + color: Appearance.colors.colOnLayer0 + } + } + + ActiveWindow { + visible: root.useShortenedForm === 0 + Layout.rightMargin: Appearance.rounding.screenRounding + Layout.fillWidth: true + Layout.fillHeight: true + } + } + } + } + + RowLayout { // Middle section + id: middleSection + anchors.centerIn: parent + spacing: Config.options?.bar.borderless ? 4 : 8 + + BarGroup { + id: leftCenterGroup + Layout.preferredWidth: root.centerSideModuleWidth + Layout.fillHeight: true + + Resources { + alwaysShowAllResources: root.useShortenedForm === 2 + Layout.fillWidth: root.useShortenedForm === 2 + } + + Media { + visible: root.useShortenedForm < 2 + Layout.fillWidth: true + } + } + + VerticalBarSeparator { + visible: Config.options?.bar.borderless + } + + BarGroup { + id: middleCenterGroup + padding: workspacesWidget.widgetPadding + Layout.fillHeight: true + + Workspaces { + id: workspacesWidget + Layout.fillHeight: true + MouseArea { + // Right-click to toggle overview + anchors.fill: parent + acceptedButtons: Qt.RightButton + + onPressed: event => { + if (event.button === Qt.RightButton) { + GlobalStates.overviewOpen = !GlobalStates.overviewOpen; + } + } + } + } + } + + VerticalBarSeparator { + visible: Config.options?.bar.borderless + } + + MouseArea { + id: rightCenterGroup + implicitWidth: rightCenterGroupContent.implicitWidth + implicitHeight: rightCenterGroupContent.implicitHeight + Layout.preferredWidth: root.centerSideModuleWidth + Layout.fillHeight: true + + onPressed: { + GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; + } + + BarGroup { + id: rightCenterGroupContent + anchors.fill: parent + + ClockWidget { + showDate: (Config.options.bar.verbose && root.useShortenedForm < 2) + Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true + } + + UtilButtons { + visible: (Config.options.bar.verbose && root.useShortenedForm === 0) + Layout.alignment: Qt.AlignVCenter + } + + BatteryIndicator { + visible: (root.useShortenedForm < 2 && UPower.displayDevice.isLaptopBattery) + Layout.alignment: Qt.AlignVCenter + } + } + } + + VerticalBarSeparator { + visible: Config.options.bar.borderless && Config.options.bar.weather.enable + } + } + + MouseArea { // Right side | scroll to change volume + id: barRightSideMouseArea + + anchors.right: parent.right + implicitHeight: Appearance.sizes.baseBarHeight + height: Appearance.sizes.barHeight + width: (root.width - middleSection.width) / 2 + + property bool hovered: false + property real lastScrollX: 0 + property real lastScrollY: 0 + property bool trackingScroll: false + + acceptedButtons: Qt.LeftButton + hoverEnabled: true + propagateComposedEvents: true + onEntered: event => { + barRightSideMouseArea.hovered = true; + } + onExited: event => { + barRightSideMouseArea.hovered = false; + barRightSideMouseArea.trackingScroll = false; + } + onPressed: event => { + if (event.button === Qt.LeftButton) { + GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; + } else if (event.button === Qt.RightButton) { + MprisController.activePlayer.next(); + } + } + // Scroll to change volume + WheelHandler { + onWheel: event => { + const currentVolume = Audio.value; + const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2; + if (event.angleDelta.y < 0) + Audio.sink.audio.volume -= step; + else if (event.angleDelta.y > 0) + Audio.sink.audio.volume = Math.min(1, Audio.sink.audio.volume + step); + // Store the mouse position and start tracking + barRightSideMouseArea.lastScrollX = event.x; + barRightSideMouseArea.lastScrollY = event.y; + barRightSideMouseArea.trackingScroll = true; + } + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + } + onPositionChanged: mouse => { + if (barRightSideMouseArea.trackingScroll) { + const dx = mouse.x - barRightSideMouseArea.lastScrollX; + const dy = mouse.y - barRightSideMouseArea.lastScrollY; + if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) { + GlobalStates.osdVolumeOpen = false; + barRightSideMouseArea.trackingScroll = false; + } + } + } + + Item { + anchors.fill: parent + implicitHeight: rightSectionRowLayout.implicitHeight + implicitWidth: rightSectionRowLayout.implicitWidth + + ScrollHint { + reveal: barRightSideMouseArea.hovered + icon: "volume_up" + tooltipText: Translation.tr("Scroll to change volume") + side: "right" + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + + RowLayout { + id: rightSectionRowLayout + anchors.fill: parent + spacing: 5 + layoutDirection: Qt.RightToLeft + + RippleButton { // Right sidebar button + id: rightSidebarButton + + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.rightMargin: Appearance.rounding.screenRounding + Layout.fillWidth: false + + implicitWidth: indicatorsRowLayout.implicitWidth + 10 * 2 + implicitHeight: indicatorsRowLayout.implicitHeight + 5 * 2 + + buttonRadius: Appearance.rounding.full + colBackground: barRightSideMouseArea.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1) + colBackgroundHover: Appearance.colors.colLayer1Hover + colRipple: Appearance.colors.colLayer1Active + colBackgroundToggled: Appearance.colors.colSecondaryContainer + colBackgroundToggledHover: Appearance.colors.colSecondaryContainerHover + colRippleToggled: Appearance.colors.colSecondaryContainerActive + toggled: GlobalStates.sidebarRightOpen + property color colText: toggled ? Appearance.m3colors.m3onSecondaryContainer : Appearance.colors.colOnLayer0 + + Behavior on colText { + animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) + } + + onPressed: { + GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; + } + + RowLayout { + id: indicatorsRowLayout + anchors.centerIn: parent + property real realSpacing: 15 + spacing: 0 + + Revealer { + reveal: Audio.sink?.audio?.muted ?? false + Layout.fillHeight: true + Layout.rightMargin: reveal ? indicatorsRowLayout.realSpacing : 0 + Behavior on Layout.rightMargin { + NumberAnimation { + duration: Appearance.animation.elementMoveFast.duration + easing.type: Appearance.animation.elementMoveFast.type + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve + } + } + MaterialSymbol { + text: "volume_off" + iconSize: Appearance.font.pixelSize.larger + color: rightSidebarButton.colText + } + } + Revealer { + reveal: Audio.source?.audio?.muted ?? false + Layout.fillHeight: true + Layout.rightMargin: reveal ? indicatorsRowLayout.realSpacing : 0 + Behavior on Layout.rightMargin { + NumberAnimation { + duration: Appearance.animation.elementMoveFast.duration + easing.type: Appearance.animation.elementMoveFast.type + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve + } + } + MaterialSymbol { + text: "mic_off" + iconSize: Appearance.font.pixelSize.larger + color: rightSidebarButton.colText + } + } + Loader { + active: HyprlandXkb.layoutCodes.length > 1 + visible: active + Layout.rightMargin: indicatorsRowLayout.realSpacing + sourceComponent: StyledText { + text: HyprlandXkb.currentLayoutCode + font.pixelSize: Appearance.font.pixelSize.small + color: rightSidebarButton.colText + } + } + MaterialSymbol { + Layout.rightMargin: indicatorsRowLayout.realSpacing + text: Network.materialSymbol + iconSize: Appearance.font.pixelSize.larger + color: rightSidebarButton.colText + } + MaterialSymbol { + text: Bluetooth.bluetoothConnected ? "bluetooth_connected" : Bluetooth.bluetoothEnabled ? "bluetooth" : "bluetooth_disabled" + iconSize: Appearance.font.pixelSize.larger + color: rightSidebarButton.colText + } + } + } + + SysTray { + visible: root.useShortenedForm === 0 + Layout.fillWidth: false + Layout.fillHeight: true + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + } + + // Weather + Loader { + Layout.leftMargin: 8 + Layout.fillHeight: true + active: Config.options.bar.weather.enable + sourceComponent: BarGroup { + implicitHeight: Appearance.sizes.baseBarHeight + WeatherBar {} + } + } + } + } + } +} diff --git a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml index 72cc932bf..fa5d5daf4 100644 --- a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml +++ b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml @@ -43,9 +43,9 @@ Item { Layout.alignment: Qt.AlignVCenter lineWidth: 2 value: percentage - size: 26 - secondaryColor: (isLow && !isCharging) ? batteryLowBackground : Appearance.colors.colSecondaryContainer - primaryColor: (isLow && !isCharging) ? batteryLowOnBackground : Appearance.m3colors.m3onSecondaryContainer + implicitSize: 26 + colSecondary: (isLow && !isCharging) ? batteryLowBackground : Appearance.colors.colSecondaryContainer + colPrimary: (isLow && !isCharging) ? batteryLowOnBackground : Appearance.m3colors.m3onSecondaryContainer fill: (isLow && !isCharging) MaterialSymbol { diff --git a/.config/quickshell/ii/modules/bar/Media.qml b/.config/quickshell/ii/modules/bar/Media.qml index f3e70a803..2ce02aee6 100644 --- a/.config/quickshell/ii/modules/bar/Media.qml +++ b/.config/quickshell/ii/modules/bar/Media.qml @@ -53,9 +53,9 @@ Item { Layout.leftMargin: rowLayout.spacing lineWidth: 2 value: activePlayer?.position / activePlayer?.length - size: 26 - secondaryColor: Appearance.colors.colSecondaryContainer - primaryColor: Appearance.m3colors.m3onSecondaryContainer + implicitSize: 26 + colSecondary: Appearance.colors.colSecondaryContainer + colPrimary: Appearance.m3colors.m3onSecondaryContainer enableAnimation: false MaterialSymbol { diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index eb3683d83..12c799111 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -21,9 +21,9 @@ Item { Layout.alignment: Qt.AlignVCenter lineWidth: 2 value: percentage - size: 26 - secondaryColor: Appearance.colors.colSecondaryContainer - primaryColor: Appearance.m3colors.m3onSecondaryContainer + implicitSize: 26 + colSecondary: Appearance.colors.colSecondaryContainer + colPrimary: Appearance.m3colors.m3onSecondaryContainer enableAnimation: false MaterialSymbol { diff --git a/.config/quickshell/ii/modules/bar/SysTray.qml b/.config/quickshell/ii/modules/bar/SysTray.qml index 34919a3ce..923bc04c7 100644 --- a/.config/quickshell/ii/modules/bar/SysTray.qml +++ b/.config/quickshell/ii/modules/bar/SysTray.qml @@ -8,8 +8,6 @@ import Quickshell.Services.SystemTray Item { id: root - required property var bar - height: parent.height implicitWidth: rowLayout.implicitWidth Layout.leftMargin: Appearance.rounding.screenRounding @@ -25,8 +23,6 @@ Item { SysTrayItem { required property SystemTrayItem modelData - - bar: root.bar item: modelData } diff --git a/.config/quickshell/ii/modules/bar/SysTrayItem.qml b/.config/quickshell/ii/modules/bar/SysTrayItem.qml index 9696c49c4..bc3eaa539 100644 --- a/.config/quickshell/ii/modules/bar/SysTrayItem.qml +++ b/.config/quickshell/ii/modules/bar/SysTrayItem.qml @@ -10,7 +10,7 @@ import Qt5Compat.GraphicalEffects MouseArea { id: root - required property var bar + property var bar: root.QsWindow.window required property SystemTrayItem item property bool targetMenuOpen: false property int trayItemWidth: Appearance.font.pixelSize.larger diff --git a/.config/quickshell/ii/modules/bar/Workspaces.qml b/.config/quickshell/ii/modules/bar/Workspaces.qml index 8758fe52a..b07dc9d18 100644 --- a/.config/quickshell/ii/modules/bar/Workspaces.qml +++ b/.config/quickshell/ii/modules/bar/Workspaces.qml @@ -13,12 +13,12 @@ import Quickshell.Widgets import Qt5Compat.GraphicalEffects Item { - required property var bar + id: root property bool borderless: Config.options.bar.borderless - readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen) + readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.QsWindow.window?.screen) readonly property Toplevel activeWindow: ToplevelManager.activeToplevel - readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / Config.options.bar.workspaces.shown) + readonly property int workspaceGroup: Math.floor((monitor?.activeWorkspace?.id - 1) / Config.options.bar.workspaces.shown) property list workspaceOccupied: [] property int widgetPadding: 4 property int workspaceButtonWidth: 26 @@ -26,7 +26,7 @@ Item { property real workspaceIconSizeShrinked: workspaceButtonWidth * 0.55 property real workspaceIconOpacityShrinked: 1 property real workspaceIconMarginShrinked: -4 - property int workspaceIndexInGroup: (monitor.activeWorkspace?.id - 1) % Config.options.bar.workspaces.shown + property int workspaceIndexInGroup: (monitor?.activeWorkspace?.id - 1) % Config.options.bar.workspaces.shown // Function to update workspaceOccupied function updateWorkspaceOccupied() { @@ -87,8 +87,8 @@ Item { implicitWidth: workspaceButtonWidth implicitHeight: workspaceButtonWidth radius: Appearance.rounding.full - property var leftOccupied: (workspaceOccupied[index-1] && !(!activeWindow?.activated && monitor.activeWorkspace?.id === index)) - property var rightOccupied: (workspaceOccupied[index+1] && !(!activeWindow?.activated && monitor.activeWorkspace?.id === index+2)) + property var leftOccupied: (workspaceOccupied[index-1] && !(!activeWindow?.activated && monitor?.activeWorkspace?.id === index)) + property var rightOccupied: (workspaceOccupied[index+1] && !(!activeWindow?.activated && monitor?.activeWorkspace?.id === index+2)) property var radiusLeft: leftOccupied ? 0 : Appearance.rounding.full property var radiusRight: rightOccupied ? 0 : Appearance.rounding.full @@ -98,7 +98,7 @@ Item { bottomRightRadius: radiusRight color: ColorUtils.transparentize(Appearance.m3colors.m3secondaryContainer, 0.4) - opacity: (workspaceOccupied[index] && !(!activeWindow?.activated && monitor.activeWorkspace?.id === index+1)) ? 1 : 0 + opacity: (workspaceOccupied[index] && !(!activeWindow?.activated && monitor?.activeWorkspace?.id === index+1)) ? 1 : 0 Behavior on opacity { animation: Appearance.animation.elementMove.numberAnimation.createObject(this) @@ -188,7 +188,7 @@ Item { font.pixelSize: Appearance.font.pixelSize.small - ((text.length - 1) * (text !== "10") * 2) text: `${button.workspaceValue}` elide: Text.ElideRight - color: (monitor.activeWorkspace?.id == button.workspaceValue) ? + color: (monitor?.activeWorkspace?.id == button.workspaceValue) ? Appearance.m3colors.m3onPrimary : (workspaceOccupied[index] ? Appearance.m3colors.m3onSecondaryContainer : Appearance.colors.colOnLayer1Inactive) @@ -208,7 +208,7 @@ Item { width: workspaceButtonWidth * 0.18 height: width radius: width / 2 - color: (monitor.activeWorkspace?.id == button.workspaceValue) ? + color: (monitor?.activeWorkspace?.id == button.workspaceValue) ? Appearance.m3colors.m3onPrimary : (workspaceOccupied[index] ? Appearance.m3colors.m3onSecondaryContainer : Appearance.colors.colOnLayer1Inactive) diff --git a/.config/quickshell/ii/modules/common/widgets/CircularProgress.qml b/.config/quickshell/ii/modules/common/widgets/CircularProgress.qml index 7ff2724fb..e1b2effaf 100644 --- a/.config/quickshell/ii/modules/common/widgets/CircularProgress.qml +++ b/.config/quickshell/ii/modules/common/widgets/CircularProgress.qml @@ -1,7 +1,5 @@ -// From https://github.com/rafzby/circular-progressbar with modifications -// License: LGPL-3.0 - A copy can be found in `licenses` folder of repo - import QtQuick +import QtQuick.Shapes import qs.modules.common /** @@ -10,88 +8,81 @@ import qs.modules.common Item { id: root - property int size: 30 + property int implicitSize: 30 property int lineWidth: 2 property real value: 0 - property color primaryColor: Appearance.m3colors.m3onSecondaryContainer - property color secondaryColor: Appearance.colors.colSecondaryContainer - property real gapAngle: Math.PI / 9 + property color colPrimary: Appearance.m3colors.m3onSecondaryContainer + property color colSecondary: Appearance.colors.colSecondaryContainer + property real gapAngle: 360 / 18 property bool fill: false property int fillOverflow: 2 property bool enableAnimation: true - property int animationDuration: 1000 + property int animationDuration: 800 property var easingType: Easing.OutCubic - width: size - height: size + implicitWidth: implicitSize + implicitHeight: implicitSize - signal animationFinished(); + property real degree: value * 360 + property real centerX: root.width / 2 + property real centerY: root.height / 2 + property real arcRadius: root.implicitSize / 2 - root.lineWidth + property real startAngle: -90 + + Behavior on degree { + enabled: root.enableAnimation + NumberAnimation { + duration: root.animationDuration + easing.type: root.easingType + } - onValueChanged: { - canvas.degree = value * 360; - } - onPrimaryColorChanged: { - canvas.requestPaint(); - } - onSecondaryColorChanged: { - canvas.requestPaint(); } - Canvas { - id: canvas - - property real degree: 0 - + Loader { + active: root.fill anchors.fill: parent - antialiasing: true - - onDegreeChanged: { - requestPaint(); + + sourceComponent: Rectangle { + radius: 9999 + color: root.colSecondary } + } - onPaint: { - var ctx = getContext("2d"); - var x = root.width / 2; - var y = root.height / 2; - var radius = root.size / 2 - root.lineWidth; - var startAngle = (Math.PI / 180) * 270; - var fullAngle = (Math.PI / 180) * (270 + 360); - var progressAngle = (Math.PI / 180) * (270 + degree); - var epsilon = 0.01; // Small angle in radians - - ctx.reset(); - if (root.fill) { - ctx.fillStyle = root.secondaryColor; - ctx.beginPath(); - ctx.arc(x, y, radius + fillOverflow, startAngle, fullAngle); - ctx.fill(); + Shape { + anchors.fill: parent + layer.enabled: true + layer.smooth: true + preferredRendererType: Shape.CurveRenderer + ShapePath { + id: secondaryPath + strokeColor: root.colSecondary + strokeWidth: root.lineWidth + capStyle: ShapePath.RoundCap + fillColor: "transparent" + PathAngleArc { + centerX: root.centerX + centerY: root.centerY + radiusX: root.arcRadius + radiusY: root.arcRadius + startAngle: root.startAngle - root.gapAngle + sweepAngle: -(360 - root.degree - 2 * root.gapAngle) } - ctx.lineCap = 'round'; - ctx.lineWidth = root.lineWidth; - - // Secondary - ctx.beginPath(); - ctx.arc(x, y, radius, progressAngle + gapAngle, fullAngle - gapAngle); - ctx.strokeStyle = root.secondaryColor; - ctx.stroke(); - - // Primary (value indication) - var endAngle = progressAngle + (value > 0 ? 0 : epsilon); - ctx.beginPath(); - ctx.arc(x, y, radius, startAngle, endAngle); - ctx.strokeStyle = root.primaryColor; - ctx.stroke(); } - - Behavior on degree { - enabled: root.enableAnimation - NumberAnimation { - duration: root.animationDuration - easing.type: root.easingType + ShapePath { + id: primaryPath + strokeColor: root.colPrimary + strokeWidth: root.lineWidth + capStyle: ShapePath.RoundCap + fillColor: "transparent" + PathAngleArc { + centerX: root.centerX + centerY: root.centerY + radiusX: root.arcRadius + radiusY: root.arcRadius + startAngle: root.startAngle + sweepAngle: root.degree } - } - } } diff --git a/.config/quickshell/ii/modules/common/widgets/RoundCorner.qml b/.config/quickshell/ii/modules/common/widgets/RoundCorner.qml index 6fba4b92d..9cda87ca5 100644 --- a/.config/quickshell/ii/modules/common/widgets/RoundCorner.qml +++ b/.config/quickshell/ii/modules/common/widgets/RoundCorner.qml @@ -1,4 +1,5 @@ -import QtQuick 2.9 +import QtQuick +import QtQuick.Shapes Item { id: root @@ -6,55 +7,57 @@ Item { enum CornerEnum { TopLeft, TopRight, BottomLeft, BottomRight } property var corner: RoundCorner.CornerEnum.TopLeft // Default to TopLeft - property int size: 25 + property int implicitSize: 25 property color color: "#000000" - onColorChanged: { - canvas.requestPaint(); - } - onCornerChanged: { - canvas.requestPaint(); - } - - implicitWidth: size - implicitHeight: size - - Canvas { - id: canvas + implicitWidth: implicitSize + implicitHeight: implicitSize + Shape { anchors.fill: parent - antialiasing: true - - onPaint: { - var ctx = getContext("2d"); - var r = root.size; - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.beginPath(); - switch (root.corner) { - case RoundCorner.CornerEnum.TopLeft: - ctx.arc(r, r, r, Math.PI, 3 * Math.PI / 2); - ctx.lineTo(0, 0); - break; - case RoundCorner.CornerEnum.TopRight: - ctx.arc(0, r, r, 3 * Math.PI / 2, 2 * Math.PI); - ctx.lineTo(r, 0); - break; - case RoundCorner.CornerEnum.BottomLeft: - ctx.arc(r, 0, r, Math.PI / 2, Math.PI); - ctx.lineTo(0, r); - break; - case RoundCorner.CornerEnum.BottomRight: - ctx.arc(0, 0, r, 0, Math.PI / 2); - ctx.lineTo(r, r); - break; + layer.enabled: true + layer.smooth: true + preferredRendererType: Shape.CurveRenderer + + ShapePath { + id: shapePath + strokeWidth: 0 + + fillColor: root.color + startX: switch (root.corner) { + case RoundCorner.CornerEnum.TopLeft: return 0; + case RoundCorner.CornerEnum.TopRight: return root.implicitSize; + case RoundCorner.CornerEnum.BottomLeft: return 0; + case RoundCorner.CornerEnum.BottomRight: return root.implicitSize; + } + startY: switch (root.corner) { + case RoundCorner.CornerEnum.TopLeft: return 0; + case RoundCorner.CornerEnum.TopRight: return 0; + case RoundCorner.CornerEnum.BottomLeft: return root.implicitSize; + case RoundCorner.CornerEnum.BottomRight: return root.implicitSize; + } + PathAngleArc { + moveToStart: false + centerX: root.implicitSize - shapePath.startX + centerY: root.implicitSize - shapePath.startY + radiusX: root.implicitSize + radiusY: root.implicitSize + startAngle: switch (root.corner) { + case RoundCorner.CornerEnum.TopLeft: return 180; + case RoundCorner.CornerEnum.TopRight: return -90; + case RoundCorner.CornerEnum.BottomLeft: return 90; + case RoundCorner.CornerEnum.BottomRight: return 0; + } + sweepAngle: 90 + } + PathLine { + x: shapePath.startX + y: shapePath.startY } - ctx.closePath(); - ctx.fillStyle = root.color; - ctx.fill(); } } - Behavior on size { + Behavior on implicitSize { animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this) } diff --git a/.config/quickshell/ii/modules/screenCorners/ScreenCorners.qml b/.config/quickshell/ii/modules/screenCorners/ScreenCorners.qml index 5bfed5cde..99dab8292 100644 --- a/.config/quickshell/ii/modules/screenCorners/ScreenCorners.qml +++ b/.config/quickshell/ii/modules/screenCorners/ScreenCorners.qml @@ -35,7 +35,7 @@ Scope { implicitHeight: cornerWidget.implicitHeight RoundCorner { id: cornerWidget - size: Appearance.rounding.screenRounding + implicitSize: Appearance.rounding.screenRounding corner: cornerPanelWindow.corner } } diff --git a/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/.config/quickshell/ii/modules/settings/InterfaceConfig.qml index 4d86ffff7..e4b712012 100644 --- a/.config/quickshell/ii/modules/settings/InterfaceConfig.qml +++ b/.config/quickshell/ii/modules/settings/InterfaceConfig.qml @@ -344,7 +344,7 @@ ContentPage { Config.options.sidebar.keepRightSidebarLoaded = checked; } StyledToolTip { - content: Translation.tr("When enabled keeps the content of the right sidebar loaded to reduce the delay when opening,\nat the cost of around 15MB of consistent RAM usage. Delay significance depends on your system's performance.\nUsing a different kernel might help with this delay") + content: Translation.tr("When enabled keeps the content of the right sidebar loaded to reduce the delay when opening,\nat the cost of around 15MB of consistent RAM usage. Delay significance depends on your system's performance.\nUsing a custom kernel like linux-cachyos might help") } } } diff --git a/.config/quickshell/ii/services/Brightness.qml b/.config/quickshell/ii/services/Brightness.qml index 927a10c06..74ef562b2 100644 --- a/.config/quickshell/ii/services/Brightness.qml +++ b/.config/quickshell/ii/services/Brightness.qml @@ -1,7 +1,7 @@ pragma Singleton pragma ComponentBehavior: Bound -// From https://github.com/caelestia-dots/shell/ (`quickshell` branch) with modifications. +// From https://github.com/caelestia-dots/shell with modifications. // License: GPLv3 import Quickshell diff --git a/.config/quickshell/ii/shell.qml b/.config/quickshell/ii/shell.qml index 7380da583..e46d7a439 100644 --- a/.config/quickshell/ii/shell.qml +++ b/.config/quickshell/ii/shell.qml @@ -22,9 +22,8 @@ import "./modules/screenCorners/" import "./modules/session/" import "./modules/sidebarLeft/" import "./modules/sidebarRight/" + import QtQuick -import QtQuick.Controls -import QtQuick.Layouts import QtQuick.Window import Quickshell import "./services/" diff --git a/.local/share/icons/quickshell.svg b/.local/share/icons/quickshell.svg deleted file mode 120000 index 8dc05d01c..000000000 --- a/.local/share/icons/quickshell.svg +++ /dev/null @@ -1 +0,0 @@ -illogical-impulse.svg \ No newline at end of file diff --git a/.local/share/konsole/Profile 1.profile b/.local/share/konsole/Profile 1.profile new file mode 100644 index 000000000..956403964 --- /dev/null +++ b/.local/share/konsole/Profile 1.profile @@ -0,0 +1,12 @@ +[Appearance] +ColorScheme=MaterialYou + +[General] +Command=/bin/fish +Environment=COLORTERM=truecolor +Name=Profile 1 +Parent=FALLBACK/ + +[Keyboard] +KeyBindings=default + diff --git a/.local/state/quickshell/user/ai/chats/chat.json b/.local/state/quickshell/user/ai/chats/chat.json deleted file mode 100644 index 20540c1d0..000000000 --- a/.local/state/quickshell/user/ai/chats/chat.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "messages": [], - "created": "2024-01-01T00:00:00Z", - "updated": "2024-01-01T00:00:00Z", - "title": "Default Chat", - "id": "default" -} \ No newline at end of file diff --git a/install.sh b/install.sh index ae9891e98..b61fdac2f 100755 --- a/install.sh +++ b/install.sh @@ -233,6 +233,7 @@ esac # since the files here come from different places, not only about one program. # v rsync -av ".local/bin/" "$XDG_BIN_HOME" # No longer needed since scripts are no longer in ~/.local/bin v rsync -av ".local/share/icons/" "${XDG_DATA_HOME:-$HOME/.local/share}"/icons/ +v rsync -av ".local/share/konsole/" "${XDG_DATA_HOME:-$HOME/.local/share}"/konsole/ # Prevent hyprland from not fully loaded sleep 1