~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to gtk2_ardour/port_matrix_body.cc

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "ardour/bundle.h"
 
22
#include "ardour/types.h"
 
23
 
 
24
#include "gui_thread.h"
 
25
#include "port_matrix_body.h"
 
26
#include "port_matrix.h"
 
27
#include "port_matrix_column_labels.h"
 
28
#include "port_matrix_row_labels.h"
 
29
#include "port_matrix_grid.h"
 
30
 
 
31
#include "i18n.h"
 
32
 
 
33
using namespace std;
 
34
 
 
35
PortMatrixBody::PortMatrixBody (PortMatrix* p)
 
36
        : _matrix (p),
 
37
          _alloc_width (0),
 
38
          _alloc_height (0),
 
39
          _xoffset (0),
 
40
          _yoffset (0),
 
41
          _column_labels_border_x (0),
 
42
          _column_labels_height (0),
 
43
          _ignore_component_size_changed (false)
 
44
{
 
45
        _column_labels = new PortMatrixColumnLabels (p, this);
 
46
        _row_labels = new PortMatrixRowLabels (p, this);
 
47
        _grid = new PortMatrixGrid (p, this);
 
48
 
 
49
        _components.push_back (_column_labels);
 
50
        _components.push_back (_row_labels);
 
51
        _components.push_back (_grid);
 
52
 
 
53
        add_events (Gdk::LEAVE_NOTIFY_MASK | Gdk::POINTER_MOTION_MASK);
 
54
}
 
55
 
 
56
 
 
57
PortMatrixBody::~PortMatrixBody ()
 
58
{
 
59
        for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
 
60
                delete *i;
 
61
        }
 
62
}
 
63
 
 
64
bool
 
65
PortMatrixBody::on_expose_event (GdkEventExpose* event)
 
66
{
 
67
        if (
 
68
                _matrix->visible_columns() == 0 || _matrix->visible_rows() == 0 ||
 
69
                _matrix->visible_columns()->bundles().empty() || _matrix->visible_rows()->bundles().empty()
 
70
                ) {
 
71
 
 
72
                /* nothing to connect */
 
73
 
 
74
                cairo_t* cr = gdk_cairo_create (get_window()->gobj());
 
75
 
 
76
                cairo_set_source_rgb (cr, 0, 0, 0);
 
77
                cairo_rectangle (cr, 0, 0, _alloc_width, _alloc_height);
 
78
                cairo_fill (cr);
 
79
 
 
80
                string t;
 
81
                if (_matrix->type() == ARDOUR::DataType::NIL) {
 
82
                        t = _("There are no ports to connect.");
 
83
                } else {
 
84
                        t = string_compose (_("There are no %1 ports to connect."), _matrix->type().to_i18n_string());
 
85
                }
 
86
 
 
87
                cairo_text_extents_t ext;
 
88
                cairo_text_extents (cr, t.c_str(), &ext);
 
89
 
 
90
                cairo_set_source_rgb (cr, 1, 1, 1);
 
91
                cairo_move_to (cr, (_alloc_width - ext.width) / 2, (_alloc_height + ext.height) / 2);
 
92
                cairo_show_text (cr, t.c_str ());
 
93
 
 
94
                cairo_destroy (cr);
 
95
 
 
96
                return true;
 
97
        }
 
98
 
 
99
        Gdk::Rectangle const exposure (
 
100
                event->area.x, event->area.y, event->area.width, event->area.height
 
101
                );
 
102
 
 
103
        bool intersects;
 
104
 
 
105
        for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
 
106
 
 
107
                Gdk::Rectangle r = exposure;
 
108
 
 
109
                /* the get_pixmap call may cause things to be rerendered and sizes to change,
 
110
                   so fetch the pixmap before calculating where to put it */
 
111
                GdkPixmap* p = (*i)->get_pixmap (get_window()->gobj());
 
112
                r.intersect ((*i)->parent_rectangle(), intersects);
 
113
 
 
114
                if (intersects) {
 
115
 
 
116
                        gdk_draw_drawable (
 
117
                                get_window()->gobj(),
 
118
                                get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
 
119
                                p,
 
120
                                (*i)->parent_to_component_x (r.get_x()),
 
121
                                (*i)->parent_to_component_y (r.get_y()),
 
122
                                r.get_x(),
 
123
                                r.get_y(),
 
124
                                r.get_width(),
 
125
                                r.get_height()
 
126
                                );
 
127
                }
 
128
 
 
129
        }
 
