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[] = {
130 static const gchar *_snap_mode_strings[] = {
137 static const gchar *_edit_point_strings[] = {
144 static const gchar *_zoom_focus_strings[] = {
154 /* Soundfile drag-n-drop */
156 Gdk::Cursor* Editor::cross_hair_cursor = 0;
157 Gdk::Cursor* Editor::selector_cursor = 0;
158 Gdk::Cursor* Editor::trimmer_cursor = 0;
159 Gdk::Cursor* Editor::grabber_cursor = 0;
160 Gdk::Cursor* Editor::zoom_cursor = 0;
161 Gdk::Cursor* Editor::time_fx_cursor = 0;
162 Gdk::Cursor* Editor::fader_cursor = 0;
163 Gdk::Cursor* Editor::speaker_cursor = 0;
164 Gdk::Cursor* Editor::wait_cursor = 0;
165 Gdk::Cursor* Editor::timebar_cursor = 0;
166 Gdk::Cursor* Editor::transparent_cursor = 0;
169 show_me_the_size (Requisition* r, const char* what)
171 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
176 /* time display buttons */
177 minsec_label (_("Mins:Secs")),
178 bbt_label (_("Bars:Beats")),
179 smpte_label (_("Timecode")),
180 frame_label (_("Samples")),
181 tempo_label (_("Tempo")),
182 meter_label (_("Meter")),
183 mark_label (_("Location Markers")),
184 range_mark_label (_("Range Markers")),
185 transport_mark_label (_("Loop/Punch Ranges")),
186 cd_mark_label (_("CD Markers")),
188 edit_packer (3, 3, true),
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),
214 meters_running(false)
219 /* we are a singleton */
221 PublicEditor::_instance = this;
225 selection = new Selection;
226 cut_buffer = new Selection;
228 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
229 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
230 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
231 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
232 selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed));
234 clicked_regionview = 0;
235 clicked_trackview = 0;
236 clicked_audio_trackview = 0;
237 clicked_crossfadeview = 0;
238 clicked_control_point = 0;
239 last_update_frame = 0;
241 current_mixer_strip = 0;
242 current_bbt_points = 0;
244 snap_type_strings = I18N (_snap_type_strings);
245 snap_mode_strings = I18N (_snap_mode_strings);
246 zoom_focus_strings = I18N (_zoom_focus_strings);
247 edit_point_strings = I18N (_edit_point_strings);
249 snap_type = SnapToBeat;
250 set_snap_to (snap_type);
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;
321 select_new_marker = false;
323 scrubbing_direction = 0;
326 ignore_route_order_sync = false;
328 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
329 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
330 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
331 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
332 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
334 range_marker_drag_rect = 0;
335 marker_drag_line = 0;
337 set_mouse_mode (MouseObject, true);
339 frames_per_unit = 2048; /* too early to use reset_zoom () */
340 reset_hscrollbar_stepping ();
342 zoom_focus = ZoomFocusLeft;
343 set_zoom_focus (ZoomFocusLeft);
344 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
346 initialize_rulers ();
347 initialize_canvas ();
349 edit_controls_vbox.set_spacing (0);
350 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
351 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
353 track_canvas.set_hadjustment (horizontal_adjustment);
354 track_canvas.set_vadjustment (vertical_adjustment);
355 time_canvas.set_hadjustment (horizontal_adjustment);
357 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
358 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
360 controls_layout.add (edit_controls_vbox);
361 controls_layout.set_name ("EditControlsBase");
362 controls_layout.add_events (Gdk::SCROLL_MASK);
363 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
365 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
366 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
367 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
369 edit_vscrollbar.set_adjustment (vertical_adjustment);
370 edit_hscrollbar.set_adjustment (horizontal_adjustment);
372 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
373 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
374 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
376 edit_hscrollbar.set_name ("EditorHScrollbar");
381 edit_point_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_point_clock_changed));
383 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
384 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
385 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
386 time_canvas_vbox.pack_start (*frames_ruler, false, false);
387 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
388 time_canvas_vbox.pack_start (time_canvas, true, true);
389 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
391 bbt_label.set_name ("EditorTimeButton");
392 bbt_label.set_size_request (-1, (int)timebar_height);
393 bbt_label.set_alignment (1.0, 0.5);
394 bbt_label.set_padding (5,0);
395 minsec_label.set_name ("EditorTimeButton");
396 minsec_label.set_size_request (-1, (int)timebar_height);
397 minsec_label.set_alignment (1.0, 0.5);
398 minsec_label.set_padding (5,0);
399 smpte_label.set_name ("EditorTimeButton");
400 smpte_label.set_size_request (-1, (int)timebar_height);
401 smpte_label.set_alignment (1.0, 0.5);
402 smpte_label.set_padding (5,0);
403 frame_label.set_name ("EditorTimeButton");
404 frame_label.set_size_request (-1, (int)timebar_height);
405 frame_label.set_alignment (1.0, 0.5);
406 frame_label.set_padding (5,0);
407 tempo_label.set_name ("EditorTimeButton");
408 tempo_label.set_size_request (-1, (int)timebar_height);
409 tempo_label.set_alignment (1.0, 0.5);
410 tempo_label.set_padding (5,0);
411 meter_label.set_name ("EditorTimeButton");
412 meter_label.set_size_request (-1, (int)timebar_height);
413 meter_label.set_alignment (1.0, 0.5);
414 meter_label.set_padding (5,0);
415 mark_label.set_name ("EditorTimeButton");
416 mark_label.set_size_request (-1, (int)timebar_height);
417 mark_label.set_alignment (1.0, 0.5);
418 mark_label.set_padding (5,0);
419 cd_mark_label.set_name ("EditorTimeButton");
420 cd_mark_label.set_size_request (-1, (int)timebar_height);
421 cd_mark_label.set_alignment (1.0, 0.5);
422 cd_mark_label.set_padding (5,0);
423 range_mark_label.set_name ("EditorTimeButton");
424 range_mark_label.set_size_request (-1, (int)timebar_height);
425 range_mark_label.set_alignment (1.0, 0.5);
426 range_mark_label.set_padding (5,0);
427 transport_mark_label.set_name ("EditorTimeButton");
428 transport_mark_label.set_size_request (-1, (int)timebar_height);
429 transport_mark_label.set_alignment (1.0, 0.5);
430 transport_mark_label.set_padding (5,0);
432 time_button_vbox.pack_start (minsec_label, false, false);
433 time_button_vbox.pack_start (smpte_label, false, false);
434 time_button_vbox.pack_start (frame_label, false, false);
435 time_button_vbox.pack_start (bbt_label, false, false);
436 time_button_vbox.pack_start (meter_label, false, false);
437 time_button_vbox.pack_start (tempo_label, false, false);
438 time_button_vbox.pack_start (mark_label, false, false);
440 time_button_event_box.add (time_button_vbox);
442 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
443 time_button_event_box.set_name ("TimebarLabelBase");
444 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
446 time_button_frame.add(time_button_event_box);
447 time_button_frame.property_shadow_type() = Gtk::SHADOW_OUT;
449 /* these enable us to have a dedicated window (for cursor setting, etc.)
450 for the canvas areas.
453 track_canvas_event_box.add (track_canvas);
455 time_canvas_event_box.add (time_canvas_vbox);
456 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
458 edit_packer.set_col_spacings (0);
459 edit_packer.set_row_spacings (0);
460 edit_packer.set_homogeneous (false);
461 edit_packer.set_border_width (0);
462 edit_packer.set_name ("EditorWindow");
464 edit_packer.attach (edit_vscrollbar, 0, 1, 1, 3, FILL, FILL|EXPAND, 0, 0);
466 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, FILL, 0, 0);
467 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
469 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
470 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
472 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
473 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
475 bottom_hbox.set_border_width (2);
476 bottom_hbox.set_spacing (3);
478 route_display_model = ListStore::create(route_display_columns);
479 route_list_display.set_model (route_display_model);
480 route_list_display.append_column (_("Show"), route_display_columns.visible);
481 route_list_display.append_column (_("Name"), route_display_columns.text);
482 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
483 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
484 route_list_display.set_headers_visible (true);
485 route_list_display.set_name ("TrackListDisplay");
486 route_list_display.get_selection()->set_mode (SELECTION_NONE);
487 route_list_display.set_reorderable (true);
488 route_list_display.set_size_request (100,-1);
490 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
491 route_list_visible_cell->property_activatable() = true;
492 route_list_visible_cell->property_radio() = false;
494 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
495 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
496 route_display_model->signal_rows_reordered().connect (mem_fun (*this, &Editor::track_list_reorder));
498 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
500 route_list_scroller.add (route_list_display);
501 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
503 group_model = ListStore::create(group_columns);
504 edit_group_display.set_model (group_model);
505 edit_group_display.append_column (_("Name"), group_columns.text);
506 edit_group_display.append_column (_("Active"), group_columns.is_active);
507 edit_group_display.append_column (_("Show"), group_columns.is_visible);
508 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
509 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
510 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
511 edit_group_display.get_column (0)->set_expand (true);
512 edit_group_display.get_column (1)->set_expand (false);
513 edit_group_display.get_column (2)->set_expand (false);
514 edit_group_display.set_headers_visible (true);
516 /* name is directly editable */
518 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
519 name_cell->property_editable() = true;
520 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
522 /* use checkbox for the active + visible columns */
524 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
525 active_cell->property_activatable() = true;
526 active_cell->property_radio() = false;
528 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
529 active_cell->property_activatable() = true;
530 active_cell->property_radio() = false;
532 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
534 edit_group_display.set_name ("EditGroupList");
535 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
536 edit_group_display.set_headers_visible (true);
537 edit_group_display.set_reorderable (false);
538 edit_group_display.set_rules_hint (true);
539 edit_group_display.set_size_request (75, -1);
541 edit_group_display_scroller.add (edit_group_display);
542 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
544 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
546 VBox* edit_group_display_packer = manage (new VBox());
547 HBox* edit_group_display_button_box = manage (new HBox());
548 edit_group_display_button_box->set_homogeneous (true);
550 Button* edit_group_add_button = manage (new Button ());
551 Button* edit_group_remove_button = manage (new Button ());
555 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
557 edit_group_add_button->add (*w);
559 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
561 edit_group_remove_button->add (*w);
563 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
564 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
566 edit_group_display_button_box->pack_start (*edit_group_add_button);
567 edit_group_display_button_box->pack_start (*edit_group_remove_button);
569 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
570 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
572 region_list_display.set_size_request (100, -1);
573 region_list_display.set_name ("RegionListDisplay");
575 region_list_model = TreeStore::create (region_list_columns);
576 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
577 region_list_model->set_sort_column (0, SORT_ASCENDING);
579 region_list_display.set_model (region_list_model);
580 region_list_display.append_column (_("Regions"), region_list_columns.name);
581 region_list_display.set_headers_visible (false);
583 CellRendererText* region_name_cell = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
584 region_name_cell->property_editable() = true;
585 region_name_cell->signal_edited().connect (mem_fun (*this, &Editor::region_name_edit));
587 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
589 TreeViewColumn* tv_col = region_list_display.get_column(0);
590 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
591 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
592 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
594 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
595 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
597 /* setup DnD handling */
599 list<TargetEntry> region_list_target_table;
601 region_list_target_table.push_back (TargetEntry ("text/plain"));
602 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
603 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
605 region_list_display.add_drop_targets (region_list_target_table);
606 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
608 region_list_scroller.add (region_list_display);
609 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
611 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
612 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
613 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
614 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
615 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
616 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
618 named_selection_scroller.add (named_selection_display);
619 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
621 named_selection_model = TreeStore::create (named_selection_columns);
622 named_selection_display.set_model (named_selection_model);
623 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
624 named_selection_display.set_headers_visible (false);
625 named_selection_display.set_size_request (100, -1);
626 named_selection_display.set_name ("NamedSelectionDisplay");
628 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
629 named_selection_display.set_size_request (100, -1);
630 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
631 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
632 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
636 snapshot_display_model = ListStore::create (snapshot_display_columns);
637 snapshot_display.set_model (snapshot_display_model);
638 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
639 snapshot_display.set_name ("SnapshotDisplay");
640 snapshot_display.set_size_request (75, -1);
641 snapshot_display.set_headers_visible (false);
642 snapshot_display.set_reorderable (false);
643 snapshot_display_scroller.add (snapshot_display);
644 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
646 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
647 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
651 nlabel = manage (new Label (_("Regions")));
652 nlabel->set_angle (-90);
653 the_notebook.append_page (region_list_scroller, *nlabel);
654 nlabel = manage (new Label (_("Tracks/Busses")));
655 nlabel->set_angle (-90);
656 the_notebook.append_page (route_list_scroller, *nlabel);
657 nlabel = manage (new Label (_("Snapshots")));
658 nlabel->set_angle (-90);
659 the_notebook.append_page (snapshot_display_scroller, *nlabel);
660 nlabel = manage (new Label (_("Edit Groups")));
661 nlabel->set_angle (-90);
662 the_notebook.append_page (*edit_group_display_packer, *nlabel);
664 if (!Profile->get_sae()) {
665 nlabel = manage (new Label (_("Chunks")));
666 nlabel->set_angle (-90);
667 the_notebook.append_page (named_selection_scroller, *nlabel);
670 the_notebook.set_show_tabs (true);
671 the_notebook.set_scrollable (true);
672 the_notebook.popup_enable ();
673 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
675 post_maximal_editor_width = 0;
676 post_maximal_pane_position = 0;
677 edit_pane.pack1 (edit_packer, true, true);
678 edit_pane.pack2 (the_notebook, false, true);
680 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
682 top_hbox.pack_start (toolbar_frame, true, true);
684 HBox *hbox = manage (new HBox);
685 hbox->pack_start (edit_pane, true, true);
687 global_vpacker.pack_start (top_hbox, false, false);
688 global_vpacker.pack_start (*hbox, true, true);
690 global_hpacker.pack_start (global_vpacker, true, true);
692 set_name ("EditorWindow");
693 add_accel_group (ActionManager::ui_manager->get_accel_group());
695 status_bar_hpacker.show ();
697 vpacker.pack_end (status_bar_hpacker, false, false);
698 vpacker.pack_end (global_hpacker, true, true);
700 /* register actions now so that set_state() can find them and set toggles/checks etc */
704 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
707 _playlist_selector = new PlaylistSelector();
708 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
710 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
714 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
715 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
717 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
718 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
720 nudge_forward_button.set_name ("TransportButton");
721 nudge_backward_button.set_name ("TransportButton");
723 fade_context_menu.set_name ("ArdourContextMenu");
725 /* icons, titles, WM stuff */
727 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
728 Glib::RefPtr<Gdk::Pixbuf> icon;
730 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
731 window_icons.push_back (icon);
733 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
734 window_icons.push_back (icon);
736 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
737 window_icons.push_back (icon);
739 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
740 window_icons.push_back (icon);
742 if (!window_icons.empty()) {
743 set_icon_list (window_icons);
744 set_default_icon_list (window_icons);
747 WindowTitle title(Glib::get_application_name());
748 title += _("Editor");
749 set_title (title.get_string());
750 set_wmclass (X_("ardour_editor"), "Ardour");
753 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
755 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
756 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
758 /* allow external control surfaces/protocols to do various things */
760 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
761 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
762 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
763 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
765 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
766 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
774 /* <CMT Additions> */
775 if(image_socket_listener)
777 if(image_socket_listener->is_connected())
779 image_socket_listener->close_connection() ;
782 delete image_socket_listener ;
783 image_socket_listener = 0 ;
785 /* </CMT Additions> */
789 Editor::add_toplevel_controls (Container& cont)
791 vpacker.pack_start (cont, false, false);
796 Editor::catch_vanishing_regionview (RegionView *rv)
798 /* note: the selection will take care of the vanishing
799 audioregionview by itself.
802 if (clicked_regionview == rv) {
803 clicked_regionview = 0;
806 if (entered_regionview == rv) {
807 set_entered_regionview (0);
812 Editor::set_entered_regionview (RegionView* rv)
814 if (rv == entered_regionview) {
818 if (entered_regionview) {
819 entered_regionview->exited ();
822 if ((entered_regionview = rv) != 0) {
823 entered_regionview->entered ();
828 Editor::set_entered_track (TimeAxisView* tav)
831 entered_track->exited ();
834 if ((entered_track = tav) != 0) {
835 entered_track->entered ();
840 Editor::show_window ()
845 /* now reset all audio_time_axis heights, because widgets might need
851 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
852 tv = (static_cast<TimeAxisView*>(*i));
858 Editor::tie_vertical_scrolling ()
860 double y1 = vertical_adjustment.get_value();
862 playhead_cursor->set_y_axis (y1);
864 logo_item->property_y() = y1;
867 controls_layout.get_vadjustment()->set_value (y1);
870 /* the way idle updates and immediate window flushing work on GTK-Quartz
871 requires that we force an immediate redraw right here. The controls
872 layout will do the same all by itself, as does the canvas widget, but
873 most of the time, the canvas itself hasn't updated itself because its
874 idle handler hasn't run. consequently, the call that its layout makes
875 to gdk_window_process_updates() finds nothing to do. here, we force
876 the update to happen, then request a flush of the new window state.
878 track_canvas.update_now ();
879 gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
884 Editor::instant_save ()
886 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
891 session->add_instant_xml(get_state(), session->path());
893 Config->add_instant_xml(get_state(), get_user_ardour_path());
898 Editor::edit_point_clock_changed()
900 if (_dragging_edit_point) {
904 if (selection->markers.empty()) {
909 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
915 loc->move_to (edit_point_clock.current_time());
919 Editor::zoom_adjustment_changed ()
925 double fpu = zoom_range_clock.current_duration() / canvas_width;
929 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
930 } else if (fpu > session->current_end_frame() / canvas_width) {
931 fpu = session->current_end_frame() / canvas_width;
932 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
939 Editor::control_scroll (float fraction)
941 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
947 double step = fraction * current_page_frames();
950 _control_scroll_target is an optional<T>
952 it acts like a pointer to an nframes_t, with
953 a operator conversion to boolean to check
954 that it has a value could possibly use
955 playhead_cursor->current_frame to store the
956 value and a boolean in the class to know
957 when it's out of date
960 if (!_control_scroll_target) {
961 _control_scroll_target = session->transport_frame();
962 _dragging_playhead = true;
965 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
966 *_control_scroll_target = 0;
967 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
968 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
970 *_control_scroll_target += (nframes_t) floor (step);
973 /* move visuals, we'll catch up with it later */
975 playhead_cursor->set_position (*_control_scroll_target);
976 UpdateAllTransportClocks (*_control_scroll_target);
978 if (*_control_scroll_target > (current_page_frames() / 2)) {
979 /* try to center PH in window */
980 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
986 Now we do a timeout to actually bring the session to the right place
987 according to the playhead. This is to avoid reading disk buffers on every
988 call to control_scroll, which is driven by ScrollTimeline and therefore
989 probably by a control surface wheel which can generate lots of events.
991 /* cancel the existing timeout */
993 control_scroll_connection.disconnect ();
995 /* add the next timeout */
997 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1001 Editor::deferred_control_scroll (nframes_t target)
1003 session->request_locate (*_control_scroll_target, session->transport_rolling());
1004 // reset for next stream
1005 _control_scroll_target = boost::none;
1006 _dragging_playhead = false;
1011 Editor::on_realize ()
1013 Window::on_realize ();
1018 Editor::start_scrolling ()
1020 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1021 (mem_fun(*this, &Editor::update_current_screen));
1025 Editor::stop_scrolling ()
1027 scroll_connection.disconnect ();
1031 Editor::map_position_change (nframes_t frame)
1033 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1035 if (session == 0 || !_follow_playhead) {
1039 center_screen (frame);
1040 playhead_cursor->set_position (frame);
1044 Editor::center_screen (nframes_t frame)
1046 double page = canvas_width * frames_per_unit;
1048 /* if we're off the page, then scroll.
1051 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1052 center_screen_internal (frame, page);
1057 Editor::center_screen_internal (nframes_t frame, float page)
1062 frame -= (nframes_t) page;
1067 reset_x_origin (frame);
1071 Editor::handle_new_duration ()
1073 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1075 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1077 if (new_end > last_canvas_frame) {
1078 last_canvas_frame = new_end;
1079 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1080 reset_scrolling_region ();
1083 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1087 Editor::update_title_s (const string & snap_name)
1089 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1095 Editor::update_title ()
1097 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1100 bool dirty = session->dirty();
1102 string session_name;
1104 if (session->snap_name() != session->name()) {
1105 session_name = session->snap_name();
1107 session_name = session->name();
1111 session_name = "*" + session_name;
1114 WindowTitle title(session_name);
1115 title += Glib::get_application_name();
1116 set_title (title.get_string());
1121 Editor::connect_to_session (Session *t)
1125 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1128 /* catch up with the playhead */
1130 session->request_locate (playhead_cursor->current_frame);
1132 if (first_action_message) {
1133 first_action_message->hide();
1138 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1139 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1141 /* These signals can all be emitted by a non-GUI thread. Therefore the
1142 handlers for them must not attempt to directly interact with the GUI,
1143 but use Gtkmm2ext::UI::instance()->call_slot();
1146 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1147 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1148 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1149 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::handle_new_audio_region)));
1150 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed)));
1151 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1152 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1153 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1154 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1155 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1156 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1157 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1158 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1159 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1161 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1163 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1165 edit_groups_changed ();
1167 edit_point_clock.set_session (session);
1168 zoom_range_clock.set_session (session);
1169 _playlist_selector->set_session (session);
1170 nudge_clock.set_session (session);
1173 if (analysis_window != 0)
1174 analysis_window->set_session (session);
1177 Location* loc = session->locations()->auto_loop_location();
1179 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1180 if (loc->start() == loc->end()) {
1181 loc->set_end (loc->start() + 1);
1183 session->locations()->add (loc, false);
1184 session->set_auto_loop_location (loc);
1187 loc->set_name (_("Loop"));
1190 loc = session->locations()->auto_punch_location();
1192 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1193 if (loc->start() == loc->end()) {
1194 loc->set_end (loc->start() + 1);
1196 session->locations()->add (loc, false);
1197 session->set_auto_punch_location (loc);
1200 loc->set_name (_("Punch"));
1203 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1205 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1207 refresh_location_display ();
1208 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1209 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1210 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1211 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1212 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1215 sfbrowser->set_session (session);
1218 handle_new_duration ();
1220 redisplay_regions ();
1221 redisplay_named_selections ();
1222 redisplay_snapshots ();
1224 initial_route_list_display ();
1226 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1227 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1230 restore_ruler_visibility ();
1231 //tempo_map_changed (Change (0));
1232 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1236 /* don't show master bus in a new session */
1238 if (ARDOUR_UI::instance()->session_is_new ()) {
1240 TreeModel::Children rows = route_display_model->children();
1241 TreeModel::Children::iterator i;
1243 no_route_list_redisplay = true;
1245 for (i = rows.begin(); i != rows.end(); ++i) {
1246 TimeAxisView *tv = (*i)[route_display_columns.tv];
1247 AudioTimeAxisView *atv;
1249 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1250 if (atv->route()->master()) {
1251 route_list_display.get_selection()->unselect (i);
1256 no_route_list_redisplay = false;
1257 redisplay_route_list ();
1260 /* register for undo history */
1262 session->register_with_memento_command_factory(_id, this);
1268 Editor::build_cursors ()
1270 using namespace Gdk;
1272 Gdk::Color mbg ("#000000" ); /* Black */
1273 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1276 RefPtr<Bitmap> source, mask;
1277 source = Bitmap::create (mag_bits, mag_width, mag_height);
1278 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1279 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1282 Gdk::Color fbg ("#ffffff" );
1283 Gdk::Color ffg ("#000000" );
1286 RefPtr<Bitmap> source, mask;
1288 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1289 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1290 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1294 RefPtr<Bitmap> source, mask;
1295 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1296 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1297 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1301 RefPtr<Bitmap> bits;
1302 char pix[4] = { 0, 0, 0, 0 };
1303 bits = Bitmap::create (pix, 2, 2);
1305 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1308 grabber_cursor = new Gdk::Cursor (HAND2);
1309 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1310 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1311 selector_cursor = new Gdk::Cursor (XTERM);
1312 time_fx_cursor = new Gdk::Cursor (SIZING);
1313 wait_cursor = new Gdk::Cursor (WATCH);
1314 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1318 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1320 using namespace Menu_Helpers;
1321 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1324 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1328 MenuList& items (fade_context_menu.items());
1332 switch (item_type) {
1334 case FadeInHandleItem:
1335 if (arv->audio_region()->fade_in_active()) {
1336 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1338 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1341 items.push_back (SeparatorElem());
1343 if (Profile->get_sae()) {
1344 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1345 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1347 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1348 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1349 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1350 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1351 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1356 case FadeOutHandleItem:
1357 if (arv->audio_region()->fade_out_active()) {
1358 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1360 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1363 items.push_back (SeparatorElem());
1365 if (Profile->get_sae()) {
1366 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1367 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1369 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1370 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1371 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1372 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1373 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1378 fatal << _("programming error: ")
1379 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1384 fade_context_menu.popup (button, time);
1388 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes_t frame)
1390 using namespace Menu_Helpers;
1391 Menu* (Editor::*build_menu_function)(nframes_t);
1394 switch (item_type) {
1396 case RegionViewName:
1397 case RegionViewNameHighlight:
1398 if (with_selection) {
1399 build_menu_function = &Editor::build_track_selection_context_menu;
1401 build_menu_function = &Editor::build_track_region_context_menu;
1406 if (with_selection) {
1407 build_menu_function = &Editor::build_track_selection_context_menu;
1409 build_menu_function = &Editor::build_track_context_menu;
1413 case CrossfadeViewItem:
1414 build_menu_function = &Editor::build_track_crossfade_context_menu;
1418 if (clicked_audio_trackview->get_diskstream()) {
1419 build_menu_function = &Editor::build_track_context_menu;
1421 build_menu_function = &Editor::build_track_bus_context_menu;
1426 /* probably shouldn't happen but if it does, we don't care */
1430 menu = (this->*build_menu_function)(frame);
1431 menu->set_name ("ArdourContextMenu");
1433 /* now handle specific situations */
1435 switch (item_type) {
1437 case RegionViewName:
1438 case RegionViewNameHighlight:
1439 if (!with_selection) {
1440 if (region_edit_menu_split_item) {
1441 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1442 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1444 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1448 if (region_edit_menu_split_multichannel_item) {
1449 if (clicked_regionview && clicked_regionview->region().n_channels() > 1) {
1450 // GTK2FIX find the action, change its sensitivity
1451 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1453 // GTK2FIX see above
1454 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1463 case CrossfadeViewItem:
1470 /* probably shouldn't happen but if it does, we don't care */
1474 if (item_type != SelectionItem && clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1476 /* Bounce to disk */
1478 using namespace Menu_Helpers;
1479 MenuList& edit_items = menu->items();
1481 edit_items.push_back (SeparatorElem());
1483 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1484 case AudioTrack::NoFreeze:
1485 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1488 case AudioTrack::Frozen:
1489 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1492 case AudioTrack::UnFrozen:
1493 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1499 menu->popup (button, time);
1503 Editor::build_track_context_menu (nframes_t ignored)
1505 using namespace Menu_Helpers;
1507 MenuList& edit_items = track_context_menu.items();
1510 add_dstream_context_items (edit_items);
1511 return &track_context_menu;
1515 Editor::build_track_bus_context_menu (nframes_t ignored)
1517 using namespace Menu_Helpers;
1519 MenuList& edit_items = track_context_menu.items();
1522 add_bus_context_items (edit_items);
1523 return &track_context_menu;
1527 Editor::build_track_region_context_menu (nframes_t frame)
1529 using namespace Menu_Helpers;
1530 MenuList& edit_items = track_region_context_menu.items();
1533 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1536 boost::shared_ptr<Diskstream> ds;
1537 boost::shared_ptr<Playlist> pl;
1539 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1540 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)frame * ds->speed()));
1541 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1542 add_region_context_items (atv->audio_view(), (*i), edit_items);
1548 add_dstream_context_items (edit_items);
1550 return &track_region_context_menu;
1554 Editor::build_track_crossfade_context_menu (nframes_t frame)
1556 using namespace Menu_Helpers;
1557 MenuList& edit_items = track_crossfade_context_menu.items();
1558 edit_items.clear ();
1560 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1563 boost::shared_ptr<Diskstream> ds;
1564 boost::shared_ptr<Playlist> pl;
1565 boost::shared_ptr<AudioPlaylist> apl;
1567 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1569 Playlist::RegionList* regions = pl->regions_at (frame);
1570 AudioPlaylist::Crossfades xfades;
1572 apl->crossfades_at (frame, xfades);
1574 bool many = xfades.size() > 1;
1576 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1577 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1580 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1581 add_region_context_items (atv->audio_view(), (*i), edit_items);
1588 add_dstream_context_items (edit_items);
1590 return &track_crossfade_context_menu;
1595 Editor::analyze_region_selection()
1597 if (analysis_window == 0) {
1598 analysis_window = new AnalysisWindow();
1601 analysis_window->set_session(session);
1603 analysis_window->show_all();
1606 analysis_window->set_regionmode();
1607 analysis_window->analyze();
1609 analysis_window->present();
1613 Editor::analyze_range_selection()
1615 if (analysis_window == 0) {
1616 analysis_window = new AnalysisWindow();
1619 analysis_window->set_session(session);
1621 analysis_window->show_all();
1624 analysis_window->set_rangemode();
1625 analysis_window->analyze();
1627 analysis_window->present();
1629 #endif /* FFT_ANALYSIS */
1634 Editor::build_track_selection_context_menu (nframes_t ignored)
1636 using namespace Menu_Helpers;
1637 MenuList& edit_items = track_selection_context_menu.items();
1638 edit_items.clear ();
1640 add_selection_context_items (edit_items);
1641 // edit_items.push_back (SeparatorElem());
1642 // add_dstream_context_items (edit_items);
1644 return &track_selection_context_menu;
1648 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1650 using namespace Menu_Helpers;
1651 Menu *xfade_menu = manage (new Menu);
1652 MenuList& items = xfade_menu->items();
1653 xfade_menu->set_name ("ArdourContextMenu");
1656 if (xfade->active()) {
1662 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1663 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1665 if (xfade->can_follow_overlap()) {
1667 if (xfade->following_overlap()) {
1668 str = _("Convert to short");
1670 str = _("Convert to full");
1673 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1677 str = xfade->out()->name();
1679 str += xfade->in()->name();
1681 str = _("Crossfade");
1684 edit_items.push_back (MenuElem (str, *xfade_menu));
1685 edit_items.push_back (SeparatorElem());
1689 Editor::xfade_edit_left_region ()
1691 if (clicked_crossfadeview) {
1692 clicked_crossfadeview->left_view.show_region_editor ();
1697 Editor::xfade_edit_right_region ()
1699 if (clicked_crossfadeview) {
1700 clicked_crossfadeview->right_view.show_region_editor ();
1705 Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region> region, Menu_Helpers::MenuList& edit_items)
1707 using namespace Menu_Helpers;
1708 Menu *region_menu = manage (new Menu);
1709 MenuList& items = region_menu->items();
1710 region_menu->set_name ("ArdourContextMenu");
1712 boost::shared_ptr<AudioRegion> ar;
1715 ar = boost::dynamic_pointer_cast<AudioRegion> (region);
1718 /* when this particular menu pops up, make the relevant region
1722 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr<Region>(region)));
1724 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1725 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1726 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1727 items.push_back (SeparatorElem());
1728 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_point)));
1729 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1730 items.push_back (SeparatorElem());
1732 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1733 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1734 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1737 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1740 items.push_back (SeparatorElem());
1742 sigc::connection fooc;
1744 items.push_back (CheckMenuElem (_("Lock")));
1745 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1746 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1747 if (region->locked()) {
1749 region_lock_item->set_active();
1752 items.push_back (CheckMenuElem (_("Mute")));
1753 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1754 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1755 if (region->muted()) {
1757 region_mute_item->set_active();
1761 if (!Profile->get_sae()) {
1762 items.push_back (CheckMenuElem (_("Opaque")));
1763 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1764 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1765 if (region->opaque()) {
1767 region_opaque_item->set_active();
1772 items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1773 if (region->at_natural_position()) {
1774 items.back().set_sensitive (false);
1777 items.push_back (SeparatorElem());
1781 RegionView* rv = sv->find_view (ar);
1782 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1784 if (!Profile->get_sae()) {
1785 items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1787 items.push_back (CheckMenuElem (_("Envelope Visible")));
1788 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1789 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1790 if (arv->envelope_visible()) {
1792 region_envelope_visible_item->set_active (true);
1796 items.push_back (CheckMenuElem (_("Envelope Active")));
1797 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1798 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1800 if (ar->envelope_active()) {
1802 region_envelope_active_item->set_active (true);
1806 items.push_back (SeparatorElem());
1809 if (ar->scale_amplitude() != 1.0f) {
1810 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1812 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1816 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1817 items.push_back (SeparatorElem());
1819 /* range related stuff */
1821 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
1822 items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)));
1823 items.push_back (SeparatorElem());
1827 Menu *nudge_menu = manage (new Menu());
1828 MenuList& nudge_items = nudge_menu->items();
1829 nudge_menu->set_name ("ArdourContextMenu");
1831 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1832 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1833 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1834 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1836 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1837 items.push_back (SeparatorElem());
1839 Menu *trim_menu = manage (new Menu);
1840 MenuList& trim_items = trim_menu->items();
1841 trim_menu->set_name ("ArdourContextMenu");
1843 trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point)));
1844 trim_items.push_back (MenuElem (_("Edit point to end"), mem_fun(*this, &Editor::trim_region_to_edit_point)));
1845 trim_items.push_back (MenuElem (_("Trim To Loop"), mem_fun(*this, &Editor::trim_region_to_loop)));
1846 trim_items.push_back (MenuElem (_("Trim To Punch"), mem_fun(*this, &Editor::trim_region_to_punch)));
1848 items.push_back (MenuElem (_("Trim"), *trim_menu));
1849 items.push_back (SeparatorElem());
1851 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1852 region_edit_menu_split_item = &items.back();
1854 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1855 region_edit_menu_split_multichannel_item = &items.back();
1857 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), false))));
1858 items.push_back (MenuElem (_("Multi-Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1859 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1860 items.push_back (SeparatorElem());
1861 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1863 /* OK, stick the region submenu at the top of the list, and then add
1867 /* we have to hack up the region name because "_" has a special
1868 meaning for menu titles.
1871 string::size_type pos = 0;
1872 string menu_item_name = region->name();
1874 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1875 menu_item_name.replace (pos, 1, "__");
1879 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1880 edit_items.push_back (SeparatorElem());
1884 Editor::add_selection_context_items (Menu_Helpers::MenuList& items)
1886 using namespace Menu_Helpers;
1888 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1889 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1892 items.push_back (SeparatorElem());
1893 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1896 items.push_back (SeparatorElem());
1897 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1898 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1900 items.push_back (SeparatorElem());
1901 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1902 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1904 items.push_back (SeparatorElem());
1905 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1907 items.push_back (SeparatorElem());
1908 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1909 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1911 items.push_back (SeparatorElem());
1912 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1913 items.push_back (SeparatorElem());
1914 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1915 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1916 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1917 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1918 items.push_back (SeparatorElem());
1919 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1920 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1924 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1926 using namespace Menu_Helpers;
1930 Menu *play_menu = manage (new Menu);
1931 MenuList& play_items = play_menu->items();
1932 play_menu->set_name ("ArdourContextMenu");
1934 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
1935 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1936 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1937 play_items.push_back (SeparatorElem());
1938 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1940 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1944 Menu *select_menu = manage (new Menu);
1945 MenuList& select_items = select_menu->items();
1946 select_menu->set_name ("ArdourContextMenu");
1948 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1949 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1950 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1951 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1952 select_items.push_back (SeparatorElem());
1953 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1954 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1955 select_items.push_back (SeparatorElem());
1956 select_items.push_back (MenuElem (_("Select All After Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1957 select_items.push_back (MenuElem (_("Select All Before Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1958 select_items.push_back (MenuElem (_("Select All After Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1959 select_items.push_back (MenuElem (_("Select All Before Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1960 select_items.push_back (MenuElem (_("Select All Between Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), false)));
1961 select_items.push_back (MenuElem (_("Select All Within Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), true)));
1962 select_items.push_back (MenuElem (_("Select Range Between Playhead & Edit Point"), mem_fun(*this, &Editor::select_range_between)));
1964 select_items.push_back (SeparatorElem());
1966 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1970 Menu *cutnpaste_menu = manage (new Menu);
1971 MenuList& cutnpaste_items = cutnpaste_menu->items();
1972 cutnpaste_menu->set_name ("ArdourContextMenu");
1974 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1975 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1976 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1978 cutnpaste_items.push_back (SeparatorElem());
1980 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1981 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1983 cutnpaste_items.push_back (SeparatorElem());
1985 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1987 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1989 /* Adding new material */
1991 edit_items.push_back (SeparatorElem());
1992 edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1993 edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1997 Menu *nudge_menu = manage (new Menu());
1998 MenuList& nudge_items = nudge_menu->items();
1999 nudge_menu->set_name ("ArdourContextMenu");
2001 edit_items.push_back (SeparatorElem());
2002 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2003 nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2004 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2005 nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2007 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2011 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2013 using namespace Menu_Helpers;
2017 Menu *play_menu = manage (new Menu);
2018 MenuList& play_items = play_menu->items();
2019 play_menu->set_name ("ArdourContextMenu");
2021 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
2022 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2023 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2027 Menu *select_menu = manage (new Menu);
2028 MenuList& select_items = select_menu->items();
2029 select_menu->set_name ("ArdourContextMenu");
2031 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2032 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
2033 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2034 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
2035 select_items.push_back (SeparatorElem());
2036 select_items.push_back (MenuElem (_("Select all after edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2037 select_items.push_back (MenuElem (_("Select all before edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2038 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2039 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2041 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2045 Menu *cutnpaste_menu = manage (new Menu);
2046 MenuList& cutnpaste_items = cutnpaste_menu->items();
2047 cutnpaste_menu->set_name ("ArdourContextMenu");
2049 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2050 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2051 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2053 Menu *nudge_menu = manage (new Menu());
2054 MenuList& nudge_items = nudge_menu->items();
2055 nudge_menu->set_name ("ArdourContextMenu");
2057 edit_items.push_back (SeparatorElem());
2058 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2059 nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2060 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2061 nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2063 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2066 /* CURSOR SETTING AND MARKS AND STUFF */
2069 Editor::set_snap_to (SnapType st)
2072 string str = snap_type_strings[(int) st];
2074 if (str != snap_type_selector.get_active_text()) {
2075 snap_type_selector.set_active_text (str);
2080 switch (snap_type) {
2081 case SnapToAThirtysecondBeat:
2082 case SnapToASixteenthBeat:
2083 case SnapToAEighthBeat:
2084 case SnapToAQuarterBeat:
2085 case SnapToAThirdBeat:
2086 update_tempo_based_rulers ();
2094 Editor::set_snap_mode (SnapMode mode)
2097 string str = snap_mode_strings[(int)mode];
2099 if (str != snap_mode_selector.get_active_text ()) {
2100 snap_mode_selector.set_active_text (str);
2106 Editor::set_edit_point_preference (EditPoint ep)
2109 string str = edit_point_strings[(int)ep];
2111 if (str != edit_point_selector.get_active_text ()) {
2112 edit_point_selector.set_active_text (str);
2119 Editor::set_state (const XMLNode& node)
2121 const XMLProperty* prop;
2123 int x, y, xoff, yoff;
2126 if ((prop = node.property ("id")) != 0) {
2127 _id = prop->value ();
2130 if ((geometry = find_named_node (node, "geometry")) == 0) {
2132 g.base_width = default_width;
2133 g.base_height = default_height;
2141 g.base_width = atoi(geometry->property("x_size")->value());
2142 g.base_height = atoi(geometry->property("y_size")->value());
2143 x = atoi(geometry->property("x_pos")->value());
2144 y = atoi(geometry->property("y_pos")->value());
2145 xoff = atoi(geometry->property("x_off")->value());
2146 yoff = atoi(geometry->property("y_off")->value());
2149 set_default_size (g.base_width, g.base_height);
2152 if (session && (prop = node.property ("playhead"))) {
2153 nframes_t pos = atol (prop->value().c_str());
2154 playhead_cursor->set_position (pos);
2156 playhead_cursor->set_position (0);
2158 /* reset_x_origin() doesn't work right here, since the old
2159 position may be zero already, and it does nothing in such
2164 horizontal_adjustment.set_value (0);
2167 if ((prop = node.property ("mixer-width"))) {
2168 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2171 if ((prop = node.property ("zoom-focus"))) {
2172 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2175 if ((prop = node.property ("zoom"))) {
2176 reset_zoom (PBD::atof (prop->value()));
2179 if ((prop = node.property ("snap-to"))) {
2180 set_snap_to ((SnapType) atoi (prop->value()));
2183 if ((prop = node.property ("snap-mode"))) {
2184 set_snap_mode ((SnapMode) atoi (prop->value()));
2187 if ((prop = node.property ("edit-point"))) {
2188 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point));
2191 if ((prop = node.property ("mouse-mode"))) {
2192 MouseMode m = str2mousemode(prop->value());
2193 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2194 set_mouse_mode (m, true);
2196 mouse_mode = MouseGain; /* lie, to force the mode switch */
2197 set_mouse_mode (MouseObject, true);
2200 if ((prop = node.property ("show-waveforms"))) {
2201 bool yn = (prop->value() == "yes");
2202 _show_waveforms = !yn;
2203 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2205 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2206 /* do it twice to force the change */
2207 tact->set_active (!yn);
2208 tact->set_active (yn);
2212 if ((prop = node.property ("show-waveforms-recording"))) {
2213 bool yn = (prop->value() == "yes");
2214 _show_waveforms_recording = !yn;
2215 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2217 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2218 /* do it twice to force the change */
2219 tact->set_active (!yn);
2220 tact->set_active (yn);
2224 if ((prop = node.property ("show-measures"))) {
2225 bool yn = (prop->value() == "yes");
2226 _show_measures = !yn;
2227 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2229 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2230 /* do it twice to force the change */
2231 tact->set_active (!yn);
2232 tact->set_active (yn);
2236 if ((prop = node.property ("follow-playhead"))) {
2237 bool yn = (prop->value() == "yes");
2238 set_follow_playhead (yn);
2239 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2241 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2242 if (tact->get_active() != yn) {
2243 tact->set_active (yn);
2248 if ((prop = node.property ("region-list-sort-type"))) {
2249 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2250 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2253 if ((prop = node.property ("xfades-visible"))) {
2254 bool yn = (prop->value() == "yes");
2255 _xfade_visibility = !yn;
2256 // set_xfade_visibility (yn);
2259 if ((prop = node.property ("show-editor-mixer"))) {
2261 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2264 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2265 bool yn = (prop->value() == X_("yes"));
2267 /* do it twice to force the change */
2269 tact->set_active (!yn);
2270 tact->set_active (yn);
2279 Editor::get_state ()
2281 XMLNode* node = new XMLNode ("Editor");
2284 _id.print (buf, sizeof (buf));
2285 node->add_property ("id", buf);
2287 if (is_realized()) {
2288 Glib::RefPtr<Gdk::Window> win = get_window();
2290 int x, y, xoff, yoff, width, height;
2291 win->get_root_origin(x, y);
2292 win->get_position(xoff, yoff);
2293 win->get_size(width, height);
2295 XMLNode* geometry = new XMLNode ("geometry");
2297 snprintf(buf, sizeof(buf), "%d", width);
2298 geometry->add_property("x_size", string(buf));
2299 snprintf(buf, sizeof(buf), "%d", height);
2300 geometry->add_property("y_size", string(buf));
2301 snprintf(buf, sizeof(buf), "%d", x);
2302 geometry->add_property("x_pos", string(buf));
2303 snprintf(buf, sizeof(buf), "%d", y);
2304 geometry->add_property("y_pos", string(buf));
2305 snprintf(buf, sizeof(buf), "%d", xoff);
2306 geometry->add_property("x_off", string(buf));
2307 snprintf(buf, sizeof(buf), "%d", yoff);
2308 geometry->add_property("y_off", string(buf));
2309 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2310 geometry->add_property("edit_pane_pos", string(buf));
2312 node->add_child_nocopy (*geometry);
2315 maybe_add_mixer_strip_width (*node);
2317 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2318 node->add_property ("zoom-focus", buf);
2319 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2320 node->add_property ("zoom", buf);
2321 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2322 node->add_property ("snap-to", buf);
2323 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2324 node->add_property ("snap-mode", buf);
2326 node->add_property ("edit-point", enum_2_string (_edit_point));
2328 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2329 node->add_property ("playhead", buf);
2331 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2332 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2333 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2334 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2335 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2336 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2337 node->add_property ("mouse-mode", enum2str(mouse_mode));
2339 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2341 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2342 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2351 Editor::trackview_by_y_position (double y)
2353 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2357 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2366 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2368 Location* before = 0;
2369 Location* after = 0;
2371 if (!session || snap_mode == SnapOff) {
2375 const nframes64_t one_second = session->frame_rate();
2376 const nframes64_t one_minute = session->frame_rate() * 60;
2377 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2378 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2379 nframes64_t presnap = start;
2381 switch (snap_type) {
2384 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2386 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2390 case SnapToSMPTEFrame:
2391 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2392 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2394 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2398 case SnapToSMPTESeconds:
2399 if (session->smpte_offset_negative())
2401 start += session->smpte_offset ();
2403 start -= session->smpte_offset ();
2405 if (start % one_smpte_second > one_smpte_second / 2) {
2406 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2408 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2411 if (session->smpte_offset_negative())
2413 start -= session->smpte_offset ();
2415 start += session->smpte_offset ();
2419 case SnapToSMPTEMinutes:
2420 if (session->smpte_offset_negative())
2422 start += session->smpte_offset ();
2424 start -= session->smpte_offset ();
2426 if (start % one_smpte_minute > one_smpte_minute / 2) {
2427 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2429 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2431 if (session->smpte_offset_negative())
2433 start -= session->smpte_offset ();
2435 start += session->smpte_offset ();
2440 if (start % one_second > one_second / 2) {
2441 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2443 start = (nframes_t) floor ((double) start / one_second) * one_second;
2448 if (start % one_minute > one_minute / 2) {
2449 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2451 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2456 start = session->tempo_map().round_to_bar (start, direction);
2460 start = session->tempo_map().round_to_beat (start, direction);
2463 case SnapToAThirtysecondBeat:
2464 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2467 case SnapToASixteenthBeat:
2468 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2471 case SnapToAEighthBeat:
2472 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2475 case SnapToAQuarterBeat:
2476 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2479 case SnapToAThirdBeat:
2480 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2488 before = session->locations()->first_location_before (start);
2489 after = session->locations()->first_location_after (start);
2491 if (direction < 0) {
2493 start = before->start();
2497 } else if (direction > 0) {
2499 start = after->start();
2501 start = session->current_end_frame();
2506 /* find nearest of the two */
2507 if ((start - before->start()) < (after->start() - start)) {
2508 start = before->start();
2510 start = after->start();
2513 start = before->start();
2516 start = after->start();
2523 case SnapToRegionStart:
2524 case SnapToRegionEnd:
2525 case SnapToRegionSync:
2526 case SnapToRegionBoundary:
2527 if (!region_boundary_cache.empty()) {
2528 vector<nframes_t>::iterator i;
2530 if (direction > 0) {
2531 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2533 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2536 if (i != region_boundary_cache.end()) {
2539 start = region_boundary_cache.back();
2545 switch (snap_mode) {
2551 if (presnap > start) {
2552 if (presnap > (start + unit_to_frame(snap_threshold))) {
2556 } else if (presnap < start) {
2557 if (presnap < (start - unit_to_frame(snap_threshold))) {
2563 /* handled at entry */
2570 Editor::setup_toolbar ()
2574 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2577 /* Mode Buttons (tool selection) */
2579 vector<ToggleButton *> mouse_mode_buttons;
2581 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2582 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2583 mouse_mode_buttons.push_back (&mouse_move_button);
2584 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2585 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2586 mouse_mode_buttons.push_back (&mouse_select_button);
2587 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2588 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2589 mouse_mode_buttons.push_back (&mouse_gain_button);
2590 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2591 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2592 mouse_mode_buttons.push_back (&mouse_zoom_button);
2593 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2594 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2595 mouse_mode_buttons.push_back (&mouse_timefx_button);
2596 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2597 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2598 mouse_mode_buttons.push_back (&mouse_audition_button);
2600 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2602 HBox* mode_box = manage(new HBox);
2603 mode_box->set_border_width (2);
2604 mode_box->set_spacing(4);
2605 mouse_mode_button_box.set_spacing(1);
2606 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2607 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2608 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2609 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2610 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2611 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2612 mouse_mode_button_box.set_homogeneous(true);
2614 vector<string> edit_mode_strings;
2615 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2616 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2618 edit_mode_selector.set_name ("EditModeSelector");
2619 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2620 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2621 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2623 mode_box->pack_start(edit_mode_selector);
2624 mode_box->pack_start(mouse_mode_button_box);
2626 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2627 mouse_mode_tearoff->set_name ("MouseModeBase");
2629 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2630 &mouse_mode_tearoff->tearoff_window()));
2631 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2632 &mouse_mode_tearoff->tearoff_window(), 1));
2633 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2634 &mouse_mode_tearoff->tearoff_window()));
2635 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2636 &mouse_mode_tearoff->tearoff_window(), 1));
2638 mouse_move_button.set_name ("MouseModeButton");
2639 mouse_select_button.set_name ("MouseModeButton");
2640 mouse_gain_button.set_name ("MouseModeButton");
2641 mouse_zoom_button.set_name ("MouseModeButton");
2642 mouse_timefx_button.set_name ("MouseModeButton");
2643 mouse_audition_button.set_name ("MouseModeButton");
2645 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2646 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2647 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2648 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2649 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2650 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2652 mouse_move_button.unset_flags (CAN_FOCUS);
2653 mouse_select_button.unset_flags (CAN_FOCUS);
2654 mouse_gain_button.unset_flags (CAN_FOCUS);
2655 mouse_zoom_button.unset_flags (CAN_FOCUS);
2656 mouse_timefx_button.unset_flags (CAN_FOCUS);
2657 mouse_audition_button.unset_flags (CAN_FOCUS);
2659 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2660 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2662 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2663 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2664 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2665 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2666 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2668 // mouse_move_button.set_active (true);
2673 zoom_box.set_spacing (1);
2674 zoom_box.set_border_width (2);
2676 zoom_in_button.set_name ("EditorTimeButton");
2677 zoom_in_button.set_size_request(-1,16);
2678 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2679 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2680 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2682 zoom_out_button.set_name ("EditorTimeButton");
2683 zoom_out_button.set_size_request(-1,16);
2684 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2685 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2686 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2688 zoom_out_full_button.set_name ("EditorTimeButton");
2689 zoom_out_full_button.set_size_request(-1,16);
2690 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2691 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2692 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2694 zoom_focus_selector.set_name ("ZoomFocusSelector");
2695 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Playhead", FUDGE, 0);
2696 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2697 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2698 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2700 zoom_box.pack_start (zoom_focus_selector, true, true);
2701 zoom_box.pack_start (zoom_out_button, false, false);
2702 zoom_box.pack_start (zoom_in_button, false, false);
2703 zoom_box.pack_start (zoom_out_full_button, false, false);
2705 snap_box.set_spacing (1);
2706 snap_box.set_border_width (2);
2708 snap_type_selector.set_name ("SnapTypeSelector");
2709 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2710 set_popdown_strings (snap_type_selector, snap_type_strings);
2711 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2712 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
2714 snap_mode_selector.set_name ("SnapModeSelector");
2715 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2716 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2717 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2718 ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2720 edit_point_selector.set_name ("SnapModeSelector");
2721 Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, "Playhead", 2+FUDGE, 10);
2722 set_popdown_strings (edit_point_selector, edit_point_strings);
2723 edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
2724 ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
2726 snap_box.pack_start (edit_point_clock, false, false);
2727 snap_box.pack_start (snap_mode_selector, false, false);
2728 snap_box.pack_start (snap_type_selector, false, false);
2729 snap_box.pack_start (edit_point_selector, false, false);
2733 HBox *nudge_box = manage (new HBox);
2734 nudge_box->set_spacing(1);
2735 nudge_box->set_border_width (2);
2737 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2738 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2740 nudge_box->pack_start (nudge_backward_button, false, false);
2741 nudge_box->pack_start (nudge_forward_button, false, false);
2742 nudge_box->pack_start (nudge_clock, false, false);
2745 /* Pack everything in... */
2747 HBox* hbox = new HBox;
2748 hbox->set_spacing(10);
2750 tools_tearoff = new TearOff (*hbox);
2751 tools_tearoff->set_name ("MouseModeBase");
2753 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2754 &tools_tearoff->tearoff_window()));
2755 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2756 &tools_tearoff->tearoff_window(), 0));
2757 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2758 &tools_tearoff->tearoff_window()));
2759 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2760 &tools_tearoff->tearoff_window(), 0));
2762 toolbar_hbox.set_spacing (10);
2763 toolbar_hbox.set_border_width (1);
2765 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2766 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2769 hbox->pack_start (snap_box, false, false);
2770 // hbox->pack_start (zoom_box, false, false);
2771 hbox->pack_start (*nudge_box, false, false);
2775 toolbar_base.set_name ("ToolBarBase");
2776 toolbar_base.add (toolbar_hbox);
2778 toolbar_frame.set_shadow_type (SHADOW_OUT);
2779 toolbar_frame.set_name ("BaseFrame");
2780 toolbar_frame.add (toolbar_base);
2784 Editor::convert_drop_to_paths (vector<ustring>& paths,
2785 const RefPtr<Gdk::DragContext>& context,
2788 const SelectionData& data,
2797 vector<ustring> uris = data.get_uris();
2801 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2802 are actually URI lists. So do it by hand.
2805 if (data.get_target() != "text/plain") {
2809 /* Parse the "uri-list" format that Nautilus provides,
2810 where each pathname is delimited by \r\n
2813 const char* p = data.get_text().c_str();
2820 while (g_ascii_isspace (*p))
2824 while (*q && (*q != '\n') && (*q != '\r'))
2830 while (q > p && g_ascii_isspace (*q))
2835 uris.push_back (ustring (p, q - p + 1));
2839 p = strchr (p, '\n');
2849 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2851 if ((*i).substr (0,7) == "file://") {
2855 PBD::url_decode (p);
2857 // scan forward past three slashes
2859 ustring::size_type slashcnt = 0;
2860 ustring::size_type n = 0;
2861 ustring::iterator x = p.begin();
2863 while (slashcnt < 3 && x != p.end()) {
2866 } else if (slashcnt == 3) {
2873 if (slashcnt != 3 || x == p.end()) {
2874 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2878 paths.push_back (p.substr (n - 1));
2886 Editor::new_tempo_section ()
2892 Editor::map_transport_state ()
2894 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2896 if (session->transport_stopped()) {
2897 have_pending_keyboard_selection = false;
2900 update_loop_range_view (true);
2905 Editor::State::State ()
2907 selection = new Selection;
2910 Editor::State::~State ()
2916 Editor::get_memento () const
2918 State *state = new State;
2920 store_state (*state);
2921 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2925 Editor::store_state (State& state) const
2927 *state.selection = *selection;
2931 Editor::restore_state (State *state)
2933 if (*selection == *state->selection) {
2937 *selection = *state->selection;
2938 time_selection_changed ();
2939 region_selection_changed ();
2941 /* XXX other selection change handlers? */
2945 Editor::begin_reversible_command (string name)
2948 // before = &get_state();
2949 session->begin_reversible_command (name);
2954 Editor::commit_reversible_command ()
2957 // session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2958 session->commit_reversible_command ();
2963 Editor::set_edit_group_solo (Route& route, bool yn)
2965 RouteGroup *edit_group;
2967 if ((edit_group = route.edit_group()) != 0) {
2968 edit_group->apply (&Route::set_solo, yn, this);
2970 route.set_solo (yn, this);
2975 Editor::set_edit_group_mute (Route& route, bool yn)
2977 RouteGroup *edit_group = 0;
2979 if ((edit_group == route.edit_group()) != 0) {
2980 edit_group->apply (&Route::set_mute, yn, this);
2982 route.set_mute (yn, this);
2987 Editor::history_changed ()
2991 if (undo_action && session) {
2992 if (session->undo_depth() == 0) {
2995 label = string_compose(_("Undo (%1)"), session->next_undo());
2997 undo_action->property_label() = label;
3000 if (redo_action && session) {
3001 if (session->redo_depth() == 0) {
3004 label = string_compose(_("Redo (%1)"), session->next_redo());
3006 redo_action->property_label() = label;
3011 Editor::duplicate_dialog (bool with_dialog)
3015 if (mouse_mode == MouseRange) {
3016 if (selection->time.length() == 0) {
3022 if (mouse_mode != MouseRange) {
3024 ensure_entered_selected (true);
3026 if (selection->regions.empty()) {
3033 ArdourDialog win ("duplicate dialog");
3034 Label label (_("Duplicate how many times?"));
3035 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3036 SpinButton spinner (adjustment);
3038 win.get_vbox()->set_spacing (12);
3039 win.get_vbox()->pack_start (label);
3041 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3042 place, visually. so do this by hand.
3045 win.get_vbox()->pack_start (spinner);
3046 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3051 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3052 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3054 win.set_position (WIN_POS_MOUSE);
3056 spinner.grab_focus ();
3058 switch (win.run ()) {
3059 case RESPONSE_ACCEPT:
3065 times = adjustment.get_value();
3068 if (mouse_mode == MouseRange) {
3069 duplicate_selection (times);
3071 duplicate_some_regions (selection->regions, times);
3076 Editor::show_verbose_canvas_cursor ()
3078 verbose_canvas_cursor->raise_to_top();
3079 verbose_canvas_cursor->show();
3080 verbose_cursor_visible = true;
3084 Editor::hide_verbose_canvas_cursor ()
3086 verbose_canvas_cursor->hide();
3087 verbose_cursor_visible = false;
3091 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3093 /* XXX get origin of canvas relative to root window,
3094 add x and y and check compared to gdk_screen_{width,height}
3096 verbose_canvas_cursor->property_text() = txt.c_str();
3097 verbose_canvas_cursor->property_x() = x;
3098 verbose_canvas_cursor->property_y() = y;
3102 Editor::set_verbose_canvas_cursor_text (const string & txt)
3104 verbose_canvas_cursor->property_text() = txt.c_str();
3108 Editor::set_edit_mode (EditMode m)
3110 Config->set_edit_mode (m);
3114 Editor::cycle_edit_mode ()
3116 switch (Config->get_edit_mode()) {
3118 Config->set_edit_mode (Splice);
3121 Config->set_edit_mode (Slide);
3127 Editor::edit_mode_selection_done ()
3133 string choice = edit_mode_selector.get_active_text();
3134 EditMode mode = Slide;
3136 if (choice == _("Splice Edit")) {
3138 } else if (choice == _("Slide Edit")) {
3142 Config->set_edit_mode (mode);
3146 Editor::snap_type_selection_done ()
3148 string choice = snap_type_selector.get_active_text();
3149 SnapType snaptype = SnapToBeat;
3151 if (choice == _("Beats/3")) {
3152 snaptype = SnapToAThirdBeat;
3153 } else if (choice == _("Beats/4")) {
3154 snaptype = SnapToAQuarterBeat;
3155 } else if (choice == _("Beats/8")) {
3156 snaptype = SnapToAEighthBeat;
3157 } else if (choice == _("Beats/16")) {
3158 snaptype = SnapToASixteenthBeat;
3159 } else if (choice == _("Beats/32")) {
3160 snaptype = SnapToAThirtysecondBeat;
3161 } else if (choice == _("Beats")) {
3162 snaptype = SnapToBeat;
3163 } else if (choice == _("Bars")) {
3164 snaptype = SnapToBar;
3165 } else if (choice == _("Marks")) {
3166 snaptype = SnapToMark;
3167 } else if (choice == _("Region starts")) {
3168 snaptype = SnapToRegionStart;
3169 } else if (choice == _("Region ends")) {
3170 snaptype = SnapToRegionEnd;
3171 } else if (choice == _("Region bounds")) {
3172 snaptype = SnapToRegionBoundary;
3173 } else if (choice == _("Region syncs")) {
3174 snaptype = SnapToRegionSync;
3175 } else if (choice == _("CD Frames")) {
3176 snaptype = SnapToCDFrame;
3177 } else if (choice == _("SMPTE Frames")) {
3178 snaptype = SnapToSMPTEFrame;
3179 } else if (choice == _("SMPTE Seconds")) {
3180 snaptype = SnapToSMPTESeconds;
3181 } else if (choice == _("SMPTE Minutes")) {
3182 snaptype = SnapToSMPTEMinutes;
3183 } else if (choice == _("Seconds")) {
3184 snaptype = SnapToSeconds;
3185 } else if (choice == _("Minutes")) {
3186 snaptype = SnapToMinutes;
3189 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3191 ract->set_active ();
3196 Editor::snap_mode_selection_done ()
3198 string choice = snap_mode_selector.get_active_text();
3199 SnapMode mode = SnapNormal;
3201 if (choice == _("No Grid")) {
3203 } else if (choice == _("Grid")) {
3205 } else if (choice == _("Magnetic")) {
3206 mode = SnapMagnetic;
3209 RefPtr<RadioAction> ract = snap_mode_action (mode);
3212 ract->set_active (true);
3217 Editor::cycle_edit_point ()
3219 switch (_edit_point) {
3221 set_edit_point_preference (EditAtPlayhead);
3223 case EditAtPlayhead:
3224 set_edit_point_preference (EditAtSelectedMarker);
3226 case EditAtSelectedMarker:
3227 set_edit_point_preference (EditAtMouse);
3233 Editor::edit_point_selection_done ()
3235 string choice = edit_point_selector.get_active_text();
3236 EditPoint ep = EditAtSelectedMarker;
3238 if (choice == _("Marker")) {
3239 _edit_point = EditAtSelectedMarker;
3240 } else if (choice == _("Playhead")) {
3241 _edit_point = EditAtPlayhead;
3243 _edit_point = EditAtMouse;
3246 RefPtr<RadioAction> ract = edit_point_action (ep);
3249 ract->set_active (true);
3254 Editor::zoom_focus_selection_done ()
3256 string choice = zoom_focus_selector.get_active_text();
3257 ZoomFocus focus_type = ZoomFocusLeft;
3259 if (choice == _("Left")) {
3260 focus_type = ZoomFocusLeft;
3261 } else if (choice == _("Right")) {
3262 focus_type = ZoomFocusRight;
3263 } else if (choice == _("Center")) {
3264 focus_type = ZoomFocusCenter;
3265 } else if (choice == _("Playhead")) {
3266 focus_type = ZoomFocusPlayhead;
3267 } else if (choice == _("Mouse")) {
3268 focus_type = ZoomFocusMouse;
3269 } else if (choice == _("Edit Point")) {
3270 focus_type = ZoomFocusEdit;
3273 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3276 ract->set_active ();
3281 Editor::edit_controls_button_release (GdkEventButton* ev)
3283 if (Keyboard::is_context_menu_event (ev)) {
3284 ARDOUR_UI::instance()->add_route (this);
3290 Editor::mouse_select_button_release (GdkEventButton* ev)
3292 /* this handles just right-clicks */
3294 if (ev->button != 3) {
3301 Editor::TrackViewList *
3302 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3305 TrackViewList::iterator i;
3307 v = new TrackViewList;
3309 if (track == 0 && group == 0) {
3313 for (i = track_views.begin(); i != track_views.end (); ++i) {
3317 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3319 /* just the view for this track
3322 v->push_back (track);
3326 /* views for all tracks in the edit group */
3328 for (i = track_views.begin(); i != track_views.end (); ++i) {
3330 if (group == 0 || (*i)->edit_group() == group) {
3340 Editor::set_zoom_focus (ZoomFocus f)
3342 string str = zoom_focus_strings[(int)f];
3344 if (str != zoom_focus_selector.get_active_text()) {
3345 zoom_focus_selector.set_active_text (str);
3348 if (zoom_focus != f) {
3351 ZoomFocusChanged (); /* EMIT_SIGNAL */
3358 Editor::ensure_float (Window& win)
3360 win.set_transient_for (*this);
3364 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3366 /* recover or initialize pane positions. do this here rather than earlier because
3367 we don't want the positions to change the child allocations, which they seem to do.
3373 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3375 static int32_t done;
3378 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3379 width = default_width;
3380 height = default_height;
3382 width = atoi(geometry->property("x_size")->value());
3383 height = atoi(geometry->property("y_size")->value());
3386 if (which == static_cast<Paned*> (&edit_pane)) {
3392 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3393 /* initial allocation is 90% to canvas, 10% to notebook */
3394 pos = (int) floor (alloc.get_width() * 0.90f);
3395 snprintf (buf, sizeof(buf), "%d", pos);
3397 pos = atoi (prop->value());
3400 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3401 edit_pane.set_position (pos);
3402 pre_maximal_pane_position = pos;
3408 Editor::detach_tearoff (Box* b, Window* w)
3410 if (tools_tearoff->torn_off() &&
3411 mouse_mode_tearoff->torn_off()) {
3412 top_hbox.remove (toolbar_frame);
3417 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3419 if (toolbar_frame.get_parent() == 0) {
3420 top_hbox.pack_end (toolbar_frame);
3425 Editor::set_show_measures (bool yn)
3427 if (_show_measures != yn) {
3430 if ((_show_measures = yn) == true) {
3438 Editor::toggle_follow_playhead ()
3440 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3442 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3443 set_follow_playhead (tact->get_active());
3448 Editor::set_follow_playhead (bool yn)
3450 if (_follow_playhead != yn) {
3451 if ((_follow_playhead = yn) == true) {
3453 update_current_screen ();
3460 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3462 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3464 xfade->set_active (!xfade->active());
3469 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3471 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3473 xfade->set_follow_overlap (!xfade->following_overlap());
3478 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3480 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3486 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3490 switch (cew.run ()) {
3491 case RESPONSE_ACCEPT:
3498 xfade->StateChanged (Change (~0));
3502 Editor::playlist_selector () const
3504 return *_playlist_selector;
3508 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3512 ret = nudge_clock.current_duration (pos);
3513 next = ret + 1; /* XXXX fix me */
3519 Editor::end_location_changed (Location* location)
3521 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3522 reset_scrolling_region ();
3526 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3528 ArdourDialog dialog ("playlist deletion dialog");
3529 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3530 "If left alone, no audio files used by it will be cleaned.\n"
3531 "If deleted, audio files used by it alone by will cleaned."),
3534 dialog.set_position (WIN_POS_CENTER);
3535 dialog.get_vbox()->pack_start (label);
3539 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3540 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3541 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3543 switch (dialog.run ()) {
3544 case RESPONSE_ACCEPT:
3545 /* delete the playlist */
3549 case RESPONSE_REJECT:
3550 /* keep the playlist */
3562 Editor::audio_region_selection_covers (nframes_t where)
3564 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3565 if ((*a)->region()->covers (where)) {
3574 Editor::prepare_for_cleanup ()
3576 cut_buffer->clear_regions ();
3577 cut_buffer->clear_playlists ();
3579 selection->clear_regions ();
3580 selection->clear_playlists ();
3584 Editor::transport_loop_location()
3587 return session->locations()->auto_loop_location();
3594 Editor::transport_punch_location()
3597 return session->locations()->auto_punch_location();
3604 Editor::control_layout_scroll (GdkEventScroll* ev)
3606 switch (ev->direction) {
3608 scroll_tracks_up_line ();
3612 case GDK_SCROLL_DOWN:
3613 scroll_tracks_down_line ();
3617 /* no left/right handling yet */
3625 /** A new snapshot has been selected.
3628 Editor::snapshot_display_selection_changed ()
3630 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3632 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3634 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3636 if (snap_name.length() == 0) {
3640 if (session->snap_name() == snap_name) {
3644 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3649 Editor::snapshot_display_button_press (GdkEventButton* ev)
3651 if (ev->button == 3) {
3652 /* Right-click on the snapshot list. Work out which snapshot it
3654 Gtk::TreeModel::Path path;
3655 Gtk::TreeViewColumn* col;
3658 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3659 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3661 Gtk::TreeModel::Row row = *iter;
3662 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3671 /** Pop up the snapshot display context menu.
3672 * @param button Button used to open the menu.
3673 * @param time Menu open time.
3674 * @snapshot_name Name of the snapshot that the menu click was over.
3678 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3680 using namespace Menu_Helpers;
3682 MenuList& items (snapshot_context_menu.items());
3685 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3687 items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)));
3688 if (!modification_allowed) {
3689 items.back().set_sensitive (false);
3692 items.push_back (MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)));
3693 if (!modification_allowed) {
3694 items.back().set_sensitive (false);
3697 snapshot_context_menu.popup (button, time);
3701 Editor::rename_snapshot (Glib::ustring old_name)
3703 ArdourPrompter prompter(true);
3707 prompter.set_name ("Prompter");
3708 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3709 prompter.set_prompt (_("New name of snapshot"));
3710 prompter.set_initial_text (old_name);
3712 if (prompter.run() == RESPONSE_ACCEPT) {
3713 prompter.get_result (new_name);
3714 if (new_name.length()) {
3715 session->rename_state (old_name, new_name);
3716 redisplay_snapshots ();
3723 Editor::remove_snapshot (Glib::ustring name)
3725 vector<string> choices;
3727 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3729 choices.push_back (_("No, do nothing."));
3730 choices.push_back (_("Yes, remove it."));
3732 Gtkmm2ext::Choice prompter (prompt, choices);
3734 if (prompter.run () == 1) {
3735 session->remove_state (name);
3736 redisplay_snapshots ();
3741 Editor::redisplay_snapshots ()
3747 vector<string*>* states;
3749 if ((states = session->possible_states()) == 0) {
3753 snapshot_display_model->clear ();
3755 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3756 string statename = *(*i);
3757 TreeModel::Row row = *(snapshot_display_model->append());
3759 /* this lingers on in case we ever want to change the visible
3760 name of the snapshot.
3763 string display_name;
3764 display_name = statename;
3766 if (statename == session->snap_name()) {
3767 snapshot_display.get_selection()->select(row);
3770 row[snapshot_display_columns.visible_name] = display_name;
3771 row[snapshot_display_columns.real_name] = statename;
3778 Editor::session_state_saved (string snap_name)
3780 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3781 redisplay_snapshots ();
3785 Editor::maximise_editing_space ()
3787 initial_ruler_update_required = true;
3789 mouse_mode_tearoff->set_visible (false);
3790 tools_tearoff->set_visible (false);
3792 pre_maximal_pane_position = edit_pane.get_position();
3793 pre_maximal_editor_width = this->get_width();
3795 if(post_maximal_pane_position == 0) {
3796 post_maximal_pane_position = edit_pane.get_width();
3801 if(post_maximal_editor_width) {
3802 edit_pane.set_position (post_maximal_pane_position -
3803 abs(post_maximal_editor_width - pre_maximal_editor_width));
3805 edit_pane.set_position (post_maximal_pane_position);
3810 Editor::restore_editing_space ()
3812 initial_ruler_update_required = true;
3814 // user changed width of pane during fullscreen
3815 if(post_maximal_pane_position != edit_pane.get_position()) {
3816 post_maximal_pane_position = edit_pane.get_position();
3821 mouse_mode_tearoff->set_visible (true);
3822 tools_tearoff->set_visible (true);
3823 post_maximal_editor_width = this->get_width();
3826 edit_pane.set_position (
3827 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3832 * Make new playlists for a given track and also any others that belong
3833 * to the same active edit group.
3838 Editor::new_playlists (TimeAxisView* v)
3840 begin_reversible_command (_("new playlists"));
3841 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3842 commit_reversible_command ();
3847 * Use a copy of the current playlist for a given track and also any others that belong
3848 * to the same active edit group.
3853 Editor::copy_playlists (TimeAxisView* v)
3855 begin_reversible_command (_("copy playlists"));
3856 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3857 commit_reversible_command ();
3862 * Clear the current playlist for a given track and also any others that belong
3863 * to the same active edit group.
3868 Editor::clear_playlists (TimeAxisView* v)
3870 begin_reversible_command (_("clear playlists"));
3871 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3872 commit_reversible_command ();
3876 Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz)
3878 atv.use_new_playlist (sz > 1 ? false : true);
3882 Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz)
3884 atv.use_copy_playlist (sz > 1 ? false : true);
3888 Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz)
3890 atv.clear_playlist ();
3894 Editor::on_key_press_event (GdkEventKey* ev)
3896 return key_press_focus_accelerator_handler (*this, ev);
3900 Editor::reset_x_origin (nframes_t frame)
3902 queue_visual_change (frame);
3906 Editor::reset_zoom (double fpu)
3908 queue_visual_change (fpu);
3912 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3914 reset_x_origin (frame);
3919 Editor::set_frames_per_unit (double fpu)
3923 /* this is the core function that controls the zoom level of the canvas. it is called
3924 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3927 if (fpu == frames_per_unit) {
3935 // convert fpu to frame count
3937 frames = (nframes_t) floor (fpu * canvas_width);
3939 /* don't allow zooms that fit more than the maximum number
3940 of frames into an 800 pixel wide space.
3943 if (max_frames / fpu < 800.0) {
3947 if (fpu == frames_per_unit) {
3951 frames_per_unit = fpu;
3953 if (frames != zoom_range_clock.current_duration()) {
3954 zoom_range_clock.set (frames);
3957 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3958 if (!selection->tracks.empty()) {
3959 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3960 (*i)->reshow_selection (selection->time);
3963 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3964 (*i)->reshow_selection (selection->time);
3969 ZoomChanged (); /* EMIT_SIGNAL */
3971 reset_hscrollbar_stepping ();
3972 reset_scrolling_region ();
3974 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3980 Editor::queue_visual_change (nframes_t where)
3982 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3983 pending_visual_change.time_origin = where;
3985 if (pending_visual_change.idle_handler_id < 0) {
3986 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3991 Editor::queue_visual_change (double fpu)
3993 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3994 pending_visual_change.frames_per_unit = fpu;
3996 if (pending_visual_change.idle_handler_id < 0) {
3997 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
4002 Editor::_idle_visual_changer (void* arg)
4004 return static_cast<Editor*>(arg)->idle_visual_changer ();
4008 Editor::idle_visual_changer ()
4010 VisualChange::Type p = pending_visual_change.pending;
4012 pending_visual_change.pending = (VisualChange::Type) 0;
4013 pending_visual_change.idle_handler_id = -1;
4015 if (p & VisualChange::ZoomLevel) {
4016 set_frames_per_unit (pending_visual_change.frames_per_unit);
4019 if (p & VisualChange::TimeOrigin) {
4020 if (pending_visual_change.time_origin != leftmost_frame) {
4021 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
4022 /* the signal handler will do the rest */
4024 update_fixed_rulers();
4025 redisplay_tempo (true);
4029 return 0; /* this is always a one-shot call */
4032 struct EditorOrderTimeAxisSorter {
4033 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4034 return a->order < b->order;
4039 Editor::sort_track_selection ()
4041 EditorOrderTimeAxisSorter cmp;
4042 selection->tracks.sort (cmp);
4046 Editor::get_preferred_edit_position()
4049 nframes64_t where = 0;
4051 if (entered_marker) {
4052 return entered_marker->position();
4055 switch (_edit_point) {
4056 case EditAtPlayhead:
4057 where = session->audible_frame();
4060 case EditAtSelectedMarker:
4061 if (!selection->markers.empty()) {
4063 Location* loc = find_location_from_marker (selection->markers.front(), whocares);
4065 where = loc->start();
4073 if (!mouse_frame (where, ignored)) {
4074 /* XXX not right but what can we do ? */
4085 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4087 if (!session) return;
4089 begin_reversible_command (cmd);
4093 if ((tll = transport_loop_location()) == 0) {
4094 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4095 XMLNode &before = session->locations()->get_state();
4096 session->locations()->add (loc, true);
4097 session->set_auto_loop_location (loc);
4098 XMLNode &after = session->locations()->get_state();
4099 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4102 XMLNode &before = tll->get_state();
4103 tll->set_hidden (false, this);
4104 tll->set (start, end);
4105 XMLNode &after = tll->get_state();
4106 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4109 commit_reversible_command ();
4113 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4115 if (!session) return;
4117 begin_reversible_command (cmd);
4121 if ((tpl = transport_punch_location()) == 0) {
4122 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4123 XMLNode &before = session->locations()->get_state();
4124 session->locations()->add (loc, true);
4125 session->set_auto_loop_location (loc);
4126 XMLNode &after = session->locations()->get_state();
4127 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4130 XMLNode &before = tpl->get_state();
4131 tpl->set_hidden (false, this);
4132 tpl->set (start, end);
4133 XMLNode &after = tpl->get_state();
4134 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4137 commit_reversible_command ();
4141 Editor::get_regions_at (nframes64_t where, const TrackSelection& ts) const
4144 const TrackSelection* tracks;
4147 tracks = &track_views;
4152 for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4154 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4157 boost::shared_ptr<Diskstream> ds;
4158 boost::shared_ptr<Playlist> pl;
4160 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4162 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)where * ds->speed()));
4164 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4166 RegionView* rv = atv->audio_view()->find_view (*i);
4183 Editor::get_regions_after (nframes64_t where, const TrackSelection& ts) const
4186 const TrackSelection* tracks;
4189 tracks = &track_views;
4194 for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4196 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4199 boost::shared_ptr<Diskstream> ds;
4200 boost::shared_ptr<Playlist> pl;
4202 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4204 Playlist::RegionList* regions = pl->regions_touched ((nframes_t) floor ( (double)where * ds->speed()), max_frames);
4206 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4208 RegionView* rv = atv->audio_view()->find_view (*i);
4224 Editor::get_regions_for_action ()
4226 if (!selection->regions.empty()) {
4227 return selection->regions;
4230 nframes64_t where = get_preferred_edit_position();
4231 tmp_regions = get_regions_at (where, selection->tracks);
4236 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4239 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4241 RouteTimeAxisView* tatv;
4243 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4245 boost::shared_ptr<Playlist> pl;
4246 vector<boost::shared_ptr<Region> > results;
4248 boost::shared_ptr<Diskstream> ds;
4250 if ((ds = tatv->get_diskstream()) == 0) {
4255 if ((pl = (ds->playlist())) != 0) {
4256 pl->get_region_list_equivalent_regions (region, results);
4259 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4260 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4261 regions.push_back (marv);