diff --git a/.config/ags/modules/.configuration/user_options.js b/.config/ags/modules/.configuration/user_options.js index c0e4f04c..e6726b12 100644 --- a/.config/ags/modules/.configuration/user_options.js +++ b/.config/ags/modules/.configuration/user_options.js @@ -14,13 +14,21 @@ function overrideConfigRecursive(userOverrides, configOptions = {}) { } // Load default options from ~/.config/ags/modules/.configuration/default_options.jsonc -const configFileContents = Utils.readFile(`${App.configDir}/modules/.configuration/default_options.jsonc`); -let configOptions = parseJSONC(configFileContents); -const userOverrideContents = Utils.readFile(`${App.configDir}/user_options.jsonc`); -let userOverrides = parseJSONC(userOverrideContents); +const defaultConfigFile = `${App.configDir}/modules/.configuration/default_options.jsonc`; +const defaultConfigFileContents = Utils.readFile(defaultConfigFile); +const defaultConfigOptions = parseJSONC(defaultConfigFileContents); + +// Clone the default config to avoid modifying the original +let configOptions = JSON.parse(JSON.stringify(defaultConfigOptions)); + +// Load user overrides +const userOverrideFile = `${App.configDir}/user_options.jsonc`; +const userOverrideContents = Utils.readFile(userOverrideFile); +const userOverrides = parseJSONC(userOverrideContents); // Override defaults with user's options overrideConfigRecursive(userOverrides, configOptions); +globalThis['userOptionsDefaults'] = defaultConfigOptions; globalThis['userOptions'] = configOptions; export default configOptions; diff --git a/.config/ags/modules/.miscutils/jsonc.js b/.config/ags/modules/.miscutils/jsonc.js index 62c4e50e..68933288 100644 --- a/.config/ags/modules/.miscutils/jsonc.js +++ b/.config/ags/modules/.miscutils/jsonc.js @@ -1,6 +1,3 @@ -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; - export function parseJSONC(jsoncString) { let result = ""; let inString = false; diff --git a/.config/ags/modules/.miscutils/objects.js b/.config/ags/modules/.miscutils/objects.js new file mode 100644 index 00000000..90ac62a2 --- /dev/null +++ b/.config/ags/modules/.miscutils/objects.js @@ -0,0 +1,33 @@ +export function getNestedProperty(obj, path) { + return path.split('.').reduce((current, key) => { + return (current && typeof current === 'object' && current.hasOwnProperty(key)) ? current[key] : undefined; + }, obj); +} + +export function updateNestedProperty(obj, path, newValue) { + const pathArray = path.split('.'); + const lastKeyIndex = pathArray.length - 1; + + let current = obj; + + for (let i = 0; i < lastKeyIndex; i++) { + const key = pathArray[i]; + if (!current || typeof current !== 'object') { + return false; // Previous part of path is not an object + } + + if (!current.hasOwnProperty(key)) { + current[key] = {}; // Create the missing object + } + current = current[key]; + } + + const lastKey = pathArray[lastKeyIndex]; + + if (!current || typeof current !== 'object') { + return false; // Parent is not an object + } + + current[lastKey] = newValue; + return true; +} diff --git a/.config/ags/modules/sideright/centermodules/configure.js b/.config/ags/modules/sideright/centermodules/configure.js index af1739f3..14947798 100644 --- a/.config/ags/modules/sideright/centermodules/configure.js +++ b/.config/ags/modules/sideright/centermodules/configure.js @@ -7,6 +7,7 @@ const { execAsync, exec } = Utils; import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { setupCursorHover } from '../../.widgetutils/cursorhover.js'; import { ConfigGap, ConfigSpinButton, ConfigToggle } from '../../.commonwidgets/configwidgets.js'; +import { getNestedProperty, updateNestedProperty } from '../../.miscutils/objects.js'; const HyprlandToggle = ({ icon, name, desc = null, option, enableValue = 1, disableValue = 0, extraOnChange = () => { }, extraOnReset = () => { }, save = true }) => ConfigToggle({ icon: icon, @@ -24,7 +25,7 @@ const HyprlandToggle = ({ icon, name, desc = null, option, enableValue = 1, disa ]).catch(print); else execAsync(['hyprctl', 'keyword', option, `${newValue ? enableValue : disableValue}`]).catch(print); - + extraOnChange(self, newValue); }, onReset: async (self) => { @@ -71,6 +72,38 @@ const HyprlandSpinButton = ({ icon, name, desc = null, option, save = true, extr ...rest, }); +const AgsSpinButton = ({ + icon, name, desc = null, option, + save = true, extraOnChange = () => { }, + ...rest +}) => ConfigSpinButton({ + icon: icon, + name: name, + desc: desc, + resetButton: true, + initValue: getNestedProperty(userOptions, option), + fetchValue: () => getNestedProperty(userOptions, option), + step: 10, minValue: 0, maxValue: 1000, + onChange: (self, newValue) => { + updateNestedProperty(userOptions, option, newValue); + if (save) execAsync(['bash', '-c', `${App.configDir}/scripts/ags/agsconfigurator.py \ + --key ${option} \ + --value ${newValue} \ + --file ${App.configDir}/user_options.jsonc` + ]).catch(print); + extraOnChange(self, newValue); + }, + onReset: async (self) => { + updateNestedProperty(userOptions, option, + getNestedProperty(userOptionsDefaults, option)); + if (save) exec(`bash -c '${App.configDir}/scripts/ags/agsconfigurator.py \ + --key ${option} \ + --reset \ + --file ${App.configDir}/user_options.jsonc'`); + }, + ...rest, +}) + const Subcategory = (children) => Box({ className: 'margin-left-20', vertical: true, @@ -130,15 +163,12 @@ export default (props) => { extraOnReset: (self, newValue) => execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', 'true']), }), Subcategory([ - ConfigSpinButton({ + AgsSpinButton({ + option: "animations.choreographyDelay", 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 - }, }) ]), ] @@ -158,21 +188,12 @@ export default (props) => { className: 'sidebar-centermodules-scrollgradient-bottom' })] }); - const footNote = Box({ - homogeneous: true, - children: [Label({ - hpack: 'center', - className: 'txt txt-italic txt-subtext margin-5', - label: getString('AGS-related changes aren\'t saved'), - })] - }) return Box({ ...props, className: 'spacing-v-5', vertical: true, children: [ mainContent, - footNote, ] }); } diff --git a/.config/ags/user_options.jsonc b/.config/ags/user_options.jsonc index 95e640f0..4c44fe01 100644 --- a/.config/ags/user_options.jsonc +++ b/.config/ags/user_options.jsonc @@ -5,9 +5,11 @@ // vim: `:vsp` to split window, move cursor to the path, press `gf`. // `Ctrl-w` twice to switch between the files // -// Limitations of this file -// Don't expect every JSONC feature in... say, vscode, to work. -// You can only have comments on top of the file +// Limitations of this file: +// * Only line comments (//) are allowed +// * Comments are not allowed in or below the actual content +// (will be nuked with updates from the UI) +// // // Example: Put this to show 8 (instead of 10) workspaces on the bar // "workspaces": {"shown": 8 }