Vkeybd: add a mod-wheel
[ardour.git] / gtk2_ardour / port_matrix_component.cc
1 /*
2  * Copyright (C) 2009-2010 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2009-2011 Carl Hetherington <carl@carlh.net>
4  * Copyright (C) 2009-2011 David Robillard <d@drobilla.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "port_matrix_component.h"
22 #include "port_matrix.h"
23 #include "port_matrix_body.h"
24
25 using namespace std;
26
27 /** Constructor.
28  *  @param m Port matrix that we're in.
29  *  @param b Port matrix body that we're in.
30  */
31 PortMatrixComponent::PortMatrixComponent (PortMatrix* m, PortMatrixBody* b)
32         : _matrix (m),
33           _body (b),
34           _pixmap (0),
35           _render_required (true),
36           _dimension_computation_required (true)
37 {
38
39 }
40
41 /** Destructor */
42 PortMatrixComponent::~PortMatrixComponent ()
43 {
44         if (_pixmap) {
45                 g_object_unref (_pixmap);
46         }
47 }
48
49 void
50 PortMatrixComponent::setup ()
51 {
52         _dimension_computation_required = true;
53         _render_required = true;
54 }
55
56 GdkPixmap *
57 PortMatrixComponent::get_pixmap (GdkDrawable *drawable)
58 {
59         if (_render_required) {
60
61                 if (_dimension_computation_required) {
62                         compute_dimensions ();
63                         _dimension_computation_required = false;
64                         _body->component_size_changed ();
65                 }
66
67                 /* we may be zero width or height; if so, just
68                    use the smallest allowable pixmap */
69                 if (_width == 0) {
70                         _width = 1;
71                 }
72                 if (_height == 0) {
73                         _height = 1;
74                 }
75
76                 /* make a pixmap of the right size */
77                 if (_pixmap) {
78                         g_object_unref (_pixmap);
79                 }
80                 _pixmap = gdk_pixmap_new (drawable, _width, _height, -1);
81
82                 /* render */
83                 cairo_t* cr = gdk_cairo_create (_pixmap);
84                 render (cr);
85                 cairo_destroy (cr);
86
87                 _render_required = false;
88         }
89
90         return _pixmap;
91 }
92
93 void
94 PortMatrixComponent::set_source_rgb (cairo_t *cr, Gdk::Color const & c)
95 {
96         cairo_set_source_rgb (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p());
97 }
98
99 void
100 PortMatrixComponent::set_source_rgba (cairo_t *cr, Gdk::Color const & c, double a)
101 {
102         cairo_set_source_rgba (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p(), a);
103 }
104
105 pair<uint32_t, uint32_t>
106 PortMatrixComponent::dimensions ()
107 {
108         if (_dimension_computation_required) {
109                 compute_dimensions ();
110                 _dimension_computation_required = false;
111                 _body->component_size_changed ();
112         }
113
114         return make_pair (_width, _height);
115 }
116
117 Gdk::Color
118 PortMatrixComponent::background_colour ()
119 {
120         return _matrix->get_style()->get_bg (Gtk::STATE_NORMAL);
121 }
122
123 /** @param g Group.
124  *  @return Visible size of the group in grid units, taking visibility and show_only_bundles into account.
125  */
126 uint32_t
127 PortMatrixComponent::group_size (boost::shared_ptr<const PortGroup> g) const
128 {
129         uint32_t s = 0;
130
131         PortGroup::BundleList const & bundles = g->bundles ();
132         if (_matrix->show_only_bundles()) {
133                 s = bundles.size();
134         } else {
135                 for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
136                         s += _matrix->count_of_our_type_min_1 ((*i)->bundle->nchannels());
137                 }
138         }
139
140         return s;
141 }
142
143 /** @param bc Channel.
144  *  @param group Group.
145  *  @return Position of bc in groups in grid units, taking show_only_bundles into account.
146  */
147 uint32_t
148 PortMatrixComponent::channel_to_position (ARDOUR::BundleChannel bc, boost::shared_ptr<const PortGroup> group) const
149 {
150         uint32_t p = 0;
151
152         PortGroup::BundleList const & bundles = group->bundles ();
153
154         for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
155
156                 if ((*i)->bundle == bc.bundle) {
157
158                         /* found the bundle */
159
160                         if (_matrix->show_only_bundles()) {
161                                 return p;
162                         } else {
163                                 return p + bc.bundle->overall_channel_to_type (_matrix->type (), bc.channel);
164                         }
165
166                 }
167
168                 /* move past this bundle */
169
170                 if (_matrix->show_only_bundles()) {
171                         p += 1;
172                 } else {
173                         p += _matrix->count_of_our_type_min_1 ((*i)->bundle->nchannels());
174                 }
175         }
176
177         return 0;
178 }
179
180
181 ARDOUR::BundleChannel
182 PortMatrixComponent::position_to_channel (double p, double, boost::shared_ptr<const PortGroup> group) const
183 {
184         p /= grid_spacing ();
185
186         PortGroup::BundleList const & bundles = group->bundles ();
187         for (PortGroup::BundleList::const_iterator j = bundles.begin(); j != bundles.end(); ++j) {
188
189                 if (_matrix->show_only_bundles()) {
190
191                         if (p < 1) {
192                                 return ARDOUR::BundleChannel ((*j)->bundle, -1);
193                         } else {
194                                 p -= 1;
195                         }
196
197                 } else {
198
199                         ARDOUR::ChanCount const N = (*j)->bundle->nchannels ();
200
201                         uint32_t const s = _matrix->count_of_our_type_min_1 (N);
202                         if (p < s) {
203                                 if (p < _matrix->count_of_our_type (N)) {
204                                         return ARDOUR::BundleChannel ((*j)->bundle, (*j)->bundle->type_channel_to_overall (_matrix->type (), p));
205                                 } else {
206                                         return ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), -1);
207                                 }
208                         } else {
209                                 p -= s;
210                         }
211
212                 }
213
214         }
215
216         return ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), -1);
217 }