130
 
 
131
        cairo_t* cr = gdk_cairo_create (get_window()->gobj());
 
132
 
 
133
        for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
 
134
                cairo_save (cr);
 
135
                set_cairo_clip (cr, (*i)->parent_rectangle ());
 
136
                (*i)->draw_extra (cr);
 
137
                cairo_restore (cr);
 
138
        }
 
139
 
 
140
        cairo_destroy (cr);
 
141
 
 
142
        return true;
 
143
}
 
144
 
 
145
void
 
146
PortMatrixBody::on_size_request (Gtk::Requisition *req)
 
147
{
 
148
        pair<int, int> const col = _column_labels->dimensions ();
 
149
        pair<int, int> const row = _row_labels->dimensions ();
 
150
        pair<int, int> const grid = _grid->dimensions ();
 
151
 
 
152
        if (grid.first == 0 && grid.second == 0) {
 
153
                /* nothing to display */
 
154
                req->width = 256;
 
155
                req->height = 64;
 
156
                return;
 
157
        }
 
158
 
 
159
        /* don't ask for the maximum size of our contents, otherwise GTK won't
 
160
           let the containing window shrink below this size */
 
161
 
 
162
        /* XXX these shouldn't be hard-coded */
 
163
        int const min_width = 512;
 
164
        int const min_height = 512;
 
165
 
 
166
        req->width = min (min_width, max (col.first, grid.first + row.first));
 
167
        req->height = min (min_height / _matrix->min_height_divisor(), col.second + grid.second);
 
168
}
 
169
 
 
170
void
 
171
PortMatrixBody::on_size_allocate (Gtk::Allocation& alloc)
 
172
{
 
173
        Gtk::EventBox::on_size_allocate (alloc);
 
174
 
 
175
        _alloc_width = alloc.get_width ();
 
176
        _alloc_height = alloc.get_height ();
 
177
 
 
178
        compute_rectangles ();
 
179
        _matrix->setup_scrollbars ();
 
180
}
 
181
 
 
182
void
 
183
PortMatrixBody::compute_rectangles ()
 
184
{
 
185
        /* full sizes of components */
 
186
        pair<uint32_t, uint32_t> const col = _column_labels->dimensions ();
 
187
        uint32_t const col_overhang = _column_labels->overhang ();
 
188
        pair<uint32_t, uint32_t> const row = _row_labels->dimensions ();
 
189
        pair<uint32_t, uint32_t> const grid = _grid->dimensions ();
 
190
 
 
191
        Gdk::Rectangle col_rect;
 
192
        Gdk::Rectangle row_rect;
 
193
        Gdk::Rectangle grid_rect;
 
194
 
 
195
        if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
 
196
 
 
197
                col_rect.set_x (0);
 
198
                _column_labels_border_x = col_overhang;
 
199
                col_rect.set_y (0);
 
200
                grid_rect.set_x (0);
 
201
 
 
202
                col_rect.set_width (min (col.first, _alloc_width));
 
203
 
 
204
                uint32_t const y = min (_alloc_height, col.second);
 
205
                col_rect.set_height (y);
 
206
                row_rect.set_y (y);
 
207
                row_rect.set_height (_alloc_height - y);
 
208
                grid_rect.set_y (y);
 
209
                grid_rect.set_height (_alloc_height - y);
 
210
 
 
211
                uint32_t x = 0;
 
212
                if (_alloc_width > (grid.first + row.first)) {
 
213
                        x = grid.first;
 
214
                } else if (_alloc_width > row.first) {
 
215
                        x = _alloc_width - row.first;
 
216
                }
 
217
 
 
218
                grid_rect.set_width (x);
 
219
                row_rect.set_x (x);
 
220
                row_rect.set_width (_alloc_width - x);
 
221
 
 
222
 
 
223
        } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
 
