Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a3f38e6414 | |||
| 6aedf6f8b7 | |||
| 4ea74ed516 | |||
| f00af9d70f | |||
| de11767d3b |
+1
-8
@@ -31,13 +31,6 @@ if("shell" IN_LIST ENABLE_MODULES)
|
|||||||
foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths)
|
foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths)
|
||||||
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
|
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
install(FILES shell.qml DESTINATION "${INSTALL_QSCONFDIR}")
|
||||||
# Disable watching for changes
|
|
||||||
file(READ shell.qml SHELL_QML)
|
|
||||||
string(REPLACE "settings.watchFiles: true" "settings.watchFiles: false" SHELL_QML "${SHELL_QML}")
|
|
||||||
file(WRITE "${CMAKE_BINARY_DIR}/qml/shell.qml" "${SHELL_QML}")
|
|
||||||
install(FILES "${CMAKE_BINARY_DIR}/qml/shell.qml" DESTINATION "${INSTALL_QSCONFDIR}")
|
|
||||||
|
|
||||||
# Greeter
|
|
||||||
install(DIRECTORY Greeter/ DESTINATION "${INSTALL_GREETERCONFDIR}")
|
install(DIRECTORY Greeter/ DESTINATION "${INSTALL_GREETERCONFDIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ Text {
|
|||||||
color: DynamicColors.palette.m3onSurface
|
color: DynamicColors.palette.m3onSurface
|
||||||
font.family: Appearance.font.family.sans
|
font.family: Appearance.font.family.sans
|
||||||
font.pointSize: Appearance.font.size.normal
|
font.pointSize: Appearance.font.size.normal
|
||||||
linkColor: DynamicColors.palette.m3onPrimaryFixedVariant
|
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
textFormat: Text.PlainText
|
textFormat: Text.PlainText
|
||||||
|
|
||||||
|
|||||||
+2
-12
@@ -22,7 +22,6 @@ Singleton {
|
|||||||
property alias notifs: adapter.notifs
|
property alias notifs: adapter.notifs
|
||||||
property alias osd: adapter.osd
|
property alias osd: adapter.osd
|
||||||
property alias overview: adapter.overview
|
property alias overview: adapter.overview
|
||||||
property alias plugins: adapter.plugins
|
|
||||||
property bool recentlySaved: false
|
property bool recentlySaved: false
|
||||||
property alias screenshot: adapter.screenshot
|
property alias screenshot: adapter.screenshot
|
||||||
property alias services: adapter.services
|
property alias services: adapter.services
|
||||||
@@ -141,8 +140,7 @@ Singleton {
|
|||||||
launcher: serializeLauncher(),
|
launcher: serializeLauncher(),
|
||||||
colors: serializeColors(),
|
colors: serializeColors(),
|
||||||
dock: serializeDock(),
|
dock: serializeDock(),
|
||||||
screenshot: serializeScreenshot(),
|
screenshot: serializeScreenshot()
|
||||||
plugins: serializePlugins()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,13 +289,6 @@ Singleton {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function serializePlugins(): var {
|
|
||||||
return {
|
|
||||||
enabled: plugins.enabled,
|
|
||||||
entries: plugins.entries
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeScreenshot(): var {
|
function serializeScreenshot(): var {
|
||||||
return {
|
return {
|
||||||
enable_pp: screenshot.enable_pp,
|
enable_pp: screenshot.enable_pp,
|
||||||
@@ -306,6 +297,7 @@ Singleton {
|
|||||||
drop_shadow: screenshot.drop_shadow,
|
drop_shadow: screenshot.drop_shadow,
|
||||||
rounded_corners: screenshot.rounded_corners,
|
rounded_corners: screenshot.rounded_corners,
|
||||||
shadow_blur_radius: screenshot.shadow_blur_radius,
|
shadow_blur_radius: screenshot.shadow_blur_radius,
|
||||||
|
shadow_blur_passes: screenshot.shadow_blur_passes,
|
||||||
shadow_color: screenshot.shadow_color,
|
shadow_color: screenshot.shadow_color,
|
||||||
shadow_offset_x: screenshot.shadow_offset_x,
|
shadow_offset_x: screenshot.shadow_offset_x,
|
||||||
shadow_offset_y: screenshot.shadow_offset_y
|
shadow_offset_y: screenshot.shadow_offset_y
|
||||||
@@ -467,8 +459,6 @@ Singleton {
|
|||||||
}
|
}
|
||||||
property Overview overview: Overview {
|
property Overview overview: Overview {
|
||||||
}
|
}
|
||||||
property PluginConfig plugins: PluginConfig {
|
|
||||||
}
|
|
||||||
property Screenshot screenshot: Screenshot {
|
property Screenshot screenshot: Screenshot {
|
||||||
}
|
}
|
||||||
property Services services: Services {
|
property Services services: Services {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import Quickshell.Io
|
|
||||||
|
|
||||||
JsonObject {
|
|
||||||
property bool enabled: false
|
|
||||||
property list<var> entries: [
|
|
||||||
{
|
|
||||||
id: "Plugin",
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,7 @@ JsonObject {
|
|||||||
property bool enable_pp: true
|
property bool enable_pp: true
|
||||||
property string mode: "manual"
|
property string mode: "manual"
|
||||||
property bool rounded_corners: false
|
property bool rounded_corners: false
|
||||||
|
property int shadow_blur_passes: 1
|
||||||
property real shadow_blur_radius: 22.0
|
property real shadow_blur_radius: 22.0
|
||||||
property list<int> shadow_color: [0, 0, 0, 160]
|
property list<int> shadow_color: [0, 0, 0, 160]
|
||||||
property real shadow_offset_x: 5.0
|
property real shadow_offset_x: 5.0
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
|
|
||||||
import Quickshell
|
|
||||||
import ZShell.Models
|
|
||||||
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property alias plugins: plugins.entries
|
|
||||||
|
|
||||||
FileSystemModel {
|
|
||||||
id: plugins
|
|
||||||
|
|
||||||
nameFilters: ["*.qml"]
|
|
||||||
path: Quickshell.env("HOME") + "/.config/zshell"
|
|
||||||
recursive: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import QtQuick
|
|
||||||
import ZShell.Models
|
|
||||||
import qs.Config
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: FetchPlugins.plugins
|
|
||||||
|
|
||||||
LazyLoader {
|
|
||||||
required property FileSystemEntry modelData
|
|
||||||
|
|
||||||
activeAsync: Config.plugins.entries.some(p => {
|
|
||||||
return p.id === modelData.baseName && p.enabled;
|
|
||||||
})
|
|
||||||
source: modelData.path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -36,7 +36,7 @@ Singleton {
|
|||||||
PersistentProperties {
|
PersistentProperties {
|
||||||
id: props
|
id: props
|
||||||
|
|
||||||
property bool enabled: Hypr.options["animations:enabled"] === 0
|
property bool enabled: Hypr.options.animations.enabled === 0
|
||||||
|
|
||||||
reloadableId: "gamemode"
|
reloadableId: "gamemode"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,6 +158,5 @@ Singleton {
|
|||||||
|
|
||||||
HyprExtras {
|
HyprExtras {
|
||||||
id: extras
|
id: extras
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-3
@@ -30,12 +30,17 @@ MouseArea {
|
|||||||
property real ey: screen.height
|
property real ey: screen.height
|
||||||
required property LazyLoader loader
|
required property LazyLoader loader
|
||||||
property bool onClient
|
property bool onClient
|
||||||
property real realBorderWidth: onClient ? (Hypr.options["general:border_size"] ?? 1) : 2
|
property real realBorderWidth: onClient ? (Hypr.options.general.border_size ?? 1) : 2
|
||||||
property real realRounding: onClient ? (Hypr.options["decoration:rounding"] ?? 0) : 0
|
property real realRounding: onClient ? (Hypr.options.decoration.rounding ?? 0) : 0
|
||||||
property real rsx: Math.min(sx, ex)
|
property real rsx: Math.min(sx, ex)
|
||||||
property real rsy: Math.min(sy, ey)
|
property real rsy: Math.min(sy, ey)
|
||||||
|
readonly property real scaleRatio: Hypr.monitorFor(screen).scale
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
property real sh: Math.abs(sy - ey)
|
property real sh: Math.abs(sy - ey)
|
||||||
|
readonly property color shadowColor: Hypr.options.decoration.shadow.color
|
||||||
|
readonly property var shadowOffset: Hypr.options.decoration.shadow.offset
|
||||||
|
readonly property int shadowRange: Hypr.options.decoration.shadow.range
|
||||||
|
readonly property int shadowRenderPower: Hypr.options.decoration.shadow.render_power
|
||||||
property real ssx
|
property real ssx
|
||||||
property real ssy
|
property real ssy
|
||||||
property real sw: Math.abs(sx - ex)
|
property real sw: Math.abs(sx - ex)
|
||||||
@@ -66,7 +71,7 @@ MouseArea {
|
|||||||
|
|
||||||
function save(): void {
|
function save(): void {
|
||||||
const tmpfile = Qt.resolvedUrl(`/tmp/zshell-picker-${Quickshell.processId}-${Date.now()}.png`);
|
const tmpfile = Qt.resolvedUrl(`/tmp/zshell-picker-${Quickshell.processId}-${Date.now()}.png`);
|
||||||
const cmd = Config.screenshot.enable_pp ? ["zshell-img-tools", "--image"] : ["swappy", "-f"];
|
const cmd = Config.screenshot.enable_pp ? ["zshell-img-tools", "--scale", root.scaleRatio, "--shadow-blur-radius", root.shadowRange, "--image"] : ["swappy", "-f"];
|
||||||
ZShellIo.saveItem(screencopy, tmpfile, Qt.rect(Math.ceil(rsx), Math.ceil(rsy), Math.floor(sw), Math.floor(sh)), path => Quickshell.execDetached([...cmd, path]));
|
ZShellIo.saveItem(screencopy, tmpfile, Qt.rect(Math.ceil(rsx), Math.ceil(rsy), Math.floor(sw), Math.floor(sh)), path => Quickshell.execDetached([...cmd, path]));
|
||||||
closeAnim.start();
|
closeAnim.start();
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-82
@@ -1,82 +1,41 @@
|
|||||||
pragma Singleton
|
// pragma Singleton
|
||||||
|
//
|
||||||
import Quickshell
|
// import Quickshell
|
||||||
import Quickshell.Io
|
// import QtQuick
|
||||||
import QtQuick
|
//
|
||||||
|
// Singleton {
|
||||||
Singleton {
|
// id: root
|
||||||
id: root
|
//
|
||||||
|
// function start(extraArgs = []): void {
|
||||||
readonly property alias elapsed: props.elapsed
|
// needsStart = true;
|
||||||
property bool needsPause
|
// startArgs = extraArgs;
|
||||||
property bool needsStart
|
// checkProc.running = true;
|
||||||
property bool needsStop
|
// }
|
||||||
readonly property alias paused: props.paused
|
//
|
||||||
readonly property alias running: props.running
|
// PersistentProperties {
|
||||||
property list<string> startArgs
|
// id: props
|
||||||
|
//
|
||||||
function start(extraArgs = []): void {
|
// property real elapsed: 0
|
||||||
needsStart = true;
|
// property bool paused: false
|
||||||
startArgs = extraArgs;
|
// property bool running: false
|
||||||
checkProc.running = true;
|
//
|
||||||
}
|
// reloadableId: "recorder"
|
||||||
|
// }
|
||||||
function stop(): void {
|
//
|
||||||
needsStop = true;
|
// Process {
|
||||||
checkProc.running = true;
|
// id: checkProc
|
||||||
}
|
//
|
||||||
|
// command: ["pidof", "gpu-screen-recorder"]
|
||||||
function togglePause(): void {
|
// running: true
|
||||||
needsPause = true;
|
//
|
||||||
checkProc.running = true;
|
// onExited: code => {
|
||||||
}
|
// props.running = code === 0;
|
||||||
|
//
|
||||||
PersistentProperties {
|
// if (code === 0) {
|
||||||
id: props
|
// if (root.needsStop) {
|
||||||
|
// Quickshell.execDetached(["zshell-cli"]);
|
||||||
property real elapsed: 0
|
// }
|
||||||
property bool paused: false
|
// }
|
||||||
property bool running: false
|
// }
|
||||||
|
// }
|
||||||
reloadableId: "recorder"
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: checkProc
|
|
||||||
|
|
||||||
command: ["pidof", "gpu-screen-recorder"]
|
|
||||||
running: true
|
|
||||||
|
|
||||||
onExited: code => {
|
|
||||||
props.running = code === 0;
|
|
||||||
|
|
||||||
if (code === 0) {
|
|
||||||
if (root.needsStop) {
|
|
||||||
Quickshell.execDetached(["zshell-cli", "record", "record"]);
|
|
||||||
props.running = false;
|
|
||||||
props.paused = false;
|
|
||||||
} else if (root.needsPause) {
|
|
||||||
Quickshell.execDetached(["zshell-cli", "record", "record", "-p"]);
|
|
||||||
props.paused = !props.paused;
|
|
||||||
}
|
|
||||||
} else if (root.needsStart) {
|
|
||||||
Quickshell.execDetached(["zshell-cli", "record", "record", ...root.startArgs]);
|
|
||||||
props.running = true;
|
|
||||||
props.paused = false;
|
|
||||||
props.elapsed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
root.needsStart = false;
|
|
||||||
root.needsStop = false;
|
|
||||||
root.needsPause = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
function onSecondsChanged(): void {
|
|
||||||
props.elapsed++;
|
|
||||||
}
|
|
||||||
|
|
||||||
target: Time // qmllint disable incompatible-type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import Quickshell
|
||||||
import "../scripts/fzf.js" as Fzf
|
import "../scripts/fzf.js" as Fzf
|
||||||
import "../scripts/fuzzysort.js" as Fuzzy
|
import "../scripts/fuzzysort.js" as Fuzzy
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
property var extraOpts: ({})
|
property var extraOpts: ({})
|
||||||
|
|||||||
@@ -136,10 +136,7 @@ CustomRect {
|
|||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
|
|
||||||
onLinkActivated: link => {
|
onLinkActivated: link => {
|
||||||
if (Config.launcher.uwsm)
|
|
||||||
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
Quickshell.execDetached(["app2unit", "-O", "--", link]);
|
||||||
else
|
|
||||||
Quickshell.execDetached(["xdg-open", link]);
|
|
||||||
root.visibilities.sidebar = false;
|
root.visibilities.sidebar = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,290 +0,0 @@
|
|||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import Quickshell
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import qs.Components
|
|
||||||
import qs.Config
|
|
||||||
import qs.Helpers
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property var props
|
|
||||||
required property PersistentProperties visibilities
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
|
||||||
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
|
|
||||||
radius: Appearance.rounding.smallest
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: layout
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Appearance.padding.large
|
|
||||||
spacing: Appearance.spacing.normal
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
spacing: Appearance.spacing.normal
|
|
||||||
z: 1
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
color: Recorder.running ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3secondaryContainer
|
|
||||||
implicitHeight: {
|
|
||||||
const h = icon.implicitHeight + Appearance.padding.smaller * 2;
|
|
||||||
return h - (h % 2);
|
|
||||||
}
|
|
||||||
implicitWidth: implicitHeight
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
id: icon
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
anchors.horizontalCenterOffset: -0.5
|
|
||||||
anchors.verticalCenterOffset: 1.5
|
|
||||||
color: Recorder.running ? DynamicColors.palette.m3onSecondary : DynamicColors.palette.m3onSecondaryContainer
|
|
||||||
font.pointSize: Appearance.font.size.large
|
|
||||||
text: "screen_record"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
elide: Text.ElideRight
|
|
||||||
font.pointSize: Appearance.font.size.normal
|
|
||||||
text: qsTr("Screen Recorder")
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
color: DynamicColors.palette.m3onSurfaceVariant
|
|
||||||
elide: Text.ElideRight
|
|
||||||
font.pointSize: Appearance.font.size.small
|
|
||||||
text: Recorder.paused ? qsTr("Recording paused") : Recorder.running ? qsTr("Recording running") : qsTr("Recording off")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomSplitButton {
|
|
||||||
active: menuItems.find(m => root.props.recordingMode === m.icon + m.text) ?? menuItems[0]
|
|
||||||
disabled: Recorder.running
|
|
||||||
|
|
||||||
menuItems: [
|
|
||||||
MenuItem {
|
|
||||||
activeText: qsTr("Fullscreen")
|
|
||||||
icon: "fullscreen"
|
|
||||||
text: qsTr("Record fullscreen")
|
|
||||||
|
|
||||||
onClicked: Recorder.start()
|
|
||||||
},
|
|
||||||
MenuItem {
|
|
||||||
activeText: qsTr("Region")
|
|
||||||
icon: "screenshot_region"
|
|
||||||
text: qsTr("Record region")
|
|
||||||
|
|
||||||
onClicked: Recorder.start(["-r"])
|
|
||||||
},
|
|
||||||
MenuItem {
|
|
||||||
activeText: qsTr("Fullscreen")
|
|
||||||
icon: "select_to_speak"
|
|
||||||
text: qsTr("Record fullscreen with sound")
|
|
||||||
|
|
||||||
onClicked: Recorder.start(["-s"])
|
|
||||||
},
|
|
||||||
MenuItem {
|
|
||||||
activeText: qsTr("Region")
|
|
||||||
icon: "volume_up"
|
|
||||||
text: qsTr("Record region with sound")
|
|
||||||
|
|
||||||
onClicked: Recorder.start(["-s", "-r"])
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
menu.onItemSelected: item => root.props.recordingMode = item.icon + item.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: listOrControls
|
|
||||||
|
|
||||||
property bool running: Recorder.running
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: implicitHeight
|
|
||||||
asynchronous: true
|
|
||||||
sourceComponent: running ? recordingControls : recordingList
|
|
||||||
|
|
||||||
Behavior on Layout.preferredHeight {
|
|
||||||
id: locHeightAnim
|
|
||||||
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on running {
|
|
||||||
SequentialAnimation {
|
|
||||||
ParallelAnimation {
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.small
|
|
||||||
easing: Appearance.anim.curves.standardAccel
|
|
||||||
property: "scale"
|
|
||||||
target: listOrControls
|
|
||||||
to: 0.7
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.small
|
|
||||||
easing: Appearance.anim.curves.standardAccel
|
|
||||||
property: "opacity"
|
|
||||||
target: listOrControls
|
|
||||||
to: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyAction {
|
|
||||||
property: "enabled"
|
|
||||||
target: locHeightAnim
|
|
||||||
value: true
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyAction {
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyAction {
|
|
||||||
property: "enabled"
|
|
||||||
target: locHeightAnim
|
|
||||||
value: false
|
|
||||||
}
|
|
||||||
|
|
||||||
ParallelAnimation {
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.small
|
|
||||||
easing: Appearance.anim.curves.standardDecel
|
|
||||||
property: "scale"
|
|
||||||
target: listOrControls
|
|
||||||
to: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.small
|
|
||||||
easing: Appearance.anim.curves.standardDecel
|
|
||||||
property: "opacity"
|
|
||||||
target: listOrControls
|
|
||||||
to: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: recordingList
|
|
||||||
|
|
||||||
RecordingList {
|
|
||||||
props: root.props
|
|
||||||
visibilities: root.visibilities
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: recordingControls
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
spacing: Appearance.spacing.normal
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
color: Recorder.paused ? DynamicColors.palette.m3tertiary : DynamicColors.palette.m3error
|
|
||||||
implicitHeight: recText.implicitHeight + Appearance.padding.smaller * 2
|
|
||||||
implicitWidth: recText.implicitWidth + Appearance.padding.normal * 2
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
|
|
||||||
Behavior on implicitWidth {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SequentialAnimation on opacity {
|
|
||||||
alwaysRunToEnd: true
|
|
||||||
loops: Animation.Infinite
|
|
||||||
running: !Recorder.paused
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.large
|
|
||||||
easing: Appearance.anim.curves.emphasizedAccel
|
|
||||||
from: 1
|
|
||||||
to: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.extraLarge
|
|
||||||
easing: Appearance.anim.curves.emphasizedDecel
|
|
||||||
from: 0
|
|
||||||
to: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
id: recText
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
animate: true
|
|
||||||
color: Recorder.paused ? DynamicColors.palette.m3onTertiary : DynamicColors.palette.m3onError
|
|
||||||
font.family: Appearance.font.family.mono
|
|
||||||
text: Recorder.paused ? "PAUSED" : "REC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
font.pointSize: Appearance.font.size.normal
|
|
||||||
text: {
|
|
||||||
const elapsed = Recorder.elapsed;
|
|
||||||
|
|
||||||
const hours = Math.floor(elapsed / 3600);
|
|
||||||
const mins = Math.floor((elapsed % 3600) / 60);
|
|
||||||
const secs = Math.floor(elapsed % 60).toString().padStart(2, "0");
|
|
||||||
|
|
||||||
let time;
|
|
||||||
if (hours > 0)
|
|
||||||
time = `${hours}:${mins.toString().padStart(2, "0")}:${secs}`;
|
|
||||||
else
|
|
||||||
time = `${mins}:${secs}`;
|
|
||||||
|
|
||||||
return qsTr("Recording for %1").arg(time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
checked: Recorder.paused
|
|
||||||
font.pointSize: Appearance.font.size.large
|
|
||||||
icon: Recorder.paused ? "play_arrow" : "pause"
|
|
||||||
label.animate: true
|
|
||||||
toggle: true
|
|
||||||
type: IconButton.Tonal
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
Recorder.togglePause();
|
|
||||||
internalChecked = Recorder.paused;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
font.pointSize: Appearance.font.size.large
|
|
||||||
icon: "stop"
|
|
||||||
inactiveColour: DynamicColors.palette.m3error
|
|
||||||
inactiveOnColour: DynamicColors.palette.m3onError
|
|
||||||
|
|
||||||
onClicked: Recorder.stop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Widgets
|
|
||||||
import ZShell.Models
|
|
||||||
import qs.Components
|
|
||||||
import qs.Helpers
|
|
||||||
import qs.Paths
|
|
||||||
import qs.Config
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property var props
|
|
||||||
required property PersistentProperties visibilities
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
WrapperMouseArea {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
|
|
||||||
onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
spacing: Appearance.spacing.smaller
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
font.pointSize: Appearance.font.size.large
|
|
||||||
text: "list"
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
font.pointSize: Appearance.font.size.normal
|
|
||||||
text: qsTr("Recordings")
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
icon: root.props.recordingListExpanded ? "unfold_less" : "unfold_more"
|
|
||||||
label.animate: true
|
|
||||||
type: IconButton.Text
|
|
||||||
|
|
||||||
onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomListView {
|
|
||||||
id: list
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.rightMargin: -Appearance.spacing.small
|
|
||||||
clip: true
|
|
||||||
implicitHeight: (Appearance.font.size.larger + Appearance.padding.small) * (root.props.recordingListExpanded ? 10 : 3)
|
|
||||||
|
|
||||||
CustomScrollBar.vertical: CustomScrollBar {
|
|
||||||
flickable: list
|
|
||||||
}
|
|
||||||
add: Transition {
|
|
||||||
Anim {
|
|
||||||
from: 0
|
|
||||||
property: "opacity"
|
|
||||||
to: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
from: 0.5
|
|
||||||
property: "scale"
|
|
||||||
to: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delegate: RowLayout {
|
|
||||||
id: recording
|
|
||||||
|
|
||||||
property string baseName
|
|
||||||
required property FileSystemEntry modelData
|
|
||||||
|
|
||||||
anchors.left: list.contentItem.left
|
|
||||||
anchors.right: list.contentItem.right
|
|
||||||
anchors.rightMargin: Appearance.spacing.small
|
|
||||||
spacing: Appearance.spacing.small / 2
|
|
||||||
|
|
||||||
Component.onCompleted: baseName = modelData.baseName
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.rightMargin: Appearance.spacing.small / 2
|
|
||||||
color: DynamicColors.palette.m3onSurfaceVariant
|
|
||||||
elide: Text.ElideRight
|
|
||||||
text: {
|
|
||||||
const time = recording.baseName;
|
|
||||||
const matches = time.match(/^recording_(\d{4})(\d{2})(\d{2})_(\d{2})-(\d{2})-(\d{2})/);
|
|
||||||
if (!matches)
|
|
||||||
return time;
|
|
||||||
const date = new Date(...matches.slice(1));
|
|
||||||
date.setMonth(date.getMonth() - 1);
|
|
||||||
return qsTr("Recording at %1").arg(Qt.formatDateTime(date, Qt.locale()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
icon: "play_arrow"
|
|
||||||
type: IconButton.Text
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
root.visibilities.sidebar = false;
|
|
||||||
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
icon: "folder"
|
|
||||||
type: IconButton.Text
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
root.visibilities.sidebar = false;
|
|
||||||
Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
displaced: Transition {
|
|
||||||
Anim {
|
|
||||||
properties: "opacity,scale"
|
|
||||||
to: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
property: "y"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on implicitHeight {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
model: FileSystemModel {
|
|
||||||
nameFilters: ["recording_*.mp4"]
|
|
||||||
path: Paths.recsdir
|
|
||||||
sortReverse: true
|
|
||||||
}
|
|
||||||
remove: Transition {
|
|
||||||
Anim {
|
|
||||||
property: "opacity"
|
|
||||||
to: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Anim {
|
|
||||||
property: "scale"
|
|
||||||
to: 0.5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
active: opacity > 0
|
|
||||||
anchors.centerIn: parent
|
|
||||||
asynchronous: true
|
|
||||||
opacity: list.count === 0 ? 1 : 0
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sourceComponent: ColumnLayout {
|
|
||||||
spacing: Appearance.spacing.small
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
Layout.preferredHeight: root.props.recordingListExpanded ? implicitHeight : 0
|
|
||||||
color: DynamicColors.palette.m3outline
|
|
||||||
font.pointSize: Appearance.font.size.extraLarge
|
|
||||||
opacity: root.props.recordingListExpanded ? 1 : 0
|
|
||||||
scale: root.props.recordingListExpanded ? 1 : 0
|
|
||||||
text: "scan_delete"
|
|
||||||
|
|
||||||
Behavior on Layout.preferredHeight {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on scale {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
spacing: Appearance.spacing.smaller
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
Layout.preferredWidth: !root.props.recordingListExpanded ? implicitWidth : 0
|
|
||||||
color: DynamicColors.palette.m3outline
|
|
||||||
opacity: !root.props.recordingListExpanded ? 1 : 0
|
|
||||||
scale: !root.props.recordingListExpanded ? 1 : 0
|
|
||||||
text: "scan_delete"
|
|
||||||
|
|
||||||
Behavior on Layout.preferredWidth {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on scale {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
color: DynamicColors.palette.m3outline
|
|
||||||
text: qsTr("No recordings found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
import Quickshell
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import qs.Modules.Notifications.Sidebar.Utils.Cards
|
import qs.Modules.Notifications.Sidebar.Utils.Cards
|
||||||
import qs.Config
|
import qs.Config
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property Item popouts
|
required property Item popouts
|
||||||
required property PersistentProperties props
|
required property var props
|
||||||
required property var visibilities
|
required property var visibilities
|
||||||
|
|
||||||
implicitHeight: layout.implicitHeight
|
implicitHeight: layout.implicitHeight
|
||||||
@@ -23,12 +22,6 @@ Item {
|
|||||||
IdleInhibit {
|
IdleInhibit {
|
||||||
}
|
}
|
||||||
|
|
||||||
Record {
|
|
||||||
props: root.props
|
|
||||||
visibilities: root.visibilities
|
|
||||||
z: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Toggles {
|
Toggles {
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
|
|||||||
@@ -100,15 +100,13 @@ Item {
|
|||||||
icon: `brightness_${(Math.round(value * 6) + 1)}`
|
icon: `brightness_${(Math.round(value * 6) + 1)}`
|
||||||
value: root.brightness
|
value: root.brightness
|
||||||
|
|
||||||
onPressedChanged: {
|
onMoved: {
|
||||||
if (!pressed) {
|
|
||||||
if (Config.osd.allMonBrightness) {
|
if (Config.osd.allMonBrightness) {
|
||||||
|
root.monitor?.setBrightness(value);
|
||||||
|
} else {
|
||||||
for (const mon of Brightness.monitors) {
|
for (const mon of Brightness.monitors) {
|
||||||
mon.setBrightness(value);
|
mon.setBrightness(value);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
root.monitor?.setBrightness(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,12 +116,6 @@ Item {
|
|||||||
key: "updates"
|
key: "updates"
|
||||||
name: "Updates"
|
name: "Updates"
|
||||||
}
|
}
|
||||||
|
|
||||||
ListElement {
|
|
||||||
icon: "extension"
|
|
||||||
key: "plugins"
|
|
||||||
name: "Extensions"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomClippingRect {
|
CustomClippingRect {
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 0
|
|
||||||
name: "Media update interval"
|
name: "Media update interval"
|
||||||
|
min: 0
|
||||||
object: Config.dashboard
|
object: Config.dashboard
|
||||||
setting: "mediaUpdateInterval"
|
setting: "mediaUpdateInterval"
|
||||||
step: 50
|
step: 50
|
||||||
@@ -30,8 +30,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 0
|
|
||||||
name: "Resource update interval"
|
name: "Resource update interval"
|
||||||
|
min: 0
|
||||||
object: Config.dashboard
|
object: Config.dashboard
|
||||||
setting: "resourceUpdateInterval"
|
setting: "resourceUpdateInterval"
|
||||||
step: 50
|
step: 50
|
||||||
@@ -41,8 +41,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 0
|
|
||||||
name: "Drag threshold"
|
name: "Drag threshold"
|
||||||
|
min: 0
|
||||||
object: Config.dashboard
|
object: Config.dashboard
|
||||||
setting: "dragThreshold"
|
setting: "dragThreshold"
|
||||||
}
|
}
|
||||||
@@ -107,112 +107,112 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SettingsSection {
|
SettingsSection {
|
||||||
// sectionId: "Layout Sizes"
|
sectionId: "Layout Sizes"
|
||||||
//
|
|
||||||
// SettingsHeader {
|
SettingsHeader {
|
||||||
// name: "Layout Sizes"
|
name: "Layout Sizes"
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Tab indicator height"
|
name: "Tab indicator height"
|
||||||
// value: String(Config.dashboard.sizes.tabIndicatorHeight)
|
value: String(Config.dashboard.sizes.tabIndicatorHeight)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Tab indicator spacing"
|
name: "Tab indicator spacing"
|
||||||
// value: String(Config.dashboard.sizes.tabIndicatorSpacing)
|
value: String(Config.dashboard.sizes.tabIndicatorSpacing)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Info width"
|
name: "Info width"
|
||||||
// value: String(Config.dashboard.sizes.infoWidth)
|
value: String(Config.dashboard.sizes.infoWidth)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Info icon size"
|
name: "Info icon size"
|
||||||
// value: String(Config.dashboard.sizes.infoIconSize)
|
value: String(Config.dashboard.sizes.infoIconSize)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Date time width"
|
name: "Date time width"
|
||||||
// value: String(Config.dashboard.sizes.dateTimeWidth)
|
value: String(Config.dashboard.sizes.dateTimeWidth)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Media width"
|
name: "Media width"
|
||||||
// value: String(Config.dashboard.sizes.mediaWidth)
|
value: String(Config.dashboard.sizes.mediaWidth)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Media progress sweep"
|
name: "Media progress sweep"
|
||||||
// value: String(Config.dashboard.sizes.mediaProgressSweep)
|
value: String(Config.dashboard.sizes.mediaProgressSweep)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Media progress thickness"
|
name: "Media progress thickness"
|
||||||
// value: String(Config.dashboard.sizes.mediaProgressThickness)
|
value: String(Config.dashboard.sizes.mediaProgressThickness)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Resource progress thickness"
|
name: "Resource progress thickness"
|
||||||
// value: String(Config.dashboard.sizes.resourceProgessThickness)
|
value: String(Config.dashboard.sizes.resourceProgessThickness)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Weather width"
|
name: "Weather width"
|
||||||
// value: String(Config.dashboard.sizes.weatherWidth)
|
value: String(Config.dashboard.sizes.weatherWidth)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Media cover art size"
|
name: "Media cover art size"
|
||||||
// value: String(Config.dashboard.sizes.mediaCoverArtSize)
|
value: String(Config.dashboard.sizes.mediaCoverArtSize)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Media visualiser size"
|
name: "Media visualiser size"
|
||||||
// value: String(Config.dashboard.sizes.mediaVisualiserSize)
|
value: String(Config.dashboard.sizes.mediaVisualiserSize)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// SettingReadOnly {
|
SettingReadOnly {
|
||||||
// name: "Resource size"
|
name: "Resource size"
|
||||||
// value: String(Config.dashboard.sizes.resourceSize)
|
value: String(Config.dashboard.sizes.resourceSize)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,18 +103,6 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSection {
|
|
||||||
sectionId: "Greeter"
|
|
||||||
|
|
||||||
SettingsHeader {
|
|
||||||
name: "Greeter"
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsIconButton {
|
|
||||||
name: "Install wallpaper and color scheme to greeter"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsSection {
|
SettingsSection {
|
||||||
sectionId: "Idle"
|
sectionId: "Idle"
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import qs.Modules.Settings.Controls
|
|||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool shouldBeActive: true
|
|
||||||
|
|
||||||
function addTimeoutEntry() {
|
function addTimeoutEntry() {
|
||||||
let list = [...Config.general.idle.timeouts];
|
let list = [...Config.general.idle.timeouts];
|
||||||
|
|
||||||
@@ -42,26 +40,8 @@ ColumnLayout {
|
|||||||
Config.save();
|
Config.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors.left: parent.left
|
Layout.fillWidth: true
|
||||||
anchors.right: parent.right
|
|
||||||
height: shouldBeActive ? implicitHeight : 0
|
|
||||||
opacity: shouldBeActive ? 1 : 0
|
|
||||||
scale: shouldBeActive ? 1 : 0.8
|
|
||||||
spacing: Appearance.spacing.smaller
|
spacing: Appearance.spacing.smaller
|
||||||
visible: opacity > 0
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on scale {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on y {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
name: "Idle Monitors"
|
name: "Idle Monitors"
|
||||||
@@ -72,8 +52,6 @@ ColumnLayout {
|
|||||||
|
|
||||||
SettingList {
|
SettingList {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
anchors.left: undefined
|
|
||||||
anchors.right: undefined
|
|
||||||
|
|
||||||
onAddActiveActionRequested: {
|
onAddActiveActionRequested: {
|
||||||
root.updateTimeoutEntry(index, "activeAction", "");
|
root.updateTimeoutEntry(index, "activeAction", "");
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import qs.Modules.Settings.Controls
|
|
||||||
import qs.Config
|
|
||||||
|
|
||||||
SettingsPage {
|
|
||||||
SettingsSection {
|
|
||||||
sectionId: "Plugins"
|
|
||||||
|
|
||||||
SettingsHeader {
|
|
||||||
name: "Plugins"
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingBarEntryList {
|
|
||||||
name: "Enable or disable plugins"
|
|
||||||
object: Config.plugins
|
|
||||||
setting: "entries"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -43,7 +43,7 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
visible: Config.screenshot.mode === "manual"
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
@@ -51,34 +51,34 @@ SettingsPage {
|
|||||||
name: "Corner radius"
|
name: "Corner radius"
|
||||||
object: Config.screenshot
|
object: Config.screenshot
|
||||||
setting: "corner_radius"
|
setting: "corner_radius"
|
||||||
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
step: 1
|
step: 1
|
||||||
visible: Config.screenshot.mode === "manual"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
visible: Config.screenshot.mode === "manual"
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Enable drop shadow"
|
name: "Enable drop shadow"
|
||||||
object: Config.screenshot
|
object: Config.screenshot
|
||||||
setting: "drop_shadow"
|
setting: "drop_shadow"
|
||||||
visible: Config.screenshot.mode === "manual"
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
visible: Config.screenshot.mode === "manual"
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Enable rounded corners"
|
name: "Enable rounded corners"
|
||||||
object: Config.screenshot
|
object: Config.screenshot
|
||||||
setting: "rounded_corners"
|
setting: "rounded_corners"
|
||||||
visible: Config.screenshot.mode === "manual"
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
visible: Config.screenshot.mode === "manual"
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
@@ -86,23 +86,36 @@ SettingsPage {
|
|||||||
name: "Shadow blur radius"
|
name: "Shadow blur radius"
|
||||||
object: Config.screenshot
|
object: Config.screenshot
|
||||||
setting: "shadow_blur_radius"
|
setting: "shadow_blur_radius"
|
||||||
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
step: 1
|
step: 1
|
||||||
visible: Config.screenshot.mode === "manual"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
visible: Config.screenshot.mode === "manual"
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Shadow color broken atm"
|
name: "Shadow color broken atm"
|
||||||
object: Config.Screenshot
|
object: Config.Screenshot
|
||||||
setting: "shadow_color"
|
setting: "shadow_color"
|
||||||
visible: Config.screenshot.mode === "manual"
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
visible: Config.screenshot.mode === "manual"
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSpinBox {
|
||||||
|
min: 1
|
||||||
|
name: "Shadow passes"
|
||||||
|
object: Config.screenshot
|
||||||
|
setting: "shadow_blur_passes"
|
||||||
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
|
step: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
@@ -110,12 +123,12 @@ SettingsPage {
|
|||||||
name: "Shadow offset X"
|
name: "Shadow offset X"
|
||||||
object: Config.screenshot
|
object: Config.screenshot
|
||||||
setting: "shadow_offset_x"
|
setting: "shadow_offset_x"
|
||||||
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
step: 1
|
step: 1
|
||||||
visible: Config.screenshot.mode === "manual"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
visible: Config.screenshot.mode === "manual"
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
@@ -123,8 +136,8 @@ SettingsPage {
|
|||||||
name: "Shadow offset Y"
|
name: "Shadow offset Y"
|
||||||
object: Config.screenshot
|
object: Config.screenshot
|
||||||
setting: "shadow_offset_y"
|
setting: "shadow_offset_y"
|
||||||
|
shouldBeActive: Config.screenshot.mode === "manual"
|
||||||
step: 1
|
step: 1
|
||||||
visible: Config.screenshot.mode === "manual"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 1
|
|
||||||
name: "Max toasts"
|
name: "Max toasts"
|
||||||
|
min: 1
|
||||||
object: Config.utilities
|
object: Config.utilities
|
||||||
setting: "maxToasts"
|
setting: "maxToasts"
|
||||||
}
|
}
|
||||||
@@ -29,8 +29,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 1
|
|
||||||
name: "Panel width"
|
name: "Panel width"
|
||||||
|
min: 1
|
||||||
object: Config.utilities.sizes
|
object: Config.utilities.sizes
|
||||||
setting: "width"
|
setting: "width"
|
||||||
}
|
}
|
||||||
@@ -39,8 +39,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
min: 1
|
|
||||||
name: "Toast width"
|
name: "Toast width"
|
||||||
|
min: 1
|
||||||
object: Config.utilities.sizes
|
object: Config.utilities.sizes
|
||||||
setting: "toastWidth"
|
setting: "toastWidth"
|
||||||
}
|
}
|
||||||
@@ -77,100 +77,100 @@ SettingsPage {
|
|||||||
setting: "gameModeChanged"
|
setting: "gameModeChanged"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separator {
|
Separator {
|
||||||
// }
|
|
||||||
//
|
|
||||||
// SettingSwitch {
|
|
||||||
// name: "Do not disturb changed"
|
|
||||||
// object: Config.utilities.toasts
|
|
||||||
// setting: "dndChanged"
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Separator {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// SettingSwitch {
|
|
||||||
// name: "Audio output changed"
|
|
||||||
// object: Config.utilities.toasts
|
|
||||||
// setting: "audioOutputChanged"
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Separator {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// SettingSwitch {
|
|
||||||
// name: "Audio input changed"
|
|
||||||
// object: Config.utilities.toasts
|
|
||||||
// setting: "audioInputChanged"
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Separator {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// SettingSwitch {
|
|
||||||
// name: "Caps lock changed"
|
|
||||||
// object: Config.utilities.toasts
|
|
||||||
// setting: "capsLockChanged"
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Separator {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// SettingSwitch {
|
|
||||||
// name: "Num lock changed"
|
|
||||||
// object: Config.utilities.toasts
|
|
||||||
// setting: "numLockChanged"
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Separator {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// SettingSwitch {
|
|
||||||
// name: "Keyboard layout changed"
|
|
||||||
// object: Config.utilities.toasts
|
|
||||||
// setting: "kbLayoutChanged"
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Separator {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// SettingSwitch {
|
|
||||||
// name: "VPN changed"
|
|
||||||
// object: Config.utilities.toasts
|
|
||||||
// setting: "vpnChanged"
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Separator {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// SettingSwitch {
|
|
||||||
// name: "Now playing"
|
|
||||||
// object: Config.utilities.toasts
|
|
||||||
// setting: "nowPlaying"
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SettingsSection {
|
SettingSwitch {
|
||||||
// sectionId: "VPN"
|
name: "Do not disturb changed"
|
||||||
//
|
object: Config.utilities.toasts
|
||||||
// SettingsHeader {
|
setting: "dndChanged"
|
||||||
// name: "VPN"
|
}
|
||||||
// }
|
|
||||||
//
|
Separator {
|
||||||
// SettingSwitch {
|
}
|
||||||
// name: "Enable VPN integration"
|
|
||||||
// object: Config.utilities.vpn
|
SettingSwitch {
|
||||||
// setting: "enabled"
|
name: "Audio output changed"
|
||||||
// }
|
object: Config.utilities.toasts
|
||||||
//
|
setting: "audioOutputChanged"
|
||||||
// Separator {
|
}
|
||||||
// }
|
|
||||||
//
|
Separator {
|
||||||
// SettingStringList {
|
}
|
||||||
// name: "Provider"
|
|
||||||
// addLabel: qsTr("Add VPN provider")
|
SettingSwitch {
|
||||||
// object: Config.utilities.vpn
|
name: "Audio input changed"
|
||||||
// setting: "provider"
|
object: Config.utilities.toasts
|
||||||
// }
|
setting: "audioInputChanged"
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Caps lock changed"
|
||||||
|
object: Config.utilities.toasts
|
||||||
|
setting: "capsLockChanged"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Num lock changed"
|
||||||
|
object: Config.utilities.toasts
|
||||||
|
setting: "numLockChanged"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Keyboard layout changed"
|
||||||
|
object: Config.utilities.toasts
|
||||||
|
setting: "kbLayoutChanged"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "VPN changed"
|
||||||
|
object: Config.utilities.toasts
|
||||||
|
setting: "vpnChanged"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Now playing"
|
||||||
|
object: Config.utilities.toasts
|
||||||
|
setting: "nowPlaying"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsSection {
|
||||||
|
sectionId: "VPN"
|
||||||
|
|
||||||
|
SettingsHeader {
|
||||||
|
name: "VPN"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Enable VPN integration"
|
||||||
|
object: Config.utilities.vpn
|
||||||
|
setting: "enabled"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingStringList {
|
||||||
|
name: "Provider"
|
||||||
|
addLabel: qsTr("Add VPN provider")
|
||||||
|
object: Config.utilities.vpn
|
||||||
|
setting: "provider"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,8 +79,6 @@ Item {
|
|||||||
stack.push(screenshot);
|
stack.push(screenshot);
|
||||||
else if (currentCategory === "updates")
|
else if (currentCategory === "updates")
|
||||||
stack.push(updates);
|
stack.push(updates);
|
||||||
else if (currentCategory === "plugins")
|
|
||||||
stack.push(plugins);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
target: root
|
target: root
|
||||||
@@ -247,11 +245,4 @@ Item {
|
|||||||
Cat.SystemUpdates {
|
Cat.SystemUpdates {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
|
||||||
id: plugins
|
|
||||||
|
|
||||||
Cat.Plugins {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,9 +127,6 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
Layout.fillWidth: true
|
|
||||||
anchors.left: undefined
|
|
||||||
anchors.right: undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -210,8 +207,6 @@ ColumnLayout {
|
|||||||
StringListEditor {
|
StringListEditor {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
addLabel: qsTr("Add command argument")
|
addLabel: qsTr("Add command argument")
|
||||||
anchors.left: undefined
|
|
||||||
anchors.right: undefined
|
|
||||||
values: [...(modelData.command ?? [])]
|
values: [...(modelData.command ?? [])]
|
||||||
|
|
||||||
onListEdited: function (values) {
|
onListEdited: function (values) {
|
||||||
@@ -220,9 +215,6 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
Layout.fillWidth: true
|
|
||||||
anchors.left: undefined
|
|
||||||
anchors.right: undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -241,9 +233,6 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
Layout.fillWidth: true
|
|
||||||
anchors.left: undefined
|
|
||||||
anchors.right: undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import qs.Components
|
|||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
|
|
||||||
CustomRect {
|
ColumnLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
|
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
|
||||||
@@ -43,9 +43,10 @@ CustomRect {
|
|||||||
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
height: shouldBeActive ? layout.implicitHeight : 0
|
height: shouldBeActive ? implicitHeight : 0
|
||||||
opacity: shouldBeActive ? 1 : 0
|
opacity: shouldBeActive ? 1 : 0
|
||||||
scale: shouldBeActive ? 1 : 0.8
|
scale: shouldBeActive ? 1 : 0.8
|
||||||
|
spacing: Appearance.spacing.smaller
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
@@ -76,14 +77,6 @@ CustomRect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: layout
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Appearance.spacing.smaller
|
|
||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
font.pointSize: Appearance.font.size.larger
|
font.pointSize: Appearance.font.size.larger
|
||||||
@@ -128,17 +121,15 @@ CustomRect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 33
|
Layout.preferredHeight: 33
|
||||||
Layout.preferredWidth: Math.max(Math.min(fromTextField.contentWidth + Appearance.padding.large * 2, 550), 50)
|
|
||||||
color: DynamicColors.tPalette.m3surfaceContainerHigh
|
color: DynamicColors.tPalette.m3surfaceContainerHigh
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
CustomTextField {
|
CustomTextField {
|
||||||
id: fromTextField
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.normal
|
||||||
anchors.centerIn: parent
|
anchors.rightMargin: Appearance.padding.normal
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, 550)
|
|
||||||
text: modelData.from ?? ""
|
text: modelData.from ?? ""
|
||||||
|
|
||||||
onEditingFinished: root.updateAlias(index, "from", text)
|
onEditingFinished: root.updateAlias(index, "from", text)
|
||||||
@@ -163,17 +154,15 @@ CustomRect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 33
|
Layout.preferredHeight: 33
|
||||||
Layout.preferredWidth: Math.max(Math.min(toTextField.contentWidth + Appearance.padding.large * 2, 550), 50)
|
color: DynamicColors.tPalette.m3surface
|
||||||
color: DynamicColors.tPalette.m3surfaceContainerHigh
|
radius: Appearance.rounding.small
|
||||||
radius: Appearance.rounding.full
|
|
||||||
|
|
||||||
CustomTextField {
|
CustomTextField {
|
||||||
id: toTextField
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Appearance.padding.normal
|
||||||
anchors.centerIn: parent
|
anchors.rightMargin: Appearance.padding.normal
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, 550)
|
|
||||||
text: modelData.to ?? ""
|
text: modelData.to ?? ""
|
||||||
|
|
||||||
onEditingFinished: root.updateAlias(index, "to", text)
|
onEditingFinished: root.updateAlias(index, "to", text)
|
||||||
@@ -200,4 +189,3 @@ CustomRect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -194,9 +194,6 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
Layout.fillWidth: true
|
|
||||||
anchors.left: undefined
|
|
||||||
anchors.right: undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -228,9 +225,6 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
Layout.fillWidth: true
|
|
||||||
anchors.left: undefined
|
|
||||||
anchors.right: undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import qs.Paths
|
|
||||||
import qs.Components
|
|
||||||
import qs.Config
|
|
||||||
import qs.Helpers
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property alias button: iButton
|
|
||||||
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
|
|
||||||
required property string name
|
|
||||||
property bool shouldBeActive: true
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
|
|
||||||
opacity: shouldBeActive ? 1 : 0
|
|
||||||
scale: shouldBeActive ? 1 : 0.8
|
|
||||||
visible: opacity > 0
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on scale {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on y {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: -Appearance.padding.smaller
|
|
||||||
color: DynamicColors.palette.m3primaryContainer
|
|
||||||
opacity: root.highlighted ? 0.5 : 0
|
|
||||||
radius: Appearance.rounding.small
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {
|
|
||||||
duration: Appearance.anim.durations.normal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: row
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.margins: Appearance.padding.small
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
id: text
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
font.pointSize: Appearance.font.size.larger
|
|
||||||
text: root.name
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
id: iButton
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
|
||||||
icon: "download"
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
const lockBg = `${Paths.state}/lockscreen_bg.png`;
|
|
||||||
const scheme = `${Paths.state}/scheme.json`;
|
|
||||||
const face = `${Paths.home}/.face`;
|
|
||||||
const destination = "/etc/zshell-greeter/images";
|
|
||||||
Quickshell.execDetached(["pkexec", "sh", "-c", `mkdir -p ${destination}; cp ${lockBg} ${destination}; cp ${scheme} /etc/zshell-greeter; cp ${face} ${destination}`]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,18 @@
|
|||||||
#include "hyprextras.hpp"
|
#include "hyprextras.hpp"
|
||||||
#include "hyprdevices.hpp"
|
#include "hyprdevices.hpp"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <qdir.h>
|
#include <qdir.h>
|
||||||
|
#include <qcolor.h>
|
||||||
#include <qjsonarray.h>
|
#include <qjsonarray.h>
|
||||||
|
#include <qjsondocument.h>
|
||||||
|
#include <qjsonobject.h>
|
||||||
#include <qlocalsocket.h>
|
#include <qlocalsocket.h>
|
||||||
#include <qloggingcategory.h>
|
#include <qloggingcategory.h>
|
||||||
#include <qmetatype.h>
|
#include <qmetatype.h>
|
||||||
|
#include <qobject.h>
|
||||||
#include <qregularexpression.h>
|
#include <qregularexpression.h>
|
||||||
#include <qvariant.h>
|
#include <qvariant.h>
|
||||||
|
|
||||||
@@ -163,6 +170,86 @@ static QString buildHlConfigCall(const QString& key, const QVariant& value) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QColor colorFromInt(quint32 value) {
|
||||||
|
const int a = (value >> 24) & 0xFF;
|
||||||
|
const int r = (value >> 16) & 0xFF;
|
||||||
|
const int g = (value >> 8) & 0xFF;
|
||||||
|
const int b = value & 0xFF;
|
||||||
|
|
||||||
|
return QColor(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QVariant parseGetOptionValue(const QJsonObject& obj) {
|
||||||
|
if (obj.contains(QStringLiteral("bool"))) {
|
||||||
|
return obj.value(QStringLiteral("bool")).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.contains(QStringLiteral("int"))) {
|
||||||
|
const auto value = obj.value(QStringLiteral("int")).toInt();
|
||||||
|
|
||||||
|
const auto option = obj.value(QStringLiteral("option")).toString();
|
||||||
|
|
||||||
|
if (option.contains(QStringLiteral("color")) || option.contains(QStringLiteral("col."))) {
|
||||||
|
return colorFromInt(static_cast<quint32>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.contains(QStringLiteral("float"))) {
|
||||||
|
return obj.value(QStringLiteral("float")).toDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.contains(QStringLiteral("str"))) {
|
||||||
|
return obj.value(QStringLiteral("str")).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.contains(QStringLiteral("current"))) {
|
||||||
|
return obj.value(QStringLiteral("current")).toVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.contains(QStringLiteral("value"))) {
|
||||||
|
return obj.value(QStringLiteral("value")).toVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.contains(QStringLiteral("vec2"))) {
|
||||||
|
return obj.value(QStringLiteral("vec2")).toVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.contains(QStringLiteral("data"))) {
|
||||||
|
const auto data = obj.value(QStringLiteral("data"));
|
||||||
|
if (data.isObject()) {
|
||||||
|
const auto d = data.toObject();
|
||||||
|
if (d.contains(QStringLiteral("current"))) {
|
||||||
|
return d.value(QStringLiteral("current")).toVariant();
|
||||||
|
}
|
||||||
|
if (d.contains(QStringLiteral("value"))) {
|
||||||
|
return d.value(QStringLiteral("value")).toVariant();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return data.toVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insertNestedValue(QVariantMap& root, const QStringList& path, const QVariant& value) {
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.size() == 1) {
|
||||||
|
root.insert(path.first(), value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString head = path.first();
|
||||||
|
QVariantMap child = root.value(head).toMap();
|
||||||
|
insertNestedValue(child, path.mid(1), value);
|
||||||
|
root.insert(head, child);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
HyprExtras::HyprExtras(QObject* parent)
|
HyprExtras::HyprExtras(QObject* parent)
|
||||||
@@ -203,7 +290,7 @@ HyprExtras::HyprExtras(QObject* parent)
|
|||||||
m_socket->connectToServer(m_eventSocket, QLocalSocket::ReadOnly);
|
m_socket->connectToServer(m_eventSocket, QLocalSocket::ReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantHash HyprExtras::options() const {
|
QVariantMap HyprExtras::options() const {
|
||||||
return m_options;
|
return m_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,30 +356,64 @@ void HyprExtras::refreshOptions() {
|
|||||||
m_optionsRefresh->close();
|
m_optionsRefresh->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_optionsRefresh = makeRequestJson(QStringLiteral("descriptions"), [this](bool success, const QJsonDocument& response) {
|
++m_optionsRefreshGeneration;
|
||||||
m_optionsRefresh.reset();
|
const quint64 generation = m_optionsRefreshGeneration;
|
||||||
if (!success) {
|
|
||||||
|
static const QStringList optionKeys = {
|
||||||
|
QStringLiteral("general:border_size"),
|
||||||
|
QStringLiteral("decoration:rounding"),
|
||||||
|
QStringLiteral("animations:enabled"),
|
||||||
|
QStringLiteral("decoration:shadow:enabled"),
|
||||||
|
QStringLiteral("decoration:shadow:offset"),
|
||||||
|
QStringLiteral("decoration:shadow:color"),
|
||||||
|
QStringLiteral("decoration:shadow:range"),
|
||||||
|
QStringLiteral("decoration:shadow:render_power"),
|
||||||
|
};
|
||||||
|
|
||||||
|
auto nextOptions = std::make_shared<QVariantMap>();
|
||||||
|
|
||||||
|
auto step = std::make_shared<std::function<void(int)> >();
|
||||||
|
*step = [this, generation, nextOptions, step](int index) {
|
||||||
|
if (generation != m_optionsRefreshGeneration) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto options = response.array();
|
if (index >= optionKeys.size()) {
|
||||||
bool dirty = false;
|
if (m_options != *nextOptions) {
|
||||||
|
m_options = *nextOptions;
|
||||||
for (const auto& o : std::as_const(options)) {
|
|
||||||
const auto obj = o.toObject();
|
|
||||||
const auto key = obj.value(QStringLiteral("value")).toString();
|
|
||||||
const auto value = obj.value(QStringLiteral("data")).toObject().value(QStringLiteral("current")).toVariant();
|
|
||||||
|
|
||||||
if (m_options.value(key) != value) {
|
|
||||||
dirty = true;
|
|
||||||
m_options.insert(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dirty) {
|
|
||||||
emit optionsChanged();
|
emit optionsChanged();
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString key = optionKeys.at(index);
|
||||||
|
|
||||||
|
m_optionsRefresh = makeRequestJson(
|
||||||
|
QStringLiteral("getoption ") + key,
|
||||||
|
[this, generation, nextOptions, step, index, key](bool success, const QJsonDocument& response)
|
||||||
|
{
|
||||||
|
m_optionsRefresh.reset();
|
||||||
|
|
||||||
|
if (generation != m_optionsRefreshGeneration) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success && response.isObject()) {
|
||||||
|
const QVariant value = parseGetOptionValue(response.object());
|
||||||
|
if (value.isValid()) {
|
||||||
|
insertNestedValue(*nextOptions, key.split(QLatin1Char(':'), Qt::SkipEmptyParts), value);
|
||||||
|
} else {
|
||||||
|
qCWarning(lcHypr) << "refreshOptions: getoption returned no usable value for" << key;
|
||||||
|
}
|
||||||
|
} else if (!success) {
|
||||||
|
qCWarning(lcHypr) << "refreshOptions: getoption request error for" << key;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*step)(index + 1);
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
(*step)(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyprExtras::refreshDevices() {
|
void HyprExtras::refreshDevices() {
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <qjsondocument.h>
|
||||||
#include <qlocalsocket.h>
|
#include <qlocalsocket.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qqmlintegration.h>
|
#include <qqmlintegration.h>
|
||||||
#include <qsharedpointer.h>
|
#include <qsharedpointer.h>
|
||||||
|
#include <qstringlist.h>
|
||||||
#include <qvariant.h>
|
#include <qvariant.h>
|
||||||
|
|
||||||
namespace ZShell::internal::hypr {
|
namespace ZShell::internal::hypr {
|
||||||
@@ -15,13 +19,13 @@ Q_OBJECT
|
|||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
Q_MOC_INCLUDE("hyprdevices.hpp")
|
Q_MOC_INCLUDE("hyprdevices.hpp")
|
||||||
|
|
||||||
Q_PROPERTY(QVariantHash options READ options NOTIFY optionsChanged)
|
Q_PROPERTY(QVariantMap options READ options NOTIFY optionsChanged)
|
||||||
Q_PROPERTY(ZShell::internal::hypr::HyprDevices* devices READ devices CONSTANT)
|
Q_PROPERTY(ZShell::internal::hypr::HyprDevices* devices READ devices CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit HyprExtras(QObject* parent = nullptr);
|
explicit HyprExtras(QObject* parent = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] QVariantHash options() const;
|
[[nodiscard]] QVariantMap options() const;
|
||||||
[[nodiscard]] HyprDevices* devices() const;
|
[[nodiscard]] HyprDevices* devices() const;
|
||||||
|
|
||||||
Q_INVOKABLE void message(const QString& message);
|
Q_INVOKABLE void message(const QString& message);
|
||||||
@@ -42,11 +46,12 @@ QString m_eventSocket;
|
|||||||
QLocalSocket* m_socket;
|
QLocalSocket* m_socket;
|
||||||
bool m_socketValid;
|
bool m_socketValid;
|
||||||
|
|
||||||
QVariantHash m_options;
|
QVariantMap m_options;
|
||||||
HyprDevices* const m_devices;
|
HyprDevices* const m_devices;
|
||||||
|
|
||||||
SocketPtr m_optionsRefresh;
|
SocketPtr m_optionsRefresh;
|
||||||
SocketPtr m_devicesRefresh;
|
SocketPtr m_devicesRefresh;
|
||||||
|
quint64 m_optionsRefreshGeneration = 0;
|
||||||
|
|
||||||
void socketError(QLocalSocket::LocalSocketError error) const;
|
void socketError(QLocalSocket::LocalSocketError error) const;
|
||||||
void socketStateChanged(QLocalSocket::LocalSocketState state);
|
void socketStateChanged(QLocalSocket::LocalSocketState state);
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ FileSystemEntry::FileSystemEntry(const QString& path, const QString& relativePat
|
|||||||
, m_path(path)
|
, m_path(path)
|
||||||
, m_relativePath(relativePath)
|
, m_relativePath(relativePath)
|
||||||
, m_isImageInitialised(false)
|
, m_isImageInitialised(false)
|
||||||
, m_mimeTypeInitialised(false) {
|
, m_mimeTypeInitialised(false) {}
|
||||||
}
|
|
||||||
|
|
||||||
QString FileSystemEntry::path() const {
|
QString FileSystemEntry::path() const {
|
||||||
return m_path;
|
return m_path;
|
||||||
@@ -58,8 +57,8 @@ bool FileSystemEntry::isImage() const {
|
|||||||
|
|
||||||
QString FileSystemEntry::mimeType() const {
|
QString FileSystemEntry::mimeType() const {
|
||||||
if (!m_mimeTypeInitialised) {
|
if (!m_mimeTypeInitialised) {
|
||||||
static const QMimeDatabase s_db;
|
const QMimeDatabase db;
|
||||||
m_mimeType = s_db.mimeTypeForFile(m_path).name();
|
m_mimeType = db.mimeTypeForFile(m_path).name();
|
||||||
m_mimeTypeInitialised = true;
|
m_mimeTypeInitialised = true;
|
||||||
}
|
}
|
||||||
return m_mimeType;
|
return m_mimeType;
|
||||||
@@ -220,7 +219,7 @@ void FileSystemModel::watchDirIfRecursive(const QString& path) {
|
|||||||
if (m_recursive && m_watchChanges) {
|
if (m_recursive && m_watchChanges) {
|
||||||
const auto currentDir = m_dir;
|
const auto currentDir = m_dir;
|
||||||
const bool showHidden = m_showHidden;
|
const bool showHidden = m_showHidden;
|
||||||
auto future = QtConcurrent::run([showHidden, path]() {
|
const auto future = QtConcurrent::run([showHidden, path]() {
|
||||||
QDir::Filters filters = QDir::Dirs | QDir::NoDotAndDotDot;
|
QDir::Filters filters = QDir::Dirs | QDir::NoDotAndDotDot;
|
||||||
if (showHidden) {
|
if (showHidden) {
|
||||||
filters |= QDir::Hidden;
|
filters |= QDir::Hidden;
|
||||||
@@ -233,12 +232,16 @@ void FileSystemModel::watchDirIfRecursive(const QString& path) {
|
|||||||
}
|
}
|
||||||
return dirs;
|
return dirs;
|
||||||
});
|
});
|
||||||
future.then(this, [currentDir, showHidden, this](const QStringList& paths) {
|
const auto watcher = new QFutureWatcher<QStringList>(this);
|
||||||
|
connect(watcher, &QFutureWatcher<QStringList>::finished, this, [currentDir, showHidden, watcher, this]() {
|
||||||
|
const auto paths = watcher->result();
|
||||||
if (currentDir == m_dir && showHidden == m_showHidden && !paths.isEmpty()) {
|
if (currentDir == m_dir && showHidden == m_showHidden && !paths.isEmpty()) {
|
||||||
// Ignore if dir or showHidden has changed
|
// Ignore if dir or showHidden has changed
|
||||||
m_watcher.addPaths(paths);
|
m_watcher.addPaths(paths);
|
||||||
}
|
}
|
||||||
|
watcher->deleteLater();
|
||||||
});
|
});
|
||||||
|
watcher->setFuture(future);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +295,7 @@ void FileSystemModel::updateEntriesForDir(const QString& dir) {
|
|||||||
oldPaths << entry->path();
|
oldPaths << entry->path();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto future = QtConcurrent::run([=](QPromise<QPair<QSet<QString>, QSet<QString> > >& promise) {
|
const auto future = QtConcurrent::run([=](QPromise<QPair<QSet<QString>, QSet<QString>>>& promise) {
|
||||||
const auto flags = recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags;
|
const auto flags = recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags;
|
||||||
|
|
||||||
std::optional<QDirIterator> iter;
|
std::optional<QDirIterator> iter;
|
||||||
@@ -350,7 +353,7 @@ void FileSystemModel::updateEntriesForDir(const QString& dir) {
|
|||||||
newPaths.insert(path);
|
newPaths.insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (promise.isCanceled()) {
|
if (promise.isCanceled() || newPaths == oldPaths) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,17 +365,23 @@ void FileSystemModel::updateEntriesForDir(const QString& dir) {
|
|||||||
}
|
}
|
||||||
m_futures.insert(dir, future);
|
m_futures.insert(dir, future);
|
||||||
|
|
||||||
future
|
const auto watcher = new QFutureWatcher<QPair<QSet<QString>, QSet<QString>>>(this);
|
||||||
.then(this,
|
|
||||||
[dir, this](QPair<QSet<QString>, QSet<QString> > result) {
|
connect(watcher, &QFutureWatcher<QPair<QSet<QString>, QSet<QString>>>::finished, this, [dir, watcher, this]() {
|
||||||
m_futures.remove(dir);
|
m_futures.remove(dir);
|
||||||
if (!result.first.isEmpty() || !result.second.isEmpty()) {
|
|
||||||
applyChanges(result.first, result.second);
|
if (!watcher->future().isResultReadyAt(0)) {
|
||||||
|
watcher->deleteLater();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.onCanceled(this, [dir, this]() {
|
const auto result = watcher->result();
|
||||||
m_futures.remove(dir);
|
applyChanges(result.first, result.second);
|
||||||
|
|
||||||
|
watcher->deleteLater();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watcher->setFuture(future);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystemModel::applyChanges(const QSet<QString>& removedPaths, const QSet<QString>& addedPaths) {
|
void FileSystemModel::applyChanges(const QSet<QString>& removedPaths, const QSet<QString>& addedPaths) {
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ QString m_path;
|
|||||||
bool m_recursive;
|
bool m_recursive;
|
||||||
bool m_watchChanges;
|
bool m_watchChanges;
|
||||||
bool m_showHidden;
|
bool m_showHidden;
|
||||||
bool m_sortReverse = false;
|
bool m_sortReverse;
|
||||||
Filter m_filter;
|
Filter m_filter;
|
||||||
QStringList m_nameFilters;
|
QStringList m_nameFilters;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"typer",
|
"typer",
|
||||||
"pillow",
|
"pillow",
|
||||||
"jinja2",
|
|
||||||
"materialyoucolor"
|
"materialyoucolor"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import typer
|
import typer
|
||||||
from zshell.subcommands import shell, scheme, screenshot, wallpaper, record
|
from zshell.subcommands import shell, scheme, screenshot, wallpaper
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer()
|
||||||
|
|
||||||
@@ -8,7 +8,6 @@ app.add_typer(shell.app, name="shell")
|
|||||||
app.add_typer(scheme.app, name="scheme")
|
app.add_typer(scheme.app, name="scheme")
|
||||||
app.add_typer(screenshot.app, name="screenshot")
|
app.add_typer(screenshot.app, name="screenshot")
|
||||||
app.add_typer(wallpaper.app, name="wallpaper")
|
app.add_typer(wallpaper.app, name="wallpaper")
|
||||||
app.add_typer(record.app, name="record")
|
|
||||||
# app.add_typer(preset.app, name="preset")
|
# app.add_typer(preset.app, name="preset")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,214 +0,0 @@
|
|||||||
import os
|
|
||||||
import json
|
|
||||||
import subprocess
|
|
||||||
import time
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import typer
|
|
||||||
|
|
||||||
app = typer.Typer()
|
|
||||||
|
|
||||||
RECORDER = "gpu-screen-recorder"
|
|
||||||
HOME = str(os.getenv("HOME", str(Path.home())))
|
|
||||||
CONFIG = Path(HOME) / ".config/zshell/config.json"
|
|
||||||
|
|
||||||
STATE_DIR = Path(HOME) / ".local/state/zshell/record"
|
|
||||||
TEMP_RECORDING = STATE_DIR / "recording.mp4"
|
|
||||||
REPLAY_RECORDING = STATE_DIR / "replay.mp4"
|
|
||||||
NOTIF_ID_FILE = STATE_DIR / "notifid.txt"
|
|
||||||
|
|
||||||
RECORDINGS_DIR = os.getenv("ZSHELL_RECORDINGS_DIR",
|
|
||||||
str(Path(HOME) / "Videos/Recordings"))
|
|
||||||
|
|
||||||
|
|
||||||
def _read_extra_args() -> list[str]:
|
|
||||||
try:
|
|
||||||
if CONFIG.is_file():
|
|
||||||
data = json.loads(CONFIG.read_text())
|
|
||||||
return data.get("record", {}).get("extraArgs", [])
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def _is_recording() -> bool:
|
|
||||||
return subprocess.run(["pidof", RECORDER], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0
|
|
||||||
|
|
||||||
|
|
||||||
def _notify(summary: str, body: str = "", actions: list = None, timeout: int = 5000) -> Optional[int]:
|
|
||||||
args = ["notify-send", summary, body, "-t", str(timeout), "-p"]
|
|
||||||
if actions:
|
|
||||||
for action in actions:
|
|
||||||
args.extend(["-A", action])
|
|
||||||
try:
|
|
||||||
proc = subprocess.run(args, capture_output=True, text=True)
|
|
||||||
return int(proc.stdout.strip()) if proc.stdout.strip().isdigit() else None
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _close_notification(notif_id: int):
|
|
||||||
subprocess.run(["notify-send", "--close", str(notif_id)],
|
|
||||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_monitors() -> list[dict]:
|
|
||||||
try:
|
|
||||||
res = subprocess.run(["hyprctl", "monitors", "-j"],
|
|
||||||
capture_output=True, text=True)
|
|
||||||
return json.loads(res.stdout)
|
|
||||||
except Exception:
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def _focused_monitor_name() -> Optional[str]:
|
|
||||||
for m in _get_monitors():
|
|
||||||
if m.get("focused"):
|
|
||||||
return m["name"]
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _monitors_intersecting_region(x: int, y: int, w: int, h: int) -> list[dict]:
|
|
||||||
region = (x, y, x + w, y + h)
|
|
||||||
intersecting = []
|
|
||||||
for m in _get_monitors():
|
|
||||||
mx, my, mw, mh = m["x"], m["y"], m["width"], m["height"]
|
|
||||||
if not (region[2] <= mx or region[0] >= mx + mw or region[3] <= my or region[1] >= my + mh):
|
|
||||||
intersecting.append(m)
|
|
||||||
return intersecting
|
|
||||||
|
|
||||||
|
|
||||||
def _highest_refresh(monitors: list[dict]) -> float:
|
|
||||||
return max((m["refreshRate"] for m in monitors), default=60.0)
|
|
||||||
|
|
||||||
|
|
||||||
def _slurp_region() -> Optional[str]:
|
|
||||||
try:
|
|
||||||
return subprocess.check_output(["slurp", "-f", "%wx%h+%x+%y"], text=True).strip()
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_geometry(geometry: str) -> Optional[tuple[int, int, int, int]]:
|
|
||||||
import re
|
|
||||||
match = re.match(r"(\d+)x(\d+)\+(\d+)\+(\d+)", geometry)
|
|
||||||
if match:
|
|
||||||
return int(match.group(3)), int(match.group(4)), int(match.group(1)), int(match.group(2))
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def start_recording(region: Optional[str], sound: bool):
|
|
||||||
STATE_DIR.mkdir(parents=True, exist_ok=True)
|
|
||||||
cmd = [RECORDER]
|
|
||||||
extra_args = _read_extra_args()
|
|
||||||
|
|
||||||
if region:
|
|
||||||
if region.lower() == "slurp" or not region:
|
|
||||||
geometry = _slurp_region()
|
|
||||||
if not geometry:
|
|
||||||
typer.echo("Region selection cancelled.")
|
|
||||||
raise typer.Abort()
|
|
||||||
else:
|
|
||||||
geometry = region
|
|
||||||
|
|
||||||
parsed = _parse_geometry(geometry)
|
|
||||||
if not parsed:
|
|
||||||
typer.echo("Invalid geometry format.")
|
|
||||||
raise typer.Abort()
|
|
||||||
x, y, w, h = parsed
|
|
||||||
|
|
||||||
monitors = _monitors_intersecting_region(x, y, w, h)
|
|
||||||
framerate = _highest_refresh(monitors)
|
|
||||||
cmd.extend(["-w", "region", "-region", geometry, "-f", str(int(framerate))])
|
|
||||||
|
|
||||||
else:
|
|
||||||
monitor_name = _focused_monitor_name()
|
|
||||||
if not monitor_name:
|
|
||||||
typer.echo("No focused monitor found.")
|
|
||||||
raise typer.Abort()
|
|
||||||
|
|
||||||
monitors = _get_monitors()
|
|
||||||
mon = next((m for m in monitors if m["name"] == monitor_name), None)
|
|
||||||
rate = int(mon["refreshRate"]) if mon else 60
|
|
||||||
cmd.extend(["-w", monitor_name, "-f", str(rate)])
|
|
||||||
|
|
||||||
if sound:
|
|
||||||
cmd.extend(["-a", "default_output"])
|
|
||||||
|
|
||||||
cmd.extend(extra_args)
|
|
||||||
cmd.extend(["-o", str(TEMP_RECORDING)])
|
|
||||||
|
|
||||||
subprocess.Popen(cmd, start_new_session=True,
|
|
||||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
||||||
|
|
||||||
notif_id = _notify("Recording started", f"Saving to {TEMP_RECORDING}")
|
|
||||||
if notif_id is not None:
|
|
||||||
NOTIF_ID_FILE.write_text(str(notif_id))
|
|
||||||
|
|
||||||
time.sleep(1)
|
|
||||||
if not _is_recording():
|
|
||||||
_notify("Recording failed",
|
|
||||||
"Check gpu-screen-recorder output.", timeout=5000)
|
|
||||||
raise typer.Exit(code=1)
|
|
||||||
|
|
||||||
|
|
||||||
def stop_recording(clipboard: bool):
|
|
||||||
subprocess.run(["pkill", "-f", RECORDER],
|
|
||||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
||||||
|
|
||||||
for _ in range(50):
|
|
||||||
if not _is_recording():
|
|
||||||
break
|
|
||||||
time.sleep(0.1)
|
|
||||||
|
|
||||||
dest_dir = Path(RECORDINGS_DIR)
|
|
||||||
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
timestamp = time.strftime("%Y-%m-%d_%H-%M-%S")
|
|
||||||
final_path = dest_dir / f"recording_{timestamp}.mp4"
|
|
||||||
|
|
||||||
if TEMP_RECORDING.exists():
|
|
||||||
TEMP_RECORDING.rename(final_path)
|
|
||||||
|
|
||||||
if NOTIF_ID_FILE.is_file():
|
|
||||||
try:
|
|
||||||
_close_notification(int(NOTIF_ID_FILE.read_text().strip()))
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
NOTIF_ID_FILE.unlink()
|
|
||||||
|
|
||||||
if clipboard:
|
|
||||||
subprocess.run(["wl-copy", "--type", "text/uri-list", f"file://{final_path}"],
|
|
||||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
||||||
|
|
||||||
_notify("Recording stopped", f"Saved to {final_path}", timeout=5000)
|
|
||||||
|
|
||||||
|
|
||||||
def toggle_pause():
|
|
||||||
subprocess.run(["pkill", "-USR2", "-f", RECORDER],
|
|
||||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
||||||
typer.echo("Toggled pause.")
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
|
||||||
def record(
|
|
||||||
region: Optional[str] = typer.Option(
|
|
||||||
None, "--region", "-r",
|
|
||||||
help="Record a region. Use 'slurp' (or omit value) to select interactively, or give 'WxH+X+Y'.",
|
|
||||||
),
|
|
||||||
sound: bool = typer.Option(
|
|
||||||
False, "--sound", "-s", help="Record audio from default output."),
|
|
||||||
pause: bool = typer.Option(
|
|
||||||
False, "--pause", "-p", help="Toggle pause/resume."),
|
|
||||||
clipboard: bool = typer.Option(
|
|
||||||
False, "--clipboard", "-c", help="Copy the final recording path to clipboard."),
|
|
||||||
):
|
|
||||||
"""Start or stop a screen recording with gpu-screen-recorder."""
|
|
||||||
if pause:
|
|
||||||
toggle_pause()
|
|
||||||
raise typer.Exit()
|
|
||||||
|
|
||||||
if _is_recording():
|
|
||||||
stop_recording(clipboard)
|
|
||||||
else:
|
|
||||||
start_recording(region, sound)
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
import click
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
args = ["qs", "-c", "zshell"]
|
args = ["qs", "-c", "zshell"]
|
||||||
@@ -12,68 +8,35 @@ app = typer.Typer()
|
|||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def kill():
|
def kill():
|
||||||
result = subprocess.run(args + ["kill"], capture_output=True)
|
subprocess.run(args + ["kill"], check=True)
|
||||||
if result.returncode != 0:
|
|
||||||
raise click.ClickException("No running instance to kill.")
|
|
||||||
sys.stderr.write(result.stderr.decode())
|
|
||||||
|
|
||||||
|
|
||||||
def start_instance(no_daemon: bool = False) -> None:
|
|
||||||
result = subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), capture_output=True)
|
|
||||||
stdout = result.stdout.decode().strip()
|
|
||||||
if stdout:
|
|
||||||
if "already running" in stdout.lower():
|
|
||||||
raise click.ClickException(stdout)
|
|
||||||
if result.returncode != 0:
|
|
||||||
stderr = result.stderr.decode().strip()
|
|
||||||
raise click.ClickException(stderr)
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def start(no_daemon: bool = False):
|
def start(no_daemon: bool = False):
|
||||||
start_instance(no_daemon)
|
subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), check=True)
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def restart(no_daemon: bool = False):
|
def restart(no_daemon: bool = False):
|
||||||
subprocess.run(args + ["kill"], capture_output=True)
|
subprocess.run(args + ["kill"], check=False)
|
||||||
deadline = time.monotonic() + 2.5
|
subprocess.run(args + ["-n"] + ([] if no_daemon else ["-d"]), check=True)
|
||||||
while time.monotonic() < deadline:
|
|
||||||
result = subprocess.run(args + ["kill"], capture_output=True)
|
|
||||||
if result.returncode == 255:
|
|
||||||
break
|
|
||||||
time.sleep(0.25)
|
|
||||||
start_instance(no_daemon=no_daemon)
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def show():
|
def show():
|
||||||
result = subprocess.run(args + ["ipc"] + ["show"], capture_output=True)
|
subprocess.run(args + ["ipc"] + ["show"], check=True)
|
||||||
if result.returncode != 0:
|
|
||||||
raise click.ClickException(result.stderr.decode().strip())
|
|
||||||
sys.stderr.write(result.stderr.decode())
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def log():
|
def log():
|
||||||
result = subprocess.run(args + ["log"], capture_output=True)
|
subprocess.run(args + ["log"], check=True)
|
||||||
if result.returncode != 0:
|
|
||||||
raise click.ClickException(result.stderr.decode().strip())
|
|
||||||
sys.stdout.write(result.stdout.decode())
|
|
||||||
sys.stderr.write(result.stderr.decode())
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def lock():
|
def lock():
|
||||||
result = subprocess.run(args + ["ipc"] + ["call"] + ["lock"] + ["lock"], capture_output=True)
|
subprocess.run(args + ["ipc"] + ["call"] + ["lock"] + ["lock"], check=True)
|
||||||
if result.returncode != 0:
|
|
||||||
raise click.ClickException(result.stderr.decode().strip())
|
|
||||||
sys.stderr.write(result.stderr.decode())
|
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def call(target: str, method: str, method_args: list[str] = typer.Argument(None)):
|
def call(target: str, method: str, method_args: list[str] = typer.Argument(None)):
|
||||||
result = subprocess.run(args + ["ipc"] + ["call"] + [target] + [method] + (method_args or []), capture_output=True)
|
subprocess.run(args + ["ipc"] + ["call"] + [target] + [method] + (method_args or []), check=True)
|
||||||
if result.returncode != 0:
|
|
||||||
raise click.ClickException(result.stderr.decode().strip())
|
|
||||||
sys.stderr.write(result.stderr.decode())
|
|
||||||
|
|||||||
Binary file not shown.
+19
-62
@@ -1,15 +1,13 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from subprocess import CompletedProcess
|
|
||||||
from unittest.mock import patch, call
|
from unittest.mock import patch, call
|
||||||
|
|
||||||
from typer.testing import CliRunner
|
|
||||||
from zshell.subcommands.shell import app
|
from zshell.subcommands.shell import app
|
||||||
|
|
||||||
|
|
||||||
|
def invoke(*args: str) -> None:
|
||||||
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
runner = CliRunner()
|
runner = CliRunner()
|
||||||
|
|
||||||
|
|
||||||
def invoke(*args: str):
|
|
||||||
result = runner.invoke(app, args)
|
result = runner.invoke(app, args)
|
||||||
if result.exit_code != 0:
|
if result.exit_code != 0:
|
||||||
raise RuntimeError(result.output)
|
raise RuntimeError(result.output)
|
||||||
@@ -18,113 +16,72 @@ def invoke(*args: str):
|
|||||||
|
|
||||||
class TestKill:
|
class TestKill:
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
@patch("zshell.subcommands.shell.subprocess.run")
|
||||||
def test_kill_runs_qs_kill_success(self, mock_run):
|
def test_kill_runs_qs_kill(self, mock_run):
|
||||||
mock_run.return_value = CompletedProcess([], 0, b"", b"Killed abc\n")
|
|
||||||
invoke("kill")
|
invoke("kill")
|
||||||
mock_run.assert_called_once_with(["qs", "-c", "zshell", "kill"], capture_output=True)
|
mock_run.assert_called_once_with(["qs", "-c", "zshell", "kill"], check=True)
|
||||||
|
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
|
||||||
def test_kill_no_instance_errors(self, mock_run):
|
|
||||||
mock_run.return_value = CompletedProcess([], 255, b"", b"No running instances\n")
|
|
||||||
result = runner.invoke(app, ["kill"])
|
|
||||||
assert result.exit_code != 0
|
|
||||||
assert "No running instance to kill" in result.output
|
|
||||||
|
|
||||||
|
|
||||||
class TestStart:
|
class TestStart:
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
@patch("zshell.subcommands.shell.subprocess.run")
|
||||||
def test_start_default_daemon(self, mock_run):
|
def test_start_default_daemon(self, mock_run):
|
||||||
mock_run.return_value = CompletedProcess([], 0, b"", b"Launching config\n")
|
|
||||||
invoke("start")
|
invoke("start")
|
||||||
mock_run.assert_called_once_with(["qs", "-c", "zshell", "-n", "-d"], capture_output=True)
|
mock_run.assert_called_once_with(["qs", "-c", "zshell", "-n", "-d"], check=True)
|
||||||
|
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
@patch("zshell.subcommands.shell.subprocess.run")
|
||||||
def test_start_no_daemon(self, mock_run):
|
def test_start_no_daemon(self, mock_run):
|
||||||
mock_run.return_value = CompletedProcess([], 0, b"", b"Launching config\n")
|
|
||||||
invoke("start", "--no-daemon")
|
invoke("start", "--no-daemon")
|
||||||
mock_run.assert_called_once_with(["qs", "-c", "zshell", "-n"], capture_output=True)
|
mock_run.assert_called_once_with(["qs", "-c", "zshell", "-n"], check=True)
|
||||||
|
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
|
||||||
def test_start_already_running_errors(self, mock_run):
|
|
||||||
mock_run.return_value = CompletedProcess([], 0, b"An instance of this configuration is already running.\n", b"")
|
|
||||||
result = runner.invoke(app, ["start"])
|
|
||||||
assert result.exit_code != 0
|
|
||||||
assert "already running" in result.output
|
|
||||||
|
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
|
||||||
def test_start_other_failure_errors(self, mock_run):
|
|
||||||
mock_run.return_value = CompletedProcess([], 1, b"", b"Config error\n")
|
|
||||||
result = runner.invoke(app, ["start"])
|
|
||||||
assert result.exit_code != 0
|
|
||||||
assert "Config error" in result.output
|
|
||||||
|
|
||||||
|
|
||||||
class TestShow:
|
class TestShow:
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
@patch("zshell.subcommands.shell.subprocess.run")
|
||||||
def test_show_runs_ipc_show(self, mock_run):
|
def test_show_runs_ipc_show(self, mock_run):
|
||||||
mock_run.return_value = CompletedProcess([], 0, b"", b"target visibilities\n")
|
|
||||||
invoke("show")
|
invoke("show")
|
||||||
mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "show"], capture_output=True)
|
mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "show"], check=True)
|
||||||
|
|
||||||
|
|
||||||
class TestLog:
|
class TestLog:
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
@patch("zshell.subcommands.shell.subprocess.run")
|
||||||
def test_log_runs_qs_log(self, mock_run):
|
def test_log_runs_qs_log(self, mock_run):
|
||||||
mock_run.return_value = CompletedProcess([], 0, b"log output\n", b"")
|
|
||||||
invoke("log")
|
invoke("log")
|
||||||
mock_run.assert_called_once_with(["qs", "-c", "zshell", "log"], capture_output=True)
|
mock_run.assert_called_once_with(["qs", "-c", "zshell", "log"], check=True)
|
||||||
|
|
||||||
|
|
||||||
class TestLock:
|
class TestLock:
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
@patch("zshell.subcommands.shell.subprocess.run")
|
||||||
def test_lock_runs_ipc_call_lock(self, mock_run):
|
def test_lock_runs_ipc_call_lock(self, mock_run):
|
||||||
mock_run.return_value = CompletedProcess([], 0, b"", b"")
|
|
||||||
invoke("lock")
|
invoke("lock")
|
||||||
mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "call", "lock", "lock"], capture_output=True)
|
mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "call", "lock", "lock"], check=True)
|
||||||
|
|
||||||
|
|
||||||
class TestCall:
|
class TestCall:
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
@patch("zshell.subcommands.shell.subprocess.run")
|
||||||
def test_call_no_args(self, mock_run):
|
def test_call_no_args(self, mock_run):
|
||||||
mock_run.return_value = CompletedProcess([], 0, b"", b"")
|
|
||||||
invoke("call", "target", "method")
|
invoke("call", "target", "method")
|
||||||
mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "call", "target", "method"], capture_output=True)
|
mock_run.assert_called_once_with(["qs", "-c", "zshell", "ipc", "call", "target", "method"], check=True)
|
||||||
|
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
@patch("zshell.subcommands.shell.subprocess.run")
|
||||||
def test_call_with_args(self, mock_run):
|
def test_call_with_args(self, mock_run):
|
||||||
mock_run.return_value = CompletedProcess([], 0, b"", b"")
|
|
||||||
invoke("call", "target", "method", "arg1", "arg2")
|
invoke("call", "target", "method", "arg1", "arg2")
|
||||||
mock_run.assert_called_once_with(
|
mock_run.assert_called_once_with(
|
||||||
["qs", "-c", "zshell", "ipc", "call", "target", "method", "arg1", "arg2"],
|
["qs", "-c", "zshell", "ipc", "call", "target", "method", "arg1", "arg2"],
|
||||||
capture_output=True,
|
check=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestRestart:
|
class TestRestart:
|
||||||
@patch("zshell.subcommands.shell.start_instance")
|
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
@patch("zshell.subcommands.shell.subprocess.run")
|
||||||
def test_restart_kills_then_starts(self, mock_run, mock_start):
|
def test_restart_kills_then_starts_daemon(self, mock_run):
|
||||||
mock_run.side_effect = [
|
|
||||||
CompletedProcess([], 0, b"", b"Killed abc\n"), # first kill (captured)
|
|
||||||
CompletedProcess([], 255, b"", b""), # poll → no instance
|
|
||||||
]
|
|
||||||
invoke("restart")
|
invoke("restart")
|
||||||
assert mock_run.call_args_list == [
|
assert mock_run.call_args_list == [
|
||||||
call(["qs", "-c", "zshell", "kill"], capture_output=True),
|
call(["qs", "-c", "zshell", "kill"], check=False),
|
||||||
call(["qs", "-c", "zshell", "kill"], capture_output=True),
|
call(["qs", "-c", "zshell", "-n", "-d"], check=True),
|
||||||
]
|
]
|
||||||
mock_start.assert_called_once_with(no_daemon=False)
|
|
||||||
|
|
||||||
@patch("zshell.subcommands.shell.start_instance")
|
|
||||||
@patch("zshell.subcommands.shell.subprocess.run")
|
@patch("zshell.subcommands.shell.subprocess.run")
|
||||||
def test_restart_no_daemon(self, mock_run, mock_start):
|
def test_restart_no_daemon(self, mock_run):
|
||||||
mock_run.side_effect = [
|
|
||||||
CompletedProcess([], 0, b"", b"Killed abc\n"),
|
|
||||||
CompletedProcess([], 255, b"", b""),
|
|
||||||
]
|
|
||||||
invoke("restart", "--no-daemon")
|
invoke("restart", "--no-daemon")
|
||||||
assert mock_run.call_args_list == [
|
assert mock_run.call_args_list == [
|
||||||
call(["qs", "-c", "zshell", "kill"], capture_output=True),
|
call(["qs", "-c", "zshell", "kill"], check=False),
|
||||||
call(["qs", "-c", "zshell", "kill"], capture_output=True),
|
call(["qs", "-c", "zshell", "-n"], check=True),
|
||||||
]
|
]
|
||||||
mock_start.assert_called_once_with(no_daemon=True)
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
//@ pragma Env QT_SCALE_FACTOR_ROUNDING_POLICY=Round
|
//@ pragma Env QT_SCALE_FACTOR_ROUNDING_POLICY=Round
|
||||||
//@ pragma DropExpensiveFonts
|
//@ pragma DropExpensiveFonts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Extensions
|
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
import qs.Modules.Wallpaper
|
import qs.Modules.Wallpaper
|
||||||
import qs.Modules.Lock
|
import qs.Modules.Lock
|
||||||
@@ -15,8 +14,6 @@ import qs.Helpers
|
|||||||
import qs.Modules.Polkit
|
import qs.Modules.Polkit
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
settings.watchFiles: true
|
|
||||||
|
|
||||||
Windows {
|
Windows {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +36,4 @@ ShellRoot {
|
|||||||
|
|
||||||
Polkit {
|
Polkit {
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadExtensions {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+3
-807
@@ -8,47 +8,12 @@ version = "2.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aligned"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685"
|
|
||||||
dependencies = [
|
|
||||||
"as-slice",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aligned-vec"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
|
|
||||||
dependencies = [
|
|
||||||
"equator",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.102"
|
version = "1.0.102"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arbitrary"
|
|
||||||
version = "1.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arg_enum_proc_macro"
|
|
||||||
version = "0.3.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@@ -61,103 +26,18 @@ version = "0.7.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "as-slice"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
|
|
||||||
dependencies = [
|
|
||||||
"stable_deref_trait",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "av-scenechange"
|
|
||||||
version = "0.14.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394"
|
|
||||||
dependencies = [
|
|
||||||
"aligned",
|
|
||||||
"anyhow",
|
|
||||||
"arg_enum_proc_macro",
|
|
||||||
"arrayvec",
|
|
||||||
"log",
|
|
||||||
"num-rational",
|
|
||||||
"num-traits",
|
|
||||||
"pastey",
|
|
||||||
"rayon",
|
|
||||||
"thiserror",
|
|
||||||
"v_frame",
|
|
||||||
"y4m",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "av1-grain"
|
|
||||||
version = "0.2.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"arrayvec",
|
|
||||||
"log",
|
|
||||||
"nom",
|
|
||||||
"num-rational",
|
|
||||||
"v_frame",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "avif-serialize"
|
|
||||||
version = "0.8.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d"
|
|
||||||
dependencies = [
|
|
||||||
"arrayvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bit_field"
|
|
||||||
version = "0.10.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.11.1"
|
version = "2.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitstream-io"
|
|
||||||
version = "4.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f"
|
|
||||||
dependencies = [
|
|
||||||
"no_std_io2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "built"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bumpalo"
|
|
||||||
version = "3.20.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.25.0"
|
version = "1.25.0"
|
||||||
@@ -170,30 +50,12 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.2.61"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
|
|
||||||
dependencies = [
|
|
||||||
"find-msvc-tools",
|
|
||||||
"jobserver",
|
|
||||||
"libc",
|
|
||||||
"shlex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "color_quant"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@@ -203,84 +65,6 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-deque"
|
|
||||||
version = "0.8.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.8.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crunchy"
|
|
||||||
version = "0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "equator"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
|
|
||||||
dependencies = [
|
|
||||||
"equator-macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "equator-macro"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "exr"
|
|
||||||
version = "1.74.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
|
|
||||||
dependencies = [
|
|
||||||
"bit_field",
|
|
||||||
"half",
|
|
||||||
"lebe",
|
|
||||||
"miniz_oxide",
|
|
||||||
"rayon-core",
|
|
||||||
"smallvec",
|
|
||||||
"zune-inflate",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fax"
|
|
||||||
version = "0.2.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdeflate"
|
name = "fdeflate"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
@@ -290,12 +74,6 @@ dependencies = [
|
|||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "find-msvc-tools"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.1.9"
|
version = "1.1.9"
|
||||||
@@ -306,39 +84,6 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.3.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"r-efi",
|
|
||||||
"wasip2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gif"
|
|
||||||
version = "0.14.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159"
|
|
||||||
dependencies = [
|
|
||||||
"color_quant",
|
|
||||||
"weezl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "half"
|
|
||||||
version = "2.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crunchy",
|
|
||||||
"zerocopy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.10"
|
version = "0.25.10"
|
||||||
@@ -347,56 +92,9 @@ checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder-lite",
|
"byteorder-lite",
|
||||||
"color_quant",
|
|
||||||
"exr",
|
|
||||||
"gif",
|
|
||||||
"image-webp",
|
|
||||||
"moxcms",
|
"moxcms",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"png 0.18.1",
|
"png",
|
||||||
"qoi",
|
|
||||||
"ravif",
|
|
||||||
"rayon",
|
|
||||||
"rgb",
|
|
||||||
"tiff",
|
|
||||||
"zune-core",
|
|
||||||
"zune-jpeg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "image-webp"
|
|
||||||
version = "0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder-lite",
|
|
||||||
"quick-error",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "imgref"
|
|
||||||
version = "1.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "40fac9d56ed6437b198fddba683305e8e2d651aa42647f00f5ae542e7f5c94a2"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "interpolate_name"
|
|
||||||
version = "0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itertools"
|
|
||||||
version = "0.14.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -405,63 +103,12 @@ version = "1.0.18"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jobserver"
|
|
||||||
version = "0.1.34"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lebe"
|
|
||||||
version = "0.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.186"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libfuzzer-sys"
|
|
||||||
version = "0.4.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
|
|
||||||
dependencies = [
|
|
||||||
"arbitrary",
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.29"
|
version = "0.4.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "loop9"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
|
|
||||||
dependencies = [
|
|
||||||
"imgref",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "maybe-rayon"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"rayon",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.8.0"
|
version = "2.8.0"
|
||||||
@@ -488,77 +135,6 @@ dependencies = [
|
|||||||
"pxfm",
|
"pxfm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "new_debug_unreachable"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "no_std_io2"
|
|
||||||
version = "0.9.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b51ed7824b6e07d354605f4abb3d9d300350701299da96642ee084f5ce631550"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nom"
|
|
||||||
version = "8.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "noop_proc_macro"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-bigint"
|
|
||||||
version = "0.4.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
|
||||||
dependencies = [
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-derive"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-integer"
|
|
||||||
version = "0.1.46"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-rational"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
|
||||||
dependencies = [
|
|
||||||
"num-bigint",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
@@ -568,59 +144,19 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "once_cell"
|
|
||||||
version = "1.21.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste"
|
|
||||||
version = "1.0.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pastey"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "png"
|
|
||||||
version = "0.17.16"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"crc32fast",
|
|
||||||
"fdeflate",
|
|
||||||
"flate2",
|
|
||||||
"miniz_oxide",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.18.1"
|
version = "0.18.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
|
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.1",
|
"bitflags",
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"fdeflate",
|
"fdeflate",
|
||||||
"flate2",
|
"flate2",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
|
||||||
dependencies = [
|
|
||||||
"zerocopy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.106"
|
version = "1.0.106"
|
||||||
@@ -630,46 +166,12 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "profiling"
|
|
||||||
version = "1.0.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
|
|
||||||
dependencies = [
|
|
||||||
"profiling-procmacros",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "profiling-procmacros"
|
|
||||||
version = "1.0.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pxfm"
|
name = "pxfm"
|
||||||
version = "0.1.29"
|
version = "0.1.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f"
|
checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "qoi"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quick-error"
|
|
||||||
version = "2.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.45"
|
version = "1.0.45"
|
||||||
@@ -679,123 +181,6 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "r-efi"
|
|
||||||
version = "5.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
|
|
||||||
dependencies = [
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.9.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rav1e"
|
|
||||||
version = "0.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b"
|
|
||||||
dependencies = [
|
|
||||||
"aligned-vec",
|
|
||||||
"arbitrary",
|
|
||||||
"arg_enum_proc_macro",
|
|
||||||
"arrayvec",
|
|
||||||
"av-scenechange",
|
|
||||||
"av1-grain",
|
|
||||||
"bitstream-io",
|
|
||||||
"built",
|
|
||||||
"cfg-if",
|
|
||||||
"interpolate_name",
|
|
||||||
"itertools",
|
|
||||||
"libc",
|
|
||||||
"libfuzzer-sys",
|
|
||||||
"log",
|
|
||||||
"maybe-rayon",
|
|
||||||
"new_debug_unreachable",
|
|
||||||
"noop_proc_macro",
|
|
||||||
"num-derive",
|
|
||||||
"num-traits",
|
|
||||||
"paste",
|
|
||||||
"profiling",
|
|
||||||
"rand",
|
|
||||||
"rand_chacha",
|
|
||||||
"simd_helpers",
|
|
||||||
"thiserror",
|
|
||||||
"v_frame",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ravif"
|
|
||||||
version = "0.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45"
|
|
||||||
dependencies = [
|
|
||||||
"avif-serialize",
|
|
||||||
"imgref",
|
|
||||||
"loop9",
|
|
||||||
"quick-error",
|
|
||||||
"rav1e",
|
|
||||||
"rayon",
|
|
||||||
"rgb",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon"
|
|
||||||
version = "1.12.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"rayon-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon-core"
|
|
||||||
version = "1.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-deque",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rgb"
|
|
||||||
version = "0.8.53"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustversion"
|
|
||||||
version = "1.0.22"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.228"
|
version = "1.0.228"
|
||||||
@@ -839,39 +224,12 @@ dependencies = [
|
|||||||
"zmij",
|
"zmij",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shlex"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simd-adler32"
|
name = "simd-adler32"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simd_helpers"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.15.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stable_deref_trait"
|
|
||||||
version = "1.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strict-num"
|
name = "strict-num"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -889,40 +247,6 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror"
|
|
||||||
version = "2.0.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror-impl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror-impl"
|
|
||||||
version = "2.0.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tiff"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
|
|
||||||
dependencies = [
|
|
||||||
"fax",
|
|
||||||
"flate2",
|
|
||||||
"half",
|
|
||||||
"quick-error",
|
|
||||||
"weezl",
|
|
||||||
"zune-jpeg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiny-skia"
|
name = "tiny-skia"
|
||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
@@ -934,7 +258,6 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"log",
|
"log",
|
||||||
"png 0.17.16",
|
|
||||||
"tiny-skia-path",
|
"tiny-skia-path",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -955,109 +278,6 @@ version = "1.0.24"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "v_frame"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2"
|
|
||||||
dependencies = [
|
|
||||||
"aligned-vec",
|
|
||||||
"num-traits",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasip2"
|
|
||||||
version = "1.0.3+wasi-0.2.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
|
||||||
dependencies = [
|
|
||||||
"wit-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen"
|
|
||||||
version = "0.2.120"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"once_cell",
|
|
||||||
"rustversion",
|
|
||||||
"wasm-bindgen-macro",
|
|
||||||
"wasm-bindgen-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro"
|
|
||||||
version = "0.2.120"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"wasm-bindgen-macro-support",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro-support"
|
|
||||||
version = "0.2.120"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
|
|
||||||
dependencies = [
|
|
||||||
"bumpalo",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"wasm-bindgen-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-shared"
|
|
||||||
version = "0.2.120"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "weezl"
|
|
||||||
version = "0.1.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wit-bindgen"
|
|
||||||
version = "0.57.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "y4m"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy"
|
|
||||||
version = "0.8.48"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
|
|
||||||
dependencies = [
|
|
||||||
"zerocopy-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy-derive"
|
|
||||||
version = "0.8.48"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zmij"
|
name = "zmij"
|
||||||
version = "1.0.21"
|
version = "1.0.21"
|
||||||
@@ -1066,7 +286,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zshell-img-tools"
|
name = "zshell-img-tools"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"image",
|
"image",
|
||||||
@@ -1074,27 +294,3 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zune-core"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zune-inflate"
|
|
||||||
version = "0.2.54"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
|
|
||||||
dependencies = [
|
|
||||||
"simd-adler32",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zune-jpeg"
|
|
||||||
version = "0.5.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
|
|
||||||
dependencies = [
|
|
||||||
"zune-core",
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "zshell-img-tools"
|
name = "zshell-img-tools"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
@@ -8,10 +8,10 @@ name = "zshell-img-tools"
|
|||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
image = { version = "0.25", features = ["png"] }
|
image = { version = "0.25", default-features = false, features = ["png"] }
|
||||||
tiny-skia = "0.11"
|
tiny-skia = { version = "0.11", default-features = false, features = ["std", "simd"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
anyhow = "1"
|
anyhow = "1.0"
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
# What_That_Claude_DO?
|
|
||||||
|
|
||||||
What That Claude Do? (WTCD)
|
|
||||||
A repository of random things I ask Claude to do for me.
|
|
||||||
|
|
||||||
In this case it is creating a screenshot tool
|
|
||||||
@@ -11,13 +11,14 @@ pub struct Config {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct EffectsConfig {
|
pub struct EffectsConfig {
|
||||||
pub mode: String,
|
pub mode: String,
|
||||||
pub rounded_corners: bool,
|
|
||||||
pub corner_radius: f32,
|
pub corner_radius: f32,
|
||||||
pub drop_shadow: bool,
|
pub drop_shadow: bool,
|
||||||
|
pub rounded_corners: bool,
|
||||||
pub shadow_blur_radius: f32,
|
pub shadow_blur_radius: f32,
|
||||||
|
pub shadow_blur_passes: u32,
|
||||||
|
pub shadow_color: [u8; 4],
|
||||||
pub shadow_offset_x: f32,
|
pub shadow_offset_x: f32,
|
||||||
pub shadow_offset_y: f32,
|
pub shadow_offset_y: f32,
|
||||||
pub shadow_color: [u8; 4],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ pub fn apply_effects(img: RgbaImage, cfg: &EffectsConfig) -> RgbaImage {
|
|||||||
cfg.shadow_blur_radius,
|
cfg.shadow_blur_radius,
|
||||||
cfg.shadow_offset_x,
|
cfg.shadow_offset_x,
|
||||||
cfg.shadow_offset_y,
|
cfg.shadow_offset_y,
|
||||||
|
cfg.shadow_blur_passes,
|
||||||
cfg.shadow_color,
|
cfg.shadow_color,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@@ -52,11 +53,16 @@ pub fn apply_drop_shadow(
|
|||||||
blur_radius: f32,
|
blur_radius: f32,
|
||||||
offset_x: f32,
|
offset_x: f32,
|
||||||
offset_y: f32,
|
offset_y: f32,
|
||||||
|
blur_passes: u32,
|
||||||
shadow_color: [u8; 4],
|
shadow_color: [u8; 4],
|
||||||
) -> RgbaImage {
|
) -> RgbaImage {
|
||||||
let (iw, ih) = img.dimensions();
|
let (iw, ih) = img.dimensions();
|
||||||
let br = blur_radius.ceil() as u32;
|
let br = blur_radius.ceil() as u32;
|
||||||
let spread = br * 2;
|
let bp = blur_passes;
|
||||||
|
// Original idea
|
||||||
|
// let spread = br * bp;
|
||||||
|
// Claude is hallucinating but let's try it **Worked btw**
|
||||||
|
let spread = (br as f32 * (bp as f32).sqrt() * 2.0).ceil() as u32;
|
||||||
|
|
||||||
let extra_left = spread + (-offset_x).max(0.0).ceil() as u32;
|
let extra_left = spread + (-offset_x).max(0.0).ceil() as u32;
|
||||||
let extra_top = spread + (-offset_y).max(0.0).ceil() as u32;
|
let extra_top = spread + (-offset_y).max(0.0).ceil() as u32;
|
||||||
@@ -86,8 +92,11 @@ pub fn apply_drop_shadow(
|
|||||||
|
|
||||||
tint_pixmap_as_shadow(&mut shadow_pixmap, shadow_color);
|
tint_pixmap_as_shadow(&mut shadow_pixmap, shadow_color);
|
||||||
|
|
||||||
|
// Shadow
|
||||||
let shadow_img = pixmap_to_rgba_image(shadow_pixmap);
|
let shadow_img = pixmap_to_rgba_image(shadow_pixmap);
|
||||||
let blurred = box_blur_rgba(&shadow_img, br);
|
// Shadow blur
|
||||||
|
let blurred = box_blur_rgba(&shadow_img, br, bp);
|
||||||
|
// Shadow pos
|
||||||
let blurred_pixmap = rgba_image_to_pixmap(&blurred);
|
let blurred_pixmap = rgba_image_to_pixmap(&blurred);
|
||||||
|
|
||||||
let mut canvas = Pixmap::new(canvas_w, canvas_h).expect("canvas pixmap");
|
let mut canvas = Pixmap::new(canvas_w, canvas_h).expect("canvas pixmap");
|
||||||
@@ -136,6 +145,7 @@ fn rounded_rect_path(x: f32, y: f32, w: f32, h: f32, r: f32) -> Path {
|
|||||||
pb.finish().expect("rounded rect path")
|
pb.finish().expect("rounded rect path")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shadow pos
|
||||||
fn rgba_image_to_pixmap(img: &RgbaImage) -> Pixmap {
|
fn rgba_image_to_pixmap(img: &RgbaImage) -> Pixmap {
|
||||||
let (w, h) = img.dimensions();
|
let (w, h) = img.dimensions();
|
||||||
let mut pixmap = Pixmap::new(w, h).expect("pixmap alloc");
|
let mut pixmap = Pixmap::new(w, h).expect("pixmap alloc");
|
||||||
@@ -154,6 +164,7 @@ fn rgba_image_to_pixmap(img: &RgbaImage) -> Pixmap {
|
|||||||
pixmap
|
pixmap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shadow
|
||||||
fn pixmap_to_rgba_image(pixmap: Pixmap) -> RgbaImage {
|
fn pixmap_to_rgba_image(pixmap: Pixmap) -> RgbaImage {
|
||||||
let (w, h) = (pixmap.width(), pixmap.height());
|
let (w, h) = (pixmap.width(), pixmap.height());
|
||||||
let mut out = RgbaImage::new(w, h);
|
let mut out = RgbaImage::new(w, h);
|
||||||
@@ -176,31 +187,16 @@ fn pixmap_to_rgba_image(pixmap: Pixmap) -> RgbaImage {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tint_pixmap_as_shadow(pixmap: &mut Pixmap, color: [u8; 4]) {
|
// Shadow blur
|
||||||
let [sr, sg, sb, _] = color;
|
fn box_blur_rgba(img: &RgbaImage, radius: u32, bp: u32) -> RgbaImage {
|
||||||
for px in pixmap.pixels_mut() {
|
|
||||||
let a = px.alpha();
|
|
||||||
if a > 0 {
|
|
||||||
let af = a as f32 / 255.0;
|
|
||||||
*px = tiny_skia::PremultipliedColorU8::from_rgba(
|
|
||||||
(sr as f32 * af) as u8,
|
|
||||||
(sg as f32 * af) as u8,
|
|
||||||
(sb as f32 * af) as u8,
|
|
||||||
a,
|
|
||||||
)
|
|
||||||
.unwrap_or(tiny_skia::PremultipliedColorU8::TRANSPARENT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn box_blur_rgba(img: &RgbaImage, radius: u32) -> RgbaImage {
|
|
||||||
if radius == 0 {
|
if radius == 0 {
|
||||||
return img.clone();
|
return img.clone();
|
||||||
}
|
}
|
||||||
let mut buf = sliding_horizontal(img, radius);
|
let mut buf = img.clone();
|
||||||
buf = sliding_vertical(&buf, radius);
|
for _ in 0..bp {
|
||||||
buf = sliding_horizontal(&buf, radius);
|
buf = sliding_horizontal(&buf, radius);
|
||||||
buf = sliding_vertical(&buf, radius);
|
buf = sliding_vertical(&buf, radius);
|
||||||
|
}
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,6 +246,23 @@ fn sliding_horizontal(img: &RgbaImage, radius: u32) -> RgbaImage {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tint_pixmap_as_shadow(pixmap: &mut Pixmap, color: [u8; 4]) {
|
||||||
|
let [sr, sg, sb, _] = color;
|
||||||
|
for px in pixmap.pixels_mut() {
|
||||||
|
let a = px.alpha();
|
||||||
|
if a > 0 {
|
||||||
|
let af = a as f32 / 255.0;
|
||||||
|
*px = tiny_skia::PremultipliedColorU8::from_rgba(
|
||||||
|
(sr as f32 * af) as u8,
|
||||||
|
(sg as f32 * af) as u8,
|
||||||
|
(sb as f32 * af) as u8,
|
||||||
|
a,
|
||||||
|
)
|
||||||
|
.unwrap_or(tiny_skia::PremultipliedColorU8::TRANSPARENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn sliding_vertical(img: &RgbaImage, radius: u32) -> RgbaImage {
|
fn sliding_vertical(img: &RgbaImage, radius: u32) -> RgbaImage {
|
||||||
let (w, h) = img.dimensions();
|
let (w, h) = img.dimensions();
|
||||||
let r = radius as i32;
|
let r = radius as i32;
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
mod config;
|
mod config;
|
||||||
mod effects;
|
mod effects;
|
||||||
|
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{bail, Context, Result};
|
||||||
use std::io::Write as _;
|
use std::io::Write as _;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
/// CLI overrides that map 1:1 to `EffectsConfig` fields.
|
|
||||||
/// All fields are `Option<T>` so we can tell "not supplied" from any concrete value.
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct CliOverrides {
|
struct CliOverrides {
|
||||||
rounded_corners: Option<bool>,
|
rounded_corners: Option<bool>,
|
||||||
corner_radius: Option<f32>,
|
corner_radius: Option<f32>,
|
||||||
drop_shadow: Option<bool>,
|
drop_shadow: Option<bool>,
|
||||||
shadow_blur_radius: Option<f32>,
|
shadow_blur_radius: Option<f32>,
|
||||||
|
shadow_blur_passes: Option<u32>,
|
||||||
shadow_offset_x: Option<f32>,
|
shadow_offset_x: Option<f32>,
|
||||||
shadow_offset_y: Option<f32>,
|
shadow_offset_y: Option<f32>,
|
||||||
/// Accepted as four comma-separated u8 values, e.g. `255,0,0,200`
|
// Accepted as four comma-separated u8 values, e.g. `255,0,0,200`
|
||||||
shadow_color: Option<[u8; 4]>,
|
shadow_color: Option<[u8; 4]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,24 +29,24 @@ fn parse_bool(s: &str) -> Result<bool> {
|
|||||||
fn parse_shadow_color(s: &str) -> Result<[u8; 4]> {
|
fn parse_shadow_color(s: &str) -> Result<[u8; 4]> {
|
||||||
let parts: Vec<&str> = s.split(',').collect();
|
let parts: Vec<&str> = s.split(',').collect();
|
||||||
if parts.len() != 4 {
|
if parts.len() != 4 {
|
||||||
bail!("--shadow_color expects four comma-separated u8 values, e.g. 255,0,0,200");
|
bail!("--shadow-color expects four comma-separated u8 values, e.g. 255,0,0,200");
|
||||||
}
|
}
|
||||||
let r = parts[0]
|
let r = parts[0]
|
||||||
.trim()
|
.trim()
|
||||||
.parse::<u8>()
|
.parse::<u8>()
|
||||||
.context("shadow_color red channel")?;
|
.context("shadow-color red channel")?;
|
||||||
let g = parts[1]
|
let g = parts[1]
|
||||||
.trim()
|
.trim()
|
||||||
.parse::<u8>()
|
.parse::<u8>()
|
||||||
.context("shadow_color green channel")?;
|
.context("shadow-color green channel")?;
|
||||||
let b = parts[2]
|
let b = parts[2]
|
||||||
.trim()
|
.trim()
|
||||||
.parse::<u8>()
|
.parse::<u8>()
|
||||||
.context("shadow_color blue channel")?;
|
.context("shadow-color blue channel")?;
|
||||||
let a = parts[3]
|
let a = parts[3]
|
||||||
.trim()
|
.trim()
|
||||||
.parse::<u8>()
|
.parse::<u8>()
|
||||||
.context("shadow_color alpha channel")?;
|
.context("shadow-color alpha channel")?;
|
||||||
Ok([r, g, b, a])
|
Ok([r, g, b, a])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,6 +55,7 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
let mut image_path: Option<String> = None;
|
let mut image_path: Option<String> = None;
|
||||||
let mut overrides = CliOverrides::default();
|
let mut overrides = CliOverrides::default();
|
||||||
|
let mut scale: Option<f32> = None;
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < args.len() {
|
while i < args.len() {
|
||||||
@@ -68,67 +68,82 @@ fn main() -> Result<()> {
|
|||||||
.context("Expected a path after --image")?,
|
.context("Expected a path after --image")?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"--rounded_corners" => {
|
"--rounded-corners" => {
|
||||||
i += 1;
|
i += 1;
|
||||||
let val = args
|
let val = args
|
||||||
.get(i)
|
.get(i)
|
||||||
.context("Expected true/false after --rounded_corners")?;
|
.context("Expected true/false after --rounded-corners")?;
|
||||||
overrides.rounded_corners = Some(parse_bool(val)?);
|
overrides.rounded_corners = Some(parse_bool(val)?);
|
||||||
}
|
}
|
||||||
"--corner_radius" => {
|
"--corner-radius" => {
|
||||||
i += 1;
|
i += 1;
|
||||||
let val = args
|
let val = args
|
||||||
.get(i)
|
.get(i)
|
||||||
.context("Expected a number after --corner_radius")?;
|
.context("Expected a number after --corner-radius")?;
|
||||||
overrides.corner_radius = Some(
|
overrides.corner_radius = Some(
|
||||||
val.parse::<f32>()
|
val.parse::<f32>()
|
||||||
.context("--corner_radius must be a number")?,
|
.context("--corner-radius must be a number")?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"--drop_shadow" => {
|
"--drop-shadow" => {
|
||||||
i += 1;
|
i += 1;
|
||||||
let val = args
|
let val = args
|
||||||
.get(i)
|
.get(i)
|
||||||
.context("Expected true/false after --drop_shadow")?;
|
.context("Expected true/false after --drop-shadow")?;
|
||||||
overrides.drop_shadow = Some(parse_bool(val)?);
|
overrides.drop_shadow = Some(parse_bool(val)?);
|
||||||
}
|
}
|
||||||
"--shadow_blur_radius" => {
|
"--shadow-blur-radius" => {
|
||||||
i += 1;
|
i += 1;
|
||||||
let val = args
|
let val = args
|
||||||
.get(i)
|
.get(i)
|
||||||
.context("Expected a number after --shadow_blur_radius")?;
|
.context("Expected a number after --shadow-blur-radius")?;
|
||||||
overrides.shadow_blur_radius = Some(
|
overrides.shadow_blur_radius = Some(
|
||||||
val.parse::<f32>()
|
val.parse::<f32>()
|
||||||
.context("--shadow_blur_radius must be a number")?,
|
.context("--shadow-blur-radius must be a number")?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"--shadow_offset_x" => {
|
"--shadow-offset-x" => {
|
||||||
i += 1;
|
i += 1;
|
||||||
let val = args
|
let val = args
|
||||||
.get(i)
|
.get(i)
|
||||||
.context("Expected a number after --shadow_offset_x")?;
|
.context("Expected a number after --shadow-offset-x")?;
|
||||||
overrides.shadow_offset_x = Some(
|
overrides.shadow_offset_x = Some(
|
||||||
val.parse::<f32>()
|
val.parse::<f32>()
|
||||||
.context("--shadow_offset_x must be a number")?,
|
.context("--shadow-offset-x must be a number")?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"--shadow_offset_y" => {
|
"--shadow-offset-y" => {
|
||||||
i += 1;
|
i += 1;
|
||||||
let val = args
|
let val = args
|
||||||
.get(i)
|
.get(i)
|
||||||
.context("Expected a number after --shadow_offset_y")?;
|
.context("Expected a number after --shadow-offset-y")?;
|
||||||
overrides.shadow_offset_y = Some(
|
overrides.shadow_offset_y = Some(
|
||||||
val.parse::<f32>()
|
val.parse::<f32>()
|
||||||
.context("--shadow_offset_y must be a number")?,
|
.context("--shadow-offset-y must be a number")?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"--shadow_color" => {
|
"--shadow-blur-passes" => {
|
||||||
i += 1;
|
i += 1;
|
||||||
let val = args
|
let val = args
|
||||||
.get(i)
|
.get(i)
|
||||||
.context("Expected r,g,b,a after --shadow_color")?;
|
.context("Expected a number after --shadow-blur-passes")?;
|
||||||
|
overrides.shadow_blur_passes = Some(
|
||||||
|
val.parse::<u32>()
|
||||||
|
.context("--shadow-blur-passes must be a number")?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"--shadow-color" => {
|
||||||
|
i += 1;
|
||||||
|
let val = args
|
||||||
|
.get(i)
|
||||||
|
.context("Expected r,g,b,a after --shadow-color")?;
|
||||||
overrides.shadow_color = Some(parse_shadow_color(val)?);
|
overrides.shadow_color = Some(parse_shadow_color(val)?);
|
||||||
}
|
}
|
||||||
|
"--scale" => {
|
||||||
|
i += 1;
|
||||||
|
let val = args.get(i).context("Expected a number after --scale")?;
|
||||||
|
scale = Some(val.parse::<f32>().context("--scale must be a number")?);
|
||||||
|
}
|
||||||
unknown => bail!("Unknown argument: {unknown}"),
|
unknown => bail!("Unknown argument: {unknown}"),
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
@@ -158,11 +173,22 @@ fn main() -> Result<()> {
|
|||||||
if let Some(v) = overrides.shadow_offset_y {
|
if let Some(v) = overrides.shadow_offset_y {
|
||||||
effects.shadow_offset_y = v;
|
effects.shadow_offset_y = v;
|
||||||
}
|
}
|
||||||
|
if let Some(v) = overrides.shadow_blur_passes {
|
||||||
|
effects.shadow_blur_passes = v;
|
||||||
|
}
|
||||||
if let Some(v) = overrides.shadow_color {
|
if let Some(v) = overrides.shadow_color {
|
||||||
effects.shadow_color = v;
|
effects.shadow_color = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if scale is set do
|
||||||
|
if let Some(scale) = scale.filter(|&s| s != 1.0) {
|
||||||
|
effects.corner_radius *= scale;
|
||||||
|
effects.shadow_blur_radius *= scale;
|
||||||
|
effects.shadow_offset_x *= scale;
|
||||||
|
effects.shadow_offset_y *= scale;
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(e) = process_image(&image_path, &effects) {
|
if let Err(e) = process_image(&image_path, &effects) {
|
||||||
eprintln!("Error processing '{}': {e:#}", image_path);
|
eprintln!("Error processing '{}': {e:#}", image_path);
|
||||||
}
|
}
|
||||||
@@ -191,20 +217,11 @@ fn process_image(path: &str, effects: &config::EffectsConfig) -> Result<()> {
|
|||||||
.spawn()
|
.spawn()
|
||||||
.context("Failed to spawn swappy. Is it installed and in PATH?")?;
|
.context("Failed to spawn swappy. Is it installed and in PATH?")?;
|
||||||
|
|
||||||
child
|
// Writes the PNG bytes to swappy's stdin and then closes
|
||||||
.stdin
|
if let Some(mut stdin) = child.stdin.take() {
|
||||||
.take()
|
stdin
|
||||||
.context("Failed to get swappy stdin")?
|
|
||||||
.write_all(&png_bytes)
|
.write_all(&png_bytes)
|
||||||
.context("Failed to write image data to swappy")?;
|
.context("Failed to write image data to swappy")?;
|
||||||
|
|
||||||
let status = child.wait().context("Failed to wait for swappy")?;
|
|
||||||
|
|
||||||
if !status.success() {
|
|
||||||
eprintln!(
|
|
||||||
"swappy exited with non-zero status for '{}': {}",
|
|
||||||
path, status
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user