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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2507 - (hide 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 schoenebeck 1225 /*
2 persson 2507 * Copyright (C) 2006-2014 Andreas Persson
3 schoenebeck 1225 *
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 persson 1714 #include <cstring>
21    
22 schoenebeck 1225 #include "paramedit.h"
23    
24 persson 1831 #include "global.h"
25 persson 2169 #include "compat.h"
26 persson 1831
27 persson 2446 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 schoenebeck 1225 namespace {
39     const char* const controlChangeTexts[] = {
40 persson 1831 _("none"), _("channelaftertouch"), _("velocity"),
41 schoenebeck 1225 0,
42 persson 1831 _("modwheel"), // "Modulation Wheel or Lever",
43     _("breath"), // "Breath Controller",
44 schoenebeck 1225 0,
45 persson 1831 _("foot"), // "Foot Controller",
46     _("portamentotime"), // "Portamento Time",
47 schoenebeck 1225 0, 0, 0, 0, 0, 0,
48 persson 1831 _("effect1"), // "Effect Control 1",
49     _("effect2"), // "Effect Control 2",
50 schoenebeck 1225 0, 0,
51 persson 1831 _("genpurpose1"), // "General Purpose Controller 1",
52     _("genpurpose2"), // "General Purpose Controller 2",
53     _("genpurpose3"), // "General Purpose Controller 3",
54     _("genpurpose4"), // "General Purpose Controller 4",
55 schoenebeck 1225 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 persson 1831 _("sustainpedal"), // "Damper Pedal on/off (Sustain)",
59     _("portamento"), // "Portamento On/Off",
60     _("sostenuto"), // "Sustenuto On/Off",
61     _("softpedal"), // "Soft Pedal On/Off",
62 schoenebeck 1225 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 persson 1831 _("genpurpose5"), // "General Purpose Controller 5",
64     _("genpurpose6"), // "General Purpose Controller 6",
65     _("genpurpose7"), // "General Purpose Controller 7",
66     _("genpurpose8"), // "General Purpose Controller 8",
67 schoenebeck 1225 0, 0, 0, 0, 0, 0, 0,
68 persson 1831 _("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 schoenebeck 1225 };
74     }
75    
76     LabelWidget::LabelWidget(const char* labelText, Gtk::Widget& widget) :
77     label(Glib::ustring(labelText) + ":"),
78     widget(widget)
79     {
80 persson 2169 label.set_alignment(Gtk::ALIGN_START);
81 schoenebeck 1225 }
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 persson 2151 LabelWidget(labelText, box),
92 persson 2169 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
93 schoenebeck 1225 adjust(lower, lower, upper, 1, 10),
94 persson 2169 #else
95     adjust(Gtk::Adjustment::create(lower, lower, upper, 1, 10)),
96     #endif
97 schoenebeck 1225 scale(adjust),
98 persson 2151 spinbutton(adjust)
99 schoenebeck 1225 {
100 persson 2423 scale.set_size_request(70);
101 schoenebeck 1225 spinbutton.set_digits(decimals);
102 persson 1460 spinbutton.set_value(0);
103 persson 2507 spinbutton.set_numeric();
104 schoenebeck 1225 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 persson 2151 value(0),
114 persson 1460 coeff(coeff),
115     connected(true)
116 schoenebeck 1225 {
117     spinbutton.signal_value_changed().connect(
118     sigc::mem_fun(*this, &NumEntryGain::value_changed));
119     }
120    
121     void NumEntryGain::value_changed()
122     {
123 persson 1460 if (!connected) return;
124    
125 schoenebeck 1359 const double f = pow(10, spinbutton.get_digits());
126     int new_value = round_to_int(spinbutton.get_value() * f);
127 persson 1460 if (new_value != round_to_int(value / coeff * f)) {
128     value = round_to_int(new_value / f * coeff);
129     sig_changed();
130 schoenebeck 1225 }
131     }
132    
133 persson 1460 void NumEntryGain::set_value(int32_t value)
134 schoenebeck 1225 {
135 persson 1460 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 schoenebeck 1225 }
147    
148    
149     BoolEntryPlus6::BoolEntryPlus6(const char* labelText, NumEntryGain& eGain, int32_t plus6value) :
150     LabelWidget(labelText, checkbutton),
151 persson 1262 checkbutton(labelText),
152 schoenebeck 1225 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 persson 1460 if (checkbutton.get_active()) eGain.set_value(plus6value);
162     else if (eGain.get_value() < 0) eGain.set_value(0);
163 schoenebeck 1225 }
164    
165 persson 1460 int32_t BoolEntryPlus6::get_value() const
166 schoenebeck 1225 {
167 persson 1460 return eGain.get_value();
168 schoenebeck 1225 }
169    
170 persson 1460 void BoolEntryPlus6::set_value(int32_t value)
171     {
172     checkbutton.set_active(value < 0);
173     }
174    
175 schoenebeck 1225 NumEntryPermille::NumEntryPermille(const char* labelText,
176     double lower, double upper, int decimals) :
177 persson 1460 NumEntry(labelText, lower, upper, decimals),
178     value(0)
179 schoenebeck 1225 {
180     spinbutton.signal_value_changed().connect(
181     sigc::mem_fun(*this, &NumEntryPermille::value_changed));
182     }
183    
184     void NumEntryPermille::value_changed()
185     {
186 persson 1460 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 schoenebeck 1225 }
191     }
192    
193 persson 1460 void NumEntryPermille::set_value(uint16_t value)
194 schoenebeck 1225 {
195 persson 1460 if (value != this->value) {
196     spinbutton.set_value(value / 10.0);
197     }
198 schoenebeck 1225 }
199    
200    
201     NoteEntry::NoteEntry(const char* labelText) :
202     NumEntryTemp<uint8_t>(labelText)
203     {
204 persson 2507 spin_button_show_notes(spinbutton);
205 schoenebeck 1225 }
206    
207 persson 2507 namespace {
208     const char* notes[] = {
209     _("C"), _("C#"), _("D"), _("D#"), _("E"), _("F"),_("F#"),
210     _("G"), _("G#"), _("A"), _("A#"), _("B")
211     };
212 schoenebeck 1225
213 persson 2507 int note_value(const Glib::ustring& note, double* value)
214     {
215     const char* str = note.c_str();
216 schoenebeck 1225
217 persson 2507 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 schoenebeck 1225 {
242 persson 2507 double value = 0;
243     note_value(note, &value);
244     return value;
245     }
246 schoenebeck 1225
247 persson 2507 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 schoenebeck 1225 }
259 persson 2507
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 schoenebeck 1225 }
266     }
267    
268 persson 2507 // Make a SpinButton show notes instead of numbers
269     void spin_button_show_notes(Gtk::SpinButton& spin_button)
270 schoenebeck 1225 {
271 persson 2507 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 schoenebeck 1225 }
278    
279     ChoiceEntryLeverageCtrl::ChoiceEntryLeverageCtrl(const char* labelText) :
280 persson 2151 LabelWidget(labelText, align),
281     align(0, 0, 0, 0)
282 schoenebeck 1225 {
283     for (int i = 0 ; i < 99 ; i++) {
284     if (controlChangeTexts[i]) {
285 persson 2507 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
286 schoenebeck 1225 combobox.append_text(controlChangeTexts[i]);
287 persson 2169 #else
288     combobox.append(controlChangeTexts[i]);
289     #endif
290 schoenebeck 1225 }
291     }
292     combobox.signal_changed().connect(
293     sigc::mem_fun(*this, &ChoiceEntryLeverageCtrl::value_changed));
294     align.add(combobox);
295 persson 1460 value.type = gig::leverage_ctrl_t::type_none;
296     value.controller_number = 0;
297 schoenebeck 1225 }
298    
299     void ChoiceEntryLeverageCtrl::value_changed()
300     {
301 persson 1460 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 persson 2151 for (uint cc = 0 ; cc < 96 ; cc++) {
319 persson 1460 if (controlChangeTexts[cc + 3]) {
320     if (rowno == x) {
321     value.controller_number = cc;
322     break;
323 schoenebeck 1225 }
324 persson 1460 x++;
325 schoenebeck 1225 }
326     }
327 persson 1460 break;
328 schoenebeck 1225 }
329 persson 1460 if (rowno >= 0) sig_changed();
330 schoenebeck 1225 }
331    
332 persson 1460 void ChoiceEntryLeverageCtrl::set_value(gig::leverage_ctrl_t value)
333 schoenebeck 1225 {
334     int x;
335 persson 1460 switch (value.type)
336 schoenebeck 1225 {
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 persson 2151 for (uint cc = 0 ; cc < 96 ; cc++) {
349 schoenebeck 1225 if (controlChangeTexts[cc + 3]) {
350     x++;
351 persson 1460 if (value.controller_number == cc) {
352 schoenebeck 1225 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 persson 1460 checkbutton(labelText)
369 schoenebeck 1225 {
370 persson 1460 checkbutton.signal_toggled().connect(sig_changed.make_slot());
371 schoenebeck 1225 }
372    
373    
374     StringEntry::StringEntry(const char* labelText) :
375     LabelWidget(labelText, entry)
376     {
377 persson 1582 entry.signal_changed().connect(sig_changed.make_slot());
378 schoenebeck 1225 }
379    
380 persson 2446 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 persson 1582 StringEntryMultiLine::StringEntryMultiLine(const char* labelText) :
391     LabelWidget(labelText, frame)
392 schoenebeck 1225 {
393 persson 1582 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 schoenebeck 1225 }
398    
399 persson 1582 gig::String StringEntryMultiLine::get_value() const
400 schoenebeck 1225 {
401 persson 1582 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 persson 2446 return gig_from_utf8(value);
405 schoenebeck 1225 }
406 persson 1582
407 persson 2446 void StringEntryMultiLine::set_value(const gig::String& value)
408 persson 1582 {
409 persson 2446 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 persson 1582 }
414 persson 2423
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