remove Glib::ustring from gtk2_ardour
[ardour.git] / gtk2_ardour / midi_list_editor.cc
1 /*
2    Copyright (C) 2009 Paul Davis
3
4         This program is free software; you can redistribute it and/or modify
5         it under the terms of the GNU General Public License as published by
6         the Free Software Foundation; either version 2 of the License, or
7         (at your option) any later version.
8
9         This program is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12         GNU General Public License for more details.
13
14         You should have received a copy of the GNU General Public License
15         along with this program; if not, write to the Free Software
16         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19 #include <cmath>
20
21 #include "evoral/midi_util.h"
22
23 #include "ardour/beats_frames_converter.h"
24 #include "ardour/midi_region.h"
25 #include "ardour/session.h"
26 #include "ardour/tempo.h"
27
28 #include "midi_list_editor.h"
29
30 #include "i18n.h"
31
32 using namespace std;
33 using namespace Gtk;
34 using namespace Glib;
35 using namespace ARDOUR;
36
37 MidiListEditor::MidiListEditor (Session* s, boost::shared_ptr<MidiRegion> r)
38         : ArdourDialog (r->name(), false, false)
39         , region (r)
40 {
41         set_session (s);
42
43         model = ListStore::create (columns);
44         view.set_model (model);
45
46         view.signal_key_press_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_press));
47         view.signal_key_release_event().connect (sigc::mem_fun (*this, &MidiListEditor::key_release));
48
49         view.append_column (_("Start"), columns.start);
50         view.append_column (_("Channel"), columns.channel);
51         view.append_column (_("Num"), columns.note);
52         view.append_column (_("Name"), columns.note_name);
53         view.append_column (_("Vel"), columns.velocity);
54         view.append_column (_("Length"), columns.length);
55         view.append_column (_("End"), columns.end);
56         view.set_headers_visible (true);
57         view.set_name (X_("MidiListView"));
58         view.set_rules_hint (true);
59
60         for (int i = 0; i < 6; ++i) {
61                 CellRendererText* renderer = dynamic_cast<CellRendererText*>(view.get_column_cell_renderer (i));
62                 renderer->property_editable() = true;
63
64                 renderer->signal_editing_started().connect (sigc::bind (sigc::mem_fun (*this, &MidiListEditor::editing_started), i));
65                 renderer->signal_editing_canceled().connect (sigc::mem_fun (*this, &MidiListEditor::editing_canceled));
66                 renderer->signal_edited().connect (sigc::mem_fun (*this, &MidiListEditor::edited));
67         }
68
69         scroller.add (view);
70         scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
71
72         redisplay_model ();
73
74         view.show ();
75         scroller.show ();
76
77         get_vbox()->pack_start (scroller);
78         set_size_request (400, 400);
79 }
80
81 MidiListEditor::~MidiListEditor ()
82 {
83 }
84
85 bool
86 MidiListEditor::key_press (GdkEventKey* ev)
87 {
88         bool editing = !_current_edit.empty();
89         bool ret = false;
90
91         if (editing) {
92                 switch (ev->keyval) {
93                 case GDK_Tab:
94                         break;
95                 case GDK_Right:
96                         break;
97                 case GDK_Left:
98                         break;
99                 case GDK_Up:
100                         break;
101                 case GDK_Down:
102                         break;
103                 case GDK_Escape:
104                         break;
105                 }
106         }
107
108         return ret;
109 }
110
111 bool
112 MidiListEditor::key_release (GdkEventKey* ev)
113 {
114         bool ret = false;
115
116         switch (ev->keyval) {
117         case GDK_Delete:
118                 delete_selected_note ();
119                 ret = true;
120                 break;
121         default:
122                 break;
123         }
124
125         return ret;
126 }
127
128 void
129 MidiListEditor::delete_selected_note ()
130 {
131         Glib::RefPtr<TreeSelection> selection = view.get_selection();
132         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
133
134         if (rows.empty()) {
135                 return;
136         }
137
138         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
139         TreeIter iter;
140
141         /* selection mode is single, so rows.begin() is it */
142
143         if ((iter = model->get_iter (*i))) {
144                 boost::shared_ptr<NoteType> note = (*iter)[columns._note];
145                 cerr << "Would have deleted " << *note << endl;
146         }
147
148 }
149
150 void
151 MidiListEditor::editing_started (CellEditable*, const string& path, int colno)
152 {
153         _current_edit = path;
154         cerr << "Now editing " << _current_edit << " Column " << colno << endl;
155 }
156
157 void
158 MidiListEditor::editing_canceled ()
159 {
160         _current_edit = "";
161 }
162
163 void
164 MidiListEditor::edited (const std::string& path, const std::string& /* text */)
165 {
166         TreeModel::iterator iter = model->get_iter (path);
167
168         cerr << "Edit at " << path << endl;
169
170         if (!iter) {
171                 return;
172         }
173
174         boost::shared_ptr<NoteType> note = (*iter)[columns._note];
175
176         cerr << "Edited " << *note << endl;
177
178         redisplay_model ();
179         
180         /* keep selected row(s), move cursor there, to allow us to continue editing */
181 }
182
183 void
184 MidiListEditor::redisplay_model ()
185 {
186         view.set_model (Glib::RefPtr<Gtk::ListStore>(0));
187         model->clear ();
188
189         if (_session) {
190                 
191                 BeatsFramesConverter conv (_session->tempo_map(), region->position());
192                 MidiModel::Notes notes = region->midi_source(0)->model()->notes();
193                 TreeModel::Row row;
194                 stringstream ss;
195                 
196                 for (MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) {
197                         row = *(model->append());
198                         row[columns.channel] = (*i)->channel() + 1;
199                         row[columns.note_name] = Evoral::midi_note_name ((*i)->note());
200                         row[columns.note] = (*i)->note();
201                         row[columns.velocity] = (*i)->velocity();
202                         
203                         BBT_Time bbt;
204                         double dur;
205
206                         _session->tempo_map().bbt_time (conv.to ((*i)->time()), bbt);
207                         
208                         ss.str ("");
209                         ss << bbt;
210                         row[columns.start] = ss.str();
211
212                         bbt.bars = 0;
213                         dur = (*i)->end_time() - (*i)->time();
214                         bbt.beats = floor (dur);
215                         bbt.ticks = (uint32_t) lrint (fmod (dur, 1.0) * Meter::ticks_per_beat);
216                         
217                         _session->tempo_map().bbt_duration_at (region->position(), bbt, 0);
218
219                         ss.str ("");
220                         ss << bbt;
221                         row[columns.length] = ss.str();
222                         
223                         _session->tempo_map().bbt_time (conv.to ((*i)->end_time()), bbt);
224                                                                                                  
225                         ss.str ("");
226                         ss << bbt;
227                         row[columns.end] = ss.str();
228                         
229                         row[columns._note] = (*i);
230                 }
231         }
232
233         view.set_model (model);
234 }