new file
[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         : GroupTabs (0),
35           _mixer (m),
36           _menu (0)
37 {
38
39 }
40
41
42 list<GroupTabs::Tab>
43 MixerGroupTabs::compute_tabs () const
44 {
45         list<Tab> tabs;
46
47         Tab tab;
48         tab.from = 0;
49         tab.group = 0;
50
51         int32_t x = 0;
52         TreeModel::Children rows = _mixer->track_model->children ();
53         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
54
55                 MixerStrip* s = (*i)[_mixer->track_columns.strip];
56
57                 if (s->route()->is_master() || s->route()->is_control() || !s->marked_for_display()) {
58                         continue;
59                 }
60
61                 RouteGroup* g = s->route_group ();
62
63                 if (g != tab.group) {
64                         if (tab.group) {
65                                 tab.to = x;
66                                 tabs.push_back (tab);
67                         }
68
69                         tab.from = x;
70                         tab.group = g;
71                         tab.colour = s->color ();
72                 }
73
74                 x += s->get_width ();
75         }
76
77         if (tab.group) {
78                 tab.to = x;
79                 tabs.push_back (tab);
80         }
81
82         return tabs;
83 }
84
85 void
86 MixerGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const
87 {
88         double const arc_radius = _height;
89
90         if (tab.group && tab.group->is_active()) {
91                 cairo_set_source_rgba (cr, tab.colour.get_red_p (), tab.colour.get_green_p (), tab.colour.get_blue_p (), 1);
92         } else {
93                 cairo_set_source_rgba (cr, 1, 1, 1, 0.2);
94         }
95
96         cairo_arc (cr, tab.from + arc_radius, _height, arc_radius, M_PI, 3 * M_PI / 2);
97         cairo_line_to (cr, tab.to - arc_radius, 0);
98         cairo_arc (cr, tab.to - arc_radius, _height, arc_radius, 3 * M_PI / 2, 2 * M_PI);
99         cairo_line_to (cr, tab.from, _height);
100         cairo_fill (cr);
101
102         if (tab.group) {
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
116 double
117 MixerGroupTabs::primary_coordinate (double x, double) const
118 {
119         return x;
120 }
121
122 RouteList
123 MixerGroupTabs::routes_for_tab (Tab const * t) const
124 {
125         RouteList routes;
126         int32_t x = 0;
127
128         TreeModel::Children rows = _mixer->track_model->children ();
129         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
130
131                 MixerStrip* s = (*i)[_mixer->track_columns.strip];
132
133                 if (s->route()->is_master() || s->route()->is_control() || !s->marked_for_display()) {
134                         continue;
135                 }
136
137                 if (x >= t->to) {
138                         /* tab finishes before this track starts */
139                         break;
140                 }
141
142                 double const h = x + s->get_width() / 2;
143
144                 if (t->from < h && t->to > h) {
145                         routes.push_back (s->route ());
146                 }
147
148                 x += s->get_width ();
149         }
150
151         return routes;
152 }
153
154 Gtk::Menu*
155 MixerGroupTabs::get_menu (RouteGroup* g)
156 {
157         if (g == 0) {
158                 return 0;
159         }
160
161         using namespace Menu_Helpers;
162
163         delete _menu;
164         _menu = new Menu;
165
166         MenuList& items = _menu->items ();
167         items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &MixerGroupTabs::edit_group), g)));
168         items.push_back (MenuElem (_("Subgroup"), sigc::bind (sigc::mem_fun (*this, &MixerGroupTabs::make_subgroup), g)));
169         items.push_back (SeparatorElem());
170         items.push_back (MenuElem (_("Remove"), sigc::bind (sigc::mem_fun (*this, &MixerGroupTabs::remove_group), g)));
171
172         return _menu;
173 }
174
175 void
176 MixerGroupTabs::edit_group (RouteGroup* g)
177 {
178         RouteGroupDialog d (g, Gtk::Stock::APPLY);
179         d.do_run ();
180 }
181
182 void
183 MixerGroupTabs::remove_group (RouteGroup *g)
184 {
185         _session->remove_route_group (*g);
186 }
187
188 void
189 MixerGroupTabs::make_subgroup (RouteGroup* g)
190 {
191         g->make_subgroup ();
192 }
193
194 void
195 MixerGroupTabs::destroy_subgroup (RouteGroup* g)
196 {
197         g->destroy_subgroup ();
198 }
199
200 ARDOUR::RouteGroup *
201 MixerGroupTabs::new_route_group () const
202 {
203         RouteGroup* g = new RouteGroup (
204                 *_session,
205                 "",
206                 RouteGroup::Active,
207                 (RouteGroup::Property) (RouteGroup::Gain | RouteGroup::Mute | RouteGroup::Solo | RouteGroup::RecEnable)
208                 );
209
210         RouteGroupDialog d (g, Gtk::Stock::NEW);
211         int const r = d.do_run ();
212
213         if (r != Gtk::RESPONSE_OK) {
214                 delete g;
215                 return 0;
216         }
217         
218         _session->add_route_group (g);
219         return g;
220 }