New matrix-based editor for connections and bundles, based on thorwil's design.
[ardour.git] / gtk2_ardour / port_matrix_row_labels.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 <iostream>
21 #include <boost/weak_ptr.hpp>
22 #include <gtkmm/menu.h>
23 #include <gtkmm/menushell.h>
24 #include <gtkmm/menu_elems.h>
25 #include <cairo/cairo.h>
26 #include "ardour/bundle.h"
27 #include "port_matrix_row_labels.h"
28 #include "port_matrix.h"
29 #include "i18n.h"
30
31 PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* p, PortMatrixBody* b)
32         : PortMatrixComponent (b), _port_matrix (p), _menu (0)
33 {
34         
35 }
36
37 PortMatrixRowLabels::~PortMatrixRowLabels ()
38 {
39         delete _menu;
40 }
41
42 void
43 PortMatrixRowLabels::compute_dimensions ()
44 {
45         GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
46         gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
47         cairo_t* cr = gdk_cairo_create (pm);
48         
49         _longest_port_name = 0;
50         for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
51                 for (uint32_t j = 0; j < (*i)->nchannels(); ++j) {
52                         cairo_text_extents_t ext;
53                         cairo_text_extents (cr, (*i)->channel_name(j).c_str(), &ext);
54                         if (ext.width > _longest_port_name) {
55                                 _longest_port_name = ext.width;
56                         }
57                 }
58         }
59
60         _longest_bundle_name = 0;
61         for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
62                 cairo_text_extents_t ext;
63                 cairo_text_extents (cr, (*i)->name().c_str(), &ext);
64                 if (ext.width > _longest_bundle_name) {
65                         _longest_bundle_name = ext.width;
66                 }
67         }
68
69         cairo_destroy (cr);
70         gdk_pixmap_unref (pm);
71
72         _height = 0;
73         for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
74                 _height += (*i)->nchannels() * row_height();
75         }
76
77         _width = _longest_port_name +
78                 name_pad() * 4 +
79                 _longest_bundle_name + name_pad() * 2;
80 }
81
82
83 void
84 PortMatrixRowLabels::render (cairo_t* cr)
85 {
86         /* BACKGROUND */
87         
88         set_source_rgb (cr, background_colour());
89         cairo_rectangle (cr, 0, 0, _width, _height);
90         cairo_fill (cr);
91
92         /* SIDE BUNDLE NAMES */
93
94         uint32_t x = _longest_port_name + name_pad() * 3;
95
96         uint32_t y = 0;
97         for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
98
99                 Gdk::Color const colour = get_a_bundle_colour (i - _body->row_bundles().begin ());
100                 set_source_rgb (cr, colour);
101                 cairo_rectangle (
102                         cr,
103                         0,
104                         y,
105                         _longest_port_name + name_pad() * 4 + _longest_bundle_name + name_pad() * 2,
106                         row_height() * (*i)->nchannels()
107                         );
108                 cairo_fill_preserve (cr);
109                 set_source_rgb (cr, background_colour());
110                 cairo_set_line_width (cr, label_border_width ());
111                 cairo_stroke (cr);
112
113                 uint32_t off = 0;
114                 if ((*i)->nchannels () > 0) {
115                         /* use the extent of our first channel name so that the bundle name is vertically aligned with it */
116                         cairo_text_extents_t ext;
117                         cairo_text_extents (cr, (*i)->channel_name(0).c_str(), &ext);
118                         off = (row_height() - ext.height) / 2;
119                 } else {
120                         off = row_height() / 2;
121                 }
122
123                 set_source_rgb (cr, text_colour());
124                 cairo_move_to (cr, x, y + name_pad() + off);
125                 cairo_show_text (cr, (*i)->name().c_str());
126                 
127                 y += row_height() * (*i)->nchannels ();
128         }
129         
130
131         /* SIDE PORT NAMES */
132
133         y = 0;
134         for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
135                 for (uint32_t j = 0; j < (*i)->nchannels(); ++j) {
136
137                         Gdk::Color const colour = get_a_bundle_colour (i - _body->row_bundles().begin ());
138                         set_source_rgb (cr, colour);
139                         cairo_rectangle (
140                                 cr,
141                                 0,
142                                 y,
143                                 _longest_port_name + (name_pad() * 2),
144                                 row_height()
145                                 );
146                         cairo_fill_preserve (cr);
147                         set_source_rgb (cr, background_colour());
148                         cairo_set_line_width (cr, label_border_width ());
149                         cairo_stroke (cr);
150
151                         cairo_text_extents_t ext;
152                         cairo_text_extents (cr, (*i)->channel_name(j).c_str(), &ext);
153                         uint32_t const off = (row_height() - ext.height) / 2;
154
155                         set_source_rgb (cr, text_colour());
156                         cairo_move_to (cr, name_pad(), y + name_pad() + off);
157                         cairo_show_text (cr, (*i)->channel_name(j).c_str());
158
159                         y += row_height();
160                 }
161         }
162 }
163
164 void
165 PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t)
166 {
167         if (b == 3 && x < (_longest_port_name + name_pad() * 2) ) {
168
169                 delete _menu;
170                 
171                 _menu = new Gtk::Menu;
172                 _menu->set_name ("ArdourContextMenu");
173                 
174                 Gtk::Menu_Helpers::MenuList& items = _menu->items ();
175
176                 
177                 uint32_t row = y / row_height ();
178
179                 boost::shared_ptr<ARDOUR::Bundle> bundle;
180                 uint32_t channel;
181                 
182                 for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
183                         if (row < (*i)->nchannels ()) {
184                                 bundle = *i;
185                                 channel = row;
186                                 break;
187                         } else {
188                                 row -= (*i)->nchannels ();
189                         }
190                 }
191
192                 if (bundle) {
193                         char buf [64];
194
195                         if (_port_matrix->can_rename_channels ()) {
196                                 snprintf (buf, sizeof (buf), _("Rename '%s'..."), bundle->channel_name (channel).c_str());
197                                 items.push_back (
198                                         Gtk::Menu_Helpers::MenuElem (
199                                                 buf,
200                                                 sigc::bind (sigc::mem_fun (*this, &PortMatrixRowLabels::rename_channel_proxy), bundle, channel)
201                                                 )
202                                         );
203                         }
204                         
205                         snprintf (buf, sizeof (buf), _("Remove '%s'"), bundle->channel_name (channel).c_str());
206                         items.push_back (
207                                 Gtk::Menu_Helpers::MenuElem (
208                                         buf,
209                                         sigc::bind (sigc::mem_fun (*this, &PortMatrixRowLabels::remove_channel_proxy), bundle, channel)
210                                         )
211                                 );
212
213                         _menu->popup (1, t);
214                 }
215         }
216 }
217
218
219 void
220 PortMatrixRowLabels::remove_channel_proxy (boost::weak_ptr<ARDOUR::Bundle> b, uint32_t c)
221 {
222         boost::shared_ptr<ARDOUR::Bundle> sb = b.lock ();
223         if (!sb) {
224                 return;
225         }
226
227         _port_matrix->remove_channel (sb, c);
228
229 }
230
231 void
232 PortMatrixRowLabels::rename_channel_proxy (boost::weak_ptr<ARDOUR::Bundle> b, uint32_t c)
233 {
234         boost::shared_ptr<ARDOUR::Bundle> sb = b.lock ();
235         if (!sb) {
236                 return;
237         }
238
239         _port_matrix->rename_channel (sb, c);
240 }