/[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 2423 - (show annotations) (download)
Sun Feb 24 15:19:39 2013 UTC (6 years, 3 months ago) by persson
File size: 10823 byte(s)
* code refactoring: created a PropEdit class for property editor
  windows, moved Table class from mainwindow to paramedit
* minor gui tweaks: made note entry fields a bit wider, set a minimum
  width for scales
* bug fix: avoid stale information in the instrument properties window
  when a new file is loaded or the instrument is removed

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

  ViewVC Help
Powered by ViewVC