2 Copyright (C) 2000-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <sigc++/bind.h>
29 #include <pbd/error.h>
31 #include <gtkmm/image.h>
32 #include <gdkmm/color.h>
33 #include <gdkmm/bitmap.h>
35 #include <gtkmm2ext/gtk_ui.h>
36 #include <gtkmm2ext/tearoff.h>
37 #include <gtkmm2ext/utils.h>
39 #include <ardour/audio_track.h>
40 #include <ardour/diskstream.h>
41 #include <ardour/plugin_manager.h>
42 #include <ardour/location.h>
43 #include <ardour/audioplaylist.h>
44 #include <ardour/audioregion.h>
45 #include <ardour/region.h>
46 #include <ardour/session_route.h>
47 #include <ardour/tempo.h>
48 #include <ardour/utils.h>
50 #include "ardour_ui.h"
52 #include "grouped_buttons.h"
55 #include "playlist_selector.h"
56 #include "regionview.h"
57 #include "rgb_macros.h"
58 #include "selection.h"
59 #include "streamview.h"
60 #include "time_axis_view.h"
62 #include "crossfade_view.h"
64 #include "public_editor.h"
65 #include "crossfade_edit.h"
66 #include "audio_time_axis.h"
67 #include "canvas_impl.h"
69 #include "gui_thread.h"
74 #include "imageframe_socket_handler.h"
75 /* </CMT Additions> */
79 using namespace ARDOUR;
82 using namespace Gtkmm2ext;
83 using namespace Editing;
85 const double Editor::timebar_height = 15.0;
87 #include "editor_xpms"
89 static const int32_t slide_index = 0;
90 static const int32_t splice_index = 1;
92 static const gchar *edit_mode_strings[] = {
98 static const gchar *snap_type_strings[] = {
122 static const gchar *snap_mode_strings[] = {
128 static const gchar *zoom_focus_strings[] = {
137 /* Soundfile drag-n-drop */
139 Gdk::Cursor* Editor::cross_hair_cursor = 0;
140 Gdk::Cursor* Editor::selector_cursor = 0;
141 Gdk::Cursor* Editor::trimmer_cursor = 0;
142 Gdk::Cursor* Editor::grabber_cursor = 0;
143 Gdk::Cursor* Editor::zoom_cursor = 0;
144 Gdk::Cursor* Editor::time_fx_cursor = 0;
145 Gdk::Cursor* Editor::fader_cursor = 0;
146 Gdk::Cursor* Editor::speaker_cursor = 0;
147 Gdk::Cursor* Editor::wait_cursor = 0;
148 Gdk::Cursor* Editor::timebar_cursor = 0;
151 Editor::on_key_press_event (GdkEventKey* ev)
153 GtkWindow* win = gobj();
155 /* This exists to allow us to override the way GTK handles
156 key events. The normal sequence is:
158 a) event is delivered to a GtkWindow
159 b) accelerators/mnemonics are activated
160 c) if (b) didn't handle the event, propagate to
161 the focus widget and/or focus chain
163 The problem with this is that if the accelerators include
164 keys without modifiers, such as the space bar or the
165 letter "e", then pressing the key while typing into
166 a text entry widget results in the accelerator being
167 activated, instead of the desired letter appearing
170 There is no good way of fixing this, but this
171 represents a compromise. The idea is that
172 key events involving modifiers (not Shift)
173 get routed into the activation pathway first, then
174 get propagated to the focus widget if necessary.
176 If the key event doesn't involve modifiers,
177 we deliver to the focus widget first, thus allowing
178 it to get "normal text" without interference
181 Of course, this can also be problematic: if there
182 is a widget with focus, then it will swallow
183 all "normal text" accelerators.
186 if (ev->state & ~Gdk::SHIFT_MASK) {
187 /* modifiers in effect, accelerate first */
188 if (!gtk_window_activate_key (win, ev)) {
189 return gtk_window_propagate_key_event (win, ev);
195 /* no modifiers, propagate first */
197 if (!gtk_window_propagate_key_event (win, ev)) {
198 return gtk_window_activate_key (win, ev);
206 show_me_the_size (Requisition* r, const char* what)
208 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
211 Editor::Editor (AudioEngine& eng)
214 /* time display buttons */
216 minsec_label (_("Mins:Secs")),
217 bbt_label (_("Bars:Beats")),
218 smpte_label (_("SMPTE")),
219 frame_label (_("Frames")),
220 tempo_label (_("Tempo")),
221 meter_label (_("Meter")),
222 mark_label (_("Location Markers")),
223 range_mark_label (_("Range Markers")),
224 transport_mark_label (_("Loop/Punch Ranges")),
226 edit_packer (3, 3, false),
228 /* the values here don't matter: layout widgets
229 reset them as needed.
232 vertical_adjustment (0.0, 0.0, 400.0, 10),
233 horizontal_adjustment (0.0, 0.0, 1200.0, 20),
235 /* tool bar related */
237 editor_mixer_button (_("editor\nmixer")),
239 selection_start_clock (X_("SelectionStartClock"), true),
240 selection_end_clock (X_("SelectionEndClock"), true),
241 edit_cursor_clock (X_("EditCursorClock"), true),
242 zoom_range_clock (X_("ZoomRangeClock"), true, true),
244 toolbar_selection_clock_table (2,3),
246 mouse_mode_button_table (2, 3),
248 mouse_select_button (_("range")),
249 mouse_move_button (_("object")),
250 mouse_gain_button (_("gain")),
251 mouse_zoom_button (_("zoom")),
252 mouse_timefx_button (_("timefx")),
253 mouse_audition_button (_("listen")),
255 automation_mode_button (_("mode")),
256 global_automation_button (_("automation")),
258 edit_mode_label (_("Edit Mode")),
259 snap_type_label (_("Snap To")),
260 snap_mode_label(_("Snap Mode")),
261 zoom_focus_label (_("Zoom Focus")),
263 /* <CMT Additions> */
264 image_socket_listener(0),
265 /* </CMT Additions> */
269 nudge_label (_("Nudge")),
270 nudge_clock (X_("NudgeClock"), true, true)
275 /* we are a singleton */
277 PublicEditor::_instance = this;
283 selection = new Selection;
284 cut_buffer = new Selection;
286 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
287 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
288 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
289 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
291 clicked_regionview = 0;
292 clicked_trackview = 0;
293 clicked_audio_trackview = 0;
294 clicked_crossfadeview = 0;
295 clicked_control_point = 0;
296 latest_regionview = 0;
297 last_update_frame = 0;
299 last_audition_region = 0;
300 current_mixer_strip = 0;
301 current_bbt_points = 0;
303 snap_type = SnapToFrame;
304 set_snap_to (snap_type);
305 snap_mode = SnapNormal;
306 set_snap_mode (snap_mode);
307 snap_threshold = 5.0;
308 bbt_beat_subdivision = 4;
311 autoscroll_timeout_tag = -1;
312 interthread_progress_window = 0;
313 current_interthread_info = 0;
314 _show_measures = true;
315 _show_waveforms = true;
316 _show_waveforms_recording = true;
317 first_action_message = 0;
319 show_gain_after_trim = false;
320 no_zoom_repos_update = false;
321 ignore_route_list_reorder = false;
322 verbose_cursor_on = true;
323 route_removal = false;
325 show_automatic_regions_in_region_list = true;
326 have_pending_keyboard_selection = false;
327 _follow_playhead = true;
328 _xfade_visibility = true;
329 editor_ruler_menu = 0;
330 no_ruler_shown_update = false;
331 edit_hscroll_dragging = false;
332 edit_group_list_menu = 0;
334 region_list_menu = 0;
336 marker_menu_item = 0;
338 transport_marker_menu = 0;
339 new_transport_marker_menu = 0;
340 editor_mixer_strip_width = Wide;
341 repos_zoom_queued = false;
342 import_audio_item = 0;
343 embed_audio_item = 0;
344 region_edit_menu_split_item = 0;
346 region_edit_menu_split_multichannel_item = 0;
348 ignore_mouse_mode_toggle = false;
349 current_stepping_trackview = 0;
351 entered_regionview = 0;
352 clear_entered_track = false;
353 _new_regionviews_show_envelope = false;
354 current_timestretch = 0;
359 location_marker_color = color_map[cLocationMarker];
360 location_range_color = color_map[cLocationRange];
361 location_cd_marker_color = color_map[cLocationCDMarker];
362 location_loop_color = color_map[cLocationLoop];
363 location_punch_color = color_map[cLocationPunch];
365 range_marker_drag_rect = 0;
366 marker_drag_line = 0;
368 set_mouse_mode (MouseObject, true);
370 frames_per_unit = 2048; /* too early to use set_frames_per_unit */
371 zoom_focus = ZoomFocusLeft;
372 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
374 initialize_rulers ();
375 initialize_canvas ();
377 edit_controls_vbox.set_spacing (0);
378 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
379 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
381 track_canvas.set_hadjustment (horizontal_adjustment);
382 track_canvas.set_vadjustment (vertical_adjustment);
383 time_canvas.set_hadjustment (horizontal_adjustment);
385 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
386 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
388 controls_layout.add (edit_controls_vbox);
389 controls_layout.set_name ("EditControlsBase");
390 controls_layout.add_events (Gdk::SCROLL_MASK);
391 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
393 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
394 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
396 edit_vscrollbar.set_adjustment (vertical_adjustment);
397 edit_hscrollbar.set_adjustment (horizontal_adjustment);
399 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press));
400 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release));
401 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
406 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
408 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
409 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
410 time_canvas_vbox.pack_start (*frames_ruler, false, false);
411 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
412 time_canvas_vbox.pack_start (time_canvas, true, true);
413 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars));
415 bbt_label.set_name ("EditorTimeButton");
416 bbt_label.set_size_request (-1, (int)timebar_height);
417 bbt_label.set_alignment (1.0, 0.5);
418 bbt_label.set_padding (5,0);
419 minsec_label.set_name ("EditorTimeButton");
420 minsec_label.set_size_request (-1, (int)timebar_height);
421 minsec_label.set_alignment (1.0, 0.5);
422 minsec_label.set_padding (5,0);
423 smpte_label.set_name ("EditorTimeButton");
424 smpte_label.set_size_request (-1, (int)timebar_height);
425 smpte_label.set_alignment (1.0, 0.5);
426 smpte_label.set_padding (5,0);
427 frame_label.set_name ("EditorTimeButton");
428 frame_label.set_size_request (-1, (int)timebar_height);
429 frame_label.set_alignment (1.0, 0.5);
430 frame_label.set_padding (5,0);
431 tempo_label.set_name ("EditorTimeButton");
432 tempo_label.set_size_request (-1, (int)timebar_height);
433 tempo_label.set_alignment (1.0, 0.5);
434 tempo_label.set_padding (5,0);
435 meter_label.set_name ("EditorTimeButton");
436 meter_label.set_size_request (-1, (int)timebar_height);
437 meter_label.set_alignment (1.0, 0.5);
438 meter_label.set_padding (5,0);
439 mark_label.set_name ("EditorTimeButton");
440 mark_label.set_size_request (-1, (int)timebar_height);
441 mark_label.set_alignment (1.0, 0.5);
442 mark_label.set_padding (5,0);
443 range_mark_label.set_name ("EditorTimeButton");
444 range_mark_label.set_size_request (-1, (int)timebar_height);
445 range_mark_label.set_alignment (1.0, 0.5);
446 range_mark_label.set_padding (5,0);
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);
452 time_button_vbox.pack_start (minsec_label, false, false);
453 time_button_vbox.pack_start (smpte_label, false, false);
454 time_button_vbox.pack_start (frame_label, false, false);
455 time_button_vbox.pack_start (bbt_label, false, false);
456 time_button_vbox.pack_start (meter_label, false, false);
457 time_button_vbox.pack_start (tempo_label, false, false);
458 time_button_vbox.pack_start (mark_label, false, false);
460 time_button_event_box.add (time_button_vbox);
462 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
463 time_button_event_box.set_name ("TimebarLabelBase");
464 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
466 /* these enable us to have a dedicated window (for cursor setting, etc.)
467 for the canvas areas.
470 track_canvas_event_box.add (track_canvas);
472 time_canvas_event_box.add (time_canvas_vbox);
473 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
475 edit_packer.set_col_spacings (0);
476 edit_packer.set_row_spacings (0);
477 edit_packer.set_homogeneous (false);
478 edit_packer.set_name ("EditorWindow");
480 edit_packer.attach (edit_hscrollbar, 1, 2, 0, 1, FILL|EXPAND, FILL, 0, 0);
482 edit_packer.attach (time_button_event_box, 0, 1, 1, 2, FILL, FILL, 0, 0);
483 edit_packer.attach (time_canvas_event_box, 1, 2, 1, 2, FILL|EXPAND, FILL, 0, 0);
485 edit_packer.attach (controls_layout, 0, 1, 2, 3, FILL, FILL|EXPAND, 0, 0);
486 edit_packer.attach (track_canvas_event_box, 1, 2, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
487 edit_packer.attach (edit_vscrollbar, 2, 3, 2, 3, FILL, FILL|EXPAND, 0, 0);
489 edit_frame.set_name ("BaseFrame");
490 edit_frame.set_shadow_type (SHADOW_IN);
491 edit_frame.add (edit_packer);
493 zoom_in_button.set_name ("EditorTimeButton");
494 zoom_out_button.set_name ("EditorTimeButton");
495 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in"));
496 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out"));
498 zoom_out_full_button.set_name ("EditorTimeButton");
499 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session"));
501 zoom_in_button.add (*(manage (new Gtk::Image (Stock::ZOOM_IN, ICON_SIZE_BUTTON))));
502 zoom_out_button.add (*(manage (new Gtk::Image (Stock::ZOOM_OUT, ICON_SIZE_BUTTON))));
503 zoom_out_full_button.add (*(manage (new Gtk::Image (Stock::ZOOM_FIT, ICON_SIZE_BUTTON))));
505 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
506 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
507 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
509 zoom_indicator_box.pack_start (zoom_out_button, false, false);
510 zoom_indicator_box.pack_start (zoom_in_button, false, false);
511 zoom_indicator_box.pack_start (zoom_range_clock, false, false);
512 zoom_indicator_box.pack_start (zoom_out_full_button, false, false);
514 zoom_indicator_label.set_text (_("Zoom Span"));
515 zoom_indicator_label.set_name ("ToolBarLabel");
517 zoom_indicator_vbox.set_spacing (3);
518 zoom_indicator_vbox.set_border_width (3);
519 zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false);
520 zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false);
522 bottom_hbox.set_border_width (3);
523 bottom_hbox.set_spacing (3);
525 route_display_model = ListStore::create(route_display_columns);
526 route_list_display.set_model (route_display_model);
527 route_list_display.append_column (_("Tracks"), route_display_columns.text);
528 route_list_display.set_headers_visible (false);
529 route_list_display.set_name ("TrackListDisplay");
530 route_list_display.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
531 route_list_display.set_reorderable (true);
533 route_list_display.set_size_request (75,-1);
534 route_list_display.set_headers_visible (true);
535 route_list_display.set_headers_clickable (true);
538 // route_list_display.signal_rows_reordered().connect (mem_fun (*this, &Editor::queue_route_list_reordered));
540 route_display_model->set_sort_func (0, mem_fun (*this, &Editor::route_list_compare_func));
541 route_display_model->set_sort_column (0, SORT_ASCENDING);
543 route_list_scroller.add (route_list_display);
544 route_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
546 route_list_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::route_display_selection_changed));
547 route_list_display.signal_columns_changed().connect (mem_fun(*this, &Editor::route_list_column_click));
549 edit_group_list_button_label.set_text (_("Edit Groups"));
550 edit_group_list_button_label.set_name ("EditGroupTitleButton");
551 edit_group_list_button.add (edit_group_list_button_label);
552 edit_group_list_button.set_name ("EditGroupTitleButton");
554 group_model = ListStore::create(group_columns);
555 edit_group_display.set_model (group_model);
556 edit_group_display.append_column (_("active"), group_columns.is_active);
557 edit_group_display.append_column (_("groupname"), group_columns.text);
558 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
559 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
560 edit_group_display.set_headers_visible (false);
562 /* use checkbox for the active column */
564 CellRendererToggle *active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (0));
565 active_cell->property_activatable() = true;
566 active_cell->property_radio() = false;
568 edit_group_display.set_name ("MixerGroupList");
569 //edit_group_display.set_shadow_type (Gtk::SHADOW_IN);
571 edit_group_display.columns_autosize ();
572 edit_group_display.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
573 edit_group_display.set_reorderable (false);
575 edit_group_display.set_size_request (75, -1);
576 edit_group_display.set_headers_visible (true);
578 edit_group_list_scroller.add (edit_group_display);
579 edit_group_list_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
581 edit_group_list_button.signal_clicked().connect (mem_fun(*this, &Editor::edit_group_list_button_clicked));
582 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event));
583 edit_group_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::edit_group_selection_changed));
585 TreeModel::Row row = *(group_model->append());
586 row[group_columns.is_active] = false;
587 row[group_columns.text] = (_("-all-"));
588 row[group_columns.routegroup] = 0;
589 edit_group_display.get_selection()->select (row);
591 edit_group_vbox.pack_start (edit_group_list_button, false, false);
592 edit_group_vbox.pack_start (edit_group_list_scroller, true, true);
594 region_list_display.set_size_request (100, -1);
595 region_list_display.set_name ("RegionListDisplay");
597 region_list_model = TreeStore::create (region_list_columns);
598 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
599 region_list_model->set_sort_column (0, SORT_ASCENDING);
601 region_list_display.set_model (region_list_model);
602 CellRendererText* renderer = Gtk::manage( new Gtk::CellRendererText() );
603 region_list_display.append_column (_("Regions"), *renderer);
605 TreeViewColumn* tv_col = region_list_display.get_column(0);
606 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
607 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
609 region_list_display.set_reorderable (true);
611 region_list_display.get_selection()->set_mode (SELECTION_SINGLE);
612 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
614 /* setup DnD handling */
616 list<Gtk::TargetEntry> region_list_target_table;
618 region_list_target_table.push_back (TargetEntry ("STRING"));
619 region_list_target_table.push_back (TargetEntry ("text/plain"));
620 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
621 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
623 region_list_display.add_drop_targets (region_list_target_table);
624 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
626 region_list_scroller.add (region_list_display);
627 region_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
629 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
630 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
631 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
632 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
633 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
634 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
636 named_selection_scroller.add (named_selection_display);
637 named_selection_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
639 named_selection_model = TreeStore::create (named_selection_columns);
640 named_selection_display.set_model (named_selection_model);
641 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
642 named_selection_display.set_headers_visible (false);
643 named_selection_display.set_size_request (100, -1);
644 named_selection_display.set_name ("RegionListDisplay");
646 named_selection_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
647 named_selection_display.set_size_request (100, -1);
648 named_selection_display.set_headers_visible (true);
649 named_selection_display.set_headers_clickable (true);
650 named_selection_display.signal_button_press_event().connect (mem_fun(*this, &Editor::named_selection_display_button_press));
651 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
653 the_notebook.append_page (region_list_scroller, _("Regions"));
654 the_notebook.append_page (route_list_scroller, _("Tracks/Busses"));
655 the_notebook.append_page (edit_group_vbox, _("Edit Groups"));
656 the_notebook.append_page (named_selection_scroller, _("Chunks"));
657 the_notebook.set_show_tabs (true);
658 the_notebook.set_scrollable (true);
659 the_notebook.popup_enable ();
661 TearOff *notebook_tearoff = manage (new TearOff (the_notebook, true));
662 notebook_tearoff->tearoff_window().set_size_request (200, 400);
664 edit_pane.pack1 (edit_frame, true, true);
665 edit_pane.pack2 (*notebook_tearoff, true, true);
667 edit_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Gtk::Paned*> (&edit_pane)));
669 top_hbox.pack_start (toolbar_frame, true, true);
671 HBox *hbox = manage (new HBox);
672 hbox->pack_start (edit_pane, true, true);
674 global_vpacker.pack_start (top_hbox, false, false);
675 global_vpacker.pack_start (*hbox, true, true);
677 global_hpacker.pack_start (global_vpacker, true, true);
679 set_name ("EditorWindow");
680 add_accel_group (ActionManager::ui_manager->get_accel_group());
682 vpacker.pack_end (global_hpacker, true, true);
684 /* register actions now so that set_state() can find them and set toggles/checks etc */
688 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
691 _playlist_selector = new PlaylistSelector();
692 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
694 AudioRegionView::AudioRegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_audio_regionview));
698 nudge_forward_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(right_arrow_xpm)))));
699 nudge_backward_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(left_arrow_xpm)))));
701 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards"));
702 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards"));
704 nudge_forward_button.set_name ("TransportButton");
705 nudge_backward_button.set_name ("TransportButton");
707 fade_context_menu.set_name ("ArdourContextMenu");
709 set_title (_("ardour: editor"));
710 set_wmclass (_("ardour_editor"), "Ardour");
713 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
715 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
716 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
724 /* <CMT Additions> */
725 if(image_socket_listener)
727 if(image_socket_listener->is_connected())
729 image_socket_listener->close_connection() ;
732 delete image_socket_listener ;
733 image_socket_listener = 0 ;
735 /* </CMT Additions> */
739 Editor::add_toplevel_controls (Container& cont)
741 vpacker.pack_start (cont, false, false);
746 Editor::catch_vanishing_audio_regionview (AudioRegionView *rv)
748 /* note: the selection will take care of the vanishing
749 audioregionview by itself.
752 if (clicked_regionview == rv) {
753 clicked_regionview = 0;
756 if (entered_regionview == rv) {
757 set_entered_regionview (0);
762 Editor::set_entered_regionview (AudioRegionView* rv)
764 if (rv == entered_regionview) {
768 if (entered_regionview) {
769 entered_regionview->exited ();
772 if ((entered_regionview = rv) != 0) {
773 entered_regionview->entered ();
778 Editor::set_entered_track (TimeAxisView* tav)
781 entered_track->exited ();
784 if ((entered_track = tav) != 0) {
785 entered_track->entered ();
790 Editor::left_track_canvas (GdkEventCrossing *ev)
792 set_entered_track (0);
793 set_entered_regionview (0);
799 Editor::show_window ()
804 /* now reset all audio_time_axis heights, because widgets might need
810 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
811 tv = (static_cast<TimeAxisView*>(*i));
817 Editor::tie_vertical_scrolling ()
819 double y1 = vertical_adjustment.get_value();
820 controls_layout.get_vadjustment()->set_value (y1);
821 playhead_cursor->set_y_axis(y1);
822 edit_cursor->set_y_axis(y1);
826 Editor::set_frames_per_unit (double fpu)
828 jack_nframes_t frames;
830 if (fpu == frames_per_unit) {
838 // convert fpu to frame count
840 frames = (jack_nframes_t) floor (fpu * canvas_width);
842 /* don't allow zooms that fit more than the maximum number
843 of frames into an 800 pixel wide space.
846 if (max_frames / fpu < 800.0) {
850 frames_per_unit = fpu;
852 if (frames != zoom_range_clock.current_duration()) {
853 zoom_range_clock.set (frames);
856 /* only update these if we not about to call reposition_x_origin,
857 which will do the same updates.
861 horizontal_adjustment.set_upper (session->current_end_frame() / frames_per_unit);
864 if (!no_zoom_repos_update) {
865 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
866 update_fixed_rulers ();
867 tempo_map_changed (Change (0));
870 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
871 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
872 (*i)->reshow_selection (selection->time);
876 ZoomChanged (); /* EMIT_SIGNAL */
878 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
879 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
886 Editor::instant_save ()
888 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
893 session->add_instant_xml(get_state(), session->path());
895 Config->add_instant_xml(get_state(), Config->get_user_ardour_path());
900 Editor::reposition_x_origin (jack_nframes_t frame)
902 if (frame != leftmost_frame) {
903 leftmost_frame = frame;
904 double pixel = frame_to_pixel (frame);
905 if (pixel >= horizontal_adjustment.get_upper()) {
906 horizontal_adjustment.set_upper (frame_to_pixel (frame + (current_page_frames())));
908 horizontal_adjustment.set_value (frame/frames_per_unit);
909 XOriginChanged (); /* EMIT_SIGNAL */
914 Editor::edit_cursor_clock_changed()
916 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
917 edit_cursor->set_position (edit_cursor_clock.current_time());
923 Editor::zoom_adjustment_changed ()
925 if (session == 0 || no_zoom_repos_update) {
929 double fpu = zoom_range_clock.current_duration() / canvas_width;
933 zoom_range_clock.set ((jack_nframes_t) floor (fpu * canvas_width));
934 } else if (fpu > session->current_end_frame() / canvas_width) {
935 fpu = session->current_end_frame() / canvas_width;
936 zoom_range_clock.set ((jack_nframes_t) floor (fpu * canvas_width));
943 Editor::canvas_horizontally_scrolled ()
945 leftmost_frame = (jack_nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
947 update_fixed_rulers ();
949 if (!edit_hscroll_dragging) {
950 tempo_map_changed (Change (0));
952 update_tempo_based_rulers();
957 Editor::reposition_and_zoom (jack_nframes_t frame, double nfpu)
959 if (!repos_zoom_queued) {
960 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu));
961 repos_zoom_queued = true;
966 Editor::deferred_reposition_and_zoom (jack_nframes_t frame, double nfpu)
968 /* if we need to force an update to the hscroller stuff,
969 don't set no_zoom_repos_update.
972 no_zoom_repos_update = (frame != leftmost_frame);
974 set_frames_per_unit (nfpu);
975 if (no_zoom_repos_update) {
976 reposition_x_origin (frame);
978 no_zoom_repos_update = false;
979 repos_zoom_queued = false;
985 Editor::on_realize ()
987 Window::on_realize ();
992 Editor::queue_session_control_changed (Session::ControlType t)
994 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::session_control_changed), t));
998 Editor::session_control_changed (Session::ControlType t)
1000 // right now we're only tracking the loop and punch state
1003 case Session::AutoLoop:
1004 update_loop_range_view (true);
1006 case Session::PunchIn:
1007 case Session::PunchOut:
1008 update_punch_range_view (true);
1017 Editor::fake_add_edit_group (RouteGroup *group)
1019 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::add_edit_group), group));
1023 Editor::fake_handle_new_audio_region (AudioRegion *region)
1025 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_new_audio_region), region));
1029 Editor::fake_handle_audio_region_removed (AudioRegion *region)
1031 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_audio_region_removed), region));
1035 Editor::fake_handle_new_duration ()
1037 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &Editor::handle_new_duration));
1041 Editor::start_scrolling ()
1043 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1044 (mem_fun(*this, &Editor::update_current_screen));
1046 slower_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
1047 (mem_fun(*this, &Editor::update_slower));
1051 Editor::stop_scrolling ()
1053 scroll_connection.disconnect ();
1054 slower_update_connection.disconnect ();
1058 Editor::map_position_change (jack_nframes_t frame)
1060 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1062 if (session == 0 || !_follow_playhead) {
1066 center_screen (frame);
1067 playhead_cursor->set_position (frame);
1071 Editor::center_screen (jack_nframes_t frame)
1073 double page = canvas_width * frames_per_unit;
1075 /* if we're off the page, then scroll.
1078 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1079 center_screen_internal (frame, page);
1084 Editor::center_screen_internal (jack_nframes_t frame, float page)
1089 frame -= (jack_nframes_t) page;
1094 reposition_x_origin (frame);
1098 Editor::handle_new_duration ()
1100 reset_scrolling_region ();
1103 horizontal_adjustment.set_upper (session->current_end_frame() / frames_per_unit);
1104 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1109 Editor::update_title_s (const string & snap_name)
1111 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1117 Editor::update_title ()
1119 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1122 bool dirty = session->dirty();
1124 string wintitle = _("ardour: editor: ");
1130 wintitle += session->name();
1132 if (session->snap_name() != session->name()) {
1134 wintitle += session->snap_name();
1141 set_title (wintitle);
1146 Editor::connect_to_session (Session *t)
1150 if (first_action_message) {
1151 first_action_message->hide();
1156 session->going_away.connect (mem_fun(*this, &Editor::session_going_away));
1158 /* These signals can all be emitted by a non-GUI thread. Therefore the
1159 handlers for them must not attempt to directly interact with the GUI,
1160 but use Gtkmm2ext::UI::instance()->call_slot();
1163 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1164 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1165 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p)));
1166 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::fake_handle_new_audio_region)));
1167 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::fake_handle_audio_region_removed)));
1168 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::fake_handle_new_duration)));
1169 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::fake_add_edit_group)));
1170 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1171 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1172 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1173 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1174 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1175 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1177 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1178 session_connections.push_back (session->SMPTETypeChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1180 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1182 session->foreach_edit_group(this, &Editor::add_edit_group);
1184 editor_mixer_button.signal_toggled().connect (mem_fun(*this, &Editor::editor_mixer_button_toggled));
1185 editor_mixer_button.set_name (X_("EditorMixerButton"));
1187 edit_cursor_clock.set_session (session);
1188 selection_start_clock.set_session (session);
1189 selection_end_clock.set_session (session);
1190 zoom_range_clock.set_session (session);
1191 _playlist_selector->set_session (session);
1192 nudge_clock.set_session (session);
1194 switch (session->get_edit_mode()) {
1196 edit_mode_selector.set_active_text (edit_mode_strings[splice_index]);
1200 edit_mode_selector.set_active_text (edit_mode_strings[slide_index]);
1204 Location* loc = session->locations()->auto_loop_location();
1206 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1207 if (loc->start() == loc->end()) {
1208 loc->set_end (loc->start() + 1);
1210 session->locations()->add (loc, false);
1211 session->set_auto_loop_location (loc);
1215 loc->set_name (_("Loop"));
1218 loc = session->locations()->auto_punch_location();
1220 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1221 if (loc->start() == loc->end()) {
1222 loc->set_end (loc->start() + 1);
1224 session->locations()->add (loc, false);
1225 session->set_auto_punch_location (loc);
1229 loc->set_name (_("Punch"));
1232 update_loop_range_view (true);
1233 update_punch_range_view (true);
1235 session->ControlChanged.connect (mem_fun(*this, &Editor::queue_session_control_changed));
1238 refresh_location_display ();
1239 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1240 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1241 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1242 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1243 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1245 reset_scrolling_region ();
1247 redisplay_regions ();
1248 redisplay_named_selections ();
1251 // route_list_display.set_model (Glib::RefPtr<TreeModel>(0));
1252 route_display_model->clear ();
1254 session->foreach_route (this, &Editor::handle_new_route);
1255 // route_list_display.select_all ();
1257 //route_list_display.sort ();
1259 route_list_reordered ();
1261 // route_list_display.set_model (route_display_model);
1263 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1264 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1267 /* ::reposition_x_origin() doesn't work right here, since the old
1268 position may be zero already, and it does nothing in such
1274 horizontal_adjustment.set_upper (session->current_end_frame() / frames_per_unit);
1275 horizontal_adjustment.set_value (0);
1277 restore_ruler_visibility ();
1278 tempo_map_changed (Change (0));
1280 edit_cursor->set_position (0);
1281 playhead_cursor->set_position (0);
1285 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1288 /* don't show master bus in a new session */
1290 if (ARDOUR_UI::instance()->session_is_new ()) {
1292 TreeModel::Children rows = route_display_model->children();
1293 TreeModel::Children::iterator i;
1295 //route_list_display.freeze ();
1297 for (i = rows.begin(); i != rows.end(); ++i) {
1298 TimeAxisView *tv = (*i)[route_display_columns.tv];
1299 AudioTimeAxisView *atv;
1301 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1302 if (atv->route().master()) {
1303 route_list_display.get_selection()->unselect (i);
1304 //(*i)->unselect ();
1309 //route_list_display.thaw ();
1314 Editor::build_cursors ()
1316 using namespace Gdk;
1318 Gdk::Color mbg ("#000000" ); /* Black */
1319 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1322 RefPtr<Bitmap> source, mask;
1323 source = Bitmap::create (mag_bits, mag_width, mag_height);
1324 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1325 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1328 Gdk::Color fbg ("#ffffff" );
1329 Gdk::Color ffg ("#000000" );
1332 RefPtr<Bitmap> source, mask;
1334 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1335 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1336 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1340 RefPtr<Bitmap> source, mask;
1341 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1342 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1343 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1346 grabber_cursor = new Gdk::Cursor (HAND2);
1347 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1348 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1349 selector_cursor = new Gdk::Cursor (XTERM);
1350 time_fx_cursor = new Gdk::Cursor (SIZING);
1351 wait_cursor = new Gdk::Cursor (WATCH);
1352 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1356 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1358 using namespace Menu_Helpers;
1359 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1362 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1366 MenuList& items (fade_context_menu.items());
1370 switch (item_type) {
1372 case FadeInHandleItem:
1373 if (arv->region.fade_in_active()) {
1374 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false)));
1376 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true)));
1379 items.push_back (SeparatorElem());
1381 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear)));
1382 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB)));
1383 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast)));
1384 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA)));
1385 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow)));
1389 case FadeOutHandleItem:
1390 if (arv->region.fade_out_active()) {
1391 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false)));
1393 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true)));
1396 items.push_back (SeparatorElem());
1398 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear)));
1399 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast)));
1400 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB)));
1401 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA)));
1402 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow)));
1406 fatal << _("programming error: ")
1407 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1412 fade_context_menu.popup (button, time);
1416 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, jack_nframes_t frame)
1418 using namespace Menu_Helpers;
1419 Menu* (Editor::*build_menu_function)(jack_nframes_t);
1422 switch (item_type) {
1424 case AudioRegionViewName:
1425 case AudioRegionViewNameHighlight:
1426 if (with_selection) {
1427 build_menu_function = &Editor::build_track_selection_context_menu;
1429 build_menu_function = &Editor::build_track_region_context_menu;
1434 if (with_selection) {
1435 build_menu_function = &Editor::build_track_selection_context_menu;
1437 build_menu_function = &Editor::build_track_context_menu;
1441 case CrossfadeViewItem:
1442 build_menu_function = &Editor::build_track_crossfade_context_menu;
1446 if (clicked_audio_trackview->get_diskstream()) {
1447 build_menu_function = &Editor::build_track_context_menu;
1449 build_menu_function = &Editor::build_track_bus_context_menu;
1454 /* probably shouldn't happen but if it does, we don't care */
1458 menu = (this->*build_menu_function)(frame);
1459 menu->set_name ("ArdourContextMenu");
1461 /* now handle specific situations */
1463 switch (item_type) {
1465 case AudioRegionViewName:
1466 case AudioRegionViewNameHighlight:
1467 if (!with_selection) {
1468 if (region_edit_menu_split_item) {
1469 if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) {
1470 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, true);
1472 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, false);
1475 if (region_edit_menu_split_multichannel_item) {
1476 if (clicked_regionview && clicked_regionview->region.n_channels() > 1) {
1477 // GTK2FIX find the action, change its sensitivity
1478 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1480 // GTK2FIX see above
1481 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1490 case CrossfadeViewItem:
1497 /* probably shouldn't happen but if it does, we don't care */
1501 if (clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1503 /* Bounce to disk */
1505 using namespace Menu_Helpers;
1506 MenuList& edit_items = menu->items();
1508 edit_items.push_back (SeparatorElem());
1510 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1511 case AudioTrack::NoFreeze:
1512 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1515 case AudioTrack::Frozen:
1516 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1519 case AudioTrack::UnFrozen:
1520 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1526 menu->popup (button, time);
1530 Editor::build_track_context_menu (jack_nframes_t ignored)
1532 using namespace Menu_Helpers;
1534 MenuList& edit_items = track_context_menu.items();
1537 add_dstream_context_items (edit_items);
1538 return &track_context_menu;
1542 Editor::build_track_bus_context_menu (jack_nframes_t ignored)
1544 using namespace Menu_Helpers;
1546 MenuList& edit_items = track_context_menu.items();
1549 add_bus_context_items (edit_items);
1550 return &track_context_menu;
1554 Editor::build_track_region_context_menu (jack_nframes_t frame)
1556 using namespace Menu_Helpers;
1557 MenuList& edit_items = track_region_context_menu.items();
1560 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1566 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1567 Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed()));
1568 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1569 add_region_context_items (atv->view, (*i), edit_items);
1575 add_dstream_context_items (edit_items);
1577 return &track_region_context_menu;
1581 Editor::build_track_crossfade_context_menu (jack_nframes_t frame)
1583 using namespace Menu_Helpers;
1584 MenuList& edit_items = track_crossfade_context_menu.items();
1585 edit_items.clear ();
1587 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1594 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = dynamic_cast<AudioPlaylist*> (pl)) != 0)) {
1596 Playlist::RegionList* regions = pl->regions_at (frame);
1597 AudioPlaylist::Crossfades xfades;
1599 apl->crossfades_at (frame, xfades);
1601 bool many = xfades.size() > 1;
1603 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1604 add_crossfade_context_items (atv->view, (*i), edit_items, many);
1607 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1608 add_region_context_items (atv->view, (*i), edit_items);
1615 add_dstream_context_items (edit_items);
1617 return &track_crossfade_context_menu;
1621 Editor::build_track_selection_context_menu (jack_nframes_t ignored)
1623 using namespace Menu_Helpers;
1624 MenuList& edit_items = track_selection_context_menu.items();
1625 edit_items.clear ();
1627 add_selection_context_items (edit_items);
1628 add_dstream_context_items (edit_items);
1630 return &track_selection_context_menu;
1634 Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many)
1636 using namespace Menu_Helpers;
1637 Menu *xfade_menu = manage (new Menu);
1638 MenuList& items = xfade_menu->items();
1639 xfade_menu->set_name ("ArdourContextMenu");
1642 if (xfade->active()) {
1648 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), xfade)));
1649 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), xfade)));
1651 if (xfade->can_follow_overlap()) {
1653 if (xfade->following_overlap()) {
1654 str = _("Convert to short");
1656 str = _("Convert to full");
1659 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1663 str = xfade->out().name();
1665 str += xfade->in().name();
1667 str = _("Crossfade");
1670 edit_items.push_back (MenuElem (str, *xfade_menu));
1671 edit_items.push_back (SeparatorElem());
1675 Editor::xfade_edit_left_region ()
1677 if (clicked_crossfadeview) {
1678 clicked_crossfadeview->left_view.show_region_editor ();
1683 Editor::xfade_edit_right_region ()
1685 if (clicked_crossfadeview) {
1686 clicked_crossfadeview->right_view.show_region_editor ();
1691 Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items)
1693 using namespace Menu_Helpers;
1694 Menu *region_menu = manage (new Menu);
1695 MenuList& items = region_menu->items();
1696 region_menu->set_name ("ArdourContextMenu");
1698 AudioRegion* ar = 0;
1701 ar = dynamic_cast<AudioRegion*> (region);
1704 /* when this particular menu pops up, make the relevant region
1708 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, region));
1710 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1711 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1712 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1713 items.push_back (SeparatorElem());
1714 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1715 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1716 items.push_back (SeparatorElem());
1718 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1719 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1720 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1721 items.push_back (SeparatorElem());
1723 /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler
1724 might be able to figure out which overloaded member function to use in
1728 void (Editor::*type_A_pmf)(void (Region::*pmf)(bool), bool) = &Editor::region_selection_op;
1730 items.push_back (MenuElem (_("Lock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, true)));
1731 items.push_back (MenuElem (_("Unlock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, false)));
1732 items.push_back (SeparatorElem());
1734 if (region->muted()) {
1735 items.push_back (MenuElem (_("Unmute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, false)));
1737 items.push_back (MenuElem (_("Mute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, true)));
1739 items.push_back (SeparatorElem());
1741 items.push_back (MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1742 items.push_back (SeparatorElem());
1747 items.push_back (MenuElem (_("Toggle envelope visibility"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility)));
1748 items.push_back (MenuElem (_("Toggle envelope active"), mem_fun(*this, &Editor::toggle_gain_envelope_active)));
1749 items.push_back (SeparatorElem());
1751 if (ar->scale_amplitude() != 1.0f) {
1752 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1754 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1757 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1758 items.push_back (SeparatorElem());
1762 Menu *nudge_menu = manage (new Menu());
1763 MenuList& nudge_items = nudge_menu->items();
1764 nudge_menu->set_name ("ArdourContextMenu");
1766 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1767 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1768 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1769 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1771 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1772 items.push_back (SeparatorElem());
1774 Menu *trim_menu = manage (new Menu);
1775 MenuList& trim_items = trim_menu->items();
1776 trim_menu->set_name ("ArdourContextMenu");
1778 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1779 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1781 items.push_back (MenuElem (_("Trim"), *trim_menu));
1782 items.push_back (SeparatorElem());
1784 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1785 region_edit_menu_split_item = &items.back();
1787 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1788 region_edit_menu_split_multichannel_item = &items.back();
1790 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1791 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1792 items.push_back (SeparatorElem());
1793 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1794 items.push_back (SeparatorElem());
1795 items.push_back (MenuElem (_("Destroy"), mem_fun(*this, &Editor::destroy_clicked_region)));
1797 /* OK, stick the region submenu at the top of the list, and then add
1801 /* we have to hack up the region name because "_" has a special
1802 meaning for menu titles.
1805 string::size_type pos = 0;
1806 string menu_item_name = region->name();
1808 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1809 menu_item_name.replace (pos, 1, "__");
1813 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1814 edit_items.push_back (SeparatorElem());
1818 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1820 using namespace Menu_Helpers;
1821 Menu *selection_menu = manage (new Menu);
1822 MenuList& items = selection_menu->items();
1823 selection_menu->set_name ("ArdourContextMenu");
1825 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1826 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1827 items.push_back (SeparatorElem());
1828 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection)));
1829 items.push_back (SeparatorElem());
1830 items.push_back (MenuElem (_("Create Region"), mem_fun(*this, &Editor::new_region_from_selection)));
1831 items.push_back (MenuElem (_("Separate Region"), mem_fun(*this, &Editor::separate_region_from_selection)));
1832 items.push_back (MenuElem (_("Crop Region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1833 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1834 items.push_back (SeparatorElem());
1835 items.push_back (MenuElem (_("Duplicate"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1836 items.push_back (SeparatorElem());
1837 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_selection)));
1838 items.push_back (SeparatorElem());
1839 items.push_back (MenuElem (_("Fill range w/Region"), mem_fun(*this, &Editor::region_fill_selection)));
1841 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1842 edit_items.push_back (SeparatorElem());
1846 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1848 using namespace Menu_Helpers;
1852 Menu *play_menu = manage (new Menu);
1853 MenuList& play_items = play_menu->items();
1854 play_menu->set_name ("ArdourContextMenu");
1856 play_items.push_back (MenuElem (_("Play from edit cursor")));
1857 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1858 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1859 play_items.push_back (SeparatorElem());
1860 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1862 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1866 Menu *select_menu = manage (new Menu);
1867 MenuList& select_items = select_menu->items();
1868 select_menu->set_name ("ArdourContextMenu");
1870 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
1871 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
1872 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1873 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
1874 select_items.push_back (SeparatorElem());
1875 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1876 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1877 select_items.push_back (SeparatorElem());
1879 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1883 Menu *cutnpaste_menu = manage (new Menu);
1884 MenuList& cutnpaste_items = cutnpaste_menu->items();
1885 cutnpaste_menu->set_name ("ArdourContextMenu");
1887 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1888 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1889 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1890 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1892 cutnpaste_items.push_back (SeparatorElem());
1894 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1895 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1897 cutnpaste_items.push_back (SeparatorElem());
1899 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1901 cutnpaste_items.push_back (SeparatorElem());
1903 cutnpaste_items.push_back (MenuElem (_("New Region from range"), mem_fun(*this, &Editor::new_region_from_selection)));
1904 cutnpaste_items.push_back (MenuElem (_("Separate Range"), mem_fun(*this, &Editor::separate_region_from_selection)));
1906 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1908 /* Adding new material */
1910 Menu *import_menu = manage (new Menu());
1911 MenuList& import_items = import_menu->items();
1912 import_menu->set_name ("ArdourContextMenu");
1914 import_items.push_back (MenuElem (_("Insert Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1915 import_items.push_back (MenuElem (_("Insert external sndfile"), bind (mem_fun(*this, &Editor::insert_sndfile), false)));
1917 edit_items.push_back (MenuElem (_("Import"), *import_menu));
1921 Menu *nudge_menu = manage (new Menu());
1922 MenuList& nudge_items = nudge_menu->items();
1923 nudge_menu->set_name ("ArdourContextMenu");
1925 edit_items.push_back (SeparatorElem());
1926 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1927 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1928 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1929 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1931 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1935 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1937 using namespace Menu_Helpers;
1941 Menu *play_menu = manage (new Menu);
1942 MenuList& play_items = play_menu->items();
1943 play_menu->set_name ("ArdourContextMenu");
1945 play_items.push_back (MenuElem (_("Play from edit cursor")));
1946 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1947 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1951 Menu *select_menu = manage (new Menu);
1952 MenuList& select_items = select_menu->items();
1953 select_menu->set_name ("ArdourContextMenu");
1955 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
1956 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
1957 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1958 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
1959 select_items.push_back (SeparatorElem());
1960 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1961 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1962 select_items.push_back (SeparatorElem());
1964 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1968 Menu *cutnpaste_menu = manage (new Menu);
1969 MenuList& cutnpaste_items = cutnpaste_menu->items();
1970 cutnpaste_menu->set_name ("ArdourContextMenu");
1972 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1973 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1974 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1976 Menu *nudge_menu = manage (new Menu());
1977 MenuList& nudge_items = nudge_menu->items();
1978 nudge_menu->set_name ("ArdourContextMenu");
1980 edit_items.push_back (SeparatorElem());
1981 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1982 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1983 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1984 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1986 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1989 /* CURSOR SETTING AND MARKS AND STUFF */
1992 Editor::set_snap_to (SnapType st)
1995 vector<string> txt = internationalize (snap_type_strings);
1996 snap_type_selector.set_active_text (txt[(int)st]);
2000 switch (snap_type) {
2001 case SnapToAThirtysecondBeat:
2002 case SnapToASixteenthBeat:
2003 case SnapToAEighthBeat:
2004 case SnapToAQuarterBeat:
2005 case SnapToAThirdBeat:
2006 update_tempo_based_rulers ();
2014 Editor::set_snap_mode (SnapMode mode)
2017 vector<string> txt = internationalize (snap_mode_strings);
2018 snap_mode_selector.set_active_text (txt[(int)mode]);
2024 Editor::add_location_from_selection ()
2026 if (selection->time.empty()) {
2030 if (session == 0 || clicked_trackview == 0) {
2034 jack_nframes_t start = selection->time[clicked_selection].start;
2035 jack_nframes_t end = selection->time[clicked_selection].end;
2037 Location *location = new Location (start, end, "selection");
2039 session->begin_reversible_command (_("add marker"));
2040 session->add_undo (session->locations()->get_memento());
2041 session->locations()->add (location, true);
2042 session->add_redo_no_execute (session->locations()->get_memento());
2043 session->commit_reversible_command ();
2047 Editor::add_location_from_playhead_cursor ()
2049 jack_nframes_t where = session->audible_frame();
2051 Location *location = new Location (where, where, "mark", Location::IsMark);
2052 session->begin_reversible_command (_("add marker"));
2053 session->add_undo (session->locations()->get_memento());
2054 session->locations()->add (location, true);
2055 session->add_redo_no_execute (session->locations()->get_memento());
2056 session->commit_reversible_command ();
2061 Editor::set_state (const XMLNode& node)
2063 const XMLProperty* prop;
2065 int x, y, width, height, xoff, yoff;
2067 if ((geometry = find_named_node (node, "geometry")) == 0) {
2069 width = default_width;
2070 height = default_height;
2078 width = atoi(geometry->property("x_size")->value());
2079 height = atoi(geometry->property("y_size")->value());
2080 x = atoi(geometry->property("x_pos")->value());
2081 y = atoi(geometry->property("y_pos")->value());
2082 xoff = atoi(geometry->property("x_off")->value());
2083 yoff = atoi(geometry->property("y_off")->value());
2086 set_default_size(width, height);
2089 if ((prop = node.property ("zoom-focus"))) {
2090 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2093 if ((prop = node.property ("zoom"))) {
2094 set_frames_per_unit (atof (prop->value()));
2097 if ((prop = node.property ("snap-to"))) {
2098 set_snap_to ((SnapType) atoi (prop->value()));
2101 if ((prop = node.property ("snap-mode"))) {
2102 set_snap_mode ((SnapMode) atoi (prop->value()));
2105 if ((prop = node.property ("show-waveforms"))) {
2106 bool yn = (prop->value() == "yes");
2107 _show_waveforms = !yn;
2108 set_show_waveforms (yn);
2111 if ((prop = node.property ("show-waveforms-recording"))) {
2112 bool yn = (prop->value() == "yes");
2113 _show_waveforms_recording = !yn;
2114 set_show_waveforms_recording (yn);
2117 if ((prop = node.property ("show-measures"))) {
2118 bool yn = (prop->value() == "yes");
2119 _show_measures = !yn;
2120 set_show_measures (yn);
2123 if ((prop = node.property ("follow-playhead"))) {
2124 bool yn = (prop->value() == "yes");
2125 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleFollowPlayhead"));
2127 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2128 /* do it twice to force the change */
2129 tact->set_active (!yn);
2130 tact->set_active (yn);
2134 if ((prop = node.property ("xfades-visible"))) {
2135 bool yn = (prop->value() == "yes");
2136 _xfade_visibility = !yn;
2137 set_xfade_visibility (yn);
2140 if ((prop = node.property ("region-list-sort-type"))) {
2141 region_list_sort_type = (Editing::RegionListSortType) -1; /* force change */
2142 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2145 if ((prop = node.property ("mouse-mode"))) {
2146 MouseMode m = str2mousemode(prop->value());
2147 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2148 set_mouse_mode (m, true);
2150 mouse_mode = MouseGain; /* lie, to force the mode switch */
2151 set_mouse_mode (MouseObject, true);
2154 if ((prop = node.property ("editor-mixer-button"))) {
2155 editor_mixer_button.set_active(prop->value() == "yes");
2162 Editor::get_state ()
2164 XMLNode* node = new XMLNode ("Editor");
2167 if (is_realized()) {
2168 Glib::RefPtr<Gdk::Window> win = get_window();
2170 int x, y, xoff, yoff, width, height;
2171 win->get_root_origin(x, y);
2172 win->get_position(xoff, yoff);
2173 win->get_size(width, height);
2175 XMLNode* geometry = new XMLNode ("geometry");
2177 snprintf(buf, sizeof(buf), "%d", width);
2178 geometry->add_property("x_size", string(buf));
2179 snprintf(buf, sizeof(buf), "%d", height);
2180 geometry->add_property("y_size", string(buf));
2181 snprintf(buf, sizeof(buf), "%d", x);
2182 geometry->add_property("x_pos", string(buf));
2183 snprintf(buf, sizeof(buf), "%d", y);
2184 geometry->add_property("y_pos", string(buf));
2185 snprintf(buf, sizeof(buf), "%d", xoff);
2186 geometry->add_property("x_off", string(buf));
2187 snprintf(buf, sizeof(buf), "%d", yoff);
2188 geometry->add_property("y_off", string(buf));
2189 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2190 geometry->add_property("edit_pane_pos", string(buf));
2192 node->add_child_nocopy (*geometry);
2195 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2196 node->add_property ("zoom-focus", buf);
2197 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2198 node->add_property ("zoom", buf);
2199 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2200 node->add_property ("snap-to", buf);
2201 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2202 node->add_property ("snap-mode", buf);
2204 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2205 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2206 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2207 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2208 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2209 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2210 node->add_property ("mouse-mode", enum2str(mouse_mode));
2211 node->add_property ("editor-mixer-button", editor_mixer_button.get_active() ? "yes" : "no");
2219 Editor::trackview_by_y_position (double y)
2221 TrackViewList::iterator iter;
2224 for (iter = track_views.begin(); iter != track_views.end(); ++iter) {
2232 if (tv->y_position <= y && y < ((tv->y_position + tv->height + track_spacing))) {
2241 Editor::snap_to (jack_nframes_t& start, int32_t direction, bool for_mark)
2243 Location* before = 0;
2244 Location* after = 0;
2250 const jack_nframes_t one_second = session->frame_rate();
2251 const jack_nframes_t one_minute = session->frame_rate() * 60;
2253 jack_nframes_t presnap = start;
2255 switch (snap_type) {
2261 start = (jack_nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2263 start = (jack_nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2266 case SnapToSMPTEFrame:
2268 start = (jack_nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2270 start = (jack_nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2274 case SnapToSMPTESeconds:
2275 if (session->smpte_offset_negative())
2277 start += session->smpte_offset ();
2279 start -= session->smpte_offset ();
2281 if (direction > 0) {
2282 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2284 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2287 if (session->smpte_offset_negative())
2289 start -= session->smpte_offset ();
2291 start += session->smpte_offset ();
2295 case SnapToSMPTEMinutes:
2296 if (session->smpte_offset_negative())
2298 start += session->smpte_offset ();
2300 start -= session->smpte_offset ();
2303 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2305 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2307 if (session->smpte_offset_negative())
2309 start -= session->smpte_offset ();
2311 start += session->smpte_offset ();
2317 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2319 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2325 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2327 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2332 start = session->tempo_map().round_to_bar (start, direction);
2336 start = session->tempo_map().round_to_beat (start, direction);
2339 case SnapToAThirtysecondBeat:
2340 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2343 case SnapToASixteenthBeat:
2344 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2347 case SnapToAEighthBeat:
2348 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2351 case SnapToAQuarterBeat:
2352 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2355 case SnapToAThirdBeat:
2356 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2359 case SnapToEditCursor:
2360 start = edit_cursor->current_frame;
2368 before = session->locations()->first_location_before (start);
2369 after = session->locations()->first_location_after (start);
2371 if (direction < 0) {
2373 start = before->start();
2377 } else if (direction > 0) {
2379 start = after->start();
2381 start = session->current_end_frame();
2386 /* find nearest of the two */
2387 if ((start - before->start()) < (after->start() - start)) {
2388 start = before->start();
2390 start = after->start();
2393 start = before->start();
2396 start = after->start();
2403 case SnapToRegionStart:
2404 case SnapToRegionEnd:
2405 case SnapToRegionSync:
2406 case SnapToRegionBoundary:
2407 if (!region_boundary_cache.empty()) {
2408 vector<jack_nframes_t>::iterator i;
2410 if (direction > 0) {
2411 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2413 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2416 if (i != region_boundary_cache.end()) {
2419 start = region_boundary_cache.back();
2425 switch (snap_mode) {
2431 if (presnap > start) {
2432 if (presnap > (start + unit_to_frame(snap_threshold))) {
2436 } else if (presnap < start) {
2437 if (presnap < (start - unit_to_frame(snap_threshold))) {
2449 Editor::setup_toolbar ()
2452 vector<ToggleButton *> mouse_mode_buttons;
2454 mouse_mode_buttons.push_back (&mouse_move_button);
2455 mouse_mode_buttons.push_back (&mouse_select_button);
2456 mouse_mode_buttons.push_back (&mouse_gain_button);
2457 mouse_mode_buttons.push_back (&mouse_zoom_button);
2458 mouse_mode_buttons.push_back (&mouse_timefx_button);
2459 mouse_mode_buttons.push_back (&mouse_audition_button);
2460 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2462 mouse_mode_button_table.set_homogeneous (true);
2463 mouse_mode_button_table.set_col_spacings (2);
2464 mouse_mode_button_table.set_row_spacings (2);
2465 mouse_mode_button_table.set_border_width (5);
2467 mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1);
2468 mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1);
2469 mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1);
2471 mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2);
2472 mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2);
2473 mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2);
2475 mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table));
2476 mouse_mode_tearoff->set_name ("MouseModeBase");
2478 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
2479 &mouse_mode_tearoff->tearoff_window()));
2480 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
2481 &mouse_mode_tearoff->tearoff_window(), 1));
2483 mouse_move_button.set_name ("MouseModeButton");
2484 mouse_select_button.set_name ("MouseModeButton");
2485 mouse_gain_button.set_name ("MouseModeButton");
2486 mouse_zoom_button.set_name ("MouseModeButton");
2487 mouse_timefx_button.set_name ("MouseModeButton");
2488 mouse_audition_button.set_name ("MouseModeButton");
2490 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects"));
2491 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges"));
2492 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation"));
2493 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range"));
2494 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions"));
2495 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions"));
2497 mouse_move_button.unset_flags (Gtk::CAN_FOCUS);
2498 mouse_select_button.unset_flags (Gtk::CAN_FOCUS);
2499 mouse_gain_button.unset_flags (Gtk::CAN_FOCUS);
2500 mouse_zoom_button.unset_flags (Gtk::CAN_FOCUS);
2501 mouse_timefx_button.unset_flags (Gtk::CAN_FOCUS);
2502 mouse_audition_button.unset_flags (Gtk::CAN_FOCUS);
2504 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2505 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2507 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2508 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2509 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2510 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2511 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2513 // mouse_move_button.set_active (true);
2515 /* automation control */
2517 global_automation_button.set_name ("MouseModeButton");
2518 automation_mode_button.set_name ("MouseModeButton");
2520 automation_box.set_spacing (2);
2521 automation_box.set_border_width (2);
2522 automation_box.pack_start (global_automation_button, false, false);
2523 automation_box.pack_start (automation_mode_button, false, false);
2527 edit_mode_label.set_name ("ToolBarLabel");
2529 edit_mode_selector.set_name ("EditModeSelector");
2531 edit_mode_box.set_spacing (3);
2532 edit_mode_box.set_border_width (3);
2534 /* XXX another disgusting hack because of the way combo boxes size themselves */
2536 const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button
2537 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2+FUDGE, 10);
2538 set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings));
2539 edit_mode_box.pack_start (edit_mode_label, false, false);
2540 edit_mode_box.pack_start (edit_mode_selector, false, false);
2542 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2546 snap_type_label.set_name ("ToolBarLabel");
2548 snap_type_selector.set_name ("SnapTypeSelector");
2550 snap_type_box.set_spacing (3);
2551 snap_type_box.set_border_width (3);
2553 /* XXX another disgusting hack because of the way combo boxes size themselves */
2555 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2556 set_popdown_strings (snap_type_selector, internationalize (snap_type_strings));
2558 snap_type_box.pack_start (snap_type_label, false, false);
2559 snap_type_box.pack_start (snap_type_selector, false, false);
2561 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2563 /* Snap mode, not snap type */
2565 snap_mode_label.set_name ("ToolBarLabel");
2567 snap_mode_selector.set_name ("SnapModeSelector");
2569 snap_mode_box.set_spacing (3);
2570 snap_mode_box.set_border_width (3);
2572 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2+FUDGE, 10);
2573 set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings));
2575 snap_mode_box.pack_start (snap_mode_label, false, false);
2576 snap_mode_box.pack_start (snap_mode_selector, false, false);
2578 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2580 /* Zoom focus mode */
2582 zoom_focus_label.set_name ("ToolBarLabel");
2584 zoom_focus_selector.set_name ("ZoomFocusSelector");
2586 zoom_focus_box.set_spacing (3);
2587 zoom_focus_box.set_border_width (3);
2589 /* XXX another disgusting hack because of the way combo boxes size themselves */
2591 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2+FUDGE, 10);
2592 set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings));
2594 zoom_focus_box.pack_start (zoom_focus_label, false, false);
2595 zoom_focus_box.pack_start (zoom_focus_selector, false, false);
2597 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2599 /* selection/cursor clocks */
2601 toolbar_selection_cursor_label.set_name ("ToolBarLabel");
2602 selection_start_clock_label.set_name ("ToolBarLabel");
2603 selection_end_clock_label.set_name ("ToolBarLabel");
2604 edit_cursor_clock_label.set_name ("ToolBarLabel");
2606 selection_start_clock_label.set_text (_("Start:"));
2607 selection_end_clock_label.set_text (_("End:"));
2608 edit_cursor_clock_label.set_text (_("Edit:"));
2610 toolbar_selection_clock_table.set_border_width (5);
2611 toolbar_selection_clock_table.set_col_spacings (2);
2612 toolbar_selection_clock_table.set_homogeneous (false);
2614 // toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0);
2615 // toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0);
2616 toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, FILL, FILL, 0, 0);
2618 // toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0);
2619 // toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0);
2620 toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, FILL, FILL);
2623 // toolbar_clock_vbox.set_spacing (2);
2624 // toolbar_clock_vbox.set_border_width (10);
2625 /* the editor/mixer button will be enabled at session connect */
2627 editor_mixer_button.set_active(false);
2628 editor_mixer_button.set_sensitive(false);
2630 HBox* hbox = new HBox;
2632 hbox->pack_start (editor_mixer_button, false, false);
2633 hbox->pack_start (toolbar_selection_clock_table, false, false);
2634 hbox->pack_start (zoom_indicator_vbox, false, false);
2635 hbox->pack_start (zoom_focus_box, false, false);
2636 hbox->pack_start (snap_type_box, false, false);
2637 hbox->pack_start (snap_mode_box, false, false);
2638 hbox->pack_start (edit_mode_box, false, false);
2640 VBox *vbox = manage (new VBox);
2642 vbox->set_spacing (3);
2643 vbox->set_border_width (3);
2645 HBox *nbox = manage (new HBox);
2647 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2648 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2650 nbox->pack_start (nudge_backward_button, false, false);
2651 nbox->pack_start (nudge_forward_button, false, false);
2652 nbox->pack_start (nudge_clock, false, false, 5);
2654 nudge_label.set_name ("ToolBarLabel");
2656 vbox->pack_start (nudge_label, false, false);
2657 vbox->pack_start (*nbox, false, false);
2659 hbox->pack_start (*vbox, false, false);
2663 tools_tearoff = new TearOff (*hbox);
2664 tools_tearoff->set_name ("MouseModeBase");
2666 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
2667 &tools_tearoff->tearoff_window()));
2668 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
2669 &tools_tearoff->tearoff_window(), 0));
2672 toolbar_hbox.set_spacing (8);
2673 toolbar_hbox.set_border_width (2);
2675 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2676 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2678 toolbar_base.set_name ("ToolBarBase");
2679 toolbar_base.add (toolbar_hbox);
2681 toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT);
2682 toolbar_frame.set_name ("BaseFrame");
2683 toolbar_frame.add (toolbar_base);
2687 Editor::_autoscroll_canvas (void *arg)
2689 return ((Editor *) arg)->autoscroll_canvas ();
2693 Editor::autoscroll_canvas ()
2695 jack_nframes_t new_frame;
2696 bool keep_calling = true;
2698 if (autoscroll_direction < 0) {
2699 if (leftmost_frame < autoscroll_distance) {
2702 new_frame = leftmost_frame - autoscroll_distance;
2705 if (leftmost_frame > max_frames - autoscroll_distance) {
2706 new_frame = max_frames;
2708 new_frame = leftmost_frame + autoscroll_distance;
2712 if (new_frame != leftmost_frame) {
2713 reposition_x_origin (new_frame);
2716 if (new_frame == 0 || new_frame == max_frames) {
2723 if (autoscroll_cnt == 1) {
2725 /* connect the timeout so that we get called repeatedly */
2727 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
2728 keep_calling = false;
2730 } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
2732 /* after about a while, speed up a bit by changing the timeout interval */
2734 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
2735 keep_calling = false;
2737 } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
2739 /* after about another while, speed up some more */
2741 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
2742 keep_calling = false;
2744 } else if (autoscroll_cnt >= 30) {
2746 /* we've been scrolling for a while ... crank it up */
2748 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
2751 return keep_calling;
2755 Editor::start_canvas_autoscroll (int dir)
2761 stop_canvas_autoscroll ();
2763 autoscroll_direction = dir;
2764 autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
2767 /* do it right now, which will start the repeated callbacks */
2769 autoscroll_canvas ();
2773 Editor::stop_canvas_autoscroll ()
2775 if (autoscroll_timeout_tag >= 0) {
2776 gtk_timeout_remove (autoscroll_timeout_tag);
2777 autoscroll_timeout_tag = -1;
2782 Editor::convert_drop_to_paths (vector<string>& paths,
2783 const RefPtr<Gdk::DragContext>& context,
2786 const SelectionData& data,
2795 vector<ustring> uris = data.get_uris();
2799 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2800 are actually URI lists. So do it by hand.
2803 if (data.get_target() != "text/plain") {
2807 /* Parse the "uri-list" format that Nautilus provides,
2808 where each pathname is delimited by \r\n
2811 const char* p = data.get_text().c_str();
2818 while (g_ascii_isspace (*p))
2822 while (*q && (*q != '\n') && (*q != '\r'))
2828 while (q > p && g_ascii_isspace (*q))
2833 uris.push_back (ustring (p, q - p + 1));
2837 p = strchr (p, '\n');
2847 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2848 if ((*i).substr (0,7) == "file://") {
2851 cerr << "adding " << p << endl;
2852 paths.push_back (p.substr (7));
2860 Editor::new_tempo_section ()
2866 Editor::map_transport_state ()
2868 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2870 if (session->transport_stopped()) {
2871 have_pending_keyboard_selection = false;
2877 Editor::State::State ()
2879 selection = new Selection;
2882 Editor::State::~State ()
2888 Editor::get_memento () const
2890 State *state = new State;
2892 store_state (*state);
2893 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2897 Editor::store_state (State& state) const
2899 *state.selection = *selection;
2903 Editor::restore_state (State *state)
2905 if (*selection == *state->selection) {
2909 *selection = *state->selection;
2910 time_selection_changed ();
2911 region_selection_changed ();
2913 /* XXX other selection change handlers? */
2917 Editor::begin_reversible_command (string name)
2920 UndoAction ua = get_memento();
2921 session->begin_reversible_command (name, &ua);
2926 Editor::commit_reversible_command ()
2929 UndoAction ua = get_memento();
2930 session->commit_reversible_command (&ua);
2935 Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove)
2937 if (!clicked_trackview) {
2942 begin_reversible_command (_("set selected trackview"));
2947 if (selection->selected (clicked_trackview)) {
2949 selection->remove (clicked_trackview);
2952 selection->add (clicked_trackview);
2957 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
2958 /* no commit necessary */
2962 selection->set (clicked_trackview);
2966 commit_reversible_command ();
2971 Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove)
2973 if (!clicked_control_point) {
2978 begin_reversible_command (_("set selected control point"));
2988 commit_reversible_command ();
2993 Editor::set_selected_regionview_from_click (bool add, bool no_track_remove)
2995 if (!clicked_regionview) {
2999 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view());
3005 RouteGroup* group = atv->route().edit_group();
3006 vector<AudioRegionView*> all_equivalent_regions;
3008 if (group && group->is_active()) {
3010 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3012 AudioTimeAxisView* tatv;
3014 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3016 if (tatv->route().edit_group() != group) {
3021 vector<AudioRegion*> results;
3022 AudioRegionView* marv;
3025 if ((ds = tatv->get_diskstream()) == 0) {
3030 if ((pl = ds->playlist()) != 0) {
3031 pl->get_equivalent_regions (clicked_regionview->region,
3035 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3036 if ((marv = tatv->view->find_view (**ir)) != 0) {
3037 all_equivalent_regions.push_back (marv);
3046 all_equivalent_regions.push_back (clicked_regionview);
3050 begin_reversible_command (_("set selected regionview"));
3054 if (clicked_regionview->get_selected()) {
3055 if (group && group->is_active() && selection->audio_regions.size() > 1) {
3056 /* reduce selection down to just the one clicked */
3057 selection->set (clicked_regionview);
3059 selection->remove (clicked_regionview);
3062 selection->add (all_equivalent_regions);
3065 set_selected_track_from_click (add, false, no_track_remove);
3069 // karsten wiese suggested these two lines to make
3070 // a selected region rise to the top. but this
3071 // leads to a mismatch between actual layering
3072 // and visual layering. resolution required ....
3074 // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3075 // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3077 if (clicked_regionview->get_selected()) {
3078 /* no commit necessary: we are the one selected. */
3083 selection->set (all_equivalent_regions);
3084 set_selected_track_from_click (add, false, false);
3088 commit_reversible_command () ;
3092 Editor::set_selected_regionview_from_region_list (Region& r, bool add)
3094 vector<AudioRegionView*> all_equivalent_regions;
3095 AudioRegion* region;
3097 if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3101 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3103 AudioTimeAxisView* tatv;
3105 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3108 vector<AudioRegion*> results;
3109 AudioRegionView* marv;
3112 if ((ds = tatv->get_diskstream()) == 0) {
3117 if ((pl = ds->playlist()) != 0) {
3118 pl->get_region_list_equivalent_regions (*region, results);
3121 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3122 if ((marv = tatv->view->find_view (**ir)) != 0) {
3123 all_equivalent_regions.push_back (marv);
3130 begin_reversible_command (_("set selected regions"));
3134 selection->add (all_equivalent_regions);
3138 selection->set (all_equivalent_regions);
3141 commit_reversible_command () ;
3145 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3147 AudioRegionView* rv;
3150 if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3154 if ((rv = sv->find_view (*ar)) == 0) {
3158 /* don't reset the selection if its something other than
3159 a single other region.
3162 if (selection->audio_regions.size() > 1) {
3166 begin_reversible_command (_("set selected regions"));
3168 selection->set (rv);
3170 commit_reversible_command () ;
3176 Editor::set_edit_group_solo (Route& route, bool yn)
3178 RouteGroup *edit_group;
3180 if ((edit_group = route.edit_group()) != 0) {
3181 edit_group->apply (&Route::set_solo, yn, this);
3183 route.set_solo (yn, this);
3188 Editor::set_edit_group_mute (Route& route, bool yn)
3190 RouteGroup *edit_group = 0;
3192 if ((edit_group == route.edit_group()) != 0) {
3193 edit_group->apply (&Route::set_mute, yn, this);
3195 route.set_mute (yn, this);
3200 Editor::set_edit_menu (Menu& menu)
3203 edit_menu->signal_map_event().connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3207 Editor::edit_menu_map_handler (GdkEventAny* ev)
3209 using namespace Menu_Helpers;
3210 MenuList& edit_items = edit_menu->items();
3213 /* Nuke all the old items */
3215 edit_items.clear ();
3221 if (session->undo_depth() == 0) {
3224 label = string_compose(_("Undo (%1)"), session->next_undo());
3227 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3229 if (session->undo_depth() == 0) {
3230 edit_items.back().set_sensitive (false);
3233 if (session->redo_depth() == 0) {
3236 label = string_compose(_("Redo (%1)"), session->next_redo());
3239 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3240 if (session->redo_depth() == 0) {
3241 edit_items.back().set_sensitive (false);
3244 vector<MenuItem*> mitems;
3246 edit_items.push_back (SeparatorElem());
3247 edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3248 mitems.push_back (&edit_items.back());
3249 edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3250 mitems.push_back (&edit_items.back());
3251 edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3252 mitems.push_back (&edit_items.back());
3253 edit_items.push_back (SeparatorElem());
3254 edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3255 mitems.push_back (&edit_items.back());
3256 edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3257 mitems.push_back (&edit_items.back());
3258 edit_items.push_back (SeparatorElem());
3260 if (selection->empty()) {
3261 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3262 (*i)->set_sensitive (false);
3266 Menu* import_menu = manage (new Menu());
3267 import_menu->set_name ("ArdourContextMenu");
3268 MenuList& import_items = import_menu->items();
3270 import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3271 import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3273 Menu* embed_menu = manage (new Menu());
3274 embed_menu->set_name ("ArdourContextMenu");
3275 MenuList& embed_items = embed_menu->items();
3277 embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3278 embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3280 edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3281 edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3282 edit_items.push_back (SeparatorElem());
3284 edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3285 if (!session->have_captured()) {
3286 edit_items.back().set_sensitive (false);
3293 Editor::duplicate_dialog (bool dup_region)
3296 if (clicked_regionview == 0) {
3300 if (selection->time.length() == 0) {
3305 ArdourDialog win ("duplicate dialog");
3307 Label label (_("Duplicate how many times?"));
3309 win.get_vbox()->pack_start (label);
3310 win.add_action_widget (entry, RESPONSE_ACCEPT);
3311 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3312 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3314 win.set_position (Gtk::WIN_POS_MOUSE);
3316 entry.set_text ("1");
3317 set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
3318 entry.select_region (0, entry.get_text_length());
3319 entry.grab_focus ();
3322 // win.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
3325 switch (win.run ()) {
3326 case RESPONSE_ACCEPT:
3332 string text = entry.get_text();
3335 if (sscanf (text.c_str(), "%f", ×) == 1) {
3337 AudioRegionSelection regions;
3338 regions.add (clicked_regionview);
3339 duplicate_some_regions (regions, times);
3341 duplicate_selection (times);
3347 Editor::show_verbose_canvas_cursor ()
3349 verbose_canvas_cursor->raise_to_top();
3350 verbose_canvas_cursor->show();
3351 verbose_cursor_visible = true;
3355 Editor::hide_verbose_canvas_cursor ()
3357 verbose_canvas_cursor->hide();
3358 verbose_cursor_visible = false;
3362 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3364 /* XXX get origin of canvas relative to root window,
3365 add x and y and check compared to gdk_screen_{width,height}
3367 verbose_canvas_cursor->property_text() = txt.c_str();
3368 verbose_canvas_cursor->property_x() = x;
3369 verbose_canvas_cursor->property_y() = y;
3373 Editor::set_verbose_canvas_cursor_text (const string & txt)
3375 verbose_canvas_cursor->property_text() = txt.c_str();
3379 Editor::edit_mode_selection_done ()
3385 string choice = edit_mode_selector.get_active_text();
3386 EditMode mode = Slide;
3388 if (choice == _("Splice")) {
3390 } else if (choice == _("Slide")) {
3394 session->set_edit_mode (mode);
3398 Editor::snap_type_selection_done ()
3404 string choice = snap_type_selector.get_active_text();
3405 SnapType snaptype = SnapToFrame;
3407 if (choice == _("Beats/3")) {
3408 snaptype = SnapToAThirdBeat;
3409 } else if (choice == _("Beats/4")) {
3410 snaptype = SnapToAQuarterBeat;
3411 } else if (choice == _("Beats/8")) {
3412 snaptype = SnapToAEighthBeat;
3413 } else if (choice == _("Beats/16")) {
3414 snaptype = SnapToASixteenthBeat;
3415 } else if (choice == _("Beats/32")) {
3416 snaptype = SnapToAThirtysecondBeat;
3417 } else if (choice == _("Beats")) {
3418 snaptype = SnapToBeat;
3419 } else if (choice == _("Bars")) {
3420 snaptype = SnapToBar;
3421 } else if (choice == _("Marks")) {
3422 snaptype = SnapToMark;
3423 } else if (choice == _("Edit Cursor")) {
3424 snaptype = SnapToEditCursor;
3425 } else if (choice == _("Region starts")) {
3426 snaptype = SnapToRegionStart;
3427 } else if (choice == _("Region ends")) {
3428 snaptype = SnapToRegionEnd;
3429 } else if (choice == _("Region bounds")) {
3430 snaptype = SnapToRegionBoundary;
3431 } else if (choice == _("Region syncs")) {
3432 snaptype = SnapToRegionSync;
3433 } else if (choice == _("CD Frames")) {
3434 snaptype = SnapToCDFrame;
3435 } else if (choice == _("SMPTE Frames")) {
3436 snaptype = SnapToSMPTEFrame;
3437 } else if (choice == _("SMPTE Seconds")) {
3438 snaptype = SnapToSMPTESeconds;
3439 } else if (choice == _("SMPTE Minutes")) {
3440 snaptype = SnapToSMPTEMinutes;
3441 } else if (choice == _("Seconds")) {
3442 snaptype = SnapToSeconds;
3443 } else if (choice == _("Minutes")) {
3444 snaptype = SnapToMinutes;
3445 } else if (choice == _("None")) {
3446 snaptype = SnapToFrame;
3449 set_snap_to (snaptype);
3453 Editor::snap_mode_selection_done ()
3459 string choice = snap_mode_selector.get_active_text();
3460 SnapMode mode = SnapNormal;
3462 if (choice == _("Normal")) {
3464 } else if (choice == _("Magnetic")) {
3465 mode = SnapMagnetic;
3468 set_snap_mode (mode);
3472 Editor::zoom_focus_selection_done ()
3478 string choice = zoom_focus_selector.get_active_text();
3479 ZoomFocus focus_type = ZoomFocusLeft;
3481 if (choice == _("Left")) {
3482 focus_type = ZoomFocusLeft;
3483 } else if (choice == _("Right")) {
3484 focus_type = ZoomFocusRight;
3485 } else if (choice == _("Center")) {
3486 focus_type = ZoomFocusCenter;
3487 } else if (choice == _("Playhead")) {
3488 focus_type = ZoomFocusPlayhead;
3489 } else if (choice == _("Edit Cursor")) {
3490 focus_type = ZoomFocusEdit;
3493 set_zoom_focus (focus_type);
3497 Editor::edit_controls_button_release (GdkEventButton* ev)
3499 if (Keyboard::is_context_menu_event (ev)) {
3500 ARDOUR_UI::instance()->add_route ();
3506 Editor::track_selection_changed ()
3508 switch (selection->tracks.size()){
3512 set_selected_mixer_strip (*(selection->tracks.front()));
3516 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3517 (*i)->set_selected (false);
3518 if (mouse_mode == MouseRange) {
3519 (*i)->hide_selection ();
3523 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3524 (*i)->set_selected (true);
3525 if (mouse_mode == MouseRange) {
3526 (*i)->show_selection (selection->time);
3532 Editor::time_selection_changed ()
3534 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3535 (*i)->hide_selection ();
3538 if (selection->tracks.empty()) {
3539 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3540 (*i)->show_selection (selection->time);
3543 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3544 (*i)->show_selection (selection->time);
3550 Editor::region_selection_changed ()
3552 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3553 (*i)->set_selected_regionviews (selection->audio_regions);
3558 Editor::point_selection_changed ()
3560 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3561 (*i)->set_selected_points (selection->points);
3566 Editor::mouse_select_button_release (GdkEventButton* ev)
3568 /* this handles just right-clicks */
3570 if (ev->button != 3) {
3577 Editor::TrackViewList *
3578 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3581 TrackViewList::iterator i;
3583 v = new TrackViewList;
3585 if (track == 0 && group == 0) {
3589 for (i = track_views.begin(); i != track_views.end (); ++i) {
3593 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3595 /* just the view for this track
3598 v->push_back (track);
3602 /* views for all tracks in the edit group */
3604 for (i = track_views.begin(); i != track_views.end (); ++i) {
3606 if (group == 0 || (*i)->edit_group() == group) {
3616 Editor::set_zoom_focus (ZoomFocus f)
3618 if (zoom_focus != f) {
3620 vector<string> txt = internationalize (zoom_focus_strings);
3621 zoom_focus_selector.set_active_text (txt[(int)f]);
3622 ZoomFocusChanged (); /* EMIT_SIGNAL */
3629 Editor::ensure_float (Window& win)
3631 win.set_transient_for (*this);
3635 Editor::pane_allocation_handler (Gtk::Allocation &alloc, Gtk::Paned* which)
3637 /* recover or initialize pane positions. do this here rather than earlier because
3638 we don't want the positions to change the child allocations, which they seem to do.
3644 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3646 static int32_t done[4] = { 0, 0, 0, 0 };
3649 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3650 width = default_width;
3651 height = default_height;
3653 width = atoi(geometry->property("x_size")->value());
3654 height = atoi(geometry->property("y_size")->value());
3657 if (which == static_cast<Gtk::Paned*> (&edit_pane)) {
3663 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3665 snprintf (buf, sizeof(buf), "%d", pos);
3667 pos = atoi (prop->value());
3670 if ((done[0] = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3671 edit_pane.set_position (pos);
3677 Editor::detach_tearoff (Gtk::Box* b, Gtk::Window* w)
3679 if (tools_tearoff->torn_off() &&
3680 mouse_mode_tearoff->torn_off()) {
3681 top_hbox.remove (toolbar_frame);
3688 Editor::reattach_tearoff (Gtk::Box* b, Gtk::Window* w, int32_t n)
3690 if (toolbar_frame.get_parent() == 0) {
3691 top_hbox.pack_end (toolbar_frame);
3696 Editor::set_show_measures (bool yn)
3698 if (_show_measures != yn) {
3701 if ((_show_measures = yn) == true) {
3704 DisplayControlChanged (ShowMeasures);
3710 Editor::toggle_follow_playhead ()
3712 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleFollowPlayhead"));
3714 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3715 set_follow_playhead (tact->get_active());
3720 Editor::set_follow_playhead (bool yn)
3722 if (_follow_playhead != yn) {
3723 if ((_follow_playhead = yn) == true) {
3725 update_current_screen ();
3727 DisplayControlChanged (FollowPlayhead);
3733 Editor::toggle_xfade_active (Crossfade* xfade)
3735 xfade->set_active (!xfade->active());
3739 Editor::toggle_xfade_length (Crossfade* xfade)
3741 xfade->set_follow_overlap (!xfade->following_overlap());
3745 Editor::edit_xfade (Crossfade* xfade)
3747 CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
3752 // cew.signal_delete_event().connect (mem_fun (cew, &ArdourDialog::wm_doi_event_stop));
3754 switch (cew.run ()) {
3755 case RESPONSE_ACCEPT:
3762 xfade->StateChanged (Change (~0));
3766 Editor::playlist_selector () const
3768 return *_playlist_selector;
3772 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
3776 ret = nudge_clock.current_duration (pos);
3777 next = ret + 1; /* XXXX fix me */
3783 Editor::end_location_changed (Location* location)
3785 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3786 horizontal_adjustment.set_upper (location->end() / frames_per_unit);
3790 Editor::playlist_deletion_dialog (Playlist* pl)
3792 ArdourDialog dialog ("playlist deletion dialog");
3793 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3794 "If left alone, no audio files used by it will be cleaned.\n"
3795 "If deleted, audio files used by it alone by will cleaned."),
3798 dialog.set_position (Gtk::WIN_POS_CENTER);
3799 dialog.get_vbox()->pack_start (label);
3801 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3802 dialog.add_button (_("Keep playlist"), RESPONSE_CANCEL);
3803 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3805 switch (dialog.run ()) {
3806 case RESPONSE_ACCEPT:
3807 /* delete the playlist */
3811 case RESPONSE_REJECT:
3812 /* keep the playlist */
3824 Editor::audio_region_selection_covers (jack_nframes_t where)
3826 for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
3827 if ((*a)->region.covers (where)) {
3836 Editor::prepare_for_cleanup ()
3838 cut_buffer->clear_audio_regions ();
3839 cut_buffer->clear_playlists ();
3841 selection->clear_audio_regions ();
3842 selection->clear_playlists ();
3846 Editor::init_colormap ()
3848 for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) {
3849 pair<ColorID,int> newpair;
3851 newpair.first = (ColorID) x;
3852 newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255);
3853 color_map.insert (newpair);
3858 Editor::transport_loop_location()
3861 return session->locations()->auto_loop_location();
3868 Editor::transport_punch_location()
3871 return session->locations()->auto_punch_location();
3878 Editor::control_layout_scroll (GdkEventScroll* ev)
3880 switch (ev->direction) {
3882 scroll_tracks_up_line ();
3886 case GDK_SCROLL_DOWN:
3887 scroll_tracks_down_line ();
3891 /* no left/right handling yet */