Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 30s
Python / test (pull_request) Successful in 42s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m36s
C++ / build (pull_request) Successful in 2m20s
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 30s
Python / test (pull_request) Successful in 42s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m36s
C++ / build (pull_request) Successful in 2m20s
This commit is contained in:
@@ -51,7 +51,9 @@ add_compile_options(
|
|||||||
-Wunreachable-code
|
-Wunreachable-code
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if("shell" IN_LIST ENABLE_MODULES)
|
if("shell" IN_LIST ENABLE_MODULES)
|
||||||
|
# Build settings index
|
||||||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||||
set(SETTINGS_INDEX_JSON "${CMAKE_BINARY_DIR}/settings-index.json")
|
set(SETTINGS_INDEX_JSON "${CMAKE_BINARY_DIR}/settings-index.json")
|
||||||
execute_process(
|
execute_process(
|
||||||
@@ -64,6 +66,49 @@ if("shell" IN_LIST ENABLE_MODULES)
|
|||||||
if(NOT SETTINGS_INDEX_RESULT EQUAL 0)
|
if(NOT SETTINGS_INDEX_RESULT EQUAL 0)
|
||||||
message(FATAL_ERROR "Failed to build settings search index")
|
message(FATAL_ERROR "Failed to build settings search index")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Nuitka compilation
|
||||||
|
set(ZSHELL_CLI_BUILD_DIR "${CMAKE_BINARY_DIR}/zshell-cli")
|
||||||
|
set(ZSHELL_CLI_DIST "${ZSHELL_CLI_BUILD_DIR}/zshell.dist")
|
||||||
|
set(ZSHELL_CLI_SRC "${CMAKE_SOURCE_DIR}/cli/src/zshell")
|
||||||
|
|
||||||
|
find_program(NUITKA_EXECUTABLE nuitka REQUIRED)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE ZSHELL_CLI_SOURCES CONFIGURE_DEPENDS
|
||||||
|
"${ZSHELL_CLI_SRC}/*.py"
|
||||||
|
)
|
||||||
|
file(GLOB_RECURSE ZSHELL_CLI_ASSETS CONFIGURE_DEPENDS
|
||||||
|
"${ZSHELL_CLI_SRC}/assets/*"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${ZSHELL_CLI_DIST}/zshell-cli"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${ZSHELL_CLI_BUILD_DIR}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E rm -rf "${ZSHELL_CLI_DIST}"
|
||||||
|
|
||||||
|
COMMAND
|
||||||
|
${NUITKA_EXECUTABLE}
|
||||||
|
--standalone
|
||||||
|
--include-data-dir=${CMAKE_SOURCE_DIR}/cli/src/zshell/assets=zshell/assets
|
||||||
|
--output-dir=${ZSHELL_CLI_BUILD_DIR}
|
||||||
|
--output-filename=zshell-cli
|
||||||
|
${CMAKE_SOURCE_DIR}/cli/src/zshell/
|
||||||
|
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/cli
|
||||||
|
DEPENDS ${ZSHELL_CLI_SOURCES} ${ZSHELL_CLI_ASSETS}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(zshell-cli ALL DEPENDS "${ZSHELL_CLI_DIST}/zshell-cli")
|
||||||
|
|
||||||
|
install(PROGRAMS "${ZSHELL_CLI_DIST}/zshell-cli" DESTINATION "${INSTALL_LIBDIR}/zshell-cli")
|
||||||
|
install(DIRECTORY "${ZSHELL_CLI_DIST}/" DESTINATION "${INSTALL_LIBDIR}/zshell-cli" PATTERN "zshell-cli" EXCLUDE)
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
"${CMAKE_SOURCE_DIR}/Plugins/cmake/zshell-cli.cmake.in"
|
||||||
|
"${CMAKE_BINARY_DIR}/Plugins/cmake/zshell-cli.cmake"
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
install(SCRIPT "${CMAKE_BINARY_DIR}/Plugins/cmake/zshell-cli.cmake")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if("plugin" IN_LIST ENABLE_MODULES)
|
if("plugin" IN_LIST ENABLE_MODULES)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ JsonObject {
|
|||||||
property bool showMemory: true
|
property bool showMemory: true
|
||||||
property bool showNetwork: true
|
property bool showNetwork: true
|
||||||
property bool showStorage: true
|
property bool showStorage: true
|
||||||
|
property bool showVram: true
|
||||||
}
|
}
|
||||||
component Sizes: JsonObject {
|
component Sizes: JsonObject {
|
||||||
readonly property int dateTimeWidth: 110
|
readonly property int dateTimeWidth: 110
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ Item {
|
|||||||
if (!root.visibilities.bar && Config.bar.autoHide && y < root.bar.implicitHeight)
|
if (!root.visibilities.bar && Config.bar.autoHide && y < root.bar.implicitHeight)
|
||||||
root.bar.isHovered = true;
|
root.bar.isHovered = true;
|
||||||
|
|
||||||
if (root.panels.sidebar.width === 0) {
|
if (root.panels.sidebar.offsetScale === 1) {
|
||||||
const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y);
|
const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y);
|
||||||
|
|
||||||
if (showOsd) {
|
if (showOsd) {
|
||||||
@@ -204,7 +204,7 @@ Item {
|
|||||||
root.panels.osd.hovered = true;
|
root.panels.osd.hovered = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const outOfSidebar = x < root.width - root.panels.sidebar.width;
|
const outOfSidebar = x < root.width - root.panels.sidebar.width * (1 - root.panels.sidebar.offsetScale);
|
||||||
const showOsd = outOfSidebar && root.inRightPanel(root.panels.osdWrapper, x, y);
|
const showOsd = outOfSidebar && root.inRightPanel(root.panels.osdWrapper, x, y);
|
||||||
|
|
||||||
if (!root.osdShortcutActive) {
|
if (!root.osdShortcutActive) {
|
||||||
|
|||||||
+3
-7
@@ -184,18 +184,14 @@ Item {
|
|||||||
Item {
|
Item {
|
||||||
id: settingsWrapper
|
id: settingsWrapper
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
clip: true
|
clip: true
|
||||||
implicitHeight: settings.implicitHeight
|
|
||||||
implicitWidth: settings.implicitWidth
|
|
||||||
x: (root.width - settings.implicitWidth) / 2
|
|
||||||
y: (settings.implicitHeight + (root.height - root.bar.implicitHeight - settings.implicitHeight) / 2) * (1 - settings.offsetScale) - settings.implicitHeight - 5
|
|
||||||
|
|
||||||
Settings.Wrapper {
|
Settings.Wrapper {
|
||||||
id: settings
|
id: settings
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.centerIn: parent
|
||||||
anchors.top: parent.top
|
anchors.verticalCenterOffset: (-implicitHeight - 5 - ((root.height - implicitHeight) / 2)) * offsetScale
|
||||||
// anchors.centerIn: parent
|
|
||||||
panels: root
|
panels: root
|
||||||
screen: root.screen
|
screen: root.screen
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ Region {
|
|||||||
}
|
}
|
||||||
|
|
||||||
R {
|
R {
|
||||||
panel: root.panels.settingsWrapper
|
panel: root.panels.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
R {
|
R {
|
||||||
|
|||||||
+2
-8
@@ -306,15 +306,9 @@ CustomWindow {
|
|||||||
PanelBg {
|
PanelBg {
|
||||||
id: settingsBg
|
id: settingsBg
|
||||||
|
|
||||||
property real extraHeight: 0
|
|
||||||
|
|
||||||
deformAmount: 0.03
|
deformAmount: 0.03
|
||||||
implicitHeight: panels.settings.height * (1 + extraHeight)
|
panel: panels.settings
|
||||||
implicitWidth: panels.settings.width
|
|
||||||
panel: panels.settingsWrapper
|
|
||||||
radius: Appearance.rounding.large + Appearance.padding.normal
|
radius: Appearance.rounding.large + Appearance.padding.normal
|
||||||
x: panels.settingsWrapper.x + panels.settings.x + root.borderThickness
|
|
||||||
y: panels.settingsWrapper.y + panels.settings.y + bar.implicitHeight - panels.settings.height * extraHeight
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelBg {
|
PanelBg {
|
||||||
@@ -422,7 +416,7 @@ CustomWindow {
|
|||||||
resources.transform: Matrix4x4 {
|
resources.transform: Matrix4x4 {
|
||||||
matrix: resourcesBg.deformMatrix
|
matrix: resourcesBg.deformMatrix
|
||||||
}
|
}
|
||||||
settingsWrapper.transform: Matrix4x4 {
|
settings.transform: Matrix4x4 {
|
||||||
matrix: settingsBg.deformMatrix
|
matrix: settingsBg.deformMatrix
|
||||||
}
|
}
|
||||||
sidebar.transform: Matrix4x4 {
|
sidebar.transform: Matrix4x4 {
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ export EGL_PLATFORM=gbm
|
|||||||
if command -v start-hyprland >/dev/null 2>&1; then
|
if command -v start-hyprland >/dev/null 2>&1; then
|
||||||
exec start-hyprland -- -c /etc/zshell-greeter/zshell-hyprland.conf
|
exec start-hyprland -- -c /etc/zshell-greeter/zshell-hyprland.conf
|
||||||
else
|
else
|
||||||
exec Hyprland -c /etc/zshell-greeter/zshell-hyprland.conf
|
exec Hyprland -c /etc/zshell-greeter/zshell-hyprland.lua
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
monitor = ,preferred,auto,1
|
|
||||||
|
|
||||||
env = XDG_SESSION_TYPE,wayland
|
|
||||||
env = QT_QPA_PLATFORM,wayland
|
|
||||||
env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1
|
|
||||||
|
|
||||||
misc {
|
|
||||||
disable_hyprland_logo = true
|
|
||||||
disable_splash_rendering = true
|
|
||||||
}
|
|
||||||
|
|
||||||
exec = sh -lc 'qs -c zshell-greeter; hyprctl dispatch exit'
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
hl.env("XDG_SESSION_TYPE", "wayland")
|
||||||
|
hl.env("QT_QPA_PLATFORM", "wayland")
|
||||||
|
hl.env("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1")
|
||||||
|
|
||||||
|
hl.config({
|
||||||
|
misc = {
|
||||||
|
disable_hyprland_logo = true,
|
||||||
|
disable_splash_rendering = true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
hl.on("hyprland.start", function()
|
||||||
|
hl.exec_cmd("sh -lc 'qs -c zshell-greeter; hyprctl dispatch exit'")
|
||||||
|
end)
|
||||||
@@ -9,31 +9,25 @@ import qs.Config
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// Private properties
|
|
||||||
property real _downloadSpeed: 0
|
property real _downloadSpeed: 0
|
||||||
property real _downloadTotal: 0
|
property real _downloadTotal: 0
|
||||||
|
|
||||||
// Initial readings for calculating totals
|
|
||||||
property real _initialRxBytes: 0
|
property real _initialRxBytes: 0
|
||||||
property real _initialTxBytes: 0
|
property real _initialTxBytes: 0
|
||||||
property bool _initialized: false
|
property bool _initialized: false
|
||||||
|
|
||||||
// Previous readings for calculating speed
|
|
||||||
property real _prevRxBytes: 0
|
property real _prevRxBytes: 0
|
||||||
property real _prevTimestamp: 0
|
property real _prevTimestamp: 0
|
||||||
property real _prevTxBytes: 0
|
property real _prevTxBytes: 0
|
||||||
property real _uploadSpeed: 0
|
property real _uploadSpeed: 0
|
||||||
property real _uploadTotal: 0
|
property real _uploadTotal: 0
|
||||||
|
|
||||||
// History buffers for sparkline
|
|
||||||
readonly property CircularBuffer downloadBuffer: _downloadBuffer
|
readonly property CircularBuffer downloadBuffer: _downloadBuffer
|
||||||
|
|
||||||
// Current speeds in bytes per second
|
|
||||||
readonly property real downloadSpeed: _downloadSpeed
|
readonly property real downloadSpeed: _downloadSpeed
|
||||||
|
|
||||||
// Total bytes transferred since tracking started
|
|
||||||
readonly property real downloadTotal: _downloadTotal
|
readonly property real downloadTotal: _downloadTotal
|
||||||
readonly property int historyLength: 30
|
readonly property int historyLength: Config.dashboard.performance.showVram ? 70 : 30
|
||||||
property int refCount: 0
|
property int refCount: 0
|
||||||
readonly property CircularBuffer uploadBuffer: _uploadBuffer
|
readonly property CircularBuffer uploadBuffer: _uploadBuffer
|
||||||
readonly property real uploadSpeed: _uploadSpeed
|
readonly property real uploadSpeed: _uploadSpeed
|
||||||
|
|||||||
@@ -149,36 +149,71 @@ WlSessionLockSurface {
|
|||||||
Image {
|
Image {
|
||||||
id: background
|
id: background
|
||||||
|
|
||||||
|
anchors.bottomMargin: -8 - lockContent.positions[lockContent.positionIndex].y
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: -8 + lockContent.positions[lockContent.positionIndex].x
|
||||||
|
anchors.rightMargin: -8 - lockContent.positions[lockContent.positionIndex].x
|
||||||
|
anchors.topMargin: -8 + lockContent.positions[lockContent.positionIndex].y
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
source: WallpaperPath.lockscreenBg
|
source: WallpaperPath.lockscreenBg
|
||||||
|
|
||||||
|
Behavior on anchors.bottomMargin {
|
||||||
|
Anim {
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on anchors.leftMargin {
|
||||||
|
Anim {
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on anchors.rightMargin {
|
||||||
|
Anim {
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on anchors.topMargin {
|
||||||
|
Anim {
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: lockContent
|
id: lockContent
|
||||||
|
|
||||||
|
property int positionIndex: 0
|
||||||
|
readonly property var positions: [Qt.point(0, 0), Qt.point(4, 0), Qt.point(4, 4), Qt.point(0, 4), Qt.point(-4, 4), Qt.point(-4, 0), Qt.point(-4, -4), Qt.point(0, -4), Qt.point(4, -4),]
|
||||||
readonly property int radius: size / 4 * Appearance.rounding.scale
|
readonly property int radius: size / 4 * Appearance.rounding.scale
|
||||||
readonly property int size: lockIcon.implicitHeight + Appearance.padding.large * 4
|
readonly property int size: lockIcon.implicitHeight + Appearance.padding.large * 4
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
anchors.horizontalCenterOffset: positions[positionIndex].x
|
||||||
|
anchors.verticalCenterOffset: positions[positionIndex].y
|
||||||
implicitHeight: size
|
implicitHeight: size
|
||||||
implicitWidth: size
|
implicitWidth: size
|
||||||
scale: 0
|
scale: 0
|
||||||
|
|
||||||
// MultiEffect {
|
Behavior on anchors.horizontalCenterOffset {
|
||||||
// anchors.fill: lockBg
|
Anim {
|
||||||
// autoPaddingEnabled: false
|
duration: 5000
|
||||||
// blur: 1
|
}
|
||||||
// blurEnabled: true
|
}
|
||||||
// blurMax: 64
|
Behavior on anchors.verticalCenterOffset {
|
||||||
// maskEnabled: true
|
Anim {
|
||||||
// maskSource: lockBg
|
duration: 5000
|
||||||
//
|
}
|
||||||
// source: ShaderEffectSource {
|
}
|
||||||
// sourceItem: background
|
|
||||||
// sourceRect: Qt.rect(lockBg.x, lockBg.y, lockBg.width, lockBg, height)
|
Timer {
|
||||||
// }
|
interval: 120000
|
||||||
// }
|
repeat: true
|
||||||
|
running: true
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
lockContent.positionIndex = (lockContent.positionIndex + 1) % lockContent.positions.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
id: lockBg
|
id: lockBg
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ CustomRect {
|
|||||||
|
|
||||||
readonly property color accent: DynamicColors.palette.m3tertiary
|
readonly property color accent: DynamicColors.palette.m3tertiary
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: layout.implicitHeight + Appearance.padding.large * 2
|
implicitHeight: layout.implicitHeight + Appearance.padding.large * 2
|
||||||
implicitWidth: layout.implicitWidth + Appearance.padding.extraLargeIncreased * 2
|
implicitWidth: layout.implicitWidth + Appearance.padding.extraLargeIncreased * 2
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import ZShell.Internal
|
import ZShell.Internal
|
||||||
import qs.Modules.Resources
|
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Config
|
import qs.Config
|
||||||
@@ -9,8 +8,6 @@ import qs.Config
|
|||||||
CustomRect {
|
CustomRect {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Wrapper wrapper
|
|
||||||
|
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: 220
|
implicitHeight: 220
|
||||||
implicitWidth: 300
|
implicitWidth: 300
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import ZShell.Services
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property color accent: DynamicColors.palette.m3tertiary
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: layout.implicitHeight + Appearance.padding.large * 2
|
||||||
|
implicitWidth: layout.implicitWidth + Appearance.padding.extraLargeIncreased
|
||||||
|
radius: Appearance.rounding.medium
|
||||||
|
|
||||||
|
ServiceRef {
|
||||||
|
service: Gpu
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: layout
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Appearance.spacing.extraSmall
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.leftMargin: -Appearance.padding.extraSmall
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: root.accent
|
||||||
|
fill: 1
|
||||||
|
text: "memory_alt"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
text: qsTr("Video memory")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CircularProgress {
|
||||||
|
id: circularIndicator
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.topMargin: Appearance.spacing.large
|
||||||
|
fgColor: root.accent
|
||||||
|
implicitSize: usageColumn.implicitHeight + thickness + Appearance.padding.largeIncreased * 2
|
||||||
|
startAngle: -225
|
||||||
|
sweepAngle: 270
|
||||||
|
value: Gpu.memoryUsed / Gpu.memoryTotal
|
||||||
|
|
||||||
|
Behavior on clampedVal {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: usageColumn
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: Appearance.padding.extraSmall
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: root.accent
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: Math.round(circularIndicator.value * 100) + "%"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
text: qsTr("Used")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: {
|
||||||
|
const fmt = UsageFmt.formatKib(Gpu.memoryUsed, Gpu.memoryTotal);
|
||||||
|
return `${fmt.value.toFixed(1)} / ${Math.floor(fmt.total)} ${fmt.unit}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -74,7 +74,7 @@ Item {
|
|||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: Appearance.spacing.normal
|
spacing: Appearance.spacing.normal
|
||||||
visible: storageCard.active || networkCard.active || memoryCard.active
|
visible: storageCard.active || memoryCard.active || vramCard.active || networkCard1.active
|
||||||
|
|
||||||
WrappedLoader {
|
WrappedLoader {
|
||||||
id: storageCard
|
id: storageCard
|
||||||
@@ -95,15 +95,32 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WrappedLoader {
|
WrappedLoader {
|
||||||
id: networkCard
|
id: vramCard
|
||||||
|
|
||||||
active: Config.dashboard.performance.showNetwork
|
active: Config.dashboard.performance.showVram
|
||||||
|
|
||||||
|
sourceComponent: VramCard {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WrappedLoader {
|
||||||
|
id: networkCard1
|
||||||
|
|
||||||
|
active: Config.dashboard.performance.showNetwork && !vramCard.active
|
||||||
|
|
||||||
sourceComponent: NetworkCard {
|
sourceComponent: NetworkCard {
|
||||||
wrapper: root.wrapper
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WrappedLoader {
|
||||||
|
id: networkCard2
|
||||||
|
|
||||||
|
active: Config.dashboard.performance.showNetwork && vramCard.active
|
||||||
|
|
||||||
|
sourceComponent: NetworkCard {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WrappedLoader {
|
WrappedLoader {
|
||||||
|
|||||||
@@ -267,8 +267,6 @@ Item {
|
|||||||
function restoreFromData() {
|
function restoreFromData() {
|
||||||
let data = Wallpapers.getCrop(wrapper.currentScreen.name);
|
let data = Wallpapers.getCrop(wrapper.currentScreen.name);
|
||||||
|
|
||||||
console.log(data.x, data.y);
|
|
||||||
|
|
||||||
if (data && (Math.abs(data.x) > 0.001 || Math.abs(data.y) > 0.001 || Math.abs(data.width - 1.0) > 0.001 || Math.abs(data.height - 1.0) > 0.001)) {
|
if (data && (Math.abs(data.x) > 0.001 || Math.abs(data.y) > 0.001 || Math.abs(data.width - 1.0) > 0.001 || Math.abs(data.height - 1.0) > 0.001)) {
|
||||||
zoom = data.zoom > 0 ? data.zoom : 1.0;
|
zoom = data.zoom > 0 ? data.zoom : 1.0;
|
||||||
x = imageX + (data.x * scaledImg.paintedWidth);
|
x = imageX + (data.x * scaledImg.paintedWidth);
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ VerticalFadeFlickable {
|
|||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
font.pointSize: Appearance.font.size.medium
|
font.pointSize: Appearance.font.size.medium
|
||||||
text: SettingsSearcher.highlight(result.modelData.title, root.search, DynamicColors.palette.m3primary)
|
text: SettingsSearcher.highlight(result.modelData.title, root.search, DynamicColors.palette.m3primary)
|
||||||
textFormat: Text.StyledText
|
textFormat: text.includes("<font") ? Text.StyledText : Text.PlainText
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
@@ -258,7 +258,7 @@ VerticalFadeFlickable {
|
|||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
font.pointSize: Appearance.font.size.small
|
font.pointSize: Appearance.font.size.small
|
||||||
text: SettingsSearcher.highlight(result.modelData.subtext, root.search, DynamicColors.palette.m3primary)
|
text: SettingsSearcher.highlight(result.modelData.subtext, root.search, DynamicColors.palette.m3primary)
|
||||||
textFormat: Text.StyledText
|
textFormat: text.includes("<font") ? Text.StyledText : Text.PlainText
|
||||||
visible: result.modelData.subtext.length > 0
|
visible: result.modelData.subtext.length > 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,14 @@ PageBase {
|
|||||||
onToggled: Config.dashboard.performance.showGpu = checked
|
onToggled: Config.dashboard.performance.showGpu = checked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.dashboard.performance.showVram
|
||||||
|
settingAnchor: "resources-vram"
|
||||||
|
text: qsTr("Video memory")
|
||||||
|
|
||||||
|
onToggled: Config.dashboard.performance.showVram = checked
|
||||||
|
}
|
||||||
|
|
||||||
ToggleRow {
|
ToggleRow {
|
||||||
checked: Config.dashboard.performance.showCpu
|
checked: Config.dashboard.performance.showCpu
|
||||||
settingAnchor: "resources-cpu"
|
settingAnchor: "resources-cpu"
|
||||||
|
|||||||
@@ -10,16 +10,39 @@ Singleton {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var fzfFinder: null
|
property var fzfFinder: null
|
||||||
|
readonly property var highlightCache: ({
|
||||||
|
"search": "",
|
||||||
|
"pattern": null
|
||||||
|
})
|
||||||
property var inverted: ({})
|
property var inverted: ({})
|
||||||
property var ranking: ({})
|
property var ranking: ({})
|
||||||
|
|
||||||
function highlight(text: string, search: string, colour: color): string {
|
function highlight(text: string, search: string, colour: color): string {
|
||||||
const escaped = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
const escaped = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||||
const tokens = tokenize(search);
|
if (search.length === 0)
|
||||||
if (tokens.length === 0)
|
|
||||||
return escaped;
|
return escaped;
|
||||||
const escapedTokens = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
||||||
const pattern = new RegExp("\\b(" + escapedTokens.join("|") + ")", "gi");
|
const cache = root.highlightCache;
|
||||||
|
if (search !== cache.search) {
|
||||||
|
const tokens = tokenize(search);
|
||||||
|
cache.search = search;
|
||||||
|
if (tokens.length === 0)
|
||||||
|
cache.pattern = null;
|
||||||
|
else {
|
||||||
|
const escapedTokens = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
||||||
|
cache.pattern = new RegExp("\\b(" + escapedTokens.join("|") + ")", "gi");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pattern = cache.pattern;
|
||||||
|
if (!pattern)
|
||||||
|
return escaped;
|
||||||
|
|
||||||
|
pattern.lastIndex = 0;
|
||||||
|
if (!pattern.test(escaped))
|
||||||
|
return escaped;
|
||||||
|
|
||||||
|
pattern.lastIndex = 0;
|
||||||
return escaped.replace(pattern, `<font color="${colour}">$1</font>`);
|
return escaped.replace(pattern, `<font color="${colour}">$1</font>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ Item {
|
|||||||
sState.animatingContainer: content.opacity < 1
|
sState.animatingContainer: content.opacity < 1
|
||||||
sState.currentPageIdx: ["wallpaper"][0]
|
sState.currentPageIdx: ["wallpaper"][0]
|
||||||
sState.screen: root.screen
|
sState.screen: root.screen
|
||||||
|
|
||||||
onClose: console.log("shouldclose")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import qs.Components
|
import qs.Components
|
||||||
@@ -12,14 +13,13 @@ import qs.Config
|
|||||||
StackView {
|
StackView {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property int biggestWidth: 0
|
|
||||||
readonly property int itemHeight: 30
|
readonly property int itemHeight: 30
|
||||||
readonly property int panelRadius: ((itemHeight / 2) + Appearance.padding.small) * Appearance.rounding.scale
|
readonly property int panelRadius: ((itemHeight / 2) + Appearance.padding.small) * Appearance.rounding.scale
|
||||||
required property PopoutState popouts
|
required property PopoutState popouts
|
||||||
property int rootWidth: 0
|
property int rootWidth: 0
|
||||||
required property QsMenuHandle trayItem
|
required property QsMenuHandle trayItem
|
||||||
|
|
||||||
implicitHeight: currentItem.implicitHeight
|
implicitHeight: currentItem.isSubMenu ? currentItem.implicitHeight : currentItem.implicitHeight - currentItem.spacing
|
||||||
implicitWidth: currentItem.implicitWidth
|
implicitWidth: currentItem.implicitWidth
|
||||||
|
|
||||||
initialItem: SubMenu {
|
initialItem: SubMenu {
|
||||||
@@ -46,7 +46,7 @@ StackView {
|
|||||||
duration: 0
|
duration: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
component SubMenu: Column {
|
component SubMenu: ColumnLayout {
|
||||||
id: menu
|
id: menu
|
||||||
|
|
||||||
required property QsMenuHandle handle
|
required property QsMenuHandle handle
|
||||||
@@ -54,9 +54,8 @@ StackView {
|
|||||||
property bool shown
|
property bool shown
|
||||||
|
|
||||||
opacity: shown ? 1 : 0
|
opacity: shown ? 1 : 0
|
||||||
padding: 0
|
|
||||||
scale: shown ? 1 : 0.8
|
scale: shown ? 1 : 0.8
|
||||||
spacing: 4
|
spacing: Appearance.spacing.extraSmall
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
Anim {
|
Anim {
|
||||||
@@ -87,22 +86,27 @@ StackView {
|
|||||||
required property int index
|
required property int index
|
||||||
required property QsMenuEntry modelData
|
required property QsMenuEntry modelData
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: modelData.isSeparator ? Appearance.padding.normal : 0
|
||||||
|
Layout.rightMargin: modelData.isSeparator ? Appearance.padding.normal : 0
|
||||||
color: modelData.isSeparator ? DynamicColors.palette.m3outlineVariant : "transparent"
|
color: modelData.isSeparator ? DynamicColors.palette.m3outlineVariant : "transparent"
|
||||||
implicitHeight: modelData.isSeparator ? 1 : children.implicitHeight
|
implicitHeight: modelData.isSeparator ? (visible ? 1 : 0) : childrenLoader.item.implicitHeight
|
||||||
implicitWidth: root.biggestWidth
|
implicitWidth: childrenLoader.item?.implicitWidth ?? 0
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
visible: index !== (menuOpener.children.values.length - 1) ? true : (modelData.isSeparator ? false : true)
|
visible: index !== (menuOpener.children.values.length - 1) ? true : (modelData.isSeparator ? false : true)
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: children
|
id: childrenLoader
|
||||||
|
|
||||||
active: !item.modelData.isSeparator
|
active: !item.modelData.isSeparator
|
||||||
anchors.left: parent.left
|
anchors.fill: parent
|
||||||
anchors.right: parent.right
|
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
|
|
||||||
sourceComponent: Item {
|
sourceComponent: Item {
|
||||||
|
property int iconWidth: icon.active ? icon.width + Appearance.spacing.normal + icon.anchors.rightMargin : 0
|
||||||
|
|
||||||
implicitHeight: root.itemHeight
|
implicitHeight: root.itemHeight
|
||||||
|
implicitWidth: label.width + label.anchors.leftMargin * 2 + iconWidth + (expand.item?.width ?? 0)
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
enabled: item.modelData.enabled
|
enabled: item.modelData.enabled
|
||||||
@@ -111,8 +115,6 @@ StackView {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
const entry = item.modelData;
|
const entry = item.modelData;
|
||||||
if (entry.hasChildren) {
|
if (entry.hasChildren) {
|
||||||
root.rootWidth = root.biggestWidth;
|
|
||||||
root.biggestWidth = 0;
|
|
||||||
root.push(subMenuComp.createObject(null, {
|
root.push(subMenuComp.createObject(null, {
|
||||||
handle: entry,
|
handle: entry,
|
||||||
isSubMenu: true
|
isSubMenu: true
|
||||||
@@ -161,23 +163,7 @@ StackView {
|
|||||||
anchors.leftMargin: 10
|
anchors.leftMargin: 10
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
color: item.modelData.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3outline
|
color: item.modelData.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3outline
|
||||||
text: labelMetrics.elidedText
|
|
||||||
}
|
|
||||||
|
|
||||||
TextMetrics {
|
|
||||||
id: labelMetrics
|
|
||||||
|
|
||||||
font.family: label.font.family
|
|
||||||
font.pointSize: label.font.pointSize
|
|
||||||
text: item.modelData.text
|
text: item.modelData.text
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
var biggestWidth = root.biggestWidth;
|
|
||||||
var currentWidth = labelMetrics.width + (item.modelData.icon ?? "" ? 30 : 0) + (item.modelData.hasChildren ? 30 : 0) + 20;
|
|
||||||
if (currentWidth > biggestWidth) {
|
|
||||||
root.biggestWidth = currentWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
@@ -201,17 +187,17 @@ StackView {
|
|||||||
Loader {
|
Loader {
|
||||||
id: loader
|
id: loader
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.maximumHeight: active ? implicitHeight : 0
|
||||||
active: menu.isSubMenu
|
active: menu.isSubMenu
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
|
|
||||||
sourceComponent: Item {
|
sourceComponent: Item {
|
||||||
implicitHeight: 30
|
implicitHeight: 30
|
||||||
implicitWidth: back.implicitWidth
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors.bottom: parent.bottom
|
anchors.fill: parent
|
||||||
implicitHeight: 30
|
implicitHeight: 30
|
||||||
implicitWidth: root.biggestWidth
|
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -224,7 +210,6 @@ StackView {
|
|||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.pop();
|
root.pop();
|
||||||
root.biggestWidth = root.rootWidth;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
#include "sensorslib.hpp"
|
#include "sensorslib.hpp"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
#include <qdir.h>
|
#include <qdir.h>
|
||||||
#include <qfile.h>
|
#include <qfile.h>
|
||||||
|
#include <qobject.h>
|
||||||
#include <qregularexpression.h>
|
#include <qregularexpression.h>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
@@ -243,6 +245,45 @@ void Gpu::detectNameOnce() {
|
|||||||
{QStringLiteral("-c"), QString::fromLatin1(kNameDetectScript)});
|
{QStringLiteral("-c"), QString::fromLatin1(kNameDetectScript)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Gpu::readGenericMemory() {
|
||||||
|
const QStringList paths = QDir(QStringLiteral("/sys/class/drm"))
|
||||||
|
.entryList(
|
||||||
|
QStringList() << QStringLiteral("card*"),
|
||||||
|
QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
|
||||||
|
qreal totalMem = 0.0;
|
||||||
|
qreal usedMem = 0.0;
|
||||||
|
for (const QString& card : paths) {
|
||||||
|
QFile total(
|
||||||
|
QStringLiteral("/sys/class/drm/%1/device/mem_info_vram_total")
|
||||||
|
.arg(card));
|
||||||
|
if (!total.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool ok = false;
|
||||||
|
const qreal v = total.readAll().trimmed().toDouble(&ok);
|
||||||
|
total.close();
|
||||||
|
if (ok) {
|
||||||
|
totalMem += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile used(QStringLiteral("/sys/class/drm/%1/device/mem_info_vram_used")
|
||||||
|
.arg(card));
|
||||||
|
if (!used.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool ok1 = false;
|
||||||
|
const qreal v1 = used.readAll().trimmed().toDouble(&ok1);
|
||||||
|
used.close();
|
||||||
|
if (ok1) {
|
||||||
|
usedMem += v1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setMemoryTotal(totalMem);
|
||||||
|
setMemoryUsed(usedMem);
|
||||||
|
}
|
||||||
|
|
||||||
void Gpu::readGenericUsage() {
|
void Gpu::readGenericUsage() {
|
||||||
const QStringList paths = QDir(QStringLiteral("/sys/class/drm"))
|
const QStringList paths = QDir(QStringLiteral("/sys/class/drm"))
|
||||||
.entryList(
|
.entryList(
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class Gpu : public TickingService {
|
|||||||
void readGenericUsage();
|
void readGenericUsage();
|
||||||
void startNvidiaUsage();
|
void startNvidiaUsage();
|
||||||
void readGpuTemperature();
|
void readGpuTemperature();
|
||||||
|
void readGenericMemory();
|
||||||
|
|
||||||
void setUserType(Type value);
|
void setUserType(Type value);
|
||||||
void setAutoType(Type value);
|
void setAutoType(Type value);
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
set(ZSHELL_CLI_BIN_DIR "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/usr/bin")
|
||||||
|
file(MAKE_DIRECTORY "${ZSHELL_CLI_BIN_DIR}")
|
||||||
|
|
||||||
|
file(RELATIVE_PATH ZSHELL_CLI_TARGET
|
||||||
|
"${ZSHELL_CLI_BIN_DIR}"
|
||||||
|
"${CMAKE_INSTALL_PREFIX}/@INSTALL_LIBDIR@/zshell-cli/zshell-cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
file(CREATE_LINK
|
||||||
|
"${ZSHELL_CLI_TARGET}"
|
||||||
|
"${ZSHELL_CLI_BIN_DIR}/zshell-cli" SYMBOLIC
|
||||||
|
)
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
cd "$(dirname $0)/../src" || exit
|
|
||||||
|
|
||||||
python3 -m zshell "$@"
|
|
||||||
@@ -19,6 +19,11 @@ zshell-cli = "zshell:main"
|
|||||||
[tool.hatch.version]
|
[tool.hatch.version]
|
||||||
source = "vcs"
|
source = "vcs"
|
||||||
|
|
||||||
|
[tool.hatch.build]
|
||||||
|
include = [
|
||||||
|
"src/zshell/assets/**",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.hatch.build.targets.sdist]
|
[tool.hatch.build.targets.sdist]
|
||||||
only-include = [
|
only-include = [
|
||||||
"src",
|
"src",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from . import main
|
from zshell import main
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ def _complete_accent(ctx, incomplete):
|
|||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def list_presets(
|
def list_presets(
|
||||||
json_format: bool = typer.Option(False, "--json", help="Output in JSON format"),
|
json_format: bool = typer.Option(
|
||||||
|
False, "--json", help="Output in JSON format"),
|
||||||
):
|
):
|
||||||
schemes = list_schemes()
|
schemes = list_schemes()
|
||||||
if json_format:
|
if json_format:
|
||||||
@@ -139,7 +140,7 @@ def generate(
|
|||||||
HOME = str(os.getenv("HOME"))
|
HOME = str(os.getenv("HOME"))
|
||||||
OUTPUT = Path(HOME + "/.local/state/zshell/scheme.json")
|
OUTPUT = Path(HOME + "/.local/state/zshell/scheme.json")
|
||||||
SEQ_STATE = Path(HOME + "/.local/state/zshell/sequences.txt")
|
SEQ_STATE = Path(HOME + "/.local/state/zshell/sequences.txt")
|
||||||
THUMB_PATH = Path(HOME + "/.cache/zshell/imagecache/thumbnail.jpg")
|
THUMB_DIR = Path(HOME + "/.cache/zshell/imagecache/thumbnails")
|
||||||
WALL_DIR_PATH = Path(HOME + "/.local/state/zshell/wallpaper_path.json")
|
WALL_DIR_PATH = Path(HOME + "/.local/state/zshell/wallpaper_path.json")
|
||||||
|
|
||||||
TEMPLATE_DIR = Path(HOME + "/.config/zshell/templates")
|
TEMPLATE_DIR = Path(HOME + "/.config/zshell/templates")
|
||||||
@@ -147,7 +148,8 @@ def generate(
|
|||||||
CONFIG = Path(HOME + "/.config/zshell/config.json")
|
CONFIG = Path(HOME + "/.config/zshell/config.json")
|
||||||
|
|
||||||
if preset is not None and image_path is not None:
|
if preset is not None and image_path is not None:
|
||||||
raise typer.BadParameter("Use either --image-path or --preset, not both.")
|
raise typer.BadParameter(
|
||||||
|
"Use either --image-path or --preset, not both.")
|
||||||
|
|
||||||
def get_scheme_class(scheme_name: str):
|
def get_scheme_class(scheme_name: str):
|
||||||
match scheme_name:
|
match scheme_name:
|
||||||
@@ -273,7 +275,8 @@ def generate(
|
|||||||
diff = difference_degrees(from_hct.hue, to_hct.hue)
|
diff = difference_degrees(from_hct.hue, to_hct.hue)
|
||||||
rotation = min(diff * 0.8, 100)
|
rotation = min(diff * 0.8, 100)
|
||||||
output_hue = sanitize_degrees_double(
|
output_hue = sanitize_degrees_double(
|
||||||
from_hct.hue + rotation * rotation_direction(from_hct.hue, to_hct.hue)
|
from_hct.hue + rotation *
|
||||||
|
rotation_direction(from_hct.hue, to_hct.hue)
|
||||||
)
|
)
|
||||||
tone = max(0.0, min(100.0, from_hct.tone * (1 + tone_boost)))
|
tone = max(0.0, min(100.0, from_hct.tone * (1 + tone_boost)))
|
||||||
return Hct.from_hct(output_hue, from_hct.chroma, tone)
|
return Hct.from_hct(output_hue, from_hct.chroma, tone)
|
||||||
@@ -307,15 +310,26 @@ def generate(
|
|||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def generate_thumbnail(image_path, thumbnail_path, size=(128, 128)):
|
def thumbnail_cache_path(image_path: Path, thumb_dir: Path) -> Path:
|
||||||
thumbnail_file = Path(thumbnail_path)
|
stat = image_path.stat()
|
||||||
|
key = f"{image_path.stem}_{stat.st_size}_{int(stat.st_mtime)}"
|
||||||
|
safe_key = re.sub(r"[^A-Za-z0-9._-]", "_", key)
|
||||||
|
return thumb_dir / f"{safe_key}_thumbnail.jpg"
|
||||||
|
|
||||||
|
def generate_thumbnail(image_path: Path, thumb_dir: Path, size=(128, 128)) -> Path:
|
||||||
|
thumb_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
cache_path = thumbnail_cache_path(image_path, thumb_dir)
|
||||||
|
|
||||||
|
if cache_path.exists():
|
||||||
|
return cache_path
|
||||||
|
|
||||||
image = Image.open(image_path)
|
image = Image.open(image_path)
|
||||||
|
image.draft("RGB", size)
|
||||||
image = image.convert("RGB")
|
image = image.convert("RGB")
|
||||||
image.thumbnail(size, Image.Resampling.NEAREST)
|
image.thumbnail(size, Image.Resampling.NEAREST)
|
||||||
|
image.save(cache_path, "JPEG")
|
||||||
|
|
||||||
thumbnail_file.parent.mkdir(parents=True, exist_ok=True)
|
return cache_path
|
||||||
image.save(thumbnail_path, "JPEG")
|
|
||||||
|
|
||||||
def apply_terms(sequences: str, sequences_tmux: str, state_path: Path) -> None:
|
def apply_terms(sequences: str, sequences_tmux: str, state_path: Path) -> None:
|
||||||
state_path.parent.mkdir(parents=True, exist_ok=True)
|
state_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -523,7 +537,8 @@ def generate(
|
|||||||
template = env.from_string(body)
|
template = env.from_string(body)
|
||||||
text = template.render(**context)
|
text = template.render(**context)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise RuntimeError(f"Template render failed for '{rel}': {e}") from e
|
raise RuntimeError(
|
||||||
|
f"Template render failed for '{rel}': {e}") from e
|
||||||
|
|
||||||
out_path.write_text(text, encoding="utf-8")
|
out_path.write_text(text, encoding="utf-8")
|
||||||
|
|
||||||
@@ -586,7 +601,8 @@ def generate(
|
|||||||
(v.accents for v in meta.variants if v.id == p_variant), ()
|
(v.accents for v in meta.variants if v.id == p_variant), ()
|
||||||
)
|
)
|
||||||
if accent not in var_accents:
|
if accent not in var_accents:
|
||||||
available = ", ".join(var_accents) if var_accents else "none"
|
available = ", ".join(
|
||||||
|
var_accents) if var_accents else "none"
|
||||||
raise typer.BadParameter(
|
raise typer.BadParameter(
|
||||||
f"Accent '{accent}' not available for '{p_scheme}:{p_variant}'. Available accents: {available}"
|
f"Accent '{accent}' not available for '{p_scheme}:{p_variant}'. Available accents: {available}"
|
||||||
)
|
)
|
||||||
@@ -623,13 +639,13 @@ def generate(
|
|||||||
seed = hex_to_hct(colors.get("primary", "#000000").lstrip("#"))
|
seed = hex_to_hct(colors.get("primary", "#000000").lstrip("#"))
|
||||||
else:
|
else:
|
||||||
image_path = image_path or Path(WALL_PATH)
|
image_path = image_path or Path(WALL_PATH)
|
||||||
generate_thumbnail(image_path, str(THUMB_PATH))
|
thumb_path = generate_thumbnail(image_path, THUMB_DIR)
|
||||||
seed = seed_from_image(THUMB_PATH)
|
seed = seed_from_image(thumb_path)
|
||||||
name = "dynamic"
|
name = "dynamic"
|
||||||
flavor = "default"
|
flavor = "default"
|
||||||
|
|
||||||
if smart:
|
if smart:
|
||||||
effective_mode = smart_mode(THUMB_PATH)
|
effective_mode = smart_mode(thumb_path)
|
||||||
elif mode is not None:
|
elif mode is not None:
|
||||||
effective_mode = mode
|
effective_mode = mode
|
||||||
else:
|
else:
|
||||||
@@ -675,7 +691,9 @@ def generate(
|
|||||||
print(f"rendered: {p}")
|
print(f"rendered: {p}")
|
||||||
|
|
||||||
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
|
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
|
||||||
with open(OUTPUT, "w") as f:
|
tmp_output = OUTPUT.with_suffix(".json.tmp")
|
||||||
|
with open(tmp_output, "w") as f:
|
||||||
json.dump(output_dict, f, indent=4)
|
json.dump(output_dict, f, indent=4)
|
||||||
|
os.replace(tmp_output, OUTPUT)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error: {e}")
|
print(f"Error: {e}")
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from importlib.resources import files
|
||||||
|
from importlib.resources.abc import Traversable
|
||||||
|
from pathlib import PurePosixPath
|
||||||
|
|
||||||
ASSETS = Path(__file__).resolve().parent.parent / "assets" / "schemes"
|
ASSETS: Traversable = files("zshell") / "assets" / "schemes"
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@@ -30,7 +32,7 @@ class Palette:
|
|||||||
accent: str | None = None
|
accent: str | None = None
|
||||||
|
|
||||||
|
|
||||||
def _parse_txt(path: Path) -> dict[str, str]:
|
def _parse_txt(path: Traversable) -> dict[str, str]:
|
||||||
colors: dict[str, str] = {}
|
colors: dict[str, str] = {}
|
||||||
for line in path.read_text().splitlines():
|
for line in path.read_text().splitlines():
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
@@ -46,7 +48,7 @@ def _parse_txt(path: Path) -> dict[str, str]:
|
|||||||
def _discover_schemes() -> dict[str, SchemeMeta]:
|
def _discover_schemes() -> dict[str, SchemeMeta]:
|
||||||
schemes: dict[str, SchemeMeta] = {}
|
schemes: dict[str, SchemeMeta] = {}
|
||||||
|
|
||||||
for scheme_dir in sorted(ASSETS.iterdir()):
|
for scheme_dir in sorted(ASSETS.iterdir(), key=lambda p: p.name):
|
||||||
if not scheme_dir.is_dir() or scheme_dir.name.startswith("."):
|
if not scheme_dir.is_dir() or scheme_dir.name.startswith("."):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -54,7 +56,7 @@ def _discover_schemes() -> dict[str, SchemeMeta]:
|
|||||||
display_name = sid.capitalize()
|
display_name = sid.capitalize()
|
||||||
|
|
||||||
variants: list[SchemeVariant] = []
|
variants: list[SchemeVariant] = []
|
||||||
for var_dir in sorted(scheme_dir.iterdir()):
|
for var_dir in sorted(scheme_dir.iterdir(), key=lambda p: p.name):
|
||||||
if not var_dir.is_dir() or var_dir.name.startswith("."):
|
if not var_dir.is_dir() or var_dir.name.startswith("."):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -62,9 +64,10 @@ def _discover_schemes() -> dict[str, SchemeMeta]:
|
|||||||
accents: set[str] = set()
|
accents: set[str] = set()
|
||||||
|
|
||||||
for f in var_dir.iterdir():
|
for f in var_dir.iterdir():
|
||||||
if f.suffix != ".txt":
|
name = PurePosixPath(f.name)
|
||||||
|
if name.suffix != ".txt":
|
||||||
continue
|
continue
|
||||||
stem = f.stem
|
stem = name.stem
|
||||||
if "-" in stem:
|
if "-" in stem:
|
||||||
maybe_accent, maybe_mode = stem.rsplit("-", 1)
|
maybe_accent, maybe_mode = stem.rsplit("-", 1)
|
||||||
if maybe_mode in ("dark", "light"):
|
if maybe_mode in ("dark", "light"):
|
||||||
@@ -101,12 +104,14 @@ SCHEMES: dict[str, SchemeMeta] = _discover_schemes()
|
|||||||
|
|
||||||
def get_palette(scheme: str, variant: str, mode: str, accent: str | None = None) -> Palette:
|
def get_palette(scheme: str, variant: str, mode: str, accent: str | None = None) -> Palette:
|
||||||
if scheme not in SCHEMES:
|
if scheme not in SCHEMES:
|
||||||
raise KeyError(f"Unknown scheme '{scheme}'. Available: {', '.join(SCHEMES)}")
|
raise KeyError(
|
||||||
|
f"Unknown scheme '{scheme}'. Available: {', '.join(SCHEMES)}")
|
||||||
|
|
||||||
meta = SCHEMES[scheme]
|
meta = SCHEMES[scheme]
|
||||||
var_ids = {v.id for v in meta.variants}
|
var_ids = {v.id for v in meta.variants}
|
||||||
if variant not in var_ids:
|
if variant not in var_ids:
|
||||||
raise KeyError(f"Unknown variant '{variant}' for scheme '{scheme}'. Available: {', '.join(sorted(var_ids))}")
|
raise KeyError(
|
||||||
|
f"Unknown variant '{variant}' for scheme '{scheme}'. Available: {', '.join(sorted(var_ids))}")
|
||||||
|
|
||||||
if accent:
|
if accent:
|
||||||
filename = f"{accent}-{mode}.txt"
|
filename = f"{accent}-{mode}.txt"
|
||||||
@@ -114,10 +119,10 @@ def get_palette(scheme: str, variant: str, mode: str, accent: str | None = None)
|
|||||||
filename = f"{mode}.txt"
|
filename = f"{mode}.txt"
|
||||||
|
|
||||||
txt_path = ASSETS / scheme / variant / filename
|
txt_path = ASSETS / scheme / variant / filename
|
||||||
if not txt_path.exists():
|
if not txt_path.is_file():
|
||||||
txt_path = ASSETS / scheme / variant / f"{mode}.txt"
|
txt_path = ASSETS / scheme / variant / f"{mode}.txt"
|
||||||
|
|
||||||
if not txt_path.exists():
|
if not txt_path.is_file():
|
||||||
var_info = next(v for v in meta.variants if v.id == variant)
|
var_info = next(v for v in meta.variants if v.id == variant)
|
||||||
raise FileNotFoundError(
|
raise FileNotFoundError(
|
||||||
f"No {mode} palette for '{scheme}:{variant}'. Available modes: {sorted(var_info.modes)}"
|
f"No {mode} palette for '{scheme}:{variant}'. Available modes: {sorted(var_info.modes)}"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
BINARY="../Greeter/scripts/start-zshell-greeter"
|
BINARY="../Greeter/scripts/start-zshell-greeter"
|
||||||
CONFIG="../Greeter/scripts/zshell-hyprland.conf"
|
CONFIG="../Greeter/scripts/zshell-hyprland.lua"
|
||||||
GREETD_CONFIG="../Greeter/scripts/greeter-config.toml"
|
GREETD_CONFIG="../Greeter/scripts/greeter-config.toml"
|
||||||
WALLPAPER="$HOME/.local/state/zshell/lockscreen_bg.png"
|
WALLPAPER="$HOME/.local/state/zshell/lockscreen_bg.png"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user