224
 
 
225
                col_rect.set_height (min (_alloc_height, col.second));
 
226
                row_rect.set_height (std::min (_alloc_height - col_rect.get_height(), row.second));
 
227
 
 
228
                row_rect.set_x (0);
 
229
                row_rect.set_y (_alloc_height - row_rect.get_height() - col_rect.get_height());
 
230
                row_rect.set_width (min (_alloc_width, row.first));
 
231
 
 
232
                grid_rect.set_x (row_rect.get_width());
 
233
                grid_rect.set_y (_alloc_height - row_rect.get_height() - col_rect.get_height());
 
234
                grid_rect.set_width (std::min (_alloc_width - row_rect.get_width(), grid.first));
 
235
                grid_rect.set_height (row_rect.get_height ());
 
236
 
 
237
                col_rect.set_width (grid_rect.get_width () + col_overhang);
 
238
                col_rect.set_x (row_rect.get_width() + grid_rect.get_width() - col_rect.get_width());
 
239
                _column_labels_border_x = col_rect.get_x () >= 0 ? col_rect.get_x () : 0;
 
240
                col_rect.set_y (_alloc_height - col_rect.get_height());
 
241
        }
 
242
 
 
243
        _column_labels_height = col_rect.get_height ();
 
244
 
 
245
        _row_labels->set_parent_rectangle (row_rect);
 
246
        _column_labels->set_parent_rectangle (col_rect);
 
247
        _grid->set_parent_rectangle (grid_rect);
 
248
 
 
249
        DimensionsChanged (); /* EMIT SIGNAL */
 
250
}
 
251
 
 
252
void
 
253
PortMatrixBody::setup ()
 
254
{
 
255
        /* Discard any old connections to bundles */
 
256
 
 
257
        _bundle_connections.drop_connections ();
 
258
 
 
259
        /* Connect to bundles so that we find out when their names change */
 
260
 
 
261
        if (_matrix->visible_rows()) {
 
262
                PortGroup::BundleList r = _matrix->visible_rows()->bundles ();
 
263
                for (PortGroup::BundleList::iterator i = r.begin(); i != r.end(); ++i) {
 
264
 
 
265
                        (*i)->bundle->Changed.connect (_bundle_connections, invalidator (*this), boost::bind (&PortMatrixBody::rebuild_and_draw_row_labels, this), gui_context());
 
266
 
 
267
                }
 
268
        }
 
269
 
 
270
        if (_matrix->visible_columns()) {
 
271
                PortGroup::BundleList c = _matrix->visible_columns()->bundles ();
 
272
                for (PortGroup::BundleList::iterator i = c.begin(); i != c.end(); ++i) {
 
273
                        (*i)->bundle->Changed.connect (_bundle_connections, invalidator (*this), boost::bind (&PortMatrixBody::rebuild_and_draw_column_labels, this), gui_context());
 
274
                }
 
275
        }
 
276
 
 
277
        for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
 
278
                (*i)->setup ();
 
279
        }
 
280
 
 
281
        set_mouseover (PortMatrixNode ());
 
282
 
 
283
        _ignore_component_size_changed = true;
 
284
        compute_rectangles ();
 
285
        _ignore_component_size_changed = false;
 
286
}
 
287
 
 
288
uint32_t
 
289
PortMatrixBody::full_scroll_width ()
 
290
{
 
291
        return _grid->dimensions().first;
 
292
 
 
293
}
 
294
 
 
295
uint32_t
 
296
PortMatrixBody::alloc_scroll_width ()
 
297
{
 
298
        return _grid->parent_rectangle().get_width();
 
299
}
 
300
 
 
301
uint32_t
 
302
PortMatrixBody::full_scroll_height ()
 
303
{
 
304
        return _grid->dimensions().second;
 
305
}
 
306
 
 
307
uint32_t
 
308
PortMatrixBody::alloc_scroll_height ()
 
309
{
 
310
        return _grid->parent_rectangle().get_height();
 
311
}
 
312
 
 
313
/** Set x offset (for scrolling) */
 
314
void
 
