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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC