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"
82 #include "rhythm_ferret.h"
85 #include "analysis_window.h"
91 #include "imageframe_socket_handler.h"
92 /* </CMT Additions> */
96 using namespace ARDOUR;
100 using namespace Gtkmm2ext;
101 using namespace Editing;
105 const double Editor::timebar_height = 15.0;
107 #include "editor_xpms"
109 static const gchar *_snap_type_strings[] = {
131 static const gchar *_snap_mode_strings[] = {
138 static const gchar *_edit_point_strings[] = {
145 static const gchar *_zoom_focus_strings[] = {
155 #ifdef USE_RUBBERBAND
156 static const gchar *_rb_opt_strings[] = {
159 N_("Balanced multitimbral mixture"),
160 N_("Unpitched percussion with stable notes"),
161 N_("Crisp monophonic instrumental"),
162 N_("Unpitched solo percussion"),
167 /* Soundfile drag-n-drop */
169 Gdk::Cursor* Editor::cross_hair_cursor = 0;
170 Gdk::Cursor* Editor::selector_cursor = 0;
171 Gdk::Cursor* Editor::trimmer_cursor = 0;
172 Gdk::Cursor* Editor::grabber_cursor = 0;
173 Gdk::Cursor* Editor::zoom_cursor = 0;
174 Gdk::Cursor* Editor::time_fx_cursor = 0;
175 Gdk::Cursor* Editor::fader_cursor = 0;
176 Gdk::Cursor* Editor::speaker_cursor = 0;
177 Gdk::Cursor* Editor::wait_cursor = 0;
178 Gdk::Cursor* Editor::timebar_cursor = 0;
179 Gdk::Cursor* Editor::transparent_cursor = 0;
182 show_me_the_size (Requisition* r, const char* what)
184 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
189 /* time display buttons */
190 minsec_label (_("Mins:Secs")),
191 bbt_label (_("Bars:Beats")),
192 smpte_label (_("Timecode")),
193 frame_label (_("Samples")),
194 tempo_label (_("Tempo")),
195 meter_label (_("Meter")),
196 mark_label (_("Location Markers")),
197 range_mark_label (_("Range Markers")),
198 transport_mark_label (_("Loop/Punch Ranges")),
199 cd_mark_label (_("CD Markers")),
201 edit_packer (3, 3, true),
203 /* the values here don't matter: layout widgets
204 reset them as needed.
207 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
208 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
210 /* tool bar related */
212 edit_point_clock (X_("editpoint"), false, X_("EditPointClock"), true),
213 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
215 toolbar_selection_clock_table (2,3),
217 automation_mode_button (_("mode")),
218 global_automation_button (_("automation")),
220 /* <CMT Additions> */
221 image_socket_listener(0),
222 /* </CMT Additions> */
226 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true),
227 meters_running(false)
232 /* we are a singleton */
234 PublicEditor::_instance = this;
238 selection = new Selection;
239 cut_buffer = new Selection;
241 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
242 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
243 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
244 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
245 selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed));
247 clicked_regionview = 0;
248 clicked_trackview = 0;
249 clicked_audio_trackview = 0;
250 clicked_crossfadeview = 0;
251 clicked_control_point = 0;
252 last_update_frame = 0;
254 current_mixer_strip = 0;
255 current_bbt_points = 0;
257 snap_type_strings = I18N (_snap_type_strings);
258 snap_mode_strings = I18N (_snap_mode_strings);
259 zoom_focus_strings = I18N (_zoom_focus_strings);
260 edit_point_strings = I18N (_edit_point_strings);
261 #ifdef USE_RUBBERBAND
262 rb_opt_strings = I18N (_rb_opt_strings);
265 snap_threshold = 5.0;
266 bbt_beat_subdivision = 4;
269 autoscroll_active = false;
270 autoscroll_timeout_tag = -1;
271 interthread_progress_window = 0;
278 current_interthread_info = 0;
279 _show_measures = true;
280 _show_waveforms = true;
281 _show_waveforms_recording = true;
282 first_action_message = 0;
284 export_range_markers_dialog = 0;
285 show_gain_after_trim = false;
286 ignore_route_list_reorder = false;
287 no_route_list_redisplay = false;
288 verbose_cursor_on = true;
289 route_removal = false;
290 show_automatic_regions_in_region_list = true;
291 last_item_entered = 0;
292 last_item_entered_n = 0;
294 region_list_sort_type = (Editing::RegionListSortType) 0;
295 have_pending_keyboard_selection = false;
296 _follow_playhead = true;
297 _xfade_visibility = true;
298 editor_ruler_menu = 0;
299 no_ruler_shown_update = false;
300 edit_group_list_menu = 0;
302 region_list_menu = 0;
304 start_end_marker_menu = 0;
305 range_marker_menu = 0;
306 marker_menu_item = 0;
308 transport_marker_menu = 0;
309 new_transport_marker_menu = 0;
310 editor_mixer_strip_width = Wide;
311 show_editor_mixer_when_tracks_arrive = false;
312 region_edit_menu_split_item = 0;
314 region_edit_menu_split_multichannel_item = 0;
316 ignore_mouse_mode_toggle = false;
317 current_stepping_trackview = 0;
319 entered_regionview = 0;
321 clear_entered_track = false;
322 _new_regionviews_show_envelope = false;
324 in_edit_group_row_change = false;
325 last_canvas_frame = 0;
327 button_release_can_deselect = true;
328 canvas_idle_queued = false;
329 _dragging_playhead = false;
330 _dragging_edit_point = false;
331 _dragging_hscrollbar = false;
332 select_new_marker = false;
333 zoomed_to_region = false;
336 scrubbing_direction = 0;
339 ignore_route_order_sync = false;
341 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
342 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
343 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
344 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
345 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
347 range_marker_drag_rect = 0;
348 marker_drag_line = 0;
350 set_mouse_mode (MouseObject, true);
352 last_visual_state.frames_per_unit = 0;
354 frames_per_unit = 2048; /* too early to use reset_zoom () */
355 reset_hscrollbar_stepping ();
357 zoom_focus = ZoomFocusLeft;
358 set_zoom_focus (ZoomFocusLeft);
359 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
361 initialize_rulers ();
362 initialize_canvas ();
364 edit_controls_vbox.set_spacing (0);
365 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled), false);
366 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
368 track_canvas.set_hadjustment (horizontal_adjustment);
369 track_canvas.set_vadjustment (vertical_adjustment);
370 time_canvas.set_hadjustment (horizontal_adjustment);
372 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
373 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
375 controls_layout.add (edit_controls_vbox);
376 controls_layout.set_name ("EditControlsBase");
377 controls_layout.add_events (Gdk::SCROLL_MASK);
378 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
380 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
381 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
382 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
384 edit_vscrollbar.set_adjustment (vertical_adjustment);
385 edit_hscrollbar.set_adjustment (horizontal_adjustment);
387 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
388 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
389 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
391 edit_hscrollbar.set_name ("EditorHScrollbar");
396 edit_point_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_point_clock_changed));
398 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
399 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
400 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
401 time_canvas_vbox.pack_start (*frames_ruler, false, false);
402 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
403 time_canvas_vbox.pack_start (time_canvas, true, true);
404 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
406 bbt_label.set_name ("EditorTimeButton");
407 bbt_label.set_size_request (-1, (int)timebar_height);
408 bbt_label.set_alignment (1.0, 0.5);
409 bbt_label.set_padding (5,0);
410 minsec_label.set_name ("EditorTimeButton");
411 minsec_label.set_size_request (-1, (int)timebar_height);
412 minsec_label.set_alignment (1.0, 0.5);
413 minsec_label.set_padding (5,0);
414 smpte_label.set_name ("EditorTimeButton");
415 smpte_label.set_size_request (-1, (int)timebar_height);
416 smpte_label.set_alignment (1.0, 0.5);
417 smpte_label.set_padding (5,0);
418 frame_label.set_name ("EditorTimeButton");
419 frame_label.set_size_request (-1, (int)timebar_height);
420 frame_label.set_alignment (1.0, 0.5);
421 frame_label.set_padding (5,0);
422 tempo_label.set_name ("EditorTimeButton");
423 tempo_label.set_size_request (-1, (int)timebar_height);
424 tempo_label.set_alignment (1.0, 0.5);
425 tempo_label.set_padding (5,0);
426 meter_label.set_name ("EditorTimeButton");
427 meter_label.set_size_request (-1, (int)timebar_height);
428 meter_label.set_alignment (1.0, 0.5);
429 meter_label.set_padding (5,0);
430 mark_label.set_name ("EditorTimeButton");
431 mark_label.set_size_request (-1, (int)timebar_height);
432 mark_label.set_alignment (1.0, 0.5);
433 mark_label.set_padding (5,0);
434 cd_mark_label.set_name ("EditorTimeButton");
435 cd_mark_label.set_size_request (-1, (int)timebar_height);
436 cd_mark_label.set_alignment (1.0, 0.5);
437 cd_mark_label.set_padding (5,0);
438 range_mark_label.set_name ("EditorTimeButton");
439 range_mark_label.set_size_request (-1, (int)timebar_height);
440 range_mark_label.set_alignment (1.0, 0.5);
441 range_mark_label.set_padding (5,0);
442 transport_mark_label.set_name ("EditorTimeButton");
443 transport_mark_label.set_size_request (-1, (int)timebar_height);
444 transport_mark_label.set_alignment (1.0, 0.5);
445 transport_mark_label.set_padding (5,0);
447 time_button_vbox.pack_start (minsec_label, false, false);
448 time_button_vbox.pack_start (smpte_label, false, false);
449 time_button_vbox.pack_start (frame_label, false, false);
450 time_button_vbox.pack_start (bbt_label, false, false);
451 time_button_vbox.pack_start (meter_label, false, false);
452 time_button_vbox.pack_start (tempo_label, false, false);
453 time_button_vbox.pack_start (mark_label, false, false);
455 time_button_event_box.add (time_button_vbox);
457 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
458 time_button_event_box.set_name ("TimebarLabelBase");
459 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
461 time_button_frame.add(time_button_event_box);
462 time_button_frame.property_shadow_type() = Gtk::SHADOW_OUT;
464 /* these enable us to have a dedicated window (for cursor setting, etc.)
465 for the canvas areas.
468 track_canvas_event_box.add (track_canvas);
470 time_canvas_event_box.add (time_canvas_vbox);
471 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
473 edit_packer.set_col_spacings (0);
474 edit_packer.set_row_spacings (0);
475 edit_packer.set_homogeneous (false);
476 edit_packer.set_border_width (0);
477 edit_packer.set_name ("EditorWindow");
479 edit_packer.attach (edit_vscrollbar, 0, 1, 1, 3, FILL, FILL|EXPAND, 0, 0);
481 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, FILL, 0, 0);
482 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
484 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
485 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
487 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
488 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
490 bottom_hbox.set_border_width (2);
491 bottom_hbox.set_spacing (3);
493 route_display_model = ListStore::create(route_display_columns);
494 route_list_display.set_model (route_display_model);
495 route_list_display.append_column (_("Show"), route_display_columns.visible);
496 route_list_display.append_column (_("Name"), route_display_columns.text);
497 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
498 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
499 route_list_display.set_headers_visible (true);
500 route_list_display.set_name ("TrackListDisplay");
501 route_list_display.get_selection()->set_mode (SELECTION_NONE);
502 route_list_display.set_reorderable (true);
503 route_list_display.set_size_request (100,-1);
505 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
506 route_list_visible_cell->property_activatable() = true;
507 route_list_visible_cell->property_radio() = false;
509 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
510 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
511 route_display_model->signal_rows_reordered().connect (mem_fun (*this, &Editor::track_list_reorder));
513 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
515 route_list_scroller.add (route_list_display);
516 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
518 group_model = ListStore::create(group_columns);
519 edit_group_display.set_model (group_model);
520 edit_group_display.append_column (_("Name"), group_columns.text);
521 edit_group_display.append_column (_("Active"), group_columns.is_active);
522 edit_group_display.append_column (_("Show"), group_columns.is_visible);
523 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
524 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
525 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
526 edit_group_display.get_column (0)->set_expand (true);
527 edit_group_display.get_column (1)->set_expand (false);
528 edit_group_display.get_column (2)->set_expand (false);
529 edit_group_display.set_headers_visible (true);
531 /* name is directly editable */
533 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
534 name_cell->property_editable() = true;
535 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
537 /* use checkbox for the active + visible columns */
539 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
540 active_cell->property_activatable() = true;
541 active_cell->property_radio() = false;
543 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
544 active_cell->property_activatable() = true;
545 active_cell->property_radio() = false;
547 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
549 edit_group_display.set_name ("EditGroupList");
550 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
551 edit_group_display.set_headers_visible (true);
552 edit_group_display.set_reorderable (false);
553 edit_group_display.set_rules_hint (true);
554 edit_group_display.set_size_request (75, -1);
556 edit_group_display_scroller.add (edit_group_display);
557 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
559 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
561 VBox* edit_group_display_packer = manage (new VBox());
562 HBox* edit_group_display_button_box = manage (new HBox());
563 edit_group_display_button_box->set_homogeneous (true);
565 Button* edit_group_add_button = manage (new Button ());
566 Button* edit_group_remove_button = manage (new Button ());
570 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
572 edit_group_add_button->add (*w);
574 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
576 edit_group_remove_button->add (*w);
578 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
579 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
581 edit_group_display_button_box->pack_start (*edit_group_add_button);
582 edit_group_display_button_box->pack_start (*edit_group_remove_button);
584 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
585 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
587 region_list_display.set_size_request (100, -1);
588 region_list_display.set_name ("RegionListDisplay");
590 region_list_model = TreeStore::create (region_list_columns);
591 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
592 region_list_model->set_sort_column (0, SORT_ASCENDING);
594 region_list_display.set_model (region_list_model);
595 region_list_display.append_column (_("Regions"), region_list_columns.name);
596 region_list_display.set_headers_visible (false);
598 CellRendererText* region_name_cell = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
599 region_name_cell->property_editable() = true;
600 region_name_cell->signal_edited().connect (mem_fun (*this, &Editor::region_name_edit));
602 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
604 TreeViewColumn* tv_col = region_list_display.get_column(0);
605 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
606 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
607 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
609 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
610 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
612 /* setup DnD handling */
614 list<TargetEntry> region_list_target_table;
616 region_list_target_table.push_back (TargetEntry ("text/plain"));
617 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
618 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
620 region_list_display.add_drop_targets (region_list_target_table);
621 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
623 region_list_scroller.add (region_list_display);
624 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
626 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
627 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
628 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
629 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
630 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
631 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
633 named_selection_scroller.add (named_selection_display);
634 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
636 named_selection_model = TreeStore::create (named_selection_columns);
637 named_selection_display.set_model (named_selection_model);
638 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
639 named_selection_display.set_headers_visible (false);
640 named_selection_display.set_size_request (100, -1);
641 named_selection_display.set_name ("NamedSelectionDisplay");
643 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
644 named_selection_display.set_size_request (100, -1);
645 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
646 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
647 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
651 snapshot_display_model = ListStore::create (snapshot_display_columns);
652 snapshot_display.set_model (snapshot_display_model);
653 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
654 snapshot_display.set_name ("SnapshotDisplay");
655 snapshot_display.set_size_request (75, -1);
656 snapshot_display.set_headers_visible (false);
657 snapshot_display.set_reorderable (false);
658 snapshot_display_scroller.add (snapshot_display);
659 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
661 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
662 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
666 nlabel = manage (new Label (_("Regions")));
667 nlabel->set_angle (-90);
668 the_notebook.append_page (region_list_scroller, *nlabel);
669 nlabel = manage (new Label (_("Tracks/Busses")));
670 nlabel->set_angle (-90);
671 the_notebook.append_page (route_list_scroller, *nlabel);
672 nlabel = manage (new Label (_("Snapshots")));
673 nlabel->set_angle (-90);
674 the_notebook.append_page (snapshot_display_scroller, *nlabel);
675 nlabel = manage (new Label (_("Edit Groups")));
676 nlabel->set_angle (-90);
677 the_notebook.append_page (*edit_group_display_packer, *nlabel);
679 if (!Profile->get_sae()) {
680 nlabel = manage (new Label (_("Chunks")));
681 nlabel->set_angle (-90);
682 the_notebook.append_page (named_selection_scroller, *nlabel);
685 the_notebook.set_show_tabs (true);
686 the_notebook.set_scrollable (true);
687 the_notebook.popup_enable ();
688 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
690 post_maximal_editor_width = 0;
691 post_maximal_pane_position = 0;
692 edit_pane.pack1 (edit_packer, true, true);
693 edit_pane.pack2 (the_notebook, false, true);
695 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
697 top_hbox.pack_start (toolbar_frame, true, true);
699 HBox *hbox = manage (new HBox);
700 hbox->pack_start (edit_pane, true, true);
702 global_vpacker.pack_start (top_hbox, false, false);
703 global_vpacker.pack_start (*hbox, true, true);
705 global_hpacker.pack_start (global_vpacker, true, true);
707 set_name ("EditorWindow");
708 add_accel_group (ActionManager::ui_manager->get_accel_group());
710 status_bar_hpacker.show ();
712 vpacker.pack_end (status_bar_hpacker, false, false);
713 vpacker.pack_end (global_hpacker, true, true);
715 /* register actions now so that set_state() can find them and set toggles/checks etc */
719 snap_type = SnapToBeat;
720 set_snap_to (snap_type);
722 set_snap_mode (snap_mode);
723 _edit_point = EditAtMouse;
724 set_edit_point_preference (_edit_point);
726 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
729 _playlist_selector = new PlaylistSelector();
730 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
732 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
736 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
737 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
739 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
740 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
742 nudge_forward_button.set_name ("TransportButton");
743 nudge_backward_button.set_name ("TransportButton");
745 fade_context_menu.set_name ("ArdourContextMenu");
747 /* icons, titles, WM stuff */
749 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
750 Glib::RefPtr<Gdk::Pixbuf> icon;
752 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
753 window_icons.push_back (icon);
755 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
756 window_icons.push_back (icon);
758 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
759 window_icons.push_back (icon);
761 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
762 window_icons.push_back (icon);
764 if (!window_icons.empty()) {
765 set_icon_list (window_icons);
766 set_default_icon_list (window_icons);
769 WindowTitle title(Glib::get_application_name());
770 title += _("Editor");
771 set_title (title.get_string());
772 set_wmclass (X_("ardour_editor"), "Ardour");
775 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
777 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
778 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
780 /* allow external control surfaces/protocols to do various things */
782 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
783 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
784 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
785 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
787 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
788 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
796 /* <CMT Additions> */
797 if(image_socket_listener)
799 if(image_socket_listener->is_connected())
801 image_socket_listener->close_connection() ;
804 delete image_socket_listener ;
805 image_socket_listener = 0 ;
807 /* </CMT Additions> */
811 Editor::add_toplevel_controls (Container& cont)
813 vpacker.pack_start (cont, false, false);
818 Editor::catch_vanishing_regionview (RegionView *rv)
820 /* note: the selection will take care of the vanishing
821 audioregionview by itself.
824 if (clicked_regionview == rv) {
825 clicked_regionview = 0;
828 if (entered_regionview == rv) {
829 set_entered_regionview (0);
834 Editor::set_entered_regionview (RegionView* rv)
836 if (rv == entered_regionview) {
840 if (entered_regionview) {
841 entered_regionview->exited ();
844 if ((entered_regionview = rv) != 0) {
845 entered_regionview->entered ();
850 Editor::set_entered_track (TimeAxisView* tav)
853 entered_track->exited ();
856 if ((entered_track = tav) != 0) {
857 entered_track->entered ();
862 Editor::show_window ()
867 /* now reset all audio_time_axis heights, because widgets might need
873 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
874 tv = (static_cast<TimeAxisView*>(*i));
880 Editor::instant_save ()
882 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
887 session->add_instant_xml(get_state(), session->path());
889 Config->add_instant_xml(get_state(), get_user_ardour_path());
894 Editor::edit_point_clock_changed()
896 if (_dragging_edit_point) {
900 if (selection->markers.empty()) {
905 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
911 loc->move_to (edit_point_clock.current_time());
915 Editor::zoom_adjustment_changed ()
921 double fpu = zoom_range_clock.current_duration() / canvas_width;
925 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
926 } else if (fpu > session->current_end_frame() / canvas_width) {
927 fpu = session->current_end_frame() / canvas_width;
928 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
935 Editor::control_scroll (float fraction)
937 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
943 double step = fraction * current_page_frames();
946 _control_scroll_target is an optional<T>
948 it acts like a pointer to an nframes_t, with
949 a operator conversion to boolean to check
950 that it has a value could possibly use
951 playhead_cursor->current_frame to store the
952 value and a boolean in the class to know
953 when it's out of date
956 if (!_control_scroll_target) {
957 _control_scroll_target = session->transport_frame();
958 _dragging_playhead = true;
961 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
962 *_control_scroll_target = 0;
963 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
964 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
966 *_control_scroll_target += (nframes_t) floor (step);
969 /* move visuals, we'll catch up with it later */
971 playhead_cursor->set_position (*_control_scroll_target);
972 UpdateAllTransportClocks (*_control_scroll_target);
974 if (*_control_scroll_target > (current_page_frames() / 2)) {
975 /* try to center PH in window */
976 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
982 Now we do a timeout to actually bring the session to the right place
983 according to the playhead. This is to avoid reading disk buffers on every
984 call to control_scroll, which is driven by ScrollTimeline and therefore
985 probably by a control surface wheel which can generate lots of events.
987 /* cancel the existing timeout */
989 control_scroll_connection.disconnect ();
991 /* add the next timeout */
993 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
997 Editor::deferred_control_scroll (nframes_t target)
999 session->request_locate (*_control_scroll_target, session->transport_rolling());
1000 // reset for next stream
1001 _control_scroll_target = boost::none;
1002 _dragging_playhead = false;
1007 Editor::on_realize ()
1009 Window::on_realize ();
1014 Editor::start_scrolling ()
1016 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1017 (mem_fun(*this, &Editor::update_current_screen));
1021 Editor::stop_scrolling ()
1023 scroll_connection.disconnect ();
1027 Editor::map_position_change (nframes_t frame)
1029 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1031 if (session == 0 || !_follow_playhead) {
1035 center_screen (frame);
1036 playhead_cursor->set_position (frame);
1040 Editor::center_screen (nframes_t frame)
1042 double page = canvas_width * frames_per_unit;
1044 /* if we're off the page, then scroll.
1047 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1048 center_screen_internal (frame, page);
1053 Editor::center_screen_internal (nframes_t frame, float page)
1058 frame -= (nframes_t) page;
1063 reset_x_origin (frame);
1067 Editor::handle_new_duration ()
1069 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1071 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1073 if (new_end > last_canvas_frame) {
1074 last_canvas_frame = new_end;
1075 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1076 reset_scrolling_region ();
1079 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1083 Editor::update_title_s (const string & snap_name)
1085 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1091 Editor::update_title ()
1093 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1096 bool dirty = session->dirty();
1098 string session_name;
1100 if (session->snap_name() != session->name()) {
1101 session_name = session->snap_name();
1103 session_name = session->name();
1107 session_name = "*" + session_name;
1110 WindowTitle title(session_name);
1111 title += Glib::get_application_name();
1112 set_title (title.get_string());
1117 Editor::connect_to_session (Session *t)
1121 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1124 /* catch up with the playhead */
1126 session->request_locate (playhead_cursor->current_frame);
1128 if (first_action_message) {
1129 first_action_message->hide();
1134 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1135 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1137 /* These signals can all be emitted by a non-GUI thread. Therefore the
1138 handlers for them must not attempt to directly interact with the GUI,
1139 but use Gtkmm2ext::UI::instance()->call_slot();
1142 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1143 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1144 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1145 session_connections.push_back (session->AudioRegionsAdded.connect (mem_fun(*this, &Editor::handle_new_audio_regions)));
1146 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed)));
1147 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1148 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1149 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1150 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1151 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1152 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1153 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1154 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1155 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1157 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1159 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1161 edit_groups_changed ();
1163 edit_point_clock.set_session (session);
1164 zoom_range_clock.set_session (session);
1165 _playlist_selector->set_session (session);
1166 nudge_clock.set_session (session);
1168 if (rhythm_ferret) {
1169 rhythm_ferret->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 (_("Rename"), mem_fun(*this, &Editor::rename_region)));
1725 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1726 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1727 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1728 items.push_back (SeparatorElem());
1729 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_point)));
1730 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1731 items.push_back (SeparatorElem());
1733 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::play_selected_region)));
1734 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1735 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1738 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1741 items.push_back (SeparatorElem());
1743 sigc::connection fooc;
1745 items.push_back (CheckMenuElem (_("Lock")));
1746 CheckMenuItem* region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1747 if (region->locked()) {
1748 region_lock_item->set_active();
1750 region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1752 items.push_back (CheckMenuElem (_("Glue to Bars&Beats")));
1753 CheckMenuItem* bbt_glue_item = static_cast<CheckMenuItem*>(&items.back());
1755 switch (region->positional_lock_style()) {
1756 case Region::MusicTime:
1757 bbt_glue_item->set_active (true);
1760 bbt_glue_item->set_active (false);
1764 bbt_glue_item->signal_activate().connect (bind (mem_fun (*this, &Editor::set_region_lock_style), Region::MusicTime));
1766 items.push_back (CheckMenuElem (_("Mute")));
1767 CheckMenuItem* region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1768 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1769 if (region->muted()) {
1771 region_mute_item->set_active();
1775 if (!Profile->get_sae()) {
1776 items.push_back (CheckMenuElem (_("Opaque")));
1777 CheckMenuItem* region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1778 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1779 if (region->opaque()) {
1781 region_opaque_item->set_active();
1786 items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1787 if (region->at_natural_position()) {
1788 items.back().set_sensitive (false);
1791 items.push_back (SeparatorElem());
1795 RegionView* rv = sv->find_view (ar);
1796 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1798 if (!Profile->get_sae()) {
1799 items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1801 items.push_back (CheckMenuElem (_("Envelope Visible")));
1802 CheckMenuItem* region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1803 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1804 if (arv->envelope_visible()) {
1806 region_envelope_visible_item->set_active (true);
1810 items.push_back (CheckMenuElem (_("Envelope Active")));
1811 CheckMenuItem* region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1812 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1814 if (ar->envelope_active()) {
1816 region_envelope_active_item->set_active (true);
1820 items.push_back (SeparatorElem());
1823 if (ar->scale_amplitude() != 1.0f) {
1824 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1826 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1830 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1831 items.push_back (SeparatorElem());
1833 /* range related stuff */
1835 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
1836 items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)));
1837 items.push_back (SeparatorElem());
1841 Menu *nudge_menu = manage (new Menu());
1842 MenuList& nudge_items = nudge_menu->items();
1843 nudge_menu->set_name ("ArdourContextMenu");
1845 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false, false))));
1846 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false, false))));
1847 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1848 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1850 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1851 items.push_back (SeparatorElem());
1853 Menu *trim_menu = manage (new Menu);
1854 MenuList& trim_items = trim_menu->items();
1855 trim_menu->set_name ("ArdourContextMenu");
1857 trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point)));
1858 trim_items.push_back (MenuElem (_("Edit point to end"), mem_fun(*this, &Editor::trim_region_to_edit_point)));
1859 trim_items.push_back (MenuElem (_("Trim To Loop"), mem_fun(*this, &Editor::trim_region_to_loop)));
1860 trim_items.push_back (MenuElem (_("Trim To Punch"), mem_fun(*this, &Editor::trim_region_to_punch)));
1862 items.push_back (MenuElem (_("Trim"), *trim_menu));
1863 items.push_back (SeparatorElem());
1865 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1866 region_edit_menu_split_item = &items.back();
1868 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1869 region_edit_menu_split_multichannel_item = &items.back();
1871 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), false))));
1872 items.push_back (MenuElem (_("Multi-Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1873 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1874 items.push_back (SeparatorElem());
1875 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1877 /* OK, stick the region submenu at the top of the list, and then add
1881 /* we have to hack up the region name because "_" has a special
1882 meaning for menu titles.
1885 string::size_type pos = 0;
1886 string menu_item_name = region->name();
1888 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1889 menu_item_name.replace (pos, 1, "__");
1893 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1894 edit_items.push_back (SeparatorElem());
1898 Editor::add_selection_context_items (Menu_Helpers::MenuList& items)
1900 using namespace Menu_Helpers;
1902 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1903 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1906 items.push_back (SeparatorElem());
1907 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1910 items.push_back (SeparatorElem());
1911 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1912 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1914 items.push_back (SeparatorElem());
1915 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1916 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1918 items.push_back (SeparatorElem());
1919 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1921 items.push_back (SeparatorElem());
1922 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1923 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1925 items.push_back (SeparatorElem());
1926 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1927 items.push_back (SeparatorElem());
1928 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1929 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1930 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1931 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1932 items.push_back (SeparatorElem());
1933 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1934 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1938 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1940 using namespace Menu_Helpers;
1944 Menu *play_menu = manage (new Menu);
1945 MenuList& play_items = play_menu->items();
1946 play_menu->set_name ("ArdourContextMenu");
1948 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
1949 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1950 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1951 play_items.push_back (SeparatorElem());
1952 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1954 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1958 Menu *select_menu = manage (new Menu);
1959 MenuList& select_items = select_menu->items();
1960 select_menu->set_name ("ArdourContextMenu");
1962 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1963 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1964 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1965 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1966 select_items.push_back (SeparatorElem());
1967 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1968 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1969 select_items.push_back (SeparatorElem());
1970 select_items.push_back (MenuElem (_("Select All After Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1971 select_items.push_back (MenuElem (_("Select All Before Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1972 select_items.push_back (MenuElem (_("Select All After Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1973 select_items.push_back (MenuElem (_("Select All Before Playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1974 select_items.push_back (MenuElem (_("Select All Between Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), false)));
1975 select_items.push_back (MenuElem (_("Select All Within Playhead & Edit Point"), bind (mem_fun(*this, &Editor::select_all_selectables_between), true)));
1976 select_items.push_back (MenuElem (_("Select Range Between Playhead & Edit Point"), mem_fun(*this, &Editor::select_range_between)));
1978 select_items.push_back (SeparatorElem());
1980 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1984 Menu *cutnpaste_menu = manage (new Menu);
1985 MenuList& cutnpaste_items = cutnpaste_menu->items();
1986 cutnpaste_menu->set_name ("ArdourContextMenu");
1988 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1989 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1990 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1992 cutnpaste_items.push_back (SeparatorElem());
1994 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1995 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1997 cutnpaste_items.push_back (SeparatorElem());
1999 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
2001 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2003 /* Adding new material */
2005 edit_items.push_back (SeparatorElem());
2006 edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2007 edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2011 Menu *nudge_menu = manage (new Menu());
2012 MenuList& nudge_items = nudge_menu->items();
2013 nudge_menu->set_name ("ArdourContextMenu");
2015 edit_items.push_back (SeparatorElem());
2016 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2017 nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2018 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2019 nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2021 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2025 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2027 using namespace Menu_Helpers;
2031 Menu *play_menu = manage (new Menu);
2032 MenuList& play_items = play_menu->items();
2033 play_menu->set_name ("ArdourContextMenu");
2035 play_items.push_back (MenuElem (_("Play from edit point"), mem_fun(*this, &Editor::play_from_edit_point)));
2036 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2037 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2041 Menu *select_menu = manage (new Menu);
2042 MenuList& select_items = select_menu->items();
2043 select_menu->set_name ("ArdourContextMenu");
2045 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2046 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
2047 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2048 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
2049 select_items.push_back (SeparatorElem());
2050 select_items.push_back (MenuElem (_("Select all after edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2051 select_items.push_back (MenuElem (_("Select all before edit point"), bind (mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2052 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2053 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2055 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2059 Menu *cutnpaste_menu = manage (new Menu);
2060 MenuList& cutnpaste_items = cutnpaste_menu->items();
2061 cutnpaste_menu->set_name ("ArdourContextMenu");
2063 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2064 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2065 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2067 Menu *nudge_menu = manage (new Menu());
2068 MenuList& nudge_items = nudge_menu->items();
2069 nudge_menu->set_name ("ArdourContextMenu");
2071 edit_items.push_back (SeparatorElem());
2072 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2073 nudge_items.push_back (MenuElem (_("Nudge track after edit point fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2074 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2075 nudge_items.push_back (MenuElem (_("Nudge track after edit point bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2077 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2080 /* CURSOR SETTING AND MARKS AND STUFF */
2083 Editor::set_snap_to (SnapType st)
2085 unsigned int snap_ind = (unsigned int)st;
2088 if ( snap_ind > snap_type_strings.size() - 1 ) {
2090 snap_type = (SnapType)snap_ind;
2093 string str = snap_type_strings[snap_ind];
2095 if (str != snap_type_selector.get_active_text()) {
2096 snap_type_selector.set_active_text (str);
2101 switch (snap_type) {
2102 case SnapToAThirtysecondBeat:
2103 case SnapToASixteenthBeat:
2104 case SnapToAEighthBeat:
2105 case SnapToAQuarterBeat:
2106 case SnapToAThirdBeat:
2107 update_tempo_based_rulers ();
2115 Editor::set_snap_mode (SnapMode mode)
2118 string str = snap_mode_strings[(int)mode];
2120 if (str != snap_mode_selector.get_active_text ()) {
2121 snap_mode_selector.set_active_text (str);
2127 Editor::set_edit_point_preference (EditPoint ep)
2129 bool changed = _edit_point != ep;
2132 string str = edit_point_strings[(int)ep];
2134 if (str != edit_point_selector.get_active_text ()) {
2135 edit_point_selector.set_active_text (str);
2142 if (Profile->get_sae()) {
2144 switch (zoom_focus) {
2145 case ZoomFocusMouse:
2146 case ZoomFocusPlayhead:
2148 switch (_edit_point) {
2150 set_zoom_focus (ZoomFocusMouse);
2152 case EditAtPlayhead:
2153 set_zoom_focus (ZoomFocusPlayhead);
2155 case EditAtSelectedMarker:
2156 set_zoom_focus (ZoomFocusEdit);
2169 Editor::set_state (const XMLNode& node)
2171 const XMLProperty* prop;
2173 int x, y, xoff, yoff;
2176 if ((prop = node.property ("id")) != 0) {
2177 _id = prop->value ();
2180 if ((geometry = find_named_node (node, "geometry")) == 0) {
2182 g.base_width = default_width;
2183 g.base_height = default_height;
2191 g.base_width = atoi(geometry->property("x_size")->value());
2192 g.base_height = atoi(geometry->property("y_size")->value());
2193 x = atoi(geometry->property("x_pos")->value());
2194 y = atoi(geometry->property("y_pos")->value());
2195 xoff = atoi(geometry->property("x_off")->value());
2196 yoff = atoi(geometry->property("y_off")->value());
2199 set_default_size (g.base_width, g.base_height);
2202 if (session && (prop = node.property ("playhead"))) {
2203 nframes_t pos = atol (prop->value().c_str());
2204 playhead_cursor->set_position (pos);
2206 playhead_cursor->set_position (0);
2208 /* reset_x_origin() doesn't work right here, since the old
2209 position may be zero already, and it does nothing in such
2214 horizontal_adjustment.set_value (0);
2217 if ((prop = node.property ("mixer-width"))) {
2218 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2221 if ((prop = node.property ("zoom-focus"))) {
2222 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2225 if ((prop = node.property ("zoom"))) {
2226 reset_zoom (PBD::atof (prop->value()));
2229 if ((prop = node.property ("snap-to"))) {
2230 set_snap_to ((SnapType) atoi (prop->value()));
2233 if ((prop = node.property ("snap-mode"))) {
2234 set_snap_mode ((SnapMode) atoi (prop->value()));
2237 if ((prop = node.property ("edit-point"))) {
2238 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point));
2241 if ((prop = node.property ("mouse-mode"))) {
2242 MouseMode m = str2mousemode(prop->value());
2243 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2244 set_mouse_mode (m, true);
2246 mouse_mode = MouseGain; /* lie, to force the mode switch */
2247 set_mouse_mode (MouseObject, true);
2250 if ((prop = node.property ("show-waveforms"))) {
2251 bool yn = (prop->value() == "yes");
2252 _show_waveforms = !yn;
2253 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2255 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2256 /* do it twice to force the change */
2257 tact->set_active (!yn);
2258 tact->set_active (yn);
2262 if ((prop = node.property ("show-waveforms-recording"))) {
2263 bool yn = (prop->value() == "yes");
2264 _show_waveforms_recording = !yn;
2265 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2267 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2268 /* do it twice to force the change */
2269 tact->set_active (!yn);
2270 tact->set_active (yn);
2274 if ((prop = node.property ("show-measures"))) {
2275 bool yn = (prop->value() == "yes");
2276 _show_measures = !yn;
2277 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2279 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2280 /* do it twice to force the change */
2281 tact->set_active (!yn);
2282 tact->set_active (yn);
2286 if ((prop = node.property ("follow-playhead"))) {
2287 bool yn = (prop->value() == "yes");
2288 set_follow_playhead (yn);
2289 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2291 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2292 if (tact->get_active() != yn) {
2293 tact->set_active (yn);
2298 if ((prop = node.property ("region-list-sort-type"))) {
2299 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2300 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2303 if ((prop = node.property ("xfades-visible"))) {
2304 bool yn = (prop->value() == "yes");
2305 _xfade_visibility = !yn;
2306 // set_xfade_visibility (yn);
2309 if ((prop = node.property ("show-editor-mixer"))) {
2311 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2314 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2315 bool yn = (prop->value() == X_("yes"));
2317 /* do it twice to force the change */
2319 tact->set_active (!yn);
2320 tact->set_active (yn);
2329 Editor::get_state ()
2331 XMLNode* node = new XMLNode ("Editor");
2334 _id.print (buf, sizeof (buf));
2335 node->add_property ("id", buf);
2337 if (is_realized()) {
2338 Glib::RefPtr<Gdk::Window> win = get_window();
2340 int x, y, xoff, yoff, width, height;
2341 win->get_root_origin(x, y);
2342 win->get_position(xoff, yoff);
2343 win->get_size(width, height);
2345 XMLNode* geometry = new XMLNode ("geometry");
2347 snprintf(buf, sizeof(buf), "%d", width);
2348 geometry->add_property("x_size", string(buf));
2349 snprintf(buf, sizeof(buf), "%d", height);
2350 geometry->add_property("y_size", string(buf));
2351 snprintf(buf, sizeof(buf), "%d", x);
2352 geometry->add_property("x_pos", string(buf));
2353 snprintf(buf, sizeof(buf), "%d", y);
2354 geometry->add_property("y_pos", string(buf));
2355 snprintf(buf, sizeof(buf), "%d", xoff);
2356 geometry->add_property("x_off", string(buf));
2357 snprintf(buf, sizeof(buf), "%d", yoff);
2358 geometry->add_property("y_off", string(buf));
2359 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2360 geometry->add_property("edit_pane_pos", string(buf));
2362 node->add_child_nocopy (*geometry);
2365 maybe_add_mixer_strip_width (*node);
2367 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2368 node->add_property ("zoom-focus", buf);
2369 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2370 node->add_property ("zoom", buf);
2371 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2372 node->add_property ("snap-to", buf);
2373 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2374 node->add_property ("snap-mode", buf);
2376 node->add_property ("edit-point", enum_2_string (_edit_point));
2378 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2379 node->add_property ("playhead", buf);
2381 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2382 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2383 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2384 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2385 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2386 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2387 node->add_property ("mouse-mode", enum2str(mouse_mode));
2389 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2391 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2392 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2401 Editor::trackview_by_y_position (double y)
2403 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2407 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2416 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2418 Location* before = 0;
2419 Location* after = 0;
2421 if (!session || snap_mode == SnapOff) {
2425 const nframes64_t one_second = session->frame_rate();
2426 const nframes64_t one_minute = session->frame_rate() * 60;
2427 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2428 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2429 nframes64_t presnap = start;
2431 switch (snap_type) {
2434 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2436 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2440 case SnapToSMPTEFrame:
2441 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2442 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2444 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2448 case SnapToSMPTESeconds:
2449 if (session->smpte_offset_negative())
2451 start += session->smpte_offset ();
2453 start -= session->smpte_offset ();
2455 if (start % one_smpte_second > one_smpte_second / 2) {
2456 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2458 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2461 if (session->smpte_offset_negative())
2463 start -= session->smpte_offset ();
2465 start += session->smpte_offset ();
2469 case SnapToSMPTEMinutes:
2470 if (session->smpte_offset_negative())
2472 start += session->smpte_offset ();
2474 start -= session->smpte_offset ();
2476 if (start % one_smpte_minute > one_smpte_minute / 2) {
2477 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2479 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2481 if (session->smpte_offset_negative())
2483 start -= session->smpte_offset ();
2485 start += session->smpte_offset ();
2490 if (start % one_second > one_second / 2) {
2491 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2493 start = (nframes_t) floor ((double) start / one_second) * one_second;
2498 if (start % one_minute > one_minute / 2) {
2499 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2501 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2506 start = session->tempo_map().round_to_bar (start, direction);
2510 start = session->tempo_map().round_to_beat (start, direction);
2513 case SnapToAThirtysecondBeat:
2514 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2517 case SnapToASixteenthBeat:
2518 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2521 case SnapToAEighthBeat:
2522 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2525 case SnapToAQuarterBeat:
2526 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2529 case SnapToAThirdBeat:
2530 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2538 before = session->locations()->first_location_before (start);
2539 after = session->locations()->first_location_after (start);
2541 if (direction < 0) {
2543 start = before->start();
2547 } else if (direction > 0) {
2549 start = after->start();
2551 start = session->current_end_frame();
2556 /* find nearest of the two */
2557 if ((start - before->start()) < (after->start() - start)) {
2558 start = before->start();
2560 start = after->start();
2563 start = before->start();
2566 start = after->start();
2573 case SnapToRegionStart:
2574 case SnapToRegionEnd:
2575 case SnapToRegionSync:
2576 case SnapToRegionBoundary:
2577 if (!region_boundary_cache.empty()) {
2578 vector<nframes_t>::iterator i;
2580 if (direction > 0) {
2581 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2583 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2586 if (i != region_boundary_cache.end()) {
2589 start = region_boundary_cache.back();
2595 switch (snap_mode) {
2601 if (presnap > start) {
2602 if (presnap > (start + unit_to_frame(snap_threshold))) {
2606 } else if (presnap < start) {
2607 if (presnap < (start - unit_to_frame(snap_threshold))) {
2613 /* handled at entry */
2620 Editor::setup_toolbar ()
2625 const guint32 FUDGE = 38; // Combo's are stupid - they steal space from the entry for the button
2627 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2630 /* Mode Buttons (tool selection) */
2632 vector<ToggleButton *> mouse_mode_buttons;
2634 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2635 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2636 mouse_mode_buttons.push_back (&mouse_move_button);
2638 if (!Profile->get_sae()) {
2639 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2640 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2641 mouse_mode_buttons.push_back (&mouse_select_button);
2643 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2644 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2645 mouse_mode_buttons.push_back (&mouse_gain_button);
2648 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2649 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2650 mouse_mode_buttons.push_back (&mouse_zoom_button);
2651 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2652 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2653 mouse_mode_buttons.push_back (&mouse_timefx_button);
2654 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2655 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2656 mouse_mode_buttons.push_back (&mouse_audition_button);
2658 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2660 HBox* mode_box = manage(new HBox);
2661 mode_box->set_border_width (2);
2662 mode_box->set_spacing(4);
2663 mouse_mode_button_box.set_spacing(1);
2664 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2665 if (!Profile->get_sae()) {
2666 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2668 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2669 if (!Profile->get_sae()) {
2670 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2672 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2673 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2674 mouse_mode_button_box.set_homogeneous(true);
2676 vector<string> edit_mode_strings;
2677 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2678 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2680 edit_mode_selector.set_name ("EditModeSelector");
2681 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2682 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2683 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2685 mode_box->pack_start(edit_mode_selector);
2686 mode_box->pack_start(mouse_mode_button_box);
2688 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2689 mouse_mode_tearoff->set_name ("MouseModeBase");
2691 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2692 &mouse_mode_tearoff->tearoff_window()));
2693 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2694 &mouse_mode_tearoff->tearoff_window(), 1));
2695 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2696 &mouse_mode_tearoff->tearoff_window()));
2697 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2698 &mouse_mode_tearoff->tearoff_window(), 1));
2700 mouse_move_button.set_name ("MouseModeButton");
2701 mouse_select_button.set_name ("MouseModeButton");
2702 mouse_gain_button.set_name ("MouseModeButton");
2703 mouse_zoom_button.set_name ("MouseModeButton");
2704 mouse_timefx_button.set_name ("MouseModeButton");
2705 mouse_audition_button.set_name ("MouseModeButton");
2707 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2708 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2709 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2710 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2711 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2712 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2714 mouse_move_button.unset_flags (CAN_FOCUS);
2715 mouse_select_button.unset_flags (CAN_FOCUS);
2716 mouse_gain_button.unset_flags (CAN_FOCUS);
2717 mouse_zoom_button.unset_flags (CAN_FOCUS);
2718 mouse_timefx_button.unset_flags (CAN_FOCUS);
2719 mouse_audition_button.unset_flags (CAN_FOCUS);
2721 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2722 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2724 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2725 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2726 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2727 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2728 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2730 // mouse_move_button.set_active (true);
2735 zoom_box.set_spacing (1);
2736 zoom_box.set_border_width (2);
2738 zoom_in_button.set_name ("EditorTimeButton");
2739 zoom_in_button.set_size_request(-1,16);
2740 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2741 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2742 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2744 zoom_out_button.set_name ("EditorTimeButton");
2745 zoom_out_button.set_size_request(-1,16);
2746 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2747 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2748 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2750 zoom_out_full_button.set_name ("EditorTimeButton");
2751 zoom_out_full_button.set_size_request(-1,16);
2752 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2753 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2754 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2756 zoom_focus_selector.set_name ("ZoomFocusSelector");
2757 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, _("Playhead"), FUDGE, 0);
2758 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2759 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2760 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2762 zoom_box.pack_start (zoom_focus_selector, true, true);
2763 zoom_box.pack_start (zoom_out_button, false, false);
2764 zoom_box.pack_start (zoom_in_button, false, false);
2765 zoom_box.pack_start (zoom_out_full_button, false, false);
2767 snap_box.set_spacing (1);
2768 snap_box.set_border_width (2);
2770 snap_type_selector.set_name ("SnapTypeSelector");
2771 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, _("SMPTE Seconds"), 2+FUDGE, 10);
2772 set_popdown_strings (snap_type_selector, snap_type_strings);
2773 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2774 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
2776 snap_mode_selector.set_name ("SnapModeSelector");
2777 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, _("Magnetic Snap"), 2+FUDGE, 10);
2778 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2779 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2780 ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2782 edit_point_selector.set_name ("SnapModeSelector");
2783 Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, _("Playhead"), 2+FUDGE, 10);
2784 set_popdown_strings (edit_point_selector, edit_point_strings);
2785 edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
2786 ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
2788 snap_box.pack_start (edit_point_clock, false, false);
2789 snap_box.pack_start (snap_mode_selector, false, false);
2790 snap_box.pack_start (snap_type_selector, false, false);
2791 snap_box.pack_start (edit_point_selector, false, false);
2795 HBox *nudge_box = manage (new HBox);
2796 nudge_box->set_spacing(1);
2797 nudge_box->set_border_width (2);
2799 nudge_forward_button.signal_button_release_event().connect (mem_fun(*this, &Editor::nudge_forward_release), false);
2800 nudge_backward_button.signal_button_release_event().connect (mem_fun(*this, &Editor::nudge_backward_release), false);
2802 nudge_box->pack_start (nudge_backward_button, false, false);
2803 nudge_box->pack_start (nudge_forward_button, false, false);
2804 nudge_box->pack_start (nudge_clock, false, false);
2807 /* Pack everything in... */
2809 HBox* hbox = new HBox;
2810 hbox->set_spacing(10);
2812 tools_tearoff = new TearOff (*hbox);
2813 tools_tearoff->set_name ("MouseModeBase");
2815 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2816 &tools_tearoff->tearoff_window()));
2817 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2818 &tools_tearoff->tearoff_window(), 0));
2819 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2820 &tools_tearoff->tearoff_window()));
2821 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2822 &tools_tearoff->tearoff_window(), 0));
2824 toolbar_hbox.set_spacing (10);
2825 toolbar_hbox.set_border_width (1);
2827 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2828 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2831 hbox->pack_start (snap_box, false, false);
2832 // hbox->pack_start (zoom_box, false, false);
2833 hbox->pack_start (*nudge_box, false, false);
2837 toolbar_base.set_name ("ToolBarBase");
2838 toolbar_base.add (toolbar_hbox);
2840 toolbar_frame.set_shadow_type (SHADOW_OUT);
2841 toolbar_frame.set_name ("BaseFrame");
2842 toolbar_frame.add (toolbar_base);
2846 Editor::convert_drop_to_paths (vector<ustring>& paths,
2847 const RefPtr<Gdk::DragContext>& context,
2850 const SelectionData& data,
2859 vector<ustring> uris = data.get_uris();
2863 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2864 are actually URI lists. So do it by hand.
2867 if (data.get_target() != "text/plain") {
2871 /* Parse the "uri-list" format that Nautilus provides,
2872 where each pathname is delimited by \r\n
2875 const char* p = data.get_text().c_str();
2882 while (g_ascii_isspace (*p))
2886 while (*q && (*q != '\n') && (*q != '\r'))
2892 while (q > p && g_ascii_isspace (*q))
2897 uris.push_back (ustring (p, q - p + 1));
2901 p = strchr (p, '\n');
2911 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2913 if ((*i).substr (0,7) == "file://") {
2917 PBD::url_decode (p);
2919 // scan forward past three slashes
2921 ustring::size_type slashcnt = 0;
2922 ustring::size_type n = 0;
2923 ustring::iterator x = p.begin();
2925 while (slashcnt < 3 && x != p.end()) {
2928 } else if (slashcnt == 3) {
2935 if (slashcnt != 3 || x == p.end()) {
2936 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2940 paths.push_back (p.substr (n - 1));
2948 Editor::new_tempo_section ()
2954 Editor::map_transport_state ()
2956 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2958 if (session->transport_stopped()) {
2959 have_pending_keyboard_selection = false;
2962 update_loop_range_view (true);
2967 Editor::State::State ()
2969 selection = new Selection;
2972 Editor::State::~State ()
2978 Editor::get_memento () const
2980 State *state = new State;
2982 store_state (*state);
2983 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2987 Editor::store_state (State& state) const
2989 *state.selection = *selection;
2993 Editor::restore_state (State *state)
2995 if (*selection == *state->selection) {
2999 *selection = *state->selection;
3000 time_selection_changed ();
3001 region_selection_changed ();
3003 /* XXX other selection change handlers? */
3007 Editor::begin_reversible_command (string name)
3010 // before = &get_state();
3011 session->begin_reversible_command (name);
3016 Editor::commit_reversible_command ()
3019 // session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
3020 session->commit_reversible_command ();
3025 Editor::set_edit_group_solo (Route& route, bool yn)
3027 RouteGroup *edit_group;
3029 if ((edit_group = route.edit_group()) != 0) {
3030 edit_group->apply (&Route::set_solo, yn, this);
3032 route.set_solo (yn, this);
3037 Editor::set_edit_group_mute (Route& route, bool yn)
3039 RouteGroup *edit_group = 0;
3041 if ((edit_group == route.edit_group()) != 0) {
3042 edit_group->apply (&Route::set_mute, yn, this);
3044 route.set_mute (yn, this);
3049 Editor::history_changed ()
3053 if (undo_action && session) {
3054 if (session->undo_depth() == 0) {
3057 label = string_compose(_("Undo (%1)"), session->next_undo());
3059 undo_action->property_label() = label;
3062 if (redo_action && session) {
3063 if (session->redo_depth() == 0) {
3066 label = string_compose(_("Redo (%1)"), session->next_redo());
3068 redo_action->property_label() = label;
3073 Editor::duplicate_dialog (bool with_dialog)
3077 if (mouse_mode == MouseRange) {
3078 if (selection->time.length() == 0) {
3084 get_regions_for_action (rs);
3086 if (mouse_mode != MouseRange) {
3095 ArdourDialog win ("Duplication Dialog");
3096 Label label (_("Number of Duplications:"));
3097 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3098 SpinButton spinner (adjustment, 0.0, 1);
3101 win.get_vbox()->set_spacing (12);
3102 win.get_vbox()->pack_start (hbox);
3103 hbox.set_border_width (6);
3104 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3106 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3107 place, visually. so do this by hand.
3110 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3111 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3112 spinner.grab_focus();
3118 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3119 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3120 win.set_default_response (RESPONSE_ACCEPT);
3122 win.set_position (WIN_POS_MOUSE);
3124 spinner.grab_focus ();
3126 switch (win.run ()) {
3127 case RESPONSE_ACCEPT:
3133 times = adjustment.get_value();
3136 if (mouse_mode == MouseRange) {
3137 duplicate_selection (times);
3139 duplicate_some_regions (rs, times);
3144 Editor::show_verbose_canvas_cursor ()
3146 verbose_canvas_cursor->raise_to_top();
3147 verbose_canvas_cursor->show();
3148 verbose_cursor_visible = true;
3152 Editor::hide_verbose_canvas_cursor ()
3154 verbose_canvas_cursor->hide();
3155 verbose_cursor_visible = false;
3159 Editor::clamp_verbose_cursor_x (double x)
3161 return min (horizontal_adjustment.get_value() + canvas_width - 75.0, x);
3165 Editor::clamp_verbose_cursor_y (double y)
3167 return min (vertical_adjustment.get_value() + canvas_height - 50.0, y);
3171 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3173 verbose_canvas_cursor->property_text() = txt.c_str();
3174 /* don't get too close to the edge */
3175 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
3176 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_x (y);
3180 Editor::set_verbose_canvas_cursor_text (const string & txt)
3182 verbose_canvas_cursor->property_text() = txt.c_str();
3186 Editor::set_edit_mode (EditMode m)
3188 Config->set_edit_mode (m);
3192 Editor::cycle_edit_mode ()
3194 switch (Config->get_edit_mode()) {
3196 Config->set_edit_mode (Splice);
3199 Config->set_edit_mode (Slide);
3205 Editor::edit_mode_selection_done ()
3211 string choice = edit_mode_selector.get_active_text();
3212 EditMode mode = Slide;
3214 if (choice == _("Splice Edit")) {
3216 } else if (choice == _("Slide Edit")) {
3220 Config->set_edit_mode (mode);
3224 Editor::snap_type_selection_done ()
3226 string choice = snap_type_selector.get_active_text();
3227 SnapType snaptype = SnapToBeat;
3229 if (choice == _("Beats/3")) {
3230 snaptype = SnapToAThirdBeat;
3231 } else if (choice == _("Beats/4")) {
3232 snaptype = SnapToAQuarterBeat;
3233 } else if (choice == _("Beats/8")) {
3234 snaptype = SnapToAEighthBeat;
3235 } else if (choice == _("Beats/16")) {
3236 snaptype = SnapToASixteenthBeat;
3237 } else if (choice == _("Beats/32")) {
3238 snaptype = SnapToAThirtysecondBeat;
3239 } else if (choice == _("Beats")) {
3240 snaptype = SnapToBeat;
3241 } else if (choice == _("Bars")) {
3242 snaptype = SnapToBar;
3243 } else if (choice == _("Marks")) {
3244 snaptype = SnapToMark;
3245 } else if (choice == _("Region starts")) {
3246 snaptype = SnapToRegionStart;
3247 } else if (choice == _("Region ends")) {
3248 snaptype = SnapToRegionEnd;
3249 } else if (choice == _("Region bounds")) {
3250 snaptype = SnapToRegionBoundary;
3251 } else if (choice == _("Region syncs")) {
3252 snaptype = SnapToRegionSync;
3253 } else if (choice == _("CD Frames")) {
3254 snaptype = SnapToCDFrame;
3255 } else if (choice == _("SMPTE Frames")) {
3256 snaptype = SnapToSMPTEFrame;
3257 } else if (choice == _("SMPTE Seconds")) {
3258 snaptype = SnapToSMPTESeconds;
3259 } else if (choice == _("SMPTE Minutes")) {
3260 snaptype = SnapToSMPTEMinutes;
3261 } else if (choice == _("Seconds")) {
3262 snaptype = SnapToSeconds;
3263 } else if (choice == _("Minutes")) {
3264 snaptype = SnapToMinutes;
3267 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3269 ract->set_active ();
3274 Editor::snap_mode_selection_done ()
3276 string choice = snap_mode_selector.get_active_text();
3277 SnapMode mode = SnapNormal;
3279 if (choice == _("No Grid")) {
3281 } else if (choice == _("Grid")) {
3283 } else if (choice == _("Magnetic")) {
3284 mode = SnapMagnetic;
3287 RefPtr<RadioAction> ract = snap_mode_action (mode);
3290 ract->set_active (true);
3295 Editor::cycle_edit_point (bool with_marker)
3297 switch (_edit_point) {
3299 set_edit_point_preference (EditAtPlayhead);
3301 case EditAtPlayhead:
3303 set_edit_point_preference (EditAtSelectedMarker);
3305 set_edit_point_preference (EditAtMouse);
3308 case EditAtSelectedMarker:
3309 set_edit_point_preference (EditAtMouse);
3315 Editor::edit_point_selection_done ()
3317 string choice = edit_point_selector.get_active_text();
3318 EditPoint ep = EditAtSelectedMarker;
3320 if (choice == _("Marker")) {
3321 set_edit_point_preference (EditAtSelectedMarker);
3322 } else if (choice == _("Playhead")) {
3323 set_edit_point_preference (EditAtPlayhead);
3325 set_edit_point_preference (EditAtMouse);
3328 RefPtr<RadioAction> ract = edit_point_action (ep);
3331 ract->set_active (true);
3336 Editor::zoom_focus_selection_done ()
3338 string choice = zoom_focus_selector.get_active_text();
3339 ZoomFocus focus_type = ZoomFocusLeft;
3341 if (choice == _("Left")) {
3342 focus_type = ZoomFocusLeft;
3343 } else if (choice == _("Right")) {
3344 focus_type = ZoomFocusRight;
3345 } else if (choice == _("Center")) {
3346 focus_type = ZoomFocusCenter;
3347 } else if (choice == _("Playhead")) {
3348 focus_type = ZoomFocusPlayhead;
3349 } else if (choice == _("Mouse")) {
3350 focus_type = ZoomFocusMouse;
3351 } else if (choice == _("Edit Point")) {
3352 focus_type = ZoomFocusEdit;
3355 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3358 ract->set_active ();
3363 Editor::edit_controls_button_release (GdkEventButton* ev)
3365 if (Keyboard::is_context_menu_event (ev)) {
3366 ARDOUR_UI::instance()->add_route (this);
3372 Editor::mouse_select_button_release (GdkEventButton* ev)
3374 /* this handles just right-clicks */
3376 if (ev->button != 3) {
3383 Editor::TrackViewList *
3384 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3387 TrackViewList::iterator i;
3389 v = new TrackViewList;
3391 if (track == 0 && group == 0) {
3395 for (i = track_views.begin(); i != track_views.end (); ++i) {
3399 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3401 /* just the view for this track
3404 v->push_back (track);
3408 /* views for all tracks in the edit group */
3410 for (i = track_views.begin(); i != track_views.end (); ++i) {
3412 if (group == 0 || (*i)->edit_group() == group) {
3422 Editor::set_zoom_focus (ZoomFocus f)
3424 string str = zoom_focus_strings[(int)f];
3426 if (str != zoom_focus_selector.get_active_text()) {
3427 zoom_focus_selector.set_active_text (str);
3430 if (zoom_focus != f) {
3433 ZoomFocusChanged (); /* EMIT_SIGNAL */
3440 Editor::ensure_float (Window& win)
3442 win.set_transient_for (*this);
3446 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3448 /* recover or initialize pane positions. do this here rather than earlier because
3449 we don't want the positions to change the child allocations, which they seem to do.
3455 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3457 static int32_t done;
3460 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3461 width = default_width;
3462 height = default_height;
3464 width = atoi(geometry->property("x_size")->value());
3465 height = atoi(geometry->property("y_size")->value());
3468 if (which == static_cast<Paned*> (&edit_pane)) {
3474 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3475 /* initial allocation is 90% to canvas, 10% to notebook */
3476 pos = (int) floor (alloc.get_width() * 0.90f);
3477 snprintf (buf, sizeof(buf), "%d", pos);
3479 pos = atoi (prop->value());
3482 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3483 edit_pane.set_position (pos);
3484 pre_maximal_pane_position = pos;
3490 Editor::detach_tearoff (Box* b, Window* w)
3492 if (tools_tearoff->torn_off() &&
3493 mouse_mode_tearoff->torn_off()) {
3494 top_hbox.remove (toolbar_frame);
3499 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3501 if (toolbar_frame.get_parent() == 0) {
3502 top_hbox.pack_end (toolbar_frame);
3507 Editor::set_show_measures (bool yn)
3509 if (_show_measures != yn) {
3512 if ((_show_measures = yn) == true) {
3520 Editor::toggle_follow_playhead ()
3522 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3524 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3525 set_follow_playhead (tact->get_active());
3530 Editor::set_follow_playhead (bool yn)
3532 if (_follow_playhead != yn) {
3533 if ((_follow_playhead = yn) == true) {
3535 update_current_screen ();
3542 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3544 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3546 xfade->set_active (!xfade->active());
3551 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3553 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3555 xfade->set_follow_overlap (!xfade->following_overlap());
3560 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3562 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3568 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3572 switch (cew.run ()) {
3573 case RESPONSE_ACCEPT:
3580 xfade->StateChanged (Change (~0));
3584 Editor::playlist_selector () const
3586 return *_playlist_selector;
3590 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3594 ret = nudge_clock.current_duration (pos);
3595 next = ret + 1; /* XXXX fix me */
3601 Editor::end_location_changed (Location* location)
3603 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3604 reset_scrolling_region ();
3608 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3610 ArdourDialog dialog ("playlist deletion dialog");
3611 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3612 "If left alone, no audio files used by it will be cleaned.\n"
3613 "If deleted, audio files used by it alone by will cleaned."),
3616 dialog.set_position (WIN_POS_CENTER);
3617 dialog.get_vbox()->pack_start (label);
3621 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3622 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3623 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3625 switch (dialog.run ()) {
3626 case RESPONSE_ACCEPT:
3627 /* delete the playlist */
3631 case RESPONSE_REJECT:
3632 /* keep the playlist */
3644 Editor::audio_region_selection_covers (nframes_t where)
3646 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3647 if ((*a)->region()->covers (where)) {
3656 Editor::prepare_for_cleanup ()
3658 cut_buffer->clear_regions ();
3659 cut_buffer->clear_playlists ();
3661 selection->clear_regions ();
3662 selection->clear_playlists ();
3666 Editor::transport_loop_location()
3669 return session->locations()->auto_loop_location();
3676 Editor::transport_punch_location()
3679 return session->locations()->auto_punch_location();
3686 Editor::control_layout_scroll (GdkEventScroll* ev)
3688 switch (ev->direction) {
3690 scroll_tracks_up_line ();
3694 case GDK_SCROLL_DOWN:
3695 scroll_tracks_down_line ();
3699 /* no left/right handling yet */
3707 /** A new snapshot has been selected.
3710 Editor::snapshot_display_selection_changed ()
3712 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3714 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3716 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3718 if (snap_name.length() == 0) {
3722 if (session->snap_name() == snap_name) {
3726 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3731 Editor::snapshot_display_button_press (GdkEventButton* ev)
3733 if (ev->button == 3) {
3734 /* Right-click on the snapshot list. Work out which snapshot it
3736 Gtk::TreeModel::Path path;
3737 Gtk::TreeViewColumn* col;
3740 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3741 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3743 Gtk::TreeModel::Row row = *iter;
3744 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3753 /** Pop up the snapshot display context menu.
3754 * @param button Button used to open the menu.
3755 * @param time Menu open time.
3756 * @snapshot_name Name of the snapshot that the menu click was over.
3760 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3762 using namespace Menu_Helpers;
3764 MenuList& items (snapshot_context_menu.items());
3767 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3769 items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)));
3770 if (!modification_allowed) {
3771 items.back().set_sensitive (false);
3774 items.push_back (MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)));
3775 if (!modification_allowed) {
3776 items.back().set_sensitive (false);
3779 snapshot_context_menu.popup (button, time);
3783 Editor::rename_snapshot (Glib::ustring old_name)
3785 ArdourPrompter prompter(true);
3789 prompter.set_name ("Prompter");
3790 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3791 prompter.set_prompt (_("New name of snapshot"));
3792 prompter.set_initial_text (old_name);
3794 if (prompter.run() == RESPONSE_ACCEPT) {
3795 prompter.get_result (new_name);
3796 if (new_name.length()) {
3797 session->rename_state (old_name, new_name);
3798 redisplay_snapshots ();
3805 Editor::remove_snapshot (Glib::ustring name)
3807 vector<string> choices;
3809 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3811 choices.push_back (_("No, do nothing."));
3812 choices.push_back (_("Yes, remove it."));
3814 Gtkmm2ext::Choice prompter (prompt, choices);
3816 if (prompter.run () == 1) {
3817 session->remove_state (name);
3818 redisplay_snapshots ();
3823 Editor::redisplay_snapshots ()
3829 vector<string*>* states;
3831 if ((states = session->possible_states()) == 0) {
3835 snapshot_display_model->clear ();
3837 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3838 string statename = *(*i);
3839 TreeModel::Row row = *(snapshot_display_model->append());
3841 /* this lingers on in case we ever want to change the visible
3842 name of the snapshot.
3845 string display_name;
3846 display_name = statename;
3848 if (statename == session->snap_name()) {
3849 snapshot_display.get_selection()->select(row);
3852 row[snapshot_display_columns.visible_name] = display_name;
3853 row[snapshot_display_columns.real_name] = statename;
3860 Editor::session_state_saved (string snap_name)
3862 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3863 redisplay_snapshots ();
3867 Editor::maximise_editing_space ()
3869 initial_ruler_update_required = true;
3871 mouse_mode_tearoff->set_visible (false);
3872 tools_tearoff->set_visible (false);
3874 pre_maximal_pane_position = edit_pane.get_position();
3875 pre_maximal_editor_width = this->get_width();
3877 if(post_maximal_pane_position == 0) {
3878 post_maximal_pane_position = edit_pane.get_width();
3883 if(post_maximal_editor_width) {
3884 edit_pane.set_position (post_maximal_pane_position -
3885 abs(post_maximal_editor_width - pre_maximal_editor_width));
3887 edit_pane.set_position (post_maximal_pane_position);
3892 Editor::restore_editing_space ()
3894 initial_ruler_update_required = true;
3896 // user changed width of pane during fullscreen
3897 if(post_maximal_pane_position != edit_pane.get_position()) {
3898 post_maximal_pane_position = edit_pane.get_position();
3903 mouse_mode_tearoff->set_visible (true);
3904 tools_tearoff->set_visible (true);
3905 post_maximal_editor_width = this->get_width();
3908 edit_pane.set_position (
3909 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3914 * Make new playlists for a given track and also any others that belong
3915 * to the same active edit group.
3920 Editor::new_playlists (TimeAxisView* v)
3922 begin_reversible_command (_("new playlists"));
3923 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3924 commit_reversible_command ();
3929 * Use a copy of the current playlist for a given track and also any others that belong
3930 * to the same active edit group.
3935 Editor::copy_playlists (TimeAxisView* v)
3937 begin_reversible_command (_("copy playlists"));
3938 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3939 commit_reversible_command ();
3944 * Clear the current playlist for a given track and also any others that belong
3945 * to the same active edit group.
3950 Editor::clear_playlists (TimeAxisView* v)
3952 begin_reversible_command (_("clear playlists"));
3953 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3954 commit_reversible_command ();
3958 Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz)
3960 atv.use_new_playlist (sz > 1 ? false : true);
3964 Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz)
3966 atv.use_copy_playlist (sz > 1 ? false : true);
3970 Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz)
3972 atv.clear_playlist ();
3976 Editor::on_key_press_event (GdkEventKey* ev)
3978 return key_press_focus_accelerator_handler (*this, ev);
3982 Editor::on_key_release_event (GdkEventKey* ev)
3984 return Gtk::Window::on_key_release_event (ev);
3985 // return key_press_focus_accelerator_handler (*this, ev);
3989 Editor::reset_x_origin (nframes_t frame)
3991 queue_visual_change (frame);
3995 Editor::reset_zoom (double fpu)
3997 queue_visual_change (fpu);
4001 Editor::reposition_and_zoom (nframes_t frame, double fpu)
4003 reset_x_origin (frame);
4008 Editor::swap_visual_state ()
4010 if (last_visual_state.frames_per_unit == 0) {
4015 /* note: the correct functionality here is very dependent on the ordering of
4016 setting zoom focus, horizontal position and finally zoom. this is because
4017 it is set_frames_per_unit() that overwrites last_visual_state.
4020 set_zoom_focus (last_visual_state.zoom_focus);
4021 reposition_and_zoom (last_visual_state.leftmost_frame, last_visual_state.frames_per_unit);
4022 zoomed_to_region = false;
4026 Editor::set_frames_per_unit (double fpu)
4028 /* this is the core function that controls the zoom level of the canvas. it is called
4029 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4032 if (fpu == frames_per_unit) {
4041 /* don't allow zooms that fit more than the maximum number
4042 of frames into an 800 pixel wide space.
4045 if (max_frames / fpu < 800.0) {
4049 if (fpu == frames_per_unit) {
4053 last_visual_state.frames_per_unit = frames_per_unit;
4054 last_visual_state.leftmost_frame = leftmost_frame;
4055 last_visual_state.zoom_focus = zoom_focus;
4057 frames_per_unit = fpu;
4062 Editor::post_zoom ()
4064 // convert fpu to frame count
4066 nframes_t frames = (nframes_t) floor (frames_per_unit * canvas_width);
4068 if (frames_per_unit != zoom_range_clock.current_duration()) {
4069 zoom_range_clock.set (frames);
4072 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4073 if (!selection->tracks.empty()) {
4074 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4075 (*i)->reshow_selection (selection->time);
4078 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4079 (*i)->reshow_selection (selection->time);
4084 ZoomChanged (); /* EMIT_SIGNAL */
4086 reset_hscrollbar_stepping ();
4087 reset_scrolling_region ();
4089 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
4095 Editor::queue_visual_change (nframes_t where)
4097 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
4098 pending_visual_change.time_origin = where;
4100 if (pending_visual_change.idle_handler_id < 0) {
4101 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4106 Editor::queue_visual_change (double fpu)
4108 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
4109 pending_visual_change.frames_per_unit = fpu;
4111 if (pending_visual_change.idle_handler_id < 0) {
4112 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
4117 Editor::_idle_visual_changer (void* arg)
4119 return static_cast<Editor*>(arg)->idle_visual_changer ();
4123 Editor::idle_visual_changer ()
4125 VisualChange::Type p = pending_visual_change.pending;
4127 pending_visual_change.pending = (VisualChange::Type) 0;
4128 pending_visual_change.idle_handler_id = -1;
4130 if (p & VisualChange::ZoomLevel) {
4131 set_frames_per_unit (pending_visual_change.frames_per_unit);
4134 if (p & VisualChange::TimeOrigin) {
4136 nframes_t time_origin = (nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
4138 if (time_origin != pending_visual_change.time_origin) {
4139 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
4141 update_fixed_rulers();
4142 redisplay_tempo (true);
4146 return 0; /* this is always a one-shot call */
4149 struct EditorOrderTimeAxisSorter {
4150 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4151 return a->order < b->order;
4156 Editor::sort_track_selection (TrackSelection* sel)
4158 EditorOrderTimeAxisSorter cmp;
4163 selection->tracks.sort (cmp);
4168 Editor::get_preferred_edit_position (bool ignore_playhead)
4171 nframes64_t where = 0;
4172 EditPoint ep = _edit_point;
4174 if (entered_marker) {
4175 return entered_marker->position();
4178 if (ignore_playhead && ep == EditAtPlayhead) {
4179 ep = EditAtSelectedMarker;
4183 case EditAtPlayhead:
4184 where = session->audible_frame();
4187 case EditAtSelectedMarker:
4188 if (!selection->markers.empty()) {
4190 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4193 where = loc->start();
4204 if (!mouse_frame (where, ignored)) {
4205 /* XXX not right but what can we do ? */
4216 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4218 if (!session) return;
4220 begin_reversible_command (cmd);
4224 if ((tll = transport_loop_location()) == 0) {
4225 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4226 XMLNode &before = session->locations()->get_state();
4227 session->locations()->add (loc, true);
4228 session->set_auto_loop_location (loc);
4229 XMLNode &after = session->locations()->get_state();
4230 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4233 XMLNode &before = tll->get_state();
4234 tll->set_hidden (false, this);
4235 tll->set (start, end);
4236 XMLNode &after = tll->get_state();
4237 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4240 commit_reversible_command ();
4244 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4246 if (!session) return;
4248 begin_reversible_command (cmd);
4252 if ((tpl = transport_punch_location()) == 0) {
4253 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4254 XMLNode &before = session->locations()->get_state();
4255 session->locations()->add (loc, true);
4256 session->set_auto_loop_location (loc);
4257 XMLNode &after = session->locations()->get_state();
4258 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4261 XMLNode &before = tpl->get_state();
4262 tpl->set_hidden (false, this);
4263 tpl->set (start, end);
4264 XMLNode &after = tpl->get_state();
4265 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4268 commit_reversible_command ();
4272 Editor::get_regions_at (RegionSelection& rs, nframes64_t where, const TrackSelection& ts) const
4274 const TrackSelection* tracks;
4277 tracks = &track_views;
4282 for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4284 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4287 boost::shared_ptr<Diskstream> ds;
4288 boost::shared_ptr<Playlist> pl;
4290 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4292 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)where * ds->speed()));
4294 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4296 RegionView* rv = atv->audio_view()->find_view (*i);
4310 Editor::get_regions_after (RegionSelection& rs, nframes64_t where, const TrackSelection& ts) const
4312 const TrackSelection* tracks;
4315 tracks = &track_views;
4320 for (TrackSelection::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4322 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*t);
4325 boost::shared_ptr<Diskstream> ds;
4326 boost::shared_ptr<Playlist> pl;
4328 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
4330 Playlist::RegionList* regions = pl->regions_touched ((nframes_t) floor ( (double)where * ds->speed()), max_frames);
4332 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4334 RegionView* rv = atv->audio_view()->find_view (*i);
4348 Editor::get_regions_for_action (RegionSelection& rs, bool allow_entered)
4350 bool use_regions_at = true;
4352 if (selection->regions.empty()) {
4354 if (selection->tracks.empty()) {
4356 /* no regions or tracks selected, but entered regionview is valid
4357 and we're in object mode - just use entered regionview
4360 if (entered_regionview && (mouse_mode == Editing::MouseObject)) {
4361 rs.add (entered_regionview);
4366 use_regions_at = false;
4369 rs = selection->regions;
4371 /* consider adding the entered regionview */
4373 if (allow_entered && entered_regionview && (mouse_mode == Editing::MouseObject)) {
4375 /* only add the entered regionview if its not selected OR
4376 (we're not going to use regions at edit point OR its track is not selected)
4378 this avoids duplicate regions ending up in "rs"
4381 if (!selection->selected (entered_regionview) &&
4382 (!use_regions_at || !selection->selected (&entered_regionview->get_time_axis_view()))) {
4383 rs.add (entered_regionview);
4387 if (use_regions_at) {
4389 /* nothing selected, so get all regions at the edit point across
4393 if (!selection->tracks.empty()) {
4394 nframes64_t where = get_preferred_edit_position();
4395 get_regions_at (rs, where, selection->tracks);
4401 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4404 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4406 RouteTimeAxisView* tatv;
4408 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4410 boost::shared_ptr<Playlist> pl;
4411 vector<boost::shared_ptr<Region> > results;
4413 boost::shared_ptr<Diskstream> ds;
4415 if ((ds = tatv->get_diskstream()) == 0) {
4420 if ((pl = (ds->playlist())) != 0) {
4421 pl->get_region_list_equivalent_regions (region, results);
4424 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4425 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4426 regions.push_back (marv);
4435 Editor::show_rhythm_ferret ()
4437 if (rhythm_ferret == 0) {
4438 rhythm_ferret = new RhythmFerret(*this);
4441 rhythm_ferret->set_session (session);
4442 rhythm_ferret->show ();
4443 rhythm_ferret->present ();