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));
231 clicked_regionview = 0;
232 clicked_trackview = 0;
233 clicked_audio_trackview = 0;
234 clicked_crossfadeview = 0;
235 clicked_control_point = 0;
236 latest_regionview = 0;
237 last_update_frame = 0;
239 current_mixer_strip = 0;
240 current_bbt_points = 0;
242 snap_type_strings = I18N (_snap_type_strings);
243 snap_mode_strings = I18N (_snap_mode_strings);
244 zoom_focus_strings = I18N (_zoom_focus_strings);
245 edit_point_strings = I18N (_edit_point_strings);
247 snap_type = SnapToFrame;
248 set_snap_to (snap_type);
250 snap_mode = SnapNormal;
251 set_snap_mode (snap_mode);
253 _edit_point = EditAtMouse;
254 set_edit_point (_edit_point);
256 snap_threshold = 5.0;
257 bbt_beat_subdivision = 4;
260 autoscroll_active = false;
261 autoscroll_timeout_tag = -1;
262 interthread_progress_window = 0;
269 current_interthread_info = 0;
270 _show_measures = true;
271 _show_waveforms = true;
272 _show_waveforms_recording = true;
273 first_action_message = 0;
275 export_range_markers_dialog = 0;
276 show_gain_after_trim = false;
277 ignore_route_list_reorder = false;
278 no_route_list_redisplay = false;
279 verbose_cursor_on = true;
280 route_removal = false;
281 show_automatic_regions_in_region_list = true;
282 region_list_sort_type = (Editing::RegionListSortType) 0;
283 have_pending_keyboard_selection = false;
284 _follow_playhead = true;
285 _xfade_visibility = true;
286 editor_ruler_menu = 0;
287 no_ruler_shown_update = false;
288 edit_group_list_menu = 0;
290 region_list_menu = 0;
292 start_end_marker_menu = 0;
293 range_marker_menu = 0;
294 marker_menu_item = 0;
296 transport_marker_menu = 0;
297 new_transport_marker_menu = 0;
298 editor_mixer_strip_width = Wide;
299 show_editor_mixer_when_tracks_arrive = false;
300 region_edit_menu_split_item = 0;
302 region_edit_menu_split_multichannel_item = 0;
304 ignore_mouse_mode_toggle = false;
305 current_stepping_trackview = 0;
307 entered_regionview = 0;
308 clear_entered_track = false;
309 _new_regionviews_show_envelope = false;
310 current_timestretch = 0;
311 in_edit_group_row_change = false;
312 last_canvas_frame = 0;
315 button_release_can_deselect = true;
316 canvas_idle_queued = false;
317 _dragging_playhead = false;
318 _dragging_hscrollbar = false;
320 scrubbing_direction = 0;
323 ignore_route_order_sync = false;
325 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
326 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
327 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
328 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
329 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
331 range_marker_drag_rect = 0;
332 marker_drag_line = 0;
334 set_mouse_mode (MouseObject, true);
336 frames_per_unit = 2048; /* too early to use reset_zoom () */
337 reset_hscrollbar_stepping ();
339 zoom_focus = ZoomFocusLeft;
340 set_zoom_focus (ZoomFocusLeft);
341 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
343 initialize_rulers ();
344 initialize_canvas ();
346 edit_controls_vbox.set_spacing (0);
347 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
348 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
350 track_canvas.set_hadjustment (horizontal_adjustment);
351 track_canvas.set_vadjustment (vertical_adjustment);
352 time_canvas.set_hadjustment (horizontal_adjustment);
354 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
355 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
357 controls_layout.add (edit_controls_vbox);
358 controls_layout.set_name ("EditControlsBase");
359 controls_layout.add_events (Gdk::SCROLL_MASK);
360 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
362 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
363 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
364 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
366 edit_vscrollbar.set_adjustment (vertical_adjustment);
367 edit_hscrollbar.set_adjustment (horizontal_adjustment);
369 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
370 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
371 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
373 edit_hscrollbar.set_name ("EditorHScrollbar");
378 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
380 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
381 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
382 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
383 time_canvas_vbox.pack_start (*frames_ruler, false, false);
384 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
385 time_canvas_vbox.pack_start (time_canvas, true, true);
386 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
388 bbt_label.set_name ("EditorTimeButton");
389 bbt_label.set_size_request (-1, (int)timebar_height);
390 bbt_label.set_alignment (1.0, 0.5);
391 bbt_label.set_padding (5,0);
392 minsec_label.set_name ("EditorTimeButton");
393 minsec_label.set_size_request (-1, (int)timebar_height);
394 minsec_label.set_alignment (1.0, 0.5);
395 minsec_label.set_padding (5,0);
396 smpte_label.set_name ("EditorTimeButton");
397 smpte_label.set_size_request (-1, (int)timebar_height);
398 smpte_label.set_alignment (1.0, 0.5);
399 smpte_label.set_padding (5,0);
400 frame_label.set_name ("EditorTimeButton");
401 frame_label.set_size_request (-1, (int)timebar_height);
402 frame_label.set_alignment (1.0, 0.5);
403 frame_label.set_padding (5,0);
404 tempo_label.set_name ("EditorTimeButton");
405 tempo_label.set_size_request (-1, (int)timebar_height);
406 tempo_label.set_alignment (1.0, 0.5);
407 tempo_label.set_padding (5,0);
408 meter_label.set_name ("EditorTimeButton");
409 meter_label.set_size_request (-1, (int)timebar_height);
410 meter_label.set_alignment (1.0, 0.5);
411 meter_label.set_padding (5,0);
412 mark_label.set_name ("EditorTimeButton");
413 mark_label.set_size_request (-1, (int)timebar_height);
414 mark_label.set_alignment (1.0, 0.5);
415 mark_label.set_padding (5,0);
416 range_mark_label.set_name ("EditorTimeButton");
417 range_mark_label.set_size_request (-1, (int)timebar_height);
418 range_mark_label.set_alignment (1.0, 0.5);
419 range_mark_label.set_padding (5,0);
420 transport_mark_label.set_name ("EditorTimeButton");
421 transport_mark_label.set_size_request (-1, (int)timebar_height);
422 transport_mark_label.set_alignment (1.0, 0.5);
423 transport_mark_label.set_padding (5,0);
425 time_button_vbox.pack_start (minsec_label, false, false);
426 time_button_vbox.pack_start (smpte_label, false, false);
427 time_button_vbox.pack_start (frame_label, false, false);
428 time_button_vbox.pack_start (bbt_label, false, false);
429 time_button_vbox.pack_start (meter_label, false, false);
430 time_button_vbox.pack_start (tempo_label, false, false);
431 time_button_vbox.pack_start (mark_label, false, false);
433 time_button_event_box.add (time_button_vbox);
435 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
436 time_button_event_box.set_name ("TimebarLabelBase");
437 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
439 time_button_frame.add(time_button_event_box);
440 time_button_frame.property_shadow_type() = Gtk::SHADOW_OUT;
442 /* these enable us to have a dedicated window (for cursor setting, etc.)
443 for the canvas areas.
446 track_canvas_event_box.add (track_canvas);
448 time_canvas_event_box.add (time_canvas_vbox);
449 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
451 edit_packer.set_col_spacings (0);
452 edit_packer.set_row_spacings (0);
453 edit_packer.set_homogeneous (false);
454 edit_packer.set_border_width (0);
455 edit_packer.set_name ("EditorWindow");
457 edit_packer.attach (edit_vscrollbar, 0, 1, 1, 3, FILL, FILL|EXPAND, 0, 0);
459 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, FILL, 0, 0);
460 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
462 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
463 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
465 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
466 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
468 bottom_hbox.set_border_width (2);
469 bottom_hbox.set_spacing (3);
471 route_display_model = ListStore::create(route_display_columns);
472 route_list_display.set_model (route_display_model);
473 route_list_display.append_column (_("Show"), route_display_columns.visible);
474 route_list_display.append_column (_("Name"), route_display_columns.text);
475 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
476 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
477 route_list_display.set_headers_visible (true);
478 route_list_display.set_name ("TrackListDisplay");
479 route_list_display.get_selection()->set_mode (SELECTION_NONE);
480 route_list_display.set_reorderable (true);
481 route_list_display.set_size_request (100,-1);
483 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
484 route_list_visible_cell->property_activatable() = true;
485 route_list_visible_cell->property_radio() = false;
487 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
488 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
489 route_display_model->signal_rows_reordered().connect (mem_fun (*this, &Editor::track_list_reorder));
491 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
493 route_list_scroller.add (route_list_display);
494 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
496 group_model = ListStore::create(group_columns);
497 edit_group_display.set_model (group_model);
498 edit_group_display.append_column (_("Name"), group_columns.text);
499 edit_group_display.append_column (_("Active"), group_columns.is_active);
500 edit_group_display.append_column (_("Show"), group_columns.is_visible);
501 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
502 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
503 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
504 edit_group_display.get_column (0)->set_expand (true);
505 edit_group_display.get_column (1)->set_expand (false);
506 edit_group_display.get_column (2)->set_expand (false);
507 edit_group_display.set_headers_visible (true);
509 /* name is directly editable */
511 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
512 name_cell->property_editable() = true;
513 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
515 /* use checkbox for the active + visible columns */
517 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
518 active_cell->property_activatable() = true;
519 active_cell->property_radio() = false;
521 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
522 active_cell->property_activatable() = true;
523 active_cell->property_radio() = false;
525 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
527 edit_group_display.set_name ("EditGroupList");
528 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
529 edit_group_display.set_headers_visible (true);
530 edit_group_display.set_reorderable (false);
531 edit_group_display.set_rules_hint (true);
532 edit_group_display.set_size_request (75, -1);
534 edit_group_display_scroller.add (edit_group_display);
535 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
537 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
539 VBox* edit_group_display_packer = manage (new VBox());
540 HBox* edit_group_display_button_box = manage (new HBox());
541 edit_group_display_button_box->set_homogeneous (true);
543 Button* edit_group_add_button = manage (new Button ());
544 Button* edit_group_remove_button = manage (new Button ());
548 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
550 edit_group_add_button->add (*w);
552 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
554 edit_group_remove_button->add (*w);
556 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
557 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
559 edit_group_display_button_box->pack_start (*edit_group_add_button);
560 edit_group_display_button_box->pack_start (*edit_group_remove_button);
562 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
563 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
565 region_list_display.set_size_request (100, -1);
566 region_list_display.set_name ("RegionListDisplay");
568 region_list_model = TreeStore::create (region_list_columns);
569 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
570 region_list_model->set_sort_column (0, SORT_ASCENDING);
572 region_list_display.set_model (region_list_model);
573 region_list_display.append_column (_("Regions"), region_list_columns.name);
574 region_list_display.set_headers_visible (false);
576 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
578 TreeViewColumn* tv_col = region_list_display.get_column(0);
579 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
580 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
581 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
583 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
584 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
586 /* setup DnD handling */
588 list<TargetEntry> region_list_target_table;
590 region_list_target_table.push_back (TargetEntry ("text/plain"));
591 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
592 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
594 region_list_display.add_drop_targets (region_list_target_table);
595 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
597 region_list_scroller.add (region_list_display);
598 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
600 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
601 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
602 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
603 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
604 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
605 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
607 named_selection_scroller.add (named_selection_display);
608 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
610 named_selection_model = TreeStore::create (named_selection_columns);
611 named_selection_display.set_model (named_selection_model);
612 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
613 named_selection_display.set_headers_visible (false);
614 named_selection_display.set_size_request (100, -1);
615 named_selection_display.set_name ("NamedSelectionDisplay");
617 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
618 named_selection_display.set_size_request (100, -1);
619 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
620 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
621 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
625 snapshot_display_model = ListStore::create (snapshot_display_columns);
626 snapshot_display.set_model (snapshot_display_model);
627 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
628 snapshot_display.set_name ("SnapshotDisplay");
629 snapshot_display.set_size_request (75, -1);
630 snapshot_display.set_headers_visible (false);
631 snapshot_display.set_reorderable (false);
632 snapshot_display_scroller.add (snapshot_display);
633 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
635 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
636 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
640 nlabel = manage (new Label (_("Regions")));
641 nlabel->set_angle (-90);
642 the_notebook.append_page (region_list_scroller, *nlabel);
643 nlabel = manage (new Label (_("Tracks/Busses")));
644 nlabel->set_angle (-90);
645 the_notebook.append_page (route_list_scroller, *nlabel);
646 nlabel = manage (new Label (_("Snapshots")));
647 nlabel->set_angle (-90);
648 the_notebook.append_page (snapshot_display_scroller, *nlabel);
649 nlabel = manage (new Label (_("Edit Groups")));
650 nlabel->set_angle (-90);
651 the_notebook.append_page (*edit_group_display_packer, *nlabel);
652 nlabel = manage (new Label (_("Chunks")));
653 nlabel->set_angle (-90);
654 the_notebook.append_page (named_selection_scroller, *nlabel);
656 the_notebook.set_show_tabs (true);
657 the_notebook.set_scrollable (true);
658 the_notebook.popup_enable ();
659 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
661 post_maximal_editor_width = 0;
662 post_maximal_pane_position = 0;
663 edit_pane.pack1 (edit_packer, true, true);
664 edit_pane.pack2 (the_notebook, false, true);
666 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
668 top_hbox.pack_start (toolbar_frame, true, true);
670 HBox *hbox = manage (new HBox);
671 hbox->pack_start (edit_pane, true, true);
673 global_vpacker.pack_start (top_hbox, false, false);
674 global_vpacker.pack_start (*hbox, true, true);
676 global_hpacker.pack_start (global_vpacker, true, true);
678 set_name ("EditorWindow");
679 add_accel_group (ActionManager::ui_manager->get_accel_group());
681 status_bar_hpacker.show ();
683 vpacker.pack_end (status_bar_hpacker, false, false);
684 vpacker.pack_end (global_hpacker, true, true);
686 /* register actions now so that set_state() can find them and set toggles/checks etc */
690 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
693 _playlist_selector = new PlaylistSelector();
694 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
696 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
700 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
701 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
703 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
704 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
706 nudge_forward_button.set_name ("TransportButton");
707 nudge_backward_button.set_name ("TransportButton");
709 fade_context_menu.set_name ("ArdourContextMenu");
711 /* icons, titles, WM stuff */
713 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
714 Glib::RefPtr<Gdk::Pixbuf> icon;
716 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
717 window_icons.push_back (icon);
719 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
720 window_icons.push_back (icon);
722 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
723 window_icons.push_back (icon);
725 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
726 window_icons.push_back (icon);
728 if (!window_icons.empty()) {
729 set_icon_list (window_icons);
730 set_default_icon_list (window_icons);
733 WindowTitle title(Glib::get_application_name());
734 title += _("Editor");
735 set_title (title.get_string());
736 set_wmclass (X_("ardour_editor"), "Ardour");
739 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
741 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
742 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
744 /* allow external control surfaces/protocols to do various things */
746 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
747 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
748 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
749 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
751 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
752 Route::SyncOrderKeys.connect (mem_fun (*this, &Editor::sync_order_keys));
760 /* <CMT Additions> */
761 if(image_socket_listener)
763 if(image_socket_listener->is_connected())
765 image_socket_listener->close_connection() ;
768 delete image_socket_listener ;
769 image_socket_listener = 0 ;
771 /* </CMT Additions> */
775 Editor::add_toplevel_controls (Container& cont)
777 vpacker.pack_start (cont, false, false);
782 Editor::catch_vanishing_regionview (RegionView *rv)
784 /* note: the selection will take care of the vanishing
785 audioregionview by itself.
788 if (clicked_regionview == rv) {
789 clicked_regionview = 0;
792 if (entered_regionview == rv) {
793 set_entered_regionview (0);
798 Editor::set_entered_regionview (RegionView* rv)
800 if (rv == entered_regionview) {
804 if (entered_regionview) {
805 entered_regionview->exited ();
808 if ((entered_regionview = rv) != 0) {
809 entered_regionview->entered ();
814 Editor::set_entered_track (TimeAxisView* tav)
817 entered_track->exited ();
820 if ((entered_track = tav) != 0) {
821 entered_track->entered ();
826 Editor::show_window ()
831 /* now reset all audio_time_axis heights, because widgets might need
837 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
838 tv = (static_cast<TimeAxisView*>(*i));
844 Editor::tie_vertical_scrolling ()
846 double y1 = vertical_adjustment.get_value();
848 playhead_cursor->set_y_axis (y1);
849 edit_cursor->set_y_axis (y1);
851 logo_item->property_y() = y1;
854 controls_layout.get_vadjustment()->set_value (y1);
857 /* the way idle updates and immediate window flushing work on GTK-Quartz
858 requires that we force an immediate redraw right here. The controls
859 layout will do the same all by itself, as does the canvas widget, but
860 most of the time, the canvas itself hasn't updated itself because its
861 idle handler hasn't run. consequently, the call that its layout makes
862 to gdk_window_process_updates() finds nothing to do. here, we force
863 the update to happen, then request a flush of the new window state.
865 track_canvas.update_now ();
866 gdk_window_process_updates (GTK_LAYOUT(track_canvas.gobj())->bin_window, true);
871 Editor::instant_save ()
873 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
878 session->add_instant_xml(get_state(), session->path());
880 Config->add_instant_xml(get_state(), get_user_ardour_path());
885 Editor::edit_cursor_clock_changed()
887 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
888 edit_cursor->set_position (edit_cursor_clock.current_time());
894 Editor::zoom_adjustment_changed ()
900 double fpu = zoom_range_clock.current_duration() / canvas_width;
904 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
905 } else if (fpu > session->current_end_frame() / canvas_width) {
906 fpu = session->current_end_frame() / canvas_width;
907 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
914 Editor::control_scroll (float fraction)
916 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
922 double step = fraction * current_page_frames();
925 _control_scroll_target is an optional<T>
927 it acts like a pointer to an nframes_t, with
928 a operator conversion to boolean to check
929 that it has a value could possibly use
930 playhead_cursor->current_frame to store the
931 value and a boolean in the class to know
932 when it's out of date
935 if (!_control_scroll_target) {
936 _control_scroll_target = session->transport_frame();
937 _dragging_playhead = true;
940 if ((fraction < 0.0f) && (*_control_scroll_target < (nframes_t) fabs(step))) {
941 *_control_scroll_target = 0;
942 } else if ((fraction > 0.0f) && (max_frames - *_control_scroll_target < step)) {
943 *_control_scroll_target = max_frames - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
945 *_control_scroll_target += (nframes_t) floor (step);
948 /* move visuals, we'll catch up with it later */
950 playhead_cursor->set_position (*_control_scroll_target);
951 UpdateAllTransportClocks (*_control_scroll_target);
953 if (*_control_scroll_target > (current_page_frames() / 2)) {
954 /* try to center PH in window */
955 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
961 Now we do a timeout to actually bring the session to the right place
962 according to the playhead. This is to avoid reading disk buffers on every
963 call to control_scroll, which is driven by ScrollTimeline and therefore
964 probably by a control surface wheel which can generate lots of events.
966 /* cancel the existing timeout */
968 control_scroll_connection.disconnect ();
970 /* add the next timeout */
972 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
976 Editor::deferred_control_scroll (nframes_t target)
978 session->request_locate (*_control_scroll_target, session->transport_rolling());
979 // reset for next stream
980 _control_scroll_target = boost::none;
981 _dragging_playhead = false;
986 Editor::on_realize ()
988 Window::on_realize ();
993 Editor::start_scrolling ()
995 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
996 (mem_fun(*this, &Editor::update_current_screen));
1000 Editor::stop_scrolling ()
1002 scroll_connection.disconnect ();
1006 Editor::map_position_change (nframes_t frame)
1008 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1010 if (session == 0 || !_follow_playhead) {
1014 center_screen (frame);
1015 playhead_cursor->set_position (frame);
1019 Editor::center_screen (nframes_t frame)
1021 double page = canvas_width * frames_per_unit;
1023 /* if we're off the page, then scroll.
1026 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1027 center_screen_internal (frame, page);
1032 Editor::center_screen_internal (nframes_t frame, float page)
1037 frame -= (nframes_t) page;
1042 reset_x_origin (frame);
1046 Editor::handle_new_duration ()
1048 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1050 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1052 if (new_end > last_canvas_frame) {
1053 last_canvas_frame = new_end;
1054 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1055 reset_scrolling_region ();
1058 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1062 Editor::update_title_s (const string & snap_name)
1064 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1070 Editor::update_title ()
1072 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1075 bool dirty = session->dirty();
1077 string session_name;
1079 if (session->snap_name() != session->name()) {
1080 session_name = session->snap_name();
1082 session_name = session->name();
1086 session_name = "*" + session_name;
1089 WindowTitle title(session_name);
1090 title += Glib::get_application_name();
1091 set_title (title.get_string());
1096 Editor::connect_to_session (Session *t)
1100 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1103 /* catch up with the playhead */
1105 session->request_locate (playhead_cursor->current_frame);
1107 if (first_action_message) {
1108 first_action_message->hide();
1113 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1114 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1116 /* These signals can all be emitted by a non-GUI thread. Therefore the
1117 handlers for them must not attempt to directly interact with the GUI,
1118 but use Gtkmm2ext::UI::instance()->call_slot();
1121 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1122 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1123 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1124 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::handle_new_audio_region)));
1125 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed)));
1126 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1127 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1128 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1129 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1130 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1131 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1132 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1133 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1134 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1136 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1138 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1140 edit_groups_changed ();
1142 edit_cursor_clock.set_session (session);
1143 zoom_range_clock.set_session (session);
1144 _playlist_selector->set_session (session);
1145 nudge_clock.set_session (session);
1148 if (analysis_window != 0)
1149 analysis_window->set_session (session);
1152 Location* loc = session->locations()->auto_loop_location();
1154 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1155 if (loc->start() == loc->end()) {
1156 loc->set_end (loc->start() + 1);
1158 session->locations()->add (loc, false);
1159 session->set_auto_loop_location (loc);
1162 loc->set_name (_("Loop"));
1165 loc = session->locations()->auto_punch_location();
1167 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1168 if (loc->start() == loc->end()) {
1169 loc->set_end (loc->start() + 1);
1171 session->locations()->add (loc, false);
1172 session->set_auto_punch_location (loc);
1175 loc->set_name (_("Punch"));
1178 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1180 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1182 refresh_location_display ();
1183 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1184 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1185 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1186 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1187 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1190 sfbrowser->set_session (session);
1193 handle_new_duration ();
1195 redisplay_regions ();
1196 redisplay_named_selections ();
1197 redisplay_snapshots ();
1199 initial_route_list_display ();
1201 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1202 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1205 restore_ruler_visibility ();
1206 //tempo_map_changed (Change (0));
1207 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1211 /* don't show master bus in a new session */
1213 if (ARDOUR_UI::instance()->session_is_new ()) {
1215 TreeModel::Children rows = route_display_model->children();
1216 TreeModel::Children::iterator i;
1218 no_route_list_redisplay = true;
1220 for (i = rows.begin(); i != rows.end(); ++i) {
1221 TimeAxisView *tv = (*i)[route_display_columns.tv];
1222 AudioTimeAxisView *atv;
1224 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1225 if (atv->route()->master()) {
1226 route_list_display.get_selection()->unselect (i);
1231 no_route_list_redisplay = false;
1232 redisplay_route_list ();
1235 /* register for undo history */
1237 session->register_with_memento_command_factory(_id, this);
1241 Editor::build_cursors ()
1243 using namespace Gdk;
1245 Gdk::Color mbg ("#000000" ); /* Black */
1246 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1249 RefPtr<Bitmap> source, mask;
1250 source = Bitmap::create (mag_bits, mag_width, mag_height);
1251 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1252 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1255 Gdk::Color fbg ("#ffffff" );
1256 Gdk::Color ffg ("#000000" );
1259 RefPtr<Bitmap> source, mask;
1261 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1262 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1263 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1267 RefPtr<Bitmap> source, mask;
1268 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1269 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1270 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1273 grabber_cursor = new Gdk::Cursor (HAND2);
1274 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1275 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1276 selector_cursor = new Gdk::Cursor (XTERM);
1277 time_fx_cursor = new Gdk::Cursor (SIZING);
1278 wait_cursor = new Gdk::Cursor (WATCH);
1279 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1283 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1285 using namespace Menu_Helpers;
1286 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1289 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1293 MenuList& items (fade_context_menu.items());
1297 switch (item_type) {
1299 case FadeInHandleItem:
1300 if (arv->audio_region()->fade_in_active()) {
1301 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1303 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1306 items.push_back (SeparatorElem());
1308 if (Profile->get_sae()) {
1309 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1310 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1312 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1313 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1314 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1315 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1316 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1321 case FadeOutHandleItem:
1322 if (arv->audio_region()->fade_out_active()) {
1323 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1325 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1328 items.push_back (SeparatorElem());
1330 if (Profile->get_sae()) {
1331 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1332 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1334 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1335 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1336 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1337 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1338 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1343 fatal << _("programming error: ")
1344 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1349 fade_context_menu.popup (button, time);
1353 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes_t frame)
1355 using namespace Menu_Helpers;
1356 Menu* (Editor::*build_menu_function)(nframes_t);
1359 switch (item_type) {
1361 case RegionViewName:
1362 case RegionViewNameHighlight:
1363 if (with_selection) {
1364 build_menu_function = &Editor::build_track_selection_context_menu;
1366 build_menu_function = &Editor::build_track_region_context_menu;
1371 if (with_selection) {
1372 build_menu_function = &Editor::build_track_selection_context_menu;
1374 build_menu_function = &Editor::build_track_context_menu;
1378 case CrossfadeViewItem:
1379 build_menu_function = &Editor::build_track_crossfade_context_menu;
1383 if (clicked_audio_trackview->get_diskstream()) {
1384 build_menu_function = &Editor::build_track_context_menu;
1386 build_menu_function = &Editor::build_track_bus_context_menu;
1391 /* probably shouldn't happen but if it does, we don't care */
1395 menu = (this->*build_menu_function)(frame);
1396 menu->set_name ("ArdourContextMenu");
1398 /* now handle specific situations */
1400 switch (item_type) {
1402 case RegionViewName:
1403 case RegionViewNameHighlight:
1404 if (!with_selection) {
1405 if (region_edit_menu_split_item) {
1406 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1407 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, true);
1409 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, false);
1413 if (region_edit_menu_split_multichannel_item) {
1414 if (clicked_regionview && clicked_regionview->region().n_channels() > 1) {
1415 // GTK2FIX find the action, change its sensitivity
1416 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1418 // GTK2FIX see above
1419 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1428 case CrossfadeViewItem:
1435 /* probably shouldn't happen but if it does, we don't care */
1439 if (item_type != SelectionItem && clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1441 /* Bounce to disk */
1443 using namespace Menu_Helpers;
1444 MenuList& edit_items = menu->items();
1446 edit_items.push_back (SeparatorElem());
1448 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1449 case AudioTrack::NoFreeze:
1450 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1453 case AudioTrack::Frozen:
1454 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1457 case AudioTrack::UnFrozen:
1458 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1464 menu->popup (button, time);
1468 Editor::build_track_context_menu (nframes_t ignored)
1470 using namespace Menu_Helpers;
1472 MenuList& edit_items = track_context_menu.items();
1475 add_dstream_context_items (edit_items);
1476 return &track_context_menu;
1480 Editor::build_track_bus_context_menu (nframes_t ignored)
1482 using namespace Menu_Helpers;
1484 MenuList& edit_items = track_context_menu.items();
1487 add_bus_context_items (edit_items);
1488 return &track_context_menu;
1492 Editor::build_track_region_context_menu (nframes_t frame)
1494 using namespace Menu_Helpers;
1495 MenuList& edit_items = track_region_context_menu.items();
1498 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1501 boost::shared_ptr<Diskstream> ds;
1502 boost::shared_ptr<Playlist> pl;
1504 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1505 Playlist::RegionList* regions = pl->regions_at ((nframes_t) floor ( (double)frame * ds->speed()));
1506 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1507 add_region_context_items (atv->audio_view(), (*i), edit_items);
1513 add_dstream_context_items (edit_items);
1515 return &track_region_context_menu;
1519 Editor::build_track_crossfade_context_menu (nframes_t frame)
1521 using namespace Menu_Helpers;
1522 MenuList& edit_items = track_crossfade_context_menu.items();
1523 edit_items.clear ();
1525 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1528 boost::shared_ptr<Diskstream> ds;
1529 boost::shared_ptr<Playlist> pl;
1530 boost::shared_ptr<AudioPlaylist> apl;
1532 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1534 Playlist::RegionList* regions = pl->regions_at (frame);
1535 AudioPlaylist::Crossfades xfades;
1537 apl->crossfades_at (frame, xfades);
1539 bool many = xfades.size() > 1;
1541 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1542 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1545 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1546 add_region_context_items (atv->audio_view(), (*i), edit_items);
1553 add_dstream_context_items (edit_items);
1555 return &track_crossfade_context_menu;
1560 Editor::analyze_region_selection()
1562 if (analysis_window == 0) {
1563 analysis_window = new AnalysisWindow();
1566 analysis_window->set_session(session);
1568 analysis_window->show_all();
1571 analysis_window->set_regionmode();
1572 analysis_window->analyze();
1574 analysis_window->present();
1578 Editor::analyze_range_selection()
1580 if (analysis_window == 0) {
1581 analysis_window = new AnalysisWindow();
1584 analysis_window->set_session(session);
1586 analysis_window->show_all();
1589 analysis_window->set_rangemode();
1590 analysis_window->analyze();
1592 analysis_window->present();
1594 #endif /* FFT_ANALYSIS */
1599 Editor::build_track_selection_context_menu (nframes_t ignored)
1601 using namespace Menu_Helpers;
1602 MenuList& edit_items = track_selection_context_menu.items();
1603 edit_items.clear ();
1605 add_selection_context_items (edit_items);
1606 // edit_items.push_back (SeparatorElem());
1607 // add_dstream_context_items (edit_items);
1609 return &track_selection_context_menu;
1613 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1615 using namespace Menu_Helpers;
1616 Menu *xfade_menu = manage (new Menu);
1617 MenuList& items = xfade_menu->items();
1618 xfade_menu->set_name ("ArdourContextMenu");
1621 if (xfade->active()) {
1627 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1628 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1630 if (xfade->can_follow_overlap()) {
1632 if (xfade->following_overlap()) {
1633 str = _("Convert to short");
1635 str = _("Convert to full");
1638 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1642 str = xfade->out()->name();
1644 str += xfade->in()->name();
1646 str = _("Crossfade");
1649 edit_items.push_back (MenuElem (str, *xfade_menu));
1650 edit_items.push_back (SeparatorElem());
1654 Editor::xfade_edit_left_region ()
1656 if (clicked_crossfadeview) {
1657 clicked_crossfadeview->left_view.show_region_editor ();
1662 Editor::xfade_edit_right_region ()
1664 if (clicked_crossfadeview) {
1665 clicked_crossfadeview->right_view.show_region_editor ();
1670 Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region> region, Menu_Helpers::MenuList& edit_items)
1672 using namespace Menu_Helpers;
1673 Menu *region_menu = manage (new Menu);
1674 MenuList& items = region_menu->items();
1675 region_menu->set_name ("ArdourContextMenu");
1677 boost::shared_ptr<AudioRegion> ar;
1680 ar = boost::dynamic_pointer_cast<AudioRegion> (region);
1683 /* when this particular menu pops up, make the relevant region
1687 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr<Region>(region)));
1689 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1690 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1691 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1692 items.push_back (SeparatorElem());
1693 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1694 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1695 items.push_back (SeparatorElem());
1697 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1698 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1699 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1702 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1705 items.push_back (SeparatorElem());
1707 sigc::connection fooc;
1709 items.push_back (CheckMenuElem (_("Lock")));
1710 region_lock_item = static_cast<CheckMenuItem*>(&items.back());
1711 fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
1712 if (region->locked()) {
1714 region_lock_item->set_active();
1717 items.push_back (CheckMenuElem (_("Mute")));
1718 region_mute_item = static_cast<CheckMenuItem*>(&items.back());
1719 fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute));
1720 if (region->muted()) {
1722 region_mute_item->set_active();
1726 if (!Profile->get_sae()) {
1727 items.push_back (CheckMenuElem (_("Opaque")));
1728 region_opaque_item = static_cast<CheckMenuItem*>(&items.back());
1729 fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque));
1730 if (region->opaque()) {
1732 region_opaque_item->set_active();
1737 items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1738 if (region->at_natural_position()) {
1739 items.back().set_sensitive (false);
1742 items.push_back (SeparatorElem());
1746 RegionView* rv = sv->find_view (ar);
1747 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1749 if (!Profile->get_sae()) {
1750 items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1752 items.push_back (CheckMenuElem (_("Envelope Visible")));
1753 region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
1754 fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
1755 if (arv->envelope_visible()) {
1757 region_envelope_visible_item->set_active (true);
1761 items.push_back (CheckMenuElem (_("Envelope Active")));
1762 region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
1763 fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
1765 if (ar->envelope_active()) {
1767 region_envelope_active_item->set_active (true);
1771 items.push_back (SeparatorElem());
1774 if (ar->scale_amplitude() != 1.0f) {
1775 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1777 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1781 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1782 items.push_back (SeparatorElem());
1784 /* range related stuff */
1786 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
1787 items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)));
1788 items.push_back (SeparatorElem());
1792 Menu *nudge_menu = manage (new Menu());
1793 MenuList& nudge_items = nudge_menu->items();
1794 nudge_menu->set_name ("ArdourContextMenu");
1796 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1797 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1798 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1799 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1801 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1802 items.push_back (SeparatorElem());
1804 Menu *trim_menu = manage (new Menu);
1805 MenuList& trim_items = trim_menu->items();
1806 trim_menu->set_name ("ArdourContextMenu");
1808 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1809 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1811 items.push_back (MenuElem (_("Trim"), *trim_menu));
1812 items.push_back (SeparatorElem());
1814 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1815 region_edit_menu_split_item = &items.back();
1817 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1818 region_edit_menu_split_multichannel_item = &items.back();
1820 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1821 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1822 items.push_back (SeparatorElem());
1823 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1825 /* OK, stick the region submenu at the top of the list, and then add
1829 /* we have to hack up the region name because "_" has a special
1830 meaning for menu titles.
1833 string::size_type pos = 0;
1834 string menu_item_name = region->name();
1836 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1837 menu_item_name.replace (pos, 1, "__");
1841 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1842 edit_items.push_back (SeparatorElem());
1846 Editor::add_selection_context_items (Menu_Helpers::MenuList& items)
1848 using namespace Menu_Helpers;
1850 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1851 items.push_back (MenuElem (_("Loop range"), bind (mem_fun(*this, &Editor::set_loop_from_selection), true)));
1854 items.push_back (SeparatorElem());
1855 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1858 items.push_back (SeparatorElem());
1859 items.push_back (MenuElem (_("Extend Range to End of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1860 items.push_back (MenuElem (_("Extend Range to Start of Region"), bind (mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1862 items.push_back (SeparatorElem());
1863 items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1864 items.push_back (MenuElem (_("Convert to region in region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1866 items.push_back (SeparatorElem());
1867 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1869 items.push_back (SeparatorElem());
1870 items.push_back (MenuElem (_("Set loop from selection"), bind (mem_fun(*this, &Editor::set_loop_from_selection), false)));
1871 items.push_back (MenuElem (_("Set punch from selection"), mem_fun(*this, &Editor::set_punch_from_selection)));
1873 items.push_back (SeparatorElem());
1874 items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1875 items.push_back (SeparatorElem());
1876 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1877 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1878 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1879 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1880 items.push_back (SeparatorElem());
1881 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1882 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1886 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1888 using namespace Menu_Helpers;
1892 Menu *play_menu = manage (new Menu);
1893 MenuList& play_items = play_menu->items();
1894 play_menu->set_name ("ArdourContextMenu");
1896 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1897 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1898 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1899 play_items.push_back (SeparatorElem());
1900 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1902 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1906 Menu *select_menu = manage (new Menu);
1907 MenuList& select_items = select_menu->items();
1908 select_menu->set_name ("ArdourContextMenu");
1910 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1911 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1912 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1913 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1914 select_items.push_back (SeparatorElem());
1915 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1916 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1917 select_items.push_back (SeparatorElem());
1918 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1919 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1920 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1921 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1922 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1923 select_items.push_back (SeparatorElem());
1925 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1929 Menu *cutnpaste_menu = manage (new Menu);
1930 MenuList& cutnpaste_items = cutnpaste_menu->items();
1931 cutnpaste_menu->set_name ("ArdourContextMenu");
1933 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1934 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1935 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1936 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1938 cutnpaste_items.push_back (SeparatorElem());
1940 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1941 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1943 cutnpaste_items.push_back (SeparatorElem());
1945 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1947 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1949 /* Adding new material */
1951 edit_items.push_back (SeparatorElem());
1952 edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1953 edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1957 Menu *nudge_menu = manage (new Menu());
1958 MenuList& nudge_items = nudge_menu->items();
1959 nudge_menu->set_name ("ArdourContextMenu");
1961 edit_items.push_back (SeparatorElem());
1962 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1963 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1964 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1965 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1967 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1971 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1973 using namespace Menu_Helpers;
1977 Menu *play_menu = manage (new Menu);
1978 MenuList& play_items = play_menu->items();
1979 play_menu->set_name ("ArdourContextMenu");
1981 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1982 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1983 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1987 Menu *select_menu = manage (new Menu);
1988 MenuList& select_items = select_menu->items();
1989 select_menu->set_name ("ArdourContextMenu");
1991 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1992 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1993 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1994 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1995 select_items.push_back (SeparatorElem());
1996 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1997 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1998 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1999 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2001 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2005 Menu *cutnpaste_menu = manage (new Menu);
2006 MenuList& cutnpaste_items = cutnpaste_menu->items();
2007 cutnpaste_menu->set_name ("ArdourContextMenu");
2009 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2010 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2011 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2013 Menu *nudge_menu = manage (new Menu());
2014 MenuList& nudge_items = nudge_menu->items();
2015 nudge_menu->set_name ("ArdourContextMenu");
2017 edit_items.push_back (SeparatorElem());
2018 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2019 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2020 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2021 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2023 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2026 /* CURSOR SETTING AND MARKS AND STUFF */
2029 Editor::set_snap_to (SnapType st)
2032 string str = snap_type_strings[(int) st];
2034 if (str != snap_type_selector.get_active_text()) {
2035 snap_type_selector.set_active_text (str);
2040 switch (snap_type) {
2041 case SnapToAThirtysecondBeat:
2042 case SnapToASixteenthBeat:
2043 case SnapToAEighthBeat:
2044 case SnapToAQuarterBeat:
2045 case SnapToAThirdBeat:
2046 update_tempo_based_rulers ();
2054 Editor::set_snap_mode (SnapMode mode)
2057 string str = snap_mode_strings[(int)mode];
2059 if (str != snap_mode_selector.get_active_text ()) {
2060 snap_mode_selector.set_active_text (str);
2066 Editor::set_edit_point (EditPoint ep)
2069 string str = edit_point_strings[(int)ep];
2071 if (str != edit_point_selector.get_active_text ()) {
2072 edit_point_selector.set_active_text (str);
2079 Editor::set_state (const XMLNode& node)
2081 const XMLProperty* prop;
2083 int x, y, xoff, yoff;
2086 if ((prop = node.property ("id")) != 0) {
2087 _id = prop->value ();
2090 if ((geometry = find_named_node (node, "geometry")) == 0) {
2092 g.base_width = default_width;
2093 g.base_height = default_height;
2101 g.base_width = atoi(geometry->property("x_size")->value());
2102 g.base_height = atoi(geometry->property("y_size")->value());
2103 x = atoi(geometry->property("x_pos")->value());
2104 y = atoi(geometry->property("y_pos")->value());
2105 xoff = atoi(geometry->property("x_off")->value());
2106 yoff = atoi(geometry->property("y_off")->value());
2109 set_default_size (g.base_width, g.base_height);
2112 if (session && (prop = node.property ("playhead"))) {
2113 nframes_t pos = atol (prop->value().c_str());
2114 playhead_cursor->set_position (pos);
2116 playhead_cursor->set_position (0);
2118 /* reset_x_origin() doesn't work right here, since the old
2119 position may be zero already, and it does nothing in such
2124 horizontal_adjustment.set_value (0);
2127 if (session && (prop = node.property ("edit-cursor"))) {
2128 nframes_t pos = atol (prop->value().c_str());
2129 edit_cursor->set_position (pos);
2131 edit_cursor->set_position (0);
2134 if ((prop = node.property ("mixer-width"))) {
2135 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2138 if ((prop = node.property ("zoom-focus"))) {
2139 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2142 if ((prop = node.property ("zoom"))) {
2143 reset_zoom (PBD::atof (prop->value()));
2146 if ((prop = node.property ("snap-to"))) {
2147 set_snap_to ((SnapType) atoi (prop->value()));
2150 if ((prop = node.property ("snap-mode"))) {
2151 set_snap_mode ((SnapMode) atoi (prop->value()));
2154 if ((prop = node.property ("edit-point"))) {
2155 set_edit_point ((EditPoint) string_2_enum (prop->value(), _edit_point));
2158 if ((prop = node.property ("mouse-mode"))) {
2159 MouseMode m = str2mousemode(prop->value());
2160 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2161 set_mouse_mode (m, true);
2163 mouse_mode = MouseGain; /* lie, to force the mode switch */
2164 set_mouse_mode (MouseObject, true);
2167 if ((prop = node.property ("show-waveforms"))) {
2168 bool yn = (prop->value() == "yes");
2169 _show_waveforms = !yn;
2170 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2172 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2173 /* do it twice to force the change */
2174 tact->set_active (!yn);
2175 tact->set_active (yn);
2179 if ((prop = node.property ("show-waveforms-recording"))) {
2180 bool yn = (prop->value() == "yes");
2181 _show_waveforms_recording = !yn;
2182 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2184 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2185 /* do it twice to force the change */
2186 tact->set_active (!yn);
2187 tact->set_active (yn);
2191 if ((prop = node.property ("show-measures"))) {
2192 bool yn = (prop->value() == "yes");
2193 _show_measures = !yn;
2194 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2196 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2197 /* do it twice to force the change */
2198 tact->set_active (!yn);
2199 tact->set_active (yn);
2203 if ((prop = node.property ("follow-playhead"))) {
2204 bool yn = (prop->value() == "yes");
2205 set_follow_playhead (yn);
2206 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2208 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2209 if (tact->get_active() != yn) {
2210 tact->set_active (yn);
2215 if ((prop = node.property ("region-list-sort-type"))) {
2216 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2217 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2220 if ((prop = node.property ("xfades-visible"))) {
2221 bool yn = (prop->value() == "yes");
2222 _xfade_visibility = !yn;
2223 // set_xfade_visibility (yn);
2226 if ((prop = node.property ("show-editor-mixer"))) {
2228 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2231 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2232 bool yn = (prop->value() == X_("yes"));
2234 /* do it twice to force the change */
2236 tact->set_active (!yn);
2237 tact->set_active (yn);
2246 Editor::get_state ()
2248 XMLNode* node = new XMLNode ("Editor");
2251 _id.print (buf, sizeof (buf));
2252 node->add_property ("id", buf);
2254 if (is_realized()) {
2255 Glib::RefPtr<Gdk::Window> win = get_window();
2257 int x, y, xoff, yoff, width, height;
2258 win->get_root_origin(x, y);
2259 win->get_position(xoff, yoff);
2260 win->get_size(width, height);
2262 XMLNode* geometry = new XMLNode ("geometry");
2264 snprintf(buf, sizeof(buf), "%d", width);
2265 geometry->add_property("x_size", string(buf));
2266 snprintf(buf, sizeof(buf), "%d", height);
2267 geometry->add_property("y_size", string(buf));
2268 snprintf(buf, sizeof(buf), "%d", x);
2269 geometry->add_property("x_pos", string(buf));
2270 snprintf(buf, sizeof(buf), "%d", y);
2271 geometry->add_property("y_pos", string(buf));
2272 snprintf(buf, sizeof(buf), "%d", xoff);
2273 geometry->add_property("x_off", string(buf));
2274 snprintf(buf, sizeof(buf), "%d", yoff);
2275 geometry->add_property("y_off", string(buf));
2276 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2277 geometry->add_property("edit_pane_pos", string(buf));
2279 node->add_child_nocopy (*geometry);
2282 maybe_add_mixer_strip_width (*node);
2284 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2285 node->add_property ("zoom-focus", buf);
2286 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2287 node->add_property ("zoom", buf);
2288 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2289 node->add_property ("snap-to", buf);
2290 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2291 node->add_property ("snap-mode", buf);
2293 node->add_property ("edit-point", enum_2_string (_edit_point));
2295 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2296 node->add_property ("playhead", buf);
2297 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2298 node->add_property ("edit-cursor", buf);
2300 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2301 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2302 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2303 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2304 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2305 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2306 node->add_property ("mouse-mode", enum2str(mouse_mode));
2308 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2310 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2311 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2320 Editor::trackview_by_y_position (double y)
2322 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2326 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2335 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2337 Location* before = 0;
2338 Location* after = 0;
2344 const nframes64_t one_second = session->frame_rate();
2345 const nframes64_t one_minute = session->frame_rate() * 60;
2346 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2347 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2348 nframes64_t presnap = start;
2350 switch (snap_type) {
2356 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2358 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2362 case SnapToSMPTEFrame:
2363 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2364 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2366 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2370 case SnapToSMPTESeconds:
2371 if (session->smpte_offset_negative())
2373 start += session->smpte_offset ();
2375 start -= session->smpte_offset ();
2377 if (start % one_smpte_second > one_smpte_second / 2) {
2378 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2380 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2383 if (session->smpte_offset_negative())
2385 start -= session->smpte_offset ();
2387 start += session->smpte_offset ();
2391 case SnapToSMPTEMinutes:
2392 if (session->smpte_offset_negative())
2394 start += session->smpte_offset ();
2396 start -= session->smpte_offset ();
2398 if (start % one_smpte_minute > one_smpte_minute / 2) {
2399 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2401 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2403 if (session->smpte_offset_negative())
2405 start -= session->smpte_offset ();
2407 start += session->smpte_offset ();
2412 if (start % one_second > one_second / 2) {
2413 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2415 start = (nframes_t) floor ((double) start / one_second) * one_second;
2420 if (start % one_minute > one_minute / 2) {
2421 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2423 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2428 start = session->tempo_map().round_to_bar (start, direction);
2432 start = session->tempo_map().round_to_beat (start, direction);
2435 case SnapToAThirtysecondBeat:
2436 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2439 case SnapToASixteenthBeat:
2440 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2443 case SnapToAEighthBeat:
2444 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2447 case SnapToAQuarterBeat:
2448 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2451 case SnapToAThirdBeat:
2452 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2455 case SnapToEditCursor:
2456 start = get_preferred_edit_position ();
2464 before = session->locations()->first_location_before (start);
2465 after = session->locations()->first_location_after (start);
2467 if (direction < 0) {
2469 start = before->start();
2473 } else if (direction > 0) {
2475 start = after->start();
2477 start = session->current_end_frame();
2482 /* find nearest of the two */
2483 if ((start - before->start()) < (after->start() - start)) {
2484 start = before->start();
2486 start = after->start();
2489 start = before->start();
2492 start = after->start();
2499 case SnapToRegionStart:
2500 case SnapToRegionEnd:
2501 case SnapToRegionSync:
2502 case SnapToRegionBoundary:
2503 if (!region_boundary_cache.empty()) {
2504 vector<nframes_t>::iterator i;
2506 if (direction > 0) {
2507 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2509 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2512 if (i != region_boundary_cache.end()) {
2515 start = region_boundary_cache.back();
2521 switch (snap_mode) {
2527 if (presnap > start) {
2528 if (presnap > (start + unit_to_frame(snap_threshold))) {
2532 } else if (presnap < start) {
2533 if (presnap < (start - unit_to_frame(snap_threshold))) {
2545 Editor::setup_toolbar ()
2549 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2552 /* Mode Buttons (tool selection) */
2554 vector<ToggleButton *> mouse_mode_buttons;
2556 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2557 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2558 mouse_mode_buttons.push_back (&mouse_move_button);
2559 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2560 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2561 mouse_mode_buttons.push_back (&mouse_select_button);
2562 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2563 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2564 mouse_mode_buttons.push_back (&mouse_gain_button);
2565 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2566 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2567 mouse_mode_buttons.push_back (&mouse_zoom_button);
2568 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2569 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2570 mouse_mode_buttons.push_back (&mouse_timefx_button);
2571 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2572 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2573 mouse_mode_buttons.push_back (&mouse_audition_button);
2575 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2577 HBox* mode_box = manage(new HBox);
2578 mode_box->set_border_width (2);
2579 mode_box->set_spacing(4);
2580 mouse_mode_button_box.set_spacing(1);
2581 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2582 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2583 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2584 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2585 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2586 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2587 mouse_mode_button_box.set_homogeneous(true);
2589 vector<string> edit_mode_strings;
2590 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2591 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2593 edit_mode_selector.set_name ("EditModeSelector");
2594 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2595 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2596 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2598 mode_box->pack_start(edit_mode_selector);
2599 mode_box->pack_start(mouse_mode_button_box);
2601 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2602 mouse_mode_tearoff->set_name ("MouseModeBase");
2604 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2605 &mouse_mode_tearoff->tearoff_window()));
2606 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2607 &mouse_mode_tearoff->tearoff_window(), 1));
2608 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2609 &mouse_mode_tearoff->tearoff_window()));
2610 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2611 &mouse_mode_tearoff->tearoff_window(), 1));
2613 mouse_move_button.set_name ("MouseModeButton");
2614 mouse_select_button.set_name ("MouseModeButton");
2615 mouse_gain_button.set_name ("MouseModeButton");
2616 mouse_zoom_button.set_name ("MouseModeButton");
2617 mouse_timefx_button.set_name ("MouseModeButton");
2618 mouse_audition_button.set_name ("MouseModeButton");
2620 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2621 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2622 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2623 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2624 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2625 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2627 mouse_move_button.unset_flags (CAN_FOCUS);
2628 mouse_select_button.unset_flags (CAN_FOCUS);
2629 mouse_gain_button.unset_flags (CAN_FOCUS);
2630 mouse_zoom_button.unset_flags (CAN_FOCUS);
2631 mouse_timefx_button.unset_flags (CAN_FOCUS);
2632 mouse_audition_button.unset_flags (CAN_FOCUS);
2634 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2635 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2637 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2638 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2639 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2640 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2641 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2643 // mouse_move_button.set_active (true);
2648 zoom_box.set_spacing (1);
2649 zoom_box.set_border_width (2);
2651 zoom_in_button.set_name ("EditorTimeButton");
2652 zoom_in_button.set_size_request(-1,16);
2653 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2654 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2655 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2657 zoom_out_button.set_name ("EditorTimeButton");
2658 zoom_out_button.set_size_request(-1,16);
2659 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2660 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2661 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2663 zoom_out_full_button.set_name ("EditorTimeButton");
2664 zoom_out_full_button.set_size_request(-1,16);
2665 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2666 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2667 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2669 zoom_focus_selector.set_name ("ZoomFocusSelector");
2670 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edit Cursor", FUDGE, 0);
2671 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2672 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2673 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2675 zoom_box.pack_start (zoom_focus_selector, true, true);
2676 zoom_box.pack_start (zoom_out_button, false, false);
2677 zoom_box.pack_start (zoom_in_button, false, false);
2678 zoom_box.pack_start (zoom_out_full_button, false, false);
2680 /* Edit Cursor / Snap */
2682 snap_box.set_spacing (1);
2683 snap_box.set_border_width (2);
2685 snap_type_selector.set_name ("SnapTypeSelector");
2686 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2687 set_popdown_strings (snap_type_selector, snap_type_strings);
2688 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2689 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Snap/Grid Units"));
2691 snap_mode_selector.set_name ("SnapModeSelector");
2692 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2693 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2694 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2695 ARDOUR_UI::instance()->tooltips().set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2697 edit_point_selector.set_name ("SnapModeSelector");
2698 Gtkmm2ext::set_size_request_to_display_given_text (edit_point_selector, "Playhead", 2+FUDGE, 10);
2699 set_popdown_strings (edit_point_selector, edit_point_strings);
2700 edit_point_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_point_selection_done));
2701 ARDOUR_UI::instance()->tooltips().set_tip (edit_point_selector, _("Edit point"));
2703 snap_box.pack_start (edit_cursor_clock, false, false);
2704 snap_box.pack_start (snap_mode_selector, false, false);
2705 snap_box.pack_start (snap_type_selector, false, false);
2706 snap_box.pack_start (edit_point_selector, false, false);
2710 HBox *nudge_box = manage (new HBox);
2711 nudge_box->set_spacing(1);
2712 nudge_box->set_border_width (2);
2714 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2715 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2717 nudge_box->pack_start (nudge_backward_button, false, false);
2718 nudge_box->pack_start (nudge_forward_button, false, false);
2719 nudge_box->pack_start (nudge_clock, false, false);
2722 /* Pack everything in... */
2724 HBox* hbox = new HBox;
2725 hbox->set_spacing(10);
2727 tools_tearoff = new TearOff (*hbox);
2728 tools_tearoff->set_name ("MouseModeBase");
2730 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2731 &tools_tearoff->tearoff_window()));
2732 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2733 &tools_tearoff->tearoff_window(), 0));
2734 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2735 &tools_tearoff->tearoff_window()));
2736 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2737 &tools_tearoff->tearoff_window(), 0));
2739 toolbar_hbox.set_spacing (10);
2740 toolbar_hbox.set_border_width (1);
2742 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2743 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2746 hbox->pack_start (snap_box, false, false);
2747 // hbox->pack_start (zoom_box, false, false);
2748 hbox->pack_start (*nudge_box, false, false);
2752 toolbar_base.set_name ("ToolBarBase");
2753 toolbar_base.add (toolbar_hbox);
2755 toolbar_frame.set_shadow_type (SHADOW_OUT);
2756 toolbar_frame.set_name ("BaseFrame");
2757 toolbar_frame.add (toolbar_base);
2761 Editor::convert_drop_to_paths (vector<ustring>& paths,
2762 const RefPtr<Gdk::DragContext>& context,
2765 const SelectionData& data,
2774 vector<ustring> uris = data.get_uris();
2778 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2779 are actually URI lists. So do it by hand.
2782 if (data.get_target() != "text/plain") {
2786 /* Parse the "uri-list" format that Nautilus provides,
2787 where each pathname is delimited by \r\n
2790 const char* p = data.get_text().c_str();
2797 while (g_ascii_isspace (*p))
2801 while (*q && (*q != '\n') && (*q != '\r'))
2807 while (q > p && g_ascii_isspace (*q))
2812 uris.push_back (ustring (p, q - p + 1));
2816 p = strchr (p, '\n');
2826 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2828 if ((*i).substr (0,7) == "file://") {
2832 PBD::url_decode (p);
2834 // scan forward past three slashes
2836 ustring::size_type slashcnt = 0;
2837 ustring::size_type n = 0;
2838 ustring::iterator x = p.begin();
2840 while (slashcnt < 3 && x != p.end()) {
2843 } else if (slashcnt == 3) {
2850 if (slashcnt != 3 || x == p.end()) {
2851 error << _("malformed URL passed to drag-n-drop code") << endmsg;
2855 paths.push_back (p.substr (n - 1));
2863 Editor::new_tempo_section ()
2869 Editor::map_transport_state ()
2871 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2873 if (session->transport_stopped()) {
2874 have_pending_keyboard_selection = false;
2877 update_loop_range_view (true);
2882 Editor::State::State ()
2884 selection = new Selection;
2887 Editor::State::~State ()
2893 Editor::get_memento () const
2895 State *state = new State;
2897 store_state (*state);
2898 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2902 Editor::store_state (State& state) const
2904 *state.selection = *selection;
2908 Editor::restore_state (State *state)
2910 if (*selection == *state->selection) {
2914 *selection = *state->selection;
2915 time_selection_changed ();
2916 region_selection_changed ();
2918 /* XXX other selection change handlers? */
2922 Editor::begin_reversible_command (string name)
2925 // before = &get_state();
2926 session->begin_reversible_command (name);
2931 Editor::commit_reversible_command ()
2934 // session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2935 session->commit_reversible_command ();
2940 Editor::set_edit_group_solo (Route& route, bool yn)
2942 RouteGroup *edit_group;
2944 if ((edit_group = route.edit_group()) != 0) {
2945 edit_group->apply (&Route::set_solo, yn, this);
2947 route.set_solo (yn, this);
2952 Editor::set_edit_group_mute (Route& route, bool yn)
2954 RouteGroup *edit_group = 0;
2956 if ((edit_group == route.edit_group()) != 0) {
2957 edit_group->apply (&Route::set_mute, yn, this);
2959 route.set_mute (yn, this);
2964 Editor::history_changed ()
2968 if (undo_action && session) {
2969 if (session->undo_depth() == 0) {
2972 label = string_compose(_("Undo (%1)"), session->next_undo());
2974 undo_action->property_label() = label;
2977 if (redo_action && session) {
2978 if (session->redo_depth() == 0) {
2981 label = string_compose(_("Redo (%1)"), session->next_redo());
2983 redo_action->property_label() = label;
2988 Editor::duplicate_dialog (bool dup_region)
2990 if (selection->regions.empty() && (selection->time.length() == 0)) {
2994 ArdourDialog win ("duplicate dialog");
2995 Label label (_("Duplicate how many times?"));
2996 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
2997 SpinButton spinner (adjustment);
2999 win.get_vbox()->set_spacing (12);
3000 win.get_vbox()->pack_start (label);
3002 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3003 place, visually. so do this by hand.
3006 win.get_vbox()->pack_start (spinner);
3007 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3012 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3013 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3015 win.set_position (WIN_POS_MOUSE);
3017 spinner.grab_focus ();
3019 switch (win.run ()) {
3020 case RESPONSE_ACCEPT:
3026 float times = adjustment.get_value();
3028 if (!selection->regions.empty()) {
3029 duplicate_some_regions (selection->regions, times);
3031 duplicate_selection (times);
3036 Editor::show_verbose_canvas_cursor ()
3038 verbose_canvas_cursor->raise_to_top();
3039 verbose_canvas_cursor->show();
3040 verbose_cursor_visible = true;
3044 Editor::hide_verbose_canvas_cursor ()
3046 verbose_canvas_cursor->hide();
3047 verbose_cursor_visible = false;
3051 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3053 /* XXX get origin of canvas relative to root window,
3054 add x and y and check compared to gdk_screen_{width,height}
3056 verbose_canvas_cursor->property_text() = txt.c_str();
3057 verbose_canvas_cursor->property_x() = x;
3058 verbose_canvas_cursor->property_y() = y;
3062 Editor::set_verbose_canvas_cursor_text (const string & txt)
3064 verbose_canvas_cursor->property_text() = txt.c_str();
3068 Editor::edit_mode_selection_done ()
3074 string choice = edit_mode_selector.get_active_text();
3075 EditMode mode = Slide;
3077 if (choice == _("Splice Edit")) {
3079 } else if (choice == _("Slide Edit")) {
3083 Config->set_edit_mode (mode);
3087 Editor::snap_type_selection_done ()
3089 string choice = snap_type_selector.get_active_text();
3090 SnapType snaptype = SnapToFrame;
3092 if (choice == _("Beats/3")) {
3093 snaptype = SnapToAThirdBeat;
3094 } else if (choice == _("Beats/4")) {
3095 snaptype = SnapToAQuarterBeat;
3096 } else if (choice == _("Beats/8")) {
3097 snaptype = SnapToAEighthBeat;
3098 } else if (choice == _("Beats/16")) {
3099 snaptype = SnapToASixteenthBeat;
3100 } else if (choice == _("Beats/32")) {
3101 snaptype = SnapToAThirtysecondBeat;
3102 } else if (choice == _("Beats")) {
3103 snaptype = SnapToBeat;
3104 } else if (choice == _("Bars")) {
3105 snaptype = SnapToBar;
3106 } else if (choice == _("Marks")) {
3107 snaptype = SnapToMark;
3108 } else if (choice == _("Edit Cursor")) {
3109 snaptype = SnapToEditCursor;
3110 } else if (choice == _("Region starts")) {
3111 snaptype = SnapToRegionStart;
3112 } else if (choice == _("Region ends")) {
3113 snaptype = SnapToRegionEnd;
3114 } else if (choice == _("Region bounds")) {
3115 snaptype = SnapToRegionBoundary;
3116 } else if (choice == _("Region syncs")) {
3117 snaptype = SnapToRegionSync;
3118 } else if (choice == _("CD Frames")) {
3119 snaptype = SnapToCDFrame;
3120 } else if (choice == _("SMPTE Frames")) {
3121 snaptype = SnapToSMPTEFrame;
3122 } else if (choice == _("SMPTE Seconds")) {
3123 snaptype = SnapToSMPTESeconds;
3124 } else if (choice == _("SMPTE Minutes")) {
3125 snaptype = SnapToSMPTEMinutes;
3126 } else if (choice == _("Seconds")) {
3127 snaptype = SnapToSeconds;
3128 } else if (choice == _("Minutes")) {
3129 snaptype = SnapToMinutes;
3130 } else if (choice == _("None")) {
3131 snaptype = SnapToFrame;
3134 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3136 ract->set_active ();
3141 Editor::snap_mode_selection_done ()
3143 string choice = snap_mode_selector.get_active_text();
3144 SnapMode mode = SnapNormal;
3146 if (choice == _("Normal")) {
3148 } else if (choice == _("Magnetic")) {
3149 mode = SnapMagnetic;
3152 RefPtr<RadioAction> ract = snap_mode_action (mode);
3155 ract->set_active (true);
3160 Editor::edit_point_selection_done ()
3162 string choice = edit_point_selector.get_active_text();
3163 EditPoint ep = EditAtSelectedMarker;
3165 if (choice == _("Marker")) {
3166 _edit_point = EditAtSelectedMarker;
3167 } else if (choice == _("Playhead")) {
3168 _edit_point = EditAtPlayhead;
3170 _edit_point = EditAtMouse;
3173 RefPtr<RadioAction> ract = edit_point_action (ep);
3176 ract->set_active (true);
3181 Editor::zoom_focus_selection_done ()
3183 string choice = zoom_focus_selector.get_active_text();
3184 ZoomFocus focus_type = ZoomFocusLeft;
3186 if (choice == _("Left")) {
3187 focus_type = ZoomFocusLeft;
3188 } else if (choice == _("Right")) {
3189 focus_type = ZoomFocusRight;
3190 } else if (choice == _("Center")) {
3191 focus_type = ZoomFocusCenter;
3192 } else if (choice == _("Playhead")) {
3193 focus_type = ZoomFocusPlayhead;
3194 } else if (choice == _("Mouse")) {
3195 focus_type = ZoomFocusMouse;
3196 } else if (choice == _("Edit Cursor")) {
3197 focus_type = ZoomFocusEdit;
3200 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3203 ract->set_active ();
3208 Editor::edit_controls_button_release (GdkEventButton* ev)
3210 if (Keyboard::is_context_menu_event (ev)) {
3211 ARDOUR_UI::instance()->add_route (this);
3217 Editor::mouse_select_button_release (GdkEventButton* ev)
3219 /* this handles just right-clicks */
3221 if (ev->button != 3) {
3228 Editor::TrackViewList *
3229 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3232 TrackViewList::iterator i;
3234 v = new TrackViewList;
3236 if (track == 0 && group == 0) {
3240 for (i = track_views.begin(); i != track_views.end (); ++i) {
3244 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3246 /* just the view for this track
3249 v->push_back (track);
3253 /* views for all tracks in the edit group */
3255 for (i = track_views.begin(); i != track_views.end (); ++i) {
3257 if (group == 0 || (*i)->edit_group() == group) {
3267 Editor::set_zoom_focus (ZoomFocus f)
3269 string str = zoom_focus_strings[(int)f];
3271 if (str != zoom_focus_selector.get_active_text()) {
3272 zoom_focus_selector.set_active_text (str);
3275 if (zoom_focus != f) {
3278 ZoomFocusChanged (); /* EMIT_SIGNAL */
3285 Editor::ensure_float (Window& win)
3287 win.set_transient_for (*this);
3291 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3293 /* recover or initialize pane positions. do this here rather than earlier because
3294 we don't want the positions to change the child allocations, which they seem to do.
3300 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3302 static int32_t done;
3305 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3306 width = default_width;
3307 height = default_height;
3309 width = atoi(geometry->property("x_size")->value());
3310 height = atoi(geometry->property("y_size")->value());
3313 if (which == static_cast<Paned*> (&edit_pane)) {
3319 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3320 /* initial allocation is 90% to canvas, 10% to notebook */
3321 pos = (int) floor (alloc.get_width() * 0.90f);
3322 snprintf (buf, sizeof(buf), "%d", pos);
3324 pos = atoi (prop->value());
3327 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3328 edit_pane.set_position (pos);
3329 pre_maximal_pane_position = pos;
3335 Editor::detach_tearoff (Box* b, Window* w)
3337 if (tools_tearoff->torn_off() &&
3338 mouse_mode_tearoff->torn_off()) {
3339 top_hbox.remove (toolbar_frame);
3344 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3346 if (toolbar_frame.get_parent() == 0) {
3347 top_hbox.pack_end (toolbar_frame);
3352 Editor::set_show_measures (bool yn)
3354 if (_show_measures != yn) {
3357 if ((_show_measures = yn) == true) {
3365 Editor::toggle_follow_playhead ()
3367 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3369 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3370 set_follow_playhead (tact->get_active());
3375 Editor::set_follow_playhead (bool yn)
3377 if (_follow_playhead != yn) {
3378 if ((_follow_playhead = yn) == true) {
3380 update_current_screen ();
3387 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3389 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3391 xfade->set_active (!xfade->active());
3396 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3398 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3400 xfade->set_follow_overlap (!xfade->following_overlap());
3405 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3407 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3413 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3417 switch (cew.run ()) {
3418 case RESPONSE_ACCEPT:
3425 xfade->StateChanged (Change (~0));
3429 Editor::playlist_selector () const
3431 return *_playlist_selector;
3435 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3439 ret = nudge_clock.current_duration (pos);
3440 next = ret + 1; /* XXXX fix me */
3446 Editor::end_location_changed (Location* location)
3448 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3449 reset_scrolling_region ();
3453 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3455 ArdourDialog dialog ("playlist deletion dialog");
3456 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3457 "If left alone, no audio files used by it will be cleaned.\n"
3458 "If deleted, audio files used by it alone by will cleaned."),
3461 dialog.set_position (WIN_POS_CENTER);
3462 dialog.get_vbox()->pack_start (label);
3466 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3467 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3468 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3470 switch (dialog.run ()) {
3471 case RESPONSE_ACCEPT:
3472 /* delete the playlist */
3476 case RESPONSE_REJECT:
3477 /* keep the playlist */
3489 Editor::audio_region_selection_covers (nframes_t where)
3491 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3492 if ((*a)->region()->covers (where)) {
3501 Editor::prepare_for_cleanup ()
3503 cut_buffer->clear_regions ();
3504 cut_buffer->clear_playlists ();
3506 selection->clear_regions ();
3507 selection->clear_playlists ();
3511 Editor::transport_loop_location()
3514 return session->locations()->auto_loop_location();
3521 Editor::transport_punch_location()
3524 return session->locations()->auto_punch_location();
3531 Editor::control_layout_scroll (GdkEventScroll* ev)
3533 switch (ev->direction) {
3535 scroll_tracks_up_line ();
3539 case GDK_SCROLL_DOWN:
3540 scroll_tracks_down_line ();
3544 /* no left/right handling yet */
3552 /** A new snapshot has been selected.
3555 Editor::snapshot_display_selection_changed ()
3557 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3559 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3561 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3563 if (snap_name.length() == 0) {
3567 if (session->snap_name() == snap_name) {
3571 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3576 Editor::snapshot_display_button_press (GdkEventButton* ev)
3578 if (ev->button == 3) {
3579 /* Right-click on the snapshot list. Work out which snapshot it
3581 Gtk::TreeModel::Path path;
3582 Gtk::TreeViewColumn* col;
3585 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3586 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3588 Gtk::TreeModel::Row row = *iter;
3589 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3598 /** Pop up the snapshot display context menu.
3599 * @param button Button used to open the menu.
3600 * @param time Menu open time.
3601 * @snapshot_name Name of the snapshot that the menu click was over.
3605 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3607 using namespace Menu_Helpers;
3609 MenuList& items (snapshot_context_menu.items());
3612 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3614 items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)));
3615 if (!modification_allowed) {
3616 items.back().set_sensitive (false);
3619 items.push_back (MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)));
3620 if (!modification_allowed) {
3621 items.back().set_sensitive (false);
3624 snapshot_context_menu.popup (button, time);
3628 Editor::rename_snapshot (Glib::ustring old_name)
3630 ArdourPrompter prompter(true);
3634 prompter.set_name ("Prompter");
3635 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3636 prompter.set_prompt (_("New name of snapshot"));
3637 prompter.set_initial_text (old_name);
3639 if (prompter.run() == RESPONSE_ACCEPT) {
3640 prompter.get_result (new_name);
3641 if (new_name.length()) {
3642 session->rename_state (old_name, new_name);
3643 redisplay_snapshots ();
3650 Editor::remove_snapshot (Glib::ustring name)
3652 vector<string> choices;
3654 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3656 choices.push_back (_("No, do nothing."));
3657 choices.push_back (_("Yes, remove it."));
3659 Gtkmm2ext::Choice prompter (prompt, choices);
3661 if (prompter.run () == 1) {
3662 session->remove_state (name);
3663 redisplay_snapshots ();
3668 Editor::redisplay_snapshots ()
3674 vector<string*>* states;
3676 if ((states = session->possible_states()) == 0) {
3680 snapshot_display_model->clear ();
3682 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
3683 string statename = *(*i);
3684 TreeModel::Row row = *(snapshot_display_model->append());
3686 /* this lingers on in case we ever want to change the visible
3687 name of the snapshot.
3690 string display_name;
3691 display_name = statename;
3693 if (statename == session->snap_name()) {
3694 snapshot_display.get_selection()->select(row);
3697 row[snapshot_display_columns.visible_name] = display_name;
3698 row[snapshot_display_columns.real_name] = statename;
3705 Editor::session_state_saved (string snap_name)
3707 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3708 redisplay_snapshots ();
3712 Editor::maximise_editing_space ()
3714 initial_ruler_update_required = true;
3716 mouse_mode_tearoff->set_visible (false);
3717 tools_tearoff->set_visible (false);
3719 pre_maximal_pane_position = edit_pane.get_position();
3720 pre_maximal_editor_width = this->get_width();
3722 if(post_maximal_pane_position == 0) {
3723 post_maximal_pane_position = edit_pane.get_width();
3728 if(post_maximal_editor_width) {
3729 edit_pane.set_position (post_maximal_pane_position -
3730 abs(post_maximal_editor_width - pre_maximal_editor_width));
3732 edit_pane.set_position (post_maximal_pane_position);
3737 Editor::restore_editing_space ()
3739 initial_ruler_update_required = true;
3741 // user changed width of pane during fullscreen
3742 if(post_maximal_pane_position != edit_pane.get_position()) {
3743 post_maximal_pane_position = edit_pane.get_position();
3748 mouse_mode_tearoff->set_visible (true);
3749 tools_tearoff->set_visible (true);
3750 post_maximal_editor_width = this->get_width();
3753 edit_pane.set_position (
3754 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3759 * Make new playlists for a given track and also any others that belong
3760 * to the same active edit group.
3765 Editor::new_playlists (TimeAxisView* v)
3767 begin_reversible_command (_("new playlists"));
3768 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3769 commit_reversible_command ();
3774 * Use a copy of the current playlist for a given track and also any others that belong
3775 * to the same active edit group.
3780 Editor::copy_playlists (TimeAxisView* v)
3782 begin_reversible_command (_("copy playlists"));
3783 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3784 commit_reversible_command ();
3789 * Clear the current playlist for a given track and also any others that belong
3790 * to the same active edit group.
3795 Editor::clear_playlists (TimeAxisView* v)
3797 begin_reversible_command (_("clear playlists"));
3798 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3799 commit_reversible_command ();
3803 Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz)
3805 atv.use_new_playlist (sz > 1 ? false : true);
3809 Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz)
3811 atv.use_copy_playlist (sz > 1 ? false : true);
3815 Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz)
3817 atv.clear_playlist ();
3821 Editor::on_key_press_event (GdkEventKey* ev)
3823 return key_press_focus_accelerator_handler (*this, ev);
3827 Editor::reset_x_origin (nframes_t frame)
3829 queue_visual_change (frame);
3833 Editor::reset_zoom (double fpu)
3835 queue_visual_change (fpu);
3839 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3841 reset_x_origin (frame);
3846 Editor::set_frames_per_unit (double fpu)
3850 /* this is the core function that controls the zoom level of the canvas. it is called
3851 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3854 if (fpu == frames_per_unit) {
3862 // convert fpu to frame count
3864 frames = (nframes_t) floor (fpu * canvas_width);
3866 /* don't allow zooms that fit more than the maximum number
3867 of frames into an 800 pixel wide space.
3870 if (max_frames / fpu < 800.0) {
3874 if (fpu == frames_per_unit) {
3878 frames_per_unit = fpu;
3880 if (frames != zoom_range_clock.current_duration()) {
3881 zoom_range_clock.set (frames);
3884 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3885 if (!selection->tracks.empty()) {
3886 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3887 (*i)->reshow_selection (selection->time);
3890 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3891 (*i)->reshow_selection (selection->time);
3896 ZoomChanged (); /* EMIT_SIGNAL */
3898 reset_hscrollbar_stepping ();
3899 reset_scrolling_region ();
3901 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3902 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3908 Editor::queue_visual_change (nframes_t where)
3910 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3911 pending_visual_change.time_origin = where;
3913 if (pending_visual_change.idle_handler_id < 0) {
3914 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3919 Editor::queue_visual_change (double fpu)
3921 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3922 pending_visual_change.frames_per_unit = fpu;
3924 if (pending_visual_change.idle_handler_id < 0) {
3925 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3930 Editor::_idle_visual_changer (void* arg)
3932 return static_cast<Editor*>(arg)->idle_visual_changer ();
3936 Editor::idle_visual_changer ()
3938 VisualChange::Type p = pending_visual_change.pending;
3940 pending_visual_change.pending = (VisualChange::Type) 0;
3941 pending_visual_change.idle_handler_id = -1;
3943 if (p & VisualChange::ZoomLevel) {
3944 set_frames_per_unit (pending_visual_change.frames_per_unit);
3947 if (p & VisualChange::TimeOrigin) {
3948 if (pending_visual_change.time_origin != leftmost_frame) {
3949 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3950 /* the signal handler will do the rest */
3952 update_fixed_rulers();
3953 redisplay_tempo (true);
3957 return 0; /* this is always a one-shot call */
3960 struct EditorOrderTimeAxisSorter {
3961 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3962 return a->order < b->order;
3967 Editor::sort_track_selection ()
3969 EditorOrderTimeAxisSorter cmp;
3970 selection->tracks.sort (cmp);
3974 Editor::edit_cursor_position(bool sync)
3976 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
3977 edit_cursor_clock.set(edit_cursor->current_frame, true);
3980 return edit_cursor->current_frame;
3984 Editor::get_preferred_edit_position() const
3989 switch (_edit_point) {
3990 case EditAtPlayhead:
3991 return playhead_cursor->current_frame;
3993 case EditAtSelectedMarker:
3994 if (!selection->markers.empty()) {
3996 Location* loc = find_location_from_marker (selection->markers.front(), whocares);
3998 return loc->start();
4005 if (mouse_frame (where, ignored)) {
4014 Editor::set_loop_range (nframes_t start, nframes_t end, string cmd)
4016 if (!session) return;
4018 begin_reversible_command (cmd);
4022 if ((tll = transport_loop_location()) == 0) {
4023 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoLoop);
4024 XMLNode &before = session->locations()->get_state();
4025 session->locations()->add (loc, true);
4026 session->set_auto_loop_location (loc);
4027 XMLNode &after = session->locations()->get_state();
4028 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4031 XMLNode &before = tll->get_state();
4032 tll->set_hidden (false, this);
4033 tll->set (start, end);
4034 XMLNode &after = tll->get_state();
4035 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4038 commit_reversible_command ();
4042 Editor::set_punch_range (nframes_t start, nframes_t end, string cmd)
4044 if (!session) return;
4046 begin_reversible_command (cmd);
4050 if ((tpl = transport_punch_location()) == 0) {
4051 Location* loc = new Location (start, end, _("Loop"), Location::IsAutoPunch);
4052 XMLNode &before = session->locations()->get_state();
4053 session->locations()->add (loc, true);
4054 session->set_auto_loop_location (loc);
4055 XMLNode &after = session->locations()->get_state();
4056 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
4059 XMLNode &before = tpl->get_state();
4060 tpl->set_hidden (false, this);
4061 tpl->set (start, end);
4062 XMLNode &after = tpl->get_state();
4063 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4066 commit_reversible_command ();