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.
27 #include <boost/none.hpp>
29 #include <sigc++/bind.h>
31 #include <pbd/convert.h>
32 #include <pbd/error.h>
33 #include <pbd/enumwriter.h>
34 #include <pbd/memento_command.h>
36 #include <glibmm/miscutils.h>
37 #include <gtkmm/image.h>
38 #include <gdkmm/color.h>
39 #include <gdkmm/bitmap.h>
41 #include <gtkmm2ext/grouped_buttons.h>
42 #include <gtkmm2ext/gtk_ui.h>
43 #include <gtkmm2ext/tearoff.h>
44 #include <gtkmm2ext/utils.h>
45 #include <gtkmm2ext/window_title.h>
46 #include <gtkmm2ext/choice.h>
48 #include <ardour/audio_track.h>
49 #include <ardour/audio_diskstream.h>
50 #include <ardour/plugin_manager.h>
51 #include <ardour/location.h>
52 #include <ardour/audioplaylist.h>
53 #include <ardour/audioregion.h>
54 #include <ardour/region.h>
55 #include <ardour/session_route.h>
56 #include <ardour/tempo.h>
57 #include <ardour/utils.h>
58 #include <ardour/profile.h>
60 #include <control_protocol/control_protocol.h>
62 #include "ardour_ui.h"
66 #include "playlist_selector.h"
67 #include "audio_region_view.h"
68 #include "rgb_macros.h"
69 #include "selection.h"
70 #include "audio_streamview.h"
71 #include "time_axis_view.h"
72 #include "audio_time_axis.h"
74 #include "crossfade_view.h"
76 #include "public_editor.h"
77 #include "crossfade_edit.h"
78 #include "canvas_impl.h"
80 #include "gui_thread.h"
84 #include "analysis_window.h"
90 #include "imageframe_socket_handler.h"
91 /* </CMT Additions> */
95 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
104 const double Editor::timebar_height = 15.0;
106 #include "editor_xpms"
108 static const gchar *_snap_type_strings[] = {
132 static const gchar *_snap_mode_strings[] = {
138 static const gchar *_edit_point_strings[] = {
145 static const gchar *_zoom_focus_strings[] = {
155 /* Soundfile drag-n-drop */
157 Gdk::Cursor* Editor::cross_hair_cursor = 0;
158 Gdk::Cursor* Editor::selector_cursor = 0;
159 Gdk::Cursor* Editor::trimmer_cursor = 0;
160 Gdk::Cursor* Editor::grabber_cursor = 0;
161 Gdk::Cursor* Editor::zoom_cursor = 0;
162 Gdk::Cursor* Editor::time_fx_cursor = 0;
163 Gdk::Cursor* Editor::fader_cursor = 0;
164 Gdk::Cursor* Editor::speaker_cursor = 0;
165 Gdk::Cursor* Editor::wait_cursor = 0;
166 Gdk::Cursor* Editor::timebar_cursor = 0;
169 show_me_the_size (Requisition* r, const char* what)
171 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
176 /* time display buttons */
177 minsec_label (_("Mins:Secs")),
178 bbt_label (_("Bars:Beats")),
179 smpte_label (_("Timecode")),
180 frame_label (_("Frames")),
181 tempo_label (_("Tempo")),
182 meter_label (_("Meter")),
183 mark_label (_("Location Markers")),
184 range_mark_label (_("Range Markers")),
185 transport_mark_label (_("Loop/Punch Ranges")),
187 edit_packer (3, 3, false),
189 /* the values here don't matter: layout widgets
190 reset them as needed.
193 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
194 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
196 /* tool bar related */
198 edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
199 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
201 toolbar_selection_clock_table (2,3),
203 automation_mode_button (_("mode")),
204 global_automation_button (_("automation")),
206 /* <CMT Additions> */
207 image_socket_listener(0),
208 /* </CMT Additions> */
212 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
217 /* we are a singleton */
219 PublicEditor::_instance = this;
223 selection = new Selection;
224 cut_buffer = new Selection;
226 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
227 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
228 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
229 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
230 selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed));
232 clicked_regionview = 0;
233 clicked_trackview = 0;
234 clicked_audio_trackview = 0;
235 clicked_crossfadeview = 0;
236 clicked_control_point = 0;
237 latest_regionview = 0;
238 last_update_frame = 0;
240 current_mixer_strip = 0;
241 current_bbt_points = 0;
243 snap_type_strings = I18N (_snap_type_strings);
244 snap_mode_strings = I18N (_snap_mode_strings);
245 zoom_focus_strings = I18N (_zoom_focus_strings);
246 edit_point_strings = I18N (_edit_point_strings);
248 snap_type = SnapToFrame;
249 set_snap_to (snap_type);
251 snap_mode = SnapNormal;
252 set_snap_mode (snap_mode);
254 _edit_point = EditAtMouse;
255 set_edit_point_preference (_edit_point);
257 snap_threshold = 5.0;
258 bbt_beat_subdivision = 4;
261 autoscroll_active = false;
262 autoscroll_timeout_tag = -1;
263 interthread_progress_window = 0;
270 current_interthread_info = 0;
271 _show_measures = true;
272 _show_waveforms = true;
273 _show_waveforms_recording = true;
274 first_action_message = 0;
276 export_range_markers_dialog = 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;
301 region_edit_menu_split_item = 0;
303 region_edit_menu_split_multichannel_item = 0;
305 ignore_mouse_mode_toggle = false;
306 current_stepping_trackview = 0;
308 entered_regionview = 0;
310 clear_entered_track = false;
311 _new_regionviews_show_envelope = false;
312 current_timestretch = 0;
313 in_edit_group_row_change = false;
314 last_canvas_frame = 0;
316 button_release_can_deselect = true;
317 canvas_idle_queued = false;
318 _dragging_playhead = false;
319 _dragging_hscrollbar = false;
321 scrubbing_direction = 0;
324 ignore_route_order_sync = false;
326 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
327 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
328 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
329 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
330 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
332 range_marker_drag_rect = 0;
333 marker_drag_line = 0;
335 set_mouse_mode (MouseObject, true);
337 frames_per_unit = 2048; /* too early to use reset_zoom () */
338 reset_hscrollbar_stepping ();
340 zoom_focus = ZoomFocusLeft;
341 set_zoom_focus (ZoomFocusLeft);
342 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
344 initialize_rulers ();
345 initialize_canvas ();
347 edit_controls_vbox.set_spacing (0);
348 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
349 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
351 track_canvas.set_hadjustment (horizontal_adjustment);
352 track_canvas.set_vadjustment (vertical_adjustment);
353 time_canvas.set_hadjustment (horizontal_adjustment);
355 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
356 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
358 controls_layout.add (edit_controls_vbox);
359 controls_layout.set_name ("EditControlsBase");
360 controls_layout.add_events (Gdk::SCROLL_MASK);
361 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
363 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
364 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
365 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
367 edit_vscrollbar.set_adjustment (vertical_adjustment);
368 edit_hscrollbar.set_adjustment (horizontal_adjustment);
370 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
371 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
372 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
374 edit_hscrollbar.set_name ("EditorHScrollbar");
379 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
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) + 2);
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);
436 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
437 time_button_event_box.set_name ("TimebarLabelBase");
438 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
440 time_button_frame.add(time_button_event_box);
441 time_button_frame.property_shadow_type() = Gtk::SHADOW_OUT;
443 /* these enable us to have a dedicated window (for cursor setting, etc.)
444 for the canvas areas.
447 track_canvas_event_box.add (track_canvas);
449 time_canvas_event_box.add (time_canvas_vbox);
450 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
452 edit_packer.set_col_spacings (0);
453 edit_packer.set_row_spacings (0);
454 edit_packer.set_homogeneous (false);
455 edit_packer.set_border_width (0);
456 edit_packer.set_name ("EditorWindow");
458 edit_packer.attach (edit_vscrollbar, 0, 1, 1, 3, FILL, FILL|EXPAND, 0, 0);
460 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, FILL, 0, 0);
461 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
463 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
464 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
466 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
467 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
469 bottom_hbox.set_border_width (2);
470 bottom_hbox.set_spacing (3);
472 route_display_model = ListStore::create(route_display_columns);
473 route_list_display.set_model (route_display_model);
474 route_list_display.append_column (_("Show"), route_display_columns.visible);
475 route_list_display.append_column (_("Name"), route_display_columns.text);
476 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
477 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
478 route_list_display.set_headers_visible (true);
479 route_list_display.set_name ("TrackListDisplay");
480 route_list_display.get_selection()->set_mode (SELECTION_NONE);
481 route_list_display.set_reorderable (true);
482 route_list_display.set_size_request (100,-1);
484 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
485 route_list_visible_cell->property_activatable() = true;
486 route_list_visible_cell->property_radio() = false;
488 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
489 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
490 route_display_model->signal_rows_reordered().connect (mem_fun (*this, &Editor::track_list_reorder));
492 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
494 route_list_scroller.add (route_list_display);
495 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
497 group_model = ListStore::create(group_columns);
498 edit_group_display.set_model (group_model);
499 edit_group_display.append_column (_("Name"), group_columns.text);
500 edit_group_display.append_column (_("Active"), group_columns.is_active);
501 edit_group_display.append_column (_("Show"), group_columns.is_visible);
502 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
503 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
504 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
505 edit_group_display.get_column (0)->set_expand (true);
506 edit_group_display.get_column (1)->set_expand (false);
507 edit_group_display.get_column (2)->set_expand (false);
508 edit_group_display.set_headers_visible (true);
510 /* name is directly editable */
512 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
513 name_cell->property_editable() = true;
514 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
516 /* use checkbox for the active + visible columns */
518 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
519 active_cell->property_activatable() = true;
520 active_cell->property_radio() = false;
522 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
523 active_cell->property_activatable() = true;
524 active_cell->property_radio() = false;
526 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
528 edit_group_display.set_name ("EditGroupList");
529 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
530 edit_group_display.set_headers_visible (true);
531 edit_group_display.set_reorderable (false);
532 edit_group_display.set_rules_hint (true);
533 edit_group_display.set_size_request (75, -1);
535 edit_group_display_scroller.add (edit_group_display);
536 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
538 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
540 VBox* edit_group_display_packer = manage (new VBox());
541 HBox* edit_group_display_button_box = manage (new HBox());
542 edit_group_display_button_box->set_homogeneous (true);
544 Button* edit_group_add_button = manage (new Button ());
545 Button* edit_group_remove_button = manage (new Button ());
549 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
551 edit_group_add_button->add (*w);
553 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
555 edit_group_remove_button->add (*w);
557 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
558 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
560 edit_group_display_button_box->pack_start (*edit_group_add_button);
561 edit_group_display_button_box->pack_start (*edit_group_remove_button);
563 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
564 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
566 region_list_display.set_size_request (100, -1);
567 region_list_display.set_name ("RegionListDisplay");
569 region_list_model = TreeStore::create (region_list_columns);
570 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
571 region_list_model->set_sort_column (0, SORT_ASCENDING);
573 region_list_display.set_model (region_list_model);
574 region_list_display.append_column (_("Regions"), region_list_columns.name);
575 region_list_display.set_headers_visible (false);
577 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
579 TreeViewColumn* tv_col = region_list_display.get_column(0);
580 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
581 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
582 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
584 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
585 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
587 /* setup DnD handling */
589 list<TargetEntry> region_list_target_table;
591 region_list_target_table.push_back (TargetEntry ("text/plain"));
592 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
593 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
595 region_list_display.add_drop_targets (region_list_target_table);
596 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
598 region_list_scroller.add (region_list_display);
599 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
601 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
602 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
603 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
604 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
605 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
606 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
608 named_selection_scroller.add (named_selection_display);
609 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
611 named_selection_model = TreeStore::create (named_selection_columns);
612 named_selection_display.set_model (named_selection_model);
613 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
614 named_selection_display.set_headers_visible (false);
615 named_selection_display.set_size_request (100, -1);
616 named_selection_display.set_name ("NamedSelectionDisplay");
618 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
619 named_selection_display.set_size_request (100, -1);
620 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
621 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
622 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
626 snapshot_display_model = ListStore::create (snapshot_display_columns);
627 snapshot_display.set_model (snapshot_display_model);
628 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
629 snapshot_display.set_name ("SnapshotDisplay");
630 snapshot_display.set_size_request (75, -1);
631 snapshot_display.set_headers_visible (false);
632 snapshot_display.set_reorderable (false);
633 snapshot_display_scroller.add (snapshot_display);
634 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
636 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
637 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
641 nlabel = manage (new Label (_("Regions")));
642 nlabel->set_angle (-90);
643 the_notebook.append_page (region_list_scroller, *nlabel);
644 nlabel = manage (new Label (_("Tracks/Busses")));
645 nlabel->set_angle (-90);
646 the_notebook.append_page (route_list_scroller, *nlabel);
647 nlabel = manage (new Label (_("Snapshots")));
648 nlabel->set_angle (-90);
649 the_notebook.append_page (snapshot_display_scroller, *nlabel);
650 nlabel = manage (new Label (_("Edit Groups")));
651 nlabel->set_angle (-90);
652 the_notebook.append_page (*edit_group_display_packer, *nlabel);
653 nlabel = manage (new Label (_("Chunks")));
654 nlabel->set_angle (-90);
655 the_notebook.append_page (named_selection_scroller, *nlabel);
657 the_notebook.set_show_tabs (true);
658 the_notebook.set_scrollable (true);
659 the_notebook.popup_enable ();
660 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
662 post_maximal_editor_width = 0;
663 post_maximal_pane_position = 0;
664 edit_pane.pack1 (edit_packer, true, true);
665 edit_pane.pack2 (the_notebook, false, true);
667 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
669 top_hbox.pack_start (toolbar_frame, true, true);
671 HBox *hbox = manage (new HBox);
672 hbox->pack_start (edit_pane, true, true);
674 global_vpacker.pack_start (top_hbox, false, false);
675 global_vpacker.pack_start (*hbox, true, true);
677 global_hpacker.pack_start (global_vpacker, true, true);
679 set_name ("EditorWindow");
680 add_accel_group (ActionManager::ui_manager->get_accel_group());
682 status_bar_hpacker.show ();
684 vpacker.pack_end (status_bar_hpacker, false, false);
685 vpacker.pack_end (global_hpacker, true, true);
687 /* register actions now so that set_state() can find them and set toggles/checks etc */
691 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
694 _playlist_selector = new PlaylistSelector();
695 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
697 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
701 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
702 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
704 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
705 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
707 nudge_forward_button.set_name ("TransportButton");
708 nudge_backward_button.set_name ("TransportButton");
710 fade_context_menu.set_name ("ArdourContextMenu");
712 /* icons, titles, WM stuff */
714 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
715 Glib::RefPtr<Gdk::Pixbuf> icon;
717 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
718 window_icons.push_back (icon);
720 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
721 window_icons.push_back (icon);
723 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
724 window_icons.push_back (icon);
726 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
727 window_icons.push_back (icon);
729 if (!window_icons.empty()) {
730 set_icon_list (window_icons);
731 set_default_icon_list (window_icons);
734 WindowTitle title(Glib::get_application_name());
735 title += _("Editor");
736 set_title (title.get_string());
737 set_wmclass (X_("ardour_editor"), "Ardour");
740 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
742 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
743 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
745 /* allow external control surfaces/protocols to do various things */
747 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
748 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
749 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
750 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
752 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
753 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
761 /* <CMT Additions> */
762 if(image_socket_listener)
764 if(image_socket_listener->is_connected())
766 image_socket_listener->close_connection() ;
769 delete image_socket_listener ;
770 image_socket_listener = 0 ;
772 /* </CMT Additions> */
776 Editor::add_toplevel_controls (Container& cont)
778 vpacker.pack_start (cont, false, false);
783 Editor::catch_vanishing_regionview (RegionView *rv)
785 /* note: the selection will take care of the vanishing
786 audioregionview by itself.
789 if (clicked_regionview == rv) {
790 clicked_regionview = 0;
793 if (entered_regionview == rv) {
794 set_entered_regionview (0);
799 Editor::set_entered_regionview (RegionView* rv)
801 if (rv == entered_regionview) {
805 if (entered_regionview) {
806 entered_regionview->exited ();
809 if ((entered_regionview = rv) != 0) {
810 entered_regionview->entered ();
815 Editor::set_entered_track (TimeAxisView* tav)
818 entered_track->exited ();
821 if ((entered_track = tav) != 0) {
822 entered_track->entered ();
827 Editor::show_window ()
832 /* now reset all audio_time_axis heights, because widgets might need
838 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
839 tv = (static_cast<TimeAxisView*>(*i));
845 Editor::tie_vertical_scrolling ()
847 double y1 = vertical_adjustment.get_value();
849 playhead_cursor->set_y_axis (y1);
851 logo_item->property_y() = y1;
854 controls_layout.get_vadjustment()->set_value (y1);
857 /* the way idle updates and immediate window flushing work on GTK-Quartz
858 requires that we force an immediate redraw right here. The controls
859 layout will do the same all by itself, as does the canvas widget, but
860 most of the time, the canvas itself hasn't updated itself because its
861 idle handler hasn't run. consequently, the call that its layout makes
862 to gdk_window_process_updates() finds nothing to do. here, we force
863 the update to happen, then request a flush of the new window state.
865 track_canvas.update_now ();
866 gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
871 Editor::instant_save ()
873 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
878 session->add_instant_xml(get_state(), session->path());
880 Config->add_instant_xml(get_state(), get_user_ardour_path());
885 Editor::edit_cursor_clock_changed()
890 Editor::zoom_adjustment_changed ()
896 double fpu = zoom_range_clock.current_duration() / canvas_width;
900 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
901 } else if (fpu > session->current_end_frame() / canvas_width) {
902 fpu = session->current_end_frame() / canvas_width;
903 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
910 Editor::control_scroll (float fraction)
912 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
918 double step = fraction * current_page_frames();
921 _control_scroll_target is an optional<T>
923 it acts like a pointer to an nframes_t, with
924 a operator conversion to boolean to check
925 that it has a value could possibly use
926 playhead_cursor->current_frame to store the
927 value and a boolean in the class to know
928 when it's out of date
931 if (!_control_scroll_target) {
932 _control_scroll_target = session->transport_frame();
933 _dragging_playhead = true;
936 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
937 *_control_scroll_target = 0;
938 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
939 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
941 *_control_scroll_target += (nframes_t) floor (step);
944 /* move visuals, we'll catch up with it later */
946 playhead_cursor->set_position (*_control_scroll_target);
947 UpdateAllTransportClocks (*_control_scroll_target);
949 if (*_control_scroll_target > (current_page_frames() / 2)) {
950 /* try to center PH in window */
951 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
957 Now we do a timeout to actually bring the session to the right place
958 according to the playhead. This is to avoid reading disk buffers on every
959 call to control_scroll, which is driven by ScrollTimeline and therefore
960 probably by a control surface wheel which can generate lots of events.
962 /* cancel the existing timeout */
964 control_scroll_connection.disconnect ();
966 /* add the next timeout */
968 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
972 Editor::deferred_control_scroll (nframes_t target)
974 session->request_locate (*_control_scroll_target, session->transport_rolling());
975 // reset for next stream
976 _control_scroll_target = boost::none;
977 _dragging_playhead = false;
982 Editor::on_realize ()
984 Window::on_realize ();
989 Editor::start_scrolling ()
991 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
992 (mem_fun(*this, &Editor::update_current_screen));
996 Editor::stop_scrolling ()
998 scroll_connection.disconnect ();
1002 Editor::map_position_change (nframes_t frame)
1004 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1006 if (session == 0 || !_follow_playhead) {
1010 center_screen (frame);
1011 playhead_cursor->set_position (frame);
1015 Editor::center_screen (nframes_t frame)
1017 double page = canvas_width * frames_per_unit;
1019 /* if we're off the page, then scroll.
1022 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1023 center_screen_internal (frame, page);
1028 Editor::center_screen_internal (nframes_t frame, float page)
1033 frame -= (nframes_t) page;
1038 reset_x_origin (frame);
1042 Editor::handle_new_duration ()
1044 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1046 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1048 if (new_end > last_canvas_frame) {
1049 last_canvas_frame = new_end;
1050 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1051 reset_scrolling_region ();
1054 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1058 Editor::update_title_s (const string & snap_name)
1060 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1066 Editor::update_title ()
1068 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1071 bool dirty = session->dirty();
1073 string session_name;
1075 if (session->snap_name() != session->name()) {
1076 session_name = session->snap_name();
1078 session_name = session->name();
1082 session_name = "*" + session_name;
1085 WindowTitle title(session_name);
1086 title += Glib::get_application_name();
1087 set_title (title.get_string());
1092 Editor::connect_to_session (Session *t)
1096 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1099 /* catch up with the playhead */
1101 session->request_locate (playhead_cursor->current_frame);
1103 if (first_action_message) {
1104 first_action_message->hide();
1109 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1110 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1112 /* These signals can all be emitted by a non-GUI thread. Therefore the
1113 handlers for them must not attempt to directly interact with the GUI,
1114 but use Gtkmm2ext::UI::instance()->call_slot();
1117 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1118 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1119 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1120 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::handle_new_audio_region)));
1121 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed)));
1122 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1123 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1124 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1125 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1126 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1127 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1128 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1129 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1130 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1132 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1134 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1136 edit_groups_changed ();
1138 edit_cursor_clock.set_session (session);
1139 zoom_range_clock.set_session (session);
1140 _playlist_selector->set_session (session);
1141 nudge_clock.set_session (session);
1144 if (analysis_window != 0)
1145 analysis_window->set_session (session);
1148 Location* loc = session->locations()->auto_loop_location();
1150 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1151 if (loc->start() == loc->end()) {
1152 loc->set_end (loc->start() + 1);
1154 session->locations()->add (loc, false);
1155 session->set_auto_loop_location (loc);
1158 loc->set_name (_("Loop"));
1161 loc = session->locations()->auto_punch_location();
1163 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1164 if (loc->start() == loc->end()) {
1165 loc->set_end (loc->start() + 1);
1167 session->locations()->add (loc, false);
1168 session->set_auto_punch_location (loc);
1171 loc->set_name (_("Punch"));
1174 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1176 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1178 refresh_location_display ();
1179 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1180 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1181 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1182 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1183 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1186 sfbrowser->set_session (session);
1189 handle_new_duration ();
1191 redisplay_regions ();
1192 redisplay_named_selections ();
1193 redisplay_snapshots ();
1195 initial_route_list_display ();
1197 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1198 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1201 restore_ruler_visibility ();
1202 //tempo_map_changed (Change (0));
1203 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1207 /* don't show master bus in a new session */
1209 if (ARDOUR_UI::instance()->session_is_new ()) {
1211 TreeModel::Children rows = route_display_model->children();
1212 TreeModel::Children::iterator i;
1214 no_route_list_redisplay = true;
1216 for (i = rows.begin(); i != rows.end(); ++i) {
1217 TimeAxisView *tv = (*i)[route_display_columns.tv];
1218 AudioTimeAxisView *atv;
1220 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1221 if (atv->route()->master()) {
1222 route_list_display.get_selection()->unselect (i);
1227 no_route_list_redisplay = false;
1228 redisplay_route_list ();
1231 /* register for undo history */
1233 session->register_with_memento_command_factory(_id, this);
1237 Editor::build_cursors ()
1239 using namespace Gdk;
1241 Gdk::Color mbg ("#000000" ); /* Black */
1242 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1245 RefPtr<Bitmap> source, mask;
1246 source = Bitmap::create (mag_bits, mag_width, mag_height);
1247 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1248 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1251 Gdk::Color fbg ("#ffffff" );
1252 Gdk::Color ffg ("#000000" );
1255 RefPtr<Bitmap> source, mask;
1257 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1258 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1259 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1263 RefPtr<Bitmap> source, mask;
1264 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1265 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1266 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1269 grabber_cursor = new Gdk::Cursor (HAND2);
1270 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1271 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1272 selector_cursor = new Gdk::Cursor (XTERM);
1273 time_fx_cursor = new Gdk::Cursor (SIZING);
1274 wait_cursor = new Gdk::Cursor (WATCH);
1275 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1279 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1281 using namespace Menu_Helpers;
1282 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1285 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1289 MenuList& items (fade_context_menu.items());
1293 switch (item_type) {
1295 case FadeInHandleItem:
1296 if (arv->audio_region()->fade_in_active()) {
1297 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1299 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1302 items.push_back (SeparatorElem());
1304 if (Profile->get_sae()) {
1305 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1306 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1308 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1309 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1310 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1311 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1312 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1317 case FadeOutHandleItem:
1318 if (arv->audio_region()->fade_out_active()) {
1319 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1321 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1324 items.push_back (SeparatorElem());
1326 if (Profile->get_sae()) {
1327 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1328 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1330 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1331 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1332 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1333 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1334 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1339 fatal << _("programming error: ")
1340 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1345 fade_context_menu.popup (button, time);
1349 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes_t frame)
1351 using namespace Menu_Helpers;
1352 Menu* (Editor::*build_menu_function)(nframes_t);
1355 switch (item_type) {
1357 case RegionViewName:
1358 case RegionViewNameHighlight:
1359 if (with_selection) {
1360 build_menu_function = &Editor::build_track_selection_context_menu;
1362 build_menu_function = &Editor::build_track_region_context_menu;
1367 if (with_selection) {
1368 build_menu_function = &Editor::build_track_selection_context_menu;
1370 build_menu_function = &Editor::build_track_context_menu;
1374 case CrossfadeViewItem:
1375 build_menu_function = &Editor::build_track_crossfade_context_menu;
1379 if (clicked_audio_trackview->get_diskstream()) {
1380 build_menu_function = &Editor::build_track_context_menu;
1382 build_menu_function = &Editor::build_track_bus_context_menu;
1387 /* probably shouldn't happen but if it does, we don't care */
1391 menu = (this->*build_menu_function)(frame);
1392 menu->set_name ("ArdourContextMenu");
1394 /* now handle specific situations */
1396 switch (item_type) {
1398 case RegionViewName:
1399 case RegionViewNameHighlight:
1400 if (!with_selection) {
1401 if (region_edit_menu_split_item) {
1402 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1403 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1405 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1409 if (region_edit_menu_split_multichannel_item) {
1410 if (clicked_regionview && clicked_regionview->region().n_channels() > 1) {
1411 // GTK2FIX find the action, change its sensitivity
1412 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1414 // GTK2FIX see above
1415 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1424 case CrossfadeViewItem:
1431 /* probably shouldn't happen but if it does, we don't care */
1435 if (item_type != SelectionItem && clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1437 /* Bounce to disk */
1439 using namespace Menu_Helpers;
1440 MenuList& edit_items = menu->items();
1442 edit_items.push_back (SeparatorElem());
1444 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1445 case AudioTrack::NoFreeze:
1446 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1449 case AudioTrack::Frozen:
1450 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1453 case AudioTrack::UnFrozen:
1454 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1460 menu->popup (button, time);
1464 Editor::build_track_context_menu (nframes_t ignored)
1466 using namespace Menu_Helpers;
1468 MenuList& edit_items = track_context_menu.items();
1471 add_dstream_context_items (edit_items);
1472 return &track_context_menu;
1476 Editor::build_track_bus_context_menu (nframes_t ignored)
1478 using namespace Menu_Helpers;
1480 MenuList& edit_items = track_context_menu.items();
1483 add_bus_context_items (edit_items);
1484 return &track_context_menu;
1488 Editor::build_track_region_context_menu (nframes_t frame)
1490 using namespace Menu_Helpers;
1491 MenuList& edit_items = track_region_context_menu.items();
1494 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1497 boost::shared_ptr<Diskstream> ds;
1498 boost::shared_ptr<Playlist> pl;
1500 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1501 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)frame * ds->speed()));
1502 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1503 add_region_context_items (atv->audio_view(), (*i), edit_items);
1509 add_dstream_context_items (edit_items);
1511 return &track_region_context_menu;
1515 Editor::build_track_crossfade_context_menu (nframes_t frame)
1517 using namespace Menu_Helpers;
1518 MenuList& edit_items = track_crossfade_context_menu.items();
1519 edit_items.clear ();
1521 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1524 boost::shared_ptr<Diskstream> ds;
1525 boost::shared_ptr<Playlist> pl;
1526 boost::shared_ptr<AudioPlaylist> apl;
1528 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1530 Playlist::RegionList* regions = pl->regions_at (frame);
1531 AudioPlaylist::Crossfades xfades;
1533 apl->crossfades_at (frame, xfades);
1535 bool many = xfades.size() > 1;
1537 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1538 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1541 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1542 add_region_context_items (atv->audio_view(), (*i), edit_items);
1549 add_dstream_context_items (edit_items);
1551 return &track_crossfade_context_menu;
1556 Editor::analyze_region_selection()
1558 if (analysis_window == 0) {
1559 analysis_window = new AnalysisWindow();
1562 analysis_window->set_session(session);
1564 analysis_window->show_all();
1567 analysis_window->set_regionmode();
1568 analysis_window->analyze();
1570 analysis_window->present();
1574 Editor::analyze_range_selection()
1576 if (analysis_window == 0) {
1577 analysis_window = new AnalysisWindow();
1580 analysis_window->set_session(session);
1582 analysis_window->show_all();
1585 analysis_window->set_rangemode();
1586 analysis_window->analyze();
1588 analysis_window->present();
1590 #endif /* FFT_ANALYSIS */
1595 Editor::build_track_selection_context_menu (nframes_t ignored)
1597 using namespace Menu_Helpers;
1598 MenuList& edit_items = track_selection_context_menu.items();
1599 edit_items.clear ();
1601 add_selection_context_items (edit_items);
1602 // edit_items.push_back (SeparatorElem());
1603 // add_dstream_context_items (edit_items);
1605 return &track_selection_context_menu;
1609 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1611 using namespace Menu_Helpers;
1612 Menu *xfade_menu = manage (new Menu);
1613 MenuList& items = xfade_menu->items();
1614 xfade_menu->set_name ("ArdourContextMenu");
1617 if (xfade->active()) {
1623 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1624 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1626 if (xfade->can_follow_overlap()) {
1628 if (xfade->following_overlap()) {
1629 str = _("Convert to short");
1631 str = _("Convert to full");
1634 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1638 str = xfade->out()->name();
1640 str += xfade->in()->name();
1642 str = _("Crossfade");
1645 edit_items.push_back (MenuElem (str, *xfade_menu));
1646 edit_items.push_back (SeparatorElem());
1650 Editor::xfade_edit_left_region ()
1652 if (clicked_crossfadeview) {
1653 clicked_crossfadeview->left_view.show_region_editor ();
1658 Editor::xfade_edit_right_region ()
1660 if (clicked_crossfadeview) {
1661 clicked_crossfadeview->right_view.show_region_editor ();
1666 Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region> region, Menu_Helpers::MenuList& edit_items)
1668 using namespace Menu_Helpers;
1669 Menu *region_menu = manage (new Menu);
1670 MenuList& items = region_menu->items();
1671 region_menu->set_name ("ArdourContextMenu");
1673 boost::shared_ptr<AudioRegion> ar;
1676 ar = boost::dynamic_pointer_cast<AudioRegion> (region);
1679 /* when this particular menu pops up, make the relevant region
1683 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr<Region>(region)));
1685 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1686 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1687 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1688 items.push_back (SeparatorElem());
1689 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_point)));
1690 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1691 items.push_back (SeparatorElem());
1693 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1694 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1695 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1698 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1701 items.push_back (SeparatorElem());
1703 sigc::connection fooc;
1705 items.push_back (CheckMenuElem (_("Lock")));
1706 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1707 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1708 if (region->locked()) {
1710 region_lock_item->set_active();
1713 items.push_back (CheckMenuElem (_("Mute")));
1714 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1715 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1716 if (region->muted()) {
1718 region_mute_item->set_active();
1722 if (!Profile->get_sae()) {
1723 items.push_back (CheckMenuElem (_("Opaque")));
1724 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1725 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1726 if (region->opaque()) {
1728 region_opaque_item->set_active();
1733 items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1734 if (region->at_natural_position()) {
1735 items.back().set_sensitive (false);
1738 items.push_back (SeparatorElem());
1742 RegionView* rv = sv->find_view (ar);
1743 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1745 if (!Profile->get_sae()) {
1746 items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1748 items.push_back (CheckMenuElem (_("Envelope Visible")));
1749 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1750 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1751 if (arv->envelope_visible()) {
1753 region_envelope_visible_item->set_active (true);
1757 items.push_back (CheckMenuElem (_("Envelope Active")));
1758 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1759 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1761 if (ar->envelope_active()) {
1763 region_envelope_active_item->set_active (true);
1767 items.push_back (SeparatorElem());
1770 if (ar->scale_amplitude() != 1.0f) {
1771 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1773 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1777 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1778 items.push_back (SeparatorElem());
1780 /* range related stuff */
1782 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
1783 items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)));
1784 items.push_back (SeparatorElem());
1788 Menu *nudge_menu = manage (new Menu());
1789 MenuList& nudge_items = nudge_menu->items();
1790 nudge_menu->set_name ("ArdourContextMenu");
1792 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1793 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1794 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1795 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1797 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1798 items.push_back (SeparatorElem());
1800 Menu *trim_menu = manage (new Menu);
1801 MenuList& trim_items = trim_menu->items();
1802 trim_menu->set_name ("ArdourContextMenu");
1804 trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point)));
1805 trim_items.push_back (MenuElem (_("Edit point to end"), mem_fun(*this, &Editor::trim_region_to_edit_point)));
1807 items.push_back (MenuElem (_("Trim"), *trim_menu));
1808 items.push_back (SeparatorElem());
1810 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1811 region_edit_menu_split_item = &items.back();
1813 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1814 region_edit_menu_split_multichannel_item = &items.back();
1816 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1817 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1818 items.push_back (SeparatorElem());
1819 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1821 /* OK, stick the region submenu at the top of the list, and then add
1825 /* we have to hack up the region name because "_" has a special
1826 meaning for menu titles.
1829 string::size_type pos = 0;
1830 string menu_item_name = region->name();
1832 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1833 menu_item_name.replace (pos, 1, "__");
1837 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1838 edit_items.push_back (SeparatorElem());
1842 Editor::add_selection_context_items (Menu_Helpers::MenuList& items)
1844 using namespace Menu_Helpers;
1846 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1847 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1850 items.push_back (SeparatorElem());
1851 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1854 items.push_back (SeparatorElem());
1855 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1856 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1858 items.push_back (SeparatorElem());
1859 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1860 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1862 items.push_back (SeparatorElem());
1863 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1865 items.push_back (SeparatorElem());
1866 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1867 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1869 items.push_back (SeparatorElem());
1870 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1871 items.push_back (SeparatorElem());
1872 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1873 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1874 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1875 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1876 items.push_back (SeparatorElem());
1877 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1878 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1882 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1884 using namespace Menu_Helpers;
1888 Menu *play_menu = manage (new Menu);
1889 MenuList& play_items = play_menu->items();
1890 play_menu->set_name ("ArdourContextMenu");
1892 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
1893 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1894 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1895 play_items.push_back (SeparatorElem());
1896 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1898 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1902 Menu *select_menu = manage (new Menu);
1903 MenuList& select_items = select_menu->items();
1904 select_menu->set_name ("ArdourContextMenu");
1906 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1907 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1908 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1909 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1910 select_items.push_back (SeparatorElem());
1911 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1912 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1913 select_items.push_back (SeparatorElem());
1914 select_items.push_back (MenuElem (_("Select all after edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1915 select_items.push_back (MenuElem (_("Select all before edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1916 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1917 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1918 select_items.push_back (MenuElem (_("Select all between cursors"), mem_fun(*this, &Editor::select_all_selectables_between)));
1919 select_items.push_back (SeparatorElem());
1921 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1925 Menu *cutnpaste_menu = manage (new Menu);
1926 MenuList& cutnpaste_items = cutnpaste_menu->items();
1927 cutnpaste_menu->set_name ("ArdourContextMenu");
1929 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1930 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1931 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1933 cutnpaste_items.push_back (SeparatorElem());
1935 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1936 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1938 cutnpaste_items.push_back (SeparatorElem());
1940 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1942 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1944 /* Adding new material */
1946 edit_items.push_back (SeparatorElem());
1947 edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1948 edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1952 Menu *nudge_menu = manage (new Menu());
1953 MenuList& nudge_items = nudge_menu->items();
1954 nudge_menu->set_name ("ArdourContextMenu");
1956 edit_items.push_back (SeparatorElem());
1957 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1958 nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1959 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1960 nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1962 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1966 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1968 using namespace Menu_Helpers;
1972 Menu *play_menu = manage (new Menu);
1973 MenuList& play_items = play_menu->items();
1974 play_menu->set_name ("ArdourContextMenu");
1976 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
1977 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1978 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1982 Menu *select_menu = manage (new Menu);
1983 MenuList& select_items = select_menu->items();
1984 select_menu->set_name ("ArdourContextMenu");
1986 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1987 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1988 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1989 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1990 select_items.push_back (SeparatorElem());
1991 select_items.push_back (MenuElem (_("Select all after edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1992 select_items.push_back (MenuElem (_("Select all before edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1993 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1994 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1996 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2000 Menu *cutnpaste_menu = manage (new Menu);
2001 MenuList& cutnpaste_items = cutnpaste_menu->items();
2002 cutnpaste_menu->set_name ("ArdourContextMenu");
2004 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2005 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2006 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2008 Menu *nudge_menu = manage (new Menu());
2009 MenuList& nudge_items = nudge_menu->items();
2010 nudge_menu->set_name ("ArdourContextMenu");
2012 edit_items.push_back (SeparatorElem());
2013 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2014 nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2015 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2016 nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2018 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2021 /* CURSOR SETTING AND MARKS AND STUFF */
2024 Editor::set_snap_to (SnapType st)
2027 string str = snap_type_strings[(int) st];
2029 if (str != snap_type_selector.get_active_text()) {
2030 snap_type_selector.set_active_text (str);
2035 switch (snap_type) {
2036 case SnapToAThirtysecondBeat:
2037 case SnapToASixteenthBeat:
2038 case SnapToAEighthBeat:
2039 case SnapToAQuarterBeat:
2040 case SnapToAThirdBeat:
2041 update_tempo_based_rulers ();
2049 Editor::set_snap_mode (SnapMode mode)
2052 string str = snap_mode_strings[(int)mode];
2054 if (str != snap_mode_selector.get_active_text ()) {
2055 snap_mode_selector.set_active_text (str);
2061 Editor::set_edit_point_preference (EditPoint ep)
2064 string str = edit_point_strings[(int)ep];
2066 if (str != edit_point_selector.get_active_text ()) {
2067 edit_point_selector.set_active_text (str);
2074 Editor::set_state (const XMLNode& node)
2076 const XMLProperty* prop;
2078 int x, y, xoff, yoff;
2081 if ((prop = node.property ("id")) != 0) {
2082 _id = prop->value ();
2085 if ((geometry = find_named_node (node, "geometry")) == 0) {
2087 g.base_width = default_width;
2088 g.base_height = default_height;
2096 g.base_width = atoi(geometry->property("x_size")->value());
2097 g.base_height = atoi(geometry->property("y_size")->value());
2098 x = atoi(geometry->property("x_pos")->value());
2099 y = atoi(geometry->property("y_pos")->value());
2100 xoff = atoi(geometry->property("x_off")->value());
2101 yoff = atoi(geometry->property("y_off")->value());
2104 set_default_size (g.base_width, g.base_height);
2107 if (session && (prop = node.property ("playhead"))) {
2108 nframes_t pos = atol (prop->value().c_str());
2109 playhead_cursor->set_position (pos);
2111 playhead_cursor->set_position (0);
2113 /* reset_x_origin() doesn't work right here, since the old
2114 position may be zero already, and it does nothing in such
2119 horizontal_adjustment.set_value (0);
2122 if ((prop = node.property ("mixer-width"))) {
2123 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2126 if ((prop = node.property ("zoom-focus"))) {
2127 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2130 if ((prop = node.property ("zoom"))) {
2131 reset_zoom (PBD::atof (prop->value()));
2134 if ((prop = node.property ("snap-to"))) {
2135 set_snap_to ((SnapType) atoi (prop->value()));
2138 if ((prop = node.property ("snap-mode"))) {
2139 set_snap_mode ((SnapMode) atoi (prop->value()));
2142 if ((prop = node.property ("edit-point"))) {
2143 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point));
2146 if ((prop = node.property ("mouse-mode"))) {
2147 MouseMode m = str2mousemode(prop->value());
2148 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2149 set_mouse_mode (m, true);
2151 mouse_mode = MouseGain; /* lie, to force the mode switch */
2152 set_mouse_mode (MouseObject, true);
2155 if ((prop = node.property ("show-waveforms"))) {
2156 bool yn = (prop->value() == "yes");
2157 _show_waveforms = !yn;
2158 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2160 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2161 /* do it twice to force the change */
2162 tact->set_active (!yn);
2163 tact->set_active (yn);
2167 if ((prop = node.property ("show-waveforms-recording"))) {
2168 bool yn = (prop->value() == "yes");
2169 _show_waveforms_recording = !yn;
2170 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2172 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2173 /* do it twice to force the change */
2174 tact->set_active (!yn);
2175 tact->set_active (yn);
2179 if ((prop = node.property ("show-measures"))) {
2180 bool yn = (prop->value() == "yes");
2181 _show_measures = !yn;
2182 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2184 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2185 /* do it twice to force the change */
2186 tact->set_active (!yn);
2187 tact->set_active (yn);
2191 if ((prop = node.property ("follow-playhead"))) {
2192 bool yn = (prop->value() == "yes");
2193 set_follow_playhead (yn);
2194 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2196 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2197 if (tact->get_active() != yn) {
2198 tact->set_active (yn);
2203 if ((prop = node.property ("region-list-sort-type"))) {
2204 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2205 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2208 if ((prop = node.property ("xfades-visible"))) {
2209 bool yn = (prop->value() == "yes");
2210 _xfade_visibility = !yn;
2211 // set_xfade_visibility (yn);
2214 if ((prop = node.property ("show-editor-mixer"))) {
2216 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2219 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2220 bool yn = (prop->value() == X_("yes"));
2222 /* do it twice to force the change */
2224 tact->set_active (!yn);
2225 tact->set_active (yn);
2234 Editor::get_state ()
2236 XMLNode* node = new XMLNode ("Editor");
2239 _id.print (buf, sizeof (buf));
2240 node->add_property ("id", buf);
2242 if (is_realized()) {
2243 Glib::RefPtr<Gdk::Window> win = get_window();
2245 int x, y, xoff, yoff, width, height;
2246 win->get_root_origin(x, y);
2247 win->get_position(xoff, yoff);
2248 win->get_size(width, height);
2250 XMLNode* geometry = new XMLNode ("geometry");
2252 snprintf(buf, sizeof(buf), "%d", width);
2253 geometry->add_property("x_size", string(buf));
2254 snprintf(buf, sizeof(buf), "%d", height);
2255 geometry->add_property("y_size", string(buf));
2256 snprintf(buf, sizeof(buf), "%d", x);
2257 geometry->add_property("x_pos", string(buf));
2258 snprintf(buf, sizeof(buf), "%d", y);
2259 geometry->add_property("y_pos", string(buf));
2260 snprintf(buf, sizeof(buf), "%d", xoff);
2261 geometry->add_property("x_off", string(buf));
2262 snprintf(buf, sizeof(buf), "%d", yoff);
2263 geometry->add_property("y_off", string(buf));
2264 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2265 geometry->add_property("edit_pane_pos", string(buf));
2267 node->add_child_nocopy (*geometry);
2270 maybe_add_mixer_strip_width (*node);
2272 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2273 node->add_property ("zoom-focus", buf);
2274 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2275 node->add_property ("zoom", buf);
2276 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2277 node->add_property ("snap-to", buf);
2278 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2279 node->add_property ("snap-mode", buf);
2281 node->add_property ("edit-point", enum_2_string (_edit_point));
2283 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2284 node->add_property ("playhead", buf);
2286 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2287 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2288 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2289 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2290 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2291 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2292 node->add_property ("mouse-mode", enum2str(mouse_mode));
2294 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2296 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2297 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2306 Editor::trackview_by_y_position (double y)
2308 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2312 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2321 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2323 Location* before = 0;
2324 Location* after = 0;
2330 const nframes64_t one_second = session->frame_rate();
2331 const nframes64_t one_minute = session->frame_rate() * 60;
2332 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2333 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2334 nframes64_t presnap = start;
2336 switch (snap_type) {
2342 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2344 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2348 case SnapToSMPTEFrame:
2349 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2350 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2352 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2356 case SnapToSMPTESeconds:
2357 if (session->smpte_offset_negative())
2359 start += session->smpte_offset ();
2361 start -= session->smpte_offset ();
2363 if (start % one_smpte_second > one_smpte_second / 2) {
2364 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2366 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2369 if (session->smpte_offset_negative())
2371 start -= session->smpte_offset ();
2373 start += session->smpte_offset ();
2377 case SnapToSMPTEMinutes:
2378 if (session->smpte_offset_negative())
2380 start += session->smpte_offset ();
2382 start -= session->smpte_offset ();
2384 if (start % one_smpte_minute > one_smpte_minute / 2) {
2385 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2387 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2389 if (session->smpte_offset_negative())
2391 start -= session->smpte_offset ();
2393 start += session->smpte_offset ();
2398 if (start % one_second > one_second / 2) {
2399 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2401 start = (nframes_t) floor ((double) start / one_second) * one_second;
2406 if (start % one_minute > one_minute / 2) {
2407 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2409 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2414 start = session->tempo_map().round_to_bar (start, direction);
2418 start = session->tempo_map().round_to_beat (start, direction);
2421 case SnapToAThirtysecondBeat:
2422 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2425 case SnapToASixteenthBeat:
2426 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2429 case SnapToAEighthBeat:
2430 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2433 case SnapToAQuarterBeat:
2434 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2437 case SnapToAThirdBeat:
2438 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2441 case SnapToEditPoint:
2442 start = get_preferred_edit_position ();
2450 before = session->locations()->first_location_before (start);
2451 after = session->locations()->first_location_after (start);
2453 if (direction < 0) {
2455 start = before->start();
2459 } else if (direction > 0) {
2461 start = after->start();
2463 start = session->current_end_frame();
2468 /* find nearest of the two */
2469 if ((start - before->start()) < (after->start() - start)) {
2470 start = before->start();
2472 start = after->start();
2475 start = before->start();
2478 start = after->start();
2485 case SnapToRegionStart:
2486 case SnapToRegionEnd:
2487 case SnapToRegionSync:
2488 case SnapToRegionBoundary:
2489 if (!region_boundary_cache.empty()) {
2490 vector<nframes_t>::iterator i;
2492 if (direction > 0) {
2493 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2495 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2498 if (i != region_boundary_cache.end()) {
2501 start = region_boundary_cache.back();
2507 switch (snap_mode) {
2513 if (presnap > start) {
2514 if (presnap > (start + unit_to_frame(snap_threshold))) {
2518 } else if (presnap < start) {
2519 if (presnap < (start - unit_to_frame(snap_threshold))) {
2531 Editor::setup_toolbar ()
2535 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2538 /* Mode Buttons (tool selection) */
2540 vector<ToggleButton *> mouse_mode_buttons;
2542 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2543 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2544 mouse_mode_buttons.push_back (&mouse_move_button);
2545 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2546 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2547 mouse_mode_buttons.push_back (&mouse_select_button);
2548 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2549 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2550 mouse_mode_buttons.push_back (&mouse_gain_button);
2551 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2552 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2553 mouse_mode_buttons.push_back (&mouse_zoom_button);
2554 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2555 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2556 mouse_mode_buttons.push_back (&mouse_timefx_button);
2557 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2558 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2559 mouse_mode_buttons.push_back (&mouse_audition_button);
2561 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2563 HBox* mode_box = manage(new HBox);
2564 mode_box->set_border_width (2);
2565 mode_box->set_spacing(4);
2566 mouse_mode_button_box.set_spacing(1);
2567 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2568 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2569 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2570 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2571 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2572 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2573 mouse_mode_button_box.set_homogeneous(true);
2575 vector<string> edit_mode_strings;
2576 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2577 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2579 edit_mode_selector.set_name ("EditModeSelector");
2580 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2581 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2582 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2584 mode_box->pack_start(edit_mode_selector);
2585 mode_box->pack_start(mouse_mode_button_box);
2587 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2588 mouse_mode_tearoff->set_name ("MouseModeBase");
2590 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2591 &mouse_mode_tearoff->tearoff_window()));
2592 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2593 &mouse_mode_tearoff->tearoff_window(), 1));
2594 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2595 &mouse_mode_tearoff->tearoff_window()));
2596 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2597 &mouse_mode_tearoff->tearoff_window(), 1));
2599 mouse_move_button.set_name ("MouseModeButton");
2600 mouse_select_button.set_name ("MouseModeButton");
2601 mouse_gain_button.set_name ("MouseModeButton");
2602 mouse_zoom_button.set_name ("MouseModeButton");
2603 mouse_timefx_button.set_name ("MouseModeButton");
2604 mouse_audition_button.set_name ("MouseModeButton");
2606 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2607 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2608 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2609 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2610 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2611 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2613 mouse_move_button.unset_flags (CAN_FOCUS);
2614 mouse_select_button.unset_flags (CAN_FOCUS);
2615 mouse_gain_button.unset_flags (CAN_FOCUS);
2616 mouse_zoom_button.unset_flags (CAN_FOCUS);
2617 mouse_timefx_button.unset_flags (CAN_FOCUS);
2618 mouse_audition_button.unset_flags (CAN_FOCUS);
2620 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2621 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2623 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2624 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2625 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2626 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2627 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2629 // mouse_move_button.set_active (true);
2634 zoom_box.set_spacing (1);
2635 zoom_box.set_border_width (2);
2637 zoom_in_button.set_name ("EditorTimeButton");
2638 zoom_in_button.set_size_request(-1,16);
2639 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2640 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2641 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2643 zoom_out_button.set_name ("EditorTimeButton");
2644 zoom_out_button.set_size_request(-1,16);
2645 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2646 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2647 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2649 zoom_out_full_button.set_name ("EditorTimeButton");
2650 zoom_out_full_button.set_size_request(-1,16);
2651 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2652 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2653 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2655 zoom_focus_selector.set_name ("ZoomFocusSelector");
2656 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Playhead", FUDGE, 0);
2657 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2658 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2659 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2661 zoom_box.pack_start (zoom_focus_selector, true, true);
2662 zoom_box.pack_start (zoom_out_button, false, false);
2663 zoom_box.pack_start (zoom_in_button, false, false);
2664 zoom_box.pack_start (zoom_out_full_button, false, false);
2666 snap_box.set_spacing (1);
2667 snap_box.set_border_width (2);
2669 snap_type_selector.set_name ("SnapTypeSelector");
2670 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2671 set_popdown_strings (snap_type_selector, snap_type_strings);
2672 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2673 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
2675 snap_mode_selector.set_name ("SnapModeSelector");
2676 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2677 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2678 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2679 ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2681 edit_point_selector.set_name ("SnapModeSelector");
2682 Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, "Playhead", 2+FUDGE, 10);
2683 set_popdown_strings (edit_point_selector, edit_point_strings);
2684 edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
2685 ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
2687 snap_box.pack_start (edit_cursor_clock, false, false);
2688 snap_box.pack_start (snap_mode_selector, false, false);
2689 snap_box.pack_start (snap_type_selector, false, false);
2690 snap_box.pack_start (edit_point_selector, false, false);
2694 HBox *nudge_box = manage (new HBox);
2695 nudge_box->set_spacing(1);
2696 nudge_box->set_border_width (2);
2698 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2699 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2701 nudge_box->pack_start (nudge_backward_button, false, false);
2702 nudge_box->pack_start (nudge_forward_button, false, false);
2703 nudge_box->pack_start (nudge_clock, false, false);
2706 /* Pack everything in... */
2708 HBox* hbox = new HBox;
2709 hbox->set_spacing(10);
2711 tools_tearoff = new TearOff (*hbox);
2712 tools_tearoff->set_name ("MouseModeBase");
2714 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2715 &tools_tearoff->tearoff_window()));
2716 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2717 &tools_tearoff->tearoff_window(), 0));
2718 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2719 &tools_tearoff->tearoff_window()));
2720 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2721 &tools_tearoff->tearoff_window(), 0));
2723 toolbar_hbox.set_spacing (10);
2724 toolbar_hbox.set_border_width (1);
2726 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2727 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2730 hbox->pack_start (snap_box, false, false);
2731 // hbox->pack_start (zoom_box, false, false);
2732 hbox->pack_start (*nudge_box, false, false);
2736 toolbar_base.set_name ("ToolBarBase");
2737 toolbar_base.add (toolbar_hbox);
2739 toolbar_frame.set_shadow_type (SHADOW_OUT);
2740 toolbar_frame.set_name ("BaseFrame");
2741 toolbar_frame.add (toolbar_base);
2745 Editor::convert_drop_to_paths (vector<ustring>& paths,
2746 const RefPtr<Gdk::DragContext>& context,
2749 const SelectionData& data,
2758 vector<ustring> uris = data.get_uris();
2762 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2763 are actually URI lists. So do it by hand.
2766 if (data.get_target() != "text/plain") {
2770 /* Parse the "uri-list" format that Nautilus provides,
2771 where each pathname is delimited by \r\n
2774 const char* p = data.get_text().c_str();
2781 while (g_ascii_isspace (*p))
2785 while (*q && (*q != '\n') && (*q != '\r'))
2791 while (q > p && g_ascii_isspace (*q))
2796 uris.push_back (ustring (p, q - p + 1));
2800 p = strchr (p, '\n');
2810 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2812 if ((*i).substr (0,7) == "file://") {
2816 PBD::url_decode (p);
2818 // scan forward past three slashes
2820 ustring::size_type slashcnt = 0;
2821 ustring::size_type n = 0;
2822 ustring::iterator x = p.begin();
2824 while (slashcnt < 3 && x != p.end()) {
2827 } else if (slashcnt == 3) {
2834 if (slashcnt != 3 || x == p.end()) {
2835 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2839 paths.push_back (p.substr (n - 1));
2847 Editor::new_tempo_section ()
2853 Editor::map_transport_state ()
2855 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2857 if (session->transport_stopped()) {
2858 have_pending_keyboard_selection = false;
2861 update_loop_range_view (true);
2866 Editor::State::State ()
2868 selection = new Selection;
2871 Editor::State::~State ()
2877 Editor::get_memento () const
2879 State *state = new State;
2881 store_state (*state);
2882 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2886 Editor::store_state (State& state) const
2888 *state.selection = *selection;
2892 Editor::restore_state (State *state)
2894 if (*selection == *state->selection) {
2898 *selection = *state->selection;
2899 time_selection_changed ();
2900 region_selection_changed ();
2902 /* XXX other selection change handlers? */
2906 Editor::begin_reversible_command (string name)
2909 // before = &get_state();
2910 session->begin_reversible_command (name);
2915 Editor::commit_reversible_command ()
2918 // session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2919 session->commit_reversible_command ();
2924 Editor::set_edit_group_solo (Route& route, bool yn)
2926 RouteGroup *edit_group;
2928 if ((edit_group = route.edit_group()) != 0) {
2929 edit_group->apply (&Route::set_solo, yn, this);
2931 route.set_solo (yn, this);
2936 Editor::set_edit_group_mute (Route& route, bool yn)
2938 RouteGroup *edit_group = 0;
2940 if ((edit_group == route.edit_group()) != 0) {
2941 edit_group->apply (&Route::set_mute, yn, this);
2943 route.set_mute (yn, this);
2948 Editor::history_changed ()
2952 if (undo_action && session) {
2953 if (session->undo_depth() == 0) {
2956 label = string_compose(_("Undo (%1)"), session->next_undo());
2958 undo_action->property_label() = label;
2961 if (redo_action && session) {
2962 if (session->redo_depth() == 0) {
2965 label = string_compose(_("Redo (%1)"), session->next_redo());
2967 redo_action->property_label() = label;
2972 Editor::duplicate_dialog (bool dup_region)
2974 if (selection->regions.empty() && (selection->time.length() == 0)) {
2978 ArdourDialog win ("duplicate dialog");
2979 Label label (_("Duplicate how many times?"));
2980 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
2981 SpinButton spinner (adjustment);
2983 win.get_vbox()->set_spacing (12);
2984 win.get_vbox()->pack_start (label);
2986 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
2987 place, visually. so do this by hand.
2990 win.get_vbox()->pack_start (spinner);
2991 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
2996 win.add_button (Stock::OK, RESPONSE_ACCEPT);
2997 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2999 win.set_position (WIN_POS_MOUSE);
3001 spinner.grab_focus ();
3003 switch (win.run ()) {
3004 case RESPONSE_ACCEPT:
3010 float times = adjustment.get_value();
3012 if (!selection->regions.empty()) {
3013 duplicate_some_regions (selection->regions, times);
3015 duplicate_selection (times);
3020 Editor::show_verbose_canvas_cursor ()
3022 verbose_canvas_cursor->raise_to_top();
3023 verbose_canvas_cursor->show();
3024 verbose_cursor_visible = true;
3028 Editor::hide_verbose_canvas_cursor ()
3030 verbose_canvas_cursor->hide();
3031 verbose_cursor_visible = false;
3035 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3037 /* XXX get origin of canvas relative to root window,
3038 add x and y and check compared to gdk_screen_{width,height}
3040 verbose_canvas_cursor->property_text() = txt.c_str();
3041 verbose_canvas_cursor->property_x() = x;
3042 verbose_canvas_cursor->property_y() = y;
3046 Editor::set_verbose_canvas_cursor_text (const string & txt)
3048 verbose_canvas_cursor->property_text() = txt.c_str();
3052 Editor::edit_mode_selection_done ()
3058 string choice = edit_mode_selector.get_active_text();
3059 EditMode mode = Slide;
3061 if (choice == _("Splice Edit")) {
3063 } else if (choice == _("Slide Edit")) {
3067 Config->set_edit_mode (mode);
3071 Editor::snap_type_selection_done ()
3073 string choice = snap_type_selector.get_active_text();
3074 SnapType snaptype = SnapToFrame;
3076 if (choice == _("Beats/3")) {
3077 snaptype = SnapToAThirdBeat;
3078 } else if (choice == _("Beats/4")) {
3079 snaptype = SnapToAQuarterBeat;
3080 } else if (choice == _("Beats/8")) {
3081 snaptype = SnapToAEighthBeat;
3082 } else if (choice == _("Beats/16")) {
3083 snaptype = SnapToASixteenthBeat;
3084 } else if (choice == _("Beats/32")) {
3085 snaptype = SnapToAThirtysecondBeat;
3086 } else if (choice == _("Beats")) {
3087 snaptype = SnapToBeat;
3088 } else if (choice == _("Bars")) {
3089 snaptype = SnapToBar;
3090 } else if (choice == _("Marks")) {
3091 snaptype = SnapToMark;
3092 } else if (choice == _("Edit Point")) {
3093 snaptype = SnapToEditPoint;
3094 } else if (choice == _("Region starts")) {
3095 snaptype = SnapToRegionStart;
3096 } else if (choice == _("Region ends")) {
3097 snaptype = SnapToRegionEnd;
3098 } else if (choice == _("Region bounds")) {
3099 snaptype = SnapToRegionBoundary;
3100 } else if (choice == _("Region syncs")) {
3101 snaptype = SnapToRegionSync;
3102 } else if (choice == _("CD Frames")) {
3103 snaptype = SnapToCDFrame;
3104 } else if (choice == _("SMPTE Frames")) {
3105 snaptype = SnapToSMPTEFrame;
3106 } else if (choice == _("SMPTE Seconds")) {
3107 snaptype = SnapToSMPTESeconds;
3108 } else if (choice == _("SMPTE Minutes")) {
3109 snaptype = SnapToSMPTEMinutes;
3110 } else if (choice == _("Seconds")) {
3111 snaptype = SnapToSeconds;
3112 } else if (choice == _("Minutes")) {
3113 snaptype = SnapToMinutes;
3114 } else if (choice == _("None")) {
3115 snaptype = SnapToFrame;
3118 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3120 ract->set_active ();
3125 Editor::snap_mode_selection_done ()
3127 string choice = snap_mode_selector.get_active_text();
3128 SnapMode mode = SnapNormal;
3130 if (choice == _("Normal")) {
3132 } else if (choice == _("Magnetic")) {
3133 mode = SnapMagnetic;
3136 RefPtr<RadioAction> ract = snap_mode_action (mode);
3139 ract->set_active (true);
3144 Editor::edit_point_selection_done ()
3146 string choice = edit_point_selector.get_active_text();
3147 EditPoint ep = EditAtSelectedMarker;
3149 if (choice == _("Marker")) {
3150 _edit_point = EditAtSelectedMarker;
3151 } else if (choice == _("Playhead")) {
3152 _edit_point = EditAtPlayhead;
3154 _edit_point = EditAtMouse;
3157 RefPtr<RadioAction> ract = edit_point_action (ep);
3160 ract->set_active (true);
3165 Editor::zoom_focus_selection_done ()
3167 string choice = zoom_focus_selector.get_active_text();
3168 ZoomFocus focus_type = ZoomFocusLeft;
3170 if (choice == _("Left")) {
3171 focus_type = ZoomFocusLeft;
3172 } else if (choice == _("Right")) {
3173 focus_type = ZoomFocusRight;
3174 } else if (choice == _("Center")) {
3175 focus_type = ZoomFocusCenter;
3176 } else if (choice == _("Playhead")) {
3177 focus_type = ZoomFocusPlayhead;
3178 } else if (choice == _("Mouse")) {
3179 focus_type = ZoomFocusMouse;
3180 } else if (choice == _("Edit Point")) {
3181 focus_type = ZoomFocusEdit;
3184 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3187 ract->set_active ();
3192 Editor::edit_controls_button_release (GdkEventButton* ev)
3194 if (Keyboard::is_context_menu_event (ev)) {
3195 ARDOUR_UI::instance()->add_route (this);
3201 Editor::mouse_select_button_release (GdkEventButton* ev)
3203 /* this handles just right-clicks */
3205 if (ev->button != 3) {
3212 Editor::TrackViewList *
3213 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3216 TrackViewList::iterator i;
3218 v = new TrackViewList;
3220 if (track == 0 && group == 0) {
3224 for (i = track_views.begin(); i != track_views.end (); ++i) {
3228 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3230 /* just the view for this track
3233 v->push_back (track);
3237 /* views for all tracks in the edit group */
3239 for (i = track_views.begin(); i != track_views.end (); ++i) {
3241 if (group == 0 || (*i)->edit_group() == group) {
3251 Editor::set_zoom_focus (ZoomFocus f)
3253 string str = zoom_focus_strings[(int)f];
3255 if (str != zoom_focus_selector.get_active_text()) {
3256 zoom_focus_selector.set_active_text (str);
3259 if (zoom_focus != f) {
3262 ZoomFocusChanged (); /* EMIT_SIGNAL */
3269 Editor::ensure_float (Window& win)
3271 win.set_transient_for (*this);
3275 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3277 /* recover or initialize pane positions. do this here rather than earlier because
3278 we don't want the positions to change the child allocations, which they seem to do.
3284 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3286 static int32_t done;
3289 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3290 width = default_width;
3291 height = default_height;
3293 width = atoi(geometry->property("x_size")->value());
3294 height = atoi(geometry->property("y_size")->value());
3297 if (which == static_cast<Paned*> (&edit_pane)) {
3303 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3304 /* initial allocation is 90% to canvas, 10% to notebook */
3305 pos = (int) floor (alloc.get_width() * 0.90f);
3306 snprintf (buf, sizeof(buf), "%d", pos);
3308 pos = atoi (prop->value());
3311 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3312 edit_pane.set_position (pos);
3313 pre_maximal_pane_position = pos;
3319 Editor::detach_tearoff (Box* b, Window* w)
3321 if (tools_tearoff->torn_off() &&
3322 mouse_mode_tearoff->torn_off()) {
3323 top_hbox.remove (toolbar_frame);
3328 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3330 if (toolbar_frame.get_parent() == 0) {
3331 top_hbox.pack_end (toolbar_frame);
3336 Editor::set_show_measures (bool yn)
3338 if (_show_measures != yn) {
3341 if ((_show_measures = yn) == true) {
3349 Editor::toggle_follow_playhead ()
3351 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3353 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3354 set_follow_playhead (tact->get_active());
3359 Editor::set_follow_playhead (bool yn)
3361 if (_follow_playhead != yn) {
3362 if ((_follow_playhead = yn) == true) {
3364 update_current_screen ();
3371 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3373 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3375 xfade->set_active (!xfade->active());
3380 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3382 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3384 xfade->set_follow_overlap (!xfade->following_overlap());
3389 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3391 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3397 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3401 switch (cew.run ()) {
3402 case RESPONSE_ACCEPT:
3409 xfade->StateChanged (Change (~0));
3413 Editor::playlist_selector () const
3415 return *_playlist_selector;
3419 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3423 ret = nudge_clock.current_duration (pos);
3424 next = ret + 1; /* XXXX fix me */
3430 Editor::end_location_changed (Location* location)
3432 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3433 reset_scrolling_region ();
3437 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3439 ArdourDialog dialog ("playlist deletion dialog");
3440 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3441 "If left alone, no audio files used by it will be cleaned.\n"
3442 "If deleted, audio files used by it alone by will cleaned."),
3445 dialog.set_position (WIN_POS_CENTER);
3446 dialog.get_vbox()->pack_start (label);
3450 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3451 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3452 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3454 switch (dialog.run ()) {
3455 case RESPONSE_ACCEPT:
3456 /* delete the playlist */
3460 case RESPONSE_REJECT:
3461 /* keep the playlist */
3473 Editor::audio_region_selection_covers (nframes_t where)
3475 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3476 if ((*a)->region()->covers (where)) {
3485 Editor::prepare_for_cleanup ()
3487 cut_buffer->clear_regions ();
3488 cut_buffer->clear_playlists ();
3490 selection->clear_regions ();
3491 selection->clear_playlists ();
3495 Editor::transport_loop_location()
3498 return session->locations()->auto_loop_location();
3505 Editor::transport_punch_location()
3508 return session->locations()->auto_punch_location();
3515 Editor::control_layout_scroll (GdkEventScroll* ev)
3517 switch (ev->direction) {
3519 scroll_tracks_up_line ();
3523 case GDK_SCROLL_DOWN:
3524 scroll_tracks_down_line ();
3528 /* no left/right handling yet */
3536 /** A new snapshot has been selected.
3539 Editor::snapshot_display_selection_changed ()
3541 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3543 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3545 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3547 if (snap_name.length() == 0) {
3551 if (session->snap_name() == snap_name) {
3555 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3560 Editor::snapshot_display_button_press (GdkEventButton* ev)
3562 if (ev->button == 3) {
3563 /* Right-click on the snapshot list. Work out which snapshot it
3565 Gtk::TreeModel::Path path;
3566 Gtk::TreeViewColumn* col;
3569 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3570 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3572 Gtk::TreeModel::Row row = *iter;
3573 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3582 /** Pop up the snapshot display context menu.
3583 * @param button Button used to open the menu.
3584 * @param time Menu open time.
3585 * @snapshot_name Name of the snapshot that the menu click was over.
3589 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3591 using namespace Menu_Helpers;
3593 MenuList& items (snapshot_context_menu.items());
3596 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3598 items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)));
3599 if (!modification_allowed) {
3600 items.back().set_sensitive (false);
3603 items.push_back (MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)));
3604 if (!modification_allowed) {
3605 items.back().set_sensitive (false);
3608 snapshot_context_menu.popup (button, time);
3612 Editor::rename_snapshot (Glib::ustring old_name)
3614 ArdourPrompter prompter(true);
3618 prompter.set_name ("Prompter");
3619 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3620 prompter.set_prompt (_("New name of snapshot"));
3621 prompter.set_initial_text (old_name);
3623 if (prompter.run() == RESPONSE_ACCEPT) {
3624 prompter.get_result (new_name);
3625 if (new_name.length()) {
3626 session->rename_state (old_name, new_name);
3627 redisplay_snapshots ();
3634 Editor::remove_snapshot (Glib::ustring name)
3636 vector<string> choices;
3638 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3640 choices.push_back (_("No, do nothing."));
3641 choices.push_back (_("Yes, remove it."));
3643 Gtkmm2ext::Choice prompter (prompt, choices);
3645 if (prompter.run () == 1) {
3646 session->remove_state (name);
3647 redisplay_snapshots ();
3652 Editor::redisplay_snapshots ()
3658 vector<string*>* states;
3660 if ((states = session->possible_states()) == 0) {
3664 snapshot_display_model->clear ();
3666 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3667 string statename = *(*i);
3668 TreeModel::Row row = *(snapshot_display_model->append());
3670 /* this lingers on in case we ever want to change the visible
3671 name of the snapshot.
3674 string display_name;
3675 display_name = statename;
3677 if (statename == session->snap_name()) {
3678 snapshot_display.get_selection()->select(row);
3681 row[snapshot_display_columns.visible_name] = display_name;
3682 row[snapshot_display_columns.real_name] = statename;
3689 Editor::session_state_saved (string snap_name)
3691 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3692 redisplay_snapshots ();
3696 Editor::maximise_editing_space ()
3698 initial_ruler_update_required = true;
3700 mouse_mode_tearoff->set_visible (false);
3701 tools_tearoff->set_visible (false);
3703 pre_maximal_pane_position = edit_pane.get_position();
3704 pre_maximal_editor_width = this->get_width();
3706 if(post_maximal_pane_position == 0) {
3707 post_maximal_pane_position = edit_pane.get_width();
3712 if(post_maximal_editor_width) {
3713 edit_pane.set_position (post_maximal_pane_position -
3714 abs(post_maximal_editor_width - pre_maximal_editor_width));
3716 edit_pane.set_position (post_maximal_pane_position);
3721 Editor::restore_editing_space ()
3723 initial_ruler_update_required = true;
3725 // user changed width of pane during fullscreen
3726 if(post_maximal_pane_position != edit_pane.get_position()) {
3727 post_maximal_pane_position = edit_pane.get_position();
3732 mouse_mode_tearoff->set_visible (true);
3733 tools_tearoff->set_visible (true);
3734 post_maximal_editor_width = this->get_width();
3737 edit_pane.set_position (
3738 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3743 * Make new playlists for a given track and also any others that belong
3744 * to the same active edit group.
3749 Editor::new_playlists (TimeAxisView* v)
3751 begin_reversible_command (_("new playlists"));
3752 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3753 commit_reversible_command ();
3758 * Use a copy of the current playlist for a given track and also any others that belong
3759 * to the same active edit group.
3764 Editor::copy_playlists (TimeAxisView* v)
3766 begin_reversible_command (_("copy playlists"));
3767 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3768 commit_reversible_command ();
3773 * Clear the current playlist for a given track and also any others that belong
3774 * to the same active edit group.
3779 Editor::clear_playlists (TimeAxisView* v)
3781 begin_reversible_command (_("clear playlists"));
3782 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3783 commit_reversible_command ();
3787 Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz)
3789 atv.use_new_playlist (sz > 1 ? false : true);
3793 Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz)
3795 atv.use_copy_playlist (sz > 1 ? false : true);
3799 Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz)
3801 atv.clear_playlist ();
3805 Editor::on_key_press_event (GdkEventKey* ev)
3807 return key_press_focus_accelerator_handler (*this, ev);
3811 Editor::reset_x_origin (nframes_t frame)
3813 queue_visual_change (frame);
3817 Editor::reset_zoom (double fpu)
3819 queue_visual_change (fpu);
3823 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3825 reset_x_origin (frame);
3830 Editor::set_frames_per_unit (double fpu)
3834 /* this is the core function that controls the zoom level of the canvas. it is called
3835 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3838 if (fpu == frames_per_unit) {
3846 // convert fpu to frame count
3848 frames = (nframes_t) floor (fpu * canvas_width);
3850 /* don't allow zooms that fit more than the maximum number
3851 of frames into an 800 pixel wide space.
3854 if (max_frames / fpu < 800.0) {
3858 if (fpu == frames_per_unit) {
3862 frames_per_unit = fpu;
3864 if (frames != zoom_range_clock.current_duration()) {
3865 zoom_range_clock.set (frames);
3868 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3869 if (!selection->tracks.empty()) {
3870 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3871 (*i)->reshow_selection (selection->time);
3874 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3875 (*i)->reshow_selection (selection->time);
3880 ZoomChanged (); /* EMIT_SIGNAL */
3882 reset_hscrollbar_stepping ();
3883 reset_scrolling_region ();
3885 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3891 Editor::queue_visual_change (nframes_t where)
3893 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3894 pending_visual_change.time_origin = where;
3896 if (pending_visual_change.idle_handler_id < 0) {
3897 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3902 Editor::queue_visual_change (double fpu)
3904 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3905 pending_visual_change.frames_per_unit = fpu;
3907 if (pending_visual_change.idle_handler_id < 0) {
3908 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3913 Editor::_idle_visual_changer (void* arg)
3915 return static_cast<Editor*>(arg)->idle_visual_changer ();
3919 Editor::idle_visual_changer ()
3921 VisualChange::Type p = pending_visual_change.pending;
3923 pending_visual_change.pending = (VisualChange::Type) 0;
3924 pending_visual_change.idle_handler_id = -1;
3926 if (p & VisualChange::ZoomLevel) {
3927 set_frames_per_unit (pending_visual_change.frames_per_unit);
3930 if (p & VisualChange::TimeOrigin) {
3931 if (pending_visual_change.time_origin != leftmost_frame) {
3932 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3933 /* the signal handler will do the rest */
3935 update_fixed_rulers();
3936 redisplay_tempo (true);
3940 return 0; /* this is always a one-shot call */
3943 struct EditorOrderTimeAxisSorter {
3944 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3945 return a->order < b->order;
3950 Editor::sort_track_selection ()
3952 EditorOrderTimeAxisSorter cmp;
3953 selection->tracks.sort (cmp);
3957 Editor::get_preferred_edit_position() const
3962 // XXX EDIT CURSOR used to sync with edit cursor clock
3964 switch (_edit_point) {
3965 case EditAtPlayhead:
3966 return playhead_cursor->current_frame;
3968 case EditAtSelectedMarker:
3969 if (!selection->markers.empty()) {
3971 Location* loc = find_location_from_marker (selection->markers.front(), whocares);
3973 return loc->start();
3980 if (mouse_frame (where, ignored)) {
3989 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
3991 if (!session) return;
3993 begin_reversible_command (cmd);
3997 if ((tll = transport_loop_location()) == 0) {
3998 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
3999 XMLNode &before = session->locations()->get_state();
4000 session->locations()->add (loc, true);
4001 session->set_auto_loop_location (loc);
4002 XMLNode &after = session->locations()->get_state();
4003 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4006 XMLNode &before = tll->get_state();
4007 tll->set_hidden (false, this);
4008 tll->set (start, end);
4009 XMLNode &after = tll->get_state();
4010 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4013 commit_reversible_command ();
4017 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4019 if (!session) return;
4021 begin_reversible_command (cmd);
4025 if ((tpl = transport_punch_location()) == 0) {
4026 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4027 XMLNode &before = session->locations()->get_state();
4028 session->locations()->add (loc, true);
4029 session->set_auto_loop_location (loc);
4030 XMLNode &after = session->locations()->get_state();
4031 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4034 XMLNode &before = tpl->get_state();
4035 tpl->set_hidden (false, this);
4036 tpl->set (start, end);
4037 XMLNode &after = tpl->get_state();
4038 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4041 commit_reversible_command ();
4045 Editor::get_regions_at (nframes64_t where, const TrackSelection& ts) const
4048 const TrackSelection* tracks;
4051 tracks = &track_views;
4056 for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4058 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4061 boost::shared_ptr<Diskstream> ds;
4062 boost::shared_ptr<Playlist> pl;
4064 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4066 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)where * ds->speed()));
4068 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4070 RegionView* rv = atv->audio_view()->find_view (*i);