2 Copyright (C) 2000-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
28 #include <boost/none.hpp>
30 #include <sigc++/bind.h>
32 #include <pbd/convert.h>
33 #include <pbd/error.h>
34 #include <pbd/enumwriter.h>
35 #include <pbd/memento_command.h>
37 #include <glibmm/miscutils.h>
38 #include <gtkmm/image.h>
39 #include <gdkmm/color.h>
40 #include <gdkmm/bitmap.h>
42 #include <gtkmm2ext/grouped_buttons.h>
43 #include <gtkmm2ext/gtk_ui.h>
44 #include <gtkmm2ext/tearoff.h>
45 #include <gtkmm2ext/utils.h>
46 #include <gtkmm2ext/window_title.h>
47 #include <gtkmm2ext/choice.h>
49 #include <ardour/audio_track.h>
50 #include <ardour/audio_diskstream.h>
51 #include <ardour/plugin_manager.h>
52 #include <ardour/location.h>
53 #include <ardour/audioplaylist.h>
54 #include <ardour/audioregion.h>
55 #include <ardour/midi_region.h>
56 #include <ardour/session_route.h>
57 #include <ardour/session_directory.h>
58 #include <ardour/session_state_utils.h>
59 #include <ardour/tempo.h>
60 #include <ardour/utils.h>
61 #include <ardour/profile.h>
63 #include <control_protocol/control_protocol.h>
65 #include "ardour_ui.h"
69 #include "playlist_selector.h"
70 #include "audio_region_view.h"
71 #include "rgb_macros.h"
72 #include "selection.h"
73 #include "audio_streamview.h"
74 #include "time_axis_view.h"
75 #include "audio_time_axis.h"
77 #include "crossfade_view.h"
79 #include "public_editor.h"
80 #include "crossfade_edit.h"
81 #include "canvas_impl.h"
84 #include "gui_thread.h"
87 #include "analysis_window.h"
93 #include "imageframe_socket_handler.h"
98 using namespace ARDOUR;
101 using namespace Glib;
102 using namespace Gtkmm2ext;
103 using namespace Editing;
105 using PBD::internationalize;
108 const double Editor::timebar_height = 15.0;
110 #include "editor_xpms"
112 static const gchar *_snap_type_strings[] = {
136 static const gchar *_snap_mode_strings[] = {
142 static const gchar *_zoom_focus_strings[] = {
151 /* Soundfile drag-n-drop */
153 Gdk::Cursor* Editor::cross_hair_cursor = 0;
154 Gdk::Cursor* Editor::selector_cursor = 0;
155 Gdk::Cursor* Editor::trimmer_cursor = 0;
156 Gdk::Cursor* Editor::grabber_cursor = 0;
157 Gdk::Cursor* Editor::zoom_cursor = 0;
158 Gdk::Cursor* Editor::time_fx_cursor = 0;
159 Gdk::Cursor* Editor::fader_cursor = 0;
160 Gdk::Cursor* Editor::speaker_cursor = 0;
161 Gdk::Cursor* Editor::midi_pencil_cursor = 0;
162 Gdk::Cursor* Editor::midi_select_cursor = 0;
163 Gdk::Cursor* Editor::midi_erase_cursor = 0;
164 Gdk::Cursor* Editor::wait_cursor = 0;
165 Gdk::Cursor* Editor::timebar_cursor = 0;
168 show_me_the_size (Requisition* r, const char* what)
170 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
174 check_adjustment (Gtk::Adjustment* adj)
176 cerr << "CHANGE adj = "
177 << adj->get_lower () << ' '
178 << adj->get_upper () << ' '
179 << adj->get_value () << ' '
180 << adj->get_step_increment () << ' '
181 << adj->get_page_increment () << ' '
182 << adj->get_page_size () << ' '
189 /* time display buttons */
191 minsec_label (_("Mins:Secs")),
192 bbt_label (_("Bars:Beats")),
193 smpte_label (_("Timecode")),
194 frame_label (_("Frames")),
195 tempo_label (_("Tempo")),
196 meter_label (_("Meter")),
197 mark_label (_("Location Markers")),
198 range_mark_label (_("Range Markers")),
199 transport_mark_label (_("Loop/Punch Ranges")),
201 edit_packer (3, 3, false),
203 /* the values here don't matter: layout widgets
204 reset them as needed.
207 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
208 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
211 marker_tempo_lines(0),
213 /* tool bar related */
215 edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
216 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
218 toolbar_selection_clock_table (2,3),
220 automation_mode_button (_("mode")),
221 global_automation_button (_("automation")),
224 image_socket_listener(0),
229 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
234 /* we are a singleton */
236 PublicEditor::_instance = this;
240 selection = new Selection (this);
241 cut_buffer = new Selection (this);
243 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
244 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
245 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
246 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
248 clicked_regionview = 0;
249 clicked_axisview = 0;
250 clicked_routeview = 0;
251 clicked_crossfadeview = 0;
252 clicked_control_point = 0;
253 latest_regionview = 0;
254 last_update_frame = 0;
256 current_mixer_strip = 0;
257 current_bbt_points = 0;
259 snap_type_strings = I18N (_snap_type_strings);
260 snap_mode_strings = I18N (_snap_mode_strings);
261 zoom_focus_strings = I18N(_zoom_focus_strings);
263 snap_type = SnapToFrame;
264 set_snap_to (snap_type);
265 snap_mode = SnapNormal;
266 set_snap_mode (snap_mode);
267 snap_threshold = 5.0;
268 bbt_beat_subdivision = 4;
271 autoscroll_active = false;
272 autoscroll_timeout_tag = -1;
273 interthread_progress_window = 0;
280 current_interthread_info = 0;
281 _show_measures = true;
282 _show_waveforms = true;
283 _show_waveforms_recording = true;
284 first_action_message = 0;
286 export_range_markers_dialog = 0;
287 show_gain_after_trim = false;
288 ignore_route_list_reorder = false;
289 no_route_list_redisplay = false;
290 verbose_cursor_on = true;
291 route_removal = false;
292 show_automatic_regions_in_region_list = true;
293 region_list_sort_type = (Editing::RegionListSortType) 0;
294 have_pending_keyboard_selection = false;
295 _follow_playhead = true;
296 _xfade_visibility = true;
297 editor_ruler_menu = 0;
298 no_ruler_shown_update = false;
299 edit_group_list_menu = 0;
301 region_list_menu = 0;
303 start_end_marker_menu = 0;
304 range_marker_menu = 0;
305 marker_menu_item = 0;
307 transport_marker_menu = 0;
308 new_transport_marker_menu = 0;
309 editor_mixer_strip_width = Wide;
310 show_editor_mixer_when_tracks_arrive = false;
311 region_edit_menu_split_multichannel_item = 0;
312 region_edit_menu_split_item = 0;
315 ignore_mouse_mode_toggle = false;
316 ignore_midi_edit_mode_toggle = false;
317 current_stepping_trackview = 0;
319 entered_regionview = 0;
320 clear_entered_track = false;
321 _new_regionviews_show_envelope = false;
322 current_timestretch = 0;
323 in_edit_group_row_change = false;
324 last_canvas_frame = 0;
327 button_release_can_deselect = true;
328 canvas_idle_queued = false;
329 _dragging_playhead = false;
330 _dragging_hscrollbar = false;
334 mouse_speed_update = -1;
335 mouse_speed_size = 16;
336 mouse_speed = new double[mouse_speed_size];
337 memset (mouse_speed, 0, sizeof(double) * mouse_speed_size);
338 mouse_speed_entries = 0;
341 ignore_route_order_sync = false;
343 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
344 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
345 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
346 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
347 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
349 range_marker_drag_rect = 0;
350 marker_drag_line = 0;
352 set_midi_edit_mode (MidiEditPencil, true);
353 set_mouse_mode (MouseObject, true);
355 frames_per_unit = 2048; /* too early to use reset_zoom () */
356 reset_hscrollbar_stepping ();
358 zoom_focus = ZoomFocusLeft;
359 set_zoom_focus (ZoomFocusLeft);
360 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
362 initialize_rulers ();
363 initialize_canvas ();
365 edit_controls_vbox.set_spacing (0);
366 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
367 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
369 track_canvas.set_hadjustment (horizontal_adjustment);
370 track_canvas.set_vadjustment (vertical_adjustment);
371 time_canvas.set_hadjustment (horizontal_adjustment);
373 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
374 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
376 controls_layout.add (edit_controls_vbox);
377 controls_layout.set_name ("EditControlsBase");
378 controls_layout.add_events (Gdk::SCROLL_MASK);
379 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
381 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
382 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
383 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
385 edit_vscrollbar.set_adjustment (vertical_adjustment);
386 edit_hscrollbar.set_adjustment (horizontal_adjustment);
388 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
389 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
390 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
392 edit_hscrollbar.set_name ("EditorHScrollbar");
396 setup_midi_toolbar ();
398 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
400 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
401 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
402 0.0, 1.0, 100.0, 1.0));
403 pad_line_1->property_color_rgba() = 0xFF0000FF;
407 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
408 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
409 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
410 time_canvas_vbox.pack_start (*frames_ruler, false, false);
411 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
412 time_canvas_vbox.pack_start (time_canvas, true, true);
413 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 5);
415 bbt_label.set_name ("EditorTimeButton");
416 bbt_label.set_size_request (-1, (int)timebar_height);
417 bbt_label.set_alignment (1.0, 0.5);
418 bbt_label.set_padding (5,0);
419 minsec_label.set_name ("EditorTimeButton");
420 minsec_label.set_size_request (-1, (int)timebar_height);
421 minsec_label.set_alignment (1.0, 0.5);
422 minsec_label.set_padding (5,0);
423 smpte_label.set_name ("EditorTimeButton");
424 smpte_label.set_size_request (-1, (int)timebar_height);
425 smpte_label.set_alignment (1.0, 0.5);
426 smpte_label.set_padding (5,0);
427 frame_label.set_name ("EditorTimeButton");
428 frame_label.set_size_request (-1, (int)timebar_height);
429 frame_label.set_alignment (1.0, 0.5);
430 frame_label.set_padding (5,0);
431 tempo_label.set_name ("EditorTimeButton");
432 tempo_label.set_size_request (-1, (int)timebar_height);
433 tempo_label.set_alignment (1.0, 0.5);
434 tempo_label.set_padding (5,0);
435 meter_label.set_name ("EditorTimeButton");
436 meter_label.set_size_request (-1, (int)timebar_height);
437 meter_label.set_alignment (1.0, 0.5);
438 meter_label.set_padding (5,0);
439 mark_label.set_name ("EditorTimeButton");
440 mark_label.set_size_request (-1, (int)timebar_height);
441 mark_label.set_alignment (1.0, 0.5);
442 mark_label.set_padding (5,0);
443 range_mark_label.set_name ("EditorTimeButton");
444 range_mark_label.set_size_request (-1, (int)timebar_height);
445 range_mark_label.set_alignment (1.0, 0.5);
446 range_mark_label.set_padding (5,0);
447 transport_mark_label.set_name ("EditorTimeButton");
448 transport_mark_label.set_size_request (-1, (int)timebar_height);
449 transport_mark_label.set_alignment (1.0, 0.5);
450 transport_mark_label.set_padding (5,0);
452 time_button_vbox.pack_start (minsec_label, false, false);
453 time_button_vbox.pack_start (smpte_label, false, false);
454 time_button_vbox.pack_start (frame_label, false, false);
455 time_button_vbox.pack_start (bbt_label, false, false);
456 time_button_vbox.pack_start (meter_label, false, false);
457 time_button_vbox.pack_start (tempo_label, false, false);
458 time_button_vbox.pack_start (mark_label, false, false);
460 time_button_event_box.add (time_button_vbox);
461 time_button_event_box.set_name ("TimebarLabelBase");
462 time_button_frame.set_shadow_type (Gtk::SHADOW_NONE);
464 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
465 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
467 time_button_frame.add (time_button_event_box);
468 time_button_frame.set_name ("TimebarLabelBase");
469 time_button_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
471 /* these enable us to have a dedicated window (for cursor setting, etc.)
472 for the canvas areas.
475 track_canvas_event_box.add (track_canvas);
477 time_canvas_event_box.add (time_canvas_vbox);
478 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
480 edit_packer.set_col_spacings (0);
481 edit_packer.set_row_spacings (0);
482 edit_packer.set_homogeneous (false);
483 edit_packer.set_border_width (0);
484 edit_packer.set_name ("EditorWindow");
486 edit_packer.attach (edit_vscrollbar, 3, 4, 1, 2, FILL, FILL|EXPAND, 0, 0);
488 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, SHRINK, 0, 0);
489 edit_packer.attach (time_canvas_event_box, 2, 4, 0, 1, FILL|EXPAND, FILL, 0, 0);
491 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
492 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
494 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
495 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
497 bottom_hbox.set_border_width (2);
498 bottom_hbox.set_spacing (3);
500 route_display_model = ListStore::create(route_display_columns);
501 route_list_display.set_model (route_display_model);
502 route_list_display.append_column (_("Show"), route_display_columns.visible);
503 route_list_display.append_column (_("Name"), route_display_columns.text);
504 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
505 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
506 route_list_display.set_headers_visible (true);
507 route_list_display.set_name ("TrackListDisplay");
508 route_list_display.get_selection()->set_mode (SELECTION_NONE);
509 route_list_display.set_reorderable (true);
510 route_list_display.set_size_request (100,-1);
512 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
513 route_list_visible_cell->property_activatable() = true;
514 route_list_visible_cell->property_radio() = false;
516 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
517 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
519 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
521 route_list_scroller.add (route_list_display);
522 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
524 group_model = ListStore::create(group_columns);
525 edit_group_display.set_model (group_model);
526 edit_group_display.append_column (_("Name"), group_columns.text);
527 edit_group_display.append_column (_("Active"), group_columns.is_active);
528 edit_group_display.append_column (_("Show"), group_columns.is_visible);
529 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
530 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
531 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
532 edit_group_display.get_column (0)->set_expand (true);
533 edit_group_display.get_column (1)->set_expand (false);
534 edit_group_display.get_column (2)->set_expand (false);
535 edit_group_display.set_headers_visible (true);
537 /* name is directly editable */
539 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
540 name_cell->property_editable() = true;
541 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
543 /* use checkbox for the active + visible columns */
545 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
546 active_cell->property_activatable() = true;
547 active_cell->property_radio() = false;
549 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
550 active_cell->property_activatable() = true;
551 active_cell->property_radio() = false;
553 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
555 edit_group_display.set_name ("EditGroupList");
556 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
557 edit_group_display.set_headers_visible (true);
558 edit_group_display.set_reorderable (false);
559 edit_group_display.set_rules_hint (true);
560 edit_group_display.set_size_request (75, -1);
562 edit_group_display_scroller.add (edit_group_display);
563 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
565 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
567 VBox* edit_group_display_packer = manage (new VBox());
568 HBox* edit_group_display_button_box = manage (new HBox());
569 edit_group_display_button_box->set_homogeneous (true);
571 Button* edit_group_add_button = manage (new Button ());
572 Button* edit_group_remove_button = manage (new Button ());
576 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
578 edit_group_add_button->add (*w);
580 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
582 edit_group_remove_button->add (*w);
584 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
585 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
587 edit_group_display_button_box->pack_start (*edit_group_add_button);
588 edit_group_display_button_box->pack_start (*edit_group_remove_button);
590 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
591 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
593 region_list_display.set_size_request (100, -1);
594 region_list_display.set_name ("RegionListDisplay");
596 region_list_model = TreeStore::create (region_list_columns);
597 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
598 region_list_model->set_sort_column (0, SORT_ASCENDING);
600 region_list_display.set_model (region_list_model);
601 region_list_display.append_column (_("Regions"), region_list_columns.name);
602 region_list_display.set_headers_visible (false);
604 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
606 TreeViewColumn* tv_col = region_list_display.get_column(0);
607 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
608 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
609 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
611 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
612 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
614 /* setup DnD handling */
616 list<TargetEntry> region_list_target_table;
618 region_list_target_table.push_back (TargetEntry ("text/plain"));
619 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
620 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
622 region_list_display.add_drop_targets (region_list_target_table);
623 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
625 region_list_scroller.add (region_list_display);
626 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
628 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
629 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
630 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
631 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
632 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
633 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
635 named_selection_scroller.add (named_selection_display);
636 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
638 named_selection_model = TreeStore::create (named_selection_columns);
639 named_selection_display.set_model (named_selection_model);
640 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
641 named_selection_display.set_headers_visible (false);
642 named_selection_display.set_size_request (100, -1);
643 named_selection_display.set_name ("NamedSelectionDisplay");
645 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
646 named_selection_display.set_size_request (100, -1);
647 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
648 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
649 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
653 snapshot_display_model = ListStore::create (snapshot_display_columns);
654 snapshot_display.set_model (snapshot_display_model);
655 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
656 snapshot_display.set_name ("SnapshotDisplay");
657 snapshot_display.set_size_request (75, -1);
658 snapshot_display.set_headers_visible (false);
659 snapshot_display.set_reorderable (false);
660 snapshot_display_scroller.add (snapshot_display);
661 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
663 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
664 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
668 nlabel = manage (new Label (_("Regions")));
669 nlabel->set_angle (-90);
670 the_notebook.append_page (region_list_scroller, *nlabel);
671 nlabel = manage (new Label (_("Tracks/Busses")));
672 nlabel->set_angle (-90);
673 the_notebook.append_page (route_list_scroller, *nlabel);
674 nlabel = manage (new Label (_("Snapshots")));
675 nlabel->set_angle (-90);
676 the_notebook.append_page (snapshot_display_scroller, *nlabel);
677 nlabel = manage (new Label (_("Edit Groups")));
678 nlabel->set_angle (-90);
679 the_notebook.append_page (*edit_group_display_packer, *nlabel);
680 nlabel = manage (new Label (_("Chunks")));
681 nlabel->set_angle (-90);
682 the_notebook.append_page (named_selection_scroller, *nlabel);
684 the_notebook.set_show_tabs (true);
685 the_notebook.set_scrollable (true);
686 the_notebook.popup_enable ();
687 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
689 post_maximal_editor_width = 0;
690 post_maximal_pane_position = 0;
691 edit_pane.pack1 (edit_packer, true, true);
692 edit_pane.pack2 (the_notebook, false, true);
694 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
696 top_hbox.pack_start (toolbar_frame, false, true);
697 top_hbox.pack_start (midi_toolbar_frame, false, true);
699 HBox *hbox = manage (new HBox);
700 hbox->pack_start (edit_pane, true, true);
702 global_vpacker.pack_start (top_hbox, false, false);
703 global_vpacker.pack_start (*hbox, true, true);
705 global_hpacker.pack_start (global_vpacker, true, true);
707 set_name ("EditorWindow");
708 add_accel_group (ActionManager::ui_manager->get_accel_group());
710 status_bar_hpacker.show ();
712 vpacker.pack_end (status_bar_hpacker, false, false);
713 vpacker.pack_end (global_hpacker, true, true);
715 /* register actions now so that set_state() can find them and set toggles/checks etc */
719 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
722 _playlist_selector = new PlaylistSelector();
723 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
725 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
729 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
730 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
732 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
733 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
735 nudge_forward_button.set_name ("TransportButton");
736 nudge_backward_button.set_name ("TransportButton");
738 fade_context_menu.set_name ("ArdourContextMenu");
740 /* icons, titles, WM stuff */
742 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
743 Glib::RefPtr<Gdk::Pixbuf> icon;
745 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
746 window_icons.push_back (icon);
748 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
749 window_icons.push_back (icon);
751 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
752 window_icons.push_back (icon);
754 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
755 window_icons.push_back (icon);
757 if (!window_icons.empty()) {
758 set_icon_list (window_icons);
759 set_default_icon_list (window_icons);
762 WindowTitle title(Glib::get_application_name());
763 title += _("Editor");
764 set_title (title.get_string());
765 set_wmclass (X_("ardour_editor"), "Ardour");
768 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
770 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
771 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
773 /* allow external control surfaces/protocols to do various things */
775 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
776 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
777 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
778 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
780 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
781 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
790 if(image_socket_listener)
792 if(image_socket_listener->is_connected())
794 image_socket_listener->close_connection() ;
797 delete image_socket_listener ;
798 image_socket_listener = 0 ;
804 Editor::add_toplevel_controls (Container& cont)
806 vpacker.pack_start (cont, false, false);
811 Editor::catch_vanishing_regionview (RegionView *rv)
813 /* note: the selection will take care of the vanishing
814 audioregionview by itself.
817 if (clicked_regionview == rv) {
818 clicked_regionview = 0;
821 if (entered_regionview == rv) {
822 set_entered_regionview (0);
827 Editor::set_entered_regionview (RegionView* rv)
829 if (rv == entered_regionview) {
833 if (entered_regionview) {
834 entered_regionview->exited ();
837 if ((entered_regionview = rv) != 0) {
838 entered_regionview->entered ();
843 Editor::set_entered_track (TimeAxisView* tav)
846 entered_track->exited ();
849 if ((entered_track = tav) != 0) {
850 entered_track->entered ();
855 Editor::show_window ()
857 show_all_children ();
859 /* re-hide editor list if necessary */
860 editor_list_button_toggled ();
862 /* now reset all audio_time_axis heights, because widgets might need
868 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
869 tv = (static_cast<TimeAxisView*>(*i));
877 Editor::tie_vertical_scrolling ()
879 double y1 = vertical_adjustment.get_value();
881 playhead_cursor->set_y_axis (y1);
882 edit_cursor->set_y_axis (y1);
884 logo_item->property_y() = y1;
887 controls_layout.get_vadjustment()->set_value (y1);
890 /* the way idle updates and immediate window flushing work on GTK-Quartz
891 requires that we force an immediate redraw right here. The controls
892 layout will do the same all by itself, as does the canvas widget, but
893 most of the time, the canvas itself hasn't updated itself because its
894 idle handler hasn't run. consequently, the call that its layout makes
895 to gdk_window_process_updates() finds nothing to do. here, we force
896 the update to happen, then request a flush of the new window state.
898 track_canvas.update_now ();
899 gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
904 Editor::instant_save ()
906 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
911 session->add_instant_xml(get_state());
913 Config->add_instant_xml(get_state());
918 Editor::edit_cursor_clock_changed()
920 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
921 edit_cursor->set_position (edit_cursor_clock.current_time());
927 Editor::zoom_adjustment_changed ()
933 double fpu = zoom_range_clock.current_duration() / canvas_width;
937 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
938 } else if (fpu > session->current_end_frame() / canvas_width) {
939 fpu = session->current_end_frame() / canvas_width;
940 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
947 Editor::control_scroll (float fraction)
949 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
955 double step = fraction * current_page_frames();
958 _control_scroll_target is an optional<T>
960 it acts like a pointer to an nframes_t, with
961 a operator conversion to boolean to check
962 that it has a value could possibly use
963 playhead_cursor->current_frame to store the
964 value and a boolean in the class to know
965 when it's out of date
968 if (!_control_scroll_target) {
969 _control_scroll_target = session->transport_frame();
970 _dragging_playhead = true;
973 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
974 *_control_scroll_target = 0;
975 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
976 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
978 *_control_scroll_target += (nframes_t) floor (step);
981 /* move visuals, we'll catch up with it later */
983 playhead_cursor->set_position (*_control_scroll_target);
984 UpdateAllTransportClocks (*_control_scroll_target);
986 if (*_control_scroll_target > (current_page_frames() / 2)) {
987 /* try to center PH in window */
988 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
994 Now we do a timeout to actually bring the session to the right place
995 according to the playhead. This is to avoid reading disk buffers on every
996 call to control_scroll, which is driven by ScrollTimeline and therefore
997 probably by a control surface wheel which can generate lots of events.
999 /* cancel the existing timeout */
1001 control_scroll_connection.disconnect ();
1003 /* add the next timeout */
1005 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1009 Editor::deferred_control_scroll (nframes_t target)
1011 session->request_locate (*_control_scroll_target, session->transport_rolling());
1012 // reset for next stream
1013 _control_scroll_target = boost::none;
1014 _dragging_playhead = false;
1019 Editor::on_realize ()
1021 Window::on_realize ();
1026 Editor::start_scrolling ()
1028 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1029 (mem_fun(*this, &Editor::update_current_screen));
1033 Editor::stop_scrolling ()
1035 scroll_connection.disconnect ();
1039 Editor::map_position_change (nframes_t frame)
1041 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1043 if (session == 0 || !_follow_playhead) {
1047 center_screen (frame);
1048 playhead_cursor->set_position (frame);
1052 Editor::center_screen (nframes_t frame)
1054 double page = canvas_width * frames_per_unit;
1056 /* if we're off the page, then scroll.
1059 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1060 center_screen_internal (frame, page);
1065 Editor::center_screen_internal (nframes_t frame, float page)
1070 frame -= (nframes_t) page;
1075 reset_x_origin (frame);
1079 Editor::handle_new_duration ()
1081 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1083 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1085 if (new_end > last_canvas_frame) {
1086 last_canvas_frame = new_end;
1087 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1088 reset_scrolling_region ();
1091 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1095 Editor::update_title_s (const string & snap_name)
1097 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1103 Editor::update_title ()
1105 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1108 bool dirty = session->dirty();
1110 string session_name;
1112 if (session->snap_name() != session->name()) {
1113 session_name = session->snap_name();
1115 session_name = session->name();
1119 session_name = "*" + session_name;
1122 WindowTitle title(session_name);
1123 title += Glib::get_application_name();
1124 set_title (title.get_string());
1129 Editor::connect_to_session (Session *t)
1133 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1136 /* catch up with the playhead */
1138 session->request_locate (playhead_cursor->current_frame);
1140 if (first_action_message) {
1141 first_action_message->hide();
1146 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1147 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1149 /* These signals can all be emitted by a non-GUI thread. Therefore the
1150 handlers for them must not attempt to directly interact with the GUI,
1151 but use Gtkmm2ext::UI::instance()->call_slot();
1154 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1155 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1156 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1157 session_connections.push_back (session->RegionAdded.connect (mem_fun(*this, &Editor::handle_new_region)));
1158 session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed)));
1159 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1160 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1161 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1162 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1163 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1164 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1165 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1166 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1167 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1169 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1171 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1173 edit_groups_changed ();
1175 edit_cursor_clock.set_session (session);
1176 zoom_range_clock.set_session (session);
1177 _playlist_selector->set_session (session);
1178 nudge_clock.set_session (session);
1181 if (analysis_window != 0)
1182 analysis_window->set_session (session);
1185 Location* loc = session->locations()->auto_loop_location();
1187 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1188 if (loc->start() == loc->end()) {
1189 loc->set_end (loc->start() + 1);
1191 session->locations()->add (loc, false);
1192 session->set_auto_loop_location (loc);
1195 loc->set_name (_("Loop"));
1198 loc = session->locations()->auto_punch_location();
1200 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1201 if (loc->start() == loc->end()) {
1202 loc->set_end (loc->start() + 1);
1204 session->locations()->add (loc, false);
1205 session->set_auto_punch_location (loc);
1208 loc->set_name (_("Punch"));
1211 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1213 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1215 refresh_location_display ();
1216 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1217 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1218 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1219 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1220 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1223 sfbrowser->set_session (session);
1226 handle_new_duration ();
1228 redisplay_regions ();
1229 redisplay_named_selections ();
1230 redisplay_snapshots ();
1232 initial_route_list_display ();
1234 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1235 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1238 restore_ruler_visibility ();
1239 //tempo_map_changed (Change (0));
1240 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1244 /* don't show master bus in a new session */
1246 if (ARDOUR_UI::instance()->session_is_new ()) {
1248 TreeModel::Children rows = route_display_model->children();
1249 TreeModel::Children::iterator i;
1251 no_route_list_redisplay = true;
1253 for (i = rows.begin(); i != rows.end(); ++i) {
1254 TimeAxisView *tv = (*i)[route_display_columns.tv];
1255 RouteTimeAxisView *rtv;
1257 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1258 if (rtv->route()->is_master()) {
1259 route_list_display.get_selection()->unselect (i);
1264 no_route_list_redisplay = false;
1265 redisplay_route_list ();
1268 /* register for undo history */
1270 session->register_with_memento_command_factory(_id, this);
1274 Editor::build_cursors ()
1276 using namespace Gdk;
1278 Gdk::Color mbg ("#000000" ); /* Black */
1279 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1282 RefPtr<Bitmap> source, mask;
1283 source = Bitmap::create (mag_bits, mag_width, mag_height);
1284 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1285 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1288 Gdk::Color fbg ("#ffffff" );
1289 Gdk::Color ffg ("#000000" );
1292 RefPtr<Bitmap> source, mask;
1294 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1295 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1296 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1300 RefPtr<Bitmap> source, mask;
1301 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1302 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1303 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1306 grabber_cursor = new Gdk::Cursor (HAND2);
1307 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1308 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1309 selector_cursor = new Gdk::Cursor (XTERM);
1310 time_fx_cursor = new Gdk::Cursor (SIZING);
1311 wait_cursor = new Gdk::Cursor (WATCH);
1312 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1313 midi_pencil_cursor = new Gdk::Cursor (PENCIL);
1314 midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
1315 midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
1318 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1320 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1322 using namespace Menu_Helpers;
1323 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1326 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1330 MenuList& items (fade_context_menu.items());
1334 switch (item_type) {
1336 case FadeInHandleItem:
1337 if (arv->audio_region()->fade_in_active()) {
1338 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1340 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1343 items.push_back (SeparatorElem());
1345 if (Profile->get_sae()) {
1346 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1347 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1349 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1350 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1351 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1352 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1353 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1359 case FadeOutHandleItem:
1360 if (arv->audio_region()->fade_out_active()) {
1361 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1363 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1366 items.push_back (SeparatorElem());
1368 if (Profile->get_sae()) {
1369 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1370 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1372 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1373 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1374 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1375 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1376 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1382 fatal << _("programming error: ")
1383 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1388 fade_context_menu.popup (button, time);
1391 /* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
1393 Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
1395 build_track_context_menu (frame)->popup (button, time);
1399 Editor::build_track_context_menu (nframes_t frame)
1401 using namespace Menu_Helpers;
1403 Menu* menu = manage (new Menu);
1404 MenuList& edit_items = menu->items();
1407 /* Build the general `track' context menu, adding what is appropriate given
1408 the current selection */
1410 /* XXX: currently crossfades can't be selected, so we can't use the selection
1411 to decide which crossfades to mention in the menu. I believe this will
1412 change at some point. For now we have to use clicked_trackview to decide. */
1413 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1416 boost::shared_ptr<Diskstream> ds;
1417 boost::shared_ptr<Playlist> pl;
1418 boost::shared_ptr<AudioPlaylist> apl;
1420 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1422 AudioPlaylist::Crossfades xfades;
1423 apl->crossfades_at (frame, xfades);
1425 bool many = xfades.size() > 1;
1427 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1428 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1433 if (!selection->time.empty()) {
1434 add_selection_context_items (edit_items);
1437 if (!selection->regions.empty()) {
1438 add_region_context_items (edit_items);
1441 if (!selection->tracks.empty()) {
1442 add_bus_or_audio_track_context_items (edit_items);
1445 menu->set_name ("ArdourContextMenu");
1452 Editor::analyze_region_selection()
1454 if (analysis_window == 0) {
1455 analysis_window = new AnalysisWindow();
1458 analysis_window->set_session(session);
1460 analysis_window->show_all();
1463 analysis_window->set_regionmode();
1464 analysis_window->analyze();
1466 analysis_window->present();
1470 Editor::analyze_range_selection()
1472 if (analysis_window == 0) {
1473 analysis_window = new AnalysisWindow();
1476 analysis_window->set_session(session);
1478 analysis_window->show_all();
1481 analysis_window->set_rangemode();
1482 analysis_window->analyze();
1484 analysis_window->present();
1486 #endif /* FFT_ANALYSIS */
1489 /** Add context menu items relevant to crossfades.
1490 * @param edit_items List to add the items to.
1493 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1495 using namespace Menu_Helpers;
1496 Menu *xfade_menu = manage (new Menu);
1497 MenuList& items = xfade_menu->items();
1498 xfade_menu->set_name ("ArdourContextMenu");
1501 if (xfade->active()) {
1507 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1508 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1510 if (xfade->can_follow_overlap()) {
1512 if (xfade->following_overlap()) {
1513 str = _("Convert to short");
1515 str = _("Convert to full");
1518 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1522 str = xfade->out()->name();
1524 str += xfade->in()->name();
1526 str = _("Crossfade");
1529 edit_items.push_back (MenuElem (str, *xfade_menu));
1530 edit_items.push_back (SeparatorElem());
1534 Editor::xfade_edit_left_region ()
1536 if (clicked_crossfadeview) {
1537 clicked_crossfadeview->left_view.show_region_editor ();
1542 Editor::xfade_edit_right_region ()
1544 if (clicked_crossfadeview) {
1545 clicked_crossfadeview->right_view.show_region_editor ();
1549 /** Add an element to a menu, settings its sensitivity.
1550 * @param m Menu to add to.
1551 * @param e Element to add.
1552 * @param s true to make sensitive, false to make insensitive
1555 Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
1559 m.back().set_sensitive (false);
1563 /** Add context menu items relevant to regions.
1564 * @param edit_items List to add the items to.
1567 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
1569 using namespace Menu_Helpers;
1570 sigc::connection fooc;
1571 Menu *region_menu = manage (new Menu);
1572 MenuList& items = region_menu->items();
1573 region_menu->set_name ("ArdourContextMenu");
1575 items.push_back (MenuElem (_("Edit..."), mem_fun(*this, &Editor::edit_region)));
1576 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1577 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1579 Menu* sync_point_menu = manage (new Menu);
1580 MenuList& sync_point_items = sync_point_menu->items();
1581 sync_point_menu->set_name("ArdourContextMenu");
1583 sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1584 sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
1586 items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
1588 add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
1590 add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
1592 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1595 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1598 items.push_back (SeparatorElem());
1600 items.push_back (CheckMenuElem (_("Lock")));
1601 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1602 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1604 #if FIXUP_REGION_MENU
1605 if (region->locked()) {
1607 region_lock_item->set_active();
1612 items.push_back (CheckMenuElem (_("Lock Position")));
1613 region_lock_position_item = static_cast<CheckMenuItem*>(&items.back());
1614 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_position_lock));
1615 #if FIXUP_REGION_MENU
1616 if (region->locked()) {
1618 region_lock_position_item->set_active();
1623 items.push_back (CheckMenuElem (_("Mute")));
1624 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1625 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1626 #if FIXUP_REGION_MENU
1627 if (region->muted()) {
1629 region_mute_item->set_active();
1634 if (!Profile->get_sae()) {
1635 items.push_back (CheckMenuElem (_("Opaque")));
1636 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1637 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1638 #if FIXUP_REGION_MENU
1639 if (region->opaque()) {
1641 region_opaque_item->set_active();
1647 /* We allow "Original position" if at least one region is not at its
1650 RegionSelection::iterator i = selection->regions.begin();
1651 while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
1655 add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
1657 items.push_back (SeparatorElem());
1659 /* Find out if we have a selected audio region */
1660 i = selection->regions.begin();
1661 while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
1664 const bool have_selected_audio_region = (i != selection->regions.end());
1666 if (have_selected_audio_region) {
1668 Menu* envelopes_menu = manage (new Menu);
1670 envelopes_menu->set_name ("ArdourContextMenu");
1672 #if FIXUP_REGION_MENU
1674 XXX NEED TO RESOLVE ONE v. MANY REGION ISSUE
1676 MenuList& envelopes_items = envelopes_menu->items();
1678 RegionView* rv = sv->find_view (ar);
1679 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1681 if (!Profile->get_sae()) {
1682 envelopes_items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1684 envelopes_items.push_back (CheckMenuElem (_("Envelope Visible")));
1685 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1686 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1687 if (arv->envelope_visible()) {
1689 region_envelope_visible_item->set_active (true);
1693 envelopes_items.push_back (CheckMenuElem (_("Envelope Active")));
1694 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1695 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1697 if (ar->envelope_active()) {
1699 region_envelope_active_item->set_active (true);
1703 items.push_back (SeparatorElem());
1707 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1709 #if FIXUP_REGION_MENU
1710 if (ar->scale_amplitude() != 1.0f) {
1711 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_regions)));
1713 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_regions)));
1718 /* Find out if we have a selected MIDI region */
1719 i = selection->regions.begin();
1720 while (i != selection->regions.end() && boost::dynamic_pointer_cast<MidiRegion>((*i)->region()) == 0) {
1723 const bool have_selected_midi_region = (i != selection->regions.end());
1725 if (have_selected_midi_region) {
1727 items.push_back (MenuElem (_("Quantize"), mem_fun(*this, &Editor::quantize_regions)));
1728 items.push_back (SeparatorElem());
1732 /* range related stuff */
1734 add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1736 add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1738 items.push_back (SeparatorElem());
1742 Menu *nudge_menu = manage (new Menu());
1743 MenuList& nudge_items = nudge_menu->items();
1744 nudge_menu->set_name ("ArdourContextMenu");
1746 nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1747 nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1748 nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1749 nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1751 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1753 Menu *trim_menu = manage (new Menu);
1754 MenuList& trim_items = trim_menu->items();
1755 trim_menu->set_name ("ArdourContextMenu");
1757 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1758 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1760 items.push_back (MenuElem (_("Trim"), *trim_menu));
1761 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1762 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1763 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1764 items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1765 items.push_back (SeparatorElem());
1766 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1768 /* OK, stick the region submenu at the top of the list, and then add
1772 string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1773 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1776 /** Add context menu items relevant to selection ranges.
1777 * @param edit_items List to add the items to.
1780 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1782 using namespace Menu_Helpers;
1783 Menu *selection_menu = manage (new Menu);
1784 MenuList& items = selection_menu->items();
1785 selection_menu->set_name ("ArdourContextMenu");
1787 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1788 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1791 items.push_back (SeparatorElem());
1792 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1795 items.push_back (SeparatorElem());
1796 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1797 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1799 items.push_back (SeparatorElem());
1800 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1801 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1803 items.push_back (SeparatorElem());
1804 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1806 items.push_back (SeparatorElem());
1807 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1808 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1810 items.push_back (SeparatorElem());
1811 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1812 items.push_back (SeparatorElem());
1813 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1814 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1815 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1816 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1817 items.push_back (SeparatorElem());
1818 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1819 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1822 /** Add context menu items relevant to busses or audio tracks.
1823 * @param edit_items List to add the items to.
1826 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1828 using namespace Menu_Helpers;
1830 /* We add every possible action here, and de-sensitize things
1831 that aren't allowed. The sensitivity logic is a bit spread out;
1832 on the one hand I'm using things like can_cut_copy (), which is
1833 reasonably complicated and so perhaps better near the function that
1834 it expresses sensitivity for, and on the other hand checks
1835 in this function as well. You can't really have can_* for everything
1836 or the number of methods would get silly. */
1838 bool const one_selected_region = selection->regions.size() == 1;
1840 /* Count the number of selected audio tracks */
1841 int n_audio_tracks = 0;
1842 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1843 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1844 if (r && r->is_audio_track()) {
1851 Menu *play_menu = manage (new Menu);
1852 MenuList& play_items = play_menu->items();
1853 play_menu->set_name ("ArdourContextMenu");
1855 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1856 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1857 add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1859 add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1861 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1865 Menu *select_menu = manage (new Menu);
1866 MenuList& select_items = select_menu->items();
1867 select_menu->set_name ("ArdourContextMenu");
1869 string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1871 select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1873 select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1875 str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1877 select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1879 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1880 select_items.push_back (SeparatorElem());
1882 if (n_audio_tracks) {
1883 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1884 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1887 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1888 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1889 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1890 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1892 if (n_audio_tracks) {
1893 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1896 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1900 Menu *cutnpaste_menu = manage (new Menu);
1901 MenuList& cutnpaste_items = cutnpaste_menu->items();
1902 cutnpaste_menu->set_name ("ArdourContextMenu");
1904 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1906 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1908 if (n_audio_tracks) {
1909 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1910 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1912 cutnpaste_items.push_back (SeparatorElem());
1914 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1915 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1916 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1918 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1921 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1923 if (n_audio_tracks) {
1925 Menu *track_menu = manage (new Menu);
1926 MenuList& track_items = track_menu->items();
1927 track_menu->set_name ("ArdourContextMenu");
1929 /* Adding new material */
1931 add_item_with_sensitivity (track_items, MenuElem (_("Insert selected region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)), n_audio_tracks == 1);
1933 add_item_with_sensitivity (track_items, MenuElem (_("Insert existing audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1937 Menu *nudge_menu = manage (new Menu());
1938 MenuList& nudge_items = nudge_menu->items();
1939 nudge_menu->set_name ("ArdourContextMenu");
1941 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1942 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1944 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1946 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1948 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1950 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1952 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1954 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1956 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1959 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1960 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1962 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1963 edit_items.push_back (MenuElem (str, *track_menu));
1967 /* CURSOR SETTING AND MARKS AND STUFF */
1970 Editor::set_snap_to (SnapType st)
1973 string str = snap_type_strings[(int) st];
1975 if (str != snap_type_selector.get_active_text()) {
1976 snap_type_selector.set_active_text (str);
1981 switch (snap_type) {
1982 case SnapToAThirtysecondBeat:
1983 case SnapToASixteenthBeat:
1984 case SnapToAEighthBeat:
1985 case SnapToAQuarterBeat:
1986 case SnapToAThirdBeat:
1987 update_tempo_based_rulers ();
1995 Editor::set_snap_mode (SnapMode mode)
1998 string str = snap_mode_strings[(int)mode];
2000 if (str != snap_mode_selector.get_active_text ()) {
2001 snap_mode_selector.set_active_text (str);
2008 Editor::set_state (const XMLNode& node)
2010 const XMLProperty* prop;
2012 int x, y, xoff, yoff;
2015 if ((prop = node.property ("id")) != 0) {
2016 _id = prop->value ();
2019 if ((geometry = find_named_node (node, "geometry")) == 0) {
2021 g.base_width = default_width;
2022 g.base_height = default_height;
2030 g.base_width = atoi(geometry->property("x_size")->value());
2031 g.base_height = atoi(geometry->property("y_size")->value());
2032 x = atoi(geometry->property("x_pos")->value());
2033 y = atoi(geometry->property("y_pos")->value());
2034 xoff = atoi(geometry->property("x_off")->value());
2035 yoff = atoi(geometry->property("y_off")->value());
2038 set_default_size (g.base_width, g.base_height);
2041 if (session && (prop = node.property ("playhead"))) {
2042 nframes_t pos = atol (prop->value().c_str());
2043 playhead_cursor->set_position (pos);
2045 playhead_cursor->set_position (0);
2047 /* reset_x_origin() doesn't work right here, since the old
2048 position may be zero already, and it does nothing in such
2053 horizontal_adjustment.set_value (0);
2056 if (session && (prop = node.property ("edit-cursor"))) {
2057 nframes_t pos = atol (prop->value().c_str());
2058 edit_cursor->set_position (pos);
2060 edit_cursor->set_position (0);
2063 if ((prop = node.property ("mixer-width"))) {
2064 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2067 if ((prop = node.property ("zoom-focus"))) {
2068 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2071 if ((prop = node.property ("zoom"))) {
2072 reset_zoom (PBD::atof (prop->value()));
2075 if ((prop = node.property ("snap-to"))) {
2076 set_snap_to ((SnapType) atoi (prop->value()));
2079 if ((prop = node.property ("snap-mode"))) {
2080 set_snap_mode ((SnapMode) atoi (prop->value()));
2083 if ((prop = node.property ("mouse-mode"))) {
2084 MouseMode m = str2mousemode(prop->value());
2085 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2086 set_mouse_mode (m, true);
2088 mouse_mode = MouseGain; /* lie, to force the mode switch */
2089 set_mouse_mode (MouseObject, true);
2092 if ((prop = node.property ("show-waveforms"))) {
2093 bool yn = (prop->value() == "yes");
2094 _show_waveforms = !yn;
2095 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2097 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2098 /* do it twice to force the change */
2099 tact->set_active (!yn);
2100 tact->set_active (yn);
2104 if ((prop = node.property ("show-waveforms-recording"))) {
2105 bool yn = (prop->value() == "yes");
2106 _show_waveforms_recording = !yn;
2107 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2109 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2110 /* do it twice to force the change */
2111 tact->set_active (!yn);
2112 tact->set_active (yn);
2116 if ((prop = node.property ("show-measures"))) {
2117 bool yn = (prop->value() == "yes");
2118 _show_measures = !yn;
2119 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2121 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2122 /* do it twice to force the change */
2123 tact->set_active (!yn);
2124 tact->set_active (yn);
2128 if ((prop = node.property ("follow-playhead"))) {
2129 bool yn = (prop->value() == "yes");
2130 set_follow_playhead (yn);
2131 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2133 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2134 if (tact->get_active() != yn) {
2135 tact->set_active (yn);
2140 if ((prop = node.property ("region-list-sort-type"))) {
2141 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2142 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2145 if ((prop = node.property ("xfades-visible"))) {
2146 bool yn = (prop->value() == "yes");
2147 _xfade_visibility = !yn;
2148 // set_xfade_visibility (yn);
2151 if ((prop = node.property ("show-editor-mixer"))) {
2153 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2156 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2157 bool yn = (prop->value() == X_("yes"));
2159 /* do it twice to force the change */
2161 tact->set_active (!yn);
2162 tact->set_active (yn);
2166 if ((prop = node.property ("show-editor-list"))) {
2168 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2172 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2173 bool yn = (prop->value() == X_("yes"));
2175 /* do it twice to force the change */
2177 tact->set_active (!yn);
2178 tact->set_active (yn);
2187 Editor::get_state ()
2189 XMLNode* node = new XMLNode ("Editor");
2192 _id.print (buf, sizeof (buf));
2193 node->add_property ("id", buf);
2195 if (is_realized()) {
2196 Glib::RefPtr<Gdk::Window> win = get_window();
2198 int x, y, xoff, yoff, width, height;
2199 win->get_root_origin(x, y);
2200 win->get_position(xoff, yoff);
2201 win->get_size(width, height);
2203 XMLNode* geometry = new XMLNode ("geometry");
2205 snprintf(buf, sizeof(buf), "%d", width);
2206 geometry->add_property("x_size", string(buf));
2207 snprintf(buf, sizeof(buf), "%d", height);
2208 geometry->add_property("y_size", string(buf));
2209 snprintf(buf, sizeof(buf), "%d", x);
2210 geometry->add_property("x_pos", string(buf));
2211 snprintf(buf, sizeof(buf), "%d", y);
2212 geometry->add_property("y_pos", string(buf));
2213 snprintf(buf, sizeof(buf), "%d", xoff);
2214 geometry->add_property("x_off", string(buf));
2215 snprintf(buf, sizeof(buf), "%d", yoff);
2216 geometry->add_property("y_off", string(buf));
2217 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2218 geometry->add_property("edit_pane_pos", string(buf));
2220 node->add_child_nocopy (*geometry);
2223 maybe_add_mixer_strip_width (*node);
2225 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2226 node->add_property ("zoom-focus", buf);
2227 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2228 node->add_property ("zoom", buf);
2229 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2230 node->add_property ("snap-to", buf);
2231 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2232 node->add_property ("snap-mode", buf);
2234 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2235 node->add_property ("playhead", buf);
2236 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2237 node->add_property ("edit-cursor", buf);
2239 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2240 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2241 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2242 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2243 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2244 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2245 node->add_property ("mouse-mode", enum2str(mouse_mode));
2247 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2249 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2250 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2253 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2255 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2256 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2265 Editor::trackview_by_y_position (double y)
2267 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2271 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2280 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2282 Location* before = 0;
2283 Location* after = 0;
2289 const nframes64_t one_second = session->frame_rate();
2290 const nframes64_t one_minute = session->frame_rate() * 60;
2291 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2292 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2293 nframes64_t presnap = start;
2295 switch (snap_type) {
2301 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2303 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2307 case SnapToSMPTEFrame:
2308 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2309 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2311 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2315 case SnapToSMPTESeconds:
2316 if (session->smpte_offset_negative())
2318 start += session->smpte_offset ();
2320 start -= session->smpte_offset ();
2322 if (start % one_smpte_second > one_smpte_second / 2) {
2323 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2325 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2328 if (session->smpte_offset_negative())
2330 start -= session->smpte_offset ();
2332 start += session->smpte_offset ();
2336 case SnapToSMPTEMinutes:
2337 if (session->smpte_offset_negative())
2339 start += session->smpte_offset ();
2341 start -= session->smpte_offset ();
2343 if (start % one_smpte_minute > one_smpte_minute / 2) {
2344 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2346 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2348 if (session->smpte_offset_negative())
2350 start -= session->smpte_offset ();
2352 start += session->smpte_offset ();
2357 if (start % one_second > one_second / 2) {
2358 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2360 start = (nframes_t) floor ((double) start / one_second) * one_second;
2365 if (start % one_minute > one_minute / 2) {
2366 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2368 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2373 start = session->tempo_map().round_to_bar (start, direction);
2377 start = session->tempo_map().round_to_beat (start, direction);
2380 case SnapToAThirtysecondBeat:
2381 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2384 case SnapToASixteenthBeat:
2385 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2388 case SnapToAEighthBeat:
2389 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2392 case SnapToAQuarterBeat:
2393 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2396 case SnapToAThirdBeat:
2397 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2400 case SnapToEditCursor:
2401 start = edit_cursor->current_frame;
2409 before = session->locations()->first_location_before (start);
2410 after = session->locations()->first_location_after (start);
2412 if (direction < 0) {
2414 start = before->start();
2418 } else if (direction > 0) {
2420 start = after->start();
2422 start = session->current_end_frame();
2427 /* find nearest of the two */
2428 if ((start - before->start()) < (after->start() - start)) {
2429 start = before->start();
2431 start = after->start();
2434 start = before->start();
2437 start = after->start();
2444 case SnapToRegionStart:
2445 case SnapToRegionEnd:
2446 case SnapToRegionSync:
2447 case SnapToRegionBoundary:
2448 if (!region_boundary_cache.empty()) {
2449 vector<nframes_t>::iterator i;
2451 if (direction > 0) {
2452 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2454 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2457 if (i != region_boundary_cache.end()) {
2460 start = region_boundary_cache.back();
2466 switch (snap_mode) {
2472 if (presnap > start) {
2473 if (presnap > (start + unit_to_frame(snap_threshold))) {
2477 } else if (presnap < start) {
2478 if (presnap < (start - unit_to_frame(snap_threshold))) {
2490 Editor::snap_length_beats (nframes_t start)
2496 /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
2498 switch (snap_type) {
2500 return session->tempo_map().meter_at(start).beats_per_bar();
2505 case SnapToAThirtysecondBeat:
2506 return 1.0 / (double)32.0;
2509 case SnapToASixteenthBeat:
2510 return 1.0 / (double)16.0;
2513 case SnapToAEighthBeat:
2514 return 1.0 / (double)8.0;
2517 case SnapToAQuarterBeat:
2518 return 1.0 / (double)4.0;
2521 case SnapToAThirdBeat:
2522 return 1.0 / (double)3.0;
2530 Editor::setup_toolbar ()
2534 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2537 /* Mode Buttons (tool selection) */
2539 vector<ToggleButton *> mouse_mode_buttons;
2541 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2542 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2543 mouse_mode_buttons.push_back (&mouse_move_button);
2544 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2545 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2546 mouse_mode_buttons.push_back (&mouse_select_button);
2547 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2548 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2549 mouse_mode_buttons.push_back (&mouse_gain_button);
2550 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2551 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2552 mouse_mode_buttons.push_back (&mouse_zoom_button);
2553 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2554 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2555 mouse_mode_buttons.push_back (&mouse_timefx_button);
2556 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2557 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2558 mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2559 mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2560 mouse_mode_buttons.push_back (&mouse_note_button);
2561 mouse_mode_buttons.push_back (&mouse_audition_button);
2563 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2565 HBox* mode_box = manage(new HBox);
2566 mode_box->set_border_width (2);
2567 mode_box->set_spacing(4);
2568 mouse_mode_button_box.set_spacing(1);
2569 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2570 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2571 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2572 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2573 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2574 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2575 mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2576 mouse_mode_button_box.set_homogeneous(true);
2578 vector<string> edit_mode_strings;
2579 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2580 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2582 edit_mode_selector.set_name ("EditModeSelector");
2583 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2584 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2585 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2587 mode_box->pack_start(edit_mode_selector);
2588 mode_box->pack_start(mouse_mode_button_box);
2590 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2591 mouse_mode_tearoff->set_name ("MouseModeBase");
2593 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2594 &mouse_mode_tearoff->tearoff_window()));
2595 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2596 &mouse_mode_tearoff->tearoff_window(), 1));
2597 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2598 &mouse_mode_tearoff->tearoff_window()));
2599 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2600 &mouse_mode_tearoff->tearoff_window(), 1));
2602 mouse_move_button.set_name ("MouseModeButton");
2603 mouse_select_button.set_name ("MouseModeButton");
2604 mouse_gain_button.set_name ("MouseModeButton");
2605 mouse_zoom_button.set_name ("MouseModeButton");
2606 mouse_timefx_button.set_name ("MouseModeButton");
2607 mouse_audition_button.set_name ("MouseModeButton");
2608 mouse_note_button.set_name ("MouseModeButton");
2610 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2611 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2612 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2613 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2614 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2615 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2616 ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2618 mouse_move_button.unset_flags (CAN_FOCUS);
2619 mouse_select_button.unset_flags (CAN_FOCUS);
2620 mouse_gain_button.unset_flags (CAN_FOCUS);
2621 mouse_zoom_button.unset_flags (CAN_FOCUS);
2622 mouse_timefx_button.unset_flags (CAN_FOCUS);
2623 mouse_audition_button.unset_flags (CAN_FOCUS);
2624 mouse_note_button.unset_flags (CAN_FOCUS);
2626 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2627 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2629 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2630 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2631 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2632 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2633 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2634 mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2636 // mouse_move_button.set_active (true);
2641 zoom_box.set_spacing (1);
2642 zoom_box.set_border_width (2);
2644 zoom_in_button.set_name ("EditorTimeButton");
2645 zoom_in_button.set_size_request(-1,16);
2646 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2647 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2648 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2650 zoom_out_button.set_name ("EditorTimeButton");
2651 zoom_out_button.set_size_request(-1,16);
2652 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2653 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2654 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2656 zoom_out_full_button.set_name ("EditorTimeButton");
2657 zoom_out_full_button.set_size_request(-1,16);
2658 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2659 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2660 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2662 zoom_focus_selector.set_name ("ZoomFocusSelector");
2663 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Center", FUDGE, 0);
2664 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2665 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2666 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2668 zoom_box.pack_start (zoom_focus_selector, true, true);
2669 zoom_box.pack_start (zoom_out_button, false, false);
2670 zoom_box.pack_start (zoom_in_button, false, false);
2671 zoom_box.pack_start (zoom_out_full_button, false, false);
2673 /* Edit Cursor / Snap */
2675 snap_box.set_spacing (1);
2676 snap_box.set_border_width (2);
2678 snap_type_selector.set_name ("SnapTypeSelector");
2679 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2680 set_popdown_strings (snap_type_selector, snap_type_strings);
2681 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2682 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2684 snap_mode_selector.set_name ("SnapModeSelector");
2685 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2686 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2687 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2689 snap_box.pack_start (edit_cursor_clock, false, false);
2690 snap_box.pack_start (snap_mode_selector, false, false);
2691 snap_box.pack_start (snap_type_selector, false, false);
2696 HBox *nudge_box = manage (new HBox);
2697 nudge_box->set_spacing(1);
2698 nudge_box->set_border_width (2);
2700 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2701 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2703 nudge_box->pack_start (nudge_backward_button, false, false);
2704 nudge_box->pack_start (nudge_forward_button, false, false);
2705 nudge_box->pack_start (nudge_clock, false, false);
2708 /* Pack everything in... */
2710 HBox* hbox = new HBox;
2711 hbox->set_spacing(10);
2713 tools_tearoff = new TearOff (*hbox);
2714 tools_tearoff->set_name ("MouseModeBase");
2716 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2717 &tools_tearoff->tearoff_window()));
2718 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2719 &tools_tearoff->tearoff_window(), 0));
2720 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2721 &tools_tearoff->tearoff_window()));
2722 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2723 &tools_tearoff->tearoff_window(), 0));
2725 toolbar_hbox.set_spacing (10);
2726 toolbar_hbox.set_border_width (1);
2728 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2729 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2732 hbox->pack_start (snap_box, false, false);
2733 // hbox->pack_start (zoom_box, false, false);
2734 hbox->pack_start (*nudge_box, false, false);
2738 toolbar_base.set_name ("ToolBarBase");
2739 toolbar_base.add (toolbar_hbox);
2741 toolbar_frame.set_shadow_type (SHADOW_OUT);
2742 toolbar_frame.set_name ("BaseFrame");
2743 toolbar_frame.add (toolbar_base);
2748 Editor::setup_midi_toolbar ()
2752 /* Mode Buttons (tool selection) */
2754 vector<ToggleButton *> midi_tool_buttons;
2756 midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
2757 midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
2758 midi_tool_buttons.push_back (&midi_tool_pencil_button);
2759 midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
2760 midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
2761 midi_tool_buttons.push_back (&midi_tool_select_button);
2762 midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
2763 midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
2764 midi_tool_buttons.push_back (&midi_tool_erase_button);
2766 midi_tool_pencil_button.set_active(true);
2768 midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
2770 midi_tool_button_box.set_border_width (2);
2771 midi_tool_button_box.set_spacing(4);
2772 midi_tool_button_box.set_spacing(1);
2773 midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
2774 midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
2775 midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
2776 midi_tool_button_box.set_homogeneous(true);
2778 midi_tool_pencil_button.set_name ("MouseModeButton");
2779 midi_tool_select_button.set_name ("MouseModeButton");
2780 midi_tool_erase_button.set_name ("MouseModeButton");
2782 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
2783 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
2784 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
2786 midi_tool_pencil_button.unset_flags (CAN_FOCUS);
2787 midi_tool_select_button.unset_flags (CAN_FOCUS);
2788 midi_tool_erase_button.unset_flags (CAN_FOCUS);
2790 midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
2791 &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
2792 midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
2793 &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
2794 midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
2795 &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
2797 /* Pack everything in... */
2799 midi_tools_tearoff = new TearOff (midi_tool_button_box);
2800 midi_tools_tearoff->set_name ("MouseModeBase");
2803 midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2804 &midi_tools_tearoff->tearoff_window()));
2805 midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2806 &midi_tools_tearoff->tearoff_window(), 0));
2807 midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2808 &midi_tools_tearoff->tearoff_window()));
2809 midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2810 &midi_tools_tearoff->tearoff_window(), 0));
2813 midi_toolbar_hbox.set_spacing (10);
2814 midi_toolbar_hbox.set_border_width (1);
2816 midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
2818 midi_tool_button_box.show_all ();
2819 midi_toolbar_hbox.show_all();
2820 midi_tools_tearoff->show_all();
2822 midi_toolbar_base.set_name ("ToolBarBase");
2823 midi_toolbar_base.add (midi_toolbar_hbox);
2825 midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
2826 midi_toolbar_frame.set_name ("BaseFrame");
2827 midi_toolbar_frame.add (midi_toolbar_base);
2831 Editor::convert_drop_to_paths (vector<ustring>& paths,
2832 const RefPtr<Gdk::DragContext>& context,
2835 const SelectionData& data,
2844 vector<ustring> uris = data.get_uris();
2846 cerr << "there were " << uris.size() << " in that drag data\n";
2850 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2851 are actually URI lists. So do it by hand.
2854 if (data.get_target() != "text/plain") {
2858 /* Parse the "uri-list" format that Nautilus provides,
2859 where each pathname is delimited by \r\n
2862 const char* p = data.get_text().c_str();
2869 while (g_ascii_isspace (*p))
2873 while (*q && (*q != '\n') && (*q != '\r'))
2879 while (q > p && g_ascii_isspace (*q))
2884 uris.push_back (ustring (p, q - p + 1));
2888 p = strchr (p, '\n');
2898 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2900 if ((*i).substr (0,7) == "file://") {
2903 PBD::url_decode (p);
2905 // scan forward past three slashes
2907 ustring::size_type slashcnt = 0;
2908 ustring::size_type n = 0;
2909 ustring::iterator x = p.begin();
2911 while (slashcnt < 3 && x != p.end()) {
2914 } else if (slashcnt == 3) {
2921 if (slashcnt != 3 || x == p.end()) {
2922 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2926 paths.push_back (p.substr (n - 1));
2934 Editor::new_tempo_section ()
2940 Editor::map_transport_state ()
2942 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2944 if (session->transport_stopped()) {
2945 have_pending_keyboard_selection = false;
2948 update_loop_range_view (true);
2953 Editor::State::State (PublicEditor const * e)
2955 selection = new Selection (e);
2958 Editor::State::~State ()
2964 Editor::get_memento () const
2966 State *state = new State (this);
2968 store_state (*state);
2969 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2973 Editor::store_state (State& state) const
2975 *state.selection = *selection;
2979 Editor::restore_state (State *state)
2981 if (*selection == *state->selection) {
2985 *selection = *state->selection;
2986 time_selection_changed ();
2987 region_selection_changed ();
2989 /* XXX other selection change handlers? */
2993 Editor::begin_reversible_command (string name)
2996 before = &get_state();
2997 session->begin_reversible_command (name);
3002 Editor::commit_reversible_command ()
3005 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
3010 Editor::set_edit_group_solo (Route& route, bool yn)
3012 RouteGroup *edit_group;
3014 if ((edit_group = route.edit_group()) != 0) {
3015 edit_group->apply (&Route::set_solo, yn, this);
3017 route.set_solo (yn, this);
3022 Editor::set_edit_group_mute (Route& route, bool yn)
3024 RouteGroup *edit_group = 0;
3026 if ((edit_group == route.edit_group()) != 0) {
3027 edit_group->apply (&Route::set_mute, yn, this);
3029 route.set_mute (yn, this);
3034 Editor::history_changed ()
3038 if (undo_action && session) {
3039 if (session->undo_depth() == 0) {
3042 label = string_compose(_("Undo (%1)"), session->next_undo());
3044 undo_action->property_label() = label;
3047 if (redo_action && session) {
3048 if (session->redo_depth() == 0) {
3051 label = string_compose(_("Redo (%1)"), session->next_redo());
3053 redo_action->property_label() = label;
3058 Editor::duplicate_dialog (bool dup_region)
3060 if (selection->regions.empty() && (selection->time.length() == 0)) {
3064 ArdourDialog win ("duplicate dialog");
3065 Label label (_("Duplicate how many times?"));
3066 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3067 SpinButton spinner (adjustment);
3069 win.get_vbox()->set_spacing (12);
3070 win.get_vbox()->pack_start (label);
3072 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3073 place, visually. so do this by hand.
3076 win.get_vbox()->pack_start (spinner);
3077 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3082 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3083 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3085 win.set_position (WIN_POS_MOUSE);
3087 spinner.grab_focus ();
3089 switch (win.run ()) {
3090 case RESPONSE_ACCEPT:
3096 float times = adjustment.get_value();
3098 if (!selection->regions.empty()) {
3099 duplicate_some_regions (selection->regions, times);
3101 duplicate_selection (times);
3106 Editor::show_verbose_canvas_cursor ()
3108 verbose_canvas_cursor->raise_to_top();
3109 verbose_canvas_cursor->show();
3110 verbose_cursor_visible = true;
3114 Editor::hide_verbose_canvas_cursor ()
3116 verbose_canvas_cursor->hide();
3117 verbose_cursor_visible = false;
3121 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3123 /* XXX get origin of canvas relative to root window,
3124 add x and y and check compared to gdk_screen_{width,height}
3126 verbose_canvas_cursor->property_text() = txt.c_str();
3127 verbose_canvas_cursor->property_x() = x;
3128 verbose_canvas_cursor->property_y() = y;
3132 Editor::set_verbose_canvas_cursor_text (const string & txt)
3134 verbose_canvas_cursor->property_text() = txt.c_str();
3138 Editor::edit_mode_selection_done ()
3144 string choice = edit_mode_selector.get_active_text();
3145 EditMode mode = Slide;
3147 if (choice == _("Splice Edit")) {
3149 } else if (choice == _("Slide Edit")) {
3153 Config->set_edit_mode (mode);
3157 Editor::snap_type_selection_done ()
3159 string choice = snap_type_selector.get_active_text();
3160 SnapType snaptype = SnapToFrame;
3162 if (choice == _("Beats/3")) {
3163 snaptype = SnapToAThirdBeat;
3164 } else if (choice == _("Beats/4")) {
3165 snaptype = SnapToAQuarterBeat;
3166 } else if (choice == _("Beats/8")) {
3167 snaptype = SnapToAEighthBeat;
3168 } else if (choice == _("Beats/16")) {
3169 snaptype = SnapToASixteenthBeat;
3170 } else if (choice == _("Beats/32")) {
3171 snaptype = SnapToAThirtysecondBeat;
3172 } else if (choice == _("Beats")) {
3173 snaptype = SnapToBeat;
3174 } else if (choice == _("Bars")) {
3175 snaptype = SnapToBar;
3176 } else if (choice == _("Marks")) {
3177 snaptype = SnapToMark;
3178 } else if (choice == _("Edit Cursor")) {
3179 snaptype = SnapToEditCursor;
3180 } else if (choice == _("Region starts")) {
3181 snaptype = SnapToRegionStart;
3182 } else if (choice == _("Region ends")) {
3183 snaptype = SnapToRegionEnd;
3184 } else if (choice == _("Region bounds")) {
3185 snaptype = SnapToRegionBoundary;
3186 } else if (choice == _("Region syncs")) {
3187 snaptype = SnapToRegionSync;
3188 } else if (choice == _("CD Frames")) {
3189 snaptype = SnapToCDFrame;
3190 } else if (choice == _("SMPTE Frames")) {
3191 snaptype = SnapToSMPTEFrame;
3192 } else if (choice == _("SMPTE Seconds")) {
3193 snaptype = SnapToSMPTESeconds;
3194 } else if (choice == _("SMPTE Minutes")) {
3195 snaptype = SnapToSMPTEMinutes;
3196 } else if (choice == _("Seconds")) {
3197 snaptype = SnapToSeconds;
3198 } else if (choice == _("Minutes")) {
3199 snaptype = SnapToMinutes;
3200 } else if (choice == _("None")) {
3201 snaptype = SnapToFrame;
3204 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3206 ract->set_active ();
3211 Editor::snap_mode_selection_done ()
3213 string choice = snap_mode_selector.get_active_text();
3214 SnapMode mode = SnapNormal;
3216 if (choice == _("Normal")) {
3218 } else if (choice == _("Magnetic")) {
3219 mode = SnapMagnetic;
3222 RefPtr<RadioAction> ract = snap_mode_action (mode);
3225 ract->set_active (true);
3230 Editor::zoom_focus_selection_done ()
3232 string choice = zoom_focus_selector.get_active_text();
3233 ZoomFocus focus_type = ZoomFocusLeft;
3235 if (choice == _("Left")) {
3236 focus_type = ZoomFocusLeft;
3237 } else if (choice == _("Right")) {
3238 focus_type = ZoomFocusRight;
3239 } else if (choice == _("Center")) {
3240 focus_type = ZoomFocusCenter;
3241 } else if (choice == _("Play")) {
3242 focus_type = ZoomFocusPlayhead;
3243 } else if (choice == _("Edit")) {
3244 focus_type = ZoomFocusEdit;
3247 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3250 ract->set_active ();
3255 Editor::edit_controls_button_release (GdkEventButton* ev)
3257 if (Keyboard::is_context_menu_event (ev)) {
3258 ARDOUR_UI::instance()->add_route (this);
3264 Editor::mouse_select_button_release (GdkEventButton* ev)
3266 /* this handles just right-clicks */
3268 if (ev->button != 3) {
3275 Editor::TrackViewList *
3276 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3279 TrackViewList::iterator i;
3281 v = new TrackViewList;
3283 if (track == 0 && group == 0) {
3287 for (i = track_views.begin(); i != track_views.end (); ++i) {
3291 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3293 /* just the view for this track
3296 v->push_back (track);
3300 /* views for all tracks in the edit group */
3302 for (i = track_views.begin(); i != track_views.end (); ++i) {
3304 if (group == 0 || (*i)->edit_group() == group) {
3314 Editor::set_zoom_focus (ZoomFocus f)
3316 string str = zoom_focus_strings[(int)f];
3318 if (str != zoom_focus_selector.get_active_text()) {
3319 zoom_focus_selector.set_active_text (str);
3322 if (zoom_focus != f) {
3325 ZoomFocusChanged (); /* EMIT_SIGNAL */
3332 Editor::ensure_float (Window& win)
3334 win.set_transient_for (*this);
3338 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3340 /* recover or initialize pane positions. do this here rather than earlier because
3341 we don't want the positions to change the child allocations, which they seem to do.
3347 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3349 static int32_t done;
3352 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3353 width = default_width;
3354 height = default_height;
3356 width = atoi(geometry->property("x_size")->value());
3357 height = atoi(geometry->property("y_size")->value());
3360 if (which == static_cast<Paned*> (&edit_pane)) {
3366 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3367 /* initial allocation is 90% to canvas, 10% to notebook */
3368 pos = (int) floor (alloc.get_width() * 0.90f);
3369 snprintf (buf, sizeof(buf), "%d", pos);
3371 pos = atoi (prop->value());
3374 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3375 edit_pane.set_position (pos);
3376 pre_maximal_pane_position = pos;
3382 Editor::detach_tearoff (Box* b, Window* w)
3384 if (tools_tearoff->torn_off() &&
3385 mouse_mode_tearoff->torn_off()) {
3386 top_hbox.remove (toolbar_frame);
3391 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3393 if (toolbar_frame.get_parent() == 0) {
3394 top_hbox.pack_end (toolbar_frame);
3399 Editor::set_show_measures (bool yn)
3401 if (_show_measures != yn) {
3404 if ((_show_measures = yn) == true) {
3412 Editor::toggle_follow_playhead ()
3414 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3416 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3417 set_follow_playhead (tact->get_active());
3422 Editor::set_follow_playhead (bool yn)
3424 if (_follow_playhead != yn) {
3425 if ((_follow_playhead = yn) == true) {
3427 update_current_screen ();
3434 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3436 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3438 xfade->set_active (!xfade->active());
3443 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3445 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3447 xfade->set_follow_overlap (!xfade->following_overlap());
3452 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3454 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3460 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3464 switch (cew.run ()) {
3465 case RESPONSE_ACCEPT:
3472 xfade->StateChanged (Change (~0));
3476 Editor::playlist_selector () const
3478 return *_playlist_selector;
3482 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3486 ret = nudge_clock.current_duration (pos);
3487 next = ret + 1; /* XXXX fix me */
3493 Editor::end_location_changed (Location* location)
3495 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3496 reset_scrolling_region ();
3500 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3502 ArdourDialog dialog ("playlist deletion dialog");
3503 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3504 "If left alone, no audio files used by it will be cleaned.\n"
3505 "If deleted, audio files used by it alone by will cleaned."),
3508 dialog.set_position (WIN_POS_CENTER);
3509 dialog.get_vbox()->pack_start (label);
3513 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3514 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3515 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3517 switch (dialog.run ()) {
3518 case RESPONSE_ACCEPT:
3519 /* delete the playlist */
3523 case RESPONSE_REJECT:
3524 /* keep the playlist */
3536 Editor::audio_region_selection_covers (nframes_t where)
3538 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3539 if ((*a)->region()->covers (where)) {
3548 Editor::prepare_for_cleanup ()
3550 cut_buffer->clear_regions ();
3551 cut_buffer->clear_playlists ();
3553 selection->clear_regions ();
3554 selection->clear_playlists ();
3558 Editor::transport_loop_location()
3561 return session->locations()->auto_loop_location();
3568 Editor::transport_punch_location()
3571 return session->locations()->auto_punch_location();
3578 Editor::control_layout_scroll (GdkEventScroll* ev)
3580 switch (ev->direction) {
3582 scroll_tracks_up_line ();
3586 case GDK_SCROLL_DOWN:
3587 scroll_tracks_down_line ();
3591 /* no left/right handling yet */
3599 /** A new snapshot has been selected.
3602 Editor::snapshot_display_selection_changed ()
3604 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3606 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3608 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3610 if (snap_name.length() == 0) {
3614 if (session->snap_name() == snap_name) {
3618 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3623 Editor::snapshot_display_button_press (GdkEventButton* ev)
3625 if (ev->button == 3) {
3626 /* Right-click on the snapshot list. Work out which snapshot it
3628 Gtk::TreeModel::Path path;
3629 Gtk::TreeViewColumn* col;
3632 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3633 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3635 Gtk::TreeModel::Row row = *iter;
3636 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3645 /** Pop up the snapshot display context menu.
3646 * @param button Button used to open the menu.
3647 * @param time Menu open time.
3648 * @snapshot_name Name of the snapshot that the menu click was over.
3652 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3654 using namespace Menu_Helpers;
3656 MenuList& items (snapshot_context_menu.items());
3659 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3661 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3663 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3665 snapshot_context_menu.popup (button, time);
3669 Editor::rename_snapshot (Glib::ustring old_name)
3671 ArdourPrompter prompter(true);
3675 prompter.set_name ("Prompter");
3676 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3677 prompter.set_prompt (_("New name of snapshot"));
3678 prompter.set_initial_text (old_name);
3680 if (prompter.run() == RESPONSE_ACCEPT) {
3681 prompter.get_result (new_name);
3682 if (new_name.length()) {
3683 session->rename_state (old_name, new_name);
3684 redisplay_snapshots ();
3691 Editor::remove_snapshot (Glib::ustring name)
3693 vector<string> choices;
3695 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3697 choices.push_back (_("No, do nothing."));
3698 choices.push_back (_("Yes, remove it."));
3700 Gtkmm2ext::Choice prompter (prompt, choices);
3702 if (prompter.run () == 1) {
3703 session->remove_state (name);
3704 redisplay_snapshots ();
3709 Editor::redisplay_snapshots ()
3715 vector<sys::path> state_file_paths;
3717 get_state_files_in_directory (session->session_directory().root_path(),
3720 if (state_file_paths.empty()) return;
3722 vector<string> state_file_names(get_file_names_no_extension(state_file_paths));
3724 snapshot_display_model->clear ();
3726 for (vector<string>::iterator i = state_file_names.begin();
3727 i != state_file_names.end(); ++i)
3729 string statename = (*i);
3730 TreeModel::Row row = *(snapshot_display_model->append());
3732 /* this lingers on in case we ever want to change the visible
3733 name of the snapshot.
3736 string display_name;
3737 display_name = statename;
3739 if (statename == session->snap_name()) {
3740 snapshot_display.get_selection()->select(row);
3743 row[snapshot_display_columns.visible_name] = display_name;
3744 row[snapshot_display_columns.real_name] = statename;
3749 Editor::session_state_saved (string snap_name)
3751 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3752 redisplay_snapshots ();
3756 Editor::maximise_editing_space ()
3758 initial_ruler_update_required = true;
3760 mouse_mode_tearoff->set_visible (false);
3761 tools_tearoff->set_visible (false);
3763 pre_maximal_pane_position = edit_pane.get_position();
3764 pre_maximal_editor_width = this->get_width();
3766 if(post_maximal_pane_position == 0) {
3767 post_maximal_pane_position = edit_pane.get_width();
3772 if(post_maximal_editor_width) {
3773 edit_pane.set_position (post_maximal_pane_position -
3774 abs(post_maximal_editor_width - pre_maximal_editor_width));
3776 edit_pane.set_position (post_maximal_pane_position);
3781 Editor::restore_editing_space ()
3783 initial_ruler_update_required = true;
3785 // user changed width of pane during fullscreen
3786 if(post_maximal_pane_position != edit_pane.get_position()) {
3787 post_maximal_pane_position = edit_pane.get_position();
3792 mouse_mode_tearoff->set_visible (true);
3793 tools_tearoff->set_visible (true);
3794 post_maximal_editor_width = this->get_width();
3797 edit_pane.set_position (
3798 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3803 * Make new playlists for a given track and also any others that belong
3804 * to the same active edit group.
3809 Editor::new_playlists (TimeAxisView* v)
3811 begin_reversible_command (_("new playlists"));
3812 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3813 commit_reversible_command ();
3817 * Use a copy of the current playlist for a given track and also any others that belong
3818 * to the same active edit group.
3823 Editor::copy_playlists (TimeAxisView* v)
3825 begin_reversible_command (_("copy playlists"));
3826 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3827 commit_reversible_command ();
3831 * Clear the current playlist for a given track and also any others that belong
3832 * to the same active edit group.
3837 Editor::clear_playlists (TimeAxisView* v)
3839 begin_reversible_command (_("clear playlists"));
3840 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3841 commit_reversible_command ();
3845 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3847 atv.use_new_playlist (sz > 1 ? false : true);
3851 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3853 atv.use_copy_playlist (sz > 1 ? false : true);
3857 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3859 atv.clear_playlist ();
3863 Editor::on_key_press_event (GdkEventKey* ev)
3865 return key_press_focus_accelerator_handler (*this, ev);
3869 Editor::reset_x_origin (nframes_t frame)
3871 queue_visual_change (frame);
3875 Editor::reset_zoom (double fpu)
3877 queue_visual_change (fpu);
3881 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3883 reset_x_origin (frame);
3888 Editor::set_frames_per_unit (double fpu)
3892 /* this is the core function that controls the zoom level of the canvas. it is called
3893 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3896 if (fpu == frames_per_unit) {
3904 // convert fpu to frame count
3906 frames = (nframes_t) floor (fpu * canvas_width);
3908 /* don't allow zooms that fit more than the maximum number
3909 of frames into an 800 pixel wide space.
3912 if (max_frames / fpu < 800.0) {
3916 if (fpu == frames_per_unit) {
3920 frames_per_unit = fpu;
3922 if (frames != zoom_range_clock.current_duration()) {
3923 zoom_range_clock.set (frames);
3926 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3927 if (!selection->tracks.empty()) {
3928 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3929 (*i)->reshow_selection (selection->time);
3932 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3933 (*i)->reshow_selection (selection->time);
3938 ZoomChanged (); /* EMIT_SIGNAL */
3940 reset_hscrollbar_stepping ();
3941 reset_scrolling_region ();
3943 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3944 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3950 Editor::queue_visual_change (nframes_t where)
3952 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3953 pending_visual_change.time_origin = where;
3955 if (pending_visual_change.idle_handler_id < 0) {
3956 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3961 Editor::queue_visual_change (double fpu)
3963 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3964 pending_visual_change.frames_per_unit = fpu;
3966 if (pending_visual_change.idle_handler_id < 0) {
3967 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3972 Editor::_idle_visual_changer (void* arg)
3974 return static_cast<Editor*>(arg)->idle_visual_changer ();
3978 Editor::idle_visual_changer ()
3980 VisualChange::Type p = pending_visual_change.pending;
3982 pending_visual_change.pending = (VisualChange::Type) 0;
3983 pending_visual_change.idle_handler_id = -1;
3985 if (p & VisualChange::ZoomLevel) {
3986 set_frames_per_unit (pending_visual_change.frames_per_unit);
3989 if (p & VisualChange::TimeOrigin) {
3990 if (pending_visual_change.time_origin != leftmost_frame) {
3991 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3992 /* the signal handler will do the rest */
3994 update_fixed_rulers();
3995 redisplay_tempo (true);
3999 return 0; /* this is always a one-shot call */
4002 struct EditorOrderTimeAxisSorter {
4003 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4004 return a->order < b->order;
4009 Editor::sort_track_selection ()
4011 EditorOrderTimeAxisSorter cmp;
4012 selection->tracks.sort (cmp);
4016 Editor::edit_cursor_position(bool sync)
4018 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
4019 edit_cursor_clock.set(edit_cursor->current_frame, true);
4022 return edit_cursor->current_frame;
4027 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4029 if (!session) return;
4031 begin_reversible_command (cmd);
4035 if ((tll = transport_loop_location()) == 0) {
4036 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4037 XMLNode &before = session->locations()->get_state();
4038 session->locations()->add (loc, true);
4039 session->set_auto_loop_location (loc);
4040 XMLNode &after = session->locations()->get_state();
4041 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4044 XMLNode &before = tll->get_state();
4045 tll->set_hidden (false, this);
4046 tll->set (start, end);
4047 XMLNode &after = tll->get_state();
4048 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4051 commit_reversible_command ();
4055 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4057 if (!session) return;
4059 begin_reversible_command (cmd);
4063 if ((tpl = transport_punch_location()) == 0) {
4064 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4065 XMLNode &before = session->locations()->get_state();
4066 session->locations()->add (loc, true);
4067 session->set_auto_loop_location (loc);
4068 XMLNode &after = session->locations()->get_state();
4069 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4072 XMLNode &before = tpl->get_state();
4073 tpl->set_hidden (false, this);
4074 tpl->set (start, end);
4075 XMLNode &after = tpl->get_state();
4076 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4079 commit_reversible_command ();