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;
167 Gdk::Cursor* Editor::transparent_cursor = 0;
170 show_me_the_size (Requisition* r, const char* what)
172 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
177 /* time display buttons */
178 minsec_label (_("Mins:Secs")),
179 bbt_label (_("Bars:Beats")),
180 smpte_label (_("Timecode")),
181 frame_label (_("Frames")),
182 tempo_label (_("Tempo")),
183 meter_label (_("Meter")),
184 mark_label (_("Location Markers")),
185 range_mark_label (_("Range Markers")),
186 transport_mark_label (_("Loop/Punch Ranges")),
188 edit_packer (3, 3, false),
190 /* the values here don't matter: layout widgets
191 reset them as needed.
194 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
195 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
197 /* tool bar related */
199 edit_point_clock (X_("editpoint"), false, X_("EditPointClock"), true),
200 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
202 toolbar_selection_clock_table (2,3),
204 automation_mode_button (_("mode")),
205 global_automation_button (_("automation")),
207 /* <CMT Additions> */
208 image_socket_listener(0),
209 /* </CMT Additions> */
213 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
218 /* we are a singleton */
220 PublicEditor::_instance = this;
224 selection = new Selection;
225 cut_buffer = new Selection;
227 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
228 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
229 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
230 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
231 selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed));
233 clicked_regionview = 0;
234 clicked_trackview = 0;
235 clicked_audio_trackview = 0;
236 clicked_crossfadeview = 0;
237 clicked_control_point = 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);
1287 RefPtr<Bitmap> bits;
1288 char pix[4] = { 0, 0, 0, 0 };
1289 bits = Bitmap::create (pix, 2, 2);
1291 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1294 grabber_cursor = new Gdk::Cursor (HAND2);
1295 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1296 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1297 selector_cursor = new Gdk::Cursor (XTERM);
1298 time_fx_cursor = new Gdk::Cursor (SIZING);
1299 wait_cursor = new Gdk::Cursor (WATCH);
1300 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1304 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1306 using namespace Menu_Helpers;
1307 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1310 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1314 MenuList& items (fade_context_menu.items());
1318 switch (item_type) {
1320 case FadeInHandleItem:
1321 if (arv->audio_region()->fade_in_active()) {
1322 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1324 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1327 items.push_back (SeparatorElem());
1329 if (Profile->get_sae()) {
1330 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1331 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1333 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1334 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1335 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1336 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1337 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1342 case FadeOutHandleItem:
1343 if (arv->audio_region()->fade_out_active()) {
1344 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1346 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1349 items.push_back (SeparatorElem());
1351 if (Profile->get_sae()) {
1352 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1353 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1355 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1356 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1357 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1358 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1359 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1364 fatal << _("programming error: ")
1365 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1370 fade_context_menu.popup (button, time);
1374 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes_t frame)
1376 using namespace Menu_Helpers;
1377 Menu* (Editor::*build_menu_function)(nframes_t);
1380 switch (item_type) {
1382 case RegionViewName:
1383 case RegionViewNameHighlight:
1384 if (with_selection) {
1385 build_menu_function = &Editor::build_track_selection_context_menu;
1387 build_menu_function = &Editor::build_track_region_context_menu;
1392 if (with_selection) {
1393 build_menu_function = &Editor::build_track_selection_context_menu;
1395 build_menu_function = &Editor::build_track_context_menu;
1399 case CrossfadeViewItem:
1400 build_menu_function = &Editor::build_track_crossfade_context_menu;
1404 if (clicked_audio_trackview->get_diskstream()) {
1405 build_menu_function = &Editor::build_track_context_menu;
1407 build_menu_function = &Editor::build_track_bus_context_menu;
1412 /* probably shouldn't happen but if it does, we don't care */
1416 menu = (this->*build_menu_function)(frame);
1417 menu->set_name ("ArdourContextMenu");
1419 /* now handle specific situations */
1421 switch (item_type) {
1423 case RegionViewName:
1424 case RegionViewNameHighlight:
1425 if (!with_selection) {
1426 if (region_edit_menu_split_item) {
1427 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1428 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1430 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1434 if (region_edit_menu_split_multichannel_item) {
1435 if (clicked_regionview && clicked_regionview->region().n_channels() > 1) {
1436 // GTK2FIX find the action, change its sensitivity
1437 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1439 // GTK2FIX see above
1440 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1449 case CrossfadeViewItem:
1456 /* probably shouldn't happen but if it does, we don't care */
1460 if (item_type != SelectionItem && clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1462 /* Bounce to disk */
1464 using namespace Menu_Helpers;
1465 MenuList& edit_items = menu->items();
1467 edit_items.push_back (SeparatorElem());
1469 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1470 case AudioTrack::NoFreeze:
1471 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1474 case AudioTrack::Frozen:
1475 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1478 case AudioTrack::UnFrozen:
1479 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1485 menu->popup (button, time);
1489 Editor::build_track_context_menu (nframes_t ignored)
1491 using namespace Menu_Helpers;
1493 MenuList& edit_items = track_context_menu.items();
1496 add_dstream_context_items (edit_items);
1497 return &track_context_menu;
1501 Editor::build_track_bus_context_menu (nframes_t ignored)
1503 using namespace Menu_Helpers;
1505 MenuList& edit_items = track_context_menu.items();
1508 add_bus_context_items (edit_items);
1509 return &track_context_menu;
1513 Editor::build_track_region_context_menu (nframes_t frame)
1515 using namespace Menu_Helpers;
1516 MenuList& edit_items = track_region_context_menu.items();
1519 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1522 boost::shared_ptr<Diskstream> ds;
1523 boost::shared_ptr<Playlist> pl;
1525 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1526 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)frame * ds->speed()));
1527 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1528 add_region_context_items (atv->audio_view(), (*i), edit_items);
1534 add_dstream_context_items (edit_items);
1536 return &track_region_context_menu;
1540 Editor::build_track_crossfade_context_menu (nframes_t frame)
1542 using namespace Menu_Helpers;
1543 MenuList& edit_items = track_crossfade_context_menu.items();
1544 edit_items.clear ();
1546 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1549 boost::shared_ptr<Diskstream> ds;
1550 boost::shared_ptr<Playlist> pl;
1551 boost::shared_ptr<AudioPlaylist> apl;
1553 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1555 Playlist::RegionList* regions = pl->regions_at (frame);
1556 AudioPlaylist::Crossfades xfades;
1558 apl->crossfades_at (frame, xfades);
1560 bool many = xfades.size() > 1;
1562 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1563 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1566 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1567 add_region_context_items (atv->audio_view(), (*i), edit_items);
1574 add_dstream_context_items (edit_items);
1576 return &track_crossfade_context_menu;
1581 Editor::analyze_region_selection()
1583 if (analysis_window == 0) {
1584 analysis_window = new AnalysisWindow();
1587 analysis_window->set_session(session);
1589 analysis_window->show_all();
1592 analysis_window->set_regionmode();
1593 analysis_window->analyze();
1595 analysis_window->present();
1599 Editor::analyze_range_selection()
1601 if (analysis_window == 0) {
1602 analysis_window = new AnalysisWindow();
1605 analysis_window->set_session(session);
1607 analysis_window->show_all();
1610 analysis_window->set_rangemode();
1611 analysis_window->analyze();
1613 analysis_window->present();
1615 #endif /* FFT_ANALYSIS */
1620 Editor::build_track_selection_context_menu (nframes_t ignored)
1622 using namespace Menu_Helpers;
1623 MenuList& edit_items = track_selection_context_menu.items();
1624 edit_items.clear ();
1626 add_selection_context_items (edit_items);
1627 // edit_items.push_back (SeparatorElem());
1628 // add_dstream_context_items (edit_items);
1630 return &track_selection_context_menu;
1634 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1636 using namespace Menu_Helpers;
1637 Menu *xfade_menu = manage (new Menu);
1638 MenuList& items = xfade_menu->items();
1639 xfade_menu->set_name ("ArdourContextMenu");
1642 if (xfade->active()) {
1648 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1649 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1651 if (xfade->can_follow_overlap()) {
1653 if (xfade->following_overlap()) {
1654 str = _("Convert to short");
1656 str = _("Convert to full");
1659 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1663 str = xfade->out()->name();
1665 str += xfade->in()->name();
1667 str = _("Crossfade");
1670 edit_items.push_back (MenuElem (str, *xfade_menu));
1671 edit_items.push_back (SeparatorElem());
1675 Editor::xfade_edit_left_region ()
1677 if (clicked_crossfadeview) {
1678 clicked_crossfadeview->left_view.show_region_editor ();
1683 Editor::xfade_edit_right_region ()
1685 if (clicked_crossfadeview) {
1686 clicked_crossfadeview->right_view.show_region_editor ();
1691 Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region> region, Menu_Helpers::MenuList& edit_items)
1693 using namespace Menu_Helpers;
1694 Menu *region_menu = manage (new Menu);
1695 MenuList& items = region_menu->items();
1696 region_menu->set_name ("ArdourContextMenu");
1698 boost::shared_ptr<AudioRegion> ar;
1701 ar = boost::dynamic_pointer_cast<AudioRegion> (region);
1704 /* when this particular menu pops up, make the relevant region
1708 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr<Region>(region)));
1710 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1711 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1712 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1713 items.push_back (SeparatorElem());
1714 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_point)));
1715 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1716 items.push_back (SeparatorElem());
1718 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1719 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1720 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1723 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1726 items.push_back (SeparatorElem());
1728 sigc::connection fooc;
1730 items.push_back (CheckMenuElem (_("Lock")));
1731 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1732 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1733 if (region->locked()) {
1735 region_lock_item->set_active();
1738 items.push_back (CheckMenuElem (_("Mute")));
1739 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1740 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1741 if (region->muted()) {
1743 region_mute_item->set_active();
1747 if (!Profile->get_sae()) {
1748 items.push_back (CheckMenuElem (_("Opaque")));
1749 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1750 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1751 if (region->opaque()) {
1753 region_opaque_item->set_active();
1758 items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1759 if (region->at_natural_position()) {
1760 items.back().set_sensitive (false);
1763 items.push_back (SeparatorElem());
1767 RegionView* rv = sv->find_view (ar);
1768 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1770 if (!Profile->get_sae()) {
1771 items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1773 items.push_back (CheckMenuElem (_("Envelope Visible")));
1774 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1775 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1776 if (arv->envelope_visible()) {
1778 region_envelope_visible_item->set_active (true);
1782 items.push_back (CheckMenuElem (_("Envelope Active")));
1783 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1784 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1786 if (ar->envelope_active()) {
1788 region_envelope_active_item->set_active (true);
1792 items.push_back (SeparatorElem());
1795 if (ar->scale_amplitude() != 1.0f) {
1796 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1798 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1802 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1803 items.push_back (SeparatorElem());
1805 /* range related stuff */
1807 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
1808 items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)));
1809 items.push_back (SeparatorElem());
1813 Menu *nudge_menu = manage (new Menu());
1814 MenuList& nudge_items = nudge_menu->items();
1815 nudge_menu->set_name ("ArdourContextMenu");
1817 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1818 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1819 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1820 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1822 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1823 items.push_back (SeparatorElem());
1825 Menu *trim_menu = manage (new Menu);
1826 MenuList& trim_items = trim_menu->items();
1827 trim_menu->set_name ("ArdourContextMenu");
1829 trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point)));
1830 trim_items.push_back (MenuElem (_("Edit point to end"), mem_fun(*this, &Editor::trim_region_to_edit_point)));
1831 trim_items.push_back (MenuElem (_("Trim To Loop"), mem_fun(*this, &Editor::trim_region_to_loop)));
1832 trim_items.push_back (MenuElem (_("Trim To Punch"), mem_fun(*this, &Editor::trim_region_to_punch)));
1834 items.push_back (MenuElem (_("Trim"), *trim_menu));
1835 items.push_back (SeparatorElem());
1837 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1838 region_edit_menu_split_item = &items.back();
1840 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1841 region_edit_menu_split_multichannel_item = &items.back();
1843 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1844 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1845 items.push_back (SeparatorElem());
1846 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1848 /* OK, stick the region submenu at the top of the list, and then add
1852 /* we have to hack up the region name because "_" has a special
1853 meaning for menu titles.
1856 string::size_type pos = 0;
1857 string menu_item_name = region->name();
1859 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1860 menu_item_name.replace (pos, 1, "__");
1864 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1865 edit_items.push_back (SeparatorElem());
1869 Editor::add_selection_context_items (Menu_Helpers::MenuList& items)
1871 using namespace Menu_Helpers;
1873 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1874 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1877 items.push_back (SeparatorElem());
1878 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1881 items.push_back (SeparatorElem());
1882 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1883 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1885 items.push_back (SeparatorElem());
1886 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1887 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1889 items.push_back (SeparatorElem());
1890 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1892 items.push_back (SeparatorElem());
1893 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1894 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1896 items.push_back (SeparatorElem());
1897 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1898 items.push_back (SeparatorElem());
1899 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1900 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1901 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1902 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1903 items.push_back (SeparatorElem());
1904 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1905 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1909 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1911 using namespace Menu_Helpers;
1915 Menu *play_menu = manage (new Menu);
1916 MenuList& play_items = play_menu->items();
1917 play_menu->set_name ("ArdourContextMenu");
1919 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
1920 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1921 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1922 play_items.push_back (SeparatorElem());
1923 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1925 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1929 Menu *select_menu = manage (new Menu);
1930 MenuList& select_items = select_menu->items();
1931 select_menu->set_name ("ArdourContextMenu");
1933 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1934 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1935 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1936 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1937 select_items.push_back (SeparatorElem());
1938 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1939 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1940 select_items.push_back (SeparatorElem());
1941 select_items.push_back (MenuElem (_("Select All After Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1942 select_items.push_back (MenuElem (_("Select All Before Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1943 select_items.push_back (MenuElem (_("Select All After Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1944 select_items.push_back (MenuElem (_("Select All Before Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1945 select_items.push_back (MenuElem (_("Select All Between Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), false)));
1946 select_items.push_back (MenuElem (_("Select All Within Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), true)));
1947 select_items.push_back (MenuElem (_("Select Range Between Playhead & Edit Point"), mem_fun(*this, &Editor::select_range_between)));
1949 select_items.push_back (SeparatorElem());
1951 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1955 Menu *cutnpaste_menu = manage (new Menu);
1956 MenuList& cutnpaste_items = cutnpaste_menu->items();
1957 cutnpaste_menu->set_name ("ArdourContextMenu");
1959 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1960 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1961 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1963 cutnpaste_items.push_back (SeparatorElem());
1965 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1966 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1968 cutnpaste_items.push_back (SeparatorElem());
1970 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1972 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1974 /* Adding new material */
1976 edit_items.push_back (SeparatorElem());
1977 edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1978 edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1982 Menu *nudge_menu = manage (new Menu());
1983 MenuList& nudge_items = nudge_menu->items();
1984 nudge_menu->set_name ("ArdourContextMenu");
1986 edit_items.push_back (SeparatorElem());
1987 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1988 nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1989 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1990 nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1992 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1996 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1998 using namespace Menu_Helpers;
2002 Menu *play_menu = manage (new Menu);
2003 MenuList& play_items = play_menu->items();
2004 play_menu->set_name ("ArdourContextMenu");
2006 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
2007 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2008 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2012 Menu *select_menu = manage (new Menu);
2013 MenuList& select_items = select_menu->items();
2014 select_menu->set_name ("ArdourContextMenu");
2016 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2017 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
2018 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2019 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
2020 select_items.push_back (SeparatorElem());
2021 select_items.push_back (MenuElem (_("Select all after edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2022 select_items.push_back (MenuElem (_("Select all before edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2023 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2024 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2026 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2030 Menu *cutnpaste_menu = manage (new Menu);
2031 MenuList& cutnpaste_items = cutnpaste_menu->items();
2032 cutnpaste_menu->set_name ("ArdourContextMenu");
2034 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2035 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2036 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2038 Menu *nudge_menu = manage (new Menu());
2039 MenuList& nudge_items = nudge_menu->items();
2040 nudge_menu->set_name ("ArdourContextMenu");
2042 edit_items.push_back (SeparatorElem());
2043 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2044 nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2045 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2046 nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2048 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2051 /* CURSOR SETTING AND MARKS AND STUFF */
2054 Editor::set_snap_to (SnapType st)
2057 string str = snap_type_strings[(int) st];
2059 if (str != snap_type_selector.get_active_text()) {
2060 snap_type_selector.set_active_text (str);
2065 switch (snap_type) {
2066 case SnapToAThirtysecondBeat:
2067 case SnapToASixteenthBeat:
2068 case SnapToAEighthBeat:
2069 case SnapToAQuarterBeat:
2070 case SnapToAThirdBeat:
2071 update_tempo_based_rulers ();
2079 Editor::set_snap_mode (SnapMode mode)
2082 string str = snap_mode_strings[(int)mode];
2084 if (str != snap_mode_selector.get_active_text ()) {
2085 snap_mode_selector.set_active_text (str);
2091 Editor::set_edit_point_preference (EditPoint ep)
2094 string str = edit_point_strings[(int)ep];
2096 if (str != edit_point_selector.get_active_text ()) {
2097 edit_point_selector.set_active_text (str);
2104 Editor::set_state (const XMLNode& node)
2106 const XMLProperty* prop;
2108 int x, y, xoff, yoff;
2111 if ((prop = node.property ("id")) != 0) {
2112 _id = prop->value ();
2115 if ((geometry = find_named_node (node, "geometry")) == 0) {
2117 g.base_width = default_width;
2118 g.base_height = default_height;
2126 g.base_width = atoi(geometry->property("x_size")->value());
2127 g.base_height = atoi(geometry->property("y_size")->value());
2128 x = atoi(geometry->property("x_pos")->value());
2129 y = atoi(geometry->property("y_pos")->value());
2130 xoff = atoi(geometry->property("x_off")->value());
2131 yoff = atoi(geometry->property("y_off")->value());
2134 set_default_size (g.base_width, g.base_height);
2137 if (session && (prop = node.property ("playhead"))) {
2138 nframes_t pos = atol (prop->value().c_str());
2139 playhead_cursor->set_position (pos);
2141 playhead_cursor->set_position (0);
2143 /* reset_x_origin() doesn't work right here, since the old
2144 position may be zero already, and it does nothing in such
2149 horizontal_adjustment.set_value (0);
2152 if ((prop = node.property ("mixer-width"))) {
2153 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2156 if ((prop = node.property ("zoom-focus"))) {
2157 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2160 if ((prop = node.property ("zoom"))) {
2161 reset_zoom (PBD::atof (prop->value()));
2164 if ((prop = node.property ("snap-to"))) {
2165 set_snap_to ((SnapType) atoi (prop->value()));
2168 if ((prop = node.property ("snap-mode"))) {
2169 set_snap_mode ((SnapMode) atoi (prop->value()));
2172 if ((prop = node.property ("edit-point"))) {
2173 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point));
2176 if ((prop = node.property ("mouse-mode"))) {
2177 MouseMode m = str2mousemode(prop->value());
2178 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2179 set_mouse_mode (m, true);
2181 mouse_mode = MouseGain; /* lie, to force the mode switch */
2182 set_mouse_mode (MouseObject, true);
2185 if ((prop = node.property ("show-waveforms"))) {
2186 bool yn = (prop->value() == "yes");
2187 _show_waveforms = !yn;
2188 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2190 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2191 /* do it twice to force the change */
2192 tact->set_active (!yn);
2193 tact->set_active (yn);
2197 if ((prop = node.property ("show-waveforms-recording"))) {
2198 bool yn = (prop->value() == "yes");
2199 _show_waveforms_recording = !yn;
2200 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2202 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2203 /* do it twice to force the change */
2204 tact->set_active (!yn);
2205 tact->set_active (yn);
2209 if ((prop = node.property ("show-measures"))) {
2210 bool yn = (prop->value() == "yes");
2211 _show_measures = !yn;
2212 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2214 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2215 /* do it twice to force the change */
2216 tact->set_active (!yn);
2217 tact->set_active (yn);
2221 if ((prop = node.property ("follow-playhead"))) {
2222 bool yn = (prop->value() == "yes");
2223 set_follow_playhead (yn);
2224 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2226 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2227 if (tact->get_active() != yn) {
2228 tact->set_active (yn);
2233 if ((prop = node.property ("region-list-sort-type"))) {
2234 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2235 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2238 if ((prop = node.property ("xfades-visible"))) {
2239 bool yn = (prop->value() == "yes");
2240 _xfade_visibility = !yn;
2241 // set_xfade_visibility (yn);
2244 if ((prop = node.property ("show-editor-mixer"))) {
2246 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2249 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2250 bool yn = (prop->value() == X_("yes"));
2252 /* do it twice to force the change */
2254 tact->set_active (!yn);
2255 tact->set_active (yn);
2264 Editor::get_state ()
2266 XMLNode* node = new XMLNode ("Editor");
2269 _id.print (buf, sizeof (buf));
2270 node->add_property ("id", buf);
2272 if (is_realized()) {
2273 Glib::RefPtr<Gdk::Window> win = get_window();
2275 int x, y, xoff, yoff, width, height;
2276 win->get_root_origin(x, y);
2277 win->get_position(xoff, yoff);
2278 win->get_size(width, height);
2280 XMLNode* geometry = new XMLNode ("geometry");
2282 snprintf(buf, sizeof(buf), "%d", width);
2283 geometry->add_property("x_size", string(buf));
2284 snprintf(buf, sizeof(buf), "%d", height);
2285 geometry->add_property("y_size", string(buf));
2286 snprintf(buf, sizeof(buf), "%d", x);
2287 geometry->add_property("x_pos", string(buf));
2288 snprintf(buf, sizeof(buf), "%d", y);
2289 geometry->add_property("y_pos", string(buf));
2290 snprintf(buf, sizeof(buf), "%d", xoff);
2291 geometry->add_property("x_off", string(buf));
2292 snprintf(buf, sizeof(buf), "%d", yoff);
2293 geometry->add_property("y_off", string(buf));
2294 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2295 geometry->add_property("edit_pane_pos", string(buf));
2297 node->add_child_nocopy (*geometry);
2300 maybe_add_mixer_strip_width (*node);
2302 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2303 node->add_property ("zoom-focus", buf);
2304 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2305 node->add_property ("zoom", buf);
2306 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2307 node->add_property ("snap-to", buf);
2308 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2309 node->add_property ("snap-mode", buf);
2311 node->add_property ("edit-point", enum_2_string (_edit_point));
2313 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2314 node->add_property ("playhead", buf);
2316 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2317 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2318 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2319 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2320 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2321 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2322 node->add_property ("mouse-mode", enum2str(mouse_mode));
2324 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2326 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2327 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2336 Editor::trackview_by_y_position (double y)
2338 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2342 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2351 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2353 Location* before = 0;
2354 Location* after = 0;
2360 const nframes64_t one_second = session->frame_rate();
2361 const nframes64_t one_minute = session->frame_rate() * 60;
2362 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2363 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2364 nframes64_t presnap = start;
2366 switch (snap_type) {
2372 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2374 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2378 case SnapToSMPTEFrame:
2379 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2380 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2382 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2386 case SnapToSMPTESeconds:
2387 if (session->smpte_offset_negative())
2389 start += session->smpte_offset ();
2391 start -= session->smpte_offset ();
2393 if (start % one_smpte_second > one_smpte_second / 2) {
2394 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2396 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2399 if (session->smpte_offset_negative())
2401 start -= session->smpte_offset ();
2403 start += session->smpte_offset ();
2407 case SnapToSMPTEMinutes:
2408 if (session->smpte_offset_negative())
2410 start += session->smpte_offset ();
2412 start -= session->smpte_offset ();
2414 if (start % one_smpte_minute > one_smpte_minute / 2) {
2415 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2417 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2419 if (session->smpte_offset_negative())
2421 start -= session->smpte_offset ();
2423 start += session->smpte_offset ();
2428 if (start % one_second > one_second / 2) {
2429 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2431 start = (nframes_t) floor ((double) start / one_second) * one_second;
2436 if (start % one_minute > one_minute / 2) {
2437 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2439 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2444 start = session->tempo_map().round_to_bar (start, direction);
2448 start = session->tempo_map().round_to_beat (start, direction);
2451 case SnapToAThirtysecondBeat:
2452 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2455 case SnapToASixteenthBeat:
2456 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2459 case SnapToAEighthBeat:
2460 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2463 case SnapToAQuarterBeat:
2464 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2467 case SnapToAThirdBeat:
2468 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2471 case SnapToEditPoint:
2472 start = get_preferred_edit_position ();
2480 before = session->locations()->first_location_before (start);
2481 after = session->locations()->first_location_after (start);
2483 if (direction < 0) {
2485 start = before->start();
2489 } else if (direction > 0) {
2491 start = after->start();
2493 start = session->current_end_frame();
2498 /* find nearest of the two */
2499 if ((start - before->start()) < (after->start() - start)) {
2500 start = before->start();
2502 start = after->start();
2505 start = before->start();
2508 start = after->start();
2515 case SnapToRegionStart:
2516 case SnapToRegionEnd:
2517 case SnapToRegionSync:
2518 case SnapToRegionBoundary:
2519 if (!region_boundary_cache.empty()) {
2520 vector<nframes_t>::iterator i;
2522 if (direction > 0) {
2523 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2525 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2528 if (i != region_boundary_cache.end()) {
2531 start = region_boundary_cache.back();
2537 switch (snap_mode) {
2543 if (presnap > start) {
2544 if (presnap > (start + unit_to_frame(snap_threshold))) {
2548 } else if (presnap < start) {
2549 if (presnap < (start - unit_to_frame(snap_threshold))) {
2561 Editor::setup_toolbar ()
2565 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2568 /* Mode Buttons (tool selection) */
2570 vector<ToggleButton *> mouse_mode_buttons;
2572 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2573 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2574 mouse_mode_buttons.push_back (&mouse_move_button);
2575 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2576 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2577 mouse_mode_buttons.push_back (&mouse_select_button);
2578 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2579 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2580 mouse_mode_buttons.push_back (&mouse_gain_button);
2581 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2582 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2583 mouse_mode_buttons.push_back (&mouse_zoom_button);
2584 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2585 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2586 mouse_mode_buttons.push_back (&mouse_timefx_button);
2587 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2588 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2589 mouse_mode_buttons.push_back (&mouse_audition_button);
2591 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2593 HBox* mode_box = manage(new HBox);
2594 mode_box->set_border_width (2);
2595 mode_box->set_spacing(4);
2596 mouse_mode_button_box.set_spacing(1);
2597 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2598 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2599 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2600 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2601 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2602 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2603 mouse_mode_button_box.set_homogeneous(true);
2605 vector<string> edit_mode_strings;
2606 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2607 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2609 edit_mode_selector.set_name ("EditModeSelector");
2610 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2611 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2612 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2614 mode_box->pack_start(edit_mode_selector);
2615 mode_box->pack_start(mouse_mode_button_box);
2617 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2618 mouse_mode_tearoff->set_name ("MouseModeBase");
2620 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2621 &mouse_mode_tearoff->tearoff_window()));
2622 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2623 &mouse_mode_tearoff->tearoff_window(), 1));
2624 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2625 &mouse_mode_tearoff->tearoff_window()));
2626 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2627 &mouse_mode_tearoff->tearoff_window(), 1));
2629 mouse_move_button.set_name ("MouseModeButton");
2630 mouse_select_button.set_name ("MouseModeButton");
2631 mouse_gain_button.set_name ("MouseModeButton");
2632 mouse_zoom_button.set_name ("MouseModeButton");
2633 mouse_timefx_button.set_name ("MouseModeButton");
2634 mouse_audition_button.set_name ("MouseModeButton");
2636 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2637 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2638 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2639 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2640 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2641 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2643 mouse_move_button.unset_flags (CAN_FOCUS);
2644 mouse_select_button.unset_flags (CAN_FOCUS);
2645 mouse_gain_button.unset_flags (CAN_FOCUS);
2646 mouse_zoom_button.unset_flags (CAN_FOCUS);
2647 mouse_timefx_button.unset_flags (CAN_FOCUS);
2648 mouse_audition_button.unset_flags (CAN_FOCUS);
2650 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2651 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2653 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2654 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2655 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2656 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2657 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2659 // mouse_move_button.set_active (true);
2664 zoom_box.set_spacing (1);
2665 zoom_box.set_border_width (2);
2667 zoom_in_button.set_name ("EditorTimeButton");
2668 zoom_in_button.set_size_request(-1,16);
2669 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2670 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2671 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2673 zoom_out_button.set_name ("EditorTimeButton");
2674 zoom_out_button.set_size_request(-1,16);
2675 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2676 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2677 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2679 zoom_out_full_button.set_name ("EditorTimeButton");
2680 zoom_out_full_button.set_size_request(-1,16);
2681 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2682 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2683 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2685 zoom_focus_selector.set_name ("ZoomFocusSelector");
2686 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Playhead", FUDGE, 0);
2687 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2688 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2689 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2691 zoom_box.pack_start (zoom_focus_selector, true, true);
2692 zoom_box.pack_start (zoom_out_button, false, false);
2693 zoom_box.pack_start (zoom_in_button, false, false);
2694 zoom_box.pack_start (zoom_out_full_button, false, false);
2696 snap_box.set_spacing (1);
2697 snap_box.set_border_width (2);
2699 snap_type_selector.set_name ("SnapTypeSelector");
2700 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2701 set_popdown_strings (snap_type_selector, snap_type_strings);
2702 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2703 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
2705 snap_mode_selector.set_name ("SnapModeSelector");
2706 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2707 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2708 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2709 ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2711 edit_point_selector.set_name ("SnapModeSelector");
2712 Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, "Playhead", 2+FUDGE, 10);
2713 set_popdown_strings (edit_point_selector, edit_point_strings);
2714 edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
2715 ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
2717 snap_box.pack_start (edit_point_clock, false, false);
2718 snap_box.pack_start (snap_mode_selector, false, false);
2719 snap_box.pack_start (snap_type_selector, false, false);
2720 snap_box.pack_start (edit_point_selector, false, false);
2724 HBox *nudge_box = manage (new HBox);
2725 nudge_box->set_spacing(1);
2726 nudge_box->set_border_width (2);
2728 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2729 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2731 nudge_box->pack_start (nudge_backward_button, false, false);
2732 nudge_box->pack_start (nudge_forward_button, false, false);
2733 nudge_box->pack_start (nudge_clock, false, false);
2736 /* Pack everything in... */
2738 HBox* hbox = new HBox;
2739 hbox->set_spacing(10);
2741 tools_tearoff = new TearOff (*hbox);
2742 tools_tearoff->set_name ("MouseModeBase");
2744 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2745 &tools_tearoff->tearoff_window()));
2746 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2747 &tools_tearoff->tearoff_window(), 0));
2748 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2749 &tools_tearoff->tearoff_window()));
2750 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2751 &tools_tearoff->tearoff_window(), 0));
2753 toolbar_hbox.set_spacing (10);
2754 toolbar_hbox.set_border_width (1);
2756 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2757 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2760 hbox->pack_start (snap_box, false, false);
2761 // hbox->pack_start (zoom_box, false, false);
2762 hbox->pack_start (*nudge_box, false, false);
2766 toolbar_base.set_name ("ToolBarBase");
2767 toolbar_base.add (toolbar_hbox);
2769 toolbar_frame.set_shadow_type (SHADOW_OUT);
2770 toolbar_frame.set_name ("BaseFrame");
2771 toolbar_frame.add (toolbar_base);
2775 Editor::convert_drop_to_paths (vector<ustring>& paths,
2776 const RefPtr<Gdk::DragContext>& context,
2779 const SelectionData& data,
2788 vector<ustring> uris = data.get_uris();
2792 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2793 are actually URI lists. So do it by hand.
2796 if (data.get_target() != "text/plain") {
2800 /* Parse the "uri-list" format that Nautilus provides,
2801 where each pathname is delimited by \r\n
2804 const char* p = data.get_text().c_str();
2811 while (g_ascii_isspace (*p))
2815 while (*q && (*q != '\n') && (*q != '\r'))
2821 while (q > p && g_ascii_isspace (*q))
2826 uris.push_back (ustring (p, q - p + 1));
2830 p = strchr (p, '\n');
2840 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2842 if ((*i).substr (0,7) == "file://") {
2846 PBD::url_decode (p);
2848 // scan forward past three slashes
2850 ustring::size_type slashcnt = 0;
2851 ustring::size_type n = 0;
2852 ustring::iterator x = p.begin();
2854 while (slashcnt < 3 && x != p.end()) {
2857 } else if (slashcnt == 3) {
2864 if (slashcnt != 3 || x == p.end()) {
2865 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2869 paths.push_back (p.substr (n - 1));
2877 Editor::new_tempo_section ()
2883 Editor::map_transport_state ()
2885 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2887 if (session->transport_stopped()) {
2888 have_pending_keyboard_selection = false;
2891 update_loop_range_view (true);
2896 Editor::State::State ()
2898 selection = new Selection;
2901 Editor::State::~State ()
2907 Editor::get_memento () const
2909 State *state = new State;
2911 store_state (*state);
2912 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2916 Editor::store_state (State& state) const
2918 *state.selection = *selection;
2922 Editor::restore_state (State *state)
2924 if (*selection == *state->selection) {
2928 *selection = *state->selection;
2929 time_selection_changed ();
2930 region_selection_changed ();
2932 /* XXX other selection change handlers? */
2936 Editor::begin_reversible_command (string name)
2939 // before = &get_state();
2940 session->begin_reversible_command (name);
2945 Editor::commit_reversible_command ()
2948 // session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2949 session->commit_reversible_command ();
2954 Editor::set_edit_group_solo (Route& route, bool yn)
2956 RouteGroup *edit_group;
2958 if ((edit_group = route.edit_group()) != 0) {
2959 edit_group->apply (&Route::set_solo, yn, this);
2961 route.set_solo (yn, this);
2966 Editor::set_edit_group_mute (Route& route, bool yn)
2968 RouteGroup *edit_group = 0;
2970 if ((edit_group == route.edit_group()) != 0) {
2971 edit_group->apply (&Route::set_mute, yn, this);
2973 route.set_mute (yn, this);
2978 Editor::history_changed ()
2982 if (undo_action && session) {
2983 if (session->undo_depth() == 0) {
2986 label = string_compose(_("Undo (%1)"), session->next_undo());
2988 undo_action->property_label() = label;
2991 if (redo_action && session) {
2992 if (session->redo_depth() == 0) {
2995 label = string_compose(_("Redo (%1)"), session->next_redo());
2997 redo_action->property_label() = label;
3002 Editor::duplicate_dialog (bool dup_region)
3004 if (selection->regions.empty() && (selection->time.length() == 0)) {
3008 ArdourDialog win ("duplicate dialog");
3009 Label label (_("Duplicate how many times?"));
3010 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3011 SpinButton spinner (adjustment);
3013 win.get_vbox()->set_spacing (12);
3014 win.get_vbox()->pack_start (label);
3016 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3017 place, visually. so do this by hand.
3020 win.get_vbox()->pack_start (spinner);
3021 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3026 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3027 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3029 win.set_position (WIN_POS_MOUSE);
3031 spinner.grab_focus ();
3033 switch (win.run ()) {
3034 case RESPONSE_ACCEPT:
3040 float times = adjustment.get_value();
3042 if (!selection->regions.empty()) {
3043 duplicate_some_regions (selection->regions, times);
3045 duplicate_selection (times);
3050 Editor::show_verbose_canvas_cursor ()
3052 verbose_canvas_cursor->raise_to_top();
3053 verbose_canvas_cursor->show();
3054 verbose_cursor_visible = true;
3058 Editor::hide_verbose_canvas_cursor ()
3060 verbose_canvas_cursor->hide();
3061 verbose_cursor_visible = false;
3065 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3067 /* XXX get origin of canvas relative to root window,
3068 add x and y and check compared to gdk_screen_{width,height}
3070 verbose_canvas_cursor->property_text() = txt.c_str();
3071 verbose_canvas_cursor->property_x() = x;
3072 verbose_canvas_cursor->property_y() = y;
3076 Editor::set_verbose_canvas_cursor_text (const string & txt)
3078 verbose_canvas_cursor->property_text() = txt.c_str();
3082 Editor::edit_mode_selection_done ()
3088 string choice = edit_mode_selector.get_active_text();
3089 EditMode mode = Slide;
3091 if (choice == _("Splice Edit")) {
3093 } else if (choice == _("Slide Edit")) {
3097 Config->set_edit_mode (mode);
3101 Editor::snap_type_selection_done ()
3103 string choice = snap_type_selector.get_active_text();
3104 SnapType snaptype = SnapToFrame;
3106 if (choice == _("Beats/3")) {
3107 snaptype = SnapToAThirdBeat;
3108 } else if (choice == _("Beats/4")) {
3109 snaptype = SnapToAQuarterBeat;
3110 } else if (choice == _("Beats/8")) {
3111 snaptype = SnapToAEighthBeat;
3112 } else if (choice == _("Beats/16")) {
3113 snaptype = SnapToASixteenthBeat;
3114 } else if (choice == _("Beats/32")) {
3115 snaptype = SnapToAThirtysecondBeat;
3116 } else if (choice == _("Beats")) {
3117 snaptype = SnapToBeat;
3118 } else if (choice == _("Bars")) {
3119 snaptype = SnapToBar;
3120 } else if (choice == _("Marks")) {
3121 snaptype = SnapToMark;
3122 } else if (choice == _("Edit Point")) {
3123 snaptype = SnapToEditPoint;
3124 } else if (choice == _("Region starts")) {
3125 snaptype = SnapToRegionStart;
3126 } else if (choice == _("Region ends")) {
3127 snaptype = SnapToRegionEnd;
3128 } else if (choice == _("Region bounds")) {
3129 snaptype = SnapToRegionBoundary;
3130 } else if (choice == _("Region syncs")) {
3131 snaptype = SnapToRegionSync;
3132 } else if (choice == _("CD Frames")) {
3133 snaptype = SnapToCDFrame;
3134 } else if (choice == _("SMPTE Frames")) {
3135 snaptype = SnapToSMPTEFrame;
3136 } else if (choice == _("SMPTE Seconds")) {
3137 snaptype = SnapToSMPTESeconds;
3138 } else if (choice == _("SMPTE Minutes")) {
3139 snaptype = SnapToSMPTEMinutes;
3140 } else if (choice == _("Seconds")) {
3141 snaptype = SnapToSeconds;
3142 } else if (choice == _("Minutes")) {
3143 snaptype = SnapToMinutes;
3144 } else if (choice == _("None")) {
3145 snaptype = SnapToFrame;
3148 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3150 ract->set_active ();
3155 Editor::snap_mode_selection_done ()
3157 string choice = snap_mode_selector.get_active_text();
3158 SnapMode mode = SnapNormal;
3160 if (choice == _("Normal")) {
3162 } else if (choice == _("Magnetic")) {
3163 mode = SnapMagnetic;
3166 RefPtr<RadioAction> ract = snap_mode_action (mode);
3169 ract->set_active (true);
3174 Editor::edit_point_selection_done ()
3176 string choice = edit_point_selector.get_active_text();
3177 EditPoint ep = EditAtSelectedMarker;
3179 if (choice == _("Marker")) {
3180 _edit_point = EditAtSelectedMarker;
3181 } else if (choice == _("Playhead")) {
3182 _edit_point = EditAtPlayhead;
3184 _edit_point = EditAtMouse;
3187 RefPtr<RadioAction> ract = edit_point_action (ep);
3190 ract->set_active (true);
3195 Editor::zoom_focus_selection_done ()
3197 string choice = zoom_focus_selector.get_active_text();
3198 ZoomFocus focus_type = ZoomFocusLeft;
3200 if (choice == _("Left")) {
3201 focus_type = ZoomFocusLeft;
3202 } else if (choice == _("Right")) {
3203 focus_type = ZoomFocusRight;
3204 } else if (choice == _("Center")) {
3205 focus_type = ZoomFocusCenter;
3206 } else if (choice == _("Playhead")) {
3207 focus_type = ZoomFocusPlayhead;
3208 } else if (choice == _("Mouse")) {
3209 focus_type = ZoomFocusMouse;
3210 } else if (choice == _("Edit Point")) {
3211 focus_type = ZoomFocusEdit;
3214 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3217 ract->set_active ();
3222 Editor::edit_controls_button_release (GdkEventButton* ev)
3224 if (Keyboard::is_context_menu_event (ev)) {
3225 ARDOUR_UI::instance()->add_route (this);
3231 Editor::mouse_select_button_release (GdkEventButton* ev)
3233 /* this handles just right-clicks */
3235 if (ev->button != 3) {
3242 Editor::TrackViewList *
3243 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3246 TrackViewList::iterator i;
3248 v = new TrackViewList;
3250 if (track == 0 && group == 0) {
3254 for (i = track_views.begin(); i != track_views.end (); ++i) {
3258 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3260 /* just the view for this track
3263 v->push_back (track);
3267 /* views for all tracks in the edit group */
3269 for (i = track_views.begin(); i != track_views.end (); ++i) {
3271 if (group == 0 || (*i)->edit_group() == group) {
3281 Editor::set_zoom_focus (ZoomFocus f)
3283 string str = zoom_focus_strings[(int)f];
3285 if (str != zoom_focus_selector.get_active_text()) {
3286 zoom_focus_selector.set_active_text (str);
3289 if (zoom_focus != f) {
3292 ZoomFocusChanged (); /* EMIT_SIGNAL */
3299 Editor::ensure_float (Window& win)
3301 win.set_transient_for (*this);
3305 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3307 /* recover or initialize pane positions. do this here rather than earlier because
3308 we don't want the positions to change the child allocations, which they seem to do.
3314 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3316 static int32_t done;
3319 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3320 width = default_width;
3321 height = default_height;
3323 width = atoi(geometry->property("x_size")->value());
3324 height = atoi(geometry->property("y_size")->value());
3327 if (which == static_cast<Paned*> (&edit_pane)) {
3333 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3334 /* initial allocation is 90% to canvas, 10% to notebook */
3335 pos = (int) floor (alloc.get_width() * 0.90f);
3336 snprintf (buf, sizeof(buf), "%d", pos);
3338 pos = atoi (prop->value());
3341 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3342 edit_pane.set_position (pos);
3343 pre_maximal_pane_position = pos;
3349 Editor::detach_tearoff (Box* b, Window* w)
3351 if (tools_tearoff->torn_off() &&
3352 mouse_mode_tearoff->torn_off()) {
3353 top_hbox.remove (toolbar_frame);
3358 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3360 if (toolbar_frame.get_parent() == 0) {
3361 top_hbox.pack_end (toolbar_frame);
3366 Editor::set_show_measures (bool yn)
3368 if (_show_measures != yn) {
3371 if ((_show_measures = yn) == true) {
3379 Editor::toggle_follow_playhead ()
3381 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3383 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3384 set_follow_playhead (tact->get_active());
3389 Editor::set_follow_playhead (bool yn)
3391 if (_follow_playhead != yn) {
3392 if ((_follow_playhead = yn) == true) {
3394 update_current_screen ();
3401 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3403 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3405 xfade->set_active (!xfade->active());
3410 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3412 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3414 xfade->set_follow_overlap (!xfade->following_overlap());
3419 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3421 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3427 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3431 switch (cew.run ()) {
3432 case RESPONSE_ACCEPT:
3439 xfade->StateChanged (Change (~0));
3443 Editor::playlist_selector () const
3445 return *_playlist_selector;
3449 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3453 ret = nudge_clock.current_duration (pos);
3454 next = ret + 1; /* XXXX fix me */
3460 Editor::end_location_changed (Location* location)
3462 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3463 reset_scrolling_region ();
3467 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3469 ArdourDialog dialog ("playlist deletion dialog");
3470 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3471 "If left alone, no audio files used by it will be cleaned.\n"
3472 "If deleted, audio files used by it alone by will cleaned."),
3475 dialog.set_position (WIN_POS_CENTER);
3476 dialog.get_vbox()->pack_start (label);
3480 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3481 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3482 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3484 switch (dialog.run ()) {
3485 case RESPONSE_ACCEPT:
3486 /* delete the playlist */
3490 case RESPONSE_REJECT:
3491 /* keep the playlist */
3503 Editor::audio_region_selection_covers (nframes_t where)
3505 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3506 if ((*a)->region()->covers (where)) {
3515 Editor::prepare_for_cleanup ()
3517 cut_buffer->clear_regions ();
3518 cut_buffer->clear_playlists ();
3520 selection->clear_regions ();
3521 selection->clear_playlists ();
3525 Editor::transport_loop_location()
3528 return session->locations()->auto_loop_location();
3535 Editor::transport_punch_location()
3538 return session->locations()->auto_punch_location();
3545 Editor::control_layout_scroll (GdkEventScroll* ev)
3547 switch (ev->direction) {
3549 scroll_tracks_up_line ();
3553 case GDK_SCROLL_DOWN:
3554 scroll_tracks_down_line ();
3558 /* no left/right handling yet */
3566 /** A new snapshot has been selected.
3569 Editor::snapshot_display_selection_changed ()
3571 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3573 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3575 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3577 if (snap_name.length() == 0) {
3581 if (session->snap_name() == snap_name) {
3585 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3590 Editor::snapshot_display_button_press (GdkEventButton* ev)
3592 if (ev->button == 3) {
3593 /* Right-click on the snapshot list. Work out which snapshot it
3595 Gtk::TreeModel::Path path;
3596 Gtk::TreeViewColumn* col;
3599 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3600 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3602 Gtk::TreeModel::Row row = *iter;
3603 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3612 /** Pop up the snapshot display context menu.
3613 * @param button Button used to open the menu.
3614 * @param time Menu open time.
3615 * @snapshot_name Name of the snapshot that the menu click was over.
3619 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3621 using namespace Menu_Helpers;
3623 MenuList& items (snapshot_context_menu.items());
3626 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3628 items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)));
3629 if (!modification_allowed) {
3630 items.back().set_sensitive (false);
3633 items.push_back (MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)));
3634 if (!modification_allowed) {
3635 items.back().set_sensitive (false);
3638 snapshot_context_menu.popup (button, time);
3642 Editor::rename_snapshot (Glib::ustring old_name)
3644 ArdourPrompter prompter(true);
3648 prompter.set_name ("Prompter");
3649 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3650 prompter.set_prompt (_("New name of snapshot"));
3651 prompter.set_initial_text (old_name);
3653 if (prompter.run() == RESPONSE_ACCEPT) {
3654 prompter.get_result (new_name);
3655 if (new_name.length()) {
3656 session->rename_state (old_name, new_name);
3657 redisplay_snapshots ();
3664 Editor::remove_snapshot (Glib::ustring name)
3666 vector<string> choices;
3668 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3670 choices.push_back (_("No, do nothing."));
3671 choices.push_back (_("Yes, remove it."));
3673 Gtkmm2ext::Choice prompter (prompt, choices);
3675 if (prompter.run () == 1) {
3676 session->remove_state (name);
3677 redisplay_snapshots ();
3682 Editor::redisplay_snapshots ()
3688 vector<string*>* states;
3690 if ((states = session->possible_states()) == 0) {
3694 snapshot_display_model->clear ();
3696 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3697 string statename = *(*i);
3698 TreeModel::Row row = *(snapshot_display_model->append());
3700 /* this lingers on in case we ever want to change the visible
3701 name of the snapshot.
3704 string display_name;
3705 display_name = statename;
3707 if (statename == session->snap_name()) {
3708 snapshot_display.get_selection()->select(row);
3711 row[snapshot_display_columns.visible_name] = display_name;
3712 row[snapshot_display_columns.real_name] = statename;
3719 Editor::session_state_saved (string snap_name)
3721 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3722 redisplay_snapshots ();
3726 Editor::maximise_editing_space ()
3728 initial_ruler_update_required = true;
3730 mouse_mode_tearoff->set_visible (false);
3731 tools_tearoff->set_visible (false);
3733 pre_maximal_pane_position = edit_pane.get_position();
3734 pre_maximal_editor_width = this->get_width();
3736 if(post_maximal_pane_position == 0) {
3737 post_maximal_pane_position = edit_pane.get_width();
3742 if(post_maximal_editor_width) {
3743 edit_pane.set_position (post_maximal_pane_position -
3744 abs(post_maximal_editor_width - pre_maximal_editor_width));
3746 edit_pane.set_position (post_maximal_pane_position);
3751 Editor::restore_editing_space ()
3753 initial_ruler_update_required = true;
3755 // user changed width of pane during fullscreen
3756 if(post_maximal_pane_position != edit_pane.get_position()) {
3757 post_maximal_pane_position = edit_pane.get_position();
3762 mouse_mode_tearoff->set_visible (true);
3763 tools_tearoff->set_visible (true);
3764 post_maximal_editor_width = this->get_width();
3767 edit_pane.set_position (
3768 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3773 * Make new playlists for a given track and also any others that belong
3774 * to the same active edit group.
3779 Editor::new_playlists (TimeAxisView* v)
3781 begin_reversible_command (_("new playlists"));
3782 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3783 commit_reversible_command ();
3788 * Use a copy of the current playlist for a given track and also any others that belong
3789 * to the same active edit group.
3794 Editor::copy_playlists (TimeAxisView* v)
3796 begin_reversible_command (_("copy playlists"));
3797 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3798 commit_reversible_command ();
3803 * Clear the current playlist for a given track and also any others that belong
3804 * to the same active edit group.
3809 Editor::clear_playlists (TimeAxisView* v)
3811 begin_reversible_command (_("clear playlists"));
3812 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3813 commit_reversible_command ();
3817 Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz)
3819 atv.use_new_playlist (sz > 1 ? false : true);
3823 Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz)
3825 atv.use_copy_playlist (sz > 1 ? false : true);
3829 Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz)
3831 atv.clear_playlist ();
3835 Editor::on_key_press_event (GdkEventKey* ev)
3837 return key_press_focus_accelerator_handler (*this, ev);
3841 Editor::reset_x_origin (nframes_t frame)
3843 queue_visual_change (frame);
3847 Editor::reset_zoom (double fpu)
3849 queue_visual_change (fpu);
3853 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3855 reset_x_origin (frame);
3860 Editor::set_frames_per_unit (double fpu)
3864 /* this is the core function that controls the zoom level of the canvas. it is called
3865 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3868 if (fpu == frames_per_unit) {
3876 // convert fpu to frame count
3878 frames = (nframes_t) floor (fpu * canvas_width);
3880 /* don't allow zooms that fit more than the maximum number
3881 of frames into an 800 pixel wide space.
3884 if (max_frames / fpu < 800.0) {
3888 if (fpu == frames_per_unit) {
3892 frames_per_unit = fpu;
3894 if (frames != zoom_range_clock.current_duration()) {
3895 zoom_range_clock.set (frames);
3898 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3899 if (!selection->tracks.empty()) {
3900 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3901 (*i)->reshow_selection (selection->time);
3904 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3905 (*i)->reshow_selection (selection->time);
3910 ZoomChanged (); /* EMIT_SIGNAL */
3912 reset_hscrollbar_stepping ();
3913 reset_scrolling_region ();
3915 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3921 Editor::queue_visual_change (nframes_t where)
3923 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3924 pending_visual_change.time_origin = where;
3926 if (pending_visual_change.idle_handler_id < 0) {
3927 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3932 Editor::queue_visual_change (double fpu)
3934 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3935 pending_visual_change.frames_per_unit = fpu;
3937 if (pending_visual_change.idle_handler_id < 0) {
3938 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3943 Editor::_idle_visual_changer (void* arg)
3945 return static_cast<Editor*>(arg)->idle_visual_changer ();
3949 Editor::idle_visual_changer ()
3951 VisualChange::Type p = pending_visual_change.pending;
3953 pending_visual_change.pending = (VisualChange::Type) 0;
3954 pending_visual_change.idle_handler_id = -1;
3956 if (p & VisualChange::ZoomLevel) {
3957 set_frames_per_unit (pending_visual_change.frames_per_unit);
3960 if (p & VisualChange::TimeOrigin) {
3961 if (pending_visual_change.time_origin != leftmost_frame) {
3962 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3963 /* the signal handler will do the rest */
3965 update_fixed_rulers();
3966 redisplay_tempo (true);
3970 return 0; /* this is always a one-shot call */
3973 struct EditorOrderTimeAxisSorter {
3974 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3975 return a->order < b->order;
3980 Editor::sort_track_selection ()
3982 EditorOrderTimeAxisSorter cmp;
3983 selection->tracks.sort (cmp);
3987 Editor::get_preferred_edit_position()
3990 nframes64_t where = 0;
3992 if (entered_marker) {
3993 return entered_marker->position();
3996 switch (_edit_point) {
3997 case EditAtPlayhead:
3998 where = session->audible_frame();
4001 case EditAtSelectedMarker:
4002 if (!selection->markers.empty()) {
4004 Location* loc = find_location_from_marker (selection->markers.front(), whocares);
4006 where = loc->start();
4014 if (!mouse_frame (where, ignored)) {
4015 /* XXX not right but what can we do ? */
4026 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4028 if (!session) return;
4030 begin_reversible_command (cmd);
4034 if ((tll = transport_loop_location()) == 0) {
4035 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4036 XMLNode &before = session->locations()->get_state();
4037 session->locations()->add (loc, true);
4038 session->set_auto_loop_location (loc);
4039 XMLNode &after = session->locations()->get_state();
4040 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4043 XMLNode &before = tll->get_state();
4044 tll->set_hidden (false, this);
4045 tll->set (start, end);
4046 XMLNode &after = tll->get_state();
4047 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4050 commit_reversible_command ();
4054 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4056 if (!session) return;
4058 begin_reversible_command (cmd);
4062 if ((tpl = transport_punch_location()) == 0) {
4063 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4064 XMLNode &before = session->locations()->get_state();
4065 session->locations()->add (loc, true);
4066 session->set_auto_loop_location (loc);
4067 XMLNode &after = session->locations()->get_state();
4068 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4071 XMLNode &before = tpl->get_state();
4072 tpl->set_hidden (false, this);
4073 tpl->set (start, end);
4074 XMLNode &after = tpl->get_state();
4075 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4078 commit_reversible_command ();
4082 Editor::get_regions_at (nframes64_t where, const TrackSelection& ts) const
4085 const TrackSelection* tracks;
4088 tracks = &track_views;
4093 for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4095 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4098 boost::shared_ptr<Diskstream> ds;
4099 boost::shared_ptr<Playlist> pl;
4101 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4103 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)where * ds->speed()));
4105 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4107 RegionView* rv = atv->audio_view()->find_view (*i);
4123 Editor::get_regions_for_action ()
4125 if (!selection->regions.empty()) {
4126 return selection->regions;
4129 nframes64_t where = get_preferred_edit_position();
4130 tmp_regions = get_regions_at (where, selection->tracks);