minor fixes/changes based on comparison with existing bindings
[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                                 tab.last_ui_size = s->get_width ();
67                                 tabs.push_back (tab);
68                         }
69
70                         tab.from = x;
71                         tab.group = g;
72                         tab.colour = s->color ();
73                         tab.first_ui_size = s->get_width ();
74                 }
75
76                 x += s->get_width ();
77         }
78
79         if (tab.group) {
80                 tab.to = x;
81                 tabs.push_back (tab);
82         }
83
84         return tabs;
85 }
86
87 void
88 MixerGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const
89 {
90         double const arc_radius = _height;
91
92         if (tab.group->is_active()) {
93                 cairo_set_source_rgba (cr, tab.colour.get_red_p (), tab.colour.get_green_p (), tab.colour.get_blue_p (), 1);
94         } else {
95                 cairo_set_source_rgba (cr, 1, 1, 1, 0.2);
96         }
97         
98         cairo_arc (cr, tab.from + arc_radius, _height, arc_radius, M_PI, 3 * M_PI / 2);
99         cairo_line_to (cr, tab.to - arc_radius, 0);
100         cairo_arc (cr, tab.to - arc_radius, _height, arc_radius, 3 * M_PI / 2, 2 * M_PI);
101         cairo_line_to (cr, tab.from, _height);
102         cairo_fill (cr);
103
104         pair<string, double> const f = fit_to_pixels (cr, tab.group->name(), tab.to - tab.from - arc_radius * 2);
105
106         cairo_text_extents_t ext;
107         cairo_text_extents (cr, tab.group->name().c_str(), &ext);
108
109         cairo_set_source_rgb (cr, 1, 1, 1);
110         cairo_move_to (cr, tab.from + (tab.to - tab.from - f.second) / 2, _height - ext.height / 2);
111         cairo_save (cr);
112         cairo_show_text (cr, f.first.c_str());
113         cairo_restore (cr);
114 }
115
116 double
117 MixerGroupTabs::primary_coordinate (double x, double) const
118 {
119         return x;
120 }
121
122 void
123 MixerGroupTabs::reflect_tabs (list<Tab> const & tabs)
124 {
125         list<Tab>::const_iterator j = tabs.begin ();
126         
127         int32_t x = 0;
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 (j == tabs.end()) {
138                         
139                         /* already run out of tabs, so no edit group */
140                         s->route()->set_route_group (0, this);
141                         
142                 } else {
143                         
144                         if (x >= j->to) {
145                                 /* this tab finishes before this track starts, so onto the next tab */
146                                 ++j;
147                         }
148                         
149                         double const h = x + s->get_width() / 2;
150                         
151                         if (j->from < h && j->to > h) {
152                                 s->route()->set_route_group (j->group, this);
153                         } else {
154                                 s->route()->set_route_group (0, this);
155                         }
156                         
157                 }
158
159                 x += s->get_width ();
160         }
161 }
162
163 Gtk::Menu*
164 MixerGroupTabs::get_menu (RouteGroup* g)
165 {
166         if (g == 0) {
167                 return 0;
168         }
169         
170         using namespace Menu_Helpers;
171         
172         delete _menu;
173         _menu = new Menu;
174         
175         MenuList& items = _menu->items ();
176         items.push_back (MenuElem (_("Edit..."), bind (mem_fun (*this, &MixerGroupTabs::edit_group), g)));
177         items.push_back (MenuElem (_("Subgroup"), bind (mem_fun (*this, &MixerGroupTabs::make_subgroup), g)));
178         items.push_back (SeparatorElem());
179         items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &MixerGroupTabs::remove_group), g)));
180
181         return _menu;
182 }
183
184 void
185 MixerGroupTabs::edit_group (RouteGroup* g)
186 {
187         RouteGroupDialog d (g, Gtk::Stock::APPLY);
188         d.do_run ();
189 }
190
191 void
192 MixerGroupTabs::remove_group (RouteGroup *g)
193 {
194         _session->remove_route_group (*g);
195 }
196
197 void
198 MixerGroupTabs::make_subgroup (RouteGroup* g)
199 {
200         g->make_subgroup ();
201 }
202
203 void
204 MixerGroupTabs::destroy_subgroup (RouteGroup* g)
205 {
206         g->destroy_subgroup ();
207 }