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);
1932 add_item_with_sensitivity (track_items, MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1936 Menu *nudge_menu = manage (new Menu());
1937 MenuList& nudge_items = nudge_menu->items();
1938 nudge_menu->set_name ("ArdourContextMenu");
1940 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1941 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1943 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1945 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1947 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1949 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1951 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1953 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1955 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1958 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1959 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1961 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1962 edit_items.push_back (MenuElem (str, *track_menu));
1966 /* CURSOR SETTING AND MARKS AND STUFF */
1969 Editor::set_snap_to (SnapType st)
1972 string str = snap_type_strings[(int) st];
1974 if (str != snap_type_selector.get_active_text()) {
1975 snap_type_selector.set_active_text (str);
1980 switch (snap_type) {
1981 case SnapToAThirtysecondBeat:
1982 case SnapToASixteenthBeat:
1983 case SnapToAEighthBeat:
1984 case SnapToAQuarterBeat:
1985 case SnapToAThirdBeat:
1986 update_tempo_based_rulers ();
1994 Editor::set_snap_mode (SnapMode mode)
1997 string str = snap_mode_strings[(int)mode];
1999 if (str != snap_mode_selector.get_active_text ()) {
2000 snap_mode_selector.set_active_text (str);
2007 Editor::set_state (const XMLNode& node)
2009 const XMLProperty* prop;
2011 int x, y, xoff, yoff;
2014 if ((prop = node.property ("id")) != 0) {
2015 _id = prop->value ();
2018 if ((geometry = find_named_node (node, "geometry")) == 0) {
2020 g.base_width = default_width;
2021 g.base_height = default_height;
2029 g.base_width = atoi(geometry->property("x_size")->value());
2030 g.base_height = atoi(geometry->property("y_size")->value());
2031 x = atoi(geometry->property("x_pos")->value());
2032 y = atoi(geometry->property("y_pos")->value());
2033 xoff = atoi(geometry->property("x_off")->value());
2034 yoff = atoi(geometry->property("y_off")->value());
2037 set_default_size (g.base_width, g.base_height);
2040 if (session && (prop = node.property ("playhead"))) {
2041 nframes_t pos = atol (prop->value().c_str());
2042 playhead_cursor->set_position (pos);
2044 playhead_cursor->set_position (0);
2046 /* reset_x_origin() doesn't work right here, since the old
2047 position may be zero already, and it does nothing in such
2052 horizontal_adjustment.set_value (0);
2055 if (session && (prop = node.property ("edit-cursor"))) {
2056 nframes_t pos = atol (prop->value().c_str());
2057 edit_cursor->set_position (pos);
2059 edit_cursor->set_position (0);
2062 if ((prop = node.property ("mixer-width"))) {
2063 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2066 if ((prop = node.property ("zoom-focus"))) {
2067 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2070 if ((prop = node.property ("zoom"))) {
2071 reset_zoom (PBD::atof (prop->value()));
2074 if ((prop = node.property ("snap-to"))) {
2075 set_snap_to ((SnapType) atoi (prop->value()));
2078 if ((prop = node.property ("snap-mode"))) {
2079 set_snap_mode ((SnapMode) atoi (prop->value()));
2082 if ((prop = node.property ("mouse-mode"))) {
2083 MouseMode m = str2mousemode(prop->value());
2084 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2085 set_mouse_mode (m, true);
2087 mouse_mode = MouseGain; /* lie, to force the mode switch */
2088 set_mouse_mode (MouseObject, true);
2091 if ((prop = node.property ("show-waveforms"))) {
2092 bool yn = (prop->value() == "yes");
2093 _show_waveforms = !yn;
2094 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2096 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2097 /* do it twice to force the change */
2098 tact->set_active (!yn);
2099 tact->set_active (yn);
2103 if ((prop = node.property ("show-waveforms-recording"))) {
2104 bool yn = (prop->value() == "yes");
2105 _show_waveforms_recording = !yn;
2106 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2108 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2109 /* do it twice to force the change */
2110 tact->set_active (!yn);
2111 tact->set_active (yn);
2115 if ((prop = node.property ("show-measures"))) {
2116 bool yn = (prop->value() == "yes");
2117 _show_measures = !yn;
2118 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2120 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2121 /* do it twice to force the change */
2122 tact->set_active (!yn);
2123 tact->set_active (yn);
2127 if ((prop = node.property ("follow-playhead"))) {
2128 bool yn = (prop->value() == "yes");
2129 set_follow_playhead (yn);
2130 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2132 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2133 if (tact->get_active() != yn) {
2134 tact->set_active (yn);
2139 if ((prop = node.property ("region-list-sort-type"))) {
2140 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2141 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2144 if ((prop = node.property ("xfades-visible"))) {
2145 bool yn = (prop->value() == "yes");
2146 _xfade_visibility = !yn;
2147 // set_xfade_visibility (yn);
2150 if ((prop = node.property ("show-editor-mixer"))) {
2152 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2155 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2156 bool yn = (prop->value() == X_("yes"));
2158 /* do it twice to force the change */
2160 tact->set_active (!yn);
2161 tact->set_active (yn);
2165 if ((prop = node.property ("show-editor-list"))) {
2167 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2171 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2172 bool yn = (prop->value() == X_("yes"));
2174 /* do it twice to force the change */
2176 tact->set_active (!yn);
2177 tact->set_active (yn);
2186 Editor::get_state ()
2188 XMLNode* node = new XMLNode ("Editor");
2191 _id.print (buf, sizeof (buf));
2192 node->add_property ("id", buf);
2194 if (is_realized()) {
2195 Glib::RefPtr<Gdk::Window> win = get_window();
2197 int x, y, xoff, yoff, width, height;
2198 win->get_root_origin(x, y);
2199 win->get_position(xoff, yoff);
2200 win->get_size(width, height);
2202 XMLNode* geometry = new XMLNode ("geometry");
2204 snprintf(buf, sizeof(buf), "%d", width);
2205 geometry->add_property("x_size", string(buf));
2206 snprintf(buf, sizeof(buf), "%d", height);
2207 geometry->add_property("y_size", string(buf));
2208 snprintf(buf, sizeof(buf), "%d", x);
2209 geometry->add_property("x_pos", string(buf));
2210 snprintf(buf, sizeof(buf), "%d", y);
2211 geometry->add_property("y_pos", string(buf));
2212 snprintf(buf, sizeof(buf), "%d", xoff);
2213 geometry->add_property("x_off", string(buf));
2214 snprintf(buf, sizeof(buf), "%d", yoff);
2215 geometry->add_property("y_off", string(buf));
2216 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2217 geometry->add_property("edit_pane_pos", string(buf));
2219 node->add_child_nocopy (*geometry);
2222 maybe_add_mixer_strip_width (*node);
2224 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2225 node->add_property ("zoom-focus", buf);
2226 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2227 node->add_property ("zoom", buf);
2228 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2229 node->add_property ("snap-to", buf);
2230 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2231 node->add_property ("snap-mode", buf);
2233 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2234 node->add_property ("playhead", buf);
2235 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2236 node->add_property ("edit-cursor", buf);
2238 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2239 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2240 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2241 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2242 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2243 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2244 node->add_property ("mouse-mode", enum2str(mouse_mode));
2246 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2248 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2249 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2252 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2254 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2255 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2264 Editor::trackview_by_y_position (double y)
2266 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2270 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2279 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2281 Location* before = 0;
2282 Location* after = 0;
2288 const nframes64_t one_second = session->frame_rate();
2289 const nframes64_t one_minute = session->frame_rate() * 60;
2290 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2291 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2292 nframes64_t presnap = start;
2294 switch (snap_type) {
2300 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2302 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2306 case SnapToSMPTEFrame:
2307 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2308 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2310 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2314 case SnapToSMPTESeconds:
2315 if (session->smpte_offset_negative())
2317 start += session->smpte_offset ();
2319 start -= session->smpte_offset ();
2321 if (start % one_smpte_second > one_smpte_second / 2) {
2322 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2324 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2327 if (session->smpte_offset_negative())
2329 start -= session->smpte_offset ();
2331 start += session->smpte_offset ();
2335 case SnapToSMPTEMinutes:
2336 if (session->smpte_offset_negative())
2338 start += session->smpte_offset ();
2340 start -= session->smpte_offset ();
2342 if (start % one_smpte_minute > one_smpte_minute / 2) {
2343 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2345 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2347 if (session->smpte_offset_negative())
2349 start -= session->smpte_offset ();
2351 start += session->smpte_offset ();
2356 if (start % one_second > one_second / 2) {
2357 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2359 start = (nframes_t) floor ((double) start / one_second) * one_second;
2364 if (start % one_minute > one_minute / 2) {
2365 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2367 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2372 start = session->tempo_map().round_to_bar (start, direction);
2376 start = session->tempo_map().round_to_beat (start, direction);
2379 case SnapToAThirtysecondBeat:
2380 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2383 case SnapToASixteenthBeat:
2384 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2387 case SnapToAEighthBeat:
2388 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2391 case SnapToAQuarterBeat:
2392 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2395 case SnapToAThirdBeat:
2396 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2399 case SnapToEditCursor:
2400 start = edit_cursor->current_frame;
2408 before = session->locations()->first_location_before (start);
2409 after = session->locations()->first_location_after (start);
2411 if (direction < 0) {
2413 start = before->start();
2417 } else if (direction > 0) {
2419 start = after->start();
2421 start = session->current_end_frame();
2426 /* find nearest of the two */
2427 if ((start - before->start()) < (after->start() - start)) {
2428 start = before->start();
2430 start = after->start();
2433 start = before->start();
2436 start = after->start();
2443 case SnapToRegionStart:
2444 case SnapToRegionEnd:
2445 case SnapToRegionSync:
2446 case SnapToRegionBoundary:
2447 if (!region_boundary_cache.empty()) {
2448 vector<nframes_t>::iterator i;
2450 if (direction > 0) {
2451 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2453 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2456 if (i != region_boundary_cache.end()) {
2459 start = region_boundary_cache.back();
2465 switch (snap_mode) {
2471 if (presnap > start) {
2472 if (presnap > (start + unit_to_frame(snap_threshold))) {
2476 } else if (presnap < start) {
2477 if (presnap < (start - unit_to_frame(snap_threshold))) {
2489 Editor::snap_length_beats (nframes_t start)
2495 /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
2497 switch (snap_type) {
2499 return session->tempo_map().meter_at(start).beats_per_bar();
2504 case SnapToAThirtysecondBeat:
2505 return 1.0 / (double)32.0;
2508 case SnapToASixteenthBeat:
2509 return 1.0 / (double)16.0;
2512 case SnapToAEighthBeat:
2513 return 1.0 / (double)8.0;
2516 case SnapToAQuarterBeat:
2517 return 1.0 / (double)4.0;
2520 case SnapToAThirdBeat:
2521 return 1.0 / (double)3.0;
2529 Editor::setup_toolbar ()
2533 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2536 /* Mode Buttons (tool selection) */
2538 vector<ToggleButton *> mouse_mode_buttons;
2540 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2541 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2542 mouse_mode_buttons.push_back (&mouse_move_button);
2543 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2544 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2545 mouse_mode_buttons.push_back (&mouse_select_button);
2546 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2547 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2548 mouse_mode_buttons.push_back (&mouse_gain_button);
2549 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2550 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2551 mouse_mode_buttons.push_back (&mouse_zoom_button);
2552 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2553 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2554 mouse_mode_buttons.push_back (&mouse_timefx_button);
2555 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2556 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2557 mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2558 mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2559 mouse_mode_buttons.push_back (&mouse_note_button);
2560 mouse_mode_buttons.push_back (&mouse_audition_button);
2562 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2564 HBox* mode_box = manage(new HBox);
2565 mode_box->set_border_width (2);
2566 mode_box->set_spacing(4);
2567 mouse_mode_button_box.set_spacing(1);
2568 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2569 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2570 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2571 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2572 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2573 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2574 mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2575 mouse_mode_button_box.set_homogeneous(true);
2577 vector<string> edit_mode_strings;
2578 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2579 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2581 edit_mode_selector.set_name ("EditModeSelector");
2582 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2583 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2584 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2586 mode_box->pack_start(edit_mode_selector);
2587 mode_box->pack_start(mouse_mode_button_box);
2589 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2590 mouse_mode_tearoff->set_name ("MouseModeBase");
2592 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2593 &mouse_mode_tearoff->tearoff_window()));
2594 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2595 &mouse_mode_tearoff->tearoff_window(), 1));
2596 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2597 &mouse_mode_tearoff->tearoff_window()));
2598 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2599 &mouse_mode_tearoff->tearoff_window(), 1));
2601 mouse_move_button.set_name ("MouseModeButton");
2602 mouse_select_button.set_name ("MouseModeButton");
2603 mouse_gain_button.set_name ("MouseModeButton");
2604 mouse_zoom_button.set_name ("MouseModeButton");
2605 mouse_timefx_button.set_name ("MouseModeButton");
2606 mouse_audition_button.set_name ("MouseModeButton");
2607 mouse_note_button.set_name ("MouseModeButton");
2609 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2610 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2611 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2612 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2613 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2614 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2615 ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2617 mouse_move_button.unset_flags (CAN_FOCUS);
2618 mouse_select_button.unset_flags (CAN_FOCUS);
2619 mouse_gain_button.unset_flags (CAN_FOCUS);
2620 mouse_zoom_button.unset_flags (CAN_FOCUS);
2621 mouse_timefx_button.unset_flags (CAN_FOCUS);
2622 mouse_audition_button.unset_flags (CAN_FOCUS);
2623 mouse_note_button.unset_flags (CAN_FOCUS);
2625 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2626 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2628 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2629 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2630 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2631 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2632 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2633 mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2635 // mouse_move_button.set_active (true);
2640 zoom_box.set_spacing (1);
2641 zoom_box.set_border_width (2);
2643 zoom_in_button.set_name ("EditorTimeButton");
2644 zoom_in_button.set_size_request(-1,16);
2645 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2646 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2647 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2649 zoom_out_button.set_name ("EditorTimeButton");
2650 zoom_out_button.set_size_request(-1,16);
2651 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2652 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2653 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2655 zoom_out_full_button.set_name ("EditorTimeButton");
2656 zoom_out_full_button.set_size_request(-1,16);
2657 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2658 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2659 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2661 zoom_focus_selector.set_name ("ZoomFocusSelector");
2662 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Center", FUDGE, 0);
2663 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2664 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2665 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2667 zoom_box.pack_start (zoom_focus_selector, true, true);
2668 zoom_box.pack_start (zoom_out_button, false, false);
2669 zoom_box.pack_start (zoom_in_button, false, false);
2670 zoom_box.pack_start (zoom_out_full_button, false, false);
2672 /* Edit Cursor / Snap */
2674 snap_box.set_spacing (1);
2675 snap_box.set_border_width (2);
2677 snap_type_selector.set_name ("SnapTypeSelector");
2678 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2679 set_popdown_strings (snap_type_selector, snap_type_strings);
2680 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2681 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2683 snap_mode_selector.set_name ("SnapModeSelector");
2684 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2685 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2686 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2688 snap_box.pack_start (edit_cursor_clock, false, false);
2689 snap_box.pack_start (snap_mode_selector, false, false);
2690 snap_box.pack_start (snap_type_selector, false, false);
2695 HBox *nudge_box = manage (new HBox);
2696 nudge_box->set_spacing(1);
2697 nudge_box->set_border_width (2);
2699 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2700 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2702 nudge_box->pack_start (nudge_backward_button, false, false);
2703 nudge_box->pack_start (nudge_forward_button, false, false);
2704 nudge_box->pack_start (nudge_clock, false, false);
2707 /* Pack everything in... */
2709 HBox* hbox = new HBox;
2710 hbox->set_spacing(10);
2712 tools_tearoff = new TearOff (*hbox);
2713 tools_tearoff->set_name ("MouseModeBase");
2715 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2716 &tools_tearoff->tearoff_window()));
2717 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2718 &tools_tearoff->tearoff_window(), 0));
2719 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2720 &tools_tearoff->tearoff_window()));
2721 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2722 &tools_tearoff->tearoff_window(), 0));
2724 toolbar_hbox.set_spacing (10);
2725 toolbar_hbox.set_border_width (1);
2727 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2728 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2731 hbox->pack_start (snap_box, false, false);
2732 // hbox->pack_start (zoom_box, false, false);
2733 hbox->pack_start (*nudge_box, false, false);
2737 toolbar_base.set_name ("ToolBarBase");
2738 toolbar_base.add (toolbar_hbox);
2740 toolbar_frame.set_shadow_type (SHADOW_OUT);
2741 toolbar_frame.set_name ("BaseFrame");
2742 toolbar_frame.add (toolbar_base);
2747 Editor::setup_midi_toolbar ()
2751 /* Mode Buttons (tool selection) */
2753 vector<ToggleButton *> midi_tool_buttons;
2755 midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
2756 midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
2757 midi_tool_buttons.push_back (&midi_tool_pencil_button);
2758 midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
2759 midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
2760 midi_tool_buttons.push_back (&midi_tool_select_button);
2761 midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
2762 midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
2763 midi_tool_buttons.push_back (&midi_tool_erase_button);
2765 midi_tool_pencil_button.set_active(true);
2767 midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
2769 midi_tool_button_box.set_border_width (2);
2770 midi_tool_button_box.set_spacing(4);
2771 midi_tool_button_box.set_spacing(1);
2772 midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
2773 midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
2774 midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
2775 midi_tool_button_box.set_homogeneous(true);
2777 midi_tool_pencil_button.set_name ("MouseModeButton");
2778 midi_tool_select_button.set_name ("MouseModeButton");
2779 midi_tool_erase_button.set_name ("MouseModeButton");
2781 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
2782 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
2783 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
2785 midi_tool_pencil_button.unset_flags (CAN_FOCUS);
2786 midi_tool_select_button.unset_flags (CAN_FOCUS);
2787 midi_tool_erase_button.unset_flags (CAN_FOCUS);
2789 midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
2790 &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
2791 midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
2792 &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
2793 midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
2794 &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
2796 /* Pack everything in... */
2798 midi_tools_tearoff = new TearOff (midi_tool_button_box);
2799 midi_tools_tearoff->set_name ("MouseModeBase");
2802 midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2803 &midi_tools_tearoff->tearoff_window()));
2804 midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2805 &midi_tools_tearoff->tearoff_window(), 0));
2806 midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2807 &midi_tools_tearoff->tearoff_window()));
2808 midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2809 &midi_tools_tearoff->tearoff_window(), 0));
2812 midi_toolbar_hbox.set_spacing (10);
2813 midi_toolbar_hbox.set_border_width (1);
2815 midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
2817 midi_tool_button_box.show_all ();
2818 midi_toolbar_hbox.show_all();
2819 midi_tools_tearoff->show_all();
2821 midi_toolbar_base.set_name ("ToolBarBase");
2822 midi_toolbar_base.add (midi_toolbar_hbox);
2824 midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
2825 midi_toolbar_frame.set_name ("BaseFrame");
2826 midi_toolbar_frame.add (midi_toolbar_base);
2830 Editor::convert_drop_to_paths (vector<ustring>& paths,
2831 const RefPtr<Gdk::DragContext>& context,
2834 const SelectionData& data,
2843 vector<ustring> uris = data.get_uris();
2845 cerr << "there were " << uris.size() << " in that drag data\n";
2849 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2850 are actually URI lists. So do it by hand.
2853 if (data.get_target() != "text/plain") {
2857 /* Parse the "uri-list" format that Nautilus provides,
2858 where each pathname is delimited by \r\n
2861 const char* p = data.get_text().c_str();
2868 while (g_ascii_isspace (*p))
2872 while (*q && (*q != '\n') && (*q != '\r'))
2878 while (q > p && g_ascii_isspace (*q))
2883 uris.push_back (ustring (p, q - p + 1));
2887 p = strchr (p, '\n');
2897 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2899 if ((*i).substr (0,7) == "file://") {
2902 PBD::url_decode (p);
2904 // scan forward past three slashes
2906 ustring::size_type slashcnt = 0;
2907 ustring::size_type n = 0;
2908 ustring::iterator x = p.begin();
2910 while (slashcnt < 3 && x != p.end()) {
2913 } else if (slashcnt == 3) {
2920 if (slashcnt != 3 || x == p.end()) {
2921 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2925 paths.push_back (p.substr (n - 1));
2933 Editor::new_tempo_section ()
2939 Editor::map_transport_state ()
2941 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2943 if (session->transport_stopped()) {
2944 have_pending_keyboard_selection = false;
2947 update_loop_range_view (true);
2952 Editor::State::State (PublicEditor const * e)
2954 selection = new Selection (e);
2957 Editor::State::~State ()
2963 Editor::get_memento () const
2965 State *state = new State (this);
2967 store_state (*state);
2968 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2972 Editor::store_state (State& state) const
2974 *state.selection = *selection;
2978 Editor::restore_state (State *state)
2980 if (*selection == *state->selection) {
2984 *selection = *state->selection;
2985 time_selection_changed ();
2986 region_selection_changed ();
2988 /* XXX other selection change handlers? */
2992 Editor::begin_reversible_command (string name)
2995 before = &get_state();
2996 session->begin_reversible_command (name);
3001 Editor::commit_reversible_command ()
3004 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
3009 Editor::set_edit_group_solo (Route& route, bool yn)
3011 RouteGroup *edit_group;
3013 if ((edit_group = route.edit_group()) != 0) {
3014 edit_group->apply (&Route::set_solo, yn, this);
3016 route.set_solo (yn, this);
3021 Editor::set_edit_group_mute (Route& route, bool yn)
3023 RouteGroup *edit_group = 0;
3025 if ((edit_group == route.edit_group()) != 0) {
3026 edit_group->apply (&Route::set_mute, yn, this);
3028 route.set_mute (yn, this);
3033 Editor::history_changed ()
3037 if (undo_action && session) {
3038 if (session->undo_depth() == 0) {
3041 label = string_compose(_("Undo (%1)"), session->next_undo());
3043 undo_action->property_label() = label;
3046 if (redo_action && session) {
3047 if (session->redo_depth() == 0) {
3050 label = string_compose(_("Redo (%1)"), session->next_redo());
3052 redo_action->property_label() = label;
3057 Editor::duplicate_dialog (bool dup_region)
3059 if (selection->regions.empty() && (selection->time.length() == 0)) {
3063 ArdourDialog win ("duplicate dialog");
3064 Label label (_("Duplicate how many times?"));
3065 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3066 SpinButton spinner (adjustment);
3068 win.get_vbox()->set_spacing (12);
3069 win.get_vbox()->pack_start (label);
3071 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3072 place, visually. so do this by hand.
3075 win.get_vbox()->pack_start (spinner);
3076 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3081 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3082 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3084 win.set_position (WIN_POS_MOUSE);
3086 spinner.grab_focus ();
3088 switch (win.run ()) {
3089 case RESPONSE_ACCEPT:
3095 float times = adjustment.get_value();
3097 if (!selection->regions.empty()) {
3098 duplicate_some_regions (selection->regions, times);
3100 duplicate_selection (times);
3105 Editor::show_verbose_canvas_cursor ()
3107 verbose_canvas_cursor->raise_to_top();
3108 verbose_canvas_cursor->show();
3109 verbose_cursor_visible = true;
3113 Editor::hide_verbose_canvas_cursor ()
3115 verbose_canvas_cursor->hide();
3116 verbose_cursor_visible = false;
3120 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3122 /* XXX get origin of canvas relative to root window,
3123 add x and y and check compared to gdk_screen_{width,height}
3125 verbose_canvas_cursor->property_text() = txt.c_str();
3126 verbose_canvas_cursor->property_x() = x;
3127 verbose_canvas_cursor->property_y() = y;
3131 Editor::set_verbose_canvas_cursor_text (const string & txt)
3133 verbose_canvas_cursor->property_text() = txt.c_str();
3137 Editor::edit_mode_selection_done ()
3143 string choice = edit_mode_selector.get_active_text();
3144 EditMode mode = Slide;
3146 if (choice == _("Splice Edit")) {
3148 } else if (choice == _("Slide Edit")) {
3152 Config->set_edit_mode (mode);
3156 Editor::snap_type_selection_done ()
3158 string choice = snap_type_selector.get_active_text();
3159 SnapType snaptype = SnapToFrame;
3161 if (choice == _("Beats/3")) {
3162 snaptype = SnapToAThirdBeat;
3163 } else if (choice == _("Beats/4")) {
3164 snaptype = SnapToAQuarterBeat;
3165 } else if (choice == _("Beats/8")) {
3166 snaptype = SnapToAEighthBeat;
3167 } else if (choice == _("Beats/16")) {
3168 snaptype = SnapToASixteenthBeat;
3169 } else if (choice == _("Beats/32")) {
3170 snaptype = SnapToAThirtysecondBeat;
3171 } else if (choice == _("Beats")) {
3172 snaptype = SnapToBeat;
3173 } else if (choice == _("Bars")) {
3174 snaptype = SnapToBar;
3175 } else if (choice == _("Marks")) {
3176 snaptype = SnapToMark;
3177 } else if (choice == _("Edit Cursor")) {
3178 snaptype = SnapToEditCursor;
3179 } else if (choice == _("Region starts")) {
3180 snaptype = SnapToRegionStart;
3181 } else if (choice == _("Region ends")) {
3182 snaptype = SnapToRegionEnd;
3183 } else if (choice == _("Region bounds")) {
3184 snaptype = SnapToRegionBoundary;
3185 } else if (choice == _("Region syncs")) {
3186 snaptype = SnapToRegionSync;
3187 } else if (choice == _("CD Frames")) {
3188 snaptype = SnapToCDFrame;
3189 } else if (choice == _("SMPTE Frames")) {
3190 snaptype = SnapToSMPTEFrame;
3191 } else if (choice == _("SMPTE Seconds")) {
3192 snaptype = SnapToSMPTESeconds;
3193 } else if (choice == _("SMPTE Minutes")) {
3194 snaptype = SnapToSMPTEMinutes;
3195 } else if (choice == _("Seconds")) {
3196 snaptype = SnapToSeconds;
3197 } else if (choice == _("Minutes")) {
3198 snaptype = SnapToMinutes;
3199 } else if (choice == _("None")) {
3200 snaptype = SnapToFrame;
3203 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3205 ract->set_active ();
3210 Editor::snap_mode_selection_done ()
3212 string choice = snap_mode_selector.get_active_text();
3213 SnapMode mode = SnapNormal;
3215 if (choice == _("Normal")) {
3217 } else if (choice == _("Magnetic")) {
3218 mode = SnapMagnetic;
3221 RefPtr<RadioAction> ract = snap_mode_action (mode);
3224 ract->set_active (true);
3229 Editor::zoom_focus_selection_done ()
3231 string choice = zoom_focus_selector.get_active_text();
3232 ZoomFocus focus_type = ZoomFocusLeft;
3234 if (choice == _("Left")) {
3235 focus_type = ZoomFocusLeft;
3236 } else if (choice == _("Right")) {
3237 focus_type = ZoomFocusRight;
3238 } else if (choice == _("Center")) {
3239 focus_type = ZoomFocusCenter;
3240 } else if (choice == _("Play")) {
3241 focus_type = ZoomFocusPlayhead;
3242 } else if (choice == _("Edit")) {
3243 focus_type = ZoomFocusEdit;
3246 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3249 ract->set_active ();
3254 Editor::edit_controls_button_release (GdkEventButton* ev)
3256 if (Keyboard::is_context_menu_event (ev)) {
3257 ARDOUR_UI::instance()->add_route (this);
3263 Editor::mouse_select_button_release (GdkEventButton* ev)
3265 /* this handles just right-clicks */
3267 if (ev->button != 3) {
3274 Editor::TrackViewList *
3275 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3278 TrackViewList::iterator i;
3280 v = new TrackViewList;
3282 if (track == 0 && group == 0) {
3286 for (i = track_views.begin(); i != track_views.end (); ++i) {
3290 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3292 /* just the view for this track
3295 v->push_back (track);
3299 /* views for all tracks in the edit group */
3301 for (i = track_views.begin(); i != track_views.end (); ++i) {
3303 if (group == 0 || (*i)->edit_group() == group) {
3313 Editor::set_zoom_focus (ZoomFocus f)
3315 string str = zoom_focus_strings[(int)f];
3317 if (str != zoom_focus_selector.get_active_text()) {
3318 zoom_focus_selector.set_active_text (str);
3321 if (zoom_focus != f) {
3324 ZoomFocusChanged (); /* EMIT_SIGNAL */
3331 Editor::ensure_float (Window& win)
3333 win.set_transient_for (*this);
3337 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3339 /* recover or initialize pane positions. do this here rather than earlier because
3340 we don't want the positions to change the child allocations, which they seem to do.
3346 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3348 static int32_t done;
3351 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3352 width = default_width;
3353 height = default_height;
3355 width = atoi(geometry->property("x_size")->value());
3356 height = atoi(geometry->property("y_size")->value());
3359 if (which == static_cast<Paned*> (&edit_pane)) {
3365 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3366 /* initial allocation is 90% to canvas, 10% to notebook */
3367 pos = (int) floor (alloc.get_width() * 0.90f);
3368 snprintf (buf, sizeof(buf), "%d", pos);
3370 pos = atoi (prop->value());
3373 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3374 edit_pane.set_position (pos);
3375 pre_maximal_pane_position = pos;
3381 Editor::detach_tearoff (Box* b, Window* w)
3383 if (tools_tearoff->torn_off() &&
3384 mouse_mode_tearoff->torn_off()) {
3385 top_hbox.remove (toolbar_frame);
3390 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3392 if (toolbar_frame.get_parent() == 0) {
3393 top_hbox.pack_end (toolbar_frame);
3398 Editor::set_show_measures (bool yn)
3400 if (_show_measures != yn) {
3403 if ((_show_measures = yn) == true) {
3411 Editor::toggle_follow_playhead ()
3413 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3415 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3416 set_follow_playhead (tact->get_active());
3421 Editor::set_follow_playhead (bool yn)
3423 if (_follow_playhead != yn) {
3424 if ((_follow_playhead = yn) == true) {
3426 update_current_screen ();
3433 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3435 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3437 xfade->set_active (!xfade->active());
3442 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3444 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3446 xfade->set_follow_overlap (!xfade->following_overlap());
3451 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3453 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3459 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3463 switch (cew.run ()) {
3464 case RESPONSE_ACCEPT:
3471 xfade->StateChanged (Change (~0));
3475 Editor::playlist_selector () const
3477 return *_playlist_selector;
3481 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3485 ret = nudge_clock.current_duration (pos);
3486 next = ret + 1; /* XXXX fix me */
3492 Editor::end_location_changed (Location* location)
3494 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3495 reset_scrolling_region ();
3499 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3501 ArdourDialog dialog ("playlist deletion dialog");
3502 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3503 "If left alone, no audio files used by it will be cleaned.\n"
3504 "If deleted, audio files used by it alone by will cleaned."),
3507 dialog.set_position (WIN_POS_CENTER);
3508 dialog.get_vbox()->pack_start (label);
3512 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3513 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3514 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3516 switch (dialog.run ()) {
3517 case RESPONSE_ACCEPT:
3518 /* delete the playlist */
3522 case RESPONSE_REJECT:
3523 /* keep the playlist */
3535 Editor::audio_region_selection_covers (nframes_t where)
3537 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3538 if ((*a)->region()->covers (where)) {
3547 Editor::prepare_for_cleanup ()
3549 cut_buffer->clear_regions ();
3550 cut_buffer->clear_playlists ();
3552 selection->clear_regions ();
3553 selection->clear_playlists ();
3557 Editor::transport_loop_location()
3560 return session->locations()->auto_loop_location();
3567 Editor::transport_punch_location()
3570 return session->locations()->auto_punch_location();
3577 Editor::control_layout_scroll (GdkEventScroll* ev)
3579 switch (ev->direction) {
3581 scroll_tracks_up_line ();
3585 case GDK_SCROLL_DOWN:
3586 scroll_tracks_down_line ();
3590 /* no left/right handling yet */
3598 /** A new snapshot has been selected.
3601 Editor::snapshot_display_selection_changed ()
3603 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3605 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3607 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3609 if (snap_name.length() == 0) {
3613 if (session->snap_name() == snap_name) {
3617 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3622 Editor::snapshot_display_button_press (GdkEventButton* ev)
3624 if (ev->button == 3) {
3625 /* Right-click on the snapshot list. Work out which snapshot it
3627 Gtk::TreeModel::Path path;
3628 Gtk::TreeViewColumn* col;
3631 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3632 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3634 Gtk::TreeModel::Row row = *iter;
3635 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3644 /** Pop up the snapshot display context menu.
3645 * @param button Button used to open the menu.
3646 * @param time Menu open time.
3647 * @snapshot_name Name of the snapshot that the menu click was over.
3651 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3653 using namespace Menu_Helpers;
3655 MenuList& items (snapshot_context_menu.items());
3658 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3660 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3662 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3664 snapshot_context_menu.popup (button, time);
3668 Editor::rename_snapshot (Glib::ustring old_name)
3670 ArdourPrompter prompter(true);
3674 prompter.set_name ("Prompter");
3675 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3676 prompter.set_prompt (_("New name of snapshot"));
3677 prompter.set_initial_text (old_name);
3679 if (prompter.run() == RESPONSE_ACCEPT) {
3680 prompter.get_result (new_name);
3681 if (new_name.length()) {
3682 session->rename_state (old_name, new_name);
3683 redisplay_snapshots ();
3690 Editor::remove_snapshot (Glib::ustring name)
3692 vector<string> choices;
3694 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3696 choices.push_back (_("No, do nothing."));
3697 choices.push_back (_("Yes, remove it."));
3699 Gtkmm2ext::Choice prompter (prompt, choices);
3701 if (prompter.run () == 1) {
3702 session->remove_state (name);
3703 redisplay_snapshots ();
3708 Editor::redisplay_snapshots ()
3714 vector<sys::path> state_file_paths;
3716 get_state_files_in_directory (session->session_directory().root_path(),
3719 if (state_file_paths.empty()) return;
3721 vector<string> state_file_names(get_file_names_no_extension(state_file_paths));
3723 snapshot_display_model->clear ();
3725 for (vector<string>::iterator i = state_file_names.begin();
3726 i != state_file_names.end(); ++i)
3728 string statename = (*i);
3729 TreeModel::Row row = *(snapshot_display_model->append());
3731 /* this lingers on in case we ever want to change the visible
3732 name of the snapshot.
3735 string display_name;
3736 display_name = statename;
3738 if (statename == session->snap_name()) {
3739 snapshot_display.get_selection()->select(row);
3742 row[snapshot_display_columns.visible_name] = display_name;
3743 row[snapshot_display_columns.real_name] = statename;
3748 Editor::session_state_saved (string snap_name)
3750 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3751 redisplay_snapshots ();
3755 Editor::maximise_editing_space ()
3757 initial_ruler_update_required = true;
3759 mouse_mode_tearoff->set_visible (false);
3760 tools_tearoff->set_visible (false);
3762 pre_maximal_pane_position = edit_pane.get_position();
3763 pre_maximal_editor_width = this->get_width();
3765 if(post_maximal_pane_position == 0) {
3766 post_maximal_pane_position = edit_pane.get_width();
3771 if(post_maximal_editor_width) {
3772 edit_pane.set_position (post_maximal_pane_position -
3773 abs(post_maximal_editor_width - pre_maximal_editor_width));
3775 edit_pane.set_position (post_maximal_pane_position);
3780 Editor::restore_editing_space ()
3782 initial_ruler_update_required = true;
3784 // user changed width of pane during fullscreen
3785 if(post_maximal_pane_position != edit_pane.get_position()) {
3786 post_maximal_pane_position = edit_pane.get_position();
3791 mouse_mode_tearoff->set_visible (true);
3792 tools_tearoff->set_visible (true);
3793 post_maximal_editor_width = this->get_width();
3796 edit_pane.set_position (
3797 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3802 * Make new playlists for a given track and also any others that belong
3803 * to the same active edit group.
3808 Editor::new_playlists (TimeAxisView* v)
3810 begin_reversible_command (_("new playlists"));
3811 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3812 commit_reversible_command ();
3816 * Use a copy of the current playlist for a given track and also any others that belong
3817 * to the same active edit group.
3822 Editor::copy_playlists (TimeAxisView* v)
3824 begin_reversible_command (_("copy playlists"));
3825 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3826 commit_reversible_command ();
3830 * Clear the current playlist for a given track and also any others that belong
3831 * to the same active edit group.
3836 Editor::clear_playlists (TimeAxisView* v)
3838 begin_reversible_command (_("clear playlists"));
3839 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3840 commit_reversible_command ();
3844 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3846 atv.use_new_playlist (sz > 1 ? false : true);
3850 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3852 atv.use_copy_playlist (sz > 1 ? false : true);
3856 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3858 atv.clear_playlist ();
3862 Editor::on_key_press_event (GdkEventKey* ev)
3864 return key_press_focus_accelerator_handler (*this, ev);
3868 Editor::reset_x_origin (nframes_t frame)
3870 queue_visual_change (frame);
3874 Editor::reset_zoom (double fpu)
3876 queue_visual_change (fpu);
3880 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3882 reset_x_origin (frame);
3887 Editor::set_frames_per_unit (double fpu)
3891 /* this is the core function that controls the zoom level of the canvas. it is called
3892 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3895 if (fpu == frames_per_unit) {
3903 // convert fpu to frame count
3905 frames = (nframes_t) floor (fpu * canvas_width);
3907 /* don't allow zooms that fit more than the maximum number
3908 of frames into an 800 pixel wide space.
3911 if (max_frames / fpu < 800.0) {
3915 if (fpu == frames_per_unit) {
3919 frames_per_unit = fpu;
3921 if (frames != zoom_range_clock.current_duration()) {
3922 zoom_range_clock.set (frames);
3925 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3926 if (!selection->tracks.empty()) {
3927 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3928 (*i)->reshow_selection (selection->time);
3931 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3932 (*i)->reshow_selection (selection->time);
3937 ZoomChanged (); /* EMIT_SIGNAL */
3939 reset_hscrollbar_stepping ();
3940 reset_scrolling_region ();
3942 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3943 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3949 Editor::queue_visual_change (nframes_t where)
3951 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3952 pending_visual_change.time_origin = where;
3954 if (pending_visual_change.idle_handler_id < 0) {
3955 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3960 Editor::queue_visual_change (double fpu)
3962 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3963 pending_visual_change.frames_per_unit = fpu;
3965 if (pending_visual_change.idle_handler_id < 0) {
3966 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3971 Editor::_idle_visual_changer (void* arg)
3973 return static_cast<Editor*>(arg)->idle_visual_changer ();
3977 Editor::idle_visual_changer ()
3979 VisualChange::Type p = pending_visual_change.pending;
3981 pending_visual_change.pending = (VisualChange::Type) 0;
3982 pending_visual_change.idle_handler_id = -1;
3984 if (p & VisualChange::ZoomLevel) {
3985 set_frames_per_unit (pending_visual_change.frames_per_unit);
3988 if (p & VisualChange::TimeOrigin) {
3989 if (pending_visual_change.time_origin != leftmost_frame) {
3990 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3991 /* the signal handler will do the rest */
3993 update_fixed_rulers();
3994 redisplay_tempo (true);
3998 return 0; /* this is always a one-shot call */
4001 struct EditorOrderTimeAxisSorter {
4002 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4003 return a->order < b->order;
4008 Editor::sort_track_selection ()
4010 EditorOrderTimeAxisSorter cmp;
4011 selection->tracks.sort (cmp);
4015 Editor::edit_cursor_position(bool sync)
4017 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
4018 edit_cursor_clock.set(edit_cursor->current_frame, true);
4021 return edit_cursor->current_frame;
4026 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4028 if (!session) return;
4030 begin_reversible_command (cmd);
4034 if ((tll = transport_loop_location()) == 0) {
4035 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4036 XMLNode &before = session->locations()->get_state();
4037 session->locations()->add (loc, true);
4038 session->set_auto_loop_location (loc);
4039 XMLNode &after = session->locations()->get_state();
4040 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4043 XMLNode &before = tll->get_state();
4044 tll->set_hidden (false, this);
4045 tll->set (start, end);
4046 XMLNode &after = tll->get_state();
4047 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4050 commit_reversible_command ();
4054 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4056 if (!session) return;
4058 begin_reversible_command (cmd);
4062 if ((tpl = transport_punch_location()) == 0) {
4063 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4064 XMLNode &before = session->locations()->get_state();
4065 session->locations()->add (loc, true);
4066 session->set_auto_loop_location (loc);
4067 XMLNode &after = session->locations()->get_state();
4068 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4071 XMLNode &before = tpl->get_state();
4072 tpl->set_hidden (false, this);
4073 tpl->set (start, end);
4074 XMLNode &after = tpl->get_state();
4075 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4078 commit_reversible_command ();