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.
20 /* Note: public Editor methods are documented in public_editor.h */
28 #include <sigc++/bind.h>
30 #include <pbd/convert.h>
31 #include <pbd/error.h>
32 #include <pbd/enumwriter.h>
33 #include <pbd/memento_command.h>
35 #include <glibmm/miscutils.h>
36 #include <gtkmm/image.h>
37 #include <gdkmm/color.h>
38 #include <gdkmm/bitmap.h>
40 #include <gtkmm2ext/grouped_buttons.h>
41 #include <gtkmm2ext/gtk_ui.h>
42 #include <gtkmm2ext/tearoff.h>
43 #include <gtkmm2ext/utils.h>
44 #include <gtkmm2ext/window_title.h>
45 #include <gtkmm2ext/choice.h>
47 #include <ardour/audio_track.h>
48 #include <ardour/audio_diskstream.h>
49 #include <ardour/plugin_manager.h>
50 #include <ardour/location.h>
51 #include <ardour/audioplaylist.h>
52 #include <ardour/audioregion.h>
53 #include <ardour/midi_region.h>
54 #include <ardour/session_route.h>
55 #include <ardour/session_directory.h>
56 #include <ardour/session_state_utils.h>
57 #include <ardour/tempo.h>
58 #include <ardour/utils.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"
83 #include "analysis_window.h"
89 #include "imageframe_socket_handler.h"
94 using namespace ARDOUR;
98 using namespace Gtkmm2ext;
99 using namespace Editing;
101 using PBD::internationalize;
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 *_zoom_focus_strings[] = {
147 /* Soundfile drag-n-drop */
149 Gdk::Cursor* Editor::cross_hair_cursor = 0;
150 Gdk::Cursor* Editor::selector_cursor = 0;
151 Gdk::Cursor* Editor::trimmer_cursor = 0;
152 Gdk::Cursor* Editor::grabber_cursor = 0;
153 Gdk::Cursor* Editor::zoom_cursor = 0;
154 Gdk::Cursor* Editor::time_fx_cursor = 0;
155 Gdk::Cursor* Editor::fader_cursor = 0;
156 Gdk::Cursor* Editor::speaker_cursor = 0;
157 Gdk::Cursor* Editor::midi_select_cursor = 0;
158 Gdk::Cursor* Editor::midi_pencil_cursor = 0;
159 Gdk::Cursor* Editor::midi_erase_cursor = 0;
160 Gdk::Cursor* Editor::wait_cursor = 0;
161 Gdk::Cursor* Editor::timebar_cursor = 0;
164 show_me_the_size (Requisition* r, const char* what)
166 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
170 check_adjustment (Gtk::Adjustment* adj)
172 cerr << "CHANGE adj = "
173 << adj->get_lower () << ' '
174 << adj->get_upper () << ' '
175 << adj->get_value () << ' '
176 << adj->get_step_increment () << ' '
177 << adj->get_page_increment () << ' '
178 << adj->get_page_size () << ' '
185 /* time display buttons */
187 minsec_label (_("Mins:Secs")),
188 bbt_label (_("Bars:Beats")),
189 smpte_label (_("Timecode")),
190 frame_label (_("Frames")),
191 tempo_label (_("Tempo")),
192 meter_label (_("Meter")),
193 mark_label (_("Location Markers")),
194 range_mark_label (_("Range Markers")),
195 transport_mark_label (_("Loop/Punch Ranges")),
197 edit_packer (3, 3, false),
199 /* the values here don't matter: layout widgets
200 reset them as needed.
203 vertical_adjustment (0.0, 0.0, 10.0, 400.0),
204 horizontal_adjustment (0.0, 0.0, 20.0, 1200.0),
207 marker_tempo_lines(0),
209 /* tool bar related */
211 edit_cursor_clock (X_("editcursor"), false, X_("EditCursorClock"), true),
212 zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, true),
214 toolbar_selection_clock_table (2,3),
216 automation_mode_button (_("mode")),
217 global_automation_button (_("automation")),
220 image_socket_listener(0),
225 nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, true)
230 /* we are a singleton */
232 PublicEditor::_instance = this;
236 selection = new Selection (this);
237 cut_buffer = new Selection (this);
239 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
240 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
241 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
242 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
244 clicked_regionview = 0;
245 clicked_axisview = 0;
246 clicked_routeview = 0;
247 clicked_crossfadeview = 0;
248 clicked_control_point = 0;
249 latest_regionview = 0;
250 last_update_frame = 0;
252 current_mixer_strip = 0;
253 current_bbt_points = 0;
255 snap_type_strings = I18N (_snap_type_strings);
256 snap_mode_strings = I18N (_snap_mode_strings);
257 zoom_focus_strings = I18N(_zoom_focus_strings);
259 snap_type = SnapToFrame;
260 set_snap_to (snap_type);
261 snap_mode = SnapNormal;
262 set_snap_mode (snap_mode);
263 snap_threshold = 5.0;
264 bbt_beat_subdivision = 4;
267 autoscroll_active = false;
268 autoscroll_timeout_tag = -1;
269 interthread_progress_window = 0;
275 current_interthread_info = 0;
276 _show_measures = true;
277 _show_waveforms = true;
278 _show_waveforms_recording = true;
279 first_action_message = 0;
281 show_gain_after_trim = false;
282 ignore_route_list_reorder = false;
283 no_route_list_redisplay = false;
284 verbose_cursor_on = true;
285 route_removal = false;
286 show_automatic_regions_in_region_list = true;
287 region_list_sort_type = (Editing::RegionListSortType) 0;
288 have_pending_keyboard_selection = false;
289 _follow_playhead = true;
290 _xfade_visibility = true;
291 editor_ruler_menu = 0;
292 no_ruler_shown_update = false;
293 edit_group_list_menu = 0;
295 region_list_menu = 0;
297 start_end_marker_menu = 0;
298 range_marker_menu = 0;
299 marker_menu_item = 0;
301 transport_marker_menu = 0;
302 new_transport_marker_menu = 0;
303 editor_mixer_strip_width = Wide;
304 show_editor_mixer_when_tracks_arrive = false;
307 ignore_mouse_mode_toggle = false;
308 ignore_midi_edit_mode_toggle = false;
309 current_stepping_trackview = 0;
311 entered_regionview = 0;
312 clear_entered_track = false;
313 _new_regionviews_show_envelope = false;
314 current_timestretch = 0;
315 in_edit_group_row_change = false;
316 last_canvas_frame = 0;
319 button_release_can_deselect = true;
320 canvas_idle_queued = false;
321 _dragging_playhead = false;
322 _dragging_hscrollbar = false;
324 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
325 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
326 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
327 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
328 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
330 range_marker_drag_rect = 0;
331 marker_drag_line = 0;
333 set_midi_edit_mode (MidiEditSelect, true);
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));
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");
377 setup_midi_toolbar ();
379 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
381 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
382 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
383 0.0, 1.0, 100.0, 1.0));
384 pad_line_1->property_color_rgba() = 0xFF0000FF;
388 time_canvas_vbox.pack_start (*_ruler_separator, false, false);
389 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
390 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
391 time_canvas_vbox.pack_start (*frames_ruler, false, false);
392 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
393 time_canvas_vbox.pack_start (time_canvas, true, true);
394 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 5);
396 bbt_label.set_name ("EditorTimeButton");
397 bbt_label.set_size_request (-1, (int)timebar_height);
398 bbt_label.set_alignment (1.0, 0.5);
399 bbt_label.set_padding (5,0);
400 minsec_label.set_name ("EditorTimeButton");
401 minsec_label.set_size_request (-1, (int)timebar_height);
402 minsec_label.set_alignment (1.0, 0.5);
403 minsec_label.set_padding (5,0);
404 smpte_label.set_name ("EditorTimeButton");
405 smpte_label.set_size_request (-1, (int)timebar_height);
406 smpte_label.set_alignment (1.0, 0.5);
407 smpte_label.set_padding (5,0);
408 frame_label.set_name ("EditorTimeButton");
409 frame_label.set_size_request (-1, (int)timebar_height);
410 frame_label.set_alignment (1.0, 0.5);
411 frame_label.set_padding (5,0);
412 tempo_label.set_name ("EditorTimeButton");
413 tempo_label.set_size_request (-1, (int)timebar_height);
414 tempo_label.set_alignment (1.0, 0.5);
415 tempo_label.set_padding (5,0);
416 meter_label.set_name ("EditorTimeButton");
417 meter_label.set_size_request (-1, (int)timebar_height);
418 meter_label.set_alignment (1.0, 0.5);
419 meter_label.set_padding (5,0);
420 mark_label.set_name ("EditorTimeButton");
421 mark_label.set_size_request (-1, (int)timebar_height);
422 mark_label.set_alignment (1.0, 0.5);
423 mark_label.set_padding (5,0);
424 range_mark_label.set_name ("EditorTimeButton");
425 range_mark_label.set_size_request (-1, (int)timebar_height);
426 range_mark_label.set_alignment (1.0, 0.5);
427 range_mark_label.set_padding (5,0);
428 transport_mark_label.set_name ("EditorTimeButton");
429 transport_mark_label.set_size_request (-1, (int)timebar_height);
430 transport_mark_label.set_alignment (1.0, 0.5);
431 transport_mark_label.set_padding (5,0);
433 time_button_vbox.pack_start (minsec_label, false, false);
434 time_button_vbox.pack_start (smpte_label, false, false);
435 time_button_vbox.pack_start (frame_label, false, false);
436 time_button_vbox.pack_start (bbt_label, false, false);
437 time_button_vbox.pack_start (meter_label, false, false);
438 time_button_vbox.pack_start (tempo_label, false, false);
439 time_button_vbox.pack_start (mark_label, false, false);
441 time_button_event_box.add (time_button_vbox);
442 time_button_event_box.set_name ("TimebarLabelBase");
443 time_button_frame.set_shadow_type (Gtk::SHADOW_NONE);
445 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
446 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
448 time_button_frame.add (time_button_event_box);
449 time_button_frame.set_name ("TimebarLabelBase");
450 time_button_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
452 /* these enable us to have a dedicated window (for cursor setting, etc.)
453 for the canvas areas.
456 track_canvas_event_box.add (track_canvas);
458 time_canvas_event_box.add (time_canvas_vbox);
459 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
461 edit_packer.set_col_spacings (0);
462 edit_packer.set_row_spacings (0);
463 edit_packer.set_homogeneous (false);
464 edit_packer.set_border_width (0);
465 edit_packer.set_name ("EditorWindow");
467 edit_packer.attach (edit_vscrollbar, 3, 4, 1, 2, FILL, FILL|EXPAND, 0, 0);
469 edit_packer.attach (time_button_frame, 0, 2, 0, 1, FILL, SHRINK, 0, 0);
470 edit_packer.attach (time_canvas_event_box, 2, 4, 0, 1, FILL|EXPAND, FILL, 0, 0);
472 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
473 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
475 edit_packer.attach (zoom_box, 1, 2, 2, 3, FILL, FILL, 0, 0);
476 edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0);
478 bottom_hbox.set_border_width (2);
479 bottom_hbox.set_spacing (3);
481 route_display_model = ListStore::create(route_display_columns);
482 route_list_display.set_model (route_display_model);
483 route_list_display.append_column (_("Show"), route_display_columns.visible);
484 route_list_display.append_column (_("Name"), route_display_columns.text);
485 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
486 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
487 route_list_display.set_headers_visible (true);
488 route_list_display.set_name ("TrackListDisplay");
489 route_list_display.get_selection()->set_mode (SELECTION_NONE);
490 route_list_display.set_reorderable (true);
491 route_list_display.set_size_request (100,-1);
493 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
494 route_list_visible_cell->property_activatable() = true;
495 route_list_visible_cell->property_radio() = false;
497 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
498 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
500 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
502 route_list_scroller.add (route_list_display);
503 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
505 group_model = ListStore::create(group_columns);
506 edit_group_display.set_model (group_model);
507 edit_group_display.append_column (_("Name"), group_columns.text);
508 edit_group_display.append_column (_("Active"), group_columns.is_active);
509 edit_group_display.append_column (_("Show"), group_columns.is_visible);
510 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
511 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
512 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
513 edit_group_display.get_column (0)->set_expand (true);
514 edit_group_display.get_column (1)->set_expand (false);
515 edit_group_display.get_column (2)->set_expand (false);
516 edit_group_display.set_headers_visible (true);
518 /* name is directly editable */
520 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(edit_group_display.get_column_cell_renderer (0));
521 name_cell->property_editable() = true;
522 name_cell->signal_edited().connect (mem_fun (*this, &Editor::edit_group_name_edit));
524 /* use checkbox for the active + visible columns */
526 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
527 active_cell->property_activatable() = true;
528 active_cell->property_radio() = false;
530 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
531 active_cell->property_activatable() = true;
532 active_cell->property_radio() = false;
534 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
536 edit_group_display.set_name ("EditGroupList");
537 edit_group_display.get_selection()->set_mode (SELECTION_SINGLE);
538 edit_group_display.set_headers_visible (true);
539 edit_group_display.set_reorderable (false);
540 edit_group_display.set_rules_hint (true);
541 edit_group_display.set_size_request (75, -1);
543 edit_group_display_scroller.add (edit_group_display);
544 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
546 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
548 VBox* edit_group_display_packer = manage (new VBox());
549 HBox* edit_group_display_button_box = manage (new HBox());
550 edit_group_display_button_box->set_homogeneous (true);
552 Button* edit_group_add_button = manage (new Button ());
553 Button* edit_group_remove_button = manage (new Button ());
557 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
559 edit_group_add_button->add (*w);
561 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
563 edit_group_remove_button->add (*w);
565 edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group));
566 edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group));
568 edit_group_display_button_box->pack_start (*edit_group_add_button);
569 edit_group_display_button_box->pack_start (*edit_group_remove_button);
571 edit_group_display_packer->pack_start (edit_group_display_scroller, true, true);
572 edit_group_display_packer->pack_start (*edit_group_display_button_box, false, false);
574 region_list_display.set_size_request (100, -1);
575 region_list_display.set_name ("RegionListDisplay");
577 region_list_model = TreeStore::create (region_list_columns);
578 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
579 region_list_model->set_sort_column (0, SORT_ASCENDING);
581 region_list_display.set_model (region_list_model);
582 region_list_display.append_column (_("Regions"), region_list_columns.name);
583 region_list_display.set_headers_visible (false);
585 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
587 TreeViewColumn* tv_col = region_list_display.get_column(0);
588 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
589 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
590 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
592 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
593 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
595 /* setup DnD handling */
597 list<TargetEntry> region_list_target_table;
599 region_list_target_table.push_back (TargetEntry ("text/plain"));
600 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
601 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
603 region_list_display.add_drop_targets (region_list_target_table);
604 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
606 region_list_scroller.add (region_list_display);
607 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
609 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
610 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
611 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
612 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
613 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
614 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
616 named_selection_scroller.add (named_selection_display);
617 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
619 named_selection_model = TreeStore::create (named_selection_columns);
620 named_selection_display.set_model (named_selection_model);
621 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
622 named_selection_display.set_headers_visible (false);
623 named_selection_display.set_size_request (100, -1);
624 named_selection_display.set_name ("NamedSelectionDisplay");
626 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
627 named_selection_display.set_size_request (100, -1);
628 named_selection_display.signal_button_release_event().connect (mem_fun(*this, &Editor::named_selection_display_button_release), false);
629 named_selection_display.signal_key_release_event().connect (mem_fun(*this, &Editor::named_selection_display_key_release), false);
630 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
634 snapshot_display_model = ListStore::create (snapshot_display_columns);
635 snapshot_display.set_model (snapshot_display_model);
636 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
637 snapshot_display.set_name ("SnapshotDisplay");
638 snapshot_display.set_size_request (75, -1);
639 snapshot_display.set_headers_visible (false);
640 snapshot_display.set_reorderable (false);
641 snapshot_display_scroller.add (snapshot_display);
642 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
644 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
645 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
649 nlabel = manage (new Label (_("Regions")));
650 nlabel->set_angle (-90);
651 the_notebook.append_page (region_list_scroller, *nlabel);
652 nlabel = manage (new Label (_("Tracks/Busses")));
653 nlabel->set_angle (-90);
654 the_notebook.append_page (route_list_scroller, *nlabel);
655 nlabel = manage (new Label (_("Snapshots")));
656 nlabel->set_angle (-90);
657 the_notebook.append_page (snapshot_display_scroller, *nlabel);
658 nlabel = manage (new Label (_("Edit Groups")));
659 nlabel->set_angle (-90);
660 the_notebook.append_page (*edit_group_display_packer, *nlabel);
661 nlabel = manage (new Label (_("Chunks")));
662 nlabel->set_angle (-90);
663 the_notebook.append_page (named_selection_scroller, *nlabel);
665 the_notebook.set_show_tabs (true);
666 the_notebook.set_scrollable (true);
667 the_notebook.popup_enable ();
668 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
670 post_maximal_editor_width = 0;
671 post_maximal_pane_position = 0;
672 edit_pane.pack1 (edit_packer, true, true);
673 edit_pane.pack2 (the_notebook, false, true);
675 edit_pane.signal_size_allocate().connect (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
677 top_hbox.pack_start (toolbar_frame, false, true);
678 top_hbox.pack_start (midi_toolbar_frame, false, true);
680 HBox *hbox = manage (new HBox);
681 hbox->pack_start (edit_pane, true, true);
683 global_vpacker.pack_start (top_hbox, false, false);
684 global_vpacker.pack_start (*hbox, true, true);
686 global_hpacker.pack_start (global_vpacker, true, true);
688 set_name ("EditorWindow");
689 add_accel_group (ActionManager::ui_manager->get_accel_group());
691 vpacker.pack_end (global_hpacker, true, true);
693 /* register actions now so that set_state() can find them and set toggles/checks etc */
697 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
700 _playlist_selector = new PlaylistSelector();
701 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
703 RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview));
707 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
708 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
710 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
711 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
713 nudge_forward_button.set_name ("TransportButton");
714 nudge_backward_button.set_name ("TransportButton");
716 fade_context_menu.set_name ("ArdourContextMenu");
718 /* icons, titles, WM stuff */
720 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
721 Glib::RefPtr<Gdk::Pixbuf> icon;
723 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
724 window_icons.push_back (icon);
726 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
727 window_icons.push_back (icon);
729 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
730 window_icons.push_back (icon);
732 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
733 window_icons.push_back (icon);
735 if (!window_icons.empty()) {
736 set_icon_list (window_icons);
737 set_default_icon_list (window_icons);
740 WindowTitle title(Glib::get_application_name());
741 title += _("Editor");
742 set_title (title.get_string());
743 set_wmclass (X_("ardour_editor"), "Ardour");
746 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
748 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
749 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
751 /* allow external control surfaces/protocols to do various things */
753 ControlProtocol::ZoomToSession.connect (mem_fun (*this, &Editor::temporal_zoom_session));
754 ControlProtocol::ZoomIn.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), false));
755 ControlProtocol::ZoomOut.connect (bind (mem_fun (*this, &Editor::temporal_zoom_step), true));
756 ControlProtocol::ScrollTimeline.connect (mem_fun (*this, &Editor::control_scroll));
758 Config->ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed));
767 if(image_socket_listener)
769 if(image_socket_listener->is_connected())
771 image_socket_listener->close_connection() ;
774 delete image_socket_listener ;
775 image_socket_listener = 0 ;
781 Editor::add_toplevel_controls (Container& cont)
783 vpacker.pack_start (cont, false, false);
788 Editor::catch_vanishing_regionview (RegionView *rv)
790 /* note: the selection will take care of the vanishing
791 audioregionview by itself.
794 if (clicked_regionview == rv) {
795 clicked_regionview = 0;
798 if (entered_regionview == rv) {
799 set_entered_regionview (0);
804 Editor::set_entered_regionview (RegionView* rv)
806 if (rv == entered_regionview) {
810 if (entered_regionview) {
811 entered_regionview->exited ();
814 if ((entered_regionview = rv) != 0) {
815 entered_regionview->entered ();
820 Editor::set_entered_track (TimeAxisView* tav)
823 entered_track->exited ();
826 if ((entered_track = tav) != 0) {
827 entered_track->entered ();
832 Editor::show_window ()
834 show_all_children ();
836 /* re-hide editor list if necessary */
837 editor_list_button_toggled ();
839 /* now reset all audio_time_axis heights, because widgets might need
845 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
846 tv = (static_cast<TimeAxisView*>(*i));
854 Editor::tie_vertical_scrolling ()
856 double y1 = vertical_adjustment.get_value();
857 controls_layout.get_vadjustment()->set_value (y1);
858 playhead_cursor->set_y_axis(y1);
859 edit_cursor->set_y_axis(y1);
863 Editor::instant_save ()
865 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
870 session->add_instant_xml(get_state());
872 Config->add_instant_xml(get_state());
877 Editor::edit_cursor_clock_changed()
879 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
880 edit_cursor->set_position (edit_cursor_clock.current_time());
886 Editor::zoom_adjustment_changed ()
892 double fpu = zoom_range_clock.current_duration() / canvas_width;
896 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
897 } else if (fpu > session->current_end_frame() / canvas_width) {
898 fpu = session->current_end_frame() / canvas_width;
899 zoom_range_clock.set ((nframes_t) floor (fpu * canvas_width));
906 Editor::control_scroll (float fraction)
908 ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::control_scroll), fraction));
914 double step = fraction * current_page_frames();
917 if ((fraction < 0.0f) && (session->transport_frame() < (nframes_t) fabs(step))) {
919 } else if ((fraction > 0.0f) && (max_frames - session->transport_frame() < step)) {
920 target = (max_frames - (current_page_frames()*2)); // allow room for slop in where the PH is on the screen
922 target = (session->transport_frame() + (nframes_t) floor ((fraction * current_page_frames())));
925 /* move visuals, we'll catch up with it later */
927 playhead_cursor->set_position (target);
929 if (target > (current_page_frames() / 2)) {
930 /* try to center PH in window */
931 reset_x_origin (target - (current_page_frames()/2));
936 /* cancel the existing */
938 control_scroll_connection.disconnect ();
940 /* add the next one */
942 control_scroll_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::deferred_control_scroll), target), 50);
946 Editor::deferred_control_scroll (nframes_t target)
948 session->request_locate (target);
953 Editor::on_realize ()
955 Window::on_realize ();
960 Editor::start_scrolling ()
962 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
963 (mem_fun(*this, &Editor::update_current_screen));
967 Editor::stop_scrolling ()
969 scroll_connection.disconnect ();
973 Editor::map_position_change (nframes_t frame)
975 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
977 if (session == 0 || !_follow_playhead) {
981 center_screen (frame);
982 playhead_cursor->set_position (frame);
986 Editor::center_screen (nframes_t frame)
988 double page = canvas_width * frames_per_unit;
990 /* if we're off the page, then scroll.
993 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
994 center_screen_internal (frame, page);
999 Editor::center_screen_internal (nframes_t frame, float page)
1004 frame -= (nframes_t) page;
1009 reset_x_origin (frame);
1013 Editor::handle_new_duration ()
1015 ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
1017 nframes_t new_end = session->get_maximum_extent() + (nframes_t) floorf (current_page_frames() * 0.10f);
1019 if (new_end > last_canvas_frame) {
1020 last_canvas_frame = new_end;
1021 horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
1022 reset_scrolling_region ();
1025 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1029 Editor::update_title_s (const string & snap_name)
1031 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1037 Editor::update_title ()
1039 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1042 bool dirty = session->dirty();
1044 string session_name;
1046 if (session->snap_name() != session->name()) {
1047 session_name = session->snap_name();
1049 session_name = session->name();
1053 session_name = "*" + session_name;
1056 WindowTitle title(session_name);
1057 title += Glib::get_application_name();
1058 set_title (title.get_string());
1063 Editor::connect_to_session (Session *t)
1067 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1070 /* catch up with the playhead */
1072 session->request_locate (playhead_cursor->current_frame);
1074 if (first_action_message) {
1075 first_action_message->hide();
1080 session->GoingAway.connect (mem_fun(*this, &Editor::session_going_away));
1081 session->history().Changed.connect (mem_fun (*this, &Editor::history_changed));
1083 /* These signals can all be emitted by a non-GUI thread. Therefore the
1084 handlers for them must not attempt to directly interact with the GUI,
1085 but use Gtkmm2ext::UI::instance()->call_slot();
1088 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1089 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1090 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route)));
1091 session_connections.push_back (session->RegionAdded.connect (mem_fun(*this, &Editor::handle_new_region)));
1092 session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed)));
1093 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration)));
1094 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::add_edit_group)));
1095 session_connections.push_back (session->edit_group_removed.connect (mem_fun(*this, &Editor::edit_groups_changed)));
1096 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1097 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1098 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1099 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1100 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1101 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1103 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1105 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1107 edit_groups_changed ();
1109 edit_cursor_clock.set_session (session);
1110 zoom_range_clock.set_session (session);
1111 _playlist_selector->set_session (session);
1112 nudge_clock.set_session (session);
1115 if (analysis_window != 0)
1116 analysis_window->set_session (session);
1119 Location* loc = session->locations()->auto_loop_location();
1121 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1122 if (loc->start() == loc->end()) {
1123 loc->set_end (loc->start() + 1);
1125 session->locations()->add (loc, false);
1126 session->set_auto_loop_location (loc);
1129 loc->set_name (_("Loop"));
1132 loc = session->locations()->auto_punch_location();
1134 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1135 if (loc->start() == loc->end()) {
1136 loc->set_end (loc->start() + 1);
1138 session->locations()->add (loc, false);
1139 session->set_auto_punch_location (loc);
1142 loc->set_name (_("Punch"));
1145 Config->map_parameters (mem_fun (*this, &Editor::parameter_changed));
1147 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1149 refresh_location_display ();
1150 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1151 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1152 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1153 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1154 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1156 handle_new_duration ();
1158 redisplay_regions ();
1159 redisplay_named_selections ();
1160 redisplay_snapshots ();
1162 initial_route_list_display ();
1164 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1165 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1168 restore_ruler_visibility ();
1169 //tempo_map_changed (Change (0));
1170 session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1174 /* don't show master bus in a new session */
1176 if (ARDOUR_UI::instance()->session_is_new ()) {
1178 TreeModel::Children rows = route_display_model->children();
1179 TreeModel::Children::iterator i;
1181 no_route_list_redisplay = true;
1183 for (i = rows.begin(); i != rows.end(); ++i) {
1184 TimeAxisView *tv = (*i)[route_display_columns.tv];
1185 RouteTimeAxisView *rtv;
1187 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1188 if (rtv->route()->is_master()) {
1189 route_list_display.get_selection()->unselect (i);
1194 no_route_list_redisplay = false;
1195 redisplay_route_list ();
1198 /* register for undo history */
1200 session->register_with_memento_command_factory(_id, this);
1204 Editor::build_cursors ()
1206 using namespace Gdk;
1208 Gdk::Color mbg ("#000000" ); /* Black */
1209 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1212 RefPtr<Bitmap> source, mask;
1213 source = Bitmap::create (mag_bits, mag_width, mag_height);
1214 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1215 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1218 Gdk::Color fbg ("#ffffff" );
1219 Gdk::Color ffg ("#000000" );
1222 RefPtr<Bitmap> source, mask;
1224 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1225 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1226 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1230 RefPtr<Bitmap> source, mask;
1231 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1232 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1233 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1236 grabber_cursor = new Gdk::Cursor (HAND2);
1237 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1238 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1239 selector_cursor = new Gdk::Cursor (XTERM);
1240 time_fx_cursor = new Gdk::Cursor (SIZING);
1241 wait_cursor = new Gdk::Cursor (WATCH);
1242 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1243 midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
1244 midi_pencil_cursor = new Gdk::Cursor (PENCIL);
1245 midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
1248 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1250 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1252 using namespace Menu_Helpers;
1253 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1256 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1260 MenuList& items (fade_context_menu.items());
1264 switch (item_type) {
1266 case FadeInHandleItem:
1267 if (arv->audio_region()->fade_in_active()) {
1268 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_in_active), false)));
1270 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_in_active), true)));
1273 items.push_back (SeparatorElem());
1275 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Linear)));
1276 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Fast)));
1277 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogB)));
1278 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::LogA)));
1279 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_in_shape), AudioRegion::Slow)));
1283 case FadeOutHandleItem:
1284 if (arv->audio_region()->fade_out_active()) {
1285 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*this, &Editor::set_fade_out_active), false)));
1287 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*this, &Editor::set_fade_out_active), true)));
1290 items.push_back (SeparatorElem());
1292 items.push_back (MenuElem (_("Linear"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Linear)));
1293 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Slow)));
1294 items.push_back (MenuElem (_("Slow"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogA)));
1295 items.push_back (MenuElem (_("Fast"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::LogB)));
1296 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (*this, &Editor::set_fade_out_shape), AudioRegion::Fast)));
1301 fatal << _("programming error: ")
1302 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1307 fade_context_menu.popup (button, time);
1310 /* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
1312 Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
1314 build_track_context_menu (frame)->popup (button, time);
1318 Editor::build_track_context_menu (nframes_t frame)
1320 using namespace Menu_Helpers;
1322 Menu* menu = manage (new Menu);
1323 MenuList& edit_items = menu->items();
1326 /* Build the general `track' context menu, adding what is appropriate given
1327 the current selection */
1329 /* XXX: currently crossfades can't be selected, so we can't use the selection
1330 to decide which crossfades to mention in the menu. I believe this will
1331 change at some point. For now we have to use clicked_trackview to decide. */
1332 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1335 boost::shared_ptr<Diskstream> ds;
1336 boost::shared_ptr<Playlist> pl;
1337 boost::shared_ptr<AudioPlaylist> apl;
1339 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1341 AudioPlaylist::Crossfades xfades;
1342 apl->crossfades_at (frame, xfades);
1344 bool many = xfades.size() > 1;
1346 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1347 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1352 if (!selection->time.empty()) {
1353 add_selection_context_items (edit_items);
1356 if (!selection->regions.empty()) {
1357 add_region_context_items (edit_items);
1360 if (!selection->tracks.empty()) {
1361 add_bus_or_audio_track_context_items (edit_items);
1364 menu->set_name ("ArdourContextMenu");
1371 Editor::analyze_region_selection()
1373 if (analysis_window == 0) {
1374 analysis_window = new AnalysisWindow();
1377 analysis_window->set_session(session);
1379 analysis_window->show_all();
1382 analysis_window->set_regionmode();
1383 analysis_window->analyze();
1385 analysis_window->present();
1389 Editor::analyze_range_selection()
1391 if (analysis_window == 0) {
1392 analysis_window = new AnalysisWindow();
1395 analysis_window->set_session(session);
1397 analysis_window->show_all();
1400 analysis_window->set_rangemode();
1401 analysis_window->analyze();
1403 analysis_window->present();
1405 #endif /* FFT_ANALYSIS */
1408 /** Add context menu items relevant to crossfades.
1409 * @param edit_items List to add the items to.
1412 Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1414 using namespace Menu_Helpers;
1415 Menu *xfade_menu = manage (new Menu);
1416 MenuList& items = xfade_menu->items();
1417 xfade_menu->set_name ("ArdourContextMenu");
1420 if (xfade->active()) {
1426 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1427 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1429 if (xfade->can_follow_overlap()) {
1431 if (xfade->following_overlap()) {
1432 str = _("Convert to short");
1434 str = _("Convert to full");
1437 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1441 str = xfade->out()->name();
1443 str += xfade->in()->name();
1445 str = _("Crossfade");
1448 edit_items.push_back (MenuElem (str, *xfade_menu));
1449 edit_items.push_back (SeparatorElem());
1453 Editor::xfade_edit_left_region ()
1455 if (clicked_crossfadeview) {
1456 clicked_crossfadeview->left_view.show_region_editor ();
1461 Editor::xfade_edit_right_region ()
1463 if (clicked_crossfadeview) {
1464 clicked_crossfadeview->right_view.show_region_editor ();
1468 /** Add an element to a menu, settings its sensitivity.
1469 * @param m Menu to add to.
1470 * @param e Element to add.
1471 * @param s true to make sensitive, false to make insensitive
1474 Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
1478 m.back().set_sensitive (false);
1482 /** Add context menu items relevant to regions.
1483 * @param edit_items List to add the items to.
1486 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
1488 using namespace Menu_Helpers;
1489 Menu *region_menu = manage (new Menu);
1490 MenuList& items = region_menu->items();
1491 region_menu->set_name ("ArdourContextMenu");
1493 items.push_back (MenuElem (_("Edit..."), mem_fun(*this, &Editor::edit_region)));
1494 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1495 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1497 Menu* sync_point_menu = manage (new Menu);
1498 MenuList& sync_point_items = sync_point_menu->items();
1499 sync_point_menu->set_name("ArdourContextMenu");
1501 sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1502 sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
1504 items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
1506 add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
1508 add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
1510 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1513 items.push_back (MenuElem (_("Analyze region"), mem_fun(*this, &Editor::analyze_region_selection)));
1516 items.push_back (SeparatorElem());
1518 items.push_back (MenuElem (_("Lock"), bind (mem_fun (*this, &Editor::set_region_lock), true)));
1519 items.push_back (MenuElem (_("Unlock"), bind (mem_fun (*this, &Editor::set_region_lock), false)));
1520 items.push_back (MenuElem (_("Lock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), true)));
1521 items.push_back (MenuElem (_("Unlock Position"), bind (mem_fun (*this, &Editor::set_region_position_lock), false)));
1522 items.push_back (MenuElem (_("Mute"), bind (mem_fun (*this, &Editor::set_region_mute), true)));
1523 items.push_back (MenuElem (_("Unmute"), bind (mem_fun (*this, &Editor::set_region_mute), false)));
1524 items.push_back (MenuElem (_("Opaque"), bind (mem_fun (*this, &Editor::set_region_opaque), true)));
1525 items.push_back (MenuElem (_("Transparent"), bind (mem_fun (*this, &Editor::set_region_opaque), false)));
1527 /* We allow "Original position" if at least one region is not at its
1530 RegionSelection::iterator i = selection->regions.begin();
1531 while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
1535 add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
1537 items.push_back (SeparatorElem());
1539 /* Find out if we have a selected audio region */
1540 i = selection->regions.begin();
1541 while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
1544 const bool have_selected_audio_region = (i != selection->regions.end());
1546 if (have_selected_audio_region) {
1548 Menu* envelopes_menu = manage (new Menu);
1549 MenuList& envelopes_items = envelopes_menu->items();
1550 envelopes_menu->set_name ("ArdourContextMenu");
1552 envelopes_items.push_back (MenuElem (_("Reset"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
1553 envelopes_items.push_back (MenuElem (_("Visible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), true)));
1554 envelopes_items.push_back (MenuElem (_("Invisible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), false)));
1555 envelopes_items.push_back (MenuElem (_("Active"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), true)));
1556 envelopes_items.push_back (MenuElem (_("Inactive"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), false)));
1558 items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
1560 items.push_back (MenuElem (_("Denormalize"), mem_fun (*this, &Editor::denormalize_regions)));
1561 items.push_back (MenuElem (_("Normalize"), mem_fun (*this, &Editor::normalize_regions)));
1564 /* Find out if we have a selected MIDI region */
1565 i = selection->regions.begin();
1566 while (i != selection->regions.end() && boost::dynamic_pointer_cast<MidiRegion>((*i)->region()) == 0) {
1569 const bool have_selected_midi_region = (i != selection->regions.end());
1571 if (have_selected_midi_region) {
1573 items.push_back (MenuElem (_("Quantize"), mem_fun(*this, &Editor::quantize_regions)));
1574 items.push_back (SeparatorElem());
1578 /* range related stuff */
1580 add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
1582 add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
1584 items.push_back (SeparatorElem());
1588 Menu *nudge_menu = manage (new Menu());
1589 MenuList& nudge_items = nudge_menu->items();
1590 nudge_menu->set_name ("ArdourContextMenu");
1592 nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1593 nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1594 nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1595 nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1597 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1599 Menu *trim_menu = manage (new Menu);
1600 MenuList& trim_items = trim_menu->items();
1601 trim_menu->set_name ("ArdourContextMenu");
1603 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1604 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1606 items.push_back (MenuElem (_("Trim"), *trim_menu));
1607 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1608 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1609 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1610 items.push_back (MenuElem (_("Fill track"), (mem_fun(*this, &Editor::region_fill_track))));
1611 items.push_back (SeparatorElem());
1612 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_selected_regions)));
1614 /* OK, stick the region submenu at the top of the list, and then add
1618 string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
1619 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1622 /** Add context menu items relevant to selection ranges.
1623 * @param edit_items List to add the items to.
1626 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1628 using namespace Menu_Helpers;
1629 Menu *selection_menu = manage (new Menu);
1630 MenuList& items = selection_menu->items();
1631 selection_menu->set_name ("ArdourContextMenu");
1633 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1634 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1637 items.push_back (SeparatorElem());
1638 items.push_back (MenuElem (_("Analyze range"), mem_fun(*this, &Editor::analyze_range_selection)));
1641 items.push_back (SeparatorElem());
1642 items.push_back (MenuElem (_("Separate range to track"), mem_fun(*this, &Editor::separate_region_from_selection)));
1643 items.push_back (MenuElem (_("Separate range to region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1645 items.push_back (SeparatorElem());
1646 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1647 items.push_back (SeparatorElem());
1648 items.push_back (MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_selection)));
1649 items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1650 items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1651 items.push_back (SeparatorElem());
1652 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1653 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1654 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1655 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::create_named_selection)));
1656 items.push_back (SeparatorElem());
1657 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1658 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1660 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1661 edit_items.push_back (SeparatorElem());
1664 /** Add context menu items relevant to busses or audio tracks.
1665 * @param edit_items List to add the items to.
1668 Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
1670 using namespace Menu_Helpers;
1672 /* We add every possible action here, and de-sensitize things
1673 that aren't allowed. The sensitivity logic is a bit spread out;
1674 on the one hand I'm using things like can_cut_copy (), which is
1675 reasonably complicated and so perhaps better near the function that
1676 it expresses sensitivity for, and on the other hand checks
1677 in this function as well. You can't really have can_* for everything
1678 or the number of methods would get silly. */
1680 bool const one_selected_region = selection->regions.size() == 1;
1682 /* Count the number of selected audio tracks */
1683 int n_audio_tracks = 0;
1684 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1685 RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
1686 if (r && r->is_audio_track()) {
1693 Menu *play_menu = manage (new Menu);
1694 MenuList& play_items = play_menu->items();
1695 play_menu->set_name ("ArdourContextMenu");
1697 play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
1698 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1699 add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
1701 add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
1703 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1707 Menu *select_menu = manage (new Menu);
1708 MenuList& select_items = select_menu->items();
1709 select_menu->set_name ("ArdourContextMenu");
1711 string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
1713 select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
1715 select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1717 str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
1719 select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
1721 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1722 select_items.push_back (SeparatorElem());
1724 if (n_audio_tracks) {
1725 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1726 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1729 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1730 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1731 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1732 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1734 if (n_audio_tracks) {
1735 select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
1738 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1742 Menu *cutnpaste_menu = manage (new Menu);
1743 MenuList& cutnpaste_items = cutnpaste_menu->items();
1744 cutnpaste_menu->set_name ("ArdourContextMenu");
1746 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
1748 add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
1750 if (n_audio_tracks) {
1751 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1752 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1754 cutnpaste_items.push_back (SeparatorElem());
1756 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1757 cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1758 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1760 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1763 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1765 if (n_audio_tracks) {
1767 Menu *track_menu = manage (new Menu);
1768 MenuList& track_items = track_menu->items();
1769 track_menu->set_name ("ArdourContextMenu");
1771 /* Adding new material */
1773 add_item_with_sensitivity (track_items, MenuElem (_("Insert selected region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)), n_audio_tracks == 1);
1775 add_item_with_sensitivity (track_items, MenuElem (_("Insert existing audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
1779 Menu *nudge_menu = manage (new Menu());
1780 MenuList& nudge_items = nudge_menu->items();
1781 nudge_menu->set_name ("ArdourContextMenu");
1783 str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
1784 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
1786 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
1788 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
1790 str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
1792 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
1794 str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
1796 nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
1798 track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1801 track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
1802 track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
1804 str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
1805 edit_items.push_back (MenuElem (str, *track_menu));
1809 /* CURSOR SETTING AND MARKS AND STUFF */
1812 Editor::set_snap_to (SnapType st)
1815 string str = snap_type_strings[(int) st];
1817 if (str != snap_type_selector.get_active_text()) {
1818 snap_type_selector.set_active_text (str);
1823 switch (snap_type) {
1824 case SnapToAThirtysecondBeat:
1825 case SnapToASixteenthBeat:
1826 case SnapToAEighthBeat:
1827 case SnapToAQuarterBeat:
1828 case SnapToAThirdBeat:
1829 update_tempo_based_rulers ();
1837 Editor::set_snap_mode (SnapMode mode)
1840 string str = snap_mode_strings[(int)mode];
1842 if (str != snap_mode_selector.get_active_text ()) {
1843 snap_mode_selector.set_active_text (str);
1850 Editor::set_state (const XMLNode& node)
1852 const XMLProperty* prop;
1854 int x, y, xoff, yoff;
1857 if ((prop = node.property ("id")) != 0) {
1858 _id = prop->value ();
1861 if ((geometry = find_named_node (node, "geometry")) == 0) {
1863 g.base_width = default_width;
1864 g.base_height = default_height;
1872 g.base_width = atoi(geometry->property("x_size")->value());
1873 g.base_height = atoi(geometry->property("y_size")->value());
1874 x = atoi(geometry->property("x_pos")->value());
1875 y = atoi(geometry->property("y_pos")->value());
1876 xoff = atoi(geometry->property("x_off")->value());
1877 yoff = atoi(geometry->property("y_off")->value());
1880 set_default_size (g.base_width, g.base_height);
1883 if (session && (prop = node.property ("playhead"))) {
1884 nframes_t pos = atol (prop->value().c_str());
1885 playhead_cursor->set_position (pos);
1887 playhead_cursor->set_position (0);
1889 /* reset_x_origin() doesn't work right here, since the old
1890 position may be zero already, and it does nothing in such
1895 horizontal_adjustment.set_value (0);
1898 if (session && (prop = node.property ("edit-cursor"))) {
1899 nframes_t pos = atol (prop->value().c_str());
1900 edit_cursor->set_position (pos);
1902 edit_cursor->set_position (0);
1905 if ((prop = node.property ("mixer-width"))) {
1906 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
1909 if ((prop = node.property ("zoom-focus"))) {
1910 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
1913 if ((prop = node.property ("zoom"))) {
1914 reset_zoom (PBD::atof (prop->value()));
1917 if ((prop = node.property ("snap-to"))) {
1918 set_snap_to ((SnapType) atoi (prop->value()));
1921 if ((prop = node.property ("snap-mode"))) {
1922 set_snap_mode ((SnapMode) atoi (prop->value()));
1925 if ((prop = node.property ("mouse-mode"))) {
1926 MouseMode m = str2mousemode(prop->value());
1927 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
1928 set_mouse_mode (m, true);
1930 mouse_mode = MouseGain; /* lie, to force the mode switch */
1931 set_mouse_mode (MouseObject, true);
1934 if ((prop = node.property ("show-waveforms"))) {
1935 bool yn = (prop->value() == "yes");
1936 _show_waveforms = !yn;
1937 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
1939 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1940 /* do it twice to force the change */
1941 tact->set_active (!yn);
1942 tact->set_active (yn);
1946 if ((prop = node.property ("show-waveforms-recording"))) {
1947 bool yn = (prop->value() == "yes");
1948 _show_waveforms_recording = !yn;
1949 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
1951 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1952 /* do it twice to force the change */
1953 tact->set_active (!yn);
1954 tact->set_active (yn);
1958 if ((prop = node.property ("show-measures"))) {
1959 bool yn = (prop->value() == "yes");
1960 _show_measures = !yn;
1961 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
1963 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1964 /* do it twice to force the change */
1965 tact->set_active (!yn);
1966 tact->set_active (yn);
1970 if ((prop = node.property ("follow-playhead"))) {
1971 bool yn = (prop->value() == "yes");
1972 set_follow_playhead (yn);
1973 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
1975 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
1976 if (tact->get_active() != yn) {
1977 tact->set_active (yn);
1982 if ((prop = node.property ("region-list-sort-type"))) {
1983 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
1984 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
1987 if ((prop = node.property ("xfades-visible"))) {
1988 bool yn = (prop->value() == "yes");
1989 _xfade_visibility = !yn;
1990 // set_xfade_visibility (yn);
1993 if ((prop = node.property ("show-editor-mixer"))) {
1995 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
1998 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1999 bool yn = (prop->value() == X_("yes"));
2001 /* do it twice to force the change */
2003 tact->set_active (!yn);
2004 tact->set_active (yn);
2008 if ((prop = node.property ("show-editor-list"))) {
2010 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2014 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2015 bool yn = (prop->value() == X_("yes"));
2017 /* do it twice to force the change */
2019 tact->set_active (!yn);
2020 tact->set_active (yn);
2029 Editor::get_state ()
2031 XMLNode* node = new XMLNode ("Editor");
2034 _id.print (buf, sizeof (buf));
2035 node->add_property ("id", buf);
2037 if (is_realized()) {
2038 Glib::RefPtr<Gdk::Window> win = get_window();
2040 int x, y, xoff, yoff, width, height;
2041 win->get_root_origin(x, y);
2042 win->get_position(xoff, yoff);
2043 win->get_size(width, height);
2045 XMLNode* geometry = new XMLNode ("geometry");
2047 snprintf(buf, sizeof(buf), "%d", width);
2048 geometry->add_property("x_size", string(buf));
2049 snprintf(buf, sizeof(buf), "%d", height);
2050 geometry->add_property("y_size", string(buf));
2051 snprintf(buf, sizeof(buf), "%d", x);
2052 geometry->add_property("x_pos", string(buf));
2053 snprintf(buf, sizeof(buf), "%d", y);
2054 geometry->add_property("y_pos", string(buf));
2055 snprintf(buf, sizeof(buf), "%d", xoff);
2056 geometry->add_property("x_off", string(buf));
2057 snprintf(buf, sizeof(buf), "%d", yoff);
2058 geometry->add_property("y_off", string(buf));
2059 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2060 geometry->add_property("edit_pane_pos", string(buf));
2062 node->add_child_nocopy (*geometry);
2065 maybe_add_mixer_strip_width (*node);
2067 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2068 node->add_property ("zoom-focus", buf);
2069 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2070 node->add_property ("zoom", buf);
2071 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2072 node->add_property ("snap-to", buf);
2073 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2074 node->add_property ("snap-mode", buf);
2076 snprintf (buf, sizeof (buf), "%" PRIu32, playhead_cursor->current_frame);
2077 node->add_property ("playhead", buf);
2078 snprintf (buf, sizeof (buf), "%" PRIu32, edit_cursor->current_frame);
2079 node->add_property ("edit-cursor", buf);
2081 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2082 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2083 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2084 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2085 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2086 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2087 node->add_property ("mouse-mode", enum2str(mouse_mode));
2089 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2091 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2092 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2095 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2097 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2098 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2107 Editor::trackview_by_y_position (double y)
2109 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2113 if ((tv = (*iter)->covers_y_position (y)) != 0) {
2122 Editor::snap_to (nframes64_t& start, int32_t direction, bool for_mark)
2124 Location* before = 0;
2125 Location* after = 0;
2131 const nframes64_t one_second = session->frame_rate();
2132 const nframes64_t one_minute = session->frame_rate() * 60;
2133 const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
2134 nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
2135 nframes64_t presnap = start;
2137 switch (snap_type) {
2143 start = (nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2145 start = (nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2149 case SnapToSMPTEFrame:
2150 if (fmod((double)start, (double)session->frames_per_smpte_frame()) > (session->frames_per_smpte_frame() / 2)) {
2151 start = (nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2153 start = (nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2157 case SnapToSMPTESeconds:
2158 if (session->smpte_offset_negative())
2160 start += session->smpte_offset ();
2162 start -= session->smpte_offset ();
2164 if (start % one_smpte_second > one_smpte_second / 2) {
2165 start = (nframes_t) ceil ((double) start / one_smpte_second) * one_smpte_second;
2167 start = (nframes_t) floor ((double) start / one_smpte_second) * one_smpte_second;
2170 if (session->smpte_offset_negative())
2172 start -= session->smpte_offset ();
2174 start += session->smpte_offset ();
2178 case SnapToSMPTEMinutes:
2179 if (session->smpte_offset_negative())
2181 start += session->smpte_offset ();
2183 start -= session->smpte_offset ();
2185 if (start % one_smpte_minute > one_smpte_minute / 2) {
2186 start = (nframes_t) ceil ((double) start / one_smpte_minute) * one_smpte_minute;
2188 start = (nframes_t) floor ((double) start / one_smpte_minute) * one_smpte_minute;
2190 if (session->smpte_offset_negative())
2192 start -= session->smpte_offset ();
2194 start += session->smpte_offset ();
2199 if (start % one_second > one_second / 2) {
2200 start = (nframes_t) ceil ((double) start / one_second) * one_second;
2202 start = (nframes_t) floor ((double) start / one_second) * one_second;
2207 if (start % one_minute > one_minute / 2) {
2208 start = (nframes_t) ceil ((double) start / one_minute) * one_minute;
2210 start = (nframes_t) floor ((double) start / one_minute) * one_minute;
2215 start = session->tempo_map().round_to_bar (start, direction);
2219 start = session->tempo_map().round_to_beat (start, direction);
2222 case SnapToAThirtysecondBeat:
2223 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2226 case SnapToASixteenthBeat:
2227 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2230 case SnapToAEighthBeat:
2231 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2234 case SnapToAQuarterBeat:
2235 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2238 case SnapToAThirdBeat:
2239 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2242 case SnapToEditCursor:
2243 start = edit_cursor->current_frame;
2251 before = session->locations()->first_location_before (start);
2252 after = session->locations()->first_location_after (start);
2254 if (direction < 0) {
2256 start = before->start();
2260 } else if (direction > 0) {
2262 start = after->start();
2264 start = session->current_end_frame();
2269 /* find nearest of the two */
2270 if ((start - before->start()) < (after->start() - start)) {
2271 start = before->start();
2273 start = after->start();
2276 start = before->start();
2279 start = after->start();
2286 case SnapToRegionStart:
2287 case SnapToRegionEnd:
2288 case SnapToRegionSync:
2289 case SnapToRegionBoundary:
2290 if (!region_boundary_cache.empty()) {
2291 vector<nframes_t>::iterator i;
2293 if (direction > 0) {
2294 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2296 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2299 if (i != region_boundary_cache.end()) {
2302 start = region_boundary_cache.back();
2308 switch (snap_mode) {
2314 if (presnap > start) {
2315 if (presnap > (start + unit_to_frame(snap_threshold))) {
2319 } else if (presnap < start) {
2320 if (presnap < (start - unit_to_frame(snap_threshold))) {
2332 Editor::snap_length_beats (nframes_t start)
2338 /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
2340 switch (snap_type) {
2342 return session->tempo_map().meter_at(start).beats_per_bar();
2347 case SnapToAThirtysecondBeat:
2348 return 1.0 / (double)32.0;
2351 case SnapToASixteenthBeat:
2352 return 1.0 / (double)16.0;
2355 case SnapToAEighthBeat:
2356 return 1.0 / (double)8.0;
2359 case SnapToAQuarterBeat:
2360 return 1.0 / (double)4.0;
2363 case SnapToAThirdBeat:
2364 return 1.0 / (double)3.0;
2372 Editor::setup_toolbar ()
2376 const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
2379 /* Mode Buttons (tool selection) */
2381 vector<ToggleButton *> mouse_mode_buttons;
2383 mouse_move_button.add (*(manage (new Image (::get_icon("tool_object")))));
2384 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2385 mouse_mode_buttons.push_back (&mouse_move_button);
2386 mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm")))));
2387 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2388 mouse_mode_buttons.push_back (&mouse_select_button);
2389 mouse_gain_button.add (*(manage (new Image (::get_icon("tool_gain")))));
2390 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2391 mouse_mode_buttons.push_back (&mouse_gain_button);
2392 mouse_zoom_button.add (*(manage (new Image (::get_icon("tool_zoom")))));
2393 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2394 mouse_mode_buttons.push_back (&mouse_zoom_button);
2395 mouse_timefx_button.add (*(manage (new Image (::get_icon("tool_stretch")))));
2396 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2397 mouse_mode_buttons.push_back (&mouse_timefx_button);
2398 mouse_audition_button.add (*(manage (new Image (::get_icon("tool_audition")))));
2399 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2400 mouse_note_button.add (*(manage (new Image (::get_icon("tool_note")))));
2401 mouse_note_button.set_relief(Gtk::RELIEF_NONE);
2402 mouse_mode_buttons.push_back (&mouse_note_button);
2403 mouse_mode_buttons.push_back (&mouse_audition_button);
2405 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2407 HBox* mode_box = manage(new HBox);
2408 mode_box->set_border_width (2);
2409 mode_box->set_spacing(4);
2410 mouse_mode_button_box.set_spacing(1);
2411 mouse_mode_button_box.pack_start(mouse_move_button, true, true);
2412 mouse_mode_button_box.pack_start(mouse_select_button, true, true);
2413 mouse_mode_button_box.pack_start(mouse_zoom_button, true, true);
2414 mouse_mode_button_box.pack_start(mouse_gain_button, true, true);
2415 mouse_mode_button_box.pack_start(mouse_timefx_button, true, true);
2416 mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
2417 mouse_mode_button_box.pack_start(mouse_note_button, true, true);
2418 mouse_mode_button_box.set_homogeneous(true);
2420 vector<string> edit_mode_strings;
2421 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2422 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2424 edit_mode_selector.set_name ("EditModeSelector");
2425 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, longest (edit_mode_strings).c_str(), 2+FUDGE, 10);
2426 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2427 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2429 mode_box->pack_start(edit_mode_selector);
2430 mode_box->pack_start(mouse_mode_button_box);
2432 mouse_mode_tearoff = manage (new TearOff (*mode_box));
2433 mouse_mode_tearoff->set_name ("MouseModeBase");
2435 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2436 &mouse_mode_tearoff->tearoff_window()));
2437 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2438 &mouse_mode_tearoff->tearoff_window(), 1));
2439 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2440 &mouse_mode_tearoff->tearoff_window()));
2441 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2442 &mouse_mode_tearoff->tearoff_window(), 1));
2444 mouse_move_button.set_name ("MouseModeButton");
2445 mouse_select_button.set_name ("MouseModeButton");
2446 mouse_gain_button.set_name ("MouseModeButton");
2447 mouse_zoom_button.set_name ("MouseModeButton");
2448 mouse_timefx_button.set_name ("MouseModeButton");
2449 mouse_audition_button.set_name ("MouseModeButton");
2450 mouse_note_button.set_name ("MouseModeButton");
2452 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects"));
2453 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges"));
2454 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation"));
2455 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range"));
2456 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions"));
2457 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2458 ARDOUR_UI::instance()->tooltips().set_tip (mouse_note_button, _("Edit MIDI Notes"));
2460 mouse_move_button.unset_flags (CAN_FOCUS);
2461 mouse_select_button.unset_flags (CAN_FOCUS);
2462 mouse_gain_button.unset_flags (CAN_FOCUS);
2463 mouse_zoom_button.unset_flags (CAN_FOCUS);
2464 mouse_timefx_button.unset_flags (CAN_FOCUS);
2465 mouse_audition_button.unset_flags (CAN_FOCUS);
2466 mouse_note_button.unset_flags (CAN_FOCUS);
2468 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2469 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2471 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2472 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2473 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2474 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2475 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2476 mouse_note_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseNote));
2478 // mouse_move_button.set_active (true);
2483 zoom_box.set_spacing (1);
2484 zoom_box.set_border_width (2);
2486 zoom_in_button.set_name ("EditorTimeButton");
2487 zoom_in_button.set_size_request(-1,16);
2488 zoom_in_button.add (*(manage (new Image (::get_icon("zoom_in")))));
2489 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
2490 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In"));
2492 zoom_out_button.set_name ("EditorTimeButton");
2493 zoom_out_button.set_size_request(-1,16);
2494 zoom_out_button.add (*(manage (new Image (::get_icon("zoom_out")))));
2495 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
2496 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out"));
2498 zoom_out_full_button.set_name ("EditorTimeButton");
2499 zoom_out_full_button.set_size_request(-1,16);
2500 zoom_out_full_button.add (*(manage (new Image (::get_icon("zoom_full")))));
2501 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
2502 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session"));
2504 zoom_focus_selector.set_name ("ZoomFocusSelector");
2505 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Center", FUDGE, 0);
2506 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2507 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2508 ARDOUR_UI::instance()->tooltips().set_tip (zoom_focus_selector, _("Zoom focus"));
2510 zoom_box.pack_start (zoom_focus_selector, true, true);
2511 zoom_box.pack_start (zoom_out_button, false, false);
2512 zoom_box.pack_start (zoom_in_button, false, false);
2513 zoom_box.pack_start (zoom_out_full_button, false, false);
2515 /* Edit Cursor / Snap */
2517 snap_box.set_spacing (1);
2518 snap_box.set_border_width (2);
2520 snap_type_selector.set_name ("SnapTypeSelector");
2521 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2522 set_popdown_strings (snap_type_selector, snap_type_strings);
2523 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2524 ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to"));
2526 snap_mode_selector.set_name ("SnapModeSelector");
2527 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10);
2528 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2529 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2531 snap_box.pack_start (edit_cursor_clock, false, false);
2532 snap_box.pack_start (snap_mode_selector, false, false);
2533 snap_box.pack_start (snap_type_selector, false, false);
2538 HBox *nudge_box = manage (new HBox);
2539 nudge_box->set_spacing(1);
2540 nudge_box->set_border_width (2);
2542 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2543 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2545 nudge_box->pack_start (nudge_backward_button, false, false);
2546 nudge_box->pack_start (nudge_forward_button, false, false);
2547 nudge_box->pack_start (nudge_clock, false, false);
2550 /* Pack everything in... */
2552 HBox* hbox = new HBox;
2553 hbox->set_spacing(10);
2555 tools_tearoff = new TearOff (*hbox);
2556 tools_tearoff->set_name ("MouseModeBase");
2558 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2559 &tools_tearoff->tearoff_window()));
2560 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2561 &tools_tearoff->tearoff_window(), 0));
2562 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2563 &tools_tearoff->tearoff_window()));
2564 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2565 &tools_tearoff->tearoff_window(), 0));
2567 toolbar_hbox.set_spacing (10);
2568 toolbar_hbox.set_border_width (1);
2570 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2571 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2574 hbox->pack_start (snap_box, false, false);
2575 // hbox->pack_start (zoom_box, false, false);
2576 hbox->pack_start (*nudge_box, false, false);
2580 toolbar_base.set_name ("ToolBarBase");
2581 toolbar_base.add (toolbar_hbox);
2583 toolbar_frame.set_shadow_type (SHADOW_OUT);
2584 toolbar_frame.set_name ("BaseFrame");
2585 toolbar_frame.add (toolbar_base);
2590 Editor::setup_midi_toolbar ()
2594 /* Mode Buttons (tool selection) */
2596 vector<ToggleButton *> midi_tool_buttons;
2598 midi_tool_select_button.add (*(manage (new Image (::get_icon("midi_tool_select")))));
2599 midi_tool_select_button.set_relief(Gtk::RELIEF_NONE);
2600 midi_tool_buttons.push_back (&midi_tool_select_button);
2601 midi_tool_pencil_button.add (*(manage (new Image (::get_icon("midi_tool_pencil")))));
2602 midi_tool_pencil_button.set_relief(Gtk::RELIEF_NONE);
2603 midi_tool_buttons.push_back (&midi_tool_pencil_button);
2604 midi_tool_erase_button.add (*(manage (new Image (::get_icon("midi_tool_erase")))));
2605 midi_tool_erase_button.set_relief(Gtk::RELIEF_NONE);
2606 midi_tool_buttons.push_back (&midi_tool_erase_button);
2608 midi_tool_select_button.set_active(true);
2610 midi_tool_button_set = new GroupedButtons (midi_tool_buttons);
2612 midi_tool_button_box.set_border_width (2);
2613 midi_tool_button_box.set_spacing(4);
2614 midi_tool_button_box.set_spacing(1);
2615 midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
2616 midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
2617 midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
2618 midi_tool_button_box.set_homogeneous(true);
2620 midi_tool_select_button.set_name ("MouseModeButton");
2621 midi_tool_pencil_button.set_name ("MouseModeButton");
2622 midi_tool_erase_button.set_name ("MouseModeButton");
2624 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
2625 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
2626 ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
2628 midi_tool_select_button.unset_flags (CAN_FOCUS);
2629 midi_tool_pencil_button.unset_flags (CAN_FOCUS);
2630 midi_tool_erase_button.unset_flags (CAN_FOCUS);
2632 midi_tool_select_button.signal_toggled().connect (bind (mem_fun(*this,
2633 &Editor::midi_edit_mode_toggled), Editing::MidiEditSelect));
2634 midi_tool_pencil_button.signal_toggled().connect (bind (mem_fun(*this,
2635 &Editor::midi_edit_mode_toggled), Editing::MidiEditPencil));
2636 midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
2637 &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
2639 /* Pack everything in... */
2641 midi_tools_tearoff = new TearOff (midi_tool_button_box);
2642 midi_tools_tearoff->set_name ("MouseModeBase");
2645 midi_tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2646 &midi_tools_tearoff->tearoff_window()));
2647 midi_tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2648 &midi_tools_tearoff->tearoff_window(), 0));
2649 midi_tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&midi_toolbar_hbox),
2650 &midi_tools_tearoff->tearoff_window()));
2651 midi_tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&midi_toolbar_hbox),
2652 &midi_tools_tearoff->tearoff_window(), 0));
2655 midi_toolbar_hbox.set_spacing (10);
2656 midi_toolbar_hbox.set_border_width (1);
2658 midi_toolbar_hbox.pack_start (*midi_tools_tearoff, false, true);
2660 midi_tool_button_box.show_all ();
2661 midi_toolbar_hbox.show_all();
2662 midi_tools_tearoff->show_all();
2664 midi_toolbar_base.set_name ("ToolBarBase");
2665 midi_toolbar_base.add (midi_toolbar_hbox);
2667 midi_toolbar_frame.set_shadow_type (SHADOW_OUT);
2668 midi_toolbar_frame.set_name ("BaseFrame");
2669 midi_toolbar_frame.add (midi_toolbar_base);
2673 Editor::convert_drop_to_paths (vector<ustring>& paths,
2674 const RefPtr<Gdk::DragContext>& context,
2677 const SelectionData& data,
2686 vector<ustring> uris = data.get_uris();
2690 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2691 are actually URI lists. So do it by hand.
2694 if (data.get_target() != "text/plain") {
2698 /* Parse the "uri-list" format that Nautilus provides,
2699 where each pathname is delimited by \r\n
2702 const char* p = data.get_text().c_str();
2709 while (g_ascii_isspace (*p))
2713 while (*q && (*q != '\n') && (*q != '\r'))
2719 while (q > p && g_ascii_isspace (*q))
2724 uris.push_back (ustring (p, q - p + 1));
2728 p = strchr (p, '\n');
2738 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2739 if ((*i).substr (0,7) == "file://") {
2741 PBD::url_decode (p);
2742 paths.push_back (p.substr (7));
2750 Editor::new_tempo_section ()
2756 Editor::map_transport_state ()
2758 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2760 if (session->transport_stopped()) {
2761 have_pending_keyboard_selection = false;
2764 update_loop_range_view (true);
2769 Editor::State::State (PublicEditor const * e)
2771 selection = new Selection (e);
2774 Editor::State::~State ()
2780 Editor::get_memento () const
2782 State *state = new State (this);
2784 store_state (*state);
2785 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2789 Editor::store_state (State& state) const
2791 *state.selection = *selection;
2795 Editor::restore_state (State *state)
2797 if (*selection == *state->selection) {
2801 *selection = *state->selection;
2802 time_selection_changed ();
2803 region_selection_changed ();
2805 /* XXX other selection change handlers? */
2809 Editor::begin_reversible_command (string name)
2812 before = &get_state();
2813 session->begin_reversible_command (name);
2818 Editor::commit_reversible_command ()
2821 session->commit_reversible_command (new MementoCommand<Editor>(*this, before, &get_state()));
2826 Editor::set_edit_group_solo (Route& route, bool yn)
2828 RouteGroup *edit_group;
2830 if ((edit_group = route.edit_group()) != 0) {
2831 edit_group->apply (&Route::set_solo, yn, this);
2833 route.set_solo (yn, this);
2838 Editor::set_edit_group_mute (Route& route, bool yn)
2840 RouteGroup *edit_group = 0;
2842 if ((edit_group == route.edit_group()) != 0) {
2843 edit_group->apply (&Route::set_mute, yn, this);
2845 route.set_mute (yn, this);
2850 Editor::history_changed ()
2854 if (undo_action && session) {
2855 if (session->undo_depth() == 0) {
2858 label = string_compose(_("Undo (%1)"), session->next_undo());
2860 undo_action->property_label() = label;
2863 if (redo_action && session) {
2864 if (session->redo_depth() == 0) {
2867 label = string_compose(_("Redo (%1)"), session->next_redo());
2869 redo_action->property_label() = label;
2874 Editor::duplicate_dialog (bool dup_region)
2876 if (selection->regions.empty() && (selection->time.length() == 0)) {
2880 ArdourDialog win ("duplicate dialog");
2881 Label label (_("Duplicate how many times?"));
2882 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
2883 SpinButton spinner (adjustment);
2885 win.get_vbox()->set_spacing (12);
2886 win.get_vbox()->pack_start (label);
2888 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
2889 place, visually. so do this by hand.
2892 win.get_vbox()->pack_start (spinner);
2893 spinner.signal_activate().connect (sigc::bind (mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
2898 win.add_button (Stock::OK, RESPONSE_ACCEPT);
2899 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2901 win.set_position (WIN_POS_MOUSE);
2903 spinner.grab_focus ();
2905 switch (win.run ()) {
2906 case RESPONSE_ACCEPT:
2912 float times = adjustment.get_value();
2914 if (!selection->regions.empty()) {
2915 duplicate_some_regions (selection->regions, times);
2917 duplicate_selection (times);
2922 Editor::show_verbose_canvas_cursor ()
2924 verbose_canvas_cursor->raise_to_top();
2925 verbose_canvas_cursor->show();
2926 verbose_cursor_visible = true;
2930 Editor::hide_verbose_canvas_cursor ()
2932 verbose_canvas_cursor->hide();
2933 verbose_cursor_visible = false;
2937 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
2939 /* XXX get origin of canvas relative to root window,
2940 add x and y and check compared to gdk_screen_{width,height}
2942 verbose_canvas_cursor->property_text() = txt.c_str();
2943 verbose_canvas_cursor->property_x() = x;
2944 verbose_canvas_cursor->property_y() = y;
2948 Editor::set_verbose_canvas_cursor_text (const string & txt)
2950 verbose_canvas_cursor->property_text() = txt.c_str();
2954 Editor::edit_mode_selection_done ()
2960 string choice = edit_mode_selector.get_active_text();
2961 EditMode mode = Slide;
2963 if (choice == _("Splice Edit")) {
2965 } else if (choice == _("Slide Edit")) {
2969 Config->set_edit_mode (mode);
2973 Editor::snap_type_selection_done ()
2975 string choice = snap_type_selector.get_active_text();
2976 SnapType snaptype = SnapToFrame;
2978 if (choice == _("Beats/3")) {
2979 snaptype = SnapToAThirdBeat;
2980 } else if (choice == _("Beats/4")) {
2981 snaptype = SnapToAQuarterBeat;
2982 } else if (choice == _("Beats/8")) {
2983 snaptype = SnapToAEighthBeat;
2984 } else if (choice == _("Beats/16")) {
2985 snaptype = SnapToASixteenthBeat;
2986 } else if (choice == _("Beats/32")) {
2987 snaptype = SnapToAThirtysecondBeat;
2988 } else if (choice == _("Beats")) {
2989 snaptype = SnapToBeat;
2990 } else if (choice == _("Bars")) {
2991 snaptype = SnapToBar;
2992 } else if (choice == _("Marks")) {
2993 snaptype = SnapToMark;
2994 } else if (choice == _("Edit Cursor")) {
2995 snaptype = SnapToEditCursor;
2996 } else if (choice == _("Region starts")) {
2997 snaptype = SnapToRegionStart;
2998 } else if (choice == _("Region ends")) {
2999 snaptype = SnapToRegionEnd;
3000 } else if (choice == _("Region bounds")) {
3001 snaptype = SnapToRegionBoundary;
3002 } else if (choice == _("Region syncs")) {
3003 snaptype = SnapToRegionSync;
3004 } else if (choice == _("CD Frames")) {
3005 snaptype = SnapToCDFrame;
3006 } else if (choice == _("SMPTE Frames")) {
3007 snaptype = SnapToSMPTEFrame;
3008 } else if (choice == _("SMPTE Seconds")) {
3009 snaptype = SnapToSMPTESeconds;
3010 } else if (choice == _("SMPTE Minutes")) {
3011 snaptype = SnapToSMPTEMinutes;
3012 } else if (choice == _("Seconds")) {
3013 snaptype = SnapToSeconds;
3014 } else if (choice == _("Minutes")) {
3015 snaptype = SnapToMinutes;
3016 } else if (choice == _("None")) {
3017 snaptype = SnapToFrame;
3020 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3022 ract->set_active ();
3027 Editor::snap_mode_selection_done ()
3029 string choice = snap_mode_selector.get_active_text();
3030 SnapMode mode = SnapNormal;
3032 if (choice == _("Normal")) {
3034 } else if (choice == _("Magnetic")) {
3035 mode = SnapMagnetic;
3038 RefPtr<RadioAction> ract = snap_mode_action (mode);
3041 ract->set_active (true);
3046 Editor::zoom_focus_selection_done ()
3048 string choice = zoom_focus_selector.get_active_text();
3049 ZoomFocus focus_type = ZoomFocusLeft;
3051 if (choice == _("Left")) {
3052 focus_type = ZoomFocusLeft;
3053 } else if (choice == _("Right")) {
3054 focus_type = ZoomFocusRight;
3055 } else if (choice == _("Center")) {
3056 focus_type = ZoomFocusCenter;
3057 } else if (choice == _("Play")) {
3058 focus_type = ZoomFocusPlayhead;
3059 } else if (choice == _("Edit")) {
3060 focus_type = ZoomFocusEdit;
3063 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3066 ract->set_active ();
3071 Editor::edit_controls_button_release (GdkEventButton* ev)
3073 if (Keyboard::is_context_menu_event (ev)) {
3074 ARDOUR_UI::instance()->add_route (this);
3080 Editor::mouse_select_button_release (GdkEventButton* ev)
3082 /* this handles just right-clicks */
3084 if (ev->button != 3) {
3091 Editor::TrackViewList *
3092 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3095 TrackViewList::iterator i;
3097 v = new TrackViewList;
3099 if (track == 0 && group == 0) {
3103 for (i = track_views.begin(); i != track_views.end (); ++i) {
3107 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3109 /* just the view for this track
3112 v->push_back (track);
3116 /* views for all tracks in the edit group */
3118 for (i = track_views.begin(); i != track_views.end (); ++i) {
3120 if (group == 0 || (*i)->edit_group() == group) {
3130 Editor::set_zoom_focus (ZoomFocus f)
3132 string str = zoom_focus_strings[(int)f];
3134 if (str != zoom_focus_selector.get_active_text()) {
3135 zoom_focus_selector.set_active_text (str);
3138 if (zoom_focus != f) {
3141 ZoomFocusChanged (); /* EMIT_SIGNAL */
3148 Editor::ensure_float (Window& win)
3150 win.set_transient_for (*this);
3154 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3156 /* recover or initialize pane positions. do this here rather than earlier because
3157 we don't want the positions to change the child allocations, which they seem to do.
3163 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3165 static int32_t done;
3168 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3169 width = default_width;
3170 height = default_height;
3172 width = atoi(geometry->property("x_size")->value());
3173 height = atoi(geometry->property("y_size")->value());
3176 if (which == static_cast<Paned*> (&edit_pane)) {
3182 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3183 /* initial allocation is 90% to canvas, 10% to notebook */
3184 pos = (int) floor (alloc.get_width() * 0.90f);
3185 snprintf (buf, sizeof(buf), "%d", pos);
3187 pos = atoi (prop->value());
3190 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3191 edit_pane.set_position (pos);
3192 pre_maximal_pane_position = pos;
3198 Editor::detach_tearoff (Box* b, Window* w)
3200 if (tools_tearoff->torn_off() &&
3201 mouse_mode_tearoff->torn_off()) {
3202 top_hbox.remove (toolbar_frame);
3207 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3209 if (toolbar_frame.get_parent() == 0) {
3210 top_hbox.pack_end (toolbar_frame);
3215 Editor::set_show_measures (bool yn)
3217 if (_show_measures != yn) {
3220 if ((_show_measures = yn) == true) {
3228 Editor::toggle_follow_playhead ()
3230 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3232 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3233 set_follow_playhead (tact->get_active());
3238 Editor::set_follow_playhead (bool yn)
3240 if (_follow_playhead != yn) {
3241 if ((_follow_playhead = yn) == true) {
3243 update_current_screen ();
3250 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3252 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3254 xfade->set_active (!xfade->active());
3259 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3261 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3263 xfade->set_follow_overlap (!xfade->following_overlap());
3268 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3270 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3276 CrossfadeEditor cew (*session, xfade, xfade->fade_in().get_min_y(), 1.0);
3280 switch (cew.run ()) {
3281 case RESPONSE_ACCEPT:
3288 xfade->StateChanged (Change (~0));
3292 Editor::playlist_selector () const
3294 return *_playlist_selector;
3298 Editor::get_nudge_distance (nframes_t pos, nframes_t& next)
3302 ret = nudge_clock.current_duration (pos);
3303 next = ret + 1; /* XXXX fix me */
3309 Editor::end_location_changed (Location* location)
3311 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3312 reset_scrolling_region ();
3316 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3318 ArdourDialog dialog ("playlist deletion dialog");
3319 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3320 "If left alone, no audio files used by it will be cleaned.\n"
3321 "If deleted, audio files used by it alone by will cleaned."),
3324 dialog.set_position (WIN_POS_CENTER);
3325 dialog.get_vbox()->pack_start (label);
3329 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3330 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3331 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3333 switch (dialog.run ()) {
3334 case RESPONSE_ACCEPT:
3335 /* delete the playlist */
3339 case RESPONSE_REJECT:
3340 /* keep the playlist */
3352 Editor::audio_region_selection_covers (nframes_t where)
3354 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3355 if ((*a)->region()->covers (where)) {
3364 Editor::prepare_for_cleanup ()
3366 cut_buffer->clear_regions ();
3367 cut_buffer->clear_playlists ();
3369 selection->clear_regions ();
3370 selection->clear_playlists ();
3374 Editor::transport_loop_location()
3377 return session->locations()->auto_loop_location();
3384 Editor::transport_punch_location()
3387 return session->locations()->auto_punch_location();
3394 Editor::control_layout_scroll (GdkEventScroll* ev)
3396 switch (ev->direction) {
3398 scroll_tracks_up_line ();
3402 case GDK_SCROLL_DOWN:
3403 scroll_tracks_down_line ();
3407 /* no left/right handling yet */
3415 /** A new snapshot has been selected.
3418 Editor::snapshot_display_selection_changed ()
3420 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
3422 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
3424 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
3426 if (snap_name.length() == 0) {
3430 if (session->snap_name() == snap_name) {
3434 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
3439 Editor::snapshot_display_button_press (GdkEventButton* ev)
3441 if (ev->button == 3) {
3442 /* Right-click on the snapshot list. Work out which snapshot it
3444 Gtk::TreeModel::Path path;
3445 Gtk::TreeViewColumn* col;
3448 snapshot_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, col, cx, cy);
3449 Gtk::TreeModel::iterator iter = snapshot_display_model->get_iter (path);
3451 Gtk::TreeModel::Row row = *iter;
3452 popup_snapshot_context_menu (ev->button, ev->time, row[snapshot_display_columns.real_name]);
3461 /** Pop up the snapshot display context menu.
3462 * @param button Button used to open the menu.
3463 * @param time Menu open time.
3464 * @snapshot_name Name of the snapshot that the menu click was over.
3468 Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring snapshot_name)
3470 using namespace Menu_Helpers;
3472 MenuList& items (snapshot_context_menu.items());
3475 const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
3477 add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
3479 add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
3481 snapshot_context_menu.popup (button, time);
3485 Editor::rename_snapshot (Glib::ustring old_name)
3487 ArdourPrompter prompter(true);
3491 prompter.set_name ("Prompter");
3492 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3493 prompter.set_prompt (_("New name of snapshot"));
3494 prompter.set_initial_text (old_name);
3496 if (prompter.run() == RESPONSE_ACCEPT) {
3497 prompter.get_result (new_name);
3498 if (new_name.length()) {
3499 session->rename_state (old_name, new_name);
3500 redisplay_snapshots ();
3507 Editor::remove_snapshot (Glib::ustring name)
3509 vector<string> choices;
3511 std::string prompt = string_compose (_("Do you really want to remove snapshot \"%1\" ?\n(cannot be undone)"), name);
3513 choices.push_back (_("No, do nothing."));
3514 choices.push_back (_("Yes, remove it."));
3516 Gtkmm2ext::Choice prompter (prompt, choices);
3518 if (prompter.run () == 1) {
3519 session->remove_state (name);
3520 redisplay_snapshots ();
3525 Editor::redisplay_snapshots ()
3531 vector<sys::path> state_file_paths;
3533 get_state_files_in_directory (session->session_directory().root_path(),
3536 if (state_file_paths.empty()) return;
3538 vector<string> state_file_names(get_file_names_no_extension(state_file_paths));
3540 snapshot_display_model->clear ();
3542 for (vector<string>::iterator i = state_file_names.begin();
3543 i != state_file_names.end(); ++i)
3545 string statename = (*i);
3546 TreeModel::Row row = *(snapshot_display_model->append());
3548 /* this lingers on in case we ever want to change the visible
3549 name of the snapshot.
3552 string display_name;
3553 display_name = statename;
3555 if (statename == session->snap_name()) {
3556 snapshot_display.get_selection()->select(row);
3559 row[snapshot_display_columns.visible_name] = display_name;
3560 row[snapshot_display_columns.real_name] = statename;
3565 Editor::session_state_saved (string snap_name)
3567 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
3568 redisplay_snapshots ();
3572 Editor::maximise_editing_space ()
3574 initial_ruler_update_required = true;
3576 mouse_mode_tearoff->set_visible (false);
3577 tools_tearoff->set_visible (false);
3579 pre_maximal_pane_position = edit_pane.get_position();
3580 pre_maximal_editor_width = this->get_width();
3582 if(post_maximal_pane_position == 0) {
3583 post_maximal_pane_position = edit_pane.get_width();
3588 if(post_maximal_editor_width) {
3589 edit_pane.set_position (post_maximal_pane_position -
3590 abs(post_maximal_editor_width - pre_maximal_editor_width));
3592 edit_pane.set_position (post_maximal_pane_position);
3597 Editor::restore_editing_space ()
3599 initial_ruler_update_required = true;
3601 // user changed width of pane during fullscreen
3602 if(post_maximal_pane_position != edit_pane.get_position()) {
3603 post_maximal_pane_position = edit_pane.get_position();
3608 mouse_mode_tearoff->set_visible (true);
3609 tools_tearoff->set_visible (true);
3610 post_maximal_editor_width = this->get_width();
3613 edit_pane.set_position (
3614 pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width)
3619 * Make new playlists for a given track and also any others that belong
3620 * to the same active edit group.
3625 Editor::new_playlists (TimeAxisView* v)
3627 begin_reversible_command (_("new playlists"));
3628 mapover_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist), v);
3629 commit_reversible_command ();
3633 * Use a copy of the current playlist for a given track and also any others that belong
3634 * to the same active edit group.
3639 Editor::copy_playlists (TimeAxisView* v)
3641 begin_reversible_command (_("copy playlists"));
3642 mapover_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist), v);
3643 commit_reversible_command ();
3647 * Clear the current playlist for a given track and also any others that belong
3648 * to the same active edit group.
3653 Editor::clear_playlists (TimeAxisView* v)
3655 begin_reversible_command (_("clear playlists"));
3656 mapover_tracks (mem_fun (*this, &Editor::mapped_clear_playlist), v);
3657 commit_reversible_command ();
3661 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz)
3663 atv.use_new_playlist (sz > 1 ? false : true);
3667 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz)
3669 atv.use_copy_playlist (sz > 1 ? false : true);
3673 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t sz)
3675 atv.clear_playlist ();
3679 Editor::on_key_press_event (GdkEventKey* ev)
3681 return key_press_focus_accelerator_handler (*this, ev);
3685 Editor::reset_x_origin (nframes_t frame)
3687 queue_visual_change (frame);
3691 Editor::reset_zoom (double fpu)
3693 queue_visual_change (fpu);
3697 Editor::reposition_and_zoom (nframes_t frame, double fpu)
3699 reset_x_origin (frame);
3704 Editor::set_frames_per_unit (double fpu)
3708 /* this is the core function that controls the zoom level of the canvas. it is called
3709 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
3712 if (fpu == frames_per_unit) {
3720 // convert fpu to frame count
3722 frames = (nframes_t) floor (fpu * canvas_width);
3724 /* don't allow zooms that fit more than the maximum number
3725 of frames into an 800 pixel wide space.
3728 if (max_frames / fpu < 800.0) {
3732 if (fpu == frames_per_unit) {
3736 frames_per_unit = fpu;
3738 if (frames != zoom_range_clock.current_duration()) {
3739 zoom_range_clock.set (frames);
3742 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
3743 if (!selection->tracks.empty()) {
3744 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3745 (*i)->reshow_selection (selection->time);
3748 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3749 (*i)->reshow_selection (selection->time);
3754 ZoomChanged (); /* EMIT_SIGNAL */
3756 reset_hscrollbar_stepping ();
3757 reset_scrolling_region ();
3759 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
3760 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
3766 Editor::queue_visual_change (nframes_t where)
3768 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::TimeOrigin);
3769 pending_visual_change.time_origin = where;
3771 if (pending_visual_change.idle_handler_id < 0) {
3772 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
3777 Editor::queue_visual_change (double fpu)
3779 pending_visual_change.pending = VisualChange::Type (pending_visual_change.pending | VisualChange::ZoomLevel);
3780 pending_visual_change.frames_per_unit = fpu;
3782 if (pending_visual_change.idle_handler_id < 0) {
3783 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0);
3788 Editor::_idle_visual_changer (void* arg)
3790 return static_cast<Editor*>(arg)->idle_visual_changer ();
3794 Editor::idle_visual_changer ()
3796 VisualChange::Type p = pending_visual_change.pending;
3798 pending_visual_change.pending = (VisualChange::Type) 0;
3799 pending_visual_change.idle_handler_id = -1;
3801 if (p & VisualChange::ZoomLevel) {
3802 set_frames_per_unit (pending_visual_change.frames_per_unit);
3805 if (p & VisualChange::TimeOrigin) {
3806 if (pending_visual_change.time_origin != leftmost_frame) {
3807 horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit);
3808 /* the signal handler will do the rest */
3810 update_fixed_rulers();
3811 redisplay_tempo (true);
3815 return 0; /* this is always a one-shot call */
3818 struct EditorOrderTimeAxisSorter {
3819 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
3820 return a->order < b->order;
3825 Editor::sort_track_selection ()
3827 EditorOrderTimeAxisSorter cmp;
3828 selection->tracks.sort (cmp);
3832 Editor::edit_cursor_position(bool sync)
3834 if (sync && edit_cursor->current_frame != edit_cursor_clock.current_time()) {
3835 edit_cursor_clock.set(edit_cursor->current_frame, true);
3838 return edit_cursor->current_frame;