feat(plugins): inspect and edit selected track effects (phase 86)

This commit is contained in:
Johannes Findeisen 2026-11-06 01:39:31 +01:00
commit eb71ca765f
5 changed files with 33 additions and 4 deletions

View file

@ -1970,12 +1970,12 @@ Implemented: selected insert Up/Down, bypass and removal, preserving effect meta
Show selected effect identity and supported generic controls. Provide reset where supported and clearly identify unavailable native editors/parameters.
### Tasks and acceptance criteria
- [ ] Implement the described workflow with validated errors and safe ownership.
- [ ] Pass relevant core and/or GUI tests.
- [ ] Document behavior and limitations; commit this phase separately.
- [x] Implement the described workflow with validated errors and safe ownership.
- [x] Pass relevant core and/or GUI tests.
- [x] Document behavior and limitations; commit this phase separately.
### Implementation status
Planned.
Implemented: selected insert Inspect/edit verifies identity and shows generic controls with reset/defaults through transactional preparation. Zero-parameter adapters explicitly explain default configuration and unavailable native editors; reset is disabled there. Focused real modal reset/apply/cancel, adoption, undo and reload tests passed with a warning-enabled GUI build.
---

View file

@ -44,3 +44,9 @@ Select a slot in the rack, then use **Up**, **Down**, **Bypass** or **Remove**.
The selection follows reordered effects. Bypassed slots retain their settings
and appear marked in the rack; their nodes are omitted from the compiled graph.
Each successful operation creates one project undo step.
**Inspect / edit** verifies the selected plugin and opens its identity and generic
controls. Reset defaults clears parameter automation on Apply. Cancel leaves the
project unchanged. Internal effects and LADSPA expose controls; modern adapters
currently expose none and run default configurations. Native plugin editor
windows and opaque plugin-state chunks are not implemented.

View file

@ -78,11 +78,16 @@ bool xtc_edit_plugin(const xtc_plugin_spec &spec, const xtc_plugin_details &deta
((details.flags[i] & XTC_PLUGIN_LOGARITHMIC) ? "; logarithmic hint" : "");
auto *range = new Fl_Box(25,y+27,715,25); range->copy_label(hint.c_str()); range->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
}
if(!spec.control_count) {
auto *unavailable=new Fl_Box(25,160,730,75,"This adapter exposes no editable parameters. The plugin runs with its default configuration.\nNative plugin editor windows are not available in this host.");
unavailable->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
}
scroll->end();
auto *note = new Fl_Box(15,515,770,30,"Automation overrides static controls. Reset defaults also clears all plugin automation.");
note->labelsize(12);
struct Reset { const xtc_plugin_details *details; std::array<Fl_Value_Input *,XTC_PLUGIN_CONTROLS> *inputs; unsigned int count; bool used; } reset{&details,&inputs,spec.control_count,false};
auto *defaults = new Fl_Button(20,555,170,30,"Reset defaults");
if(!spec.control_count)defaults->deactivate();
defaults->callback([](Fl_Widget *, void *data) {
auto *r = static_cast<Reset *>(data); r->used = true;
for (unsigned int i = 0; i < r->count; ++i) (*r->inputs)[i]->value(r->details->parameters[i].default_value);

View file

@ -35,6 +35,8 @@ class TrackInsertsPanel : public Fl_Group {
auto *button=new Fl_Button(left,y+12,82,28,action.name);left+=90;
button->callback([](Fl_Widget *w,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);int command=!strcmp(w->label(),"Up") ? -1 : !strcmp(w->label(),"Down") ? 1 : !strcmp(w->label(),"Bypass") ? 2 : 3;p->result(p->edit_slot(command));},this);
}
auto *inspect=new Fl_Button(x+850,y+12,120,28,"Inspect / edit");
inspect->callback([](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->inspect_slot());},this);
message_=new Fl_Box(x+16,y+50,w-32,32,"Track input > inserts > output gain > track fader > bus/master");message_->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
slots_=new Fl_Hold_Browser(x+16,y+94,230,h-110);slots_->format_char(0);
graph_=new GraphWidget(x+260,y+94,w-276,h-110,nullptr,[](void *,const xtc_graph_edit &,size_t *){return XTC_ERR_UNSUPPORTED;},nullptr,message_);
@ -46,6 +48,15 @@ class TrackInsertsPanel : public Fl_Group {
void select_track(uint64_t id) {track_=id;refresh(true);}
const xtc_graph *graph() const {return model_;}
void add(const char *file,unsigned int index) { result(owner_->add_track_effect(track_,file,index)); }
xtc_result inspect_slot() {
xtc_track_chain chain{};auto r=xtc_project_get_chain(owner_->project_.get(),track_,&chain);size_t index=selected_slot();
if(r!=XTC_OK)return r;
if(index>=chain.count)return XTC_ERR_INVALID_STATE;
xtc_plugin_details details{};xtc_plugin_spec edited{};
r=xtc_plugin_describe(&chain.slots[index].plugin,owner_->sample_rate(),&details);if(r!=XTC_OK)return r;
if(!xtc_edit_plugin(chain.slots[index].plugin,details,edited))return XTC_OK;
chain.slots[index].plugin=edited;return owner_->set_track_chain(track_,chain);
}
/* Commands: -1 up, 1 down, 2 toggle bypass, 3 remove. */
xtc_result edit_slot(int command) {
xtc_track_chain chain{};auto r=xtc_project_get_chain(owner_->project_.get(),track_,&chain);size_t index=selected_slot();

View file

@ -242,6 +242,13 @@ int track_insert_tests()
CHECK(panel->edit_slot(3)==XTC_OK && window.undo()==XTC_OK);panel->refresh(true);
CHECK(xtc_project_get_chain(s->project(),track,&chain)==XTC_OK && chain.count==2);
CHECK(panel->edit_slot(3)==XTC_OK);
CHECK(xtc_project_get_chain(s->project(),track,&chain)==XTC_OK);chain.slots[0].plugin.values[0]=10;
CHECK(window.set_track_chain(track,chain)==XTC_OK);
Fl::add_timeout(.05,[](void *){auto *dialog=Fl::modal();CHECK(dialog);press(find(dialog,"Reset defaults"));press(find(dialog,"Apply"));});
CHECK(panel->inspect_slot()==XTC_OK);
CHECK(xtc_project_get_chain(s->project(),track,&chain)==XTC_OK && chain.slots[0].plugin.values[0]!=10);
const auto *cancel_before=s->project();
Fl::add_timeout(.05,[](void *){press(find(Fl::modal(),"Cancel"));});CHECK(panel->inspect_slot()==XTC_OK && s->project()==cancel_before);
CHECK(window.save_project("/tmp/xtc-inserts-gui.xtc")==XTC_OK && window.new_project()==XTC_OK && window.open_project("/tmp/xtc-inserts-gui.xtc")==XTC_OK);
CHECK(xtc_project_get_chain(s->project(),track,&chain)==XTC_OK && chain.count==1);unlink("/tmp/xtc-inserts-gui.xtc");
window.do_callback();puts("Track inserts GUI adoption/undo/rollback/reload passed.");return failures ? 1 : 0;