/[svn]/gigedit/trunk/src/gigedit/midirules.cpp
ViewVC logotype

Contents of /gigedit/trunk/src/gigedit/midirules.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2845 - (show annotations) (download)
Sun Sep 20 10:18:22 2015 UTC (8 years, 6 months ago) by persson
File size: 18964 byte(s)
* avoid using gtk stock items, as they are deprecated in gtk 3.10

1 /*
2 * Copyright (C) 2013-2015 Andreas Persson
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * 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., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 #include "midirules.h"
21
22 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
23 #include <gtkmm/stock.h>
24 #endif
25
26 #include "global.h"
27
28 MidiRules::MidiRules() :
29 label(_("Midi rule:")),
30 quit_button(_("_Close"), true),
31 unknown(_("unknown"))
32 {
33 set_title(_("Midi Rules"));
34 set_border_width(6);
35
36 add(vbox);
37
38 hbox.set_border_width(6);
39 hbox.set_spacing(6);
40 hbox.pack_start(label, Gtk::PACK_SHRINK);
41 hbox.pack_start(combo, Gtk::PACK_SHRINK);
42 const char* choices[] = { _("none"), _("Controller trigger"),
43 _("Legato"), 0 };
44 for (int i = 0 ; choices[i] ; i++) {
45 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
46 combo.append_text(choices[i]);
47 #else
48 combo.append(choices[i]);
49 #endif
50 }
51 combo.signal_changed().connect(
52 sigc::mem_fun(*this, &MidiRules::combo_changed));
53 vbox.pack_start(hbox, Gtk::PACK_SHRINK);
54
55 box.set_border_width(6);
56 vbox.pack_start(box);
57
58 button_box.set_border_width(6);
59 button_box.set_layout(Gtk::BUTTONBOX_END);
60 button_box.pack_start(quit_button);
61 quit_button.set_can_default();
62 quit_button.grab_focus();
63 quit_button.signal_clicked().connect(
64 sigc::mem_fun(*this, &MidiRules::hide));
65 vbox.pack_start(button_box, Gtk::PACK_SHRINK);
66
67 legato.signal_changed().connect(sig_changed.make_slot());
68 ctrl_trigger.signal_changed().connect(sig_changed.make_slot());
69
70 show_all_children();
71 }
72
73 void MidiRules::combo_changed() {
74 if (update_model) return;
75
76 int rowno = combo.get_active_row_number();
77
78 if (remove_unknown_from_combo()) {
79 rowno--;
80 }
81
82 gig::MidiRule* rule = m->GetMidiRule(0);
83 switch (rowno) {
84 case NONE:
85 if (rule) {
86 m->DeleteMidiRule(0);
87 set_instrument(m);
88 }
89 break;
90 case CTRL_TRIGGER:
91 if (!dynamic_cast<gig::MidiRuleCtrlTrigger*>(rule)) {
92 m->AddMidiRuleCtrlTrigger();
93 set_instrument(m);
94 }
95 break;
96 case LEGATO:
97 if (!dynamic_cast<gig::MidiRuleLegato*>(rule)) {
98 m->AddMidiRuleLegato();
99 set_instrument(m);
100 }
101 break;
102 }
103 sig_changed();
104 }
105
106 void MidiRules::set_instrument(gig::Instrument* instrument) {
107 m = instrument;
108 update_model++;
109
110 std::vector<Widget*> children = box.get_children();
111 if (children.size() == 1) {
112 box.remove(*children[0]);
113 }
114
115 gig::MidiRule* rule = instrument->GetMidiRule(0);
116 int active = -1;
117 if (!rule) {
118 active = NONE;
119 } else if (gig::MidiRuleLegato* r =
120 dynamic_cast<gig::MidiRuleLegato*>(rule)) {
121 active = LEGATO;
122 box.add(legato);
123 legato.set_rule(r);
124 } else if (gig::MidiRuleCtrlTrigger* r =
125 dynamic_cast<gig::MidiRuleCtrlTrigger*>(rule)) {
126 active = CTRL_TRIGGER;
127 box.add(ctrl_trigger);
128 ctrl_trigger.set_rule(r);
129 } else {
130 if (combo.get_model()->children().size() == NUMBER_OF_RULES) {
131 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
132 combo.prepend_text(unknown);
133 #else
134 combo.prepend(unknown);
135 #endif
136 }
137 combo.set_active(0);
138 }
139 if (active != -1) {
140 remove_unknown_from_combo();
141 combo.set_active(active);
142 }
143 show_all_children();
144 update_model--;
145 }
146
147 bool MidiRules::remove_unknown_from_combo() {
148 if (combo.get_model()->children().size() == NUMBER_OF_RULES + 1) {
149 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
150 combo.remove_text(unknown);
151 #else
152 combo.remove_text(0);
153 #endif
154 return true;
155 }
156 return false;
157 }
158
159
160 MidiRuleCtrlTrigger::MidiRuleCtrlTrigger() :
161 table(2, 1),
162 eControllerNumber(_("Controller"))
163 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
164 , add_button(Gtk::Stock::ADD),
165 remove_button(Gtk::Stock::REMOVE)
166 #endif
167 {
168 connect(eControllerNumber, &gig::MidiRuleCtrlTrigger::ControllerNumber);
169
170 set_spacing(6);
171
172 scrolled_window.set_size_request(-1, 120);
173
174 list_store = Gtk::ListStore::create(columns);
175 tree_view.set_model(list_store);
176 list_store->signal_row_changed().connect(
177 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::row_changed));
178 list_store->signal_row_inserted().connect(
179 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::row_inserted));
180 list_store->signal_row_deleted().connect(
181 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::row_deleted));
182
183 append_num_column(_("Trigger point"), columns.trigger_point);
184 tree_view.append_column_editable(_("Descending"), columns.descending);
185 append_num_column(_("Vel sensitivity"), columns.vel_sensitivity, 1, 100);
186 append_note_column(_("Key"), columns.key);
187 tree_view.append_column_editable(_("Note off"), columns.note_off);
188 tree_view.append_column_editable(_("Switch"), columns.switch_logic);
189
190 int cols_count = append_num_column(_("Velocity"), columns.velocity);
191 Gtk::TreeViewColumn* col = tree_view.get_column(cols_count - 1);
192 col->add_attribute(*col->get_first_cell(), "visible", columns.switch_logic);
193 cols_count = tree_view.append_column_editable(_("Override pedal"),
194 columns.override_pedal);
195 col = tree_view.get_column(cols_count - 1);
196 col->add_attribute(*col->get_first_cell(), "visible", columns.note_off);
197
198 tree_view.get_selection()->signal_changed().connect(
199 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::sel_changed));
200
201 scrolled_window.add(tree_view);
202 scrolled_window.set_shadow_type(Gtk::SHADOW_IN);
203 scrolled_window.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
204
205 table.set_col_spacings(5);
206 table.add(eControllerNumber);
207 pack_start(table, Gtk::PACK_SHRINK);
208
209 vbox.add(scrolled_window);
210
211 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
212 vbox.set_spacing(6);
213 toolbar.set_layout(Gtk::BUTTONBOX_START);
214 toolbar.set_homogeneous();
215 toolbar.set_spacing(6);
216 #else
217 toolbar.set_toolbar_style(Gtk::TOOLBAR_ICONS);
218 toolbar.set_show_arrow(false);
219 toolbar.set_icon_size(Gtk::IconSize(1));
220 toolbar.get_style_context()->add_class("inline-toolbar");
221
222 add_button.set_icon_name("list-add-symbolic");
223 remove_button.set_icon_name("list-remove-symbolic");
224 #endif
225
226 add_button.signal_clicked().connect(
227 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::add_row));
228 toolbar.add(add_button);
229
230 remove_button.signal_clicked().connect(
231 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::remove_row));
232 toolbar.add(remove_button);
233
234 vbox.pack_start(toolbar, Gtk::PACK_SHRINK);
235 add(vbox);
236 }
237
238 int MidiRuleCtrlTrigger::append_num_column(
239 const char* title,
240 const Gtk::TreeModelColumn<int>& column,
241 int lower, int upper) {
242 Gtk::CellRendererSpin* renderer = Gtk::manage(new Gtk::CellRendererSpin());
243 renderer->property_editable() = true;
244 renderer->signal_editing_started().connect(
245 sigc::bind(
246 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::num_editing_started),
247 renderer));
248 renderer->signal_edited().connect(
249 sigc::bind(
250 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::num_edited),
251 column));
252 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
253 renderer->property_adjustment() = new Gtk::Adjustment(lower, lower, upper);
254 #else
255 renderer->property_adjustment() =
256 Gtk::Adjustment::create(lower, lower, upper);
257 #endif
258
259 int cols_count = tree_view.append_column(title, *renderer);
260 Gtk::TreeViewColumn* col = tree_view.get_column(cols_count - 1);
261 col->add_attribute(*renderer, "text", column);
262 col->set_min_width(92);
263 return cols_count;
264 }
265
266 int MidiRuleCtrlTrigger::append_note_column(
267 const char* title,
268 const Gtk::TreeModelColumn<Glib::ustring>& column) {
269 Gtk::CellRendererSpin* renderer = Gtk::manage(new Gtk::CellRendererSpin());
270 renderer->property_editable() = true;
271 renderer->signal_editing_started().connect(
272 sigc::bind(
273 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::note_editing_started),
274 renderer));
275 renderer->signal_edited().connect(
276 sigc::bind(
277 sigc::mem_fun(*this, &MidiRuleCtrlTrigger::note_edited),
278 column));
279 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
280 renderer->property_adjustment() = new Gtk::Adjustment(0, 0, 127);
281 #else
282 renderer->property_adjustment() = Gtk::Adjustment::create(0, 0, 127);
283 #endif
284
285 int cols_count = tree_view.append_column(title, *renderer);
286 Gtk::TreeViewColumn* col = tree_view.get_column(cols_count - 1);
287 col->add_attribute(*renderer, "text", column);
288 col->set_min_width(98);
289 return cols_count;
290 }
291
292 void MidiRuleCtrlTrigger::set_rule(gig::MidiRuleCtrlTrigger* r) {
293 update_model++;
294 update(r);
295 list_store->clear();
296 for (int i = 0 ; i < r->Triggers ; i++) {
297 Gtk::TreeModel::Row row = *list_store->append();
298 row[columns.trigger_point] = r->pTriggers[i].TriggerPoint;
299 row[columns.descending] = r->pTriggers[i].Descending;
300 row[columns.vel_sensitivity] = r->pTriggers[i].VelSensitivity;
301 row[columns.key] = note_str(r->pTriggers[i].Key);
302 row[columns.note_off] = r->pTriggers[i].NoteOff;
303 row[columns.switch_logic] = r->pTriggers[i].Velocity != 255;
304 if (r->pTriggers[i].Velocity != 255) {
305 row[columns.velocity] = r->pTriggers[i].Velocity;
306 }
307 row[columns.override_pedal] = r->pTriggers[i].OverridePedal;
308 }
309 sel_changed();
310 add_button.set_sensitive();
311 if (r->Triggers == 32) add_button.set_sensitive(false);
312 update_model--;
313 }
314
315 void MidiRuleCtrlTrigger::num_editing_started(
316 Gtk::CellEditable* editable,
317 const Glib::ustring& path,
318 Gtk::CellRendererSpin* renderer) {
319 int lower = renderer->property_adjustment().get_value()->get_lower();
320 int upper = renderer->property_adjustment().get_value()->get_upper();
321 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
322 renderer->property_adjustment() = new Gtk::Adjustment(lower, lower, upper);
323 #else
324 renderer->property_adjustment() =
325 Gtk::Adjustment::create(lower, lower, upper);
326 #endif
327 Gtk::SpinButton* spin_button = dynamic_cast<Gtk::SpinButton*>(editable);
328 if (spin_button) {
329 spin_button->set_numeric();
330 }
331 }
332
333 void MidiRuleCtrlTrigger::note_editing_started(
334 Gtk::CellEditable* editable,
335 const Glib::ustring& path,
336 Gtk::CellRendererSpin* renderer) {
337 int value = note_value(renderer->property_text());
338 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
339 renderer->property_adjustment() = new Gtk::Adjustment(0, 0, 127);
340 #else
341 renderer->property_adjustment() = Gtk::Adjustment::create(0, 0, 127);
342 #endif
343 Gtk::SpinButton* spin_button = dynamic_cast<Gtk::SpinButton*>(editable);
344 if (spin_button) {
345 spin_button->get_adjustment()->set_value(value);
346 spin_button_show_notes(*spin_button);
347 }
348 }
349
350 void MidiRuleCtrlTrigger::num_edited(
351 const Glib::ustring& path,
352 const Glib::ustring& new_text,
353 const Gtk::TreeModelColumn<int>& column) {
354 Gtk::TreeModel::Row row = *list_store->get_iter(path);
355
356 Gtk::TreeModel::Path cpath;
357 Gtk::TreeViewColumn* col;
358 tree_view.get_cursor(cpath, col);
359
360 int lower = 0;
361 int upper = 127;
362 const Gtk::CellRenderer* r = col->get_first_cell();
363 if (const Gtk::CellRendererSpin* renderer =
364 dynamic_cast<const Gtk::CellRendererSpin*>(r)) {
365 lower = renderer->property_adjustment().get_value()->get_lower();
366 upper = renderer->property_adjustment().get_value()->get_upper();
367 }
368
369 row[column] = std::max(lower, std::min(atoi(new_text.c_str()), upper));
370 }
371
372 void MidiRuleCtrlTrigger::note_edited(
373 const Glib::ustring& path,
374 const Glib::ustring& new_text,
375 const Gtk::TreeModelColumn<Glib::ustring>& column) {
376 Gtk::TreeModel::Row row = *list_store->get_iter(path);
377
378 row[column] = note_str(note_value(new_text));
379 }
380
381 void MidiRuleCtrlTrigger::sel_changed() {
382 Gtk::TreeModel::iterator it = tree_view.get_selection()->get_selected();
383 remove_button.set_sensitive();
384 if (!it) remove_button.set_sensitive(false);
385 }
386
387 void MidiRuleCtrlTrigger::add_row() {
388 Gtk::TreeModel::Path path;
389 Gtk::TreeViewColumn* col;
390 tree_view.get_cursor(path, col);
391 if (!path.empty()) tree_view.set_cursor(path);
392
393 Gtk::TreeModel::iterator it = list_store->append();
394 Gtk::TreeModel::Row row = *it;
395
396 update_model++;
397 row[columns.trigger_point] = 64;
398 row[columns.descending] = false;
399 row[columns.vel_sensitivity] = 50;
400 row[columns.key] = note_str(60);
401 row[columns.note_off] = false;
402 row[columns.switch_logic] = false;
403 row[columns.override_pedal] = false;
404 update_model--;
405
406 tree_view.get_selection()->select(row);
407 path = list_store->get_path(it);
408 tree_view.scroll_to_row(path);
409 tree_view.set_cursor(path);
410 }
411
412 void MidiRuleCtrlTrigger::remove_row() {
413 Gtk::TreeModel::Path cpath;
414 Gtk::TreeViewColumn* col;
415 tree_view.get_cursor(cpath, col);
416 if (!cpath.empty()) tree_view.set_cursor(cpath);
417
418 Gtk::TreeModel::iterator it = tree_view.get_selection()->get_selected();
419 if (it) {
420 Gtk::TreePath path = list_store->get_path(it);
421 list_store->erase(it);
422
423 it = tree_view.get_selection()->get_selected();
424 if (!it) {
425 int i = path[0];
426 int n = list_store->children().size();
427 if (n) {
428 if (i >= n) i = n - 1;
429 path[0] = i;
430 tree_view.get_selection()->select(path);
431 }
432 }
433 }
434 }
435
436 void MidiRuleCtrlTrigger::row_changed(const Gtk::TreeModel::Path& path,
437 const Gtk::TreeModel::iterator& iter) {
438 if (update_model) return;
439
440 Gtk::TreeModel::Row row = *iter;
441 int i = path[0];
442
443 if (m->pTriggers[i].Velocity == 255 && row[columns.switch_logic]) {
444 update_model++;
445 row[columns.velocity] = 100;
446 update_model--;
447 }
448
449 int key = note_value(row[columns.key]);
450
451 if (m->pTriggers[i].TriggerPoint != row[columns.trigger_point] ||
452 m->pTriggers[i].Descending != row[columns.descending] ||
453 m->pTriggers[i].VelSensitivity != row[columns.vel_sensitivity] ||
454 m->pTriggers[i].Key != key ||
455 m->pTriggers[i].NoteOff != row[columns.note_off] ||
456 (m->pTriggers[i].Velocity != 255) != row[columns.switch_logic] ||
457 m->pTriggers[i].Velocity != row[columns.velocity] ||
458 m->pTriggers[i].OverridePedal != row[columns.override_pedal])
459 {
460 m->pTriggers[i].TriggerPoint = row[columns.trigger_point];
461 m->pTriggers[i].Descending = row[columns.descending];
462 m->pTriggers[i].VelSensitivity = row[columns.vel_sensitivity];
463 m->pTriggers[i].Key = key;
464 m->pTriggers[i].NoteOff = row[columns.note_off];
465 m->pTriggers[i].Velocity =
466 row[columns.switch_logic] ? row[columns.velocity] : 255;
467 m->pTriggers[i].OverridePedal = row[columns.override_pedal];
468 sig_changed();
469 }
470 }
471
472 void MidiRuleCtrlTrigger::row_inserted(const Gtk::TreeModel::Path& path,
473 const Gtk::TreeModel::iterator& iter) {
474 if (update_model) return;
475 int i = m->Triggers++;
476 m->pTriggers[i].TriggerPoint = 64;
477 m->pTriggers[i].Descending = false;
478 m->pTriggers[i].VelSensitivity = 50;
479 m->pTriggers[i].Key = 60;
480 m->pTriggers[i].NoteOff = false;
481 m->pTriggers[i].Velocity = 255;
482 m->pTriggers[i].OverridePedal = false;
483 add_button.set_sensitive();
484 if (m->Triggers == 32) add_button.set_sensitive(false);
485 sig_changed();
486 }
487
488 void MidiRuleCtrlTrigger::row_deleted(const Gtk::TreeModel::Path& path) {
489 if (update_model) return;
490 for (int i = path[0] + 1 ; i < m->Triggers ; i++) {
491 m->pTriggers[i - 1] = m->pTriggers[i];
492 }
493 m->Triggers--;
494 add_button.set_sensitive();
495 sig_changed();
496 }
497
498
499
500 MidiRuleLegato::MidiRuleLegato() :
501 Table(2, 1),
502 eBypassUseController(_("Bypass use controller")),
503 eBypassKey(_("Bypass key")),
504 eBypassController(_("Bypass controller")),
505 eThresholdTime(_("Threshold time"), 10, 500),
506 eReleaseTime(_("Release time"), 10, 500),
507 eKeyRangeLow(_("Key range low")),
508 eKeyRangeHigh(_("Key range high")),
509 eReleaseTriggerKey(_("Release trigger key")),
510 eAltSustain1Key(_("Alt sustain 1 key")),
511 eAltSustain2Key(_("Alt sustain 2 key"))
512 {
513 connect(eBypassUseController, &gig::MidiRuleLegato::BypassUseController);
514 connect(eBypassKey, &gig::MidiRuleLegato::BypassKey);
515 connect(eBypassController, &gig::MidiRuleLegato::BypassController);
516 connect(eThresholdTime, &gig::MidiRuleLegato::ThresholdTime);
517 connect(eReleaseTime, &gig::MidiRuleLegato::ReleaseTime);
518 connect(eKeyRangeLow, eKeyRangeHigh, &gig::MidiRuleLegato::KeyRange);
519 connect(eReleaseTriggerKey, &gig::MidiRuleLegato::ReleaseTriggerKey);
520 connect(eAltSustain1Key, &gig::MidiRuleLegato::AltSustain1Key);
521 connect(eAltSustain2Key, &gig::MidiRuleLegato::AltSustain2Key);
522
523 set_col_spacings(5);
524
525 add(eBypassUseController);
526 add(eBypassKey);
527 add(eBypassController);
528 add(eThresholdTime);
529 add(eReleaseTime);
530 add(eKeyRangeLow);
531 add(eKeyRangeHigh);
532 add(eReleaseTriggerKey);
533 add(eAltSustain1Key);
534 add(eAltSustain2Key);
535
536 eBypassUseController.signal_value_changed().connect(
537 sigc::mem_fun(*this, &MidiRuleLegato::BypassUseController_toggled));
538 }
539
540 void MidiRuleLegato::BypassUseController_toggled() {
541 bool useController = eBypassUseController.get_value();
542 eBypassKey.set_sensitive(!useController);
543 eBypassController.set_sensitive(useController);
544 }
545
546 void MidiRuleLegato::set_rule(gig::MidiRuleLegato* r) {
547 update_model++;
548 update(r);
549 BypassUseController_toggled();
550 update_model--;
551 }

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC