2 #include <cairo/cairo.h>
15 using namespace ARDOUR;
30 angle_radians = M_PI/4.0;
34 add_events (Gdk::POINTER_MOTION_MASK|Gdk::LEAVE_NOTIFY_MASK);
38 Matrix::set_ports (const list<string>& ports)
45 Matrix::add_group (PortGroup& pg)
47 for (vector<string>::const_iterator s = pg.ports.begin(); s != pg.ports.end(); ++s) {
48 others.push_back (OtherPort (*s, pg));
62 Matrix::remove_group (PortGroup& pg)
64 for (list<OtherPort>::iterator o = others.begin(); o != others.end(); ) {
65 if (&(*o).group() == &pg) {
75 Matrix::hide_group (PortGroup& pg)
81 Matrix::show_group (PortGroup& pg)
87 Matrix::setup_nodes ()
90 list<string>::iterator m;
91 list<OtherPort>::iterator s;
93 for (vector<MatrixNode*>::iterator p = nodes.begin(); p != nodes.end(); ++p) {
98 list<OtherPort>::size_type visible_others = 0;
100 for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
101 if ((*s).visible()) {
106 nodes.assign (ours.size() * visible_others, 0);
108 for (n = 0, y = 0, m = ours.begin(); m != ours.end(); ++m, ++y) {
109 for (x = 0, s = others.begin(); s != others.end(); ++s) {
110 if ((*s).visible()) {
111 nodes[n] = new MatrixNode (*m, *s, x, y);
120 Matrix::reset_size ()
122 list<OtherPort>::size_type visible_others = 0;
124 for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
125 if ((*s).visible()) {
130 if (!visible_others) {
131 cerr << "There are no visible others!\n";
145 if (alloc_width > line_width) {
147 xstep = (alloc_width - labels_x_shift - (2 * border) - (2 * arc_radius)) / visible_others;
148 line_width = xstep * (others.size() - 1);
150 ystep = (alloc_height - labels_y_shift - (2 * border) - (2 * arc_radius)) / (ours.size() - 1);
151 line_height = ystep * (ours.size() - 1);
158 line_height = (ours.size() - 1) * ystep;
159 line_width = visible_others * xstep;
162 int half_step = min (ystep/2,xstep/2);
164 arc_radius = half_step - 5;
169 arc_radius = min (arc_radius, 10);
171 /* scan all the port names that will be rotated, and compute
172 how much space we need for them
177 cairo_text_extents_t extents;
181 pm = gdk_pixmap_new (NULL, 1, 1, 24);
182 gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
184 cr = gdk_cairo_create (pm);
186 for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
187 if ((*s).visible()) {
188 cairo_text_extents (cr, (*s).name().c_str(), &extents);
189 w = max ((float) extents.width, w);
190 h = max ((float) extents.height, h);
195 gdk_pixmap_unref (pm);
199 w = fabs (w * cos (angle_radians) + h * sin (angle_radians));
200 h = fabs (w * sin (angle_radians) + h * cos (angle_radians));
202 labels_y_shift = (int) ceil (h) + 10;
203 labels_x_shift = (int) ceil (w);
208 cerr << "Based on ours = " << ours.size() << " others = " << others.size()
210 << " xstep " << xstep << endl
211 << " ystep " << ystep << endl
212 << " line_width " << line_width << endl
213 << " line_height " << line_height << endl
214 << " border " << border << endl
215 << " arc_radius " << arc_radius << endl
216 << " labels_x_shift " << labels_x_shift << endl
217 << " labels_y_shift " << labels_y_shift << endl;
221 Matrix::on_motion_notify_event (GdkEventMotion* ev)
230 Matrix::on_leave_notify_event (GdkEventCrossing *ev)
239 Matrix::on_size_request (Requisition* req)
241 req->width = labels_x_shift + line_width + (2*border) + (2*arc_radius);
242 req->height = labels_y_shift + line_height + (2*border) + (2*arc_radius);
246 Matrix::get_node (int32_t x, int32_t y)
248 int half_xstep = xstep / 2;
249 int half_ystep = ystep / 2;
251 x -= labels_x_shift - border;
252 if (x < half_xstep) {
256 y -= labels_y_shift - border;
257 if (y < half_ystep) {
261 x = (x - half_xstep) / xstep;
262 y = (y - half_ystep) / ystep;
264 x = y*ours.size() + x;
266 if (x >= nodes.size()) {
274 Matrix::on_button_press_event (GdkEventButton* ev)
278 if ((node = get_node (ev->x, ev->y)) != 0) {
279 cerr << "Event in node " << node->our_name() << " x " << node->their_name () << endl;
280 node->set_connected (!node->connected());
287 Matrix::alloc_pixmap ()
290 gdk_pixmap_unref (pixmap);
293 pixmap = gdk_pixmap_new (get_window()->gobj(),
302 Matrix::on_size_allocate (Allocation& alloc)
304 EventBox::on_size_allocate (alloc);
306 alloc_width = alloc.get_width();
307 alloc_height = alloc.get_height();
312 #ifdef MATRIX_USE_BACKING_PIXMAP
313 redraw (pixmap, 0, 0, alloc_width, alloc_height);
319 Matrix::on_realize ()
321 EventBox::on_realize ();
326 Matrix::redraw (GdkDrawable* drawable, GdkRectangle* rect)
328 list<string>::iterator o;
329 list<OtherPort>::iterator t;
331 uint32_t top_shift, bottom_shift, left_shift, right_shift;
334 cr = gdk_cairo_create (drawable);
336 cairo_set_source_rgb (cr, 0.83, 0.83, 0.83);
337 cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
340 cairo_set_line_width (cr, 0.5);
342 top_shift = labels_y_shift + border;
343 left_shift = labels_x_shift + border;
347 /* horizontal grid lines and side labels */
349 for (y = top_shift, o = ours.begin(); o != ours.end(); ++o, y += ystep) {
351 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
352 cairo_move_to (cr, left_shift, y);
353 cairo_line_to (cr, left_shift+line_width, y);
357 cairo_text_extents_t extents;
358 cairo_text_extents (cr, (*o).c_str(),&extents);
359 cairo_move_to (cr, border, y+extents.height/2);
360 cairo_show_text (cr, (*o).c_str());
365 /* vertical grid lines and rotated labels*/
367 for (x = left_shift, t = others.begin(); t != others.end(); ++t, x += xstep) {
369 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
370 cairo_move_to (cr, x, top_shift);
371 cairo_line_to (cr, x, top_shift+line_height);
374 cairo_move_to (cr, x-left_shift+12, border);
375 cairo_set_source_rgb (cr, 0, 0, 1.0);
378 cairo_rotate (cr, angle_radians);
379 cairo_show_text (cr, (*t).name().c_str());
386 for (vector<MatrixNode*>::iterator n = nodes.begin(); n != nodes.end(); ++n) {
388 x = (*n)->x() * xstep;
389 y = (*n)->y() * ystep;
394 cairo_arc (cr, left_shift+x, top_shift+y, arc_radius, 0, 2.0 * M_PI);
395 if ((*n)->connected()) {
396 cairo_set_source_rgba (cr, 1.0, 0, 0, 1.0);
399 cairo_set_source_rgba (cr, 1.0, 0, 0, 0.7);
405 /* motion indicators */
407 if (motion_x >= left_shift && motion_y >= top_shift) {
409 int col_left = left_shift + ((motion_x - left_shift) / xstep) * xstep;
410 int row_top = top_shift + ((motion_y - top_shift) / ystep) * ystep;
412 cairo_set_line_width (cr, 5);
413 cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.3);
415 /* horizontal (row) */
417 cairo_line_to (cr, left_shift, row_top);
418 cairo_line_to (cr, left_shift + line_width, row_top);
423 cairo_move_to (cr, col_left, top_shift);
424 cairo_line_to (cr, col_left, top_shift + line_height);
430 #ifdef MATRIX_USE_BACKING_PIXMAP
436 Matrix::on_expose_event (GdkEventExpose* event)
438 #ifdef MATRIX_USE_BACKING_PIXMAP
440 redraw (pixmap, 0, 0, alloc_width, alloc_height);
443 gdk_draw_drawable (get_window()->gobj(),
444 get_style()->get_fg_gc (STATE_NORMAL)->gobj(),
453 redraw (get_window()->gobj(), &event->area);