315
PortMatrixBody::set_xoffset (uint32_t xo)
 
316
{
 
317
        _xoffset = xo;
 
318
        queue_draw ();
 
319
}
 
320
 
 
321
/** Set y offset (for scrolling) */
 
322
void
 
323
PortMatrixBody::set_yoffset (uint32_t yo)
 
324
{
 
325
        _yoffset = yo;
 
326
        queue_draw ();
 
327
}
 
328
 
 
329
bool
 
330
PortMatrixBody::on_button_press_event (GdkEventButton* ev)
 
331
{
 
332
        for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
 
333
                if (Gdk::Region ((*i)->parent_rectangle()).point_in (ev->x, ev->y)) {
 
334
                        (*i)->button_press (
 
335
                                (*i)->parent_to_component_x (ev->x),
 
336
                                (*i)->parent_to_component_y (ev->y),
 
337
                                ev
 
338
                                );
 
339
                }
 
340
        }
 
341
 
 
342
        return true;
 
343
}
 
344
 
 
345
bool
 
346
PortMatrixBody::on_button_release_event (GdkEventButton* ev)
 
347
{
 
348
        for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
 
349
                if (Gdk::Region ((*i)->parent_rectangle()).point_in (ev->x, ev->y)) {
 
350
                        (*i)->button_release (
 
351
                                (*i)->parent_to_component_x (ev->x),
 
352
                                (*i)->parent_to_component_y (ev->y),
 
353
                                ev
 
354
                                );
 
355
                } else {
 
356
                        (*i)->button_release (
 
357
                                -1, -1,
 
358
                                ev
 
359
                                );
 
360
                }
 
361
        }
 
362
 
 
363
        return true;
 
364
}
 
365
 
 
366
void
 
367
PortMatrixBody::rebuild_and_draw_grid ()
 
368
{
 
369
        _grid->require_rebuild ();
 
370
        queue_draw ();
 
371
}
 
372
 
 
373
void
 
374
PortMatrixBody::rebuild_and_draw_column_labels ()
 
375
{
 
376
        _column_labels->require_rebuild ();
 
377
        queue_draw ();
 
378
}
 
379
 
 
380
void
 
381
PortMatrixBody::rebuild_and_draw_row_labels ()
 
382
{
 
383
        _row_labels->require_rebuild ();
 
384
        queue_draw ();
 
385
}
 
386
 
 
387
bool
 
388
PortMatrixBody::on_leave_notify_event (GdkEventCrossing* ev)
 
389
{
 
390
        if (ev->type == GDK_LEAVE_NOTIFY) {
 
391
                set_mouseover (PortMatrixNode ());
 
392
        }
 
393
 
 
394
        return true;
 
395
}
 
396
 
 
397
bool
 
398
PortMatrixBody::on_motion_notify_event (GdkEventMotion* ev)
 
399
{
 
400
        bool done = false;
 
401
 
 
402
        for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
 
403
                if (Gdk::Region ((*i)->parent_rectangle()).point_in (ev->x, ev->y)) {
 
404
                        (*i)->motion (
 
405
                                (*i)->parent_to_component_x (ev->x),
 
406
                                (*i)->parent_to_component_y (ev->y)
 
407
                                );
 
408
 
 
409
                        done = true;
 
410
                }
 
411
        }
 
412
 
 
413
 
 
414
        if (!done) {
 
415
                set_mouseover (PortMatrixNode ());
 
416
        }
 
417
 
 
418
        return true;
 
419
}
 
420
 
 
421
void
 
422
PortMatrixBody::set_mouseover (PortMatrixNode const & n)
 
423
{
 
424
        list<PortMatrixNode> m;
 
425
        m.push_back (n);
 
426
        set_mouseover (m);
 
427
}
 
428
 
 
429
void
 
430
PortMatrixBody::set_mouseover (list<PortMatrixNode> const & n)
 
