summaryrefslogtreecommitdiff
path: root/src/til_settings.c
AgeCommit message (Collapse)Author
2023-06-12til_settings: pivot settings path printing to til_strVito Caputo
This eliminates more open_memstream() usage in favor of the new til_str stuff. While here I've split up the path construction API exposing the til_str oriented variants, rather than only providing a FILE*-oriented API. This way you just use the FILE* stuff when convenient (like printing to stdout/stderr) and go til_str_t when you're building up a buffer. Such is life in a sans-open_memstream-world. Also while here the FILE*-oriented settings path printers were renamed s/print/fprint/g hence touching setup.c
2023-06-12til_settings: migrate til_settings_as_arg() to til_strVito Caputo
First elimination of open_memstream() usage...
2023-06-03til_settings: add an optional til_settings_t.prefixVito Caputo
Preparatory commit for bridging the gap separating a baked til_setup_t from a runtime-populated descendant til_settings_t like modules::rtv produces for its channels via til_module_setup_randomize(). For these currently orphaned til_settings_t instances we don't readily have access to the logical ancestor til_settings_t that was used to produce the module_context's bound til_setup_t. But we don't really need the ancestor til_settings_t, all we _really_ want is the ancestral path to prefix the orphan til_settings_t instances. So this commit introduces supplying a prefix which gets prepended to paths printed via the settings instance. A later commit will make use of this in modules::rtv when producing the settings instance passed to til_module_setup_randomize()
2023-06-03til_settings: free til_settings_t.labelVito Caputo
These were being leaked by til_esttings_free()
2023-06-03til_settings: drop desc from til_settings_add_value()Vito Caputo
In a world where "describing" settings is an iterative process, especially post-nested-settings which are realized via the desc-applying process, it's better to not even offer desc-setting while adding a new setting. This commit just gets rid of that. The one caller that was passing a non-NULL desc to til_settings_add_value(), til_module_setup_randomize(), was redundantly doing so since the subsequent desc-processing was assigning it again anyways. Future commits will likely change til_module_setup_randomize() use a non-NULL desc for skipping desc-applying, which wouldn't even work if it was always setting the desc @ add time. That becomes necessary for partially randomizing sparsely-populated settings.
2023-06-03til_settings,setup: introduce til_setting_spec_t.override()Vito Caputo
In situations where modules wish to alias setting values like expanding "all" -> "mod0,mod1,mod2,mod3" they need a way to intercept the value-acceptance @ desc-assignment time in the front-end. This optional override() function does just that when present in the spec. The current setting's value is passed to the override, and if what's returned differs from what was passed (by pointer value), then the current value is freed and the override takes its place. The override function is expected to _always_ return non-NULL; either the value provided, or a newly allocated value override. The override function must never free the supplied value, that's the front-end's job in applying the override. The override() must return NULL on errors, which are assumed to be limited to ENOMEM failures.
2023-06-03til_settings: require value in til_settings_add_value()Vito Caputo
There doesn't seem to be a use case for inserting NULL-value settings, and it's ergonomic to assume a til_setting_t.value is always a non-NULL heap-allocated string.
2023-05-26til_settings: add some settings and desc path printersVito Caputo
These print to a stdio FILE*, which for now is harmless since setup_interactively() will be the only consumer (... for now). If one needed the path in a buffer, they could use open_memstream() and pass that FILE* to the printers. And since commit 40feb61 there's already a dependency on the function, but it's icky to dig deeper into that portability trap. Although it seemed like rototiller actually compiled on MacOS at Gene's house, so maybe open_memstream() isn't as problematic as it once was. Anywhow, this commit only adds the path printing helpers, nothing is using them yet.
2023-05-26til_settings: add til_setting_spec_t.as_labelVito Caputo
Currently settings instances get labels from three sources: 1. explicitly labeled by a root-level til_settings_new() call, like main.c::til_settings_new(NULL, "video", args->video); 2. implicitly labeled in a spec.as_nested_settings w/spec.key 3. positionally labeled in a spec.as_nested_settings w/o spec.key But when constructing setting/desc paths, using strictly these settings instance labels as the "directory name path component" equivalent, leaves something to be desired. Take this hypothetical module setting path for example: /module/layers/[0]/viscosity Strictly using settings instance labels as-is, the above is what you'd get for the drizzle::viscosity setting in something like: --module=compose,layers=drizzle Which is really awkward. What's really desired is more like: /module/compose/layers/[0]/drizzle/viscosity Now one way to achieve that is to just create more settings instances to hold these module names as labels and things would Just Work more or less. But that would be rather annoying and heavyweight, when what's _really_ wanted is a way to turn the first entry's value of a given setting instance into a sort of synthetic directory component in the path. So that's what this commit does. When a spec has .as_label specified, it's saying that path construction should treat this setting's value as if it were a label on a settings instance. But it's special cased to only apply to descs hanging off the first entry of a settings instance, as that's the only scenario we're making use of, and it avoids having to do crazy things like search all the entries for specs w/.as_label set. It feels a bit janky but it does achieve what's needed with little pain/churn.
2023-05-26til_settings: drop settings->label from generated labelVito Caputo
Since these are ultimately intended for use in path construction, it's redundant to include the settings->label in the generated label. Instead what's really useful is just the subscript part: /module/compose/layers/layers[0]/drizzle/viscosity Becomes: /module/compose/layers/[0]/drizzle/viscosity which is far better. It may seem silly to have both the positional subscript *and* the module name, as in why not just have: /module/compose/layers/drizzle/viscosity But there's a need ot handle potential collisions like so: /module/compose/layers/[0]/drizzle/viscosity /module/compose/layers/[1]/stars /module/compose/layers/[2]/drizzle/viscosity So then maybe you think; ok, why have the module name? just use the positional subscript since that alone prevents the collisions. Result: /module/compose/layers/[0]/viscosity ... /module/compose/layers/[2]/viscosity Well, now we've lost useful context. The viscosity setting recurs on multiple modules, and we don't know just at a glance what we're working with anymore. Hence, why there's both. The module name in the path makes things substantially more self-explanatory. These paths will likely be what you're looking at as the labels of tracks in a multitrack sequencer like GNU Rocket. So this decision is likely affecting the UX at that level in the fullness of time.
2023-05-24til_settings: til_setting_t,til_settings_t get parent pointersVito Caputo
Preparatory for constructing unique paths from a given setting/settings instance by walking up the tree
2023-05-11til_settings: free nested settingsVito Caputo
til_settings_free() needs to recur on nested settings
2023-05-11til_settings: rename til_settings_t.settings to entriesVito Caputo
settings->settings[] is obnoxious largely mechanical rename to settings->entries[]
2023-05-11til_settings: helper for labeling positional instancesVito Caputo
When there's a bare-value setting turned into a nested settings instance, there's no key onhand for labeling the instance. But such nameless settings are basically array elements only positionally accessed. This helper produces labels in that style for such settings by taking the container settings label and adding [$idx] to the end. These labels aren't really used as more than a debugging aid at the moment. But module contexts already have paths in main, and it seems like these settings instance labels will likely become the name components in constructing those paths.
2023-05-11til_settings: recursive til_settings_as_arg()Vito Caputo
Currently in rototiller the only (de)serialization format of settings is the args strings, so this is a rather critical piece to get in for recursive settings to really be usable. This is a quick and dirty implementation utilizing open_memstream() which despite being POSIX has spotty support (I don't think MacOS has it for instance). So that's probably something to rip out in the future. Nonetheless, this moves things forward and works fine on GNU.
2023-05-11til_settings: make use of til_setting_desc_t.containerVito Caputo
This commit pivots everything over to using desc->container as the target settings instance when adding settings, as well as actually assigning the settings container @ desc create. Given nothing is actually triggering settings heirarchies yet (no specs set as_nested_settings) this shouldn't actually result in any realized functional difference, yet. The settings pointer being placed in desc->container should be identical to what was getting used before.
2023-05-11til_settings: don't check values on nested settingsVito Caputo
There needs to be more flexibility in the value checking enforcement. This is just a quick blunt-hammer fix to not trip over nested settings values which will be huge undeterministic messes vs. what's likely just a set of simple presets in the spec.values[] The individual leaf settings will still be checked if they specify values. So this change just stops even bothering to check unless the setting is a leaf. This area needs more work in general, see comments. For instance right now we can't just pass in arbitrary floats for settings which list float values, not if that arbitrary float isn't a member of the list. In some circumstances that's the right thing to do, as in the module can only work with the presets. But most of the time, the module would be perfectly happy with e.g. foo=.3379 with foo's spec.values[] = { .01, .1, .25, .75, 1} so the check fails. That's dumb, and interferes with the creative process when you're just poking different numbers into the settings to see what happens. TODO
2023-05-11til_settings: add til_settings_get_count()Vito Caputo
Getter for accessing til_settings_t.num With recursive settings modules will start using settings instances to represent things like lists of module names. (modules/compose::layers for instance) For those cases they'll want to know the number of settings in the instance before iterating across getting their values positionally.
2023-05-11til_settings: introduce til_setting_spec_t concept vs. descVito Caputo
For recursive settings the individual setting being described needs to get added to a potentially different settings instance than the one being operated on at the top of the current setup_func phase. The settings instance being passed around for a setup_func to operate on is constified, mainly to try ensure modules don't start directly mucking with the settings. They're supposed to just describe what they want next and iterate back and forth, with the front-end creating the settings from the returned descs however is appropriate, eventually building up the settings to completion. But since it's the setup_func that decides which settings instance is appropriate for containing the setting.. at some point it must associate a settings instance with the desc it's producing, one that is going to be necessarily written to. So here I'm just turning the existing til_setting_desc_t to a "spec", unchanged. And introducing a new til_setting_desc_t embedding the spec, accompanied by a non-const til_settings_t* "container". Now what setup_funcs use to express settings are a spec, otherwise identically to before. Instead of cloning a desc to allocate it for returning to the front-end, the desc is created from a spec with the target settings instance passed in. This turns the desc step where we take a constified settings instance and cast it into a non-const a more formal act of going from spec->desc, binding the spec to a specific settings instance. It will also serve to isolate that hacky cast to a til_settings function, and all the accessors of til_setting_desc_t needing to operate on the containing settings instance can just do so. As of this commit, the container pointer is just sitting in the desc_t but isn't being made use of or even assigned yet. This is just to minimize the amount of churn happening in this otherwise mostly mechanical and sprawling commit. There's also been some small changes surrounding the desc generators and plumbing of the settings instance where there previously wasn't any. It's unclear to me if desc generators will stay desc generators or turn into spec generators. For now those are mostly just used by the drm_fb stuff anyways, modules haven't made use of them, so they can stay a little crufty harmlessly for now.
2023-05-11til_settings: rework setting get/add for bare valuesVito Caputo
The core thing here is rather than turning a bare value into a key as I was doing before - we just leave the bare value as a bare value and its setting must be located positionally via get_value_by_idx since there's no key. Existing callers that used to get_key() positionally now get_value_by_idx() positionally all the same, except it's the value instead of the key. This is mostly done for things like the module or fb name at the front of a settings instance. The impetus for this change is partially just cosmetic/ergonomics, but it's also rather strange for what's really a key-less value to be treated as a value-less key. It was also awkward to talk/reason about on the road to recursive settings where bare values would be supported as a standalone settings instance if properly escaped... This also adds unescaping of keys, and adds a dependency on the somewhat linux-specific open_memstream() which may need changing in the future (see comments).
2023-05-11til_settings: add til_settings_t.value_as_nested_settingsVito Caputo
Preparatory commit for settings hierarchies.
2023-05-10til_settings: label til_settings_t instancesVito Caputo
This adds a mandatory label string to til_setttings_new() and updates call sites accordingly. For now the root-level settings created by main.c are simply named "module" and "video" respectively. Any nested settings creations on behalf of modules will be labeled using the module's name the settings are being created for use with. This might evolve with time, for now it's just a minimum churn kind of decision. I can see it changing such that the top-level settings also become labeled by the module/video driver name rather than the obtuse "module" "video" strings. How these will be leveraged is unclear presently. At the least it'll be nice to have a label for debugging til_settings_t heirarchies once recursive settings support lands. In a sense this is a preparatory commit for that work. But I could see the labels ending up in serialization contents as markup/syntactic sugar just to self-document things as well. There might also be a need to address til_settings_t instances in the settings heirarchy, which may be something like a "label/label/label/label" path style thing - though there'd be a need to deal with name collisions in that approach. I'm just thinking a bit about how knobs will become addressed when those become a real thing. The settings label heirarchy might be the convenient place to name everything in a tree, which knobs could then inherit their parent paths from under which their respective knob labels will reside. For the whole name collision issue there could just be some builtin settings keys for overriding the automatic module name labeling, something like: --module=compose,layers=checkers\,label=first\,fill_module=shapes:checkers\,label=second\,fill_module=shapes would result in: /module/first/shapes /module/second/shapes or in a world where the root settings weren't just named "module" and "video": /compose/first/shapes /compose/second/shapes then if there were knobs under checkers and shapes, say checkers had a "foo" knob and checkers had a "bar" knob, they'd be under .knobs in each directory: /compose/first/.knobs/foo /compose/first/shapes/.knobs/bar /compose/second/.knobs/foo /compose/second/shapes/.knobs/bar something along those lines, and of course if compose had knobs they'd be under /compose/.knobs This is just a brain dump and will surely all change before implemented.
2022-07-20til_settings: support rudimentary =value escapingVito Caputo
This is a step towards properly handling nested settings, so we can do stuff like: --module=rtv,channels=compose\,layers=checkers\\\,fill_module=shapes\\\,size=64\,texture=plasma and have rtv actually cycle through just compose with checkers+plasma layers but holding the specified checkers settings to shapes filler with a size of 64, randomizing the rest. There's more work to do before that can actually happen, but first thing is to just support escaping the settings values.
2022-07-15til_fb: switch til_fb_ops_t.init() to use til_setup_tVito Caputo
Until now the fb init has been receiving a til_settings_t to access its setup. Now that there's a til_setup_t for representing the fully baked setup, let's bring the fb stuff up to speed so their init() behaves more like til_module_t.create_context() WRT settings/setup. This involves some reworking of how settings are handled in {drm,sdl}_fb.c but nothing majorly different. The only real funcitonal change that happened in the course of this work is I made it possible now to actually instruct SDL to do a more legacy SDL_WINDOW_FULLSCREEN vs. SDL_WINDOW_FULLSCREEN_DESKTOP where SDL will attempt to switch the video mode. This is triggered by specifying both a size=WxH and fullscreen=on for video=sdl. Be careful though, I've observed some broken display states when specifying goofy sizes, which look like Xorg bugs.
2022-05-25*: normalize on all case-insensitive comparisonsVito Caputo
I don't think rototiller is an appropriate place for being so uncooperative, if someone gets the case wrong anywhere just make it work. We should avoid making different things so subtly different that case alone is the distinction anyways, so I don't see this creating any future namespace collision problems.
2022-04-01til_settings: make res_{desc,setting} optionalVito Caputo
The til_settings_get_and_describe_value() helper (and the calling setup methods in the modules) can be useful in independently spitting out a baked setup instance from a fully resolved til_settings_t which has already gone through the whole rigamarole of getting populated and described. Normally when this all happens in one place with the setup instance then either immediately fed to create_context(), or stowed somewhere for future use, it's not a problem to always require the res_desc,res_setting parameters. But especially in GUI scenarios (glimmer) the whole populate and describe phase of til_settings_t can very easily be done in a separate place from the convenient place to produce a setup out of it. So when the caller /knows/ the setup is finished and a subsequent call with the same til_settings_t would produce a res_setup immediately, the caller should be able to omit res_setting and res_desc as they're of no use now. This is all kind of crufty, but it's nice to have all this happening in a single setup method to help keep the res_setup phase from diverging/becoming out of sync with the populate+describe phase. Will live with it for now. Frontends get written far less than modules, so the API cruft from the frontend perspective is relatively benign. It's still relatively sane and ergonomic from the module writer's perspective.
2022-03-30til_settings: fix empty values in til_settings_new()Vito Caputo
Previously if you supplied an empty setting value like so: "--module=compose,layers=" The interactive setup would get itself into an infinite loop because the layers setting is already present, but has a NULL value. This wasn't a NULL value, it was a "" value. The parser should just fallthrough to the value state from the equal state after recording the value's start pointer. This will result in a "" value getting allocated and assigned to the value before the loop breaks out on the '\0' immediately following the '='. There are probably other edge cases which need better handling here.
2022-03-30til_settings: remove vestigial return missed by 7ff8efVito Caputo
Commit 7ff8ef included some fast and dirty fixups to til_settings_apply_desc_generators(), but left an inappropriate return path out of the iterator resulting in the caller accessing a NULL res_desc. The practical result of this was segfaulting in rototiller when configuring anything utilizing desc generators, like drm_fb.
2022-03-28til_settings: provide a user_data pointer w/til_setting_tVito Caputo
Particularly in implementing a stateful/"retained" GUI it can be desirable to embed something like a widget pointer in a til_setting_t once described and shown to the user. Management of this pointer is largely nonexistant from the libtil perspective. It's simply initialized to NULL when a new setting is added, and never accessed again. 100% the caller's responsibility. This works fine since libtil/til_settings_t only accumulates til_setting_t entries and never removes them except when discarding an entire til_settings_t wholesale.
2022-03-19*: de-constify til_setting_t throughoutVito Caputo
Now that til_setting_t.desc is not only a thing, but a thing that is intended to be refreshed regularly in the course of things like GUI interactive settings construction, it's not really appropriate to try even act like this these are const anymore.
2022-03-19til_settings: introduce til_settings_reset_descs()Vito Caputo
This is helpful for forcing underlying setup methods to redescribe their settings, regardless of what a til_settings_t's internal state is.
2022-03-12til_settings: always describe relevant settingsVito Caputo
The existing iterative *_setup() interface only described settings not found, quietly accepting usable settings already present in the til_settings_t. This worked fine for the existing interactive text setup thing, but it's especially problematic for providing a GUI setup frontend. This commit makes it so the *_setup() methods always describe undescribed settings they recognize, leaving the setup frontend loop calling into the *_setup() methods to both apply the description validation if wanted and actually tie the description to respective setting returned by the _setup() methods as being related to the returned description. A new helper called til_settings_get_and_describe_value() has been introduced primarily for use of module setup methods to simplify this nonsense, replacing the til_settings_get_value() calls and surrounding logic, but retaining the til_setting_desc_t definitions largely verbatim. This also results in discarding of some ad-hoc til_setting_desc_check() calls, now that there's a centralized place where settings become "described" (setup_interactively in the case of rototiller). Now a GUI frontend (like glimmer) would just provide its own setup_interactively() equivalent for constructing its widgets for a given *_setup() method's chain of returned descs. Whereas in the past this wasn't really feasible unless there was never going to be pre-supplied settings. I suspect the til_setting_desc_check() integration into setup_interactively() needs more work, but I think this is good enough for now and I'm out of spare time for the moment.
2021-10-01*: librototiller->libtilVito Caputo
Largely mechanical rename of librototiller -> libtil, but introducing a til_ prefix to all librototiller (now libtil) functions and types where a rototiller prefix was absent. This is just a step towards a more libized librototiller, and til is just a nicer to type/read prefix than rototiller_.
© All Rights Reserved