Strip trailing whitespace and fix other whitespace errors (e.g. space/tab mixing...
[ardour.git] / gtk2_ardour / panner.cc
1 /*
2     Copyright (C) 2000-2007 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <iostream>
21 #include <iomanip>
22 #include <cstring>
23 #include "ardour/panner.h"
24 #include "panner.h"
25 #include "i18n.h"
26
27 using namespace std;
28 using namespace Gtk;
29
30 static const int triangle_size = 5;
31
32 PannerBar::PannerBar (Adjustment& adj, boost::shared_ptr<PBD::Controllable> c)
33         : BarController (adj, c)
34 {
35         set_style (BarController::Line);
36 }
37
38 PannerBar::~PannerBar ()
39 {
40 }
41
42 bool
43 PannerBar::expose (GdkEventExpose* ev)
44 {
45         Glib::RefPtr<Gdk::Window> win (darea.get_window());
46         Glib::RefPtr<Gdk::GC> gc (get_style()->get_base_gc (get_state()));
47
48         BarController::expose (ev);
49
50         /* now draw triangles for left, right and center */
51
52         GdkPoint points[3];
53
54         // left
55
56         points[0].x = 0;
57         points[0].y = 0;
58
59         points[1].x = triangle_size;
60         points[1].y = 0;
61
62         points[2].x = 0;
63         points[2].y = triangle_size;
64
65         gdk_draw_polygon (win->gobj(), gc->gobj(), true, points, 3);
66
67         // center
68
69         points[0].x = (darea.get_width()/2 - triangle_size);
70         points[0].y = 0;
71
72         points[1].x = (darea.get_width()/2 + triangle_size);
73         points[1].y = 0;
74
75         points[2].x = darea.get_width()/2;
76         points[2].y = triangle_size - 1;
77
78         gdk_draw_polygon (win->gobj(), gc->gobj(), true, points, 3);
79
80         // right
81
82         points[0].x = (darea.get_width() - triangle_size);
83         points[0].y = 0;
84
85         points[1].x = darea.get_width();
86         points[1].y = 0;
87
88         points[2].x = darea.get_width();
89         points[2].y = triangle_size;
90
91         gdk_draw_polygon (win->gobj(), gc->gobj(), true, points, 3);
92
93         return true;
94 }
95
96 bool
97 PannerBar::button_press (GdkEventButton* ev)
98 {
99         if (ev->button == 1 && ev->type == GDK_BUTTON_PRESS && ev->y < 10) {
100                 if (ev->x < triangle_size) {
101                         adjustment.set_value (adjustment.get_lower());
102                 } else if (ev->x > (darea.get_width() - triangle_size)) {
103                         adjustment.set_value (adjustment.get_upper());
104                 } else if (ev->x > (darea.get_width()/2 - triangle_size) &&
105                            ev->x < (darea.get_width()/2 + triangle_size)) {
106                         adjustment.set_value (adjustment.get_lower() + ((adjustment.get_upper() - adjustment.get_lower()) / 2.0));
107                 }
108         }
109
110         return BarController::button_press (ev);
111 }
112
113 bool
114 PannerBar::button_release (GdkEventButton* ev)
115 {
116         bool const r = BarController::button_release (ev);
117
118         /* get rid of any `C' labels that may exist */
119         queue_draw ();
120         return r;
121 }
122
123 bool
124 PannerBar::entry_input (double *new_value)
125 {
126         Entry* e = dynamic_cast<Entry*> (&spinner);
127         string const text = e->get_text ();
128
129         string digits;
130         string letters;
131
132         string const L = _("L");
133         string const C = _("C");
134         string const R = _("R");
135
136         for (string::size_type i = 0; i < text.length(); ++i) {
137                 if (isdigit (text[i])) {
138                         digits += text[i];
139                 } else if (text[i] != '%') {
140                         letters += text[i];
141                 }
142         }
143
144         if (letters.empty()) {
145                 /* no letter specified, so take any number as a percentage where
146                  * 0 is left and 100 right */
147                 *new_value = digits.empty() ? 0.5 : (atoi (digits.c_str()) / 100.0);
148         } else {
149                 /* letter given, so value is a percentage to the extreme
150                  * (e.g. 100L is full left, 1L is slightly left */
151                 if (letters[0] == L[0] || letters[0] == tolower (L[0])) {
152                         *new_value = digits.empty() ? 0 : (0.5 - atoi (digits.c_str()) / 200.0);
153                 } else if (letters[0] == R[0] || letters[0] == tolower (R[0])) {
154                         *new_value = digits.empty() ? 1 : 0.5 + atoi (digits.c_str()) / 200.0;
155                 } else if (letters[0] == C[0] || letters[0] == tolower (C[0])) {
156                         *new_value = 0.5;
157                 }
158         }
159
160         return true;
161 }
162
163 bool
164 PannerBar::entry_output ()
165 {
166         Entry* e = dynamic_cast<Entry*> (&spinner);
167         e->set_text (value_as_string (spinner.get_adjustment()->get_value()));
168         return true;
169 }
170
171 string
172 PannerBar::value_as_string (double v) const
173 {
174         if (ARDOUR::Panner::equivalent (v, 0.5)) {
175                 return _("C");
176         } else if (ARDOUR::Panner::equivalent (v, 0)) {
177                 return _("L");
178         } else if (ARDOUR::Panner::equivalent (v, 1)) {
179                 return _("R");
180         } else if (v < 0.5) {
181                 std::stringstream s;
182                 s << fixed << setprecision (0) << _("L") << ((0.5 - v) * 200) << "%";
183                 return s.str();
184         } else if (v > 0.5) {
185                 std::stringstream s;
186                 s << fixed << setprecision (0) << _("R") << ((v -0.5) * 200) << "%";
187                 return s.str ();
188         }
189
190         return "";
191 }
192
193 std::string
194 PannerBar::get_label (int& x)
195 {
196         double const value = spinner.get_adjustment()->get_value ();
197
198         if (ARDOUR::Panner::equivalent (value, 0.5)) {
199
200                 /* centre: only display text during a drag */
201
202                 if (!grabbed) {
203                         return "";
204                 }
205
206         } else {
207
208                 /* non-centre: display text on the side of the panner which has more space */
209
210                 Glib::RefPtr<Pango::Context> p = get_pango_context ();
211                 Glib::RefPtr<Pango::Layout> l = Pango::Layout::create (p);
212                 l->set_text (value_as_string (value));
213
214                 Pango::Rectangle const ext = l->get_ink_extents ();
215
216                 if (value < 0.5) {
217                         x = (darea.get_width() - 4 - ext.get_width() / Pango::SCALE);
218                 } else {
219                         x = 4;
220                 }
221         }
222
223         return value_as_string (value);
224 }