Update mixer group tabs on strip width change. Don't display the mixer group tab...
[ardour.git] / gtk2_ardour / mixer_group_tabs.cc
1 /*
2     Copyright (C) 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 "ardour/route_group.h"
21 #include "ardour/session.h"
22 #include "mixer_group_tabs.h"
23 #include "mixer_strip.h"
24 #include "mixer_ui.h"
25 #include "utils.h"
26 #include "i18n.h"
27 #include "route_group_dialog.h"
28
29 using namespace std;
30 using namespace Gtk;
31 using namespace ARDOUR;
32
33 MixerGroupTabs::MixerGroupTabs (Mixer_UI* m)
34         : _mixer (m),
35           _menu (0)
36 {
37         
38 }
39
40
41 list<GroupTabs::Tab>
42 MixerGroupTabs::compute_tabs () const
43 {
44         list<Tab> tabs;
45         
46         Tab tab;
47         tab.from = 0;
48         tab.group = 0;
49
50         int32_t x = 0;
51         TreeModel::Children rows = _mixer->track_model->children ();
52         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
53
54                 MixerStrip* s = (*i)[_mixer->track_columns.strip];
55
56                 if (s->route()->is_master() || s->route()->is_control() || !s->marked_for_display()) {
57                         continue;
58                 }
59
60                 RouteGroup* g = s->route_group ();
61
62                 if (g != tab.group) {
63                         if (tab.group) {
64                                 tab.to = x;
65                                 tab.last_ui_size = s->get_width ();
66                                 tabs.push_back (tab);
67                         }
68
69                         tab.from = x;
70                         tab.group = g;
71                         tab.colour = s->color ();
72                         tab.first_ui_size = s->get_width ();
73                 }
74
75                 x += s->get_width ();
76         }
77
78         if (tab.group) {
79                 tab.to = x;
80                 tabs.push_back (tab);
81         }
82
83         return tabs;
84 }
85
86 void
87 MixerGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const
88 {
89         double const arc_radius = _height;
90
91         if (tab.group->is_active()) {
92                 cairo_set_source_rgba (cr, tab.colour.get_red_p (), tab.colour.get_green_p (), tab.colour.get_blue_p (), 1);
93         } else {
94                 cairo_set_source_rgba (cr, 1, 1, 1, 0.2);
95         }
96         
97         cairo_arc (cr, tab.from + arc_radius, _height, arc_radius, M_PI, 3 * M_PI / 2);
98         cairo_line_to (cr, tab.to - arc_radius, 0);
99         cairo_arc (cr, tab.to - arc_radius, _height, arc_radius, 3 * M_PI / 2, 2 * M_PI);
100         cairo_line_to (cr, tab.from, _height);
101         cairo_fill (cr);
102
103         pair<string, double> const f = fit_to_pixels (cr, tab.group->name(), tab.to - tab.from - arc_radius * 2);
104
105         cairo_text_extents_t ext;
106         cairo_text_extents (cr, tab.group->name().c_str(), &ext);
107
108         cairo_set_source_rgb (cr, 1, 1, 1);
109         cairo_move_to (cr, tab.from + (tab.to - tab.from - f.second) / 2, _height - ext.height / 2);
110         cairo_save (cr);
111         cairo_show_text (cr, f.first.c_str());
112         cairo_restore (cr);
113 }
114
115 double
116 MixerGroupTabs::primary_coordinate (double x, double) const
117 {
118         return x;
119 }
120
121 void
122 MixerGroupTabs::reflect_tabs (list<Tab> const & tabs)
123 {
124         list<Tab>::const_iterator j = tabs.begin ();
125         
126         int32_t x = 0;
127         TreeModel::Children rows = _mixer->track_model->children ();
128         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
129
130                 MixerStrip* s = (*i)[_mixer->track_columns.strip];
131                 
132                 if (s->route()->is_master() || s->route()->is_control() || !s->marked_for_display()) {
133                         continue;
134                 }
135                 
136                 if (j == tabs.end()) {
137                         
138                         /* already run out of tabs, so no edit group */
139                         s->route()->set_route_group (0, this);
140                         
141                 } else {
142                         
143                         if (x >= j->to) {
144                                 /* this tab finishes before this track starts, so onto the next tab */
145                                 ++j;
146                         }
147                         
148                         double const h = x + s->get_width() / 2;
149                         
150                         if (j->from < h && j->to > h) {
151                                 s->route()->set_route_group (j->group, this);
152                         } else {
153                                 s->route()->set_route_group (0, this);
154                         }
155                         
156                 }
157
158                 x += s->get_width ();
159         }
160 }
161
162 Gtk::Menu*
163 MixerGroupTabs::get_menu (RouteGroup* g)
164 {
165         if (g == 0) {
166                 return 0;
167         }
168         
169         using namespace Menu_Helpers;
170         
171         delete _menu;
172         _menu = new Menu;
173         
174         MenuList& items = _menu->items ();
175         items.push_back (MenuElem (_("Edit..."), bind (mem_fun (*this, &MixerGroupTabs::edit_group), g)));
176         items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &MixerGroupTabs::remove_group), g)));
177
178         return _menu;
179 }
180
181 void
182 MixerGroupTabs::edit_group (RouteGroup* g)
183 {
184         RouteGroupDialog d (g, Gtk::Stock::APPLY);
185         d.do_run ();
186 }
187
188 void
189 MixerGroupTabs::remove_group (RouteGroup *g)
190 {
191         _session->remove_route_group (*g);
192 }