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