feat(inserts): copy and paste chains between tracks (phase 92)
This commit is contained in:
parent
062b33f55f
commit
58f0dc51c5
5 changed files with 40 additions and 4 deletions
|
|
@ -17,3 +17,12 @@ Select a slot, then **Rack actions → Duplicate effect**. The copy appears dire
|
|||
after it, retaining controls, automation, wet amount and bypass. It is an
|
||||
independent instance with fresh processing history. Eight-slot capacity and
|
||||
plugin preparation errors preserve the old chain; Undo removes the copy.
|
||||
|
||||
## Copy a chain between tracks
|
||||
|
||||
**Rack actions → Copy chain** stores an independent metadata snapshot. Select
|
||||
another track and use **Paste chain (replace)** to replace its complete chain,
|
||||
including output gain. Copying neither loads modules nor changes undo history;
|
||||
pasting prepares the candidate and is undoable. The clipboard is internal to
|
||||
this session and clears on successful New/Open. Preparation errors keep both
|
||||
the destination and clipboard intact.
|
||||
|
|
|
|||
|
|
@ -2088,12 +2088,12 @@ Implemented: bounded C99 metadata duplication and Rack actions/Duplicate effect
|
|||
Copy and paste independent chain metadata between tracks, with explicit replacement, undo and document-lifecycle cleanup. Clipboard operations must not load modules.
|
||||
|
||||
### Tasks and acceptance criteria
|
||||
- [ ] Implement the workflow with bounded validation, safe preparation and documented limits.
|
||||
- [ ] Pass meaningful core and/or GUI checks, including error and undo behavior.
|
||||
- [ ] Document results and commit this phase separately.
|
||||
- [x] Implement the workflow with bounded validation, safe preparation and documented limits.
|
||||
- [x] Pass meaningful core and/or GUI checks, including error and undo behavior.
|
||||
- [x] Document results and commit this phase separately.
|
||||
|
||||
### Implementation status
|
||||
Planned.
|
||||
Implemented: session-local independent chain copy/paste with explicit destination replacement, output-gain preservation and prepared undoable adoption. Paste readiness is visible in the menu and successful New/Open clears the clipboard. Focused GUI tests passed for independence, cross-track paste, undo, failed preparation and lifecycle cleanup.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1405,6 +1405,7 @@ xtc_result MainWindow::install_project(xtc_project *candidate, bool reset_histor
|
|||
if (reset_history) {
|
||||
history_.swap(new_history);
|
||||
for(auto &snapshot:mix_snapshots_)snapshot.reset();
|
||||
if(track_inserts_)track_inserts_->clear_session();
|
||||
}
|
||||
graph_widget_->reset_layout();
|
||||
graph_widget_->set_graph(xtc_project_graph(candidate));
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ class TrackInsertsPanel : public Fl_Group {
|
|||
xtc_graph *model_=nullptr;
|
||||
uint64_t track_=UINT64_MAX;
|
||||
xtc_track_chain cached_{};
|
||||
xtc_track_chain clipboard_{};
|
||||
bool clipboard_ready_=false;
|
||||
std::vector<uint64_t> ids_;
|
||||
std::vector<std::string> names_;
|
||||
void result(xtc_result r) { if(r!=XTC_OK)owner_->report_error("Track inserts",r);refresh(true); }
|
||||
|
|
@ -51,6 +53,8 @@ class TrackInsertsPanel : public Fl_Group {
|
|||
gain_=new Fl_Value_Input(x+360,y+52,100,26,"Chain gain");gain_->bounds(0,4);gain_->step(.01);gain_->when(FL_WHEN_RELEASE);
|
||||
for(auto *input:{wet_,gain_})input->callback([](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->set_mix(p->wet_->value(),p->gain_->value()));},this);
|
||||
actions_=new Fl_Menu_Button(x+486,y+52,150,26,"Rack actions");
|
||||
actions_->add("Copy chain",0,[](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->copy_chain());},this);
|
||||
actions_->add("Paste chain (replace)",0,[](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->paste_chain());},this,FL_MENU_INACTIVE);
|
||||
actions_->add("Duplicate effect",0,[](Fl_Widget *,void *c){auto *p=static_cast<TrackInsertsPanel *>(c);p->result(p->duplicate_slot());},this);
|
||||
message_=new Fl_Box(x+16,y+84,w-32,30,"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+126,230,h-142);slots_->format_char(0);slots_->callback([](Fl_Widget *,void *c){static_cast<TrackInsertsPanel *>(c)->update_mix();},this);
|
||||
|
|
@ -64,6 +68,20 @@ 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)); }
|
||||
void clear_session() {clipboard_={};clipboard_ready_=false;update_actions();}
|
||||
bool clipboard_ready() const {return clipboard_ready_;}
|
||||
void update_actions() {
|
||||
int index=actions_->find_index("Paste chain (replace)");
|
||||
if(index>=0)actions_->mode(index,clipboard_ready_ ? 0 : FL_MENU_INACTIVE);
|
||||
}
|
||||
xtc_result copy_chain() {
|
||||
xtc_track_chain chain{};auto r=xtc_project_get_chain(owner_->project_.get(),track_,&chain);
|
||||
if(r==XTC_OK){clipboard_=chain;clipboard_ready_=true;update_actions();}return r;
|
||||
}
|
||||
xtc_result paste_chain() {
|
||||
if(!clipboard_ready_)return XTC_ERR_NOT_FOUND;
|
||||
return owner_->set_track_chain(track_,clipboard_);
|
||||
}
|
||||
xtc_result duplicate_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)r=xtc_track_chain_duplicate(&chain,index,&chain);
|
||||
|
|
|
|||
|
|
@ -232,6 +232,14 @@ int creative_workflow_tests()
|
|||
CHECK(panel->duplicate_slot()==XTC_OK && panel->selected_slot()==1);
|
||||
xtc_track_chain chain{};CHECK(xtc_project_get_chain(s->project(),first_track,&chain)==XTC_OK && chain.count==2);
|
||||
CHECK(window.undo()==XTC_OK);panel->refresh(true);CHECK(xtc_project_get_chain(s->project(),first_track,&chain)==XTC_OK && chain.count==1);
|
||||
CHECK(!panel->clipboard_ready() && panel->paste_chain()==XTC_ERR_NOT_FOUND);
|
||||
CHECK(panel->copy_chain()==XTC_OK && panel->clipboard_ready());
|
||||
CHECK(panel->set_mix(.2,.6)==XTC_OK);
|
||||
panel->select_track(second_track);CHECK(panel->paste_chain()==XTC_OK);
|
||||
CHECK(xtc_project_get_chain(s->project(),second_track,&chain)==XTC_OK && chain.count==1 && chain.output_gain==1 && chain.slots[0].wet==1);
|
||||
CHECK(window.undo()==XTC_OK);panel->refresh(true);CHECK(xtc_project_get_chain(s->project(),second_track,&chain)==XTC_OK && chain.count==0);
|
||||
submit_result=XTC_ERR_INVALID_STATE;auto *unchanged=s->project();CHECK(panel->paste_chain()==XTC_ERR_INVALID_STATE && s->project()==unchanged);submit_result=XTC_OK;
|
||||
CHECK(window.new_project()==XTC_OK && !panel->clipboard_ready() && panel->paste_chain()==XTC_ERR_NOT_FOUND);
|
||||
window.do_callback();puts("Creative workflow GUI checks passed.");return failures ? 1 : 0;
|
||||
}
|
||||
int track_insert_tests()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue