mirror of
https://github.com/danbulant/dots-hyprland
synced 2026-05-24 12:22:09 +00:00
sidebar: configure: save settings
This commit is contained in:
parent
2cded1cd38
commit
1028a02b0e
7 changed files with 233 additions and 70 deletions
|
|
@ -7,8 +7,9 @@ const { Box, Button, Label, Revealer, SpinButton } = Widget;
|
|||
|
||||
export const ConfigToggle = ({
|
||||
icon, name, desc = '', initValue,
|
||||
expandWidget = true,
|
||||
expandWidget = true, resetButton = false,
|
||||
onChange = () => { }, extraSetup = () => { },
|
||||
onReset = () => { },
|
||||
...rest
|
||||
}) => {
|
||||
const enabled = Variable(initValue);
|
||||
|
|
@ -48,7 +49,7 @@ export const ConfigToggle = ({
|
|||
});
|
||||
const widgetContent = Box({
|
||||
tooltipText: desc,
|
||||
className: 'txt spacing-h-5 configtoggle-box',
|
||||
className: 'txt spacing-h-5',
|
||||
children: [
|
||||
...(icon !== undefined ? [MaterialIcon(icon, 'norm')] : []),
|
||||
...(name !== undefined ? [Label({
|
||||
|
|
@ -85,7 +86,18 @@ export const ConfigToggle = ({
|
|||
...rest,
|
||||
});
|
||||
interactionWrapper.enabled = enabled;
|
||||
return interactionWrapper;
|
||||
return Box({
|
||||
className: 'configtoggle-box spacing-h-5',
|
||||
children: [
|
||||
interactionWrapper,
|
||||
...(resetButton ? [Button({
|
||||
className: 'spinbutton-reset',
|
||||
onClicked: onReset,
|
||||
child: MaterialIcon('settings_backup_restore', 'small'),
|
||||
setup: setupCursorHover,
|
||||
})] : []),
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
export const ConfigSegmentedSelection = ({
|
||||
|
|
@ -187,8 +199,9 @@ export const ConfigGap = ({ vertical = true, size = 5, ...rest }) => Box({
|
|||
export const ConfigSpinButton = ({
|
||||
icon, name, desc = '', initValue,
|
||||
minValue = 0, maxValue = 100, step = 1,
|
||||
expandWidget = true,
|
||||
expandWidget = true, resetButton = false,
|
||||
onChange = () => { }, extraSetup = () => { },
|
||||
onReset = () => { },
|
||||
...rest
|
||||
}) => {
|
||||
const value = Variable(initValue);
|
||||
|
|
@ -213,6 +226,12 @@ export const ConfigSpinButton = ({
|
|||
})] : []),
|
||||
...(expandWidget ? [Box({ hexpand: true })] : []),
|
||||
spinButton,
|
||||
...(resetButton ? [Button({
|
||||
className: 'spinbutton-reset',
|
||||
onClicked: onReset,
|
||||
child: MaterialIcon('settings_backup_restore', 'small'),
|
||||
setup: setupCursorHover,
|
||||
})] : []),
|
||||
],
|
||||
setup: (self) => {
|
||||
extraSetup(self);
|
||||
|
|
|
|||
|
|
@ -2,30 +2,68 @@ const { GLib } = imports.gi;
|
|||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { Box, Button, Icon, Label, Scrollable, Slider, Stack } = Widget;
|
||||
const { Box, Button, Icon, Label, Scrollable, Slider, Stack, Overlay } = Widget;
|
||||
const { execAsync, exec } = Utils;
|
||||
import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
|
||||
import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
|
||||
import { ConfigGap, ConfigSpinButton, ConfigToggle } from '../../.commonwidgets/configwidgets.js';
|
||||
|
||||
const HyprlandToggle = ({ icon, name, desc = null, option, enableValue = 1, disableValue = 0, extraOnChange = () => { } }) => ConfigToggle({
|
||||
const HyprlandToggle = ({ icon, name, desc = null, option, enableValue = 1, disableValue = 0, extraOnChange = () => { }, extraOnReset = () => { }, save = true }) => ConfigToggle({
|
||||
icon: icon,
|
||||
name: name,
|
||||
desc: desc,
|
||||
resetButton: true,
|
||||
initValue: JSON.parse(exec(`hyprctl getoption -j ${option}`))["int"] != 0,
|
||||
onChange: (self, newValue) => {
|
||||
execAsync(['hyprctl', 'keyword', option, `${newValue ? enableValue : disableValue}`]).catch(print);
|
||||
if (save)
|
||||
execAsync(['bash', '-c', `${App.configDir}/scripts/hyprland/hyprconfigurator.py \
|
||||
--key ${option} \
|
||||
--value ${newValue ? enableValue : disableValue} \
|
||||
--file \${XDG_CONFIG_HOME:-$HOME/.config}/hypr/custom/general.conf`
|
||||
]).catch(print);
|
||||
else
|
||||
execAsync(['hyprctl', 'keyword', option, `${newValue ? enableValue : disableValue}`]).catch(print);
|
||||
// scripts/hyprland/hyprconfigurator.py --key decoration:rounding --value 12 --file '/home/end/.config/hypr/custom/general.conf'
|
||||
extraOnChange(self, newValue);
|
||||
}
|
||||
},
|
||||
onReset: (self, newValue) => {
|
||||
if (save)
|
||||
execAsync(['bash', '-c', `${App.configDir}/scripts/hyprland/hyprconfigurator.py \
|
||||
--key ${option} \
|
||||
--reset \
|
||||
--file \${XDG_CONFIG_HOME:-$HOME/.config}/hypr/custom/general.conf`
|
||||
]).catch(print);
|
||||
else
|
||||
execAsync(['bash', '-c', `hyprctl reload`]).catch(print);
|
||||
extraOnReset(self, newValue);
|
||||
},
|
||||
});
|
||||
|
||||
const HyprlandSpinButton = ({ icon, name, desc = null, option, ...rest }) => ConfigSpinButton({
|
||||
const HyprlandSpinButton = ({ icon, name, desc = null, option, save = true, ...rest }) => ConfigSpinButton({
|
||||
icon: icon,
|
||||
name: name,
|
||||
desc: desc,
|
||||
resetButton: true,
|
||||
initValue: Number(JSON.parse(exec(`hyprctl getoption -j ${option}`))["int"]),
|
||||
onChange: (self, newValue) => {
|
||||
execAsync(['hyprctl', 'keyword', option, `${newValue}`]).catch(print);
|
||||
if (save)
|
||||
execAsync(['bash', '-c', `${App.configDir}/scripts/hyprland/hyprconfigurator.py \
|
||||
--key ${option} \
|
||||
--value ${newValue} \
|
||||
--file \${XDG_CONFIG_HOME:-$HOME/.config}/hypr/custom/general.conf`
|
||||
]).catch(print);
|
||||
else
|
||||
execAsync(['hyprctl', 'keyword', option, `${newValue}`]).catch(print);
|
||||
},
|
||||
onReset: (self, newValue) => {
|
||||
if (save)
|
||||
execAsync(['bash', '-c', `${App.configDir}/scripts/hyprland/hyprconfigurator.py \
|
||||
--key ${option} \
|
||||
--reset \
|
||||
--file \${XDG_CONFIG_HOME:-$HOME/.config}/hypr/custom/general.conf`
|
||||
]).catch(print);
|
||||
else
|
||||
execAsync(['bash', '-c', `hyprctl reload`]).catch(print);
|
||||
},
|
||||
...rest,
|
||||
});
|
||||
|
|
@ -53,69 +91,76 @@ export default (props) => {
|
|||
})
|
||||
]
|
||||
})
|
||||
const mainContent = Scrollable({
|
||||
vexpand: true,
|
||||
child: Box({
|
||||
vertical: true,
|
||||
className: 'spacing-v-10',
|
||||
children: [
|
||||
ConfigSection({
|
||||
name: getString('Effects'), children: [
|
||||
ConfigToggle({
|
||||
icon: 'border_clear',
|
||||
name: getString('Transparency'),
|
||||
desc: getString('[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this'),
|
||||
initValue: exec(`bash -c "sed -n \'2p\' ${GLib.get_user_state_dir()}/ags/user/colormode.txt"`) == "transparent",
|
||||
onChange: (self, newValue) => {
|
||||
const transparency = newValue == 0 ? "opaque" : "transparent";
|
||||
console.log(transparency);
|
||||
execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_state_dir()}/ags/user && sed -i "2s/.*/${transparency}/" ${GLib.get_user_state_dir()}/ags/user/colormode.txt`])
|
||||
.then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`]))
|
||||
.catch(print);
|
||||
},
|
||||
}),
|
||||
HyprlandToggle({ icon: 'blur_on', name: getString('Blur'), desc: getString("[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows."), option: "decoration:blur:enabled" }),
|
||||
Subcategory([
|
||||
HyprlandToggle({ icon: 'stack_off', name: getString('X-ray'), desc: getString("[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) "), option: "decoration:blur:xray" }),
|
||||
HyprlandSpinButton({ icon: 'target', name: getString('Size'), desc: getString('[Hyprland]\nAdjust the blur radius. Generally doesn\'t affect performance\nHigher = more color spread'), option: 'decoration:blur:size', minValue: 1, maxValue: 1000 }),
|
||||
HyprlandSpinButton({ icon: 'repeat', name: getString('Passes'), desc: getString('[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.'), option: 'decoration:blur:passes', minValue: 1, maxValue: 10 }),
|
||||
]),
|
||||
ConfigGap({}),
|
||||
HyprlandToggle({
|
||||
icon: 'animation', name: getString('Animations'), desc: getString('[Hyprland] [GTK]\nEnable animations'), option: 'animations:enabled',
|
||||
extraOnChange: (self, newValue) => execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', `${newValue}`])
|
||||
}),
|
||||
Subcategory([
|
||||
ConfigSpinButton({
|
||||
icon: 'clear_all',
|
||||
name: getString('Choreography delay'),
|
||||
desc: getString('In milliseconds, the delay between animations of a series'),
|
||||
initValue: userOptions.animations.choreographyDelay,
|
||||
step: 10, minValue: 0, maxValue: 1000,
|
||||
const mainContent = Overlay({
|
||||
passThrough: true,
|
||||
child: Scrollable({
|
||||
vexpand: true,
|
||||
child: Box({
|
||||
vertical: true,
|
||||
className: 'spacing-v-10 sidebar-centermodules-scrollgradient-bottom-contentmargin',
|
||||
children: [
|
||||
ConfigSection({
|
||||
name: getString('Effects'), children: [
|
||||
ConfigToggle({
|
||||
icon: 'border_clear',
|
||||
name: getString('Transparency'),
|
||||
desc: getString('[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this'),
|
||||
initValue: exec(`bash -c "sed -n \'2p\' ${GLib.get_user_state_dir()}/ags/user/colormode.txt"`) == "transparent",
|
||||
onChange: (self, newValue) => {
|
||||
userOptions.animations.choreographyDelay = newValue
|
||||
const transparency = newValue == 0 ? "opaque" : "transparent";
|
||||
console.log(transparency);
|
||||
execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_state_dir()}/ags/user && sed -i "2s/.*/${transparency}/" ${GLib.get_user_state_dir()}/ags/user/colormode.txt`])
|
||||
.then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`]))
|
||||
.catch(print);
|
||||
},
|
||||
})
|
||||
]),
|
||||
]
|
||||
}),
|
||||
ConfigSection({
|
||||
name: getString('Developer'), children: [
|
||||
HyprlandToggle({ icon: 'speed', name: getString('Show FPS'), desc: getString("[Hyprland]\nShow FPS overlay on top-left corner"), option: "debug:overlay" }),
|
||||
HyprlandToggle({ icon: 'sort', name: getString('Log to stdout'), desc: getString("[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console"), option: "debug:enable_stdout_logs" }),
|
||||
HyprlandToggle({ icon: 'motion_sensor_active', name: getString('Damage tracking'), desc: getString("[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work"), option: "debug:damage_tracking", enableValue: 2 }),
|
||||
HyprlandToggle({ icon: 'destruction', name: getString('Damage blink'), desc: getString("[Hyprland] [Epilepsy warning!]\nShow screen damage flashes"), option: "debug:damage_blink" }),
|
||||
]
|
||||
}),
|
||||
]
|
||||
})
|
||||
}),
|
||||
HyprlandToggle({ icon: 'blur_on', name: getString('Blur'), desc: getString("[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows."), option: "decoration:blur:enabled" }),
|
||||
Subcategory([
|
||||
HyprlandToggle({ icon: 'stack_off', name: getString('X-ray'), desc: getString("[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) "), option: "decoration:blur:xray" }),
|
||||
HyprlandSpinButton({ icon: 'target', name: getString('Size'), desc: getString('[Hyprland]\nAdjust the blur radius. Generally doesn\'t affect performance\nHigher = more color spread'), option: 'decoration:blur:size', minValue: 1, maxValue: 1000 }),
|
||||
HyprlandSpinButton({ icon: 'repeat', name: getString('Passes'), desc: getString('[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.'), option: 'decoration:blur:passes', minValue: 1, maxValue: 10 }),
|
||||
]),
|
||||
ConfigGap({}),
|
||||
HyprlandToggle({
|
||||
icon: 'animation', name: getString('Animations'), desc: getString('[Hyprland] [GTK]\nEnable animations'), option: 'animations:enabled',
|
||||
extraOnChange: (self, newValue) => execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', `${newValue}`]),
|
||||
extraOnReset: (self, newValue) => execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', 'true']),
|
||||
}),
|
||||
Subcategory([
|
||||
ConfigSpinButton({
|
||||
icon: 'clear_all',
|
||||
name: getString('Choreography delay'),
|
||||
desc: getString('In milliseconds, the delay between animations of a series'),
|
||||
initValue: userOptions.animations.choreographyDelay,
|
||||
step: 10, minValue: 0, maxValue: 1000,
|
||||
onChange: (self, newValue) => {
|
||||
userOptions.animations.choreographyDelay = newValue
|
||||
},
|
||||
})
|
||||
]),
|
||||
]
|
||||
}),
|
||||
ConfigSection({
|
||||
name: getString('Developer'), children: [
|
||||
HyprlandToggle({ icon: 'speed', name: getString('Show FPS'), desc: getString("[Hyprland]\nShow FPS overlay on top-left corner"), option: "debug:overlay", save: false }),
|
||||
HyprlandToggle({ icon: 'sort', name: getString('Log to stdout'), desc: getString("[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console"), option: "debug:enable_stdout_logs" }),
|
||||
HyprlandToggle({ icon: 'motion_sensor_active', name: getString('Damage tracking'), desc: getString("[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work"), option: "debug:damage_tracking", enableValue: 2, save: false }),
|
||||
HyprlandToggle({ icon: 'destruction', name: getString('Damage blink'), desc: getString("[Hyprland] [Epilepsy warning!]\nShow screen damage flashes"), option: "debug:damage_blink", save: false }),
|
||||
]
|
||||
}),
|
||||
]
|
||||
})
|
||||
}),
|
||||
overlays: [Box({
|
||||
className: 'sidebar-centermodules-scrollgradient-bottom'
|
||||
})]
|
||||
});
|
||||
const footNote = Box({
|
||||
homogeneous: true,
|
||||
children: [Label({
|
||||
hpack: 'center',
|
||||
className: 'txt txt-italic txt-subtext margin-5',
|
||||
label: getString('Not all changes are saved'),
|
||||
label: getString('AGS-related changes aren\'t saved'),
|
||||
})]
|
||||
})
|
||||
return Box({
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ export default (props) => {
|
|||
},
|
||||
},
|
||||
vertical: true,
|
||||
className: 'spacing-v-5 margin-bottom-15',
|
||||
className: 'spacing-v-5 sidebar-centermodules-scrollgradient-bottom-contentmargin',
|
||||
setup: (self) => self.hook(Network, self.attribute.updateNetworks),
|
||||
}),
|
||||
}),
|
||||
|
|
|
|||
51
.config/ags/scripts/hyprland/hyprconfigurator.py
Executable file
51
.config/ags/scripts/hyprland/hyprconfigurator.py
Executable file
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env -S\_/bin/sh\_-xc\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@""
|
||||
import argparse
|
||||
import re
|
||||
import os
|
||||
|
||||
def edit_hyprland_config(file_path, key, value, reset):
|
||||
try:
|
||||
with open(file_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
except FileNotFoundError:
|
||||
print(f"Error: File '{file_path}' not found.")
|
||||
return
|
||||
|
||||
key_pattern = re.compile(rf'^\s*{re.escape(key)}\s*=')
|
||||
new_lines = []
|
||||
found = False
|
||||
|
||||
for line in lines:
|
||||
if key_pattern.match(line):
|
||||
found = True
|
||||
if reset:
|
||||
continue # Skip this line to remove the key
|
||||
line = f"{key} = {value}\n"
|
||||
new_lines.append(line)
|
||||
|
||||
if not found and not reset:
|
||||
new_lines.append(f"{key} = {value}\n")
|
||||
|
||||
with open(file_path, 'w') as file:
|
||||
file.writelines(new_lines)
|
||||
|
||||
if reset:
|
||||
print(f"Removed '{key}' from '{file_path}'")
|
||||
else:
|
||||
print(f"Updated '{file_path}' with {key} = {value}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Edit a Hyprland config file.")
|
||||
parser.add_argument("--file", default="~/.config/hypr/hyprland.conf", help="Path to the Hyprland config file (default: ~/.config/hypr/hyprland.conf).")
|
||||
parser.add_argument("--key", required=True, help="Configuration key to modify or remove.")
|
||||
parser.add_argument("--value", help="New value for the configuration key (optional).", default=None)
|
||||
parser.add_argument("--reset", action="store_true", help="Remove the specified key from the config file.")
|
||||
args = parser.parse_args()
|
||||
|
||||
file_path = os.path.expanduser(args.file)
|
||||
|
||||
if args.reset and args.value:
|
||||
print("Error: --reset and --value cannot be used together.")
|
||||
else:
|
||||
edit_hyprland_config(file_path, args.key, args.value or "", args.reset)
|
||||
|
||||
|
|
@ -306,14 +306,53 @@ widget {
|
|||
|
||||
.spinbutton {
|
||||
@include small-rounding;
|
||||
color: $onLayer2;
|
||||
background-color: $layer2;
|
||||
padding: 0.341rem;
|
||||
min-width: 2.045rem;
|
||||
min-height: 2.045rem;
|
||||
caret-color: $onLayer2;
|
||||
|
||||
entry {
|
||||
color: $onLayer2;
|
||||
margin: 0.136rem 0.273rem;
|
||||
margin: 0.477rem 0.614rem;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 0.205rem;
|
||||
padding: 0.136rem;
|
||||
@include unsharpen-rounding;
|
||||
min-width: 2.045rem;
|
||||
min-height: 2.045rem;
|
||||
-gtk-outline-radius: $rounding_small;
|
||||
}
|
||||
|
||||
button.up {
|
||||
// Only apply rounding to (+) button
|
||||
border-top-right-radius: $rounding_small;
|
||||
border-bottom-right-radius: $rounding_small;
|
||||
}
|
||||
|
||||
// button:focus, // Looks weird after clicking cuz it'll highlight both + and -
|
||||
button:hover {
|
||||
background-color: $layer2Hover;
|
||||
}
|
||||
|
||||
button:active {
|
||||
background-color: $layer2Active;
|
||||
}
|
||||
}
|
||||
|
||||
.spinbutton-reset {
|
||||
@include small-rounding;
|
||||
color: $onLayer2;
|
||||
background-color: $layer2;
|
||||
min-width: 2.045rem;
|
||||
min-height: 2.045rem;
|
||||
}
|
||||
|
||||
.spinbutton-reset:focus,
|
||||
.spinbutton-reset:hover {
|
||||
background-color: $layer2Hover;
|
||||
}
|
||||
|
||||
.spinbutton-reset:active {
|
||||
background-color: $layer2Active;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Common colors
|
||||
$hovercolor: $surfaceContainerHigh;
|
||||
$activecolor: $surfaceContainerHighest;
|
||||
$rounding_unsharpen: 0.136rem;
|
||||
$rounding_verysmall: 0.477rem;
|
||||
$rounding_small: 0.818rem;
|
||||
$rounding_mediumsmall: 0.955rem;
|
||||
|
|
@ -9,6 +10,10 @@ $rounding_mediumlarge: 1.364rem;
|
|||
$rounding_large: 1.705rem;
|
||||
|
||||
// Common rules
|
||||
@mixin unsharpen-rounding {
|
||||
border-radius: $rounding_unsharpen;
|
||||
}
|
||||
|
||||
@mixin small-rounding {
|
||||
border-radius: $rounding_small;
|
||||
-gtk-outline-radius: $rounding_small;
|
||||
|
|
|
|||
|
|
@ -1041,6 +1041,10 @@ $waifu_image_overlay_transparency: 0.7;
|
|||
background: linear-gradient(to top, $layer1 0%, transparentize($layer1, 1) 1.023rem);
|
||||
}
|
||||
|
||||
.sidebar-centermodules-scrollgradient-bottom-contentmargin {
|
||||
margin-bottom: 1.023rem;
|
||||
}
|
||||
|
||||
.sidebar-wifinetworks-network-button {
|
||||
@include full-rounding;
|
||||
@include element_decel;
|
||||
|
|
|
|||
Loading…
Reference in a new issue