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_point_clock (X_("editpoint"), false, X_("EditPointClock"), 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_edit_point = false;
320 _dragging_hscrollbar = false;
322 scrubbing_direction = 0;
325 ignore_route_order_sync = false;
327 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
328 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
329 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
330 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
331 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
333 range_marker_drag_rect = 0;
334 marker_drag_line = 0;
336 set_mouse_mode (MouseObject, true);
338 frames_per_unit = 2048; /* too early to use reset_zoom () */
339 reset_hscrollbar_stepping ();
341 zoom_focus = ZoomFocusLeft;
342 set_zoom_focus (ZoomFocusLeft);
343 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
345 initialize_rulers ();
346 initialize_canvas ();
348 edit_controls_vbox.set_spacing (0);
349 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
350 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
352 track_canvas.set_hadjustment (horizontal_adjustment);
353 track_canvas.set_vadjustment (vertical_adjustment);
354 time_canvas.set_hadjustment (horizontal_adjustment);
356 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
357 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
359 controls_layout.add (edit_controls_vbox);
360 controls_layout.set_name ("EditControlsBase");
361 controls_layout.add_events (Gdk::SCROLL_MASK);
362 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
364 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
365 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
366 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
368 edit_vscrollbar.set_adjustment (vertical_adjustment);
369 edit_hscrollbar.set_adjustment (horizontal_adjustment);
371 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
372 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
373 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
375 edit_hscrollbar.set_name ("EditorHScrollbar");
380 edit_point_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_point_clock_changed));
382 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
383 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
384 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
385 time_canvas_vbox.pack_start (*frames_ruler, false, false);
386 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
387 time_canvas_vbox.pack_start (time_canvas, true, true);
388 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
390 bbt_label.set_name ("EditorTimeButton");
391 bbt_label.set_size_request (-1, (int)timebar_height);
392 bbt_label.set_alignment (1.0, 0.5);
393 bbt_label.set_padding (5,0);
394 minsec_label.set_name ("EditorTimeButton");
395 minsec_label.set_size_request (-1, (int)timebar_height);
396 minsec_label.set_alignment (1.0, 0.5);
397 minsec_label.set_padding (5,0);
398 smpte_label.set_name ("EditorTimeButton");
399 smpte_label.set_size_request (-1, (int)timebar_height);
400 smpte_label.set_alignment (1.0, 0.5);
401 smpte_label.set_padding (5,0);
402 frame_label.set_name ("EditorTimeButton");
403 frame_label.set_size_request (-1, (int)timebar_height);
404 frame_label.set_alignment (1.0, 0.5);
405 frame_label.set_padding (5,0);
406 tempo_label.set_name ("EditorTimeButton");
407 tempo_label.set_size_request (-1, (int)timebar_height);
408 tempo_label.set_alignment (1.0, 0.5);
409 tempo_label.set_padding (5,0);
410 meter_label.set_name ("EditorTimeButton");
411 meter_label.set_size_request (-1, (int)timebar_height);
412 meter_label.set_alignment (1.0, 0.5);
413 meter_label.set_padding (5,0);
414 mark_label.set_name ("EditorTimeButton");
415 mark_label.set_size_request (-1, (int)timebar_height);
416 mark_label.set_alignment (1.0, 0.5);
417 mark_label.set_padding (5,0);
418 range_mark_label.set_name ("EditorTimeButton");
419 range_mark_label.set_size_request (-1, (int)timebar_height);
420 range_mark_label.set_alignment (1.0, 0.5);
421 range_mark_label.set_padding (5,0);
422 transport_mark_label.set_name ("EditorTimeButton");
423 transport_mark_label.set_size_request (-1, (int)timebar_height);
424 transport_mark_label.set_alignment (1.0, 0.5);
425 transport_mark_label.set_padding (5,0);
427 time_button_vbox.pack_start (minsec_label, false, false);
428 time_button_vbox.pack_start (smpte_label, false, false);
429 time_button_vbox.pack_start (frame_label, false, false);
430 time_button_vbox.pack_start (bbt_label, false, false);
431 time_button_vbox.pack_start (meter_label, false, false);
432 time_button_vbox.pack_start (tempo_label, false, false);
433 time_button_vbox.pack_start (mark_label, false, false);
435 time_button_event_box.add (time_button_vbox);
437 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
438 time_button_event_box.set_name ("TimebarLabelBase");
439 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
441 time_button_frame.add(time_button_event_box);
442 time_button_frame.property_shadow_type() = Gtk::SHADOW_OUT;
444 /* these enable us to have a dedicated window (for cursor setting, etc.)
445 for the canvas areas.
448 track_canvas_event_box.add (track_canvas);
450 time_canvas_event_box.add (time_canvas_vbox);
451 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
453 edit_packer.set_col_spacings (0);
454 edit_packer.set_row_spacings (0);
455 edit_packer.set_homogeneous (false);
456 edit_packer.set_border_width (0);
457 edit_packer.set_name ("EditorWindow");
459 edit_packer.attach (edit_vscrollbar, 0, 1, 1, 3, FILL, FILL|EXPAND, 0, 0);
461 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, FILL, 0, 0);
462 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
464 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
465 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
467 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
468 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
470 bottom_hbox.set_border_width (2);
471 bottom_hbox.set_spacing (3);
473 route_display_model = ListStore::create(route_display_columns);
474 route_list_display.set_model (route_display_model);
475 route_list_display.append_column (_("Show"), route_display_columns.visible);
476 route_list_display.append_column (_("Name"), route_display_columns.text);
477 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
478 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
479 route_list_display.set_headers_visible (true);
480 route_list_display.set_name ("TrackListDisplay");
481 route_list_display.get_selection()->set_mode (SELECTION_NONE);
482 route_list_display.set_reorderable (true);
483 route_list_display.set_size_request (100,-1);
485 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
486 route_list_visible_cell->property_activatable() = true;
487 route_list_visible_cell->property_radio() = false;
489 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
490 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
491 route_display_model->signal_rows_reordered().connect (mem_fun (*this, &Editor::track_list_reorder));
493 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
495 route_list_scroller.add (route_list_display);
496 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
498 group_model = ListStore::create(group_columns);
499 edit_group_display.set_model (group_model);
500 edit_group_display.append_column (_("Name"), group_columns.text);
501 edit_group_display.append_column (_("Active"), group_columns.is_active);
502 edit_group_display.append_column (_("Show"), group_columns.is_visible);
503 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
504 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
505 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
506 edit_group_display.get_column (0)->set_expand (true);
507 edit_group_display.get_column (1)->set_expand (false);
508 edit_group_display.get_column (2)->set_expand (false);
509 edit_group_display.set_headers_visible (true);
511 /* name is directly editable */
513 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
514 name_cell->property_editable() = true;
515 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
517 /* use checkbox for the active + visible columns */
519 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
520 active_cell->property_activatable() = true;
521 active_cell->property_radio() = false;
523 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
524 active_cell->property_activatable() = true;
525 active_cell->property_radio() = false;
527 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
529 edit_group_display.set_name ("EditGroupList");
530 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
531 edit_group_display.set_headers_visible (true);
532 edit_group_display.set_reorderable (false);
533 edit_group_display.set_rules_hint (true);
534 edit_group_display.set_size_request (75, -1);
536 edit_group_display_scroller.add (edit_group_display);
537 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
539 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
541 VBox* edit_group_display_packer = manage (new VBox());
542 HBox* edit_group_display_button_box = manage (new HBox());
543 edit_group_display_button_box->set_homogeneous (true);
545 Button* edit_group_add_button = manage (new Button ());
546 Button* edit_group_remove_button = manage (new Button ());
550 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
552 edit_group_add_button->add (*w);
554 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
556 edit_group_remove_button->add (*w);
558 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
559 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
561 edit_group_display_button_box->pack_start (*edit_group_add_button);
562 edit_group_display_button_box->pack_start (*edit_group_remove_button);
564 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
565 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
567 region_list_display.set_size_request (100, -1);
568 region_list_display.set_name ("RegionListDisplay");
570 region_list_model = TreeStore::create (region_list_columns);
571 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
572 region_list_model->set_sort_column (0, SORT_ASCENDING);
574 region_list_display.set_model (region_list_model);
575 region_list_display.append_column (_("Regions"), region_list_columns.name);
576 region_list_display.set_headers_visible (false);
578 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
580 TreeViewColumn* tv_col = region_list_display.get_column(0);
581 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
582 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
583 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
585 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
586 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
588 /* setup DnD handling */
590 list<TargetEntry> region_list_target_table;
592 region_list_target_table.push_back (TargetEntry ("text/plain"));
593 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
594 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
596 region_list_display.add_drop_targets (region_list_target_table);
597 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
599 region_list_scroller.add (region_list_display);
600 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
602 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
603 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
604 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
605 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
606 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
607 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
609 named_selection_scroller.add (named_selection_display);
610 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
612 named_selection_model = TreeStore::create (named_selection_columns);
613 named_selection_display.set_model (named_selection_model);
614 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
615 named_selection_display.set_headers_visible (false);
616 named_selection_display.set_size_request (100, -1);
617 named_selection_display.set_name ("NamedSelectionDisplay");
619 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
620 named_selection_display.set_size_request (100, -1);
621 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
622 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
623 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
627 snapshot_display_model = ListStore::create (snapshot_display_columns);
628 snapshot_display.set_model (snapshot_display_model);
629 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
630 snapshot_display.set_name ("SnapshotDisplay");
631 snapshot_display.set_size_request (75, -1);
632 snapshot_display.set_headers_visible (false);
633 snapshot_display.set_reorderable (false);
634 snapshot_display_scroller.add (snapshot_display);
635 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
637 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
638 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
642 nlabel = manage (new Label (_("Regions")));
643 nlabel->set_angle (-90);
644 the_notebook.append_page (region_list_scroller, *nlabel);
645 nlabel = manage (new Label (_("Tracks/Busses")));
646 nlabel->set_angle (-90);
647 the_notebook.append_page (route_list_scroller, *nlabel);
648 nlabel = manage (new Label (_("Snapshots")));
649 nlabel->set_angle (-90);
650 the_notebook.append_page (snapshot_display_scroller, *nlabel);
651 nlabel = manage (new Label (_("Edit Groups")));
652 nlabel->set_angle (-90);
653 the_notebook.append_page (*edit_group_display_packer, *nlabel);
654 nlabel = manage (new Label (_("Chunks")));
655 nlabel->set_angle (-90);
656 the_notebook.append_page (named_selection_scroller, *nlabel);
658 the_notebook.set_show_tabs (true);
659 the_notebook.set_scrollable (true);
660 the_notebook.popup_enable ();
661 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
663 post_maximal_editor_width = 0;
664 post_maximal_pane_position = 0;
665 edit_pane.pack1 (edit_packer, true, true);
666 edit_pane.pack2 (the_notebook, false, true);
668 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
670 top_hbox.pack_start (toolbar_frame, true, true);
672 HBox *hbox = manage (new HBox);
673 hbox->pack_start (edit_pane, true, true);
675 global_vpacker.pack_start (top_hbox, false, false);
676 global_vpacker.pack_start (*hbox, true, true);
678 global_hpacker.pack_start (global_vpacker, true, true);
680 set_name ("EditorWindow");
681 add_accel_group (ActionManager::ui_manager->get_accel_group());
683 status_bar_hpacker.show ();
685 vpacker.pack_end (status_bar_hpacker, false, false);
686 vpacker.pack_end (global_hpacker, true, true);
688 /* register actions now so that set_state() can find them and set toggles/checks etc */
692 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
695 _playlist_selector = new PlaylistSelector();
696 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
698 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
702 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
703 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
705 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
706 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
708 nudge_forward_button.set_name ("TransportButton");
709 nudge_backward_button.set_name ("TransportButton");
711 fade_context_menu.set_name ("ArdourContextMenu");
713 /* icons, titles, WM stuff */
715 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
716 Glib::RefPtr<Gdk::Pixbuf> icon;
718 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
719 window_icons.push_back (icon);
721 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
722 window_icons.push_back (icon);
724 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
725 window_icons.push_back (icon);
727 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
728 window_icons.push_back (icon);
730 if (!window_icons.empty()) {
731 set_icon_list (window_icons);
732 set_default_icon_list (window_icons);
735 WindowTitle title(Glib::get_application_name());
736 title += _("Editor");
737 set_title (title.get_string());
738 set_wmclass (X_("ardour_editor"), "Ardour");
741 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
743 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
744 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
746 /* allow external control surfaces/protocols to do various things */
748 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
749 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
750 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
751 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
753 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
754 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
762 /* <CMT Additions> */
763 if(image_socket_listener)
765 if(image_socket_listener->is_connected())
767 image_socket_listener->close_connection() ;
770 delete image_socket_listener ;
771 image_socket_listener = 0 ;
773 /* </CMT Additions> */
777 Editor::add_toplevel_controls (Container& cont)
779 vpacker.pack_start (cont, false, false);
784 Editor::catch_vanishing_regionview (RegionView *rv)
786 /* note: the selection will take care of the vanishing
787 audioregionview by itself.
790 if (clicked_regionview == rv) {
791 clicked_regionview = 0;
794 if (entered_regionview == rv) {
795 set_entered_regionview (0);
800 Editor::set_entered_regionview (RegionView* rv)
802 if (rv == entered_regionview) {
806 if (entered_regionview) {
807 entered_regionview->exited ();
810 if ((entered_regionview = rv) != 0) {
811 entered_regionview->entered ();
816 Editor::set_entered_track (TimeAxisView* tav)
819 entered_track->exited ();
822 if ((entered_track = tav) != 0) {
823 entered_track->entered ();
828 Editor::show_window ()
833 /* now reset all audio_time_axis heights, because widgets might need
839 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
840 tv = (static_cast<TimeAxisView*>(*i));
846 Editor::tie_vertical_scrolling ()
848 double y1 = vertical_adjustment.get_value();
850 playhead_cursor->set_y_axis (y1);
852 logo_item->property_y() = y1;
855 controls_layout.get_vadjustment()->set_value (y1);
858 /* the way idle updates and immediate window flushing work on GTK-Quartz
859 requires that we force an immediate redraw right here. The controls
860 layout will do the same all by itself, as does the canvas widget, but
861 most of the time, the canvas itself hasn't updated itself because its
862 idle handler hasn't run. consequently, the call that its layout makes
863 to gdk_window_process_updates() finds nothing to do. here, we force
864 the update to happen, then request a flush of the new window state.
866 track_canvas.update_now ();
867 gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
872 Editor::instant_save ()
874 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
879 session->add_instant_xml(get_state(), session->path());
881 Config->add_instant_xml(get_state(), get_user_ardour_path());
886 Editor::edit_point_clock_changed()
888 if (_dragging_edit_point) {
892 if (selection->markers.empty()) {
897 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
903 loc->move_to (edit_point_clock.current_time());
907 Editor::zoom_adjustment_changed ()
913 double fpu = zoom_range_clock.current_duration() / canvas_width;
917 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
918 } else if (fpu > session->current_end_frame() / canvas_width) {
919 fpu = session->current_end_frame() / canvas_width;
920 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
927 Editor::control_scroll (float fraction)
929 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
935 double step = fraction * current_page_frames();
938 _control_scroll_target is an optional<T>
940 it acts like a pointer to an nframes_t, with
941 a operator conversion to boolean to check
942 that it has a value could possibly use
943 playhead_cursor->current_frame to store the
944 value and a boolean in the class to know
945 when it's out of date
948 if (!_control_scroll_target) {
949 _control_scroll_target = session->transport_frame();
950 _dragging_playhead = true;
953 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
954 *_control_scroll_target = 0;
955 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
956 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
958 *_control_scroll_target += (nframes_t) floor (step);
961 /* move visuals, we'll catch up with it later */
963 playhead_cursor->set_position (*_control_scroll_target);
964 UpdateAllTransportClocks (*_control_scroll_target);
966 if (*_control_scroll_target > (current_page_frames() / 2)) {
967 /* try to center PH in window */
968 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
974 Now we do a timeout to actually bring the session to the right place
975 according to the playhead. This is to avoid reading disk buffers on every
976 call to control_scroll, which is driven by ScrollTimeline and therefore
977 probably by a control surface wheel which can generate lots of events.
979 /* cancel the existing timeout */
981 control_scroll_connection.disconnect ();
983 /* add the next timeout */
985 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
989 Editor::deferred_control_scroll (nframes_t target)
991 session->request_locate (*_control_scroll_target, session->transport_rolling());
992 // reset for next stream
993 _control_scroll_target = boost::none;
994 _dragging_playhead = false;
999 Editor::on_realize ()
1001 Window::on_realize ();
1006 Editor::start_scrolling ()
1008 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1009 (mem_fun(*this, &Editor::update_current_screen));
1013 Editor::stop_scrolling ()
1015 scroll_connection.disconnect ();
1019 Editor::map_position_change (nframes_t frame)
1021 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1023 if (session == 0 || !_follow_playhead) {
1027 center_screen (frame);
1028 playhead_cursor->set_position (frame);
1032 Editor::center_screen (nframes_t frame)
1034 double page = canvas_width * frames_per_unit;
1036 /* if we're off the page, then scroll.
1039 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1040 center_screen_internal (frame, page);
1045 Editor::center_screen_internal (nframes_t frame, float page)
1050 frame -= (nframes_t) page;
1055 reset_x_origin (frame);
1059 Editor::handle_new_duration ()
1061 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1063 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1065 if (new_end > last_canvas_frame) {
1066 last_canvas_frame = new_end;
1067 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1068 reset_scrolling_region ();
1071 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1075 Editor::update_title_s (const string & snap_name)
1077 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1083 Editor::update_title ()
1085 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1088 bool dirty = session->dirty();
1090 string session_name;
1092 if (session->snap_name() != session->name()) {
1093 session_name = session->snap_name();
1095 session_name = session->name();
1099 session_name = "*" + session_name;
1102 WindowTitle title(session_name);
1103 title += Glib::get_application_name();
1104 set_title (title.get_string());
1109 Editor::connect_to_session (Session *t)
1113 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1116 /* catch up with the playhead */
1118 session->request_locate (playhead_cursor->current_frame);
1120 if (first_action_message) {
1121 first_action_message->hide();
1126 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1127 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1129 /* These signals can all be emitted by a non-GUI thread. Therefore the
1130 handlers for them must not attempt to directly interact with the GUI,
1131 but use Gtkmm2ext::UI::instance()->call_slot();
1134 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1135 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1136 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1137 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::handle_new_audio_region)));
1138 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed)));
1139 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1140 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1141 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1142 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1143 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1144 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1145 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1146 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1147 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1149 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1151 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1153 edit_groups_changed ();
1155 edit_point_clock.set_session (session);
1156 zoom_range_clock.set_session (session);
1157 _playlist_selector->set_session (session);
1158 nudge_clock.set_session (session);
1161 if (analysis_window != 0)
1162 analysis_window->set_session (session);
1165 Location* loc = session->locations()->auto_loop_location();
1167 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1168 if (loc->start() == loc->end()) {
1169 loc->set_end (loc->start() + 1);
1171 session->locations()->add (loc, false);
1172 session->set_auto_loop_location (loc);
1175 loc->set_name (_("Loop"));
1178 loc = session->locations()->auto_punch_location();
1180 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1181 if (loc->start() == loc->end()) {
1182 loc->set_end (loc->start() + 1);
1184 session->locations()->add (loc, false);
1185 session->set_auto_punch_location (loc);
1188 loc->set_name (_("Punch"));
1191 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1193 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1195 refresh_location_display ();
1196 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1197 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1198 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1199 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1200 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1203 sfbrowser->set_session (session);
1206 handle_new_duration ();
1208 redisplay_regions ();
1209 redisplay_named_selections ();
1210 redisplay_snapshots ();
1212 initial_route_list_display ();
1214 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1215 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1218 restore_ruler_visibility ();
1219 //tempo_map_changed (Change (0));
1220 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1224 /* don't show master bus in a new session */
1226 if (ARDOUR_UI::instance()->session_is_new ()) {
1228 TreeModel::Children rows = route_display_model->children();
1229 TreeModel::Children::iterator i;
1231 no_route_list_redisplay = true;
1233 for (i = rows.begin(); i != rows.end(); ++i) {
1234 TimeAxisView *tv = (*i)[route_display_columns.tv];
1235 AudioTimeAxisView *atv;
1237 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1238 if (atv->route()->master()) {
1239 route_list_display.get_selection()->unselect (i);
1244 no_route_list_redisplay = false;
1245 redisplay_route_list ();
1248 /* register for undo history */
1250 session->register_with_memento_command_factory(_id, this);
1254 Editor::build_cursors ()
1256 using namespace Gdk;
1258 Gdk::Color mbg ("#000000" ); /* Black */
1259 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1262 RefPtr<Bitmap> source, mask;
1263 source = Bitmap::create (mag_bits, mag_width, mag_height);
1264 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1265 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1268 Gdk::Color fbg ("#ffffff" );
1269 Gdk::Color ffg ("#000000" );
1272 RefPtr<Bitmap> source, mask;
1274 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1275 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1276 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1280 RefPtr<Bitmap> source, mask;
1281 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1282 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1283 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1286 grabber_cursor = new Gdk::Cursor (HAND2);
1287 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1288 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1289 selector_cursor = new Gdk::Cursor (XTERM);
1290 time_fx_cursor = new Gdk::Cursor (SIZING);
1291 wait_cursor = new Gdk::Cursor (WATCH);
1292 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1296 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1298 using namespace Menu_Helpers;
1299 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1302 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1306 MenuList& items (fade_context_menu.items());
1310 switch (item_type) {
1312 case FadeInHandleItem:
1313 if (arv->audio_region()->fade_in_active()) {
1314 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1316 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1319 items.push_back (SeparatorElem());
1321 if (Profile->get_sae()) {
1322 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1323 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1325 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1326 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1327 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1328 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1329 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1334 case FadeOutHandleItem:
1335 if (arv->audio_region()->fade_out_active()) {
1336 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1338 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1341 items.push_back (SeparatorElem());
1343 if (Profile->get_sae()) {
1344 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1345 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1347 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1348 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1349 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1350 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1351 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1356 fatal << _("programming error: ")
1357 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1362 fade_context_menu.popup (button, time);
1366 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes_t frame)
1368 using namespace Menu_Helpers;
1369 Menu* (Editor::*build_menu_function)(nframes_t);
1372 switch (item_type) {
1374 case RegionViewName:
1375 case RegionViewNameHighlight:
1376 if (with_selection) {
1377 build_menu_function = &Editor::build_track_selection_context_menu;
1379 build_menu_function = &Editor::build_track_region_context_menu;
1384 if (with_selection) {
1385 build_menu_function = &Editor::build_track_selection_context_menu;
1387 build_menu_function = &Editor::build_track_context_menu;
1391 case CrossfadeViewItem:
1392 build_menu_function = &Editor::build_track_crossfade_context_menu;
1396 if (clicked_audio_trackview->get_diskstream()) {
1397 build_menu_function = &Editor::build_track_context_menu;
1399 build_menu_function = &Editor::build_track_bus_context_menu;
1404 /* probably shouldn't happen but if it does, we don't care */
1408 menu = (this->*build_menu_function)(frame);
1409 menu->set_name ("ArdourContextMenu");
1411 /* now handle specific situations */
1413 switch (item_type) {
1415 case RegionViewName:
1416 case RegionViewNameHighlight:
1417 if (!with_selection) {
1418 if (region_edit_menu_split_item) {
1419 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1420 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1422 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1426 if (region_edit_menu_split_multichannel_item) {
1427 if (clicked_regionview && clicked_regionview->region().n_channels() > 1) {
1428 // GTK2FIX find the action, change its sensitivity
1429 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1431 // GTK2FIX see above
1432 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1441 case CrossfadeViewItem:
1448 /* probably shouldn't happen but if it does, we don't care */
1452 if (item_type != SelectionItem && clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1454 /* Bounce to disk */
1456 using namespace Menu_Helpers;
1457 MenuList& edit_items = menu->items();
1459 edit_items.push_back (SeparatorElem());
1461 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1462 case AudioTrack::NoFreeze:
1463 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1466 case AudioTrack::Frozen:
1467 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1470 case AudioTrack::UnFrozen:
1471 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1477 menu->popup (button, time);
1481 Editor::build_track_context_menu (nframes_t ignored)
1483 using namespace Menu_Helpers;
1485 MenuList& edit_items = track_context_menu.items();
1488 add_dstream_context_items (edit_items);
1489 return &track_context_menu;
1493 Editor::build_track_bus_context_menu (nframes_t ignored)
1495 using namespace Menu_Helpers;
1497 MenuList& edit_items = track_context_menu.items();
1500 add_bus_context_items (edit_items);
1501 return &track_context_menu;
1505 Editor::build_track_region_context_menu (nframes_t frame)
1507 using namespace Menu_Helpers;
1508 MenuList& edit_items = track_region_context_menu.items();
1511 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1514 boost::shared_ptr<Diskstream> ds;
1515 boost::shared_ptr<Playlist> pl;
1517 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1518 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)frame * ds->speed()));
1519 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1520 add_region_context_items (atv->audio_view(), (*i), edit_items);
1526 add_dstream_context_items (edit_items);
1528 return &track_region_context_menu;
1532 Editor::build_track_crossfade_context_menu (nframes_t frame)
1534 using namespace Menu_Helpers;
1535 MenuList& edit_items = track_crossfade_context_menu.items();
1536 edit_items.clear ();
1538 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1541 boost::shared_ptr<Diskstream> ds;
1542 boost::shared_ptr<Playlist> pl;
1543 boost::shared_ptr<AudioPlaylist> apl;
1545 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1547 Playlist::RegionList* regions = pl->regions_at (frame);
1548 AudioPlaylist::Crossfades xfades;
1550 apl->crossfades_at (frame, xfades);
1552 bool many = xfades.size() > 1;
1554 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1555 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1558 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1559 add_region_context_items (atv->audio_view(), (*i), edit_items);
1566 add_dstream_context_items (edit_items);
1568 return &track_crossfade_context_menu;
1573 Editor::analyze_region_selection()
1575 if (analysis_window == 0) {
1576 analysis_window = new AnalysisWindow();
1579 analysis_window->set_session(session);
1581 analysis_window->show_all();
1584 analysis_window->set_regionmode();
1585 analysis_window->analyze();
1587 analysis_window->present();
1591 Editor::analyze_range_selection()
1593 if (analysis_window == 0) {
1594 analysis_window = new AnalysisWindow();
1597 analysis_window->set_session(session);
1599 analysis_window->show_all();
1602 analysis_window->set_rangemode();
1603 analysis_window->analyze();
1605 analysis_window->present();
1607 #endif /* FFT_ANALYSIS */
1612 Editor::build_track_selection_context_menu (nframes_t ignored)
1614 using namespace Menu_Helpers;
1615 MenuList& edit_items = track_selection_context_menu.items();
1616 edit_items.clear ();
1618 add_selection_context_items (edit_items);
1619 // edit_items.push_back (SeparatorElem());
1620 // add_dstream_context_items (edit_items);
1622 return &track_selection_context_menu;
1626 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1628 using namespace Menu_Helpers;
1629 Menu *xfade_menu = manage (new Menu);
1630 MenuList& items = xfade_menu->items();
1631 xfade_menu->set_name ("ArdourContextMenu");
1634 if (xfade->active()) {
1640 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1641 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1643 if (xfade->can_follow_overlap()) {
1645 if (xfade->following_overlap()) {
1646 str = _("Convert to short");
1648 str = _("Convert to full");
1651 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1655 str = xfade->out()->name();
1657 str += xfade->in()->name();
1659 str = _("Crossfade");
1662 edit_items.push_back (MenuElem (str, *xfade_menu));
1663 edit_items.push_back (SeparatorElem());
1667 Editor::xfade_edit_left_region ()
1669 if (clicked_crossfadeview) {
1670 clicked_crossfadeview->left_view.show_region_editor ();
1675 Editor::xfade_edit_right_region ()
1677 if (clicked_crossfadeview) {
1678 clicked_crossfadeview->right_view.show_region_editor ();
1683 Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region> region, Menu_Helpers::MenuList& edit_items)
1685 using namespace Menu_Helpers;
1686 Menu *region_menu = manage (new Menu);
1687 MenuList& items = region_menu->items();
1688 region_menu->set_name ("ArdourContextMenu");
1690 boost::shared_ptr<AudioRegion> ar;
1693 ar = boost::dynamic_pointer_cast<AudioRegion> (region);
1696 /* when this particular menu pops up, make the relevant region
1700 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr<Region>(region)));
1702 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1703 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1704 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1705 items.push_back (SeparatorElem());
1706 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_point)));
1707 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1708 items.push_back (SeparatorElem());
1710 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1711 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1712 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1715 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1718 items.push_back (SeparatorElem());
1720 sigc::connection fooc;
1722 items.push_back (CheckMenuElem (_("Lock")));
1723 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1724 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1725 if (region->locked()) {
1727 region_lock_item->set_active();
1730 items.push_back (CheckMenuElem (_("Mute")));
1731 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1732 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1733 if (region->muted()) {
1735 region_mute_item->set_active();
1739 if (!Profile->get_sae()) {
1740 items.push_back (CheckMenuElem (_("Opaque")));
1741 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1742 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1743 if (region->opaque()) {
1745 region_opaque_item->set_active();
1750 items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1751 if (region->at_natural_position()) {
1752 items.back().set_sensitive (false);
1755 items.push_back (SeparatorElem());
1759 RegionView* rv = sv->find_view (ar);
1760 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1762 if (!Profile->get_sae()) {
1763 items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1765 items.push_back (CheckMenuElem (_("Envelope Visible")));
1766 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1767 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1768 if (arv->envelope_visible()) {
1770 region_envelope_visible_item->set_active (true);
1774 items.push_back (CheckMenuElem (_("Envelope Active")));
1775 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1776 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1778 if (ar->envelope_active()) {
1780 region_envelope_active_item->set_active (true);
1784 items.push_back (SeparatorElem());
1787 if (ar->scale_amplitude() != 1.0f) {
1788 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1790 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1794 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1795 items.push_back (SeparatorElem());
1797 /* range related stuff */
1799 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
1800 items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)));
1801 items.push_back (SeparatorElem());
1805 Menu *nudge_menu = manage (new Menu());
1806 MenuList& nudge_items = nudge_menu->items();
1807 nudge_menu->set_name ("ArdourContextMenu");
1809 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1810 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1811 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1812 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1814 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1815 items.push_back (SeparatorElem());
1817 Menu *trim_menu = manage (new Menu);
1818 MenuList& trim_items = trim_menu->items();
1819 trim_menu->set_name ("ArdourContextMenu");
1821 trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point)));
1822 trim_items.push_back (MenuElem (_("Edit point to end"), mem_fun(*this, &Editor::trim_region_to_edit_point)));
1824 items.push_back (MenuElem (_("Trim"), *trim_menu));
1825 items.push_back (SeparatorElem());
1827 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1828 region_edit_menu_split_item = &items.back();
1830 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1831 region_edit_menu_split_multichannel_item = &items.back();
1833 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1834 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1835 items.push_back (SeparatorElem());
1836 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1838 /* OK, stick the region submenu at the top of the list, and then add
1842 /* we have to hack up the region name because "_" has a special
1843 meaning for menu titles.
1846 string::size_type pos = 0;
1847 string menu_item_name = region->name();
1849 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1850 menu_item_name.replace (pos, 1, "__");
1854 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1855 edit_items.push_back (SeparatorElem());
1859 Editor::add_selection_context_items (Menu_Helpers::MenuList& items)
1861 using namespace Menu_Helpers;
1863 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1864 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1867 items.push_back (SeparatorElem());
1868 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1871 items.push_back (SeparatorElem());
1872 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1873 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1875 items.push_back (SeparatorElem());
1876 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1877 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1879 items.push_back (SeparatorElem());
1880 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1882 items.push_back (SeparatorElem());
1883 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1884 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1886 items.push_back (SeparatorElem());
1887 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1888 items.push_back (SeparatorElem());
1889 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1890 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1891 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1892 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1893 items.push_back (SeparatorElem());
1894 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1895 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1899 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1901 using namespace Menu_Helpers;
1905 Menu *play_menu = manage (new Menu);
1906 MenuList& play_items = play_menu->items();
1907 play_menu->set_name ("ArdourContextMenu");
1909 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
1910 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1911 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1912 play_items.push_back (SeparatorElem());
1913 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1915 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1919 Menu *select_menu = manage (new Menu);
1920 MenuList& select_items = select_menu->items();
1921 select_menu->set_name ("ArdourContextMenu");
1923 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1924 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1925 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1926 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1927 select_items.push_back (SeparatorElem());
1928 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1929 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1930 select_items.push_back (SeparatorElem());
1931 select_items.push_back (MenuElem (_("Select All After Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1932 select_items.push_back (MenuElem (_("Select All Before Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1933 select_items.push_back (MenuElem (_("Select All After Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1934 select_items.push_back (MenuElem (_("Select All Before Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1935 select_items.push_back (MenuElem (_("Select All Between Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), false)));
1936 select_items.push_back (MenuElem (_("Select All Within Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), true)));
1937 select_items.push_back (MenuElem (_("Select Range Between Playhead & Edit Point"), mem_fun(*this, &Editor::select_range_between)));
1940 select_items.push_back (SeparatorElem());
1942 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1946 Menu *cutnpaste_menu = manage (new Menu);
1947 MenuList& cutnpaste_items = cutnpaste_menu->items();
1948 cutnpaste_menu->set_name ("ArdourContextMenu");
1950 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1951 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1952 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1954 cutnpaste_items.push_back (SeparatorElem());
1956 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1957 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1959 cutnpaste_items.push_back (SeparatorElem());
1961 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1963 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1965 /* Adding new material */
1967 edit_items.push_back (SeparatorElem());
1968 edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1969 edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1973 Menu *nudge_menu = manage (new Menu());
1974 MenuList& nudge_items = nudge_menu->items();
1975 nudge_menu->set_name ("ArdourContextMenu");
1977 edit_items.push_back (SeparatorElem());
1978 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1979 nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1980 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1981 nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1983 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1987 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1989 using namespace Menu_Helpers;
1993 Menu *play_menu = manage (new Menu);
1994 MenuList& play_items = play_menu->items();
1995 play_menu->set_name ("ArdourContextMenu");
1997 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
1998 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1999 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2003 Menu *select_menu = manage (new Menu);
2004 MenuList& select_items = select_menu->items();
2005 select_menu->set_name ("ArdourContextMenu");
2007 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2008 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
2009 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2010 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
2011 select_items.push_back (SeparatorElem());
2012 select_items.push_back (MenuElem (_("Select all after edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2013 select_items.push_back (MenuElem (_("Select all before edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2014 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2015 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2017 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2021 Menu *cutnpaste_menu = manage (new Menu);
2022 MenuList& cutnpaste_items = cutnpaste_menu->items();
2023 cutnpaste_menu->set_name ("ArdourContextMenu");
2025 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2026 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2027 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2029 Menu *nudge_menu = manage (new Menu());
2030 MenuList& nudge_items = nudge_menu->items();
2031 nudge_menu->set_name ("ArdourContextMenu");
2033 edit_items.push_back (SeparatorElem());
2034 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2035 nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2036 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2037 nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2039 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2042 /* CURSOR SETTING AND MARKS AND STUFF */
2045 Editor::set_snap_to (SnapType st)
2048 string str = snap_type_strings[(int) st];
2050 if (str != snap_type_selector.get_active_text()) {
2051 snap_type_selector.set_active_text (str);
2056 switch (snap_type) {
2057 case SnapToAThirtysecondBeat:
2058 case SnapToASixteenthBeat:
2059 case SnapToAEighthBeat:
2060 case SnapToAQuarterBeat:
2061 case SnapToAThirdBeat:
2062 update_tempo_based_rulers ();
2070 Editor::set_snap_mode (SnapMode mode)
2073 string str = snap_mode_strings[(int)mode];
2075 if (str != snap_mode_selector.get_active_text ()) {
2076 snap_mode_selector.set_active_text (str);
2082 Editor::set_edit_point_preference (EditPoint ep)
2085 string str = edit_point_strings[(int)ep];
2087 if (str != edit_point_selector.get_active_text ()) {
2088 edit_point_selector.set_active_text (str);
2095 Editor::set_state (const XMLNode& node)
2097 const XMLProperty* prop;
2099 int x, y, xoff, yoff;
2102 if ((prop = node.property ("id")) != 0) {
2103 _id = prop->value ();
2106 if ((geometry = find_named_node (node, "geometry")) == 0) {
2108 g.base_width = default_width;
2109 g.base_height = default_height;
2117 g.base_width = atoi(geometry->property("x_size")->value());
2118 g.base_height = atoi(geometry->property("y_size")->value());
2119 x = atoi(geometry->property("x_pos")->value());
2120 y = atoi(geometry->property("y_pos")->value());
2121 xoff = atoi(geometry->property("x_off")->value());
2122 yoff = atoi(geometry->property("y_off")->value());
2125 set_default_size (g.base_width, g.base_height);
2128 if (session && (prop = node.property ("playhead"))) {
2129 nframes_t pos = atol (prop->value().c_str());
2130 playhead_cursor->set_position (pos);
2132 playhead_cursor->set_position (0);
2134 /* reset_x_origin() doesn't work right here, since the old
2135 position may be zero already, and it does nothing in such
2140 horizontal_adjustment.set_value (0);
2143 if ((prop = node.property ("mixer-width"))) {
2144 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2147 if ((prop = node.property ("zoom-focus"))) {
2148 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2151 if ((prop = node.property ("zoom"))) {
2152 reset_zoom (PBD::atof (prop->value()));
2155 if ((prop = node.property ("snap-to"))) {
2156 set_snap_to ((SnapType) atoi (prop->value()));
2159 if ((prop = node.property ("snap-mode"))) {
2160 set_snap_mode ((SnapMode) atoi (prop->value()));
2163 if ((prop = node.property ("edit-point"))) {
2164 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point));
2167 if ((prop = node.property ("mouse-mode"))) {
2168 MouseMode m = str2mousemode(prop->value());
2169 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2170 set_mouse_mode (m, true);
2172 mouse_mode = MouseGain; /* lie, to force the mode switch */
2173 set_mouse_mode (MouseObject, true);
2176 if ((prop = node.property ("show-waveforms"))) {
2177 bool yn = (prop->value() == "yes");
2178 _show_waveforms = !yn;
2179 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2181 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2182 /* do it twice to force the change */
2183 tact->set_active (!yn);
2184 tact->set_active (yn);
2188 if ((prop = node.property ("show-waveforms-recording"))) {
2189 bool yn = (prop->value() == "yes");
2190 _show_waveforms_recording = !yn;
2191 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2193 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2194 /* do it twice to force the change */
2195 tact->set_active (!yn);
2196 tact->set_active (yn);
2200 if ((prop = node.property ("show-measures"))) {
2201 bool yn = (prop->value() == "yes");
2202 _show_measures = !yn;
2203 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2205 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2206 /* do it twice to force the change */
2207 tact->set_active (!yn);
2208 tact->set_active (yn);
2212 if ((prop = node.property ("follow-playhead"))) {
2213 bool yn = (prop->value() == "yes");
2214 set_follow_playhead (yn);
2215 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2217 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2218 if (tact->get_active() != yn) {
2219 tact->set_active (yn);
2224 if ((prop = node.property ("region-list-sort-type"))) {
2225 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2226 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2229 if ((prop = node.property ("xfades-visible"))) {
2230 bool yn = (prop->value() == "yes");
2231 _xfade_visibility = !yn;
2232 // set_xfade_visibility (yn);
2235 if ((prop = node.property ("show-editor-mixer"))) {
2237 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2240 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2241 bool yn = (prop->value() == X_("yes"));
2243 /* do it twice to force the change */
2245 tact->set_active (!yn);
2246 tact->set_active (yn);
2255 Editor::get_state ()
2257 XMLNode* node = new XMLNode ("Editor");
2260 _id.print (buf, sizeof (buf));
2261 node->add_property ("id", buf);
2263 if (is_realized()) {
2264 Glib::RefPtr<Gdk::Window> win = get_window();
2266 int x, y, xoff, yoff, width, height;
2267 win->get_root_origin(x, y);
2268 win->get_position(xoff, yoff);
2269 win->get_size(width, height);
2271 XMLNode* geometry = new XMLNode ("geometry");
2273 snprintf(buf, sizeof(buf), "%d", width);
2274 geometry->add_property("x_size", string(buf));
2275 snprintf(buf, sizeof(buf), "%d", height);
2276 geometry->add_property("y_size", string(buf));
2277 snprintf(buf, sizeof(buf), "%d", x);
2278 geometry->add_property("x_pos", string(buf));
2279 snprintf(buf, sizeof(buf), "%d", y);
2280 geometry->add_property("y_pos", string(buf));
2281 snprintf(buf, sizeof(buf), "%d", xoff);
2282 geometry->add_property("x_off", string(buf));
2283 snprintf(buf, sizeof(buf), "%d", yoff);
2284 geometry->add_property("y_off", string(buf));
2285 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2286 geometry->add_property("edit_pane_pos", string(buf));
2288 node->add_child_nocopy (*geometry);
2291 maybe_add_mixer_strip_width (*node);
2293 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2294 node->add_property ("zoom-focus", buf);
2295 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2296 node->add_property ("zoom", buf);
2297 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2298 node->add_property ("snap-to", buf);
2299 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2300 node->add_property ("snap-mode", buf);
2302 node->add_property ("edit-point", enum_2_string (_edit_point));
2304 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2305 node->add_property ("playhead", buf);
2307 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2308 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2309 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2310 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2311 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2312 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2313 node->add_property ("mouse-mode", enum2str(mouse_mode));
2315 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2317 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2318 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2327 Editor::trackview_by_y_position (double y)
2329 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2333 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2342 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2344 Location* before = 0;
2345 Location* after = 0;
2351 const nframes64_t one_second = session->frame_rate();
2352 const nframes64_t one_minute = session->frame_rate() * 60;
2353 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2354 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2355 nframes64_t presnap = start;
2357 switch (snap_type) {
2363 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2365 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2369 case SnapToSMPTEFrame:
2370 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2371 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2373 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2377 case SnapToSMPTESeconds:
2378 if (session->smpte_offset_negative())
2380 start += session->smpte_offset ();
2382 start -= session->smpte_offset ();
2384 if (start % one_smpte_second > one_smpte_second / 2) {
2385 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2387 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2390 if (session->smpte_offset_negative())
2392 start -= session->smpte_offset ();
2394 start += session->smpte_offset ();
2398 case SnapToSMPTEMinutes:
2399 if (session->smpte_offset_negative())
2401 start += session->smpte_offset ();
2403 start -= session->smpte_offset ();
2405 if (start % one_smpte_minute > one_smpte_minute / 2) {
2406 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2408 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2410 if (session->smpte_offset_negative())
2412 start -= session->smpte_offset ();
2414 start += session->smpte_offset ();
2419 if (start % one_second > one_second / 2) {
2420 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2422 start = (nframes_t) floor ((double) start / one_second) * one_second;
2427 if (start % one_minute > one_minute / 2) {
2428 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2430 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2435 start = session->tempo_map().round_to_bar (start, direction);
2439 start = session->tempo_map().round_to_beat (start, direction);
2442 case SnapToAThirtysecondBeat:
2443 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2446 case SnapToASixteenthBeat:
2447 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2450 case SnapToAEighthBeat:
2451 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2454 case SnapToAQuarterBeat:
2455 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2458 case SnapToAThirdBeat:
2459 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2462 case SnapToEditPoint:
2463 start = get_preferred_edit_position ();
2471 before = session->locations()->first_location_before (start);
2472 after = session->locations()->first_location_after (start);
2474 if (direction < 0) {
2476 start = before->start();
2480 } else if (direction > 0) {
2482 start = after->start();
2484 start = session->current_end_frame();
2489 /* find nearest of the two */
2490 if ((start - before->start()) < (after->start() - start)) {
2491 start = before->start();
2493 start = after->start();
2496 start = before->start();
2499 start = after->start();
2506 case SnapToRegionStart:
2507 case SnapToRegionEnd:
2508 case SnapToRegionSync:
2509 case SnapToRegionBoundary:
2510 if (!region_boundary_cache.empty()) {
2511 vector<nframes_t>::iterator i;
2513 if (direction > 0) {
2514 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2516 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2519 if (i != region_boundary_cache.end()) {
2522 start = region_boundary_cache.back();
2528 switch (snap_mode) {
2534 if (presnap > start) {
2535 if (presnap > (start + unit_to_frame(snap_threshold))) {
2539 } else if (presnap < start) {
2540 if (presnap < (start - unit_to_frame(snap_threshold))) {
2552 Editor::setup_toolbar ()
2556 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2559 /* Mode Buttons (tool selection) */
2561 vector<ToggleButton *> mouse_mode_buttons;
2563 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2564 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2565 mouse_mode_buttons.push_back (&mouse_move_button);
2566 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2567 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2568 mouse_mode_buttons.push_back (&mouse_select_button);
2569 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2570 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2571 mouse_mode_buttons.push_back (&mouse_gain_button);
2572 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2573 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2574 mouse_mode_buttons.push_back (&mouse_zoom_button);
2575 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2576 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2577 mouse_mode_buttons.push_back (&mouse_timefx_button);
2578 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2579 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2580 mouse_mode_buttons.push_back (&mouse_audition_button);
2582 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2584 HBox* mode_box = manage(new HBox);
2585 mode_box->set_border_width (2);
2586 mode_box->set_spacing(4);
2587 mouse_mode_button_box.set_spacing(1);
2588 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2589 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2590 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2591 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2592 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2593 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2594 mouse_mode_button_box.set_homogeneous(true);
2596 vector<string> edit_mode_strings;
2597 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2598 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2600 edit_mode_selector.set_name ("EditModeSelector");
2601 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2602 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2603 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2605 mode_box->pack_start(edit_mode_selector);
2606 mode_box->pack_start(mouse_mode_button_box);
2608 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2609 mouse_mode_tearoff->set_name ("MouseModeBase");
2611 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2612 &mouse_mode_tearoff->tearoff_window()));
2613 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2614 &mouse_mode_tearoff->tearoff_window(), 1));
2615 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2616 &mouse_mode_tearoff->tearoff_window()));
2617 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2618 &mouse_mode_tearoff->tearoff_window(), 1));
2620 mouse_move_button.set_name ("MouseModeButton");
2621 mouse_select_button.set_name ("MouseModeButton");
2622 mouse_gain_button.set_name ("MouseModeButton");
2623 mouse_zoom_button.set_name ("MouseModeButton");
2624 mouse_timefx_button.set_name ("MouseModeButton");
2625 mouse_audition_button.set_name ("MouseModeButton");
2627 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2628 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2629 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2630 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2631 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2632 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2634 mouse_move_button.unset_flags (CAN_FOCUS);
2635 mouse_select_button.unset_flags (CAN_FOCUS);
2636 mouse_gain_button.unset_flags (CAN_FOCUS);
2637 mouse_zoom_button.unset_flags (CAN_FOCUS);
2638 mouse_timefx_button.unset_flags (CAN_FOCUS);
2639 mouse_audition_button.unset_flags (CAN_FOCUS);
2641 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2642 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2644 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2645 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2646 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2647 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2648 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2650 // mouse_move_button.set_active (true);
2655 zoom_box.set_spacing (1);
2656 zoom_box.set_border_width (2);
2658 zoom_in_button.set_name ("EditorTimeButton");
2659 zoom_in_button.set_size_request(-1,16);
2660 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2661 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2662 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2664 zoom_out_button.set_name ("EditorTimeButton");
2665 zoom_out_button.set_size_request(-1,16);
2666 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2667 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2668 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2670 zoom_out_full_button.set_name ("EditorTimeButton");
2671 zoom_out_full_button.set_size_request(-1,16);
2672 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2673 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2674 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2676 zoom_focus_selector.set_name ("ZoomFocusSelector");
2677 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Playhead", FUDGE, 0);
2678 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2679 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2680 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2682 zoom_box.pack_start (zoom_focus_selector, true, true);
2683 zoom_box.pack_start (zoom_out_button, false, false);
2684 zoom_box.pack_start (zoom_in_button, false, false);
2685 zoom_box.pack_start (zoom_out_full_button, false, false);
2687 snap_box.set_spacing (1);
2688 snap_box.set_border_width (2);
2690 snap_type_selector.set_name ("SnapTypeSelector");
2691 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2692 set_popdown_strings (snap_type_selector, snap_type_strings);
2693 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2694 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
2696 snap_mode_selector.set_name ("SnapModeSelector");
2697 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2698 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2699 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2700 ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2702 edit_point_selector.set_name ("SnapModeSelector");
2703 Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, "Playhead", 2+FUDGE, 10);
2704 set_popdown_strings (edit_point_selector, edit_point_strings);
2705 edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
2706 ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
2708 snap_box.pack_start (edit_point_clock, false, false);
2709 snap_box.pack_start (snap_mode_selector, false, false);
2710 snap_box.pack_start (snap_type_selector, false, false);
2711 snap_box.pack_start (edit_point_selector, false, false);
2715 HBox *nudge_box = manage (new HBox);
2716 nudge_box->set_spacing(1);
2717 nudge_box->set_border_width (2);
2719 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2720 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2722 nudge_box->pack_start (nudge_backward_button, false, false);
2723 nudge_box->pack_start (nudge_forward_button, false, false);
2724 nudge_box->pack_start (nudge_clock, false, false);
2727 /* Pack everything in... */
2729 HBox* hbox = new HBox;
2730 hbox->set_spacing(10);
2732 tools_tearoff = new TearOff (*hbox);
2733 tools_tearoff->set_name ("MouseModeBase");
2735 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2736 &tools_tearoff->tearoff_window()));
2737 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2738 &tools_tearoff->tearoff_window(), 0));
2739 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2740 &tools_tearoff->tearoff_window()));
2741 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2742 &tools_tearoff->tearoff_window(), 0));
2744 toolbar_hbox.set_spacing (10);
2745 toolbar_hbox.set_border_width (1);
2747 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2748 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2751 hbox->pack_start (snap_box, false, false);
2752 // hbox->pack_start (zoom_box, false, false);
2753 hbox->pack_start (*nudge_box, false, false);
2757 toolbar_base.set_name ("ToolBarBase");
2758 toolbar_base.add (toolbar_hbox);
2760 toolbar_frame.set_shadow_type (SHADOW_OUT);
2761 toolbar_frame.set_name ("BaseFrame");
2762 toolbar_frame.add (toolbar_base);
2766 Editor::convert_drop_to_paths (vector<ustring>& paths,
2767 const RefPtr<Gdk::DragContext>& context,
2770 const SelectionData& data,
2779 vector<ustring> uris = data.get_uris();
2783 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2784 are actually URI lists. So do it by hand.
2787 if (data.get_target() != "text/plain") {
2791 /* Parse the "uri-list" format that Nautilus provides,
2792 where each pathname is delimited by \r\n
2795 const char* p = data.get_text().c_str();
2802 while (g_ascii_isspace (*p))
2806 while (*q && (*q != '\n') && (*q != '\r'))
2812 while (q > p && g_ascii_isspace (*q))
2817 uris.push_back (ustring (p, q - p + 1));
2821 p = strchr (p, '\n');
2831 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2833 if ((*i).substr (0,7) == "file://") {
2837 PBD::url_decode (p);
2839 // scan forward past three slashes
2841 ustring::size_type slashcnt = 0;
2842 ustring::size_type n = 0;
2843 ustring::iterator x = p.begin();
2845 while (slashcnt < 3 && x != p.end()) {
2848 } else if (slashcnt == 3) {
2855 if (slashcnt != 3 || x == p.end()) {
2856 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2860 paths.push_back (p.substr (n - 1));
2868 Editor::new_tempo_section ()
2874 Editor::map_transport_state ()
2876 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2878 if (session->transport_stopped()) {
2879 have_pending_keyboard_selection = false;
2882 update_loop_range_view (true);
2887 Editor::State::State ()
2889 selection = new Selection;
2892 Editor::State::~State ()
2898 Editor::get_memento () const
2900 State *state = new State;
2902 store_state (*state);
2903 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2907 Editor::store_state (State& state) const
2909 *state.selection = *selection;
2913 Editor::restore_state (State *state)
2915 if (*selection == *state->selection) {
2919 *selection = *state->selection;
2920 time_selection_changed ();
2921 region_selection_changed ();
2923 /* XXX other selection change handlers? */
2927 Editor::begin_reversible_command (string name)
2930 // before = &get_state();
2931 session->begin_reversible_command (name);
2936 Editor::commit_reversible_command ()
2939 // session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2940 session->commit_reversible_command ();
2945 Editor::set_edit_group_solo (Route& route, bool yn)
2947 RouteGroup *edit_group;
2949 if ((edit_group = route.edit_group()) != 0) {
2950 edit_group->apply (&Route::set_solo, yn, this);
2952 route.set_solo (yn, this);
2957 Editor::set_edit_group_mute (Route& route, bool yn)
2959 RouteGroup *edit_group = 0;
2961 if ((edit_group == route.edit_group()) != 0) {
2962 edit_group->apply (&Route::set_mute, yn, this);
2964 route.set_mute (yn, this);
2969 Editor::history_changed ()
2973 if (undo_action && session) {
2974 if (session->undo_depth() == 0) {
2977 label = string_compose(_("Undo (%1)"), session->next_undo());
2979 undo_action->property_label() = label;
2982 if (redo_action && session) {
2983 if (session->redo_depth() == 0) {
2986 label = string_compose(_("Redo (%1)"), session->next_redo());
2988 redo_action->property_label() = label;
2993 Editor::duplicate_dialog (bool dup_region)
2995 if (selection->regions.empty() && (selection->time.length() == 0)) {
2999 ArdourDialog win ("duplicate dialog");
3000 Label label (_("Duplicate how many times?"));
3001 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3002 SpinButton spinner (adjustment);
3004 win.get_vbox()->set_spacing (12);
3005 win.get_vbox()->pack_start (label);
3007 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3008 place, visually. so do this by hand.
3011 win.get_vbox()->pack_start (spinner);
3012 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3017 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3018 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3020 win.set_position (WIN_POS_MOUSE);
3022 spinner.grab_focus ();
3024 switch (win.run ()) {
3025 case RESPONSE_ACCEPT:
3031 float times = adjustment.get_value();
3033 if (!selection->regions.empty()) {
3034 duplicate_some_regions (selection->regions, times);
3036 duplicate_selection (times);
3041 Editor::show_verbose_canvas_cursor ()
3043 verbose_canvas_cursor->raise_to_top();
3044 verbose_canvas_cursor->show();
3045 verbose_cursor_visible = true;
3049 Editor::hide_verbose_canvas_cursor ()
3051 verbose_canvas_cursor->hide();
3052 verbose_cursor_visible = false;
3056 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3058 /* XXX get origin of canvas relative to root window,
3059 add x and y and check compared to gdk_screen_{width,height}
3061 verbose_canvas_cursor->property_text() = txt.c_str();
3062 verbose_canvas_cursor->property_x() = x;
3063 verbose_canvas_cursor->property_y() = y;
3067 Editor::set_verbose_canvas_cursor_text (const string & txt)
3069 verbose_canvas_cursor->property_text() = txt.c_str();
3073 Editor::edit_mode_selection_done ()
3079 string choice = edit_mode_selector.get_active_text();
3080 EditMode mode = Slide;
3082 if (choice == _("Splice Edit")) {
3084 } else if (choice == _("Slide Edit")) {
3088 Config->set_edit_mode (mode);
3092 Editor::snap_type_selection_done ()
3094 string choice = snap_type_selector.get_active_text();
3095 SnapType snaptype = SnapToFrame;
3097 if (choice == _("Beats/3")) {
3098 snaptype = SnapToAThirdBeat;
3099 } else if (choice == _("Beats/4")) {
3100 snaptype = SnapToAQuarterBeat;
3101 } else if (choice == _("Beats/8")) {
3102 snaptype = SnapToAEighthBeat;
3103 } else if (choice == _("Beats/16")) {
3104 snaptype = SnapToASixteenthBeat;
3105 } else if (choice == _("Beats/32")) {
3106 snaptype = SnapToAThirtysecondBeat;
3107 } else if (choice == _("Beats")) {
3108 snaptype = SnapToBeat;
3109 } else if (choice == _("Bars")) {
3110 snaptype = SnapToBar;
3111 } else if (choice == _("Marks")) {
3112 snaptype = SnapToMark;
3113 } else if (choice == _("Edit Point")) {
3114 snaptype = SnapToEditPoint;
3115 } else if (choice == _("Region starts")) {
3116 snaptype = SnapToRegionStart;
3117 } else if (choice == _("Region ends")) {
3118 snaptype = SnapToRegionEnd;
3119 } else if (choice == _("Region bounds")) {
3120 snaptype = SnapToRegionBoundary;
3121 } else if (choice == _("Region syncs")) {
3122 snaptype = SnapToRegionSync;
3123 } else if (choice == _("CD Frames")) {
3124 snaptype = SnapToCDFrame;
3125 } else if (choice == _("SMPTE Frames")) {
3126 snaptype = SnapToSMPTEFrame;
3127 } else if (choice == _("SMPTE Seconds")) {
3128 snaptype = SnapToSMPTESeconds;
3129 } else if (choice == _("SMPTE Minutes")) {
3130 snaptype = SnapToSMPTEMinutes;
3131 } else if (choice == _("Seconds")) {
3132 snaptype = SnapToSeconds;
3133 } else if (choice == _("Minutes")) {
3134 snaptype = SnapToMinutes;
3135 } else if (choice == _("None")) {
3136 snaptype = SnapToFrame;
3139 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3141 ract->set_active ();
3146 Editor::snap_mode_selection_done ()
3148 string choice = snap_mode_selector.get_active_text();
3149 SnapMode mode = SnapNormal;
3151 if (choice == _("Normal")) {
3153 } else if (choice == _("Magnetic")) {
3154 mode = SnapMagnetic;
3157 RefPtr<RadioAction> ract = snap_mode_action (mode);
3160 ract->set_active (true);
3165 Editor::edit_point_selection_done ()
3167 string choice = edit_point_selector.get_active_text();
3168 EditPoint ep = EditAtSelectedMarker;
3170 if (choice == _("Marker")) {
3171 _edit_point = EditAtSelectedMarker;
3172 } else if (choice == _("Playhead")) {
3173 _edit_point = EditAtPlayhead;
3175 _edit_point = EditAtMouse;
3178 RefPtr<RadioAction> ract = edit_point_action (ep);
3181 ract->set_active (true);
3186 Editor::zoom_focus_selection_done ()
3188 string choice = zoom_focus_selector.get_active_text();
3189 ZoomFocus focus_type = ZoomFocusLeft;
3191 if (choice == _("Left")) {
3192 focus_type = ZoomFocusLeft;
3193 } else if (choice == _("Right")) {
3194 focus_type = ZoomFocusRight;
3195 } else if (choice == _("Center")) {
3196 focus_type = ZoomFocusCenter;
3197 } else if (choice == _("Playhead")) {
3198 focus_type = ZoomFocusPlayhead;
3199 } else if (choice == _("Mouse")) {
3200 focus_type = ZoomFocusMouse;
3201 } else if (choice == _("Edit Point")) {
3202 focus_type = ZoomFocusEdit;
3205 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3208 ract->set_active ();
3213 Editor::edit_controls_button_release (GdkEventButton* ev)
3215 if (Keyboard::is_context_menu_event (ev)) {
3216 ARDOUR_UI::instance()->add_route (this);
3222 Editor::mouse_select_button_release (GdkEventButton* ev)
3224 /* this handles just right-clicks */
3226 if (ev->button != 3) {
3233 Editor::TrackViewList *
3234 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3237 TrackViewList::iterator i;
3239 v = new TrackViewList;
3241 if (track == 0 && group == 0) {
3245 for (i = track_views.begin(); i != track_views.end (); ++i) {
3249 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3251 /* just the view for this track
3254 v->push_back (track);
3258 /* views for all tracks in the edit group */
3260 for (i = track_views.begin(); i != track_views.end (); ++i) {
3262 if (group == 0 || (*i)->edit_group() == group) {
3272 Editor::set_zoom_focus (ZoomFocus f)
3274 string str = zoom_focus_strings[(int)f];
3276 if (str != zoom_focus_selector.get_active_text()) {
3277 zoom_focus_selector.set_active_text (str);
3280 if (zoom_focus != f) {
3283 ZoomFocusChanged (); /* EMIT_SIGNAL */
3290 Editor::ensure_float (Window& win)
3292 win.set_transient_for (*this);
3296 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3298 /* recover or initialize pane positions. do this here rather than earlier because
3299 we don't want the positions to change the child allocations, which they seem to do.
3305 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3307 static int32_t done;
3310 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3311 width = default_width;
3312 height = default_height;
3314 width = atoi(geometry->property("x_size")->value());
3315 height = atoi(geometry->property("y_size")->value());
3318 if (which == static_cast<Paned*> (&edit_pane)) {
3324 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3325 /* initial allocation is 90% to canvas, 10% to notebook */
3326 pos = (int) floor (alloc.get_width() * 0.90f);
3327 snprintf (buf, sizeof(buf), "%d", pos);
3329 pos = atoi (prop->value());
3332 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3333 edit_pane.set_position (pos);
3334 pre_maximal_pane_position = pos;
3340 Editor::detach_tearoff (Box* b, Window* w)
3342 if (tools_tearoff->torn_off() &&
3343 mouse_mode_tearoff->torn_off()) {
3344 top_hbox.remove (toolbar_frame);
3349 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3351 if (toolbar_frame.get_parent() == 0) {
3352 top_hbox.pack_end (toolbar_frame);
3357 Editor::set_show_measures (bool yn)
3359 if (_show_measures != yn) {
3362 if ((_show_measures = yn) == true) {
3370 Editor::toggle_follow_playhead ()
3372 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3374 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3375 set_follow_playhead (tact->get_active());
3380 Editor::set_follow_playhead (bool yn)
3382 if (_follow_playhead != yn) {
3383 if ((_follow_playhead = yn) == true) {
3385 update_current_screen ();
3392 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3394 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3396 xfade->set_active (!xfade->active());
3401 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3403 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3405 xfade->set_follow_overlap (!xfade->following_overlap());
3410 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3412 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3418 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3422 switch (cew.run ()) {
3423 case RESPONSE_ACCEPT:
3430 xfade->StateChanged (Change (~0));
3434 Editor::playlist_selector () const
3436 return *_playlist_selector;
3440 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3444 ret = nudge_clock.current_duration (pos);
3445 next = ret + 1; /* XXXX fix me */
3451 Editor::end_location_changed (Location* location)
3453 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3454 reset_scrolling_region ();
3458 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3460 ArdourDialog dialog ("playlist deletion dialog");
3461 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3462 "If left alone, no audio files used by it will be cleaned.\n"
3463 "If deleted, audio files used by it alone by will cleaned."),
3466 dialog.set_position (WIN_POS_CENTER);
3467 dialog.get_vbox()->pack_start (label);
3471 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3472 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3473 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3475 switch (dialog.run ()) {
3476 case RESPONSE_ACCEPT:
3477 /* delete the playlist */
3481 case RESPONSE_REJECT:
3482 /* keep the playlist */
3494 Editor::audio_region_selection_covers (nframes_t where)
3496 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3497 if ((*a)->region()->covers (where)) {
3506 Editor::prepare_for_cleanup ()
3508 cut_buffer->clear_regions ();
3509 cut_buffer->clear_playlists ();
3511 selection->clear_regions ();
3512 selection->clear_playlists ();
3516 Editor::transport_loop_location()
3519 return session->locations()->auto_loop_location();
3526 Editor::transport_punch_location()
3529 return session->locations()->auto_punch_location();
3536 Editor::control_layout_scroll (GdkEventScroll* ev)
3538 switch (ev->direction) {
3540 scroll_tracks_up_line ();
3544 case GDK_SCROLL_DOWN:
3545 scroll_tracks_down_line ();
3549 /* no left/right handling yet */
3557 /** A new snapshot has been selected.
3560 Editor::snapshot_display_selection_changed ()
3562 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3564 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3566 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3568 if (snap_name.length() == 0) {
3572 if (session->snap_name() == snap_name) {
3576 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3581 Editor::snapshot_display_button_press (GdkEventButton* ev)
3583 if (ev->button == 3) {
3584 /* Right-click on the snapshot list. Work out which snapshot it
3586 Gtk::TreeModel::Path path;
3587 Gtk::TreeViewColumn* col;
3590 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3591 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3593 Gtk::TreeModel::Row row = *iter;
3594 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3603 /** Pop up the snapshot display context menu.
3604 * @param button Button used to open the menu.
3605 * @param time Menu open time.
3606 * @snapshot_name Name of the snapshot that the menu click was over.
3610 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3612 using namespace Menu_Helpers;
3614 MenuList& items (snapshot_context_menu.items());
3617 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3619 items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)));
3620 if (!modification_allowed) {
3621 items.back().set_sensitive (false);
3624 items.push_back (MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)));
3625 if (!modification_allowed) {
3626 items.back().set_sensitive (false);
3629 snapshot_context_menu.popup (button, time);
3633 Editor::rename_snapshot (Glib::ustring old_name)
3635 ArdourPrompter prompter(true);
3639 prompter.set_name ("Prompter");
3640 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3641 prompter.set_prompt (_("New name of snapshot"));
3642 prompter.set_initial_text (old_name);
3644 if (prompter.run() == RESPONSE_ACCEPT) {
3645 prompter.get_result (new_name);
3646 if (new_name.length()) {
3647 session->rename_state (old_name, new_name);
3648 redisplay_snapshots ();
3655 Editor::remove_snapshot (Glib::ustring name)
3657 vector<string> choices;
3659 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3661 choices.push_back (_("No, do nothing."));
3662 choices.push_back (_("Yes, remove it."));
3664 Gtkmm2ext::Choice prompter (prompt, choices);
3666 if (prompter.run () == 1) {
3667 session->remove_state (name);
3668 redisplay_snapshots ();
3673 Editor::redisplay_snapshots ()
3679 vector<string*>* states;
3681 if ((states = session->possible_states()) == 0) {
3685 snapshot_display_model->clear ();
3687 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3688 string statename = *(*i);
3689 TreeModel::Row row = *(snapshot_display_model->append());
3691 /* this lingers on in case we ever want to change the visible
3692 name of the snapshot.
3695 string display_name;
3696 display_name = statename;
3698 if (statename == session->snap_name()) {
3699 snapshot_display.get_selection()->select(row);
3702 row[snapshot_display_columns.visible_name] = display_name;
3703 row[snapshot_display_columns.real_name] = statename;
3710 Editor::session_state_saved (string snap_name)
3712 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3713 redisplay_snapshots ();
3717 Editor::maximise_editing_space ()
3719 initial_ruler_update_required = true;
3721 mouse_mode_tearoff->set_visible (false);
3722 tools_tearoff->set_visible (false);
3724 pre_maximal_pane_position = edit_pane.get_position();
3725 pre_maximal_editor_width = this->get_width();
3727 if(post_maximal_pane_position == 0) {
3728 post_maximal_pane_position = edit_pane.get_width();
3733 if(post_maximal_editor_width) {
3734 edit_pane.set_position (post_maximal_pane_position -
3735 abs(post_maximal_editor_width - pre_maximal_editor_width));
3737 edit_pane.set_position (post_maximal_pane_position);
3742 Editor::restore_editing_space ()
3744 initial_ruler_update_required = true;
3746 // user changed width of pane during fullscreen
3747 if(post_maximal_pane_position != edit_pane.get_position()) {
3748 post_maximal_pane_position = edit_pane.get_position();
3753 mouse_mode_tearoff->set_visible (true);
3754 tools_tearoff->set_visible (true);
3755 post_maximal_editor_width = this->get_width();
3758 edit_pane.set_position (
3759 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3764 * Make new playlists for a given track and also any others that belong
3765 * to the same active edit group.
3770 Editor::new_playlists (TimeAxisView* v)
3772 begin_reversible_command (_("new playlists"));
3773 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3774 commit_reversible_command ();
3779 * Use a copy of the current playlist for a given track and also any others that belong
3780 * to the same active edit group.
3785 Editor::copy_playlists (TimeAxisView* v)
3787 begin_reversible_command (_("copy playlists"));
3788 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3789 commit_reversible_command ();
3794 * Clear the current playlist for a given track and also any others that belong
3795 * to the same active edit group.
3800 Editor::clear_playlists (TimeAxisView* v)
3802 begin_reversible_command (_("clear playlists"));
3803 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3804 commit_reversible_command ();
3808 Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz)
3810 atv.use_new_playlist (sz > 1 ? false : true);
3814 Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz)
3816 atv.use_copy_playlist (sz > 1 ? false : true);
3820 Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz)
3822 atv.clear_playlist ();
3826 Editor::on_key_press_event (GdkEventKey* ev)
3828 return key_press_focus_accelerator_handler (*this, ev);
3832 Editor::reset_x_origin (nframes_t frame)
3834 queue_visual_change (frame);
3838 Editor::reset_zoom (double fpu)
3840 queue_visual_change (fpu);
3844 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3846 reset_x_origin (frame);
3851 Editor::set_frames_per_unit (double fpu)
3855 /* this is the core function that controls the zoom level of the canvas. it is called
3856 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3859 if (fpu == frames_per_unit) {
3867 // convert fpu to frame count
3869 frames = (nframes_t) floor (fpu * canvas_width);
3871 /* don't allow zooms that fit more than the maximum number
3872 of frames into an 800 pixel wide space.
3875 if (max_frames / fpu < 800.0) {
3879 if (fpu == frames_per_unit) {
3883 frames_per_unit = fpu;
3885 if (frames != zoom_range_clock.current_duration()) {
3886 zoom_range_clock.set (frames);
3889 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3890 if (!selection->tracks.empty()) {
3891 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3892 (*i)->reshow_selection (selection->time);
3895 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3896 (*i)->reshow_selection (selection->time);
3901 ZoomChanged (); /* EMIT_SIGNAL */
3903 reset_hscrollbar_stepping ();
3904 reset_scrolling_region ();
3906 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3912 Editor::queue_visual_change (nframes_t where)
3914 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3915 pending_visual_change.time_origin = where;
3917 if (pending_visual_change.idle_handler_id < 0) {
3918 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3923 Editor::queue_visual_change (double fpu)
3925 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3926 pending_visual_change.frames_per_unit = fpu;
3928 if (pending_visual_change.idle_handler_id < 0) {
3929 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3934 Editor::_idle_visual_changer (void* arg)
3936 return static_cast<Editor*>(arg)->idle_visual_changer ();
3940 Editor::idle_visual_changer ()
3942 VisualChange::Type p = pending_visual_change.pending;
3944 pending_visual_change.pending = (VisualChange::Type) 0;
3945 pending_visual_change.idle_handler_id = -1;
3947 if (p & VisualChange::ZoomLevel) {
3948 set_frames_per_unit (pending_visual_change.frames_per_unit);
3951 if (p & VisualChange::TimeOrigin) {
3952 if (pending_visual_change.time_origin != leftmost_frame) {
3953 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3954 /* the signal handler will do the rest */
3956 update_fixed_rulers();
3957 redisplay_tempo (true);
3961 return 0; /* this is always a one-shot call */
3964 struct EditorOrderTimeAxisSorter {
3965 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3966 return a->order < b->order;
3971 Editor::sort_track_selection ()
3973 EditorOrderTimeAxisSorter cmp;
3974 selection->tracks.sort (cmp);
3978 Editor::get_preferred_edit_position()
3981 nframes64_t where = 0;
3983 switch (_edit_point) {
3984 case EditAtPlayhead:
3985 where = session->audible_frame();
3988 case EditAtSelectedMarker:
3989 if (!selection->markers.empty()) {
3991 Location* loc = find_location_from_marker (selection->markers.front(), whocares);
3993 where = loc->start();
4001 if (!mouse_frame (where, ignored)) {
4002 /* XXX not right but what can we do ? */
4013 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4015 if (!session) return;
4017 begin_reversible_command (cmd);
4021 if ((tll = transport_loop_location()) == 0) {
4022 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4023 XMLNode &before = session->locations()->get_state();
4024 session->locations()->add (loc, true);
4025 session->set_auto_loop_location (loc);
4026 XMLNode &after = session->locations()->get_state();
4027 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4030 XMLNode &before = tll->get_state();
4031 tll->set_hidden (false, this);
4032 tll->set (start, end);
4033 XMLNode &after = tll->get_state();
4034 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4037 commit_reversible_command ();
4041 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4043 if (!session) return;
4045 begin_reversible_command (cmd);
4049 if ((tpl = transport_punch_location()) == 0) {
4050 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4051 XMLNode &before = session->locations()->get_state();
4052 session->locations()->add (loc, true);
4053 session->set_auto_loop_location (loc);
4054 XMLNode &after = session->locations()->get_state();
4055 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4058 XMLNode &before = tpl->get_state();
4059 tpl->set_hidden (false, this);
4060 tpl->set (start, end);
4061 XMLNode &after = tpl->get_state();
4062 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4065 commit_reversible_command ();
4069 Editor::get_regions_at (nframes64_t where, const TrackSelection& ts) const
4072 const TrackSelection* tracks;
4075 tracks = &track_views;
4080 for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4082 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4085 boost::shared_ptr<Diskstream> ds;
4086 boost::shared_ptr<Playlist> pl;
4088 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4090 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)where * ds->speed()));
4092 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4094 RegionView* rv = atv->audio_view()->find_view (*i);