various fixes to MidiRegionView selection handling, key handling, drawing of ghost...
[ardour2.git] / gtk2_ardour / port_matrix_row_labels.cc
blob8c8dcd4dfff5ab09d6f4a0945f54e694168493de
1 /*
2 Copyright (C) 2002-2009 Paul Davis
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.
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.
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.
20 #include <iostream>
21 #include <boost/weak_ptr.hpp>
22 #include <cairo/cairo.h>
23 #include "ardour/bundle.h"
24 #include "port_matrix_row_labels.h"
25 #include "port_matrix.h"
26 #include "port_matrix_body.h"
27 #include "i18n.h"
28 #include "utils.h"
30 using namespace std;
32 PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* m, PortMatrixBody* b)
33 : PortMatrixLabels (m, b)
38 void
39 PortMatrixRowLabels::compute_dimensions ()
41 GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
42 gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
43 cairo_t* cr = gdk_cairo_create (pm);
45 _longest_port_name = 0;
46 _longest_bundle_name = 0;
48 /* Compute maximum dimensions using all port groups, so that we allow for the largest and hence
49 we can change between visible groups without the size of the labels jumping around.
52 for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) {
54 PortGroup::BundleList const r = (*i)->bundles ();
55 for (PortGroup::BundleList::const_iterator j = r.begin(); j != r.end(); ++j) {
57 for (uint32_t k = 0; k < (*j)->bundle->nchannels().n_total(); ++k) {
59 if (!_matrix->should_show ((*j)->bundle->channel_type(k))) {
60 continue;
63 cairo_text_extents_t ext;
64 cairo_text_extents (cr, (*j)->bundle->channel_name(k).c_str(), &ext);
65 if (ext.width > _longest_port_name) {
66 _longest_port_name = ext.width;
70 cairo_text_extents_t ext;
71 cairo_text_extents (cr, (*j)->bundle->name().c_str(), &ext);
72 if (ext.width > _longest_bundle_name) {
73 _longest_bundle_name = ext.width;
79 if (_matrix->visible_rows()) {
80 _height = group_size (_matrix->visible_rows()) * grid_spacing ();
81 } else {
82 _height = 0;
85 cairo_destroy (cr);
86 g_object_unref (pm);
88 _width = _longest_bundle_name +
89 name_pad() * 2;
91 if (!_matrix->show_only_bundles()) {
92 _width += _longest_port_name;
93 _width += name_pad() * 2;
98 void
99 PortMatrixRowLabels::render (cairo_t* cr)
101 /* BACKGROUND */
103 set_source_rgb (cr, background_colour());
104 cairo_rectangle (cr, 0, 0, _width, _height);
105 cairo_fill (cr);
107 /* BUNDLE AND PORT NAMES */
109 double y = 0;
110 int N = 0;
111 int M = 0;
113 PortGroup::BundleList const & bundles = _matrix->visible_rows()->bundles ();
114 for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
115 render_bundle_name (cr, background_colour (), (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N), 0, y, (*i)->bundle);
117 if (!_matrix->show_only_bundles()) {
118 uint32_t const N = _matrix->count_of_our_type ((*i)->bundle->nchannels());
119 for (uint32_t j = 0; j < N; ++j) {
120 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (M);
121 render_channel_name (cr, background_colour (), c, 0, y, ARDOUR::BundleChannel ((*i)->bundle, j));
122 y += grid_spacing();
123 ++M;
126 if (N == 0) {
127 y += grid_spacing ();
130 } else {
131 y += grid_spacing();
134 ++N;
138 void
139 PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t, guint)
141 ARDOUR::BundleChannel w = position_to_channel (y, x, _matrix->visible_rows());
143 if (
144 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_longest_port_name + name_pad() * 2)) ||
145 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < (_longest_bundle_name + name_pad() * 2))
148 w.channel = -1;
151 if (b == 3) {
153 _matrix->popup_menu (
154 ARDOUR::BundleChannel (),
161 double
162 PortMatrixRowLabels::component_to_parent_x (double x) const
164 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
165 return x + _parent_rectangle.get_x();
168 double
169 PortMatrixRowLabels::parent_to_component_x (double x) const
171 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
172 return x - _parent_rectangle.get_x();
175 double
176 PortMatrixRowLabels::component_to_parent_y (double y) const
178 return y - _body->yoffset() + _parent_rectangle.get_y();
181 double
182 PortMatrixRowLabels::parent_to_component_y (double y) const
184 return y + _body->yoffset() - _parent_rectangle.get_y();
188 double
189 PortMatrixRowLabels::bundle_name_x () const
191 double x = 0;
193 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && !_matrix->show_only_bundles ()) {
194 x = _longest_port_name + name_pad() * 2;
197 return x;
200 double
201 PortMatrixRowLabels::port_name_x () const
203 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
204 return _longest_bundle_name + name_pad() * 2;
205 } else {
206 return 0;
209 return 0;
212 void
213 PortMatrixRowLabels::render_bundle_name (
214 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
217 double const x = bundle_name_x ();
219 int const n = _matrix->show_only_bundles() ? 1 : _matrix->count_of_our_type_min_1 (b->nchannels());
220 set_source_rgb (cr, bg_colour);
221 cairo_rectangle (cr, xoff + x, yoff, _longest_bundle_name + name_pad() * 2, grid_spacing() * n);
222 cairo_fill_preserve (cr);
223 set_source_rgb (cr, fg_colour);
224 cairo_set_line_width (cr, label_border_width ());
225 cairo_stroke (cr);
227 cairo_text_extents_t ext;
228 cairo_text_extents (cr, b->name().c_str(), &ext);
229 double const off = (grid_spacing() - ext.height) / 2;
231 set_source_rgb (cr, text_colour());
232 cairo_move_to (cr, xoff + x + name_pad(), yoff + name_pad() + off);
233 cairo_show_text (cr, b->name().c_str());
236 void
237 PortMatrixRowLabels::render_channel_name (
238 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const& bc
241 set_source_rgb (cr, bg_colour);
242 cairo_rectangle (cr, port_name_x() + xoff, yoff, _longest_port_name + name_pad() * 2, grid_spacing());
243 cairo_fill_preserve (cr);
244 set_source_rgb (cr, fg_colour);
245 cairo_set_line_width (cr, label_border_width ());
246 cairo_stroke (cr);
248 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
250 /* only plot the name if the bundle has more than one channel;
251 the name of a single channel is assumed to be redundant */
253 cairo_text_extents_t ext;
254 cairo_text_extents (cr, bc.bundle->channel_name(bc.channel).c_str(), &ext);
255 double const off = (grid_spacing() - ext.height) / 2;
257 set_source_rgb (cr, text_colour());
258 cairo_move_to (cr, port_name_x() + xoff + name_pad(), yoff + name_pad() + off);
259 cairo_show_text (cr, bc.bundle->channel_name(bc.channel).c_str());
263 double
264 PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel const &) const
266 return 0;
269 double
270 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel const& bc) const
272 return channel_to_position (bc, _matrix->visible_rows()) * grid_spacing ();
275 void
276 PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
278 if (bc.bundle) {
280 if (_matrix->show_only_bundles()) {
281 _body->queue_draw_area (
282 component_to_parent_x (bundle_name_x()) - 1,
283 component_to_parent_y (channel_y (bc)) - 1,
284 _longest_bundle_name + name_pad() * 2 + 2,
285 grid_spacing() + 2
287 } else {
288 _body->queue_draw_area (
289 component_to_parent_x (port_name_x()) - 1,
290 component_to_parent_y (channel_y (bc)) - 1,
291 _longest_port_name + name_pad() * 2 + 2,
292 grid_spacing() + 2
299 void
300 PortMatrixRowLabels::mouseover_changed (list<PortMatrixNode> const &)
302 list<PortMatrixNode> const m = _body->mouseover ();
303 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
305 ARDOUR::BundleChannel c = i->column;
306 ARDOUR::BundleChannel r = i->row;
308 if (PortMatrix::bundle_with_channels (c.bundle) && PortMatrix::bundle_with_channels (r.bundle)) {
309 add_channel_highlight (r);
310 } else if (r.bundle) {
311 _body->highlight_associated_channels (_matrix->row_index(), r);
316 void
317 PortMatrixRowLabels::motion (double x, double y)
319 ARDOUR::BundleChannel const w = position_to_channel (y, x, _matrix->visible_rows());
321 uint32_t const bw = _longest_bundle_name + 2 * name_pad();
323 bool done = false;
325 if (w.bundle) {
327 if (
328 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < bw) ||
329 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_width - bw) && x < _width)
333 /* if the mouse is over a bundle name, highlight all channels in the bundle */
335 list<PortMatrixNode> n;
337 for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
339 if (!_matrix->should_show (w.bundle->channel_type(i))) {
340 continue;
343 ARDOUR::BundleChannel const bc (w.bundle, i);
344 n.push_back (PortMatrixNode (bc, ARDOUR::BundleChannel ()));
347 _body->set_mouseover (n);
348 done = true;
350 } else if (x < _width) {
352 _body->set_mouseover (PortMatrixNode (w, ARDOUR::BundleChannel ()));
353 done = true;
359 if (!done) {
360 /* not over any bundle */
361 _body->set_mouseover (PortMatrixNode ());
362 return;