, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _mouse_changed_selection (false)
{
CANVAS_DEBUG_NAME (_note_group, string_compose ("note group for %1", get_item_name()));
_note_group->raise_to_top();
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _mouse_changed_selection (false)
{
CANVAS_DEBUG_NAME (_note_group, string_compose ("note group for %1", get_item_name()));
_note_group->raise_to_top();
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _mouse_changed_selection (false)
{
init (false);
}
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _mouse_changed_selection (false)
{
init (true);
}
}
_pressed_button = ev->button;
+ _mouse_changed_selection = false;
return true;
}
case MouseRange:
/* no motion occured - simple click */
clear_selection ();
+ _mouse_changed_selection = true;
break;
case MouseContent:
case MouseTimeFX:
{
clear_selection();
+ _mouse_changed_selection = true;
if (Keyboard::is_insert_note_event(ev)) {
break;
}
+ if (_mouse_changed_selection) {
+ trackview.editor().begin_reversible_selection_op (_("Mouse Selection Change"));
+ trackview.editor().commit_reversible_selection_op ();
+ }
+
return false;
}
editor.drags()->set (new MidiRubberbandSelectDrag (dynamic_cast<Editor *> (&editor), this), (GdkEvent *) ev);
if (!Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
clear_selection ();
+ _mouse_changed_selection = true;
}
_mouse_state = SelectRectDragging;
return true;
delete_selection();
return true;
- } else if (ev->keyval == GDK_Tab) {
+ } else if (ev->keyval == GDK_Tab || ev->keyval == GDK_ISO_Left_Tab) {
- if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier)) {
- goto_previous_note (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
- } else {
- goto_next_note (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
- }
- return true;
-
- } else if (ev->keyval == GDK_ISO_Left_Tab) {
-
- /* Shift-TAB generates ISO Left Tab, for some reason */
+ trackview.editor().begin_reversible_selection_op (_("Select Adjacent Note"));
if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier)) {
goto_previous_note (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
} else {
goto_next_note (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
}
- return true;
+ trackview.editor().commit_reversible_selection_op();
+ return true;
} else if (ev->keyval == GDK_Up) {
view->update_note_range(new_note->note());
- MidiModel::NoteDiffCommand* cmd = _model->new_note_diff_command(_("add note"));
- cmd->add (new_note);
- _model->apply_command(*trackview.session(), cmd);
+ start_note_diff_command(_("add note"));
+
+ clear_selection ();
+ note_diff_add_note (new_note, true, false);
+
+ apply_diff();
play_midi_note (new_note);
}
content_connection.disconnect ();
_model->ContentsChanged.connect (content_connection, invalidator (*this), boost::bind (&MidiRegionView::redisplay_model, this), gui_context());
-
- clear_events ();
+ /* Don't signal as nobody else needs to know until selection has been altered. */
+ clear_events (false);
if (_enable_display) {
redisplay_model();
MidiRegionView::start_note_diff_command (string name)
{
if (!_note_diff_command) {
+ trackview.editor().begin_reversible_command (name);
_note_diff_command = _model->new_note_diff_command (name);
}
}
MidiRegionView::apply_diff (bool as_subcommand)
{
bool add_or_remove;
+ bool commit = false;
if (!_note_diff_command) {
return;
_model->apply_command_as_subcommand (*trackview.session(), _note_diff_command);
} else {
_model->apply_command (*trackview.session(), _note_diff_command);
+ commit = true;
}
_note_diff_command = 0;
}
_marked_for_velocity.clear();
+ if (commit) {
+ trackview.editor().commit_reversible_command ();
+ }
}
void
return 0;
}
+/** This version finds any canvas note matching the supplied note. */
+NoteBase*
+MidiRegionView::find_canvas_note (NoteType note)
+{
+ Events::iterator it;
+
+ for (it = _events.begin(); it != _events.end(); ++it) {
+ if (*((*it)->note()) == note) {
+ return *it;
+ }
+ }
+
+ return 0;
+}
+
void
MidiRegionView::get_events (Events& e, Evoral::Sequence<Evoral::Beats>::NoteOperator op, uint8_t val, int chan_mask)
{
} else {
- add_note (note, visible);
+ cne = add_note (note, visible);
+ }
+
+ set<boost::shared_ptr<NoteType> >::iterator it;
+ for (it = _pending_note_selection.begin(); it != _pending_note_selection.end(); ++it) {
+ if (*(*it) == *note) {
+ add_to_selection (cne);
+ }
}
} else {
}
}
-
/* remove note items that are no longer valid */
if (!empty_when_starting) {
_marked_for_selection.clear ();
_marked_for_velocity.clear ();
+ _pending_note_selection.clear ();
/* we may have caused _events to contain things out of order (e.g. if a note
moved earlier or later). we don't generally need them in time order, but
bool
MidiRegionView::note_in_region_range (const boost::shared_ptr<NoteType> note, bool& visible) const
{
+ /* This is imprecise due to all the conversion conversion involved, so only
+ hide notes if they seem to start more than one tick before the start. */
+ const framecnt_t tick_frames = Evoral::Beats::tick().to_ticks(trackview.session()->frame_rate());
const framepos_t note_start_frames = source_beats_to_region_frames (note->time());
- bool outside = (note_start_frames < 0) || (note_start_frames > _region->last_frame());
+ const bool outside = ((note_start_frames <= -tick_frames) ||
+ (note_start_frames > _region->last_frame()));
visible = (note->note() >= midi_stream_view()->lowest_note()) &&
(note->note() <= midi_stream_view()->highest_note());
* notes, and resolve_note should be called when the corresponding note off
* event arrives, to properly display the note.
*/
-void
+NoteBase*
MidiRegionView::add_note(const boost::shared_ptr<NoteType> note, bool visible)
{
NoteBase* event = 0;
MidiStreamView* const view = mtv->midi_view();
view->update_note_range (note->note());
+ return event;
}
void
view->update_note_range(new_note->note());
_marked_for_selection.clear ();
- clear_selection ();
start_note_diff_command (_("step add"));
+
+ clear_selection ();
note_diff_add_note (new_note, true, false);
+
apply_diff();
// last_step_edit_note = new_note;
void
MidiRegionView::change_patch_change (PatchChange& pc, const MIDI::Name::PatchPrimaryKey& new_patch)
{
- MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("alter patch change"));
+ string name = _("alter patch change");
+ trackview.editor().begin_reversible_command (name);
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (name);
if (pc.patch()->program() != new_patch.program()) {
c->change_program (pc.patch (), new_patch.program());
}
_model->apply_command (*trackview.session(), c);
+ trackview.editor().commit_reversible_command ();
_patch_changes.clear ();
display_patch_changes ();
void
MidiRegionView::change_patch_change (MidiModel::PatchChangePtr old_change, const Evoral::PatchChange<Evoral::Beats> & new_change)
{
- MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("alter patch change"));
+ string name = _("alter patch change");
+ trackview.editor().begin_reversible_command (name);
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (name);
if (old_change->time() != new_change.time()) {
c->change_time (old_change, new_change.time());
}
_model->apply_command (*trackview.session(), c);
+ trackview.editor().commit_reversible_command ();
_patch_changes.clear ();
display_patch_changes ();
MidiRegionView::add_patch_change (framecnt_t t, Evoral::PatchChange<Evoral::Beats> const & patch)
{
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+ string name = _("add patch change");
- MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("add patch change"));
+ trackview.editor().begin_reversible_command (name);
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (name);
c->add (MidiModel::PatchChangePtr (
new Evoral::PatchChange<Evoral::Beats> (
absolute_frames_to_source_beats (_region->position() + t),
);
_model->apply_command (*trackview.session(), c);
+ trackview.editor().commit_reversible_command ();
_patch_changes.clear ();
display_patch_changes ();
void
MidiRegionView::move_patch_change (PatchChange& pc, Evoral::Beats t)
{
+ trackview.editor().begin_reversible_command (_("move patch change"));
MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("move patch change"));
c->change_time (pc.patch (), t);
_model->apply_command (*trackview.session(), c);
+ trackview.editor().commit_reversible_command ();
_patch_changes.clear ();
display_patch_changes ();
void
MidiRegionView::delete_patch_change (PatchChange* pc)
{
+ trackview.editor().begin_reversible_command (_("delete patch change"));
MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("delete patch change"));
c->remove (pc->patch ());
_model->apply_command (*trackview.session(), c);
+ trackview.editor().commit_reversible_command ();
_patch_changes.clear ();
display_patch_changes ();
}
}
+/** Used for selection undo/redo.
+ The requested notes most likely won't exist in the view until the next model redisplay.
+*/
+void
+MidiRegionView::select_notes (list<boost::shared_ptr<NoteType> > notes)
+{
+ NoteBase* cne;
+ list<boost::shared_ptr<NoteType> >::iterator n;
+
+ for (n = notes.begin(); n != notes.end(); ++n) {
+ if ((cne = find_canvas_note(*(*n))) != 0) {
+ add_to_selection (cne);
+ } else {
+ _pending_note_selection.insert(*n);
+ }
+ }
+}
+
void
MidiRegionView::select_matching_notes (uint8_t notenum, uint16_t channel_mask, bool add, bool extend)
{
void
MidiRegionView::commit_resizing (NoteBase* primary, bool at_front, double delta_x, bool relative)
{
- start_note_diff_command (_("resize notes"));
+ _note_diff_command = _model->new_note_diff_command (_("resize notes"));
for (std::vector<NoteResizeData *>::iterator i = _resize_data.begin(); i != _resize_data.end(); ++i) {
Note* canvas_note = (*i)->note;
}
_resize_data.clear();
- apply_diff();
+ apply_diff(true);
}
void
"midi frame base");
if (_selected) {
return ARDOUR_UI::config()->color_mod ("selected region base", mod_name);
- } else if (high_enough_for_name || !ARDOUR_UI::config()->get_color_regions_using_track_color()) {
+ } else if ((!ARDOUR_UI::config()->get_show_name_highlight() || high_enough_for_name) &&
+ !ARDOUR_UI::config()->get_color_regions_using_track_color()) {
return ARDOUR_UI::config()->color_mod ("midi frame base", mod_name);
}
return ARDOUR_UI::config()->color_mod (fill_color, mod_name);
bool
MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx)
{
+ bool commit = false;
// Paste notes, if available
MidiNoteSelection::const_iterator m = selection.midi_notes.get_nth(ctx.counts.n_notes());
if (m != selection.midi_notes.end()) {
ctx.counts.increase_n_notes();
+ if (!(*m)->empty()) { commit = true; }
paste_internal(pos, ctx.count, ctx.times, **m);
}
typedef RouteTimeAxisView::AutomationTracks ATracks;
const ATracks& atracks = midi_view()->automation_tracks();
for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
- a->second->paste(pos, selection, ctx);
+ if (a->second->paste(pos, selection, ctx)) {
+ commit = true;
+ }
}
+ if (commit) {
+ trackview.editor().commit_reversible_command ();
+ }
return true;
}