2 Copyright (C) 2000-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
28 #include <boost/none.hpp>
30 #include <sigc++/bind.h>
32 #include <pbd/convert.h>
33 #include <pbd/error.h>
34 #include <pbd/enumwriter.h>
35 #include <pbd/memento_command.h>
37 #include <glibmm/miscutils.h>
38 #include <gtkmm/image.h>
39 #include <gdkmm/color.h>
40 #include <gdkmm/bitmap.h>
42 #include <gtkmm2ext/grouped_buttons.h>
43 #include <gtkmm2ext/gtk_ui.h>
44 #include <gtkmm2ext/tearoff.h>
45 #include <gtkmm2ext/utils.h>
46 #include <gtkmm2ext/window_title.h>
47 #include <gtkmm2ext/choice.h>
49 #include <ardour/audio_track.h>
50 #include <ardour/audio_diskstream.h>
51 #include <ardour/plugin_manager.h>
52 #include <ardour/location.h>
53 #include <ardour/audioplaylist.h>
54 #include <ardour/audioregion.h>
55 #include <ardour/midi_region.h>
56 #include <ardour/session_route.h>
57 #include <ardour/session_directory.h>
58 #include <ardour/session_state_utils.h>
59 #include <ardour/tempo.h>
60 #include <ardour/utils.h>
61 #include <ardour/profile.h>
63 #include <control_protocol/control_protocol.h>
65 #include "ardour_ui.h"
69 #include "playlist_selector.h"
70 #include "audio_region_view.h"
71 #include "rgb_macros.h"
72 #include "selection.h"
73 #include "audio_streamview.h"
74 #include "time_axis_view.h"
75 #include "audio_time_axis.h"
77 #include "crossfade_view.h"
79 #include "public_editor.h"
80 #include "crossfade_edit.h"
81 #include "canvas_impl.h"
84 #include "gui_thread.h"
87 #include "analysis_window.h"
93 #include "imageframe_socket_handler.h"
98 using namespace ARDOUR;
101 using namespace Glib;
102 using namespace Gtkmm2ext;
103 using namespace Editing;
105 using PBD::internationalize;
108 const double Editor::timebar_height = 15.0;
110 #include "editor_xpms"
112 static const gchar *_snap_type_strings[] = {
136 static const gchar *_snap_mode_strings[] = {
142 static const gchar *_edit_point_strings[] = {
149 static const gchar *_zoom_focus_strings[] = {
159 /* Soundfile drag-n-drop */
161 Gdk::Cursor* Editor::cross_hair_cursor = 0;
162 Gdk::Cursor* Editor::selector_cursor = 0;
163 Gdk::Cursor* Editor::trimmer_cursor = 0;
164 Gdk::Cursor* Editor::grabber_cursor = 0;
165 Gdk::Cursor* Editor::zoom_cursor = 0;
166 Gdk::Cursor* Editor::time_fx_cursor = 0;
167 Gdk::Cursor* Editor::fader_cursor = 0;
168 Gdk::Cursor* Editor::speaker_cursor = 0;
169 Gdk::Cursor* Editor::midi_pencil_cursor = 0;
170 Gdk::Cursor* Editor::midi_select_cursor = 0;
171 Gdk::Cursor* Editor::midi_erase_cursor = 0;
172 Gdk::Cursor* Editor::wait_cursor = 0;
173 Gdk::Cursor* Editor::timebar_cursor = 0;
174 Gdk::Cursor* Editor::transparent_cursor = 0;
177 show_me_the_size (Requisition* r, const char* what)
179 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
184 /* time display buttons */
186 minsec_label (_("Mins:Secs")),
187 bbt_label (_("Bars:Beats")),
188 smpte_label (_("Timecode")),
189 frame_label (_("Frames")),
190 tempo_label (_("Tempo")),
191 meter_label (_("Meter")),
192 mark_label (_("Location Markers")),
193 range_mark_label (_("Range Markers")),
194 transport_mark_label (_("Loop/Punch Ranges")),
196 edit_packer (3, 3, false),
198 /* the values here don't matter: layout widgets
199 reset them as needed.
202 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
203 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
206 marker_tempo_lines(0),
208 /* tool bar related */
210 edit_point_clock (X_("editpoint"), false, X_("EditPointClock"), true),
211 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
213 toolbar_selection_clock_table (2,3),
215 automation_mode_button (_("mode")),
216 global_automation_button (_("automation")),
219 image_socket_listener(0),
224 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
229 /* we are a singleton */
231 PublicEditor::_instance = this;
235 selection = new Selection (this);
236 cut_buffer = new Selection (this);
238 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
239 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
240 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
241 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
242 selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed));
244 clicked_regionview = 0;
245 clicked_axisview = 0;
246 clicked_routeview = 0;
247 clicked_crossfadeview = 0;
248 clicked_control_point = 0;
249 latest_regionview = 0;
250 last_update_frame = 0;
252 current_mixer_strip = 0;
253 current_bbt_points = 0;
255 snap_type_strings = I18N (_snap_type_strings);
256 snap_mode_strings = I18N (_snap_mode_strings);
257 zoom_focus_strings = I18N (_zoom_focus_strings);
258 edit_point_strings = I18N (_edit_point_strings);
260 snap_type = SnapToFrame;
261 set_snap_to (snap_type);
263 snap_mode = SnapNormal;
264 set_snap_mode (snap_mode);
266 _edit_point = EditAtMouse;
267 set_edit_point_preference (_edit_point);
269 snap_threshold = 5.0;
270 bbt_beat_subdivision = 4;
273 autoscroll_active = false;
274 autoscroll_timeout_tag = -1;
275 interthread_progress_window = 0;
282 current_interthread_info = 0;
283 _show_measures = true;
284 _show_waveforms = true;
285 _show_waveforms_recording = true;
286 first_action_message = 0;
288 export_range_markers_dialog = 0;
289 show_gain_after_trim = false;
290 ignore_route_list_reorder = false;
291 no_route_list_redisplay = false;
292 verbose_cursor_on = true;
293 route_removal = false;
294 show_automatic_regions_in_region_list = true;
295 region_list_sort_type = (Editing::RegionListSortType) 0;
296 have_pending_keyboard_selection = false;
297 _follow_playhead = true;
298 _xfade_visibility = true;
299 editor_ruler_menu = 0;
300 no_ruler_shown_update = false;
301 edit_group_list_menu = 0;
303 region_list_menu = 0;
305 start_end_marker_menu = 0;
306 range_marker_menu = 0;
307 marker_menu_item = 0;
309 transport_marker_menu = 0;
310 new_transport_marker_menu = 0;
311 editor_mixer_strip_width = Wide;
312 show_editor_mixer_when_tracks_arrive = false;
313 region_edit_menu_split_multichannel_item = 0;
314 region_edit_menu_split_item = 0;
317 ignore_mouse_mode_toggle = false;
318 ignore_midi_edit_mode_toggle = false;
319 current_stepping_trackview = 0;
321 entered_regionview = 0;
323 clear_entered_track = false;
324 _new_regionviews_show_envelope = false;
325 current_timestretch = 0;
326 in_edit_group_row_change = false;
327 last_canvas_frame = 0;
329 button_release_can_deselect = true;
330 canvas_idle_queued = false;
331 _dragging_playhead = false;
332 _dragging_edit_point = false;
333 _dragging_hscrollbar = false;
335 scrubbing_direction = 0;
338 ignore_route_order_sync = false;
340 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
341 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
342 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
343 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
344 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
346 range_marker_drag_rect = 0;
347 marker_drag_line = 0;
348 tempo_map_change_idle_handler_id = -1;
349 canvas_hroizontally_scrolled_handler_id = -1;
350 set_midi_edit_mode (MidiEditPencil, true);
351 set_mouse_mode (MouseObject, true);
353 frames_per_unit = 2048; /* too early to use reset_zoom () */
354 reset_hscrollbar_stepping ();
356 zoom_focus = ZoomFocusLeft;
357 set_zoom_focus (ZoomFocusLeft);
358 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
360 initialize_rulers ();
361 initialize_canvas ();
363 edit_controls_vbox.set_spacing (0);
364 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
365 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
367 track_canvas.set_hadjustment (horizontal_adjustment);
368 track_canvas.set_vadjustment (vertical_adjustment);
369 time_canvas.set_hadjustment (horizontal_adjustment);
371 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
372 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
374 controls_layout.add (edit_controls_vbox);
375 controls_layout.set_name ("EditControlsBase");
376 controls_layout.add_events (Gdk::SCROLL_MASK);
377 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
379 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
380 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
381 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
383 edit_vscrollbar.set_adjustment (vertical_adjustment);
384 edit_hscrollbar.set_adjustment (horizontal_adjustment);
386 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
387 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
388 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
390 edit_hscrollbar.set_name ("EditorHScrollbar");
394 setup_midi_toolbar ();
396 edit_point_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_point_clock_changed));
398 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
399 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
400 0.0, 1.0, 100.0, 1.0));
401 pad_line_1->property_color_rgba() = 0xFF0000FF;
405 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
406 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
407 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
408 time_canvas_vbox.pack_start (*frames_ruler, false, false);
409 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
410 time_canvas_vbox.pack_start (time_canvas, true, true);
411 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 5);
413 bbt_label.set_name ("EditorTimeButton");
414 bbt_label.set_size_request (-1, (int)timebar_height);
415 bbt_label.set_alignment (1.0, 0.5);
416 bbt_label.set_padding (5,0);
417 minsec_label.set_name ("EditorTimeButton");
418 minsec_label.set_size_request (-1, (int)timebar_height);
419 minsec_label.set_alignment (1.0, 0.5);
420 minsec_label.set_padding (5,0);
421 smpte_label.set_name ("EditorTimeButton");
422 smpte_label.set_size_request (-1, (int)timebar_height);
423 smpte_label.set_alignment (1.0, 0.5);
424 smpte_label.set_padding (5,0);
425 frame_label.set_name ("EditorTimeButton");
426 frame_label.set_size_request (-1, (int)timebar_height);
427 frame_label.set_alignment (1.0, 0.5);
428 frame_label.set_padding (5,0);
429 tempo_label.set_name ("EditorTimeButton");
430 tempo_label.set_size_request (-1, (int)timebar_height);
431 tempo_label.set_alignment (1.0, 0.5);
432 tempo_label.set_padding (5,0);
433 meter_label.set_name ("EditorTimeButton");
434 meter_label.set_size_request (-1, (int)timebar_height);
435 meter_label.set_alignment (1.0, 0.5);
436 meter_label.set_padding (5,0);
437 mark_label.set_name ("EditorTimeButton");
438 mark_label.set_size_request (-1, (int)timebar_height);
439 mark_label.set_alignment (1.0, 0.5);
440 mark_label.set_padding (5,0);
441 range_mark_label.set_name ("EditorTimeButton");
442 range_mark_label.set_size_request (-1, (int)timebar_height);
443 range_mark_label.set_alignment (1.0, 0.5);
444 range_mark_label.set_padding (5,0);
445 transport_mark_label.set_name ("EditorTimeButton");
446 transport_mark_label.set_size_request (-1, (int)timebar_height);
447 transport_mark_label.set_alignment (1.0, 0.5);
448 transport_mark_label.set_padding (5,0);
450 time_button_vbox.pack_start (minsec_label, false, false);
451 time_button_vbox.pack_start (smpte_label, false, false);
452 time_button_vbox.pack_start (frame_label, false, false);
453 time_button_vbox.pack_start (bbt_label, false, false);
454 time_button_vbox.pack_start (meter_label, false, false);
455 time_button_vbox.pack_start (tempo_label, false, false);
456 time_button_vbox.pack_start (mark_label, false, false);
458 time_button_event_box.add (time_button_vbox);
459 time_button_event_box.set_name ("TimebarLabelBase");
460 time_button_frame.set_shadow_type (Gtk::SHADOW_NONE);
462 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
463 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
465 time_button_frame.add (time_button_event_box);
466 time_button_frame.set_name ("TimebarLabelBase");
467 time_button_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
469 /* these enable us to have a dedicated window (for cursor setting, etc.)
470 for the canvas areas.
473 track_canvas_event_box.add (track_canvas);
475 time_canvas_event_box.add (time_canvas_vbox);
476 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
478 edit_packer.set_col_spacings (0);
479 edit_packer.set_row_spacings (0);
480 edit_packer.set_homogeneous (false);
481 edit_packer.set_border_width (0);
482 edit_packer.set_name ("EditorWindow");
484 edit_packer.attach (edit_vscrollbar, 3, 4, 1, 2, FILL, FILL|EXPAND, 0, 0);
486 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, SHRINK, 0, 0);
487 edit_packer.attach (time_canvas_event_box, 2, 4, 0, 1, FILL|EXPAND, FILL, 0, 0);
489 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
490 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
492 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
493 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
495 bottom_hbox.set_border_width (2);
496 bottom_hbox.set_spacing (3);
498 route_display_model = ListStore::create(route_display_columns);
499 route_list_display.set_model (route_display_model);
500 route_list_display.append_column (_("Show"), route_display_columns.visible);
501 route_list_display.append_column (_("Name"), route_display_columns.text);
502 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
503 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
504 route_list_display.set_headers_visible (true);
505 route_list_display.set_name ("TrackListDisplay");
506 route_list_display.get_selection()->set_mode (SELECTION_NONE);
507 route_list_display.set_reorderable (true);
508 route_list_display.set_size_request (100,-1);
510 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
511 route_list_visible_cell->property_activatable() = true;
512 route_list_visible_cell->property_radio() = false;
514 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
515 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
517 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
519 route_list_scroller.add (route_list_display);
520 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
522 group_model = ListStore::create(group_columns);
523 edit_group_display.set_model (group_model);
524 edit_group_display.append_column (_("Name"), group_columns.text);
525 edit_group_display.append_column (_("Active"), group_columns.is_active);
526 edit_group_display.append_column (_("Show"), group_columns.is_visible);
527 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
528 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
529 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
530 edit_group_display.get_column (0)->set_expand (true);
531 edit_group_display.get_column (1)->set_expand (false);
532 edit_group_display.get_column (2)->set_expand (false);
533 edit_group_display.set_headers_visible (true);
535 /* name is directly editable */
537 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
538 name_cell->property_editable() = true;
539 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
541 /* use checkbox for the active + visible columns */
543 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
544 active_cell->property_activatable() = true;
545 active_cell->property_radio() = false;
547 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
548 active_cell->property_activatable() = true;
549 active_cell->property_radio() = false;
551 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
553 edit_group_display.set_name ("EditGroupList");
554 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
555 edit_group_display.set_headers_visible (true);
556 edit_group_display.set_reorderable (false);
557 edit_group_display.set_rules_hint (true);
558 edit_group_display.set_size_request (75, -1);
560 edit_group_display_scroller.add (edit_group_display);
561 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
563 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
565 VBox* edit_group_display_packer = manage (new VBox());
566 HBox* edit_group_display_button_box = manage (new HBox());
567 edit_group_display_button_box->set_homogeneous (true);
569 Button* edit_group_add_button = manage (new Button ());
570 Button* edit_group_remove_button = manage (new Button ());
574 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
576 edit_group_add_button->add (*w);
578 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
580 edit_group_remove_button->add (*w);
582 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
583 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
585 edit_group_display_button_box->pack_start (*edit_group_add_button);
586 edit_group_display_button_box->pack_start (*edit_group_remove_button);
588 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
589 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
591 region_list_display.set_size_request (100, -1);
592 region_list_display.set_name ("RegionListDisplay");
594 region_list_model = TreeStore::create (region_list_columns);
595 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
596 region_list_model->set_sort_column (0, SORT_ASCENDING);
598 region_list_display.set_model (region_list_model);
599 region_list_display.append_column (_("Regions"), region_list_columns.name);
600 region_list_display.set_headers_visible (false);
602 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
604 TreeViewColumn* tv_col = region_list_display.get_column(0);
605 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
606 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
607 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
609 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
610 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
612 /* setup DnD handling */
614 list<TargetEntry> region_list_target_table;
616 region_list_target_table.push_back (TargetEntry ("text/plain"));
617 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
618 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
620 region_list_display.add_drop_targets (region_list_target_table);
621 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
623 region_list_scroller.add (region_list_display);
624 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
626 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
627 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
628 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
629 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
630 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
631 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
633 named_selection_scroller.add (named_selection_display);
634 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
636 named_selection_model = TreeStore::create (named_selection_columns);
637 named_selection_display.set_model (named_selection_model);
638 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
639 named_selection_display.set_headers_visible (false);
640 named_selection_display.set_size_request (100, -1);
641 named_selection_display.set_name ("NamedSelectionDisplay");
643 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
644 named_selection_display.set_size_request (100, -1);
645 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
646 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
647 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
651 snapshot_display_model = ListStore::create (snapshot_display_columns);
652 snapshot_display.set_model (snapshot_display_model);
653 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
654 snapshot_display.set_name ("SnapshotDisplay");
655 snapshot_display.set_size_request (75, -1);
656 snapshot_display.set_headers_visible (false);
657 snapshot_display.set_reorderable (false);
658 snapshot_display_scroller.add (snapshot_display);
659 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
661 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
662 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
666 nlabel = manage (new Label (_("Regions")));
667 nlabel->set_angle (-90);
668 the_notebook.append_page (region_list_scroller, *nlabel);
669 nlabel = manage (new Label (_("Tracks/Busses")));
670 nlabel->set_angle (-90);
671 the_notebook.append_page (route_list_scroller, *nlabel);
672 nlabel = manage (new Label (_("Snapshots")));
673 nlabel->set_angle (-90);
674 the_notebook.append_page (snapshot_display_scroller, *nlabel);
675 nlabel = manage (new Label (_("Edit Groups")));
676 nlabel->set_angle (-90);
677 the_notebook.append_page (*edit_group_display_packer, *nlabel);
678 nlabel = manage (new Label (_("Chunks")));
679 nlabel->set_angle (-90);
680 the_notebook.append_page (named_selection_scroller, *nlabel);
682 the_notebook.set_show_tabs (true);
683 the_notebook.set_scrollable (true);
684 the_notebook.popup_enable ();
685 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
687 post_maximal_editor_width = 0;
688 post_maximal_pane_position = 0;
689 edit_pane.pack1 (edit_packer, true, true);
690 edit_pane.pack2 (the_notebook, false, true);
692 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
694 top_hbox.pack_start (toolbar_frame, false, true);
695 top_hbox.pack_start (midi_toolbar_frame, false, true);
697 HBox *hbox = manage (new HBox);
698 hbox->pack_start (edit_pane, true, true);
700 global_vpacker.pack_start (top_hbox, false, false);
701 global_vpacker.pack_start (*hbox, true, true);
703 global_hpacker.pack_start (global_vpacker, true, true);
705 set_name ("EditorWindow");
706 add_accel_group (ActionManager::ui_manager->get_accel_group());
708 status_bar_hpacker.show ();
710 vpacker.pack_end (status_bar_hpacker, false, false);
711 vpacker.pack_end (global_hpacker, true, true);
713 /* register actions now so that set_state() can find them and set toggles/checks etc */
717 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
720 _playlist_selector = new PlaylistSelector();
721 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
723 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
727 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
728 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
730 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
731 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
733 nudge_forward_button.set_name ("TransportButton");
734 nudge_backward_button.set_name ("TransportButton");
736 fade_context_menu.set_name ("ArdourContextMenu");
738 /* icons, titles, WM stuff */
740 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
741 Glib::RefPtr<Gdk::Pixbuf> icon;
743 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
744 window_icons.push_back (icon);
746 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
747 window_icons.push_back (icon);
749 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
750 window_icons.push_back (icon);
752 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
753 window_icons.push_back (icon);
755 if (!window_icons.empty()) {
756 set_icon_list (window_icons);
757 set_default_icon_list (window_icons);
760 WindowTitle title(Glib::get_application_name());
761 title += _("Editor");
762 set_title (title.get_string());
763 set_wmclass (X_("ardour_editor"), "Ardour");
766 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
768 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
769 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
771 /* allow external control surfaces/protocols to do various things */
773 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
774 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
775 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
776 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
778 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
779 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
788 if(image_socket_listener)
790 if(image_socket_listener->is_connected())
792 image_socket_listener->close_connection() ;
795 delete image_socket_listener ;
796 image_socket_listener = 0 ;
802 Editor::add_toplevel_controls (Container& cont)
804 vpacker.pack_start (cont, false, false);
809 Editor::catch_vanishing_regionview (RegionView *rv)
811 /* note: the selection will take care of the vanishing
812 audioregionview by itself.
815 if (clicked_regionview == rv) {
816 clicked_regionview = 0;
819 if (entered_regionview == rv) {
820 set_entered_regionview (0);
825 Editor::set_entered_regionview (RegionView* rv)
827 if (rv == entered_regionview) {
831 if (entered_regionview) {
832 entered_regionview->exited ();
835 if ((entered_regionview = rv) != 0) {
836 entered_regionview->entered ();
841 Editor::set_entered_track (TimeAxisView* tav)
844 entered_track->exited ();
847 if ((entered_track = tav) != 0) {
848 entered_track->entered ();
853 Editor::show_window ()
855 show_all_children ();
857 /* re-hide editor list if necessary */
858 editor_list_button_toggled ();
860 /* now reset all audio_time_axis heights, because widgets might need
866 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
867 tv = (static_cast<TimeAxisView*>(*i));
875 Editor::tie_vertical_scrolling ()
877 double y1 = vertical_adjustment.get_value();
879 playhead_cursor->set_y_axis (y1);
881 logo_item->property_y() = y1;
884 controls_layout.get_vadjustment()->set_value (y1);
887 /* the way idle updates and immediate window flushing work on GTK-Quartz
888 requires that we force an immediate redraw right here. The controls
889 layout will do the same all by itself, as does the canvas widget, but
890 most of the time, the canvas itself hasn't updated itself because its
891 idle handler hasn't run. consequently, the call that its layout makes
892 to gdk_window_process_updates() finds nothing to do. here, we force
893 the update to happen, then request a flush of the new window state.
895 track_canvas.update_now ();
896 gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
901 Editor::instant_save ()
903 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
908 session->add_instant_xml(get_state());
910 Config->add_instant_xml(get_state());
915 Editor::edit_point_clock_changed()
917 if (_dragging_edit_point) {
921 if (selection->markers.empty()) {
926 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
932 loc->move_to (edit_point_clock.current_time());
936 Editor::zoom_adjustment_changed ()
942 double fpu = zoom_range_clock.current_duration() / canvas_width;
946 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
947 } else if (fpu > session->current_end_frame() / canvas_width) {
948 fpu = session->current_end_frame() / canvas_width;
949 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
956 Editor::control_scroll (float fraction)
958 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
964 double step = fraction * current_page_frames();
967 _control_scroll_target is an optional<T>
969 it acts like a pointer to an nframes_t, with
970 a operator conversion to boolean to check
971 that it has a value could possibly use
972 playhead_cursor->current_frame to store the
973 value and a boolean in the class to know
974 when it's out of date
977 if (!_control_scroll_target) {
978 _control_scroll_target = session->transport_frame();
979 _dragging_playhead = true;
982 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
983 *_control_scroll_target = 0;
984 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
985 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
987 *_control_scroll_target += (nframes_t) floor (step);
990 /* move visuals, we'll catch up with it later */
992 playhead_cursor->set_position (*_control_scroll_target);
993 UpdateAllTransportClocks (*_control_scroll_target);
995 if (*_control_scroll_target > (current_page_frames() / 2)) {
996 /* try to center PH in window */
997 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1003 Now we do a timeout to actually bring the session to the right place
1004 according to the playhead. This is to avoid reading disk buffers on every
1005 call to control_scroll, which is driven by ScrollTimeline and therefore
1006 probably by a control surface wheel which can generate lots of events.
1008 /* cancel the existing timeout */
1010 control_scroll_connection.disconnect ();
1012 /* add the next timeout */
1014 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1018 Editor::deferred_control_scroll (nframes_t target)
1020 session->request_locate (*_control_scroll_target, session->transport_rolling());
1021 // reset for next stream
1022 _control_scroll_target = boost::none;
1023 _dragging_playhead = false;
1028 Editor::on_realize ()
1030 Window::on_realize ();
1035 Editor::start_scrolling ()
1037 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1038 (mem_fun(*this, &Editor::update_current_screen));
1042 Editor::stop_scrolling ()
1044 scroll_connection.disconnect ();
1048 Editor::map_position_change (nframes_t frame)
1050 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1052 if (session == 0 || !_follow_playhead) {
1056 center_screen (frame);
1057 playhead_cursor->set_position (frame);
1061 Editor::center_screen (nframes_t frame)
1063 double page = canvas_width * frames_per_unit;
1065 /* if we're off the page, then scroll.
1068 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1069 center_screen_internal (frame, page);
1074 Editor::center_screen_internal (nframes_t frame, float page)
1079 frame -= (nframes_t) page;
1084 reset_x_origin (frame);
1088 Editor::handle_new_duration ()
1090 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1092 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1094 if (new_end > last_canvas_frame) {
1095 last_canvas_frame = new_end;
1096 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1097 reset_scrolling_region ();
1100 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1104 Editor::update_title_s (const string & snap_name)
1106 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1112 Editor::update_title ()
1114 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1117 bool dirty = session->dirty();
1119 string session_name;
1121 if (session->snap_name() != session->name()) {
1122 session_name = session->snap_name();
1124 session_name = session->name();
1128 session_name = "*" + session_name;
1131 WindowTitle title(session_name);
1132 title += Glib::get_application_name();
1133 set_title (title.get_string());
1138 Editor::connect_to_session (Session *t)
1142 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1145 /* catch up with the playhead */
1147 session->request_locate (playhead_cursor->current_frame);
1149 if (first_action_message) {
1150 first_action_message->hide();
1155 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1156 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1158 /* These signals can all be emitted by a non-GUI thread. Therefore the
1159 handlers for them must not attempt to directly interact with the GUI,
1160 but use Gtkmm2ext::UI::instance()->call_slot();
1163 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1164 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1165 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1166 session_connections.push_back (session->RegionAdded.connect (mem_fun(*this, &Editor::handle_new_region)));
1167 session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed)));
1168 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1169 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1170 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1171 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1172 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1173 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1174 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1175 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1176 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1178 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1180 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1182 edit_groups_changed ();
1184 edit_point_clock.set_session (session);
1185 zoom_range_clock.set_session (session);
1186 _playlist_selector->set_session (session);
1187 nudge_clock.set_session (session);
1190 if (analysis_window != 0)
1191 analysis_window->set_session (session);
1194 Location* loc = session->locations()->auto_loop_location();
1196 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1197 if (loc->start() == loc->end()) {
1198 loc->set_end (loc->start() + 1);
1200 session->locations()->add (loc, false);
1201 session->set_auto_loop_location (loc);
1204 loc->set_name (_("Loop"));
1207 loc = session->locations()->auto_punch_location();
1209 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1210 if (loc->start() == loc->end()) {
1211 loc->set_end (loc->start() + 1);
1213 session->locations()->add (loc, false);
1214 session->set_auto_punch_location (loc);
1217 loc->set_name (_("Punch"));
1220 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1222 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1224 refresh_location_display ();
1225 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1226 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1227 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1228 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1229 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1232 sfbrowser->set_session (session);
1235 handle_new_duration ();
1237 redisplay_regions ();
1238 redisplay_named_selections ();
1239 redisplay_snapshots ();
1241 initial_route_list_display ();
1243 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1244 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1247 restore_ruler_visibility ();
1248 //tempo_map_changed (Change (0));
1249 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1253 /* don't show master bus in a new session */
1255 if (ARDOUR_UI::instance()->session_is_new ()) {
1257 TreeModel::Children rows = route_display_model->children();
1258 TreeModel::Children::iterator i;
1260 no_route_list_redisplay = true;
1262 for (i = rows.begin(); i != rows.end(); ++i) {
1263 TimeAxisView *tv = (*i)[route_display_columns.tv];
1264 RouteTimeAxisView *rtv;
1266 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1267 if (rtv->route()->is_master()) {
1268 route_list_display.get_selection()->unselect (i);
1273 no_route_list_redisplay = false;
1274 redisplay_route_list ();
1277 /* register for undo history */
1279 session->register_with_memento_command_factory(_id, this);
1283 Editor::build_cursors ()
1285 using namespace Gdk;
1287 Gdk::Color mbg ("#000000" ); /* Black */
1288 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1291 RefPtr<Bitmap> source, mask;
1292 source = Bitmap::create (mag_bits, mag_width, mag_height);
1293 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1294 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1297 Gdk::Color fbg ("#ffffff" );
1298 Gdk::Color ffg ("#000000" );
1301 RefPtr<Bitmap> source, mask;
1303 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1304 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1305 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1309 RefPtr<Bitmap> source, mask;
1310 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1311 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1312 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1316 RefPtr<Bitmap> bits;
1317 char pix[4] = { 0, 0, 0, 0 };
1318 bits = Bitmap::create (pix, 2, 2);
1320 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1323 grabber_cursor = new Gdk::Cursor (HAND2);
1324 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1325 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1326 selector_cursor = new Gdk::Cursor (XTERM);
1327 time_fx_cursor = new Gdk::Cursor (SIZING);
1328 wait_cursor = new Gdk::Cursor (WATCH);
1329 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1330 midi_pencil_cursor = new Gdk::Cursor (PENCIL);
1331 midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
1332 midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
1335 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1337 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1339 using namespace Menu_Helpers;
1340 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1343 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1347 MenuList& items (fade_context_menu.items());
1351 switch (item_type) {
1353 case FadeInHandleItem:
1354 if (arv->audio_region()->fade_in_active()) {
1355 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1357 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1360 items.push_back (SeparatorElem());
1362 if (Profile->get_sae()) {
1363 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1364 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1366 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1367 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1368 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1369 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1370 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1376 case FadeOutHandleItem:
1377 if (arv->audio_region()->fade_out_active()) {
1378 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1380 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1383 items.push_back (SeparatorElem());
1385 if (Profile->get_sae()) {
1386 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1387 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1389 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1390 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1391 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1392 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1393 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1399 fatal << _("programming error: ")
1400 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1405 fade_context_menu.popup (button, time);
1408 /* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
1410 Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
1412 build_track_context_menu (frame)->popup (button, time);
1416 Editor::build_track_context_menu (nframes_t frame)
1418 using namespace Menu_Helpers;
1420 Menu* menu = manage (new Menu);
1421 MenuList& edit_items = menu->items();
1424 /* Build the general `track' context menu, adding what is appropriate given
1425 the current selection */
1427 /* XXX: currently crossfades can't be selected, so we can't use the selection
1428 to decide which crossfades to mention in the menu. I believe this will
1429 change at some point. For now we have to use clicked_trackview to decide. */
1430 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1433 boost::shared_ptr<Diskstream> ds;
1434 boost::shared_ptr<Playlist> pl;
1435 boost::shared_ptr<AudioPlaylist> apl;
1437 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1439 AudioPlaylist::Crossfades xfades;
1440 apl->crossfades_at (frame, xfades);
1442 bool many = xfades.size() > 1;
1444 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1445 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1450 if (!selection->time.empty()) {
1451 add_selection_context_items (edit_items);
1454 if (!selection->regions.empty()) {
1455 add_region_context_items (edit_items);
1458 if (!selection->tracks.empty()) {
1459 add_bus_or_audio_track_context_items (edit_items);
1462 menu->set_name ("ArdourContextMenu");
1469 Editor::analyze_region_selection()
1471 if (analysis_window == 0) {
1472 analysis_window = new AnalysisWindow();
1475 analysis_window->set_session(session);
1477 analysis_window->show_all();
1480 analysis_window->set_regionmode();
1481 analysis_window->analyze();
1483 analysis_window->present();
1487 Editor::analyze_range_selection()
1489 if (analysis_window == 0) {
1490 analysis_window = new AnalysisWindow();
1493 analysis_window->set_session(session);
1495 analysis_window->show_all();
1498 analysis_window->set_rangemode();
1499 analysis_window->analyze();
1501 analysis_window->present();
1503 #endif /* FFT_ANALYSIS */
1506 /** Add context menu items relevant to crossfades.
1507 * @param edit_items List to add the items to.
1510 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1512 using namespace Menu_Helpers;
1513 Menu *xfade_menu = manage (new Menu);
1514 MenuList& items = xfade_menu->items();
1515 xfade_menu->set_name ("ArdourContextMenu");
1518 if (xfade->active()) {
1524 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1525 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1527 if (xfade->can_follow_overlap()) {
1529 if (xfade->following_overlap()) {
1530 str = _("Convert to short");
1532 str = _("Convert to full");
1535 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1539 str = xfade->out()->name();
1541 str += xfade->in()->name();
1543 str = _("Crossfade");
1546 edit_items.push_back (MenuElem (str, *xfade_menu));
1547 edit_items.push_back (SeparatorElem());
1551 Editor::xfade_edit_left_region ()
1553 if (clicked_crossfadeview) {
1554 clicked_crossfadeview->left_view.show_region_editor ();
1559 Editor::xfade_edit_right_region ()
1561 if (clicked_crossfadeview) {
1562 clicked_crossfadeview->right_view.show_region_editor ();
1566 /** Add an element to a menu, settings its sensitivity.
1567 * @param m Menu to add to.
1568 * @param e Element to add.
1569 * @param s true to make sensitive, false to make insensitive
1572 Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
1576 m.back().set_sensitive (false);
1580 /** Add context menu items relevant to regions.
1581 * @param edit_items List to add the items to.
1584 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
1586 using namespace Menu_Helpers;
1587 sigc::connection fooc;
1588 Menu *region_menu = manage (new Menu);
1589 MenuList& items = region_menu->items();
1590 region_menu->set_name ("ArdourContextMenu");
1592 items.push_back (MenuElem (_("Edit..."), mem_fun(*this, &Editor::edit_region)));
1593 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1594 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1596 Menu* sync_point_menu = manage (new Menu);
1597 MenuList& sync_point_items = sync_point_menu->items();
1598 sync_point_menu->set_name("ArdourContextMenu");
1600 sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_point)));
1601 sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
1603 items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
1605 add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
1607 add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
1609 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1612 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1615 items.push_back (SeparatorElem());
1617 items.push_back (CheckMenuElem (_("Lock")));
1618 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1619 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1621 #if FIXUP_REGION_MENU
1622 if (region->locked()) {
1624 region_lock_item->set_active();
1629 items.push_back (CheckMenuElem (_("Lock Position")));
1630 region_lock_position_item = static_cast<CheckMenuItem*>(&items.back());
1631 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_position_lock));
1632 #if FIXUP_REGION_MENU
1633 if (region->locked()) {
1635 region_lock_position_item->set_active();
1640 items.push_back (CheckMenuElem (_("Mute")));
1641 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1642 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1643 #if FIXUP_REGION_MENU
1644 if (region->muted()) {
1646 region_mute_item->set_active();
1651 if (!Profile->get_sae()) {
1652 items.push_back (CheckMenuElem (_("Opaque")));
1653 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1654 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1655 #if FIXUP_REGION_MENU
1656 if (region->opaque()) {
1658 region_opaque_item->set_active();
1664 /* We allow "Original position" if at least one region is not at its
1667 RegionSelection::iterator i = selection->regions.begin();
1668 while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
1672 add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
1674 items.push_back (SeparatorElem());
1676 /* Find out if we have a selected audio region */
1677 i = selection->regions.begin();
1678 while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
1681 const bool have_selected_audio_region = (i != selection->regions.end());
1683 if (have_selected_audio_region) {
1685 Menu* envelopes_menu = manage (new Menu);
1687 envelopes_menu->set_name ("ArdourContextMenu");
1689 #if FIXUP_REGION_MENU
1691 XXX NEED TO RESOLVE ONE v. MANY REGION ISSUE
1693 MenuList& envelopes_items = envelopes_menu->items();
1695 RegionView* rv = sv->find_view (ar);
1696 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1698 if (!Profile->get_sae()) {
1699 envelopes_items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1701 envelopes_items.push_back (CheckMenuElem (_("Envelope Visible")));
1702 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1703 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1704 if (arv->envelope_visible()) {
1706 region_envelope_visible_item->set_active (true);
1710 envelopes_items.push_back (CheckMenuElem (_("Envelope Active")));
1711 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1712 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1714 if (ar->envelope_active()) {
1716 region_envelope_active_item->set_active (true);
1720 items.push_back (SeparatorElem());
1724 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1726 #if FIXUP_REGION_MENU
1727 if (ar->scale_amplitude() != 1.0f) {
1728 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_regions)));
1730 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_regions)));
1735 /* Find out if we have a selected MIDI region */
1736 i = selection->regions.begin();
1737 while (i != selection->regions.end() && boost::dynamic_pointer_cast<MidiRegion>((*i)->region()) == 0) {
1740 const bool have_selected_midi_region = (i != selection->regions.end());
1742 if (have_selected_midi_region) {
1744 items.push_back (MenuElem (_("Quantize"), mem_fun(*this, &Editor::quantize_regions)));
1745 items.push_back (SeparatorElem());
1749 /* range related stuff */
1751 add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1753 add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1755 items.push_back (SeparatorElem());
1759 Menu *nudge_menu = manage (new Menu());
1760 MenuList& nudge_items = nudge_menu->items();
1761 nudge_menu->set_name ("ArdourContextMenu");
1763 nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1764 nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1765 nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1766 nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1768 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1770 Menu *trim_menu = manage (new Menu);
1771 MenuList& trim_items = trim_menu->items();
1772 trim_menu->set_name ("ArdourContextMenu");
1774 trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point)));
1775 trim_items.push_back (MenuElem (_("Edit point to end"), mem_fun(*this, &Editor::trim_region_to_edit_point)));
1776 trim_items.push_back (MenuElem (_("Trim To Loop"), mem_fun(*this, &Editor::trim_region_to_loop)));
1777 trim_items.push_back (MenuElem (_("Trim To Punch"), mem_fun(*this, &Editor::trim_region_to_punch)));
1779 items.push_back (MenuElem (_("Trim"), *trim_menu));
1780 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1781 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1782 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1783 items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1784 items.push_back (SeparatorElem());
1785 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1787 /* OK, stick the region submenu at the top of the list, and then add
1791 string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1792 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1795 /** Add context menu items relevant to selection ranges.
1796 * @param edit_items List to add the items to.
1799 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1801 using namespace Menu_Helpers;
1802 Menu *selection_menu = manage (new Menu);
1803 MenuList& items = selection_menu->items();
1804 selection_menu->set_name ("ArdourContextMenu");
1806 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1807 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1810 items.push_back (SeparatorElem());
1811 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1814 items.push_back (SeparatorElem());
1815 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1816 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1818 items.push_back (SeparatorElem());
1819 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1820 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1822 items.push_back (SeparatorElem());
1823 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1825 items.push_back (SeparatorElem());
1826 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1827 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1829 items.push_back (SeparatorElem());
1830 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1831 items.push_back (SeparatorElem());
1832 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1833 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1834 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1835 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1836 items.push_back (SeparatorElem());
1837 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1838 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1841 /** Add context menu items relevant to busses or audio tracks.
1842 * @param edit_items List to add the items to.
1845 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1847 using namespace Menu_Helpers;
1849 /* We add every possible action here, and de-sensitize things
1850 that aren't allowed. The sensitivity logic is a bit spread out;
1851 on the one hand I'm using things like can_cut_copy (), which is
1852 reasonably complicated and so perhaps better near the function that
1853 it expresses sensitivity for, and on the other hand checks
1854 in this function as well. You can't really have can_* for everything
1855 or the number of methods would get silly. */
1857 bool const one_selected_region = selection->regions.size() == 1;
1859 /* Count the number of selected audio tracks */
1860 int n_audio_tracks = 0;
1861 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1862 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1863 if (r && r->is_audio_track()) {
1870 Menu *play_menu = manage (new Menu);
1871 MenuList& play_items = play_menu->items();
1872 play_menu->set_name ("ArdourContextMenu");
1874 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
1875 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1876 add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1878 add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1880 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1884 Menu *select_menu = manage (new Menu);
1885 MenuList& select_items = select_menu->items();
1886 select_menu->set_name ("ArdourContextMenu");
1888 string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1890 select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1892 select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1894 str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1896 select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1898 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1899 select_items.push_back (SeparatorElem());
1901 if (n_audio_tracks) {
1902 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1903 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1906 select_items.push_back (MenuElem (_("Select All After Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1907 select_items.push_back (MenuElem (_("Select All Before Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1908 select_items.push_back (MenuElem (_("Select All After Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1909 select_items.push_back (MenuElem (_("Select All Before Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1910 select_items.push_back (MenuElem (_("Select All Between Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), false)));
1911 select_items.push_back (MenuElem (_("Select All Within Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), true)));
1912 select_items.push_back (MenuElem (_("Select Range Between Playhead & Edit Point"), mem_fun(*this, &Editor::select_range_between)));
1914 select_items.push_back (SeparatorElem());
1916 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1920 Menu *cutnpaste_menu = manage (new Menu);
1921 MenuList& cutnpaste_items = cutnpaste_menu->items();
1922 cutnpaste_menu->set_name ("ArdourContextMenu");
1924 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1925 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1926 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1928 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1930 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1932 if (n_audio_tracks) {
1933 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1934 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1936 cutnpaste_items.push_back (SeparatorElem());
1938 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1939 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1940 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1942 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1945 edit_items.push_back (SeparatorElem());
1946 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1948 if (n_audio_tracks) {
1950 Menu *track_menu = manage (new Menu);
1951 MenuList& track_items = track_menu->items();
1952 track_menu->set_name ("ArdourContextMenu");
1954 /* Adding new material */
1956 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);
1957 add_item_with_sensitivity (track_items, MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1961 Menu *nudge_menu = manage (new Menu());
1962 MenuList& nudge_items = nudge_menu->items();
1963 nudge_menu->set_name ("ArdourContextMenu");
1965 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1967 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1969 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1971 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1973 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1975 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1977 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1980 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1981 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1983 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1984 edit_items.push_back (MenuElem (str, *track_menu));
1988 /* CURSOR SETTING AND MARKS AND STUFF */
1991 Editor::set_snap_to (SnapType st)
1994 string str = snap_type_strings[(int) st];
1996 if (str != snap_type_selector.get_active_text()) {
1997 snap_type_selector.set_active_text (str);
2002 switch (snap_type) {
2003 case SnapToAThirtysecondBeat:
2004 case SnapToASixteenthBeat:
2005 case SnapToAEighthBeat:
2006 case SnapToAQuarterBeat:
2007 case SnapToAThirdBeat:
2008 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + (nframes_t)(canvas_width * frames_per_unit));
2009 update_tempo_based_rulers ();
2018 Editor::set_snap_mode (SnapMode mode)
2021 string str = snap_mode_strings[(int)mode];
2023 if (str != snap_mode_selector.get_active_text ()) {
2024 snap_mode_selector.set_active_text (str);
2030 Editor::set_edit_point_preference (EditPoint ep)
2033 string str = edit_point_strings[(int)ep];
2035 if (str != edit_point_selector.get_active_text ()) {
2036 edit_point_selector.set_active_text (str);
2043 Editor::set_state (const XMLNode& node)
2045 const XMLProperty* prop;
2047 int x, y, xoff, yoff;
2050 if ((prop = node.property ("id")) != 0) {
2051 _id = prop->value ();
2054 if ((geometry = find_named_node (node, "geometry")) == 0) {
2056 g.base_width = default_width;
2057 g.base_height = default_height;
2065 g.base_width = atoi(geometry->property("x_size")->value());
2066 g.base_height = atoi(geometry->property("y_size")->value());
2067 x = atoi(geometry->property("x_pos")->value());
2068 y = atoi(geometry->property("y_pos")->value());
2069 xoff = atoi(geometry->property("x_off")->value());
2070 yoff = atoi(geometry->property("y_off")->value());
2073 set_default_size (g.base_width, g.base_height);
2076 if (session && (prop = node.property ("playhead"))) {
2077 nframes_t pos = atol (prop->value().c_str());
2078 playhead_cursor->set_position (pos);
2080 playhead_cursor->set_position (0);
2082 /* reset_x_origin() doesn't work right here, since the old
2083 position may be zero already, and it does nothing in such
2088 horizontal_adjustment.set_value (0);
2091 if ((prop = node.property ("mixer-width"))) {
2092 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2095 if ((prop = node.property ("zoom-focus"))) {
2096 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2099 if ((prop = node.property ("zoom"))) {
2100 reset_zoom (PBD::atof (prop->value()));
2103 if ((prop = node.property ("snap-to"))) {
2104 set_snap_to ((SnapType) atoi (prop->value()));
2107 if ((prop = node.property ("snap-mode"))) {
2108 set_snap_mode ((SnapMode) atoi (prop->value()));
2111 if ((prop = node.property ("edit-point"))) {
2112 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point));
2115 if ((prop = node.property ("mouse-mode"))) {
2116 MouseMode m = str2mousemode(prop->value());
2117 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2118 set_mouse_mode (m, true);
2120 mouse_mode = MouseGain; /* lie, to force the mode switch */
2121 set_mouse_mode (MouseObject, true);
2124 if ((prop = node.property ("show-waveforms"))) {
2125 bool yn = (prop->value() == "yes");
2126 _show_waveforms = !yn;
2127 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2129 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2130 /* do it twice to force the change */
2131 tact->set_active (!yn);
2132 tact->set_active (yn);
2136 if ((prop = node.property ("show-waveforms-recording"))) {
2137 bool yn = (prop->value() == "yes");
2138 _show_waveforms_recording = !yn;
2139 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2141 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2142 /* do it twice to force the change */
2143 tact->set_active (!yn);
2144 tact->set_active (yn);
2148 if ((prop = node.property ("show-measures"))) {
2149 bool yn = (prop->value() == "yes");
2150 _show_measures = !yn;
2151 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2153 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2154 /* do it twice to force the change */
2155 tact->set_active (!yn);
2156 tact->set_active (yn);
2160 if ((prop = node.property ("follow-playhead"))) {
2161 bool yn = (prop->value() == "yes");
2162 set_follow_playhead (yn);
2163 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2165 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2166 if (tact->get_active() != yn) {
2167 tact->set_active (yn);
2172 if ((prop = node.property ("region-list-sort-type"))) {
2173 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2174 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2177 if ((prop = node.property ("xfades-visible"))) {
2178 bool yn = (prop->value() == "yes");
2179 _xfade_visibility = !yn;
2180 // set_xfade_visibility (yn);
2183 if ((prop = node.property ("show-editor-mixer"))) {
2185 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2188 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2189 bool yn = (prop->value() == X_("yes"));
2191 /* do it twice to force the change */
2193 tact->set_active (!yn);
2194 tact->set_active (yn);
2198 if ((prop = node.property ("show-editor-list"))) {
2200 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2204 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2205 bool yn = (prop->value() == X_("yes"));
2207 /* do it twice to force the change */
2209 tact->set_active (!yn);
2210 tact->set_active (yn);
2219 Editor::get_state ()
2221 XMLNode* node = new XMLNode ("Editor");
2224 _id.print (buf, sizeof (buf));
2225 node->add_property ("id", buf);
2227 if (is_realized()) {
2228 Glib::RefPtr<Gdk::Window> win = get_window();
2230 int x, y, xoff, yoff, width, height;
2231 win->get_root_origin(x, y);
2232 win->get_position(xoff, yoff);
2233 win->get_size(width, height);
2235 XMLNode* geometry = new XMLNode ("geometry");
2237 snprintf(buf, sizeof(buf), "%d", width);
2238 geometry->add_property("x_size", string(buf));
2239 snprintf(buf, sizeof(buf), "%d", height);
2240 geometry->add_property("y_size", string(buf));
2241 snprintf(buf, sizeof(buf), "%d", x);
2242 geometry->add_property("x_pos", string(buf));
2243 snprintf(buf, sizeof(buf), "%d", y);
2244 geometry->add_property("y_pos", string(buf));
2245 snprintf(buf, sizeof(buf), "%d", xoff);
2246 geometry->add_property("x_off", string(buf));
2247 snprintf(buf, sizeof(buf), "%d", yoff);
2248 geometry->add_property("y_off", string(buf));
2249 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2250 geometry->add_property("edit_pane_pos", string(buf));
2252 node->add_child_nocopy (*geometry);
2255 maybe_add_mixer_strip_width (*node);
2257 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2258 node->add_property ("zoom-focus", buf);
2259 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2260 node->add_property ("zoom", buf);
2261 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2262 node->add_property ("snap-to", buf);
2263 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2264 node->add_property ("snap-mode", buf);
2266 node->add_property ("edit-point", enum_2_string (_edit_point));
2268 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2269 node->add_property ("playhead", buf);
2271 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2272 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2273 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2274 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2275 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2276 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2277 node->add_property ("mouse-mode", enum2str(mouse_mode));
2279 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2281 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2282 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2285 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2287 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2288 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2297 Editor::trackview_by_y_position (double y)
2299 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2303 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2312 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2314 Location* before = 0;
2315 Location* after = 0;
2321 const nframes64_t one_second = session->frame_rate();
2322 const nframes64_t one_minute = session->frame_rate() * 60;
2323 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2324 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2325 nframes64_t presnap = start;
2327 switch (snap_type) {
2333 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2335 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2339 case SnapToSMPTEFrame:
2340 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2341 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2343 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2347 case SnapToSMPTESeconds:
2348 if (session->smpte_offset_negative())
2350 start += session->smpte_offset ();
2352 start -= session->smpte_offset ();
2354 if (start % one_smpte_second > one_smpte_second / 2) {
2355 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2357 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2360 if (session->smpte_offset_negative())
2362 start -= session->smpte_offset ();
2364 start += session->smpte_offset ();
2368 case SnapToSMPTEMinutes:
2369 if (session->smpte_offset_negative())
2371 start += session->smpte_offset ();
2373 start -= session->smpte_offset ();
2375 if (start % one_smpte_minute > one_smpte_minute / 2) {
2376 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2378 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2380 if (session->smpte_offset_negative())
2382 start -= session->smpte_offset ();
2384 start += session->smpte_offset ();
2389 if (start % one_second > one_second / 2) {
2390 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2392 start = (nframes_t) floor ((double) start / one_second) * one_second;
2397 if (start % one_minute > one_minute / 2) {
2398 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2400 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2405 start = session->tempo_map().round_to_bar (start, direction);
2409 start = session->tempo_map().round_to_beat (start, direction);
2412 case SnapToAThirtysecondBeat:
2413 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2416 case SnapToASixteenthBeat:
2417 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2420 case SnapToAEighthBeat:
2421 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2424 case SnapToAQuarterBeat:
2425 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2428 case SnapToAThirdBeat:
2429 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2432 case SnapToEditPoint:
2433 start = get_preferred_edit_position ();
2441 before = session->locations()->first_location_before (start);
2442 after = session->locations()->first_location_after (start);
2444 if (direction < 0) {
2446 start = before->start();
2450 } else if (direction > 0) {
2452 start = after->start();
2454 start = session->current_end_frame();
2459 /* find nearest of the two */
2460 if ((start - before->start()) < (after->start() - start)) {
2461 start = before->start();
2463 start = after->start();
2466 start = before->start();
2469 start = after->start();
2476 case SnapToRegionStart:
2477 case SnapToRegionEnd:
2478 case SnapToRegionSync:
2479 case SnapToRegionBoundary:
2480 if (!region_boundary_cache.empty()) {
2481 vector<nframes_t>::iterator i;
2483 if (direction > 0) {
2484 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2486 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2489 if (i != region_boundary_cache.end()) {
2492 start = region_boundary_cache.back();
2498 switch (snap_mode) {
2504 if (presnap > start) {
2505 if (presnap > (start + unit_to_frame(snap_threshold))) {
2509 } else if (presnap < start) {
2510 if (presnap < (start - unit_to_frame(snap_threshold))) {
2522 Editor::snap_length_beats (nframes_t start)
2528 /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
2530 switch (snap_type) {
2532 return session->tempo_map().meter_at(start).beats_per_bar();
2537 case SnapToAThirtysecondBeat:
2538 return 1.0 / (double)32.0;
2541 case SnapToASixteenthBeat:
2542 return 1.0 / (double)16.0;
2545 case SnapToAEighthBeat:
2546 return 1.0 / (double)8.0;
2549 case SnapToAQuarterBeat:
2550 return 1.0 / (double)4.0;
2553 case SnapToAThirdBeat:
2554 return 1.0 / (double)3.0;
2562 Editor::setup_toolbar ()
2566 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2569 /* Mode Buttons (tool selection) */
2571 vector<ToggleButton *> mouse_mode_buttons;
2573 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2574 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2575 mouse_mode_buttons.push_back (&mouse_move_button);
2576 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2577 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2578 mouse_mode_buttons.push_back (&mouse_select_button);
2579 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2580 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2581 mouse_mode_buttons.push_back (&mouse_gain_button);
2582 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2583 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2584 mouse_mode_buttons.push_back (&mouse_zoom_button);
2585 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2586 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2587 mouse_mode_buttons.push_back (&mouse_timefx_button);
2588 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2589 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2590 mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2591 mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2592 mouse_mode_buttons.push_back (&mouse_note_button);
2593 mouse_mode_buttons.push_back (&mouse_audition_button);
2595 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2597 HBox* mode_box = manage(new HBox);
2598 mode_box->set_border_width (2);
2599 mode_box->set_spacing(4);
2600 mouse_mode_button_box.set_spacing(1);
2601 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2602 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2603 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2604 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2605 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2606 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2607 mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2608 mouse_mode_button_box.set_homogeneous(true);
2610 vector<string> edit_mode_strings;
2611 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2612 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2614 edit_mode_selector.set_name ("EditModeSelector");
2615 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2616 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2617 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2619 mode_box->pack_start(edit_mode_selector);
2620 mode_box->pack_start(mouse_mode_button_box);
2622 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2623 mouse_mode_tearoff->set_name ("MouseModeBase");
2625 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2626 &mouse_mode_tearoff->tearoff_window()));
2627 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2628 &mouse_mode_tearoff->tearoff_window(), 1));
2629 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2630 &mouse_mode_tearoff->tearoff_window()));
2631 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2632 &mouse_mode_tearoff->tearoff_window(), 1));
2634 mouse_move_button.set_name ("MouseModeButton");
2635 mouse_select_button.set_name ("MouseModeButton");
2636 mouse_gain_button.set_name ("MouseModeButton");
2637 mouse_zoom_button.set_name ("MouseModeButton");
2638 mouse_timefx_button.set_name ("MouseModeButton");
2639 mouse_audition_button.set_name ("MouseModeButton");
2640 mouse_note_button.set_name ("MouseModeButton");
2642 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2643 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2644 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2645 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2646 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2647 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2648 ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2650 mouse_move_button.unset_flags (CAN_FOCUS);
2651 mouse_select_button.unset_flags (CAN_FOCUS);
2652 mouse_gain_button.unset_flags (CAN_FOCUS);
2653 mouse_zoom_button.unset_flags (CAN_FOCUS);
2654 mouse_timefx_button.unset_flags (CAN_FOCUS);
2655 mouse_audition_button.unset_flags (CAN_FOCUS);
2656 mouse_note_button.unset_flags (CAN_FOCUS);
2658 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2659 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2661 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2662 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2663 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2664 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2665 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2666 mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2668 // mouse_move_button.set_active (true);
2673 zoom_box.set_spacing (1);
2674 zoom_box.set_border_width (0);
2676 zoom_in_button.set_name ("EditorTimeButton");
2677 zoom_in_button.set_size_request(-1,16);
2678 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2679 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2680 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2682 zoom_out_button.set_name ("EditorTimeButton");
2683 zoom_out_button.set_size_request(-1,16);
2684 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2685 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2686 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2688 zoom_out_full_button.set_name ("EditorTimeButton");
2689 zoom_out_full_button.set_size_request(-1,16);
2690 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2691 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2692 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2694 zoom_focus_selector.set_name ("ZoomFocusSelector");
2695 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Playhead", FUDGE, 0);
2696 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2697 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2698 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2700 zoom_box.pack_start (zoom_focus_selector, true, true);
2701 zoom_box.pack_start (zoom_out_button, false, false);
2702 zoom_box.pack_start (zoom_in_button, false, false);
2703 zoom_box.pack_start (zoom_out_full_button, false, false);
2705 snap_box.set_spacing (1);
2706 snap_box.set_border_width (2);
2708 snap_type_selector.set_name ("SnapTypeSelector");
2709 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2710 set_popdown_strings (snap_type_selector, snap_type_strings);
2711 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2712 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
2714 snap_mode_selector.set_name ("SnapModeSelector");
2715 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2716 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2717 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2718 ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2720 edit_point_selector.set_name ("SnapModeSelector");
2721 Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, "Playhead", 2+FUDGE, 10);
2722 set_popdown_strings (edit_point_selector, edit_point_strings);
2723 edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
2724 ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
2726 snap_box.pack_start (edit_point_clock, false, false);
2727 snap_box.pack_start (snap_mode_selector, false, false);
2728 snap_box.pack_start (snap_type_selector, false, false);
2729 snap_box.pack_start (edit_point_selector, false, false);
2733 HBox *nudge_box = manage (new HBox);
2734 nudge_box->set_spacing(1);
2735 nudge_box->set_border_width (2);
2737 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2738 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2740 nudge_box->pack_start (nudge_backward_button, false, false);
2741 nudge_box->pack_start (nudge_forward_button, false, false);
2742 nudge_box->pack_start (nudge_clock, false, false);
2745 /* Pack everything in... */
2747 HBox* hbox = manage (new HBox);
2748 hbox->set_spacing(10);
2750 tools_tearoff = manage (new TearOff (*hbox));
2751 tools_tearoff->set_name ("MouseModeBase");
2753 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2754 &tools_tearoff->tearoff_window()));
2755 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2756 &tools_tearoff->tearoff_window(), 0));
2757 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2758 &tools_tearoff->tearoff_window()));
2759 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2760 &tools_tearoff->tearoff_window(), 0));
2762 toolbar_hbox.set_spacing (10);
2763 toolbar_hbox.set_border_width (1);
2765 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2766 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2769 hbox->pack_start (snap_box, false, false);
2770 // hbox->pack_start (zoom_box, false, false);
2771 hbox->pack_start (*nudge_box, false, false);
2775 toolbar_base.set_name ("ToolBarBase");
2776 toolbar_base.add (toolbar_hbox);
2778 toolbar_frame.set_shadow_type (SHADOW_OUT);
2779 toolbar_frame.set_name ("BaseFrame");
2780 toolbar_frame.add (toolbar_base);
2785 Editor::setup_midi_toolbar ()
2789 /* Mode Buttons (tool selection) */
2791 vector<ToggleButton *> midi_tool_buttons;
2793 midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
2794 midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
2795 midi_tool_buttons.push_back (&midi_tool_pencil_button);
2796 midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
2797 midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
2798 midi_tool_buttons.push_back (&midi_tool_select_button);
2799 midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
2800 midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
2801 midi_tool_buttons.push_back (&midi_tool_erase_button);
2803 midi_tool_pencil_button.set_active(true);
2805 midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
2807 midi_tool_button_box.set_border_width (2);
2808 midi_tool_button_box.set_spacing(4);
2809 midi_tool_button_box.set_spacing(1);
2810 midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
2811 midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
2812 midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
2813 midi_tool_button_box.set_homogeneous(true);
2815 midi_tool_pencil_button.set_name ("MouseModeButton");
2816 midi_tool_select_button.set_name ("MouseModeButton");
2817 midi_tool_erase_button.set_name ("MouseModeButton");
2819 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
2820 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
2821 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
2823 midi_tool_pencil_button.unset_flags (CAN_FOCUS);
2824 midi_tool_select_button.unset_flags (CAN_FOCUS);
2825 midi_tool_erase_button.unset_flags (CAN_FOCUS);
2827 midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
2828 &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
2829 midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
2830 &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
2831 midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
2832 &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
2834 /* Pack everything in... */
2836 midi_tools_tearoff = manage (new TearOff (midi_tool_button_box));
2837 midi_tools_tearoff->set_name ("MouseModeBase");
2840 midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2841 &midi_tools_tearoff->tearoff_window()));
2842 midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2843 &midi_tools_tearoff->tearoff_window(), 0));
2844 midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2845 &midi_tools_tearoff->tearoff_window()));
2846 midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2847 &midi_tools_tearoff->tearoff_window(), 0));
2850 midi_toolbar_hbox.set_spacing (10);
2851 midi_toolbar_hbox.set_border_width (1);
2853 midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
2855 midi_tool_button_box.show_all ();
2856 midi_toolbar_hbox.show_all();
2857 midi_tools_tearoff->show_all();
2859 midi_toolbar_base.set_name ("ToolBarBase");
2860 midi_toolbar_base.add (midi_toolbar_hbox);
2862 midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
2863 midi_toolbar_frame.set_name ("BaseFrame");
2864 midi_toolbar_frame.add (midi_toolbar_base);
2868 Editor::convert_drop_to_paths (vector<ustring>& paths,
2869 const RefPtr<Gdk::DragContext>& context,
2872 const SelectionData& data,
2881 vector<ustring> uris = data.get_uris();
2885 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2886 are actually URI lists. So do it by hand.
2889 if (data.get_target() != "text/plain") {
2893 /* Parse the "uri-list" format that Nautilus provides,
2894 where each pathname is delimited by \r\n
2897 const char* p = data.get_text().c_str();
2904 while (g_ascii_isspace (*p))
2908 while (*q && (*q != '\n') && (*q != '\r'))
2914 while (q > p && g_ascii_isspace (*q))
2919 uris.push_back (ustring (p, q - p + 1));
2923 p = strchr (p, '\n');
2933 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2935 if ((*i).substr (0,7) == "file://") {
2938 PBD::url_decode (p);
2940 // scan forward past three slashes
2942 ustring::size_type slashcnt = 0;
2943 ustring::size_type n = 0;
2944 ustring::iterator x = p.begin();
2946 while (slashcnt < 3 && x != p.end()) {
2949 } else if (slashcnt == 3) {
2956 if (slashcnt != 3 || x == p.end()) {
2957 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2961 paths.push_back (p.substr (n - 1));
2969 Editor::new_tempo_section ()
2975 Editor::map_transport_state ()
2977 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2979 if (session->transport_stopped()) {
2980 have_pending_keyboard_selection = false;
2983 update_loop_range_view (true);
2988 Editor::State::State (PublicEditor const * e)
2990 selection = new Selection (e);
2993 Editor::State::~State ()
2999 Editor::get_memento () const
3001 State *state = new State (this);
3003 store_state (*state);
3004 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
3008 Editor::store_state (State& state) const
3010 *state.selection = *selection;
3014 Editor::restore_state (State *state)
3016 if (*selection == *state->selection) {
3020 *selection = *state->selection;
3021 time_selection_changed ();
3022 region_selection_changed ();
3024 /* XXX other selection change handlers? */
3028 Editor::begin_reversible_command (string name)
3031 before = &get_state();
3032 session->begin_reversible_command (name);
3037 Editor::commit_reversible_command ()
3040 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
3045 Editor::set_edit_group_solo (Route& route, bool yn)
3047 RouteGroup *edit_group;
3049 if ((edit_group = route.edit_group()) != 0) {
3050 edit_group->apply (&Route::set_solo, yn, this);
3052 route.set_solo (yn, this);
3057 Editor::set_edit_group_mute (Route& route, bool yn)
3059 RouteGroup *edit_group = 0;
3061 if ((edit_group == route.edit_group()) != 0) {
3062 edit_group->apply (&Route::set_mute, yn, this);
3064 route.set_mute (yn, this);
3069 Editor::history_changed ()
3073 if (undo_action && session) {
3074 if (session->undo_depth() == 0) {
3077 label = string_compose(_("Undo (%1)"), session->next_undo());
3079 undo_action->property_label() = label;
3082 if (redo_action && session) {
3083 if (session->redo_depth() == 0) {
3086 label = string_compose(_("Redo (%1)"), session->next_redo());
3088 redo_action->property_label() = label;
3093 Editor::duplicate_dialog (bool dup_region)
3095 if (selection->regions.empty() && (selection->time.length() == 0)) {
3099 ArdourDialog win ("duplicate dialog");
3100 Label label (_("Duplicate how many times?"));
3101 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3102 SpinButton spinner (adjustment);
3104 win.get_vbox()->set_spacing (12);
3105 win.get_vbox()->pack_start (label);
3107 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3108 place, visually. so do this by hand.
3111 win.get_vbox()->pack_start (spinner);
3112 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3117 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3118 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3120 win.set_position (WIN_POS_MOUSE);
3122 spinner.grab_focus ();
3124 switch (win.run ()) {
3125 case RESPONSE_ACCEPT:
3131 float times = adjustment.get_value();
3133 if (!selection->regions.empty()) {
3134 duplicate_some_regions (selection->regions, times);
3136 duplicate_selection (times);
3141 Editor::show_verbose_canvas_cursor ()
3143 verbose_canvas_cursor->raise_to_top();
3144 verbose_canvas_cursor->show();
3145 verbose_cursor_visible = true;
3149 Editor::hide_verbose_canvas_cursor ()
3151 verbose_canvas_cursor->hide();
3152 verbose_cursor_visible = false;
3156 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3158 /* XXX get origin of canvas relative to root window,
3159 add x and y and check compared to gdk_screen_{width,height}
3161 verbose_canvas_cursor->property_text() = txt.c_str();
3162 verbose_canvas_cursor->property_x() = x;
3163 verbose_canvas_cursor->property_y() = y;
3167 Editor::set_verbose_canvas_cursor_text (const string & txt)
3169 verbose_canvas_cursor->property_text() = txt.c_str();
3173 Editor::edit_mode_selection_done ()
3179 string choice = edit_mode_selector.get_active_text();
3180 EditMode mode = Slide;
3182 if (choice == _("Splice Edit")) {
3184 } else if (choice == _("Slide Edit")) {
3188 Config->set_edit_mode (mode);
3192 Editor::snap_type_selection_done ()
3194 string choice = snap_type_selector.get_active_text();
3195 SnapType snaptype = SnapToFrame;
3197 if (choice == _("Beats/3")) {
3198 snaptype = SnapToAThirdBeat;
3199 } else if (choice == _("Beats/4")) {
3200 snaptype = SnapToAQuarterBeat;
3201 } else if (choice == _("Beats/8")) {
3202 snaptype = SnapToAEighthBeat;
3203 } else if (choice == _("Beats/16")) {
3204 snaptype = SnapToASixteenthBeat;
3205 } else if (choice == _("Beats/32")) {
3206 snaptype = SnapToAThirtysecondBeat;
3207 } else if (choice == _("Beats")) {
3208 snaptype = SnapToBeat;
3209 } else if (choice == _("Bars")) {
3210 snaptype = SnapToBar;
3211 } else if (choice == _("Marks")) {
3212 snaptype = SnapToMark;
3213 } else if (choice == _("Edit Point")) {
3214 snaptype = SnapToEditPoint;
3215 } else if (choice == _("Region starts")) {
3216 snaptype = SnapToRegionStart;
3217 } else if (choice == _("Region ends")) {
3218 snaptype = SnapToRegionEnd;
3219 } else if (choice == _("Region bounds")) {
3220 snaptype = SnapToRegionBoundary;
3221 } else if (choice == _("Region syncs")) {
3222 snaptype = SnapToRegionSync;
3223 } else if (choice == _("CD Frames")) {
3224 snaptype = SnapToCDFrame;
3225 } else if (choice == _("SMPTE Frames")) {
3226 snaptype = SnapToSMPTEFrame;
3227 } else if (choice == _("SMPTE Seconds")) {
3228 snaptype = SnapToSMPTESeconds;
3229 } else if (choice == _("SMPTE Minutes")) {
3230 snaptype = SnapToSMPTEMinutes;
3231 } else if (choice == _("Seconds")) {
3232 snaptype = SnapToSeconds;
3233 } else if (choice == _("Minutes")) {
3234 snaptype = SnapToMinutes;
3235 } else if (choice == _("None")) {
3236 snaptype = SnapToFrame;
3239 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3241 ract->set_active ();
3246 Editor::snap_mode_selection_done ()
3248 string choice = snap_mode_selector.get_active_text();
3249 SnapMode mode = SnapNormal;
3251 if (choice == _("Normal")) {
3253 } else if (choice == _("Magnetic")) {
3254 mode = SnapMagnetic;
3257 RefPtr<RadioAction> ract = snap_mode_action (mode);
3260 ract->set_active (true);
3265 Editor::edit_point_selection_done ()
3267 string choice = edit_point_selector.get_active_text();
3268 EditPoint ep = EditAtSelectedMarker;
3270 if (choice == _("Marker")) {
3271 _edit_point = EditAtSelectedMarker;
3272 } else if (choice == _("Playhead")) {
3273 _edit_point = EditAtPlayhead;
3275 _edit_point = EditAtMouse;
3278 RefPtr<RadioAction> ract = edit_point_action (ep);
3281 ract->set_active (true);
3286 Editor::zoom_focus_selection_done ()
3288 string choice = zoom_focus_selector.get_active_text();
3289 ZoomFocus focus_type = ZoomFocusLeft;
3291 if (choice == _("Left")) {
3292 focus_type = ZoomFocusLeft;
3293 } else if (choice == _("Right")) {
3294 focus_type = ZoomFocusRight;
3295 } else if (choice == _("Center")) {
3296 focus_type = ZoomFocusCenter;
3297 } else if (choice == _("Play")) {
3298 focus_type = ZoomFocusPlayhead;
3299 } else if (choice == _("Edit")) {
3300 focus_type = ZoomFocusEdit;
3301 } else if (choice == _("Edit Point")) {
3302 focus_type = ZoomFocusEdit;
3304 focus_type = ZoomFocusMouse;
3307 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3310 ract->set_active ();
3315 Editor::edit_controls_button_release (GdkEventButton* ev)
3317 if (Keyboard::is_context_menu_event (ev)) {
3318 ARDOUR_UI::instance()->add_route (this);
3324 Editor::mouse_select_button_release (GdkEventButton* ev)
3326 /* this handles just right-clicks */
3328 if (ev->button != 3) {
3335 Editor::TrackViewList *
3336 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3339 TrackViewList::iterator i;
3341 v = new TrackViewList;
3343 if (track == 0 && group == 0) {
3347 for (i = track_views.begin(); i != track_views.end (); ++i) {
3351 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3353 /* just the view for this track
3356 v->push_back (track);
3360 /* views for all tracks in the edit group */
3362 for (i = track_views.begin(); i != track_views.end (); ++i) {
3364 if (group == 0 || (*i)->edit_group() == group) {
3374 Editor::set_zoom_focus (ZoomFocus f)
3376 string str = zoom_focus_strings[(int)f];
3378 if (str != zoom_focus_selector.get_active_text()) {
3379 zoom_focus_selector.set_active_text (str);
3382 if (zoom_focus != f) {
3385 ZoomFocusChanged (); /* EMIT_SIGNAL */
3392 Editor::ensure_float (Window& win)
3394 win.set_transient_for (*this);
3398 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3400 /* recover or initialize pane positions. do this here rather than earlier because
3401 we don't want the positions to change the child allocations, which they seem to do.
3407 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3409 static int32_t done;
3412 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3413 width = default_width;
3414 height = default_height;
3416 width = atoi(geometry->property("x_size")->value());
3417 height = atoi(geometry->property("y_size")->value());
3420 if (which == static_cast<Paned*> (&edit_pane)) {
3426 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3427 /* initial allocation is 90% to canvas, 10% to notebook */
3428 pos = (int) floor (alloc.get_width() * 0.90f);
3429 snprintf (buf, sizeof(buf), "%d", pos);
3431 pos = atoi (prop->value());
3434 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3435 edit_pane.set_position (pos);
3436 pre_maximal_pane_position = pos;
3442 Editor::detach_tearoff (Box* b, Window* w)
3444 if (tools_tearoff->torn_off() &&
3445 mouse_mode_tearoff->torn_off()) {
3446 top_hbox.remove (toolbar_frame);
3451 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3453 if (toolbar_frame.get_parent() == 0) {
3454 top_hbox.pack_end (toolbar_frame);
3459 Editor::set_show_measures (bool yn)
3461 if (_show_measures != yn) {
3464 if ((_show_measures = yn) == true) {
3472 Editor::toggle_follow_playhead ()
3474 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3476 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3477 set_follow_playhead (tact->get_active());
3482 Editor::set_follow_playhead (bool yn)
3484 if (_follow_playhead != yn) {
3485 if ((_follow_playhead = yn) == true) {
3487 update_current_screen ();
3494 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3496 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3498 xfade->set_active (!xfade->active());
3503 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3505 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3507 xfade->set_follow_overlap (!xfade->following_overlap());
3512 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3514 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3520 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3524 switch (cew.run ()) {
3525 case RESPONSE_ACCEPT:
3532 xfade->StateChanged (Change (~0));
3536 Editor::playlist_selector () const
3538 return *_playlist_selector;
3542 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3546 ret = nudge_clock.current_duration (pos);
3547 next = ret + 1; /* XXXX fix me */
3553 Editor::end_location_changed (Location* location)
3555 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3556 reset_scrolling_region ();
3560 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3562 ArdourDialog dialog ("playlist deletion dialog");
3563 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3564 "If left alone, no audio files used by it will be cleaned.\n"
3565 "If deleted, audio files used by it alone by will cleaned."),
3568 dialog.set_position (WIN_POS_CENTER);
3569 dialog.get_vbox()->pack_start (label);
3573 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3574 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3575 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3577 switch (dialog.run ()) {
3578 case RESPONSE_ACCEPT:
3579 /* delete the playlist */
3583 case RESPONSE_REJECT:
3584 /* keep the playlist */
3596 Editor::audio_region_selection_covers (nframes_t where)
3598 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3599 if ((*a)->region()->covers (where)) {
3608 Editor::prepare_for_cleanup ()
3610 cut_buffer->clear_regions ();
3611 cut_buffer->clear_playlists ();
3613 selection->clear_regions ();
3614 selection->clear_playlists ();
3618 Editor::transport_loop_location()
3621 return session->locations()->auto_loop_location();
3628 Editor::transport_punch_location()
3631 return session->locations()->auto_punch_location();
3638 Editor::control_layout_scroll (GdkEventScroll* ev)
3640 switch (ev->direction) {
3642 scroll_tracks_up_line ();
3646 case GDK_SCROLL_DOWN:
3647 scroll_tracks_down_line ();
3651 /* no left/right handling yet */
3659 /** A new snapshot has been selected.
3662 Editor::snapshot_display_selection_changed ()
3664 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3666 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3668 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3670 if (snap_name.length() == 0) {
3674 if (session->snap_name() == snap_name) {
3678 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3683 Editor::snapshot_display_button_press (GdkEventButton* ev)
3685 if (ev->button == 3) {
3686 /* Right-click on the snapshot list. Work out which snapshot it
3688 Gtk::TreeModel::Path path;
3689 Gtk::TreeViewColumn* col;
3692 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3693 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3695 Gtk::TreeModel::Row row = *iter;
3696 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3705 /** Pop up the snapshot display context menu.
3706 * @param button Button used to open the menu.
3707 * @param time Menu open time.
3708 * @snapshot_name Name of the snapshot that the menu click was over.
3712 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3714 using namespace Menu_Helpers;
3716 MenuList& items (snapshot_context_menu.items());
3719 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3721 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3723 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3725 snapshot_context_menu.popup (button, time);
3729 Editor::rename_snapshot (Glib::ustring old_name)
3731 ArdourPrompter prompter(true);
3735 prompter.set_name ("Prompter");
3736 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3737 prompter.set_prompt (_("New name of snapshot"));
3738 prompter.set_initial_text (old_name);
3740 if (prompter.run() == RESPONSE_ACCEPT) {
3741 prompter.get_result (new_name);
3742 if (new_name.length()) {
3743 session->rename_state (old_name, new_name);
3744 redisplay_snapshots ();
3751 Editor::remove_snapshot (Glib::ustring name)
3753 vector<string> choices;
3755 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3757 choices.push_back (_("No, do nothing."));
3758 choices.push_back (_("Yes, remove it."));
3760 Gtkmm2ext::Choice prompter (prompt, choices);
3762 if (prompter.run () == 1) {
3763 session->remove_state (name);
3764 redisplay_snapshots ();
3769 Editor::redisplay_snapshots ()
3775 vector<sys::path> state_file_paths;
3777 get_state_files_in_directory (session->session_directory().root_path(),
3780 if (state_file_paths.empty()) return;
3782 vector<string> state_file_names(get_file_names_no_extension(state_file_paths));
3784 snapshot_display_model->clear ();
3786 for (vector<string>::iterator i = state_file_names.begin();
3787 i != state_file_names.end(); ++i)
3789 string statename = (*i);
3790 TreeModel::Row row = *(snapshot_display_model->append());
3792 /* this lingers on in case we ever want to change the visible
3793 name of the snapshot.
3796 string display_name;
3797 display_name = statename;
3799 if (statename == session->snap_name()) {
3800 snapshot_display.get_selection()->select(row);
3803 row[snapshot_display_columns.visible_name] = display_name;
3804 row[snapshot_display_columns.real_name] = statename;
3809 Editor::session_state_saved (string snap_name)
3811 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3812 redisplay_snapshots ();
3816 Editor::maximise_editing_space ()
3818 initial_ruler_update_required = true;
3820 mouse_mode_tearoff->set_visible (false);
3821 tools_tearoff->set_visible (false);
3823 pre_maximal_pane_position = edit_pane.get_position();
3824 pre_maximal_editor_width = this->get_width();
3826 if(post_maximal_pane_position == 0) {
3827 post_maximal_pane_position = edit_pane.get_width();
3832 if(post_maximal_editor_width) {
3833 edit_pane.set_position (post_maximal_pane_position -
3834 abs(post_maximal_editor_width - pre_maximal_editor_width));
3836 edit_pane.set_position (post_maximal_pane_position);
3841 Editor::restore_editing_space ()
3843 initial_ruler_update_required = true;
3845 // user changed width of pane during fullscreen
3846 if(post_maximal_pane_position != edit_pane.get_position()) {
3847 post_maximal_pane_position = edit_pane.get_position();
3852 mouse_mode_tearoff->set_visible (true);
3853 tools_tearoff->set_visible (true);
3854 post_maximal_editor_width = this->get_width();
3857 edit_pane.set_position (
3858 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3863 * Make new playlists for a given track and also any others that belong
3864 * to the same active edit group.
3869 Editor::new_playlists (TimeAxisView* v)
3871 begin_reversible_command (_("new playlists"));
3872 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3873 commit_reversible_command ();
3877 * Use a copy of the current playlist for a given track and also any others that belong
3878 * to the same active edit group.
3883 Editor::copy_playlists (TimeAxisView* v)
3885 begin_reversible_command (_("copy playlists"));
3886 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3887 commit_reversible_command ();
3891 * Clear the current playlist for a given track and also any others that belong
3892 * to the same active edit group.
3897 Editor::clear_playlists (TimeAxisView* v)
3899 begin_reversible_command (_("clear playlists"));
3900 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3901 commit_reversible_command ();
3905 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3907 atv.use_new_playlist (sz > 1 ? false : true);
3911 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3913 atv.use_copy_playlist (sz > 1 ? false : true);
3917 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3919 atv.clear_playlist ();
3923 Editor::on_key_press_event (GdkEventKey* ev)
3925 return key_press_focus_accelerator_handler (*this, ev);
3929 Editor::reset_x_origin (nframes_t frame)
3931 queue_visual_change (frame);
3935 Editor::reset_zoom (double fpu)
3937 queue_visual_change (fpu);
3941 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3943 reset_x_origin (frame);
3948 Editor::set_frames_per_unit (double fpu)
3952 /* this is the core function that controls the zoom level of the canvas. it is called
3953 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3956 if (fpu == frames_per_unit) {
3964 // convert fpu to frame count
3966 frames = (nframes_t) floor (fpu * canvas_width);
3968 /* don't allow zooms that fit more than the maximum number
3969 of frames into an 800 pixel wide space.
3972 if (max_frames / fpu < 800.0) {
3976 if (fpu == frames_per_unit) {
3980 frames_per_unit = fpu;
3982 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3983 if (!selection->tracks.empty()) {
3984 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3985 (*i)->reshow_selection (selection->time);
3988 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3989 (*i)->reshow_selection (selection->time);
3994 ZoomChanged (); /* EMIT_SIGNAL */
3996 reset_hscrollbar_stepping ();
3997 reset_scrolling_region ();
3999 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
4005 Editor::queue_visual_change (nframes_t where)
4007 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
4008 pending_visual_change.time_origin = where;
4010 if (pending_visual_change.idle_handler_id < 0) {
4011 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4016 Editor::queue_visual_change (double fpu)
4018 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
4019 pending_visual_change.frames_per_unit = fpu;
4021 if (pending_visual_change.idle_handler_id < 0) {
4022 pending_visual_change.idle_handler_id = g_idle_add ( _idle_visual_changer, this);
4028 Editor::_idle_visual_changer (void* arg)
4030 return static_cast<Editor*>(arg)->idle_visual_changer ();
4034 Editor::idle_visual_changer ()
4036 VisualChange::Type p = pending_visual_change.pending;
4038 pending_visual_change.pending = (VisualChange::Type) 0;
4040 if (p & VisualChange::ZoomLevel) {
4041 set_frames_per_unit (pending_visual_change.frames_per_unit);
4043 compute_fixed_ruler_scale ();
4044 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(canvas_width * pending_visual_change.frames_per_unit));
4045 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(canvas_width * pending_visual_change.frames_per_unit));
4046 update_tempo_based_rulers ();
4048 if (p & VisualChange::TimeOrigin) {
4049 if (pending_visual_change.time_origin != leftmost_frame) {
4050 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
4051 /* the signal handler will do the rest */
4053 update_fixed_rulers();
4054 redisplay_tempo (true);
4057 pending_visual_change.idle_handler_id = -1;
4059 return 0; /* this is always a one-shot call */
4062 struct EditorOrderTimeAxisSorter {
4063 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4064 return a->order < b->order;
4069 Editor::sort_track_selection ()
4071 EditorOrderTimeAxisSorter cmp;
4072 selection->tracks.sort (cmp);
4076 Editor::get_preferred_edit_position()
4079 nframes64_t where = 0;
4081 switch (_edit_point) {
4082 case EditAtPlayhead:
4083 where = session->audible_frame();
4086 case EditAtSelectedMarker:
4087 if (!selection->markers.empty()) {
4089 Location* loc = find_location_from_marker (selection->markers.front(), whocares);
4091 where = loc->start();
4099 if (!mouse_frame (where, ignored)) {
4100 /* XXX not right but what can we do ? */
4111 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4113 if (!session) return;
4115 begin_reversible_command (cmd);
4119 if ((tll = transport_loop_location()) == 0) {
4120 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4121 XMLNode &before = session->locations()->get_state();
4122 session->locations()->add (loc, true);
4123 session->set_auto_loop_location (loc);
4124 XMLNode &after = session->locations()->get_state();
4125 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4128 XMLNode &before = tll->get_state();
4129 tll->set_hidden (false, this);
4130 tll->set (start, end);
4131 XMLNode &after = tll->get_state();
4132 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4135 commit_reversible_command ();
4139 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4141 if (!session) return;
4143 begin_reversible_command (cmd);
4147 if ((tpl = transport_punch_location()) == 0) {
4148 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4149 XMLNode &before = session->locations()->get_state();
4150 session->locations()->add (loc, true);
4151 session->set_auto_loop_location (loc);
4152 XMLNode &after = session->locations()->get_state();
4153 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4156 XMLNode &before = tpl->get_state();
4157 tpl->set_hidden (false, this);
4158 tpl->set (start, end);
4159 XMLNode &after = tpl->get_state();
4160 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4163 commit_reversible_command ();
4167 Editor::get_regions_at (nframes64_t where, const TrackSelection& ts) const
4170 const TrackSelection* tracks;
4173 tracks = &track_views;
4178 for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4180 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4183 boost::shared_ptr<Diskstream> ds;
4184 boost::shared_ptr<Playlist> pl;
4186 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4188 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)where * ds->speed()));
4190 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4192 RegionView* rv = atv->audio_view()->find_view (*i);
4208 Editor::get_regions_for_action ()
4210 if (!selection->regions.empty()) {
4211 return selection->regions;
4214 nframes64_t where = get_preferred_edit_position();
4215 tmp_regions = get_regions_at (where, selection->tracks);