Fix thinkos in cubasish theme
[ardour.git] / gtk2_ardour / tempo_lines.cc
1 /*
2  * Copyright (C) 2007-2015 David Robillard <d@drobilla.net>
3  * Copyright (C) 2010-2017 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2012 Carl Hetherington <carl@carlh.net>
5  * Copyright (C) 2014-2017 Nick Mainsbridge <mainsbridge@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "pbd/compose.h"
23
24 #include "canvas/canvas.h"
25 #include "canvas/debug.h"
26
27 #include "tempo_lines.h"
28 #include "public_editor.h"
29 #include "rgb_macros.h"
30 #include "ui_config.h"
31
32 using namespace std;
33
34 TempoLines::TempoLines (ArdourCanvas::Container* group, double, ARDOUR::BeatsSamplesConverter* bfc)
35         : lines (group, ArdourCanvas::LineSet::Vertical)
36         , _bfc (bfc)
37 {
38         lines.set_extent (ArdourCanvas::COORD_MAX);
39 }
40
41 TempoLines::~TempoLines ()
42 {
43         delete _bfc;
44         _bfc = 0;
45 }
46
47 void
48 TempoLines::tempo_map_changed (samplepos_t new_origin)
49 {
50         lines.clear ();
51         _bfc->set_origin_b (new_origin);
52 }
53
54 void
55 TempoLines::show ()
56 {
57         lines.show ();
58 }
59
60 void
61 TempoLines::hide ()
62 {
63         lines.hide ();
64 }
65
66 void
67 TempoLines::draw_ticks (std::vector<ARDOUR::TempoMap::BBTPoint>& grid,
68                         unsigned                                 divisions,
69                         samplecnt_t                              leftmost_sample,
70                         samplecnt_t                              sample_rate)
71 {
72         const uint32_t base = UIConfiguration::instance().color_mod("measure line beat", "measure line beat");
73
74         for (unsigned l = 1; l < divisions; ++l) {
75                 /* find the coarsest division level this tick falls on */
76                 unsigned level = divisions;
77                 for (unsigned d = divisions; d >= 4; d /= 2) {
78                         if (l % (divisions / d) == 0) {
79                                 level = d;
80                         }
81                 }
82                 /* draw line with alpha corresponding to coarsest level */
83                 const uint8_t    a = max(8, (int)rint(UINT_RGBA_A(base) / (0.8 * log2(level))));
84                 const uint32_t   c = UINT_RGBA_CHANGE_A(base, a);
85                 const samplepos_t f = _bfc->to (Temporal::Beats (grid.begin()->qn + (l / (double) divisions))) + _bfc->origin_b();
86
87                 if (f > leftmost_sample) {
88                         lines.add (PublicEditor::instance().sample_to_pixel_unrounded (f), 1.0, c);
89                 }
90         }
91 }
92
93 void
94 TempoLines::draw (std::vector<ARDOUR::TempoMap::BBTPoint>& grid,
95                   unsigned                                 divisions,
96                   samplecnt_t                              leftmost_sample,
97                   samplecnt_t                              sample_rate)
98 {
99         std::vector<ARDOUR::TempoMap::BBTPoint>::const_iterator i;
100         double  beat_density;
101
102         uint32_t beats = 0;
103         uint32_t bars = 0;
104         const uint32_t bar_color = UIConfiguration::instance().color ("measure line bar");
105         const uint32_t beat_color = UIConfiguration::instance().color_mod ("measure line beat", "measure line beat");
106         uint32_t color;
107
108         bool all_bars = false;
109         /* get the first bar spacing */
110
111         i = grid.end();
112         i--;
113         bars = (*i).bar - (*grid.begin()).bar;
114
115         int32_t bar_mod = 4;
116
117         if (bars < distance (grid.begin(), grid.end()) - 1) {
118                 /* grid contains beats and bars */
119                 beats = distance (grid.begin(), grid.end()) - bars;
120         } else {
121                 /* grid contains only bars */
122                 beats = distance (grid.begin(), grid.end());
123
124                 if (i != grid.begin()) {
125                         const int32_t last_bar = (*i).bar;
126                         i--;
127                         bar_mod = (last_bar - (*i).bar) * 4;
128                 }
129
130                 all_bars = true;
131         }
132
133         double canvas_width_used = 1.0;
134         if (leftmost_sample < grid.front().sample) {
135                 const samplecnt_t sample_distance = max ((samplecnt_t) 1, grid.back().sample - grid.front().sample);
136                 canvas_width_used = 1.0 - ((grid.front().sample - leftmost_sample) / (double) (sample_distance + grid.front().sample));
137         }
138
139         beat_density = (beats * 10.0f) / (lines.canvas()->width() * canvas_width_used);
140
141         if (beat_density > 2.0f) {
142                 /* if the lines are too close together, they become useless */
143                 lines.clear ();
144                 return;
145         }
146
147         /* constrain divisions to a log2 factor to cap line density */
148         while (divisions > 3 && beat_density * divisions > 0.4) {
149                 divisions /= 2;
150         }
151
152         lines.clear ();
153         if (beat_density <= 0.12 && grid.begin() != grid.end() && grid.begin()->sample > 0 && !all_bars) {
154                 /* draw subdivisions of the beat before the first visible beat line XX this shouldn't happen now */
155                 std::vector<ARDOUR::TempoMap::BBTPoint> vec;
156                 vec.push_back (*i);
157                 draw_ticks (vec, divisions, leftmost_sample, sample_rate);
158         }
159
160         for (i = grid.begin(); i != grid.end(); ++i) {
161
162                 if ((*i).is_bar()) {
163                         /* keep all_bar beat density down */
164                         if (all_bars && beat_density > 0.3 && ((*i).bar % bar_mod) != 1) {
165                                 continue;
166                         }
167
168                         color = bar_color;
169                 } else {
170                         if (beat_density > 0.3) {
171                                 continue; /* only draw beat lines if the gaps between beats are large. */
172                         }
173                         color = beat_color;
174                 }
175
176                 ArdourCanvas::Coord xpos = PublicEditor::instance().sample_to_pixel_unrounded ((*i).sample);
177
178                 lines.add (xpos, 1.0, color);
179
180                 if (beat_density <= 0.12 && !all_bars) {
181                         /* draw subdivisions of this beat */
182                         std::vector<ARDOUR::TempoMap::BBTPoint> vec;
183                         vec.push_back (*i);
184                         draw_ticks (vec, divisions, leftmost_sample, sample_rate);
185                 }
186         }
187 }
188