1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2 
3 #ifndef SPECTMORPH_SLIDER_HH
4 #define SPECTMORPH_SLIDER_HH
5 
6 #include <math.h>
7 #include "smmath.hh"
8 
9 namespace SpectMorph
10 {
11 
12 class Slider : public Widget
13 {
14   double m_value;
15   bool highlight = false;
16   bool mouse_down = false;
17   int int_range_min = 0;
18   int int_range_max = 0;
19 
20 public:
21   Signal<double> signal_value_changed;
22   Signal<int>    signal_int_value_changed;
23 
24   Slider (Widget *parent, double value) :
25     Widget (parent),
26     m_value (value)
27   {
28   }
29   void
30   set_int_range (int mn, int mx)
31   {
32     int_range_min = mn;
33     int_range_max = mx;
34   }
35   void
36   set_int_value (int ivalue)
37   {
38     m_value = double (ivalue - int_range_min) / (int_range_max - int_range_min);
39     update();
40   }
41   void
42   draw (const DrawEvent& devent) override
43   {
44     cairo_t *cr = devent.cr;
45     DrawUtils du (cr);
46 
47     double H = 6; // height of slider thing
48     double C = 6;
49     double value_pos = C + (width() - C * 2) * m_value;
50 
51     Color slider_color_l = ThemeColor::SLIDER;
52     if (enabled())
53       {
54         if (highlight)
55           slider_color_l = slider_color_l.lighter();
56       }
57     else
58       slider_color_l.set_rgb (0.4, 0.4, 0.4);
59     du.round_box (0, height() / 2 - H / 2, value_pos, H, 1, 2, slider_color_l.darker(), slider_color_l);
60 
61     Color slider_color_r (0.3, 0.3, 0.3);
62     if (highlight)
63       slider_color_r = slider_color_r.lighter();
64     du.round_box (value_pos, height() / 2 - H / 2, (width() - value_pos), H, 1, 2, slider_color_r.darker(), slider_color_r);
65 
66     if (enabled())
67       {
68         if (highlight || mouse_down)
69           cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
70         else
71           cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
72       }
73     else
74       {
75         cairo_set_source_rgb (cr, 0.4, 0.4, 0.4);
76       }
77     cairo_arc (cr, value_pos, height() / 2, C, 0, 2 * M_PI);
78     cairo_fill (cr);
79   }
80   void
81   slider_value_from_x (double x)
82   {
83     double C = 6;
84     m_value = sm_bound (0.0, (x - C) / (width() - C * 2), 1.0);
85 
86     /* optional: only allow discrete integer values */
87     if (int_range_min != int_range_max)
88       {
89         int ivalue = int_range_min + sm_round_positive (m_value * (int_range_max - int_range_min));
90         m_value = double (ivalue - int_range_min) / (int_range_max - int_range_min);
91 
92         signal_int_value_changed (ivalue);
93       }
94 
95     signal_value_changed (m_value);
96   }
97   void
98   mouse_move (const MouseEvent& event) override
99   {
100     if (mouse_down)
101       {
102         slider_value_from_x (event.x);
103         update();
104       }
105   }
106   void
107   mouse_press (const MouseEvent& event) override
108   {
109     if (event.button == LEFT_BUTTON)
110       {
111         slider_value_from_x (event.x);
112         mouse_down = true;
113         update();
114       }
115   }
116   void
117   mouse_release (const MouseEvent& event) override
118   {
119     if (event.button == LEFT_BUTTON)
120       {
121         mouse_down = false;
122         update();
123       }
124   }
125   void
126   enter_event() override
127   {
128     highlight = true;
129     update();
130   }
131   void
132   leave_event() override
133   {
134     highlight = false;
135     update();
136   }
137   void
138   set_value (double v)
139   {
140     m_value = v;
141     update();
142   }
143   double
144   value() const
145   {
146     return m_value;
147   }
148 };
149 
150 }
151 
152 #endif
153