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