Add some more options to the route group list context menu. Fix a crash bug on remov...
[ardour.git] / gtk2_ardour / 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 <gtkmm/stock.h>
21 #include "ardour/session.h"
22 #include "ardour/route_group.h"
23 #include "route_group_dialog.h"
24 #include "group_tabs.h"
25 #include "i18n.h"
26
27 using namespace std;
28 using namespace Gtk;
29 using namespace ARDOUR;
30
31 GroupTabs::GroupTabs ()
32         : _session (0),
33           _menu (0),
34           _dragging (0)
35 {
36
37 }
38
39 void
40 GroupTabs::set_session (Session* s)
41 {
42         _session = s;
43         s->RouteGroupChanged.connect (mem_fun (*this, &GroupTabs::set_dirty));
44 }
45
46
47 /** Handle a size request.
48  *  @param req GTK requisition
49  */
50 void
51 GroupTabs::on_size_request (Gtk::Requisition *req)
52 {
53         /* Use a dummy, small width and the actual height that we want */
54         req->width = 16;
55         req->height = 16;
56 }
57
58 bool
59 GroupTabs::on_button_press_event (GdkEventButton* ev)
60 {
61         using namespace Menu_Helpers;
62
63         double const p = primary_coordinate (ev->x, ev->y);
64
65         Tab* prev;
66         Tab* next;
67         Tab* t = click_to_tab (p, &prev, &next);
68         if (t == 0) {
69                 return false;
70         }
71
72         if (ev->button == 1) {
73
74                 _dragging = t;
75                 _drag_moved = false;
76                 _drag_last = p;
77
78                 double const h = (t->from + t->to) / 2;
79                 _drag_from = p < h;
80
81                 if (_drag_from) {
82                         _drag_limit = prev ? prev->to : 0;
83                 } else {
84                         _drag_limit = next ? next->from : extent ();
85                 }
86
87         } else if (ev->button == 3) {
88
89                 delete _menu;
90                 _menu = new Menu;
91                 MenuList& items = _menu->items ();
92                 items.push_back (MenuElem (_("Edit..."), bind (mem_fun (*this, &GroupTabs::edit_group), t->group)));
93                 items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &GroupTabs::remove_group), t->group)));
94
95                 _menu->popup (ev->button, ev->time);
96
97         }
98
99         return true;
100 }
101
102
103 bool
104 GroupTabs::on_motion_notify_event (GdkEventMotion* ev)
105 {
106         if (_dragging == 0) {
107                 return false;
108         }
109
110         double const p = primary_coordinate (ev->x, ev->y);
111         
112         if (p != _drag_last) {
113                 _drag_moved = true;
114         }
115
116         if (_drag_from) {
117                 double f = _dragging->from + p - _drag_last;
118                 if (f < _drag_limit) {
119                         f = _drag_limit;
120                 }
121                 _dragging->from = f;
122         } else {
123                 double t = _dragging->to + p - _drag_last;
124                 if (t > _drag_limit) {
125                         t = _drag_limit;
126                 }
127                 _dragging->to = t;
128         }
129
130         set_dirty ();
131         queue_draw ();
132
133         _drag_last = p;
134         
135         return true;
136 }
137
138
139 bool
140 GroupTabs::on_button_release_event (GdkEventButton* ev)
141 {
142         if (_dragging == 0) {
143                 return false;
144         }
145
146         if (!_drag_moved) {
147                 _dragging->group->set_active (!_dragging->group->is_active (), this);
148                 _dragging = 0;
149         } else {
150                 _dragging = 0;
151                 reflect_tabs (_tabs);
152                 set_dirty ();
153                 queue_draw ();
154         }
155
156         return true;
157 }
158
159
160 void
161 GroupTabs::edit_group (RouteGroup* g)
162 {
163         RouteGroupDialog d (g, Gtk::Stock::APPLY);
164         d.do_run ();
165 }
166
167 void
168 GroupTabs::remove_group (RouteGroup *g)
169 {
170         _session->remove_route_group (*g);
171 }
172
173 void
174 GroupTabs::render (cairo_t* cr)
175 {
176         if (_dragging == 0) {
177                 _tabs = compute_tabs ();
178         }
179
180         /* background */
181         
182         cairo_set_source_rgb (cr, 0, 0, 0);
183         cairo_rectangle (cr, 0, 0, _width, _height);
184         cairo_fill (cr);
185
186         /* tabs */
187
188         for (list<Tab>::const_iterator i = _tabs.begin(); i != _tabs.end(); ++i) {
189                 draw_tab (cr, *i);
190         }       
191 }
192
193
194 GroupTabs::Tab *
195 GroupTabs::click_to_tab (double c, Tab** prev, Tab** next)
196 {
197         list<Tab>::iterator i = _tabs.begin ();
198         while (i != _tabs.end() && (c < i->from || c > i->to)) {
199                 *prev = &(*i);
200                 ++i;
201         }
202
203         if (i == _tabs.end()) {
204                 *next = 0;
205                 return 0;
206         }
207
208         list<Tab>::iterator j = i;
209         ++j;
210         if (j == _tabs.end()) {
211                 *next = 0;
212         } else {
213                 *next = &(*j);
214         }
215
216         return &(*i);
217 }