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 *_zoom_focus_strings[] = {
151 /* Soundfile drag-n-drop */
153 Gdk::Cursor* Editor::cross_hair_cursor = 0;
154 Gdk::Cursor* Editor::selector_cursor = 0;
155 Gdk::Cursor* Editor::trimmer_cursor = 0;
156 Gdk::Cursor* Editor::grabber_cursor = 0;
157 Gdk::Cursor* Editor::zoom_cursor = 0;
158 Gdk::Cursor* Editor::time_fx_cursor = 0;
159 Gdk::Cursor* Editor::fader_cursor = 0;
160 Gdk::Cursor* Editor::speaker_cursor = 0;
161 Gdk::Cursor* Editor::midi_pencil_cursor = 0;
162 Gdk::Cursor* Editor::midi_select_cursor = 0;
163 Gdk::Cursor* Editor::midi_erase_cursor = 0;
164 Gdk::Cursor* Editor::wait_cursor = 0;
165 Gdk::Cursor* Editor::timebar_cursor = 0;
168 show_me_the_size (Requisition* r, const char* what)
170 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
174 check_adjustment (Gtk::Adjustment* adj)
176 cerr << "CHANGE adj = "
177 << adj->get_lower () << ' '
178 << adj->get_upper () << ' '
179 << adj->get_value () << ' '
180 << adj->get_step_increment () << ' '
181 << adj->get_page_increment () << ' '
182 << adj->get_page_size () << ' '
189 /* time display buttons */
191 minsec_label (_("Mins:Secs")),
192 bbt_label (_("Bars:Beats")),
193 smpte_label (_("Timecode")),
194 frame_label (_("Frames")),
195 tempo_label (_("Tempo")),
196 meter_label (_("Meter")),
197 mark_label (_("Location Markers")),
198 range_mark_label (_("Range Markers")),
199 transport_mark_label (_("Loop/Punch Ranges")),
201 edit_packer (3, 3, false),
203 /* the values here don't matter: layout widgets
204 reset them as needed.
207 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
208 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
211 marker_tempo_lines(0),
213 /* tool bar related */
215 edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
216 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
218 toolbar_selection_clock_table (2,3),
220 automation_mode_button (_("mode")),
221 global_automation_button (_("automation")),
224 image_socket_listener(0),
229 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
234 /* we are a singleton */
236 PublicEditor::_instance = this;
240 selection = new Selection (this);
241 cut_buffer = new Selection (this);
243 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
244 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
245 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
246 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
248 clicked_regionview = 0;
249 clicked_axisview = 0;
250 clicked_routeview = 0;
251 clicked_crossfadeview = 0;
252 clicked_control_point = 0;
253 latest_regionview = 0;
254 last_update_frame = 0;
256 current_mixer_strip = 0;
257 current_bbt_points = 0;
259 snap_type_strings = I18N (_snap_type_strings);
260 snap_mode_strings = I18N (_snap_mode_strings);
261 zoom_focus_strings = I18N(_zoom_focus_strings);
263 snap_type = SnapToFrame;
264 set_snap_to (snap_type);
265 snap_mode = SnapNormal;
266 set_snap_mode (snap_mode);
267 snap_threshold = 5.0;
268 bbt_beat_subdivision = 4;
271 autoscroll_active = false;
272 autoscroll_timeout_tag = -1;
273 interthread_progress_window = 0;
280 current_interthread_info = 0;
281 _show_measures = true;
282 _show_waveforms = true;
283 _show_waveforms_recording = true;
284 first_action_message = 0;
286 export_range_markers_dialog = 0;
287 show_gain_after_trim = false;
288 ignore_route_list_reorder = false;
289 no_route_list_redisplay = false;
290 verbose_cursor_on = true;
291 route_removal = false;
292 show_automatic_regions_in_region_list = true;
293 region_list_sort_type = (Editing::RegionListSortType) 0;
294 have_pending_keyboard_selection = false;
295 _follow_playhead = true;
296 _xfade_visibility = true;
297 editor_ruler_menu = 0;
298 no_ruler_shown_update = false;
299 edit_group_list_menu = 0;
301 region_list_menu = 0;
303 start_end_marker_menu = 0;
304 range_marker_menu = 0;
305 marker_menu_item = 0;
307 transport_marker_menu = 0;
308 new_transport_marker_menu = 0;
309 editor_mixer_strip_width = Wide;
310 show_editor_mixer_when_tracks_arrive = false;
311 region_edit_menu_split_multichannel_item = 0;
312 region_edit_menu_split_item = 0;
315 ignore_mouse_mode_toggle = false;
316 ignore_midi_edit_mode_toggle = false;
317 current_stepping_trackview = 0;
319 entered_regionview = 0;
320 clear_entered_track = false;
321 _new_regionviews_show_envelope = false;
322 current_timestretch = 0;
323 in_edit_group_row_change = false;
324 last_canvas_frame = 0;
327 button_release_can_deselect = true;
328 canvas_idle_queued = false;
329 _dragging_playhead = false;
330 _dragging_hscrollbar = false;
334 mouse_speed_update = -1;
335 mouse_speed_size = 16;
336 mouse_speed = new double[mouse_speed_size];
337 memset (mouse_speed, 0, sizeof(double) * mouse_speed_size);
338 mouse_speed_entries = 0;
341 ignore_route_order_sync = false;
343 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
344 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
345 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
346 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
347 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
349 range_marker_drag_rect = 0;
350 marker_drag_line = 0;
351 tempo_map_change_idle_handler_id = -1;
352 canvas_hroizontally_scrolled_handler_id = -1;
353 set_midi_edit_mode (MidiEditPencil, true);
354 set_mouse_mode (MouseObject, true);
356 frames_per_unit = 2048; /* too early to use reset_zoom () */
357 reset_hscrollbar_stepping ();
359 zoom_focus = ZoomFocusLeft;
360 set_zoom_focus (ZoomFocusLeft);
361 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
363 initialize_rulers ();
364 initialize_canvas ();
366 edit_controls_vbox.set_spacing (0);
367 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
368 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
370 track_canvas.set_hadjustment (horizontal_adjustment);
371 track_canvas.set_vadjustment (vertical_adjustment);
372 time_canvas.set_hadjustment (horizontal_adjustment);
374 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
375 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
377 controls_layout.add (edit_controls_vbox);
378 controls_layout.set_name ("EditControlsBase");
379 controls_layout.add_events (Gdk::SCROLL_MASK);
380 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
382 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
383 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
384 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
386 edit_vscrollbar.set_adjustment (vertical_adjustment);
387 edit_hscrollbar.set_adjustment (horizontal_adjustment);
389 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
390 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
391 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
393 edit_hscrollbar.set_name ("EditorHScrollbar");
397 setup_midi_toolbar ();
399 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
401 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
402 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
403 0.0, 1.0, 100.0, 1.0));
404 pad_line_1->property_color_rgba() = 0xFF0000FF;
408 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
409 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
410 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
411 time_canvas_vbox.pack_start (*frames_ruler, false, false);
412 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
413 time_canvas_vbox.pack_start (time_canvas, true, true);
414 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 5);
416 bbt_label.set_name ("EditorTimeButton");
417 bbt_label.set_size_request (-1, (int)timebar_height);
418 bbt_label.set_alignment (1.0, 0.5);
419 bbt_label.set_padding (5,0);
420 minsec_label.set_name ("EditorTimeButton");
421 minsec_label.set_size_request (-1, (int)timebar_height);
422 minsec_label.set_alignment (1.0, 0.5);
423 minsec_label.set_padding (5,0);
424 smpte_label.set_name ("EditorTimeButton");
425 smpte_label.set_size_request (-1, (int)timebar_height);
426 smpte_label.set_alignment (1.0, 0.5);
427 smpte_label.set_padding (5,0);
428 frame_label.set_name ("EditorTimeButton");
429 frame_label.set_size_request (-1, (int)timebar_height);
430 frame_label.set_alignment (1.0, 0.5);
431 frame_label.set_padding (5,0);
432 tempo_label.set_name ("EditorTimeButton");
433 tempo_label.set_size_request (-1, (int)timebar_height);
434 tempo_label.set_alignment (1.0, 0.5);
435 tempo_label.set_padding (5,0);
436 meter_label.set_name ("EditorTimeButton");
437 meter_label.set_size_request (-1, (int)timebar_height);
438 meter_label.set_alignment (1.0, 0.5);
439 meter_label.set_padding (5,0);
440 mark_label.set_name ("EditorTimeButton");
441 mark_label.set_size_request (-1, (int)timebar_height);
442 mark_label.set_alignment (1.0, 0.5);
443 mark_label.set_padding (5,0);
444 range_mark_label.set_name ("EditorTimeButton");
445 range_mark_label.set_size_request (-1, (int)timebar_height);
446 range_mark_label.set_alignment (1.0, 0.5);
447 range_mark_label.set_padding (5,0);
448 transport_mark_label.set_name ("EditorTimeButton");
449 transport_mark_label.set_size_request (-1, (int)timebar_height);
450 transport_mark_label.set_alignment (1.0, 0.5);
451 transport_mark_label.set_padding (5,0);
453 time_button_vbox.pack_start (minsec_label, false, false);
454 time_button_vbox.pack_start (smpte_label, false, false);
455 time_button_vbox.pack_start (frame_label, false, false);
456 time_button_vbox.pack_start (bbt_label, false, false);
457 time_button_vbox.pack_start (meter_label, false, false);
458 time_button_vbox.pack_start (tempo_label, false, false);
459 time_button_vbox.pack_start (mark_label, false, false);
461 time_button_event_box.add (time_button_vbox);
462 time_button_event_box.set_name ("TimebarLabelBase");
463 time_button_frame.set_shadow_type (Gtk::SHADOW_NONE);
465 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
466 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
468 time_button_frame.add (time_button_event_box);
469 time_button_frame.set_name ("TimebarLabelBase");
470 time_button_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
472 /* these enable us to have a dedicated window (for cursor setting, etc.)
473 for the canvas areas.
476 track_canvas_event_box.add (track_canvas);
478 time_canvas_event_box.add (time_canvas_vbox);
479 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
481 edit_packer.set_col_spacings (0);
482 edit_packer.set_row_spacings (0);
483 edit_packer.set_homogeneous (false);
484 edit_packer.set_border_width (0);
485 edit_packer.set_name ("EditorWindow");
487 edit_packer.attach (edit_vscrollbar, 3, 4, 1, 2, FILL, FILL|EXPAND, 0, 0);
489 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, SHRINK, 0, 0);
490 edit_packer.attach (time_canvas_event_box, 2, 4, 0, 1, FILL|EXPAND, FILL, 0, 0);
492 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
493 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
495 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
496 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
498 bottom_hbox.set_border_width (2);
499 bottom_hbox.set_spacing (3);
501 route_display_model = ListStore::create(route_display_columns);
502 route_list_display.set_model (route_display_model);
503 route_list_display.append_column (_("Show"), route_display_columns.visible);
504 route_list_display.append_column (_("Name"), route_display_columns.text);
505 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
506 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
507 route_list_display.set_headers_visible (true);
508 route_list_display.set_name ("TrackListDisplay");
509 route_list_display.get_selection()->set_mode (SELECTION_NONE);
510 route_list_display.set_reorderable (true);
511 route_list_display.set_size_request (100,-1);
513 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
514 route_list_visible_cell->property_activatable() = true;
515 route_list_visible_cell->property_radio() = false;
517 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
518 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
520 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
522 route_list_scroller.add (route_list_display);
523 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
525 group_model = ListStore::create(group_columns);
526 edit_group_display.set_model (group_model);
527 edit_group_display.append_column (_("Name"), group_columns.text);
528 edit_group_display.append_column (_("Active"), group_columns.is_active);
529 edit_group_display.append_column (_("Show"), group_columns.is_visible);
530 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
531 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
532 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
533 edit_group_display.get_column (0)->set_expand (true);
534 edit_group_display.get_column (1)->set_expand (false);
535 edit_group_display.get_column (2)->set_expand (false);
536 edit_group_display.set_headers_visible (true);
538 /* name is directly editable */
540 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
541 name_cell->property_editable() = true;
542 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
544 /* use checkbox for the active + visible columns */
546 CellRendererToggle* 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 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
551 active_cell->property_activatable() = true;
552 active_cell->property_radio() = false;
554 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
556 edit_group_display.set_name ("EditGroupList");
557 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
558 edit_group_display.set_headers_visible (true);
559 edit_group_display.set_reorderable (false);
560 edit_group_display.set_rules_hint (true);
561 edit_group_display.set_size_request (75, -1);
563 edit_group_display_scroller.add (edit_group_display);
564 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
566 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
568 VBox* edit_group_display_packer = manage (new VBox());
569 HBox* edit_group_display_button_box = manage (new HBox());
570 edit_group_display_button_box->set_homogeneous (true);
572 Button* edit_group_add_button = manage (new Button ());
573 Button* edit_group_remove_button = manage (new Button ());
577 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
579 edit_group_add_button->add (*w);
581 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
583 edit_group_remove_button->add (*w);
585 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
586 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
588 edit_group_display_button_box->pack_start (*edit_group_add_button);
589 edit_group_display_button_box->pack_start (*edit_group_remove_button);
591 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
592 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
594 region_list_display.set_size_request (100, -1);
595 region_list_display.set_name ("RegionListDisplay");
597 region_list_model = TreeStore::create (region_list_columns);
598 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
599 region_list_model->set_sort_column (0, SORT_ASCENDING);
601 region_list_display.set_model (region_list_model);
602 region_list_display.append_column (_("Regions"), region_list_columns.name);
603 region_list_display.set_headers_visible (false);
605 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
607 TreeViewColumn* tv_col = region_list_display.get_column(0);
608 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
609 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
610 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
612 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
613 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
615 /* setup DnD handling */
617 list<TargetEntry> region_list_target_table;
619 region_list_target_table.push_back (TargetEntry ("text/plain"));
620 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
621 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
623 region_list_display.add_drop_targets (region_list_target_table);
624 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
626 region_list_scroller.add (region_list_display);
627 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
629 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
630 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
631 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
632 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
633 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
634 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
636 named_selection_scroller.add (named_selection_display);
637 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
639 named_selection_model = TreeStore::create (named_selection_columns);
640 named_selection_display.set_model (named_selection_model);
641 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
642 named_selection_display.set_headers_visible (false);
643 named_selection_display.set_size_request (100, -1);
644 named_selection_display.set_name ("NamedSelectionDisplay");
646 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
647 named_selection_display.set_size_request (100, -1);
648 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
649 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
650 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
654 snapshot_display_model = ListStore::create (snapshot_display_columns);
655 snapshot_display.set_model (snapshot_display_model);
656 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
657 snapshot_display.set_name ("SnapshotDisplay");
658 snapshot_display.set_size_request (75, -1);
659 snapshot_display.set_headers_visible (false);
660 snapshot_display.set_reorderable (false);
661 snapshot_display_scroller.add (snapshot_display);
662 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
664 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
665 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
669 nlabel = manage (new Label (_("Regions")));
670 nlabel->set_angle (-90);
671 the_notebook.append_page (region_list_scroller, *nlabel);
672 nlabel = manage (new Label (_("Tracks/Busses")));
673 nlabel->set_angle (-90);
674 the_notebook.append_page (route_list_scroller, *nlabel);
675 nlabel = manage (new Label (_("Snapshots")));
676 nlabel->set_angle (-90);
677 the_notebook.append_page (snapshot_display_scroller, *nlabel);
678 nlabel = manage (new Label (_("Edit Groups")));
679 nlabel->set_angle (-90);
680 the_notebook.append_page (*edit_group_display_packer, *nlabel);
681 nlabel = manage (new Label (_("Chunks")));
682 nlabel->set_angle (-90);
683 the_notebook.append_page (named_selection_scroller, *nlabel);
685 the_notebook.set_show_tabs (true);
686 the_notebook.set_scrollable (true);
687 the_notebook.popup_enable ();
688 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
690 post_maximal_editor_width = 0;
691 post_maximal_pane_position = 0;
692 edit_pane.pack1 (edit_packer, true, true);
693 edit_pane.pack2 (the_notebook, false, true);
695 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
697 top_hbox.pack_start (toolbar_frame, false, true);
698 top_hbox.pack_start (midi_toolbar_frame, false, true);
700 HBox *hbox = manage (new HBox);
701 hbox->pack_start (edit_pane, true, true);
703 global_vpacker.pack_start (top_hbox, false, false);
704 global_vpacker.pack_start (*hbox, true, true);
706 global_hpacker.pack_start (global_vpacker, true, true);
708 set_name ("EditorWindow");
709 add_accel_group (ActionManager::ui_manager->get_accel_group());
711 status_bar_hpacker.show ();
713 vpacker.pack_end (status_bar_hpacker, false, false);
714 vpacker.pack_end (global_hpacker, true, true);
716 /* register actions now so that set_state() can find them and set toggles/checks etc */
720 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
723 _playlist_selector = new PlaylistSelector();
724 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
726 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
730 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
731 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
733 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
734 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
736 nudge_forward_button.set_name ("TransportButton");
737 nudge_backward_button.set_name ("TransportButton");
739 fade_context_menu.set_name ("ArdourContextMenu");
741 /* icons, titles, WM stuff */
743 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
744 Glib::RefPtr<Gdk::Pixbuf> icon;
746 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
747 window_icons.push_back (icon);
749 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
750 window_icons.push_back (icon);
752 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
753 window_icons.push_back (icon);
755 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
756 window_icons.push_back (icon);
758 if (!window_icons.empty()) {
759 set_icon_list (window_icons);
760 set_default_icon_list (window_icons);
763 WindowTitle title(Glib::get_application_name());
764 title += _("Editor");
765 set_title (title.get_string());
766 set_wmclass (X_("ardour_editor"), "Ardour");
769 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
771 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
772 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
774 /* allow external control surfaces/protocols to do various things */
776 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
777 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
778 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
779 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
781 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
782 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
791 if(image_socket_listener)
793 if(image_socket_listener->is_connected())
795 image_socket_listener->close_connection() ;
798 delete image_socket_listener ;
799 image_socket_listener = 0 ;
805 Editor::add_toplevel_controls (Container& cont)
807 vpacker.pack_start (cont, false, false);
812 Editor::catch_vanishing_regionview (RegionView *rv)
814 /* note: the selection will take care of the vanishing
815 audioregionview by itself.
818 if (clicked_regionview == rv) {
819 clicked_regionview = 0;
822 if (entered_regionview == rv) {
823 set_entered_regionview (0);
828 Editor::set_entered_regionview (RegionView* rv)
830 if (rv == entered_regionview) {
834 if (entered_regionview) {
835 entered_regionview->exited ();
838 if ((entered_regionview = rv) != 0) {
839 entered_regionview->entered ();
844 Editor::set_entered_track (TimeAxisView* tav)
847 entered_track->exited ();
850 if ((entered_track = tav) != 0) {
851 entered_track->entered ();
856 Editor::show_window ()
858 show_all_children ();
860 /* re-hide editor list if necessary */
861 editor_list_button_toggled ();
863 /* now reset all audio_time_axis heights, because widgets might need
869 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
870 tv = (static_cast<TimeAxisView*>(*i));
878 Editor::tie_vertical_scrolling ()
880 double y1 = vertical_adjustment.get_value();
882 playhead_cursor->set_y_axis (y1);
883 edit_cursor->set_y_axis (y1);
885 logo_item->property_y() = y1;
888 controls_layout.get_vadjustment()->set_value (y1);
891 /* the way idle updates and immediate window flushing work on GTK-Quartz
892 requires that we force an immediate redraw right here. The controls
893 layout will do the same all by itself, as does the canvas widget, but
894 most of the time, the canvas itself hasn't updated itself because its
895 idle handler hasn't run. consequently, the call that its layout makes
896 to gdk_window_process_updates() finds nothing to do. here, we force
897 the update to happen, then request a flush of the new window state.
899 track_canvas.update_now ();
900 gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
905 Editor::instant_save ()
907 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
912 session->add_instant_xml(get_state());
914 Config->add_instant_xml(get_state());
919 Editor::edit_cursor_clock_changed()
921 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
922 edit_cursor->set_position (edit_cursor_clock.current_time());
928 Editor::zoom_adjustment_changed ()
934 double fpu = zoom_range_clock.current_duration() / canvas_width;
938 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
939 } else if (fpu > session->current_end_frame() / canvas_width) {
940 fpu = session->current_end_frame() / canvas_width;
941 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
948 Editor::control_scroll (float fraction)
950 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
956 double step = fraction * current_page_frames();
959 _control_scroll_target is an optional<T>
961 it acts like a pointer to an nframes_t, with
962 a operator conversion to boolean to check
963 that it has a value could possibly use
964 playhead_cursor->current_frame to store the
965 value and a boolean in the class to know
966 when it's out of date
969 if (!_control_scroll_target) {
970 _control_scroll_target = session->transport_frame();
971 _dragging_playhead = true;
974 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
975 *_control_scroll_target = 0;
976 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
977 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
979 *_control_scroll_target += (nframes_t) floor (step);
982 /* move visuals, we'll catch up with it later */
984 playhead_cursor->set_position (*_control_scroll_target);
985 UpdateAllTransportClocks (*_control_scroll_target);
987 if (*_control_scroll_target > (current_page_frames() / 2)) {
988 /* try to center PH in window */
989 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
995 Now we do a timeout to actually bring the session to the right place
996 according to the playhead. This is to avoid reading disk buffers on every
997 call to control_scroll, which is driven by ScrollTimeline and therefore
998 probably by a control surface wheel which can generate lots of events.
1000 /* cancel the existing timeout */
1002 control_scroll_connection.disconnect ();
1004 /* add the next timeout */
1006 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1010 Editor::deferred_control_scroll (nframes_t target)
1012 session->request_locate (*_control_scroll_target, session->transport_rolling());
1013 // reset for next stream
1014 _control_scroll_target = boost::none;
1015 _dragging_playhead = false;
1020 Editor::on_realize ()
1022 Window::on_realize ();
1027 Editor::start_scrolling ()
1029 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1030 (mem_fun(*this, &Editor::update_current_screen));
1034 Editor::stop_scrolling ()
1036 scroll_connection.disconnect ();
1040 Editor::map_position_change (nframes_t frame)
1042 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1044 if (session == 0 || !_follow_playhead) {
1048 center_screen (frame);
1049 playhead_cursor->set_position (frame);
1053 Editor::center_screen (nframes_t frame)
1055 double page = canvas_width * frames_per_unit;
1057 /* if we're off the page, then scroll.
1060 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1061 center_screen_internal (frame, page);
1066 Editor::center_screen_internal (nframes_t frame, float page)
1071 frame -= (nframes_t) page;
1076 reset_x_origin (frame);
1080 Editor::handle_new_duration ()
1082 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1084 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1086 if (new_end > last_canvas_frame) {
1087 last_canvas_frame = new_end;
1088 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1089 reset_scrolling_region ();
1092 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1096 Editor::update_title_s (const string & snap_name)
1098 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1104 Editor::update_title ()
1106 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1109 bool dirty = session->dirty();
1111 string session_name;
1113 if (session->snap_name() != session->name()) {
1114 session_name = session->snap_name();
1116 session_name = session->name();
1120 session_name = "*" + session_name;
1123 WindowTitle title(session_name);
1124 title += Glib::get_application_name();
1125 set_title (title.get_string());
1130 Editor::connect_to_session (Session *t)
1134 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1137 /* catch up with the playhead */
1139 session->request_locate (playhead_cursor->current_frame);
1141 if (first_action_message) {
1142 first_action_message->hide();
1147 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1148 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1150 /* These signals can all be emitted by a non-GUI thread. Therefore the
1151 handlers for them must not attempt to directly interact with the GUI,
1152 but use Gtkmm2ext::UI::instance()->call_slot();
1155 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1156 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1157 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1158 session_connections.push_back (session->RegionAdded.connect (mem_fun(*this, &Editor::handle_new_region)));
1159 session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed)));
1160 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1161 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1162 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1163 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1164 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1165 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1166 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1167 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1168 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1170 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1172 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1174 edit_groups_changed ();
1176 edit_cursor_clock.set_session (session);
1177 zoom_range_clock.set_session (session);
1178 _playlist_selector->set_session (session);
1179 nudge_clock.set_session (session);
1182 if (analysis_window != 0)
1183 analysis_window->set_session (session);
1186 Location* loc = session->locations()->auto_loop_location();
1188 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1189 if (loc->start() == loc->end()) {
1190 loc->set_end (loc->start() + 1);
1192 session->locations()->add (loc, false);
1193 session->set_auto_loop_location (loc);
1196 loc->set_name (_("Loop"));
1199 loc = session->locations()->auto_punch_location();
1201 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1202 if (loc->start() == loc->end()) {
1203 loc->set_end (loc->start() + 1);
1205 session->locations()->add (loc, false);
1206 session->set_auto_punch_location (loc);
1209 loc->set_name (_("Punch"));
1212 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1214 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1216 refresh_location_display ();
1217 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1218 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1219 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1220 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1221 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1224 sfbrowser->set_session (session);
1227 handle_new_duration ();
1229 redisplay_regions ();
1230 redisplay_named_selections ();
1231 redisplay_snapshots ();
1233 initial_route_list_display ();
1235 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1236 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1239 restore_ruler_visibility ();
1240 //tempo_map_changed (Change (0));
1241 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1245 /* don't show master bus in a new session */
1247 if (ARDOUR_UI::instance()->session_is_new ()) {
1249 TreeModel::Children rows = route_display_model->children();
1250 TreeModel::Children::iterator i;
1252 no_route_list_redisplay = true;
1254 for (i = rows.begin(); i != rows.end(); ++i) {
1255 TimeAxisView *tv = (*i)[route_display_columns.tv];
1256 RouteTimeAxisView *rtv;
1258 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1259 if (rtv->route()->is_master()) {
1260 route_list_display.get_selection()->unselect (i);
1265 no_route_list_redisplay = false;
1266 redisplay_route_list ();
1269 /* register for undo history */
1271 session->register_with_memento_command_factory(_id, this);
1275 Editor::build_cursors ()
1277 using namespace Gdk;
1279 Gdk::Color mbg ("#000000" ); /* Black */
1280 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1283 RefPtr<Bitmap> source, mask;
1284 source = Bitmap::create (mag_bits, mag_width, mag_height);
1285 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1286 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1289 Gdk::Color fbg ("#ffffff" );
1290 Gdk::Color ffg ("#000000" );
1293 RefPtr<Bitmap> source, mask;
1295 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1296 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1297 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1301 RefPtr<Bitmap> source, mask;
1302 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1303 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1304 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1307 grabber_cursor = new Gdk::Cursor (HAND2);
1308 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1309 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1310 selector_cursor = new Gdk::Cursor (XTERM);
1311 time_fx_cursor = new Gdk::Cursor (SIZING);
1312 wait_cursor = new Gdk::Cursor (WATCH);
1313 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1314 midi_pencil_cursor = new Gdk::Cursor (PENCIL);
1315 midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
1316 midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
1319 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1321 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1323 using namespace Menu_Helpers;
1324 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1327 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1331 MenuList& items (fade_context_menu.items());
1335 switch (item_type) {
1337 case FadeInHandleItem:
1338 if (arv->audio_region()->fade_in_active()) {
1339 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1341 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1344 items.push_back (SeparatorElem());
1346 if (Profile->get_sae()) {
1347 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1348 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1350 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1351 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1352 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1353 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1354 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1360 case FadeOutHandleItem:
1361 if (arv->audio_region()->fade_out_active()) {
1362 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1364 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1367 items.push_back (SeparatorElem());
1369 if (Profile->get_sae()) {
1370 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1371 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1373 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1374 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1375 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1376 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1377 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1383 fatal << _("programming error: ")
1384 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1389 fade_context_menu.popup (button, time);
1392 /* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
1394 Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
1396 build_track_context_menu (frame)->popup (button, time);
1400 Editor::build_track_context_menu (nframes_t frame)
1402 using namespace Menu_Helpers;
1404 Menu* menu = manage (new Menu);
1405 MenuList& edit_items = menu->items();
1408 /* Build the general `track' context menu, adding what is appropriate given
1409 the current selection */
1411 /* XXX: currently crossfades can't be selected, so we can't use the selection
1412 to decide which crossfades to mention in the menu. I believe this will
1413 change at some point. For now we have to use clicked_trackview to decide. */
1414 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1417 boost::shared_ptr<Diskstream> ds;
1418 boost::shared_ptr<Playlist> pl;
1419 boost::shared_ptr<AudioPlaylist> apl;
1421 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1423 AudioPlaylist::Crossfades xfades;
1424 apl->crossfades_at (frame, xfades);
1426 bool many = xfades.size() > 1;
1428 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1429 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1434 if (!selection->time.empty()) {
1435 add_selection_context_items (edit_items);
1438 if (!selection->regions.empty()) {
1439 add_region_context_items (edit_items);
1442 if (!selection->tracks.empty()) {
1443 add_bus_or_audio_track_context_items (edit_items);
1446 menu->set_name ("ArdourContextMenu");
1453 Editor::analyze_region_selection()
1455 if (analysis_window == 0) {
1456 analysis_window = new AnalysisWindow();
1459 analysis_window->set_session(session);
1461 analysis_window->show_all();
1464 analysis_window->set_regionmode();
1465 analysis_window->analyze();
1467 analysis_window->present();
1471 Editor::analyze_range_selection()
1473 if (analysis_window == 0) {
1474 analysis_window = new AnalysisWindow();
1477 analysis_window->set_session(session);
1479 analysis_window->show_all();
1482 analysis_window->set_rangemode();
1483 analysis_window->analyze();
1485 analysis_window->present();
1487 #endif /* FFT_ANALYSIS */
1490 /** Add context menu items relevant to crossfades.
1491 * @param edit_items List to add the items to.
1494 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1496 using namespace Menu_Helpers;
1497 Menu *xfade_menu = manage (new Menu);
1498 MenuList& items = xfade_menu->items();
1499 xfade_menu->set_name ("ArdourContextMenu");
1502 if (xfade->active()) {
1508 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1509 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1511 if (xfade->can_follow_overlap()) {
1513 if (xfade->following_overlap()) {
1514 str = _("Convert to short");
1516 str = _("Convert to full");
1519 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1523 str = xfade->out()->name();
1525 str += xfade->in()->name();
1527 str = _("Crossfade");
1530 edit_items.push_back (MenuElem (str, *xfade_menu));
1531 edit_items.push_back (SeparatorElem());
1535 Editor::xfade_edit_left_region ()
1537 if (clicked_crossfadeview) {
1538 clicked_crossfadeview->left_view.show_region_editor ();
1543 Editor::xfade_edit_right_region ()
1545 if (clicked_crossfadeview) {
1546 clicked_crossfadeview->right_view.show_region_editor ();
1550 /** Add an element to a menu, settings its sensitivity.
1551 * @param m Menu to add to.
1552 * @param e Element to add.
1553 * @param s true to make sensitive, false to make insensitive
1556 Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
1560 m.back().set_sensitive (false);
1564 /** Add context menu items relevant to regions.
1565 * @param edit_items List to add the items to.
1568 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
1570 using namespace Menu_Helpers;
1571 sigc::connection fooc;
1572 Menu *region_menu = manage (new Menu);
1573 MenuList& items = region_menu->items();
1574 region_menu->set_name ("ArdourContextMenu");
1576 items.push_back (MenuElem (_("Edit..."), mem_fun(*this, &Editor::edit_region)));
1577 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1578 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1580 Menu* sync_point_menu = manage (new Menu);
1581 MenuList& sync_point_items = sync_point_menu->items();
1582 sync_point_menu->set_name("ArdourContextMenu");
1584 sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1585 sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
1587 items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
1589 add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
1591 add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
1593 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1596 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1599 items.push_back (SeparatorElem());
1601 items.push_back (CheckMenuElem (_("Lock")));
1602 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1603 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1605 #if FIXUP_REGION_MENU
1606 if (region->locked()) {
1608 region_lock_item->set_active();
1613 items.push_back (CheckMenuElem (_("Lock Position")));
1614 region_lock_position_item = static_cast<CheckMenuItem*>(&items.back());
1615 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_position_lock));
1616 #if FIXUP_REGION_MENU
1617 if (region->locked()) {
1619 region_lock_position_item->set_active();
1624 items.push_back (CheckMenuElem (_("Mute")));
1625 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1626 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1627 #if FIXUP_REGION_MENU
1628 if (region->muted()) {
1630 region_mute_item->set_active();
1635 if (!Profile->get_sae()) {
1636 items.push_back (CheckMenuElem (_("Opaque")));
1637 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1638 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1639 #if FIXUP_REGION_MENU
1640 if (region->opaque()) {
1642 region_opaque_item->set_active();
1648 /* We allow "Original position" if at least one region is not at its
1651 RegionSelection::iterator i = selection->regions.begin();
1652 while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
1656 add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
1658 items.push_back (SeparatorElem());
1660 /* Find out if we have a selected audio region */
1661 i = selection->regions.begin();
1662 while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
1665 const bool have_selected_audio_region = (i != selection->regions.end());
1667 if (have_selected_audio_region) {
1669 Menu* envelopes_menu = manage (new Menu);
1671 envelopes_menu->set_name ("ArdourContextMenu");
1673 #if FIXUP_REGION_MENU
1675 XXX NEED TO RESOLVE ONE v. MANY REGION ISSUE
1677 MenuList& envelopes_items = envelopes_menu->items();
1679 RegionView* rv = sv->find_view (ar);
1680 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1682 if (!Profile->get_sae()) {
1683 envelopes_items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1685 envelopes_items.push_back (CheckMenuElem (_("Envelope Visible")));
1686 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1687 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1688 if (arv->envelope_visible()) {
1690 region_envelope_visible_item->set_active (true);
1694 envelopes_items.push_back (CheckMenuElem (_("Envelope Active")));
1695 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1696 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1698 if (ar->envelope_active()) {
1700 region_envelope_active_item->set_active (true);
1704 items.push_back (SeparatorElem());
1708 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1710 #if FIXUP_REGION_MENU
1711 if (ar->scale_amplitude() != 1.0f) {
1712 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_regions)));
1714 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_regions)));
1719 /* Find out if we have a selected MIDI region */
1720 i = selection->regions.begin();
1721 while (i != selection->regions.end() && boost::dynamic_pointer_cast<MidiRegion>((*i)->region()) == 0) {
1724 const bool have_selected_midi_region = (i != selection->regions.end());
1726 if (have_selected_midi_region) {
1728 items.push_back (MenuElem (_("Quantize"), mem_fun(*this, &Editor::quantize_regions)));
1729 items.push_back (SeparatorElem());
1733 /* range related stuff */
1735 add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1737 add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1739 items.push_back (SeparatorElem());
1743 Menu *nudge_menu = manage (new Menu());
1744 MenuList& nudge_items = nudge_menu->items();
1745 nudge_menu->set_name ("ArdourContextMenu");
1747 nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1748 nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1749 nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1750 nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1752 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1754 Menu *trim_menu = manage (new Menu);
1755 MenuList& trim_items = trim_menu->items();
1756 trim_menu->set_name ("ArdourContextMenu");
1758 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1759 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1761 items.push_back (MenuElem (_("Trim"), *trim_menu));
1762 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1763 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1764 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1765 items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1766 items.push_back (SeparatorElem());
1767 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1769 /* OK, stick the region submenu at the top of the list, and then add
1773 string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1774 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1777 /** Add context menu items relevant to selection ranges.
1778 * @param edit_items List to add the items to.
1781 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1783 using namespace Menu_Helpers;
1784 Menu *selection_menu = manage (new Menu);
1785 MenuList& items = selection_menu->items();
1786 selection_menu->set_name ("ArdourContextMenu");
1788 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1789 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1792 items.push_back (SeparatorElem());
1793 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1796 items.push_back (SeparatorElem());
1797 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1798 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1800 items.push_back (SeparatorElem());
1801 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1802 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1804 items.push_back (SeparatorElem());
1805 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1807 items.push_back (SeparatorElem());
1808 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1809 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1811 items.push_back (SeparatorElem());
1812 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1813 items.push_back (SeparatorElem());
1814 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1815 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1816 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1817 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1818 items.push_back (SeparatorElem());
1819 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1820 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1823 /** Add context menu items relevant to busses or audio tracks.
1824 * @param edit_items List to add the items to.
1827 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1829 using namespace Menu_Helpers;
1831 /* We add every possible action here, and de-sensitize things
1832 that aren't allowed. The sensitivity logic is a bit spread out;
1833 on the one hand I'm using things like can_cut_copy (), which is
1834 reasonably complicated and so perhaps better near the function that
1835 it expresses sensitivity for, and on the other hand checks
1836 in this function as well. You can't really have can_* for everything
1837 or the number of methods would get silly. */
1839 bool const one_selected_region = selection->regions.size() == 1;
1841 /* Count the number of selected audio tracks */
1842 int n_audio_tracks = 0;
1843 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1844 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1845 if (r && r->is_audio_track()) {
1852 Menu *play_menu = manage (new Menu);
1853 MenuList& play_items = play_menu->items();
1854 play_menu->set_name ("ArdourContextMenu");
1856 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1857 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1858 add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1860 add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1862 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1866 Menu *select_menu = manage (new Menu);
1867 MenuList& select_items = select_menu->items();
1868 select_menu->set_name ("ArdourContextMenu");
1870 string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1872 select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1874 select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1876 str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1878 select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1880 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1881 select_items.push_back (SeparatorElem());
1883 if (n_audio_tracks) {
1884 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1885 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1888 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1889 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1890 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1891 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1893 if (n_audio_tracks) {
1894 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1897 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1901 Menu *cutnpaste_menu = manage (new Menu);
1902 MenuList& cutnpaste_items = cutnpaste_menu->items();
1903 cutnpaste_menu->set_name ("ArdourContextMenu");
1905 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1907 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1909 if (n_audio_tracks) {
1910 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1911 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1913 cutnpaste_items.push_back (SeparatorElem());
1915 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1916 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1917 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1919 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1922 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1924 if (n_audio_tracks) {
1926 Menu *track_menu = manage (new Menu);
1927 MenuList& track_items = track_menu->items();
1928 track_menu->set_name ("ArdourContextMenu");
1930 /* Adding new material */
1932 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);
1933 add_item_with_sensitivity (track_items, MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1937 Menu *nudge_menu = manage (new Menu());
1938 MenuList& nudge_items = nudge_menu->items();
1939 nudge_menu->set_name ("ArdourContextMenu");
1941 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1942 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1944 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1946 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1948 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1950 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1952 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1954 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1956 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1959 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1960 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1962 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1963 edit_items.push_back (MenuElem (str, *track_menu));
1967 /* CURSOR SETTING AND MARKS AND STUFF */
1970 Editor::set_snap_to (SnapType st)
1973 string str = snap_type_strings[(int) st];
1975 if (str != snap_type_selector.get_active_text()) {
1976 snap_type_selector.set_active_text (str);
1981 switch (snap_type) {
1982 case SnapToAThirtysecondBeat:
1983 case SnapToASixteenthBeat:
1984 case SnapToAEighthBeat:
1985 case SnapToAQuarterBeat:
1986 case SnapToAThirdBeat:
1987 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + (nframes_t)(canvas_width * frames_per_unit));
1988 update_tempo_based_rulers ();
1997 Editor::set_snap_mode (SnapMode mode)
2000 string str = snap_mode_strings[(int)mode];
2002 if (str != snap_mode_selector.get_active_text ()) {
2003 snap_mode_selector.set_active_text (str);
2010 Editor::set_state (const XMLNode& node)
2012 const XMLProperty* prop;
2014 int x, y, xoff, yoff;
2017 if ((prop = node.property ("id")) != 0) {
2018 _id = prop->value ();
2021 if ((geometry = find_named_node (node, "geometry")) == 0) {
2023 g.base_width = default_width;
2024 g.base_height = default_height;
2032 g.base_width = atoi(geometry->property("x_size")->value());
2033 g.base_height = atoi(geometry->property("y_size")->value());
2034 x = atoi(geometry->property("x_pos")->value());
2035 y = atoi(geometry->property("y_pos")->value());
2036 xoff = atoi(geometry->property("x_off")->value());
2037 yoff = atoi(geometry->property("y_off")->value());
2040 set_default_size (g.base_width, g.base_height);
2043 if (session && (prop = node.property ("playhead"))) {
2044 nframes_t pos = atol (prop->value().c_str());
2045 playhead_cursor->set_position (pos);
2047 playhead_cursor->set_position (0);
2049 /* reset_x_origin() doesn't work right here, since the old
2050 position may be zero already, and it does nothing in such
2055 horizontal_adjustment.set_value (0);
2058 if (session && (prop = node.property ("edit-cursor"))) {
2059 nframes_t pos = atol (prop->value().c_str());
2060 edit_cursor->set_position (pos);
2062 edit_cursor->set_position (0);
2065 if ((prop = node.property ("mixer-width"))) {
2066 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2069 if ((prop = node.property ("zoom-focus"))) {
2070 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2073 if ((prop = node.property ("zoom"))) {
2074 reset_zoom (PBD::atof (prop->value()));
2077 if ((prop = node.property ("snap-to"))) {
2078 set_snap_to ((SnapType) atoi (prop->value()));
2081 if ((prop = node.property ("snap-mode"))) {
2082 set_snap_mode ((SnapMode) atoi (prop->value()));
2085 if ((prop = node.property ("mouse-mode"))) {
2086 MouseMode m = str2mousemode(prop->value());
2087 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2088 set_mouse_mode (m, true);
2090 mouse_mode = MouseGain; /* lie, to force the mode switch */
2091 set_mouse_mode (MouseObject, true);
2094 if ((prop = node.property ("show-waveforms"))) {
2095 bool yn = (prop->value() == "yes");
2096 _show_waveforms = !yn;
2097 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2099 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2100 /* do it twice to force the change */
2101 tact->set_active (!yn);
2102 tact->set_active (yn);
2106 if ((prop = node.property ("show-waveforms-recording"))) {
2107 bool yn = (prop->value() == "yes");
2108 _show_waveforms_recording = !yn;
2109 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2111 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2112 /* do it twice to force the change */
2113 tact->set_active (!yn);
2114 tact->set_active (yn);
2118 if ((prop = node.property ("show-measures"))) {
2119 bool yn = (prop->value() == "yes");
2120 _show_measures = !yn;
2121 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2123 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2124 /* do it twice to force the change */
2125 tact->set_active (!yn);
2126 tact->set_active (yn);
2130 if ((prop = node.property ("follow-playhead"))) {
2131 bool yn = (prop->value() == "yes");
2132 set_follow_playhead (yn);
2133 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2135 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2136 if (tact->get_active() != yn) {
2137 tact->set_active (yn);
2142 if ((prop = node.property ("region-list-sort-type"))) {
2143 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2144 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2147 if ((prop = node.property ("xfades-visible"))) {
2148 bool yn = (prop->value() == "yes");
2149 _xfade_visibility = !yn;
2150 // set_xfade_visibility (yn);
2153 if ((prop = node.property ("show-editor-mixer"))) {
2155 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2158 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2159 bool yn = (prop->value() == X_("yes"));
2161 /* do it twice to force the change */
2163 tact->set_active (!yn);
2164 tact->set_active (yn);
2168 if ((prop = node.property ("show-editor-list"))) {
2170 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2174 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2175 bool yn = (prop->value() == X_("yes"));
2177 /* do it twice to force the change */
2179 tact->set_active (!yn);
2180 tact->set_active (yn);
2189 Editor::get_state ()
2191 XMLNode* node = new XMLNode ("Editor");
2194 _id.print (buf, sizeof (buf));
2195 node->add_property ("id", buf);
2197 if (is_realized()) {
2198 Glib::RefPtr<Gdk::Window> win = get_window();
2200 int x, y, xoff, yoff, width, height;
2201 win->get_root_origin(x, y);
2202 win->get_position(xoff, yoff);
2203 win->get_size(width, height);
2205 XMLNode* geometry = new XMLNode ("geometry");
2207 snprintf(buf, sizeof(buf), "%d", width);
2208 geometry->add_property("x_size", string(buf));
2209 snprintf(buf, sizeof(buf), "%d", height);
2210 geometry->add_property("y_size", string(buf));
2211 snprintf(buf, sizeof(buf), "%d", x);
2212 geometry->add_property("x_pos", string(buf));
2213 snprintf(buf, sizeof(buf), "%d", y);
2214 geometry->add_property("y_pos", string(buf));
2215 snprintf(buf, sizeof(buf), "%d", xoff);
2216 geometry->add_property("x_off", string(buf));
2217 snprintf(buf, sizeof(buf), "%d", yoff);
2218 geometry->add_property("y_off", string(buf));
2219 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2220 geometry->add_property("edit_pane_pos", string(buf));
2222 node->add_child_nocopy (*geometry);
2225 maybe_add_mixer_strip_width (*node);
2227 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2228 node->add_property ("zoom-focus", buf);
2229 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2230 node->add_property ("zoom", buf);
2231 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2232 node->add_property ("snap-to", buf);
2233 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2234 node->add_property ("snap-mode", buf);
2236 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2237 node->add_property ("playhead", buf);
2238 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2239 node->add_property ("edit-cursor", buf);
2241 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2242 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2243 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2244 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2245 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2246 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2247 node->add_property ("mouse-mode", enum2str(mouse_mode));
2249 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2251 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2252 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2255 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2257 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2258 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2267 Editor::trackview_by_y_position (double y)
2269 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2273 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2282 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2284 Location* before = 0;
2285 Location* after = 0;
2291 const nframes64_t one_second = session->frame_rate();
2292 const nframes64_t one_minute = session->frame_rate() * 60;
2293 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2294 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2295 nframes64_t presnap = start;
2297 switch (snap_type) {
2303 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2305 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2309 case SnapToSMPTEFrame:
2310 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2311 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2313 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2317 case SnapToSMPTESeconds:
2318 if (session->smpte_offset_negative())
2320 start += session->smpte_offset ();
2322 start -= session->smpte_offset ();
2324 if (start % one_smpte_second > one_smpte_second / 2) {
2325 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2327 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2330 if (session->smpte_offset_negative())
2332 start -= session->smpte_offset ();
2334 start += session->smpte_offset ();
2338 case SnapToSMPTEMinutes:
2339 if (session->smpte_offset_negative())
2341 start += session->smpte_offset ();
2343 start -= session->smpte_offset ();
2345 if (start % one_smpte_minute > one_smpte_minute / 2) {
2346 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2348 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2350 if (session->smpte_offset_negative())
2352 start -= session->smpte_offset ();
2354 start += session->smpte_offset ();
2359 if (start % one_second > one_second / 2) {
2360 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2362 start = (nframes_t) floor ((double) start / one_second) * one_second;
2367 if (start % one_minute > one_minute / 2) {
2368 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2370 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2375 start = session->tempo_map().round_to_bar (start, direction);
2379 start = session->tempo_map().round_to_beat (start, direction);
2382 case SnapToAThirtysecondBeat:
2383 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2386 case SnapToASixteenthBeat:
2387 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2390 case SnapToAEighthBeat:
2391 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2394 case SnapToAQuarterBeat:
2395 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2398 case SnapToAThirdBeat:
2399 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2402 case SnapToEditCursor:
2403 start = edit_cursor->current_frame;
2411 before = session->locations()->first_location_before (start);
2412 after = session->locations()->first_location_after (start);
2414 if (direction < 0) {
2416 start = before->start();
2420 } else if (direction > 0) {
2422 start = after->start();
2424 start = session->current_end_frame();
2429 /* find nearest of the two */
2430 if ((start - before->start()) < (after->start() - start)) {
2431 start = before->start();
2433 start = after->start();
2436 start = before->start();
2439 start = after->start();
2446 case SnapToRegionStart:
2447 case SnapToRegionEnd:
2448 case SnapToRegionSync:
2449 case SnapToRegionBoundary:
2450 if (!region_boundary_cache.empty()) {
2451 vector<nframes_t>::iterator i;
2453 if (direction > 0) {
2454 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2456 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2459 if (i != region_boundary_cache.end()) {
2462 start = region_boundary_cache.back();
2468 switch (snap_mode) {
2474 if (presnap > start) {
2475 if (presnap > (start + unit_to_frame(snap_threshold))) {
2479 } else if (presnap < start) {
2480 if (presnap < (start - unit_to_frame(snap_threshold))) {
2492 Editor::snap_length_beats (nframes_t start)
2498 /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
2500 switch (snap_type) {
2502 return session->tempo_map().meter_at(start).beats_per_bar();
2507 case SnapToAThirtysecondBeat:
2508 return 1.0 / (double)32.0;
2511 case SnapToASixteenthBeat:
2512 return 1.0 / (double)16.0;
2515 case SnapToAEighthBeat:
2516 return 1.0 / (double)8.0;
2519 case SnapToAQuarterBeat:
2520 return 1.0 / (double)4.0;
2523 case SnapToAThirdBeat:
2524 return 1.0 / (double)3.0;
2532 Editor::setup_toolbar ()
2536 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2539 /* Mode Buttons (tool selection) */
2541 vector<ToggleButton *> mouse_mode_buttons;
2543 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2544 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2545 mouse_mode_buttons.push_back (&mouse_move_button);
2546 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2547 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2548 mouse_mode_buttons.push_back (&mouse_select_button);
2549 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2550 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2551 mouse_mode_buttons.push_back (&mouse_gain_button);
2552 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2553 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2554 mouse_mode_buttons.push_back (&mouse_zoom_button);
2555 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2556 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2557 mouse_mode_buttons.push_back (&mouse_timefx_button);
2558 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2559 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2560 mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2561 mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2562 mouse_mode_buttons.push_back (&mouse_note_button);
2563 mouse_mode_buttons.push_back (&mouse_audition_button);
2565 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2567 HBox* mode_box = manage(new HBox);
2568 mode_box->set_border_width (2);
2569 mode_box->set_spacing(4);
2570 mouse_mode_button_box.set_spacing(1);
2571 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2572 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2573 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2574 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2575 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2576 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2577 mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2578 mouse_mode_button_box.set_homogeneous(true);
2580 vector<string> edit_mode_strings;
2581 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2582 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2584 edit_mode_selector.set_name ("EditModeSelector");
2585 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2586 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2587 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2589 mode_box->pack_start(edit_mode_selector);
2590 mode_box->pack_start(mouse_mode_button_box);
2592 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2593 mouse_mode_tearoff->set_name ("MouseModeBase");
2595 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2596 &mouse_mode_tearoff->tearoff_window()));
2597 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2598 &mouse_mode_tearoff->tearoff_window(), 1));
2599 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2600 &mouse_mode_tearoff->tearoff_window()));
2601 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2602 &mouse_mode_tearoff->tearoff_window(), 1));
2604 mouse_move_button.set_name ("MouseModeButton");
2605 mouse_select_button.set_name ("MouseModeButton");
2606 mouse_gain_button.set_name ("MouseModeButton");
2607 mouse_zoom_button.set_name ("MouseModeButton");
2608 mouse_timefx_button.set_name ("MouseModeButton");
2609 mouse_audition_button.set_name ("MouseModeButton");
2610 mouse_note_button.set_name ("MouseModeButton");
2612 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2613 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2614 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2615 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2616 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2617 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2618 ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2620 mouse_move_button.unset_flags (CAN_FOCUS);
2621 mouse_select_button.unset_flags (CAN_FOCUS);
2622 mouse_gain_button.unset_flags (CAN_FOCUS);
2623 mouse_zoom_button.unset_flags (CAN_FOCUS);
2624 mouse_timefx_button.unset_flags (CAN_FOCUS);
2625 mouse_audition_button.unset_flags (CAN_FOCUS);
2626 mouse_note_button.unset_flags (CAN_FOCUS);
2628 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2629 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2631 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2632 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2633 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2634 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2635 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2636 mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2638 // mouse_move_button.set_active (true);
2643 zoom_box.set_spacing (1);
2644 zoom_box.set_border_width (0);
2646 zoom_in_button.set_name ("EditorTimeButton");
2647 zoom_in_button.set_size_request(-1,16);
2648 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2649 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2650 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2652 zoom_out_button.set_name ("EditorTimeButton");
2653 zoom_out_button.set_size_request(-1,16);
2654 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2655 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2656 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2658 zoom_out_full_button.set_name ("EditorTimeButton");
2659 zoom_out_full_button.set_size_request(-1,16);
2660 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2661 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2662 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2664 zoom_focus_selector.set_name ("ZoomFocusSelector");
2665 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Center", FUDGE, 0);
2666 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2667 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2668 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2670 zoom_box.pack_start (zoom_focus_selector, true, true);
2671 zoom_box.pack_start (zoom_out_button, false, false);
2672 zoom_box.pack_start (zoom_in_button, false, false);
2673 zoom_box.pack_start (zoom_out_full_button, false, false);
2675 /* Edit Cursor / Snap */
2677 snap_box.set_spacing (1);
2678 snap_box.set_border_width (2);
2680 snap_type_selector.set_name ("SnapTypeSelector");
2681 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2682 set_popdown_strings (snap_type_selector, snap_type_strings);
2683 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2684 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2686 snap_mode_selector.set_name ("SnapModeSelector");
2687 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2688 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2689 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2691 snap_box.pack_start (edit_cursor_clock, false, false);
2692 snap_box.pack_start (snap_mode_selector, false, false);
2693 snap_box.pack_start (snap_type_selector, false, false);
2698 HBox *nudge_box = manage (new HBox);
2699 nudge_box->set_spacing(1);
2700 nudge_box->set_border_width (2);
2702 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2703 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2705 nudge_box->pack_start (nudge_backward_button, false, false);
2706 nudge_box->pack_start (nudge_forward_button, false, false);
2707 nudge_box->pack_start (nudge_clock, false, false);
2710 /* Pack everything in... */
2712 HBox* hbox = new HBox;
2713 hbox->set_spacing(10);
2715 tools_tearoff = new TearOff (*hbox);
2716 tools_tearoff->set_name ("MouseModeBase");
2718 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2719 &tools_tearoff->tearoff_window()));
2720 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2721 &tools_tearoff->tearoff_window(), 0));
2722 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2723 &tools_tearoff->tearoff_window()));
2724 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2725 &tools_tearoff->tearoff_window(), 0));
2727 toolbar_hbox.set_spacing (10);
2728 toolbar_hbox.set_border_width (1);
2730 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2731 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2734 hbox->pack_start (snap_box, false, false);
2735 // hbox->pack_start (zoom_box, false, false);
2736 hbox->pack_start (*nudge_box, false, false);
2740 toolbar_base.set_name ("ToolBarBase");
2741 toolbar_base.add (toolbar_hbox);
2743 toolbar_frame.set_shadow_type (SHADOW_OUT);
2744 toolbar_frame.set_name ("BaseFrame");
2745 toolbar_frame.add (toolbar_base);
2750 Editor::setup_midi_toolbar ()
2754 /* Mode Buttons (tool selection) */
2756 vector<ToggleButton *> midi_tool_buttons;
2758 midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
2759 midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
2760 midi_tool_buttons.push_back (&midi_tool_pencil_button);
2761 midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
2762 midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
2763 midi_tool_buttons.push_back (&midi_tool_select_button);
2764 midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
2765 midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
2766 midi_tool_buttons.push_back (&midi_tool_erase_button);
2768 midi_tool_pencil_button.set_active(true);
2770 midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
2772 midi_tool_button_box.set_border_width (2);
2773 midi_tool_button_box.set_spacing(4);
2774 midi_tool_button_box.set_spacing(1);
2775 midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
2776 midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
2777 midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
2778 midi_tool_button_box.set_homogeneous(true);
2780 midi_tool_pencil_button.set_name ("MouseModeButton");
2781 midi_tool_select_button.set_name ("MouseModeButton");
2782 midi_tool_erase_button.set_name ("MouseModeButton");
2784 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
2785 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
2786 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
2788 midi_tool_pencil_button.unset_flags (CAN_FOCUS);
2789 midi_tool_select_button.unset_flags (CAN_FOCUS);
2790 midi_tool_erase_button.unset_flags (CAN_FOCUS);
2792 midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
2793 &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
2794 midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
2795 &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
2796 midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
2797 &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
2799 /* Pack everything in... */
2801 midi_tools_tearoff = new TearOff (midi_tool_button_box);
2802 midi_tools_tearoff->set_name ("MouseModeBase");
2805 midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2806 &midi_tools_tearoff->tearoff_window()));
2807 midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2808 &midi_tools_tearoff->tearoff_window(), 0));
2809 midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2810 &midi_tools_tearoff->tearoff_window()));
2811 midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2812 &midi_tools_tearoff->tearoff_window(), 0));
2815 midi_toolbar_hbox.set_spacing (10);
2816 midi_toolbar_hbox.set_border_width (1);
2818 midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
2820 midi_tool_button_box.show_all ();
2821 midi_toolbar_hbox.show_all();
2822 midi_tools_tearoff->show_all();
2824 midi_toolbar_base.set_name ("ToolBarBase");
2825 midi_toolbar_base.add (midi_toolbar_hbox);
2827 midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
2828 midi_toolbar_frame.set_name ("BaseFrame");
2829 midi_toolbar_frame.add (midi_toolbar_base);
2833 Editor::convert_drop_to_paths (vector<ustring>& paths,
2834 const RefPtr<Gdk::DragContext>& context,
2837 const SelectionData& data,
2846 vector<ustring> uris = data.get_uris();
2848 cerr << "there were " << uris.size() << " in that drag data\n";
2852 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2853 are actually URI lists. So do it by hand.
2856 if (data.get_target() != "text/plain") {
2860 /* Parse the "uri-list" format that Nautilus provides,
2861 where each pathname is delimited by \r\n
2864 const char* p = data.get_text().c_str();
2871 while (g_ascii_isspace (*p))
2875 while (*q && (*q != '\n') && (*q != '\r'))
2881 while (q > p && g_ascii_isspace (*q))
2886 uris.push_back (ustring (p, q - p + 1));
2890 p = strchr (p, '\n');
2900 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2902 if ((*i).substr (0,7) == "file://") {
2905 PBD::url_decode (p);
2907 // scan forward past three slashes
2909 ustring::size_type slashcnt = 0;
2910 ustring::size_type n = 0;
2911 ustring::iterator x = p.begin();
2913 while (slashcnt < 3 && x != p.end()) {
2916 } else if (slashcnt == 3) {
2923 if (slashcnt != 3 || x == p.end()) {
2924 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2928 paths.push_back (p.substr (n - 1));
2936 Editor::new_tempo_section ()
2942 Editor::map_transport_state ()
2944 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2946 if (session->transport_stopped()) {
2947 have_pending_keyboard_selection = false;
2950 update_loop_range_view (true);
2955 Editor::State::State (PublicEditor const * e)
2957 selection = new Selection (e);
2960 Editor::State::~State ()
2966 Editor::get_memento () const
2968 State *state = new State (this);
2970 store_state (*state);
2971 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2975 Editor::store_state (State& state) const
2977 *state.selection = *selection;
2981 Editor::restore_state (State *state)
2983 if (*selection == *state->selection) {
2987 *selection = *state->selection;
2988 time_selection_changed ();
2989 region_selection_changed ();
2991 /* XXX other selection change handlers? */
2995 Editor::begin_reversible_command (string name)
2998 before = &get_state();
2999 session->begin_reversible_command (name);
3004 Editor::commit_reversible_command ()
3007 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
3012 Editor::set_edit_group_solo (Route& route, bool yn)
3014 RouteGroup *edit_group;
3016 if ((edit_group = route.edit_group()) != 0) {
3017 edit_group->apply (&Route::set_solo, yn, this);
3019 route.set_solo (yn, this);
3024 Editor::set_edit_group_mute (Route& route, bool yn)
3026 RouteGroup *edit_group = 0;
3028 if ((edit_group == route.edit_group()) != 0) {
3029 edit_group->apply (&Route::set_mute, yn, this);
3031 route.set_mute (yn, this);
3036 Editor::history_changed ()
3040 if (undo_action && session) {
3041 if (session->undo_depth() == 0) {
3044 label = string_compose(_("Undo (%1)"), session->next_undo());
3046 undo_action->property_label() = label;
3049 if (redo_action && session) {
3050 if (session->redo_depth() == 0) {
3053 label = string_compose(_("Redo (%1)"), session->next_redo());
3055 redo_action->property_label() = label;
3060 Editor::duplicate_dialog (bool dup_region)
3062 if (selection->regions.empty() && (selection->time.length() == 0)) {
3066 ArdourDialog win ("duplicate dialog");
3067 Label label (_("Duplicate how many times?"));
3068 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3069 SpinButton spinner (adjustment);
3071 win.get_vbox()->set_spacing (12);
3072 win.get_vbox()->pack_start (label);
3074 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3075 place, visually. so do this by hand.
3078 win.get_vbox()->pack_start (spinner);
3079 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3084 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3085 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3087 win.set_position (WIN_POS_MOUSE);
3089 spinner.grab_focus ();
3091 switch (win.run ()) {
3092 case RESPONSE_ACCEPT:
3098 float times = adjustment.get_value();
3100 if (!selection->regions.empty()) {
3101 duplicate_some_regions (selection->regions, times);
3103 duplicate_selection (times);
3108 Editor::show_verbose_canvas_cursor ()
3110 verbose_canvas_cursor->raise_to_top();
3111 verbose_canvas_cursor->show();
3112 verbose_cursor_visible = true;
3116 Editor::hide_verbose_canvas_cursor ()
3118 verbose_canvas_cursor->hide();
3119 verbose_cursor_visible = false;
3123 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3125 /* XXX get origin of canvas relative to root window,
3126 add x and y and check compared to gdk_screen_{width,height}
3128 verbose_canvas_cursor->property_text() = txt.c_str();
3129 verbose_canvas_cursor->property_x() = x;
3130 verbose_canvas_cursor->property_y() = y;
3134 Editor::set_verbose_canvas_cursor_text (const string & txt)
3136 verbose_canvas_cursor->property_text() = txt.c_str();
3140 Editor::edit_mode_selection_done ()
3146 string choice = edit_mode_selector.get_active_text();
3147 EditMode mode = Slide;
3149 if (choice == _("Splice Edit")) {
3151 } else if (choice == _("Slide Edit")) {
3155 Config->set_edit_mode (mode);
3159 Editor::snap_type_selection_done ()
3161 string choice = snap_type_selector.get_active_text();
3162 SnapType snaptype = SnapToFrame;
3164 if (choice == _("Beats/3")) {
3165 snaptype = SnapToAThirdBeat;
3166 } else if (choice == _("Beats/4")) {
3167 snaptype = SnapToAQuarterBeat;
3168 } else if (choice == _("Beats/8")) {
3169 snaptype = SnapToAEighthBeat;
3170 } else if (choice == _("Beats/16")) {
3171 snaptype = SnapToASixteenthBeat;
3172 } else if (choice == _("Beats/32")) {
3173 snaptype = SnapToAThirtysecondBeat;
3174 } else if (choice == _("Beats")) {
3175 snaptype = SnapToBeat;
3176 } else if (choice == _("Bars")) {
3177 snaptype = SnapToBar;
3178 } else if (choice == _("Marks")) {
3179 snaptype = SnapToMark;
3180 } else if (choice == _("Edit Cursor")) {
3181 snaptype = SnapToEditCursor;
3182 } else if (choice == _("Region starts")) {
3183 snaptype = SnapToRegionStart;
3184 } else if (choice == _("Region ends")) {
3185 snaptype = SnapToRegionEnd;
3186 } else if (choice == _("Region bounds")) {
3187 snaptype = SnapToRegionBoundary;
3188 } else if (choice == _("Region syncs")) {
3189 snaptype = SnapToRegionSync;
3190 } else if (choice == _("CD Frames")) {
3191 snaptype = SnapToCDFrame;
3192 } else if (choice == _("SMPTE Frames")) {
3193 snaptype = SnapToSMPTEFrame;
3194 } else if (choice == _("SMPTE Seconds")) {
3195 snaptype = SnapToSMPTESeconds;
3196 } else if (choice == _("SMPTE Minutes")) {
3197 snaptype = SnapToSMPTEMinutes;
3198 } else if (choice == _("Seconds")) {
3199 snaptype = SnapToSeconds;
3200 } else if (choice == _("Minutes")) {
3201 snaptype = SnapToMinutes;
3202 } else if (choice == _("None")) {
3203 snaptype = SnapToFrame;
3206 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3208 ract->set_active ();
3213 Editor::snap_mode_selection_done ()
3215 string choice = snap_mode_selector.get_active_text();
3216 SnapMode mode = SnapNormal;
3218 if (choice == _("Normal")) {
3220 } else if (choice == _("Magnetic")) {
3221 mode = SnapMagnetic;
3224 RefPtr<RadioAction> ract = snap_mode_action (mode);
3227 ract->set_active (true);
3232 Editor::zoom_focus_selection_done ()
3234 string choice = zoom_focus_selector.get_active_text();
3235 ZoomFocus focus_type = ZoomFocusLeft;
3237 if (choice == _("Left")) {
3238 focus_type = ZoomFocusLeft;
3239 } else if (choice == _("Right")) {
3240 focus_type = ZoomFocusRight;
3241 } else if (choice == _("Center")) {
3242 focus_type = ZoomFocusCenter;
3243 } else if (choice == _("Play")) {
3244 focus_type = ZoomFocusPlayhead;
3245 } else if (choice == _("Edit")) {
3246 focus_type = ZoomFocusEdit;
3249 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3252 ract->set_active ();
3257 Editor::edit_controls_button_release (GdkEventButton* ev)
3259 if (Keyboard::is_context_menu_event (ev)) {
3260 ARDOUR_UI::instance()->add_route (this);
3266 Editor::mouse_select_button_release (GdkEventButton* ev)
3268 /* this handles just right-clicks */
3270 if (ev->button != 3) {
3277 Editor::TrackViewList *
3278 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3281 TrackViewList::iterator i;
3283 v = new TrackViewList;
3285 if (track == 0 && group == 0) {
3289 for (i = track_views.begin(); i != track_views.end (); ++i) {
3293 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3295 /* just the view for this track
3298 v->push_back (track);
3302 /* views for all tracks in the edit group */
3304 for (i = track_views.begin(); i != track_views.end (); ++i) {
3306 if (group == 0 || (*i)->edit_group() == group) {
3316 Editor::set_zoom_focus (ZoomFocus f)
3318 string str = zoom_focus_strings[(int)f];
3320 if (str != zoom_focus_selector.get_active_text()) {
3321 zoom_focus_selector.set_active_text (str);
3324 if (zoom_focus != f) {
3327 ZoomFocusChanged (); /* EMIT_SIGNAL */
3334 Editor::ensure_float (Window& win)
3336 win.set_transient_for (*this);
3340 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3342 /* recover or initialize pane positions. do this here rather than earlier because
3343 we don't want the positions to change the child allocations, which they seem to do.
3349 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3351 static int32_t done;
3354 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3355 width = default_width;
3356 height = default_height;
3358 width = atoi(geometry->property("x_size")->value());
3359 height = atoi(geometry->property("y_size")->value());
3362 if (which == static_cast<Paned*> (&edit_pane)) {
3368 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3369 /* initial allocation is 90% to canvas, 10% to notebook */
3370 pos = (int) floor (alloc.get_width() * 0.90f);
3371 snprintf (buf, sizeof(buf), "%d", pos);
3373 pos = atoi (prop->value());
3376 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3377 edit_pane.set_position (pos);
3378 pre_maximal_pane_position = pos;
3384 Editor::detach_tearoff (Box* b, Window* w)
3386 if (tools_tearoff->torn_off() &&
3387 mouse_mode_tearoff->torn_off()) {
3388 top_hbox.remove (toolbar_frame);
3393 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3395 if (toolbar_frame.get_parent() == 0) {
3396 top_hbox.pack_end (toolbar_frame);
3401 Editor::set_show_measures (bool yn)
3403 if (_show_measures != yn) {
3406 if ((_show_measures = yn) == true) {
3414 Editor::toggle_follow_playhead ()
3416 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3418 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3419 set_follow_playhead (tact->get_active());
3424 Editor::set_follow_playhead (bool yn)
3426 if (_follow_playhead != yn) {
3427 if ((_follow_playhead = yn) == true) {
3429 update_current_screen ();
3436 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3438 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3440 xfade->set_active (!xfade->active());
3445 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3447 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3449 xfade->set_follow_overlap (!xfade->following_overlap());
3454 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3456 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3462 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3466 switch (cew.run ()) {
3467 case RESPONSE_ACCEPT:
3474 xfade->StateChanged (Change (~0));
3478 Editor::playlist_selector () const
3480 return *_playlist_selector;
3484 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3488 ret = nudge_clock.current_duration (pos);
3489 next = ret + 1; /* XXXX fix me */
3495 Editor::end_location_changed (Location* location)
3497 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3498 reset_scrolling_region ();
3502 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3504 ArdourDialog dialog ("playlist deletion dialog");
3505 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3506 "If left alone, no audio files used by it will be cleaned.\n"
3507 "If deleted, audio files used by it alone by will cleaned."),
3510 dialog.set_position (WIN_POS_CENTER);
3511 dialog.get_vbox()->pack_start (label);
3515 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3516 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3517 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3519 switch (dialog.run ()) {
3520 case RESPONSE_ACCEPT:
3521 /* delete the playlist */
3525 case RESPONSE_REJECT:
3526 /* keep the playlist */
3538 Editor::audio_region_selection_covers (nframes_t where)
3540 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3541 if ((*a)->region()->covers (where)) {
3550 Editor::prepare_for_cleanup ()
3552 cut_buffer->clear_regions ();
3553 cut_buffer->clear_playlists ();
3555 selection->clear_regions ();
3556 selection->clear_playlists ();
3560 Editor::transport_loop_location()
3563 return session->locations()->auto_loop_location();
3570 Editor::transport_punch_location()
3573 return session->locations()->auto_punch_location();
3580 Editor::control_layout_scroll (GdkEventScroll* ev)
3582 switch (ev->direction) {
3584 scroll_tracks_up_line ();
3588 case GDK_SCROLL_DOWN:
3589 scroll_tracks_down_line ();
3593 /* no left/right handling yet */
3601 /** A new snapshot has been selected.
3604 Editor::snapshot_display_selection_changed ()
3606 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3608 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3610 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3612 if (snap_name.length() == 0) {
3616 if (session->snap_name() == snap_name) {
3620 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3625 Editor::snapshot_display_button_press (GdkEventButton* ev)
3627 if (ev->button == 3) {
3628 /* Right-click on the snapshot list. Work out which snapshot it
3630 Gtk::TreeModel::Path path;
3631 Gtk::TreeViewColumn* col;
3634 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3635 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3637 Gtk::TreeModel::Row row = *iter;
3638 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3647 /** Pop up the snapshot display context menu.
3648 * @param button Button used to open the menu.
3649 * @param time Menu open time.
3650 * @snapshot_name Name of the snapshot that the menu click was over.
3654 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3656 using namespace Menu_Helpers;
3658 MenuList& items (snapshot_context_menu.items());
3661 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3663 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3665 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3667 snapshot_context_menu.popup (button, time);
3671 Editor::rename_snapshot (Glib::ustring old_name)
3673 ArdourPrompter prompter(true);
3677 prompter.set_name ("Prompter");
3678 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3679 prompter.set_prompt (_("New name of snapshot"));
3680 prompter.set_initial_text (old_name);
3682 if (prompter.run() == RESPONSE_ACCEPT) {
3683 prompter.get_result (new_name);
3684 if (new_name.length()) {
3685 session->rename_state (old_name, new_name);
3686 redisplay_snapshots ();
3693 Editor::remove_snapshot (Glib::ustring name)
3695 vector<string> choices;
3697 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3699 choices.push_back (_("No, do nothing."));
3700 choices.push_back (_("Yes, remove it."));
3702 Gtkmm2ext::Choice prompter (prompt, choices);
3704 if (prompter.run () == 1) {
3705 session->remove_state (name);
3706 redisplay_snapshots ();
3711 Editor::redisplay_snapshots ()
3717 vector<sys::path> state_file_paths;
3719 get_state_files_in_directory (session->session_directory().root_path(),
3722 if (state_file_paths.empty()) return;
3724 vector<string> state_file_names(get_file_names_no_extension(state_file_paths));
3726 snapshot_display_model->clear ();
3728 for (vector<string>::iterator i = state_file_names.begin();
3729 i != state_file_names.end(); ++i)
3731 string statename = (*i);
3732 TreeModel::Row row = *(snapshot_display_model->append());
3734 /* this lingers on in case we ever want to change the visible
3735 name of the snapshot.
3738 string display_name;
3739 display_name = statename;
3741 if (statename == session->snap_name()) {
3742 snapshot_display.get_selection()->select(row);
3745 row[snapshot_display_columns.visible_name] = display_name;
3746 row[snapshot_display_columns.real_name] = statename;
3751 Editor::session_state_saved (string snap_name)
3753 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3754 redisplay_snapshots ();
3758 Editor::maximise_editing_space ()
3760 initial_ruler_update_required = true;
3762 mouse_mode_tearoff->set_visible (false);
3763 tools_tearoff->set_visible (false);
3765 pre_maximal_pane_position = edit_pane.get_position();
3766 pre_maximal_editor_width = this->get_width();
3768 if(post_maximal_pane_position == 0) {
3769 post_maximal_pane_position = edit_pane.get_width();
3774 if(post_maximal_editor_width) {
3775 edit_pane.set_position (post_maximal_pane_position -
3776 abs(post_maximal_editor_width - pre_maximal_editor_width));
3778 edit_pane.set_position (post_maximal_pane_position);
3783 Editor::restore_editing_space ()
3785 initial_ruler_update_required = true;
3787 // user changed width of pane during fullscreen
3788 if(post_maximal_pane_position != edit_pane.get_position()) {
3789 post_maximal_pane_position = edit_pane.get_position();
3794 mouse_mode_tearoff->set_visible (true);
3795 tools_tearoff->set_visible (true);
3796 post_maximal_editor_width = this->get_width();
3799 edit_pane.set_position (
3800 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3805 * Make new playlists for a given track and also any others that belong
3806 * to the same active edit group.
3811 Editor::new_playlists (TimeAxisView* v)
3813 begin_reversible_command (_("new playlists"));
3814 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3815 commit_reversible_command ();
3819 * Use a copy of the current playlist for a given track and also any others that belong
3820 * to the same active edit group.
3825 Editor::copy_playlists (TimeAxisView* v)
3827 begin_reversible_command (_("copy playlists"));
3828 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3829 commit_reversible_command ();
3833 * Clear the current playlist for a given track and also any others that belong
3834 * to the same active edit group.
3839 Editor::clear_playlists (TimeAxisView* v)
3841 begin_reversible_command (_("clear playlists"));
3842 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3843 commit_reversible_command ();
3847 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3849 atv.use_new_playlist (sz > 1 ? false : true);
3853 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3855 atv.use_copy_playlist (sz > 1 ? false : true);
3859 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3861 atv.clear_playlist ();
3865 Editor::on_key_press_event (GdkEventKey* ev)
3867 return key_press_focus_accelerator_handler (*this, ev);
3871 Editor::reset_x_origin (nframes_t frame)
3873 queue_visual_change (frame);
3877 Editor::reset_zoom (double fpu)
3879 queue_visual_change (fpu);
3883 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3885 reset_x_origin (frame);
3890 Editor::set_frames_per_unit (double fpu)
3894 /* this is the core function that controls the zoom level of the canvas. it is called
3895 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3898 if (fpu == frames_per_unit) {
3906 // convert fpu to frame count
3908 frames = (nframes_t) floor (fpu * canvas_width);
3910 /* don't allow zooms that fit more than the maximum number
3911 of frames into an 800 pixel wide space.
3914 if (max_frames / fpu < 800.0) {
3918 if (fpu == frames_per_unit) {
3922 frames_per_unit = fpu;
3924 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3925 if (!selection->tracks.empty()) {
3926 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3927 (*i)->reshow_selection (selection->time);
3930 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3931 (*i)->reshow_selection (selection->time);
3936 ZoomChanged (); /* EMIT_SIGNAL */
3938 reset_hscrollbar_stepping ();
3939 reset_scrolling_region ();
3941 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3942 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3948 Editor::queue_visual_change (nframes_t where)
3950 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3951 pending_visual_change.time_origin = where;
3953 if (pending_visual_change.idle_handler_id < 0) {
3954 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3959 Editor::queue_visual_change (double fpu)
3961 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3962 pending_visual_change.frames_per_unit = fpu;
3964 if (pending_visual_change.idle_handler_id < 0) {
3965 pending_visual_change.idle_handler_id = g_idle_add ( _idle_visual_changer, this);
3971 Editor::_idle_visual_changer (void* arg)
3973 return static_cast<Editor*>(arg)->idle_visual_changer ();
3977 Editor::idle_visual_changer ()
3979 VisualChange::Type p = pending_visual_change.pending;
3981 pending_visual_change.pending = (VisualChange::Type) 0;
3983 if (p & VisualChange::ZoomLevel) {
3984 set_frames_per_unit (pending_visual_change.frames_per_unit);
3986 compute_fixed_ruler_scale ();
3987 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(canvas_width * pending_visual_change.frames_per_unit));
3988 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(canvas_width * pending_visual_change.frames_per_unit));
3989 update_tempo_based_rulers ();
3991 if (p & VisualChange::TimeOrigin) {
3992 if (pending_visual_change.time_origin != leftmost_frame) {
3993 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3994 /* the signal handler will do the rest */
3996 update_fixed_rulers();
3997 redisplay_tempo (true);
4000 pending_visual_change.idle_handler_id = -1;
4002 return 0; /* this is always a one-shot call */
4005 struct EditorOrderTimeAxisSorter {
4006 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4007 return a->order < b->order;
4012 Editor::sort_track_selection ()
4014 EditorOrderTimeAxisSorter cmp;
4015 selection->tracks.sort (cmp);
4019 Editor::edit_cursor_position(bool sync)
4021 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
4022 edit_cursor_clock.set(edit_cursor->current_frame, true);
4025 return edit_cursor->current_frame;
4030 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4032 if (!session) return;
4034 begin_reversible_command (cmd);
4038 if ((tll = transport_loop_location()) == 0) {
4039 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4040 XMLNode &before = session->locations()->get_state();
4041 session->locations()->add (loc, true);
4042 session->set_auto_loop_location (loc);
4043 XMLNode &after = session->locations()->get_state();
4044 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4047 XMLNode &before = tll->get_state();
4048 tll->set_hidden (false, this);
4049 tll->set (start, end);
4050 XMLNode &after = tll->get_state();
4051 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4054 commit_reversible_command ();
4058 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4060 if (!session) return;
4062 begin_reversible_command (cmd);
4066 if ((tpl = transport_punch_location()) == 0) {
4067 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4068 XMLNode &before = session->locations()->get_state();
4069 session->locations()->add (loc, true);
4070 session->set_auto_loop_location (loc);
4071 XMLNode &after = session->locations()->get_state();
4072 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4075 XMLNode &before = tpl->get_state();
4076 tpl->set_hidden (false, this);
4077 tpl->set (start, end);
4078 XMLNode &after = tpl->get_state();
4079 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4082 commit_reversible_command ();