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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2507 - (show annotations) (download)
Sun Jan 12 19:37:55 2014 UTC (10 years, 3 months ago) by persson
File size: 12362 byte(s)
* added dialog for editing the CtrlTrigger and Legato midi rules

1 /*
2 * Copyright (C) 2006-2014 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, or (at
7 * 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 program; see the file COPYING. If not, write to the Free
16 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #include <cstring>
21
22 #include "paramedit.h"
23
24 #include "global.h"
25 #include "compat.h"
26
27 std::string gig_encoding("CP1252");
28
29 Glib::ustring gig_to_utf8(const gig::String& gig_string) {
30 return Glib::convert_with_fallback(gig_string, "UTF-8", gig_encoding, "?");
31 }
32
33 gig::String gig_from_utf8(const Glib::ustring& utf8_string) {
34 return Glib::convert_with_fallback(utf8_string, gig_encoding, "UTF-8", "?");
35 }
36
37
38 namespace {
39 const char* const controlChangeTexts[] = {
40 _("none"), _("channelaftertouch"), _("velocity"),
41 0,
42 _("modwheel"), // "Modulation Wheel or Lever",
43 _("breath"), // "Breath Controller",
44 0,
45 _("foot"), // "Foot Controller",
46 _("portamentotime"), // "Portamento Time",
47 0, 0, 0, 0, 0, 0,
48 _("effect1"), // "Effect Control 1",
49 _("effect2"), // "Effect Control 2",
50 0, 0,
51 _("genpurpose1"), // "General Purpose Controller 1",
52 _("genpurpose2"), // "General Purpose Controller 2",
53 _("genpurpose3"), // "General Purpose Controller 3",
54 _("genpurpose4"), // "General Purpose Controller 4",
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57 0, 0, 0, 0, 0, 0,
58 _("sustainpedal"), // "Damper Pedal on/off (Sustain)",
59 _("portamento"), // "Portamento On/Off",
60 _("sostenuto"), // "Sustenuto On/Off",
61 _("softpedal"), // "Soft Pedal On/Off",
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 _("genpurpose5"), // "General Purpose Controller 5",
64 _("genpurpose6"), // "General Purpose Controller 6",
65 _("genpurpose7"), // "General Purpose Controller 7",
66 _("genpurpose8"), // "General Purpose Controller 8",
67 0, 0, 0, 0, 0, 0, 0,
68 _("effect1depth"), // "Effects 1 Depth",
69 _("effect2depth"), // "Effects 2 Depth",
70 _("effect3depth"), // "Effects 3 Depth",
71 _("effect4depth"), // "Effects 4 Depth",
72 _("effect5depth"), // "Effects 5 Depth"
73 };
74 }
75
76 LabelWidget::LabelWidget(const char* labelText, Gtk::Widget& widget) :
77 label(Glib::ustring(labelText) + ":"),
78 widget(widget)
79 {
80 label.set_alignment(Gtk::ALIGN_START);
81 }
82
83 void LabelWidget::set_sensitive(bool sensitive)
84 {
85 label.set_sensitive(sensitive);
86 widget.set_sensitive(sensitive);
87 }
88
89 NumEntry::NumEntry(const char* labelText, double lower, double upper,
90 int decimals) :
91 LabelWidget(labelText, box),
92 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
93 adjust(lower, lower, upper, 1, 10),
94 #else
95 adjust(Gtk::Adjustment::create(lower, lower, upper, 1, 10)),
96 #endif
97 scale(adjust),
98 spinbutton(adjust)
99 {
100 scale.set_size_request(70);
101 spinbutton.set_digits(decimals);
102 spinbutton.set_value(0);
103 spinbutton.set_numeric();
104 scale.set_draw_value(false);
105 box.pack_start(spinbutton, Gtk::PACK_SHRINK);
106 box.add(scale);
107 }
108
109 NumEntryGain::NumEntryGain(const char* labelText,
110 double lower, double upper,
111 int decimals, double coeff) :
112 NumEntry(labelText, lower, upper, decimals),
113 value(0),
114 coeff(coeff),
115 connected(true)
116 {
117 spinbutton.signal_value_changed().connect(
118 sigc::mem_fun(*this, &NumEntryGain::value_changed));
119 }
120
121 void NumEntryGain::value_changed()
122 {
123 if (!connected) return;
124
125 const double f = pow(10, spinbutton.get_digits());
126 int new_value = round_to_int(spinbutton.get_value() * f);
127 if (new_value != round_to_int(value / coeff * f)) {
128 value = round_to_int(new_value / f * coeff);
129 sig_changed();
130 }
131 }
132
133 void NumEntryGain::set_value(int32_t value)
134 {
135 if (value != this->value) {
136 this->value = value;
137
138 connected = false;
139 bool plus6 = value < 0;
140 spinbutton.set_value(plus6 ? 0 : value / coeff);
141 set_sensitive(!plus6);
142 connected = true;
143
144 sig_changed();
145 }
146 }
147
148
149 BoolEntryPlus6::BoolEntryPlus6(const char* labelText, NumEntryGain& eGain, int32_t plus6value) :
150 LabelWidget(labelText, checkbutton),
151 checkbutton(labelText),
152 eGain(eGain),
153 plus6value(plus6value)
154 {
155 checkbutton.signal_toggled().connect(
156 sigc::mem_fun(*this, &BoolEntryPlus6::value_changed));
157 }
158
159 void BoolEntryPlus6::value_changed()
160 {
161 if (checkbutton.get_active()) eGain.set_value(plus6value);
162 else if (eGain.get_value() < 0) eGain.set_value(0);
163 }
164
165 int32_t BoolEntryPlus6::get_value() const
166 {
167 return eGain.get_value();
168 }
169
170 void BoolEntryPlus6::set_value(int32_t value)
171 {
172 checkbutton.set_active(value < 0);
173 }
174
175 NumEntryPermille::NumEntryPermille(const char* labelText,
176 double lower, double upper, int decimals) :
177 NumEntry(labelText, lower, upper, decimals),
178 value(0)
179 {
180 spinbutton.signal_value_changed().connect(
181 sigc::mem_fun(*this, &NumEntryPermille::value_changed));
182 }
183
184 void NumEntryPermille::value_changed()
185 {
186 uint16_t new_value = uint16_t(spinbutton.get_value() * 10 + 0.5);
187 if (new_value != value) {
188 value = uint16_t(spinbutton.get_value() * 10 + 0.5);
189 sig_changed();
190 }
191 }
192
193 void NumEntryPermille::set_value(uint16_t value)
194 {
195 if (value != this->value) {
196 spinbutton.set_value(value / 10.0);
197 }
198 }
199
200
201 NoteEntry::NoteEntry(const char* labelText) :
202 NumEntryTemp<uint8_t>(labelText)
203 {
204 spin_button_show_notes(spinbutton);
205 }
206
207 namespace {
208 const char* notes[] = {
209 _("C"), _("C#"), _("D"), _("D#"), _("E"), _("F"),_("F#"),
210 _("G"), _("G#"), _("A"), _("A#"), _("B")
211 };
212
213 int note_value(const Glib::ustring& note, double* value)
214 {
215 const char* str = note.c_str();
216
217 int i;
218 for (i = 11 ; i >= 0 ; i--) {
219 if (strncasecmp(str, notes[i], strlen(notes[i])) == 0) break;
220 }
221 if (i >= 0) {
222 char* endptr;
223 long x = strtol(str + strlen(notes[i]), &endptr, 10);
224 if (endptr != str + strlen(notes[i])) {
225 *value = std::max(0L, std::min(i + (x + 1) * 12, 127L));
226 return true;
227 }
228 } else {
229 char* endptr;
230 long x = strtol(str, &endptr, 10);
231 if (endptr != str) {
232 *value = std::max(0L, std::min(x, 127L));
233 return true;
234 }
235 }
236 return Gtk::INPUT_ERROR;
237 }
238 }
239
240 int note_value(const Glib::ustring& note)
241 {
242 double value = 0;
243 note_value(note, &value);
244 return value;
245 }
246
247 Glib::ustring note_str(int note)
248 {
249 char buf[10];
250 sprintf(buf, "%s%d", notes[note % 12], note / 12 - 1);
251 return buf;
252 }
253
254 namespace {
255 // Convert the Entry text to a number
256 int on_input(double* new_value, Gtk::SpinButton* spinbutton) {
257 return note_value(spinbutton->get_text(), new_value);
258 }
259
260 // Convert the Adjustment position to text
261 bool on_output(Gtk::SpinButton* spinbutton) {
262 spinbutton->set_text(
263 note_str(spinbutton->get_adjustment()->get_value() + 0.5));
264 return true;
265 }
266 }
267
268 // Make a SpinButton show notes instead of numbers
269 void spin_button_show_notes(Gtk::SpinButton& spin_button)
270 {
271 spin_button.set_numeric(false);
272 spin_button.set_width_chars(4);
273 spin_button.signal_input().connect(
274 sigc::bind(sigc::ptr_fun(&on_input), &spin_button));
275 spin_button.signal_output().connect(
276 sigc::bind(sigc::ptr_fun(&on_output), &spin_button));
277 }
278
279 ChoiceEntryLeverageCtrl::ChoiceEntryLeverageCtrl(const char* labelText) :
280 LabelWidget(labelText, align),
281 align(0, 0, 0, 0)
282 {
283 for (int i = 0 ; i < 99 ; i++) {
284 if (controlChangeTexts[i]) {
285 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
286 combobox.append_text(controlChangeTexts[i]);
287 #else
288 combobox.append(controlChangeTexts[i]);
289 #endif
290 }
291 }
292 combobox.signal_changed().connect(
293 sigc::mem_fun(*this, &ChoiceEntryLeverageCtrl::value_changed));
294 align.add(combobox);
295 value.type = gig::leverage_ctrl_t::type_none;
296 value.controller_number = 0;
297 }
298
299 void ChoiceEntryLeverageCtrl::value_changed()
300 {
301 int rowno = combobox.get_active_row_number();
302 switch (rowno)
303 {
304 case -1:
305 break;
306 case 0:
307 value.type = gig::leverage_ctrl_t::type_none;
308 break;
309 case 1:
310 value.type = gig::leverage_ctrl_t::type_channelaftertouch;
311 break;
312 case 2:
313 value.type = gig::leverage_ctrl_t::type_velocity;
314 break;
315 default:
316 value.type = gig::leverage_ctrl_t::type_controlchange;
317 int x = 3;
318 for (uint cc = 0 ; cc < 96 ; cc++) {
319 if (controlChangeTexts[cc + 3]) {
320 if (rowno == x) {
321 value.controller_number = cc;
322 break;
323 }
324 x++;
325 }
326 }
327 break;
328 }
329 if (rowno >= 0) sig_changed();
330 }
331
332 void ChoiceEntryLeverageCtrl::set_value(gig::leverage_ctrl_t value)
333 {
334 int x;
335 switch (value.type)
336 {
337 case gig::leverage_ctrl_t::type_none:
338 x = 0;
339 break;
340 case gig::leverage_ctrl_t::type_channelaftertouch:
341 x = 1;
342 break;
343 case gig::leverage_ctrl_t::type_velocity:
344 x = 2;
345 break;
346 case gig::leverage_ctrl_t::type_controlchange:
347 x = -1;
348 for (uint cc = 0 ; cc < 96 ; cc++) {
349 if (controlChangeTexts[cc + 3]) {
350 x++;
351 if (value.controller_number == cc) {
352 x += 3;
353 break;
354 }
355 }
356 }
357 break;
358 default:
359 x = -1;
360 break;
361 }
362 combobox.set_active(x);
363 }
364
365
366 BoolEntry::BoolEntry(const char* labelText) :
367 LabelWidget(labelText, checkbutton),
368 checkbutton(labelText)
369 {
370 checkbutton.signal_toggled().connect(sig_changed.make_slot());
371 }
372
373
374 StringEntry::StringEntry(const char* labelText) :
375 LabelWidget(labelText, entry)
376 {
377 entry.signal_changed().connect(sig_changed.make_slot());
378 }
379
380 gig::String StringEntry::get_value() const
381 {
382 return gig_from_utf8(entry.get_text());
383 }
384
385 void StringEntry::set_value(const gig::String& value) {
386 entry.set_text(gig_to_utf8(value));
387 }
388
389
390 StringEntryMultiLine::StringEntryMultiLine(const char* labelText) :
391 LabelWidget(labelText, frame)
392 {
393 text_buffer = text_view.get_buffer();
394 frame.set_shadow_type(Gtk::SHADOW_IN);
395 frame.add(text_view);
396 text_buffer->signal_changed().connect(sig_changed.make_slot());
397 }
398
399 gig::String StringEntryMultiLine::get_value() const
400 {
401 Glib::ustring value = text_buffer->get_text();
402 for (int i = 0 ; (i = value.find("\x0a", i)) >= 0 ; i += 2)
403 value.replace(i, 1, "\x0d\x0a");
404 return gig_from_utf8(value);
405 }
406
407 void StringEntryMultiLine::set_value(const gig::String& value)
408 {
409 Glib::ustring text = gig_to_utf8(value);
410 for (int i = 0 ; (i = text.find("\x0d\x0a", i, 2)) >= 0 ; i++)
411 text.replace(i, 2, "\x0a");
412 text_buffer->set_text(text);
413 }
414
415
416 Table::Table(int x, int y) : Gtk::Table(x, y), rowno(0) { }
417
418 void Table::add(BoolEntry& boolentry)
419 {
420 attach(boolentry.widget, 0, 2, rowno, rowno + 1,
421 Gtk::FILL, Gtk::SHRINK);
422 rowno++;
423 }
424
425 void Table::add(BoolEntryPlus6& boolentry)
426 {
427 attach(boolentry.widget, 0, 2, rowno, rowno + 1,
428 Gtk::FILL, Gtk::SHRINK);
429 rowno++;
430 }
431
432 void Table::add(LabelWidget& prop)
433 {
434 attach(prop.label, 1, 2, rowno, rowno + 1,
435 Gtk::FILL, Gtk::SHRINK);
436 attach(prop.widget, 2, 3, rowno, rowno + 1,
437 Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK);
438 rowno++;
439 }

  ViewVC Help
Powered by ViewVC