431
{
 
432
        if (n == _mouseover) {
 
433
                return;
 
434
        }
 
435
 
 
436
        /* Channel highlights are set up only on mouseovers, so
 
437
           it's reasonable to remove all channel highlights here.
 
438
           We can't let individual components clear their own highlights
 
439
           because of the case where, say, the row labels set up some column
 
440
           highlights, and then we ask the column labels to set up their
 
441
           own highlights and they clear them out before they start.
 
442
        */
 
443
 
 
444
        _row_labels->clear_channel_highlights ();
 
445
        _column_labels->clear_channel_highlights ();
 
446
 
 
447
        list<PortMatrixNode> old = _mouseover;
 
448
        _mouseover = n;
 
449
 
 
450
        for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
 
451
                (*i)->mouseover_changed (old);
 
452
        }
 
453
}
 
454
 
 
455
void
 
456
PortMatrixBody::highlight_associated_channels (int dim, ARDOUR::BundleChannel h)
 
457
{
 
458
        ARDOUR::BundleChannel bc[2];
 
459
        bc[dim] = h;
 
460
 
 
461
        if (!PortMatrix::bundle_with_channels (bc[dim].bundle)) {
 
462
                return;
 
463
        }
 
464
 
 
465
        if (dim == _matrix->column_index()) {
 
466
                _column_labels->add_channel_highlight (bc[dim]);
 
467
        } else {
 
468
                _row_labels->add_channel_highlight (bc[dim]);
 
469
        }
 
470
 
 
471
        PortGroup::BundleList const b = _matrix->visible_ports(1 - dim)->bundles ();
 
472
 
 
473
        for (PortGroup::BundleList::const_iterator i = b.begin(); i != b.end(); ++i) {
 
474
                for (uint32_t j = 0; j < (*i)->bundle->nchannels().n_total(); ++j) {
 
475
 
 
476
                        if (!_matrix->should_show ((*i)->bundle->channel_type(j))) {
 
477
                                continue;
 
478
                        }
 
479
 
 
480
                        bc[1 - dim] = ARDOUR::BundleChannel ((*i)->bundle, j);
 
481
 
 
482
                        PortMatrixNode n;
 
483
                        n.row = bc[_matrix->row_index()];
 
484
                        n.column = bc[_matrix->column_index()];
 
485
 
 
486
                        if (_matrix->get_association(n) != PortMatrixNode::NOT_ASSOCIATED) {
 
487
                                if (dim == _matrix->column_index()) {
 
488
                                        _row_labels->add_channel_highlight (bc[1 - dim]);
 
489
                                } else {
 
490
                                        _column_labels->add_channel_highlight (bc[1 - dim]);
 
491
                                }
 
492
                        }
 
493
                }
 
494
        }
 
495
}
 
496
 
 
497
void
 
498
PortMatrixBody::set_cairo_clip (cairo_t* cr, Gdk::Rectangle const & r) const
 
499
{
 
500
        cairo_rectangle (cr, r.get_x(), r.get_y(), r.get_width(), r.get_height());
 
501
        cairo_clip (cr);
 
502
}
 
503
 
 
504
void
 
505
PortMatrixBody::component_size_changed ()
 
506
{
 
507
        if (_ignore_component_size_changed) {
 
508
                return;
 
509
        }
 
510
 
 
511
        compute_rectangles ();
 
512
        _matrix->setup_scrollbars ();
 
513
}
 
514
 
 
515
pair<uint32_t, uint32_t>
 
516
PortMatrixBody::max_size () const
 
517
{
 
518
        pair<uint32_t, uint32_t> const col = _column_labels->dimensions ();
 
519
        pair<uint32_t, uint32_t> const row = _row_labels->dimensions ();
 
520
        pair<uint32_t, uint32_t> const grid = _grid->dimensions ();
 
521
 
 
522
        return make_pair (std::max (row.first, _column_labels->overhang()) + grid.first, col.second + grid.second);
 
523
}
 
524
 
 
525
/** @return x position at which the column labels meet the border of the matrix */
 
526
uint32_t
 
527
PortMatrixBody::column_labels_border_x () const
 
528
{
 
529
        return _column_labels_border_x;
 
530
}
 
531
 
 
532
uint32_t
 
533
PortMatrixBody::column_labels_height () const
 
534
{
 
535
        return _column_labels_height;
 
536
}