feat(gui): compact track creation and make the inspector optional (phase 80)
This commit is contained in:
parent
9e380d4dd0
commit
e9d783146f
4 changed files with 198 additions and 41 deletions
150
docs/ROADMAP.md
150
docs/ROADMAP.md
|
|
@ -1874,6 +1874,156 @@ See [AUDIO_EDITOR.md](AUDIO_EDITOR.md) for precise workflows and limits.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Phase 80 — Compact Creation and Optional Track Inspector
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
Replace the large creation sidebar with a sequencer Create dropdown. Keep all creation actions and shortcuts, and provide an optional track inspector to reclaim horizontal editing space.
|
||||||
|
|
||||||
|
### Tasks and acceptance criteria
|
||||||
|
- [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
|
||||||
|
Implemented: sequencer Create menu retains empty/audio/MIDI track creation, WAV import, instrument loading and MIDI editing. The inspector is hidden by default and available under View/Track inspector, reclaiming 204 pixels. Core baseline and full Xvfb GUI suite passed, including menu callbacks, creation/undo, layout sizes and floating panels. Inspector visibility is session-local.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 81 — Persistent Track Insert Chains
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
Add a bounded C99 per-track insert model with validation, clone/history/duplicate support and backward-compatible project persistence. Loading metadata must not load plugin binaries.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
### Implementation status
|
||||||
|
Planned.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 82 — Prepared Track Insert Processing
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
Compile track inserts into serial modular graphs before track gain/pan. Cover audio and MIDI rendering, export, bypass, cleanup and callback safety; explicitly reject unsupported routing.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
### Implementation status
|
||||||
|
Planned.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 83 — Track Inserts in the Modular Workspace
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
Offer a selected-track insert view alongside the global graph, with clear signal order and transactional Add effect actions.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
### Implementation status
|
||||||
|
Planned.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 84 — Searchable Effect Discovery
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
Make LADSPA, VST2, VST3 and CLAP effects easy to find and add, including Linux VST3 bundles, format filters and clear compatibility errors.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
### Implementation status
|
||||||
|
Planned.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 85 — Insert Chain Editing
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
Expose move up/down, remove and bypass with one undo step per action and safe prepared-plan adoption.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
### Implementation status
|
||||||
|
Planned.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 86 — Insert Inspection and Controls
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
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.
|
||||||
|
|
||||||
|
### Implementation status
|
||||||
|
Planned.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 87 — Reusable Effect Chain Presets
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
Save and load portable chain metadata with bounded validation, transactional replacement and explicit missing-plugin errors at preparation.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
### Implementation status
|
||||||
|
Planned.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 88 — Parallel Insert Mix and Chain Output
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
Expose per-slot wet/dry and chain output gain with finite bounded values and render tests for endpoints and ordering.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
### Implementation status
|
||||||
|
Planned.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 89 — Host VST3 Gallery and Integrated Qualification
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
Load compatible installed host VST3 effects in real track chains, capture screenshots, update usage documentation and qualify integration, persistence and real-time boundaries.
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
### Implementation status
|
||||||
|
Planned.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Recommended Execution Order
|
## Recommended Execution Order
|
||||||
|
|
||||||
Reorder the phases when the audit reveals a blocking dependency. Do not mark a phase complete merely because code exists: its acceptance criteria must be demonstrated by builds, tests, or documented manual verification.
|
Reorder the phases when the audit reveals a blocking dependency. Do not mark a phase complete merely because code exists: its acceptance criteria must be demonstrated by builds, tests, or documented manual verification.
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include <FL/Fl_Group.H>
|
#include <FL/Fl_Group.H>
|
||||||
#include <FL/Fl_Scroll.H>
|
#include <FL/Fl_Scroll.H>
|
||||||
#include <FL/Fl_Menu_Bar.H>
|
#include <FL/Fl_Menu_Bar.H>
|
||||||
|
#include <FL/Fl_Menu_Button.H>
|
||||||
#include <FL/Fl_Input_.H>
|
#include <FL/Fl_Input_.H>
|
||||||
#include <FL/Fl_Tabs.H>
|
#include <FL/Fl_Tabs.H>
|
||||||
#include <FL/fl_ask.H>
|
#include <FL/fl_ask.H>
|
||||||
|
|
@ -291,7 +292,7 @@ MainWindow::MainWindow(bool prompt_unsaved,const char *configuration)
|
||||||
editors_[0].owner=this;editors_[0].index=0;editors_[0].page=sequencer;
|
editors_[0].owner=this;editors_[0].index=0;editors_[0].page=sequencer;
|
||||||
editors_[0].content=new Fl_Group(216,158,1056,546);
|
editors_[0].content=new Fl_Group(216,158,1056,546);
|
||||||
editors_[0].content->begin();
|
editors_[0].content->begin();
|
||||||
auto *add_track = new Fl_Button(228, 168, 100, 26, "Add track");
|
auto *add_track = new Fl_Menu_Button(228, 168, 100, 26, "Create");
|
||||||
auto *add_region = new Fl_Button(336, 168, 110, 26, "Add region");
|
auto *add_region = new Fl_Button(336, 168, 110, 26, "Add region");
|
||||||
auto *delete_region = new Fl_Button(454, 168, 130, 26, "Delete region/track");
|
auto *delete_region = new Fl_Button(454, 168, 130, 26, "Delete region/track");
|
||||||
auto *zoom_in = new Fl_Button(592, 168, 80, 26, "Zoom +");
|
auto *zoom_in = new Fl_Button(592, 168, 80, 26, "Zoom +");
|
||||||
|
|
@ -373,11 +374,6 @@ MainWindow::MainWindow(bool prompt_unsaved,const char *configuration)
|
||||||
static_cast<MainWindow *>(c)->mark_dirty();
|
static_cast<MainWindow *>(c)->mark_dirty();
|
||||||
},
|
},
|
||||||
this);
|
this);
|
||||||
add_track->callback(
|
|
||||||
[](Fl_Widget *, void *c) {
|
|
||||||
static_cast<SequencerWidget *>(c)->add_track();
|
|
||||||
},
|
|
||||||
sequencer_);
|
|
||||||
add_midi->callback(
|
add_midi->callback(
|
||||||
[](Fl_Widget *, void *c) {
|
[](Fl_Widget *, void *c) {
|
||||||
static_cast<SequencerWidget *>(c)->add_midi_clip();
|
static_cast<SequencerWidget *>(c)->add_midi_clip();
|
||||||
|
|
@ -510,36 +506,33 @@ MainWindow::MainWindow(bool prompt_unsaved,const char *configuration)
|
||||||
auto *sidebar = new Fl_Group(12,126,192,578);
|
auto *sidebar = new Fl_Group(12,126,192,578);
|
||||||
sidebar_=sidebar;
|
sidebar_=sidebar;
|
||||||
sidebar->box(FL_BORDER_BOX);
|
sidebar->box(FL_BORDER_BOX);
|
||||||
auto *create_title = new Fl_Box(24,140,168,24,"CREATE TRACKS");
|
auto midi_create = [](Fl_Widget *, void *c) { auto *w=static_cast<MainWindow *>(c);
|
||||||
create_title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
|
xtc_result r=w->create_track(true); if(r!=XTC_OK)w->report_error("Create MIDI track",r); };
|
||||||
auto *midi_track = new Fl_Button(24,176,168,34,"New MIDI track");
|
auto audio_create = [](Fl_Widget *, void *c) { auto *w=static_cast<MainWindow *>(c);
|
||||||
midi_track->tooltip("Create a track and one-bar MIDI clip at the cursor; undo as one edit.");
|
xtc_result r=w->create_track(false); if(r!=XTC_OK)w->report_error("Create audio track",r); };
|
||||||
midi_track->callback([](Fl_Widget *, void *c) { auto *w = static_cast<MainWindow *>(c);
|
add_track->add("Empty track",0,[](Fl_Widget *,void *c){static_cast<SequencerWidget *>(c)->add_track();},sequencer_);
|
||||||
xtc_result r = w->create_track(true); if (r != XTC_OK) w->report_error("Create MIDI track",r); },this);
|
add_track->add("New MIDI track",0,midi_create,this);
|
||||||
auto *audio_track = new Fl_Button(24,218,168,34,"New audio track");
|
add_track->add("New audio track",0,audio_create,this);
|
||||||
audio_track->tooltip("Create an empty audio track, ready for WAV import or recording.");
|
add_track->add("Import WAV",0,audio_file_callback,this);
|
||||||
audio_track->callback([](Fl_Widget *, void *c) { auto *w = static_cast<MainWindow *>(c);
|
add_track->add("Load instrument plugin",0,instrument_callback,this);
|
||||||
xtc_result r = w->create_track(false); if (r != XTC_OK) w->report_error("Create audio track",r); },this);
|
add_track->add("Edit MIDI notes",0,piano_callback,this);
|
||||||
menu->add("Track/New MIDI track",FL_CTRL+FL_SHIFT+'m',midi_track->callback(),this);
|
menu->add("Track/New MIDI track",FL_CTRL+FL_SHIFT+'m',midi_create,this);
|
||||||
menu->add("Track/New audio track",FL_CTRL+FL_SHIFT+'a',audio_track->callback(),this);
|
menu->add("Track/New audio track",FL_CTRL+FL_SHIFT+'a',audio_create,this);
|
||||||
auto *import = new Fl_Button(24,260,168,34,"Import WAV");
|
menu->add("View/Track inspector",0,[](Fl_Widget *,void *c){
|
||||||
import->callback(audio_file_callback,this);
|
auto *w=static_cast<MainWindow *>(c);w->show_track_inspector(!w->sidebar_->visible());
|
||||||
auto *load = new Fl_Button(24,302,168,34,"Load instrument plugin");
|
},this,FL_MENU_TOGGLE);
|
||||||
load->callback(instrument_callback,this);
|
auto *selection_title = new Fl_Box(24,140,168,24,"TRACK INSPECTOR");
|
||||||
auto *editor = new Fl_Button(24,344,168,34,"Edit MIDI notes");
|
|
||||||
editor->callback(piano_callback,this);
|
|
||||||
auto *selection_title = new Fl_Box(24,404,168,24,"TRACK INSPECTOR");
|
|
||||||
selection_title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
|
selection_title->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
|
||||||
selection_info_ = new Fl_Box(24,438,168,82,"Select a track to inspect it.");
|
selection_info_ = new Fl_Box(24,174,168,82,"Select a track to inspect it.");
|
||||||
selection_info_->align(FL_ALIGN_TOP_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_WRAP);
|
selection_info_->align(FL_ALIGN_TOP_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_WRAP);
|
||||||
inspector_gain_ = new Fl_Value_Input(78, 528, 114, 26, "Gain");
|
inspector_gain_ = new Fl_Value_Input(78, 264, 114, 26, "Gain");
|
||||||
inspector_gain_->bounds(0, 4);
|
inspector_gain_->bounds(0, 4);
|
||||||
inspector_gain_->step(.01);
|
inspector_gain_->step(.01);
|
||||||
inspector_pan_ = new Fl_Value_Input(78, 562, 114, 26, "Pan");
|
inspector_pan_ = new Fl_Value_Input(78, 298, 114, 26, "Pan");
|
||||||
inspector_pan_->bounds(-1, 1);
|
inspector_pan_->bounds(-1, 1);
|
||||||
inspector_pan_->step(.01);
|
inspector_pan_->step(.01);
|
||||||
inspector_mute_ = new Fl_Check_Button(24, 596, 78, 24, "Mute");
|
inspector_mute_ = new Fl_Check_Button(24, 332, 78, 24, "Mute");
|
||||||
inspector_solo_ = new Fl_Check_Button(108, 596, 84, 24, "Solo");
|
inspector_solo_ = new Fl_Check_Button(108, 332, 84, 24, "Solo");
|
||||||
for (auto *control : {static_cast<Fl_Widget *>(inspector_gain_), static_cast<Fl_Widget *>(inspector_pan_),
|
for (auto *control : {static_cast<Fl_Widget *>(inspector_gain_), static_cast<Fl_Widget *>(inspector_pan_),
|
||||||
static_cast<Fl_Widget *>(inspector_mute_), static_cast<Fl_Widget *>(inspector_solo_)}) {
|
static_cast<Fl_Widget *>(inspector_mute_), static_cast<Fl_Widget *>(inspector_solo_)}) {
|
||||||
control->when(FL_WHEN_RELEASE);
|
control->when(FL_WHEN_RELEASE);
|
||||||
|
|
@ -548,7 +541,7 @@ MainWindow::MainWindow(bool prompt_unsaved,const char *configuration)
|
||||||
inspector_gain_->tooltip(
|
inspector_gain_->tooltip(
|
||||||
"Selected track linear gain: 0 silence, 1 unity, 4 maximum. Automation overrides static gain.");
|
"Selected track linear gain: 0 silence, 1 unity, 4 maximum. Automation overrides static gain.");
|
||||||
inspector_pan_->tooltip("Selected track pan: -1 left, 0 center, +1 right.");
|
inspector_pan_->tooltip("Selected track pan: -1 left, 0 center, +1 right.");
|
||||||
auto *tip = new Fl_Box(24, 632, 168, 52, "Ctrl+P Commands\nCtrl+1/2/3 Views\nCtrl+0 Fit song");
|
auto *tip = new Fl_Box(24, 368, 168, 52, "Ctrl+P Commands\nCtrl+1/2/3 Views\nCtrl+0 Fit song");
|
||||||
tip->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
|
tip->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
|
||||||
sidebar->end();
|
sidebar->end();
|
||||||
status_ = new Fl_Box(12,714,1256,26,"JACK: not connected");
|
status_ = new Fl_Box(12,714,1256,26,"JACK: not connected");
|
||||||
|
|
@ -557,12 +550,11 @@ MainWindow::MainWindow(bool prompt_unsaved,const char *configuration)
|
||||||
error_->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_WRAP);
|
error_->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_WRAP);
|
||||||
xtc_ui::style(this);
|
xtc_ui::style(this);
|
||||||
color(xtc_ui::background());
|
color(xtc_ui::background());
|
||||||
create_title->labelcolor(xtc_ui::muted()); selection_title->labelcolor(xtc_ui::muted());
|
selection_title->labelcolor(xtc_ui::muted());
|
||||||
tip->labelcolor(xtc_ui::muted()); hint->labelcolor(xtc_ui::muted());
|
tip->labelcolor(xtc_ui::muted()); hint->labelcolor(xtc_ui::muted());
|
||||||
transport_position_->box(xtc_ui::flat); transport_position_->color(xtc_ui::background());
|
transport_position_->box(xtc_ui::flat); transport_position_->color(xtc_ui::background());
|
||||||
transport_position_->labelfont(FL_COURIER_BOLD); transport_position_->labelsize(18);
|
transport_position_->labelfont(FL_COURIER_BOLD); transport_position_->labelsize(18);
|
||||||
tempo_display_->labelcolor(xtc_ui::muted());
|
tempo_display_->labelcolor(xtc_ui::muted());
|
||||||
midi_track->color(fl_rgb_color(45,91,86));
|
|
||||||
play_->labelcolor(xtc_ui::accent()); record_->labelcolor(fl_rgb_color(245,132,142));
|
play_->labelcolor(xtc_ui::accent()); record_->labelcolor(fl_rgb_color(245,132,142));
|
||||||
error_->labelcolor(fl_rgb_color(255,166,139));
|
error_->labelcolor(fl_rgb_color(255,166,139));
|
||||||
end();
|
end();
|
||||||
|
|
@ -570,6 +562,7 @@ MainWindow::MainWindow(bool prompt_unsaved,const char *configuration)
|
||||||
size_range(1220, 720);
|
size_range(1220, 720);
|
||||||
callback(close_callback, this);
|
callback(close_callback, this);
|
||||||
apply_ui_preferences();
|
apply_ui_preferences();
|
||||||
|
show_track_inspector(false);
|
||||||
open_backend();
|
open_backend();
|
||||||
if(config_result!=XTC_OK && config_result!=XTC_ERR_NOT_FOUND) report_error("Preferences file invalid; using defaults",config_result);
|
if(config_result!=XTC_OK && config_result!=XTC_ERR_NOT_FOUND) report_error("Preferences file invalid; using defaults",config_result);
|
||||||
Fl::add_timeout(static_cast<double>(settings_.refresh_ms)/1000,timer_callback,this);
|
Fl::add_timeout(static_cast<double>(settings_.refresh_ms)/1000,timer_callback,this);
|
||||||
|
|
@ -636,6 +629,16 @@ void MainWindow::reset_layout()
|
||||||
settings_.piano_width=900;settings_.piano_height=620;settings_.track_header_width=180;
|
settings_.piano_width=900;settings_.piano_height=620;settings_.track_header_width=180;
|
||||||
sequencer_->header_width(180);tabs_->value(editors_[0].page);apply_ui_preferences();
|
sequencer_->header_width(180);tabs_->value(editors_[0].page);apply_ui_preferences();
|
||||||
}
|
}
|
||||||
|
void MainWindow::show_track_inspector(bool visible)
|
||||||
|
{
|
||||||
|
const int left=visible ? 216 : 12;
|
||||||
|
if(visible)sidebar_->show();else sidebar_->hide();
|
||||||
|
tabs_->resize(left,tabs_->y(),w()-left-8,tabs_->h());
|
||||||
|
auto *menu=dynamic_cast<Fl_Menu_Bar *>(child(0));
|
||||||
|
if(menu) { auto *item=const_cast<Fl_Menu_Item *>(menu->find_item("View/Track inspector"));
|
||||||
|
if(item) { if(visible)item->set();else item->clear(); } }
|
||||||
|
init_sizes();redraw();
|
||||||
|
}
|
||||||
void MainWindow::resize(int x,int y,int width,int height)
|
void MainWindow::resize(int x,int y,int width,int height)
|
||||||
{
|
{
|
||||||
Fl_Double_Window::resize(x,y,width,height);
|
Fl_Double_Window::resize(x,y,width,height);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ class Fl_Check_Button;
|
||||||
|
|
||||||
class MainWindow : public Fl_Double_Window {
|
class MainWindow : public Fl_Double_Window {
|
||||||
public:
|
public:
|
||||||
|
void show_track_inspector(bool visible);
|
||||||
/* One undoable candidate edit. MIDI also adds a one-bar clip at the cursor.
|
/* One undoable candidate edit. MIDI also adds a one-bar clip at the cursor.
|
||||||
* Preparation stops/resets transport; recording and failed candidates retain
|
* Preparation stops/resets transport; recording and failed candidates retain
|
||||||
* the current document. No engine/model changes happen in audio callbacks. */
|
* the current document. No engine/model changes happen in audio callbacks. */
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include <FL/Fl_Button.H>
|
#include <FL/Fl_Button.H>
|
||||||
#include <FL/Fl_Group.H>
|
#include <FL/Fl_Group.H>
|
||||||
#include <FL/Fl_Menu_Bar.H>
|
#include <FL/Fl_Menu_Bar.H>
|
||||||
|
#include <FL/Fl_Menu_Button.H>
|
||||||
#include <FL/Fl_Tabs.H>
|
#include <FL/Fl_Tabs.H>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
@ -342,7 +343,7 @@ int main(int argc, char **argv)
|
||||||
CHECK(sequence != nullptr);
|
CHECK(sequence != nullptr);
|
||||||
char directory[] = "/tmp/xtc-gui-XXXXXX"; CHECK(mkdtemp(directory) != nullptr);
|
char directory[] = "/tmp/xtc-gui-XXXXXX"; CHECK(mkdtemp(directory) != nullptr);
|
||||||
std::string filename = std::string(directory) + "/song.xtc";
|
std::string filename = std::string(directory) + "/song.xtc";
|
||||||
press(find(&window, "Add track")); press(find(&window, "Add region"));
|
auto *creation=dynamic_cast<Fl_Menu_Button *>(find(&window,"Create")); CHECK(creation); if(creation)creation->picked(creation->find_item("Empty track")); press(find(&window, "Add region"));
|
||||||
size_t track_count, clip_count;
|
size_t track_count, clip_count;
|
||||||
CHECK(xtc_project_get_counts(sequence->project(), &track_count, &clip_count) == XTC_OK && track_count == 1 && clip_count == 1);
|
CHECK(xtc_project_get_counts(sequence->project(), &track_count, &clip_count) == XTC_OK && track_count == 1 && clip_count == 1);
|
||||||
xtc_clip_info region{};
|
xtc_clip_info region{};
|
||||||
|
|
@ -957,10 +958,12 @@ int main(int argc, char **argv)
|
||||||
MainWindow window(false,""); window.show();
|
MainWindow window(false,""); window.show();
|
||||||
auto *sequence = timeline(&window);
|
auto *sequence = timeline(&window);
|
||||||
CHECK(sequence != nullptr);
|
CHECK(sequence != nullptr);
|
||||||
auto *midi = find(&window,"New MIDI track");
|
auto *create=dynamic_cast<Fl_Menu_Button *>(find(&window,"Create"));
|
||||||
auto *audio = find(&window,"New audio track");
|
CHECK(create && create->find_item("New MIDI track") && create->find_item("Import WAV"));
|
||||||
CHECK(midi && audio && find(&window,"Import WAV") && find(&window,"Edit MIDI notes"));
|
CHECK(sequence->x()<100);
|
||||||
press(midi);
|
window.show_track_inspector(true);CHECK(sequence->x()>200);
|
||||||
|
window.show_track_inspector(false);CHECK(sequence->x()<100);
|
||||||
|
create->picked(create->find_item("New MIDI track"));
|
||||||
size_t tracks = 0, clips = 0;
|
size_t tracks = 0, clips = 0;
|
||||||
xtc_project_get_counts(sequence->project(),&tracks,&clips);
|
xtc_project_get_counts(sequence->project(),&tracks,&clips);
|
||||||
CHECK(tracks == 1 && clips == 1);
|
CHECK(tracks == 1 && clips == 1);
|
||||||
|
|
@ -973,7 +976,7 @@ int main(int argc, char **argv)
|
||||||
CHECK(window.undo(true) == XTC_OK);
|
CHECK(window.undo(true) == XTC_OK);
|
||||||
CHECK(sequence->select(track,clip)); pump();
|
CHECK(sequence->select(track,clip)); pump();
|
||||||
CHECK(contains(&window,"MIDI track"));
|
CHECK(contains(&window,"MIDI track"));
|
||||||
press(audio);
|
create->picked(create->find_item("New audio track"));
|
||||||
xtc_project_get_counts(sequence->project(),&tracks,&clips); CHECK(tracks == 2 && clips == 1);
|
xtc_project_get_counts(sequence->project(),&tracks,&clips); CHECK(tracks == 2 && clips == 1);
|
||||||
const xtc_project *before = sequence->project();
|
const xtc_project *before = sequence->project();
|
||||||
reserve_result = XTC_ERR_OUT_OF_MEMORY;
|
reserve_result = XTC_ERR_OUT_OF_MEMORY;
|
||||||
|
|
@ -984,9 +987,9 @@ int main(int argc, char **argv)
|
||||||
// Exercise the supported minimum and a larger workspace with real layout.
|
// Exercise the supported minimum and a larger workspace with real layout.
|
||||||
for (auto size : {std::pair<int,int>{1220,720},{1600,1000}}) {
|
for (auto size : {std::pair<int,int>{1220,720},{1600,1000}}) {
|
||||||
window.resize(window.x(),window.y(),size.first,size.second); pump();
|
window.resize(window.x(),window.y(),size.first,size.second); pump();
|
||||||
CHECK(midi->x() >= 0 && midi->x()+midi->w() <= sequence->parent()->x());
|
CHECK(create->x() >= 0 && create->x()+create->w() <= window.w());
|
||||||
CHECK(sequence->parent()->x()+sequence->parent()->w() <= window.w());
|
CHECK(sequence->parent()->x()+sequence->parent()->w() <= window.w());
|
||||||
CHECK(find(&window,"Play")->visible_r() && midi->visible_r());
|
CHECK(find(&window,"Play")->visible_r() && create->visible_r());
|
||||||
}
|
}
|
||||||
CHECK(window.save_project("/tmp/xtc-workspace.xtc") == XTC_OK);
|
CHECK(window.save_project("/tmp/xtc-workspace.xtc") == XTC_OK);
|
||||||
CHECK(window.new_project() == XTC_OK && window.open_project("/tmp/xtc-workspace.xtc") == XTC_OK);
|
CHECK(window.new_project() == XTC_OK && window.open_project("/tmp/xtc-workspace.xtc") == XTC_OK);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue