using namespace std;
using Gtkmm2ext::Keyboard;
-PBD::Signal1<void, MidiRegionView *> MidiRegionView::SelectionCleared;
-
#define MIDI_BP_ZERO ((Config->get_first_midi_bank_is_zero())?0:1)
MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent,
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _note_entered (false)
, _mouse_changed_selection (false)
{
CANVAS_DEBUG_NAME (_note_group, string_compose ("note group for %1", get_item_name()));
Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
connect_to_diskstream ();
-
- SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
-
- PublicEditor& editor (trackview.editor());
- editor.get_selection().ClearMidiNoteSelection.connect (_clear_midi_selection_connection, invalidator (*this), boost::bind (&MidiRegionView::clear_midi_selection, this), gui_context ());
}
MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent,
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _note_entered (false)
, _mouse_changed_selection (false)
{
CANVAS_DEBUG_NAME (_note_group, string_compose ("note group for %1", get_item_name()));
PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
connect_to_diskstream ();
-
- SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
-
- PublicEditor& editor (trackview.editor());
- editor.get_selection().ClearMidiNoteSelection.connect (_clear_midi_selection_connection, invalidator (*this), boost::bind (&MidiRegionView::clear_midi_selection, this), gui_context ());
}
void
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _note_entered (false)
, _mouse_changed_selection (false)
{
init (false);
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _note_entered (false)
, _mouse_changed_selection (false)
{
init (true);
RegionView::init (false);
- set_height (trackview.current_height());
+ //set_height (trackview.current_height());
region_muted ();
region_sync_changed ();
region_resized (ARDOUR::bounds_change);
- region_locked ();
+ //region_locked ();
set_colors ();
Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
connect_to_diskstream ();
-
- SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
-
- PublicEditor& editor (trackview.editor());
- editor.get_selection().ClearMidiNoteSelection.connect (_clear_midi_selection_connection, invalidator (*this), boost::bind (&MidiRegionView::clear_midi_selection, this), gui_context ());
}
InstrumentInfo&
set_frame_color();
if (_entered) {
- if (trackview.editor().internal_editing()) {
- // Switched in to internal editing mode while entered
- enter_internal();
- } else {
- // Switched out of internal editing mode while entered
+ if (!trackview.editor().internal_editing()) {
+ /* Switched out of internal editing mode while entered.
+ Only necessary for leave as a mouse_mode_change over a region
+ automatically triggers an enter event. */
leave_internal();
}
+ else if (trackview.editor().current_mouse_mode() == MouseContent) {
+ // hide cursor and ghost note after changing to internal edit mode
+ remove_ghost_note ();
+
+ /* XXX This is problematic as the function is executed for every region
+ and only for one region _note_entered can be true. Still it's
+ necessary as to hide the verbose cursor when we're changing from
+ draw mode to internal edit mode. These lines are the reason why
+ in some situations no verbose cursor is shown when we enter internal
+ edit mode over a note. */
+ if (!_note_entered) {
+ hide_verbose_cursor ();
+ }
+ }
}
}
{
hide_verbose_cursor ();
remove_ghost_note ();
+ _note_entered = false;
if (_grabbed_keyboard) {
Keyboard::magic_widget_drop_focus();
switch (editor.current_mouse_mode()) {
case MouseRange:
- /* no motion occured - simple click */
- clear_selection ();
+ /* no motion occurred - simple click */
+ clear_editor_note_selection ();
_mouse_changed_selection = true;
break;
Evoral::Beats beats = get_grid_beats(editor.pixel_to_sample(event_x));
create_note_at (editor.pixel_to_sample (event_x), event_y, beats, true);
} else {
- clear_selection ();
+ clear_editor_note_selection ();
}
break;
_mouse_state = None;
break;
- case SelectRectDragging:
case AddDragging:
+ /* Only create a ghost note when we added a note, not when we were drag-selecting. */
+ create_ghost_note (ev->x, ev->y);
+ case SelectRectDragging:
editor.drags()->end_grab ((GdkEvent *) ev);
_mouse_state = None;
- create_ghost_note (ev->x, ev->y);
break;
{
PublicEditor& editor = trackview.editor ();
- if (!_ghost_note && editor.current_mouse_mode() == MouseContent &&
- Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier()) &&
- _mouse_state != AddDragging) {
+ if (!_note_entered) {
- create_ghost_note (ev->x, ev->y);
+ if (!_ghost_note && editor.current_mouse_mode() == MouseContent &&
+ Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier()) &&
+ _mouse_state != AddDragging) {
- } else if (_ghost_note && editor.current_mouse_mode() == MouseContent &&
- Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())) {
+ create_ghost_note (ev->x, ev->y);
- update_ghost_note (ev->x, ev->y);
+ } else if (_ghost_note && editor.current_mouse_mode() == MouseContent &&
+ Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())) {
- } else if (_ghost_note && editor.current_mouse_mode() == MouseContent) {
+ update_ghost_note (ev->x, ev->y);
- remove_ghost_note ();
- hide_verbose_cursor ();
+ } else if (_ghost_note && editor.current_mouse_mode() == MouseContent) {
- } else if (_ghost_note && editor.current_mouse_mode() == MouseDraw) {
+ remove_ghost_note ();
+ hide_verbose_cursor ();
- update_ghost_note (ev->x, ev->y);
+ } else if (editor.current_mouse_mode() == MouseDraw) {
+
+ if (_ghost_note) {
+ update_ghost_note (ev->x, ev->y);
+ }
+ else {
+ create_ghost_note (ev->x, ev->y);
+ }
+ }
}
/* any motion immediately hides velocity text that may have been visible */
} else if (m == MouseContent) {
editor.drags()->set (new MidiRubberbandSelectDrag (dynamic_cast<Editor *> (&editor), this), (GdkEvent *) ev);
if (!Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
- clear_selection ();
+ clear_editor_note_selection ();
_mouse_changed_selection = true;
}
_mouse_state = SelectRectDragging;
return true;
} else if (ev->keyval == GDK_Escape && unmodified) {
- clear_selection();
+ clear_editor_note_selection ();
_mouse_state = None;
} else if (ev->keyval == GDK_comma || ev->keyval == GDK_period) {
start_note_diff_command(_("add note"));
- clear_selection ();
+ clear_editor_note_selection ();
note_diff_add_note (new_note, true, false);
apply_diff();
}
void
-MidiRegionView::clear_events (bool with_selection_signal)
+MidiRegionView::clear_events ()
{
- clear_selection (with_selection_signal);
+ // clear selection without signaling
+ clear_selection_internal ();
MidiGhostRegion* gr;
for (std::vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) {
content_connection.disconnect ();
_model->ContentsChanged.connect (content_connection, invalidator (*this), boost::bind (&MidiRegionView::redisplay_model, this), gui_context());
/* Don't signal as nobody else needs to know until selection has been altered. */
- clear_events (false);
+ clear_events ();
if (_enable_display) {
redisplay_model();
{
delete _note_diff_command;
_note_diff_command = 0;
- clear_selection();
+ clear_editor_note_selection();
}
NoteBase*
if (!empty_when_starting && (cne = find_canvas_note (note)) != 0) {
- cne->validate ();
- update_note (cne);
-
if (visible) {
+ cne->validate ();
+ update_note (cne);
cne->show ();
} else {
cne->hide ();
end_write();
}
- _selection_cleared_connection.disconnect ();
-
_selection.clear();
- clear_events (false);
+ clear_events ();
delete _note_group;
delete _note_diff_command;
void
MidiRegionView::region_resized (const PropertyChange& what_changed)
{
- RegionView::region_resized(what_changed);
+ RegionView::region_resized(what_changed); // calls RegionView::set_duration()
if (what_changed.contains (ARDOUR::Properties::position)) {
_region_relative_time_converter.set_origin_b(_region->position());
_region_relative_time_converter_double.set_origin_b(_region->position());
- set_duration(_region->length(), 0);
- if (_enable_display) {
- redisplay_model();
- }
+ /* reset_width dependent_items() redisplays model */
}
if (what_changed.contains (ARDOUR::Properties::start) ||
MidiRegionView::update_sustained (Note* ev, bool update_ghost_regions)
{
boost::shared_ptr<NoteType> note = ev->note();
- const double x = trackview.editor().sample_to_pixel (source_beats_to_region_frames (note->time()));
+ const double x0 = trackview.editor().sample_to_pixel (source_beats_to_region_frames (note->time()));
+ double x1;
const double y0 = 1 + floor(midi_stream_view()->note_to_y(note->note()));
-
- ev->set_x0 (x);
- ev->set_y0 (y0);
+ double y1;
/* trim note display to not overlap the end of its region */
if (note->length() > 0) {
const framepos_t note_end_frames = min (source_beats_to_region_frames (note->end_time()), _region->length());
- ev->set_x1 (std::max(1., trackview.editor().sample_to_pixel (note_end_frames)) - 1);
+ x1 = std::max(1., trackview.editor().sample_to_pixel (note_end_frames)) - 1;
} else {
- ev->set_x1 (std::max(1., trackview.editor().sample_to_pixel (_region->length())) - 1);
+ x1 = std::max(1., trackview.editor().sample_to_pixel (_region->length())) - 1;
}
- ev->set_y1 (y0 + std::max(1., floor(midi_stream_view()->note_height()) - 1));
+ y1 = y0 + std::max(1., floor(midi_stream_view()->note_height()) - 1);
+
+ ev->set_x0 (x0);
+ ev->set_x1 (x1);
+ ev->set_y0 (y0);
+ ev->set_y1 (y1);
if (!note->length()) {
if (_active_notes && note->note() < 128) {
if (old_rect) {
/* There is an active note on this key, so we have a stuck
note. Finish the old rectangle here. */
- old_rect->set_x1 (x);
+ old_rect->set_x1 (x1);
old_rect->set_outline_all ();
}
_active_notes[note->note()] = ev;
}
// Update color in case velocity has changed
- ev->set_fill_color(ev->base_color());
- ev->set_outline_color(ev->calculate_outline(ev->base_color(), ev->selected()));
+ //ev->set_fill_color(ev->base_color());
+ //ev->set_outline_color(ev->calculate_outline(ev->base_color(), ev->selected()));
if (update_ghost_regions) {
for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
start_note_diff_command (_("step add"));
- clear_selection ();
+ clear_editor_note_selection ();
note_diff_add_note (new_note, true, false);
apply_diff();
}
void
-MidiRegionView::clear_selection_except (NoteBase* ev, bool signal)
+MidiRegionView::clear_editor_note_selection ()
{
- for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
- if ((*i) != ev) {
- Selection::iterator tmp = i;
- ++tmp;
+ DEBUG_TRACE(DEBUG::Selection, "MRV::clear_editor_note_selection\n");
+ PublicEditor& editor(trackview.editor());
+ editor.get_selection().clear_midi_notes();
+}
- (*i)->set_selected (false);
- (*i)->hide_velocity ();
- _selection.erase (i);
+void
+MidiRegionView::clear_selection ()
+{
+ clear_selection_internal();
+ PublicEditor& editor(trackview.editor());
+ editor.get_selection().remove(this);
+}
- i = tmp;
- } else {
- ++i;
- }
+void
+MidiRegionView::clear_selection_internal ()
+{
+ DEBUG_TRACE(DEBUG::Selection, "MRV::clear_selection_internal\n");
+
+ for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ (*i)->set_selected(false);
+ (*i)->hide_velocity();
}
+ _selection.clear();
- if (!ev && _entered) {
+ if (_entered) {
// Clearing selection entirely, ungrab keyboard
Keyboard::magic_widget_drop_focus();
_grabbed_keyboard = false;
}
-
- /* this does not change the status of this regionview w.r.t the editor
- selection.
- */
-
- if (signal) {
- SelectionCleared (this); /* EMIT SIGNAL */
- }
}
void
MidiRegionView::unique_select(NoteBase* ev)
{
- const bool selection_was_empty = _selection.empty();
-
- clear_selection_except (ev);
-
- /* don't bother with checking to see if we should remove this
- regionview from the editor selection, since we're about to add
- another note, and thus put/keep this regionview in the editor
- selection anyway.
- */
-
- if (!ev->selected()) {
- add_to_selection (ev);
- if (selection_was_empty && _entered) {
- // Grab keyboard for moving notes with arrow keys
- Keyboard::magic_widget_grab_focus();
- _grabbed_keyboard = true;
- }
- }
+ clear_editor_note_selection();
+ add_to_selection(ev);
}
void
MidiRegionView::select_all_notes ()
{
- clear_selection ();
+ clear_editor_note_selection ();
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
add_to_selection (*i);
void
MidiRegionView::select_range (framepos_t start, framepos_t end)
{
- clear_selection ();
+ clear_editor_note_selection ();
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
framepos_t t = source_beats_to_absolute_frames((*i)->note()->time());
}
if (!add) {
- clear_selection ();
+ clear_editor_note_selection ();
if (!extend && (low_note == high_note) && (high_note == notenum)) {
/* only note previously selected is the one we are
MidiRegionView::note_selected (NoteBase* ev, bool add, bool extend)
{
if (!add) {
- clear_selection_except (ev);
- if (!_selection.empty()) {
- PublicEditor& editor (trackview.editor());
- editor.get_selection().add (this);
- }
+ clear_editor_note_selection();
+ add_to_selection (ev);
}
if (!extend) {
if (!fine) {
/* non-fine, move by 1 bar regardless of snap */
- delta = Evoral::Beats(trackview.session()->tempo_map().meter_at(ref_point).divisions_per_bar());
+ delta = Evoral::Beats(trackview.session()->tempo_map().meter_at_frame (ref_point).divisions_per_bar());
} else if (trackview.editor().snap_mode() == Editing::SnapOff) {
void
MidiRegionView::note_entered(NoteBase* ev)
{
+ _note_entered = true;
+
Editor* editor = dynamic_cast<Editor*>(&trackview.editor());
if (_mouse_state == SelectTouchDragging) {
+
note_selected (ev, true);
+
} else if (editor->current_mouse_mode() == MouseContent) {
+
+ remove_ghost_note ();
show_verbose_cursor (ev->note ());
+
} else if (editor->current_mouse_mode() == MouseDraw) {
+
+ remove_ghost_note ();
show_verbose_cursor (ev->note ());
}
}
void
MidiRegionView::note_left (NoteBase*)
{
+ _note_entered = false;
+
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
(*i)->hide_velocity ();
}
duration, pos, _region->position(),
pos_beats));
- clear_selection ();
+ clear_editor_note_selection ();
for (int n = 0; n < (int) times; ++n) {
void
MidiRegionView::enable_display (bool yn)
{
+
RegionView::enable_display (yn);
if (yn) {
redisplay_model ();
// display_sysexes();
}
-void
-MidiRegionView::show_verbose_cursor (boost::shared_ptr<NoteType> n) const
+std::string
+MidiRegionView::get_note_name (boost::shared_ptr<NoteType> n, uint8_t note_value) const
{
using namespace MIDI::Name;
-
std::string name;
MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
n->channel(),
patch_key.bank(),
patch_key.program(),
- n->note());
+ note_value);
}
- mtv->set_note_highlight (n->note());
}
char buf[128];
snprintf (buf, sizeof (buf), "%d %s\nCh %d Vel %d",
- (int) n->note (),
- name.empty() ? Evoral::midi_note_name (n->note()).c_str() : name.c_str(),
+ (int) note_value,
+ name.empty() ? Evoral::midi_note_name (note_value).c_str() : name.c_str(),
(int) n->channel() + 1,
(int) n->velocity());
- show_verbose_cursor(buf, 10, 20);
+ return buf;
+}
+
+void
+MidiRegionView::show_verbose_cursor_for_new_note_value(boost::shared_ptr<NoteType> current_note,
+ uint8_t new_value) const
+{
+ MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+ if (mtv) {
+ mtv->set_note_highlight (new_value);
+ }
+
+ show_verbose_cursor(get_note_name(current_note, new_value), 10, 20);
+}
+
+void
+MidiRegionView::show_verbose_cursor (boost::shared_ptr<NoteType> n) const
+{
+ show_verbose_cursor_for_new_note_value(n, n->note());
}
void
MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, framecnt_t& grid_frames) const
{
PublicEditor& editor = trackview.editor ();
-
+ const Evoral::Beats p_beat = region_frames_to_region_beats (p);
const Evoral::Beats grid_beats = get_grid_beats(p);
- grid_frames = region_beats_to_region_frames (grid_beats);
+ grid_frames = region_beats_to_region_frames (p_beat + grid_beats) - region_beats_to_region_frames (p_beat);
/* Hack so that we always snap to the note that we are over, instead of snapping
to the next one if we're more than halfway through the one we're over.
return snap_frame_to_frame (p);
}
-/** Called when the selection has been cleared in any MidiRegionView.
- * @param rv MidiRegionView that the selection was cleared in.
- */
-void
-MidiRegionView::selection_cleared (MidiRegionView* rv)
-{
- if (rv == this) {
- return;
- }
-
- /* Clear our selection in sympathy; but don't signal the fact */
- clear_selection (false);
-}
-
ChannelMode
MidiRegionView::get_channel_mode () const
{
{
PublicEditor& editor = trackview.editor();
bool success = false;
- Evoral::Beats beats = editor.get_grid_type_as_beats(success, pos);
+ Evoral::Beats beats = editor.get_grid_type_as_beats (success, pos);
if (!success) {
beats = Evoral::Beats(1);
}