2 Copyright (C) 2001 Paul Davis
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.
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.
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.
21 #include <pbd/memento_command.h>
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>
30 #include "audio_region_editor.h"
31 #include "audio_region_view.h"
32 #include "ardour_ui.h"
34 #include "gui_thread.h"
38 using namespace ARDOUR;
43 AudioRegionEditor::AudioRegionEditor (Session& s, boost::shared_ptr<AudioRegion> r, AudioRegionView& rv)
47 name_label (_("NAME:")),
48 audition_button (_("play")),
50 start_clock ("AudioRegionEditorClock", true),
51 end_clock ("AudioRegionEditorClock", true),
52 length_clock ("AudioRegionEditorClock", true, true),
53 sync_offset_clock ("AudioRegionEditorClock", true, true)
56 start_clock.set_session (&_session);
57 end_clock.set_session (&_session);
58 length_clock.set_session (&_session);
60 name_entry.set_name ("AudioRegionEditorEntry");
61 name_label.set_name ("AudioRegionEditorLabel");
63 name_hbox.set_spacing (5);
64 name_hbox.pack_start (name_label, false, false);
65 name_hbox.pack_start (name_entry, false, false);
67 ARDOUR_UI::instance()->tooltips().set_tip (audition_button, _("audition this region"));
69 audition_button.unset_flags (Gtk::CAN_FOCUS);
71 audition_button.set_events (audition_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
73 top_row_button_hbox.set_border_width (5);
74 top_row_button_hbox.set_spacing (5);
75 top_row_button_hbox.set_homogeneous (false);
76 top_row_button_hbox.pack_end (audition_button, false, false);
78 top_row_hbox.pack_start (name_hbox, true, true);
79 top_row_hbox.pack_end (top_row_button_hbox, true, true);
81 start_label.set_name ("AudioRegionEditorLabel");
82 start_label.set_text (_("START:"));
83 end_label.set_name ("AudioRegionEditorLabel");
84 end_label.set_text (_("END:"));
85 length_label.set_name ("AudioRegionEditorLabel");
86 length_label.set_text (_("LENGTH:"));
88 time_table.set_col_spacings (2);
89 time_table.set_row_spacings (5);
90 time_table.set_border_width (5);
92 start_alignment.set (1.0, 0.5);
93 end_alignment.set (1.0, 0.5);
94 length_alignment.set (1.0, 0.5);
96 start_alignment.add (start_label);
97 end_alignment.add (end_label);
98 length_alignment.add (length_label);
100 time_table.attach (start_alignment, 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
101 time_table.attach (start_clock, 1, 2, 0, 1, Gtk::FILL, Gtk::FILL);
103 time_table.attach (end_alignment, 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
104 time_table.attach (end_clock, 1, 2, 1, 2, Gtk::FILL, Gtk::FILL);
106 time_table.attach (length_alignment, 0, 1, 2, 3, Gtk::FILL, Gtk::FILL);
107 time_table.attach (length_clock, 1, 2, 2, 3, Gtk::FILL, Gtk::FILL);
109 lower_hbox.pack_start (time_table, true, true);
110 lower_hbox.pack_start (sep1, false, false);
111 lower_hbox.pack_start (sep2, false, false);
113 get_vbox()->pack_start (top_row_hbox, true, true);
114 get_vbox()->pack_start (sep3, false, false);
115 get_vbox()->pack_start (lower_hbox, true, true);
117 set_name ("AudioRegionEditorWindow");
118 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
120 signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (this)));
122 string title = _("ardour: region ");
123 title += _region->name();
129 bounds_changed (Change (StartChanged|LengthChanged|PositionChanged));
131 _region->StateChanged.connect (mem_fun(*this, &AudioRegionEditor::region_changed));
133 spin_arrow_grab = false;
135 connect_editor_events ();
138 AudioRegionEditor::~AudioRegionEditor ()
143 AudioRegionEditor::region_changed (Change what_changed)
145 if (what_changed & NameChanged) {
148 if (what_changed & BoundsChanged) {
149 bounds_changed (what_changed);
154 AudioRegionEditor::bpressed (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)())
156 switch (ev->button) {
160 if (ev->type == GDK_BUTTON_PRESS) { /* no double clicks here */
161 if (!spin_arrow_grab) {
162 // GTK2FIX probably nuke the region editor
163 // if ((ev->window == but->gobj()->panel)) {
164 // spin_arrow_grab = true;
177 AudioRegionEditor::breleased (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)())
179 if (spin_arrow_grab) {
181 spin_arrow_grab = false;
187 AudioRegionEditor::connect_editor_events ()
189 name_entry.signal_changed().connect (mem_fun(*this, &AudioRegionEditor::name_entry_changed));
191 start_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::start_clock_changed));
192 end_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::end_clock_changed));
193 length_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::length_clock_changed));
195 audition_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::audition_button_toggled));
196 _session.AuditionActive.connect (mem_fun(*this, &AudioRegionEditor::audition_state_changed));
200 AudioRegionEditor::start_clock_changed ()
202 _session.begin_reversible_command (_("change region start position"));
204 Playlist* const pl = _region->playlist();
207 XMLNode &before = pl->get_state();
208 _region->set_position (start_clock.current_time(), this);
209 XMLNode &after = pl->get_state();
210 _session.add_command(new MementoCommand<Playlist>(*pl, &before, &after));
213 _session.commit_reversible_command ();
217 AudioRegionEditor::end_clock_changed ()
219 _session.begin_reversible_command (_("change region end position"));
221 Playlist* const pl = _region->playlist();
224 XMLNode &before = pl->get_state();
225 _region->trim_end (end_clock.current_time(), this);
226 XMLNode &after = pl->get_state();
227 _session.add_command(new MementoCommand<Playlist>(*pl, &before, &after));
230 _session.commit_reversible_command ();
232 end_clock.set (_region->position() + _region->length(), true);
236 AudioRegionEditor::length_clock_changed ()
238 nframes_t frames = length_clock.current_time();
240 _session.begin_reversible_command (_("change region length"));
242 Playlist* const pl = _region->playlist();
245 XMLNode &before = pl->get_state();
246 _region->trim_end (_region->position() + frames, this);
247 XMLNode &after = pl->get_state();
248 _session.add_command(new MementoCommand<Playlist>(*pl, &before, &after));
251 _session.commit_reversible_command ();
253 length_clock.set (_region->length());
257 AudioRegionEditor::audition_button_toggled ()
259 if (audition_button.get_active()) {
260 _session.audition_region (_region);
262 _session.cancel_audition ();
267 AudioRegionEditor::name_changed ()
269 if (name_entry.get_text() != _region->name()) {
270 name_entry.set_text (_region->name());
275 AudioRegionEditor::bounds_changed (Change what_changed)
277 if (what_changed & Change ((PositionChanged|LengthChanged))) {
278 start_clock.set (_region->position(), true);
279 end_clock.set (_region->position() + _region->length(), true);
280 length_clock.set (_region->length(), true);
285 AudioRegionEditor::activation ()
291 AudioRegionEditor::name_entry_changed ()
293 if (name_entry.get_text() != _region->name()) {
294 _region->set_name (name_entry.get_text());
299 AudioRegionEditor::audition_state_changed (bool yn)
301 ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioRegionEditor::audition_state_changed), yn));
304 audition_button.set_active (false);