Popup the standard route group menu even when you don't right-click on a tab.
[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           _dragging (0)
34 {
35
36 }
37
38 void
39 GroupTabs::set_session (Session* s)
40 {
41         _session = s;
42         s->RouteGroupChanged.connect (mem_fun (*this, &GroupTabs::set_dirty));
43 }
44
45
46 /** Handle a size request.
47  *  @param req GTK requisition
48  */
49 void
50 GroupTabs::on_size_request (Gtk::Requisition *req)
51 {
52         /* Use a dummy, small width and the actual height that we want */
53         req->width = 16;
54         req->height = 16;
55 }
56
57 bool
58 GroupTabs::on_button_press_event (GdkEventButton* ev)
59 {
60         using namespace Menu_Helpers;
61
62         double const p = primary_coordinate (ev->x, ev->y);
63
64         Tab* prev;
65         Tab* next;
66         Tab* t = click_to_tab (p, &prev, &next);
67
68         if (ev->button == 1 && t) {
69
70                 _dragging = t;
71                 _drag_moved = false;
72                 _drag_last = p;
73
74                 double const h = (t->from + t->to) / 2;
75                 _drag_from = p < h;
76
77                 if (_drag_from) {
78                         /* limit is the end of the previous tab */
79                         _drag_limit = prev ? prev->to : 0;
80                 } else {
81                         /* limit is the start of the next tab */
82                         _drag_limit = next ? next->from : extent ();
83                 }
84
85         } else if (ev->button == 3) {
86
87                 RouteGroup* g = t ? t->group : 0;
88                 get_menu(g)->popup (ev->button, ev->time);
89                 
90         }
91
92         return true;
93 }
94
95
96 bool
97 GroupTabs::on_motion_notify_event (GdkEventMotion* ev)
98 {
99         if (_dragging == 0) {
100                 return false;
101         }
102
103         double const p = primary_coordinate (ev->x, ev->y);
104         
105         if (p != _drag_last) {
106                 _drag_moved = true;
107         }
108
109         if (_drag_from) {
110                 
111                 double f = _dragging->from + p - _drag_last;
112
113                 if (f < _drag_limit) {
114                         /* limit drag in the `too big' direction */
115                         f = _drag_limit;
116                 }
117
118                 double const t = _dragging->to - _dragging->last_ui_size;
119                 if (f > t) {
120                         /* limit drag in the `too small' direction */
121                         f = t;
122                 }
123                 
124                 _dragging->from = f;
125                 
126         } else {
127                 
128                 double t = _dragging->to + p - _drag_last;
129
130                 if (t > _drag_limit) {
131                         /* limit drag in the `too big' direction */
132                         t = _drag_limit;
133                 }
134
135                 double const f = _dragging->from + _dragging->first_ui_size;
136                 if (t < f) {
137                         /* limit drag in the `too small' direction */
138                         t = f;
139                 }
140                 
141                 _dragging->to = t;
142         }
143
144         set_dirty ();
145         queue_draw ();
146
147         _drag_last = p;
148         
149         return true;
150 }
151
152
153 bool
154 GroupTabs::on_button_release_event (GdkEventButton* ev)
155 {
156         if (_dragging == 0) {
157                 return false;
158         }
159
160         if (!_drag_moved) {
161                 /* toggle active state */
162                 _dragging->group->set_active (!_dragging->group->is_active (), this);
163                 _dragging = 0;
164         } else {
165                 /* finish drag */
166                 _dragging = 0;
167                 reflect_tabs (_tabs);
168                 set_dirty ();
169                 queue_draw ();
170         }
171
172         return true;
173 }
174
175 void
176 GroupTabs::render (cairo_t* cr)
177 {
178         if (_dragging == 0) {
179                 _tabs = compute_tabs ();
180         }
181
182         /* background */
183         
184         cairo_set_source_rgb (cr, 0, 0, 0);
185         cairo_rectangle (cr, 0, 0, _width, _height);
186         cairo_fill (cr);
187
188         /* tabs */
189
190         for (list<Tab>::const_iterator i = _tabs.begin(); i != _tabs.end(); ++i) {
191                 draw_tab (cr, *i);
192         }       
193 }
194
195
196 /** Convert a click position to a tab.
197  *  @param c Click position.
198  *  @param prev Filled in with the previous tab to the click, or 0.
199  *  @param next Filled in with the next tab after the click, or 0.
200  *  @return Tab under the click, or 0.
201  */
202  
203 GroupTabs::Tab *
204 GroupTabs::click_to_tab (double c, Tab** prev, Tab** next)
205 {
206         *prev = 0;
207         
208         list<Tab>::iterator i = _tabs.begin ();
209         while (i != _tabs.end() && (c < i->from || c > i->to)) {
210                 *prev = &(*i);
211                 ++i;
212         }
213
214         if (i == _tabs.end()) {
215                 *next = 0;
216                 return 0;
217         }
218
219         list<Tab>::iterator j = i;
220         ++j;
221         if (j == _tabs.end()) {
222                 *next = 0;
223         } else {
224                 *next = &(*j);
225         }
226
227         return &(*i);
228 }
229