2 Copyright (C) 2000-2009 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 */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
47 #include <glibmm/miscutils.h>
48 #include <gtkmm/image.h>
49 #include <gdkmm/color.h>
50 #include <gdkmm/bitmap.h>
52 #include <gtkmm2ext/grouped_buttons.h>
53 #include <gtkmm2ext/gtk_ui.h>
54 #include <gtkmm2ext/tearoff.h>
55 #include <gtkmm2ext/utils.h>
56 #include <gtkmm2ext/window_title.h>
57 #include <gtkmm2ext/choice.h>
58 #include <gtkmm2ext/cell_renderer_pixbuf_toggle.h>
60 #include "ardour/audio_diskstream.h"
61 #include "ardour/audio_track.h"
62 #include "ardour/audioplaylist.h"
63 #include "ardour/audioregion.h"
64 #include "ardour/location.h"
65 #include "ardour/midi_region.h"
66 #include "ardour/plugin_manager.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_directory.h"
70 #include "ardour/session_route.h"
71 #include "ardour/session_state_utils.h"
72 #include "ardour/tempo.h"
73 #include "ardour/utils.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/audioengine.h"
77 #include "control_protocol/control_protocol.h"
82 #include "playlist_selector.h"
83 #include "audio_region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "audio_streamview.h"
87 #include "time_axis_view.h"
88 #include "audio_time_axis.h"
90 #include "crossfade_view.h"
91 #include "canvas-noevent-text.h"
93 #include "public_editor.h"
94 #include "crossfade_edit.h"
95 #include "canvas_impl.h"
98 #include "gui_thread.h"
99 #include "simpleline.h"
100 #include "rhythm_ferret.h"
102 #include "tempo_lines.h"
103 #include "analysis_window.h"
104 #include "bundle_manager.h"
105 #include "global_port_matrix.h"
106 #include "editor_drag.h"
107 #include "editor_group_tabs.h"
108 #include "automation_time_axis.h"
109 #include "editor_routes.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "editor_route_groups.h"
113 #include "editor_regions.h"
114 #include "editor_locations.h"
115 #include "editor_snapshots.h"
116 #include "editor_summary.h"
117 #include "region_layering_order_editor.h"
118 #include "mouse_cursors.h"
119 #include "editor_cursors.h"
124 #include "imageframe_socket_handler.h"
128 using namespace ARDOUR
;
131 using namespace Glib
;
132 using namespace Gtkmm2ext
;
133 using namespace Editing
;
135 using PBD::internationalize
;
137 using Gtkmm2ext::Keyboard
;
139 const double Editor::timebar_height
= 15.0;
141 static const gchar
*_snap_type_strings
[] = {
143 N_("Timecode Frames"),
144 N_("Timecode Seconds"),
145 N_("Timecode Minutes"),
173 static const gchar
*_snap_mode_strings
[] = {
180 static const gchar
*_edit_point_strings
[] = {
187 static const gchar
*_zoom_focus_strings
[] = {
197 #ifdef USE_RUBBERBAND
198 static const gchar
*_rb_opt_strings
[] = {
201 N_("Balanced multitimbral mixture"),
202 N_("Unpitched percussion with stable notes"),
203 N_("Crisp monophonic instrumental"),
204 N_("Unpitched solo percussion"),
205 N_("Resample without preserving pitch"),
211 show_me_the_size (Requisition
* r
, const char* what
)
213 cerr
<< "size of " << what
<< " = " << r
->width
<< " x " << r
->height
<< endl
;
218 pane_size_watcher (Paned
* pane
)
220 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
221 it is no longer accessible. so stop that. this doesn't happen on X11,
222 just the quartz backend.
227 int max_width_of_lhs
= GTK_WIDGET(pane
->gobj())->allocation
.width
- 25;
229 gint pos
= pane
->get_position ();
231 if (pos
> max_width_of_lhs
) {
232 pane
->set_position (max_width_of_lhs
);
238 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE
)
240 /* time display buttons */
241 , minsec_label (_("Mins:Secs"))
242 , bbt_label (_("Bars:Beats"))
243 , timecode_label (_("Timecode"))
244 , frame_label (_("Samples"))
245 , tempo_label (_("Tempo"))
246 , meter_label (_("Meter"))
247 , mark_label (_("Location Markers"))
248 , range_mark_label (_("Range Markers"))
249 , transport_mark_label (_("Loop/Punch Ranges"))
250 , cd_mark_label (_("CD Markers"))
251 , edit_packer (4, 4, true)
253 /* the values here don't matter: layout widgets
254 reset them as needed.
257 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
259 /* tool bar related */
261 , zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, false, true)
263 , toolbar_selection_clock_table (2,3)
265 , automation_mode_button (_("mode"))
266 , global_automation_button (_("automation"))
268 , midi_panic_button (_("Panic"))
271 , image_socket_listener(0)
276 , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, false, true)
277 , meters_running(false)
278 , _pending_locate_request (false)
279 , _pending_initial_locate (false)
280 , _last_cut_copy_source_track (0)
282 , _region_selection_change_updates_region_list (true)
286 /* we are a singleton */
288 PublicEditor::_instance
= this;
292 selection
= new Selection (this);
293 cut_buffer
= new Selection (this);
295 clicked_regionview
= 0;
296 clicked_axisview
= 0;
297 clicked_routeview
= 0;
298 clicked_crossfadeview
= 0;
299 clicked_control_point
= 0;
300 last_update_frame
= 0;
301 pre_press_cursor
= 0;
302 _drags
= new DragManager (this);
303 current_mixer_strip
= 0;
304 current_bbt_points
= 0;
307 snap_type_strings
= I18N (_snap_type_strings
);
308 snap_mode_strings
= I18N (_snap_mode_strings
);
309 zoom_focus_strings
= I18N (_zoom_focus_strings
);
310 edit_point_strings
= I18N (_edit_point_strings
);
311 #ifdef USE_RUBBERBAND
312 rb_opt_strings
= I18N (_rb_opt_strings
);
316 snap_threshold
= 5.0;
317 bbt_beat_subdivision
= 4;
320 last_autoscroll_x
= 0;
321 last_autoscroll_y
= 0;
322 autoscroll_active
= false;
323 autoscroll_timeout_tag
= -1;
328 current_interthread_info
= 0;
329 _show_measures
= true;
330 show_gain_after_trim
= false;
331 verbose_cursor_on
= true;
332 last_item_entered
= 0;
334 have_pending_keyboard_selection
= false;
335 _follow_playhead
= true;
336 _stationary_playhead
= false;
337 _xfade_visibility
= true;
338 editor_ruler_menu
= 0;
339 no_ruler_shown_update
= false;
341 session_range_marker_menu
= 0;
342 range_marker_menu
= 0;
343 marker_menu_item
= 0;
344 tempo_or_meter_marker_menu
= 0;
345 transport_marker_menu
= 0;
346 new_transport_marker_menu
= 0;
347 editor_mixer_strip_width
= Wide
;
348 show_editor_mixer_when_tracks_arrive
= false;
349 region_edit_menu_split_multichannel_item
= 0;
350 region_edit_menu_split_item
= 0;
353 current_stepping_trackview
= 0;
355 entered_regionview
= 0;
357 clear_entered_track
= false;
360 button_release_can_deselect
= true;
361 _dragging_playhead
= false;
362 _dragging_edit_point
= false;
363 select_new_marker
= false;
365 layering_order_editor
= 0;
367 no_save_visual
= false;
370 scrubbing_direction
= 0;
374 location_marker_color
= ARDOUR_UI::config()->canvasvar_LocationMarker
.get();
375 location_range_color
= ARDOUR_UI::config()->canvasvar_LocationRange
.get();
376 location_cd_marker_color
= ARDOUR_UI::config()->canvasvar_LocationCDMarker
.get();
377 location_loop_color
= ARDOUR_UI::config()->canvasvar_LocationLoop
.get();
378 location_punch_color
= ARDOUR_UI::config()->canvasvar_LocationPunch
.get();
380 _edit_point
= EditAtMouse
;
381 _internal_editing
= false;
382 current_canvas_cursor
= 0;
384 frames_per_unit
= 2048; /* too early to use reset_zoom () */
386 _scroll_callbacks
= 0;
388 zoom_focus
= ZoomFocusLeft
;
389 set_zoom_focus (ZoomFocusLeft
);
390 zoom_range_clock
.ValueChanged
.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed
));
392 bbt_label
.set_name ("EditorTimeButton");
393 bbt_label
.set_size_request (-1, (int)timebar_height
);
394 bbt_label
.set_alignment (1.0, 0.5);
395 bbt_label
.set_padding (5,0);
397 bbt_label
.set_no_show_all();
398 minsec_label
.set_name ("EditorTimeButton");
399 minsec_label
.set_size_request (-1, (int)timebar_height
);
400 minsec_label
.set_alignment (1.0, 0.5);
401 minsec_label
.set_padding (5,0);
402 minsec_label
.hide ();
403 minsec_label
.set_no_show_all();
404 timecode_label
.set_name ("EditorTimeButton");
405 timecode_label
.set_size_request (-1, (int)timebar_height
);
406 timecode_label
.set_alignment (1.0, 0.5);
407 timecode_label
.set_padding (5,0);
408 timecode_label
.hide ();
409 timecode_label
.set_no_show_all();
410 frame_label
.set_name ("EditorTimeButton");
411 frame_label
.set_size_request (-1, (int)timebar_height
);
412 frame_label
.set_alignment (1.0, 0.5);
413 frame_label
.set_padding (5,0);
415 frame_label
.set_no_show_all();
417 tempo_label
.set_name ("EditorTimeButton");
418 tempo_label
.set_size_request (-1, (int)timebar_height
);
419 tempo_label
.set_alignment (1.0, 0.5);
420 tempo_label
.set_padding (5,0);
422 tempo_label
.set_no_show_all();
423 meter_label
.set_name ("EditorTimeButton");
424 meter_label
.set_size_request (-1, (int)timebar_height
);
425 meter_label
.set_alignment (1.0, 0.5);
426 meter_label
.set_padding (5,0);
428 meter_label
.set_no_show_all();
429 mark_label
.set_name ("EditorTimeButton");
430 mark_label
.set_size_request (-1, (int)timebar_height
);
431 mark_label
.set_alignment (1.0, 0.5);
432 mark_label
.set_padding (5,0);
434 mark_label
.set_no_show_all();
435 cd_mark_label
.set_name ("EditorTimeButton");
436 cd_mark_label
.set_size_request (-1, (int)timebar_height
);
437 cd_mark_label
.set_alignment (1.0, 0.5);
438 cd_mark_label
.set_padding (5,0);
439 cd_mark_label
.hide();
440 cd_mark_label
.set_no_show_all();
441 range_mark_label
.set_name ("EditorTimeButton");
442 range_mark_label
.set_size_request (-1, (int)timebar_height
);
443 range_mark_label
.set_alignment (1.0, 0.5);
444 range_mark_label
.set_padding (5,0);
445 range_mark_label
.hide();
446 range_mark_label
.set_no_show_all();
447 transport_mark_label
.set_name ("EditorTimeButton");
448 transport_mark_label
.set_size_request (-1, (int)timebar_height
);
449 transport_mark_label
.set_alignment (1.0, 0.5);
450 transport_mark_label
.set_padding (5,0);
451 transport_mark_label
.hide();
452 transport_mark_label
.set_no_show_all();
454 initialize_rulers ();
455 initialize_canvas ();
456 _summary
= new EditorSummary (this);
458 selection
->TimeChanged
.connect (sigc::mem_fun(*this, &Editor::time_selection_changed
));
459 selection
->TracksChanged
.connect (sigc::mem_fun(*this, &Editor::track_selection_changed
));
460 editor_regions_selection_changed_connection
= selection
->RegionsChanged
.connect (sigc::mem_fun(*this, &Editor::region_selection_changed
));
461 selection
->PointsChanged
.connect (sigc::mem_fun(*this, &Editor::point_selection_changed
));
462 selection
->MarkersChanged
.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed
));
464 edit_controls_vbox
.set_spacing (0);
465 vertical_adjustment
.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling
), true);
466 track_canvas
->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler
));
468 HBox
* h
= manage (new HBox
);
469 _group_tabs
= new EditorGroupTabs (this);
470 h
->pack_start (*_group_tabs
, PACK_SHRINK
);
471 h
->pack_start (edit_controls_vbox
);
472 controls_layout
.add (*h
);
474 controls_layout
.set_name ("EditControlsBase");
475 controls_layout
.add_events (Gdk::SCROLL_MASK
);
476 controls_layout
.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll
), false);
478 controls_layout
.add_events (Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
|Gdk::ENTER_NOTIFY_MASK
|Gdk::LEAVE_NOTIFY_MASK
);
479 controls_layout
.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release
));
480 controls_layout_size_request_connection
= controls_layout
.signal_size_request().connect (sigc::mem_fun (*this, &Editor::controls_layout_size_request
));
482 _cursors
= new MouseCursors
;
484 ArdourCanvas::Canvas
* time_pad
= manage(new ArdourCanvas::Canvas());
485 ArdourCanvas::SimpleLine
* pad_line_1
= manage(new ArdourCanvas::SimpleLine(*time_pad
->root(),
486 0.0, 1.0, 100.0, 1.0));
487 pad_line_1
->property_color_rgba() = 0xFF0000FF;
491 time_canvas_vbox
.set_size_request (-1, (int)(timebar_height
* visible_timebars
) + 2);
492 time_canvas_vbox
.set_size_request (-1, -1);
494 ruler_label_event_box
.add (ruler_label_vbox
);
495 ruler_label_event_box
.set_events (Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
);
496 ruler_label_event_box
.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release
));
498 time_button_event_box
.add (time_button_vbox
);
499 time_button_event_box
.set_events (Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
);
500 time_button_event_box
.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release
));
502 /* these enable us to have a dedicated window (for cursor setting, etc.)
503 for the canvas areas.
506 track_canvas_event_box
.add (*track_canvas
);
508 time_canvas_event_box
.add (time_canvas_vbox
);
509 time_canvas_event_box
.set_events (Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
|Gdk::POINTER_MOTION_MASK
);
511 edit_packer
.set_col_spacings (0);
512 edit_packer
.set_row_spacings (0);
513 edit_packer
.set_homogeneous (false);
514 edit_packer
.set_border_width (0);
515 edit_packer
.set_name ("EditorWindow");
517 /* labels for the rulers */
518 edit_packer
.attach (ruler_label_event_box
, 1, 2, 0, 1, FILL
, SHRINK
, 0, 0);
519 /* labels for the marker "tracks" */
520 edit_packer
.attach (time_button_event_box
, 1, 2, 1, 2, FILL
, SHRINK
, 0, 0);
522 edit_packer
.attach (time_canvas_event_box
, 2, 3, 0, 1, FILL
|EXPAND
, FILL
, 0, 0);
524 edit_packer
.attach (controls_layout
, 0, 2, 2, 3, FILL
, FILL
|EXPAND
, 0, 0);
526 edit_packer
.attach (track_canvas_event_box
, 2, 3, 1, 3, FILL
|EXPAND
, FILL
|EXPAND
, 0, 0);
528 bottom_hbox
.set_border_width (2);
529 bottom_hbox
.set_spacing (3);
531 _route_groups
= new EditorRouteGroups (this);
532 _routes
= new EditorRoutes (this);
533 _regions
= new EditorRegions (this);
534 _snapshots
= new EditorSnapshots (this);
535 _locations
= new EditorLocations (this);
539 nlabel
= manage (new Label (_("Regions")));
540 nlabel
->set_angle (-90);
541 the_notebook
.append_page (_regions
->widget (), *nlabel
);
542 nlabel
= manage (new Label (_("Tracks & Busses")));
543 nlabel
->set_angle (-90);
544 the_notebook
.append_page (_routes
->widget (), *nlabel
);
545 nlabel
= manage (new Label (_("Snapshots")));
546 nlabel
->set_angle (-90);
547 the_notebook
.append_page (_snapshots
->widget (), *nlabel
);
548 nlabel
= manage (new Label (_("Route Groups")));
549 nlabel
->set_angle (-90);
550 the_notebook
.append_page (_route_groups
->widget (), *nlabel
);
551 nlabel
= manage (new Label (_("Ranges & Marks")));
552 nlabel
->set_angle (-90);
553 the_notebook
.append_page (_locations
->widget (), *nlabel
);
555 the_notebook
.set_show_tabs (true);
556 the_notebook
.set_scrollable (true);
557 the_notebook
.popup_disable ();
558 the_notebook
.set_tab_pos (Gtk::POS_RIGHT
);
559 the_notebook
.show_all ();
561 post_maximal_editor_width
= 0;
562 post_maximal_horizontal_pane_position
= 0;
563 post_maximal_editor_height
= 0;
564 post_maximal_vertical_pane_position
= 0;
566 editor_summary_pane
.pack1(edit_packer
);
568 Button
* summary_arrows_left_left
= manage (new Button
);
569 summary_arrows_left_left
->add (*manage (new Arrow (ARROW_LEFT
, SHADOW_NONE
)));
570 summary_arrows_left_left
->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press
)));
571 summary_arrows_left_left
->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release
));
572 Button
* summary_arrows_left_right
= manage (new Button
);
573 summary_arrows_left_right
->add (*manage (new Arrow (ARROW_RIGHT
, SHADOW_NONE
)));
574 summary_arrows_left_right
->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press
)));
575 summary_arrows_left_right
->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release
));
576 VBox
* summary_arrows_left
= manage (new VBox
);
577 summary_arrows_left
->pack_start (*summary_arrows_left_left
);
578 summary_arrows_left
->pack_start (*summary_arrows_left_right
);
580 Button
* summary_arrows_right_left
= manage (new Button
);
581 summary_arrows_right_left
->add (*manage (new Arrow (ARROW_LEFT
, SHADOW_NONE
)));
582 summary_arrows_right_left
->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press
)));
583 summary_arrows_right_left
->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release
));
584 Button
* summary_arrows_right_right
= manage (new Button
);
585 summary_arrows_right_right
->add (*manage (new Arrow (ARROW_RIGHT
, SHADOW_NONE
)));
586 summary_arrows_right_right
->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press
)));
587 summary_arrows_right_right
->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release
));
588 VBox
* summary_arrows_right
= manage (new VBox
);
589 summary_arrows_right
->pack_start (*summary_arrows_right_left
);
590 summary_arrows_right
->pack_start (*summary_arrows_right_right
);
592 Frame
* summary_frame
= manage (new Frame
);
593 summary_frame
->set_shadow_type (Gtk::SHADOW_ETCHED_IN
);
594 summary_frame
->add (*_summary
);
595 summary_frame
->show ();
597 _summary_hbox
.pack_start (*summary_arrows_left
, false, false);
598 _summary_hbox
.pack_start (*summary_frame
, true, true);
599 _summary_hbox
.pack_start (*summary_arrows_right
, false, false);
601 editor_summary_pane
.pack2 (_summary_hbox
);
603 edit_pane
.pack1 (editor_summary_pane
, true, true);
604 edit_pane
.pack2 (the_notebook
, false, true);
606 editor_summary_pane
.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler
), static_cast<Paned
*> (&editor_summary_pane
)));
608 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
610 edit_pane
.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler
), static_cast<Paned
*> (&edit_pane
)));
612 Glib::PropertyProxy
<int> proxy
= edit_pane
.property_position();
613 proxy
.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher
), static_cast<Paned
*> (&edit_pane
)));
615 top_hbox
.pack_start (toolbar_frame
, false, true);
617 HBox
*hbox
= manage (new HBox
);
618 hbox
->pack_start (edit_pane
, true, true);
620 global_vpacker
.pack_start (top_hbox
, false, false);
621 global_vpacker
.pack_start (*hbox
, true, true);
623 global_hpacker
.pack_start (global_vpacker
, true, true);
625 set_name ("EditorWindow");
626 add_accel_group (ActionManager::ui_manager
->get_accel_group());
628 status_bar_hpacker
.show ();
630 vpacker
.pack_end (status_bar_hpacker
, false, false);
631 vpacker
.pack_end (global_hpacker
, true, true);
633 /* register actions now so that set_state() can find them and set toggles/checks etc */
638 setup_midi_toolbar ();
640 _snap_type
= SnapToBeat
;
641 set_snap_to (_snap_type
);
642 _snap_mode
= SnapOff
;
643 set_snap_mode (_snap_mode
);
644 set_mouse_mode (MouseObject
, true);
645 set_edit_point_preference (EditAtMouse
, true);
647 _playlist_selector
= new PlaylistSelector();
648 _playlist_selector
->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it
), static_cast<Window
*> (_playlist_selector
)));
650 RegionView::RegionViewGoingAway
.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview
, this, _1
), gui_context());
654 nudge_forward_button
.add (*(manage (new Image (::get_icon("nudge_right")))));
655 nudge_backward_button
.add (*(manage (new Image (::get_icon("nudge_left")))));
657 nudge_forward_button
.set_name ("TransportButton");
658 nudge_backward_button
.set_name ("TransportButton");
660 fade_context_menu
.set_name ("ArdourContextMenu");
662 /* icons, titles, WM stuff */
664 list
<Glib::RefPtr
<Gdk::Pixbuf
> > window_icons
;
665 Glib::RefPtr
<Gdk::Pixbuf
> icon
;
667 if ((icon
= ::get_icon ("ardour_icon_16px")) != 0) {
668 window_icons
.push_back (icon
);
670 if ((icon
= ::get_icon ("ardour_icon_22px")) != 0) {
671 window_icons
.push_back (icon
);
673 if ((icon
= ::get_icon ("ardour_icon_32px")) != 0) {
674 window_icons
.push_back (icon
);
676 if ((icon
= ::get_icon ("ardour_icon_48px")) != 0) {
677 window_icons
.push_back (icon
);
679 if (!window_icons
.empty()) {
680 set_icon_list (window_icons
);
681 set_default_icon_list (window_icons
);
684 WindowTitle
title(Glib::get_application_name());
685 title
+= _("Editor");
686 set_title (title
.get_string());
687 set_wmclass (X_("ardour_editor"), PROGRAM_NAME
);
690 add_events (Gdk::KEY_PRESS_MASK
|Gdk::KEY_RELEASE_MASK
);
692 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler
));
693 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close
));
695 /* allow external control surfaces/protocols to do various things */
697 ControlProtocol::ZoomToSession
.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session
, this), gui_context());
698 ControlProtocol::ZoomIn
.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step
, this, false), gui_context());
699 ControlProtocol::ZoomOut
.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step
, this, true), gui_context());
700 ControlProtocol::ScrollTimeline
.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll
, this, _1
), gui_context());
701 BasicUI::AccessAction
.connect (*this, invalidator (*this), ui_bind (&Editor::access_action
, this, _1
, _2
), gui_context());
703 /* problematic: has to return a value and thus cannot be x-thread */
705 Session::AskAboutPlaylistDeletion
.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog
, this, _1
));
707 Config
->ParameterChanged
.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed
, this, _1
), gui_context());
709 TimeAxisView::CatchDeletion
.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted
, this, _1
), gui_context());
711 _ignore_region_action
= false;
712 _last_region_menu_was_main
= false;
713 _popup_region_menu_item
= 0;
715 _show_marker_lines
= false;
716 _over_region_trim_target
= false;
721 setup_fade_images ();
727 if(image_socket_listener
) {
728 if(image_socket_listener
->is_connected())
730 image_socket_listener
->close_connection() ;
733 delete image_socket_listener
;
734 image_socket_listener
= 0 ;
739 delete _route_groups
;
745 Editor::add_toplevel_controls (Container
& cont
)
747 vpacker
.pack_start (cont
, false, false);
752 Editor::catch_vanishing_regionview (RegionView
*rv
)
754 /* note: the selection will take care of the vanishing
755 audioregionview by itself.
758 if (_drags
->active() && _drags
->have_item (rv
->get_canvas_group()) && !_drags
->ending()) {
762 if (clicked_regionview
== rv
) {
763 clicked_regionview
= 0;
766 if (entered_regionview
== rv
) {
767 set_entered_regionview (0);
770 if (!_all_region_actions_sensitized
) {
771 sensitize_all_region_actions (true);
776 Editor::set_entered_regionview (RegionView
* rv
)
778 if (rv
== entered_regionview
) {
782 if (entered_regionview
) {
783 entered_regionview
->exited ();
786 if ((entered_regionview
= rv
) != 0) {
787 entered_regionview
->entered (internal_editing ());
790 if (!_all_region_actions_sensitized
&& _last_region_menu_was_main
) {
791 /* This RegionView entry might have changed what region actions
792 are allowed, so sensitize them all in case a key is pressed.
794 sensitize_all_region_actions (true);
799 Editor::set_entered_track (TimeAxisView
* tav
)
802 entered_track
->exited ();
805 if ((entered_track
= tav
) != 0) {
806 entered_track
->entered ();
811 Editor::show_window ()
813 if (! is_visible ()) {
816 /* re-hide editor list if necessary */
817 editor_list_button_toggled ();
819 /* re-hide summary widget if necessary */
820 parameter_changed ("show-summary");
822 parameter_changed ("show-edit-group-tabs");
824 /* now reset all audio_time_axis heights, because widgets might need
830 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
831 tv
= (static_cast<TimeAxisView
*>(*i
));
840 Editor::instant_save ()
842 if (!constructed
|| !ARDOUR_UI::instance()->session_loaded
) {
847 _session
->add_instant_xml(get_state());
849 Config
->add_instant_xml(get_state());
854 Editor::zoom_adjustment_changed ()
860 double fpu
= zoom_range_clock
.current_duration() / _canvas_width
;
864 zoom_range_clock
.set ((framepos_t
) floor (fpu
* _canvas_width
));
865 } else if (fpu
> _session
->current_end_frame() / _canvas_width
) {
866 fpu
= _session
->current_end_frame() / _canvas_width
;
867 zoom_range_clock
.set ((framepos_t
) floor (fpu
* _canvas_width
));
874 Editor::control_scroll (float fraction
)
876 ENSURE_GUI_THREAD (*this, &Editor::control_scroll
, fraction
)
882 double step
= fraction
* current_page_frames();
885 _control_scroll_target is an optional<T>
887 it acts like a pointer to an framepos_t, with
888 a operator conversion to boolean to check
889 that it has a value could possibly use
890 playhead_cursor->current_frame to store the
891 value and a boolean in the class to know
892 when it's out of date
895 if (!_control_scroll_target
) {
896 _control_scroll_target
= _session
->transport_frame();
897 _dragging_playhead
= true;
900 if ((fraction
< 0.0f
) && (*_control_scroll_target
< (framepos_t
) fabs(step
))) {
901 *_control_scroll_target
= 0;
902 } else if ((fraction
> 0.0f
) && (max_framepos
- *_control_scroll_target
< step
)) {
903 *_control_scroll_target
= max_framepos
- (current_page_frames()*2); // allow room for slop in where the PH is on the screen
905 *_control_scroll_target
+= (framepos_t
) floor (step
);
908 /* move visuals, we'll catch up with it later */
910 playhead_cursor
->set_position (*_control_scroll_target
);
911 UpdateAllTransportClocks (*_control_scroll_target
);
913 if (*_control_scroll_target
> (current_page_frames() / 2)) {
914 /* try to center PH in window */
915 reset_x_origin (*_control_scroll_target
- (current_page_frames()/2));
921 Now we do a timeout to actually bring the session to the right place
922 according to the playhead. This is to avoid reading disk buffers on every
923 call to control_scroll, which is driven by ScrollTimeline and therefore
924 probably by a control surface wheel which can generate lots of events.
926 /* cancel the existing timeout */
928 control_scroll_connection
.disconnect ();
930 /* add the next timeout */
932 control_scroll_connection
= Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll
), *_control_scroll_target
), 250);
936 Editor::deferred_control_scroll (framepos_t
/*target*/)
938 _session
->request_locate (*_control_scroll_target
, _session
->transport_rolling());
939 // reset for next stream
940 _control_scroll_target
= boost::none
;
941 _dragging_playhead
= false;
946 Editor::access_action (std::string action_group
, std::string action_item
)
952 ENSURE_GUI_THREAD (*this, &Editor::access_action
, action_group
, action_item
)
955 act
= ActionManager::get_action( action_group
.c_str(), action_item
.c_str() );
963 Editor::on_realize ()
965 Window::on_realize ();
970 Editor::map_position_change (framepos_t frame
)
972 ENSURE_GUI_THREAD (*this, &Editor::map_position_change
, frame
)
978 if (_follow_playhead
) {
979 center_screen (frame
);
982 playhead_cursor
->set_position (frame
);
986 Editor::center_screen (framepos_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 (framepos_t frame
, float page
)
1004 frame
-= (framepos_t
) page
;
1009 reset_x_origin (frame
);
1014 Editor::update_title ()
1016 ENSURE_GUI_THREAD (*this, &Editor::update_title
)
1019 bool dirty
= _session
->dirty();
1021 string session_name
;
1023 if (_session
->snap_name() != _session
->name()) {
1024 session_name
= _session
->snap_name();
1026 session_name
= _session
->name();
1030 session_name
= "*" + session_name
;
1033 WindowTitle
title(session_name
);
1034 title
+= Glib::get_application_name();
1035 set_title (title
.get_string());
1040 Editor::set_session (Session
*t
)
1042 SessionHandlePtr::set_session (t
);
1048 zoom_range_clock
.set_session (_session
);
1049 _playlist_selector
->set_session (_session
);
1050 nudge_clock
.set_session (_session
);
1051 _summary
->set_session (_session
);
1052 _group_tabs
->set_session (_session
);
1053 _route_groups
->set_session (_session
);
1054 _regions
->set_session (_session
);
1055 _snapshots
->set_session (_session
);
1056 _routes
->set_session (_session
);
1057 _locations
->set_session (_session
);
1059 if (rhythm_ferret
) {
1060 rhythm_ferret
->set_session (_session
);
1063 if (analysis_window
) {
1064 analysis_window
->set_session (_session
);
1068 sfbrowser
->set_session (_session
);
1071 compute_fixed_ruler_scale ();
1073 XMLNode
* node
= ARDOUR_UI::instance()->editor_settings();
1074 set_state (*node
, Stateful::loading_state_version
);
1076 /* catch up with the playhead */
1078 _session
->request_locate (playhead_cursor
->current_frame
);
1079 _pending_initial_locate
= true;
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
->StepEditStatusChange
.connect (_session_connections
, invalidator (*this), ui_bind(&Editor::step_edit_status_change
, this, _1
), gui_context());
1089 _session
->TransportStateChange
.connect (_session_connections
, invalidator (*this), boost::bind (&Editor::map_transport_state
, this), gui_context());
1090 _session
->PositionChanged
.connect (_session_connections
, invalidator (*this), ui_bind (&Editor::map_position_change
, this, _1
), gui_context());
1091 _session
->RouteAdded
.connect (_session_connections
, invalidator (*this), ui_bind (&Editor::handle_new_route
, this, _1
), gui_context());
1092 _session
->DirtyChanged
.connect (_session_connections
, invalidator (*this), boost::bind (&Editor::update_title
, this), gui_context());
1093 _session
->TimecodeOffsetChanged
.connect (_session_connections
, invalidator (*this), boost::bind (&Editor::update_just_timecode
, this), gui_context());
1094 _session
->tempo_map().PropertyChanged
.connect (_session_connections
, invalidator (*this), ui_bind (&Editor::tempo_map_changed
, this, _1
), gui_context());
1095 _session
->Located
.connect (_session_connections
, invalidator (*this), boost::bind (&Editor::located
, this), gui_context());
1096 _session
->config
.ParameterChanged
.connect (_session_connections
, invalidator (*this), ui_bind (&Editor::parameter_changed
, this, _1
), gui_context());
1097 _session
->StateSaved
.connect (_session_connections
, invalidator (*this), ui_bind (&Editor::session_state_saved
, this, _1
), gui_context());
1098 _session
->locations()->added
.connect (_session_connections
, invalidator (*this), ui_bind (&Editor::add_new_location
, this, _1
), gui_context());
1099 _session
->locations()->removed
.connect (_session_connections
, invalidator (*this), ui_bind (&Editor::location_gone
, this, _1
), gui_context());
1100 _session
->locations()->changed
.connect (_session_connections
, invalidator (*this), boost::bind (&Editor::refresh_location_display
, this), gui_context());
1101 _session
->locations()->StateChanged
.connect (_session_connections
, invalidator (*this), ui_bind (&Editor::refresh_location_display_s
, this, _1
), gui_context());
1102 _session
->history().Changed
.connect (_session_connections
, invalidator (*this), boost::bind (&Editor::history_changed
, this), gui_context());
1104 if (Profile
->get_sae()) {
1109 nframes_t pos
= _session
->tempo_map().bbt_duration_at (0, bbt
, 1);
1110 nudge_clock
.set_mode(AudioClock::BBT
);
1111 nudge_clock
.set (pos
, true, 0, AudioClock::BBT
);
1114 nudge_clock
.set (_session
->frame_rate() * 5, true, 0, AudioClock::Timecode
); // default of 5 seconds
1117 playhead_cursor
->canvas_item
.show ();
1119 Location
* loc
= _session
->locations()->auto_loop_location();
1121 loc
= new Location (*_session
, 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 (*_session
, 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 boost::function
<void (string
)> pc (boost::bind (&Editor::parameter_changed
, this, _1
));
1146 Config
->map_parameters (pc
);
1147 _session
->config
.map_parameters (pc
);
1149 refresh_location_display ();
1151 restore_ruler_visibility ();
1152 //tempo_map_changed (PropertyChange (0));
1153 _session
->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks
);
1155 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
1156 (static_cast<TimeAxisView
*>(*i
))->set_samples_per_unit (frames_per_unit
);
1159 super_rapid_screen_update_connection
= ARDOUR_UI::instance()->SuperRapidScreenUpdate
.connect (
1160 sigc::mem_fun (*this, &Editor::super_rapid_screen_update
)
1163 switch (_snap_type
) {
1164 case SnapToRegionStart
:
1165 case SnapToRegionEnd
:
1166 case SnapToRegionSync
:
1167 case SnapToRegionBoundary
:
1168 build_region_boundary_cache ();
1175 /* register for undo history */
1176 _session
->register_with_memento_command_factory(_id
, this);
1178 ActionManager::ui_manager
->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated
));
1180 start_updating_meters ();
1184 Editor::action_pre_activated (Glib::RefPtr
<Action
> const & a
)
1186 if (a
->get_name() == "RegionMenu") {
1187 /* When the main menu's region menu is opened, we setup the actions so that they look right
1188 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1189 so we resensitize all region actions when the entered regionview or the region selection
1190 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1191 happens after the region context menu is opened. So we set a flag here, too.
1195 sensitize_the_right_region_actions ();
1196 _last_region_menu_was_main
= true;
1200 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1202 Editor::popup_fade_context_menu (int button
, int32_t time
, ArdourCanvas::Item
* item
, ItemType item_type
)
1204 using namespace Menu_Helpers
;
1205 AudioRegionView
* arv
= static_cast<AudioRegionView
*> (item
->get_data ("regionview"));
1208 fatal
<< _("programming error: fade in canvas item has no regionview data pointer!") << endmsg
;
1212 MenuList
& items (fade_context_menu
.items());
1216 switch (item_type
) {
1218 case FadeInHandleItem
:
1219 if (arv
->audio_region()->fade_in_active()) {
1220 items
.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active
), false)));
1222 items
.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active
), true)));
1225 items
.push_back (SeparatorElem());
1227 if (Profile
->get_sae()) {
1229 items
.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape
), FadeLinear
)));
1230 items
.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape
), FadeFast
)));
1237 *_fade_in_images
[FadeLinear
],
1238 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape
), FadeLinear
)
1242 dynamic_cast<ImageMenuItem
*>(&items
.back())->set_always_show_image ();
1247 *_fade_in_images
[FadeFast
],
1248 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape
), FadeFast
)
1251 dynamic_cast<ImageMenuItem
*>(&items
.back())->set_always_show_image ();
1256 *_fade_in_images
[FadeLogB
],
1257 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape
), FadeLogB
)
1260 dynamic_cast<ImageMenuItem
*>(&items
.back())->set_always_show_image ();
1265 *_fade_in_images
[FadeLogA
],
1266 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape
), FadeLogA
)
1269 dynamic_cast<ImageMenuItem
*>(&items
.back())->set_always_show_image ();
1274 *_fade_in_images
[FadeSlow
],
1275 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape
), FadeSlow
)
1278 dynamic_cast<ImageMenuItem
*>(&items
.back())->set_always_show_image ();
1284 case FadeOutHandleItem
:
1285 if (arv
->audio_region()->fade_out_active()) {
1286 items
.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active
), false)));
1288 items
.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active
), true)));
1291 items
.push_back (SeparatorElem());
1293 if (Profile
->get_sae()) {
1294 items
.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape
), FadeLinear
)));
1295 items
.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape
), FadeSlow
)));
1301 *_fade_out_images
[FadeLinear
],
1302 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape
), FadeLinear
)
1306 dynamic_cast<ImageMenuItem
*>(&items
.back())->set_always_show_image ();
1311 *_fade_out_images
[FadeFast
],
1312 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape
), FadeSlow
)
1315 dynamic_cast<ImageMenuItem
*>(&items
.back())->set_always_show_image ();
1320 *_fade_out_images
[FadeLogB
],
1321 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape
), FadeLogA
)
1324 dynamic_cast<ImageMenuItem
*>(&items
.back())->set_always_show_image ();
1329 *_fade_out_images
[FadeLogA
],
1330 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape
), FadeLogB
)
1333 dynamic_cast<ImageMenuItem
*>(&items
.back())->set_always_show_image ();
1338 *_fade_out_images
[FadeSlow
],
1339 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape
), FadeFast
)
1342 dynamic_cast<ImageMenuItem
*>(&items
.back())->set_always_show_image ();
1348 fatal
<< _("programming error: ")
1349 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1354 fade_context_menu
.popup (button
, time
);
1358 Editor::popup_track_context_menu (int button
, int32_t time
, ItemType item_type
, bool with_selection
)
1360 using namespace Menu_Helpers
;
1361 Menu
* (Editor::*build_menu_function
)();
1364 switch (item_type
) {
1366 case RegionViewName
:
1367 case RegionViewNameHighlight
:
1368 case LeftFrameHandle
:
1369 case RightFrameHandle
:
1370 if (with_selection
) {
1371 build_menu_function
= &Editor::build_track_selection_context_menu
;
1373 build_menu_function
= &Editor::build_track_region_context_menu
;
1378 if (with_selection
) {
1379 build_menu_function
= &Editor::build_track_selection_context_menu
;
1381 build_menu_function
= &Editor::build_track_context_menu
;
1385 case CrossfadeViewItem
:
1386 build_menu_function
= &Editor::build_track_crossfade_context_menu
;
1390 if (clicked_routeview
->track()) {
1391 build_menu_function
= &Editor::build_track_context_menu
;
1393 build_menu_function
= &Editor::build_track_bus_context_menu
;
1398 /* probably shouldn't happen but if it does, we don't care */
1402 menu
= (this->*build_menu_function
)();
1403 menu
->set_name ("ArdourContextMenu");
1405 /* now handle specific situations */
1407 switch (item_type
) {
1409 case RegionViewName
:
1410 case RegionViewNameHighlight
:
1411 case LeftFrameHandle
:
1412 case RightFrameHandle
:
1413 if (!with_selection
) {
1414 if (region_edit_menu_split_item
) {
1415 if (clicked_regionview
&& clicked_regionview
->region()->covers (get_preferred_edit_position())) {
1416 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions
, true);
1418 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions
, false);
1421 if (region_edit_menu_split_multichannel_item
) {
1422 if (clicked_regionview
&& clicked_regionview
->region()->n_channels() > 1) {
1423 region_edit_menu_split_multichannel_item
->set_sensitive (true);
1425 region_edit_menu_split_multichannel_item
->set_sensitive (false);
1434 case CrossfadeViewItem
:
1441 /* probably shouldn't happen but if it does, we don't care */
1445 if (item_type
!= SelectionItem
&& clicked_routeview
&& clicked_routeview
->audio_track()) {
1447 /* Bounce to disk */
1449 using namespace Menu_Helpers
;
1450 MenuList
& edit_items
= menu
->items();
1452 edit_items
.push_back (SeparatorElem());
1454 switch (clicked_routeview
->audio_track()->freeze_state()) {
1455 case AudioTrack::NoFreeze
:
1456 edit_items
.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route
)));
1459 case AudioTrack::Frozen
:
1460 edit_items
.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route
)));
1463 case AudioTrack::UnFrozen
:
1464 edit_items
.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route
)));
1470 if (item_type
== StreamItem
&& clicked_routeview
) {
1471 clicked_routeview
->build_underlay_menu(menu
);
1474 /* When the region menu is opened, we setup the actions so that they look right
1477 sensitize_the_right_region_actions ();
1478 _last_region_menu_was_main
= false;
1480 menu
->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions
), true));
1481 menu
->popup (button
, time
);
1485 Editor::build_track_context_menu ()
1487 using namespace Menu_Helpers
;
1489 MenuList
& edit_items
= track_context_menu
.items();
1492 add_dstream_context_items (edit_items
);
1493 return &track_context_menu
;
1497 Editor::build_track_bus_context_menu ()
1499 using namespace Menu_Helpers
;
1501 MenuList
& edit_items
= track_context_menu
.items();
1504 add_bus_context_items (edit_items
);
1505 return &track_context_menu
;
1509 Editor::build_track_region_context_menu ()
1511 using namespace Menu_Helpers
;
1512 MenuList
& edit_items
= track_region_context_menu
.items();
1515 /* we've just cleared the track region context menu, so the menu that these
1516 two items were on will have disappeared; stop them dangling.
1518 region_edit_menu_split_item
= 0;
1519 region_edit_menu_split_multichannel_item
= 0;
1521 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (clicked_axisview
);
1524 boost::shared_ptr
<Track
> tr
;
1525 boost::shared_ptr
<Playlist
> pl
;
1527 /* Don't offer a region submenu if we are in internal edit mode, as we don't select regions in this
1528 mode and so offering region context is somewhat confusing.
1530 if ((tr
= rtv
->track()) && ((pl
= tr
->playlist())) && !internal_editing()) {
1531 framepos_t
const framepos
= (framepos_t
) floor ((double) get_preferred_edit_position() * tr
->speed());
1532 uint32_t regions_at
= pl
->count_regions_at (framepos
);
1533 add_region_context_items (edit_items
, regions_at
> 1);
1537 add_dstream_context_items (edit_items
);
1539 return &track_region_context_menu
;
1543 Editor::build_track_crossfade_context_menu ()
1545 using namespace Menu_Helpers
;
1546 MenuList
& edit_items
= track_crossfade_context_menu
.items();
1547 edit_items
.clear ();
1549 AudioTimeAxisView
* atv
= dynamic_cast<AudioTimeAxisView
*> (clicked_axisview
);
1552 boost::shared_ptr
<Track
> tr
;
1553 boost::shared_ptr
<Playlist
> pl
;
1554 boost::shared_ptr
<AudioPlaylist
> apl
;
1556 if ((tr
= atv
->track()) && ((pl
= tr
->playlist()) != 0) && ((apl
= boost::dynamic_pointer_cast
<AudioPlaylist
> (pl
)) != 0)) {
1558 AudioPlaylist::Crossfades xfades
;
1560 apl
->crossfades_at (get_preferred_edit_position (), xfades
);
1562 bool many
= xfades
.size() > 1;
1564 for (AudioPlaylist::Crossfades::iterator i
= xfades
.begin(); i
!= xfades
.end(); ++i
) {
1565 add_crossfade_context_items (atv
->audio_view(), (*i
), edit_items
, many
);
1568 framepos_t framepos
= (framepos_t
) floor ((double) get_preferred_edit_position() * tr
->speed());
1569 uint32_t regions_at
= pl
->count_regions_at (framepos
);
1570 add_region_context_items (edit_items
, regions_at
> 1);
1574 add_dstream_context_items (edit_items
);
1576 return &track_crossfade_context_menu
;
1580 Editor::analyze_region_selection ()
1582 if (analysis_window
== 0) {
1583 analysis_window
= new AnalysisWindow();
1586 analysis_window
->set_session(_session
);
1588 analysis_window
->show_all();
1591 analysis_window
->set_regionmode();
1592 analysis_window
->analyze();
1594 analysis_window
->present();
1598 Editor::analyze_range_selection()
1600 if (analysis_window
== 0) {
1601 analysis_window
= new AnalysisWindow();
1604 analysis_window
->set_session(_session
);
1606 analysis_window
->show_all();
1609 analysis_window
->set_rangemode();
1610 analysis_window
->analyze();
1612 analysis_window
->present();
1616 Editor::build_track_selection_context_menu ()
1618 using namespace Menu_Helpers
;
1619 MenuList
& edit_items
= track_selection_context_menu
.items();
1620 edit_items
.clear ();
1622 add_selection_context_items (edit_items
);
1623 // edit_items.push_back (SeparatorElem());
1624 // add_dstream_context_items (edit_items);
1626 return &track_selection_context_menu
;
1629 /** Add context menu items relevant to crossfades.
1630 * @param edit_items List to add the items to.
1633 Editor::add_crossfade_context_items (AudioStreamView
* /*view*/, boost::shared_ptr
<Crossfade
> xfade
, Menu_Helpers::MenuList
& edit_items
, bool many
)
1635 using namespace Menu_Helpers
;
1636 Menu
*xfade_menu
= manage (new Menu
);
1637 MenuList
& items
= xfade_menu
->items();
1638 xfade_menu
->set_name ("ArdourContextMenu");
1641 if (xfade
->active()) {
1647 items
.push_back (MenuElem (str
, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active
), boost::weak_ptr
<Crossfade
> (xfade
))));
1648 items
.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade
), boost::weak_ptr
<Crossfade
> (xfade
))));
1650 if (xfade
->can_follow_overlap()) {
1652 if (xfade
->following_overlap()) {
1653 str
= _("Convert to Short");
1655 str
= _("Convert to Full");
1658 items
.push_back (MenuElem (str
, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length
), xfade
)));
1662 str
= xfade
->out()->name();
1664 str
+= xfade
->in()->name();
1666 str
= _("Crossfade");
1669 edit_items
.push_back (MenuElem (str
, *xfade_menu
));
1670 edit_items
.push_back (SeparatorElem());
1674 Editor::xfade_edit_left_region ()
1676 if (clicked_crossfadeview
) {
1677 clicked_crossfadeview
->left_view
.show_region_editor ();
1682 Editor::xfade_edit_right_region ()
1684 if (clicked_crossfadeview
) {
1685 clicked_crossfadeview
->right_view
.show_region_editor ();
1690 Editor::add_region_context_items (Menu_Helpers::MenuList
& edit_items
, bool multiple_regions_at_position
)
1692 using namespace Menu_Helpers
;
1694 /* OK, stick the region submenu at the top of the list, and then add
1698 /* we have to hack up the region name because "_" has a special
1699 meaning for menu titles.
1702 RegionSelection rs
= get_regions_from_selection_and_entered ();
1704 string::size_type pos
= 0;
1705 string menu_item_name
= (rs
.size() == 1) ? rs
.front()->region()->name() : _("Selected Regions");
1707 while ((pos
= menu_item_name
.find ("_", pos
)) != string::npos
) {
1708 menu_item_name
.replace (pos
, 1, "__");
1712 if (_popup_region_menu_item
== 0) {
1713 _popup_region_menu_item
= new MenuItem (menu_item_name
);
1714 _popup_region_menu_item
->set_submenu (*dynamic_cast<Menu
*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1715 _popup_region_menu_item
->show ();
1717 _popup_region_menu_item
->set_label (menu_item_name
);
1720 edit_items
.push_back (*_popup_region_menu_item
);
1721 if (multiple_regions_at_position
&& (layering_order_editor
== 0 || !layering_order_editor
->is_visible ())) {
1722 edit_items
.push_back (*manage (_region_actions
->get_action ("choose-top-region")->create_menu_item ()));
1724 edit_items
.push_back (SeparatorElem());
1727 /** Add context menu items relevant to selection ranges.
1728 * @param edit_items List to add the items to.
1731 Editor::add_selection_context_items (Menu_Helpers::MenuList
& edit_items
)
1733 using namespace Menu_Helpers
;
1735 edit_items
.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection
)));
1736 edit_items
.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection
), true)));
1738 edit_items
.push_back (SeparatorElem());
1739 edit_items
.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection
)));
1741 if (!selection
->regions
.empty()) {
1742 edit_items
.push_back (SeparatorElem());
1743 edit_items
.push_back (MenuElem (_("Extend Range to End of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_end_of_region
), false)));
1744 edit_items
.push_back (MenuElem (_("Extend Range to Start of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_start_of_region
), false)));
1747 edit_items
.push_back (SeparatorElem());
1748 edit_items
.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection
)));
1749 edit_items
.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection
)));
1751 edit_items
.push_back (SeparatorElem());
1752 edit_items
.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection
)));
1754 edit_items
.push_back (SeparatorElem());
1755 edit_items
.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection
), false)));
1756 edit_items
.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection
)));
1758 edit_items
.push_back (SeparatorElem());
1759 edit_items
.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection
)));
1761 edit_items
.push_back (SeparatorElem());
1762 edit_items
.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection
)));
1763 edit_items
.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection
)));
1764 edit_items
.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog
), false)));
1766 edit_items
.push_back (SeparatorElem());
1767 edit_items
.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection
), true, false)));
1768 edit_items
.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection
), true, true)));
1769 edit_items
.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection
), false, false)));
1770 edit_items
.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection
), false, true)));
1771 edit_items
.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection
)));
1776 Editor::add_dstream_context_items (Menu_Helpers::MenuList
& edit_items
)
1778 using namespace Menu_Helpers
;
1782 Menu
*play_menu
= manage (new Menu
);
1783 MenuList
& play_items
= play_menu
->items();
1784 play_menu
->set_name ("ArdourContextMenu");
1786 play_items
.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point
)));
1787 play_items
.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start
)));
1788 play_items
.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region
)));
1789 play_items
.push_back (SeparatorElem());
1790 play_items
.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region
), true)));
1792 edit_items
.push_back (MenuElem (_("Play"), *play_menu
));
1796 Menu
*select_menu
= manage (new Menu
);
1797 MenuList
& select_items
= select_menu
->items();
1798 select_menu
->set_name ("ArdourContextMenu");
1800 select_items
.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track
), Selection::Set
)));
1801 select_items
.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all
), Selection::Set
)));
1802 select_items
.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track
)));
1803 select_items
.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection
)));
1804 select_items
.push_back (SeparatorElem());
1805 select_items
.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop
)));
1806 select_items
.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch
)));
1807 select_items
.push_back (SeparatorElem());
1808 select_items
.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit
), true)));
1809 select_items
.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit
), false)));
1810 select_items
.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor
), playhead_cursor
, true)));
1811 select_items
.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor
), playhead_cursor
, false)));
1812 select_items
.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between
), false)));
1813 select_items
.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between
), true)));
1814 select_items
.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between
)));
1816 edit_items
.push_back (MenuElem (_("Select"), *select_menu
));
1820 Menu
*cutnpaste_menu
= manage (new Menu
);
1821 MenuList
& cutnpaste_items
= cutnpaste_menu
->items();
1822 cutnpaste_menu
->set_name ("ArdourContextMenu");
1824 cutnpaste_items
.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut
)));
1825 cutnpaste_items
.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy
)));
1826 cutnpaste_items
.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste
), 1.0f
)));
1828 cutnpaste_items
.push_back (SeparatorElem());
1830 cutnpaste_items
.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions
), ARDOUR::SyncPoint
)));
1831 cutnpaste_items
.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative
), ARDOUR::SyncPoint
)));
1833 edit_items
.push_back (MenuElem (_("Edit"), *cutnpaste_menu
));
1835 /* Adding new material */
1837 edit_items
.push_back (SeparatorElem());
1838 edit_items
.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection
), 1.0f
)));
1839 edit_items
.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action
), ImportToTrack
)));
1843 Menu
*nudge_menu
= manage (new Menu());
1844 MenuList
& nudge_items
= nudge_menu
->items();
1845 nudge_menu
->set_name ("ArdourContextMenu");
1847 edit_items
.push_back (SeparatorElem());
1848 nudge_items
.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track
), false, true))));
1849 nudge_items
.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track
), true, true))));
1850 nudge_items
.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track
), false, false))));
1851 nudge_items
.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track
), true, false))));
1853 edit_items
.push_back (MenuElem (_("Nudge"), *nudge_menu
));
1857 Editor::add_bus_context_items (Menu_Helpers::MenuList
& edit_items
)
1859 using namespace Menu_Helpers
;
1863 Menu
*play_menu
= manage (new Menu
);
1864 MenuList
& play_items
= play_menu
->items();
1865 play_menu
->set_name ("ArdourContextMenu");
1867 play_items
.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point
)));
1868 play_items
.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start
)));
1869 edit_items
.push_back (MenuElem (_("Play"), *play_menu
));
1873 Menu
*select_menu
= manage (new Menu
);
1874 MenuList
& select_items
= select_menu
->items();
1875 select_menu
->set_name ("ArdourContextMenu");
1877 select_items
.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track
), Selection::Set
)));
1878 select_items
.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all
), Selection::Set
)));
1879 select_items
.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track
)));
1880 select_items
.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection
)));
1881 select_items
.push_back (SeparatorElem());
1882 select_items
.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit
), true)));
1883 select_items
.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit
), false)));
1884 select_items
.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor
), playhead_cursor
, true)));
1885 select_items
.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor
), playhead_cursor
, false)));
1887 edit_items
.push_back (MenuElem (_("Select"), *select_menu
));
1891 Menu
*cutnpaste_menu
= manage (new Menu
);
1892 MenuList
& cutnpaste_items
= cutnpaste_menu
->items();
1893 cutnpaste_menu
->set_name ("ArdourContextMenu");
1895 cutnpaste_items
.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut
)));
1896 cutnpaste_items
.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy
)));
1897 cutnpaste_items
.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste
), 1.0f
)));
1899 Menu
*nudge_menu
= manage (new Menu());
1900 MenuList
& nudge_items
= nudge_menu
->items();
1901 nudge_menu
->set_name ("ArdourContextMenu");
1903 edit_items
.push_back (SeparatorElem());
1904 nudge_items
.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track
), false, true))));
1905 nudge_items
.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track
), true, true))));
1906 nudge_items
.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track
), false, false))));
1907 nudge_items
.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track
), true, false))));
1909 edit_items
.push_back (MenuElem (_("Nudge"), *nudge_menu
));
1913 Editor::snap_type() const
1919 Editor::snap_mode() const
1925 Editor::set_snap_to (SnapType st
)
1927 unsigned int snap_ind
= (unsigned int)st
;
1931 if (snap_ind
> snap_type_strings
.size() - 1) {
1933 _snap_type
= (SnapType
)snap_ind
;
1936 string str
= snap_type_strings
[snap_ind
];
1938 if (str
!= snap_type_selector
.get_active_text()) {
1939 snap_type_selector
.set_active_text (str
);
1944 switch (_snap_type
) {
1945 case SnapToBeatDiv32
:
1946 case SnapToBeatDiv28
:
1947 case SnapToBeatDiv24
:
1948 case SnapToBeatDiv20
:
1949 case SnapToBeatDiv16
:
1950 case SnapToBeatDiv14
:
1951 case SnapToBeatDiv12
:
1952 case SnapToBeatDiv10
:
1953 case SnapToBeatDiv8
:
1954 case SnapToBeatDiv7
:
1955 case SnapToBeatDiv6
:
1956 case SnapToBeatDiv5
:
1957 case SnapToBeatDiv4
:
1958 case SnapToBeatDiv3
:
1959 case SnapToBeatDiv2
:
1960 compute_bbt_ruler_scale (leftmost_frame
, leftmost_frame
+ current_page_frames());
1961 update_tempo_based_rulers ();
1964 case SnapToRegionStart
:
1965 case SnapToRegionEnd
:
1966 case SnapToRegionSync
:
1967 case SnapToRegionBoundary
:
1968 build_region_boundary_cache ();
1976 SnapChanged (); /* EMIT SIGNAL */
1980 Editor::set_snap_mode (SnapMode mode
)
1983 string str
= snap_mode_strings
[(int)mode
];
1985 if (str
!= snap_mode_selector
.get_active_text ()) {
1986 snap_mode_selector
.set_active_text (str
);
1992 Editor::set_edit_point_preference (EditPoint ep
, bool force
)
1994 bool changed
= (_edit_point
!= ep
);
1997 string str
= edit_point_strings
[(int)ep
];
1999 if (str
!= edit_point_selector
.get_active_text ()) {
2000 edit_point_selector
.set_active_text (str
);
2003 set_canvas_cursor ();
2005 if (!force
&& !changed
) {
2009 const char* action
=NULL
;
2011 switch (_edit_point
) {
2012 case EditAtPlayhead
:
2013 action
= "edit-at-playhead";
2015 case EditAtSelectedMarker
:
2016 action
= "edit-at-marker";
2019 action
= "edit-at-mouse";
2023 Glib::RefPtr
<Action
> act
= ActionManager::get_action ("Editor", action
);
2025 Glib::RefPtr
<RadioAction
>::cast_dynamic(act
)->set_active (true);
2029 bool in_track_canvas
;
2031 if (!mouse_frame (foo
, in_track_canvas
)) {
2032 in_track_canvas
= false;
2035 reset_canvas_action_sensitivity (in_track_canvas
);
2041 Editor::set_state (const XMLNode
& node
, int /*version*/)
2043 const XMLProperty
* prop
;
2045 int x
, y
, xoff
, yoff
;
2048 if ((prop
= node
.property ("id")) != 0) {
2049 _id
= prop
->value ();
2052 g
.base_width
= default_width
;
2053 g
.base_height
= default_height
;
2059 if ((geometry
= find_named_node (node
, "geometry")) != 0) {
2063 if ((prop
= geometry
->property("x_size")) == 0) {
2064 prop
= geometry
->property ("x-size");
2067 g
.base_width
= atoi(prop
->value());
2069 if ((prop
= geometry
->property("y_size")) == 0) {
2070 prop
= geometry
->property ("y-size");
2073 g
.base_height
= atoi(prop
->value());
2076 if ((prop
= geometry
->property ("x_pos")) == 0) {
2077 prop
= geometry
->property ("x-pos");
2080 x
= atoi (prop
->value());
2083 if ((prop
= geometry
->property ("y_pos")) == 0) {
2084 prop
= geometry
->property ("y-pos");
2087 y
= atoi (prop
->value());
2090 if ((prop
= geometry
->property ("x_off")) == 0) {
2091 prop
= geometry
->property ("x-off");
2094 xoff
= atoi (prop
->value());
2096 if ((prop
= geometry
->property ("y_off")) == 0) {
2097 prop
= geometry
->property ("y-off");
2100 yoff
= atoi (prop
->value());
2104 set_default_size (g
.base_width
, g
.base_height
);
2107 if (_session
&& (prop
= node
.property ("playhead"))) {
2109 sscanf (prop
->value().c_str(), "%" PRIi64
, &pos
);
2110 playhead_cursor
->set_position (pos
);
2112 playhead_cursor
->set_position (0);
2115 if ((prop
= node
.property ("mixer-width"))) {
2116 editor_mixer_strip_width
= Width (string_2_enum (prop
->value(), editor_mixer_strip_width
));
2119 if ((prop
= node
.property ("zoom-focus"))) {
2120 set_zoom_focus ((ZoomFocus
) atoi (prop
->value()));
2123 if ((prop
= node
.property ("zoom"))) {
2124 reset_zoom (PBD::atof (prop
->value()));
2126 reset_zoom (frames_per_unit
);
2129 if ((prop
= node
.property ("snap-to"))) {
2130 set_snap_to ((SnapType
) atoi (prop
->value()));
2133 if ((prop
= node
.property ("snap-mode"))) {
2134 set_snap_mode ((SnapMode
) atoi (prop
->value()));
2137 if ((prop
= node
.property ("mouse-mode"))) {
2138 MouseMode m
= str2mousemode(prop
->value());
2139 set_mouse_mode (m
, true);
2141 set_mouse_mode (MouseObject
, true);
2144 if ((prop
= node
.property ("left-frame")) != 0){
2146 if (sscanf (prop
->value().c_str(), "%" PRId64
, &pos
) == 1) {
2147 reset_x_origin (pos
);
2151 if ((prop
= node
.property ("y-origin")) != 0) {
2152 reset_y_origin (atof (prop
->value ()));
2155 if ((prop
= node
.property ("internal-edit"))) {
2156 bool yn
= string_is_affirmative (prop
->value());
2157 RefPtr
<Action
> act
= ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2159 RefPtr
<ToggleAction
> tact
= RefPtr
<ToggleAction
>::cast_dynamic(act
);
2160 tact
->set_active (!yn
);
2161 tact
->set_active (yn
);
2165 if ((prop
= node
.property ("join-object-range"))) {
2166 join_object_range_button
.set_active (string_is_affirmative (prop
->value ()));
2169 if ((prop
= node
.property ("edit-point"))) {
2170 set_edit_point_preference ((EditPoint
) string_2_enum (prop
->value(), _edit_point
), true);
2173 if ((prop
= node
.property ("show-measures"))) {
2174 bool yn
= string_is_affirmative (prop
->value());
2175 _show_measures
= yn
;
2176 RefPtr
<Action
> act
= ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2178 RefPtr
<ToggleAction
> tact
= RefPtr
<ToggleAction
>::cast_dynamic(act
);
2179 /* do it twice to force the change */
2180 tact
->set_active (!yn
);
2181 tact
->set_active (yn
);
2185 if ((prop
= node
.property ("follow-playhead"))) {
2186 bool yn
= string_is_affirmative (prop
->value());
2187 set_follow_playhead (yn
);
2188 RefPtr
<Action
> act
= ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2190 RefPtr
<ToggleAction
> tact
= RefPtr
<ToggleAction
>::cast_dynamic(act
);
2191 if (tact
->get_active() != yn
) {
2192 tact
->set_active (yn
);
2197 if ((prop
= node
.property ("stationary-playhead"))) {
2198 bool yn
= (prop
->value() == "yes");
2199 set_stationary_playhead (yn
);
2200 RefPtr
<Action
> act
= ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2202 RefPtr
<ToggleAction
> tact
= RefPtr
<ToggleAction
>::cast_dynamic(act
);
2203 if (tact
->get_active() != yn
) {
2204 tact
->set_active (yn
);
2209 if ((prop
= node
.property ("region-list-sort-type"))) {
2210 RegionListSortType st
;
2211 _regions
->reset_sort_type ((RegionListSortType
) string_2_enum (prop
->value(), st
), true);
2214 if ((prop
= node
.property ("xfades-visible"))) {
2215 bool yn
= string_is_affirmative (prop
->value());
2216 _xfade_visibility
= !yn
;
2217 // set_xfade_visibility (yn);
2220 if ((prop
= node
.property ("show-editor-mixer"))) {
2222 Glib::RefPtr
<Action
> act
= ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2225 Glib::RefPtr
<ToggleAction
> tact
= Glib::RefPtr
<ToggleAction
>::cast_dynamic(act
);
2226 bool yn
= string_is_affirmative (prop
->value());
2228 /* do it twice to force the change */
2230 tact
->set_active (!yn
);
2231 tact
->set_active (yn
);
2234 if ((prop
= node
.property ("show-editor-list"))) {
2236 Glib::RefPtr
<Action
> act
= ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2239 Glib::RefPtr
<ToggleAction
> tact
= Glib::RefPtr
<ToggleAction
>::cast_dynamic(act
);
2240 bool yn
= string_is_affirmative (prop
->value());
2242 /* do it twice to force the change */
2244 tact
->set_active (!yn
);
2245 tact
->set_active (yn
);
2248 if ((prop
= node
.property (X_("editor-list-page")))) {
2249 the_notebook
.set_current_page (atoi (prop
->value ()));
2252 if ((prop
= node
.property (X_("show-marker-lines")))) {
2253 Glib::RefPtr
<Action
> act
= ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2255 Glib::RefPtr
<ToggleAction
> tact
= Glib::RefPtr
<ToggleAction
>::cast_dynamic (act
);
2256 bool yn
= string_is_affirmative (prop
->value ());
2258 tact
->set_active (!yn
);
2259 tact
->set_active (yn
);
2262 XMLNodeList children
= node
.children ();
2263 for (XMLNodeList::const_iterator i
= children
.begin(); i
!= children
.end(); ++i
) {
2264 selection
->set_state (**i
, Stateful::current_state_version
);
2265 _regions
->set_state (**i
);
2272 Editor::get_state ()
2274 XMLNode
* node
= new XMLNode ("Editor");
2277 _id
.print (buf
, sizeof (buf
));
2278 node
->add_property ("id", buf
);
2280 if (is_realized()) {
2281 Glib::RefPtr
<Gdk::Window
> win
= get_window();
2283 int x
, y
, xoff
, yoff
, width
, height
;
2284 win
->get_root_origin(x
, y
);
2285 win
->get_position(xoff
, yoff
);
2286 win
->get_size(width
, height
);
2288 XMLNode
* geometry
= new XMLNode ("geometry");
2290 snprintf(buf
, sizeof(buf
), "%d", width
);
2291 geometry
->add_property("x-size", string(buf
));
2292 snprintf(buf
, sizeof(buf
), "%d", height
);
2293 geometry
->add_property("y-size", string(buf
));
2294 snprintf(buf
, sizeof(buf
), "%d", x
);
2295 geometry
->add_property("x-pos", string(buf
));
2296 snprintf(buf
, sizeof(buf
), "%d", y
);
2297 geometry
->add_property("y-pos", string(buf
));
2298 snprintf(buf
, sizeof(buf
), "%d", xoff
);
2299 geometry
->add_property("x-off", string(buf
));
2300 snprintf(buf
, sizeof(buf
), "%d", yoff
);
2301 geometry
->add_property("y-off", string(buf
));
2302 snprintf(buf
,sizeof(buf
), "%d",gtk_paned_get_position (static_cast<Paned
*>(&edit_pane
)->gobj()));
2303 geometry
->add_property("edit-horizontal-pane-pos", string(buf
));
2304 snprintf(buf
,sizeof(buf
), "%d",gtk_paned_get_position (static_cast<Paned
*>(&editor_summary_pane
)->gobj()));
2305 geometry
->add_property("edit-vertical-pane-pos", string(buf
));
2307 node
->add_child_nocopy (*geometry
);
2310 maybe_add_mixer_strip_width (*node
);
2312 snprintf (buf
, sizeof(buf
), "%d", (int) zoom_focus
);
2313 node
->add_property ("zoom-focus", buf
);
2314 snprintf (buf
, sizeof(buf
), "%f", frames_per_unit
);
2315 node
->add_property ("zoom", buf
);
2316 snprintf (buf
, sizeof(buf
), "%d", (int) _snap_type
);
2317 node
->add_property ("snap-to", buf
);
2318 snprintf (buf
, sizeof(buf
), "%d", (int) _snap_mode
);
2319 node
->add_property ("snap-mode", buf
);
2321 node
->add_property ("edit-point", enum_2_string (_edit_point
));
2323 snprintf (buf
, sizeof (buf
), "%" PRIi64
, playhead_cursor
->current_frame
);
2324 node
->add_property ("playhead", buf
);
2325 snprintf (buf
, sizeof (buf
), "%" PRIi64
, leftmost_frame
);
2326 node
->add_property ("left-frame", buf
);
2327 snprintf (buf
, sizeof (buf
), "%f", vertical_adjustment
.get_value ());
2328 node
->add_property ("y-origin", buf
);
2330 node
->add_property ("show-measures", _show_measures
? "yes" : "no");
2331 node
->add_property ("follow-playhead", _follow_playhead
? "yes" : "no");
2332 node
->add_property ("stationary-playhead", _stationary_playhead
? "yes" : "no");
2333 node
->add_property ("xfades-visible", _xfade_visibility
? "yes" : "no");
2334 node
->add_property ("region-list-sort-type", enum_2_string (_regions
->sort_type ()));
2335 node
->add_property ("mouse-mode", enum2str(mouse_mode
));
2336 node
->add_property ("internal-edit", _internal_editing
? "yes" : "no");
2337 node
->add_property ("join-object-range", join_object_range_button
.get_active () ? "yes" : "no");
2339 Glib::RefPtr
<Action
> act
= ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2341 Glib::RefPtr
<ToggleAction
> tact
= Glib::RefPtr
<ToggleAction
>::cast_dynamic(act
);
2342 node
->add_property (X_("show-editor-mixer"), tact
->get_active() ? "yes" : "no");
2345 act
= ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2347 Glib::RefPtr
<ToggleAction
> tact
= Glib::RefPtr
<ToggleAction
>::cast_dynamic(act
);
2348 node
->add_property (X_("show-editor-list"), tact
->get_active() ? "yes" : "no");
2351 snprintf (buf
, sizeof (buf
), "%d", the_notebook
.get_current_page ());
2352 node
->add_property (X_("editor-list-page"), buf
);
2354 node
->add_property (X_("show-marker-lines"), _show_marker_lines
? "yes" : "no");
2356 node
->add_child_nocopy (selection
->get_state ());
2357 node
->add_child_nocopy (_regions
->get_state ());
2364 /** @param y y offset from the top of all trackviews.
2365 * @return pair: TimeAxisView that y is over, layer index.
2366 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2367 * in stacked region display mode, otherwise 0.
2369 std::pair
<TimeAxisView
*, layer_t
>
2370 Editor::trackview_by_y_position (double y
)
2372 for (TrackViewList::iterator iter
= track_views
.begin(); iter
!= track_views
.end(); ++iter
) {
2374 std::pair
<TimeAxisView
*, int> const r
= (*iter
)->covers_y_position (y
);
2380 return std::make_pair ( (TimeAxisView
*) 0, 0);
2383 /** Snap a position to the grid, if appropriate, taking into account current
2384 * grid settings and also the state of any snap modifier keys that may be pressed.
2385 * @param start Position to snap.
2386 * @param event Event to get current key modifier information from, or 0.
2389 Editor::snap_to_with_modifier (framepos_t
& start
, GdkEvent
const * event
, int32_t direction
, bool for_mark
)
2391 if (!_session
|| !event
) {
2395 if (Keyboard::modifier_state_contains (event
->button
.state
, Keyboard::snap_modifier())) {
2396 if (_snap_mode
== SnapOff
) {
2397 snap_to_internal (start
, direction
, for_mark
);
2400 if (_snap_mode
!= SnapOff
) {
2401 snap_to_internal (start
, direction
, for_mark
);
2407 Editor::snap_to (framepos_t
& start
, int32_t direction
, bool for_mark
)
2409 if (!_session
|| _snap_mode
== SnapOff
) {
2413 snap_to_internal (start
, direction
, for_mark
);
2417 Editor::timecode_snap_to_internal (framepos_t
& start
, int32_t direction
, bool /*for_mark*/)
2419 const framepos_t one_timecode_second
= (framepos_t
)(rint(_session
->timecode_frames_per_second()) * _session
->frames_per_timecode_frame());
2420 framepos_t one_timecode_minute
= (framepos_t
)(rint(_session
->timecode_frames_per_second()) * _session
->frames_per_timecode_frame() * 60);
2422 switch (_snap_type
) {
2423 case SnapToTimecodeFrame
:
2424 if (((direction
== 0) && (fmod((double)start
, (double)_session
->frames_per_timecode_frame()) > (_session
->frames_per_timecode_frame() / 2))) || (direction
> 0)) {
2425 start
= (framepos_t
) (ceil ((double) start
/ _session
->frames_per_timecode_frame()) * _session
->frames_per_timecode_frame());
2427 start
= (framepos_t
) (floor ((double) start
/ _session
->frames_per_timecode_frame()) * _session
->frames_per_timecode_frame());
2431 case SnapToTimecodeSeconds
:
2432 if (_session
->timecode_offset_negative())
2434 start
+= _session
->timecode_offset ();
2436 start
-= _session
->timecode_offset ();
2438 if (((direction
== 0) && (start
% one_timecode_second
> one_timecode_second
/ 2)) || direction
> 0) {
2439 start
= (framepos_t
) ceil ((double) start
/ one_timecode_second
) * one_timecode_second
;
2441 start
= (framepos_t
) floor ((double) start
/ one_timecode_second
) * one_timecode_second
;
2444 if (_session
->timecode_offset_negative())
2446 start
-= _session
->timecode_offset ();
2448 start
+= _session
->timecode_offset ();
2452 case SnapToTimecodeMinutes
:
2453 if (_session
->timecode_offset_negative())
2455 start
+= _session
->timecode_offset ();
2457 start
-= _session
->timecode_offset ();
2459 if (((direction
== 0) && (start
% one_timecode_minute
> one_timecode_minute
/ 2)) || direction
> 0) {
2460 start
= (framepos_t
) ceil ((double) start
/ one_timecode_minute
) * one_timecode_minute
;
2462 start
= (framepos_t
) floor ((double) start
/ one_timecode_minute
) * one_timecode_minute
;
2464 if (_session
->timecode_offset_negative())
2466 start
-= _session
->timecode_offset ();
2468 start
+= _session
->timecode_offset ();
2472 fatal
<< "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg
;
2478 Editor::snap_to_internal (framepos_t
& start
, int32_t direction
, bool for_mark
)
2480 const framepos_t one_second
= _session
->frame_rate();
2481 const framepos_t one_minute
= _session
->frame_rate() * 60;
2482 framepos_t presnap
= start
;
2486 switch (_snap_type
) {
2487 case SnapToTimecodeFrame
:
2488 case SnapToTimecodeSeconds
:
2489 case SnapToTimecodeMinutes
:
2490 return timecode_snap_to_internal (start
, direction
, for_mark
);
2493 if (((direction
== 0) && (start
% (one_second
/75) > (one_second
/75) / 2)) || (direction
> 0)) {
2494 start
= (framepos_t
) ceil ((double) start
/ (one_second
/ 75)) * (one_second
/ 75);
2496 start
= (framepos_t
) floor ((double) start
/ (one_second
/ 75)) * (one_second
/ 75);
2501 if (((direction
== 0) && (start
% one_second
> one_second
/ 2)) || (direction
> 0)) {
2502 start
= (framepos_t
) ceil ((double) start
/ one_second
) * one_second
;
2504 start
= (framepos_t
) floor ((double) start
/ one_second
) * one_second
;
2509 if (((direction
== 0) && (start
% one_minute
> one_minute
/ 2)) || (direction
> 0)) {
2510 start
= (framepos_t
) ceil ((double) start
/ one_minute
) * one_minute
;
2512 start
= (framepos_t
) floor ((double) start
/ one_minute
) * one_minute
;
2517 start
= _session
->tempo_map().round_to_bar (start
, direction
);
2521 start
= _session
->tempo_map().round_to_beat (start
, direction
);
2524 case SnapToBeatDiv32
:
2525 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 32, direction
);
2527 case SnapToBeatDiv28
:
2528 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 28, direction
);
2530 case SnapToBeatDiv24
:
2531 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 24, direction
);
2533 case SnapToBeatDiv20
:
2534 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 20, direction
);
2536 case SnapToBeatDiv16
:
2537 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 16, direction
);
2539 case SnapToBeatDiv14
:
2540 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 14, direction
);
2542 case SnapToBeatDiv12
:
2543 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 12, direction
);
2545 case SnapToBeatDiv10
:
2546 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 10, direction
);
2548 case SnapToBeatDiv8
:
2549 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 8, direction
);
2551 case SnapToBeatDiv7
:
2552 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 7, direction
);
2554 case SnapToBeatDiv6
:
2555 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 6, direction
);
2557 case SnapToBeatDiv5
:
2558 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 5, direction
);
2560 case SnapToBeatDiv4
:
2561 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 4, direction
);
2563 case SnapToBeatDiv3
:
2564 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 3, direction
);
2566 case SnapToBeatDiv2
:
2567 start
= _session
->tempo_map().round_to_beat_subdivision (start
, 2, direction
);
2575 _session
->locations()->marks_either_side (start
, before
, after
);
2577 if (before
== max_framepos
) {
2579 } else if (after
== max_framepos
) {
2581 } else if (before
!= max_framepos
&& after
!= max_framepos
) {
2582 /* have before and after */
2583 if ((start
- before
) < (after
- start
)) {
2592 case SnapToRegionStart
:
2593 case SnapToRegionEnd
:
2594 case SnapToRegionSync
:
2595 case SnapToRegionBoundary
:
2596 if (!region_boundary_cache
.empty()) {
2598 vector
<framepos_t
>::iterator prev
= region_boundary_cache
.end ();
2599 vector
<framepos_t
>::iterator next
= region_boundary_cache
.end ();
2601 if (direction
> 0) {
2602 next
= std::upper_bound (region_boundary_cache
.begin(), region_boundary_cache
.end(), start
);
2604 next
= std::lower_bound (region_boundary_cache
.begin(), region_boundary_cache
.end(), start
);
2607 if (next
!= region_boundary_cache
.begin ()) {
2612 framepos_t
const p
= (prev
== region_boundary_cache
.end()) ? region_boundary_cache
.front () : *prev
;
2613 framepos_t
const n
= (next
== region_boundary_cache
.end()) ? region_boundary_cache
.back () : *next
;
2615 if (start
> (p
+ n
) / 2) {
2624 switch (_snap_mode
) {
2630 if (presnap
> start
) {
2631 if (presnap
> (start
+ unit_to_frame(snap_threshold
))) {
2635 } else if (presnap
< start
) {
2636 if (presnap
< (start
- unit_to_frame(snap_threshold
))) {
2642 /* handled at entry */
2650 Editor::setup_toolbar ()
2654 /* Mode Buttons (tool selection) */
2656 mouse_move_button
.set_relief(Gtk::RELIEF_NONE
);
2657 mouse_select_button
.set_relief(Gtk::RELIEF_NONE
);
2658 mouse_gain_button
.set_relief(Gtk::RELIEF_NONE
);
2659 mouse_zoom_button
.set_relief(Gtk::RELIEF_NONE
);
2660 mouse_timefx_button
.set_relief(Gtk::RELIEF_NONE
);
2661 mouse_audition_button
.set_relief(Gtk::RELIEF_NONE
);
2662 // internal_edit_button.set_relief(Gtk::RELIEF_NONE);
2663 join_object_range_button
.set_relief(Gtk::RELIEF_NONE
);
2665 HBox
* mode_box
= manage(new HBox
);
2666 mode_box
->set_border_width (2);
2667 mode_box
->set_spacing(4);
2669 /* table containing mode buttons */
2671 HBox
* mouse_mode_button_box
= manage (new HBox ());
2673 if (Profile
->get_sae()) {
2674 mouse_mode_button_box
->pack_start (mouse_move_button
);
2676 mouse_mode_button_box
->pack_start (mouse_move_button
);
2677 mouse_mode_button_box
->pack_start (join_object_range_button
);
2678 mouse_mode_button_box
->pack_start (mouse_select_button
);
2681 mouse_mode_button_box
->pack_start (mouse_zoom_button
);
2683 if (!Profile
->get_sae()) {
2684 mouse_mode_button_box
->pack_start (mouse_gain_button
);
2687 mouse_mode_button_box
->pack_start (mouse_timefx_button
);
2688 mouse_mode_button_box
->pack_start (mouse_audition_button
);
2689 mouse_mode_button_box
->pack_start (internal_edit_button
);
2691 vector
<string
> edit_mode_strings
;
2692 edit_mode_strings
.push_back (edit_mode_to_string (Slide
));
2693 if (!Profile
->get_sae()) {
2694 edit_mode_strings
.push_back (edit_mode_to_string (Splice
));
2696 edit_mode_strings
.push_back (edit_mode_to_string (Lock
));
2698 edit_mode_selector
.set_name ("EditModeSelector");
2699 set_popdown_strings (edit_mode_selector
, edit_mode_strings
, true);
2700 edit_mode_selector
.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done
));
2702 mode_box
->pack_start (edit_mode_selector
);
2703 mode_box
->pack_start (*mouse_mode_button_box
);
2705 _mouse_mode_tearoff
= manage (new TearOff (*mode_box
));
2706 _mouse_mode_tearoff
->set_name ("MouseModeBase");
2707 _mouse_mode_tearoff
->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press
), &_mouse_mode_tearoff
->tearoff_window()), false);
2709 if (Profile
->get_sae()) {
2710 _mouse_mode_tearoff
->set_can_be_torn_off (false);
2713 _mouse_mode_tearoff
->Detach
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff
), static_cast<Box
*>(&toolbar_hbox
),
2714 &_mouse_mode_tearoff
->tearoff_window()));
2715 _mouse_mode_tearoff
->Attach
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff
), static_cast<Box
*> (&toolbar_hbox
),
2716 &_mouse_mode_tearoff
->tearoff_window(), 1));
2717 _mouse_mode_tearoff
->Hidden
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff
), static_cast<Box
*>(&toolbar_hbox
),
2718 &_mouse_mode_tearoff
->tearoff_window()));
2719 _mouse_mode_tearoff
->Visible
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff
), static_cast<Box
*> (&toolbar_hbox
),
2720 &_mouse_mode_tearoff
->tearoff_window(), 1));
2722 mouse_move_button
.set_mode (false);
2723 mouse_select_button
.set_mode (false);
2724 mouse_gain_button
.set_mode (false);
2725 mouse_zoom_button
.set_mode (false);
2726 mouse_timefx_button
.set_mode (false);
2727 mouse_audition_button
.set_mode (false);
2728 join_object_range_button
.set_mode (false);
2730 mouse_move_button
.set_name ("MouseModeButton");
2731 mouse_select_button
.set_name ("MouseModeButton");
2732 mouse_gain_button
.set_name ("MouseModeButton");
2733 mouse_zoom_button
.set_name ("MouseModeButton");
2734 mouse_timefx_button
.set_name ("MouseModeButton");
2735 mouse_audition_button
.set_name ("MouseModeButton");
2736 internal_edit_button
.set_name ("MouseModeButton");
2737 join_object_range_button
.set_name ("MouseModeButton");
2739 mouse_move_button
.unset_flags (CAN_FOCUS
);
2740 mouse_select_button
.unset_flags (CAN_FOCUS
);
2741 mouse_gain_button
.unset_flags (CAN_FOCUS
);
2742 mouse_zoom_button
.unset_flags (CAN_FOCUS
);
2743 mouse_timefx_button
.unset_flags (CAN_FOCUS
);
2744 mouse_audition_button
.unset_flags (CAN_FOCUS
);
2745 internal_edit_button
.unset_flags (CAN_FOCUS
);
2746 join_object_range_button
.unset_flags (CAN_FOCUS
);
2750 _zoom_box
.set_spacing (1);
2751 _zoom_box
.set_border_width (0);
2753 zoom_in_button
.set_name ("EditorTimeButton");
2754 zoom_in_button
.set_image (*(manage (new Image (Stock::ZOOM_IN
, Gtk::ICON_SIZE_MENU
))));
2755 zoom_in_button
.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step
), false));
2757 zoom_out_button
.set_name ("EditorTimeButton");
2758 zoom_out_button
.set_image (*(manage (new Image (Stock::ZOOM_OUT
, Gtk::ICON_SIZE_MENU
))));
2759 zoom_out_button
.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step
), true));
2761 zoom_out_full_button
.set_name ("EditorTimeButton");
2762 zoom_out_full_button
.set_image (*(manage (new Image (Stock::ZOOM_100
, Gtk::ICON_SIZE_MENU
))));
2763 zoom_out_full_button
.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session
));
2765 zoom_focus_selector
.set_name ("ZoomFocusSelector");
2766 set_popdown_strings (zoom_focus_selector
, zoom_focus_strings
, true);
2767 zoom_focus_selector
.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done
));
2769 _zoom_box
.pack_start (zoom_out_button
, false, false);
2770 _zoom_box
.pack_start (zoom_in_button
, false, false);
2771 _zoom_box
.pack_start (zoom_out_full_button
, false, false);
2773 _zoom_box
.pack_start (zoom_focus_selector
);
2775 /* Track zoom buttons */
2776 tav_expand_button
.set_name ("TrackHeightButton");
2777 tav_expand_button
.set_size_request(-1,20);
2778 tav_expand_button
.add (*(manage (new Image (::get_icon("tav_exp")))));
2779 tav_expand_button
.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step
), true));
2781 tav_shrink_button
.set_name ("TrackHeightButton");
2782 tav_shrink_button
.set_size_request(-1,20);
2783 tav_shrink_button
.add (*(manage (new Image (::get_icon("tav_shrink")))));
2784 tav_shrink_button
.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step
), false));
2786 _zoom_box
.pack_start (tav_shrink_button
);
2787 _zoom_box
.pack_start (tav_expand_button
);
2789 _zoom_tearoff
= manage (new TearOff (_zoom_box
));
2791 _zoom_tearoff
->Detach
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff
), static_cast<Box
*>(&toolbar_hbox
),
2792 &_zoom_tearoff
->tearoff_window()));
2793 _zoom_tearoff
->Attach
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff
), static_cast<Box
*> (&toolbar_hbox
),
2794 &_zoom_tearoff
->tearoff_window(), 0));
2795 _zoom_tearoff
->Hidden
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff
), static_cast<Box
*>(&toolbar_hbox
),
2796 &_zoom_tearoff
->tearoff_window()));
2797 _zoom_tearoff
->Visible
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff
), static_cast<Box
*> (&toolbar_hbox
),
2798 &_zoom_tearoff
->tearoff_window(), 0));
2800 snap_box
.set_spacing (1);
2801 snap_box
.set_border_width (2);
2803 snap_type_selector
.set_name ("SnapTypeSelector");
2804 set_popdown_strings (snap_type_selector
, snap_type_strings
, true);
2805 snap_type_selector
.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done
));
2807 snap_mode_selector
.set_name ("SnapModeSelector");
2808 set_popdown_strings (snap_mode_selector
, snap_mode_strings
, true);
2809 snap_mode_selector
.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done
));
2811 edit_point_selector
.set_name ("EditPointSelector");
2812 set_popdown_strings (edit_point_selector
, edit_point_strings
, true);
2813 edit_point_selector
.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done
));
2815 snap_box
.pack_start (snap_mode_selector
, false, false);
2816 snap_box
.pack_start (snap_type_selector
, false, false);
2817 snap_box
.pack_start (edit_point_selector
, false, false);
2821 HBox
*nudge_box
= manage (new HBox
);
2822 nudge_box
->set_spacing(1);
2823 nudge_box
->set_border_width (2);
2825 nudge_forward_button
.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release
), false);
2826 nudge_backward_button
.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release
), false);
2828 nudge_box
->pack_start (nudge_backward_button
, false, false);
2829 nudge_box
->pack_start (nudge_forward_button
, false, false);
2830 nudge_box
->pack_start (nudge_clock
, false, false);
2833 /* Pack everything in... */
2835 HBox
* hbox
= manage (new HBox
);
2836 hbox
->set_spacing(10);
2838 _tools_tearoff
= manage (new TearOff (*hbox
));
2839 _tools_tearoff
->set_name ("MouseModeBase");
2840 _tools_tearoff
->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press
), &_tools_tearoff
->tearoff_window()), false);
2842 if (Profile
->get_sae()) {
2843 _tools_tearoff
->set_can_be_torn_off (false);
2846 _tools_tearoff
->Detach
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff
), static_cast<Box
*>(&toolbar_hbox
),
2847 &_tools_tearoff
->tearoff_window()));
2848 _tools_tearoff
->Attach
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff
), static_cast<Box
*> (&toolbar_hbox
),
2849 &_tools_tearoff
->tearoff_window(), 0));
2850 _tools_tearoff
->Hidden
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff
), static_cast<Box
*>(&toolbar_hbox
),
2851 &_tools_tearoff
->tearoff_window()));
2852 _tools_tearoff
->Visible
.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff
), static_cast<Box
*> (&toolbar_hbox
),
2853 &_tools_tearoff
->tearoff_window(), 0));
2855 toolbar_hbox
.set_spacing (10);
2856 toolbar_hbox
.set_border_width (1);
2858 toolbar_hbox
.pack_start (*_mouse_mode_tearoff
, false, false);
2859 toolbar_hbox
.pack_start (*_zoom_tearoff
, false, false);
2860 toolbar_hbox
.pack_start (*_tools_tearoff
, false, false);
2862 hbox
->pack_start (snap_box
, false, false);
2863 hbox
->pack_start (*nudge_box
, false, false);
2864 hbox
->pack_start (panic_box
, false, false);
2868 toolbar_base
.set_name ("ToolBarBase");
2869 toolbar_base
.add (toolbar_hbox
);
2871 toolbar_frame
.set_shadow_type (SHADOW_OUT
);
2872 toolbar_frame
.set_name ("BaseFrame");
2873 toolbar_frame
.add (toolbar_base
);
2877 Editor::setup_tooltips ()
2879 ARDOUR_UI::instance()->set_tip (mouse_move_button
, _("Select/Move Objects"));
2880 ARDOUR_UI::instance()->set_tip (mouse_gain_button
, _("Draw Region Gain"));
2881 ARDOUR_UI::instance()->set_tip (mouse_zoom_button
, _("Select Zoom Range"));
2882 ARDOUR_UI::instance()->set_tip (mouse_timefx_button
, _("Stretch/Shrink Regions and MIDI Notes"));
2883 ARDOUR_UI::instance()->set_tip (mouse_audition_button
, _("Listen to Specific Regions"));
2884 ARDOUR_UI::instance()->set_tip (join_object_range_button
, _("Select/Move Objects or Ranges"));
2885 ARDOUR_UI::instance()->set_tip (internal_edit_button
, _("Edit Region Contents (e.g. notes)"));
2886 ARDOUR_UI::instance()->set_tip (*_group_tabs
, _("Groups: click to (de)activate\nContext-click for other operations"));
2887 ARDOUR_UI::instance()->set_tip (nudge_forward_button
, _("Nudge Region/Selection Forwards"));
2888 ARDOUR_UI::instance()->set_tip (nudge_backward_button
, _("Nudge Region/Selection Backwards"));
2889 ARDOUR_UI::instance()->set_tip (zoom_in_button
, _("Zoom In"));
2890 ARDOUR_UI::instance()->set_tip (zoom_out_button
, _("Zoom Out"));
2891 ARDOUR_UI::instance()->set_tip (zoom_out_full_button
, _("Zoom to Session"));
2892 ARDOUR_UI::instance()->set_tip (zoom_focus_selector
, _("Zoom focus"));
2893 ARDOUR_UI::instance()->set_tip (tav_expand_button
, _("Expand Tracks"));
2894 ARDOUR_UI::instance()->set_tip (tav_shrink_button
, _("Shrink Tracks"));
2895 ARDOUR_UI::instance()->set_tip (snap_type_selector
, _("Snap/Grid Units"));
2896 ARDOUR_UI::instance()->set_tip (snap_mode_selector
, _("Snap/Grid Mode"));
2897 ARDOUR_UI::instance()->set_tip (edit_point_selector
, _("Edit point"));
2898 ARDOUR_UI::instance()->set_tip (midi_sound_notes
, _("Sound Notes"));
2899 ARDOUR_UI::instance()->set_tip (midi_panic_button
, _("Send note off and reset controller messages on all MIDI channels"));
2900 ARDOUR_UI::instance()->set_tip (edit_mode_selector
, _("Edit Mode"));
2904 Editor::midi_panic ()
2906 cerr
<< "MIDI panic\n";
2909 _session
->midi_panic();
2914 Editor::setup_midi_toolbar ()
2918 /* Midi sound notes */
2919 midi_sound_notes
.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
2920 midi_sound_notes
.set_relief(Gtk::RELIEF_NONE
);
2921 midi_sound_notes
.unset_flags (CAN_FOCUS
);
2925 act
= ActionManager::get_action (X_("MIDI"), X_("panic"));
2926 midi_panic_button
.set_name("MidiPanicButton");
2927 act
->connect_proxy (midi_panic_button
);
2929 panic_box
.pack_start (midi_sound_notes
, true, true);
2930 panic_box
.pack_start (midi_panic_button
, true, true);
2934 Editor::convert_drop_to_paths (
2935 vector
<string
>& paths
,
2936 const RefPtr
<Gdk::DragContext
>& /*context*/,
2939 const SelectionData
& data
,
2943 if (_session
== 0) {
2947 vector
<string
> uris
= data
.get_uris();
2951 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2952 are actually URI lists. So do it by hand.
2955 if (data
.get_target() != "text/plain") {
2959 /* Parse the "uri-list" format that Nautilus provides,
2960 where each pathname is delimited by \r\n.
2962 THERE MAY BE NO NULL TERMINATING CHAR!!!
2965 string txt
= data
.get_text();
2969 p
= (const char *) malloc (txt
.length() + 1);
2970 txt
.copy ((char *) p
, txt
.length(), 0);
2971 ((char*)p
)[txt
.length()] = '\0';
2977 while (g_ascii_isspace (*p
))
2981 while (*q
&& (*q
!= '\n') && (*q
!= '\r')) {
2988 while (q
> p
&& g_ascii_isspace (*q
))
2993 uris
.push_back (string (p
, q
- p
+ 1));
2997 p
= strchr (p
, '\n');
3009 for (vector
<string
>::iterator i
= uris
.begin(); i
!= uris
.end(); ++i
) {
3011 if ((*i
).substr (0,7) == "file://") {
3014 PBD::url_decode (p
);
3016 // scan forward past three slashes
3018 string::size_type slashcnt
= 0;
3019 string::size_type n
= 0;
3020 string::iterator x
= p
.begin();
3022 while (slashcnt
< 3 && x
!= p
.end()) {
3025 } else if (slashcnt
== 3) {
3032 if (slashcnt
!= 3 || x
== p
.end()) {
3033 error
<< _("malformed URL passed to drag-n-drop code") << endmsg
;
3037 paths
.push_back (p
.substr (n
- 1));
3045 Editor::new_tempo_section ()
3051 Editor::map_transport_state ()
3053 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state
)
3055 if (_session
&& _session
->transport_stopped()) {
3056 have_pending_keyboard_selection
= false;
3059 update_loop_range_view (true);
3064 Editor::State::State (PublicEditor
const * e
)
3066 selection
= new Selection (e
);
3069 Editor::State::~State ()
3075 Editor::begin_reversible_command (string name
)
3078 _session
->begin_reversible_command (name
);
3083 Editor::commit_reversible_command ()
3086 _session
->commit_reversible_command ();
3091 Editor::set_route_group_solo (Route
& route
, bool yn
)
3093 RouteGroup
*route_group
;
3095 if ((route_group
= route
.route_group()) != 0) {
3096 route_group
->apply (&Route::set_solo
, yn
, this);
3098 route
.set_solo (yn
, this);
3103 Editor::set_route_group_mute (Route
& route
, bool yn
)
3105 RouteGroup
*route_group
= 0;
3107 if ((route_group
= route
.route_group()) != 0) {
3108 route_group
->apply (&Route::set_mute
, yn
, this);
3110 route
.set_mute (yn
, this);
3115 Editor::history_changed ()
3119 if (undo_action
&& _session
) {
3120 if (_session
->undo_depth() == 0) {
3123 label
= string_compose(_("Undo (%1)"), _session
->next_undo());
3125 undo_action
->property_label() = label
;
3128 if (redo_action
&& _session
) {
3129 if (_session
->redo_depth() == 0) {
3132 label
= string_compose(_("Redo (%1)"), _session
->next_redo());
3134 redo_action
->property_label() = label
;
3139 Editor::duplicate_dialog (bool with_dialog
)
3143 if (mouse_mode
== MouseRange
) {
3144 if (selection
->time
.length() == 0) {
3149 RegionSelection rs
= get_regions_from_selection_and_entered ();
3151 if (mouse_mode
!= MouseRange
&& rs
.empty()) {
3157 ArdourDialog
win (_("Duplicate"));
3158 Label
label (_("Number of duplications:"));
3159 Adjustment
adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3160 SpinButton
spinner (adjustment
, 0.0, 1);
3163 win
.get_vbox()->set_spacing (12);
3164 win
.get_vbox()->pack_start (hbox
);
3165 hbox
.set_border_width (6);
3166 hbox
.pack_start (label
, PACK_EXPAND_PADDING
, 12);
3168 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3169 place, visually. so do this by hand.
3172 hbox
.pack_start (spinner
, PACK_EXPAND_PADDING
, 12);
3173 spinner
.signal_activate().connect (sigc::bind (sigc::mem_fun (win
, &ArdourDialog::response
), RESPONSE_ACCEPT
));
3174 spinner
.grab_focus();
3180 win
.add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
3181 win
.add_button (_("Duplicate"), RESPONSE_ACCEPT
);
3182 win
.set_default_response (RESPONSE_ACCEPT
);
3184 win
.set_position (WIN_POS_MOUSE
);
3186 spinner
.grab_focus ();
3188 switch (win
.run ()) {
3189 case RESPONSE_ACCEPT
:
3195 times
= adjustment
.get_value();
3198 if (mouse_mode
== MouseRange
) {
3199 duplicate_selection (times
);
3201 duplicate_some_regions (rs
, times
);
3206 Editor::show_verbose_canvas_cursor ()
3208 verbose_canvas_cursor
->raise_to_top();
3209 verbose_canvas_cursor
->show();
3210 verbose_cursor_visible
= true;
3214 Editor::hide_verbose_canvas_cursor ()
3216 verbose_canvas_cursor
->hide();
3217 verbose_cursor_visible
= false;
3221 Editor::clamp_verbose_cursor_x (double x
)
3226 x
= min (_canvas_width
- 200.0, x
);
3232 Editor::clamp_verbose_cursor_y (double y
)
3234 if (y
< canvas_timebars_vsize
) {
3235 y
= canvas_timebars_vsize
;
3237 y
= min (_canvas_height
- 50, y
);
3243 Editor::show_verbose_canvas_cursor_with (const string
& txt
, int32_t xoffset
, int32_t yoffset
)
3245 verbose_canvas_cursor
->property_text() = txt
.c_str();
3250 track_canvas
->get_pointer (x
, y
);
3251 track_canvas
->window_to_world (x
, y
, wx
, wy
);
3256 /* don't get too close to the edge */
3257 verbose_canvas_cursor
->property_x() = clamp_verbose_cursor_x (wx
);
3258 verbose_canvas_cursor
->property_y() = clamp_verbose_cursor_y (wy
);
3260 show_verbose_canvas_cursor ();
3264 Editor::set_verbose_canvas_cursor (const string
& txt
, double x
, double y
)
3266 verbose_canvas_cursor
->property_text() = txt
.c_str();
3267 /* don't get too close to the edge */
3268 verbose_canvas_cursor
->property_x() = clamp_verbose_cursor_x (x
);
3269 verbose_canvas_cursor
->property_y() = clamp_verbose_cursor_y (y
);
3273 Editor::set_verbose_canvas_cursor_text (const string
& txt
)
3275 verbose_canvas_cursor
->property_text() = txt
.c_str();
3279 Editor::set_edit_mode (EditMode m
)
3281 Config
->set_edit_mode (m
);
3285 Editor::cycle_edit_mode ()
3287 switch (Config
->get_edit_mode()) {
3289 if (Profile
->get_sae()) {
3290 Config
->set_edit_mode (Lock
);
3292 Config
->set_edit_mode (Splice
);
3296 Config
->set_edit_mode (Lock
);
3299 Config
->set_edit_mode (Slide
);
3305 Editor::edit_mode_selection_done ()
3307 Config
->set_edit_mode (string_to_edit_mode (edit_mode_selector
.get_active_text ()));
3311 Editor::snap_type_selection_done ()
3313 string choice
= snap_type_selector
.get_active_text();
3314 SnapType snaptype
= SnapToBeat
;
3316 if (choice
== _("Beats/2")) {
3317 snaptype
= SnapToBeatDiv2
;
3318 } else if (choice
== _("Beats/3")) {
3319 snaptype
= SnapToBeatDiv3
;
3320 } else if (choice
== _("Beats/4")) {
3321 snaptype
= SnapToBeatDiv4
;
3322 } else if (choice
== _("Beats/5")) {
3323 snaptype
= SnapToBeatDiv5
;
3324 } else if (choice
== _("Beats/6")) {
3325 snaptype
= SnapToBeatDiv6
;
3326 } else if (choice
== _("Beats/7")) {
3327 snaptype
= SnapToBeatDiv7
;
3328 } else if (choice
== _("Beats/8")) {
3329 snaptype
= SnapToBeatDiv8
;
3330 } else if (choice
== _("Beats/10")) {
3331 snaptype
= SnapToBeatDiv10
;
3332 } else if (choice
== _("Beats/12")) {
3333 snaptype
= SnapToBeatDiv12
;
3334 } else if (choice
== _("Beats/14")) {
3335 snaptype
= SnapToBeatDiv14
;
3336 } else if (choice
== _("Beats/16")) {
3337 snaptype
= SnapToBeatDiv16
;
3338 } else if (choice
== _("Beats/20")) {
3339 snaptype
= SnapToBeatDiv20
;
3340 } else if (choice
== _("Beats/24")) {
3341 snaptype
= SnapToBeatDiv24
;
3342 } else if (choice
== _("Beats/28")) {
3343 snaptype
= SnapToBeatDiv28
;
3344 } else if (choice
== _("Beats/32")) {
3345 snaptype
= SnapToBeatDiv32
;
3346 } else if (choice
== _("Beats")) {
3347 snaptype
= SnapToBeat
;
3348 } else if (choice
== _("Bars")) {
3349 snaptype
= SnapToBar
;
3350 } else if (choice
== _("Marks")) {
3351 snaptype
= SnapToMark
;
3352 } else if (choice
== _("Region starts")) {
3353 snaptype
= SnapToRegionStart
;
3354 } else if (choice
== _("Region ends")) {
3355 snaptype
= SnapToRegionEnd
;
3356 } else if (choice
== _("Region bounds")) {
3357 snaptype
= SnapToRegionBoundary
;
3358 } else if (choice
== _("Region syncs")) {
3359 snaptype
= SnapToRegionSync
;
3360 } else if (choice
== _("CD Frames")) {
3361 snaptype
= SnapToCDFrame
;
3362 } else if (choice
== _("Timecode Frames")) {
3363 snaptype
= SnapToTimecodeFrame
;
3364 } else if (choice
== _("Timecode Seconds")) {
3365 snaptype
= SnapToTimecodeSeconds
;
3366 } else if (choice
== _("Timecode Minutes")) {
3367 snaptype
= SnapToTimecodeMinutes
;
3368 } else if (choice
== _("Seconds")) {
3369 snaptype
= SnapToSeconds
;
3370 } else if (choice
== _("Minutes")) {
3371 snaptype
= SnapToMinutes
;
3374 RefPtr
<RadioAction
> ract
= snap_type_action (snaptype
);
3376 ract
->set_active ();
3381 Editor::snap_mode_selection_done ()
3383 string choice
= snap_mode_selector
.get_active_text();
3384 SnapMode mode
= SnapNormal
;
3386 if (choice
== _("No Grid")) {
3388 } else if (choice
== _("Grid")) {
3390 } else if (choice
== _("Magnetic")) {
3391 mode
= SnapMagnetic
;
3394 RefPtr
<RadioAction
> ract
= snap_mode_action (mode
);
3397 ract
->set_active (true);
3402 Editor::cycle_edit_point (bool with_marker
)
3404 switch (_edit_point
) {
3406 set_edit_point_preference (EditAtPlayhead
);
3408 case EditAtPlayhead
:
3410 set_edit_point_preference (EditAtSelectedMarker
);
3412 set_edit_point_preference (EditAtMouse
);
3415 case EditAtSelectedMarker
:
3416 set_edit_point_preference (EditAtMouse
);
3422 Editor::edit_point_selection_done ()
3424 string choice
= edit_point_selector
.get_active_text();
3425 EditPoint ep
= EditAtSelectedMarker
;
3427 if (choice
== _("Marker")) {
3428 set_edit_point_preference (EditAtSelectedMarker
);
3429 } else if (choice
== _("Playhead")) {
3430 set_edit_point_preference (EditAtPlayhead
);
3432 set_edit_point_preference (EditAtMouse
);
3435 RefPtr
<RadioAction
> ract
= edit_point_action (ep
);
3438 ract
->set_active (true);
3443 Editor::zoom_focus_selection_done ()
3445 string choice
= zoom_focus_selector
.get_active_text();
3446 ZoomFocus focus_type
= ZoomFocusLeft
;
3448 if (choice
== _("Left")) {
3449 focus_type
= ZoomFocusLeft
;
3450 } else if (choice
== _("Right")) {
3451 focus_type
= ZoomFocusRight
;
3452 } else if (choice
== _("Center")) {
3453 focus_type
= ZoomFocusCenter
;
3454 } else if (choice
== _("Playhead")) {
3455 focus_type
= ZoomFocusPlayhead
;
3456 } else if (choice
== _("Mouse")) {
3457 focus_type
= ZoomFocusMouse
;
3458 } else if (choice
== _("Edit point")) {
3459 focus_type
= ZoomFocusEdit
;
3462 RefPtr
<RadioAction
> ract
= zoom_focus_action (focus_type
);
3465 ract
->set_active ();
3470 Editor::edit_controls_button_release (GdkEventButton
* ev
)
3472 if (Keyboard::is_context_menu_event (ev
)) {
3473 ARDOUR_UI::instance()->add_route (this);
3479 Editor::mouse_select_button_release (GdkEventButton
* ev
)
3481 /* this handles just right-clicks */
3483 if (ev
->button
!= 3) {
3491 Editor::set_zoom_focus (ZoomFocus f
)
3493 string str
= zoom_focus_strings
[(int)f
];
3495 if (str
!= zoom_focus_selector
.get_active_text()) {
3496 zoom_focus_selector
.set_active_text (str
);
3499 if (zoom_focus
!= f
) {
3502 ZoomFocusChanged (); /* EMIT_SIGNAL */
3509 Editor::ensure_float (Window
& win
)
3511 win
.set_transient_for (*this);
3515 Editor::pane_allocation_handler (Allocation
&alloc
, Paned
* which
)
3517 /* recover or initialize pane positions. do this here rather than earlier because
3518 we don't want the positions to change the child allocations, which they seem to do.
3524 XMLNode
* node
= ARDOUR_UI::instance()->editor_settings();
3536 width
= default_width
;
3537 height
= default_height
;
3539 if ((geometry
= find_named_node (*node
, "geometry")) != 0) {
3541 prop
= geometry
->property ("x-size");
3543 width
= atoi (prop
->value());
3545 prop
= geometry
->property ("y-size");
3547 height
= atoi (prop
->value());
3551 if (which
== static_cast<Paned
*> (&edit_pane
)) {
3553 if (done
& Horizontal
) {
3557 if (!geometry
|| (prop
= geometry
->property ("edit-horizontal-pane-pos")) == 0) {
3558 /* initial allocation is 90% to canvas, 10% to notebook */
3559 pos
= (int) floor (alloc
.get_width() * 0.90f
);
3560 snprintf (buf
, sizeof(buf
), "%d", pos
);
3562 pos
= atoi (prop
->value());
3565 if (GTK_WIDGET(edit_pane
.gobj())->allocation
.width
> pos
) {
3566 edit_pane
.set_position (pos
);
3567 pre_maximal_horizontal_pane_position
= pos
;
3570 done
= (Pane
) (done
| Horizontal
);
3572 } else if (which
== static_cast<Paned
*> (&editor_summary_pane
)) {
3574 if (done
& Vertical
) {
3578 if (!geometry
|| (prop
= geometry
->property ("edit-vertical-pane-pos")) == 0) {
3579 /* initial allocation is 90% to canvas, 10% to summary */
3580 pos
= (int) floor (alloc
.get_height() * 0.90f
);
3581 snprintf (buf
, sizeof(buf
), "%d", pos
);
3583 pos
= atoi (prop
->value());
3586 if (GTK_WIDGET(editor_summary_pane
.gobj())->allocation
.height
> pos
) {
3587 editor_summary_pane
.set_position (pos
);
3588 pre_maximal_vertical_pane_position
= pos
;
3591 done
= (Pane
) (done
| Vertical
);
3596 Editor::detach_tearoff (Box
* /*b*/, Window
* /*w*/)
3598 if (_tools_tearoff
->torn_off() && _mouse_mode_tearoff
->torn_off()) {
3599 top_hbox
.remove (toolbar_frame
);
3604 Editor::reattach_tearoff (Box
* /*b*/, Window
* /*w*/, int32_t /*n*/)
3606 if (toolbar_frame
.get_parent() == 0) {
3607 top_hbox
.pack_end (toolbar_frame
);
3612 Editor::set_show_measures (bool yn
)
3614 if (_show_measures
!= yn
) {
3617 if ((_show_measures
= yn
) == true) {
3619 tempo_lines
->show();
3627 Editor::toggle_follow_playhead ()
3629 RefPtr
<Action
> act
= ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3631 RefPtr
<ToggleAction
> tact
= RefPtr
<ToggleAction
>::cast_dynamic(act
);
3632 set_follow_playhead (tact
->get_active());
3637 Editor::set_follow_playhead (bool yn
)
3639 if (_follow_playhead
!= yn
) {
3640 if ((_follow_playhead
= yn
) == true) {
3642 reset_x_origin_to_follow_playhead ();
3649 Editor::toggle_stationary_playhead ()
3651 RefPtr
<Action
> act
= ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3653 RefPtr
<ToggleAction
> tact
= RefPtr
<ToggleAction
>::cast_dynamic(act
);
3654 set_stationary_playhead (tact
->get_active());
3659 Editor::set_stationary_playhead (bool yn
)
3661 if (_stationary_playhead
!= yn
) {
3662 if ((_stationary_playhead
= yn
) == true) {
3664 // FIXME need a 3.0 equivalent of this 2.X call
3665 // update_current_screen ();
3672 Editor::toggle_xfade_active (boost::weak_ptr
<Crossfade
> wxfade
)
3674 boost::shared_ptr
<Crossfade
> xfade (wxfade
.lock());
3676 xfade
->set_active (!xfade
->active());
3681 Editor::toggle_xfade_length (boost::weak_ptr
<Crossfade
> wxfade
)
3683 boost::shared_ptr
<Crossfade
> xfade (wxfade
.lock());
3685 xfade
->set_follow_overlap (!xfade
->following_overlap());
3690 Editor::edit_xfade (boost::weak_ptr
<Crossfade
> wxfade
)
3692 boost::shared_ptr
<Crossfade
> xfade (wxfade
.lock());
3698 CrossfadeEditor
cew (_session
, xfade
, xfade
->fade_in().get_min_y(), 1.0);
3702 switch (cew
.run ()) {
3703 case RESPONSE_ACCEPT
:
3710 PropertyChange all_crossfade_properties
;
3711 all_crossfade_properties
.add (ARDOUR::Properties::active
);
3712 all_crossfade_properties
.add (ARDOUR::Properties::follow_overlap
);
3713 xfade
->PropertyChanged (all_crossfade_properties
);
3717 Editor::playlist_selector () const
3719 return *_playlist_selector
;
3723 Editor::get_grid_type_as_beats (bool& success
, framepos_t position
)
3727 switch (_snap_type
) {
3732 case SnapToBeatDiv32
:
3735 case SnapToBeatDiv28
:
3738 case SnapToBeatDiv24
:
3741 case SnapToBeatDiv20
:
3744 case SnapToBeatDiv16
:
3747 case SnapToBeatDiv14
:
3750 case SnapToBeatDiv12
:
3753 case SnapToBeatDiv10
:
3756 case SnapToBeatDiv8
:
3759 case SnapToBeatDiv7
:
3762 case SnapToBeatDiv6
:
3765 case SnapToBeatDiv5
:
3768 case SnapToBeatDiv4
:
3771 case SnapToBeatDiv3
:
3774 case SnapToBeatDiv2
:
3780 return _session
->tempo_map().meter_at (position
).beats_per_bar();
3785 case SnapToTimecodeFrame
:
3786 case SnapToTimecodeSeconds
:
3787 case SnapToTimecodeMinutes
:
3790 case SnapToRegionStart
:
3791 case SnapToRegionEnd
:
3792 case SnapToRegionSync
:
3793 case SnapToRegionBoundary
:
3803 Editor::get_nudge_distance (framepos_t pos
, framecnt_t
& next
)
3807 ret
= nudge_clock
.current_duration (pos
);
3808 next
= ret
+ 1; /* XXXX fix me */
3814 Editor::playlist_deletion_dialog (boost::shared_ptr
<Playlist
> pl
)
3816 ArdourDialog
dialog (_("Playlist Deletion"));
3817 Label
label (string_compose (_("Playlist %1 is currently unused.\n"
3818 "If left alone, no audio files used by it will be cleaned.\n"
3819 "If deleted, audio files used by it alone by will cleaned."),
3822 dialog
.set_position (WIN_POS_CENTER
);
3823 dialog
.get_vbox()->pack_start (label
);
3827 dialog
.add_button (_("Delete playlist"), RESPONSE_ACCEPT
);
3828 dialog
.add_button (_("Keep playlist"), RESPONSE_REJECT
);
3829 dialog
.add_button (_("Cancel"), RESPONSE_CANCEL
);
3831 switch (dialog
.run ()) {
3832 case RESPONSE_ACCEPT
:
3833 /* delete the playlist */
3837 case RESPONSE_REJECT
:
3838 /* keep the playlist */
3850 Editor::audio_region_selection_covers (framepos_t where
)
3852 for (RegionSelection::iterator a
= selection
->regions
.begin(); a
!= selection
->regions
.end(); ++a
) {
3853 if ((*a
)->region()->covers (where
)) {
3862 Editor::prepare_for_cleanup ()
3864 cut_buffer
->clear_regions ();
3865 cut_buffer
->clear_playlists ();
3867 selection
->clear_regions ();
3868 selection
->clear_playlists ();
3870 _regions
->suspend_redisplay ();
3874 Editor::finish_cleanup ()
3876 _regions
->resume_redisplay ();
3880 Editor::transport_loop_location()
3883 return _session
->locations()->auto_loop_location();
3890 Editor::transport_punch_location()
3893 return _session
->locations()->auto_punch_location();
3900 Editor::control_layout_scroll (GdkEventScroll
* ev
)
3902 if (Keyboard::some_magic_widget_has_focus()) {
3906 switch (ev
->direction
) {
3908 scroll_tracks_up_line ();
3912 case GDK_SCROLL_DOWN
:
3913 scroll_tracks_down_line ();
3917 /* no left/right handling yet */
3925 Editor::session_state_saved (string
)
3928 _snapshots
->redisplay ();
3932 Editor::maximise_editing_space ()
3934 _mouse_mode_tearoff
->set_visible (false);
3935 _tools_tearoff
->set_visible (false);
3936 _zoom_tearoff
->set_visible (false);
3938 pre_maximal_horizontal_pane_position
= edit_pane
.get_position ();
3939 pre_maximal_vertical_pane_position
= editor_summary_pane
.get_position ();
3940 pre_maximal_editor_width
= this->get_width ();
3941 pre_maximal_editor_height
= this->get_height ();
3943 if (post_maximal_horizontal_pane_position
== 0) {
3944 post_maximal_horizontal_pane_position
= edit_pane
.get_width();
3947 if (post_maximal_vertical_pane_position
== 0) {
3948 post_maximal_vertical_pane_position
= editor_summary_pane
.get_height();
3953 if (post_maximal_editor_width
) {
3954 edit_pane
.set_position (post_maximal_horizontal_pane_position
-
3955 abs(post_maximal_editor_width
- pre_maximal_editor_width
));
3957 edit_pane
.set_position (post_maximal_horizontal_pane_position
);
3960 if (post_maximal_editor_height
) {
3961 editor_summary_pane
.set_position (post_maximal_vertical_pane_position
-
3962 abs(post_maximal_editor_height
- pre_maximal_editor_height
));
3964 editor_summary_pane
.set_position (post_maximal_vertical_pane_position
);
3967 if (Config
->get_keep_tearoffs()) {
3968 _mouse_mode_tearoff
->set_visible (true);
3969 _tools_tearoff
->set_visible (true);
3970 _zoom_tearoff
->set_visible (true);
3976 Editor::restore_editing_space ()
3978 // user changed width/height of panes during fullscreen
3980 if (post_maximal_horizontal_pane_position
!= edit_pane
.get_position()) {
3981 post_maximal_horizontal_pane_position
= edit_pane
.get_position();
3984 if (post_maximal_vertical_pane_position
!= editor_summary_pane
.get_position()) {
3985 post_maximal_vertical_pane_position
= editor_summary_pane
.get_position();
3990 _mouse_mode_tearoff
->set_visible (true);
3991 _tools_tearoff
->set_visible (true);
3992 _zoom_tearoff
->set_visible (true);
3993 post_maximal_editor_width
= this->get_width();
3994 post_maximal_editor_height
= this->get_height();
3996 edit_pane
.set_position (pre_maximal_horizontal_pane_position
+ abs(this->get_width() - pre_maximal_editor_width
));
3997 editor_summary_pane
.set_position (pre_maximal_vertical_pane_position
+ abs(this->get_height() - pre_maximal_editor_height
));
4001 * Make new playlists for a given track and also any others that belong
4002 * to the same active route group with the `edit' property.
4007 Editor::new_playlists (TimeAxisView
* v
)
4009 begin_reversible_command (_("new playlists"));
4010 vector
<boost::shared_ptr
<ARDOUR::Playlist
> > playlists
;
4011 _session
->playlists
->get (playlists
);
4012 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist
), playlists
), v
, ARDOUR::Properties::edit
.property_id
);
4013 commit_reversible_command ();
4017 * Use a copy of the current playlist for a given track and also any others that belong
4018 * to the same active route group with the `edit' property.
4023 Editor::copy_playlists (TimeAxisView
* v
)
4025 begin_reversible_command (_("copy playlists"));
4026 vector
<boost::shared_ptr
<ARDOUR::Playlist
> > playlists
;
4027 _session
->playlists
->get (playlists
);
4028 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist
), playlists
), v
, ARDOUR::Properties::edit
.property_id
);
4029 commit_reversible_command ();
4032 /** Clear the current playlist for a given track and also any others that belong
4033 * to the same active route group with the `edit' property.
4038 Editor::clear_playlists (TimeAxisView
* v
)
4040 begin_reversible_command (_("clear playlists"));
4041 vector
<boost::shared_ptr
<ARDOUR::Playlist
> > playlists
;
4042 _session
->playlists
->get (playlists
);
4043 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist
), v
, ARDOUR::Properties::edit
.property_id
);
4044 commit_reversible_command ();
4048 Editor::mapped_use_new_playlist (RouteTimeAxisView
& atv
, uint32_t sz
, vector
<boost::shared_ptr
<ARDOUR::Playlist
> > const & playlists
)
4050 atv
.use_new_playlist (sz
> 1 ? false : true, playlists
);
4054 Editor::mapped_use_copy_playlist (RouteTimeAxisView
& atv
, uint32_t sz
, vector
<boost::shared_ptr
<ARDOUR::Playlist
> > const & playlists
)
4056 atv
.use_copy_playlist (sz
> 1 ? false : true, playlists
);
4060 Editor::mapped_clear_playlist (RouteTimeAxisView
& atv
, uint32_t /*sz*/)
4062 atv
.clear_playlist ();
4066 Editor::on_key_press_event (GdkEventKey
* ev
)
4068 return key_press_focus_accelerator_handler (*this, ev
);
4072 Editor::on_key_release_event (GdkEventKey
* ev
)
4074 return Gtk::Window::on_key_release_event (ev
);
4075 // return key_press_focus_accelerator_handler (*this, ev);
4078 /** Queue up a change to the viewport x origin.
4079 * @param frame New x origin.
4082 Editor::reset_x_origin (framepos_t frame
)
4084 queue_visual_change (frame
);
4088 Editor::reset_y_origin (double y
)
4090 queue_visual_change_y (y
);
4094 Editor::reset_zoom (double fpu
)
4096 queue_visual_change (fpu
);
4100 Editor::reposition_and_zoom (framepos_t frame
, double fpu
)
4102 reset_x_origin (frame
);
4105 if (!no_save_visual
) {
4106 undo_visual_stack
.push_back (current_visual_state(false));
4110 Editor::VisualState
*
4111 Editor::current_visual_state (bool with_tracks
)
4113 VisualState
* vs
= new VisualState
;
4114 vs
->y_position
= vertical_adjustment
.get_value();
4115 vs
->frames_per_unit
= frames_per_unit
;
4116 vs
->leftmost_frame
= leftmost_frame
;
4117 vs
->zoom_focus
= zoom_focus
;
4120 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
4121 vs
->track_states
.push_back (TAVState ((*i
), &(*i
)->get_state()));
4129 Editor::undo_visual_state ()
4131 if (undo_visual_stack
.empty()) {
4135 redo_visual_stack
.push_back (current_visual_state());
4137 VisualState
* vs
= undo_visual_stack
.back();
4138 undo_visual_stack
.pop_back();
4139 use_visual_state (*vs
);
4143 Editor::redo_visual_state ()
4145 if (redo_visual_stack
.empty()) {
4149 undo_visual_stack
.push_back (current_visual_state());
4151 VisualState
* vs
= redo_visual_stack
.back();
4152 redo_visual_stack
.pop_back();
4153 use_visual_state (*vs
);
4157 Editor::swap_visual_state ()
4159 if (undo_visual_stack
.empty()) {
4160 redo_visual_state ();
4162 undo_visual_state ();
4167 Editor::use_visual_state (VisualState
& vs
)
4169 no_save_visual
= true;
4171 _routes
->suspend_redisplay ();
4173 vertical_adjustment
.set_value (vs
.y_position
);
4175 set_zoom_focus (vs
.zoom_focus
);
4176 reposition_and_zoom (vs
.leftmost_frame
, vs
.frames_per_unit
);
4178 for (list
<TAVState
>::iterator i
= vs
.track_states
.begin(); i
!= vs
.track_states
.end(); ++i
) {
4179 TrackViewList::iterator t
;
4181 /* check if the track still exists - it could have been deleted */
4183 if ((t
= find (track_views
.begin(), track_views
.end(), i
->first
)) != track_views
.end()) {
4184 (*t
)->set_state (*(i
->second
), Stateful::loading_state_version
);
4189 if (!vs
.track_states
.empty()) {
4190 _routes
->update_visibility ();
4193 _routes
->resume_redisplay ();
4195 no_save_visual
= false;
4199 Editor::set_frames_per_unit (double fpu
)
4201 /* this is the core function that controls the zoom level of the canvas. it is called
4202 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4205 if (fpu
== frames_per_unit
) {
4214 /* don't allow zooms that fit more than the maximum number
4215 of frames into an 800 pixel wide space.
4218 if (max_framepos
/ fpu
< 800.0) {
4223 tempo_lines
->tempo_map_changed();
4225 frames_per_unit
= fpu
;
4230 Editor::post_zoom ()
4232 // convert fpu to frame count
4234 framepos_t frames
= (framepos_t
) floor (frames_per_unit
* _canvas_width
);
4236 if (frames_per_unit
!= zoom_range_clock
.current_duration()) {
4237 zoom_range_clock
.set (frames
);
4240 if (mouse_mode
== MouseRange
&& selection
->time
.start () != selection
->time
.end_frame ()) {
4241 for (TrackViewList::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
4242 (*i
)->reshow_selection (selection
->time
);
4246 ZoomChanged (); /* EMIT_SIGNAL */
4248 //reset_scrolling_region ();
4250 if (playhead_cursor
) {
4251 playhead_cursor
->set_position (playhead_cursor
->current_frame
);
4254 refresh_location_display();
4255 _summary
->set_overlays_dirty ();
4257 update_marker_labels ();
4263 Editor::queue_visual_change (framepos_t where
)
4265 pending_visual_change
.add (VisualChange::TimeOrigin
);
4266 pending_visual_change
.time_origin
= where
;
4267 ensure_visual_change_idle_handler ();
4271 Editor::queue_visual_change (double fpu
)
4273 pending_visual_change
.add (VisualChange::ZoomLevel
);
4274 pending_visual_change
.frames_per_unit
= fpu
;
4276 ensure_visual_change_idle_handler ();
4280 Editor::queue_visual_change_y (double y
)
4282 pending_visual_change
.add (VisualChange::YOrigin
);
4283 pending_visual_change
.y_origin
= y
;
4285 ensure_visual_change_idle_handler ();
4289 Editor::ensure_visual_change_idle_handler ()
4291 if (pending_visual_change
.idle_handler_id
< 0) {
4292 pending_visual_change
.idle_handler_id
= g_idle_add (_idle_visual_changer
, this);
4297 Editor::_idle_visual_changer (void* arg
)
4299 return static_cast<Editor
*>(arg
)->idle_visual_changer ();
4303 Editor::idle_visual_changer ()
4305 VisualChange::Type p
= pending_visual_change
.pending
;
4306 pending_visual_change
.pending
= (VisualChange::Type
) 0;
4308 double const last_time_origin
= horizontal_position ();
4310 if (p
& VisualChange::TimeOrigin
) {
4311 /* This is a bit of a hack, but set_frames_per_unit
4312 below will (if called) end up with the
4313 CrossfadeViews looking at Editor::leftmost_frame,
4314 and if we're changing origin and zoom in the same
4315 operation it will be the wrong value unless we
4319 leftmost_frame
= pending_visual_change
.time_origin
;
4322 if (p
& VisualChange::ZoomLevel
) {
4323 set_frames_per_unit (pending_visual_change
.frames_per_unit
);
4325 compute_fixed_ruler_scale ();
4326 compute_current_bbt_points(pending_visual_change
.time_origin
, pending_visual_change
.time_origin
+ current_page_frames());
4327 compute_bbt_ruler_scale (pending_visual_change
.time_origin
, pending_visual_change
.time_origin
+ current_page_frames());
4328 update_tempo_based_rulers ();
4330 if (p
& VisualChange::TimeOrigin
) {
4331 set_horizontal_position (pending_visual_change
.time_origin
/ frames_per_unit
);
4333 if (p
& VisualChange::YOrigin
) {
4334 vertical_adjustment
.set_value (pending_visual_change
.y_origin
);
4337 if (last_time_origin
== horizontal_position ()) {
4338 /* changed signal not emitted */
4339 update_fixed_rulers ();
4340 redisplay_tempo (true);
4343 _summary
->set_overlays_dirty ();
4345 pending_visual_change
.idle_handler_id
= -1;
4346 return 0; /* this is always a one-shot call */
4349 struct EditorOrderTimeAxisSorter
{
4350 bool operator() (const TimeAxisView
* a
, const TimeAxisView
* b
) const {
4351 return a
->order () < b
->order ();
4356 Editor::sort_track_selection (TrackViewList
* sel
)
4358 EditorOrderTimeAxisSorter cmp
;
4363 selection
->tracks
.sort (cmp
);
4368 Editor::get_preferred_edit_position (bool ignore_playhead
)
4371 framepos_t where
= 0;
4372 EditPoint ep
= _edit_point
;
4374 if (entered_marker
) {
4375 return entered_marker
->position();
4378 if (ignore_playhead
&& ep
== EditAtPlayhead
) {
4379 ep
= EditAtSelectedMarker
;
4383 case EditAtPlayhead
:
4384 where
= _session
->audible_frame();
4387 case EditAtSelectedMarker
:
4388 if (!selection
->markers
.empty()) {
4390 Location
* loc
= find_location_from_marker (selection
->markers
.front(), is_start
);
4393 where
= loc
->start();
4404 if (!mouse_frame (where
, ignored
)) {
4405 /* XXX not right but what can we do ? */
4416 Editor::set_loop_range (framepos_t start
, framepos_t end
, string cmd
)
4418 if (!_session
) return;
4420 begin_reversible_command (cmd
);
4424 if ((tll
= transport_loop_location()) == 0) {
4425 Location
* loc
= new Location (*_session
, start
, end
, _("Loop"), Location::IsAutoLoop
);
4426 XMLNode
&before
= _session
->locations()->get_state();
4427 _session
->locations()->add (loc
, true);
4428 _session
->set_auto_loop_location (loc
);
4429 XMLNode
&after
= _session
->locations()->get_state();
4430 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
4432 XMLNode
&before
= tll
->get_state();
4433 tll
->set_hidden (false, this);
4434 tll
->set (start
, end
);
4435 XMLNode
&after
= tll
->get_state();
4436 _session
->add_command (new MementoCommand
<Location
>(*tll
, &before
, &after
));
4439 commit_reversible_command ();
4443 Editor::set_punch_range (framepos_t start
, framepos_t end
, string cmd
)
4445 if (!_session
) return;
4447 begin_reversible_command (cmd
);
4451 if ((tpl
= transport_punch_location()) == 0) {
4452 Location
* loc
= new Location (*_session
, start
, end
, _("Loop"), Location::IsAutoPunch
);
4453 XMLNode
&before
= _session
->locations()->get_state();
4454 _session
->locations()->add (loc
, true);
4455 _session
->set_auto_loop_location (loc
);
4456 XMLNode
&after
= _session
->locations()->get_state();
4457 _session
->add_command (new MementoCommand
<Locations
>(*(_session
->locations()), &before
, &after
));
4460 XMLNode
&before
= tpl
->get_state();
4461 tpl
->set_hidden (false, this);
4462 tpl
->set (start
, end
);
4463 XMLNode
&after
= tpl
->get_state();
4464 _session
->add_command (new MementoCommand
<Location
>(*tpl
, &before
, &after
));
4467 commit_reversible_command ();
4470 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4471 * @param rs List to which found regions are added.
4472 * @param where Time to look at.
4473 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4476 Editor::get_regions_at (RegionSelection
& rs
, framepos_t where
, const TrackViewList
& ts
) const
4478 const TrackViewList
* tracks
;
4481 tracks
= &track_views
;
4486 for (TrackViewList::const_iterator t
= tracks
->begin(); t
!= tracks
->end(); ++t
) {
4487 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*>(*t
);
4489 boost::shared_ptr
<Track
> tr
;
4490 boost::shared_ptr
<Playlist
> pl
;
4492 if ((tr
= rtv
->track()) && ((pl
= tr
->playlist()))) {
4494 Playlist::RegionList
* regions
= pl
->regions_at (
4495 (framepos_t
) floor ( (double)where
* tr
->speed()));
4497 for (Playlist::RegionList::iterator i
= regions
->begin(); i
!= regions
->end(); ++i
) {
4498 RegionView
* rv
= rtv
->view()->find_view (*i
);
4511 Editor::get_regions_after (RegionSelection
& rs
, framepos_t where
, const TrackViewList
& ts
) const
4513 const TrackViewList
* tracks
;
4516 tracks
= &track_views
;
4521 for (TrackViewList::const_iterator t
= tracks
->begin(); t
!= tracks
->end(); ++t
) {
4522 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*>(*t
);
4524 boost::shared_ptr
<Track
> tr
;
4525 boost::shared_ptr
<Playlist
> pl
;
4527 if ((tr
= rtv
->track()) && ((pl
= tr
->playlist()))) {
4529 Playlist::RegionList
* regions
= pl
->regions_touched (
4530 (framepos_t
) floor ( (double)where
* tr
->speed()), max_framepos
);
4532 for (Playlist::RegionList::iterator i
= regions
->begin(); i
!= regions
->end(); ++i
) {
4534 RegionView
* rv
= rtv
->view()->find_view (*i
);
4547 /** Get regions using the following conditions:
4548 * 1. If the edit point is `mouse':
4549 * if the mouse is over a selected region, or no region, return all selected regions.
4550 * if the mouse is over an unselected region, return just that region.
4551 * 2. For all other edit points:
4552 * return the selected regions AND those that are both under the edit position
4553 * AND on a selected track, or on a track which is in the same active edit-enabled route group
4554 * as a selected region.
4556 * The rationale here is that the mouse edit point is special in that its position describes
4557 * both a time and a track; the other edit modes only describe a time.
4559 * @param rs Returned region list.
4563 Editor::get_regions_from_selection_and_edit_point ()
4565 if (_edit_point
== EditAtMouse
) {
4566 if (entered_regionview
== 0 || selection
->regions
.contains (entered_regionview
)) {
4567 return selection
->regions
;
4570 rs
.add (entered_regionview
);
4575 /* We're using the edit point, but its not EditAtMouse */
4577 /* Start with selected regions */
4578 RegionSelection rs
= selection
->regions
;
4580 TrackViewList tracks
= selection
->tracks
;
4582 /* Tracks is currently the set of selected tracks; add any other tracks that
4583 have regions that are in the same edit-activated route group as one of
4586 for (RegionSelection::iterator i
= rs
.begin (); i
!= rs
.end(); ++i
) {
4588 RouteGroup
* g
= (*i
)->get_time_axis_view().route_group ();
4589 if (g
&& g
->is_active() && g
->is_edit()) {
4590 tracks
.add (axis_views_from_routes (g
->route_list()));
4595 if (!tracks
.empty()) {
4596 /* now find regions that are at the edit position on those tracks */
4597 framepos_t
const where
= get_preferred_edit_position ();
4598 get_regions_at (rs
, where
, tracks
);
4606 Editor::get_regions_from_selection_and_entered ()
4608 RegionSelection rs
= selection
->regions
;
4610 if (rs
.empty() && entered_regionview
) {
4611 rs
.add (entered_regionview
);
4618 Editor::get_regions_corresponding_to (boost::shared_ptr
<Region
> region
, vector
<RegionView
*>& regions
)
4620 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
4622 RouteTimeAxisView
* tatv
;
4624 if ((tatv
= dynamic_cast<RouteTimeAxisView
*> (*i
)) != 0) {
4626 boost::shared_ptr
<Playlist
> pl
;
4627 vector
<boost::shared_ptr
<Region
> > results
;
4629 boost::shared_ptr
<Track
> tr
;
4631 if ((tr
= tatv
->track()) == 0) {
4636 if ((pl
= (tr
->playlist())) != 0) {
4637 pl
->get_region_list_equivalent_regions (region
, results
);
4640 for (vector
<boost::shared_ptr
<Region
> >::iterator ir
= results
.begin(); ir
!= results
.end(); ++ir
) {
4641 if ((marv
= tatv
->view()->find_view (*ir
)) != 0) {
4642 regions
.push_back (marv
);
4651 Editor::show_rhythm_ferret ()
4653 if (rhythm_ferret
== 0) {
4654 rhythm_ferret
= new RhythmFerret(*this);
4657 rhythm_ferret
->set_session (_session
);
4658 rhythm_ferret
->show ();
4659 rhythm_ferret
->present ();
4663 Editor::first_idle ()
4665 MessageDialog
* dialog
= 0;
4667 if (track_views
.size() > 1) {
4668 dialog
= new MessageDialog (*this,
4669 string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME
),
4674 ARDOUR_UI::instance()->flush_pending ();
4677 for (TrackViewList::iterator t
= track_views
.begin(); t
!= track_views
.end(); ++t
) {
4681 // first idle adds route children (automation tracks), so we need to redisplay here
4682 _routes
->redisplay ();
4690 Editor::_idle_resize (gpointer arg
)
4692 return ((Editor
*)arg
)->idle_resize ();
4696 Editor::add_to_idle_resize (TimeAxisView
* view
, int32_t h
)
4698 if (resize_idle_id
< 0) {
4699 resize_idle_id
= g_idle_add (_idle_resize
, this);
4700 _pending_resize_amount
= 0;
4703 /* make a note of the smallest resulting height, so that we can clamp the
4704 lower limit at TimeAxisView::hSmall */
4706 int32_t min_resulting
= INT32_MAX
;
4708 _pending_resize_amount
+= h
;
4709 _pending_resize_view
= view
;
4711 min_resulting
= min (min_resulting
, int32_t (_pending_resize_view
->current_height()) + _pending_resize_amount
);
4713 if (selection
->tracks
.contains (_pending_resize_view
)) {
4714 for (TrackViewList::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
4715 min_resulting
= min (min_resulting
, int32_t ((*i
)->current_height()) + _pending_resize_amount
);
4719 if (min_resulting
< 0) {
4724 if (uint32_t (min_resulting
) < TimeAxisView::preset_height (HeightSmall
)) {
4725 _pending_resize_amount
+= TimeAxisView::preset_height (HeightSmall
) - min_resulting
;
4729 /** Handle pending resizing of tracks */
4731 Editor::idle_resize ()
4733 _pending_resize_view
->idle_resize (_pending_resize_view
->current_height() + _pending_resize_amount
);
4735 if (dynamic_cast<AutomationTimeAxisView
*> (_pending_resize_view
) == 0 &&
4736 selection
->tracks
.contains (_pending_resize_view
)) {
4738 for (TrackViewList::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
4739 if (*i
!= _pending_resize_view
) {
4740 (*i
)->idle_resize ((*i
)->current_height() + _pending_resize_amount
);
4745 _pending_resize_amount
= 0;
4747 _group_tabs
->set_dirty ();
4748 resize_idle_id
= -1;
4756 ENSURE_GUI_THREAD (*this, &Editor::located
);
4758 playhead_cursor
->set_position (_session
->audible_frame ());
4759 if (_follow_playhead
&& !_pending_initial_locate
) {
4760 reset_x_origin_to_follow_playhead ();
4763 _pending_locate_request
= false;
4764 _pending_initial_locate
= false;
4768 Editor::region_view_added (RegionView
*)
4770 _summary
->set_dirty ();
4774 Editor::axis_view_from_route (boost::shared_ptr
<Route
> r
) const
4776 TrackViewList::const_iterator j
= track_views
.begin ();
4777 while (j
!= track_views
.end()) {
4778 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (*j
);
4779 if (rtv
&& rtv
->route() == r
) {
4790 Editor::axis_views_from_routes (boost::shared_ptr
<RouteList
> r
) const
4794 for (RouteList::const_iterator i
= r
->begin(); i
!= r
->end(); ++i
) {
4795 TimeAxisView
* tv
= axis_view_from_route (*i
);
4806 Editor::handle_new_route (RouteList
& routes
)
4808 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route
, routes
)
4810 RouteTimeAxisView
*rtv
;
4811 list
<RouteTimeAxisView
*> new_views
;
4813 for (RouteList::iterator x
= routes
.begin(); x
!= routes
.end(); ++x
) {
4814 boost::shared_ptr
<Route
> route
= (*x
);
4816 if (route
->is_hidden() || route
->is_monitor()) {
4820 DataType dt
= route
->input()->default_type();
4822 if (dt
== ARDOUR::DataType::AUDIO
) {
4823 rtv
= new AudioTimeAxisView (*this, _session
, route
, *track_canvas
);
4824 } else if (dt
== ARDOUR::DataType::MIDI
) {
4825 rtv
= new MidiTimeAxisView (*this, _session
, route
, *track_canvas
);
4827 throw unknown_type();
4830 new_views
.push_back (rtv
);
4831 track_views
.push_back (rtv
);
4833 rtv
->effective_gain_display ();
4835 rtv
->view()->RegionViewAdded
.connect (sigc::mem_fun (*this, &Editor::region_view_added
));
4838 _routes
->routes_added (new_views
);
4840 if (show_editor_mixer_when_tracks_arrive
) {
4841 show_editor_mixer (true);
4844 editor_list_button
.set_sensitive (true);
4846 _summary
->set_dirty ();
4850 Editor::timeaxisview_deleted (TimeAxisView
*tv
)
4852 if (_session
&& _session
->deletion_in_progress()) {
4853 /* the situation is under control */
4857 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted
, tv
);
4859 RouteTimeAxisView
* rtav
= dynamic_cast<RouteTimeAxisView
*> (tv
);
4861 _routes
->route_removed (tv
);
4863 if (tv
== entered_track
) {
4867 TimeAxisView::Children c
= tv
->get_child_list ();
4868 for (TimeAxisView::Children::const_iterator i
= c
.begin(); i
!= c
.end(); ++i
) {
4869 if (entered_track
== i
->get()) {
4874 /* remove it from the list of track views */
4876 TrackViewList::iterator i
;
4878 if ((i
= find (track_views
.begin(), track_views
.end(), tv
)) != track_views
.end()) {
4879 i
= track_views
.erase (i
);
4882 /* update whatever the current mixer strip is displaying, if revelant */
4884 boost::shared_ptr
<Route
> route
;
4887 route
= rtav
->route ();
4890 if (current_mixer_strip
&& current_mixer_strip
->route() == route
) {
4892 TimeAxisView
* next_tv
;
4894 if (track_views
.empty()) {
4896 } else if (i
== track_views
.end()) {
4897 next_tv
= track_views
.front();
4904 set_selected_mixer_strip (*next_tv
);
4906 /* make the editor mixer strip go away setting the
4907 * button to inactive (which also unticks the menu option)
4910 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4916 Editor::hide_track_in_display (TimeAxisView
* tv
, bool /*temponly*/)
4918 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
4920 if (rtv
&& current_mixer_strip
&& (rtv
->route() == current_mixer_strip
->route())) {
4921 // this will hide the mixer strip
4922 set_selected_mixer_strip (*tv
);
4925 _routes
->hide_track_in_display (*tv
);
4929 Editor::sync_track_view_list_and_routes ()
4931 track_views
= TrackViewList (_routes
->views ());
4933 _summary
->set_dirty ();
4934 _group_tabs
->set_dirty ();
4936 return false; // do not call again (until needed)
4940 Editor::foreach_time_axis_view (sigc::slot
<void,TimeAxisView
&> theslot
)
4942 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
4947 /** Find a RouteTimeAxisView by the ID of its route */
4949 Editor::get_route_view_by_route_id (PBD::ID
& id
) const
4951 RouteTimeAxisView
* v
;
4953 for (TrackViewList::const_iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
4954 if((v
= dynamic_cast<RouteTimeAxisView
*>(*i
)) != 0) {
4955 if(v
->route()->id() == id
) {
4965 Editor::fit_route_group (RouteGroup
*g
)
4967 TrackViewList ts
= axis_views_from_routes (g
->route_list ());
4972 Editor::consider_auditioning (boost::shared_ptr
<Region
> region
)
4974 boost::shared_ptr
<AudioRegion
> r
= boost::dynamic_pointer_cast
<AudioRegion
> (region
);
4977 _session
->cancel_audition ();
4981 if (_session
->is_auditioning()) {
4982 _session
->cancel_audition ();
4983 if (r
== last_audition_region
) {
4988 _session
->audition_region (r
);
4989 last_audition_region
= r
;
4994 Editor::hide_a_region (boost::shared_ptr
<Region
> r
)
4996 r
->set_hidden (true);
5000 Editor::show_a_region (boost::shared_ptr
<Region
> r
)
5002 r
->set_hidden (false);
5006 Editor::audition_region_from_region_list ()
5008 _regions
->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning
));
5012 Editor::hide_region_from_region_list ()
5014 _regions
->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region
));
5018 Editor::show_region_in_region_list ()
5020 _regions
->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region
));
5024 Editor::step_edit_status_change (bool yn
)
5027 start_step_editing ();
5029 stop_step_editing ();
5034 Editor::start_step_editing ()
5036 step_edit_connection
= Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit
), 20);
5040 Editor::stop_step_editing ()
5042 step_edit_connection
.disconnect ();
5046 Editor::check_step_edit ()
5048 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
5049 MidiTimeAxisView
* mtv
= dynamic_cast<MidiTimeAxisView
*> (*i
);
5051 mtv
->check_step_edit ();
5055 return true; // do it again, till we stop
5059 Editor::horizontal_scroll_left_press ()
5061 ++_scroll_callbacks
;
5063 if (_scroll_connection
.connected() && _scroll_callbacks
< 5) {
5064 /* delay the first auto-repeat */
5068 double x
= leftmost_position() - current_page_frames() / 5;
5075 /* do hacky auto-repeat */
5076 if (!_scroll_connection
.connected ()) {
5077 _scroll_connection
= Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press
), 100);
5078 _scroll_callbacks
= 0;
5085 Editor::horizontal_scroll_left_release ()
5087 _scroll_connection
.disconnect ();
5091 Editor::horizontal_scroll_right_press ()
5093 ++_scroll_callbacks
;
5095 if (_scroll_connection
.connected() && _scroll_callbacks
< 5) {
5096 /* delay the first auto-repeat */
5100 reset_x_origin (leftmost_position() + current_page_frames() / 5);
5102 /* do hacky auto-repeat */
5103 if (!_scroll_connection
.connected ()) {
5104 _scroll_connection
= Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press
), 100);
5105 _scroll_callbacks
= 0;
5112 Editor::horizontal_scroll_right_release ()
5114 _scroll_connection
.disconnect ();
5117 /** Queue a change for the Editor viewport x origin to follow the playhead */
5119 Editor::reset_x_origin_to_follow_playhead ()
5121 framepos_t
const frame
= playhead_cursor
->current_frame
;
5123 if (frame
< leftmost_frame
|| frame
> leftmost_frame
+ current_page_frames()) {
5125 if (_session
->transport_speed() < 0) {
5127 if (frame
> (current_page_frames() / 2)) {
5128 center_screen (frame
-(current_page_frames()/2));
5130 center_screen (current_page_frames()/2);
5135 if (frame
< leftmost_frame
) {
5138 if (_session
->transport_rolling()) {
5139 /* rolling; end up with the playhead at the right of the page */
5140 l
= frame
- current_page_frames ();
5142 /* not rolling: end up with the playhead 3/4 of the way along the page */
5143 l
= frame
- (3 * current_page_frames() / 4);
5150 center_screen_internal (l
+ (current_page_frames() / 2), current_page_frames ());
5153 if (_session
->transport_rolling()) {
5154 /* rolling: end up with the playhead on the left of the page */
5155 center_screen_internal (frame
+ (current_page_frames() / 2), current_page_frames ());
5157 /* not rolling: end up with the playhead 1/4 of the way along the page */
5158 center_screen_internal (frame
+ (current_page_frames() / 4), current_page_frames ());
5166 Editor::super_rapid_screen_update ()
5168 if (!_session
|| !_session
->engine().running()) {
5172 /* METERING / MIXER STRIPS */
5174 /* update track meters, if required */
5175 if (is_mapped() && meters_running
) {
5176 RouteTimeAxisView
* rtv
;
5177 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
5178 if ((rtv
= dynamic_cast<RouteTimeAxisView
*>(*i
)) != 0) {
5179 rtv
->fast_update ();
5184 /* and any current mixer strip */
5185 if (current_mixer_strip
) {
5186 current_mixer_strip
->fast_update ();
5189 /* PLAYHEAD AND VIEWPORT */
5191 framepos_t
const frame
= _session
->audible_frame();
5193 /* There are a few reasons why we might not update the playhead / viewport stuff:
5195 * 1. we don't update things when there's a pending locate request, otherwise
5196 * when the editor requests a locate there is a chance that this method
5197 * will move the playhead before the locate request is processed, causing
5199 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5200 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5203 if (!_pending_locate_request
&& _session
->transport_speed() != 0 && frame
!= last_update_frame
) {
5205 last_update_frame
= frame
;
5207 if (!_dragging_playhead
) {
5208 playhead_cursor
->set_position (frame
);
5211 if (!_stationary_playhead
) {
5213 if (!_dragging_playhead
&& _follow_playhead
&& _session
->requested_return_frame() < 0) {
5214 reset_x_origin_to_follow_playhead ();
5219 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5223 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5224 double target
= ((double)frame
- (double)current_page_frames()/2.0) / frames_per_unit
;
5225 if (target
<= 0.0) {
5228 if (fabs(target
- current
) < current_page_frames() / frames_per_unit
) {
5229 target
= (target
* 0.15) + (current
* 0.85);
5235 set_horizontal_position (current
);
5244 Editor::session_going_away ()
5246 _have_idled
= false;
5248 _session_connections
.drop_connections ();
5250 super_rapid_screen_update_connection
.disconnect ();
5252 selection
->clear ();
5253 cut_buffer
->clear ();
5255 clicked_regionview
= 0;
5256 clicked_axisview
= 0;
5257 clicked_routeview
= 0;
5258 clicked_crossfadeview
= 0;
5259 entered_regionview
= 0;
5261 last_update_frame
= 0;
5264 playhead_cursor
->canvas_item
.hide ();
5266 /* rip everything out of the list displays */
5270 _route_groups
->clear ();
5272 /* do this first so that deleting a track doesn't reset cms to null
5273 and thus cause a leak.
5276 if (current_mixer_strip
) {
5277 if (current_mixer_strip
->get_parent() != 0) {
5278 global_hpacker
.remove (*current_mixer_strip
);
5280 delete current_mixer_strip
;
5281 current_mixer_strip
= 0;
5284 /* delete all trackviews */
5286 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
5289 track_views
.clear ();
5291 zoom_range_clock
.set_session (0);
5292 nudge_clock
.set_session (0);
5294 editor_list_button
.set_active(false);
5295 editor_list_button
.set_sensitive(false);
5297 /* clear tempo/meter rulers */
5298 remove_metric_marks ();
5300 clear_marker_display ();
5302 delete current_bbt_points
;
5303 current_bbt_points
= 0;
5305 /* get rid of any existing editor mixer strip */
5307 WindowTitle
title(Glib::get_application_name());
5308 title
+= _("Editor");
5310 set_title (title
.get_string());
5312 SessionHandlePtr::session_going_away ();
5317 Editor::show_editor_list (bool yn
)
5320 the_notebook
.show();
5322 the_notebook
.hide();
5327 Editor::change_region_layering_order ()
5329 framepos_t
const position
= get_preferred_edit_position ();
5331 if (!clicked_routeview
) {
5332 if (layering_order_editor
) {
5333 layering_order_editor
->hide ();
5338 boost::shared_ptr
<Track
> track
= boost::dynamic_pointer_cast
<Track
> (clicked_routeview
->route());
5344 boost::shared_ptr
<Playlist
> pl
= track
->playlist();
5350 if (layering_order_editor
== 0) {
5351 layering_order_editor
= new RegionLayeringOrderEditor(*this);
5354 layering_order_editor
->set_context (clicked_routeview
->name(), _session
, pl
, position
);
5355 layering_order_editor
->maybe_present ();
5359 Editor::update_region_layering_order_editor ()
5361 if (layering_order_editor
&& layering_order_editor
->is_visible ()) {
5362 change_region_layering_order ();
5367 Editor::setup_fade_images ()
5369 _fade_in_images
[FadeLinear
] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5370 _fade_in_images
[FadeFast
] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5371 _fade_in_images
[FadeLogB
] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5372 _fade_in_images
[FadeLogA
] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5373 _fade_in_images
[FadeSlow
] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5375 _fade_out_images
[FadeLinear
] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5376 _fade_out_images
[FadeFast
] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5377 _fade_out_images
[FadeLogB
] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5378 _fade_out_images
[FadeLogA
] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5379 _fade_out_images
[FadeSlow
] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5383 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5385 Editor::action_menu_item (std::string
const & name
)
5387 Glib::RefPtr
<Action
> a
= editor_actions
->get_action (name
);
5390 return *manage (a
->create_menu_item ());