Split route group list out of Editor.
[ardour.git] / gtk2_ardour / editor_mixer.cc
1 /*
2     Copyright (C) 2003-2004 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 <glibmm/miscutils.h>
21 #include <gtkmm2ext/utils.h>
22 #include <gtkmm2ext/window_title.h>
23
24 #include "pbd/enumwriter.h"
25
26 #include "ardour/audioengine.h"
27
28 #include "editor.h"
29 #include "mixer_strip.h"
30 #include "ardour_ui.h"
31 #include "selection.h"
32 #include "audio_time_axis.h"
33 #include "actions.h"
34 #include "editor_routes.h"
35 #include "editor_route_groups.h"
36
37 #include "i18n.h"
38
39 using namespace std;
40 using namespace Gtkmm2ext;
41 using namespace PBD;
42
43 void
44 Editor::editor_mixer_button_toggled ()
45 {
46         Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
47         if (act) {
48                 Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(act);
49                 show_editor_mixer (tact->get_active());
50         }
51 }
52
53 void
54 Editor::editor_list_button_toggled ()
55 {
56         Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
57         if (act) {
58                 Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(act);
59                 show_editor_list (tact->get_active());
60         }
61 }
62
63 void
64 Editor::cms_deleted ()
65 {
66         current_mixer_strip = 0;
67 }
68
69 void
70 Editor::show_editor_mixer (bool yn)
71 {
72         boost::shared_ptr<ARDOUR::Route> r;
73
74         show_editor_mixer_when_tracks_arrive = false;
75
76         if (!session) {
77                 show_editor_mixer_when_tracks_arrive = yn;
78                 return;
79         }
80
81         if (yn) {
82
83                 if (selection->tracks.empty()) {
84
85                         if (track_views.empty()) {      
86                                 show_editor_mixer_when_tracks_arrive = true;
87                                 return;
88                         } 
89
90                         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
91                                 RouteTimeAxisView* atv;
92                                 
93                                 if ((atv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
94                                         r = atv->route();
95                                         break;
96                                 }
97                         }
98
99                 } else {
100                         sort_track_selection ();
101                         
102                         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
103                                 RouteTimeAxisView* atv;
104                                 
105                                 if ((atv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
106                                         r = atv->route();
107                                         break;
108                                 }
109                         }
110                 }
111
112                 if (r) {
113                         bool created;
114
115                         if (current_mixer_strip == 0) {
116                                 create_editor_mixer ();
117                                 created = true;
118                         } else {
119                                 created = false;
120                         }
121
122                         current_mixer_strip->set_route (r);
123
124                         if (created) {
125                                 current_mixer_strip->set_width_enum (editor_mixer_strip_width, (void*) this);
126                         }
127                 }
128                 
129                 if (current_mixer_strip->get_parent() == 0) {
130                         global_hpacker.pack_start (*current_mixer_strip, Gtk::PACK_SHRINK );
131                         global_hpacker.reorder_child (*current_mixer_strip, 0);
132                         current_mixer_strip->show_all ();
133                 }
134
135         } else {
136
137                 if (current_mixer_strip) {
138                         if (current_mixer_strip->get_parent() != 0) {
139                                 global_hpacker.remove (*current_mixer_strip);
140                         }
141                 }
142         }
143
144 #ifdef GTKOSX
145         /* XXX gtk problem here */
146         ensure_all_elements_drawn();
147 #endif
148 }
149
150 #ifdef GTKOSX
151 void
152 Editor::ensure_all_elements_drawn ()
153 {
154         controls_layout.queue_draw ();
155         ruler_label_event_box.queue_draw ();
156         time_button_event_box.queue_draw ();
157 }
158 #endif
159
160 void
161 Editor::show_editor_list (bool yn)
162 {
163         if (yn) {
164                 the_notebook.show();
165         } else {
166                 the_notebook.hide();
167         }
168 }
169
170 void
171 Editor::create_editor_mixer ()
172 {
173         current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(),
174                                               *session,
175                                               false);
176         current_mixer_strip->Hiding.connect (mem_fun(*this, &Editor::current_mixer_strip_hidden));
177         current_mixer_strip->GoingAway.connect (mem_fun(*this, &Editor::current_mixer_strip_removed));
178 #ifdef GTKOSX
179         current_mixer_strip->WidthChanged.connect (mem_fun(*this, &Editor::ensure_all_elements_drawn));
180 #endif
181         current_mixer_strip->set_embedded (true);
182 }       
183
184 void
185 Editor::set_selected_mixer_strip (TimeAxisView& view)
186 {
187         RouteTimeAxisView* at;
188         bool created;
189
190         if (!session || (at = dynamic_cast<RouteTimeAxisView*>(&view)) == 0) {
191                 return;
192         }
193
194         Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
195         
196         if (act) {
197                 Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(act);
198                 if (!tact || !tact->get_active()) {
199                         /* not showing mixer strip presently */
200                         return;
201                 }
202         }
203
204         if (current_mixer_strip == 0) {
205                 create_editor_mixer ();
206                 created = true;
207         } else {
208                 created = false;
209         }
210
211         /* might be nothing to do */
212         
213         if (current_mixer_strip->route() == at->route()) {
214                 return;
215         }
216         
217         if (created) {
218                 current_mixer_strip->set_width_enum (editor_mixer_strip_width, (void*) this);
219         }
220
221         current_mixer_strip->set_route (at->route());
222 }
223
224 double current = 0.0;
225
226 void
227 Editor::update_current_screen ()
228 {
229         if (_pending_locate_request) {
230                 /* we don't update things when there's a pending locate request, otherwise
231                    when the editor requests a locate there is a chance that this method
232                    will move the playhead before the locate request is processed, causing
233                    a visual glitch. */
234                 return;
235         }
236         
237         if (session && session->engine().running()) {
238
239                 nframes64_t const frame = session->audible_frame();
240
241                 if (_dragging_playhead) {
242                         goto almost_done;
243                 }
244
245                 /* only update if the playhead is on screen or we are following it */
246
247                 if (_follow_playhead && session->requested_return_frame() < 0) {
248
249                         //playhead_cursor->canvas_item.show();
250
251                         if (frame != last_update_frame) {
252
253
254 #undef CONTINUOUS_SCROLL
255 #ifndef  CONTINUOUS_SCROLL
256                                 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
257                                         
258                                         if (session->transport_speed() < 0) {
259                                                 if (frame > (current_page_frames()/2)) {
260                                                         center_screen (frame-(current_page_frames()/2));
261                                                 } else {
262                                                         center_screen (current_page_frames()/2);
263                                                 }
264                                         } else {
265                                                 center_screen (frame+(current_page_frames()/2));
266                                         }
267                                 }
268
269                                 playhead_cursor->set_position (frame);
270
271 #else  // CONTINUOUS_SCROLL
272                                 
273                                 /* don't do continuous scroll till the new position is in the rightmost quarter of the 
274                                    editor canvas
275                                 */
276                                 
277                                 if (session->transport_speed()) {
278                                         double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
279                                         if (target <= 0.0) target = 0.0;
280                                         if ( fabs(target - current) < current_page_frames()/frames_per_unit ) {
281                                                 target = (target * 0.15) + (current * 0.85);
282                                         } else {
283                                                 /* relax */
284                                         }
285                                         //printf("frame: %d,  cpf: %d,  fpu: %6.6f, current: %6.6f, target : %6.6f\n", frame, current_page_frames(), frames_per_unit, current, target );
286                                         current = target;
287                                         horizontal_adjustment.set_value ( current );
288                                 }
289                                 
290                                 playhead_cursor->set_position (frame);
291
292 #endif // CONTINUOUS_SCROLL
293
294                         }
295
296                 } else {
297                         if (frame != last_update_frame) {
298                                 playhead_cursor->set_position (frame);
299                         }
300                 }
301
302           almost_done:
303                 last_update_frame = frame;
304                 if (current_mixer_strip) {
305                         current_mixer_strip->fast_update ();
306                 }
307                 
308         }
309 }
310
311 void
312 Editor::current_mixer_strip_removed ()
313 {
314         if (current_mixer_strip) {
315                 /* it is being deleted elsewhere */
316                 current_mixer_strip = 0;
317         }
318 }
319
320 void
321 Editor::current_mixer_strip_hidden ()
322 {
323         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
324                 
325                 RouteTimeAxisView* tmp;
326                 
327                 if ((tmp = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
328                         if (tmp->route() == current_mixer_strip->route()) {
329                                 (*i)->set_selected (false);
330                                 break;
331                         }
332                 }
333         }
334
335         Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
336         if (act) {
337                 Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(act);
338                 tact->set_active (false);
339         }
340 }
341
342 void
343 Editor::session_going_away ()
344 {
345         _have_idled = false;
346         
347         for (vector<sigc::connection>::iterator i = session_connections.begin(); i != session_connections.end(); ++i) {
348                 (*i).disconnect ();
349         }
350
351         stop_scrolling ();
352         selection->clear ();
353         cut_buffer->clear ();
354
355         clicked_regionview = 0;
356         clicked_axisview = 0;
357         clicked_routeview = 0;
358         clicked_crossfadeview = 0;
359         entered_regionview = 0;
360         entered_track = 0;
361         last_update_frame = 0;
362         _drag = 0;
363
364         playhead_cursor->canvas_item.hide ();
365
366         /* hide all tracks */
367
368         _routes->hide_all_tracks (false);
369
370         /* rip everything out of the list displays */
371
372         region_list_display.set_model (Glib::RefPtr<Gtk::TreeStore>(0));
373         _routes->clear ();
374         _route_groups->clear ();
375         named_selection_display.set_model (Glib::RefPtr<Gtk::TreeStore>(0));
376
377         region_list_model->clear ();
378         named_selection_model->clear ();
379
380         region_list_display.set_model (region_list_model);
381         named_selection_display.set_model (named_selection_model);
382
383         edit_point_clock_connection_a.disconnect();
384         edit_point_clock_connection_b.disconnect();
385
386         edit_point_clock.set_session (0);
387         zoom_range_clock.set_session (0);
388         nudge_clock.set_session (0);
389
390         editor_list_button.set_active(false);
391         editor_list_button.set_sensitive(false);
392         
393         /* clear tempo/meter rulers */
394         remove_metric_marks ();
395         hide_measures ();
396         clear_marker_display ();
397
398         delete current_bbt_points;
399         current_bbt_points = 0;
400         
401         /* get rid of any existing editor mixer strip */
402         
403         if (current_mixer_strip) {
404                 if (current_mixer_strip->get_parent() != 0) {
405                         global_hpacker.remove (*current_mixer_strip);
406                 }
407                 delete current_mixer_strip;
408                 current_mixer_strip = 0;
409         }
410
411         WindowTitle title(Glib::get_application_name());
412         title += _("Editor");
413
414         set_title (title.get_string());
415
416         session = 0;
417 }
418
419 void
420 Editor::maybe_add_mixer_strip_width (XMLNode& node)
421 {
422         if (current_mixer_strip) {
423                 node.add_property ("mixer-width", enum_2_string (current_mixer_strip->get_width_enum()));
424         }
425 }
426