#include "public_editor.h"
#include "ghostregion.h"
#include "midi_time_axis.h"
+#include "automation_time_axis.h"
+#include "automation_region_view.h"
#include "utils.h"
#include "midi_util.h"
#include "gui_thread.h"
using namespace Editing;
using namespace ArdourCanvas;
-MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<MidiRegion> r, double spu,
- Gdk::Color& basic_color)
+MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color& basic_color)
: RegionView (parent, tv, r, spu, basic_color)
, _default_note_length(0.0)
, _active_notes(0)
_note_group->raise_to_top();
}
-MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<MidiRegion> r, double spu,
- Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility)
+MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility)
: RegionView (parent, tv, r, spu, basic_color, visibility)
, _default_note_length(0.0)
, _active_notes(0)
}
_model->ContentsChanged.connect(sigc::mem_fun(this, &MidiRegionView::redisplay_model));
}
+
+ midi_region()->midi_source(0)->Switched.connect(sigc::mem_fun(this, &MidiRegionView::switch_source));
group->signal_event().connect (mem_fun (this, &MidiRegionView::canvas_event), false);
original_mode = trackview.editor.current_midi_edit_mode();
trackview.editor.set_midi_edit_mode(MidiEditErase);
start_remove_command();
- _mouse_state = EraseDragging;
+ _mouse_state = EraseTouchDragging;
+ } else if (ev->key.keyval == GDK_Shift_L || ev->key.keyval == GDK_Control_L) {
+ _mouse_state = SelectTouchDragging;
}
- break;
+ return true;
case GDK_KEY_RELEASE:
if (ev->key.keyval == GDK_Delete) {
- if (_mouse_state == EraseDragging) {
+ if (_mouse_state == EraseTouchDragging) {
delete_selection();
apply_command();
}
trackview.editor.set_midi_edit_mode(original_mode);
delete_mod = false;
}
+ } else if (ev->key.keyval == GDK_Shift_L || ev->key.keyval == GDK_Control_L) {
+ _mouse_state = None;
}
- break;
+ return true;
case GDK_BUTTON_PRESS:
- //group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, ev->button.time);
- _mouse_state = Pressed;
+ if (_mouse_state != SelectTouchDragging && _mouse_state != EraseTouchDragging)
+ _mouse_state = Pressed;
_pressed_button = ev->button.button;
- //cerr << "PRESSED: " << press_button << endl;
return true;
case GDK_ENTER_NOTIFY:
switch (_mouse_state) {
case Pressed: // Drag start
- // Select rect start
+ // Select drag start
if (_pressed_button == 1 && trackview.editor.current_midi_edit_mode() == MidiEditSelect) {
- cerr << "SELECT START\n";
group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
Gdk::Cursor(Gdk::FLEUR), ev->motion.time);
last_x = event_x;
drag_rect->property_fill_color_rgba()
= ARDOUR_UI::config()->canvasvar_MidiSelectRectFill.get();
- _mouse_state = SelectDragging;
+ _mouse_state = SelectRectDragging;
return true;
// Add note drag start
} else if (trackview.editor.current_midi_edit_mode() == MidiEditPencil) {
- cerr << "PENCIL START\n";
group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
Gdk::Cursor(Gdk::FLEUR), ev->motion.time);
last_x = event_x;
_mouse_state = AddDragging;
return true;
-
- // Eraser drag start
- } else if (trackview.editor.current_midi_edit_mode() == MidiEditErase) {
- cerr << "ERASE DRAGGING\n";
- _mouse_state = EraseDragging;
- return false; // ?
}
- break;
+ return false;
- case SelectDragging: // Select rect motion
- case AddDragging: // Add note rect motion
+ case SelectRectDragging: // Select drag motion
+ case AddDragging: // Add note drag motion
if (ev->motion.is_hint) {
int t_x;
int t_y;
event_x = trackview.editor.frame_to_pixel(event_frame);
if (drag_rect)
- drag_rect->property_x2() = event_x;
-
- if (drag_rect && _mouse_state == SelectDragging) {
- drag_rect->property_y2() = event_y;
-
+ if (event_x > drag_start_x)
+ drag_rect->property_x2() = event_x;
+ else
+ drag_rect->property_x1() = event_x;
+
+ if (drag_rect && _mouse_state == SelectRectDragging) {
+ if (event_y > drag_start_y)
+ drag_rect->property_y2() = event_y;
+ else
+ drag_rect->property_y1() = event_y;
+
update_drag_selection(drag_start_x, event_x, drag_start_y, event_y);
}
last_x = event_x;
last_y = event_y;
- case EraseDragging:
- return true;
+ case EraseTouchDragging:
+ case SelectTouchDragging:
+ return false;
default:
- _mouse_state = None;
break;
}
break;
}
_mouse_state = None;
return true;
- case SelectDragging: // Select drag done
+ case SelectRectDragging: // Select drag done
_mouse_state = None;
delete drag_rect;
drag_rect = NULL;
void
MidiRegionView::redisplay_model()
{
- clear_events();
+ // Don't redisplay the model if we're currently recording and displaying that
+ if (_active_notes)
+ return;
if (_model) {
+
+ clear_events();
begin_write();
+
+ _model->read_lock();
for (size_t i=0; i < _model->n_notes(); ++i)
add_note(_model->note_at(i));
end_write();
+
+ for (Automatable::Controls::const_iterator i = _model->controls().begin();
+ i != _model->controls().end(); ++i) {
+
+ assert(i->second);
+
+ boost::shared_ptr<AutomationTimeAxisView> at
+ = midi_view()->automation_child(i->second->parameter());
+ if (!at)
+ continue;
+
+ Gdk::Color col = midi_stream_view()->get_region_color();
+
+ boost::shared_ptr<AutomationRegionView> arv;
+
+ {
+ Glib::Mutex::Lock list_lock (i->second->list()->lock());
+
+ arv = boost::shared_ptr<AutomationRegionView>(
+ new AutomationRegionView(at->canvas_display,
+ *at.get(), _region, i->second->list(),
+ midi_stream_view()->get_samples_per_unit(), col));
+
+ _automation_children.insert(std::make_pair(i->second->parameter(), arv));
+ }
+
+ arv->init(col, true);
+ }
+
+ _model->read_unlock();
+
} else {
- warning << "MidiRegionView::redisplay_model called without a model" << endmsg;
+ cerr << "MidiRegionView::redisplay_model called without a model" << endmsg;
}
}
MidiRegionView::~MidiRegionView ()
{
in_destructor = true;
- end_write();
+ if (_active_notes)
+ end_write();
+
+ clear_events();
RegionViewGoingAway (this); /* EMIT_SIGNAL */
}
void
MidiRegionView::begin_write()
{
+ assert(!_active_notes);
_active_notes = new CanvasNote*[128];
for (unsigned i=0; i < 128; ++i)
_active_notes[i] = NULL;
void
MidiRegionView::add_event (const MidiEvent& ev)
{
- /*printf("Event, time = %f, size = %zu, data = ", ev.time, ev.size);
- for (size_t i=0; i < ev.size; ++i) {
- printf("%X ", ev.buffer[i]);
+ /*printf("MRV add Event, time = %f, size = %u, data = ", ev.time(), ev.size());
+ for (size_t i=0; i < ev.size(); ++i) {
+ printf("%X ", ev.buffer()[i]);
}
printf("\n\n");*/
_selection.clear();
_selection.insert(ev);
- ev->selected(true);
+
+ if ( ! ev->selected())
+ ev->selected(true);
}
void
clear_selection_except(ev);
_selection.insert(ev);
- ev->selected(true);
+
+ if ( ! ev->selected())
+ ev->selected(true);
}
clear_selection_except(ev);
_selection.erase(ev);
- ev->selected(false);
+
+ if (ev->selected())
+ ev->selected(false);
}
void
-MidiRegionView::update_drag_selection(double last_x, double x, double last_y, double y)
+MidiRegionView::update_drag_selection(double x1, double x2, double y1, double y2)
{
+ const double last_y = std::min(y1, y2);
+ const double y = std::max(y1, y2);
+
// FIXME: so, so, so much slower than this should be
- for (std::vector<CanvasMidiEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->x1() >= last_x && (*i)->x1() <= x && (*i)->y1() >= last_y && (*i)->y1() <= y) {
- (*i)->selected(true);
- _selection.insert(*i);
- } else {
- (*i)->selected(false);
- _selection.erase(*i);
+
+ if (x1 < x2) {
+ for (std::vector<CanvasMidiEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
+ if ((*i)->x1() >= x1 && (*i)->x1() <= x2 && (*i)->y1() >= last_y && (*i)->y1() <= y) {
+ (*i)->selected(true);
+ _selection.insert(*i);
+ } else {
+ (*i)->selected(false);
+ _selection.erase(*i);
+ }
+ }
+ } else {
+ for (std::vector<CanvasMidiEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
+ if ((*i)->x2() <= x1 && (*i)->x2() >= x2 && (*i)->y1() >= last_y && (*i)->y1() <= y) {
+ (*i)->selected(true);
+ _selection.insert(*i);
+ } else {
+ (*i)->selected(false);
+ _selection.erase(*i);
+ }
}
}
}
void
MidiRegionView::move_selection(double dx, double dy)
{
- cerr << "MOVE SELECTION: " << dx << ", " << dy << endl;
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i)
(*i)->item()->move(dx, dy);
}
+
void
MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote)
{
apply_command();
}
}
+
+
+void
+MidiRegionView::note_entered(ArdourCanvas::CanvasMidiEvent* ev)
+{
+ cerr << "NOTE ENTERED: " << _mouse_state << endl;
+ if (ev->note() && _mouse_state == EraseTouchDragging) {
+ start_delta_command();
+ ev->selected(true);
+ _delta_command->remove(*ev->note());
+ } else if (_mouse_state == SelectTouchDragging) {
+ note_selected(ev, true);
+ }
+}
+
+
+void
+MidiRegionView::switch_source(boost::shared_ptr<Source> src)
+{
+ boost::shared_ptr<MidiSource> msrc = boost::dynamic_pointer_cast<MidiSource>(src);
+ if (msrc)
+ display_model(msrc->model());
+}