markers are not allowed to have empty names, especially since it causes a crash in...
[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 p Port matrix that we're in.
28  */
29 PortMatrixComponent::PortMatrixComponent (PortMatrix* m, PortMatrixBody* b)
30         : _matrix (m),
31           _body (b),
32           _pixmap (0),
33           _render_required (true),
34           _dimension_computation_required (true)
35 {
36
37 }
38
39 /** Destructor */
40 PortMatrixComponent::~PortMatrixComponent ()
41 {
42         if (_pixmap) {
43                 gdk_pixmap_unref (_pixmap);
44         }
45 }
46
47 void
48 PortMatrixComponent::setup ()
49 {
50         _dimension_computation_required = true;
51         _render_required = true;
52 }
53
54 GdkPixmap *
55 PortMatrixComponent::get_pixmap (GdkDrawable *drawable)
56 {
57         if (_render_required) {
58
59                 if (_dimension_computation_required) {
60                         compute_dimensions ();
61                         _dimension_computation_required = false;
62                         _body->component_size_changed ();
63                 }
64
65                 /* we may be zero width or height; if so, just
66                    use the smallest allowable pixmap */
67                 if (_width == 0) {
68                         _width = 1;
69                 }
70                 if (_height == 0) {
71                         _height = 1;
72                 }
73
74                 /* make a pixmap of the right size */
75                 if (_pixmap) {
76                         gdk_pixmap_unref (_pixmap);
77                 }
78                 _pixmap = gdk_pixmap_new (drawable, _width, _height, -1);
79
80                 /* render */
81                 cairo_t* cr = gdk_cairo_create (_pixmap);
82                 render (cr);
83                 cairo_destroy (cr);
84
85                 _render_required = false;
86         }
87
88         return _pixmap;
89 }
90
91 void
92 PortMatrixComponent::set_source_rgb (cairo_t *cr, Gdk::Color const & c)
93 {
94         cairo_set_source_rgb (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p());
95 }
96
97 void
98 PortMatrixComponent::set_source_rgba (cairo_t *cr, Gdk::Color const & c, double a)
99 {
100         cairo_set_source_rgba (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p(), a);
101 }
102
103 pair<uint32_t, uint32_t>
104 PortMatrixComponent::dimensions ()
105 {
106         if (_dimension_computation_required) {
107                 compute_dimensions ();
108                 _dimension_computation_required = false;
109                 _body->component_size_changed ();
110         }
111
112         return make_pair (_width, _height);
113 }
114
115 Gdk::Color
116 PortMatrixComponent::background_colour ()
117 {
118         return _matrix->get_style()->get_bg (Gtk::STATE_NORMAL);
119 }
120
121 /** @param g Group.
122  *  @return Visible size of the group in grid units, taking visibility and show_only_bundles into account.
123  */
124 uint32_t
125 PortMatrixComponent::group_size (boost::shared_ptr<const PortGroup> g) const
126 {
127         uint32_t s = 0;
128
129         if (g->visible()) {
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 += i->bundle->nchannels();
136                         }
137                 }
138         } else {
139                 s = 1;
140         }
141
142         return s;
143 }
144
145 /** @param bc Channel.
146  *  @param groups List of groups.
147  *  @return Position of bc in groups in grid units, taking visibility and show_only_bundles into account.
148  */
149 uint32_t
150 PortMatrixComponent::channel_to_position (ARDOUR::BundleChannel bc, PortGroupList const * groups) const
151 {
152         uint32_t p = 0;
153
154         for (PortGroupList::List::const_iterator i = groups->begin(); i != groups->end(); ++i) {
155
156                 PortGroup::BundleList const & bundles = (*i)->bundles ();
157
158                 for (PortGroup::BundleList::const_iterator j = bundles.begin(); j != bundles.end(); ++j) {
159
160                         if (j->bundle == bc.bundle) {
161
162                                 /* found the bundle */
163
164                                 if (_matrix->show_only_bundles() || !(*i)->visible()) {
165                                         return p;
166                                 } else {
167                                         return p + bc.channel;
168                                 }
169
170                         }
171
172                         if ((*i)->visible()) {
173
174                                 /* move past this bundle */
175
176                                 if (_matrix->show_only_bundles()) {
177                                         p += 1;
178                                 } else {
179                                         p += j->bundle->nchannels ();
180                                 }
181                         }
182                 }
183
184                 if (!(*i)->visible()) {
185                         /* if this group isn't visible we won't have updated p, so do it now */
186                         p += 1;
187                 }
188         }
189
190         return 0;
191 }
192
193
194 pair<boost::shared_ptr<PortGroup>, ARDOUR::BundleChannel>
195 PortMatrixComponent::position_to_group_and_channel (uint32_t p, PortGroupList const * groups) const
196 {
197         PortGroupList::List::const_iterator i = groups->begin ();
198
199         while (i != groups->end()) {
200
201                 uint32_t const gs = group_size (*i);
202
203                 if (p < gs) {
204
205                         /* it's in this group */
206
207                         if (!(*i)->visible()) {
208                                 return make_pair (*i, ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), 0));
209                         }
210
211                         PortGroup::BundleList const & bundles = (*i)->bundles ();
212                         for (PortGroup::BundleList::const_iterator j = bundles.begin(); j != bundles.end(); ++j) {
213
214                                 if (_matrix->show_only_bundles()) {
215
216                                         if (p == 0) {
217                                                 return make_pair (*i, ARDOUR::BundleChannel (j->bundle, 0));
218                                         } else {
219                                                 p -= 1;
220                                         }
221
222                                 } else {
223
224                                         uint32_t const s = j->bundle->nchannels ();
225                                         if (p < s) {
226                                                 return make_pair (*i, ARDOUR::BundleChannel (j->bundle, p));
227                                         } else {
228                                                 p -= s;
229                                         }
230
231                                 }
232
233                         }
234
235                 } else {
236
237                         p -= gs;
238
239                 }
240
241                 ++i;
242         }
243
244         return make_pair (boost::shared_ptr<PortGroup> (), ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), 0));
245 }