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