2 Copyright (C) 2000-2007 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.
20 /* Note: public Editor methods are documented in public_editor.h */
28 #include <boost/none.hpp>
30 #include <sigc++/bind.h>
32 #include <pbd/convert.h>
33 #include <pbd/error.h>
34 #include <pbd/enumwriter.h>
35 #include <pbd/memento_command.h>
37 #include <glibmm/miscutils.h>
38 #include <gtkmm/image.h>
39 #include <gdkmm/color.h>
40 #include <gdkmm/bitmap.h>
42 #include <gtkmm2ext/grouped_buttons.h>
43 #include <gtkmm2ext/gtk_ui.h>
44 #include <gtkmm2ext/tearoff.h>
45 #include <gtkmm2ext/utils.h>
46 #include <gtkmm2ext/window_title.h>
47 #include <gtkmm2ext/choice.h>
49 #include <ardour/audio_track.h>
50 #include <ardour/audio_diskstream.h>
51 #include <ardour/plugin_manager.h>
52 #include <ardour/location.h>
53 #include <ardour/audioplaylist.h>
54 #include <ardour/audioregion.h>
55 #include <ardour/midi_region.h>
56 #include <ardour/session_route.h>
57 #include <ardour/session_directory.h>
58 #include <ardour/session_state_utils.h>
59 #include <ardour/tempo.h>
60 #include <ardour/utils.h>
61 #include <ardour/profile.h>
63 #include <control_protocol/control_protocol.h>
65 #include "ardour_ui.h"
69 #include "playlist_selector.h"
70 #include "audio_region_view.h"
71 #include "rgb_macros.h"
72 #include "selection.h"
73 #include "audio_streamview.h"
74 #include "time_axis_view.h"
75 #include "audio_time_axis.h"
77 #include "crossfade_view.h"
79 #include "public_editor.h"
80 #include "crossfade_edit.h"
81 #include "canvas_impl.h"
84 #include "gui_thread.h"
87 #include "analysis_window.h"
93 #include "imageframe_socket_handler.h"
98 using namespace ARDOUR;
101 using namespace Glib;
102 using namespace Gtkmm2ext;
103 using namespace Editing;
105 using PBD::internationalize;
108 const double Editor::timebar_height = 15.0;
110 #include "editor_xpms"
112 static const gchar *_snap_type_strings[] = {
136 static const gchar *_snap_mode_strings[] = {
142 static const gchar *_edit_point_strings[] = {
149 static const gchar *_zoom_focus_strings[] = {
159 /* Soundfile drag-n-drop */
161 Gdk::Cursor* Editor::cross_hair_cursor = 0;
162 Gdk::Cursor* Editor::selector_cursor = 0;
163 Gdk::Cursor* Editor::trimmer_cursor = 0;
164 Gdk::Cursor* Editor::grabber_cursor = 0;
165 Gdk::Cursor* Editor::zoom_cursor = 0;
166 Gdk::Cursor* Editor::time_fx_cursor = 0;
167 Gdk::Cursor* Editor::fader_cursor = 0;
168 Gdk::Cursor* Editor::speaker_cursor = 0;
169 Gdk::Cursor* Editor::midi_pencil_cursor = 0;
170 Gdk::Cursor* Editor::midi_select_cursor = 0;
171 Gdk::Cursor* Editor::midi_erase_cursor = 0;
172 Gdk::Cursor* Editor::wait_cursor = 0;
173 Gdk::Cursor* Editor::timebar_cursor = 0;
176 show_me_the_size (Requisition* r, const char* what)
178 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
183 /* time display buttons */
185 minsec_label (_("Mins:Secs")),
186 bbt_label (_("Bars:Beats")),
187 smpte_label (_("Timecode")),
188 frame_label (_("Frames")),
189 tempo_label (_("Tempo")),
190 meter_label (_("Meter")),
191 mark_label (_("Location Markers")),
192 range_mark_label (_("Range Markers")),
193 transport_mark_label (_("Loop/Punch Ranges")),
195 edit_packer (3, 3, false),
197 /* the values here don't matter: layout widgets
198 reset them as needed.
201 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
202 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
205 marker_tempo_lines(0),
207 /* tool bar related */
209 edit_point_clock (X_("editpoint"), false, X_("EditPointClock"), true),
210 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
212 toolbar_selection_clock_table (2,3),
214 automation_mode_button (_("mode")),
215 global_automation_button (_("automation")),
218 image_socket_listener(0),
223 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
228 /* we are a singleton */
230 PublicEditor::_instance = this;
234 selection = new Selection (this);
235 cut_buffer = new Selection (this);
237 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
238 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
239 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
240 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
241 selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed));
243 clicked_regionview = 0;
244 clicked_axisview = 0;
245 clicked_routeview = 0;
246 clicked_crossfadeview = 0;
247 clicked_control_point = 0;
248 latest_regionview = 0;
249 last_update_frame = 0;
251 current_mixer_strip = 0;
252 current_bbt_points = 0;
254 snap_type_strings = I18N (_snap_type_strings);
255 snap_mode_strings = I18N (_snap_mode_strings);
256 zoom_focus_strings = I18N (_zoom_focus_strings);
257 edit_point_strings = I18N (_edit_point_strings);
259 snap_type = SnapToFrame;
260 set_snap_to (snap_type);
262 snap_mode = SnapNormal;
263 set_snap_mode (snap_mode);
265 _edit_point = EditAtMouse;
266 set_edit_point_preference (_edit_point);
268 snap_threshold = 5.0;
269 bbt_beat_subdivision = 4;
272 autoscroll_active = false;
273 autoscroll_timeout_tag = -1;
274 interthread_progress_window = 0;
281 current_interthread_info = 0;
282 _show_measures = true;
283 _show_waveforms = true;
284 _show_waveforms_recording = true;
285 first_action_message = 0;
287 export_range_markers_dialog = 0;
288 show_gain_after_trim = false;
289 ignore_route_list_reorder = false;
290 no_route_list_redisplay = false;
291 verbose_cursor_on = true;
292 route_removal = false;
293 show_automatic_regions_in_region_list = true;
294 region_list_sort_type = (Editing::RegionListSortType) 0;
295 have_pending_keyboard_selection = false;
296 _follow_playhead = true;
297 _xfade_visibility = true;
298 editor_ruler_menu = 0;
299 no_ruler_shown_update = false;
300 edit_group_list_menu = 0;
302 region_list_menu = 0;
304 start_end_marker_menu = 0;
305 range_marker_menu = 0;
306 marker_menu_item = 0;
308 transport_marker_menu = 0;
309 new_transport_marker_menu = 0;
310 editor_mixer_strip_width = Wide;
311 show_editor_mixer_when_tracks_arrive = false;
312 region_edit_menu_split_multichannel_item = 0;
313 region_edit_menu_split_item = 0;
316 ignore_mouse_mode_toggle = false;
317 ignore_midi_edit_mode_toggle = false;
318 current_stepping_trackview = 0;
320 entered_regionview = 0;
322 clear_entered_track = false;
323 _new_regionviews_show_envelope = false;
324 current_timestretch = 0;
325 in_edit_group_row_change = false;
326 last_canvas_frame = 0;
328 button_release_can_deselect = true;
329 canvas_idle_queued = false;
330 _dragging_playhead = false;
331 _dragging_edit_point = false;
332 _dragging_hscrollbar = false;
334 scrubbing_direction = 0;
337 ignore_route_order_sync = false;
339 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
340 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
341 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
342 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
343 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
345 range_marker_drag_rect = 0;
346 marker_drag_line = 0;
347 tempo_map_change_idle_handler_id = -1;
348 canvas_hroizontally_scrolled_handler_id = -1;
349 set_midi_edit_mode (MidiEditPencil, true);
350 set_mouse_mode (MouseObject, true);
352 frames_per_unit = 2048; /* too early to use reset_zoom () */
353 reset_hscrollbar_stepping ();
355 zoom_focus = ZoomFocusLeft;
356 set_zoom_focus (ZoomFocusLeft);
357 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
359 initialize_rulers ();
360 initialize_canvas ();
362 edit_controls_vbox.set_spacing (0);
363 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
364 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
366 track_canvas.set_hadjustment (horizontal_adjustment);
367 track_canvas.set_vadjustment (vertical_adjustment);
368 time_canvas.set_hadjustment (horizontal_adjustment);
370 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
371 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
373 controls_layout.add (edit_controls_vbox);
374 controls_layout.set_name ("EditControlsBase");
375 controls_layout.add_events (Gdk::SCROLL_MASK);
376 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
378 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
379 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
380 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
382 edit_vscrollbar.set_adjustment (vertical_adjustment);
383 edit_hscrollbar.set_adjustment (horizontal_adjustment);
385 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
386 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
387 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
389 edit_hscrollbar.set_name ("EditorHScrollbar");
393 setup_midi_toolbar ();
395 edit_point_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_point_clock_changed));
397 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
398 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
399 0.0, 1.0, 100.0, 1.0));
400 pad_line_1->property_color_rgba() = 0xFF0000FF;
404 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
405 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
406 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
407 time_canvas_vbox.pack_start (*frames_ruler, false, false);
408 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
409 time_canvas_vbox.pack_start (time_canvas, true, true);
410 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 5);
412 bbt_label.set_name ("EditorTimeButton");
413 bbt_label.set_size_request (-1, (int)timebar_height);
414 bbt_label.set_alignment (1.0, 0.5);
415 bbt_label.set_padding (5,0);
416 minsec_label.set_name ("EditorTimeButton");
417 minsec_label.set_size_request (-1, (int)timebar_height);
418 minsec_label.set_alignment (1.0, 0.5);
419 minsec_label.set_padding (5,0);
420 smpte_label.set_name ("EditorTimeButton");
421 smpte_label.set_size_request (-1, (int)timebar_height);
422 smpte_label.set_alignment (1.0, 0.5);
423 smpte_label.set_padding (5,0);
424 frame_label.set_name ("EditorTimeButton");
425 frame_label.set_size_request (-1, (int)timebar_height);
426 frame_label.set_alignment (1.0, 0.5);
427 frame_label.set_padding (5,0);
428 tempo_label.set_name ("EditorTimeButton");
429 tempo_label.set_size_request (-1, (int)timebar_height);
430 tempo_label.set_alignment (1.0, 0.5);
431 tempo_label.set_padding (5,0);
432 meter_label.set_name ("EditorTimeButton");
433 meter_label.set_size_request (-1, (int)timebar_height);
434 meter_label.set_alignment (1.0, 0.5);
435 meter_label.set_padding (5,0);
436 mark_label.set_name ("EditorTimeButton");
437 mark_label.set_size_request (-1, (int)timebar_height);
438 mark_label.set_alignment (1.0, 0.5);
439 mark_label.set_padding (5,0);
440 range_mark_label.set_name ("EditorTimeButton");
441 range_mark_label.set_size_request (-1, (int)timebar_height);
442 range_mark_label.set_alignment (1.0, 0.5);
443 range_mark_label.set_padding (5,0);
444 transport_mark_label.set_name ("EditorTimeButton");
445 transport_mark_label.set_size_request (-1, (int)timebar_height);
446 transport_mark_label.set_alignment (1.0, 0.5);
447 transport_mark_label.set_padding (5,0);
449 time_button_vbox.pack_start (minsec_label, false, false);
450 time_button_vbox.pack_start (smpte_label, false, false);
451 time_button_vbox.pack_start (frame_label, false, false);
452 time_button_vbox.pack_start (bbt_label, false, false);
453 time_button_vbox.pack_start (meter_label, false, false);
454 time_button_vbox.pack_start (tempo_label, false, false);
455 time_button_vbox.pack_start (mark_label, false, false);
457 time_button_event_box.add (time_button_vbox);
458 time_button_event_box.set_name ("TimebarLabelBase");
459 time_button_frame.set_shadow_type (Gtk::SHADOW_NONE);
461 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
462 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
464 time_button_frame.add (time_button_event_box);
465 time_button_frame.set_name ("TimebarLabelBase");
466 time_button_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
468 /* these enable us to have a dedicated window (for cursor setting, etc.)
469 for the canvas areas.
472 track_canvas_event_box.add (track_canvas);
474 time_canvas_event_box.add (time_canvas_vbox);
475 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
477 edit_packer.set_col_spacings (0);
478 edit_packer.set_row_spacings (0);
479 edit_packer.set_homogeneous (false);
480 edit_packer.set_border_width (0);
481 edit_packer.set_name ("EditorWindow");
483 edit_packer.attach (edit_vscrollbar, 3, 4, 1, 2, FILL, FILL|EXPAND, 0, 0);
485 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, SHRINK, 0, 0);
486 edit_packer.attach (time_canvas_event_box, 2, 4, 0, 1, FILL|EXPAND, FILL, 0, 0);
488 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
489 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
491 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
492 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
494 bottom_hbox.set_border_width (2);
495 bottom_hbox.set_spacing (3);
497 route_display_model = ListStore::create(route_display_columns);
498 route_list_display.set_model (route_display_model);
499 route_list_display.append_column (_("Show"), route_display_columns.visible);
500 route_list_display.append_column (_("Name"), route_display_columns.text);
501 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
502 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
503 route_list_display.set_headers_visible (true);
504 route_list_display.set_name ("TrackListDisplay");
505 route_list_display.get_selection()->set_mode (SELECTION_NONE);
506 route_list_display.set_reorderable (true);
507 route_list_display.set_size_request (100,-1);
509 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
510 route_list_visible_cell->property_activatable() = true;
511 route_list_visible_cell->property_radio() = false;
513 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
514 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
516 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
518 route_list_scroller.add (route_list_display);
519 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
521 group_model = ListStore::create(group_columns);
522 edit_group_display.set_model (group_model);
523 edit_group_display.append_column (_("Name"), group_columns.text);
524 edit_group_display.append_column (_("Active"), group_columns.is_active);
525 edit_group_display.append_column (_("Show"), group_columns.is_visible);
526 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
527 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
528 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
529 edit_group_display.get_column (0)->set_expand (true);
530 edit_group_display.get_column (1)->set_expand (false);
531 edit_group_display.get_column (2)->set_expand (false);
532 edit_group_display.set_headers_visible (true);
534 /* name is directly editable */
536 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
537 name_cell->property_editable() = true;
538 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
540 /* use checkbox for the active + visible columns */
542 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
543 active_cell->property_activatable() = true;
544 active_cell->property_radio() = false;
546 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
547 active_cell->property_activatable() = true;
548 active_cell->property_radio() = false;
550 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
552 edit_group_display.set_name ("EditGroupList");
553 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
554 edit_group_display.set_headers_visible (true);
555 edit_group_display.set_reorderable (false);
556 edit_group_display.set_rules_hint (true);
557 edit_group_display.set_size_request (75, -1);
559 edit_group_display_scroller.add (edit_group_display);
560 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
562 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
564 VBox* edit_group_display_packer = manage (new VBox());
565 HBox* edit_group_display_button_box = manage (new HBox());
566 edit_group_display_button_box->set_homogeneous (true);
568 Button* edit_group_add_button = manage (new Button ());
569 Button* edit_group_remove_button = manage (new Button ());
573 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
575 edit_group_add_button->add (*w);
577 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
579 edit_group_remove_button->add (*w);
581 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
582 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
584 edit_group_display_button_box->pack_start (*edit_group_add_button);
585 edit_group_display_button_box->pack_start (*edit_group_remove_button);
587 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
588 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
590 region_list_display.set_size_request (100, -1);
591 region_list_display.set_name ("RegionListDisplay");
593 region_list_model = TreeStore::create (region_list_columns);
594 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
595 region_list_model->set_sort_column (0, SORT_ASCENDING);
597 region_list_display.set_model (region_list_model);
598 region_list_display.append_column (_("Regions"), region_list_columns.name);
599 region_list_display.set_headers_visible (false);
601 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
603 TreeViewColumn* tv_col = region_list_display.get_column(0);
604 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
605 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
606 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
608 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
609 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
611 /* setup DnD handling */
613 list<TargetEntry> region_list_target_table;
615 region_list_target_table.push_back (TargetEntry ("text/plain"));
616 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
617 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
619 region_list_display.add_drop_targets (region_list_target_table);
620 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
622 region_list_scroller.add (region_list_display);
623 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
625 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
626 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
627 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
628 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
629 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
630 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
632 named_selection_scroller.add (named_selection_display);
633 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
635 named_selection_model = TreeStore::create (named_selection_columns);
636 named_selection_display.set_model (named_selection_model);
637 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
638 named_selection_display.set_headers_visible (false);
639 named_selection_display.set_size_request (100, -1);
640 named_selection_display.set_name ("NamedSelectionDisplay");
642 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
643 named_selection_display.set_size_request (100, -1);
644 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
645 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
646 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
650 snapshot_display_model = ListStore::create (snapshot_display_columns);
651 snapshot_display.set_model (snapshot_display_model);
652 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
653 snapshot_display.set_name ("SnapshotDisplay");
654 snapshot_display.set_size_request (75, -1);
655 snapshot_display.set_headers_visible (false);
656 snapshot_display.set_reorderable (false);
657 snapshot_display_scroller.add (snapshot_display);
658 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
660 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
661 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
665 nlabel = manage (new Label (_("Regions")));
666 nlabel->set_angle (-90);
667 the_notebook.append_page (region_list_scroller, *nlabel);
668 nlabel = manage (new Label (_("Tracks/Busses")));
669 nlabel->set_angle (-90);
670 the_notebook.append_page (route_list_scroller, *nlabel);
671 nlabel = manage (new Label (_("Snapshots")));
672 nlabel->set_angle (-90);
673 the_notebook.append_page (snapshot_display_scroller, *nlabel);
674 nlabel = manage (new Label (_("Edit Groups")));
675 nlabel->set_angle (-90);
676 the_notebook.append_page (*edit_group_display_packer, *nlabel);
677 nlabel = manage (new Label (_("Chunks")));
678 nlabel->set_angle (-90);
679 the_notebook.append_page (named_selection_scroller, *nlabel);
681 the_notebook.set_show_tabs (true);
682 the_notebook.set_scrollable (true);
683 the_notebook.popup_enable ();
684 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
686 post_maximal_editor_width = 0;
687 post_maximal_pane_position = 0;
688 edit_pane.pack1 (edit_packer, true, true);
689 edit_pane.pack2 (the_notebook, false, true);
691 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
693 top_hbox.pack_start (toolbar_frame, false, true);
694 top_hbox.pack_start (midi_toolbar_frame, false, true);
696 HBox *hbox = manage (new HBox);
697 hbox->pack_start (edit_pane, true, true);
699 global_vpacker.pack_start (top_hbox, false, false);
700 global_vpacker.pack_start (*hbox, true, true);
702 global_hpacker.pack_start (global_vpacker, true, true);
704 set_name ("EditorWindow");
705 add_accel_group (ActionManager::ui_manager->get_accel_group());
707 status_bar_hpacker.show ();
709 vpacker.pack_end (status_bar_hpacker, false, false);
710 vpacker.pack_end (global_hpacker, true, true);
712 /* register actions now so that set_state() can find them and set toggles/checks etc */
716 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
719 _playlist_selector = new PlaylistSelector();
720 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
722 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
726 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
727 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
729 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
730 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
732 nudge_forward_button.set_name ("TransportButton");
733 nudge_backward_button.set_name ("TransportButton");
735 fade_context_menu.set_name ("ArdourContextMenu");
737 /* icons, titles, WM stuff */
739 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
740 Glib::RefPtr<Gdk::Pixbuf> icon;
742 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
743 window_icons.push_back (icon);
745 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
746 window_icons.push_back (icon);
748 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
749 window_icons.push_back (icon);
751 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
752 window_icons.push_back (icon);
754 if (!window_icons.empty()) {
755 set_icon_list (window_icons);
756 set_default_icon_list (window_icons);
759 WindowTitle title(Glib::get_application_name());
760 title += _("Editor");
761 set_title (title.get_string());
762 set_wmclass (X_("ardour_editor"), "Ardour");
765 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
767 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
768 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
770 /* allow external control surfaces/protocols to do various things */
772 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
773 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
774 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
775 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
777 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
778 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
787 if(image_socket_listener)
789 if(image_socket_listener->is_connected())
791 image_socket_listener->close_connection() ;
794 delete image_socket_listener ;
795 image_socket_listener = 0 ;
801 Editor::add_toplevel_controls (Container& cont)
803 vpacker.pack_start (cont, false, false);
808 Editor::catch_vanishing_regionview (RegionView *rv)
810 /* note: the selection will take care of the vanishing
811 audioregionview by itself.
814 if (clicked_regionview == rv) {
815 clicked_regionview = 0;
818 if (entered_regionview == rv) {
819 set_entered_regionview (0);
824 Editor::set_entered_regionview (RegionView* rv)
826 if (rv == entered_regionview) {
830 if (entered_regionview) {
831 entered_regionview->exited ();
834 if ((entered_regionview = rv) != 0) {
835 entered_regionview->entered ();
840 Editor::set_entered_track (TimeAxisView* tav)
843 entered_track->exited ();
846 if ((entered_track = tav) != 0) {
847 entered_track->entered ();
852 Editor::show_window ()
854 show_all_children ();
856 /* re-hide editor list if necessary */
857 editor_list_button_toggled ();
859 /* now reset all audio_time_axis heights, because widgets might need
865 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
866 tv = (static_cast<TimeAxisView*>(*i));
874 Editor::tie_vertical_scrolling ()
876 double y1 = vertical_adjustment.get_value();
878 playhead_cursor->set_y_axis (y1);
880 logo_item->property_y() = y1;
883 controls_layout.get_vadjustment()->set_value (y1);
886 /* the way idle updates and immediate window flushing work on GTK-Quartz
887 requires that we force an immediate redraw right here. The controls
888 layout will do the same all by itself, as does the canvas widget, but
889 most of the time, the canvas itself hasn't updated itself because its
890 idle handler hasn't run. consequently, the call that its layout makes
891 to gdk_window_process_updates() finds nothing to do. here, we force
892 the update to happen, then request a flush of the new window state.
894 track_canvas.update_now ();
895 gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
900 Editor::instant_save ()
902 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
907 session->add_instant_xml(get_state());
909 Config->add_instant_xml(get_state());
914 Editor::edit_point_clock_changed()
916 if (_dragging_edit_point) {
920 if (selection->markers.empty()) {
925 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
931 loc->move_to (edit_point_clock.current_time());
935 Editor::zoom_adjustment_changed ()
941 double fpu = zoom_range_clock.current_duration() / canvas_width;
945 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
946 } else if (fpu > session->current_end_frame() / canvas_width) {
947 fpu = session->current_end_frame() / canvas_width;
948 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
955 Editor::control_scroll (float fraction)
957 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
963 double step = fraction * current_page_frames();
966 _control_scroll_target is an optional<T>
968 it acts like a pointer to an nframes_t, with
969 a operator conversion to boolean to check
970 that it has a value could possibly use
971 playhead_cursor->current_frame to store the
972 value and a boolean in the class to know
973 when it's out of date
976 if (!_control_scroll_target) {
977 _control_scroll_target = session->transport_frame();
978 _dragging_playhead = true;
981 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
982 *_control_scroll_target = 0;
983 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
984 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
986 *_control_scroll_target += (nframes_t) floor (step);
989 /* move visuals, we'll catch up with it later */
991 playhead_cursor->set_position (*_control_scroll_target);
992 UpdateAllTransportClocks (*_control_scroll_target);
994 if (*_control_scroll_target > (current_page_frames() / 2)) {
995 /* try to center PH in window */
996 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1002 Now we do a timeout to actually bring the session to the right place
1003 according to the playhead. This is to avoid reading disk buffers on every
1004 call to control_scroll, which is driven by ScrollTimeline and therefore
1005 probably by a control surface wheel which can generate lots of events.
1007 /* cancel the existing timeout */
1009 control_scroll_connection.disconnect ();
1011 /* add the next timeout */
1013 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1017 Editor::deferred_control_scroll (nframes_t target)
1019 session->request_locate (*_control_scroll_target, session->transport_rolling());
1020 // reset for next stream
1021 _control_scroll_target = boost::none;
1022 _dragging_playhead = false;
1027 Editor::on_realize ()
1029 Window::on_realize ();
1034 Editor::start_scrolling ()
1036 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1037 (mem_fun(*this, &Editor::update_current_screen));
1041 Editor::stop_scrolling ()
1043 scroll_connection.disconnect ();
1047 Editor::map_position_change (nframes_t frame)
1049 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1051 if (session == 0 || !_follow_playhead) {
1055 center_screen (frame);
1056 playhead_cursor->set_position (frame);
1060 Editor::center_screen (nframes_t frame)
1062 double page = canvas_width * frames_per_unit;
1064 /* if we're off the page, then scroll.
1067 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1068 center_screen_internal (frame, page);
1073 Editor::center_screen_internal (nframes_t frame, float page)
1078 frame -= (nframes_t) page;
1083 reset_x_origin (frame);
1087 Editor::handle_new_duration ()
1089 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1091 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1093 if (new_end > last_canvas_frame) {
1094 last_canvas_frame = new_end;
1095 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1096 reset_scrolling_region ();
1099 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1103 Editor::update_title_s (const string & snap_name)
1105 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1111 Editor::update_title ()
1113 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1116 bool dirty = session->dirty();
1118 string session_name;
1120 if (session->snap_name() != session->name()) {
1121 session_name = session->snap_name();
1123 session_name = session->name();
1127 session_name = "*" + session_name;
1130 WindowTitle title(session_name);
1131 title += Glib::get_application_name();
1132 set_title (title.get_string());
1137 Editor::connect_to_session (Session *t)
1141 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1144 /* catch up with the playhead */
1146 session->request_locate (playhead_cursor->current_frame);
1148 if (first_action_message) {
1149 first_action_message->hide();
1154 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1155 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1157 /* These signals can all be emitted by a non-GUI thread. Therefore the
1158 handlers for them must not attempt to directly interact with the GUI,
1159 but use Gtkmm2ext::UI::instance()->call_slot();
1162 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1163 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1164 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1165 session_connections.push_back (session->RegionAdded.connect (mem_fun(*this, &Editor::handle_new_region)));
1166 session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed)));
1167 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1168 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1169 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1170 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1171 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1172 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1173 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1174 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1175 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1177 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1179 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1181 edit_groups_changed ();
1183 edit_point_clock.set_session (session);
1184 zoom_range_clock.set_session (session);
1185 _playlist_selector->set_session (session);
1186 nudge_clock.set_session (session);
1189 if (analysis_window != 0)
1190 analysis_window->set_session (session);
1193 Location* loc = session->locations()->auto_loop_location();
1195 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1196 if (loc->start() == loc->end()) {
1197 loc->set_end (loc->start() + 1);
1199 session->locations()->add (loc, false);
1200 session->set_auto_loop_location (loc);
1203 loc->set_name (_("Loop"));
1206 loc = session->locations()->auto_punch_location();
1208 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1209 if (loc->start() == loc->end()) {
1210 loc->set_end (loc->start() + 1);
1212 session->locations()->add (loc, false);
1213 session->set_auto_punch_location (loc);
1216 loc->set_name (_("Punch"));
1219 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1221 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1223 refresh_location_display ();
1224 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1225 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1226 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1227 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1228 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1231 sfbrowser->set_session (session);
1234 handle_new_duration ();
1236 redisplay_regions ();
1237 redisplay_named_selections ();
1238 redisplay_snapshots ();
1240 initial_route_list_display ();
1242 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1243 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1246 restore_ruler_visibility ();
1247 //tempo_map_changed (Change (0));
1248 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1252 /* don't show master bus in a new session */
1254 if (ARDOUR_UI::instance()->session_is_new ()) {
1256 TreeModel::Children rows = route_display_model->children();
1257 TreeModel::Children::iterator i;
1259 no_route_list_redisplay = true;
1261 for (i = rows.begin(); i != rows.end(); ++i) {
1262 TimeAxisView *tv = (*i)[route_display_columns.tv];
1263 RouteTimeAxisView *rtv;
1265 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1266 if (rtv->route()->is_master()) {
1267 route_list_display.get_selection()->unselect (i);
1272 no_route_list_redisplay = false;
1273 redisplay_route_list ();
1276 /* register for undo history */
1278 session->register_with_memento_command_factory(_id, this);
1282 Editor::build_cursors ()
1284 using namespace Gdk;
1286 Gdk::Color mbg ("#000000" ); /* Black */
1287 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1290 RefPtr<Bitmap> source, mask;
1291 source = Bitmap::create (mag_bits, mag_width, mag_height);
1292 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1293 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1296 Gdk::Color fbg ("#ffffff" );
1297 Gdk::Color ffg ("#000000" );
1300 RefPtr<Bitmap> source, mask;
1302 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1303 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1304 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1308 RefPtr<Bitmap> source, mask;
1309 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1310 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1311 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1314 grabber_cursor = new Gdk::Cursor (HAND2);
1315 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1316 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1317 selector_cursor = new Gdk::Cursor (XTERM);
1318 time_fx_cursor = new Gdk::Cursor (SIZING);
1319 wait_cursor = new Gdk::Cursor (WATCH);
1320 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1321 midi_pencil_cursor = new Gdk::Cursor (PENCIL);
1322 midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
1323 midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
1326 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1328 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1330 using namespace Menu_Helpers;
1331 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1334 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1338 MenuList& items (fade_context_menu.items());
1342 switch (item_type) {
1344 case FadeInHandleItem:
1345 if (arv->audio_region()->fade_in_active()) {
1346 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1348 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1351 items.push_back (SeparatorElem());
1353 if (Profile->get_sae()) {
1354 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1355 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1357 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1358 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1359 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1360 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1361 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1367 case FadeOutHandleItem:
1368 if (arv->audio_region()->fade_out_active()) {
1369 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1371 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1374 items.push_back (SeparatorElem());
1376 if (Profile->get_sae()) {
1377 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1378 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1380 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1381 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1382 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1383 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1384 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1390 fatal << _("programming error: ")
1391 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1396 fade_context_menu.popup (button, time);
1399 /* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
1401 Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
1403 build_track_context_menu (frame)->popup (button, time);
1407 Editor::build_track_context_menu (nframes_t frame)
1409 using namespace Menu_Helpers;
1411 Menu* menu = manage (new Menu);
1412 MenuList& edit_items = menu->items();
1415 /* Build the general `track' context menu, adding what is appropriate given
1416 the current selection */
1418 /* XXX: currently crossfades can't be selected, so we can't use the selection
1419 to decide which crossfades to mention in the menu. I believe this will
1420 change at some point. For now we have to use clicked_trackview to decide. */
1421 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1424 boost::shared_ptr<Diskstream> ds;
1425 boost::shared_ptr<Playlist> pl;
1426 boost::shared_ptr<AudioPlaylist> apl;
1428 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1430 AudioPlaylist::Crossfades xfades;
1431 apl->crossfades_at (frame, xfades);
1433 bool many = xfades.size() > 1;
1435 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1436 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1441 if (!selection->time.empty()) {
1442 add_selection_context_items (edit_items);
1445 if (!selection->regions.empty()) {
1446 add_region_context_items (edit_items);
1449 if (!selection->tracks.empty()) {
1450 add_bus_or_audio_track_context_items (edit_items);
1453 menu->set_name ("ArdourContextMenu");
1460 Editor::analyze_region_selection()
1462 if (analysis_window == 0) {
1463 analysis_window = new AnalysisWindow();
1466 analysis_window->set_session(session);
1468 analysis_window->show_all();
1471 analysis_window->set_regionmode();
1472 analysis_window->analyze();
1474 analysis_window->present();
1478 Editor::analyze_range_selection()
1480 if (analysis_window == 0) {
1481 analysis_window = new AnalysisWindow();
1484 analysis_window->set_session(session);
1486 analysis_window->show_all();
1489 analysis_window->set_rangemode();
1490 analysis_window->analyze();
1492 analysis_window->present();
1494 #endif /* FFT_ANALYSIS */
1497 /** Add context menu items relevant to crossfades.
1498 * @param edit_items List to add the items to.
1501 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1503 using namespace Menu_Helpers;
1504 Menu *xfade_menu = manage (new Menu);
1505 MenuList& items = xfade_menu->items();
1506 xfade_menu->set_name ("ArdourContextMenu");
1509 if (xfade->active()) {
1515 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1516 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1518 if (xfade->can_follow_overlap()) {
1520 if (xfade->following_overlap()) {
1521 str = _("Convert to short");
1523 str = _("Convert to full");
1526 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1530 str = xfade->out()->name();
1532 str += xfade->in()->name();
1534 str = _("Crossfade");
1537 edit_items.push_back (MenuElem (str, *xfade_menu));
1538 edit_items.push_back (SeparatorElem());
1542 Editor::xfade_edit_left_region ()
1544 if (clicked_crossfadeview) {
1545 clicked_crossfadeview->left_view.show_region_editor ();
1550 Editor::xfade_edit_right_region ()
1552 if (clicked_crossfadeview) {
1553 clicked_crossfadeview->right_view.show_region_editor ();
1557 /** Add an element to a menu, settings its sensitivity.
1558 * @param m Menu to add to.
1559 * @param e Element to add.
1560 * @param s true to make sensitive, false to make insensitive
1563 Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
1567 m.back().set_sensitive (false);
1571 /** Add context menu items relevant to regions.
1572 * @param edit_items List to add the items to.
1575 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
1577 using namespace Menu_Helpers;
1578 sigc::connection fooc;
1579 Menu *region_menu = manage (new Menu);
1580 MenuList& items = region_menu->items();
1581 region_menu->set_name ("ArdourContextMenu");
1583 items.push_back (MenuElem (_("Edit..."), mem_fun(*this, &Editor::edit_region)));
1584 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1585 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1587 Menu* sync_point_menu = manage (new Menu);
1588 MenuList& sync_point_items = sync_point_menu->items();
1589 sync_point_menu->set_name("ArdourContextMenu");
1591 sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_point)));
1592 sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
1594 items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
1596 add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
1598 add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
1600 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1603 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1606 items.push_back (SeparatorElem());
1608 items.push_back (CheckMenuElem (_("Lock")));
1609 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1610 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1612 #if FIXUP_REGION_MENU
1613 if (region->locked()) {
1615 region_lock_item->set_active();
1620 items.push_back (CheckMenuElem (_("Lock Position")));
1621 region_lock_position_item = static_cast<CheckMenuItem*>(&items.back());
1622 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_position_lock));
1623 #if FIXUP_REGION_MENU
1624 if (region->locked()) {
1626 region_lock_position_item->set_active();
1631 items.push_back (CheckMenuElem (_("Mute")));
1632 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1633 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1634 #if FIXUP_REGION_MENU
1635 if (region->muted()) {
1637 region_mute_item->set_active();
1642 if (!Profile->get_sae()) {
1643 items.push_back (CheckMenuElem (_("Opaque")));
1644 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1645 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1646 #if FIXUP_REGION_MENU
1647 if (region->opaque()) {
1649 region_opaque_item->set_active();
1655 /* We allow "Original position" if at least one region is not at its
1658 RegionSelection::iterator i = selection->regions.begin();
1659 while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
1663 add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
1665 items.push_back (SeparatorElem());
1667 /* Find out if we have a selected audio region */
1668 i = selection->regions.begin();
1669 while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
1672 const bool have_selected_audio_region = (i != selection->regions.end());
1674 if (have_selected_audio_region) {
1676 Menu* envelopes_menu = manage (new Menu);
1678 envelopes_menu->set_name ("ArdourContextMenu");
1680 #if FIXUP_REGION_MENU
1682 XXX NEED TO RESOLVE ONE v. MANY REGION ISSUE
1684 MenuList& envelopes_items = envelopes_menu->items();
1686 RegionView* rv = sv->find_view (ar);
1687 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1689 if (!Profile->get_sae()) {
1690 envelopes_items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1692 envelopes_items.push_back (CheckMenuElem (_("Envelope Visible")));
1693 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1694 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1695 if (arv->envelope_visible()) {
1697 region_envelope_visible_item->set_active (true);
1701 envelopes_items.push_back (CheckMenuElem (_("Envelope Active")));
1702 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1703 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1705 if (ar->envelope_active()) {
1707 region_envelope_active_item->set_active (true);
1711 items.push_back (SeparatorElem());
1715 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1717 #if FIXUP_REGION_MENU
1718 if (ar->scale_amplitude() != 1.0f) {
1719 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_regions)));
1721 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_regions)));
1726 /* Find out if we have a selected MIDI region */
1727 i = selection->regions.begin();
1728 while (i != selection->regions.end() && boost::dynamic_pointer_cast<MidiRegion>((*i)->region()) == 0) {
1731 const bool have_selected_midi_region = (i != selection->regions.end());
1733 if (have_selected_midi_region) {
1735 items.push_back (MenuElem (_("Quantize"), mem_fun(*this, &Editor::quantize_regions)));
1736 items.push_back (SeparatorElem());
1740 /* range related stuff */
1742 add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1744 add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1746 items.push_back (SeparatorElem());
1750 Menu *nudge_menu = manage (new Menu());
1751 MenuList& nudge_items = nudge_menu->items();
1752 nudge_menu->set_name ("ArdourContextMenu");
1754 nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1755 nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1756 nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1757 nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1759 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1761 Menu *trim_menu = manage (new Menu);
1762 MenuList& trim_items = trim_menu->items();
1763 trim_menu->set_name ("ArdourContextMenu");
1765 trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point)));
1766 trim_items.push_back (MenuElem (_("Edit point to end"), mem_fun(*this, &Editor::trim_region_to_edit_point)));
1767 trim_items.push_back (MenuElem (_("Trim To Loop"), mem_fun(*this, &Editor::trim_region_to_loop)));
1768 trim_items.push_back (MenuElem (_("Trim To Punch"), mem_fun(*this, &Editor::trim_region_to_punch)));
1770 items.push_back (MenuElem (_("Trim"), *trim_menu));
1771 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1772 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1773 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1774 items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1775 items.push_back (SeparatorElem());
1776 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1778 /* OK, stick the region submenu at the top of the list, and then add
1782 string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1783 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1786 /** Add context menu items relevant to selection ranges.
1787 * @param edit_items List to add the items to.
1790 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1792 using namespace Menu_Helpers;
1793 Menu *selection_menu = manage (new Menu);
1794 MenuList& items = selection_menu->items();
1795 selection_menu->set_name ("ArdourContextMenu");
1797 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1798 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1801 items.push_back (SeparatorElem());
1802 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1805 items.push_back (SeparatorElem());
1806 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1807 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1809 items.push_back (SeparatorElem());
1810 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1811 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1813 items.push_back (SeparatorElem());
1814 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1816 items.push_back (SeparatorElem());
1817 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1818 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1820 items.push_back (SeparatorElem());
1821 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1822 items.push_back (SeparatorElem());
1823 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1824 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1825 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1826 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1827 items.push_back (SeparatorElem());
1828 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1829 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1832 /** Add context menu items relevant to busses or audio tracks.
1833 * @param edit_items List to add the items to.
1836 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1838 using namespace Menu_Helpers;
1840 /* We add every possible action here, and de-sensitize things
1841 that aren't allowed. The sensitivity logic is a bit spread out;
1842 on the one hand I'm using things like can_cut_copy (), which is
1843 reasonably complicated and so perhaps better near the function that
1844 it expresses sensitivity for, and on the other hand checks
1845 in this function as well. You can't really have can_* for everything
1846 or the number of methods would get silly. */
1848 bool const one_selected_region = selection->regions.size() == 1;
1850 /* Count the number of selected audio tracks */
1851 int n_audio_tracks = 0;
1852 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1853 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1854 if (r && r->is_audio_track()) {
1861 Menu *play_menu = manage (new Menu);
1862 MenuList& play_items = play_menu->items();
1863 play_menu->set_name ("ArdourContextMenu");
1865 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
1866 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1867 add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1869 add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1871 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1875 Menu *select_menu = manage (new Menu);
1876 MenuList& select_items = select_menu->items();
1877 select_menu->set_name ("ArdourContextMenu");
1879 string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1881 select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1883 select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1885 str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1887 select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1889 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1890 select_items.push_back (SeparatorElem());
1892 if (n_audio_tracks) {
1893 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1894 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1897 select_items.push_back (MenuElem (_("Select All After Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1898 select_items.push_back (MenuElem (_("Select All Before Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1899 select_items.push_back (MenuElem (_("Select All After Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1900 select_items.push_back (MenuElem (_("Select All Before Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1901 select_items.push_back (MenuElem (_("Select All Between Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), false)));
1902 select_items.push_back (MenuElem (_("Select All Within Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), true)));
1903 select_items.push_back (MenuElem (_("Select Range Between Playhead & Edit Point"), mem_fun(*this, &Editor::select_range_between)));
1905 select_items.push_back (SeparatorElem());
1907 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1911 Menu *cutnpaste_menu = manage (new Menu);
1912 MenuList& cutnpaste_items = cutnpaste_menu->items();
1913 cutnpaste_menu->set_name ("ArdourContextMenu");
1915 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1916 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1917 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1919 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1921 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1923 if (n_audio_tracks) {
1924 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1925 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1927 cutnpaste_items.push_back (SeparatorElem());
1929 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1930 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1931 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1933 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1936 edit_items.push_back (SeparatorElem());
1937 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1939 if (n_audio_tracks) {
1941 Menu *track_menu = manage (new Menu);
1942 MenuList& track_items = track_menu->items();
1943 track_menu->set_name ("ArdourContextMenu");
1945 /* Adding new material */
1947 add_item_with_sensitivity (track_items, MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)), n_audio_tracks == 1);
1948 add_item_with_sensitivity (track_items, MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1952 Menu *nudge_menu = manage (new Menu());
1953 MenuList& nudge_items = nudge_menu->items();
1954 nudge_menu->set_name ("ArdourContextMenu");
1956 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1958 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1960 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1962 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1964 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1966 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1968 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1971 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1972 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1974 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1975 edit_items.push_back (MenuElem (str, *track_menu));
1979 /* CURSOR SETTING AND MARKS AND STUFF */
1982 Editor::set_snap_to (SnapType st)
1985 string str = snap_type_strings[(int) st];
1987 if (str != snap_type_selector.get_active_text()) {
1988 snap_type_selector.set_active_text (str);
1993 switch (snap_type) {
1994 case SnapToAThirtysecondBeat:
1995 case SnapToASixteenthBeat:
1996 case SnapToAEighthBeat:
1997 case SnapToAQuarterBeat:
1998 case SnapToAThirdBeat:
1999 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + (nframes_t)(canvas_width * frames_per_unit));
2000 update_tempo_based_rulers ();
2009 Editor::set_snap_mode (SnapMode mode)
2012 string str = snap_mode_strings[(int)mode];
2014 if (str != snap_mode_selector.get_active_text ()) {
2015 snap_mode_selector.set_active_text (str);
2021 Editor::set_edit_point_preference (EditPoint ep)
2024 string str = edit_point_strings[(int)ep];
2026 if (str != edit_point_selector.get_active_text ()) {
2027 edit_point_selector.set_active_text (str);
2034 Editor::set_state (const XMLNode& node)
2036 const XMLProperty* prop;
2038 int x, y, xoff, yoff;
2041 if ((prop = node.property ("id")) != 0) {
2042 _id = prop->value ();
2045 if ((geometry = find_named_node (node, "geometry")) == 0) {
2047 g.base_width = default_width;
2048 g.base_height = default_height;
2056 g.base_width = atoi(geometry->property("x_size")->value());
2057 g.base_height = atoi(geometry->property("y_size")->value());
2058 x = atoi(geometry->property("x_pos")->value());
2059 y = atoi(geometry->property("y_pos")->value());
2060 xoff = atoi(geometry->property("x_off")->value());
2061 yoff = atoi(geometry->property("y_off")->value());
2064 set_default_size (g.base_width, g.base_height);
2067 if (session && (prop = node.property ("playhead"))) {
2068 nframes_t pos = atol (prop->value().c_str());
2069 playhead_cursor->set_position (pos);
2071 playhead_cursor->set_position (0);
2073 /* reset_x_origin() doesn't work right here, since the old
2074 position may be zero already, and it does nothing in such
2079 horizontal_adjustment.set_value (0);
2082 if ((prop = node.property ("mixer-width"))) {
2083 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2086 if ((prop = node.property ("zoom-focus"))) {
2087 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2090 if ((prop = node.property ("zoom"))) {
2091 reset_zoom (PBD::atof (prop->value()));
2094 if ((prop = node.property ("snap-to"))) {
2095 set_snap_to ((SnapType) atoi (prop->value()));
2098 if ((prop = node.property ("snap-mode"))) {
2099 set_snap_mode ((SnapMode) atoi (prop->value()));
2102 if ((prop = node.property ("edit-point"))) {
2103 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point));
2106 if ((prop = node.property ("mouse-mode"))) {
2107 MouseMode m = str2mousemode(prop->value());
2108 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2109 set_mouse_mode (m, true);
2111 mouse_mode = MouseGain; /* lie, to force the mode switch */
2112 set_mouse_mode (MouseObject, true);
2115 if ((prop = node.property ("show-waveforms"))) {
2116 bool yn = (prop->value() == "yes");
2117 _show_waveforms = !yn;
2118 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2120 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2121 /* do it twice to force the change */
2122 tact->set_active (!yn);
2123 tact->set_active (yn);
2127 if ((prop = node.property ("show-waveforms-recording"))) {
2128 bool yn = (prop->value() == "yes");
2129 _show_waveforms_recording = !yn;
2130 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2132 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2133 /* do it twice to force the change */
2134 tact->set_active (!yn);
2135 tact->set_active (yn);
2139 if ((prop = node.property ("show-measures"))) {
2140 bool yn = (prop->value() == "yes");
2141 _show_measures = !yn;
2142 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2144 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2145 /* do it twice to force the change */
2146 tact->set_active (!yn);
2147 tact->set_active (yn);
2151 if ((prop = node.property ("follow-playhead"))) {
2152 bool yn = (prop->value() == "yes");
2153 set_follow_playhead (yn);
2154 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2156 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2157 if (tact->get_active() != yn) {
2158 tact->set_active (yn);
2163 if ((prop = node.property ("region-list-sort-type"))) {
2164 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2165 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2168 if ((prop = node.property ("xfades-visible"))) {
2169 bool yn = (prop->value() == "yes");
2170 _xfade_visibility = !yn;
2171 // set_xfade_visibility (yn);
2174 if ((prop = node.property ("show-editor-mixer"))) {
2176 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2179 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2180 bool yn = (prop->value() == X_("yes"));
2182 /* do it twice to force the change */
2184 tact->set_active (!yn);
2185 tact->set_active (yn);
2189 if ((prop = node.property ("show-editor-list"))) {
2191 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2195 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2196 bool yn = (prop->value() == X_("yes"));
2198 /* do it twice to force the change */
2200 tact->set_active (!yn);
2201 tact->set_active (yn);
2210 Editor::get_state ()
2212 XMLNode* node = new XMLNode ("Editor");
2215 _id.print (buf, sizeof (buf));
2216 node->add_property ("id", buf);
2218 if (is_realized()) {
2219 Glib::RefPtr<Gdk::Window> win = get_window();
2221 int x, y, xoff, yoff, width, height;
2222 win->get_root_origin(x, y);
2223 win->get_position(xoff, yoff);
2224 win->get_size(width, height);
2226 XMLNode* geometry = new XMLNode ("geometry");
2228 snprintf(buf, sizeof(buf), "%d", width);
2229 geometry->add_property("x_size", string(buf));
2230 snprintf(buf, sizeof(buf), "%d", height);
2231 geometry->add_property("y_size", string(buf));
2232 snprintf(buf, sizeof(buf), "%d", x);
2233 geometry->add_property("x_pos", string(buf));
2234 snprintf(buf, sizeof(buf), "%d", y);
2235 geometry->add_property("y_pos", string(buf));
2236 snprintf(buf, sizeof(buf), "%d", xoff);
2237 geometry->add_property("x_off", string(buf));
2238 snprintf(buf, sizeof(buf), "%d", yoff);
2239 geometry->add_property("y_off", string(buf));
2240 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2241 geometry->add_property("edit_pane_pos", string(buf));
2243 node->add_child_nocopy (*geometry);
2246 maybe_add_mixer_strip_width (*node);
2248 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2249 node->add_property ("zoom-focus", buf);
2250 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2251 node->add_property ("zoom", buf);
2252 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2253 node->add_property ("snap-to", buf);
2254 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2255 node->add_property ("snap-mode", buf);
2257 node->add_property ("edit-point", enum_2_string (_edit_point));
2259 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2260 node->add_property ("playhead", buf);
2262 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2263 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2264 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2265 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2266 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2267 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2268 node->add_property ("mouse-mode", enum2str(mouse_mode));
2270 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2272 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2273 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2276 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2278 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2279 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2288 Editor::trackview_by_y_position (double y)
2290 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2294 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2303 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2305 Location* before = 0;
2306 Location* after = 0;
2312 const nframes64_t one_second = session->frame_rate();
2313 const nframes64_t one_minute = session->frame_rate() * 60;
2314 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2315 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2316 nframes64_t presnap = start;
2318 switch (snap_type) {
2324 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2326 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2330 case SnapToSMPTEFrame:
2331 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2332 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2334 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2338 case SnapToSMPTESeconds:
2339 if (session->smpte_offset_negative())
2341 start += session->smpte_offset ();
2343 start -= session->smpte_offset ();
2345 if (start % one_smpte_second > one_smpte_second / 2) {
2346 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2348 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2351 if (session->smpte_offset_negative())
2353 start -= session->smpte_offset ();
2355 start += session->smpte_offset ();
2359 case SnapToSMPTEMinutes:
2360 if (session->smpte_offset_negative())
2362 start += session->smpte_offset ();
2364 start -= session->smpte_offset ();
2366 if (start % one_smpte_minute > one_smpte_minute / 2) {
2367 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2369 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2371 if (session->smpte_offset_negative())
2373 start -= session->smpte_offset ();
2375 start += session->smpte_offset ();
2380 if (start % one_second > one_second / 2) {
2381 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2383 start = (nframes_t) floor ((double) start / one_second) * one_second;
2388 if (start % one_minute > one_minute / 2) {
2389 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2391 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2396 start = session->tempo_map().round_to_bar (start, direction);
2400 start = session->tempo_map().round_to_beat (start, direction);
2403 case SnapToAThirtysecondBeat:
2404 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2407 case SnapToASixteenthBeat:
2408 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2411 case SnapToAEighthBeat:
2412 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2415 case SnapToAQuarterBeat:
2416 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2419 case SnapToAThirdBeat:
2420 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2423 case SnapToEditPoint:
2424 start = get_preferred_edit_position ();
2432 before = session->locations()->first_location_before (start);
2433 after = session->locations()->first_location_after (start);
2435 if (direction < 0) {
2437 start = before->start();
2441 } else if (direction > 0) {
2443 start = after->start();
2445 start = session->current_end_frame();
2450 /* find nearest of the two */
2451 if ((start - before->start()) < (after->start() - start)) {
2452 start = before->start();
2454 start = after->start();
2457 start = before->start();
2460 start = after->start();
2467 case SnapToRegionStart:
2468 case SnapToRegionEnd:
2469 case SnapToRegionSync:
2470 case SnapToRegionBoundary:
2471 if (!region_boundary_cache.empty()) {
2472 vector<nframes_t>::iterator i;
2474 if (direction > 0) {
2475 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2477 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2480 if (i != region_boundary_cache.end()) {
2483 start = region_boundary_cache.back();
2489 switch (snap_mode) {
2495 if (presnap > start) {
2496 if (presnap > (start + unit_to_frame(snap_threshold))) {
2500 } else if (presnap < start) {
2501 if (presnap < (start - unit_to_frame(snap_threshold))) {
2513 Editor::snap_length_beats (nframes_t start)
2519 /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
2521 switch (snap_type) {
2523 return session->tempo_map().meter_at(start).beats_per_bar();
2528 case SnapToAThirtysecondBeat:
2529 return 1.0 / (double)32.0;
2532 case SnapToASixteenthBeat:
2533 return 1.0 / (double)16.0;
2536 case SnapToAEighthBeat:
2537 return 1.0 / (double)8.0;
2540 case SnapToAQuarterBeat:
2541 return 1.0 / (double)4.0;
2544 case SnapToAThirdBeat:
2545 return 1.0 / (double)3.0;
2553 Editor::setup_toolbar ()
2557 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2560 /* Mode Buttons (tool selection) */
2562 vector<ToggleButton *> mouse_mode_buttons;
2564 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2565 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2566 mouse_mode_buttons.push_back (&mouse_move_button);
2567 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2568 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2569 mouse_mode_buttons.push_back (&mouse_select_button);
2570 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2571 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2572 mouse_mode_buttons.push_back (&mouse_gain_button);
2573 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2574 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2575 mouse_mode_buttons.push_back (&mouse_zoom_button);
2576 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2577 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2578 mouse_mode_buttons.push_back (&mouse_timefx_button);
2579 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2580 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2581 mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2582 mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2583 mouse_mode_buttons.push_back (&mouse_note_button);
2584 mouse_mode_buttons.push_back (&mouse_audition_button);
2586 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2588 HBox* mode_box = manage(new HBox);
2589 mode_box->set_border_width (2);
2590 mode_box->set_spacing(4);
2591 mouse_mode_button_box.set_spacing(1);
2592 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2593 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2594 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2595 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2596 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2597 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2598 mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2599 mouse_mode_button_box.set_homogeneous(true);
2601 vector<string> edit_mode_strings;
2602 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2603 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2605 edit_mode_selector.set_name ("EditModeSelector");
2606 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2607 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2608 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2610 mode_box->pack_start(edit_mode_selector);
2611 mode_box->pack_start(mouse_mode_button_box);
2613 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2614 mouse_mode_tearoff->set_name ("MouseModeBase");
2616 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2617 &mouse_mode_tearoff->tearoff_window()));
2618 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2619 &mouse_mode_tearoff->tearoff_window(), 1));
2620 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2621 &mouse_mode_tearoff->tearoff_window()));
2622 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2623 &mouse_mode_tearoff->tearoff_window(), 1));
2625 mouse_move_button.set_name ("MouseModeButton");
2626 mouse_select_button.set_name ("MouseModeButton");
2627 mouse_gain_button.set_name ("MouseModeButton");
2628 mouse_zoom_button.set_name ("MouseModeButton");
2629 mouse_timefx_button.set_name ("MouseModeButton");
2630 mouse_audition_button.set_name ("MouseModeButton");
2631 mouse_note_button.set_name ("MouseModeButton");
2633 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2634 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2635 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2636 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2637 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2638 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2639 ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2641 mouse_move_button.unset_flags (CAN_FOCUS);
2642 mouse_select_button.unset_flags (CAN_FOCUS);
2643 mouse_gain_button.unset_flags (CAN_FOCUS);
2644 mouse_zoom_button.unset_flags (CAN_FOCUS);
2645 mouse_timefx_button.unset_flags (CAN_FOCUS);
2646 mouse_audition_button.unset_flags (CAN_FOCUS);
2647 mouse_note_button.unset_flags (CAN_FOCUS);
2649 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2650 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2652 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2653 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2654 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2655 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2656 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2657 mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2659 // mouse_move_button.set_active (true);
2664 zoom_box.set_spacing (1);
2665 zoom_box.set_border_width (0);
2667 zoom_in_button.set_name ("EditorTimeButton");
2668 zoom_in_button.set_size_request(-1,16);
2669 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2670 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2671 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2673 zoom_out_button.set_name ("EditorTimeButton");
2674 zoom_out_button.set_size_request(-1,16);
2675 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2676 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2677 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2679 zoom_out_full_button.set_name ("EditorTimeButton");
2680 zoom_out_full_button.set_size_request(-1,16);
2681 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2682 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2683 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2685 zoom_focus_selector.set_name ("ZoomFocusSelector");
2686 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Playhead", FUDGE, 0);
2687 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2688 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2689 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2691 zoom_box.pack_start (zoom_focus_selector, true, true);
2692 zoom_box.pack_start (zoom_out_button, false, false);
2693 zoom_box.pack_start (zoom_in_button, false, false);
2694 zoom_box.pack_start (zoom_out_full_button, false, false);
2696 snap_box.set_spacing (1);
2697 snap_box.set_border_width (2);
2699 snap_type_selector.set_name ("SnapTypeSelector");
2700 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2701 set_popdown_strings (snap_type_selector, snap_type_strings);
2702 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2703 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
2705 snap_mode_selector.set_name ("SnapModeSelector");
2706 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2707 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2708 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2709 ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2711 edit_point_selector.set_name ("SnapModeSelector");
2712 Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, "Playhead", 2+FUDGE, 10);
2713 set_popdown_strings (edit_point_selector, edit_point_strings);
2714 edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
2715 ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
2717 snap_box.pack_start (edit_point_clock, false, false);
2718 snap_box.pack_start (snap_mode_selector, false, false);
2719 snap_box.pack_start (snap_type_selector, false, false);
2720 snap_box.pack_start (edit_point_selector, false, false);
2724 HBox *nudge_box = manage (new HBox);
2725 nudge_box->set_spacing(1);
2726 nudge_box->set_border_width (2);
2728 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2729 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2731 nudge_box->pack_start (nudge_backward_button, false, false);
2732 nudge_box->pack_start (nudge_forward_button, false, false);
2733 nudge_box->pack_start (nudge_clock, false, false);
2736 /* Pack everything in... */
2738 HBox* hbox = manage (new HBox);
2739 hbox->set_spacing(10);
2741 tools_tearoff = manage (new TearOff (*hbox));
2742 tools_tearoff->set_name ("MouseModeBase");
2744 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2745 &tools_tearoff->tearoff_window()));
2746 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2747 &tools_tearoff->tearoff_window(), 0));
2748 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2749 &tools_tearoff->tearoff_window()));
2750 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2751 &tools_tearoff->tearoff_window(), 0));
2753 toolbar_hbox.set_spacing (10);
2754 toolbar_hbox.set_border_width (1);
2756 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2757 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2760 hbox->pack_start (snap_box, false, false);
2761 // hbox->pack_start (zoom_box, false, false);
2762 hbox->pack_start (*nudge_box, false, false);
2766 toolbar_base.set_name ("ToolBarBase");
2767 toolbar_base.add (toolbar_hbox);
2769 toolbar_frame.set_shadow_type (SHADOW_OUT);
2770 toolbar_frame.set_name ("BaseFrame");
2771 toolbar_frame.add (toolbar_base);
2776 Editor::setup_midi_toolbar ()
2780 /* Mode Buttons (tool selection) */
2782 vector<ToggleButton *> midi_tool_buttons;
2784 midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
2785 midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
2786 midi_tool_buttons.push_back (&midi_tool_pencil_button);
2787 midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
2788 midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
2789 midi_tool_buttons.push_back (&midi_tool_select_button);
2790 midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
2791 midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
2792 midi_tool_buttons.push_back (&midi_tool_erase_button);
2794 midi_tool_pencil_button.set_active(true);
2796 midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
2798 midi_tool_button_box.set_border_width (2);
2799 midi_tool_button_box.set_spacing(4);
2800 midi_tool_button_box.set_spacing(1);
2801 midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
2802 midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
2803 midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
2804 midi_tool_button_box.set_homogeneous(true);
2806 midi_tool_pencil_button.set_name ("MouseModeButton");
2807 midi_tool_select_button.set_name ("MouseModeButton");
2808 midi_tool_erase_button.set_name ("MouseModeButton");
2810 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
2811 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
2812 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
2814 midi_tool_pencil_button.unset_flags (CAN_FOCUS);
2815 midi_tool_select_button.unset_flags (CAN_FOCUS);
2816 midi_tool_erase_button.unset_flags (CAN_FOCUS);
2818 midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
2819 &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
2820 midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
2821 &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
2822 midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
2823 &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
2825 /* Pack everything in... */
2827 midi_tools_tearoff = manage (new TearOff (midi_tool_button_box));
2828 midi_tools_tearoff->set_name ("MouseModeBase");
2831 midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2832 &midi_tools_tearoff->tearoff_window()));
2833 midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2834 &midi_tools_tearoff->tearoff_window(), 0));
2835 midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2836 &midi_tools_tearoff->tearoff_window()));
2837 midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2838 &midi_tools_tearoff->tearoff_window(), 0));
2841 midi_toolbar_hbox.set_spacing (10);
2842 midi_toolbar_hbox.set_border_width (1);
2844 midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
2846 midi_tool_button_box.show_all ();
2847 midi_toolbar_hbox.show_all();
2848 midi_tools_tearoff->show_all();
2850 midi_toolbar_base.set_name ("ToolBarBase");
2851 midi_toolbar_base.add (midi_toolbar_hbox);
2853 midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
2854 midi_toolbar_frame.set_name ("BaseFrame");
2855 midi_toolbar_frame.add (midi_toolbar_base);
2859 Editor::convert_drop_to_paths (vector<ustring>& paths,
2860 const RefPtr<Gdk::DragContext>& context,
2863 const SelectionData& data,
2872 vector<ustring> uris = data.get_uris();
2876 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2877 are actually URI lists. So do it by hand.
2880 if (data.get_target() != "text/plain") {
2884 /* Parse the "uri-list" format that Nautilus provides,
2885 where each pathname is delimited by \r\n
2888 const char* p = data.get_text().c_str();
2895 while (g_ascii_isspace (*p))
2899 while (*q && (*q != '\n') && (*q != '\r'))
2905 while (q > p && g_ascii_isspace (*q))
2910 uris.push_back (ustring (p, q - p + 1));
2914 p = strchr (p, '\n');
2924 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2926 if ((*i).substr (0,7) == "file://") {
2929 PBD::url_decode (p);
2931 // scan forward past three slashes
2933 ustring::size_type slashcnt = 0;
2934 ustring::size_type n = 0;
2935 ustring::iterator x = p.begin();
2937 while (slashcnt < 3 && x != p.end()) {
2940 } else if (slashcnt == 3) {
2947 if (slashcnt != 3 || x == p.end()) {
2948 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2952 paths.push_back (p.substr (n - 1));
2960 Editor::new_tempo_section ()
2966 Editor::map_transport_state ()
2968 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2970 if (session->transport_stopped()) {
2971 have_pending_keyboard_selection = false;
2974 update_loop_range_view (true);
2979 Editor::State::State (PublicEditor const * e)
2981 selection = new Selection (e);
2984 Editor::State::~State ()
2990 Editor::get_memento () const
2992 State *state = new State (this);
2994 store_state (*state);
2995 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2999 Editor::store_state (State& state) const
3001 *state.selection = *selection;
3005 Editor::restore_state (State *state)
3007 if (*selection == *state->selection) {
3011 *selection = *state->selection;
3012 time_selection_changed ();
3013 region_selection_changed ();
3015 /* XXX other selection change handlers? */
3019 Editor::begin_reversible_command (string name)
3022 before = &get_state();
3023 session->begin_reversible_command (name);
3028 Editor::commit_reversible_command ()
3031 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
3036 Editor::set_edit_group_solo (Route& route, bool yn)
3038 RouteGroup *edit_group;
3040 if ((edit_group = route.edit_group()) != 0) {
3041 edit_group->apply (&Route::set_solo, yn, this);
3043 route.set_solo (yn, this);
3048 Editor::set_edit_group_mute (Route& route, bool yn)
3050 RouteGroup *edit_group = 0;
3052 if ((edit_group == route.edit_group()) != 0) {
3053 edit_group->apply (&Route::set_mute, yn, this);
3055 route.set_mute (yn, this);
3060 Editor::history_changed ()
3064 if (undo_action && session) {
3065 if (session->undo_depth() == 0) {
3068 label = string_compose(_("Undo (%1)"), session->next_undo());
3070 undo_action->property_label() = label;
3073 if (redo_action && session) {
3074 if (session->redo_depth() == 0) {
3077 label = string_compose(_("Redo (%1)"), session->next_redo());
3079 redo_action->property_label() = label;
3084 Editor::duplicate_dialog (bool dup_region)
3086 if (selection->regions.empty() && (selection->time.length() == 0)) {
3090 ArdourDialog win ("duplicate dialog");
3091 Label label (_("Duplicate how many times?"));
3092 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3093 SpinButton spinner (adjustment);
3095 win.get_vbox()->set_spacing (12);
3096 win.get_vbox()->pack_start (label);
3098 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3099 place, visually. so do this by hand.
3102 win.get_vbox()->pack_start (spinner);
3103 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3108 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3109 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3111 win.set_position (WIN_POS_MOUSE);
3113 spinner.grab_focus ();
3115 switch (win.run ()) {
3116 case RESPONSE_ACCEPT:
3122 float times = adjustment.get_value();
3124 if (!selection->regions.empty()) {
3125 duplicate_some_regions (selection->regions, times);
3127 duplicate_selection (times);
3132 Editor::show_verbose_canvas_cursor ()
3134 verbose_canvas_cursor->raise_to_top();
3135 verbose_canvas_cursor->show();
3136 verbose_cursor_visible = true;
3140 Editor::hide_verbose_canvas_cursor ()
3142 verbose_canvas_cursor->hide();
3143 verbose_cursor_visible = false;
3147 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3149 /* XXX get origin of canvas relative to root window,
3150 add x and y and check compared to gdk_screen_{width,height}
3152 verbose_canvas_cursor->property_text() = txt.c_str();
3153 verbose_canvas_cursor->property_x() = x;
3154 verbose_canvas_cursor->property_y() = y;
3158 Editor::set_verbose_canvas_cursor_text (const string & txt)
3160 verbose_canvas_cursor->property_text() = txt.c_str();
3164 Editor::edit_mode_selection_done ()
3170 string choice = edit_mode_selector.get_active_text();
3171 EditMode mode = Slide;
3173 if (choice == _("Splice Edit")) {
3175 } else if (choice == _("Slide Edit")) {
3179 Config->set_edit_mode (mode);
3183 Editor::snap_type_selection_done ()
3185 string choice = snap_type_selector.get_active_text();
3186 SnapType snaptype = SnapToFrame;
3188 if (choice == _("Beats/3")) {
3189 snaptype = SnapToAThirdBeat;
3190 } else if (choice == _("Beats/4")) {
3191 snaptype = SnapToAQuarterBeat;
3192 } else if (choice == _("Beats/8")) {
3193 snaptype = SnapToAEighthBeat;
3194 } else if (choice == _("Beats/16")) {
3195 snaptype = SnapToASixteenthBeat;
3196 } else if (choice == _("Beats/32")) {
3197 snaptype = SnapToAThirtysecondBeat;
3198 } else if (choice == _("Beats")) {
3199 snaptype = SnapToBeat;
3200 } else if (choice == _("Bars")) {
3201 snaptype = SnapToBar;
3202 } else if (choice == _("Marks")) {
3203 snaptype = SnapToMark;
3204 } else if (choice == _("Edit Point")) {
3205 snaptype = SnapToEditPoint;
3206 } else if (choice == _("Region starts")) {
3207 snaptype = SnapToRegionStart;
3208 } else if (choice == _("Region ends")) {
3209 snaptype = SnapToRegionEnd;
3210 } else if (choice == _("Region bounds")) {
3211 snaptype = SnapToRegionBoundary;
3212 } else if (choice == _("Region syncs")) {
3213 snaptype = SnapToRegionSync;
3214 } else if (choice == _("CD Frames")) {
3215 snaptype = SnapToCDFrame;
3216 } else if (choice == _("SMPTE Frames")) {
3217 snaptype = SnapToSMPTEFrame;
3218 } else if (choice == _("SMPTE Seconds")) {
3219 snaptype = SnapToSMPTESeconds;
3220 } else if (choice == _("SMPTE Minutes")) {
3221 snaptype = SnapToSMPTEMinutes;
3222 } else if (choice == _("Seconds")) {
3223 snaptype = SnapToSeconds;
3224 } else if (choice == _("Minutes")) {
3225 snaptype = SnapToMinutes;
3226 } else if (choice == _("None")) {
3227 snaptype = SnapToFrame;
3230 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3232 ract->set_active ();
3237 Editor::snap_mode_selection_done ()
3239 string choice = snap_mode_selector.get_active_text();
3240 SnapMode mode = SnapNormal;
3242 if (choice == _("Normal")) {
3244 } else if (choice == _("Magnetic")) {
3245 mode = SnapMagnetic;
3248 RefPtr<RadioAction> ract = snap_mode_action (mode);
3251 ract->set_active (true);
3256 Editor::edit_point_selection_done ()
3258 string choice = edit_point_selector.get_active_text();
3259 EditPoint ep = EditAtSelectedMarker;
3261 if (choice == _("Marker")) {
3262 _edit_point = EditAtSelectedMarker;
3263 } else if (choice == _("Playhead")) {
3264 _edit_point = EditAtPlayhead;
3266 _edit_point = EditAtMouse;
3269 RefPtr<RadioAction> ract = edit_point_action (ep);
3272 ract->set_active (true);
3277 Editor::zoom_focus_selection_done ()
3279 string choice = zoom_focus_selector.get_active_text();
3280 ZoomFocus focus_type = ZoomFocusLeft;
3282 if (choice == _("Left")) {
3283 focus_type = ZoomFocusLeft;
3284 } else if (choice == _("Right")) {
3285 focus_type = ZoomFocusRight;
3286 } else if (choice == _("Center")) {
3287 focus_type = ZoomFocusCenter;
3288 } else if (choice == _("Play")) {
3289 focus_type = ZoomFocusPlayhead;
3290 } else if (choice == _("Edit")) {
3291 focus_type = ZoomFocusEdit;
3292 } else if (choice == _("Edit Point")) {
3293 focus_type = ZoomFocusEdit;
3295 focus_type = ZoomFocusMouse;
3298 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3301 ract->set_active ();
3306 Editor::edit_controls_button_release (GdkEventButton* ev)
3308 if (Keyboard::is_context_menu_event (ev)) {
3309 ARDOUR_UI::instance()->add_route (this);
3315 Editor::mouse_select_button_release (GdkEventButton* ev)
3317 /* this handles just right-clicks */
3319 if (ev->button != 3) {
3326 Editor::TrackViewList *
3327 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3330 TrackViewList::iterator i;
3332 v = new TrackViewList;
3334 if (track == 0 && group == 0) {
3338 for (i = track_views.begin(); i != track_views.end (); ++i) {
3342 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3344 /* just the view for this track
3347 v->push_back (track);
3351 /* views for all tracks in the edit group */
3353 for (i = track_views.begin(); i != track_views.end (); ++i) {
3355 if (group == 0 || (*i)->edit_group() == group) {
3365 Editor::set_zoom_focus (ZoomFocus f)
3367 string str = zoom_focus_strings[(int)f];
3369 if (str != zoom_focus_selector.get_active_text()) {
3370 zoom_focus_selector.set_active_text (str);
3373 if (zoom_focus != f) {
3376 ZoomFocusChanged (); /* EMIT_SIGNAL */
3383 Editor::ensure_float (Window& win)
3385 win.set_transient_for (*this);
3389 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3391 /* recover or initialize pane positions. do this here rather than earlier because
3392 we don't want the positions to change the child allocations, which they seem to do.
3398 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3400 static int32_t done;
3403 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3404 width = default_width;
3405 height = default_height;
3407 width = atoi(geometry->property("x_size")->value());
3408 height = atoi(geometry->property("y_size")->value());
3411 if (which == static_cast<Paned*> (&edit_pane)) {
3417 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3418 /* initial allocation is 90% to canvas, 10% to notebook */
3419 pos = (int) floor (alloc.get_width() * 0.90f);
3420 snprintf (buf, sizeof(buf), "%d", pos);
3422 pos = atoi (prop->value());
3425 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3426 edit_pane.set_position (pos);
3427 pre_maximal_pane_position = pos;
3433 Editor::detach_tearoff (Box* b, Window* w)
3435 if (tools_tearoff->torn_off() &&
3436 mouse_mode_tearoff->torn_off()) {
3437 top_hbox.remove (toolbar_frame);
3442 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3444 if (toolbar_frame.get_parent() == 0) {
3445 top_hbox.pack_end (toolbar_frame);
3450 Editor::set_show_measures (bool yn)
3452 if (_show_measures != yn) {
3455 if ((_show_measures = yn) == true) {
3463 Editor::toggle_follow_playhead ()
3465 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3467 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3468 set_follow_playhead (tact->get_active());
3473 Editor::set_follow_playhead (bool yn)
3475 if (_follow_playhead != yn) {
3476 if ((_follow_playhead = yn) == true) {
3478 update_current_screen ();
3485 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3487 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3489 xfade->set_active (!xfade->active());
3494 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3496 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3498 xfade->set_follow_overlap (!xfade->following_overlap());
3503 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3505 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3511 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3515 switch (cew.run ()) {
3516 case RESPONSE_ACCEPT:
3523 xfade->StateChanged (Change (~0));
3527 Editor::playlist_selector () const
3529 return *_playlist_selector;
3533 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3537 ret = nudge_clock.current_duration (pos);
3538 next = ret + 1; /* XXXX fix me */
3544 Editor::end_location_changed (Location* location)
3546 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3547 reset_scrolling_region ();
3551 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3553 ArdourDialog dialog ("playlist deletion dialog");
3554 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3555 "If left alone, no audio files used by it will be cleaned.\n"
3556 "If deleted, audio files used by it alone by will cleaned."),
3559 dialog.set_position (WIN_POS_CENTER);
3560 dialog.get_vbox()->pack_start (label);
3564 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3565 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3566 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3568 switch (dialog.run ()) {
3569 case RESPONSE_ACCEPT:
3570 /* delete the playlist */
3574 case RESPONSE_REJECT:
3575 /* keep the playlist */
3587 Editor::audio_region_selection_covers (nframes_t where)
3589 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3590 if ((*a)->region()->covers (where)) {
3599 Editor::prepare_for_cleanup ()
3601 cut_buffer->clear_regions ();
3602 cut_buffer->clear_playlists ();
3604 selection->clear_regions ();
3605 selection->clear_playlists ();
3609 Editor::transport_loop_location()
3612 return session->locations()->auto_loop_location();
3619 Editor::transport_punch_location()
3622 return session->locations()->auto_punch_location();
3629 Editor::control_layout_scroll (GdkEventScroll* ev)
3631 switch (ev->direction) {
3633 scroll_tracks_up_line ();
3637 case GDK_SCROLL_DOWN:
3638 scroll_tracks_down_line ();
3642 /* no left/right handling yet */
3650 /** A new snapshot has been selected.
3653 Editor::snapshot_display_selection_changed ()
3655 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3657 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3659 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3661 if (snap_name.length() == 0) {
3665 if (session->snap_name() == snap_name) {
3669 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3674 Editor::snapshot_display_button_press (GdkEventButton* ev)
3676 if (ev->button == 3) {
3677 /* Right-click on the snapshot list. Work out which snapshot it
3679 Gtk::TreeModel::Path path;
3680 Gtk::TreeViewColumn* col;
3683 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3684 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3686 Gtk::TreeModel::Row row = *iter;
3687 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3696 /** Pop up the snapshot display context menu.
3697 * @param button Button used to open the menu.
3698 * @param time Menu open time.
3699 * @snapshot_name Name of the snapshot that the menu click was over.
3703 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3705 using namespace Menu_Helpers;
3707 MenuList& items (snapshot_context_menu.items());
3710 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3712 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3714 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3716 snapshot_context_menu.popup (button, time);
3720 Editor::rename_snapshot (Glib::ustring old_name)
3722 ArdourPrompter prompter(true);
3726 prompter.set_name ("Prompter");
3727 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3728 prompter.set_prompt (_("New name of snapshot"));
3729 prompter.set_initial_text (old_name);
3731 if (prompter.run() == RESPONSE_ACCEPT) {
3732 prompter.get_result (new_name);
3733 if (new_name.length()) {
3734 session->rename_state (old_name, new_name);
3735 redisplay_snapshots ();
3742 Editor::remove_snapshot (Glib::ustring name)
3744 vector<string> choices;
3746 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3748 choices.push_back (_("No, do nothing."));
3749 choices.push_back (_("Yes, remove it."));
3751 Gtkmm2ext::Choice prompter (prompt, choices);
3753 if (prompter.run () == 1) {
3754 session->remove_state (name);
3755 redisplay_snapshots ();
3760 Editor::redisplay_snapshots ()
3766 vector<sys::path> state_file_paths;
3768 get_state_files_in_directory (session->session_directory().root_path(),
3771 if (state_file_paths.empty()) return;
3773 vector<string> state_file_names(get_file_names_no_extension(state_file_paths));
3775 snapshot_display_model->clear ();
3777 for (vector<string>::iterator i = state_file_names.begin();
3778 i != state_file_names.end(); ++i)
3780 string statename = (*i);
3781 TreeModel::Row row = *(snapshot_display_model->append());
3783 /* this lingers on in case we ever want to change the visible
3784 name of the snapshot.
3787 string display_name;
3788 display_name = statename;
3790 if (statename == session->snap_name()) {
3791 snapshot_display.get_selection()->select(row);
3794 row[snapshot_display_columns.visible_name] = display_name;
3795 row[snapshot_display_columns.real_name] = statename;
3800 Editor::session_state_saved (string snap_name)
3802 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3803 redisplay_snapshots ();
3807 Editor::maximise_editing_space ()
3809 initial_ruler_update_required = true;
3811 mouse_mode_tearoff->set_visible (false);
3812 tools_tearoff->set_visible (false);
3814 pre_maximal_pane_position = edit_pane.get_position();
3815 pre_maximal_editor_width = this->get_width();
3817 if(post_maximal_pane_position == 0) {
3818 post_maximal_pane_position = edit_pane.get_width();
3823 if(post_maximal_editor_width) {
3824 edit_pane.set_position (post_maximal_pane_position -
3825 abs(post_maximal_editor_width - pre_maximal_editor_width));
3827 edit_pane.set_position (post_maximal_pane_position);
3832 Editor::restore_editing_space ()
3834 initial_ruler_update_required = true;
3836 // user changed width of pane during fullscreen
3837 if(post_maximal_pane_position != edit_pane.get_position()) {
3838 post_maximal_pane_position = edit_pane.get_position();
3843 mouse_mode_tearoff->set_visible (true);
3844 tools_tearoff->set_visible (true);
3845 post_maximal_editor_width = this->get_width();
3848 edit_pane.set_position (
3849 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3854 * Make new playlists for a given track and also any others that belong
3855 * to the same active edit group.
3860 Editor::new_playlists (TimeAxisView* v)
3862 begin_reversible_command (_("new playlists"));
3863 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3864 commit_reversible_command ();
3868 * Use a copy of the current playlist for a given track and also any others that belong
3869 * to the same active edit group.
3874 Editor::copy_playlists (TimeAxisView* v)
3876 begin_reversible_command (_("copy playlists"));
3877 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3878 commit_reversible_command ();
3882 * Clear the current playlist for a given track and also any others that belong
3883 * to the same active edit group.
3888 Editor::clear_playlists (TimeAxisView* v)
3890 begin_reversible_command (_("clear playlists"));
3891 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3892 commit_reversible_command ();
3896 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3898 atv.use_new_playlist (sz > 1 ? false : true);
3902 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3904 atv.use_copy_playlist (sz > 1 ? false : true);
3908 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3910 atv.clear_playlist ();
3914 Editor::on_key_press_event (GdkEventKey* ev)
3916 return key_press_focus_accelerator_handler (*this, ev);
3920 Editor::reset_x_origin (nframes_t frame)
3922 queue_visual_change (frame);
3926 Editor::reset_zoom (double fpu)
3928 queue_visual_change (fpu);
3932 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3934 reset_x_origin (frame);
3939 Editor::set_frames_per_unit (double fpu)
3943 /* this is the core function that controls the zoom level of the canvas. it is called
3944 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3947 if (fpu == frames_per_unit) {
3955 // convert fpu to frame count
3957 frames = (nframes_t) floor (fpu * canvas_width);
3959 /* don't allow zooms that fit more than the maximum number
3960 of frames into an 800 pixel wide space.
3963 if (max_frames / fpu < 800.0) {
3967 if (fpu == frames_per_unit) {
3971 frames_per_unit = fpu;
3973 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3974 if (!selection->tracks.empty()) {
3975 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3976 (*i)->reshow_selection (selection->time);
3979 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3980 (*i)->reshow_selection (selection->time);
3985 ZoomChanged (); /* EMIT_SIGNAL */
3987 reset_hscrollbar_stepping ();
3988 reset_scrolling_region ();
3990 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3996 Editor::queue_visual_change (nframes_t where)
3998 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3999 pending_visual_change.time_origin = where;
4001 if (pending_visual_change.idle_handler_id < 0) {
4002 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4007 Editor::queue_visual_change (double fpu)
4009 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
4010 pending_visual_change.frames_per_unit = fpu;
4012 if (pending_visual_change.idle_handler_id < 0) {
4013 pending_visual_change.idle_handler_id = g_idle_add ( _idle_visual_changer, this);
4019 Editor::_idle_visual_changer (void* arg)
4021 return static_cast<Editor*>(arg)->idle_visual_changer ();
4025 Editor::idle_visual_changer ()
4027 VisualChange::Type p = pending_visual_change.pending;
4029 pending_visual_change.pending = (VisualChange::Type) 0;
4031 if (p & VisualChange::ZoomLevel) {
4032 set_frames_per_unit (pending_visual_change.frames_per_unit);
4034 compute_fixed_ruler_scale ();
4035 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(canvas_width * pending_visual_change.frames_per_unit));
4036 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(canvas_width * pending_visual_change.frames_per_unit));
4037 update_tempo_based_rulers ();
4039 if (p & VisualChange::TimeOrigin) {
4040 if (pending_visual_change.time_origin != leftmost_frame) {
4041 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
4042 /* the signal handler will do the rest */
4044 update_fixed_rulers();
4045 redisplay_tempo (true);
4048 pending_visual_change.idle_handler_id = -1;
4050 return 0; /* this is always a one-shot call */
4053 struct EditorOrderTimeAxisSorter {
4054 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4055 return a->order < b->order;
4060 Editor::sort_track_selection ()
4062 EditorOrderTimeAxisSorter cmp;
4063 selection->tracks.sort (cmp);
4067 Editor::get_preferred_edit_position()
4070 nframes64_t where = 0;
4072 switch (_edit_point) {
4073 case EditAtPlayhead:
4074 where = session->audible_frame();
4077 case EditAtSelectedMarker:
4078 if (!selection->markers.empty()) {
4080 Location* loc = find_location_from_marker (selection->markers.front(), whocares);
4082 where = loc->start();
4090 if (!mouse_frame (where, ignored)) {
4091 /* XXX not right but what can we do ? */
4102 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4104 if (!session) return;
4106 begin_reversible_command (cmd);
4110 if ((tll = transport_loop_location()) == 0) {
4111 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4112 XMLNode &before = session->locations()->get_state();
4113 session->locations()->add (loc, true);
4114 session->set_auto_loop_location (loc);
4115 XMLNode &after = session->locations()->get_state();
4116 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4119 XMLNode &before = tll->get_state();
4120 tll->set_hidden (false, this);
4121 tll->set (start, end);
4122 XMLNode &after = tll->get_state();
4123 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4126 commit_reversible_command ();
4130 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4132 if (!session) return;
4134 begin_reversible_command (cmd);
4138 if ((tpl = transport_punch_location()) == 0) {
4139 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4140 XMLNode &before = session->locations()->get_state();
4141 session->locations()->add (loc, true);
4142 session->set_auto_loop_location (loc);
4143 XMLNode &after = session->locations()->get_state();
4144 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4147 XMLNode &before = tpl->get_state();
4148 tpl->set_hidden (false, this);
4149 tpl->set (start, end);
4150 XMLNode &after = tpl->get_state();
4151 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4154 commit_reversible_command ();
4158 Editor::get_regions_at (nframes64_t where, const TrackSelection& ts) const
4161 const TrackSelection* tracks;
4164 tracks = &track_views;
4169 for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4171 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4174 boost::shared_ptr<Diskstream> ds;
4175 boost::shared_ptr<Playlist> pl;
4177 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4179 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)where * ds->speed()));
4181 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4183 RegionView* rv = atv->audio_view()->find_view (*i);
4199 Editor::get_regions_for_action ()
4201 if (!selection->regions.empty()) {
4202 return selection->regions;
4205 nframes64_t where = get_preferred_edit_position();
4206 tmp_regions = get_regions_at (where, selection->tracks);