Seperating the sequencer into multiple widgets.

This commit is contained in:
Johannes Findeisen 2026-11-06 21:39:38 +01:00
commit e664414796
23 changed files with 1455 additions and 914 deletions

View file

@ -2,6 +2,10 @@
#include "../../src/gui/sample_editor.hpp"
#include "../../src/gui/graph_widget.hpp"
#include "../../src/gui/sequencer_widget.hpp"
#include "../../src/gui/sequencer_track_widget.hpp"
#include "../../src/gui/sequencer_clip_widget.hpp"
#include "../../src/gui/sequencer_velocity_widget.hpp"
#include "../../src/gui/sequencer_ruler_widget.hpp"
#include "../../src/gui/piano_roll.hpp"
#include "../../src/gui/mixer_widget.hpp"
#include "../../src/gui/plugin_dialog.hpp"
@ -428,8 +432,78 @@ int midi_device_label_tests()
press(find(&dialog,"Apply"));CHECK(!applied.midi_input_port[0] && !applied.midi_output_port[0]);
puts("MIDI device dropdown labels/selection/refresh checks passed.");return failures ? 1 : 0;
}
int sequencer_component_tests()
{
reset();
{
MainWindow window(false,""); window.show(); auto *s=timeline(&window);
CHECK(window.create_track(true)==XTC_OK);
uint64_t first=s->selected_track(),clip=s->selected_clip();
CHECK(window.create_track(true)==XTC_OK);
uint64_t second=s->selected_track();
auto *first_view=s->track_widget(first),*second_view=s->track_widget(second);
CHECK(first_view && second_view && first_view->parent()==s && second_view->parent()==s);
CHECK(first_view->clip_widget(clip) && first_view->clip_widget(clip)->parent()==first_view);
CHECK(first_view->velocity_lane()->parent()==first_view && !first_view->velocity_lane()->visible());
CHECK(first_view->header()->parent()==first_view && s->instrument_choice(first)->parent()==first_view->header());
int rulers=0;
for(int i=0;i<s->children();++i) if(dynamic_cast<SequencerRulerWidget *>(s->child(i))) ++rulers;
CHECK(rulers==1 && s->children()==3);
CHECK(s->expand_track(first,true));
CHECK(first_view->velocity_lane()->visible() && second_view->y()==first_view->y()+first_view->h());
CHECK(s->select(first,clip));
CHECK(s->move_track(1)==XTC_OK);
CHECK(s->track_widget(first)==first_view && s->track_widget(second)==second_view);
CHECK(s->move_track(-1)==XTC_OK);
// Route through FLTK's window dispatch and mouse capture, across track boundaries.
pump();
int ox=Fl::e_x,oy=Fl::e_y,ok=Fl::e_keysym,os=Fl::e_state;
Fl::e_x=s->x()+s->header_width()+20; Fl::e_y=s->track_top(0)+20;
Fl::e_keysym=FL_Button+FL_LEFT_MOUSE; Fl::e_state=FL_BUTTON1;
CHECK(Fl::handle(FL_PUSH,&window)==1 && Fl::pushed());
Fl::e_x+=48; Fl::e_y=s->track_top(1)+20;
CHECK(Fl::handle(FL_DRAG,&window)==1);
Fl::e_state=0; CHECK(Fl::handle(FL_RELEASE,&window)==1);
Fl::e_x=ox; Fl::e_y=oy; Fl::e_keysym=ok; Fl::e_state=os;
xtc_clip_info moved{}; CHECK(xtc_project_find_clip(s->project(),clip,&moved)==XTC_OK);
CHECK(moved.track_id==second && moved.start_tick==960);
CHECK(!first_view->clip_widget(clip) && second_view->clip_widget(clip));
CHECK(window.undo(false)==XTC_OK);
CHECK(s->track_widget(first)==first_view && first_view->clip_widget(clip));
CHECK(window.undo(true)==XTC_OK && second_view->clip_widget(clip));
CHECK(s->expand_track(second,true) && s->select(second,clip));
uint64_t note_id=0;
CHECK(xtc_project_add_note(s->project(),clip,480,480,60,90,0,&note_id)==XTC_OK);
CHECK(s->rename_selection("Nested clip")==XTC_OK); pump();
Fl::e_x=s->x()+s->header_width()+72;
Fl::e_y=second_view->y()+56+80-90*60/127;
Fl::e_keysym=FL_Button+FL_LEFT_MOUSE; Fl::e_state=FL_BUTTON1;
CHECK(Fl::handle(FL_PUSH,&window)==1);
Fl::e_y+=20; CHECK(Fl::handle(FL_DRAG,&window)==1);
Fl::e_state=0; CHECK(Fl::handle(FL_RELEASE,&window)==1);
xtc_note_info note{}; CHECK(xtc_project_get_note(s->project(),0,&note)==XTC_OK && note.velocity<90);
Fl::e_x=ox; Fl::e_y=oy; Fl::e_keysym=ok; Fl::e_state=os;
CHECK(s->select(first) && s->delete_selection()==XTC_OK);
CHECK(!s->track_widget(first) && s->track_widget(second)==second_view);
pump(); // Deferred removal of a widget during its event is safe.
CHECK(window.undo(false)==XTC_OK && s->track_widget(first));
CHECK(s->expand_track(second,true)); pump();
Fl::e_x=s->x()+s->header_width()+72;
Fl::e_y=second_view->y()+56+80-static_cast<int>(note.velocity)*60/127;
Fl::e_keysym=FL_Button+FL_LEFT_MOUSE; Fl::e_state=FL_BUTTON1;
CHECK(Fl::handle(FL_PUSH,&window)==1);
// Replacing a project also cancels a captured child gesture.
CHECK(window.new_project()==XTC_OK && s->children()==1 && !s->track_widget(second));
Fl::e_state=0; Fl::handle(FL_RELEASE,&window);
Fl::e_x=ox; Fl::e_y=oy; Fl::e_keysym=ok; Fl::e_state=os;
pump(); window.do_callback();
}
return failures ? 1 : 0;
}
int main(int argc, char **argv)
{
if(std::getenv("XTC_TEST_SEQUENCER_COMPONENTS_ONLY")) return sequencer_component_tests();
if(std::getenv("XTC_TEST_MIDI_LABELS_ONLY"))return midi_device_label_tests();
if(std::getenv("XTC_TEST_MIDI_WORKFLOWS_ONLY"))return midi_workflow_tests();
if(std::getenv("XTC_TEST_CREATIVE_ONLY"))return creative_workflow_tests();
@ -1213,6 +1287,7 @@ int main(int argc, char **argv)
xtc_project_get_counts(sequence->project(),&tracks,&clips); CHECK(tracks == 2 && clips == 1);
unlink("/tmp/xtc-workspace.xtc"); window.do_callback();
}
sequencer_component_tests();
reset();
{
MainWindow window(false,""); window.show(); auto *s=timeline(&window);