diff --git a/dots/.config/quickshell/ii/GlobalStates.qml b/dots/.config/quickshell/ii/GlobalStates.qml index 85a0414d6..ba680220b 100644 --- a/dots/.config/quickshell/ii/GlobalStates.qml +++ b/dots/.config/quickshell/ii/GlobalStates.qml @@ -37,14 +37,6 @@ Singleton { } } - property real screenZoom: 1 - onScreenZoomChanged: { - Quickshell.execDetached(["hyprctl", "keyword", "cursor:zoom_factor", root.screenZoom.toString()]); - } - Behavior on screenZoom { - animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) - } - GlobalShortcut { name: "workspaceNumber" description: "Hold to show workspace numbers, release to show icons" @@ -56,16 +48,4 @@ Singleton { root.superDown = false } } - - IpcHandler { - target: "zoom" - - function zoomIn() { - screenZoom = Math.min(screenZoom + 0.4, 3.0) - } - - function zoomOut() { - screenZoom = Math.max(screenZoom - 0.4, 1) - } - } } \ No newline at end of file diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index 4b4f54f92..fc418675d 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -3,7 +3,9 @@ pragma ComponentBehavior: Bound import QtQuick import Quickshell import Quickshell.Io -import qs.modules.common.functions + +import "functions" +import "config" Singleton { id: root @@ -603,26 +605,8 @@ Singleton { } } - property JsonObject waffles: JsonObject { - // Some spots are kinda janky/awkward. Setting the following to - // false will make (some) stuff also be like that for accuracy. - // Example: the right-click menu of the Start button - property JsonObject tweaks: JsonObject { - property bool switchHandlePositionFix: true - property bool smootherMenuAnimations: true - property bool smootherSearchBar: true - } - property JsonObject bar: JsonObject { - property bool bottom: true - property bool leftAlignApps: false - } - property JsonObject actionCenter: JsonObject { - property list toggles: [ "network", "bluetooth", "easyEffects", "powerProfile", "idleInhibitor", "nightLight", "darkMode", "antiFlashbang", "cloudflareWarp", "mic", "musicRecognition", "notifications", "onScreenKeyboard", "gameMode", "screenSnip", "colorPicker" ] - } - property JsonObject calendar: JsonObject { - property bool force2CharDayOfWeek: true - } - } + property JsonObject hefty: HeftyConfig {} + property JsonObject waffles: WaffleConfig {} } } } diff --git a/dots/.config/quickshell/ii/modules/common/Directories.qml b/dots/.config/quickshell/ii/modules/common/Directories.qml index 78b0a9edb..f0dcc8a30 100644 --- a/dots/.config/quickshell/ii/modules/common/Directories.qml +++ b/dots/.config/quickshell/ii/modules/common/Directories.qml @@ -20,7 +20,8 @@ Singleton { readonly property string music: StandardPaths.standardLocations(StandardPaths.MusicLocation)[0] readonly property string videos: StandardPaths.standardLocations(StandardPaths.MoviesLocation)[0] - // Other dirs used by the shell, without "file://" + /////// Stuff below are without "file://" ///////// + // General property string assetsPath: Quickshell.shellPath("assets") property string scriptPath: Quickshell.shellPath("scripts") property string favicons: FileUtils.trimFileProtocol(`${Directories.cache}/media/favicons`) @@ -30,9 +31,6 @@ Singleton { property string booruDownloads: FileUtils.trimFileProtocol(Directories.pictures + "/homework") property string booruDownloadsNsfw: FileUtils.trimFileProtocol(Directories.pictures + "/homework/🌶️") property string latexOutput: FileUtils.trimFileProtocol(`${Directories.cache}/media/latex`) - property string shellConfig: FileUtils.trimFileProtocol(`${Directories.config}/illogical-impulse`) - property string shellConfigName: "config.json" - property string shellConfigPath: `${Directories.shellConfig}/${Directories.shellConfigName}` property string todoPath: FileUtils.trimFileProtocol(`${Directories.state}/user/todo.json`) property string notesPath: FileUtils.trimFileProtocol(`${Directories.state}/user/notes.txt`) property string conflictCachePath: FileUtils.trimFileProtocol(`${Directories.cache}/conflict-killer`) @@ -43,14 +41,21 @@ Singleton { property string screenshotTemp: "/tmp/quickshell/media/screenshot" property string wallpaperSwitchScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/switchwall.sh`) property string defaultAiPrompts: Quickshell.shellPath("defaults/ai/prompts") - property string userAiPrompts: FileUtils.trimFileProtocol(`${Directories.shellConfig}/ai/prompts`) - property string userActions: FileUtils.trimFileProtocol(`${Directories.shellConfig}/actions`) property string aiChats: FileUtils.trimFileProtocol(`${Directories.state}/user/ai/chats`) property string aiTranslationScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/ai/gemini-translate.sh`) property string recordScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/videos/record.sh`) property string userAvatarPathAccountsService: FileUtils.trimFileProtocol(`/var/lib/AccountsService/icons/${SystemInfo.username}`) property string userAvatarPathRicersAndWeirdSystems: FileUtils.trimFileProtocol(`${Directories.home}.face`) property string userAvatarPathRicersAndWeirdSystems2: FileUtils.trimFileProtocol(`${Directories.home}.face.icon`) + + // User + property string shellConfig: FileUtils.trimFileProtocol(`${Directories.config}/illogical-impulse`) + property string shellConfigName: "config.json" + property string shellConfigPath: `${Directories.shellConfig}/${Directories.shellConfigName}` + property string userAiPrompts: FileUtils.trimFileProtocol(`${Directories.shellConfig}/ai/prompts`) + property string userActions: FileUtils.trimFileProtocol(`${Directories.shellConfig}/actions`) + property string userComponents: FileUtils.trimFileProtocol(`${Directories.shellConfig}/components`) + // Cleanup on init Component.onCompleted: { Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`]) diff --git a/dots/.config/quickshell/ii/modules/common/config/HeftyConfig.qml b/dots/.config/quickshell/ii/modules/common/config/HeftyConfig.qml new file mode 100644 index 000000000..57a18fe86 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/config/HeftyConfig.qml @@ -0,0 +1,11 @@ +import QtQuick +import Quickshell +import Quickshell.Io + +JsonObject { + property JsonObject bar: JsonObject { + property list leftWidgets: [] + property list centerWidgets: [] + property list rightWidgets: [] + } +} diff --git a/dots/.config/quickshell/ii/modules/common/config/WaffleConfig.qml b/dots/.config/quickshell/ii/modules/common/config/WaffleConfig.qml new file mode 100644 index 000000000..9509ff166 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/config/WaffleConfig.qml @@ -0,0 +1,24 @@ +import QtQuick +import Quickshell +import Quickshell.Io + +JsonObject { + // Some spots are kinda janky/awkward. Setting the following to + // false will make (some) stuff also be like that for accuracy. + // Example: the right-click menu of the Start button + property JsonObject tweaks: JsonObject { + property bool switchHandlePositionFix: true + property bool smootherMenuAnimations: true + property bool smootherSearchBar: true + } + property JsonObject bar: JsonObject { + property bool bottom: true + property bool leftAlignApps: false + } + property JsonObject actionCenter: JsonObject { + property list toggles: [ "network", "bluetooth", "easyEffects", "powerProfile", "idleInhibitor", "nightLight", "darkMode", "antiFlashbang", "cloudflareWarp", "mic", "musicRecognition", "notifications", "onScreenKeyboard", "gameMode", "screenSnip", "colorPicker" ] + } + property JsonObject calendar: JsonObject { + property bool force2CharDayOfWeek: true + } +} diff --git a/dots/.config/quickshell/ii/modules/common/widgets/Colorizer.qml b/dots/.config/quickshell/ii/modules/common/widgets/Colorizer.qml new file mode 100644 index 000000000..032d59eb1 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/Colorizer.qml @@ -0,0 +1,14 @@ +import QtQuick +import QtQuick.Effects +import qs.modules.common + +MultiEffect { + property color sourceColor: "black" + + colorization: 1 + brightness: 1 - sourceColor.hslLightness + + Behavior on colorizationColor { + animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) + } +} diff --git a/dots/.config/quickshell/ii/modules/common/widgets/FadeLazyLoader.qml b/dots/.config/quickshell/ii/modules/common/widgets/FadeLazyLoader.qml new file mode 100644 index 000000000..f826a9fbc --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/FadeLazyLoader.qml @@ -0,0 +1,25 @@ +import QtQuick +import Quickshell +import qs.modules.common + +Item { + id: root + + property alias load: loader.activeAsync + property bool shown: true // By default show immediately when loaded + property alias component: loader.component + + property alias fade: opacityBehavior.enabled + property alias animation: opacityBehavior.animation + + opacity: loader.active && shown ? 1 : 0 + visible: opacity > 0 + Behavior on opacity { + id: opacityBehavior + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) + } + + LazyLoader { + id: loader + } +} diff --git a/dots/.config/quickshell/ii/modules/common/widgets/FallbackLoader.qml b/dots/.config/quickshell/ii/modules/common/widgets/FallbackLoader.qml new file mode 100644 index 000000000..0da12fbb7 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/FallbackLoader.qml @@ -0,0 +1,25 @@ +import QtQuick + +Loader { + id: root + + property int fallbackIndex: 0 + property list fallbacks: [] + property list fallbackComponents: [] + + onStatusChanged: { + if (status === Loader.Error && fallbackIndex < fallbacks.length) { + if (fallbacks[fallbackIndex]) { + source = fallbacks[fallbackIndex]; + if (fallbackComponents[fallbackIndex]) { + console.warn("[FallbackLoader] Both fallbacks urls and components are set, using url fallback"); + } + } else if (fallbackComponents[fallbackIndex]) { + sourceComponent = fallbackComponents[fallbackIndex]; + } else { + console.error("[FallbackLoader] Out of fallbacks, tried all", fallbackIndex); + } + fallbackIndex += 1; + } + } +} diff --git a/dots/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml b/dots/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml index e3d64027b..8802aaf69 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/NotificationGroup.qml @@ -85,7 +85,7 @@ MouseArea { // Notification group area automaticallyReset: false acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onPressed: { + onPressed: (mouse) => { if (mouse.button === Qt.RightButton) root.toggleExpanded(); } @@ -102,6 +102,7 @@ MouseArea { // Notification group area } onDragDiffXChanged: () => { + if (!dragging) return; root.qmlParent.dragDistance = dragDiffX; } diff --git a/dots/.config/quickshell/ii/modules/hefty/topLayer/HAbstractMorphedPanel.qml b/dots/.config/quickshell/ii/modules/hefty/topLayer/HAbstractMorphedPanel.qml index 2dd545f96..5eb6e21aa 100644 --- a/dots/.config/quickshell/ii/modules/hefty/topLayer/HAbstractMorphedPanel.qml +++ b/dots/.config/quickshell/ii/modules/hefty/topLayer/HAbstractMorphedPanel.qml @@ -18,9 +18,11 @@ Item { property int screenWidth: QsWindow.window.width property int screenHeight: QsWindow.window.height - // Signals + // Signals & loading signal requestFocus() signal dismissed() + property bool load: true + property bool shown: true // Some info property int reservedTop: 0 diff --git a/dots/.config/quickshell/ii/modules/hefty/topLayer/HTopLayerPanel.qml b/dots/.config/quickshell/ii/modules/hefty/topLayer/HTopLayerPanel.qml index 526ed653a..a96129f7f 100644 --- a/dots/.config/quickshell/ii/modules/hefty/topLayer/HTopLayerPanel.qml +++ b/dots/.config/quickshell/ii/modules/hefty/topLayer/HTopLayerPanel.qml @@ -10,6 +10,8 @@ import "../../common/widgets/shapes/material-shapes.js" as MaterialShapes import "../../common/widgets/shapes/shapes/corner-rounding.js" as CornerRounding import "../../common/widgets/shapes/geometry/offset.js" as Offset +import "bar" + /** * Fullscreen layer. Uses masking to not block clicks on windows n' stuff. */ @@ -35,15 +37,31 @@ PanelWindow { ///////////////// Content ////////////////// property alias roundedPolygon: backgroundShape.roundedPolygon + property bool finishedMorphing: true + onRoundedPolygonChanged: finishedMorphing = false + Connections { + target: backgroundShape + function onProgressChanged() { + // While it overshoots because of the spring animation, waiting for the bounce to finish entirely would be too slow + // ^ (totally not an excuse for my laziness) + if (backgroundShape.progress >= 1.0) { + root.finishedMorphing = true + } + } + } S.ShapeCanvas { id: backgroundShape anchors.fill: parent polygonIsNormalized: false roundedPolygon: MaterialShapes.customPolygon([new MaterialShapes.PointNRound(new Offset.Offset(root.screen.width, 0), new CornerRounding.CornerRounding(9999)),]) - animation: NumberAnimation { - duration: 500 - easing.type: Easing.BezierSpline - easing.bezierCurve: Appearance.animationCurves.expressiveDefaultSpatial + // animation: NumberAnimation { + // duration: 500 + // easing.type: Easing.BezierSpline + // easing.bezierCurve: Appearance.animationCurves.expressiveDefaultSpatial + // } + animation: SpringAnimation { + spring: 3.5 + damping: 0.35 } color: Appearance.colors.colLayer0 borderWidth: (root.currentPanel === bar && Config.options.bar.cornerStyle !== 1) ? 0 : 1 @@ -60,7 +78,8 @@ PanelWindow { color: "#44000000" } - property HAbstractMorphedPanel currentPanel: bar + property HAbstractMorphedPanel currentPanel: null + Component.onCompleted: currentPanel = bar roundedPolygon: currentPanel.backgroundPolygon // Do we want to have reserved area always follow the bar or maybe differ per panel? @@ -89,10 +108,14 @@ PanelWindow { HBar { id: bar + load: root.currentPanel === this + shown: root.finishedMorphing } HOverview { id: overview + load: root.currentPanel === this + shown: root.finishedMorphing onRequestFocus: root.currentPanel = overview; onDismissed: root.dismiss(); } diff --git a/dots/.config/quickshell/ii/modules/hefty/topLayer/HBar.qml b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBar.qml similarity index 91% rename from dots/.config/quickshell/ii/modules/hefty/topLayer/HBar.qml rename to dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBar.qml index d3ba215da..8da64c902 100644 --- a/dots/.config/quickshell/ii/modules/hefty/topLayer/HBar.qml +++ b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBar.qml @@ -1,8 +1,11 @@ +pragma ComponentBehavior: Bound import QtQuick import qs.modules.common -import "../../common/widgets/shapes/material-shapes.js" as MaterialShapes -import "../../common/widgets/shapes/shapes/corner-rounding.js" as CornerRounding -import "../../common/widgets/shapes/geometry/offset.js" as Offset +import qs.modules.common.widgets +import "../../../common/widgets/shapes/material-shapes.js" as MaterialShapes +import "../../../common/widgets/shapes/shapes/corner-rounding.js" as CornerRounding +import "../../../common/widgets/shapes/geometry/offset.js" as Offset +import ".." HAbstractMorphedPanel { id: root @@ -131,4 +134,15 @@ HAbstractMorphedPanel { easing.bezierCurve: Appearance.animationCurves.expressiveDefaultSpatial } } + + FadeLazyLoader { + id: contentLoader + load: root.load + shown: root.shown + anchors.fill: parent + component: HBarContent { + parent: contentLoader + anchors.fill: parent + } + } } diff --git a/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBarContent.qml b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBarContent.qml new file mode 100644 index 000000000..6db44b69e --- /dev/null +++ b/dots/.config/quickshell/ii/modules/hefty/topLayer/bar/HBarContent.qml @@ -0,0 +1,39 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.services +import qs.modules.common.widgets + +Item { + id: root + + Side { + id: leftSide + anchors.left: parent.left + width: (parent.width - centerSide.width) / 2 + } + + Side { + id: centerSide + anchors.horizontalCenter: parent.horizontalCenter + + FallbackLoader { + asynchronous: true + source: "/home/end/.config/quickshell/ii/modules/ii/bar/WrongModuleName" + fallbacks: ["/home/end/.config/quickshell/ii/modules/ii/bar/Workspaces.qml"] + } + } + + Side { + id: rightSide + anchors.right: parent.right + width: (parent.width - centerSide.width) / 2 + } + + component Side: RowLayout { + anchors { + top: parent.top + bottom: parent.bottom + } + } +} diff --git a/dots/.config/quickshell/ii/modules/ii/bar/BarContent.qml b/dots/.config/quickshell/ii/modules/ii/bar/BarContent.qml index bcca26740..2a72e3382 100644 --- a/dots/.config/quickshell/ii/modules/ii/bar/BarContent.qml +++ b/dots/.config/quickshell/ii/modules/ii/bar/BarContent.qml @@ -80,19 +80,21 @@ Item { // Bar content region RowLayout { id: leftSectionRowLayout anchors.fill: parent - spacing: 10 + spacing: 0 LeftSidebarButton { // Left sidebar button + id: leftSidebarButton Layout.alignment: Qt.AlignVCenter Layout.leftMargin: Appearance.rounding.screenRounding colBackground: barLeftSideMouseArea.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1) } ActiveWindow { - visible: root.useShortenedForm === 0 + Layout.leftMargin: 10 + (leftSidebarButton.visible ? 0 : Appearance.rounding.screenRounding) Layout.rightMargin: Appearance.rounding.screenRounding Layout.fillWidth: true Layout.fillHeight: true + visible: root.useShortenedForm === 0 } } } diff --git a/dots/.config/quickshell/ii/modules/ii/bar/LeftSidebarButton.qml b/dots/.config/quickshell/ii/modules/ii/bar/LeftSidebarButton.qml index 5ea1bf5a9..6c73ca72e 100644 --- a/dots/.config/quickshell/ii/modules/ii/bar/LeftSidebarButton.qml +++ b/dots/.config/quickshell/ii/modules/ii/bar/LeftSidebarButton.qml @@ -9,6 +9,11 @@ RippleButton { property bool showPing: false + property bool aiChatEnabled: Config.options.policies.ai !== 0 + property bool translatorEnabled: Config.options.sidebar.translator.enable + property bool animeEnabled: Config.options.policies.weeb !== 0 + visible: aiChatEnabled || translatorEnabled || animeEnabled + property real buttonPadding: 5 implicitWidth: distroIcon.width + buttonPadding * 2 implicitHeight: distroIcon.height + buttonPadding * 2 diff --git a/dots/.config/quickshell/ii/modules/ii/bar/Workspaces.qml b/dots/.config/quickshell/ii/modules/ii/bar/Workspaces.qml index f0a61ef23..0ac6e3ea7 100644 --- a/dots/.config/quickshell/ii/modules/ii/bar/Workspaces.qml +++ b/dots/.config/quickshell/ii/modules/ii/bar/Workspaces.qml @@ -181,6 +181,7 @@ Item { // Workspaces - numbers Grid { + id: wsNumbers z: 3 columns: root.vertical ? 1 : root.workspacesShown @@ -209,6 +210,11 @@ Item { property var biggestWindow: HyprlandData.biggestWindowForWorkspace(button.workspaceValue) property var mainAppIconSource: Quickshell.iconPath(AppSearch.guessIcon(biggestWindow?.class), "image-missing") + property color numberColor: (monitor?.activeWorkspace?.id == button.workspaceValue) ? + Appearance.m3colors.m3onPrimary : + (workspaceOccupied[index] ? Appearance.m3colors.m3onSecondaryContainer : + Appearance.colors.colOnLayer1Inactive) + StyledText { // Workspace number text opacity: root.showNumbers || ((Config.options?.bar.workspaces.alwaysShowNumbers && (!Config.options?.bar.workspaces.showAppIcons || !workspaceButtonBackground.biggestWindow || root.showNumbers)) @@ -225,10 +231,7 @@ Item { } text: Config.options?.bar.workspaces.numberMap[button.workspaceValue - 1] || button.workspaceValue elide: Text.ElideRight - color: (monitor?.activeWorkspace?.id == button.workspaceValue) ? - Appearance.m3colors.m3onPrimary : - (workspaceOccupied[index] ? Appearance.m3colors.m3onSecondaryContainer : - Appearance.colors.colOnLayer1Inactive) + color: workspaceButtonBackground.numberColor Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) @@ -245,10 +248,7 @@ Item { width: workspaceButtonWidth * 0.18 height: width radius: width / 2 - color: (monitor?.activeWorkspace?.id == button.workspaceValue) ? - Appearance.m3colors.m3onPrimary : - (workspaceOccupied[index] ? Appearance.m3colors.m3onSecondaryContainer : - Appearance.colors.colOnLayer1Inactive) + color: workspaceButtonBackground.numberColor Behavior on opacity { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) @@ -308,12 +308,8 @@ Item { } } } - - } - } - } } diff --git a/dots/.config/quickshell/ii/modules/ii/dock/DockApps.qml b/dots/.config/quickshell/ii/modules/ii/dock/DockApps.qml index d575b7dd4..6e5e4cbc5 100644 --- a/dots/.config/quickshell/ii/modules/ii/dock/DockApps.qml +++ b/dots/.config/quickshell/ii/modules/ii/dock/DockApps.qml @@ -133,7 +133,7 @@ Item { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } clip: true - color: Appearance.colors.colSurfaceContainer + color: Appearance.m3colors.m3surfaceContainer radius: Appearance.rounding.normal anchors.bottom: parent.bottom anchors.bottomMargin: Appearance.sizes.elevationMargin diff --git a/dots/.config/quickshell/ii/modules/ii/lock/LockSurface.qml b/dots/.config/quickshell/ii/modules/ii/lock/LockSurface.qml index b2482132d..82d10260a 100644 --- a/dots/.config/quickshell/ii/modules/ii/lock/LockSurface.qml +++ b/dots/.config/quickshell/ii/modules/ii/lock/LockSurface.qml @@ -136,6 +136,8 @@ MouseArea { // Style clip: true font.pixelSize: Appearance.font.pixelSize.small + selectedTextColor: materialShapeChars ? "transparent" : Appearance.colors.colOnSecondaryContainer + selectionColor: materialShapeChars ? "transparent" : Appearance.colors.colSecondaryContainer // Password enabled: !root.context.unlockInProgress @@ -195,6 +197,9 @@ MouseArea { } sourceComponent: PasswordChars { length: root.context.currentText.length + selectionStart: passwordBox.selectionStart + selectionEnd: passwordBox.selectionEnd + cursorPosition: passwordBox.cursorPosition } } } @@ -215,7 +220,7 @@ MouseArea { iconSize: 24 text: { if (root.context.targetAction === LockContext.ActionEnum.Unlock) { - return root.ctrlHeld ? "emoji_food_beverage" : "arrow_right_alt"; + return root.ctrlHeld ? "coffee" : "arrow_right_alt"; } else if (root.context.targetAction === LockContext.ActionEnum.Poweroff) { return "power_settings_new"; } else if (root.context.targetAction === LockContext.ActionEnum.Reboot) { diff --git a/dots/.config/quickshell/ii/modules/ii/lock/PasswordChars.qml b/dots/.config/quickshell/ii/modules/ii/lock/PasswordChars.qml index 400c2495a..07c856c05 100644 --- a/dots/.config/quickshell/ii/modules/ii/lock/PasswordChars.qml +++ b/dots/.config/quickshell/ii/modules/ii/lock/PasswordChars.qml @@ -9,29 +9,62 @@ import Quickshell StyledFlickable { id: root + required property int length + property int selectionStart + property int selectionEnd + property int cursorPosition + + property color color: Appearance.colors.colPrimary + property color selectedTextColor: Appearance.colors.colOnSecondaryContainer + property color selectionColor: Appearance.colors.colSecondaryContainer + + property int charSize: 20 + contentWidth: dotsRow.implicitWidth contentX: (Math.max(contentWidth - width, 0)) Behavior on contentX { animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) } + + Rectangle { + id: cursor + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: root.charSize * root.cursorPosition + } + color: root.color + implicitWidth: 2 + implicitHeight: root.charSize + Behavior on anchors.leftMargin { + animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(cursor) + } + } + Row { id: dotsRow anchors { left: parent.left verticalCenter: parent.verticalCenter - leftMargin: 4 + leftMargin: 4 - 5 // -5 to account for spacing being simulated by char item width } - spacing: 10 + spacing: 0 + Repeater { - model: ScriptModel { + model: ScriptModel { // TODO: use proper custom object model to insert new char at the correct pos values: Array(root.length) } - delegate: Item { + + delegate: Rectangle { id: charItem required property int index - implicitWidth: 10 - implicitHeight: 10 + implicitWidth: root.charSize + implicitHeight: root.charSize + property bool selected: index >= root.selectionStart && index < root.selectionEnd + + color: ColorUtils.transparentize(root.selectionColor, selected ? 0 : 1) + MaterialShape { id: materialShape anchors.centerIn: parent @@ -46,7 +79,7 @@ StyledFlickable { ] shape: charShapes[charItem.index % charShapes.length] // Animate on appearance - color: Appearance.colors.colPrimary + color: charItem.selected ? root.selectedTextColor : root.color implicitSize: 0 opacity: 0 scale: 0.5 diff --git a/dots/.config/quickshell/ii/modules/ii/regionSelector/CursorGuide.qml b/dots/.config/quickshell/ii/modules/ii/regionSelector/CursorGuide.qml new file mode 100644 index 000000000..0cbec1297 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/ii/regionSelector/CursorGuide.qml @@ -0,0 +1,112 @@ +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import QtQuick + +Item { + id: root + property var action + property var selectionMode + + property string description: switch (root.action) { + case RegionSelection.SnipAction.Copy: + case RegionSelection.SnipAction.Edit: + return Translation.tr("Copy region (LMB) or annotate (RMB)"); + case RegionSelection.SnipAction.Search: + return Translation.tr("Search with Google Lens"); + case RegionSelection.SnipAction.CharRecognition: + return Translation.tr("Recognize text"); + case RegionSelection.SnipAction.Record: + case RegionSelection.SnipAction.RecordWithSound: + return Translation.tr("Record region"); + } + property string materialSymbol: switch (root.action) { + case RegionSelection.SnipAction.Copy: + case RegionSelection.SnipAction.Edit: + return "content_cut"; + case RegionSelection.SnipAction.Search: + return "image_search"; + case RegionSelection.SnipAction.CharRecognition: + return "document_scanner"; + case RegionSelection.SnipAction.Record: + case RegionSelection.SnipAction.RecordWithSound: + return "videocam"; + default: + return ""; + } + + property bool showDescription: true + function hideDescription() { + root.showDescription = false + } + Timer { + id: descTimeout + interval: 1000 + running: true + onTriggered: { + root.hideDescription() + } + } + onActionChanged: { + root.showDescription = true + descTimeout.restart() + } + + property int margins: 8 + implicitWidth: content.implicitWidth + margins * 2 + implicitHeight: content.implicitHeight + margins * 2 + + Rectangle { + id: content + anchors.centerIn: parent + + property real padding: 8 + implicitHeight: 38 + implicitWidth: root.showDescription ? contentRow.implicitWidth + padding * 2 : implicitHeight + clip: true + + topLeftRadius: 6 + bottomLeftRadius: implicitHeight - topLeftRadius + bottomRightRadius: bottomLeftRadius + topRightRadius: bottomLeftRadius + + color: Appearance.colors.colPrimary + + Behavior on topLeftRadius { + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } + Behavior on implicitWidth { + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } + + Row { + id: contentRow + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: content.padding + } + spacing: 12 + + MaterialSymbol { + anchors.verticalCenter: parent.verticalCenter + iconSize: 22 + color: Appearance.colors.colOnPrimary + animateChange: true + text: root.materialSymbol + } + + FadeLoader { + id: descriptionLoader + anchors.verticalCenter: parent.verticalCenter + shown: root.showDescription + sourceComponent: StyledText { + color: Appearance.colors.colOnPrimary + text: root.description + anchors.right: parent.right + anchors.rightMargin: 6 + } + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/ii/regionSelector/OptionsToolbar.qml b/dots/.config/quickshell/ii/modules/ii/regionSelector/OptionsToolbar.qml index 63a3e8c7e..1c68886c8 100644 --- a/dots/.config/quickshell/ii/modules/ii/regionSelector/OptionsToolbar.qml +++ b/dots/.config/quickshell/ii/modules/ii/regionSelector/OptionsToolbar.qml @@ -23,48 +23,6 @@ Toolbar { // Signals signal dismiss() - MaterialShape { - Layout.fillHeight: true - Layout.leftMargin: 2 - Layout.rightMargin: 2 - implicitSize: 36 // Intentionally smaller because this one is brighter than others - shape: switch (root.action) { - case RegionSelection.SnipAction.Copy: - case RegionSelection.SnipAction.Edit: - return MaterialShape.Shape.Cookie4Sided; - case RegionSelection.SnipAction.Search: - return MaterialShape.Shape.Pentagon; - case RegionSelection.SnipAction.CharRecognition: - return MaterialShape.Shape.Sunny; - case RegionSelection.SnipAction.Record: - case RegionSelection.SnipAction.RecordWithSound: - return MaterialShape.Shape.Gem; - default: - return MaterialShape.Shape.Cookie12Sided; - } - color: Appearance.colors.colPrimary - MaterialSymbol { - anchors.centerIn: parent - iconSize: 22 - color: Appearance.colors.colOnPrimary - animateChange: true - text: switch (root.action) { - case RegionSelection.SnipAction.Copy: - case RegionSelection.SnipAction.Edit: - return "content_cut"; - case RegionSelection.SnipAction.Search: - return "image_search"; - case RegionSelection.SnipAction.CharRecognition: - return "document_scanner"; - case RegionSelection.SnipAction.Record: - case RegionSelection.SnipAction.RecordWithSound: - return "videocam"; - default: - return ""; - } - } - } - ToolbarTabBar { id: tabBar tabButtonList: [ @@ -76,5 +34,4 @@ Toolbar { root.selectionMode = currentIndex === 0 ? RegionSelection.SelectionMode.RectCorners : RegionSelection.SelectionMode.Circle; } } - } diff --git a/dots/.config/quickshell/ii/modules/ii/regionSelector/RectCornersSelectionDetails.qml b/dots/.config/quickshell/ii/modules/ii/regionSelector/RectCornersSelectionDetails.qml index 40069131d..3682e7d51 100644 --- a/dots/.config/quickshell/ii/modules/ii/regionSelector/RectCornersSelectionDetails.qml +++ b/dots/.config/quickshell/ii/modules/ii/regionSelector/RectCornersSelectionDetails.qml @@ -33,22 +33,40 @@ Item { } // Selection border - Rectangle { + // Rectangle { + // id: selectionBorder + // z: 1 + // anchors { + // left: parent.left + // top: parent.top + // leftMargin: root.regionX + // topMargin: root.regionY + // } + // width: root.regionWidth + // height: root.regionHeight + // color: "transparent" + // border.color: root.color + // border.width: 2 + // // radius: root.standardRounding + // radius: 0 // TODO: figure out how to make the overlay thing work with rounding + // } + + DashedBorder { id: selectionBorder - z: 1 + z: 9 anchors { left: parent.left top: parent.top - leftMargin: root.regionX - topMargin: root.regionY + leftMargin: Math.round(root.regionX) - borderWidth + topMargin: Math.round(root.regionY) - borderWidth } - width: root.regionWidth - height: root.regionHeight - color: "transparent" - border.color: root.color - border.width: 2 - // radius: root.standardRounding - radius: 0 // TODO: figure out how to make the overlay thing work with rounding + width: Math.round(root.regionWidth) + borderWidth * 2 + height: Math.round(root.regionHeight) + borderWidth * 2 + + color: root.color + dashLength: 6 + gapLength: 3 + borderWidth: 1 } StyledText { diff --git a/dots/.config/quickshell/ii/modules/ii/regionSelector/RegionSelection.qml b/dots/.config/quickshell/ii/modules/ii/regionSelector/RegionSelection.qml index 920e69b56..5f5ed79ab 100644 --- a/dots/.config/quickshell/ii/modules/ii/regionSelector/RegionSelection.qml +++ b/dots/.config/quickshell/ii/modules/ii/regionSelector/RegionSelection.qml @@ -35,7 +35,7 @@ PanelWindow { signal dismiss() property string screenshotDir: Directories.screenshotTemp - property color overlayColor: "#88111111" + property color overlayColor: ColorUtils.transparentize("#000000", 0.4) property color brightText: Appearance.m3colors.darkmode ? Appearance.colors.colOnLayer0 : Appearance.colors.colLayer0 property color brightSecondary: Appearance.m3colors.darkmode ? Appearance.colors.colSecondary : Appearance.colors.colOnSecondary property color brightTertiary: Appearance.m3colors.darkmode ? Appearance.colors.colTertiary : Qt.lighter(Appearance.colors.colPrimary) @@ -375,6 +375,14 @@ PanelWindow { } } + CursorGuide { + z: 9999 + x: root.dragging ? root.regionX + root.regionWidth : mouseArea.mouseX + y: root.dragging ? root.regionY + root.regionHeight : mouseArea.mouseY + action: root.action + selectionMode: root.selectionMode + } + // Window regions Repeater { model: ScriptModel { @@ -447,7 +455,7 @@ PanelWindow { // Controls Row { id: regionSelectionControls - z: 9999 + z: 10 anchors { horizontalCenter: parent.horizontalCenter bottom: parent.bottom diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarLeft/SidebarLeftContent.qml b/dots/.config/quickshell/ii/modules/ii/sidebarLeft/SidebarLeftContent.qml index f3ebfd356..654b46dfc 100644 --- a/dots/.config/quickshell/ii/modules/ii/sidebarLeft/SidebarLeftContent.qml +++ b/dots/.config/quickshell/ii/modules/ii/sidebarLeft/SidebarLeftContent.qml @@ -48,6 +48,7 @@ Item { spacing: sidebarPadding Toolbar { + visible: tabButtonList.length > 0 Layout.alignment: Qt.AlignHCenter enableShadow: false ToolbarTabBar { @@ -83,9 +84,10 @@ Item { } contentChildren: [ - ...((root.aiChatEnabled || (!root.translatorEnabled && !root.animeEnabled)) ? [aiChat.createObject()] : []), + ...(root.aiChatEnabled ? [aiChat.createObject()] : []), ...(root.translatorEnabled ? [translator.createObject()] : []), - ...(root.animeEnabled ? [anime.createObject()] : []) + ...((root.tabButtonList.length === 0 || (!root.aiChatEnabled && !root.translatorEnabled && root.animeCloset)) ? [placeholder.createObject()] : []), + ...(root.animeEnabled ? [anime.createObject()] : []), ] } } @@ -102,6 +104,15 @@ Item { id: anime Anime {} } - + Component { + id: placeholder + Item { + StyledText { + anchors.centerIn: parent + text: root.animeCloset ? Translation.tr("Nothing") : Translation.tr("Enjoy your empty sidebar...") + color: Appearance.colors.colSubtext + } + } + } } } \ No newline at end of file diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml index 4c6ea6dd9..e9c49dd4b 100644 --- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml +++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml @@ -138,7 +138,7 @@ Rectangle { anchors.fill: parent // implicitHeight: tabStack.implicitHeight - spacing: 10 + spacing: 20 // Navigation rail Item { @@ -146,7 +146,7 @@ Rectangle { Layout.fillWidth: false Layout.leftMargin: 10 Layout.topMargin: 10 - width: tabBar.width + implicitWidth: tabBar.implicitWidth // Navigation rail buttons NavigationRailTabArray { id: tabBar diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/SidebarRight.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/SidebarRight.qml index 62946cb61..69bc07c03 100644 --- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/SidebarRight.qml +++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/SidebarRight.qml @@ -54,6 +54,7 @@ Scope { margins: Appearance.sizes.hyprlandGapsOut leftMargin: Appearance.sizes.elevationMargin } + asynchronous: true width: sidebarWidth - Appearance.sizes.hyprlandGapsOut - Appearance.sizes.elevationMargin height: parent.height - Appearance.sizes.hyprlandGapsOut * 2 diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/bluetoothDevices/BluetoothDeviceItem.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/bluetoothDevices/BluetoothDeviceItem.qml index 8c713d3ca..e9d817563 100644 --- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/bluetoothDevices/BluetoothDeviceItem.qml +++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/bluetoothDevices/BluetoothDeviceItem.qml @@ -47,6 +47,7 @@ DialogListItem { color: Appearance.colors.colOnSurfaceVariant elide: Text.ElideRight text: root.device?.name || Translation.tr("Unknown device") + textFormat: Text.PlainText } StyledText { visible: (root.device?.connected || root.device?.paired) ?? false diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/wifiNetworks/WifiNetworkItem.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/wifiNetworks/WifiNetworkItem.qml index 9f75224dd..9d411c4d9 100644 --- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/wifiNetworks/WifiNetworkItem.qml +++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/wifiNetworks/WifiNetworkItem.qml @@ -40,6 +40,7 @@ DialogListItem { color: Appearance.colors.colOnSurfaceVariant elide: Text.ElideRight text: root.wifiNetwork?.ssid ?? Translation.tr("Unknown") + textFormat: Text.PlainText } MaterialSymbol { visible: (root.wifiNetwork?.isSecure || root.wifiNetwork?.active) ?? false diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothDeviceItem.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothDeviceItem.qml index 73d7bee83..1d9af6c63 100644 --- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothDeviceItem.qml +++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/bluetooth/BluetoothDeviceItem.qml @@ -41,6 +41,7 @@ ExpandableChoiceButton { elide: Text.ElideRight font.pixelSize: Looks.font.pixelSize.large text: root.device?.name || Translation.tr("Unknown device") + textFormat: Text.PlainText } WText { // Status id: statusText diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WWifiNetworkItem.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WWifiNetworkItem.qml index 9274b2e86..ff3d09eb6 100644 --- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WWifiNetworkItem.qml +++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/wifi/WWifiNetworkItem.qml @@ -61,6 +61,7 @@ ExpandableChoiceButton { elide: Text.ElideRight font.pixelSize: Looks.font.pixelSize.large text: root.wifiNetwork?.ssid ?? Translation.tr("Unknown") + textFormat: Text.PlainText } WText { // Status id: statusText diff --git a/dots/.config/quickshell/ii/services/Brightness.qml b/dots/.config/quickshell/ii/services/Brightness.qml index f2f4f0a7e..b0c7f303e 100644 --- a/dots/.config/quickshell/ii/services/Brightness.qml +++ b/dots/.config/quickshell/ii/services/Brightness.qml @@ -148,14 +148,12 @@ Singleton { const brightnessValue = Math.max(monitor.multipliedBrightness, 0); if (isDdc) { const rawValueRounded = Math.max(Math.floor(brightnessValue * monitor.rawMaxBrightness), 1); - setProc.command = ["ddcutil", "-b", busNum, "setvcp", "10", rawValueRounded]; - setProc.startDetached(); + setProc.exec(["ddcutil", "-b", busNum, "setvcp", "10", rawValueRounded]); } else { const valuePercentNumber = Math.floor(brightnessValue * 100); let valuePercent = `${valuePercentNumber}%`; if (valuePercentNumber == 0) valuePercent = "1"; // Prevent fully black - setProc.command = ["brightnessctl", "--class", "backlight", "s", valuePercent, "--quiet"]; - setProc.startDetached(); + setProc.exec(["brightnessctl", "--class", "backlight", "s", valuePercent, "--quiet"]) } } diff --git a/dots/.config/quickshell/ii/services/LauncherSearch.qml b/dots/.config/quickshell/ii/services/LauncherSearch.qml index 52e783e28..787da3090 100644 --- a/dots/.config/quickshell/ii/services/LauncherSearch.qml +++ b/dots/.config/quickshell/ii/services/LauncherSearch.qml @@ -43,9 +43,9 @@ Singleton { const actionName = fileName.replace(/\.[^/.]+$/, ""); // strip extension actions.push({ action: actionName, - execute: ((path) => (args) => { - Quickshell.execDetached([path, ...(args ? args.split(" ") : [])]); - })(FileUtils.trimFileProtocol(filePath.toString())) + execute: (path => args => { + Quickshell.execDetached([path, ...(args ? args.split(" ") : [])]); + })(FileUtils.trimFileProtocol(filePath.toString())) }); } } @@ -250,8 +250,8 @@ Singleton { if (!entry.runInTerminal) entry.execute(); else { - // Probably needs more proper escaping, but this will do for now - Quickshell.execDetached(["bash", '-c', `${Config.options.apps.terminal} -e '${StringUtils.shellSingleQuoteEscape(entry.command.join(' '))}'`]); + print([...Config.options.apps.terminal, "-e", ...entry.command]) + Quickshell.execDetached([...Config.options.apps.terminal, "-e", ...entry.command]); } }, comment: entry.comment, @@ -267,7 +267,7 @@ Singleton { if (!action.runInTerminal) action.execute(); else { - Quickshell.execDetached(["bash", '-c', `${Config.options.apps.terminal} -e '${StringUtils.shellSingleQuoteEscape(action.command.join(' '))}'`]); + Quickshell.execDetached([...Config.options.apps.terminal, "-e", ...action.command]); } } }); diff --git a/dots/.config/quickshell/ii/shell.qml b/dots/.config/quickshell/ii/shell.qml index 96d469c03..689d78b6d 100644 --- a/dots/.config/quickshell/ii/shell.qml +++ b/dots/.config/quickshell/ii/shell.qml @@ -3,8 +3,8 @@ //@ pragma Env QT_QUICK_CONTROLS_STYLE=Basic //@ pragma Env QT_QUICK_FLICKABLE_WHEEL_DECELERATION=10000 -// Adjust this to make the shell smaller or larger -//@ pragma Env QT_SCALE_FACTOR=1 +// Remove two slashes below and adjust the value to change the UI scale +////@ pragma Env QT_SCALE_FACTOR=1 import "modules/common" import "services"