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_select_cursor = 0;
162 Gdk::Cursor* Editor::midi_pencil_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 (MidiEditSelect, 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_select_cursor = new Gdk::Cursor (CENTER_PTR);
1314 midi_pencil_cursor = new Gdk::Cursor (PENCIL);
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);
1669 MenuList& envelopes_items = envelopes_menu->items();
1670 envelopes_menu->set_name ("ArdourContextMenu");
1672 #if FIXUP_REGION_MENU
1674 XXX NEED TO RESOLVE ONE v. MANY REGION ISSUE
1676 RegionView* rv = sv->find_view (ar);
1677 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1679 if (!Profile->get_sae()) {
1680 envelopes_items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1682 envelopes_items.push_back (CheckMenuElem (_("Envelope Visible")));
1683 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1684 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1685 if (arv->envelope_visible()) {
1687 region_envelope_visible_item->set_active (true);
1691 envelopes_items.push_back (CheckMenuElem (_("Envelope Active")));
1692 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1693 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1695 if (ar->envelope_active()) {
1697 region_envelope_active_item->set_active (true);
1701 items.push_back (SeparatorElem());
1705 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1707 #if FIXUP_REGION_MENU
1708 if (ar->scale_amplitude() != 1.0f) {
1709 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_regions)));
1711 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_regions)));
1716 /* Find out if we have a selected MIDI region */
1717 i = selection->regions.begin();
1718 while (i != selection->regions.end() && boost::dynamic_pointer_cast<MidiRegion>((*i)->region()) == 0) {
1721 const bool have_selected_midi_region = (i != selection->regions.end());
1723 if (have_selected_midi_region) {
1725 items.push_back (MenuElem (_("Quantize"), mem_fun(*this, &Editor::quantize_regions)));
1726 items.push_back (SeparatorElem());
1730 /* range related stuff */
1732 add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1734 add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1736 items.push_back (SeparatorElem());
1740 Menu *nudge_menu = manage (new Menu());
1741 MenuList& nudge_items = nudge_menu->items();
1742 nudge_menu->set_name ("ArdourContextMenu");
1744 nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1745 nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1746 nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1747 nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1749 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1751 Menu *trim_menu = manage (new Menu);
1752 MenuList& trim_items = trim_menu->items();
1753 trim_menu->set_name ("ArdourContextMenu");
1755 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1756 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1758 items.push_back (MenuElem (_("Trim"), *trim_menu));
1759 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1760 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1761 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1762 items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1763 items.push_back (SeparatorElem());
1764 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1766 /* OK, stick the region submenu at the top of the list, and then add
1770 string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1771 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1774 /** Add context menu items relevant to selection ranges.
1775 * @param edit_items List to add the items to.
1778 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1780 using namespace Menu_Helpers;
1781 Menu *selection_menu = manage (new Menu);
1782 MenuList& items = selection_menu->items();
1783 selection_menu->set_name ("ArdourContextMenu");
1785 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1786 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1789 items.push_back (SeparatorElem());
1790 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1793 items.push_back (SeparatorElem());
1794 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1795 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1797 items.push_back (SeparatorElem());
1798 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1799 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1801 items.push_back (SeparatorElem());
1802 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1804 items.push_back (SeparatorElem());
1805 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1806 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1808 items.push_back (SeparatorElem());
1809 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1810 items.push_back (SeparatorElem());
1811 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1812 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1813 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1814 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1815 items.push_back (SeparatorElem());
1816 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1817 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1820 /** Add context menu items relevant to busses or audio tracks.
1821 * @param edit_items List to add the items to.
1824 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1826 using namespace Menu_Helpers;
1828 /* We add every possible action here, and de-sensitize things
1829 that aren't allowed. The sensitivity logic is a bit spread out;
1830 on the one hand I'm using things like can_cut_copy (), which is
1831 reasonably complicated and so perhaps better near the function that
1832 it expresses sensitivity for, and on the other hand checks
1833 in this function as well. You can't really have can_* for everything
1834 or the number of methods would get silly. */
1836 bool const one_selected_region = selection->regions.size() == 1;
1838 /* Count the number of selected audio tracks */
1839 int n_audio_tracks = 0;
1840 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1841 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1842 if (r && r->is_audio_track()) {
1849 Menu *play_menu = manage (new Menu);
1850 MenuList& play_items = play_menu->items();
1851 play_menu->set_name ("ArdourContextMenu");
1853 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1854 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1855 add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1857 add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1859 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1863 Menu *select_menu = manage (new Menu);
1864 MenuList& select_items = select_menu->items();
1865 select_menu->set_name ("ArdourContextMenu");
1867 string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1869 select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1871 select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1873 str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1875 select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1877 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1878 select_items.push_back (SeparatorElem());
1880 if (n_audio_tracks) {
1881 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1882 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1885 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1886 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1887 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1888 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1890 if (n_audio_tracks) {
1891 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1894 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1898 Menu *cutnpaste_menu = manage (new Menu);
1899 MenuList& cutnpaste_items = cutnpaste_menu->items();
1900 cutnpaste_menu->set_name ("ArdourContextMenu");
1902 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1904 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1906 if (n_audio_tracks) {
1907 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1908 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1910 cutnpaste_items.push_back (SeparatorElem());
1912 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1913 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1914 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1916 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1919 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1921 if (n_audio_tracks) {
1923 Menu *track_menu = manage (new Menu);
1924 MenuList& track_items = track_menu->items();
1925 track_menu->set_name ("ArdourContextMenu");
1927 /* Adding new material */
1929 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);
1931 add_item_with_sensitivity (track_items, MenuElem (_("Insert existing audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1935 Menu *nudge_menu = manage (new Menu());
1936 MenuList& nudge_items = nudge_menu->items();
1937 nudge_menu->set_name ("ArdourContextMenu");
1939 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1940 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1942 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1944 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1946 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1948 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1950 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1952 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1954 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1957 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1958 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1960 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1961 edit_items.push_back (MenuElem (str, *track_menu));
1965 /* CURSOR SETTING AND MARKS AND STUFF */
1968 Editor::set_snap_to (SnapType st)
1971 string str = snap_type_strings[(int) st];
1973 if (str != snap_type_selector.get_active_text()) {
1974 snap_type_selector.set_active_text (str);
1979 switch (snap_type) {
1980 case SnapToAThirtysecondBeat:
1981 case SnapToASixteenthBeat:
1982 case SnapToAEighthBeat:
1983 case SnapToAQuarterBeat:
1984 case SnapToAThirdBeat:
1985 update_tempo_based_rulers ();
1993 Editor::set_snap_mode (SnapMode mode)
1996 string str = snap_mode_strings[(int)mode];
1998 if (str != snap_mode_selector.get_active_text ()) {
1999 snap_mode_selector.set_active_text (str);
2006 Editor::set_state (const XMLNode& node)
2008 const XMLProperty* prop;
2010 int x, y, xoff, yoff;
2013 if ((prop = node.property ("id")) != 0) {
2014 _id = prop->value ();
2017 if ((geometry = find_named_node (node, "geometry")) == 0) {
2019 g.base_width = default_width;
2020 g.base_height = default_height;
2028 g.base_width = atoi(geometry->property("x_size")->value());
2029 g.base_height = atoi(geometry->property("y_size")->value());
2030 x = atoi(geometry->property("x_pos")->value());
2031 y = atoi(geometry->property("y_pos")->value());
2032 xoff = atoi(geometry->property("x_off")->value());
2033 yoff = atoi(geometry->property("y_off")->value());
2036 set_default_size (g.base_width, g.base_height);
2039 if (session && (prop = node.property ("playhead"))) {
2040 nframes_t pos = atol (prop->value().c_str());
2041 playhead_cursor->set_position (pos);
2043 playhead_cursor->set_position (0);
2045 /* reset_x_origin() doesn't work right here, since the old
2046 position may be zero already, and it does nothing in such
2051 horizontal_adjustment.set_value (0);
2054 if (session && (prop = node.property ("edit-cursor"))) {
2055 nframes_t pos = atol (prop->value().c_str());
2056 edit_cursor->set_position (pos);
2058 edit_cursor->set_position (0);
2061 if ((prop = node.property ("mixer-width"))) {
2062 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2065 if ((prop = node.property ("zoom-focus"))) {
2066 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2069 if ((prop = node.property ("zoom"))) {
2070 reset_zoom (PBD::atof (prop->value()));
2073 if ((prop = node.property ("snap-to"))) {
2074 set_snap_to ((SnapType) atoi (prop->value()));
2077 if ((prop = node.property ("snap-mode"))) {
2078 set_snap_mode ((SnapMode) atoi (prop->value()));
2081 if ((prop = node.property ("mouse-mode"))) {
2082 MouseMode m = str2mousemode(prop->value());
2083 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2084 set_mouse_mode (m, true);
2086 mouse_mode = MouseGain; /* lie, to force the mode switch */
2087 set_mouse_mode (MouseObject, true);
2090 if ((prop = node.property ("show-waveforms"))) {
2091 bool yn = (prop->value() == "yes");
2092 _show_waveforms = !yn;
2093 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2095 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2096 /* do it twice to force the change */
2097 tact->set_active (!yn);
2098 tact->set_active (yn);
2102 if ((prop = node.property ("show-waveforms-recording"))) {
2103 bool yn = (prop->value() == "yes");
2104 _show_waveforms_recording = !yn;
2105 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2107 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2108 /* do it twice to force the change */
2109 tact->set_active (!yn);
2110 tact->set_active (yn);
2114 if ((prop = node.property ("show-measures"))) {
2115 bool yn = (prop->value() == "yes");
2116 _show_measures = !yn;
2117 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2119 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2120 /* do it twice to force the change */
2121 tact->set_active (!yn);
2122 tact->set_active (yn);
2126 if ((prop = node.property ("follow-playhead"))) {
2127 bool yn = (prop->value() == "yes");
2128 set_follow_playhead (yn);
2129 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2131 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2132 if (tact->get_active() != yn) {
2133 tact->set_active (yn);
2138 if ((prop = node.property ("region-list-sort-type"))) {
2139 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2140 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2143 if ((prop = node.property ("xfades-visible"))) {
2144 bool yn = (prop->value() == "yes");
2145 _xfade_visibility = !yn;
2146 // set_xfade_visibility (yn);
2149 if ((prop = node.property ("show-editor-mixer"))) {
2151 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2154 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2155 bool yn = (prop->value() == X_("yes"));
2157 /* do it twice to force the change */
2159 tact->set_active (!yn);
2160 tact->set_active (yn);
2164 if ((prop = node.property ("show-editor-list"))) {
2166 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2170 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2171 bool yn = (prop->value() == X_("yes"));
2173 /* do it twice to force the change */
2175 tact->set_active (!yn);
2176 tact->set_active (yn);
2185 Editor::get_state ()
2187 XMLNode* node = new XMLNode ("Editor");
2190 _id.print (buf, sizeof (buf));
2191 node->add_property ("id", buf);
2193 if (is_realized()) {
2194 Glib::RefPtr<Gdk::Window> win = get_window();
2196 int x, y, xoff, yoff, width, height;
2197 win->get_root_origin(x, y);
2198 win->get_position(xoff, yoff);
2199 win->get_size(width, height);
2201 XMLNode* geometry = new XMLNode ("geometry");
2203 snprintf(buf, sizeof(buf), "%d", width);
2204 geometry->add_property("x_size", string(buf));
2205 snprintf(buf, sizeof(buf), "%d", height);
2206 geometry->add_property("y_size", string(buf));
2207 snprintf(buf, sizeof(buf), "%d", x);
2208 geometry->add_property("x_pos", string(buf));
2209 snprintf(buf, sizeof(buf), "%d", y);
2210 geometry->add_property("y_pos", string(buf));
2211 snprintf(buf, sizeof(buf), "%d", xoff);
2212 geometry->add_property("x_off", string(buf));
2213 snprintf(buf, sizeof(buf), "%d", yoff);
2214 geometry->add_property("y_off", string(buf));
2215 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2216 geometry->add_property("edit_pane_pos", string(buf));
2218 node->add_child_nocopy (*geometry);
2221 maybe_add_mixer_strip_width (*node);
2223 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2224 node->add_property ("zoom-focus", buf);
2225 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2226 node->add_property ("zoom", buf);
2227 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2228 node->add_property ("snap-to", buf);
2229 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2230 node->add_property ("snap-mode", buf);
2232 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2233 node->add_property ("playhead", buf);
2234 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2235 node->add_property ("edit-cursor", buf);
2237 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2238 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2239 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2240 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2241 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2242 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2243 node->add_property ("mouse-mode", enum2str(mouse_mode));
2245 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2247 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2248 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2251 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2253 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2254 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2263 Editor::trackview_by_y_position (double y)
2265 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2269 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2278 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2280 Location* before = 0;
2281 Location* after = 0;
2287 const nframes64_t one_second = session->frame_rate();
2288 const nframes64_t one_minute = session->frame_rate() * 60;
2289 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2290 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2291 nframes64_t presnap = start;
2293 switch (snap_type) {
2299 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2301 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2305 case SnapToSMPTEFrame:
2306 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2307 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2309 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2313 case SnapToSMPTESeconds:
2314 if (session->smpte_offset_negative())
2316 start += session->smpte_offset ();
2318 start -= session->smpte_offset ();
2320 if (start % one_smpte_second > one_smpte_second / 2) {
2321 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2323 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2326 if (session->smpte_offset_negative())
2328 start -= session->smpte_offset ();
2330 start += session->smpte_offset ();
2334 case SnapToSMPTEMinutes:
2335 if (session->smpte_offset_negative())
2337 start += session->smpte_offset ();
2339 start -= session->smpte_offset ();
2341 if (start % one_smpte_minute > one_smpte_minute / 2) {
2342 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2344 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2346 if (session->smpte_offset_negative())
2348 start -= session->smpte_offset ();
2350 start += session->smpte_offset ();
2355 if (start % one_second > one_second / 2) {
2356 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2358 start = (nframes_t) floor ((double) start / one_second) * one_second;
2363 if (start % one_minute > one_minute / 2) {
2364 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2366 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2371 start = session->tempo_map().round_to_bar (start, direction);
2375 start = session->tempo_map().round_to_beat (start, direction);
2378 case SnapToAThirtysecondBeat:
2379 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2382 case SnapToASixteenthBeat:
2383 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2386 case SnapToAEighthBeat:
2387 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2390 case SnapToAQuarterBeat:
2391 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2394 case SnapToAThirdBeat:
2395 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2398 case SnapToEditCursor:
2399 start = edit_cursor->current_frame;
2407 before = session->locations()->first_location_before (start);
2408 after = session->locations()->first_location_after (start);
2410 if (direction < 0) {
2412 start = before->start();
2416 } else if (direction > 0) {
2418 start = after->start();
2420 start = session->current_end_frame();
2425 /* find nearest of the two */
2426 if ((start - before->start()) < (after->start() - start)) {
2427 start = before->start();
2429 start = after->start();
2432 start = before->start();
2435 start = after->start();
2442 case SnapToRegionStart:
2443 case SnapToRegionEnd:
2444 case SnapToRegionSync:
2445 case SnapToRegionBoundary:
2446 if (!region_boundary_cache.empty()) {
2447 vector<nframes_t>::iterator i;
2449 if (direction > 0) {
2450 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2452 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2455 if (i != region_boundary_cache.end()) {
2458 start = region_boundary_cache.back();
2464 switch (snap_mode) {
2470 if (presnap > start) {
2471 if (presnap > (start + unit_to_frame(snap_threshold))) {
2475 } else if (presnap < start) {
2476 if (presnap < (start - unit_to_frame(snap_threshold))) {
2488 Editor::snap_length_beats (nframes_t start)
2494 /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
2496 switch (snap_type) {
2498 return session->tempo_map().meter_at(start).beats_per_bar();
2503 case SnapToAThirtysecondBeat:
2504 return 1.0 / (double)32.0;
2507 case SnapToASixteenthBeat:
2508 return 1.0 / (double)16.0;
2511 case SnapToAEighthBeat:
2512 return 1.0 / (double)8.0;
2515 case SnapToAQuarterBeat:
2516 return 1.0 / (double)4.0;
2519 case SnapToAThirdBeat:
2520 return 1.0 / (double)3.0;
2528 Editor::setup_toolbar ()
2532 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2535 /* Mode Buttons (tool selection) */
2537 vector<ToggleButton *> mouse_mode_buttons;
2539 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2540 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2541 mouse_mode_buttons.push_back (&mouse_move_button);
2542 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2543 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2544 mouse_mode_buttons.push_back (&mouse_select_button);
2545 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2546 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2547 mouse_mode_buttons.push_back (&mouse_gain_button);
2548 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2549 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2550 mouse_mode_buttons.push_back (&mouse_zoom_button);
2551 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2552 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2553 mouse_mode_buttons.push_back (&mouse_timefx_button);
2554 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2555 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2556 mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2557 mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2558 mouse_mode_buttons.push_back (&mouse_note_button);
2559 mouse_mode_buttons.push_back (&mouse_audition_button);
2561 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2563 HBox* mode_box = manage(new HBox);
2564 mode_box->set_border_width (2);
2565 mode_box->set_spacing(4);
2566 mouse_mode_button_box.set_spacing(1);
2567 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2568 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2569 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2570 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2571 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2572 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2573 mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2574 mouse_mode_button_box.set_homogeneous(true);
2576 vector<string> edit_mode_strings;
2577 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2578 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2580 edit_mode_selector.set_name ("EditModeSelector");
2581 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2582 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2583 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2585 mode_box->pack_start(edit_mode_selector);
2586 mode_box->pack_start(mouse_mode_button_box);
2588 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2589 mouse_mode_tearoff->set_name ("MouseModeBase");
2591 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2592 &mouse_mode_tearoff->tearoff_window()));
2593 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2594 &mouse_mode_tearoff->tearoff_window(), 1));
2595 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2596 &mouse_mode_tearoff->tearoff_window()));
2597 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2598 &mouse_mode_tearoff->tearoff_window(), 1));
2600 mouse_move_button.set_name ("MouseModeButton");
2601 mouse_select_button.set_name ("MouseModeButton");
2602 mouse_gain_button.set_name ("MouseModeButton");
2603 mouse_zoom_button.set_name ("MouseModeButton");
2604 mouse_timefx_button.set_name ("MouseModeButton");
2605 mouse_audition_button.set_name ("MouseModeButton");
2606 mouse_note_button.set_name ("MouseModeButton");
2608 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2609 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2610 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2611 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2612 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2613 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2614 ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2616 mouse_move_button.unset_flags (CAN_FOCUS);
2617 mouse_select_button.unset_flags (CAN_FOCUS);
2618 mouse_gain_button.unset_flags (CAN_FOCUS);
2619 mouse_zoom_button.unset_flags (CAN_FOCUS);
2620 mouse_timefx_button.unset_flags (CAN_FOCUS);
2621 mouse_audition_button.unset_flags (CAN_FOCUS);
2622 mouse_note_button.unset_flags (CAN_FOCUS);
2624 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2625 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2627 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2628 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2629 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2630 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2631 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2632 mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2634 // mouse_move_button.set_active (true);
2639 zoom_box.set_spacing (1);
2640 zoom_box.set_border_width (2);
2642 zoom_in_button.set_name ("EditorTimeButton");
2643 zoom_in_button.set_size_request(-1,16);
2644 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2645 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2646 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2648 zoom_out_button.set_name ("EditorTimeButton");
2649 zoom_out_button.set_size_request(-1,16);
2650 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2651 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2652 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2654 zoom_out_full_button.set_name ("EditorTimeButton");
2655 zoom_out_full_button.set_size_request(-1,16);
2656 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2657 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2658 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2660 zoom_focus_selector.set_name ("ZoomFocusSelector");
2661 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Center", FUDGE, 0);
2662 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2663 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2664 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2666 zoom_box.pack_start (zoom_focus_selector, true, true);
2667 zoom_box.pack_start (zoom_out_button, false, false);
2668 zoom_box.pack_start (zoom_in_button, false, false);
2669 zoom_box.pack_start (zoom_out_full_button, false, false);
2671 /* Edit Cursor / Snap */
2673 snap_box.set_spacing (1);
2674 snap_box.set_border_width (2);
2676 snap_type_selector.set_name ("SnapTypeSelector");
2677 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2678 set_popdown_strings (snap_type_selector, snap_type_strings);
2679 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2680 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2682 snap_mode_selector.set_name ("SnapModeSelector");
2683 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2684 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2685 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2687 snap_box.pack_start (edit_cursor_clock, false, false);
2688 snap_box.pack_start (snap_mode_selector, false, false);
2689 snap_box.pack_start (snap_type_selector, false, false);
2694 HBox *nudge_box = manage (new HBox);
2695 nudge_box->set_spacing(1);
2696 nudge_box->set_border_width (2);
2698 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2699 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2701 nudge_box->pack_start (nudge_backward_button, false, false);
2702 nudge_box->pack_start (nudge_forward_button, false, false);
2703 nudge_box->pack_start (nudge_clock, false, false);
2706 /* Pack everything in... */
2708 HBox* hbox = new HBox;
2709 hbox->set_spacing(10);
2711 tools_tearoff = new TearOff (*hbox);
2712 tools_tearoff->set_name ("MouseModeBase");
2714 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2715 &tools_tearoff->tearoff_window()));
2716 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2717 &tools_tearoff->tearoff_window(), 0));
2718 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2719 &tools_tearoff->tearoff_window()));
2720 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2721 &tools_tearoff->tearoff_window(), 0));
2723 toolbar_hbox.set_spacing (10);
2724 toolbar_hbox.set_border_width (1);
2726 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2727 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2730 hbox->pack_start (snap_box, false, false);
2731 // hbox->pack_start (zoom_box, false, false);
2732 hbox->pack_start (*nudge_box, false, false);
2736 toolbar_base.set_name ("ToolBarBase");
2737 toolbar_base.add (toolbar_hbox);
2739 toolbar_frame.set_shadow_type (SHADOW_OUT);
2740 toolbar_frame.set_name ("BaseFrame");
2741 toolbar_frame.add (toolbar_base);
2746 Editor::setup_midi_toolbar ()
2750 /* Mode Buttons (tool selection) */
2752 vector<ToggleButton *> midi_tool_buttons;
2754 midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
2755 midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
2756 midi_tool_buttons.push_back (&midi_tool_select_button);
2757 midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
2758 midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
2759 midi_tool_buttons.push_back (&midi_tool_pencil_button);
2760 midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
2761 midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
2762 midi_tool_buttons.push_back (&midi_tool_erase_button);
2764 midi_tool_select_button.set_active(true);
2766 midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
2768 midi_tool_button_box.set_border_width (2);
2769 midi_tool_button_box.set_spacing(4);
2770 midi_tool_button_box.set_spacing(1);
2771 midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
2772 midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
2773 midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
2774 midi_tool_button_box.set_homogeneous(true);
2776 midi_tool_select_button.set_name ("MouseModeButton");
2777 midi_tool_pencil_button.set_name ("MouseModeButton");
2778 midi_tool_erase_button.set_name ("MouseModeButton");
2780 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
2781 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
2782 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
2784 midi_tool_select_button.unset_flags (CAN_FOCUS);
2785 midi_tool_pencil_button.unset_flags (CAN_FOCUS);
2786 midi_tool_erase_button.unset_flags (CAN_FOCUS);
2788 midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
2789 &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
2790 midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
2791 &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
2792 midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
2793 &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
2795 /* Pack everything in... */
2797 midi_tools_tearoff = new TearOff (midi_tool_button_box);
2798 midi_tools_tearoff->set_name ("MouseModeBase");
2801 midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2802 &midi_tools_tearoff->tearoff_window()));
2803 midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2804 &midi_tools_tearoff->tearoff_window(), 0));
2805 midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2806 &midi_tools_tearoff->tearoff_window()));
2807 midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2808 &midi_tools_tearoff->tearoff_window(), 0));
2811 midi_toolbar_hbox.set_spacing (10);
2812 midi_toolbar_hbox.set_border_width (1);
2814 midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
2816 midi_tool_button_box.show_all ();
2817 midi_toolbar_hbox.show_all();
2818 midi_tools_tearoff->show_all();
2820 midi_toolbar_base.set_name ("ToolBarBase");
2821 midi_toolbar_base.add (midi_toolbar_hbox);
2823 midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
2824 midi_toolbar_frame.set_name ("BaseFrame");
2825 midi_toolbar_frame.add (midi_toolbar_base);
2829 Editor::convert_drop_to_paths (vector<ustring>& paths,
2830 const RefPtr<Gdk::DragContext>& context,
2833 const SelectionData& data,
2842 vector<ustring> uris = data.get_uris();
2844 cerr << "there were " << uris.size() << " in that drag data\n";
2848 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2849 are actually URI lists. So do it by hand.
2852 if (data.get_target() != "text/plain") {
2856 /* Parse the "uri-list" format that Nautilus provides,
2857 where each pathname is delimited by \r\n
2860 const char* p = data.get_text().c_str();
2867 while (g_ascii_isspace (*p))
2871 while (*q && (*q != '\n') && (*q != '\r'))
2877 while (q > p && g_ascii_isspace (*q))
2882 uris.push_back (ustring (p, q - p + 1));
2886 p = strchr (p, '\n');
2896 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2898 if ((*i).substr (0,7) == "file://") {
2901 PBD::url_decode (p);
2903 // scan forward past three slashes
2905 ustring::size_type slashcnt = 0;
2906 ustring::size_type n = 0;
2907 ustring::iterator x = p.begin();
2909 while (slashcnt < 3 && x != p.end()) {
2912 } else if (slashcnt == 3) {
2919 if (slashcnt != 3 || x == p.end()) {
2920 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2924 paths.push_back (p.substr (n - 1));
2932 Editor::new_tempo_section ()
2938 Editor::map_transport_state ()
2940 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2942 if (session->transport_stopped()) {
2943 have_pending_keyboard_selection = false;
2946 update_loop_range_view (true);
2951 Editor::State::State (PublicEditor const * e)
2953 selection = new Selection (e);
2956 Editor::State::~State ()
2962 Editor::get_memento () const
2964 State *state = new State (this);
2966 store_state (*state);
2967 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2971 Editor::store_state (State& state) const
2973 *state.selection = *selection;
2977 Editor::restore_state (State *state)
2979 if (*selection == *state->selection) {
2983 *selection = *state->selection;
2984 time_selection_changed ();
2985 region_selection_changed ();
2987 /* XXX other selection change handlers? */
2991 Editor::begin_reversible_command (string name)
2994 before = &get_state();
2995 session->begin_reversible_command (name);
3000 Editor::commit_reversible_command ()
3003 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
3008 Editor::set_edit_group_solo (Route& route, bool yn)
3010 RouteGroup *edit_group;
3012 if ((edit_group = route.edit_group()) != 0) {
3013 edit_group->apply (&Route::set_solo, yn, this);
3015 route.set_solo (yn, this);
3020 Editor::set_edit_group_mute (Route& route, bool yn)
3022 RouteGroup *edit_group = 0;
3024 if ((edit_group == route.edit_group()) != 0) {
3025 edit_group->apply (&Route::set_mute, yn, this);
3027 route.set_mute (yn, this);
3032 Editor::history_changed ()
3036 if (undo_action && session) {
3037 if (session->undo_depth() == 0) {
3040 label = string_compose(_("Undo (%1)"), session->next_undo());
3042 undo_action->property_label() = label;
3045 if (redo_action && session) {
3046 if (session->redo_depth() == 0) {
3049 label = string_compose(_("Redo (%1)"), session->next_redo());
3051 redo_action->property_label() = label;
3056 Editor::duplicate_dialog (bool dup_region)
3058 if (selection->regions.empty() && (selection->time.length() == 0)) {
3062 ArdourDialog win ("duplicate dialog");
3063 Label label (_("Duplicate how many times?"));
3064 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3065 SpinButton spinner (adjustment);
3067 win.get_vbox()->set_spacing (12);
3068 win.get_vbox()->pack_start (label);
3070 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3071 place, visually. so do this by hand.
3074 win.get_vbox()->pack_start (spinner);
3075 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3080 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3081 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3083 win.set_position (WIN_POS_MOUSE);
3085 spinner.grab_focus ();
3087 switch (win.run ()) {
3088 case RESPONSE_ACCEPT:
3094 float times = adjustment.get_value();
3096 if (!selection->regions.empty()) {
3097 duplicate_some_regions (selection->regions, times);
3099 duplicate_selection (times);
3104 Editor::show_verbose_canvas_cursor ()
3106 verbose_canvas_cursor->raise_to_top();
3107 verbose_canvas_cursor->show();
3108 verbose_cursor_visible = true;
3112 Editor::hide_verbose_canvas_cursor ()
3114 verbose_canvas_cursor->hide();
3115 verbose_cursor_visible = false;
3119 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3121 /* XXX get origin of canvas relative to root window,
3122 add x and y and check compared to gdk_screen_{width,height}
3124 verbose_canvas_cursor->property_text() = txt.c_str();
3125 verbose_canvas_cursor->property_x() = x;
3126 verbose_canvas_cursor->property_y() = y;
3130 Editor::set_verbose_canvas_cursor_text (const string & txt)
3132 verbose_canvas_cursor->property_text() = txt.c_str();
3136 Editor::edit_mode_selection_done ()
3142 string choice = edit_mode_selector.get_active_text();
3143 EditMode mode = Slide;
3145 if (choice == _("Splice Edit")) {
3147 } else if (choice == _("Slide Edit")) {
3151 Config->set_edit_mode (mode);
3155 Editor::snap_type_selection_done ()
3157 string choice = snap_type_selector.get_active_text();
3158 SnapType snaptype = SnapToFrame;
3160 if (choice == _("Beats/3")) {
3161 snaptype = SnapToAThirdBeat;
3162 } else if (choice == _("Beats/4")) {
3163 snaptype = SnapToAQuarterBeat;
3164 } else if (choice == _("Beats/8")) {
3165 snaptype = SnapToAEighthBeat;
3166 } else if (choice == _("Beats/16")) {
3167 snaptype = SnapToASixteenthBeat;
3168 } else if (choice == _("Beats/32")) {
3169 snaptype = SnapToAThirtysecondBeat;
3170 } else if (choice == _("Beats")) {
3171 snaptype = SnapToBeat;
3172 } else if (choice == _("Bars")) {
3173 snaptype = SnapToBar;
3174 } else if (choice == _("Marks")) {
3175 snaptype = SnapToMark;
3176 } else if (choice == _("Edit Cursor")) {
3177 snaptype = SnapToEditCursor;
3178 } else if (choice == _("Region starts")) {
3179 snaptype = SnapToRegionStart;
3180 } else if (choice == _("Region ends")) {
3181 snaptype = SnapToRegionEnd;
3182 } else if (choice == _("Region bounds")) {
3183 snaptype = SnapToRegionBoundary;
3184 } else if (choice == _("Region syncs")) {
3185 snaptype = SnapToRegionSync;
3186 } else if (choice == _("CD Frames")) {
3187 snaptype = SnapToCDFrame;
3188 } else if (choice == _("SMPTE Frames")) {
3189 snaptype = SnapToSMPTEFrame;
3190 } else if (choice == _("SMPTE Seconds")) {
3191 snaptype = SnapToSMPTESeconds;
3192 } else if (choice == _("SMPTE Minutes")) {
3193 snaptype = SnapToSMPTEMinutes;
3194 } else if (choice == _("Seconds")) {
3195 snaptype = SnapToSeconds;
3196 } else if (choice == _("Minutes")) {
3197 snaptype = SnapToMinutes;
3198 } else if (choice == _("None")) {
3199 snaptype = SnapToFrame;
3202 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3204 ract->set_active ();
3209 Editor::snap_mode_selection_done ()
3211 string choice = snap_mode_selector.get_active_text();
3212 SnapMode mode = SnapNormal;
3214 if (choice == _("Normal")) {
3216 } else if (choice == _("Magnetic")) {
3217 mode = SnapMagnetic;
3220 RefPtr<RadioAction> ract = snap_mode_action (mode);
3223 ract->set_active (true);
3228 Editor::zoom_focus_selection_done ()
3230 string choice = zoom_focus_selector.get_active_text();
3231 ZoomFocus focus_type = ZoomFocusLeft;
3233 if (choice == _("Left")) {
3234 focus_type = ZoomFocusLeft;
3235 } else if (choice == _("Right")) {
3236 focus_type = ZoomFocusRight;
3237 } else if (choice == _("Center")) {
3238 focus_type = ZoomFocusCenter;
3239 } else if (choice == _("Play")) {
3240 focus_type = ZoomFocusPlayhead;
3241 } else if (choice == _("Edit")) {
3242 focus_type = ZoomFocusEdit;
3245 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3248 ract->set_active ();
3253 Editor::edit_controls_button_release (GdkEventButton* ev)
3255 if (Keyboard::is_context_menu_event (ev)) {
3256 ARDOUR_UI::instance()->add_route (this);
3262 Editor::mouse_select_button_release (GdkEventButton* ev)
3264 /* this handles just right-clicks */
3266 if (ev->button != 3) {
3273 Editor::TrackViewList *
3274 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3277 TrackViewList::iterator i;
3279 v = new TrackViewList;
3281 if (track == 0 && group == 0) {
3285 for (i = track_views.begin(); i != track_views.end (); ++i) {
3289 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3291 /* just the view for this track
3294 v->push_back (track);
3298 /* views for all tracks in the edit group */
3300 for (i = track_views.begin(); i != track_views.end (); ++i) {
3302 if (group == 0 || (*i)->edit_group() == group) {
3312 Editor::set_zoom_focus (ZoomFocus f)
3314 string str = zoom_focus_strings[(int)f];
3316 if (str != zoom_focus_selector.get_active_text()) {
3317 zoom_focus_selector.set_active_text (str);
3320 if (zoom_focus != f) {
3323 ZoomFocusChanged (); /* EMIT_SIGNAL */
3330 Editor::ensure_float (Window& win)
3332 win.set_transient_for (*this);
3336 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3338 /* recover or initialize pane positions. do this here rather than earlier because
3339 we don't want the positions to change the child allocations, which they seem to do.
3345 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3347 static int32_t done;
3350 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3351 width = default_width;
3352 height = default_height;
3354 width = atoi(geometry->property("x_size")->value());
3355 height = atoi(geometry->property("y_size")->value());
3358 if (which == static_cast<Paned*> (&edit_pane)) {
3364 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3365 /* initial allocation is 90% to canvas, 10% to notebook */
3366 pos = (int) floor (alloc.get_width() * 0.90f);
3367 snprintf (buf, sizeof(buf), "%d", pos);
3369 pos = atoi (prop->value());
3372 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3373 edit_pane.set_position (pos);
3374 pre_maximal_pane_position = pos;
3380 Editor::detach_tearoff (Box* b, Window* w)
3382 if (tools_tearoff->torn_off() &&
3383 mouse_mode_tearoff->torn_off()) {
3384 top_hbox.remove (toolbar_frame);
3389 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3391 if (toolbar_frame.get_parent() == 0) {
3392 top_hbox.pack_end (toolbar_frame);
3397 Editor::set_show_measures (bool yn)
3399 if (_show_measures != yn) {
3402 if ((_show_measures = yn) == true) {
3410 Editor::toggle_follow_playhead ()
3412 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3414 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3415 set_follow_playhead (tact->get_active());
3420 Editor::set_follow_playhead (bool yn)
3422 if (_follow_playhead != yn) {
3423 if ((_follow_playhead = yn) == true) {
3425 update_current_screen ();
3432 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3434 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3436 xfade->set_active (!xfade->active());
3441 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3443 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3445 xfade->set_follow_overlap (!xfade->following_overlap());
3450 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3452 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3458 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3462 switch (cew.run ()) {
3463 case RESPONSE_ACCEPT:
3470 xfade->StateChanged (Change (~0));
3474 Editor::playlist_selector () const
3476 return *_playlist_selector;
3480 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3484 ret = nudge_clock.current_duration (pos);
3485 next = ret + 1; /* XXXX fix me */
3491 Editor::end_location_changed (Location* location)
3493 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3494 reset_scrolling_region ();
3498 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3500 ArdourDialog dialog ("playlist deletion dialog");
3501 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3502 "If left alone, no audio files used by it will be cleaned.\n"
3503 "If deleted, audio files used by it alone by will cleaned."),
3506 dialog.set_position (WIN_POS_CENTER);
3507 dialog.get_vbox()->pack_start (label);
3511 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3512 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3513 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3515 switch (dialog.run ()) {
3516 case RESPONSE_ACCEPT:
3517 /* delete the playlist */
3521 case RESPONSE_REJECT:
3522 /* keep the playlist */
3534 Editor::audio_region_selection_covers (nframes_t where)
3536 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3537 if ((*a)->region()->covers (where)) {
3546 Editor::prepare_for_cleanup ()
3548 cut_buffer->clear_regions ();
3549 cut_buffer->clear_playlists ();
3551 selection->clear_regions ();
3552 selection->clear_playlists ();
3556 Editor::transport_loop_location()
3559 return session->locations()->auto_loop_location();
3566 Editor::transport_punch_location()
3569 return session->locations()->auto_punch_location();
3576 Editor::control_layout_scroll (GdkEventScroll* ev)
3578 switch (ev->direction) {
3580 scroll_tracks_up_line ();
3584 case GDK_SCROLL_DOWN:
3585 scroll_tracks_down_line ();
3589 /* no left/right handling yet */
3597 /** A new snapshot has been selected.
3600 Editor::snapshot_display_selection_changed ()
3602 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3604 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3606 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3608 if (snap_name.length() == 0) {
3612 if (session->snap_name() == snap_name) {
3616 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3621 Editor::snapshot_display_button_press (GdkEventButton* ev)
3623 if (ev->button == 3) {
3624 /* Right-click on the snapshot list. Work out which snapshot it
3626 Gtk::TreeModel::Path path;
3627 Gtk::TreeViewColumn* col;
3630 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3631 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3633 Gtk::TreeModel::Row row = *iter;
3634 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3643 /** Pop up the snapshot display context menu.
3644 * @param button Button used to open the menu.
3645 * @param time Menu open time.
3646 * @snapshot_name Name of the snapshot that the menu click was over.
3650 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3652 using namespace Menu_Helpers;
3654 MenuList& items (snapshot_context_menu.items());
3657 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3659 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3661 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3663 snapshot_context_menu.popup (button, time);
3667 Editor::rename_snapshot (Glib::ustring old_name)
3669 ArdourPrompter prompter(true);
3673 prompter.set_name ("Prompter");
3674 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3675 prompter.set_prompt (_("New name of snapshot"));
3676 prompter.set_initial_text (old_name);
3678 if (prompter.run() == RESPONSE_ACCEPT) {
3679 prompter.get_result (new_name);
3680 if (new_name.length()) {
3681 session->rename_state (old_name, new_name);
3682 redisplay_snapshots ();
3689 Editor::remove_snapshot (Glib::ustring name)
3691 vector<string> choices;
3693 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3695 choices.push_back (_("No, do nothing."));
3696 choices.push_back (_("Yes, remove it."));
3698 Gtkmm2ext::Choice prompter (prompt, choices);
3700 if (prompter.run () == 1) {
3701 session->remove_state (name);
3702 redisplay_snapshots ();
3707 Editor::redisplay_snapshots ()
3713 vector<sys::path> state_file_paths;
3715 get_state_files_in_directory (session->session_directory().root_path(),
3718 if (state_file_paths.empty()) return;
3720 vector<string> state_file_names(get_file_names_no_extension(state_file_paths));
3722 snapshot_display_model->clear ();
3724 for (vector<string>::iterator i = state_file_names.begin();
3725 i != state_file_names.end(); ++i)
3727 string statename = (*i);
3728 TreeModel::Row row = *(snapshot_display_model->append());
3730 /* this lingers on in case we ever want to change the visible
3731 name of the snapshot.
3734 string display_name;
3735 display_name = statename;
3737 if (statename == session->snap_name()) {
3738 snapshot_display.get_selection()->select(row);
3741 row[snapshot_display_columns.visible_name] = display_name;
3742 row[snapshot_display_columns.real_name] = statename;
3747 Editor::session_state_saved (string snap_name)
3749 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3750 redisplay_snapshots ();
3754 Editor::maximise_editing_space ()
3756 initial_ruler_update_required = true;
3758 mouse_mode_tearoff->set_visible (false);
3759 tools_tearoff->set_visible (false);
3761 pre_maximal_pane_position = edit_pane.get_position();
3762 pre_maximal_editor_width = this->get_width();
3764 if(post_maximal_pane_position == 0) {
3765 post_maximal_pane_position = edit_pane.get_width();
3770 if(post_maximal_editor_width) {
3771 edit_pane.set_position (post_maximal_pane_position -
3772 abs(post_maximal_editor_width - pre_maximal_editor_width));
3774 edit_pane.set_position (post_maximal_pane_position);
3779 Editor::restore_editing_space ()
3781 initial_ruler_update_required = true;
3783 // user changed width of pane during fullscreen
3784 if(post_maximal_pane_position != edit_pane.get_position()) {
3785 post_maximal_pane_position = edit_pane.get_position();
3790 mouse_mode_tearoff->set_visible (true);
3791 tools_tearoff->set_visible (true);
3792 post_maximal_editor_width = this->get_width();
3795 edit_pane.set_position (
3796 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3801 * Make new playlists for a given track and also any others that belong
3802 * to the same active edit group.
3807 Editor::new_playlists (TimeAxisView* v)
3809 begin_reversible_command (_("new playlists"));
3810 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3811 commit_reversible_command ();
3815 * Use a copy of the current playlist for a given track and also any others that belong
3816 * to the same active edit group.
3821 Editor::copy_playlists (TimeAxisView* v)
3823 begin_reversible_command (_("copy playlists"));
3824 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3825 commit_reversible_command ();
3829 * Clear the current playlist for a given track and also any others that belong
3830 * to the same active edit group.
3835 Editor::clear_playlists (TimeAxisView* v)
3837 begin_reversible_command (_("clear playlists"));
3838 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3839 commit_reversible_command ();
3843 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3845 atv.use_new_playlist (sz > 1 ? false : true);
3849 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3851 atv.use_copy_playlist (sz > 1 ? false : true);
3855 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3857 atv.clear_playlist ();
3861 Editor::on_key_press_event (GdkEventKey* ev)
3863 return key_press_focus_accelerator_handler (*this, ev);
3867 Editor::reset_x_origin (nframes_t frame)
3869 queue_visual_change (frame);
3873 Editor::reset_zoom (double fpu)
3875 queue_visual_change (fpu);
3879 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3881 reset_x_origin (frame);
3886 Editor::set_frames_per_unit (double fpu)
3890 /* this is the core function that controls the zoom level of the canvas. it is called
3891 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3894 if (fpu == frames_per_unit) {
3902 // convert fpu to frame count
3904 frames = (nframes_t) floor (fpu * canvas_width);
3906 /* don't allow zooms that fit more than the maximum number
3907 of frames into an 800 pixel wide space.
3910 if (max_frames / fpu < 800.0) {
3914 if (fpu == frames_per_unit) {
3918 frames_per_unit = fpu;
3920 if (frames != zoom_range_clock.current_duration()) {
3921 zoom_range_clock.set (frames);
3924 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3925 if (!selection->tracks.empty()) {
3926 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3927 (*i)->reshow_selection (selection->time);
3930 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3931 (*i)->reshow_selection (selection->time);
3936 ZoomChanged (); /* EMIT_SIGNAL */
3938 reset_hscrollbar_stepping ();
3939 reset_scrolling_region ();
3941 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3942 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3948 Editor::queue_visual_change (nframes_t where)
3950 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3951 pending_visual_change.time_origin = where;
3953 if (pending_visual_change.idle_handler_id < 0) {
3954 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3959 Editor::queue_visual_change (double fpu)
3961 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3962 pending_visual_change.frames_per_unit = fpu;
3964 if (pending_visual_change.idle_handler_id < 0) {
3965 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3970 Editor::_idle_visual_changer (void* arg)
3972 return static_cast<Editor*>(arg)->idle_visual_changer ();
3976 Editor::idle_visual_changer ()
3978 VisualChange::Type p = pending_visual_change.pending;
3980 pending_visual_change.pending = (VisualChange::Type) 0;
3981 pending_visual_change.idle_handler_id = -1;
3983 if (p & VisualChange::ZoomLevel) {
3984 set_frames_per_unit (pending_visual_change.frames_per_unit);
3987 if (p & VisualChange::TimeOrigin) {
3988 if (pending_visual_change.time_origin != leftmost_frame) {
3989 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3990 /* the signal handler will do the rest */
3992 update_fixed_rulers();
3993 redisplay_tempo (true);
3997 return 0; /* this is always a one-shot call */
4000 struct EditorOrderTimeAxisSorter {
4001 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4002 return a->order < b->order;
4007 Editor::sort_track_selection ()
4009 EditorOrderTimeAxisSorter cmp;
4010 selection->tracks.sort (cmp);
4014 Editor::edit_cursor_position(bool sync)
4016 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
4017 edit_cursor_clock.set(edit_cursor->current_frame, true);
4020 return edit_cursor->current_frame;
4025 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4027 if (!session) return;
4029 begin_reversible_command (cmd);
4033 if ((tll = transport_loop_location()) == 0) {
4034 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4035 XMLNode &before = session->locations()->get_state();
4036 session->locations()->add (loc, true);
4037 session->set_auto_loop_location (loc);
4038 XMLNode &after = session->locations()->get_state();
4039 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4042 XMLNode &before = tll->get_state();
4043 tll->set_hidden (false, this);
4044 tll->set (start, end);
4045 XMLNode &after = tll->get_state();
4046 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4049 commit_reversible_command ();
4053 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4055 if (!session) return;
4057 begin_reversible_command (cmd);
4061 if ((tpl = transport_punch_location()) == 0) {
4062 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4063 XMLNode &before = session->locations()->get_state();
4064 session->locations()->add (loc, true);
4065 session->set_auto_loop_location (loc);
4066 XMLNode &after = session->locations()->get_state();
4067 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4070 XMLNode &before = tpl->get_state();
4071 tpl->set_hidden (false, this);
4072 tpl->set (start, end);
4073 XMLNode &after = tpl->get_state();
4074 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4077 commit_reversible_command ();