2 Copyright (C) 2000-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <boost/none.hpp>
29 #include <sigc++/bind.h>
31 #include <pbd/convert.h>
32 #include <pbd/error.h>
33 #include <pbd/enumwriter.h>
34 #include <pbd/memento_command.h>
36 #include <glibmm/miscutils.h>
37 #include <gtkmm/image.h>
38 #include <gdkmm/color.h>
39 #include <gdkmm/bitmap.h>
41 #include <gtkmm2ext/grouped_buttons.h>
42 #include <gtkmm2ext/gtk_ui.h>
43 #include <gtkmm2ext/tearoff.h>
44 #include <gtkmm2ext/utils.h>
45 #include <gtkmm2ext/window_title.h>
46 #include <gtkmm2ext/choice.h>
48 #include <ardour/audio_track.h>
49 #include <ardour/audio_diskstream.h>
50 #include <ardour/plugin_manager.h>
51 #include <ardour/location.h>
52 #include <ardour/audioplaylist.h>
53 #include <ardour/audioregion.h>
54 #include <ardour/region.h>
55 #include <ardour/session_route.h>
56 #include <ardour/tempo.h>
57 #include <ardour/utils.h>
58 #include <ardour/profile.h>
60 #include <control_protocol/control_protocol.h>
62 #include "ardour_ui.h"
66 #include "playlist_selector.h"
67 #include "audio_region_view.h"
68 #include "rgb_macros.h"
69 #include "selection.h"
70 #include "audio_streamview.h"
71 #include "time_axis_view.h"
72 #include "audio_time_axis.h"
74 #include "crossfade_view.h"
76 #include "public_editor.h"
77 #include "crossfade_edit.h"
78 #include "canvas_impl.h"
80 #include "gui_thread.h"
84 #include "analysis_window.h"
90 #include "imageframe_socket_handler.h"
91 /* </CMT Additions> */
95 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
104 const double Editor::timebar_height = 15.0;
106 #include "editor_xpms"
108 static const gchar *_snap_type_strings[] = {
132 static const gchar *_snap_mode_strings[] = {
138 static const gchar *_edit_point_strings[] = {
145 static const gchar *_zoom_focus_strings[] = {
155 /* Soundfile drag-n-drop */
157 Gdk::Cursor* Editor::cross_hair_cursor = 0;
158 Gdk::Cursor* Editor::selector_cursor = 0;
159 Gdk::Cursor* Editor::trimmer_cursor = 0;
160 Gdk::Cursor* Editor::grabber_cursor = 0;
161 Gdk::Cursor* Editor::zoom_cursor = 0;
162 Gdk::Cursor* Editor::time_fx_cursor = 0;
163 Gdk::Cursor* Editor::fader_cursor = 0;
164 Gdk::Cursor* Editor::speaker_cursor = 0;
165 Gdk::Cursor* Editor::wait_cursor = 0;
166 Gdk::Cursor* Editor::timebar_cursor = 0;
169 show_me_the_size (Requisition* r, const char* what)
171 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
176 /* time display buttons */
177 minsec_label (_("Mins:Secs")),
178 bbt_label (_("Bars:Beats")),
179 smpte_label (_("Timecode")),
180 frame_label (_("Frames")),
181 tempo_label (_("Tempo")),
182 meter_label (_("Meter")),
183 mark_label (_("Location Markers")),
184 range_mark_label (_("Range Markers")),
185 transport_mark_label (_("Loop/Punch Ranges")),
187 edit_packer (3, 3, false),
189 /* the values here don't matter: layout widgets
190 reset them as needed.
193 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
194 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
196 /* tool bar related */
198 edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
199 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
201 toolbar_selection_clock_table (2,3),
203 automation_mode_button (_("mode")),
204 global_automation_button (_("automation")),
206 /* <CMT Additions> */
207 image_socket_listener(0),
208 /* </CMT Additions> */
212 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
217 /* we are a singleton */
219 PublicEditor::_instance = this;
223 selection = new Selection;
224 cut_buffer = new Selection;
226 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
227 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
228 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
229 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
230 selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed));
232 clicked_regionview = 0;
233 clicked_trackview = 0;
234 clicked_audio_trackview = 0;
235 clicked_crossfadeview = 0;
236 clicked_control_point = 0;
237 latest_regionview = 0;
238 last_update_frame = 0;
240 current_mixer_strip = 0;
241 current_bbt_points = 0;
243 snap_type_strings = I18N (_snap_type_strings);
244 snap_mode_strings = I18N (_snap_mode_strings);
245 zoom_focus_strings = I18N (_zoom_focus_strings);
246 edit_point_strings = I18N (_edit_point_strings);
248 snap_type = SnapToFrame;
249 set_snap_to (snap_type);
251 snap_mode = SnapNormal;
252 set_snap_mode (snap_mode);
254 _edit_point = EditAtMouse;
255 set_edit_point (_edit_point);
257 snap_threshold = 5.0;
258 bbt_beat_subdivision = 4;
261 autoscroll_active = false;
262 autoscroll_timeout_tag = -1;
263 interthread_progress_window = 0;
270 current_interthread_info = 0;
271 _show_measures = true;
272 _show_waveforms = true;
273 _show_waveforms_recording = true;
274 first_action_message = 0;
276 export_range_markers_dialog = 0;
277 show_gain_after_trim = false;
278 ignore_route_list_reorder = false;
279 no_route_list_redisplay = false;
280 verbose_cursor_on = true;
281 route_removal = false;
282 show_automatic_regions_in_region_list = true;
283 region_list_sort_type = (Editing::RegionListSortType) 0;
284 have_pending_keyboard_selection = false;
285 _follow_playhead = true;
286 _xfade_visibility = true;
287 editor_ruler_menu = 0;
288 no_ruler_shown_update = false;
289 edit_group_list_menu = 0;
291 region_list_menu = 0;
293 start_end_marker_menu = 0;
294 range_marker_menu = 0;
295 marker_menu_item = 0;
297 transport_marker_menu = 0;
298 new_transport_marker_menu = 0;
299 editor_mixer_strip_width = Wide;
300 show_editor_mixer_when_tracks_arrive = false;
301 region_edit_menu_split_item = 0;
303 region_edit_menu_split_multichannel_item = 0;
305 ignore_mouse_mode_toggle = false;
306 current_stepping_trackview = 0;
308 entered_regionview = 0;
309 clear_entered_track = false;
310 _new_regionviews_show_envelope = false;
311 current_timestretch = 0;
312 in_edit_group_row_change = false;
313 last_canvas_frame = 0;
316 button_release_can_deselect = true;
317 canvas_idle_queued = false;
318 _dragging_playhead = false;
319 _dragging_hscrollbar = false;
321 scrubbing_direction = 0;
324 ignore_route_order_sync = false;
326 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
327 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
328 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
329 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
330 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
332 range_marker_drag_rect = 0;
333 marker_drag_line = 0;
335 set_mouse_mode (MouseObject, true);
337 frames_per_unit = 2048; /* too early to use reset_zoom () */
338 reset_hscrollbar_stepping ();
340 zoom_focus = ZoomFocusLeft;
341 set_zoom_focus (ZoomFocusLeft);
342 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
344 initialize_rulers ();
345 initialize_canvas ();
347 edit_controls_vbox.set_spacing (0);
348 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
349 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
351 track_canvas.set_hadjustment (horizontal_adjustment);
352 track_canvas.set_vadjustment (vertical_adjustment);
353 time_canvas.set_hadjustment (horizontal_adjustment);
355 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
356 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
358 controls_layout.add (edit_controls_vbox);
359 controls_layout.set_name ("EditControlsBase");
360 controls_layout.add_events (Gdk::SCROLL_MASK);
361 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
363 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
364 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
365 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
367 edit_vscrollbar.set_adjustment (vertical_adjustment);
368 edit_hscrollbar.set_adjustment (horizontal_adjustment);
370 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
371 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
372 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
374 edit_hscrollbar.set_name ("EditorHScrollbar");
379 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
381 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
382 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
383 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
384 time_canvas_vbox.pack_start (*frames_ruler, false, false);
385 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
386 time_canvas_vbox.pack_start (time_canvas, true, true);
387 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
389 bbt_label.set_name ("EditorTimeButton");
390 bbt_label.set_size_request (-1, (int)timebar_height);
391 bbt_label.set_alignment (1.0, 0.5);
392 bbt_label.set_padding (5,0);
393 minsec_label.set_name ("EditorTimeButton");
394 minsec_label.set_size_request (-1, (int)timebar_height);
395 minsec_label.set_alignment (1.0, 0.5);
396 minsec_label.set_padding (5,0);
397 smpte_label.set_name ("EditorTimeButton");
398 smpte_label.set_size_request (-1, (int)timebar_height);
399 smpte_label.set_alignment (1.0, 0.5);
400 smpte_label.set_padding (5,0);
401 frame_label.set_name ("EditorTimeButton");
402 frame_label.set_size_request (-1, (int)timebar_height);
403 frame_label.set_alignment (1.0, 0.5);
404 frame_label.set_padding (5,0);
405 tempo_label.set_name ("EditorTimeButton");
406 tempo_label.set_size_request (-1, (int)timebar_height);
407 tempo_label.set_alignment (1.0, 0.5);
408 tempo_label.set_padding (5,0);
409 meter_label.set_name ("EditorTimeButton");
410 meter_label.set_size_request (-1, (int)timebar_height);
411 meter_label.set_alignment (1.0, 0.5);
412 meter_label.set_padding (5,0);
413 mark_label.set_name ("EditorTimeButton");
414 mark_label.set_size_request (-1, (int)timebar_height);
415 mark_label.set_alignment (1.0, 0.5);
416 mark_label.set_padding (5,0);
417 range_mark_label.set_name ("EditorTimeButton");
418 range_mark_label.set_size_request (-1, (int)timebar_height);
419 range_mark_label.set_alignment (1.0, 0.5);
420 range_mark_label.set_padding (5,0);
421 transport_mark_label.set_name ("EditorTimeButton");
422 transport_mark_label.set_size_request (-1, (int)timebar_height);
423 transport_mark_label.set_alignment (1.0, 0.5);
424 transport_mark_label.set_padding (5,0);
426 time_button_vbox.pack_start (minsec_label, false, false);
427 time_button_vbox.pack_start (smpte_label, false, false);
428 time_button_vbox.pack_start (frame_label, false, false);
429 time_button_vbox.pack_start (bbt_label, false, false);
430 time_button_vbox.pack_start (meter_label, false, false);
431 time_button_vbox.pack_start (tempo_label, false, false);
432 time_button_vbox.pack_start (mark_label, false, false);
434 time_button_event_box.add (time_button_vbox);
436 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
437 time_button_event_box.set_name ("TimebarLabelBase");
438 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
440 time_button_frame.add(time_button_event_box);
441 time_button_frame.property_shadow_type() = Gtk::SHADOW_OUT;
443 /* these enable us to have a dedicated window (for cursor setting, etc.)
444 for the canvas areas.
447 track_canvas_event_box.add (track_canvas);
449 time_canvas_event_box.add (time_canvas_vbox);
450 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
452 edit_packer.set_col_spacings (0);
453 edit_packer.set_row_spacings (0);
454 edit_packer.set_homogeneous (false);
455 edit_packer.set_border_width (0);
456 edit_packer.set_name ("EditorWindow");
458 edit_packer.attach (edit_vscrollbar, 0, 1, 1, 3, FILL, FILL|EXPAND, 0, 0);
460 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, FILL, 0, 0);
461 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
463 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
464 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
466 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
467 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
469 bottom_hbox.set_border_width (2);
470 bottom_hbox.set_spacing (3);
472 route_display_model = ListStore::create(route_display_columns);
473 route_list_display.set_model (route_display_model);
474 route_list_display.append_column (_("Show"), route_display_columns.visible);
475 route_list_display.append_column (_("Name"), route_display_columns.text);
476 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
477 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
478 route_list_display.set_headers_visible (true);
479 route_list_display.set_name ("TrackListDisplay");
480 route_list_display.get_selection()->set_mode (SELECTION_NONE);
481 route_list_display.set_reorderable (true);
482 route_list_display.set_size_request (100,-1);
484 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
485 route_list_visible_cell->property_activatable() = true;
486 route_list_visible_cell->property_radio() = false;
488 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
489 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
490 route_display_model->signal_rows_reordered().connect (mem_fun (*this, &Editor::track_list_reorder));
492 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
494 route_list_scroller.add (route_list_display);
495 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
497 group_model = ListStore::create(group_columns);
498 edit_group_display.set_model (group_model);
499 edit_group_display.append_column (_("Name"), group_columns.text);
500 edit_group_display.append_column (_("Active"), group_columns.is_active);
501 edit_group_display.append_column (_("Show"), group_columns.is_visible);
502 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
503 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
504 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
505 edit_group_display.get_column (0)->set_expand (true);
506 edit_group_display.get_column (1)->set_expand (false);
507 edit_group_display.get_column (2)->set_expand (false);
508 edit_group_display.set_headers_visible (true);
510 /* name is directly editable */
512 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
513 name_cell->property_editable() = true;
514 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
516 /* use checkbox for the active + visible columns */
518 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
519 active_cell->property_activatable() = true;
520 active_cell->property_radio() = false;
522 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
523 active_cell->property_activatable() = true;
524 active_cell->property_radio() = false;
526 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
528 edit_group_display.set_name ("EditGroupList");
529 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
530 edit_group_display.set_headers_visible (true);
531 edit_group_display.set_reorderable (false);
532 edit_group_display.set_rules_hint (true);
533 edit_group_display.set_size_request (75, -1);
535 edit_group_display_scroller.add (edit_group_display);
536 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
538 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
540 VBox* edit_group_display_packer = manage (new VBox());
541 HBox* edit_group_display_button_box = manage (new HBox());
542 edit_group_display_button_box->set_homogeneous (true);
544 Button* edit_group_add_button = manage (new Button ());
545 Button* edit_group_remove_button = manage (new Button ());
549 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
551 edit_group_add_button->add (*w);
553 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
555 edit_group_remove_button->add (*w);
557 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
558 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
560 edit_group_display_button_box->pack_start (*edit_group_add_button);
561 edit_group_display_button_box->pack_start (*edit_group_remove_button);
563 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
564 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
566 region_list_display.set_size_request (100, -1);
567 region_list_display.set_name ("RegionListDisplay");
569 region_list_model = TreeStore::create (region_list_columns);
570 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
571 region_list_model->set_sort_column (0, SORT_ASCENDING);
573 region_list_display.set_model (region_list_model);
574 region_list_display.append_column (_("Regions"), region_list_columns.name);
575 region_list_display.set_headers_visible (false);
577 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
579 TreeViewColumn* tv_col = region_list_display.get_column(0);
580 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
581 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
582 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
584 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
585 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
587 /* setup DnD handling */
589 list<TargetEntry> region_list_target_table;
591 region_list_target_table.push_back (TargetEntry ("text/plain"));
592 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
593 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
595 region_list_display.add_drop_targets (region_list_target_table);
596 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
598 region_list_scroller.add (region_list_display);
599 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
601 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
602 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
603 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
604 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
605 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
606 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
608 named_selection_scroller.add (named_selection_display);
609 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
611 named_selection_model = TreeStore::create (named_selection_columns);
612 named_selection_display.set_model (named_selection_model);
613 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
614 named_selection_display.set_headers_visible (false);
615 named_selection_display.set_size_request (100, -1);
616 named_selection_display.set_name ("NamedSelectionDisplay");
618 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
619 named_selection_display.set_size_request (100, -1);
620 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
621 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
622 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
626 snapshot_display_model = ListStore::create (snapshot_display_columns);
627 snapshot_display.set_model (snapshot_display_model);
628 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
629 snapshot_display.set_name ("SnapshotDisplay");
630 snapshot_display.set_size_request (75, -1);
631 snapshot_display.set_headers_visible (false);
632 snapshot_display.set_reorderable (false);
633 snapshot_display_scroller.add (snapshot_display);
634 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
636 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
637 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
641 nlabel = manage (new Label (_("Regions")));
642 nlabel->set_angle (-90);
643 the_notebook.append_page (region_list_scroller, *nlabel);
644 nlabel = manage (new Label (_("Tracks/Busses")));
645 nlabel->set_angle (-90);
646 the_notebook.append_page (route_list_scroller, *nlabel);
647 nlabel = manage (new Label (_("Snapshots")));
648 nlabel->set_angle (-90);
649 the_notebook.append_page (snapshot_display_scroller, *nlabel);
650 nlabel = manage (new Label (_("Edit Groups")));
651 nlabel->set_angle (-90);
652 the_notebook.append_page (*edit_group_display_packer, *nlabel);
653 nlabel = manage (new Label (_("Chunks")));
654 nlabel->set_angle (-90);
655 the_notebook.append_page (named_selection_scroller, *nlabel);
657 the_notebook.set_show_tabs (true);
658 the_notebook.set_scrollable (true);
659 the_notebook.popup_enable ();
660 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
662 post_maximal_editor_width = 0;
663 post_maximal_pane_position = 0;
664 edit_pane.pack1 (edit_packer, true, true);
665 edit_pane.pack2 (the_notebook, false, true);
667 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
669 top_hbox.pack_start (toolbar_frame, true, true);
671 HBox *hbox = manage (new HBox);
672 hbox->pack_start (edit_pane, true, true);
674 global_vpacker.pack_start (top_hbox, false, false);
675 global_vpacker.pack_start (*hbox, true, true);
677 global_hpacker.pack_start (global_vpacker, true, true);
679 set_name ("EditorWindow");
680 add_accel_group (ActionManager::ui_manager->get_accel_group());
682 status_bar_hpacker.show ();
684 vpacker.pack_end (status_bar_hpacker, false, false);
685 vpacker.pack_end (global_hpacker, true, true);
687 /* register actions now so that set_state() can find them and set toggles/checks etc */
691 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
694 _playlist_selector = new PlaylistSelector();
695 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
697 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
701 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
702 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
704 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
705 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
707 nudge_forward_button.set_name ("TransportButton");
708 nudge_backward_button.set_name ("TransportButton");
710 fade_context_menu.set_name ("ArdourContextMenu");
712 /* icons, titles, WM stuff */
714 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
715 Glib::RefPtr<Gdk::Pixbuf> icon;
717 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
718 window_icons.push_back (icon);
720 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
721 window_icons.push_back (icon);
723 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
724 window_icons.push_back (icon);
726 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
727 window_icons.push_back (icon);
729 if (!window_icons.empty()) {
730 set_icon_list (window_icons);
731 set_default_icon_list (window_icons);
734 WindowTitle title(Glib::get_application_name());
735 title += _("Editor");
736 set_title (title.get_string());
737 set_wmclass (X_("ardour_editor"), "Ardour");
740 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
742 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
743 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
745 /* allow external control surfaces/protocols to do various things */
747 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
748 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
749 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
750 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
752 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
753 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
761 /* <CMT Additions> */
762 if(image_socket_listener)
764 if(image_socket_listener->is_connected())
766 image_socket_listener->close_connection() ;
769 delete image_socket_listener ;
770 image_socket_listener = 0 ;
772 /* </CMT Additions> */
776 Editor::add_toplevel_controls (Container& cont)
778 vpacker.pack_start (cont, false, false);
783 Editor::catch_vanishing_regionview (RegionView *rv)
785 /* note: the selection will take care of the vanishing
786 audioregionview by itself.
789 if (clicked_regionview == rv) {
790 clicked_regionview = 0;
793 if (entered_regionview == rv) {
794 set_entered_regionview (0);
799 Editor::set_entered_regionview (RegionView* rv)
801 if (rv == entered_regionview) {
805 if (entered_regionview) {
806 entered_regionview->exited ();
809 if ((entered_regionview = rv) != 0) {
810 entered_regionview->entered ();
815 Editor::set_entered_track (TimeAxisView* tav)
818 entered_track->exited ();
821 if ((entered_track = tav) != 0) {
822 entered_track->entered ();
827 Editor::show_window ()
832 /* now reset all audio_time_axis heights, because widgets might need
838 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
839 tv = (static_cast<TimeAxisView*>(*i));
845 Editor::tie_vertical_scrolling ()
847 double y1 = vertical_adjustment.get_value();
849 playhead_cursor->set_y_axis (y1);
850 edit_cursor->set_y_axis (y1);
852 logo_item->property_y() = y1;
855 controls_layout.get_vadjustment()->set_value (y1);
858 /* the way idle updates and immediate window flushing work on GTK-Quartz
859 requires that we force an immediate redraw right here. The controls
860 layout will do the same all by itself, as does the canvas widget, but
861 most of the time, the canvas itself hasn't updated itself because its
862 idle handler hasn't run. consequently, the call that its layout makes
863 to gdk_window_process_updates() finds nothing to do. here, we force
864 the update to happen, then request a flush of the new window state.
866 track_canvas.update_now ();
867 gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
872 Editor::instant_save ()
874 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
879 session->add_instant_xml(get_state(), session->path());
881 Config->add_instant_xml(get_state(), get_user_ardour_path());
886 Editor::edit_cursor_clock_changed()
888 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
889 edit_cursor->set_position (edit_cursor_clock.current_time());
895 Editor::zoom_adjustment_changed ()
901 double fpu = zoom_range_clock.current_duration() / canvas_width;
905 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
906 } else if (fpu > session->current_end_frame() / canvas_width) {
907 fpu = session->current_end_frame() / canvas_width;
908 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
915 Editor::control_scroll (float fraction)
917 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
923 double step = fraction * current_page_frames();
926 _control_scroll_target is an optional<T>
928 it acts like a pointer to an nframes_t, with
929 a operator conversion to boolean to check
930 that it has a value could possibly use
931 playhead_cursor->current_frame to store the
932 value and a boolean in the class to know
933 when it's out of date
936 if (!_control_scroll_target) {
937 _control_scroll_target = session->transport_frame();
938 _dragging_playhead = true;
941 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
942 *_control_scroll_target = 0;
943 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
944 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
946 *_control_scroll_target += (nframes_t) floor (step);
949 /* move visuals, we'll catch up with it later */
951 playhead_cursor->set_position (*_control_scroll_target);
952 UpdateAllTransportClocks (*_control_scroll_target);
954 if (*_control_scroll_target > (current_page_frames() / 2)) {
955 /* try to center PH in window */
956 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
962 Now we do a timeout to actually bring the session to the right place
963 according to the playhead. This is to avoid reading disk buffers on every
964 call to control_scroll, which is driven by ScrollTimeline and therefore
965 probably by a control surface wheel which can generate lots of events.
967 /* cancel the existing timeout */
969 control_scroll_connection.disconnect ();
971 /* add the next timeout */
973 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
977 Editor::deferred_control_scroll (nframes_t target)
979 session->request_locate (*_control_scroll_target, session->transport_rolling());
980 // reset for next stream
981 _control_scroll_target = boost::none;
982 _dragging_playhead = false;
987 Editor::on_realize ()
989 Window::on_realize ();
994 Editor::start_scrolling ()
996 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
997 (mem_fun(*this, &Editor::update_current_screen));
1001 Editor::stop_scrolling ()
1003 scroll_connection.disconnect ();
1007 Editor::map_position_change (nframes_t frame)
1009 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1011 if (session == 0 || !_follow_playhead) {
1015 center_screen (frame);
1016 playhead_cursor->set_position (frame);
1020 Editor::center_screen (nframes_t frame)
1022 double page = canvas_width * frames_per_unit;
1024 /* if we're off the page, then scroll.
1027 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1028 center_screen_internal (frame, page);
1033 Editor::center_screen_internal (nframes_t frame, float page)
1038 frame -= (nframes_t) page;
1043 reset_x_origin (frame);
1047 Editor::handle_new_duration ()
1049 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1051 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1053 if (new_end > last_canvas_frame) {
1054 last_canvas_frame = new_end;
1055 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1056 reset_scrolling_region ();
1059 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1063 Editor::update_title_s (const string & snap_name)
1065 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1071 Editor::update_title ()
1073 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1076 bool dirty = session->dirty();
1078 string session_name;
1080 if (session->snap_name() != session->name()) {
1081 session_name = session->snap_name();
1083 session_name = session->name();
1087 session_name = "*" + session_name;
1090 WindowTitle title(session_name);
1091 title += Glib::get_application_name();
1092 set_title (title.get_string());
1097 Editor::connect_to_session (Session *t)
1101 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1104 /* catch up with the playhead */
1106 session->request_locate (playhead_cursor->current_frame);
1108 if (first_action_message) {
1109 first_action_message->hide();
1114 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1115 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1117 /* These signals can all be emitted by a non-GUI thread. Therefore the
1118 handlers for them must not attempt to directly interact with the GUI,
1119 but use Gtkmm2ext::UI::instance()->call_slot();
1122 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1123 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1124 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1125 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::handle_new_audio_region)));
1126 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed)));
1127 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1128 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1129 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1130 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1131 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1132 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1133 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1134 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1135 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1137 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1139 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1141 edit_groups_changed ();
1143 edit_cursor_clock.set_session (session);
1144 zoom_range_clock.set_session (session);
1145 _playlist_selector->set_session (session);
1146 nudge_clock.set_session (session);
1149 if (analysis_window != 0)
1150 analysis_window->set_session (session);
1153 Location* loc = session->locations()->auto_loop_location();
1155 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1156 if (loc->start() == loc->end()) {
1157 loc->set_end (loc->start() + 1);
1159 session->locations()->add (loc, false);
1160 session->set_auto_loop_location (loc);
1163 loc->set_name (_("Loop"));
1166 loc = session->locations()->auto_punch_location();
1168 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1169 if (loc->start() == loc->end()) {
1170 loc->set_end (loc->start() + 1);
1172 session->locations()->add (loc, false);
1173 session->set_auto_punch_location (loc);
1176 loc->set_name (_("Punch"));
1179 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1181 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1183 refresh_location_display ();
1184 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1185 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1186 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1187 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1188 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1191 sfbrowser->set_session (session);
1194 handle_new_duration ();
1196 redisplay_regions ();
1197 redisplay_named_selections ();
1198 redisplay_snapshots ();
1200 initial_route_list_display ();
1202 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1203 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1206 restore_ruler_visibility ();
1207 //tempo_map_changed (Change (0));
1208 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1212 /* don't show master bus in a new session */
1214 if (ARDOUR_UI::instance()->session_is_new ()) {
1216 TreeModel::Children rows = route_display_model->children();
1217 TreeModel::Children::iterator i;
1219 no_route_list_redisplay = true;
1221 for (i = rows.begin(); i != rows.end(); ++i) {
1222 TimeAxisView *tv = (*i)[route_display_columns.tv];
1223 AudioTimeAxisView *atv;
1225 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1226 if (atv->route()->master()) {
1227 route_list_display.get_selection()->unselect (i);
1232 no_route_list_redisplay = false;
1233 redisplay_route_list ();
1236 /* register for undo history */
1238 session->register_with_memento_command_factory(_id, this);
1242 Editor::build_cursors ()
1244 using namespace Gdk;
1246 Gdk::Color mbg ("#000000" ); /* Black */
1247 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1250 RefPtr<Bitmap> source, mask;
1251 source = Bitmap::create (mag_bits, mag_width, mag_height);
1252 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1253 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1256 Gdk::Color fbg ("#ffffff" );
1257 Gdk::Color ffg ("#000000" );
1260 RefPtr<Bitmap> source, mask;
1262 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1263 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1264 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1268 RefPtr<Bitmap> source, mask;
1269 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1270 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1271 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1274 grabber_cursor = new Gdk::Cursor (HAND2);
1275 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1276 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1277 selector_cursor = new Gdk::Cursor (XTERM);
1278 time_fx_cursor = new Gdk::Cursor (SIZING);
1279 wait_cursor = new Gdk::Cursor (WATCH);
1280 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1284 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1286 using namespace Menu_Helpers;
1287 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1290 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1294 MenuList& items (fade_context_menu.items());
1298 switch (item_type) {
1300 case FadeInHandleItem:
1301 if (arv->audio_region()->fade_in_active()) {
1302 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1304 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1307 items.push_back (SeparatorElem());
1309 if (Profile->get_sae()) {
1310 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1311 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1313 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1314 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1315 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1316 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1317 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1322 case FadeOutHandleItem:
1323 if (arv->audio_region()->fade_out_active()) {
1324 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1326 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1329 items.push_back (SeparatorElem());
1331 if (Profile->get_sae()) {
1332 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1333 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1335 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1336 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1337 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1338 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1339 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1344 fatal << _("programming error: ")
1345 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1350 fade_context_menu.popup (button, time);
1354 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes_t frame)
1356 using namespace Menu_Helpers;
1357 Menu* (Editor::*build_menu_function)(nframes_t);
1360 switch (item_type) {
1362 case RegionViewName:
1363 case RegionViewNameHighlight:
1364 if (with_selection) {
1365 build_menu_function = &Editor::build_track_selection_context_menu;
1367 build_menu_function = &Editor::build_track_region_context_menu;
1372 if (with_selection) {
1373 build_menu_function = &Editor::build_track_selection_context_menu;
1375 build_menu_function = &Editor::build_track_context_menu;
1379 case CrossfadeViewItem:
1380 build_menu_function = &Editor::build_track_crossfade_context_menu;
1384 if (clicked_audio_trackview->get_diskstream()) {
1385 build_menu_function = &Editor::build_track_context_menu;
1387 build_menu_function = &Editor::build_track_bus_context_menu;
1392 /* probably shouldn't happen but if it does, we don't care */
1396 menu = (this->*build_menu_function)(frame);
1397 menu->set_name ("ArdourContextMenu");
1399 /* now handle specific situations */
1401 switch (item_type) {
1403 case RegionViewName:
1404 case RegionViewNameHighlight:
1405 if (!with_selection) {
1406 if (region_edit_menu_split_item) {
1407 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1408 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, true);
1410 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, false);
1414 if (region_edit_menu_split_multichannel_item) {
1415 if (clicked_regionview && clicked_regionview->region().n_channels() > 1) {
1416 // GTK2FIX find the action, change its sensitivity
1417 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1419 // GTK2FIX see above
1420 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1429 case CrossfadeViewItem:
1436 /* probably shouldn't happen but if it does, we don't care */
1440 if (item_type != SelectionItem && clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1442 /* Bounce to disk */
1444 using namespace Menu_Helpers;
1445 MenuList& edit_items = menu->items();
1447 edit_items.push_back (SeparatorElem());
1449 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1450 case AudioTrack::NoFreeze:
1451 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1454 case AudioTrack::Frozen:
1455 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1458 case AudioTrack::UnFrozen:
1459 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1465 menu->popup (button, time);
1469 Editor::build_track_context_menu (nframes_t ignored)
1471 using namespace Menu_Helpers;
1473 MenuList& edit_items = track_context_menu.items();
1476 add_dstream_context_items (edit_items);
1477 return &track_context_menu;
1481 Editor::build_track_bus_context_menu (nframes_t ignored)
1483 using namespace Menu_Helpers;
1485 MenuList& edit_items = track_context_menu.items();
1488 add_bus_context_items (edit_items);
1489 return &track_context_menu;
1493 Editor::build_track_region_context_menu (nframes_t frame)
1495 using namespace Menu_Helpers;
1496 MenuList& edit_items = track_region_context_menu.items();
1499 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1502 boost::shared_ptr<Diskstream> ds;
1503 boost::shared_ptr<Playlist> pl;
1505 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1506 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)frame * ds->speed()));
1507 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1508 add_region_context_items (atv->audio_view(), (*i), edit_items);
1514 add_dstream_context_items (edit_items);
1516 return &track_region_context_menu;
1520 Editor::build_track_crossfade_context_menu (nframes_t frame)
1522 using namespace Menu_Helpers;
1523 MenuList& edit_items = track_crossfade_context_menu.items();
1524 edit_items.clear ();
1526 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1529 boost::shared_ptr<Diskstream> ds;
1530 boost::shared_ptr<Playlist> pl;
1531 boost::shared_ptr<AudioPlaylist> apl;
1533 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1535 Playlist::RegionList* regions = pl->regions_at (frame);
1536 AudioPlaylist::Crossfades xfades;
1538 apl->crossfades_at (frame, xfades);
1540 bool many = xfades.size() > 1;
1542 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1543 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1546 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1547 add_region_context_items (atv->audio_view(), (*i), edit_items);
1554 add_dstream_context_items (edit_items);
1556 return &track_crossfade_context_menu;
1561 Editor::analyze_region_selection()
1563 if (analysis_window == 0) {
1564 analysis_window = new AnalysisWindow();
1567 analysis_window->set_session(session);
1569 analysis_window->show_all();
1572 analysis_window->set_regionmode();
1573 analysis_window->analyze();
1575 analysis_window->present();
1579 Editor::analyze_range_selection()
1581 if (analysis_window == 0) {
1582 analysis_window = new AnalysisWindow();
1585 analysis_window->set_session(session);
1587 analysis_window->show_all();
1590 analysis_window->set_rangemode();
1591 analysis_window->analyze();
1593 analysis_window->present();
1595 #endif /* FFT_ANALYSIS */
1600 Editor::build_track_selection_context_menu (nframes_t ignored)
1602 using namespace Menu_Helpers;
1603 MenuList& edit_items = track_selection_context_menu.items();
1604 edit_items.clear ();
1606 add_selection_context_items (edit_items);
1607 // edit_items.push_back (SeparatorElem());
1608 // add_dstream_context_items (edit_items);
1610 return &track_selection_context_menu;
1614 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1616 using namespace Menu_Helpers;
1617 Menu *xfade_menu = manage (new Menu);
1618 MenuList& items = xfade_menu->items();
1619 xfade_menu->set_name ("ArdourContextMenu");
1622 if (xfade->active()) {
1628 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1629 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1631 if (xfade->can_follow_overlap()) {
1633 if (xfade->following_overlap()) {
1634 str = _("Convert to short");
1636 str = _("Convert to full");
1639 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1643 str = xfade->out()->name();
1645 str += xfade->in()->name();
1647 str = _("Crossfade");
1650 edit_items.push_back (MenuElem (str, *xfade_menu));
1651 edit_items.push_back (SeparatorElem());
1655 Editor::xfade_edit_left_region ()
1657 if (clicked_crossfadeview) {
1658 clicked_crossfadeview->left_view.show_region_editor ();
1663 Editor::xfade_edit_right_region ()
1665 if (clicked_crossfadeview) {
1666 clicked_crossfadeview->right_view.show_region_editor ();
1671 Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region> region, Menu_Helpers::MenuList& edit_items)
1673 using namespace Menu_Helpers;
1674 Menu *region_menu = manage (new Menu);
1675 MenuList& items = region_menu->items();
1676 region_menu->set_name ("ArdourContextMenu");
1678 boost::shared_ptr<AudioRegion> ar;
1681 ar = boost::dynamic_pointer_cast<AudioRegion> (region);
1684 /* when this particular menu pops up, make the relevant region
1688 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr<Region>(region)));
1690 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1691 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1692 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1693 items.push_back (SeparatorElem());
1694 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1695 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1696 items.push_back (SeparatorElem());
1698 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1699 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1700 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1703 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1706 items.push_back (SeparatorElem());
1708 sigc::connection fooc;
1710 items.push_back (CheckMenuElem (_("Lock")));
1711 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1712 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1713 if (region->locked()) {
1715 region_lock_item->set_active();
1718 items.push_back (CheckMenuElem (_("Mute")));
1719 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1720 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1721 if (region->muted()) {
1723 region_mute_item->set_active();
1727 if (!Profile->get_sae()) {
1728 items.push_back (CheckMenuElem (_("Opaque")));
1729 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1730 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1731 if (region->opaque()) {
1733 region_opaque_item->set_active();
1738 items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1739 if (region->at_natural_position()) {
1740 items.back().set_sensitive (false);
1743 items.push_back (SeparatorElem());
1747 RegionView* rv = sv->find_view (ar);
1748 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1750 if (!Profile->get_sae()) {
1751 items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1753 items.push_back (CheckMenuElem (_("Envelope Visible")));
1754 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1755 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1756 if (arv->envelope_visible()) {
1758 region_envelope_visible_item->set_active (true);
1762 items.push_back (CheckMenuElem (_("Envelope Active")));
1763 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1764 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1766 if (ar->envelope_active()) {
1768 region_envelope_active_item->set_active (true);
1772 items.push_back (SeparatorElem());
1775 if (ar->scale_amplitude() != 1.0f) {
1776 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1778 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1782 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1783 items.push_back (SeparatorElem());
1785 /* range related stuff */
1787 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
1788 items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)));
1789 items.push_back (SeparatorElem());
1793 Menu *nudge_menu = manage (new Menu());
1794 MenuList& nudge_items = nudge_menu->items();
1795 nudge_menu->set_name ("ArdourContextMenu");
1797 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1798 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1799 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1800 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1802 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1803 items.push_back (SeparatorElem());
1805 Menu *trim_menu = manage (new Menu);
1806 MenuList& trim_items = trim_menu->items();
1807 trim_menu->set_name ("ArdourContextMenu");
1809 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1810 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1812 items.push_back (MenuElem (_("Trim"), *trim_menu));
1813 items.push_back (SeparatorElem());
1815 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1816 region_edit_menu_split_item = &items.back();
1818 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1819 region_edit_menu_split_multichannel_item = &items.back();
1821 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1822 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1823 items.push_back (SeparatorElem());
1824 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1826 /* OK, stick the region submenu at the top of the list, and then add
1830 /* we have to hack up the region name because "_" has a special
1831 meaning for menu titles.
1834 string::size_type pos = 0;
1835 string menu_item_name = region->name();
1837 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1838 menu_item_name.replace (pos, 1, "__");
1842 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1843 edit_items.push_back (SeparatorElem());
1847 Editor::add_selection_context_items (Menu_Helpers::MenuList& items)
1849 using namespace Menu_Helpers;
1851 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1852 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1855 items.push_back (SeparatorElem());
1856 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1859 items.push_back (SeparatorElem());
1860 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1861 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1863 items.push_back (SeparatorElem());
1864 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1865 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1867 items.push_back (SeparatorElem());
1868 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1870 items.push_back (SeparatorElem());
1871 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1872 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1874 items.push_back (SeparatorElem());
1875 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1876 items.push_back (SeparatorElem());
1877 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1878 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1879 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1880 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1881 items.push_back (SeparatorElem());
1882 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1883 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1887 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1889 using namespace Menu_Helpers;
1893 Menu *play_menu = manage (new Menu);
1894 MenuList& play_items = play_menu->items();
1895 play_menu->set_name ("ArdourContextMenu");
1897 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1898 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1899 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1900 play_items.push_back (SeparatorElem());
1901 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1903 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1907 Menu *select_menu = manage (new Menu);
1908 MenuList& select_items = select_menu->items();
1909 select_menu->set_name ("ArdourContextMenu");
1911 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1912 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1913 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1914 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1915 select_items.push_back (SeparatorElem());
1916 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1917 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1918 select_items.push_back (SeparatorElem());
1919 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1920 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1921 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1922 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1923 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1924 select_items.push_back (SeparatorElem());
1926 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1930 Menu *cutnpaste_menu = manage (new Menu);
1931 MenuList& cutnpaste_items = cutnpaste_menu->items();
1932 cutnpaste_menu->set_name ("ArdourContextMenu");
1934 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1935 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1936 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1937 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1939 cutnpaste_items.push_back (SeparatorElem());
1941 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1942 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1944 cutnpaste_items.push_back (SeparatorElem());
1946 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1948 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1950 /* Adding new material */
1952 edit_items.push_back (SeparatorElem());
1953 edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1954 edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1958 Menu *nudge_menu = manage (new Menu());
1959 MenuList& nudge_items = nudge_menu->items();
1960 nudge_menu->set_name ("ArdourContextMenu");
1962 edit_items.push_back (SeparatorElem());
1963 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1964 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1965 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1966 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1968 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1972 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1974 using namespace Menu_Helpers;
1978 Menu *play_menu = manage (new Menu);
1979 MenuList& play_items = play_menu->items();
1980 play_menu->set_name ("ArdourContextMenu");
1982 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1983 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1984 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1988 Menu *select_menu = manage (new Menu);
1989 MenuList& select_items = select_menu->items();
1990 select_menu->set_name ("ArdourContextMenu");
1992 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1993 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1994 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1995 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1996 select_items.push_back (SeparatorElem());
1997 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1998 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1999 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2000 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2002 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2006 Menu *cutnpaste_menu = manage (new Menu);
2007 MenuList& cutnpaste_items = cutnpaste_menu->items();
2008 cutnpaste_menu->set_name ("ArdourContextMenu");
2010 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2011 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2012 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2014 Menu *nudge_menu = manage (new Menu());
2015 MenuList& nudge_items = nudge_menu->items();
2016 nudge_menu->set_name ("ArdourContextMenu");
2018 edit_items.push_back (SeparatorElem());
2019 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2020 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2021 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2022 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2024 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2027 /* CURSOR SETTING AND MARKS AND STUFF */
2030 Editor::set_snap_to (SnapType st)
2033 string str = snap_type_strings[(int) st];
2035 if (str != snap_type_selector.get_active_text()) {
2036 snap_type_selector.set_active_text (str);
2041 switch (snap_type) {
2042 case SnapToAThirtysecondBeat:
2043 case SnapToASixteenthBeat:
2044 case SnapToAEighthBeat:
2045 case SnapToAQuarterBeat:
2046 case SnapToAThirdBeat:
2047 update_tempo_based_rulers ();
2055 Editor::set_snap_mode (SnapMode mode)
2058 string str = snap_mode_strings[(int)mode];
2060 if (str != snap_mode_selector.get_active_text ()) {
2061 snap_mode_selector.set_active_text (str);
2067 Editor::set_edit_point (EditPoint ep)
2070 string str = edit_point_strings[(int)ep];
2072 if (str != edit_point_selector.get_active_text ()) {
2073 edit_point_selector.set_active_text (str);
2080 Editor::set_state (const XMLNode& node)
2082 const XMLProperty* prop;
2084 int x, y, xoff, yoff;
2087 if ((prop = node.property ("id")) != 0) {
2088 _id = prop->value ();
2091 if ((geometry = find_named_node (node, "geometry")) == 0) {
2093 g.base_width = default_width;
2094 g.base_height = default_height;
2102 g.base_width = atoi(geometry->property("x_size")->value());
2103 g.base_height = atoi(geometry->property("y_size")->value());
2104 x = atoi(geometry->property("x_pos")->value());
2105 y = atoi(geometry->property("y_pos")->value());
2106 xoff = atoi(geometry->property("x_off")->value());
2107 yoff = atoi(geometry->property("y_off")->value());
2110 set_default_size (g.base_width, g.base_height);
2113 if (session && (prop = node.property ("playhead"))) {
2114 nframes_t pos = atol (prop->value().c_str());
2115 playhead_cursor->set_position (pos);
2117 playhead_cursor->set_position (0);
2119 /* reset_x_origin() doesn't work right here, since the old
2120 position may be zero already, and it does nothing in such
2125 horizontal_adjustment.set_value (0);
2128 if (session && (prop = node.property ("edit-cursor"))) {
2129 nframes_t pos = atol (prop->value().c_str());
2130 edit_cursor->set_position (pos);
2132 edit_cursor->set_position (0);
2135 if ((prop = node.property ("mixer-width"))) {
2136 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2139 if ((prop = node.property ("zoom-focus"))) {
2140 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2143 if ((prop = node.property ("zoom"))) {
2144 reset_zoom (PBD::atof (prop->value()));
2147 if ((prop = node.property ("snap-to"))) {
2148 set_snap_to ((SnapType) atoi (prop->value()));
2151 if ((prop = node.property ("snap-mode"))) {
2152 set_snap_mode ((SnapMode) atoi (prop->value()));
2155 if ((prop = node.property ("edit-point"))) {
2156 set_edit_point ((EditPoint) string_2_enum (prop->value(), _edit_point));
2159 if ((prop = node.property ("mouse-mode"))) {
2160 MouseMode m = str2mousemode(prop->value());
2161 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2162 set_mouse_mode (m, true);
2164 mouse_mode = MouseGain; /* lie, to force the mode switch */
2165 set_mouse_mode (MouseObject, true);
2168 if ((prop = node.property ("show-waveforms"))) {
2169 bool yn = (prop->value() == "yes");
2170 _show_waveforms = !yn;
2171 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2173 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2174 /* do it twice to force the change */
2175 tact->set_active (!yn);
2176 tact->set_active (yn);
2180 if ((prop = node.property ("show-waveforms-recording"))) {
2181 bool yn = (prop->value() == "yes");
2182 _show_waveforms_recording = !yn;
2183 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2185 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2186 /* do it twice to force the change */
2187 tact->set_active (!yn);
2188 tact->set_active (yn);
2192 if ((prop = node.property ("show-measures"))) {
2193 bool yn = (prop->value() == "yes");
2194 _show_measures = !yn;
2195 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2197 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2198 /* do it twice to force the change */
2199 tact->set_active (!yn);
2200 tact->set_active (yn);
2204 if ((prop = node.property ("follow-playhead"))) {
2205 bool yn = (prop->value() == "yes");
2206 set_follow_playhead (yn);
2207 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2209 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2210 if (tact->get_active() != yn) {
2211 tact->set_active (yn);
2216 if ((prop = node.property ("region-list-sort-type"))) {
2217 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2218 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2221 if ((prop = node.property ("xfades-visible"))) {
2222 bool yn = (prop->value() == "yes");
2223 _xfade_visibility = !yn;
2224 // set_xfade_visibility (yn);
2227 if ((prop = node.property ("show-editor-mixer"))) {
2229 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2232 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2233 bool yn = (prop->value() == X_("yes"));
2235 /* do it twice to force the change */
2237 tact->set_active (!yn);
2238 tact->set_active (yn);
2247 Editor::get_state ()
2249 XMLNode* node = new XMLNode ("Editor");
2252 _id.print (buf, sizeof (buf));
2253 node->add_property ("id", buf);
2255 if (is_realized()) {
2256 Glib::RefPtr<Gdk::Window> win = get_window();
2258 int x, y, xoff, yoff, width, height;
2259 win->get_root_origin(x, y);
2260 win->get_position(xoff, yoff);
2261 win->get_size(width, height);
2263 XMLNode* geometry = new XMLNode ("geometry");
2265 snprintf(buf, sizeof(buf), "%d", width);
2266 geometry->add_property("x_size", string(buf));
2267 snprintf(buf, sizeof(buf), "%d", height);
2268 geometry->add_property("y_size", string(buf));
2269 snprintf(buf, sizeof(buf), "%d", x);
2270 geometry->add_property("x_pos", string(buf));
2271 snprintf(buf, sizeof(buf), "%d", y);
2272 geometry->add_property("y_pos", string(buf));
2273 snprintf(buf, sizeof(buf), "%d", xoff);
2274 geometry->add_property("x_off", string(buf));
2275 snprintf(buf, sizeof(buf), "%d", yoff);
2276 geometry->add_property("y_off", string(buf));
2277 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2278 geometry->add_property("edit_pane_pos", string(buf));
2280 node->add_child_nocopy (*geometry);
2283 maybe_add_mixer_strip_width (*node);
2285 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2286 node->add_property ("zoom-focus", buf);
2287 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2288 node->add_property ("zoom", buf);
2289 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2290 node->add_property ("snap-to", buf);
2291 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2292 node->add_property ("snap-mode", buf);
2294 node->add_property ("edit-point", enum_2_string (_edit_point));
2296 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2297 node->add_property ("playhead", buf);
2298 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2299 node->add_property ("edit-cursor", buf);
2301 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2302 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2303 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2304 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2305 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2306 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2307 node->add_property ("mouse-mode", enum2str(mouse_mode));
2309 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2311 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2312 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2321 Editor::trackview_by_y_position (double y)
2323 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2327 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2336 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2338 Location* before = 0;
2339 Location* after = 0;
2345 const nframes64_t one_second = session->frame_rate();
2346 const nframes64_t one_minute = session->frame_rate() * 60;
2347 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2348 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2349 nframes64_t presnap = start;
2351 switch (snap_type) {
2357 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2359 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2363 case SnapToSMPTEFrame:
2364 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2365 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2367 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2371 case SnapToSMPTESeconds:
2372 if (session->smpte_offset_negative())
2374 start += session->smpte_offset ();
2376 start -= session->smpte_offset ();
2378 if (start % one_smpte_second > one_smpte_second / 2) {
2379 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2381 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2384 if (session->smpte_offset_negative())
2386 start -= session->smpte_offset ();
2388 start += session->smpte_offset ();
2392 case SnapToSMPTEMinutes:
2393 if (session->smpte_offset_negative())
2395 start += session->smpte_offset ();
2397 start -= session->smpte_offset ();
2399 if (start % one_smpte_minute > one_smpte_minute / 2) {
2400 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2402 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2404 if (session->smpte_offset_negative())
2406 start -= session->smpte_offset ();
2408 start += session->smpte_offset ();
2413 if (start % one_second > one_second / 2) {
2414 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2416 start = (nframes_t) floor ((double) start / one_second) * one_second;
2421 if (start % one_minute > one_minute / 2) {
2422 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2424 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2429 start = session->tempo_map().round_to_bar (start, direction);
2433 start = session->tempo_map().round_to_beat (start, direction);
2436 case SnapToAThirtysecondBeat:
2437 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2440 case SnapToASixteenthBeat:
2441 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2444 case SnapToAEighthBeat:
2445 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2448 case SnapToAQuarterBeat:
2449 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2452 case SnapToAThirdBeat:
2453 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2456 case SnapToEditCursor:
2457 start = get_preferred_edit_position ();
2465 before = session->locations()->first_location_before (start);
2466 after = session->locations()->first_location_after (start);
2468 if (direction < 0) {
2470 start = before->start();
2474 } else if (direction > 0) {
2476 start = after->start();
2478 start = session->current_end_frame();
2483 /* find nearest of the two */
2484 if ((start - before->start()) < (after->start() - start)) {
2485 start = before->start();
2487 start = after->start();
2490 start = before->start();
2493 start = after->start();
2500 case SnapToRegionStart:
2501 case SnapToRegionEnd:
2502 case SnapToRegionSync:
2503 case SnapToRegionBoundary:
2504 if (!region_boundary_cache.empty()) {
2505 vector<nframes_t>::iterator i;
2507 if (direction > 0) {
2508 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2510 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2513 if (i != region_boundary_cache.end()) {
2516 start = region_boundary_cache.back();
2522 switch (snap_mode) {
2528 if (presnap > start) {
2529 if (presnap > (start + unit_to_frame(snap_threshold))) {
2533 } else if (presnap < start) {
2534 if (presnap < (start - unit_to_frame(snap_threshold))) {
2546 Editor::setup_toolbar ()
2550 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2553 /* Mode Buttons (tool selection) */
2555 vector<ToggleButton *> mouse_mode_buttons;
2557 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2558 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2559 mouse_mode_buttons.push_back (&mouse_move_button);
2560 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2561 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2562 mouse_mode_buttons.push_back (&mouse_select_button);
2563 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2564 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2565 mouse_mode_buttons.push_back (&mouse_gain_button);
2566 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2567 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2568 mouse_mode_buttons.push_back (&mouse_zoom_button);
2569 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2570 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2571 mouse_mode_buttons.push_back (&mouse_timefx_button);
2572 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2573 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2574 mouse_mode_buttons.push_back (&mouse_audition_button);
2576 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2578 HBox* mode_box = manage(new HBox);
2579 mode_box->set_border_width (2);
2580 mode_box->set_spacing(4);
2581 mouse_mode_button_box.set_spacing(1);
2582 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2583 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2584 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2585 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2586 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2587 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2588 mouse_mode_button_box.set_homogeneous(true);
2590 vector<string> edit_mode_strings;
2591 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2592 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2594 edit_mode_selector.set_name ("EditModeSelector");
2595 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2596 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2597 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2599 mode_box->pack_start(edit_mode_selector);
2600 mode_box->pack_start(mouse_mode_button_box);
2602 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2603 mouse_mode_tearoff->set_name ("MouseModeBase");
2605 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2606 &mouse_mode_tearoff->tearoff_window()));
2607 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2608 &mouse_mode_tearoff->tearoff_window(), 1));
2609 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2610 &mouse_mode_tearoff->tearoff_window()));
2611 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2612 &mouse_mode_tearoff->tearoff_window(), 1));
2614 mouse_move_button.set_name ("MouseModeButton");
2615 mouse_select_button.set_name ("MouseModeButton");
2616 mouse_gain_button.set_name ("MouseModeButton");
2617 mouse_zoom_button.set_name ("MouseModeButton");
2618 mouse_timefx_button.set_name ("MouseModeButton");
2619 mouse_audition_button.set_name ("MouseModeButton");
2621 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2622 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2623 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2624 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2625 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2626 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2628 mouse_move_button.unset_flags (CAN_FOCUS);
2629 mouse_select_button.unset_flags (CAN_FOCUS);
2630 mouse_gain_button.unset_flags (CAN_FOCUS);
2631 mouse_zoom_button.unset_flags (CAN_FOCUS);
2632 mouse_timefx_button.unset_flags (CAN_FOCUS);
2633 mouse_audition_button.unset_flags (CAN_FOCUS);
2635 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2636 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2638 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2639 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2640 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2641 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2642 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2644 // mouse_move_button.set_active (true);
2649 zoom_box.set_spacing (1);
2650 zoom_box.set_border_width (2);
2652 zoom_in_button.set_name ("EditorTimeButton");
2653 zoom_in_button.set_size_request(-1,16);
2654 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2655 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2656 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2658 zoom_out_button.set_name ("EditorTimeButton");
2659 zoom_out_button.set_size_request(-1,16);
2660 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2661 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2662 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2664 zoom_out_full_button.set_name ("EditorTimeButton");
2665 zoom_out_full_button.set_size_request(-1,16);
2666 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2667 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2668 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2670 zoom_focus_selector.set_name ("ZoomFocusSelector");
2671 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edit Cursor", FUDGE, 0);
2672 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2673 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2674 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2676 zoom_box.pack_start (zoom_focus_selector, true, true);
2677 zoom_box.pack_start (zoom_out_button, false, false);
2678 zoom_box.pack_start (zoom_in_button, false, false);
2679 zoom_box.pack_start (zoom_out_full_button, false, false);
2681 /* Edit Cursor / Snap */
2683 snap_box.set_spacing (1);
2684 snap_box.set_border_width (2);
2686 snap_type_selector.set_name ("SnapTypeSelector");
2687 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2688 set_popdown_strings (snap_type_selector, snap_type_strings);
2689 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2690 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
2692 snap_mode_selector.set_name ("SnapModeSelector");
2693 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2694 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2695 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2696 ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2698 edit_point_selector.set_name ("SnapModeSelector");
2699 Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, "Playhead", 2+FUDGE, 10);
2700 set_popdown_strings (edit_point_selector, edit_point_strings);
2701 edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
2702 ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
2704 snap_box.pack_start (edit_cursor_clock, false, false);
2705 snap_box.pack_start (snap_mode_selector, false, false);
2706 snap_box.pack_start (snap_type_selector, false, false);
2707 snap_box.pack_start (edit_point_selector, false, false);
2711 HBox *nudge_box = manage (new HBox);
2712 nudge_box->set_spacing(1);
2713 nudge_box->set_border_width (2);
2715 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2716 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2718 nudge_box->pack_start (nudge_backward_button, false, false);
2719 nudge_box->pack_start (nudge_forward_button, false, false);
2720 nudge_box->pack_start (nudge_clock, false, false);
2723 /* Pack everything in... */
2725 HBox* hbox = new HBox;
2726 hbox->set_spacing(10);
2728 tools_tearoff = new TearOff (*hbox);
2729 tools_tearoff->set_name ("MouseModeBase");
2731 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2732 &tools_tearoff->tearoff_window()));
2733 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2734 &tools_tearoff->tearoff_window(), 0));
2735 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2736 &tools_tearoff->tearoff_window()));
2737 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2738 &tools_tearoff->tearoff_window(), 0));
2740 toolbar_hbox.set_spacing (10);
2741 toolbar_hbox.set_border_width (1);
2743 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2744 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2747 hbox->pack_start (snap_box, false, false);
2748 // hbox->pack_start (zoom_box, false, false);
2749 hbox->pack_start (*nudge_box, false, false);
2753 toolbar_base.set_name ("ToolBarBase");
2754 toolbar_base.add (toolbar_hbox);
2756 toolbar_frame.set_shadow_type (SHADOW_OUT);
2757 toolbar_frame.set_name ("BaseFrame");
2758 toolbar_frame.add (toolbar_base);
2762 Editor::convert_drop_to_paths (vector<ustring>& paths,
2763 const RefPtr<Gdk::DragContext>& context,
2766 const SelectionData& data,
2775 vector<ustring> uris = data.get_uris();
2779 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2780 are actually URI lists. So do it by hand.
2783 if (data.get_target() != "text/plain") {
2787 /* Parse the "uri-list" format that Nautilus provides,
2788 where each pathname is delimited by \r\n
2791 const char* p = data.get_text().c_str();
2798 while (g_ascii_isspace (*p))
2802 while (*q && (*q != '\n') && (*q != '\r'))
2808 while (q > p && g_ascii_isspace (*q))
2813 uris.push_back (ustring (p, q - p + 1));
2817 p = strchr (p, '\n');
2827 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2829 if ((*i).substr (0,7) == "file://") {
2833 PBD::url_decode (p);
2835 // scan forward past three slashes
2837 ustring::size_type slashcnt = 0;
2838 ustring::size_type n = 0;
2839 ustring::iterator x = p.begin();
2841 while (slashcnt < 3 && x != p.end()) {
2844 } else if (slashcnt == 3) {
2851 if (slashcnt != 3 || x == p.end()) {
2852 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2856 paths.push_back (p.substr (n - 1));
2864 Editor::new_tempo_section ()
2870 Editor::map_transport_state ()
2872 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2874 if (session->transport_stopped()) {
2875 have_pending_keyboard_selection = false;
2878 update_loop_range_view (true);
2883 Editor::State::State ()
2885 selection = new Selection;
2888 Editor::State::~State ()
2894 Editor::get_memento () const
2896 State *state = new State;
2898 store_state (*state);
2899 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2903 Editor::store_state (State& state) const
2905 *state.selection = *selection;
2909 Editor::restore_state (State *state)
2911 if (*selection == *state->selection) {
2915 *selection = *state->selection;
2916 time_selection_changed ();
2917 region_selection_changed ();
2919 /* XXX other selection change handlers? */
2923 Editor::begin_reversible_command (string name)
2926 // before = &get_state();
2927 session->begin_reversible_command (name);
2932 Editor::commit_reversible_command ()
2935 // session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2936 session->commit_reversible_command ();
2941 Editor::set_edit_group_solo (Route& route, bool yn)
2943 RouteGroup *edit_group;
2945 if ((edit_group = route.edit_group()) != 0) {
2946 edit_group->apply (&Route::set_solo, yn, this);
2948 route.set_solo (yn, this);
2953 Editor::set_edit_group_mute (Route& route, bool yn)
2955 RouteGroup *edit_group = 0;
2957 if ((edit_group == route.edit_group()) != 0) {
2958 edit_group->apply (&Route::set_mute, yn, this);
2960 route.set_mute (yn, this);
2965 Editor::history_changed ()
2969 if (undo_action && session) {
2970 if (session->undo_depth() == 0) {
2973 label = string_compose(_("Undo (%1)"), session->next_undo());
2975 undo_action->property_label() = label;
2978 if (redo_action && session) {
2979 if (session->redo_depth() == 0) {
2982 label = string_compose(_("Redo (%1)"), session->next_redo());
2984 redo_action->property_label() = label;
2989 Editor::duplicate_dialog (bool dup_region)
2991 if (selection->regions.empty() && (selection->time.length() == 0)) {
2995 ArdourDialog win ("duplicate dialog");
2996 Label label (_("Duplicate how many times?"));
2997 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
2998 SpinButton spinner (adjustment);
3000 win.get_vbox()->set_spacing (12);
3001 win.get_vbox()->pack_start (label);
3003 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3004 place, visually. so do this by hand.
3007 win.get_vbox()->pack_start (spinner);
3008 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3013 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3014 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3016 win.set_position (WIN_POS_MOUSE);
3018 spinner.grab_focus ();
3020 switch (win.run ()) {
3021 case RESPONSE_ACCEPT:
3027 float times = adjustment.get_value();
3029 if (!selection->regions.empty()) {
3030 duplicate_some_regions (selection->regions, times);
3032 duplicate_selection (times);
3037 Editor::show_verbose_canvas_cursor ()
3039 verbose_canvas_cursor->raise_to_top();
3040 verbose_canvas_cursor->show();
3041 verbose_cursor_visible = true;
3045 Editor::hide_verbose_canvas_cursor ()
3047 verbose_canvas_cursor->hide();
3048 verbose_cursor_visible = false;
3052 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3054 /* XXX get origin of canvas relative to root window,
3055 add x and y and check compared to gdk_screen_{width,height}
3057 verbose_canvas_cursor->property_text() = txt.c_str();
3058 verbose_canvas_cursor->property_x() = x;
3059 verbose_canvas_cursor->property_y() = y;
3063 Editor::set_verbose_canvas_cursor_text (const string & txt)
3065 verbose_canvas_cursor->property_text() = txt.c_str();
3069 Editor::edit_mode_selection_done ()
3075 string choice = edit_mode_selector.get_active_text();
3076 EditMode mode = Slide;
3078 if (choice == _("Splice Edit")) {
3080 } else if (choice == _("Slide Edit")) {
3084 Config->set_edit_mode (mode);
3088 Editor::snap_type_selection_done ()
3090 string choice = snap_type_selector.get_active_text();
3091 SnapType snaptype = SnapToFrame;
3093 if (choice == _("Beats/3")) {
3094 snaptype = SnapToAThirdBeat;
3095 } else if (choice == _("Beats/4")) {
3096 snaptype = SnapToAQuarterBeat;
3097 } else if (choice == _("Beats/8")) {
3098 snaptype = SnapToAEighthBeat;
3099 } else if (choice == _("Beats/16")) {
3100 snaptype = SnapToASixteenthBeat;
3101 } else if (choice == _("Beats/32")) {
3102 snaptype = SnapToAThirtysecondBeat;
3103 } else if (choice == _("Beats")) {
3104 snaptype = SnapToBeat;
3105 } else if (choice == _("Bars")) {
3106 snaptype = SnapToBar;
3107 } else if (choice == _("Marks")) {
3108 snaptype = SnapToMark;
3109 } else if (choice == _("Edit Cursor")) {
3110 snaptype = SnapToEditCursor;
3111 } else if (choice == _("Region starts")) {
3112 snaptype = SnapToRegionStart;
3113 } else if (choice == _("Region ends")) {
3114 snaptype = SnapToRegionEnd;
3115 } else if (choice == _("Region bounds")) {
3116 snaptype = SnapToRegionBoundary;
3117 } else if (choice == _("Region syncs")) {
3118 snaptype = SnapToRegionSync;
3119 } else if (choice == _("CD Frames")) {
3120 snaptype = SnapToCDFrame;
3121 } else if (choice == _("SMPTE Frames")) {
3122 snaptype = SnapToSMPTEFrame;
3123 } else if (choice == _("SMPTE Seconds")) {
3124 snaptype = SnapToSMPTESeconds;
3125 } else if (choice == _("SMPTE Minutes")) {
3126 snaptype = SnapToSMPTEMinutes;
3127 } else if (choice == _("Seconds")) {
3128 snaptype = SnapToSeconds;
3129 } else if (choice == _("Minutes")) {
3130 snaptype = SnapToMinutes;
3131 } else if (choice == _("None")) {
3132 snaptype = SnapToFrame;
3135 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3137 ract->set_active ();
3142 Editor::snap_mode_selection_done ()
3144 string choice = snap_mode_selector.get_active_text();
3145 SnapMode mode = SnapNormal;
3147 if (choice == _("Normal")) {
3149 } else if (choice == _("Magnetic")) {
3150 mode = SnapMagnetic;
3153 RefPtr<RadioAction> ract = snap_mode_action (mode);
3156 ract->set_active (true);
3161 Editor::edit_point_selection_done ()
3163 string choice = edit_point_selector.get_active_text();
3164 EditPoint ep = EditAtSelectedMarker;
3166 if (choice == _("Marker")) {
3167 _edit_point = EditAtSelectedMarker;
3168 } else if (choice == _("Playhead")) {
3169 _edit_point = EditAtPlayhead;
3171 _edit_point = EditAtMouse;
3174 RefPtr<RadioAction> ract = edit_point_action (ep);
3177 ract->set_active (true);
3182 Editor::zoom_focus_selection_done ()
3184 string choice = zoom_focus_selector.get_active_text();
3185 ZoomFocus focus_type = ZoomFocusLeft;
3187 if (choice == _("Left")) {
3188 focus_type = ZoomFocusLeft;
3189 } else if (choice == _("Right")) {
3190 focus_type = ZoomFocusRight;
3191 } else if (choice == _("Center")) {
3192 focus_type = ZoomFocusCenter;
3193 } else if (choice == _("Playhead")) {
3194 focus_type = ZoomFocusPlayhead;
3195 } else if (choice == _("Mouse")) {
3196 focus_type = ZoomFocusMouse;
3197 } else if (choice == _("Edit Cursor")) {
3198 focus_type = ZoomFocusEdit;
3201 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3204 ract->set_active ();
3209 Editor::edit_controls_button_release (GdkEventButton* ev)
3211 if (Keyboard::is_context_menu_event (ev)) {
3212 ARDOUR_UI::instance()->add_route (this);
3218 Editor::mouse_select_button_release (GdkEventButton* ev)
3220 /* this handles just right-clicks */
3222 if (ev->button != 3) {
3229 Editor::TrackViewList *
3230 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3233 TrackViewList::iterator i;
3235 v = new TrackViewList;
3237 if (track == 0 && group == 0) {
3241 for (i = track_views.begin(); i != track_views.end (); ++i) {
3245 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3247 /* just the view for this track
3250 v->push_back (track);
3254 /* views for all tracks in the edit group */
3256 for (i = track_views.begin(); i != track_views.end (); ++i) {
3258 if (group == 0 || (*i)->edit_group() == group) {
3268 Editor::set_zoom_focus (ZoomFocus f)
3270 string str = zoom_focus_strings[(int)f];
3272 if (str != zoom_focus_selector.get_active_text()) {
3273 zoom_focus_selector.set_active_text (str);
3276 if (zoom_focus != f) {
3279 ZoomFocusChanged (); /* EMIT_SIGNAL */
3286 Editor::ensure_float (Window& win)
3288 win.set_transient_for (*this);
3292 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3294 /* recover or initialize pane positions. do this here rather than earlier because
3295 we don't want the positions to change the child allocations, which they seem to do.
3301 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3303 static int32_t done;
3306 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3307 width = default_width;
3308 height = default_height;
3310 width = atoi(geometry->property("x_size")->value());
3311 height = atoi(geometry->property("y_size")->value());
3314 if (which == static_cast<Paned*> (&edit_pane)) {
3320 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3321 /* initial allocation is 90% to canvas, 10% to notebook */
3322 pos = (int) floor (alloc.get_width() * 0.90f);
3323 snprintf (buf, sizeof(buf), "%d", pos);
3325 pos = atoi (prop->value());
3328 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3329 edit_pane.set_position (pos);
3330 pre_maximal_pane_position = pos;
3336 Editor::detach_tearoff (Box* b, Window* w)
3338 if (tools_tearoff->torn_off() &&
3339 mouse_mode_tearoff->torn_off()) {
3340 top_hbox.remove (toolbar_frame);
3345 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3347 if (toolbar_frame.get_parent() == 0) {
3348 top_hbox.pack_end (toolbar_frame);
3353 Editor::set_show_measures (bool yn)
3355 if (_show_measures != yn) {
3358 if ((_show_measures = yn) == true) {
3366 Editor::toggle_follow_playhead ()
3368 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3370 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3371 set_follow_playhead (tact->get_active());
3376 Editor::set_follow_playhead (bool yn)
3378 if (_follow_playhead != yn) {
3379 if ((_follow_playhead = yn) == true) {
3381 update_current_screen ();
3388 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3390 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3392 xfade->set_active (!xfade->active());
3397 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3399 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3401 xfade->set_follow_overlap (!xfade->following_overlap());
3406 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3408 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3414 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3418 switch (cew.run ()) {
3419 case RESPONSE_ACCEPT:
3426 xfade->StateChanged (Change (~0));
3430 Editor::playlist_selector () const
3432 return *_playlist_selector;
3436 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3440 ret = nudge_clock.current_duration (pos);
3441 next = ret + 1; /* XXXX fix me */
3447 Editor::end_location_changed (Location* location)
3449 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3450 reset_scrolling_region ();
3454 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3456 ArdourDialog dialog ("playlist deletion dialog");
3457 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3458 "If left alone, no audio files used by it will be cleaned.\n"
3459 "If deleted, audio files used by it alone by will cleaned."),
3462 dialog.set_position (WIN_POS_CENTER);
3463 dialog.get_vbox()->pack_start (label);
3467 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3468 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3469 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3471 switch (dialog.run ()) {
3472 case RESPONSE_ACCEPT:
3473 /* delete the playlist */
3477 case RESPONSE_REJECT:
3478 /* keep the playlist */
3490 Editor::audio_region_selection_covers (nframes_t where)
3492 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3493 if ((*a)->region()->covers (where)) {
3502 Editor::prepare_for_cleanup ()
3504 cut_buffer->clear_regions ();
3505 cut_buffer->clear_playlists ();
3507 selection->clear_regions ();
3508 selection->clear_playlists ();
3512 Editor::transport_loop_location()
3515 return session->locations()->auto_loop_location();
3522 Editor::transport_punch_location()
3525 return session->locations()->auto_punch_location();
3532 Editor::control_layout_scroll (GdkEventScroll* ev)
3534 switch (ev->direction) {
3536 scroll_tracks_up_line ();
3540 case GDK_SCROLL_DOWN:
3541 scroll_tracks_down_line ();
3545 /* no left/right handling yet */
3553 /** A new snapshot has been selected.
3556 Editor::snapshot_display_selection_changed ()
3558 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3560 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3562 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3564 if (snap_name.length() == 0) {
3568 if (session->snap_name() == snap_name) {
3572 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3577 Editor::snapshot_display_button_press (GdkEventButton* ev)
3579 if (ev->button == 3) {
3580 /* Right-click on the snapshot list. Work out which snapshot it
3582 Gtk::TreeModel::Path path;
3583 Gtk::TreeViewColumn* col;
3586 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3587 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3589 Gtk::TreeModel::Row row = *iter;
3590 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3599 /** Pop up the snapshot display context menu.
3600 * @param button Button used to open the menu.
3601 * @param time Menu open time.
3602 * @snapshot_name Name of the snapshot that the menu click was over.
3606 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3608 using namespace Menu_Helpers;
3610 MenuList& items (snapshot_context_menu.items());
3613 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3615 items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)));
3616 if (!modification_allowed) {
3617 items.back().set_sensitive (false);
3620 items.push_back (MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)));
3621 if (!modification_allowed) {
3622 items.back().set_sensitive (false);
3625 snapshot_context_menu.popup (button, time);
3629 Editor::rename_snapshot (Glib::ustring old_name)
3631 ArdourPrompter prompter(true);
3635 prompter.set_name ("Prompter");
3636 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3637 prompter.set_prompt (_("New name of snapshot"));
3638 prompter.set_initial_text (old_name);
3640 if (prompter.run() == RESPONSE_ACCEPT) {
3641 prompter.get_result (new_name);
3642 if (new_name.length()) {
3643 session->rename_state (old_name, new_name);
3644 redisplay_snapshots ();
3651 Editor::remove_snapshot (Glib::ustring name)
3653 vector<string> choices;
3655 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3657 choices.push_back (_("No, do nothing."));
3658 choices.push_back (_("Yes, remove it."));
3660 Gtkmm2ext::Choice prompter (prompt, choices);
3662 if (prompter.run () == 1) {
3663 session->remove_state (name);
3664 redisplay_snapshots ();
3669 Editor::redisplay_snapshots ()
3675 vector<string*>* states;
3677 if ((states = session->possible_states()) == 0) {
3681 snapshot_display_model->clear ();
3683 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3684 string statename = *(*i);
3685 TreeModel::Row row = *(snapshot_display_model->append());
3687 /* this lingers on in case we ever want to change the visible
3688 name of the snapshot.
3691 string display_name;
3692 display_name = statename;
3694 if (statename == session->snap_name()) {
3695 snapshot_display.get_selection()->select(row);
3698 row[snapshot_display_columns.visible_name] = display_name;
3699 row[snapshot_display_columns.real_name] = statename;
3706 Editor::session_state_saved (string snap_name)
3708 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3709 redisplay_snapshots ();
3713 Editor::maximise_editing_space ()
3715 initial_ruler_update_required = true;
3717 mouse_mode_tearoff->set_visible (false);
3718 tools_tearoff->set_visible (false);
3720 pre_maximal_pane_position = edit_pane.get_position();
3721 pre_maximal_editor_width = this->get_width();
3723 if(post_maximal_pane_position == 0) {
3724 post_maximal_pane_position = edit_pane.get_width();
3729 if(post_maximal_editor_width) {
3730 edit_pane.set_position (post_maximal_pane_position -
3731 abs(post_maximal_editor_width - pre_maximal_editor_width));
3733 edit_pane.set_position (post_maximal_pane_position);
3738 Editor::restore_editing_space ()
3740 initial_ruler_update_required = true;
3742 // user changed width of pane during fullscreen
3743 if(post_maximal_pane_position != edit_pane.get_position()) {
3744 post_maximal_pane_position = edit_pane.get_position();
3749 mouse_mode_tearoff->set_visible (true);
3750 tools_tearoff->set_visible (true);
3751 post_maximal_editor_width = this->get_width();
3754 edit_pane.set_position (
3755 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3760 * Make new playlists for a given track and also any others that belong
3761 * to the same active edit group.
3766 Editor::new_playlists (TimeAxisView* v)
3768 begin_reversible_command (_("new playlists"));
3769 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3770 commit_reversible_command ();
3775 * Use a copy of the current playlist for a given track and also any others that belong
3776 * to the same active edit group.
3781 Editor::copy_playlists (TimeAxisView* v)
3783 begin_reversible_command (_("copy playlists"));
3784 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3785 commit_reversible_command ();
3790 * Clear the current playlist for a given track and also any others that belong
3791 * to the same active edit group.
3796 Editor::clear_playlists (TimeAxisView* v)
3798 begin_reversible_command (_("clear playlists"));
3799 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3800 commit_reversible_command ();
3804 Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz)
3806 atv.use_new_playlist (sz > 1 ? false : true);
3810 Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz)
3812 atv.use_copy_playlist (sz > 1 ? false : true);
3816 Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz)
3818 atv.clear_playlist ();
3822 Editor::on_key_press_event (GdkEventKey* ev)
3824 return key_press_focus_accelerator_handler (*this, ev);
3828 Editor::reset_x_origin (nframes_t frame)
3830 queue_visual_change (frame);
3834 Editor::reset_zoom (double fpu)
3836 queue_visual_change (fpu);
3840 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3842 reset_x_origin (frame);
3847 Editor::set_frames_per_unit (double fpu)
3851 /* this is the core function that controls the zoom level of the canvas. it is called
3852 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3855 if (fpu == frames_per_unit) {
3863 // convert fpu to frame count
3865 frames = (nframes_t) floor (fpu * canvas_width);
3867 /* don't allow zooms that fit more than the maximum number
3868 of frames into an 800 pixel wide space.
3871 if (max_frames / fpu < 800.0) {
3875 if (fpu == frames_per_unit) {
3879 frames_per_unit = fpu;
3881 if (frames != zoom_range_clock.current_duration()) {
3882 zoom_range_clock.set (frames);
3885 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3886 if (!selection->tracks.empty()) {
3887 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3888 (*i)->reshow_selection (selection->time);
3891 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3892 (*i)->reshow_selection (selection->time);
3897 ZoomChanged (); /* EMIT_SIGNAL */
3899 reset_hscrollbar_stepping ();
3900 reset_scrolling_region ();
3902 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3903 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3909 Editor::queue_visual_change (nframes_t where)
3911 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3912 pending_visual_change.time_origin = where;
3914 if (pending_visual_change.idle_handler_id < 0) {
3915 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3920 Editor::queue_visual_change (double fpu)
3922 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3923 pending_visual_change.frames_per_unit = fpu;
3925 if (pending_visual_change.idle_handler_id < 0) {
3926 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3931 Editor::_idle_visual_changer (void* arg)
3933 return static_cast<Editor*>(arg)->idle_visual_changer ();
3937 Editor::idle_visual_changer ()
3939 VisualChange::Type p = pending_visual_change.pending;
3941 pending_visual_change.pending = (VisualChange::Type) 0;
3942 pending_visual_change.idle_handler_id = -1;
3944 if (p & VisualChange::ZoomLevel) {
3945 set_frames_per_unit (pending_visual_change.frames_per_unit);
3948 if (p & VisualChange::TimeOrigin) {
3949 if (pending_visual_change.time_origin != leftmost_frame) {
3950 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3951 /* the signal handler will do the rest */
3953 update_fixed_rulers();
3954 redisplay_tempo (true);
3958 return 0; /* this is always a one-shot call */
3961 struct EditorOrderTimeAxisSorter {
3962 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3963 return a->order < b->order;
3968 Editor::sort_track_selection ()
3970 EditorOrderTimeAxisSorter cmp;
3971 selection->tracks.sort (cmp);
3975 Editor::edit_cursor_position(bool sync)
3977 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
3978 edit_cursor_clock.set(edit_cursor->current_frame, true);
3981 return edit_cursor->current_frame;
3985 Editor::get_preferred_edit_position() const
3990 switch (_edit_point) {
3991 case EditAtPlayhead:
3992 return playhead_cursor->current_frame;
3994 case EditAtSelectedMarker:
3995 if (!selection->markers.empty()) {
3997 Location* loc = find_location_from_marker (selection->markers.front(), whocares);
3999 return loc->start();
4006 if (mouse_frame (where, ignored)) {
4015 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4017 if (!session) return;
4019 begin_reversible_command (cmd);
4023 if ((tll = transport_loop_location()) == 0) {
4024 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4025 XMLNode &before = session->locations()->get_state();
4026 session->locations()->add (loc, true);
4027 session->set_auto_loop_location (loc);
4028 XMLNode &after = session->locations()->get_state();
4029 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4032 XMLNode &before = tll->get_state();
4033 tll->set_hidden (false, this);
4034 tll->set (start, end);
4035 XMLNode &after = tll->get_state();
4036 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4039 commit_reversible_command ();
4043 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4045 if (!session) return;
4047 begin_reversible_command (cmd);
4051 if ((tpl = transport_punch_location()) == 0) {
4052 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4053 XMLNode &before = session->locations()->get_state();
4054 session->locations()->add (loc, true);
4055 session->set_auto_loop_location (loc);
4056 XMLNode &after = session->locations()->get_state();
4057 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4060 XMLNode &before = tpl->get_state();
4061 tpl->set_hidden (false, this);
4062 tpl->set (start, end);
4063 XMLNode &after = tpl->get_state();
4064 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4067 commit_reversible_command ();