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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2844 - (show annotations) (download) (as text)
Sun Sep 20 08:49:40 2015 UTC (8 years, 6 months ago) by persson
File MIME type: text/x-c++hdr
File size: 13000 byte(s)
* allow building with gtkmm 2 and G/GDK/GTK_DISABLE_DEPRECATED

1 /* -*- c++ -*-
2 * Copyright (C) 2006-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, 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 #ifndef GIGEDIT_PARAMEDIT_H
21 #define GIGEDIT_PARAMEDIT_H
22
23 #include <gig.h>
24
25 #include <cmath>
26
27 #include <glibmm/convert.h>
28 #include <gtkmm/box.h>
29 #include <gtkmm/adjustment.h>
30 #include <gtkmm/alignment.h>
31 #include <gtkmm/checkbutton.h>
32 #include <gtkmm/comboboxtext.h>
33 #include <gtkmm/frame.h>
34 #include <gtkmm/label.h>
35 #include <gtkmm/scale.h>
36 #include <gtkmm/spinbutton.h>
37 #include <gtkmm/table.h>
38 #include <gtkmm/textview.h>
39
40 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 12) || GTKMM_MAJOR_VERSION < 2
41 #define OLD_TOOLTIPS
42 #include <gtkmm/tooltips.h>
43 #endif
44
45
46 Glib::ustring gig_to_utf8(const gig::String& gig_string);
47 gig::String gig_from_utf8(const Glib::ustring& utf8_string);
48
49 int note_value(const Glib::ustring& note);
50 Glib::ustring note_str(int note);
51
52 void spin_button_show_notes(Gtk::SpinButton& spin_button);
53
54 class LabelWidget {
55 public:
56 Gtk::Label label;
57 Gtk::Widget& widget;
58
59 LabelWidget(const char* labelText, Gtk::Widget& widget);
60 void set_sensitive(bool sensitive = true);
61 sigc::signal<void>& signal_value_changed() {
62 return sig_changed;
63 }
64 protected:
65 #ifdef OLD_TOOLTIPS
66 Gtk::Tooltips tooltips;
67 #endif
68 sigc::signal<void> sig_changed;
69 };
70
71 class ReadOnlyLabelWidget : public LabelWidget {
72 public:
73 Gtk::Label text;
74
75 ReadOnlyLabelWidget(const char* leftHandText);
76 ReadOnlyLabelWidget(const char* leftHandText, const char* rightHandText);
77 };
78
79 class NumEntry : public LabelWidget {
80 protected:
81 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
82 Gtk::Adjustment adjust;
83 #else
84 Glib::RefPtr<Gtk::Adjustment> adjust;
85 #endif
86 Gtk::HScale scale;
87 Gtk::SpinButton spinbutton;
88 Gtk::HBox box;
89
90 static int round_to_int(double x) {
91 return int(x < 0.0 ? x - 0.5 : x + 0.5);
92 }
93 public:
94 NumEntry(const char* labelText, double lower = 0, double upper = 127,
95 int decimals = 0);
96 void set_tip(const Glib::ustring& tip_text) {
97 #ifdef OLD_TOOLTIPS
98 tooltips.set_tip(spinbutton, tip_text);
99 #else
100 spinbutton.set_tooltip_text(tip_text);
101 #endif
102 }
103 void set_upper(double upper) {
104 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
105 adjust.set_upper(upper);
106 #else
107 adjust->set_upper(upper);
108 #endif
109 }
110 };
111
112 class NumEntryGain : public NumEntry {
113 private:
114 int32_t value;
115 void value_changed();
116 double coeff;
117 bool connected;
118 public:
119 NumEntryGain(const char* labelText,
120 double lower, double upper, int decimals, double coeff);
121 int32_t get_value() const { return value; }
122 void set_value(int32_t value);
123 };
124
125 template<typename T>
126 class NumEntryTemp : public NumEntry {
127 private:
128 T value;
129 void value_changed();
130 public:
131 NumEntryTemp(const char* labelText,
132 double lower = 0, double upper = 127, int decimals = 0);
133 T get_value() const { return value; }
134 void set_value(T value);
135 };
136
137 template<typename T>
138 NumEntryTemp<T>::NumEntryTemp(const char* labelText,
139 double lower, double upper, int decimals) :
140 NumEntry(labelText, lower, upper, decimals),
141 value(0)
142 {
143 spinbutton.signal_value_changed().connect(
144 sigc::mem_fun(*this, &NumEntryTemp::value_changed));
145 }
146
147 template<typename T>
148 void NumEntryTemp<T>::value_changed()
149 {
150 const double f = pow(10, spinbutton.get_digits());
151 int new_value = round_to_int(spinbutton.get_value() * f);
152 if (new_value != round_to_int(value * f)) {
153 value = T(new_value / f);
154 sig_changed();
155 }
156 }
157
158 template<typename T>
159 void NumEntryTemp<T>::set_value(T value)
160 {
161 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 90) || GTKMM_MAJOR_VERSION < 2
162 if (value > adjust.get_upper()) value = T(adjust.get_upper());
163 #else
164 if (value > adjust->get_upper()) value = T(adjust->get_upper());
165 #endif
166 if (this->value != value) {
167 this->value = value;
168 const double f = pow(10, spinbutton.get_digits());
169 if (round_to_int(spinbutton.get_value() * f) != round_to_int(value * f)) {
170 spinbutton.set_value(value);
171 }
172 sig_changed();
173 }
174 }
175
176
177 class NoteEntry : public NumEntryTemp<uint8_t> {
178 public:
179 NoteEntry(const char* labelText);
180 private:
181 int on_input(double* new_value);
182 bool on_output();
183 };
184
185
186 class NumEntryPermille : public NumEntry {
187 private:
188 uint16_t value;
189 void value_changed();
190 public:
191 NumEntryPermille(const char* labelText,
192 double lower = 0, double upper = 127, int decimals = 0);
193 uint16_t get_value() const { return value; }
194 void set_value(uint16_t value);
195 };
196
197
198 template<typename T>
199 class ChoiceEntry : public LabelWidget {
200 private:
201 Gtk::ComboBoxText combobox;
202 Gtk::Alignment align;
203 const T* values;
204 public:
205 ChoiceEntry(const char* labelText);
206 T get_value() const;
207 void set_value(T value);
208 void set_choices(const char** texts, const T* values);
209
210 void set_tip(const Glib::ustring& tip_text) {
211 #ifdef OLD_TOOLTIPS
212 tooltips.set_tip(combobox, tip_text);
213 #else
214 combobox.set_tooltip_text(tip_text);
215 #endif
216 }
217 };
218
219 template<typename T>
220 ChoiceEntry<T>::ChoiceEntry(const char* labelText) :
221 LabelWidget(labelText, align),
222 align(0, 0, 0, 0),
223 values(0)
224 {
225 combobox.signal_changed().connect(sig_changed.make_slot());
226 align.add(combobox);
227 }
228
229 template<typename T>
230 void ChoiceEntry<T>::set_choices(const char** texts, const T* values)
231 {
232 for (int i = 0 ; texts[i] ; i++) {
233 #if (GTKMM_MAJOR_VERSION == 2 && GTKMM_MINOR_VERSION < 24) || GTKMM_MAJOR_VERSION < 2
234 combobox.append_text(texts[i]);
235 #else
236 combobox.append(texts[i]);
237 #endif
238 }
239 this->values = values;
240 }
241
242 template<typename T>
243 T ChoiceEntry<T>::get_value() const
244 {
245 int rowno = combobox.get_active_row_number();
246 return values[rowno];
247 }
248
249 template<typename T>
250 void ChoiceEntry<T>::set_value(T value)
251 {
252 int row = 0;
253 int nb_rows = combobox.get_model()->children().size();
254 for (; row < nb_rows ; row++) {
255 if (value == values[row]) break;
256 }
257 combobox.set_active(row == nb_rows ? -1 : row);
258 }
259
260
261 class ChoiceEntryLeverageCtrl : public LabelWidget {
262 private:
263 gig::leverage_ctrl_t value;
264 Gtk::ComboBoxText combobox;
265 Gtk::Alignment align;
266 void value_changed();
267 public:
268 ChoiceEntryLeverageCtrl(const char* labelText);
269 gig::leverage_ctrl_t get_value() const { return value; }
270 void set_value(gig::leverage_ctrl_t value);
271 void set_tip(const Glib::ustring& tip_text) {
272 combobox.set_tooltip_text(tip_text);
273 }
274 };
275
276
277 class BoolEntry : public LabelWidget {
278 private:
279 Gtk::CheckButton checkbutton;
280 public:
281 BoolEntry(const char* labelText);
282 bool get_value() const { return checkbutton.get_active(); }
283 void set_value(bool value) { checkbutton.set_active(value); }
284
285 void set_tip(const Glib::ustring& tip_text) {
286 #ifdef OLD_TOOLTIPS
287 tooltips.set_tip(checkbutton, tip_text);
288 #else
289 checkbutton.set_tooltip_text(tip_text);
290 #endif
291 }
292 };
293
294
295 class BoolEntryPlus6 : public LabelWidget {
296 private:
297 Gtk::CheckButton checkbutton;
298 void value_changed();
299 NumEntryGain& eGain;
300 int32_t plus6value;
301 public:
302 BoolEntryPlus6(const char* labelText, NumEntryGain& eGain, int32_t plus6value);
303 int32_t get_value() const;
304 void set_value(int32_t value);
305 };
306
307
308 class StringEntry : public LabelWidget {
309 private:
310 Gtk::Entry entry;
311 public:
312 StringEntry(const char* labelText);
313 gig::String get_value() const;
314 void set_value(const gig::String& value);
315 void set_width_chars(int n_chars) { entry.set_width_chars(n_chars); }
316 };
317
318 class StringEntryMultiLine : public LabelWidget {
319 private:
320 Gtk::TextView text_view;
321 Glib::RefPtr<Gtk::TextBuffer> text_buffer;
322 Gtk::Frame frame;
323 public:
324 StringEntryMultiLine(const char* labelText);
325 gig::String get_value() const;
326 void set_value(const gig::String& value);
327 };
328
329
330 /**
331 * Container widget for LabelWidgets.
332 */
333 class Table : public Gtk::Table
334 {
335 public:
336 Table(int x, int y);
337 void add(BoolEntry& boolentry);
338 void add(BoolEntryPlus6& boolentry);
339 void add(LabelWidget& labelwidget);
340 private:
341 int rowno;
342 };
343
344
345 /**
346 * Base class for editor components that use LabelWidgets to edit
347 * member variables of the same class. By connecting the widgets to
348 * members of the model class, the model is automatically kept
349 * updated.
350 */
351 template<class M>
352 class PropEditor {
353 public:
354 sigc::signal<void>& signal_changed() {
355 return sig_changed;
356 }
357 protected:
358 M* m;
359 int update_model; // to prevent infinite update loops
360 PropEditor() : m(0), update_model(0) { }
361 sigc::signal<void> sig_changed;
362
363 template<class C, typename T>
364 void connect(C& widget, T M::* member) {
365 // gcc 4.1.2 needs this temporary variable to resolve the
366 // address
367 void (PropEditor::*f)(const C* w, T M::* member) =
368 &PropEditor::set_member;
369 widget.signal_value_changed().connect(
370 sigc::bind(sigc::mem_fun(*this, f), &widget, member));
371
372 void (PropEditor::*g)(C* w, T M::* member) =
373 &PropEditor::get_member;
374 sig.connect(
375 sigc::bind(sigc::mem_fun(*this, g), &widget, member));
376 }
377
378 template<class C, class S, typename T>
379 void connect(C& widget, void (S::*setter)(T)) {
380 void (PropEditor::*f)(const C* w, void (S::*setter)(T)) =
381 &PropEditor<M>::call_setter;
382 widget.signal_value_changed().connect(
383 sigc::bind(sigc::mem_fun(*this, f), &widget, setter));
384 }
385
386 void connect(NoteEntry& eKeyRangeLow, NoteEntry& eKeyRangeHigh,
387 gig::range_t M::* range) {
388 eKeyRangeLow.signal_value_changed().connect(
389 sigc::bind(
390 sigc::mem_fun(*this, &PropEditor::key_range_low_changed),
391 &eKeyRangeLow, &eKeyRangeHigh, range));
392 eKeyRangeHigh.signal_value_changed().connect(
393 sigc::bind(
394 sigc::mem_fun(*this, &PropEditor::key_range_high_changed),
395 &eKeyRangeLow, &eKeyRangeHigh, range));
396 sig.connect(
397 sigc::bind(sigc::mem_fun(*this, &PropEditor::get_key_range),
398 &eKeyRangeLow, &eKeyRangeHigh, range));
399 }
400
401 void update(M* m) {
402 update_model++;
403 this->m = m;
404 sig.emit();
405 update_model--;
406 }
407
408 private:
409 sigc::signal<void> sig;
410
411 void key_range_low_changed(NoteEntry* eKeyRangeLow,
412 NoteEntry* eKeyRangeHigh,
413 gig::range_t M::* range) {
414 if (update_model == 0) {
415 uint8_t value = eKeyRangeLow->get_value();
416 (m->*range).low = value;
417 if (value > (m->*range).high) {
418 eKeyRangeHigh->set_value(value);
419 }
420 sig_changed();
421 }
422 }
423
424 void key_range_high_changed(NoteEntry* eKeyRangeLow,
425 NoteEntry* eKeyRangeHigh,
426 gig::range_t M::* range) {
427 if (update_model == 0) {
428 uint8_t value = eKeyRangeHigh->get_value();
429 (m->*range).high = value;
430 if (value < (m->*range).low) {
431 eKeyRangeLow->set_value(value);
432 }
433 sig_changed();
434 }
435 }
436
437 template<class C, typename T>
438 void set_member(const C* w, T M::* member) {
439 if (update_model == 0) {
440 m->*member = w->get_value();
441 sig_changed();
442 }
443 }
444
445 template<class C, typename T>
446 void get_member(C* w, T M::* member) {
447 w->set_value(m->*member);
448 }
449
450 void get_key_range(NoteEntry* eKeyRangeLow,
451 NoteEntry* eKeyRangeHigh,
452 gig::range_t M::* range) const {
453 eKeyRangeLow->set_value((m->*range).low);
454 eKeyRangeHigh->set_value((m->*range).high);
455 }
456
457 template<class C, class S, typename T>
458 void call_setter(const C* w, void (S::*setter)(T)) {
459 if (update_model == 0) {
460 (static_cast<S*>(this)->*setter)(w->get_value());
461 sig_changed();
462 }
463 }
464 };
465
466 #endif

  ViewVC Help
Powered by ViewVC