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 <sigc++/bind.h>
30 #include <pbd/convert.h>
31 #include <pbd/error.h>
32 #include <pbd/enumwriter.h>
33 #include <pbd/memento_command.h>
35 #include <glibmm/miscutils.h>
36 #include <gtkmm/image.h>
37 #include <gdkmm/color.h>
38 #include <gdkmm/bitmap.h>
40 #include <gtkmm2ext/grouped_buttons.h>
41 #include <gtkmm2ext/gtk_ui.h>
42 #include <gtkmm2ext/tearoff.h>
43 #include <gtkmm2ext/utils.h>
44 #include <gtkmm2ext/window_title.h>
45 #include <gtkmm2ext/choice.h>
47 #include <ardour/audio_track.h>
48 #include <ardour/audio_diskstream.h>
49 #include <ardour/plugin_manager.h>
50 #include <ardour/location.h>
51 #include <ardour/audioplaylist.h>
52 #include <ardour/audioregion.h>
53 #include <ardour/region.h>
54 #include <ardour/session_route.h>
55 #include <ardour/tempo.h>
56 #include <ardour/utils.h>
58 #include <control_protocol/control_protocol.h>
60 #include "ardour_ui.h"
64 #include "playlist_selector.h"
65 #include "audio_region_view.h"
66 #include "rgb_macros.h"
67 #include "selection.h"
68 #include "audio_streamview.h"
69 #include "time_axis_view.h"
70 #include "audio_time_axis.h"
72 #include "crossfade_view.h"
74 #include "public_editor.h"
75 #include "crossfade_edit.h"
76 #include "canvas_impl.h"
78 #include "gui_thread.h"
81 #include "analysis_window.h"
87 #include "imageframe_socket_handler.h"
92 using namespace ARDOUR;
96 using namespace Gtkmm2ext;
97 using namespace Editing;
99 using PBD::internationalize;
102 const double Editor::timebar_height = 15.0;
104 #include "editor_xpms"
106 static const gchar *_snap_type_strings[] = {
130 static const gchar *_snap_mode_strings[] = {
136 static const gchar *_zoom_focus_strings[] = {
145 /* Soundfile drag-n-drop */
147 Gdk::Cursor* Editor::cross_hair_cursor = 0;
148 Gdk::Cursor* Editor::selector_cursor = 0;
149 Gdk::Cursor* Editor::trimmer_cursor = 0;
150 Gdk::Cursor* Editor::grabber_cursor = 0;
151 Gdk::Cursor* Editor::zoom_cursor = 0;
152 Gdk::Cursor* Editor::time_fx_cursor = 0;
153 Gdk::Cursor* Editor::fader_cursor = 0;
154 Gdk::Cursor* Editor::speaker_cursor = 0;
155 Gdk::Cursor* Editor::note_cursor = 0;
156 Gdk::Cursor* Editor::wait_cursor = 0;
157 Gdk::Cursor* Editor::timebar_cursor = 0;
160 show_me_the_size (Requisition* r, const char* what)
162 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
166 check_adjustment (Gtk::Adjustment* adj)
168 cerr << "CHANGE adj = "
169 << adj->get_lower () << ' '
170 << adj->get_upper () << ' '
171 << adj->get_value () << ' '
172 << adj->get_step_increment () << ' '
173 << adj->get_page_increment () << ' '
174 << adj->get_page_size () << ' '
181 /* time display buttons */
183 minsec_label (_("Mins:Secs")),
184 bbt_label (_("Bars:Beats")),
185 smpte_label (_("Timecode")),
186 frame_label (_("Frames")),
187 tempo_label (_("Tempo")),
188 meter_label (_("Meter")),
189 mark_label (_("Location Markers")),
190 range_mark_label (_("Range Markers")),
191 transport_mark_label (_("Loop/Punch Ranges")),
193 edit_packer (3, 3, false),
195 /* the values here don't matter: layout widgets
196 reset them as needed.
199 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
200 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
203 marker_tempo_lines(0),
205 /* tool bar related */
207 edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
208 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
210 toolbar_selection_clock_table (2,3),
212 automation_mode_button (_("mode")),
213 global_automation_button (_("automation")),
216 image_socket_listener(0),
221 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
226 /* we are a singleton */
228 PublicEditor::_instance = this;
232 selection = new Selection;
233 cut_buffer = new Selection;
235 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
236 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
237 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
238 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
240 clicked_regionview = 0;
241 clicked_axisview = 0;
242 clicked_routeview = 0;
243 clicked_crossfadeview = 0;
244 clicked_control_point = 0;
245 latest_regionview = 0;
246 last_update_frame = 0;
248 current_mixer_strip = 0;
249 current_bbt_points = 0;
251 snap_type_strings = I18N (_snap_type_strings);
252 snap_mode_strings = I18N (_snap_mode_strings);
253 zoom_focus_strings = I18N(_zoom_focus_strings);
255 snap_type = SnapToFrame;
256 set_snap_to (snap_type);
257 snap_mode = SnapNormal;
258 set_snap_mode (snap_mode);
259 snap_threshold = 5.0;
260 bbt_beat_subdivision = 4;
263 autoscroll_active = false;
264 autoscroll_timeout_tag = -1;
265 interthread_progress_window = 0;
271 current_interthread_info = 0;
272 _show_measures = true;
273 _show_waveforms = true;
274 _show_waveforms_recording = true;
275 first_action_message = 0;
277 show_gain_after_trim = false;
278 ignore_route_list_reorder = false;
279 no_route_list_redisplay = false;
280 verbose_cursor_on = true;
281 route_removal = false;
282 show_automatic_regions_in_region_list = true;
283 region_list_sort_type = (Editing::RegionListSortType) 0;
284 have_pending_keyboard_selection = false;
285 _follow_playhead = true;
286 _xfade_visibility = true;
287 editor_ruler_menu = 0;
288 no_ruler_shown_update = false;
289 edit_group_list_menu = 0;
291 region_list_menu = 0;
293 start_end_marker_menu = 0;
294 range_marker_menu = 0;
295 marker_menu_item = 0;
297 transport_marker_menu = 0;
298 new_transport_marker_menu = 0;
299 editor_mixer_strip_width = Wide;
300 show_editor_mixer_when_tracks_arrive = false;
303 ignore_mouse_mode_toggle = false;
304 current_stepping_trackview = 0;
306 entered_regionview = 0;
307 clear_entered_track = false;
308 _new_regionviews_show_envelope = false;
309 current_timestretch = 0;
310 in_edit_group_row_change = false;
311 last_canvas_frame = 0;
314 button_release_can_deselect = true;
315 canvas_idle_queued = false;
316 _dragging_playhead = false;
317 _dragging_hscrollbar = false;
319 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
320 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
321 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
322 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
323 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
325 range_marker_drag_rect = 0;
326 marker_drag_line = 0;
328 set_mouse_mode (MouseObject, true);
330 frames_per_unit = 2048; /* too early to use reset_zoom () */
331 reset_hscrollbar_stepping ();
333 zoom_focus = ZoomFocusLeft;
334 set_zoom_focus (ZoomFocusLeft);
335 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
337 initialize_rulers ();
338 initialize_canvas ();
340 edit_controls_vbox.set_spacing (0);
341 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
342 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
344 track_canvas.set_hadjustment (horizontal_adjustment);
345 track_canvas.set_vadjustment (vertical_adjustment);
346 time_canvas.set_hadjustment (horizontal_adjustment);
348 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
349 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
351 controls_layout.add (edit_controls_vbox);
352 controls_layout.set_name ("EditControlsBase");
353 controls_layout.add_events (Gdk::SCROLL_MASK);
354 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
356 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
357 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
358 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
360 edit_vscrollbar.set_adjustment (vertical_adjustment);
361 edit_hscrollbar.set_adjustment (horizontal_adjustment);
363 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
364 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
365 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
367 edit_hscrollbar.set_name ("EditorHScrollbar");
372 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
374 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
375 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
376 0.0, 1.0, 100.0, 1.0));
377 pad_line_1->property_color_rgba() = 0xFF0000FF;
381 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
382 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
383 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
384 time_canvas_vbox.pack_start (*frames_ruler, false, false);
385 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
386 time_canvas_vbox.pack_start (time_canvas, true, true);
387 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 5);
389 bbt_label.set_name ("EditorTimeButton");
390 bbt_label.set_size_request (-1, (int)timebar_height);
391 bbt_label.set_alignment (1.0, 0.5);
392 bbt_label.set_padding (5,0);
393 minsec_label.set_name ("EditorTimeButton");
394 minsec_label.set_size_request (-1, (int)timebar_height);
395 minsec_label.set_alignment (1.0, 0.5);
396 minsec_label.set_padding (5,0);
397 smpte_label.set_name ("EditorTimeButton");
398 smpte_label.set_size_request (-1, (int)timebar_height);
399 smpte_label.set_alignment (1.0, 0.5);
400 smpte_label.set_padding (5,0);
401 frame_label.set_name ("EditorTimeButton");
402 frame_label.set_size_request (-1, (int)timebar_height);
403 frame_label.set_alignment (1.0, 0.5);
404 frame_label.set_padding (5,0);
405 tempo_label.set_name ("EditorTimeButton");
406 tempo_label.set_size_request (-1, (int)timebar_height);
407 tempo_label.set_alignment (1.0, 0.5);
408 tempo_label.set_padding (5,0);
409 meter_label.set_name ("EditorTimeButton");
410 meter_label.set_size_request (-1, (int)timebar_height);
411 meter_label.set_alignment (1.0, 0.5);
412 meter_label.set_padding (5,0);
413 mark_label.set_name ("EditorTimeButton");
414 mark_label.set_size_request (-1, (int)timebar_height);
415 mark_label.set_alignment (1.0, 0.5);
416 mark_label.set_padding (5,0);
417 range_mark_label.set_name ("EditorTimeButton");
418 range_mark_label.set_size_request (-1, (int)timebar_height);
419 range_mark_label.set_alignment (1.0, 0.5);
420 range_mark_label.set_padding (5,0);
421 transport_mark_label.set_name ("EditorTimeButton");
422 transport_mark_label.set_size_request (-1, (int)timebar_height);
423 transport_mark_label.set_alignment (1.0, 0.5);
424 transport_mark_label.set_padding (5,0);
426 time_button_vbox.pack_start (minsec_label, false, false);
427 time_button_vbox.pack_start (smpte_label, false, false);
428 time_button_vbox.pack_start (frame_label, false, false);
429 time_button_vbox.pack_start (bbt_label, false, false);
430 time_button_vbox.pack_start (meter_label, false, false);
431 time_button_vbox.pack_start (tempo_label, false, false);
432 time_button_vbox.pack_start (mark_label, false, false);
434 time_button_event_box.add (time_button_vbox);
435 time_button_event_box.set_name ("TimebarLabelBase");
436 time_button_frame.set_shadow_type (Gtk::SHADOW_NONE);
438 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
439 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
441 time_button_frame.add (time_button_event_box);
442 time_button_frame.set_name ("TimebarLabelBase");
443 time_button_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
445 /* these enable us to have a dedicated window (for cursor setting, etc.)
446 for the canvas areas.
449 track_canvas_event_box.add (track_canvas);
451 time_canvas_event_box.add (time_canvas_vbox);
452 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
454 edit_packer.set_col_spacings (0);
455 edit_packer.set_row_spacings (0);
456 edit_packer.set_homogeneous (false);
457 edit_packer.set_border_width (0);
458 edit_packer.set_name ("EditorWindow");
460 edit_packer.attach (edit_vscrollbar, 3, 4, 1, 2, FILL, FILL|EXPAND, 0, 0);
462 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, SHRINK, 0, 0);
463 edit_packer.attach (time_canvas_event_box, 2, 4, 0, 1, FILL|EXPAND, FILL, 0, 0);
465 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
466 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
468 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
469 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
471 bottom_hbox.set_border_width (2);
472 bottom_hbox.set_spacing (3);
474 route_display_model = ListStore::create(route_display_columns);
475 route_list_display.set_model (route_display_model);
476 route_list_display.append_column (_("Show"), route_display_columns.visible);
477 route_list_display.append_column (_("Name"), route_display_columns.text);
478 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
479 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
480 route_list_display.set_headers_visible (true);
481 route_list_display.set_name ("TrackListDisplay");
482 route_list_display.get_selection()->set_mode (SELECTION_NONE);
483 route_list_display.set_reorderable (true);
484 route_list_display.set_size_request (100,-1);
486 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
487 route_list_visible_cell->property_activatable() = true;
488 route_list_visible_cell->property_radio() = false;
490 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
491 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
493 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
495 route_list_scroller.add (route_list_display);
496 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
498 group_model = ListStore::create(group_columns);
499 edit_group_display.set_model (group_model);
500 edit_group_display.append_column (_("Name"), group_columns.text);
501 edit_group_display.append_column (_("Active"), group_columns.is_active);
502 edit_group_display.append_column (_("Show"), group_columns.is_visible);
503 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
504 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
505 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
506 edit_group_display.get_column (0)->set_expand (true);
507 edit_group_display.get_column (1)->set_expand (false);
508 edit_group_display.get_column (2)->set_expand (false);
509 edit_group_display.set_headers_visible (true);
511 /* name is directly editable */
513 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
514 name_cell->property_editable() = true;
515 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
517 /* use checkbox for the active + visible columns */
519 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
520 active_cell->property_activatable() = true;
521 active_cell->property_radio() = false;
523 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
524 active_cell->property_activatable() = true;
525 active_cell->property_radio() = false;
527 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
529 edit_group_display.set_name ("EditGroupList");
530 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
531 edit_group_display.set_headers_visible (true);
532 edit_group_display.set_reorderable (false);
533 edit_group_display.set_rules_hint (true);
534 edit_group_display.set_size_request (75, -1);
536 edit_group_display_scroller.add (edit_group_display);
537 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
539 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
541 VBox* edit_group_display_packer = manage (new VBox());
542 HBox* edit_group_display_button_box = manage (new HBox());
543 edit_group_display_button_box->set_homogeneous (true);
545 Button* edit_group_add_button = manage (new Button ());
546 Button* edit_group_remove_button = manage (new Button ());
550 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
552 edit_group_add_button->add (*w);
554 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
556 edit_group_remove_button->add (*w);
558 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
559 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
561 edit_group_display_button_box->pack_start (*edit_group_add_button);
562 edit_group_display_button_box->pack_start (*edit_group_remove_button);
564 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
565 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
567 region_list_display.set_size_request (100, -1);
568 region_list_display.set_name ("RegionListDisplay");
570 region_list_model = TreeStore::create (region_list_columns);
571 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
572 region_list_model->set_sort_column (0, SORT_ASCENDING);
574 region_list_display.set_model (region_list_model);
575 region_list_display.append_column (_("Regions"), region_list_columns.name);
576 region_list_display.set_headers_visible (false);
578 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
580 TreeViewColumn* tv_col = region_list_display.get_column(0);
581 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
582 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
583 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
585 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
586 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
588 /* setup DnD handling */
590 list<TargetEntry> region_list_target_table;
592 region_list_target_table.push_back (TargetEntry ("text/plain"));
593 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
594 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
596 region_list_display.add_drop_targets (region_list_target_table);
597 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
599 region_list_scroller.add (region_list_display);
600 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
602 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
603 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
604 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
605 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
606 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
607 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
609 named_selection_scroller.add (named_selection_display);
610 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
612 named_selection_model = TreeStore::create (named_selection_columns);
613 named_selection_display.set_model (named_selection_model);
614 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
615 named_selection_display.set_headers_visible (false);
616 named_selection_display.set_size_request (100, -1);
617 named_selection_display.set_name ("NamedSelectionDisplay");
619 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
620 named_selection_display.set_size_request (100, -1);
621 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
622 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
623 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
627 snapshot_display_model = ListStore::create (snapshot_display_columns);
628 snapshot_display.set_model (snapshot_display_model);
629 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
630 snapshot_display.set_name ("SnapshotDisplay");
631 snapshot_display.set_size_request (75, -1);
632 snapshot_display.set_headers_visible (false);
633 snapshot_display.set_reorderable (false);
634 snapshot_display_scroller.add (snapshot_display);
635 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
637 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
638 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
642 nlabel = manage (new Label (_("Regions")));
643 nlabel->set_angle (-90);
644 the_notebook.append_page (region_list_scroller, *nlabel);
645 nlabel = manage (new Label (_("Tracks/Busses")));
646 nlabel->set_angle (-90);
647 the_notebook.append_page (route_list_scroller, *nlabel);
648 nlabel = manage (new Label (_("Snapshots")));
649 nlabel->set_angle (-90);
650 the_notebook.append_page (snapshot_display_scroller, *nlabel);
651 nlabel = manage (new Label (_("Edit Groups")));
652 nlabel->set_angle (-90);
653 the_notebook.append_page (*edit_group_display_packer, *nlabel);
654 nlabel = manage (new Label (_("Chunks")));
655 nlabel->set_angle (-90);
656 the_notebook.append_page (named_selection_scroller, *nlabel);
658 the_notebook.set_show_tabs (true);
659 the_notebook.set_scrollable (true);
660 the_notebook.popup_enable ();
661 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
663 post_maximal_editor_width = 0;
664 post_maximal_pane_position = 0;
665 edit_pane.pack1 (edit_packer, true, true);
666 edit_pane.pack2 (the_notebook, false, true);
668 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
670 top_hbox.pack_start (toolbar_frame, true, true);
672 HBox *hbox = manage (new HBox);
673 hbox->pack_start (edit_pane, true, true);
675 global_vpacker.pack_start (top_hbox, false, false);
676 global_vpacker.pack_start (*hbox, true, true);
678 global_hpacker.pack_start (global_vpacker, true, true);
680 set_name ("EditorWindow");
681 add_accel_group (ActionManager::ui_manager->get_accel_group());
683 vpacker.pack_end (global_hpacker, true, true);
685 /* register actions now so that set_state() can find them and set toggles/checks etc */
689 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
692 _playlist_selector = new PlaylistSelector();
693 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
695 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
699 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
700 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
702 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
703 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
705 nudge_forward_button.set_name ("TransportButton");
706 nudge_backward_button.set_name ("TransportButton");
708 fade_context_menu.set_name ("ArdourContextMenu");
710 /* icons, titles, WM stuff */
712 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
713 Glib::RefPtr<Gdk::Pixbuf> icon;
715 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
716 window_icons.push_back (icon);
718 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
719 window_icons.push_back (icon);
721 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
722 window_icons.push_back (icon);
724 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
725 window_icons.push_back (icon);
727 if (!window_icons.empty()) {
728 set_icon_list (window_icons);
729 set_default_icon_list (window_icons);
732 WindowTitle title(Glib::get_application_name());
733 title += _("Editor");
734 set_title (title.get_string());
735 set_wmclass (X_("ardour_editor"), "Ardour");
738 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
740 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
741 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
743 /* allow external control surfaces/protocols to do various things */
745 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
746 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
747 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
748 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
750 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
759 if(image_socket_listener)
761 if(image_socket_listener->is_connected())
763 image_socket_listener->close_connection() ;
766 delete image_socket_listener ;
767 image_socket_listener = 0 ;
773 Editor::add_toplevel_controls (Container& cont)
775 vpacker.pack_start (cont, false, false);
780 Editor::catch_vanishing_regionview (RegionView *rv)
782 /* note: the selection will take care of the vanishing
783 audioregionview by itself.
786 if (clicked_regionview == rv) {
787 clicked_regionview = 0;
790 if (entered_regionview == rv) {
791 set_entered_regionview (0);
796 Editor::set_entered_regionview (RegionView* rv)
798 if (rv == entered_regionview) {
802 if (entered_regionview) {
803 entered_regionview->exited ();
806 if ((entered_regionview = rv) != 0) {
807 entered_regionview->entered ();
812 Editor::set_entered_track (TimeAxisView* tav)
815 entered_track->exited ();
818 if ((entered_track = tav) != 0) {
819 entered_track->entered ();
824 Editor::show_window ()
826 show_all_children ();
828 /* re-hide editor list if necessary */
829 editor_list_button_toggled ();
831 /* now reset all audio_time_axis heights, because widgets might need
837 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
838 tv = (static_cast<TimeAxisView*>(*i));
846 Editor::tie_vertical_scrolling ()
848 double y1 = vertical_adjustment.get_value();
849 controls_layout.get_vadjustment()->set_value (y1);
850 playhead_cursor->set_y_axis(y1);
851 edit_cursor->set_y_axis(y1);
855 Editor::instant_save ()
857 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
862 session->add_instant_xml(get_state());
864 Config->add_instant_xml(get_state());
869 Editor::edit_cursor_clock_changed()
871 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
872 edit_cursor->set_position (edit_cursor_clock.current_time());
878 Editor::zoom_adjustment_changed ()
884 double fpu = zoom_range_clock.current_duration() / canvas_width;
888 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
889 } else if (fpu > session->current_end_frame() / canvas_width) {
890 fpu = session->current_end_frame() / canvas_width;
891 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
898 Editor::control_scroll (float fraction)
900 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
906 double step = fraction * current_page_frames();
909 if ((fraction < 0.0f) && (session->transport_frame() < (nframes_t) fabs(step))) {
911 } else if ((fraction > 0.0f) && (max_frames - session->transport_frame() < step)) {
912 target = (max_frames - (current_page_frames()*2)); // allow room for slop in where the PH is on the screen
914 target = (session->transport_frame() + (nframes_t) floor ((fraction * current_page_frames())));
917 /* move visuals, we'll catch up with it later */
919 playhead_cursor->set_position (target);
921 if (target > (current_page_frames() / 2)) {
922 /* try to center PH in window */
923 reset_x_origin (target - (current_page_frames()/2));
928 /* cancel the existing */
930 control_scroll_connection.disconnect ();
932 /* add the next one */
934 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), target), 50);
938 Editor::deferred_control_scroll (nframes_t target)
940 session->request_locate (target);
945 Editor::on_realize ()
947 Window::on_realize ();
952 Editor::start_scrolling ()
954 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
955 (mem_fun(*this, &Editor::update_current_screen));
959 Editor::stop_scrolling ()
961 scroll_connection.disconnect ();
965 Editor::map_position_change (nframes_t frame)
967 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
969 if (session == 0 || !_follow_playhead) {
973 center_screen (frame);
974 playhead_cursor->set_position (frame);
978 Editor::center_screen (nframes_t frame)
980 double page = canvas_width * frames_per_unit;
982 /* if we're off the page, then scroll.
985 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
986 center_screen_internal (frame, page);
991 Editor::center_screen_internal (nframes_t frame, float page)
996 frame -= (nframes_t) page;
1001 reset_x_origin (frame);
1005 Editor::handle_new_duration ()
1007 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1009 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1011 if (new_end > last_canvas_frame) {
1012 last_canvas_frame = new_end;
1013 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1014 reset_scrolling_region ();
1017 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1021 Editor::update_title_s (const string & snap_name)
1023 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1029 Editor::update_title ()
1031 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1034 bool dirty = session->dirty();
1036 string session_name;
1038 if (session->snap_name() != session->name()) {
1039 session_name = session->snap_name();
1041 session_name = session->name();
1045 session_name = "*" + session_name;
1048 WindowTitle title(session_name);
1049 title += Glib::get_application_name();
1050 set_title (title.get_string());
1055 Editor::connect_to_session (Session *t)
1059 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1062 /* catch up with the playhead */
1064 session->request_locate (playhead_cursor->current_frame);
1066 if (first_action_message) {
1067 first_action_message->hide();
1072 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1073 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1075 /* These signals can all be emitted by a non-GUI thread. Therefore the
1076 handlers for them must not attempt to directly interact with the GUI,
1077 but use Gtkmm2ext::UI::instance()->call_slot();
1080 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1081 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1082 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1083 session_connections.push_back (session->RegionAdded.connect (mem_fun(*this, &Editor::handle_new_region)));
1084 session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed)));
1085 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1086 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1087 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1088 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1089 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1090 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1091 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1092 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1093 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1095 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1097 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1099 edit_groups_changed ();
1101 edit_cursor_clock.set_session (session);
1102 zoom_range_clock.set_session (session);
1103 _playlist_selector->set_session (session);
1104 nudge_clock.set_session (session);
1107 if (analysis_window != 0)
1108 analysis_window->set_session (session);
1111 Location* loc = session->locations()->auto_loop_location();
1113 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1114 if (loc->start() == loc->end()) {
1115 loc->set_end (loc->start() + 1);
1117 session->locations()->add (loc, false);
1118 session->set_auto_loop_location (loc);
1121 loc->set_name (_("Loop"));
1124 loc = session->locations()->auto_punch_location();
1126 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1127 if (loc->start() == loc->end()) {
1128 loc->set_end (loc->start() + 1);
1130 session->locations()->add (loc, false);
1131 session->set_auto_punch_location (loc);
1134 loc->set_name (_("Punch"));
1137 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1139 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1141 refresh_location_display ();
1142 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1143 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1144 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1145 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1146 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1148 handle_new_duration ();
1150 redisplay_regions ();
1151 redisplay_named_selections ();
1152 redisplay_snapshots ();
1154 initial_route_list_display ();
1156 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1157 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1160 restore_ruler_visibility ();
1161 //tempo_map_changed (Change (0));
1162 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1166 /* don't show master bus in a new session */
1168 if (ARDOUR_UI::instance()->session_is_new ()) {
1170 TreeModel::Children rows = route_display_model->children();
1171 TreeModel::Children::iterator i;
1173 no_route_list_redisplay = true;
1175 for (i = rows.begin(); i != rows.end(); ++i) {
1176 TimeAxisView *tv = (*i)[route_display_columns.tv];
1177 RouteTimeAxisView *rtv;
1179 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1180 if (rtv->route()->is_master()) {
1181 route_list_display.get_selection()->unselect (i);
1186 no_route_list_redisplay = false;
1187 redisplay_route_list ();
1190 /* register for undo history */
1192 session->register_with_memento_command_factory(_id, this);
1196 Editor::build_cursors ()
1198 using namespace Gdk;
1200 Gdk::Color mbg ("#000000" ); /* Black */
1201 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1204 RefPtr<Bitmap> source, mask;
1205 source = Bitmap::create (mag_bits, mag_width, mag_height);
1206 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1207 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1210 Gdk::Color fbg ("#ffffff" );
1211 Gdk::Color ffg ("#000000" );
1214 RefPtr<Bitmap> source, mask;
1216 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1217 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1218 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1222 RefPtr<Bitmap> source, mask;
1223 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1224 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1225 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1228 grabber_cursor = new Gdk::Cursor (HAND2);
1229 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1230 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1231 selector_cursor = new Gdk::Cursor (XTERM);
1232 time_fx_cursor = new Gdk::Cursor (SIZING);
1233 wait_cursor = new Gdk::Cursor (WATCH);
1234 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1235 note_cursor = new Gdk::Cursor (PENCIL);
1238 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1240 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1242 using namespace Menu_Helpers;
1243 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1246 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1250 MenuList& items (fade_context_menu.items());
1254 switch (item_type) {
1256 case FadeInHandleItem:
1257 if (arv->audio_region()->fade_in_active()) {
1258 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1260 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1263 items.push_back (SeparatorElem());
1265 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1266 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1267 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1268 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1269 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1273 case FadeOutHandleItem:
1274 if (arv->audio_region()->fade_out_active()) {
1275 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1277 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1280 items.push_back (SeparatorElem());
1282 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1283 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1284 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1285 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1286 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1291 fatal << _("programming error: ")
1292 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1297 fade_context_menu.popup (button, time);
1300 /* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
1302 Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
1304 build_track_context_menu (frame)->popup (button, time);
1308 Editor::build_track_context_menu (nframes_t frame)
1310 using namespace Menu_Helpers;
1312 Menu* menu = manage (new Menu);
1313 MenuList& edit_items = menu->items();
1316 /* Build the general `track' context menu, adding what is appropriate given
1317 the current selection */
1319 /* XXX: currently crossfades can't be selected, so we can't use the selection
1320 to decide which crossfades to mention in the menu. I believe this will
1321 change at some point. For now we have to use clicked_trackview to decide. */
1322 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1325 boost::shared_ptr<Diskstream> ds;
1326 boost::shared_ptr<Playlist> pl;
1327 boost::shared_ptr<AudioPlaylist> apl;
1329 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1331 AudioPlaylist::Crossfades xfades;
1332 apl->crossfades_at (frame, xfades);
1334 bool many = xfades.size() > 1;
1336 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1337 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1342 if (!selection->time.empty()) {
1343 add_selection_context_items (edit_items);
1346 if (!selection->regions.empty()) {
1347 add_region_context_items (edit_items);
1350 if (!selection->tracks.empty()) {
1351 add_bus_or_audio_track_context_items (edit_items);
1354 menu->set_name ("ArdourContextMenu");
1361 Editor::analyze_region_selection()
1363 if (analysis_window == 0) {
1364 analysis_window = new AnalysisWindow();
1367 analysis_window->set_session(session);
1369 analysis_window->show_all();
1372 analysis_window->set_regionmode();
1373 analysis_window->analyze();
1375 analysis_window->present();
1379 Editor::analyze_range_selection()
1381 if (analysis_window == 0) {
1382 analysis_window = new AnalysisWindow();
1385 analysis_window->set_session(session);
1387 analysis_window->show_all();
1390 analysis_window->set_rangemode();
1391 analysis_window->analyze();
1393 analysis_window->present();
1395 #endif /* FFT_ANALYSIS */
1398 /** Add context menu items relevant to crossfades.
1399 * @param edit_items List to add the items to.
1402 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1404 using namespace Menu_Helpers;
1405 Menu *xfade_menu = manage (new Menu);
1406 MenuList& items = xfade_menu->items();
1407 xfade_menu->set_name ("ArdourContextMenu");
1410 if (xfade->active()) {
1416 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1417 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1419 if (xfade->can_follow_overlap()) {
1421 if (xfade->following_overlap()) {
1422 str = _("Convert to short");
1424 str = _("Convert to full");
1427 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1431 str = xfade->out()->name();
1433 str += xfade->in()->name();
1435 str = _("Crossfade");
1438 edit_items.push_back (MenuElem (str, *xfade_menu));
1439 edit_items.push_back (SeparatorElem());
1443 Editor::xfade_edit_left_region ()
1445 if (clicked_crossfadeview) {
1446 clicked_crossfadeview->left_view.show_region_editor ();
1451 Editor::xfade_edit_right_region ()
1453 if (clicked_crossfadeview) {
1454 clicked_crossfadeview->right_view.show_region_editor ();
1458 /** Add an element to a menu, settings its sensitivity.
1459 * @param m Menu to add to.
1460 * @param e Element to add.
1461 * @param s true to make sensitive, false to make insensitive
1464 Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
1468 m.back().set_sensitive (false);
1472 /** Add context menu items relevant to regions.
1473 * @param edit_items List to add the items to.
1476 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
1478 using namespace Menu_Helpers;
1479 Menu *region_menu = manage (new Menu);
1480 MenuList& items = region_menu->items();
1481 region_menu->set_name ("ArdourContextMenu");
1483 items.push_back (MenuElem (_("Edit..."), mem_fun(*this, &Editor::edit_region)));
1484 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1485 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1487 Menu* sync_point_menu = manage (new Menu);
1488 MenuList& sync_point_items = sync_point_menu->items();
1489 sync_point_menu->set_name("ArdourContextMenu");
1491 sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1492 sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
1494 items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
1496 add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
1498 add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
1500 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1503 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1506 items.push_back (SeparatorElem());
1508 items.push_back (MenuElem (_("Lock"), bind (mem_fun (*this, &Editor::set_region_lock), true)));
1509 items.push_back (MenuElem (_("Unlock"), bind (mem_fun (*this, &Editor::set_region_lock), false)));
1510 items.push_back (MenuElem (_("Lock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), true)));
1511 items.push_back (MenuElem (_("Unlock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), false)));
1512 items.push_back (MenuElem (_("Mute"), bind (mem_fun (*this, &Editor::set_region_mute), true)));
1513 items.push_back (MenuElem (_("Unmute"), bind (mem_fun (*this, &Editor::set_region_mute), false)));
1514 items.push_back (MenuElem (_("Opaque"), bind (mem_fun (*this, &Editor::set_region_opaque), true)));
1515 items.push_back (MenuElem (_("Transparent"), bind (mem_fun (*this, &Editor::set_region_opaque), false)));
1517 /* We allow "Original position" if at least one region is not at its
1520 RegionSelection::iterator i = selection->regions.begin();
1521 while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
1525 add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
1527 items.push_back (SeparatorElem());
1529 /* Find out if we have a selected audio region */
1530 i = selection->regions.begin();
1531 while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
1534 bool const have_selected_audio_region = (i != selection->regions.end());
1536 if (have_selected_audio_region) {
1538 Menu* envelopes_menu = manage (new Menu);
1539 MenuList& envelopes_items = envelopes_menu->items();
1540 envelopes_menu->set_name ("ArdourContextMenu");
1542 envelopes_items.push_back (MenuElem (_("Reset"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1543 envelopes_items.push_back (MenuElem (_("Visible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), true)));
1544 envelopes_items.push_back (MenuElem (_("Invisible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), false)));
1545 envelopes_items.push_back (MenuElem (_("Active"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), true)));
1546 envelopes_items.push_back (MenuElem (_("Inactive"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), false)));
1548 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1550 items.push_back (MenuElem (_("Denormalize"), mem_fun (*this, &Editor::denormalize_regions)));
1551 items.push_back (MenuElem (_("Normalize"), mem_fun (*this, &Editor::normalize_regions)));
1554 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_regions)));
1555 items.push_back (SeparatorElem());
1558 /* range related stuff */
1560 add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1562 add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1564 items.push_back (SeparatorElem());
1568 Menu *nudge_menu = manage (new Menu());
1569 MenuList& nudge_items = nudge_menu->items();
1570 nudge_menu->set_name ("ArdourContextMenu");
1572 nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1573 nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1574 nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1575 nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1577 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1579 Menu *trim_menu = manage (new Menu);
1580 MenuList& trim_items = trim_menu->items();
1581 trim_menu->set_name ("ArdourContextMenu");
1583 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1584 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1586 items.push_back (MenuElem (_("Trim"), *trim_menu));
1587 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1588 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1589 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1590 items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1591 items.push_back (SeparatorElem());
1592 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1594 /* OK, stick the region submenu at the top of the list, and then add
1598 string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1599 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1602 /** Add context menu items relevant to selection ranges.
1603 * @param edit_items List to add the items to.
1606 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1608 using namespace Menu_Helpers;
1609 Menu *selection_menu = manage (new Menu);
1610 MenuList& items = selection_menu->items();
1611 selection_menu->set_name ("ArdourContextMenu");
1613 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1614 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1617 items.push_back (SeparatorElem());
1618 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1621 items.push_back (SeparatorElem());
1622 items.push_back (MenuElem (_("Separate range to track"), mem_fun(*this, &Editor::separate_region_from_selection)));
1623 items.push_back (MenuElem (_("Separate range to region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1625 items.push_back (SeparatorElem());
1626 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1627 items.push_back (SeparatorElem());
1628 items.push_back (MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1629 items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1630 items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1631 items.push_back (SeparatorElem());
1632 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1633 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1634 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1635 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1636 items.push_back (SeparatorElem());
1637 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1638 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1640 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1641 edit_items.push_back (SeparatorElem());
1644 /** Add context menu items relevant to busses or audio tracks.
1645 * @param edit_items List to add the items to.
1648 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1650 using namespace Menu_Helpers;
1652 /* We add every possible action here, and de-sensitize things
1653 that aren't allowed. The sensitivity logic is a bit spread out;
1654 on the one hand I'm using things like can_cut_copy (), which is
1655 reasonably complicated and so perhaps better near the function that
1656 it expresses sensitivity for, and on the other hand checks
1657 in this function as well. You can't really have can_* for everything
1658 or the number of methods would get silly. */
1660 bool const one_selected_region = selection->regions.size() == 1;
1662 /* Count the number of selected audio tracks */
1663 int n_audio_tracks = 0;
1664 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1665 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1666 if (r && r->is_audio_track()) {
1673 Menu *play_menu = manage (new Menu);
1674 MenuList& play_items = play_menu->items();
1675 play_menu->set_name ("ArdourContextMenu");
1677 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1678 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1679 add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1681 add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1683 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1687 Menu *select_menu = manage (new Menu);
1688 MenuList& select_items = select_menu->items();
1689 select_menu->set_name ("ArdourContextMenu");
1691 string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1693 select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1695 select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1697 str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1699 select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1701 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1702 select_items.push_back (SeparatorElem());
1704 if (n_audio_tracks) {
1705 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1706 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1709 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1710 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1711 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1712 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1714 if (n_audio_tracks) {
1715 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1718 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1722 Menu *cutnpaste_menu = manage (new Menu);
1723 MenuList& cutnpaste_items = cutnpaste_menu->items();
1724 cutnpaste_menu->set_name ("ArdourContextMenu");
1726 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1728 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1730 if (n_audio_tracks) {
1731 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1732 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1734 cutnpaste_items.push_back (SeparatorElem());
1736 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1737 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1738 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1740 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1743 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1745 if (n_audio_tracks) {
1747 Menu *track_menu = manage (new Menu);
1748 MenuList& track_items = track_menu->items();
1749 track_menu->set_name ("ArdourContextMenu");
1751 /* Adding new material */
1753 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);
1755 add_item_with_sensitivity (track_items, MenuElem (_("Insert existing audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1759 Menu *nudge_menu = manage (new Menu());
1760 MenuList& nudge_items = nudge_menu->items();
1761 nudge_menu->set_name ("ArdourContextMenu");
1763 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1764 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1766 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1768 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1770 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1772 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1774 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1776 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1778 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1781 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1782 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1784 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1785 edit_items.push_back (MenuElem (str, *track_menu));
1789 /* CURSOR SETTING AND MARKS AND STUFF */
1792 Editor::set_snap_to (SnapType st)
1795 string str = snap_type_strings[(int) st];
1797 if (str != snap_type_selector.get_active_text()) {
1798 snap_type_selector.set_active_text (str);
1803 switch (snap_type) {
1804 case SnapToAThirtysecondBeat:
1805 case SnapToASixteenthBeat:
1806 case SnapToAEighthBeat:
1807 case SnapToAQuarterBeat:
1808 case SnapToAThirdBeat:
1809 update_tempo_based_rulers ();
1817 Editor::set_snap_mode (SnapMode mode)
1820 string str = snap_mode_strings[(int)mode];
1822 if (str != snap_mode_selector.get_active_text ()) {
1823 snap_mode_selector.set_active_text (str);
1830 Editor::set_state (const XMLNode& node)
1832 const XMLProperty* prop;
1834 int x, y, xoff, yoff;
1837 if ((prop = node.property ("id")) != 0) {
1838 _id = prop->value ();
1841 if ((geometry = find_named_node (node, "geometry")) == 0) {
1843 g.base_width = default_width;
1844 g.base_height = default_height;
1852 g.base_width = atoi(geometry->property("x_size")->value());
1853 g.base_height = atoi(geometry->property("y_size")->value());
1854 x = atoi(geometry->property("x_pos")->value());
1855 y = atoi(geometry->property("y_pos")->value());
1856 xoff = atoi(geometry->property("x_off")->value());
1857 yoff = atoi(geometry->property("y_off")->value());
1860 set_default_size (g.base_width, g.base_height);
1863 if (session && (prop = node.property ("playhead"))) {
1864 nframes_t pos = atol (prop->value().c_str());
1865 playhead_cursor->set_position (pos);
1867 playhead_cursor->set_position (0);
1869 /* reset_x_origin() doesn't work right here, since the old
1870 position may be zero already, and it does nothing in such
1875 horizontal_adjustment.set_value (0);
1878 if (session && (prop = node.property ("edit-cursor"))) {
1879 nframes_t pos = atol (prop->value().c_str());
1880 edit_cursor->set_position (pos);
1882 edit_cursor->set_position (0);
1885 if ((prop = node.property ("mixer-width"))) {
1886 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
1889 if ((prop = node.property ("zoom-focus"))) {
1890 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
1893 if ((prop = node.property ("zoom"))) {
1894 reset_zoom (PBD::atof (prop->value()));
1897 if ((prop = node.property ("snap-to"))) {
1898 set_snap_to ((SnapType) atoi (prop->value()));
1901 if ((prop = node.property ("snap-mode"))) {
1902 set_snap_mode ((SnapMode) atoi (prop->value()));
1905 if ((prop = node.property ("mouse-mode"))) {
1906 MouseMode m = str2mousemode(prop->value());
1907 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
1908 set_mouse_mode (m, true);
1910 mouse_mode = MouseGain; /* lie, to force the mode switch */
1911 set_mouse_mode (MouseObject, true);
1914 if ((prop = node.property ("show-waveforms"))) {
1915 bool yn = (prop->value() == "yes");
1916 _show_waveforms = !yn;
1917 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
1919 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1920 /* do it twice to force the change */
1921 tact->set_active (!yn);
1922 tact->set_active (yn);
1926 if ((prop = node.property ("show-waveforms-recording"))) {
1927 bool yn = (prop->value() == "yes");
1928 _show_waveforms_recording = !yn;
1929 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
1931 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1932 /* do it twice to force the change */
1933 tact->set_active (!yn);
1934 tact->set_active (yn);
1938 if ((prop = node.property ("show-measures"))) {
1939 bool yn = (prop->value() == "yes");
1940 _show_measures = !yn;
1941 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
1943 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1944 /* do it twice to force the change */
1945 tact->set_active (!yn);
1946 tact->set_active (yn);
1950 if ((prop = node.property ("follow-playhead"))) {
1951 bool yn = (prop->value() == "yes");
1952 set_follow_playhead (yn);
1953 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
1955 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1956 if (tact->get_active() != yn) {
1957 tact->set_active (yn);
1962 if ((prop = node.property ("region-list-sort-type"))) {
1963 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
1964 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
1967 if ((prop = node.property ("xfades-visible"))) {
1968 bool yn = (prop->value() == "yes");
1969 _xfade_visibility = !yn;
1970 // set_xfade_visibility (yn);
1973 if ((prop = node.property ("show-editor-mixer"))) {
1975 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
1978 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1979 bool yn = (prop->value() == X_("yes"));
1981 /* do it twice to force the change */
1983 tact->set_active (!yn);
1984 tact->set_active (yn);
1988 if ((prop = node.property ("show-editor-list"))) {
1990 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
1994 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1995 bool yn = (prop->value() == X_("yes"));
1997 /* do it twice to force the change */
1999 tact->set_active (!yn);
2000 tact->set_active (yn);
2009 Editor::get_state ()
2011 XMLNode* node = new XMLNode ("Editor");
2014 _id.print (buf, sizeof (buf));
2015 node->add_property ("id", buf);
2017 if (is_realized()) {
2018 Glib::RefPtr<Gdk::Window> win = get_window();
2020 int x, y, xoff, yoff, width, height;
2021 win->get_root_origin(x, y);
2022 win->get_position(xoff, yoff);
2023 win->get_size(width, height);
2025 XMLNode* geometry = new XMLNode ("geometry");
2027 snprintf(buf, sizeof(buf), "%d", width);
2028 geometry->add_property("x_size", string(buf));
2029 snprintf(buf, sizeof(buf), "%d", height);
2030 geometry->add_property("y_size", string(buf));
2031 snprintf(buf, sizeof(buf), "%d", x);
2032 geometry->add_property("x_pos", string(buf));
2033 snprintf(buf, sizeof(buf), "%d", y);
2034 geometry->add_property("y_pos", string(buf));
2035 snprintf(buf, sizeof(buf), "%d", xoff);
2036 geometry->add_property("x_off", string(buf));
2037 snprintf(buf, sizeof(buf), "%d", yoff);
2038 geometry->add_property("y_off", string(buf));
2039 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2040 geometry->add_property("edit_pane_pos", string(buf));
2042 node->add_child_nocopy (*geometry);
2045 maybe_add_mixer_strip_width (*node);
2047 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2048 node->add_property ("zoom-focus", buf);
2049 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2050 node->add_property ("zoom", buf);
2051 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2052 node->add_property ("snap-to", buf);
2053 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2054 node->add_property ("snap-mode", buf);
2056 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2057 node->add_property ("playhead", buf);
2058 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2059 node->add_property ("edit-cursor", buf);
2061 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2062 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2063 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2064 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2065 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2066 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2067 node->add_property ("mouse-mode", enum2str(mouse_mode));
2069 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2071 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2072 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2075 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2077 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2078 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2087 Editor::trackview_by_y_position (double y)
2089 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2093 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2102 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2104 Location* before = 0;
2105 Location* after = 0;
2111 const nframes64_t one_second = session->frame_rate();
2112 const nframes64_t one_minute = session->frame_rate() * 60;
2113 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2114 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2115 nframes64_t presnap = start;
2117 switch (snap_type) {
2123 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2125 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2129 case SnapToSMPTEFrame:
2130 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2131 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2133 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2137 case SnapToSMPTESeconds:
2138 if (session->smpte_offset_negative())
2140 start += session->smpte_offset ();
2142 start -= session->smpte_offset ();
2144 if (start % one_smpte_second > one_smpte_second / 2) {
2145 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2147 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2150 if (session->smpte_offset_negative())
2152 start -= session->smpte_offset ();
2154 start += session->smpte_offset ();
2158 case SnapToSMPTEMinutes:
2159 if (session->smpte_offset_negative())
2161 start += session->smpte_offset ();
2163 start -= session->smpte_offset ();
2165 if (start % one_smpte_minute > one_smpte_minute / 2) {
2166 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2168 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2170 if (session->smpte_offset_negative())
2172 start -= session->smpte_offset ();
2174 start += session->smpte_offset ();
2179 if (start % one_second > one_second / 2) {
2180 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2182 start = (nframes_t) floor ((double) start / one_second) * one_second;
2187 if (start % one_minute > one_minute / 2) {
2188 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2190 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2195 start = session->tempo_map().round_to_bar (start, direction);
2199 start = session->tempo_map().round_to_beat (start, direction);
2202 case SnapToAThirtysecondBeat:
2203 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2206 case SnapToASixteenthBeat:
2207 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2210 case SnapToAEighthBeat:
2211 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2214 case SnapToAQuarterBeat:
2215 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2218 case SnapToAThirdBeat:
2219 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2222 case SnapToEditCursor:
2223 start = edit_cursor->current_frame;
2231 before = session->locations()->first_location_before (start);
2232 after = session->locations()->first_location_after (start);
2234 if (direction < 0) {
2236 start = before->start();
2240 } else if (direction > 0) {
2242 start = after->start();
2244 start = session->current_end_frame();
2249 /* find nearest of the two */
2250 if ((start - before->start()) < (after->start() - start)) {
2251 start = before->start();
2253 start = after->start();
2256 start = before->start();
2259 start = after->start();
2266 case SnapToRegionStart:
2267 case SnapToRegionEnd:
2268 case SnapToRegionSync:
2269 case SnapToRegionBoundary:
2270 if (!region_boundary_cache.empty()) {
2271 vector<nframes_t>::iterator i;
2273 if (direction > 0) {
2274 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2276 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2279 if (i != region_boundary_cache.end()) {
2282 start = region_boundary_cache.back();
2288 switch (snap_mode) {
2294 if (presnap > start) {
2295 if (presnap > (start + unit_to_frame(snap_threshold))) {
2299 } else if (presnap < start) {
2300 if (presnap < (start - unit_to_frame(snap_threshold))) {
2312 Editor::setup_toolbar ()
2316 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2319 /* Mode Buttons (tool selection) */
2321 vector<ToggleButton *> mouse_mode_buttons;
2323 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2324 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2325 mouse_mode_buttons.push_back (&mouse_move_button);
2326 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2327 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2328 mouse_mode_buttons.push_back (&mouse_select_button);
2329 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2330 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2331 mouse_mode_buttons.push_back (&mouse_gain_button);
2332 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2333 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2334 mouse_mode_buttons.push_back (&mouse_zoom_button);
2335 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2336 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2337 mouse_mode_buttons.push_back (&mouse_timefx_button);
2338 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2339 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2340 mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2341 mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2342 mouse_mode_buttons.push_back (&mouse_note_button);
2343 mouse_mode_buttons.push_back (&mouse_audition_button);
2345 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2347 HBox* mode_box = manage(new HBox);
2348 mode_box->set_border_width (2);
2349 mode_box->set_spacing(4);
2350 mouse_mode_button_box.set_spacing(1);
2351 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2352 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2353 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2354 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2355 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2356 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2357 mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2358 mouse_mode_button_box.set_homogeneous(true);
2360 vector<string> edit_mode_strings;
2361 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2362 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2364 edit_mode_selector.set_name ("EditModeSelector");
2365 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2366 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2367 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2369 mode_box->pack_start(edit_mode_selector);
2370 mode_box->pack_start(mouse_mode_button_box);
2372 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2373 mouse_mode_tearoff->set_name ("MouseModeBase");
2375 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2376 &mouse_mode_tearoff->tearoff_window()));
2377 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2378 &mouse_mode_tearoff->tearoff_window(), 1));
2379 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2380 &mouse_mode_tearoff->tearoff_window()));
2381 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2382 &mouse_mode_tearoff->tearoff_window(), 1));
2384 mouse_move_button.set_name ("MouseModeButton");
2385 mouse_select_button.set_name ("MouseModeButton");
2386 mouse_gain_button.set_name ("MouseModeButton");
2387 mouse_zoom_button.set_name ("MouseModeButton");
2388 mouse_timefx_button.set_name ("MouseModeButton");
2389 mouse_audition_button.set_name ("MouseModeButton");
2390 mouse_note_button.set_name ("MouseModeButton");
2392 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2393 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2394 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2395 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2396 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2397 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2398 ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2400 mouse_move_button.unset_flags (CAN_FOCUS);
2401 mouse_select_button.unset_flags (CAN_FOCUS);
2402 mouse_gain_button.unset_flags (CAN_FOCUS);
2403 mouse_zoom_button.unset_flags (CAN_FOCUS);
2404 mouse_timefx_button.unset_flags (CAN_FOCUS);
2405 mouse_audition_button.unset_flags (CAN_FOCUS);
2406 mouse_note_button.unset_flags (CAN_FOCUS);
2408 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2409 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2411 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2412 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2413 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2414 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2415 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2416 mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2418 // mouse_move_button.set_active (true);
2423 zoom_box.set_spacing (1);
2424 zoom_box.set_border_width (2);
2426 zoom_in_button.set_name ("EditorTimeButton");
2427 zoom_in_button.set_size_request(-1,16);
2428 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2429 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2430 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2432 zoom_out_button.set_name ("EditorTimeButton");
2433 zoom_out_button.set_size_request(-1,16);
2434 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2435 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2436 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2438 zoom_out_full_button.set_name ("EditorTimeButton");
2439 zoom_out_full_button.set_size_request(-1,16);
2440 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2441 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2442 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2444 zoom_focus_selector.set_name ("ZoomFocusSelector");
2445 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Center", FUDGE, 0);
2446 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2447 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2448 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2450 zoom_box.pack_start (zoom_focus_selector, true, true);
2451 zoom_box.pack_start (zoom_out_button, false, false);
2452 zoom_box.pack_start (zoom_in_button, false, false);
2453 zoom_box.pack_start (zoom_out_full_button, false, false);
2455 /* Edit Cursor / Snap */
2457 snap_box.set_spacing (1);
2458 snap_box.set_border_width (2);
2460 snap_type_selector.set_name ("SnapTypeSelector");
2461 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2462 set_popdown_strings (snap_type_selector, snap_type_strings);
2463 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2464 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2466 snap_mode_selector.set_name ("SnapModeSelector");
2467 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2468 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2469 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2471 snap_box.pack_start (edit_cursor_clock, false, false);
2472 snap_box.pack_start (snap_mode_selector, false, false);
2473 snap_box.pack_start (snap_type_selector, false, false);
2478 HBox *nudge_box = manage (new HBox);
2479 nudge_box->set_spacing(1);
2480 nudge_box->set_border_width (2);
2482 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2483 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2485 nudge_box->pack_start (nudge_backward_button, false, false);
2486 nudge_box->pack_start (nudge_forward_button, false, false);
2487 nudge_box->pack_start (nudge_clock, false, false);
2490 /* Pack everything in... */
2492 HBox* hbox = new HBox;
2493 hbox->set_spacing(10);
2495 tools_tearoff = new TearOff (*hbox);
2496 tools_tearoff->set_name ("MouseModeBase");
2498 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2499 &tools_tearoff->tearoff_window()));
2500 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2501 &tools_tearoff->tearoff_window(), 0));
2502 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2503 &tools_tearoff->tearoff_window()));
2504 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2505 &tools_tearoff->tearoff_window(), 0));
2507 toolbar_hbox.set_spacing (10);
2508 toolbar_hbox.set_border_width (1);
2510 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2511 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2514 hbox->pack_start (snap_box, false, false);
2515 // hbox->pack_start (zoom_box, false, false);
2516 hbox->pack_start (*nudge_box, false, false);
2520 toolbar_base.set_name ("ToolBarBase");
2521 toolbar_base.add (toolbar_hbox);
2523 toolbar_frame.set_shadow_type (SHADOW_OUT);
2524 toolbar_frame.set_name ("BaseFrame");
2525 toolbar_frame.add (toolbar_base);
2529 Editor::convert_drop_to_paths (vector<ustring>& paths,
2530 const RefPtr<Gdk::DragContext>& context,
2533 const SelectionData& data,
2542 vector<ustring> uris = data.get_uris();
2546 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2547 are actually URI lists. So do it by hand.
2550 if (data.get_target() != "text/plain") {
2554 /* Parse the "uri-list" format that Nautilus provides,
2555 where each pathname is delimited by \r\n
2558 const char* p = data.get_text().c_str();
2565 while (g_ascii_isspace (*p))
2569 while (*q && (*q != '\n') && (*q != '\r'))
2575 while (q > p && g_ascii_isspace (*q))
2580 uris.push_back (ustring (p, q - p + 1));
2584 p = strchr (p, '\n');
2594 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2595 if ((*i).substr (0,7) == "file://") {
2597 PBD::url_decode (p);
2598 paths.push_back (p.substr (7));
2606 Editor::new_tempo_section ()
2612 Editor::map_transport_state ()
2614 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2616 if (session->transport_stopped()) {
2617 have_pending_keyboard_selection = false;
2620 update_loop_range_view (true);
2625 Editor::State::State ()
2627 selection = new Selection;
2630 Editor::State::~State ()
2636 Editor::get_memento () const
2638 State *state = new State;
2640 store_state (*state);
2641 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2645 Editor::store_state (State& state) const
2647 *state.selection = *selection;
2651 Editor::restore_state (State *state)
2653 if (*selection == *state->selection) {
2657 *selection = *state->selection;
2658 time_selection_changed ();
2659 region_selection_changed ();
2661 /* XXX other selection change handlers? */
2665 Editor::begin_reversible_command (string name)
2668 before = &get_state();
2669 session->begin_reversible_command (name);
2674 Editor::commit_reversible_command ()
2677 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2682 Editor::set_edit_group_solo (Route& route, bool yn)
2684 RouteGroup *edit_group;
2686 if ((edit_group = route.edit_group()) != 0) {
2687 edit_group->apply (&Route::set_solo, yn, this);
2689 route.set_solo (yn, this);
2694 Editor::set_edit_group_mute (Route& route, bool yn)
2696 RouteGroup *edit_group = 0;
2698 if ((edit_group == route.edit_group()) != 0) {
2699 edit_group->apply (&Route::set_mute, yn, this);
2701 route.set_mute (yn, this);
2706 Editor::history_changed ()
2710 if (undo_action && session) {
2711 if (session->undo_depth() == 0) {
2714 label = string_compose(_("Undo (%1)"), session->next_undo());
2716 undo_action->property_label() = label;
2719 if (redo_action && session) {
2720 if (session->redo_depth() == 0) {
2723 label = string_compose(_("Redo (%1)"), session->next_redo());
2725 redo_action->property_label() = label;
2730 Editor::duplicate_dialog (bool dup_region)
2732 if (selection->regions.empty() && (selection->time.length() == 0)) {
2736 ArdourDialog win ("duplicate dialog");
2737 Label label (_("Duplicate how many times?"));
2738 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
2739 SpinButton spinner (adjustment);
2741 win.get_vbox()->set_spacing (12);
2742 win.get_vbox()->pack_start (label);
2744 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
2745 place, visually. so do this by hand.
2748 win.get_vbox()->pack_start (spinner);
2749 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
2754 win.add_button (Stock::OK, RESPONSE_ACCEPT);
2755 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2757 win.set_position (WIN_POS_MOUSE);
2759 spinner.grab_focus ();
2761 switch (win.run ()) {
2762 case RESPONSE_ACCEPT:
2768 float times = adjustment.get_value();
2770 if (!selection->regions.empty()) {
2771 duplicate_some_regions (selection->regions, times);
2773 duplicate_selection (times);
2778 Editor::show_verbose_canvas_cursor ()
2780 verbose_canvas_cursor->raise_to_top();
2781 verbose_canvas_cursor->show();
2782 verbose_cursor_visible = true;
2786 Editor::hide_verbose_canvas_cursor ()
2788 verbose_canvas_cursor->hide();
2789 verbose_cursor_visible = false;
2793 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
2795 /* XXX get origin of canvas relative to root window,
2796 add x and y and check compared to gdk_screen_{width,height}
2798 verbose_canvas_cursor->property_text() = txt.c_str();
2799 verbose_canvas_cursor->property_x() = x;
2800 verbose_canvas_cursor->property_y() = y;
2804 Editor::set_verbose_canvas_cursor_text (const string & txt)
2806 verbose_canvas_cursor->property_text() = txt.c_str();
2810 Editor::edit_mode_selection_done ()
2816 string choice = edit_mode_selector.get_active_text();
2817 EditMode mode = Slide;
2819 if (choice == _("Splice Edit")) {
2821 } else if (choice == _("Slide Edit")) {
2825 Config->set_edit_mode (mode);
2829 Editor::snap_type_selection_done ()
2831 string choice = snap_type_selector.get_active_text();
2832 SnapType snaptype = SnapToFrame;
2834 if (choice == _("Beats/3")) {
2835 snaptype = SnapToAThirdBeat;
2836 } else if (choice == _("Beats/4")) {
2837 snaptype = SnapToAQuarterBeat;
2838 } else if (choice == _("Beats/8")) {
2839 snaptype = SnapToAEighthBeat;
2840 } else if (choice == _("Beats/16")) {
2841 snaptype = SnapToASixteenthBeat;
2842 } else if (choice == _("Beats/32")) {
2843 snaptype = SnapToAThirtysecondBeat;
2844 } else if (choice == _("Beats")) {
2845 snaptype = SnapToBeat;
2846 } else if (choice == _("Bars")) {
2847 snaptype = SnapToBar;
2848 } else if (choice == _("Marks")) {
2849 snaptype = SnapToMark;
2850 } else if (choice == _("Edit Cursor")) {
2851 snaptype = SnapToEditCursor;
2852 } else if (choice == _("Region starts")) {
2853 snaptype = SnapToRegionStart;
2854 } else if (choice == _("Region ends")) {
2855 snaptype = SnapToRegionEnd;
2856 } else if (choice == _("Region bounds")) {
2857 snaptype = SnapToRegionBoundary;
2858 } else if (choice == _("Region syncs")) {
2859 snaptype = SnapToRegionSync;
2860 } else if (choice == _("CD Frames")) {
2861 snaptype = SnapToCDFrame;
2862 } else if (choice == _("SMPTE Frames")) {
2863 snaptype = SnapToSMPTEFrame;
2864 } else if (choice == _("SMPTE Seconds")) {
2865 snaptype = SnapToSMPTESeconds;
2866 } else if (choice == _("SMPTE Minutes")) {
2867 snaptype = SnapToSMPTEMinutes;
2868 } else if (choice == _("Seconds")) {
2869 snaptype = SnapToSeconds;
2870 } else if (choice == _("Minutes")) {
2871 snaptype = SnapToMinutes;
2872 } else if (choice == _("None")) {
2873 snaptype = SnapToFrame;
2876 RefPtr<RadioAction> ract = snap_type_action (snaptype);
2878 ract->set_active ();
2883 Editor::snap_mode_selection_done ()
2885 string choice = snap_mode_selector.get_active_text();
2886 SnapMode mode = SnapNormal;
2888 if (choice == _("Normal")) {
2890 } else if (choice == _("Magnetic")) {
2891 mode = SnapMagnetic;
2894 RefPtr<RadioAction> ract = snap_mode_action (mode);
2897 ract->set_active (true);
2902 Editor::zoom_focus_selection_done ()
2904 string choice = zoom_focus_selector.get_active_text();
2905 ZoomFocus focus_type = ZoomFocusLeft;
2907 if (choice == _("Left")) {
2908 focus_type = ZoomFocusLeft;
2909 } else if (choice == _("Right")) {
2910 focus_type = ZoomFocusRight;
2911 } else if (choice == _("Center")) {
2912 focus_type = ZoomFocusCenter;
2913 } else if (choice == _("Play")) {
2914 focus_type = ZoomFocusPlayhead;
2915 } else if (choice == _("Edit")) {
2916 focus_type = ZoomFocusEdit;
2919 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
2922 ract->set_active ();
2927 Editor::edit_controls_button_release (GdkEventButton* ev)
2929 if (Keyboard::is_context_menu_event (ev)) {
2930 ARDOUR_UI::instance()->add_route (this);
2936 Editor::mouse_select_button_release (GdkEventButton* ev)
2938 /* this handles just right-clicks */
2940 if (ev->button != 3) {
2947 Editor::TrackViewList *
2948 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
2951 TrackViewList::iterator i;
2953 v = new TrackViewList;
2955 if (track == 0 && group == 0) {
2959 for (i = track_views.begin(); i != track_views.end (); ++i) {
2963 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
2965 /* just the view for this track
2968 v->push_back (track);
2972 /* views for all tracks in the edit group */
2974 for (i = track_views.begin(); i != track_views.end (); ++i) {
2976 if (group == 0 || (*i)->edit_group() == group) {
2986 Editor::set_zoom_focus (ZoomFocus f)
2988 string str = zoom_focus_strings[(int)f];
2990 if (str != zoom_focus_selector.get_active_text()) {
2991 zoom_focus_selector.set_active_text (str);
2994 if (zoom_focus != f) {
2997 ZoomFocusChanged (); /* EMIT_SIGNAL */
3004 Editor::ensure_float (Window& win)
3006 win.set_transient_for (*this);
3010 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3012 /* recover or initialize pane positions. do this here rather than earlier because
3013 we don't want the positions to change the child allocations, which they seem to do.
3019 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3021 static int32_t done;
3024 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3025 width = default_width;
3026 height = default_height;
3028 width = atoi(geometry->property("x_size")->value());
3029 height = atoi(geometry->property("y_size")->value());
3032 if (which == static_cast<Paned*> (&edit_pane)) {
3038 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3039 /* initial allocation is 90% to canvas, 10% to notebook */
3040 pos = (int) floor (alloc.get_width() * 0.90f);
3041 snprintf (buf, sizeof(buf), "%d", pos);
3043 pos = atoi (prop->value());
3046 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3047 edit_pane.set_position (pos);
3048 pre_maximal_pane_position = pos;
3054 Editor::detach_tearoff (Box* b, Window* w)
3056 if (tools_tearoff->torn_off() &&
3057 mouse_mode_tearoff->torn_off()) {
3058 top_hbox.remove (toolbar_frame);
3063 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3065 if (toolbar_frame.get_parent() == 0) {
3066 top_hbox.pack_end (toolbar_frame);
3071 Editor::set_show_measures (bool yn)
3073 if (_show_measures != yn) {
3076 if ((_show_measures = yn) == true) {
3084 Editor::toggle_follow_playhead ()
3086 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3088 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3089 set_follow_playhead (tact->get_active());
3094 Editor::set_follow_playhead (bool yn)
3096 if (_follow_playhead != yn) {
3097 if ((_follow_playhead = yn) == true) {
3099 update_current_screen ();
3106 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3108 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3110 xfade->set_active (!xfade->active());
3115 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3117 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3119 xfade->set_follow_overlap (!xfade->following_overlap());
3124 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3126 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3132 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3136 switch (cew.run ()) {
3137 case RESPONSE_ACCEPT:
3144 xfade->StateChanged (Change (~0));
3148 Editor::playlist_selector () const
3150 return *_playlist_selector;
3154 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3158 ret = nudge_clock.current_duration (pos);
3159 next = ret + 1; /* XXXX fix me */
3165 Editor::end_location_changed (Location* location)
3167 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3168 reset_scrolling_region ();
3172 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3174 ArdourDialog dialog ("playlist deletion dialog");
3175 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3176 "If left alone, no audio files used by it will be cleaned.\n"
3177 "If deleted, audio files used by it alone by will cleaned."),
3180 dialog.set_position (WIN_POS_CENTER);
3181 dialog.get_vbox()->pack_start (label);
3185 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3186 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3187 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3189 switch (dialog.run ()) {
3190 case RESPONSE_ACCEPT:
3191 /* delete the playlist */
3195 case RESPONSE_REJECT:
3196 /* keep the playlist */
3208 Editor::audio_region_selection_covers (nframes_t where)
3210 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3211 if ((*a)->region()->covers (where)) {
3220 Editor::prepare_for_cleanup ()
3222 cut_buffer->clear_regions ();
3223 cut_buffer->clear_playlists ();
3225 selection->clear_regions ();
3226 selection->clear_playlists ();
3230 Editor::transport_loop_location()
3233 return session->locations()->auto_loop_location();
3240 Editor::transport_punch_location()
3243 return session->locations()->auto_punch_location();
3250 Editor::control_layout_scroll (GdkEventScroll* ev)
3252 switch (ev->direction) {
3254 scroll_tracks_up_line ();
3258 case GDK_SCROLL_DOWN:
3259 scroll_tracks_down_line ();
3263 /* no left/right handling yet */
3271 /** A new snapshot has been selected.
3274 Editor::snapshot_display_selection_changed ()
3276 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3278 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3280 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3282 if (snap_name.length() == 0) {
3286 if (session->snap_name() == snap_name) {
3290 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3295 Editor::snapshot_display_button_press (GdkEventButton* ev)
3297 if (ev->button == 3) {
3298 /* Right-click on the snapshot list. Work out which snapshot it
3300 Gtk::TreeModel::Path path;
3301 Gtk::TreeViewColumn* col;
3304 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3305 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3307 Gtk::TreeModel::Row row = *iter;
3308 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3317 /** Pop up the snapshot display context menu.
3318 * @param button Button used to open the menu.
3319 * @param time Menu open time.
3320 * @snapshot_name Name of the snapshot that the menu click was over.
3324 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3326 using namespace Menu_Helpers;
3328 MenuList& items (snapshot_context_menu.items());
3331 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3333 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3335 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3337 snapshot_context_menu.popup (button, time);
3341 Editor::rename_snapshot (Glib::ustring old_name)
3343 ArdourPrompter prompter(true);
3347 prompter.set_name ("Prompter");
3348 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3349 prompter.set_prompt (_("New name of snapshot"));
3350 prompter.set_initial_text (old_name);
3352 if (prompter.run() == RESPONSE_ACCEPT) {
3353 prompter.get_result (new_name);
3354 if (new_name.length()) {
3355 session->rename_state (old_name, new_name);
3356 redisplay_snapshots ();
3363 Editor::remove_snapshot (Glib::ustring name)
3365 vector<string> choices;
3367 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3369 choices.push_back (_("No, do nothing."));
3370 choices.push_back (_("Yes, remove it."));
3372 Gtkmm2ext::Choice prompter (prompt, choices);
3374 if (prompter.run () == 1) {
3375 session->remove_state (name);
3376 redisplay_snapshots ();
3381 Editor::redisplay_snapshots ()
3387 vector<string*>* states;
3389 if ((states = session->possible_states()) == 0) {
3393 snapshot_display_model->clear ();
3395 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3396 string statename = *(*i);
3397 TreeModel::Row row = *(snapshot_display_model->append());
3399 /* this lingers on in case we ever want to change the visible
3400 name of the snapshot.
3403 string display_name;
3404 display_name = statename;
3406 if (statename == session->snap_name()) {
3407 snapshot_display.get_selection()->select(row);
3410 row[snapshot_display_columns.visible_name] = display_name;
3411 row[snapshot_display_columns.real_name] = statename;
3418 Editor::session_state_saved (string snap_name)
3420 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3421 redisplay_snapshots ();
3425 Editor::maximise_editing_space ()
3427 initial_ruler_update_required = true;
3429 mouse_mode_tearoff->set_visible (false);
3430 tools_tearoff->set_visible (false);
3432 pre_maximal_pane_position = edit_pane.get_position();
3433 pre_maximal_editor_width = this->get_width();
3435 if(post_maximal_pane_position == 0) {
3436 post_maximal_pane_position = edit_pane.get_width();
3441 if(post_maximal_editor_width) {
3442 edit_pane.set_position (post_maximal_pane_position -
3443 abs(post_maximal_editor_width - pre_maximal_editor_width));
3445 edit_pane.set_position (post_maximal_pane_position);
3450 Editor::restore_editing_space ()
3452 initial_ruler_update_required = true;
3454 // user changed width of pane during fullscreen
3455 if(post_maximal_pane_position != edit_pane.get_position()) {
3456 post_maximal_pane_position = edit_pane.get_position();
3461 mouse_mode_tearoff->set_visible (true);
3462 tools_tearoff->set_visible (true);
3463 post_maximal_editor_width = this->get_width();
3466 edit_pane.set_position (
3467 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3472 Editor::new_playlists ()
3474 begin_reversible_command (_("new playlists"));
3475 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist));
3476 commit_reversible_command ();
3480 Editor::copy_playlists ()
3482 begin_reversible_command (_("copy playlists"));
3483 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist));
3484 commit_reversible_command ();
3488 Editor::clear_playlists ()
3490 begin_reversible_command (_("clear playlists"));
3491 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist));
3492 commit_reversible_command ();
3496 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3498 atv.use_new_playlist (sz > 1 ? false : true);
3502 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3504 atv.use_copy_playlist (sz > 1 ? false : true);
3508 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3510 atv.clear_playlist ();
3514 Editor::on_key_press_event (GdkEventKey* ev)
3516 return key_press_focus_accelerator_handler (*this, ev);
3520 Editor::reset_x_origin (nframes_t frame)
3522 queue_visual_change (frame);
3526 Editor::reset_zoom (double fpu)
3528 queue_visual_change (fpu);
3532 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3534 reset_x_origin (frame);
3539 Editor::set_frames_per_unit (double fpu)
3543 /* this is the core function that controls the zoom level of the canvas. it is called
3544 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3547 if (fpu == frames_per_unit) {
3555 // convert fpu to frame count
3557 frames = (nframes_t) floor (fpu * canvas_width);
3559 /* don't allow zooms that fit more than the maximum number
3560 of frames into an 800 pixel wide space.
3563 if (max_frames / fpu < 800.0) {
3567 if (fpu == frames_per_unit) {
3571 frames_per_unit = fpu;
3573 if (frames != zoom_range_clock.current_duration()) {
3574 zoom_range_clock.set (frames);
3577 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3578 if (!selection->tracks.empty()) {
3579 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3580 (*i)->reshow_selection (selection->time);
3583 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3584 (*i)->reshow_selection (selection->time);
3589 ZoomChanged (); /* EMIT_SIGNAL */
3591 reset_hscrollbar_stepping ();
3592 reset_scrolling_region ();
3594 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3595 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3601 Editor::queue_visual_change (nframes_t where)
3603 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3604 pending_visual_change.time_origin = where;
3606 if (pending_visual_change.idle_handler_id < 0) {
3607 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3612 Editor::queue_visual_change (double fpu)
3614 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3615 pending_visual_change.frames_per_unit = fpu;
3617 if (pending_visual_change.idle_handler_id < 0) {
3618 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3623 Editor::_idle_visual_changer (void* arg)
3625 return static_cast<Editor*>(arg)->idle_visual_changer ();
3629 Editor::idle_visual_changer ()
3631 VisualChange::Type p = pending_visual_change.pending;
3633 pending_visual_change.pending = (VisualChange::Type) 0;
3634 pending_visual_change.idle_handler_id = -1;
3636 if (p & VisualChange::ZoomLevel) {
3637 set_frames_per_unit (pending_visual_change.frames_per_unit);
3640 if (p & VisualChange::TimeOrigin) {
3641 if (pending_visual_change.time_origin != leftmost_frame) {
3642 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3643 /* the signal handler will do the rest */
3645 update_fixed_rulers();
3646 redisplay_tempo (true);
3650 return 0; /* this is always a one-shot call */
3653 struct EditorOrderTimeAxisSorter {
3654 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3655 return a->order < b->order;
3660 Editor::sort_track_selection ()
3662 EditorOrderTimeAxisSorter cmp;
3663 selection->tracks.sort (cmp);
3667 Editor::edit_cursor_position(bool sync)
3669 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
3670 edit_cursor_clock.set(edit_cursor->current_frame, true);
3673 return edit_cursor->current_frame;