fix bad behaviour by +/- buttons in edit group list. yes, i was supposed to be in...
[ardour.git] / gtk2_ardour / audio_region_editor.cc
1 /*
2     Copyright (C) 2001 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     $Id$
19 */
20
21 #include <pbd/memento_command.h>
22
23 #include <ardour/audioregion.h>
24 #include <ardour/playlist.h>
25 #include <ardour/utils.h>
26 #include <gtkmm2ext/utils.h>
27 #include <gtkmm2ext/stop_signal.h>
28 #include <cmath>
29
30 #include "audio_region_editor.h"
31 #include "audio_region_view.h"
32 #include "ardour_ui.h"
33 #include "utils.h"
34 #include "gui_thread.h"
35
36 #include "i18n.h"
37
38 using namespace ARDOUR;
39 using namespace PBD;
40 using namespace sigc;
41 using namespace std;
42
43 AudioRegionEditor::AudioRegionEditor (Session& s, boost::shared_ptr<AudioRegion> r, AudioRegionView& rv)
44         : RegionEditor (s),
45           _region (r),
46           _region_view (rv),
47           name_label (_("NAME:")),
48           lock_button (_("lock")),
49           mute_button (_("mute")),
50           opaque_button (_("opaque")),
51           envelope_active_button(_("active")),
52           envelope_view_button(_("visible")),
53           raise_arrow (Gtk::ARROW_UP, Gtk::SHADOW_OUT),
54           lower_arrow (Gtk::ARROW_DOWN, Gtk::SHADOW_OUT),
55           layer_label (_("Layer")),
56           audition_button (_("play")),
57           time_table (3, 2),
58           start_clock ("AudioRegionEditorClock", true),
59           end_clock ("AudioRegionEditorClock", true),
60           length_clock ("AudioRegionEditorClock", true, true),
61           sync_offset_clock ("AudioRegionEditorClock", true, true),
62           envelope_loop_table (1, 3),
63           envelope_label (_("ENVELOPE"))
64
65 {
66         start_clock.set_session (&_session);
67         end_clock.set_session (&_session);
68         length_clock.set_session (&_session);
69
70         name_entry.set_name ("AudioRegionEditorEntry");
71         name_label.set_name ("AudioRegionEditorLabel");
72
73         name_hbox.set_spacing (5);
74         name_hbox.pack_start (name_label, false, false);
75         name_hbox.pack_start (name_entry, false, false);
76
77         raise_button.add (raise_arrow);
78         lower_button.add (lower_arrow);
79         layer_frame.set_name ("BaseFrame");
80         layer_frame.set_shadow_type (Gtk::SHADOW_IN);
81         layer_frame.add (layer_value_label);
82         layer_label.set_name ("AudioRegionEditorLabel");
83         layer_value_label.set_name ("AudioRegionEditorLabel");
84         Gtkmm2ext::set_size_request_to_display_given_text (layer_value_label, "99", 5, 2);
85
86         layer_hbox.set_spacing (5);
87         layer_hbox.pack_start (layer_label, false, false);
88         layer_hbox.pack_start (layer_frame, false, false);
89 #if 0
90         layer_hbox.pack_start (raise_button, false, false);
91         layer_hbox.pack_start (lower_button, false, false);
92 #endif
93
94         mute_button.set_name ("AudioRegionEditorToggleButton");
95         opaque_button.set_name ("AudioRegionEditorToggleButton");
96         lock_button.set_name ("AudioRegionEditorToggleButton");
97         envelope_active_button.set_name ("AudioRegionEditorToggleButton");
98         envelope_view_button.set_name ("AudioRegionEditorToggleButton");
99
100         ARDOUR_UI::instance()->tooltips().set_tip (mute_button, _("mute this region"));
101         ARDOUR_UI::instance()->tooltips().set_tip (opaque_button, _("regions underneath this one cannot be heard"));
102         ARDOUR_UI::instance()->tooltips().set_tip (lock_button, _("prevent any changes to this region"));
103         ARDOUR_UI::instance()->tooltips().set_tip (envelope_active_button, _("use the gain envelope during playback"));
104         ARDOUR_UI::instance()->tooltips().set_tip (envelope_view_button, _("show the gain envelope"));
105         ARDOUR_UI::instance()->tooltips().set_tip (audition_button, _("audition this region"));
106
107         mute_button.unset_flags (Gtk::CAN_FOCUS);
108         opaque_button.unset_flags (Gtk::CAN_FOCUS);
109         lock_button.unset_flags (Gtk::CAN_FOCUS);
110         envelope_active_button.unset_flags (Gtk::CAN_FOCUS);
111         envelope_view_button.unset_flags (Gtk::CAN_FOCUS);
112         audition_button.unset_flags (Gtk::CAN_FOCUS);
113         
114         mute_button.set_events (mute_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
115         opaque_button.set_events (opaque_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
116         lock_button.set_events (lock_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
117         envelope_active_button.set_events (envelope_active_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
118         envelope_view_button.set_events (envelope_view_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
119         audition_button.set_events (audition_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
120
121         top_row_button_hbox.set_border_width (5);
122         top_row_button_hbox.set_spacing (5);
123         top_row_button_hbox.set_homogeneous (false);
124         top_row_button_hbox.pack_start (mute_button, false, false);
125         top_row_button_hbox.pack_start (opaque_button, false, false);
126         top_row_button_hbox.pack_start (lock_button, false, false);
127         top_row_button_hbox.pack_start (layer_hbox, false, false, 5);
128         top_row_button_hbox.pack_end (audition_button, false, false);
129         
130         top_row_hbox.pack_start (name_hbox, true, true);
131         top_row_hbox.pack_end (top_row_button_hbox, true, true);
132
133         start_label.set_name ("AudioRegionEditorLabel");
134         start_label.set_text (_("START:"));
135         end_label.set_name ("AudioRegionEditorLabel");
136         end_label.set_text (_("END:"));
137         length_label.set_name ("AudioRegionEditorLabel");
138         length_label.set_text (_("LENGTH:"));
139         
140         time_table.set_col_spacings (2);
141         time_table.set_row_spacings (5);
142         time_table.set_border_width (5);
143
144         start_alignment.set (1.0, 0.5);
145         end_alignment.set (1.0, 0.5);
146         length_alignment.set (1.0, 0.5);
147
148         start_alignment.add (start_label);
149         end_alignment.add (end_label);
150         length_alignment.add (length_label);
151
152         time_table.attach (start_alignment, 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
153         time_table.attach (start_clock, 1, 2, 0, 1, Gtk::FILL, Gtk::FILL);
154
155         time_table.attach (end_alignment, 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
156         time_table.attach (end_clock, 1, 2, 1, 2, Gtk::FILL, Gtk::FILL);
157
158         time_table.attach (length_alignment, 0, 1, 2, 3, Gtk::FILL, Gtk::FILL);
159         time_table.attach (length_clock, 1, 2, 2, 3, Gtk::FILL, Gtk::FILL);
160
161         envelope_label.set_name ("AudioRegionEditorLabel");
162
163         envelope_loop_table.set_border_width (5);
164         envelope_loop_table.set_row_spacings (2);
165         envelope_loop_table.attach (envelope_label, 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
166         envelope_loop_table.attach (envelope_active_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL);
167         envelope_loop_table.attach (envelope_view_button, 0, 1, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL);
168
169         lower_hbox.pack_start (time_table, true, true);
170         lower_hbox.pack_start (sep1, false, false);
171         lower_hbox.pack_start (envelope_loop_table, true, true);
172         lower_hbox.pack_start (sep2, false, false);
173
174         get_vbox()->pack_start (top_row_hbox, true, true);
175         get_vbox()->pack_start (sep3, false, false);
176         get_vbox()->pack_start (lower_hbox, true, true);
177
178         set_name ("AudioRegionEditorWindow");
179         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
180
181         signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (this)));
182
183         string title = _("ardour: region ");
184         title += _region->name();
185         set_title (title);
186
187         show_all();
188
189         name_changed ();
190         bounds_changed (Change (StartChanged|LengthChanged|PositionChanged));
191         envelope_active_changed ();
192         mute_changed ();
193         opacity_changed ();
194         lock_changed ();
195         layer_changed ();
196
197         XMLNode *node  = _region->extra_xml ("GUI");
198         XMLProperty *prop = 0;
199         bool showing_envelope = false;
200
201         if (node && (prop = node->property ("envelope-visible")) != 0) {
202                 if (prop->value() == "yes") {
203                         showing_envelope = true;
204                 } 
205         } 
206
207         if (showing_envelope) {
208                 envelope_view_button.set_active (true);
209         } else {
210                 envelope_view_button.set_active (false);
211         }
212
213         _region->StateChanged.connect (mem_fun(*this, &AudioRegionEditor::region_changed));
214         
215         spin_arrow_grab = false;
216         
217         connect_editor_events ();
218 }
219
220 AudioRegionEditor::~AudioRegionEditor ()
221 {
222 }
223
224 void
225 AudioRegionEditor::region_changed (Change what_changed)
226 {
227         if (what_changed & NameChanged) {
228                 name_changed ();
229         }
230         if (what_changed & BoundsChanged) {
231                 bounds_changed (what_changed);
232         }
233
234         if (what_changed & Region::OpacityChanged) {
235                 opacity_changed ();
236         }
237         if (what_changed & Region::MuteChanged) {
238                 mute_changed ();
239         }
240         if (what_changed & Region::LockChanged) {
241                 lock_changed ();
242         }
243         if (what_changed & Region::LayerChanged) {
244                 layer_changed ();
245         }
246
247         if (what_changed & AudioRegion::EnvelopeActiveChanged) {
248                 envelope_active_changed ();
249         }
250 }
251
252 gint 
253 AudioRegionEditor::bpressed (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)())
254 {
255         switch (ev->button) {
256         case 1:
257         case 2:
258         case 3:
259                 if (ev->type == GDK_BUTTON_PRESS) { /* no double clicks here */
260                         if (!spin_arrow_grab) {
261                                 // GTK2FIX probably nuke the region editor
262                                 // if ((ev->window == but->gobj()->panel)) {
263                                 // spin_arrow_grab = true;
264                                 // (this->*pmf)();
265                                 // } 
266                         } 
267                 } 
268                 break;
269         default:
270                 break;
271         }
272         return FALSE;
273 }
274
275 gint 
276 AudioRegionEditor::breleased (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)())
277 {
278         if (spin_arrow_grab) {
279                 (this->*pmf)();
280                 spin_arrow_grab = false;
281         }
282         return FALSE;
283 }
284
285 void
286 AudioRegionEditor::connect_editor_events ()
287 {
288         name_entry.signal_changed().connect (mem_fun(*this, &AudioRegionEditor::name_entry_changed));
289
290         start_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::start_clock_changed));
291         end_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::end_clock_changed));
292         length_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::length_clock_changed));
293
294         envelope_active_button.signal_button_press_event().connect (mem_fun(*this, &AudioRegionEditor::envelope_active_button_press));
295         envelope_active_button.signal_button_release_event().connect (mem_fun(*this, &AudioRegionEditor::envelope_active_button_release));
296         audition_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::audition_button_toggled));
297         envelope_view_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::envelope_view_button_toggled));
298         lock_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::lock_button_clicked));
299         mute_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::mute_button_clicked));
300         opaque_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::opaque_button_clicked));
301         raise_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::raise_button_clicked));
302         lower_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::lower_button_clicked));
303         _session.AuditionActive.connect (mem_fun(*this, &AudioRegionEditor::audition_state_changed));
304 }
305
306 void
307 AudioRegionEditor::start_clock_changed ()
308 {
309         _session.begin_reversible_command (_("change region start position"));
310
311         Playlist* const pl = _region->playlist();
312
313         if (pl) {
314                 XMLNode &before = pl->get_state();
315                 _region->set_position (start_clock.current_time(), this);
316                 XMLNode &after = pl->get_state();
317                 _session.add_command(new MementoCommand<Playlist>(*pl, &before, &after));
318         }
319
320         _session.commit_reversible_command ();
321 }
322
323 void
324 AudioRegionEditor::end_clock_changed ()
325 {
326         _session.begin_reversible_command (_("change region end position"));
327
328         Playlist* const pl = _region->playlist();
329
330         if (pl) {
331                 XMLNode &before = pl->get_state();
332                 _region->trim_end (end_clock.current_time(), this);
333                 XMLNode &after = pl->get_state();
334                 _session.add_command(new MementoCommand<Playlist>(*pl, &before, &after));
335         }
336
337         _session.commit_reversible_command ();
338
339         end_clock.set (_region->position() + _region->length(), true);
340 }
341
342 void
343 AudioRegionEditor::length_clock_changed ()
344 {
345         nframes_t frames = length_clock.current_time();
346         
347         _session.begin_reversible_command (_("change region length"));
348         
349         Playlist* const pl = _region->playlist();
350
351         if (pl) {
352                 XMLNode &before = pl->get_state();
353                 _region->trim_end (_region->position() + frames, this);
354                 XMLNode &after = pl->get_state();
355                 _session.add_command(new MementoCommand<Playlist>(*pl, &before, &after));
356         }
357
358         _session.commit_reversible_command ();
359
360         length_clock.set (_region->length());
361 }
362
363 gint
364 AudioRegionEditor::envelope_active_button_press(GdkEventButton *ev)
365 {
366         return stop_signal (envelope_active_button, "button_press_event");
367 }
368
369 gint
370 AudioRegionEditor::envelope_active_button_release (GdkEventButton *ev)
371 {
372         _region->set_envelope_active (!_region->envelope_active());
373         return stop_signal (envelope_active_button, "button_release_event");
374 }
375
376 void
377 AudioRegionEditor::envelope_view_button_toggled ()
378 {
379         bool visible = envelope_view_button.get_active ();
380
381         _region_view.set_envelope_visible (visible);
382 }
383
384 void
385 AudioRegionEditor::audition_button_toggled ()
386 {
387         if (audition_button.get_active()) {
388                 _session.audition_region (_region);
389         } else {
390                 _session.cancel_audition ();
391         }
392 }
393
394 void
395 AudioRegionEditor::raise_button_clicked ()
396 {
397         _region->raise ();
398 }
399
400 void
401 AudioRegionEditor::lower_button_clicked ()
402 {
403         _region->lower ();
404 }
405
406 void
407 AudioRegionEditor::opaque_button_clicked ()
408 {
409         bool ractive = _region->opaque();
410
411         if (opaque_button.get_active() != ractive) {
412                 _region->set_opaque (!ractive);
413         }
414 }
415
416 void
417 AudioRegionEditor::mute_button_clicked ()
418 {
419         bool ractive = _region->muted();
420
421         if (mute_button.get_active() != ractive) {
422                 _region->set_muted (!ractive);
423         }
424 }
425
426 void
427 AudioRegionEditor::lock_button_clicked ()
428 {
429         bool ractive = _region->locked();
430
431         if (lock_button.get_active() != ractive) {
432                 _region->set_locked (!ractive);
433         }
434 }
435
436 void
437 AudioRegionEditor::layer_changed ()
438 {
439         char buf[8];
440         snprintf (buf, sizeof(buf), "%d", (int) _region->layer() + 1);
441         layer_value_label.set_text (buf);
442 }
443
444 void
445 AudioRegionEditor::name_changed ()
446 {
447         if (name_entry.get_text() != _region->name()) {
448                 name_entry.set_text (_region->name());
449         }
450 }
451
452 void
453 AudioRegionEditor::lock_changed ()
454 {
455         bool yn;
456
457         if ((yn = _region->locked()) != lock_button.get_active()) {
458                 lock_button.set_active (yn);
459         }
460
461         start_clock.set_sensitive (!yn);
462         end_clock.set_sensitive (!yn);
463         length_clock.set_sensitive (!yn);
464 }
465
466 void
467 AudioRegionEditor::envelope_active_changed ()
468 {
469         bool yn;
470
471         if ((yn = _region->envelope_active()) != envelope_active_button.get_active()) {
472                 envelope_active_button.set_active (yn);
473         }
474 }
475
476 void
477 AudioRegionEditor::opacity_changed ()
478 {
479         bool yn;
480         if ((yn = _region->opaque()) != opaque_button.get_active()) {
481                 opaque_button.set_active (yn);
482         }
483 }
484
485 void
486 AudioRegionEditor::mute_changed ()
487 {
488         bool yn;
489         if ((yn = _region->muted()) != mute_button.get_active()) {
490                 mute_button.set_active (yn);
491         }
492 }
493
494 void
495 AudioRegionEditor::bounds_changed (Change what_changed)
496 {
497         if (what_changed & Change ((PositionChanged|LengthChanged))) {
498                 start_clock.set (_region->position(), true);
499                 end_clock.set (_region->position() + _region->length(), true);
500                 length_clock.set (_region->length(), true);
501         }
502 }
503
504 void
505 AudioRegionEditor::activation ()
506 {
507         
508 }       
509
510 void
511 AudioRegionEditor::name_entry_changed ()
512 {
513         if (name_entry.get_text() != _region->name()) {
514                 _region->set_name (name_entry.get_text());
515         }
516 }
517
518 void
519 AudioRegionEditor::audition_state_changed (bool yn)
520 {
521         ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioRegionEditor::audition_state_changed), yn));
522
523         if (!yn) {
524                 audition_button.set_active (false);
525         }
526 }
527