merge with master
[ardour.git] / gtk2_ardour / verbose_cursor.cc
1 /*
2     Copyright (C) 2000-2011 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 <string>
21 #include <gtkmm/enums.h>
22 #include "pbd/stacktrace.h"
23 #include "ardour/profile.h"
24
25 #include "canvas/debug.h"
26
27 #include "ardour_ui.h"
28 #include "audio_clock.h"
29 #include "editor.h"
30 #include "editor_drag.h"
31 #include "main_clock.h"
32 #include "utils.h"
33 #include "verbose_cursor.h"
34
35 #include "i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39
40 VerboseCursor::VerboseCursor (Editor* editor)
41         : _editor (editor)
42         , _visible (false)
43         , _xoffset (0)
44         , _yoffset (0)
45 {
46         _canvas_item = new ArdourCanvas::Text (_editor->_track_canvas->root());
47         CANVAS_DEBUG_NAME (_canvas_item, "verbose canvas cursor");
48         _canvas_item->set_ignore_events (true);
49         _canvas_item->set_font_description (get_font_for_style (N_("VerboseCanvasCursor")));
50 }
51
52 ArdourCanvas::Item *
53 VerboseCursor::canvas_item () const
54 {
55         return _canvas_item;
56 }
57
58 void
59 VerboseCursor::set (string const & text, double x, double y)
60 {
61         set_text (text);
62         set_position (x, y);
63 }
64
65 void
66 VerboseCursor::set_text (string const & text)
67 {
68         _canvas_item->set (text);
69 }
70
71 /** @param xoffset x offset to be applied on top of any set_position() call
72  *  before the next show ().
73  *  @param yoffset y offset as above.
74  */
75 void
76 VerboseCursor::show (double xoffset, double yoffset)
77 {
78         _xoffset = xoffset;
79         _yoffset = yoffset;
80
81         if (_visible) {
82                 return;
83         }
84
85         _canvas_item->raise_to_top ();
86         _canvas_item->show ();
87         _visible = true;
88 }
89
90 void
91 VerboseCursor::hide ()
92 {
93         _canvas_item->hide ();
94         _visible = false;
95 }
96
97 double
98 VerboseCursor::clamp_x (double x)
99 {
100         _editor->clamp_verbose_cursor_x (x);
101         return x;
102 }
103
104 double
105 VerboseCursor::clamp_y (double y)
106 {
107         _editor->clamp_verbose_cursor_y (y);
108         return y;
109 }
110
111 void
112 VerboseCursor::set_time (framepos_t frame, double x, double y)
113 {
114         char buf[128];
115         Timecode::Time timecode;
116         Timecode::BBT_Time bbt;
117         int hours, mins;
118         framepos_t frame_rate;
119         float secs;
120
121         if (_editor->_session == 0) {
122                 return;
123         }
124
125         AudioClock::Mode m;
126
127         if (Profile->get_sae() || Profile->get_small_screen()) {
128                 m = ARDOUR_UI::instance()->primary_clock->mode();
129         } else {
130                 m = ARDOUR_UI::instance()->secondary_clock->mode();
131         }
132
133         switch (m) {
134         case AudioClock::BBT:
135                 _editor->_session->bbt_time (frame, bbt);
136                 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
137                 break;
138
139         case AudioClock::Timecode:
140                 _editor->_session->timecode_time (frame, timecode);
141                 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
142                 break;
143
144         case AudioClock::MinSec:
145                 /* XXX this is copied from show_verbose_duration_cursor() */
146                 frame_rate = _editor->_session->frame_rate();
147                 hours = frame / (frame_rate * 3600);
148                 frame = frame % (frame_rate * 3600);
149                 mins = frame / (frame_rate * 60);
150                 frame = frame % (frame_rate * 60);
151                 secs = (float) frame / (float) frame_rate;
152                 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%07.4f", hours, mins, secs);
153                 break;
154
155         default:
156                 snprintf (buf, sizeof(buf), "%" PRIi64, frame);
157                 break;
158         }
159
160         set (buf, x, y);
161 }
162
163 void
164 VerboseCursor::set_duration (framepos_t start, framepos_t end, double x, double y)
165 {
166         char buf[128];
167         Timecode::Time timecode;
168         Timecode::BBT_Time sbbt;
169         Timecode::BBT_Time ebbt;
170         int hours, mins;
171         framepos_t distance, frame_rate;
172         float secs;
173         Meter meter_at_start (_editor->_session->tempo_map().meter_at(start));
174
175         if (_editor->_session == 0) {
176                 return;
177         }
178
179         AudioClock::Mode m;
180
181         if (Profile->get_sae() || Profile->get_small_screen()) {
182                 m = ARDOUR_UI::instance()->primary_clock->mode ();
183         } else {
184                 m = ARDOUR_UI::instance()->secondary_clock->mode ();
185         }
186
187         switch (m) {
188         case AudioClock::BBT:
189         {
190                 _editor->_session->bbt_time (start, sbbt);
191                 _editor->_session->bbt_time (end, ebbt);
192
193                 /* subtract */
194                 /* XXX this computation won't work well if the
195                 user makes a selection that spans any meter changes.
196                 */
197
198                 /* use signed integers for the working values so that
199                    we can underflow.
200                 */
201
202                 int ticks = ebbt.ticks;
203                 int beats = ebbt.beats;
204                 int bars = ebbt.bars;
205
206                 ticks -= sbbt.ticks;
207                 if (ticks < 0) {
208                         ticks += int (Timecode::BBT_Time::ticks_per_beat);
209                         --beats;
210                 }
211
212                 beats -= sbbt.beats;
213                 if (beats < 0) {
214                         beats += int (meter_at_start.divisions_per_bar());
215                         --bars;
216                 }
217
218                 bars -= sbbt.bars;
219
220                 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bars, beats, ticks);
221                 break;
222         }
223
224         case AudioClock::Timecode:
225                 _editor->_session->timecode_duration (end - start, timecode);
226                 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
227                 break;
228
229         case AudioClock::MinSec:
230                 /* XXX this stuff should be elsewhere.. */
231                 distance = end - start;
232                 frame_rate = _editor->_session->frame_rate();
233                 hours = distance / (frame_rate * 3600);
234                 distance = distance % (frame_rate * 3600);
235                 mins = distance / (frame_rate * 60);
236                 distance = distance % (frame_rate * 60);
237                 secs = (float) distance / (float) frame_rate;
238                 snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%07.4f", hours, mins, secs);
239                 break;
240
241         default:
242                 snprintf (buf, sizeof(buf), "%" PRIi64, end - start);
243                 break;
244         }
245
246         set (buf, x, y);
247 }
248
249 void
250 VerboseCursor::set_color (uint32_t color)
251 {
252         _canvas_item->set_color (color);
253 }
254
255 /** Set the position of the verbose cursor.  Any x/y offsets
256  *  passed to the last call to show() will be applied to the
257  *  coordinates passed in here.
258  */
259 void
260 VerboseCursor::set_position (double x, double y)
261 {
262         _canvas_item->set_x_position (clamp_x (x + _xoffset));
263         _canvas_item->set_y_position (clamp_y (y + _yoffset));
264 }
265
266 bool
267 VerboseCursor::visible () const
268 {
269         return _visible;
270 }