Optimize automation-event process splitting
[ardour.git] / gtk2_ardour / port_matrix_component.cc
1 /*
2     Copyright (C) 2002-2009 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 "port_matrix_component.h"
21 #include "port_matrix.h"
22 #include "port_matrix_body.h"
23
24 using namespace std;
25
26 /** Constructor.
27  *  @param m Port matrix that we're in.
28  *  @param b Port matrix body that we're in.
29  */
30 PortMatrixComponent::PortMatrixComponent (PortMatrix* m, PortMatrixBody* b)
31         : _matrix (m),
32           _body (b),
33           _pixmap (0),
34           _render_required (true),
35           _dimension_computation_required (true)
36 {
37
38 }
39
40 /** Destructor */
41 PortMatrixComponent::~PortMatrixComponent ()
42 {
43         if (_pixmap) {
44                 g_object_unref (_pixmap);
45         }
46 }
47
48 void
49 PortMatrixComponent::setup ()
50 {
51         _dimension_computation_required = true;
52         _render_required = true;
53 }
54
55 GdkPixmap *
56 PortMatrixComponent::get_pixmap (GdkDrawable *drawable)
57 {
58         if (_render_required) {
59
60                 if (_dimension_computation_required) {
61                         compute_dimensions ();
62                         _dimension_computation_required = false;
63                         _body->component_size_changed ();
64                 }
65
66                 /* we may be zero width or height; if so, just
67                    use the smallest allowable pixmap */
68                 if (_width == 0) {
69                         _width = 1;
70                 }
71                 if (_height == 0) {
72                         _height = 1;
73                 }
74
75                 /* make a pixmap of the right size */
76                 if (_pixmap) {
77                         g_object_unref (_pixmap);
78                 }
79                 _pixmap = gdk_pixmap_new (drawable, _width, _height, -1);
80
81                 /* render */
82                 cairo_t* cr = gdk_cairo_create (_pixmap);
83                 render (cr);
84                 cairo_destroy (cr);
85
86                 _render_required = false;
87         }
88
89         return _pixmap;
90 }
91
92 void
93 PortMatrixComponent::set_source_rgb (cairo_t *cr, Gdk::Color const & c)
94 {
95         cairo_set_source_rgb (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p());
96 }
97
98 void
99 PortMatrixComponent::set_source_rgba (cairo_t *cr, Gdk::Color const & c, double a)
100 {
101         cairo_set_source_rgba (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p(), a);
102 }
103
104 pair<uint32_t, uint32_t>
105 PortMatrixComponent::dimensions ()
106 {
107         if (_dimension_computation_required) {
108                 compute_dimensions ();
109                 _dimension_computation_required = false;
110                 _body->component_size_changed ();
111         }
112
113         return make_pair (_width, _height);
114 }
115
116 Gdk::Color
117 PortMatrixComponent::background_colour ()
118 {
119         return _matrix->get_style()->get_bg (Gtk::STATE_NORMAL);
120 }
121
122 /** @param g Group.
123  *  @return Visible size of the group in grid units, taking visibility and show_only_bundles into account.
124  */
125 uint32_t
126 PortMatrixComponent::group_size (boost::shared_ptr<const PortGroup> g) const
127 {
128         uint32_t s = 0;
129
130         PortGroup::BundleList const & bundles = g->bundles ();
131         if (_matrix->show_only_bundles()) {
132                 s = bundles.size();
133         } else {
134                 for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
135                         s += _matrix->count_of_our_type_min_1 ((*i)->bundle->nchannels());
136                 }
137         }
138
139         return s;
140 }
141
142 /** @param bc Channel.
143  *  @param group Group.
144  *  @return Position of bc in groups in grid units, taking show_only_bundles into account.
145  */
146 uint32_t
147 PortMatrixComponent::channel_to_position (ARDOUR::BundleChannel bc, boost::shared_ptr<const PortGroup> group) const
148 {
149         uint32_t p = 0;
150
151         PortGroup::BundleList const & bundles = group->bundles ();
152
153         for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
154
155                 if ((*i)->bundle == bc.bundle) {
156
157                         /* found the bundle */
158
159                         if (_matrix->show_only_bundles()) {
160                                 return p;
161                         } else {
162                                 return p + bc.bundle->overall_channel_to_type (_matrix->type (), bc.channel);
163                         }
164
165                 }
166
167                 /* move past this bundle */
168
169                 if (_matrix->show_only_bundles()) {
170                         p += 1;
171                 } else {
172                         p += _matrix->count_of_our_type_min_1 ((*i)->bundle->nchannels());
173                 }
174         }
175
176         return 0;
177 }
178
179
180 ARDOUR::BundleChannel
181 PortMatrixComponent::position_to_channel (double p, double, boost::shared_ptr<const PortGroup> group) const
182 {
183         p /= grid_spacing ();
184
185         PortGroup::BundleList const & bundles = group->bundles ();
186         for (PortGroup::BundleList::const_iterator j = bundles.begin(); j != bundles.end(); ++j) {
187
188                 if (_matrix->show_only_bundles()) {
189
190                         if (p < 1) {
191                                 return ARDOUR::BundleChannel ((*j)->bundle, -1);
192                         } else {
193                                 p -= 1;
194                         }
195
196                 } else {
197
198                         ARDOUR::ChanCount const N = (*j)->bundle->nchannels ();
199
200                         uint32_t const s = _matrix->count_of_our_type_min_1 (N);
201                         if (p < s) {
202                                 if (p < _matrix->count_of_our_type (N)) {
203                                         return ARDOUR::BundleChannel ((*j)->bundle, (*j)->bundle->type_channel_to_overall (_matrix->type (), p));
204                                 } else {
205                                         return ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), -1);
206                                 }
207                         } else {
208                                 p -= s;
209                         }
210
211                 }
212
213         }
214
215         return ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), -1);
216 }