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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.1261  
changed lines
  Added in v.3068

  ViewVC Help
Powered by ViewVC