-/*
+/*
Copyright (C) 2009 Paul Davis
This program is free software; you can redistribute it and/or modify
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <cmath>
#include "evoral/midi_util.h"
+
+#include "ardour/beats_frames_converter.h"
#include "ardour/midi_region.h"
#include "ardour/session.h"
#include "ardour/tempo.h"
using namespace Glib;
using namespace ARDOUR;
-MidiListEditor::MidiListEditor (Session& s, boost::shared_ptr<MidiRegion> r)
+MidiListEditor::MidiListEditor (Session* s, boost::shared_ptr<MidiRegion> r)
: ArdourDialog (r->name(), false, false)
- , session (s)
, region (r)
{
+ set_session (s);
+
model = ListStore::create (columns);
view.set_model (model);
+ view.signal_key_press_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_press));
+ view.signal_key_release_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_release));
+
view.append_column (_("Start"), columns.start);
view.append_column (_("Channel"), columns.channel);
view.append_column (_("Num"), columns.note);
for (int i = 0; i < 6; ++i) {
CellRendererText* renderer = dynamic_cast<CellRendererText*>(view.get_column_cell_renderer (i));
renderer->property_editable() = true;
- renderer->signal_edited().connect (mem_fun (*this, &MidiListEditor::edited));
+
+ renderer->signal_editing_started().connect (sigc::bind (sigc::mem_fun (*this, &MidiListEditor::editing_started), i));
+ renderer->signal_editing_canceled().connect (sigc::mem_fun (*this, &MidiListEditor::editing_canceled));
+ renderer->signal_edited().connect (sigc::mem_fun (*this, &MidiListEditor::edited));
}
-
+
scroller.add (view);
scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
{
}
+bool
+MidiListEditor::key_press (GdkEventKey* ev)
+{
+ bool editing = !_current_edit.empty();
+ bool ret = false;
+
+ if (editing) {
+ switch (ev->keyval) {
+ case GDK_Tab:
+ break;
+ case GDK_Right:
+ break;
+ case GDK_Left:
+ break;
+ case GDK_Up:
+ break;
+ case GDK_Down:
+ break;
+ case GDK_Escape:
+ break;
+ }
+ }
+
+ return ret;
+}
+
+bool
+MidiListEditor::key_release (GdkEventKey* ev)
+{
+ bool ret = false;
+
+ switch (ev->keyval) {
+ case GDK_Delete:
+ delete_selected_note ();
+ ret = true;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+void
+MidiListEditor::delete_selected_note ()
+{
+ Glib::RefPtr<TreeSelection> selection = view.get_selection();
+ TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
+
+ if (rows.empty()) {
+ return;
+ }
+
+ TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
+ TreeIter iter;
+
+ /* selection mode is single, so rows.begin() is it */
+
+ if ((iter = model->get_iter (*i))) {
+ boost::shared_ptr<NoteType> note = (*iter)[columns._note];
+ cerr << "Would have deleted " << *note << endl;
+ }
+
+}
+
+void
+MidiListEditor::editing_started (CellEditable*, const ustring& path, int colno)
+{
+ _current_edit = path;
+ cerr << "Now editing " << _current_edit << " Column " << colno << endl;
+}
+
+void
+MidiListEditor::editing_canceled ()
+{
+ _current_edit = "";
+}
+
void
MidiListEditor::edited (const Glib::ustring& path, const Glib::ustring& /* text */)
{
cerr << "Edited " << *note << endl;
redisplay_model ();
+
+ /* keep selected row(s), move cursor there, to allow us to continue editing */
}
void
view.set_model (Glib::RefPtr<Gtk::ListStore>(0));
model->clear ();
- MidiModel::Notes notes = region->midi_source(0)->model()->notes();
- TreeModel::Row row;
-
- for (MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) {
- row = *(model->append());
- row[columns.channel] = (*i)->channel();
- row[columns.note_name] = _("Note");
- row[columns.note] = (*i)->note();
- row[columns.velocity] = (*i)->velocity();
-
- BBT_Time bbt;
- BBT_Time dur;
- stringstream ss;
+ if (_session) {
- session.tempo_map().bbt_time (region->position(), bbt);
-
- dur.bars = 0;
- dur.beats = floor ((*i)->time());
- dur.ticks = 0;
-
- session.tempo_map().bbt_duration_at (region->position(), dur, 0);
-
- ss << bbt;
- row[columns.start] = ss.str();
- ss << dur;
- row[columns.length] = ss.str();
-
- session.tempo_map().bbt_time (region->position(), bbt);
- /* XXX get end point */
+ BeatsFramesConverter conv (_session->tempo_map(), region->position());
+ MidiModel::Notes notes = region->midi_source(0)->model()->notes();
+ TreeModel::Row row;
+ stringstream ss;
- ss << bbt;
- row[columns.end] = ss.str();
-
- row[columns._note] = (*i);
+ for (MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) {
+ row = *(model->append());
+ row[columns.channel] = (*i)->channel() + 1;
+ row[columns.note_name] = Evoral::midi_note_name ((*i)->note());
+ row[columns.note] = (*i)->note();
+ row[columns.velocity] = (*i)->velocity();
+
+ BBT_Time bbt;
+ double dur;
+
+ _session->tempo_map().bbt_time (conv.to ((*i)->time()), bbt);
+
+ ss.str ("");
+ ss << bbt;
+ row[columns.start] = ss.str();
+
+ bbt.bars = 0;
+ dur = (*i)->end_time() - (*i)->time();
+ bbt.beats = floor (dur);
+ bbt.ticks = (uint32_t) lrint (fmod (dur, 1.0) * Meter::ticks_per_beat);
+
+ _session->tempo_map().bbt_duration_at (region->position(), bbt, 0);
+
+ ss.str ("");
+ ss << bbt;
+ row[columns.length] = ss.str();
+
+ _session->tempo_map().bbt_time (conv.to ((*i)->end_time()), bbt);
+
+ ss.str ("");
+ ss << bbt;
+ row[columns.end] = ss.str();
+
+ row[columns._note] = (*i);
+ }
}
view.set_model (model);
-}
+}