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 region_edit_menu_split_item = 0;
344 region_edit_menu_split_multichannel_item = 0;
346 ignore_mouse_mode_toggle = false;
347 current_stepping_trackview = 0;
349 entered_regionview = 0;
350 clear_entered_track = false;
351 _new_regionviews_show_envelope = false;
352 current_timestretch = 0;
357 location_marker_color = color_map[cLocationMarker];
358 location_range_color = color_map[cLocationRange];
359 location_cd_marker_color = color_map[cLocationCDMarker];
360 location_loop_color = color_map[cLocationLoop];
361 location_punch_color = color_map[cLocationPunch];
363 range_marker_drag_rect = 0;
364 marker_drag_line = 0;
366 set_mouse_mode (MouseObject, true);
368 frames_per_unit = 2048; /* too early to use set_frames_per_unit */
369 zoom_focus = ZoomFocusLeft;
370 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
372 initialize_rulers ();
373 initialize_canvas ();
375 edit_controls_vbox.set_spacing (0);
376 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
377 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
379 track_canvas.set_hadjustment (horizontal_adjustment);
380 track_canvas.set_vadjustment (vertical_adjustment);
381 time_canvas.set_hadjustment (horizontal_adjustment);
383 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
384 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
386 controls_layout.add (edit_controls_vbox);
387 controls_layout.set_name ("EditControlsBase");
388 controls_layout.add_events (Gdk::SCROLL_MASK);
389 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
391 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
392 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
394 edit_vscrollbar.set_adjustment (vertical_adjustment);
395 edit_hscrollbar.set_adjustment (horizontal_adjustment);
397 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press));
398 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release));
399 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
404 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
406 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
407 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
408 time_canvas_vbox.pack_start (*frames_ruler, false, false);
409 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
410 time_canvas_vbox.pack_start (time_canvas, true, true);
411 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars));
413 bbt_label.set_name ("EditorTimeButton");
414 bbt_label.set_size_request (-1, (int)timebar_height);
415 bbt_label.set_alignment (1.0, 0.5);
416 bbt_label.set_padding (5,0);
417 minsec_label.set_name ("EditorTimeButton");
418 minsec_label.set_size_request (-1, (int)timebar_height);
419 minsec_label.set_alignment (1.0, 0.5);
420 minsec_label.set_padding (5,0);
421 smpte_label.set_name ("EditorTimeButton");
422 smpte_label.set_size_request (-1, (int)timebar_height);
423 smpte_label.set_alignment (1.0, 0.5);
424 smpte_label.set_padding (5,0);
425 frame_label.set_name ("EditorTimeButton");
426 frame_label.set_size_request (-1, (int)timebar_height);
427 frame_label.set_alignment (1.0, 0.5);
428 frame_label.set_padding (5,0);
429 tempo_label.set_name ("EditorTimeButton");
430 tempo_label.set_size_request (-1, (int)timebar_height);
431 tempo_label.set_alignment (1.0, 0.5);
432 tempo_label.set_padding (5,0);
433 meter_label.set_name ("EditorTimeButton");
434 meter_label.set_size_request (-1, (int)timebar_height);
435 meter_label.set_alignment (1.0, 0.5);
436 meter_label.set_padding (5,0);
437 mark_label.set_name ("EditorTimeButton");
438 mark_label.set_size_request (-1, (int)timebar_height);
439 mark_label.set_alignment (1.0, 0.5);
440 mark_label.set_padding (5,0);
441 range_mark_label.set_name ("EditorTimeButton");
442 range_mark_label.set_size_request (-1, (int)timebar_height);
443 range_mark_label.set_alignment (1.0, 0.5);
444 range_mark_label.set_padding (5,0);
445 transport_mark_label.set_name ("EditorTimeButton");
446 transport_mark_label.set_size_request (-1, (int)timebar_height);
447 transport_mark_label.set_alignment (1.0, 0.5);
448 transport_mark_label.set_padding (5,0);
450 time_button_vbox.pack_start (minsec_label, false, false);
451 time_button_vbox.pack_start (smpte_label, false, false);
452 time_button_vbox.pack_start (frame_label, false, false);
453 time_button_vbox.pack_start (bbt_label, false, false);
454 time_button_vbox.pack_start (meter_label, false, false);
455 time_button_vbox.pack_start (tempo_label, false, false);
456 time_button_vbox.pack_start (mark_label, false, false);
458 time_button_event_box.add (time_button_vbox);
460 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
461 time_button_event_box.set_name ("TimebarLabelBase");
462 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
464 /* these enable us to have a dedicated window (for cursor setting, etc.)
465 for the canvas areas.
468 track_canvas_event_box.add (track_canvas);
470 time_canvas_event_box.add (time_canvas_vbox);
471 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
473 edit_packer.set_col_spacings (0);
474 edit_packer.set_row_spacings (0);
475 edit_packer.set_homogeneous (false);
476 edit_packer.set_name ("EditorWindow");
478 edit_packer.attach (edit_hscrollbar, 1, 2, 0, 1, FILL|EXPAND, FILL, 0, 0);
480 edit_packer.attach (time_button_event_box, 0, 1, 1, 2, FILL, FILL, 0, 0);
481 edit_packer.attach (time_canvas_event_box, 1, 2, 1, 2, FILL|EXPAND, FILL, 0, 0);
483 edit_packer.attach (controls_layout, 0, 1, 2, 3, FILL, FILL|EXPAND, 0, 0);
484 edit_packer.attach (track_canvas_event_box, 1, 2, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
485 edit_packer.attach (edit_vscrollbar, 2, 3, 2, 3, FILL, FILL|EXPAND, 0, 0);
487 edit_frame.set_name ("BaseFrame");
488 edit_frame.set_shadow_type (SHADOW_IN);
489 edit_frame.add (edit_packer);
491 zoom_in_button.set_name ("EditorTimeButton");
492 zoom_out_button.set_name ("EditorTimeButton");
493 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in"));
494 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out"));
496 zoom_out_full_button.set_name ("EditorTimeButton");
497 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session"));
499 zoom_in_button.add (*(manage (new Gtk::Image (Stock::ZOOM_IN, ICON_SIZE_BUTTON))));
500 zoom_out_button.add (*(manage (new Gtk::Image (Stock::ZOOM_OUT, ICON_SIZE_BUTTON))));
501 zoom_out_full_button.add (*(manage (new Gtk::Image (Stock::ZOOM_FIT, ICON_SIZE_BUTTON))));
503 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
504 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
505 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
507 zoom_indicator_box.pack_start (zoom_out_button, false, false);
508 zoom_indicator_box.pack_start (zoom_in_button, false, false);
509 zoom_indicator_box.pack_start (zoom_range_clock, false, false);
510 zoom_indicator_box.pack_start (zoom_out_full_button, false, false);
512 zoom_indicator_label.set_text (_("Zoom Span"));
513 zoom_indicator_label.set_name ("ToolBarLabel");
515 zoom_indicator_vbox.set_spacing (3);
516 zoom_indicator_vbox.set_border_width (3);
517 zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false);
518 zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false);
520 bottom_hbox.set_border_width (3);
521 bottom_hbox.set_spacing (3);
523 route_display_model = ListStore::create(route_display_columns);
524 route_list_display.set_model (route_display_model);
525 route_list_display.append_column (_("Tracks"), route_display_columns.text);
526 route_list_display.set_headers_visible (false);
527 route_list_display.set_name ("TrackListDisplay");
528 route_list_display.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
529 route_list_display.set_reorderable (true);
531 route_list_display.set_size_request (75,-1);
532 route_list_display.set_headers_visible (true);
533 route_list_display.set_headers_clickable (true);
536 // route_list_display.signal_rows_reordered().connect (mem_fun (*this, &Editor::queue_route_list_reordered));
538 route_display_model->set_sort_func (0, mem_fun (*this, &Editor::route_list_compare_func));
539 route_display_model->set_sort_column (0, SORT_ASCENDING);
541 route_list_scroller.add (route_list_display);
542 route_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
544 route_list_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::route_display_selection_changed));
545 route_list_display.signal_columns_changed().connect (mem_fun(*this, &Editor::route_list_column_click));
547 edit_group_list_button_label.set_text (_("Edit Groups"));
548 edit_group_list_button_label.set_name ("EditGroupTitleButton");
549 edit_group_list_button.add (edit_group_list_button_label);
550 edit_group_list_button.set_name ("EditGroupTitleButton");
552 group_model = ListStore::create(group_columns);
553 edit_group_display.set_model (group_model);
554 edit_group_display.append_column (_("active"), group_columns.is_active);
555 edit_group_display.append_column (_("groupname"), group_columns.text);
556 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
557 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
558 edit_group_display.set_headers_visible (false);
560 /* use checkbox for the active column */
562 CellRendererToggle *active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (0));
563 active_cell->property_activatable() = true;
564 active_cell->property_radio() = false;
566 edit_group_display.set_name ("MixerGroupList");
567 //edit_group_display.set_shadow_type (Gtk::SHADOW_IN);
569 edit_group_display.columns_autosize ();
570 edit_group_display.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
571 edit_group_display.set_reorderable (false);
573 edit_group_display.set_size_request (75, -1);
574 edit_group_display.set_headers_visible (true);
576 edit_group_list_scroller.add (edit_group_display);
577 edit_group_list_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
579 edit_group_list_button.signal_clicked().connect (mem_fun(*this, &Editor::edit_group_list_button_clicked));
580 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event));
581 edit_group_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::edit_group_selection_changed));
583 TreeModel::Row row = *(group_model->append());
584 row[group_columns.is_active] = false;
585 row[group_columns.text] = (_("-all-"));
586 row[group_columns.routegroup] = 0;
587 edit_group_display.get_selection()->select (row);
589 edit_group_vbox.pack_start (edit_group_list_button, false, false);
590 edit_group_vbox.pack_start (edit_group_list_scroller, true, true);
592 region_list_display.set_size_request (100, -1);
593 region_list_display.set_name ("RegionListDisplay");
595 region_list_model = TreeStore::create (region_list_columns);
596 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
597 region_list_model->set_sort_column (0, SORT_ASCENDING);
599 region_list_display.set_model (region_list_model);
600 CellRendererText* renderer = Gtk::manage( new Gtk::CellRendererText() );
601 region_list_display.append_column (_("Regions"), *renderer);
603 TreeViewColumn* tv_col = region_list_display.get_column(0);
604 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
605 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
607 region_list_display.set_reorderable (true);
609 region_list_display.get_selection()->set_mode (SELECTION_SINGLE);
610 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
612 /* setup DnD handling */
614 list<Gtk::TargetEntry> region_list_target_table;
616 region_list_target_table.push_back (TargetEntry ("text/plain"));
617 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
618 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
620 region_list_display.add_drop_targets (region_list_target_table);
621 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
623 region_list_scroller.add (region_list_display);
624 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
626 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
627 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
628 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
629 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
630 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
631 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
633 named_selection_scroller.add (named_selection_display);
634 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
636 named_selection_model = TreeStore::create (named_selection_columns);
637 named_selection_display.set_model (named_selection_model);
638 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
639 named_selection_display.set_headers_visible (false);
640 named_selection_display.set_size_request (100, -1);
641 named_selection_display.set_name ("RegionListDisplay");
643 named_selection_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
644 named_selection_display.set_size_request (100, -1);
645 named_selection_display.set_headers_visible (true);
646 named_selection_display.set_headers_clickable (true);
647 named_selection_display.signal_button_press_event().connect (mem_fun(*this, &Editor::named_selection_display_button_press));
648 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
650 the_notebook.append_page (region_list_scroller, _("Regions"));
651 the_notebook.append_page (route_list_scroller, _("Tracks/Busses"));
652 the_notebook.append_page (edit_group_vbox, _("Edit Groups"));
653 the_notebook.append_page (named_selection_scroller, _("Chunks"));
654 the_notebook.set_show_tabs (true);
655 the_notebook.set_scrollable (true);
656 the_notebook.popup_enable ();
658 TearOff *notebook_tearoff = manage (new TearOff (the_notebook, true));
659 notebook_tearoff->tearoff_window().set_size_request (200, 400);
661 edit_pane.pack1 (edit_frame, true, true);
662 edit_pane.pack2 (*notebook_tearoff, true, true);
664 edit_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Gtk::Paned*> (&edit_pane)));
666 top_hbox.pack_start (toolbar_frame, true, true);
668 HBox *hbox = manage (new HBox);
669 hbox->pack_start (edit_pane, true, true);
671 global_vpacker.pack_start (top_hbox, false, false);
672 global_vpacker.pack_start (*hbox, true, true);
674 global_hpacker.pack_start (global_vpacker, true, true);
676 set_name ("EditorWindow");
677 add_accel_group (ActionManager::ui_manager->get_accel_group());
679 vpacker.pack_end (global_hpacker, true, true);
681 /* register actions now so that set_state() can find them and set toggles/checks etc */
685 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
688 _playlist_selector = new PlaylistSelector();
689 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
691 AudioRegionView::AudioRegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_audio_regionview));
695 nudge_forward_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(right_arrow_xpm)))));
696 nudge_backward_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(left_arrow_xpm)))));
698 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards"));
699 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards"));
701 nudge_forward_button.set_name ("TransportButton");
702 nudge_backward_button.set_name ("TransportButton");
704 fade_context_menu.set_name ("ArdourContextMenu");
706 set_title (_("ardour: editor"));
707 set_wmclass (_("ardour_editor"), "Ardour");
710 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
712 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
713 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
721 /* <CMT Additions> */
722 if(image_socket_listener)
724 if(image_socket_listener->is_connected())
726 image_socket_listener->close_connection() ;
729 delete image_socket_listener ;
730 image_socket_listener = 0 ;
732 /* </CMT Additions> */
736 Editor::add_toplevel_controls (Container& cont)
738 vpacker.pack_start (cont, false, false);
743 Editor::catch_vanishing_audio_regionview (AudioRegionView *rv)
745 /* note: the selection will take care of the vanishing
746 audioregionview by itself.
749 if (clicked_regionview == rv) {
750 clicked_regionview = 0;
753 if (entered_regionview == rv) {
754 set_entered_regionview (0);
759 Editor::set_entered_regionview (AudioRegionView* rv)
761 if (rv == entered_regionview) {
765 if (entered_regionview) {
766 entered_regionview->exited ();
769 if ((entered_regionview = rv) != 0) {
770 entered_regionview->entered ();
775 Editor::set_entered_track (TimeAxisView* tav)
778 entered_track->exited ();
781 if ((entered_track = tav) != 0) {
782 entered_track->entered ();
787 Editor::left_track_canvas (GdkEventCrossing *ev)
789 set_entered_track (0);
790 set_entered_regionview (0);
796 Editor::show_window ()
801 /* now reset all audio_time_axis heights, because widgets might need
807 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
808 tv = (static_cast<TimeAxisView*>(*i));
814 Editor::tie_vertical_scrolling ()
816 double y1 = vertical_adjustment.get_value();
817 controls_layout.get_vadjustment()->set_value (y1);
818 playhead_cursor->set_y_axis(y1);
819 edit_cursor->set_y_axis(y1);
823 Editor::set_frames_per_unit (double fpu)
825 jack_nframes_t frames;
827 if (fpu == frames_per_unit) {
835 // convert fpu to frame count
837 frames = (jack_nframes_t) floor (fpu * canvas_width);
839 /* don't allow zooms that fit more than the maximum number
840 of frames into an 800 pixel wide space.
843 if (max_frames / fpu < 800.0) {
847 frames_per_unit = fpu;
849 if (frames != zoom_range_clock.current_duration()) {
850 zoom_range_clock.set (frames);
853 /* only update these if we not about to call reposition_x_origin,
854 which will do the same updates.
858 horizontal_adjustment.set_upper (session->current_end_frame() / frames_per_unit);
861 if (!no_zoom_repos_update) {
862 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
863 update_fixed_rulers ();
864 tempo_map_changed (Change (0));
867 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
868 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
869 (*i)->reshow_selection (selection->time);
873 ZoomChanged (); /* EMIT_SIGNAL */
875 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
876 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
883 Editor::instant_save ()
885 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
890 session->add_instant_xml(get_state(), session->path());
892 Config->add_instant_xml(get_state(), Config->get_user_ardour_path());
897 Editor::reposition_x_origin (jack_nframes_t frame)
899 if (frame != leftmost_frame) {
900 leftmost_frame = frame;
901 double pixel = frame_to_pixel (frame);
902 if (pixel >= horizontal_adjustment.get_upper()) {
903 horizontal_adjustment.set_upper (frame_to_pixel (frame + (current_page_frames())));
905 horizontal_adjustment.set_value (frame/frames_per_unit);
906 XOriginChanged (); /* EMIT_SIGNAL */
911 Editor::edit_cursor_clock_changed()
913 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
914 edit_cursor->set_position (edit_cursor_clock.current_time());
920 Editor::zoom_adjustment_changed ()
922 if (session == 0 || no_zoom_repos_update) {
926 double fpu = zoom_range_clock.current_duration() / canvas_width;
930 zoom_range_clock.set ((jack_nframes_t) floor (fpu * canvas_width));
931 } else if (fpu > session->current_end_frame() / canvas_width) {
932 fpu = session->current_end_frame() / canvas_width;
933 zoom_range_clock.set ((jack_nframes_t) floor (fpu * canvas_width));
940 Editor::canvas_horizontally_scrolled ()
942 leftmost_frame = (jack_nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
944 update_fixed_rulers ();
946 if (!edit_hscroll_dragging) {
947 tempo_map_changed (Change (0));
949 update_tempo_based_rulers();
954 Editor::reposition_and_zoom (jack_nframes_t frame, double nfpu)
956 if (!repos_zoom_queued) {
957 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu));
958 repos_zoom_queued = true;
963 Editor::deferred_reposition_and_zoom (jack_nframes_t frame, double nfpu)
965 /* if we need to force an update to the hscroller stuff,
966 don't set no_zoom_repos_update.
969 no_zoom_repos_update = (frame != leftmost_frame);
971 set_frames_per_unit (nfpu);
972 if (no_zoom_repos_update) {
973 reposition_x_origin (frame);
975 no_zoom_repos_update = false;
976 repos_zoom_queued = false;
982 Editor::on_realize ()
984 Window::on_realize ();
989 Editor::queue_session_control_changed (Session::ControlType t)
991 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::session_control_changed), t));
995 Editor::session_control_changed (Session::ControlType t)
997 // right now we're only tracking the loop and punch state
1000 case Session::AutoLoop:
1001 update_loop_range_view (true);
1003 case Session::PunchIn:
1004 case Session::PunchOut:
1005 update_punch_range_view (true);
1014 Editor::fake_add_edit_group (RouteGroup *group)
1016 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::add_edit_group), group));
1020 Editor::fake_handle_new_audio_region (AudioRegion *region)
1022 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_new_audio_region), region));
1026 Editor::fake_handle_audio_region_removed (AudioRegion *region)
1028 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_audio_region_removed), region));
1032 Editor::fake_handle_new_duration ()
1034 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &Editor::handle_new_duration));
1038 Editor::start_scrolling ()
1040 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1041 (mem_fun(*this, &Editor::update_current_screen));
1043 slower_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
1044 (mem_fun(*this, &Editor::update_slower));
1048 Editor::stop_scrolling ()
1050 scroll_connection.disconnect ();
1051 slower_update_connection.disconnect ();
1055 Editor::map_position_change (jack_nframes_t frame)
1057 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1059 if (session == 0 || !_follow_playhead) {
1063 center_screen (frame);
1064 playhead_cursor->set_position (frame);
1068 Editor::center_screen (jack_nframes_t frame)
1070 double page = canvas_width * frames_per_unit;
1072 /* if we're off the page, then scroll.
1075 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1076 center_screen_internal (frame, page);
1081 Editor::center_screen_internal (jack_nframes_t frame, float page)
1086 frame -= (jack_nframes_t) page;
1091 reposition_x_origin (frame);
1095 Editor::handle_new_duration ()
1097 reset_scrolling_region ();
1100 horizontal_adjustment.set_upper (session->current_end_frame() / frames_per_unit);
1101 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1106 Editor::update_title_s (const string & snap_name)
1108 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1114 Editor::update_title ()
1116 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1119 bool dirty = session->dirty();
1121 string wintitle = _("ardour: editor: ");
1127 wintitle += session->name();
1129 if (session->snap_name() != session->name()) {
1131 wintitle += session->snap_name();
1138 set_title (wintitle);
1143 Editor::connect_to_session (Session *t)
1147 if (first_action_message) {
1148 first_action_message->hide();
1153 session->going_away.connect (mem_fun(*this, &Editor::session_going_away));
1155 /* These signals can all be emitted by a non-GUI thread. Therefore the
1156 handlers for them must not attempt to directly interact with the GUI,
1157 but use Gtkmm2ext::UI::instance()->call_slot();
1160 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1161 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1162 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p)));
1163 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::fake_handle_new_audio_region)));
1164 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::fake_handle_audio_region_removed)));
1165 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::fake_handle_new_duration)));
1166 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::fake_add_edit_group)));
1167 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1168 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1169 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1170 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1171 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1172 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1174 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1175 session_connections.push_back (session->SMPTETypeChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1177 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1179 session->foreach_edit_group(this, &Editor::add_edit_group);
1181 editor_mixer_button.signal_toggled().connect (mem_fun(*this, &Editor::editor_mixer_button_toggled));
1182 editor_mixer_button.set_name (X_("EditorMixerButton"));
1184 edit_cursor_clock.set_session (session);
1185 selection_start_clock.set_session (session);
1186 selection_end_clock.set_session (session);
1187 zoom_range_clock.set_session (session);
1188 _playlist_selector->set_session (session);
1189 nudge_clock.set_session (session);
1191 switch (session->get_edit_mode()) {
1193 edit_mode_selector.set_active_text (edit_mode_strings[splice_index]);
1197 edit_mode_selector.set_active_text (edit_mode_strings[slide_index]);
1201 Location* loc = session->locations()->auto_loop_location();
1203 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1204 if (loc->start() == loc->end()) {
1205 loc->set_end (loc->start() + 1);
1207 session->locations()->add (loc, false);
1208 session->set_auto_loop_location (loc);
1212 loc->set_name (_("Loop"));
1215 loc = session->locations()->auto_punch_location();
1217 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1218 if (loc->start() == loc->end()) {
1219 loc->set_end (loc->start() + 1);
1221 session->locations()->add (loc, false);
1222 session->set_auto_punch_location (loc);
1226 loc->set_name (_("Punch"));
1229 update_loop_range_view (true);
1230 update_punch_range_view (true);
1232 session->ControlChanged.connect (mem_fun(*this, &Editor::queue_session_control_changed));
1235 refresh_location_display ();
1236 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1237 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1238 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1239 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1240 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1242 reset_scrolling_region ();
1244 redisplay_regions ();
1245 redisplay_named_selections ();
1248 // route_list_display.set_model (Glib::RefPtr<TreeModel>(0));
1249 route_display_model->clear ();
1251 session->foreach_route (this, &Editor::handle_new_route);
1252 // route_list_display.select_all ();
1254 //route_list_display.sort ();
1256 route_list_reordered ();
1258 // route_list_display.set_model (route_display_model);
1260 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1261 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1264 /* ::reposition_x_origin() doesn't work right here, since the old
1265 position may be zero already, and it does nothing in such
1271 horizontal_adjustment.set_upper (session->current_end_frame() / frames_per_unit);
1272 horizontal_adjustment.set_value (0);
1274 restore_ruler_visibility ();
1275 tempo_map_changed (Change (0));
1277 edit_cursor->set_position (0);
1278 playhead_cursor->set_position (0);
1282 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1285 /* don't show master bus in a new session */
1287 if (ARDOUR_UI::instance()->session_is_new ()) {
1289 TreeModel::Children rows = route_display_model->children();
1290 TreeModel::Children::iterator i;
1292 //route_list_display.freeze ();
1294 for (i = rows.begin(); i != rows.end(); ++i) {
1295 TimeAxisView *tv = (*i)[route_display_columns.tv];
1296 AudioTimeAxisView *atv;
1298 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1299 if (atv->route().master()) {
1300 route_list_display.get_selection()->unselect (i);
1301 //(*i)->unselect ();
1306 //route_list_display.thaw ();
1311 Editor::build_cursors ()
1313 using namespace Gdk;
1315 Gdk::Color mbg ("#000000" ); /* Black */
1316 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1319 RefPtr<Bitmap> source, mask;
1320 source = Bitmap::create (mag_bits, mag_width, mag_height);
1321 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1322 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1325 Gdk::Color fbg ("#ffffff" );
1326 Gdk::Color ffg ("#000000" );
1329 RefPtr<Bitmap> source, mask;
1331 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1332 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1333 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1337 RefPtr<Bitmap> source, mask;
1338 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1339 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1340 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1343 grabber_cursor = new Gdk::Cursor (HAND2);
1344 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1345 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1346 selector_cursor = new Gdk::Cursor (XTERM);
1347 time_fx_cursor = new Gdk::Cursor (SIZING);
1348 wait_cursor = new Gdk::Cursor (WATCH);
1349 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1353 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1355 using namespace Menu_Helpers;
1356 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1359 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1363 MenuList& items (fade_context_menu.items());
1367 switch (item_type) {
1369 case FadeInHandleItem:
1370 if (arv->region.fade_in_active()) {
1371 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false)));
1373 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true)));
1376 items.push_back (SeparatorElem());
1378 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear)));
1379 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB)));
1380 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast)));
1381 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA)));
1382 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow)));
1386 case FadeOutHandleItem:
1387 if (arv->region.fade_out_active()) {
1388 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false)));
1390 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true)));
1393 items.push_back (SeparatorElem());
1395 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear)));
1396 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast)));
1397 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB)));
1398 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA)));
1399 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow)));
1403 fatal << _("programming error: ")
1404 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1409 fade_context_menu.popup (button, time);
1413 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, jack_nframes_t frame)
1415 using namespace Menu_Helpers;
1416 Menu* (Editor::*build_menu_function)(jack_nframes_t);
1419 switch (item_type) {
1421 case AudioRegionViewName:
1422 case AudioRegionViewNameHighlight:
1423 if (with_selection) {
1424 build_menu_function = &Editor::build_track_selection_context_menu;
1426 build_menu_function = &Editor::build_track_region_context_menu;
1431 if (with_selection) {
1432 build_menu_function = &Editor::build_track_selection_context_menu;
1434 build_menu_function = &Editor::build_track_context_menu;
1438 case CrossfadeViewItem:
1439 build_menu_function = &Editor::build_track_crossfade_context_menu;
1443 if (clicked_audio_trackview->get_diskstream()) {
1444 build_menu_function = &Editor::build_track_context_menu;
1446 build_menu_function = &Editor::build_track_bus_context_menu;
1451 /* probably shouldn't happen but if it does, we don't care */
1455 menu = (this->*build_menu_function)(frame);
1456 menu->set_name ("ArdourContextMenu");
1458 /* now handle specific situations */
1460 switch (item_type) {
1462 case AudioRegionViewName:
1463 case AudioRegionViewNameHighlight:
1464 if (!with_selection) {
1465 if (region_edit_menu_split_item) {
1466 if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) {
1467 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, true);
1469 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, false);
1472 if (region_edit_menu_split_multichannel_item) {
1473 if (clicked_regionview && clicked_regionview->region.n_channels() > 1) {
1474 // GTK2FIX find the action, change its sensitivity
1475 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1477 // GTK2FIX see above
1478 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1487 case CrossfadeViewItem:
1494 /* probably shouldn't happen but if it does, we don't care */
1498 if (clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1500 /* Bounce to disk */
1502 using namespace Menu_Helpers;
1503 MenuList& edit_items = menu->items();
1505 edit_items.push_back (SeparatorElem());
1507 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1508 case AudioTrack::NoFreeze:
1509 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1512 case AudioTrack::Frozen:
1513 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1516 case AudioTrack::UnFrozen:
1517 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1523 menu->popup (button, time);
1527 Editor::build_track_context_menu (jack_nframes_t ignored)
1529 using namespace Menu_Helpers;
1531 MenuList& edit_items = track_context_menu.items();
1534 add_dstream_context_items (edit_items);
1535 return &track_context_menu;
1539 Editor::build_track_bus_context_menu (jack_nframes_t ignored)
1541 using namespace Menu_Helpers;
1543 MenuList& edit_items = track_context_menu.items();
1546 add_bus_context_items (edit_items);
1547 return &track_context_menu;
1551 Editor::build_track_region_context_menu (jack_nframes_t frame)
1553 using namespace Menu_Helpers;
1554 MenuList& edit_items = track_region_context_menu.items();
1557 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1563 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1564 Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed()));
1565 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1566 add_region_context_items (atv->view, (*i), edit_items);
1572 add_dstream_context_items (edit_items);
1574 return &track_region_context_menu;
1578 Editor::build_track_crossfade_context_menu (jack_nframes_t frame)
1580 using namespace Menu_Helpers;
1581 MenuList& edit_items = track_crossfade_context_menu.items();
1582 edit_items.clear ();
1584 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1591 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = dynamic_cast<AudioPlaylist*> (pl)) != 0)) {
1593 Playlist::RegionList* regions = pl->regions_at (frame);
1594 AudioPlaylist::Crossfades xfades;
1596 apl->crossfades_at (frame, xfades);
1598 bool many = xfades.size() > 1;
1600 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1601 add_crossfade_context_items (atv->view, (*i), edit_items, many);
1604 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1605 add_region_context_items (atv->view, (*i), edit_items);
1612 add_dstream_context_items (edit_items);
1614 return &track_crossfade_context_menu;
1618 Editor::build_track_selection_context_menu (jack_nframes_t ignored)
1620 using namespace Menu_Helpers;
1621 MenuList& edit_items = track_selection_context_menu.items();
1622 edit_items.clear ();
1624 add_selection_context_items (edit_items);
1625 add_dstream_context_items (edit_items);
1627 return &track_selection_context_menu;
1631 Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many)
1633 using namespace Menu_Helpers;
1634 Menu *xfade_menu = manage (new Menu);
1635 MenuList& items = xfade_menu->items();
1636 xfade_menu->set_name ("ArdourContextMenu");
1639 if (xfade->active()) {
1645 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), xfade)));
1646 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), xfade)));
1648 if (xfade->can_follow_overlap()) {
1650 if (xfade->following_overlap()) {
1651 str = _("Convert to short");
1653 str = _("Convert to full");
1656 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1660 str = xfade->out().name();
1662 str += xfade->in().name();
1664 str = _("Crossfade");
1667 edit_items.push_back (MenuElem (str, *xfade_menu));
1668 edit_items.push_back (SeparatorElem());
1672 Editor::xfade_edit_left_region ()
1674 if (clicked_crossfadeview) {
1675 clicked_crossfadeview->left_view.show_region_editor ();
1680 Editor::xfade_edit_right_region ()
1682 if (clicked_crossfadeview) {
1683 clicked_crossfadeview->right_view.show_region_editor ();
1688 Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items)
1690 using namespace Menu_Helpers;
1691 Menu *region_menu = manage (new Menu);
1692 MenuList& items = region_menu->items();
1693 region_menu->set_name ("ArdourContextMenu");
1695 AudioRegion* ar = 0;
1698 ar = dynamic_cast<AudioRegion*> (region);
1701 /* when this particular menu pops up, make the relevant region
1705 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, region));
1707 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1708 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1709 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1710 items.push_back (SeparatorElem());
1711 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1712 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1713 items.push_back (SeparatorElem());
1715 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1716 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1717 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1718 items.push_back (SeparatorElem());
1720 /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler
1721 might be able to figure out which overloaded member function to use in
1725 void (Editor::*type_A_pmf)(void (Region::*pmf)(bool), bool) = &Editor::region_selection_op;
1727 items.push_back (MenuElem (_("Lock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, true)));
1728 items.push_back (MenuElem (_("Unlock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, false)));
1729 items.push_back (SeparatorElem());
1731 if (region->muted()) {
1732 items.push_back (MenuElem (_("Unmute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, false)));
1734 items.push_back (MenuElem (_("Mute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, true)));
1736 items.push_back (SeparatorElem());
1738 items.push_back (MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1739 items.push_back (SeparatorElem());
1744 items.push_back (MenuElem (_("Toggle envelope visibility"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility)));
1745 items.push_back (MenuElem (_("Toggle envelope active"), mem_fun(*this, &Editor::toggle_gain_envelope_active)));
1746 items.push_back (SeparatorElem());
1748 if (ar->scale_amplitude() != 1.0f) {
1749 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1751 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1754 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1755 items.push_back (SeparatorElem());
1759 Menu *nudge_menu = manage (new Menu());
1760 MenuList& nudge_items = nudge_menu->items();
1761 nudge_menu->set_name ("ArdourContextMenu");
1763 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1764 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1765 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1766 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1768 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1769 items.push_back (SeparatorElem());
1771 Menu *trim_menu = manage (new Menu);
1772 MenuList& trim_items = trim_menu->items();
1773 trim_menu->set_name ("ArdourContextMenu");
1775 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1776 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1778 items.push_back (MenuElem (_("Trim"), *trim_menu));
1779 items.push_back (SeparatorElem());
1781 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1782 region_edit_menu_split_item = &items.back();
1784 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1785 region_edit_menu_split_multichannel_item = &items.back();
1787 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1788 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1789 items.push_back (SeparatorElem());
1790 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1791 items.push_back (SeparatorElem());
1792 items.push_back (MenuElem (_("Destroy"), mem_fun(*this, &Editor::destroy_clicked_region)));
1794 /* OK, stick the region submenu at the top of the list, and then add
1798 /* we have to hack up the region name because "_" has a special
1799 meaning for menu titles.
1802 string::size_type pos = 0;
1803 string menu_item_name = region->name();
1805 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1806 menu_item_name.replace (pos, 1, "__");
1810 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1811 edit_items.push_back (SeparatorElem());
1815 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1817 using namespace Menu_Helpers;
1818 Menu *selection_menu = manage (new Menu);
1819 MenuList& items = selection_menu->items();
1820 selection_menu->set_name ("ArdourContextMenu");
1822 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1823 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1824 items.push_back (SeparatorElem());
1825 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection)));
1826 items.push_back (SeparatorElem());
1827 items.push_back (MenuElem (_("Create Region"), mem_fun(*this, &Editor::new_region_from_selection)));
1828 items.push_back (MenuElem (_("Separate Region"), mem_fun(*this, &Editor::separate_region_from_selection)));
1829 items.push_back (MenuElem (_("Crop Region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1830 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1831 items.push_back (SeparatorElem());
1832 items.push_back (MenuElem (_("Duplicate"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1833 items.push_back (SeparatorElem());
1834 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_selection)));
1835 items.push_back (SeparatorElem());
1836 items.push_back (MenuElem (_("Fill range w/Region"), mem_fun(*this, &Editor::region_fill_selection)));
1838 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1839 edit_items.push_back (SeparatorElem());
1843 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1845 using namespace Menu_Helpers;
1849 Menu *play_menu = manage (new Menu);
1850 MenuList& play_items = play_menu->items();
1851 play_menu->set_name ("ArdourContextMenu");
1853 play_items.push_back (MenuElem (_("Play from edit cursor")));
1854 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1855 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1856 play_items.push_back (SeparatorElem());
1857 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1859 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1863 Menu *select_menu = manage (new Menu);
1864 MenuList& select_items = select_menu->items();
1865 select_menu->set_name ("ArdourContextMenu");
1867 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
1868 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
1869 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1870 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
1871 select_items.push_back (SeparatorElem());
1872 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1873 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1874 select_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1880 Menu *cutnpaste_menu = manage (new Menu);
1881 MenuList& cutnpaste_items = cutnpaste_menu->items();
1882 cutnpaste_menu->set_name ("ArdourContextMenu");
1884 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1885 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1886 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1887 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1889 cutnpaste_items.push_back (SeparatorElem());
1891 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1892 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1894 cutnpaste_items.push_back (SeparatorElem());
1896 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1898 cutnpaste_items.push_back (SeparatorElem());
1900 cutnpaste_items.push_back (MenuElem (_("New Region from range"), mem_fun(*this, &Editor::new_region_from_selection)));
1901 cutnpaste_items.push_back (MenuElem (_("Separate Range"), mem_fun(*this, &Editor::separate_region_from_selection)));
1903 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1905 /* Adding new material */
1907 Menu *import_menu = manage (new Menu());
1908 MenuList& import_items = import_menu->items();
1909 import_menu->set_name ("ArdourContextMenu");
1911 import_items.push_back (MenuElem (_("Insert Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1912 import_items.push_back (MenuElem (_("Insert external sndfile"), bind (mem_fun(*this, &Editor::insert_sndfile), false)));
1914 edit_items.push_back (MenuElem (_("Import"), *import_menu));
1918 Menu *nudge_menu = manage (new Menu());
1919 MenuList& nudge_items = nudge_menu->items();
1920 nudge_menu->set_name ("ArdourContextMenu");
1922 edit_items.push_back (SeparatorElem());
1923 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1924 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1925 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1926 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1928 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1932 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1934 using namespace Menu_Helpers;
1938 Menu *play_menu = manage (new Menu);
1939 MenuList& play_items = play_menu->items();
1940 play_menu->set_name ("ArdourContextMenu");
1942 play_items.push_back (MenuElem (_("Play from edit cursor")));
1943 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1944 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1948 Menu *select_menu = manage (new Menu);
1949 MenuList& select_items = select_menu->items();
1950 select_menu->set_name ("ArdourContextMenu");
1952 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
1953 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
1954 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1955 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
1956 select_items.push_back (SeparatorElem());
1957 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1958 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1959 select_items.push_back (SeparatorElem());
1961 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1965 Menu *cutnpaste_menu = manage (new Menu);
1966 MenuList& cutnpaste_items = cutnpaste_menu->items();
1967 cutnpaste_menu->set_name ("ArdourContextMenu");
1969 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1970 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1971 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1973 Menu *nudge_menu = manage (new Menu());
1974 MenuList& nudge_items = nudge_menu->items();
1975 nudge_menu->set_name ("ArdourContextMenu");
1977 edit_items.push_back (SeparatorElem());
1978 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1979 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1980 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1981 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1983 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1986 /* CURSOR SETTING AND MARKS AND STUFF */
1989 Editor::set_snap_to (SnapType st)
1992 vector<string> txt = internationalize (snap_type_strings);
1993 snap_type_selector.set_active_text (txt[(int)st]);
1997 switch (snap_type) {
1998 case SnapToAThirtysecondBeat:
1999 case SnapToASixteenthBeat:
2000 case SnapToAEighthBeat:
2001 case SnapToAQuarterBeat:
2002 case SnapToAThirdBeat:
2003 update_tempo_based_rulers ();
2011 Editor::set_snap_mode (SnapMode mode)
2014 vector<string> txt = internationalize (snap_mode_strings);
2015 snap_mode_selector.set_active_text (txt[(int)mode]);
2021 Editor::add_location_from_selection ()
2023 if (selection->time.empty()) {
2027 if (session == 0 || clicked_trackview == 0) {
2031 jack_nframes_t start = selection->time[clicked_selection].start;
2032 jack_nframes_t end = selection->time[clicked_selection].end;
2034 Location *location = new Location (start, end, "selection");
2036 session->begin_reversible_command (_("add marker"));
2037 session->add_undo (session->locations()->get_memento());
2038 session->locations()->add (location, true);
2039 session->add_redo_no_execute (session->locations()->get_memento());
2040 session->commit_reversible_command ();
2044 Editor::add_location_from_playhead_cursor ()
2046 jack_nframes_t where = session->audible_frame();
2048 Location *location = new Location (where, where, "mark", Location::IsMark);
2049 session->begin_reversible_command (_("add marker"));
2050 session->add_undo (session->locations()->get_memento());
2051 session->locations()->add (location, true);
2052 session->add_redo_no_execute (session->locations()->get_memento());
2053 session->commit_reversible_command ();
2058 Editor::set_state (const XMLNode& node)
2060 const XMLProperty* prop;
2062 int x, y, width, height, xoff, yoff;
2064 if ((geometry = find_named_node (node, "geometry")) == 0) {
2066 width = default_width;
2067 height = default_height;
2075 width = atoi(geometry->property("x_size")->value());
2076 height = atoi(geometry->property("y_size")->value());
2077 x = atoi(geometry->property("x_pos")->value());
2078 y = atoi(geometry->property("y_pos")->value());
2079 xoff = atoi(geometry->property("x_off")->value());
2080 yoff = atoi(geometry->property("y_off")->value());
2083 set_default_size(width, height);
2086 if ((prop = node.property ("zoom-focus"))) {
2087 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2090 if ((prop = node.property ("zoom"))) {
2091 set_frames_per_unit (atof (prop->value()));
2094 if ((prop = node.property ("snap-to"))) {
2095 set_snap_to ((SnapType) atoi (prop->value()));
2098 if ((prop = node.property ("snap-mode"))) {
2099 set_snap_mode ((SnapMode) atoi (prop->value()));
2102 if ((prop = node.property ("show-waveforms"))) {
2103 bool yn = (prop->value() == "yes");
2104 _show_waveforms = !yn;
2105 set_show_waveforms (yn);
2108 if ((prop = node.property ("show-waveforms-recording"))) {
2109 bool yn = (prop->value() == "yes");
2110 _show_waveforms_recording = !yn;
2111 set_show_waveforms_recording (yn);
2114 if ((prop = node.property ("show-measures"))) {
2115 bool yn = (prop->value() == "yes");
2116 _show_measures = !yn;
2117 set_show_measures (yn);
2120 if ((prop = node.property ("follow-playhead"))) {
2121 bool yn = (prop->value() == "yes");
2122 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleFollowPlayhead"));
2124 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2125 /* do it twice to force the change */
2126 tact->set_active (!yn);
2127 tact->set_active (yn);
2131 if ((prop = node.property ("xfades-visible"))) {
2132 bool yn = (prop->value() == "yes");
2133 _xfade_visibility = !yn;
2134 set_xfade_visibility (yn);
2137 if ((prop = node.property ("region-list-sort-type"))) {
2138 region_list_sort_type = (Editing::RegionListSortType) -1; /* force change */
2139 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2142 if ((prop = node.property ("mouse-mode"))) {
2143 MouseMode m = str2mousemode(prop->value());
2144 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2145 set_mouse_mode (m, true);
2147 mouse_mode = MouseGain; /* lie, to force the mode switch */
2148 set_mouse_mode (MouseObject, true);
2151 if ((prop = node.property ("editor-mixer-button"))) {
2152 editor_mixer_button.set_active(prop->value() == "yes");
2159 Editor::get_state ()
2161 XMLNode* node = new XMLNode ("Editor");
2164 if (is_realized()) {
2165 Glib::RefPtr<Gdk::Window> win = get_window();
2167 int x, y, xoff, yoff, width, height;
2168 win->get_root_origin(x, y);
2169 win->get_position(xoff, yoff);
2170 win->get_size(width, height);
2172 XMLNode* geometry = new XMLNode ("geometry");
2174 snprintf(buf, sizeof(buf), "%d", width);
2175 geometry->add_property("x_size", string(buf));
2176 snprintf(buf, sizeof(buf), "%d", height);
2177 geometry->add_property("y_size", string(buf));
2178 snprintf(buf, sizeof(buf), "%d", x);
2179 geometry->add_property("x_pos", string(buf));
2180 snprintf(buf, sizeof(buf), "%d", y);
2181 geometry->add_property("y_pos", string(buf));
2182 snprintf(buf, sizeof(buf), "%d", xoff);
2183 geometry->add_property("x_off", string(buf));
2184 snprintf(buf, sizeof(buf), "%d", yoff);
2185 geometry->add_property("y_off", string(buf));
2186 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2187 geometry->add_property("edit_pane_pos", string(buf));
2189 node->add_child_nocopy (*geometry);
2192 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2193 node->add_property ("zoom-focus", buf);
2194 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2195 node->add_property ("zoom", buf);
2196 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2197 node->add_property ("snap-to", buf);
2198 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2199 node->add_property ("snap-mode", buf);
2201 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2202 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2203 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2204 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2205 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2206 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2207 node->add_property ("mouse-mode", enum2str(mouse_mode));
2208 node->add_property ("editor-mixer-button", editor_mixer_button.get_active() ? "yes" : "no");
2216 Editor::trackview_by_y_position (double y)
2218 TrackViewList::iterator iter;
2221 for (iter = track_views.begin(); iter != track_views.end(); ++iter) {
2229 if (tv->y_position <= y && y < ((tv->y_position + tv->height + track_spacing))) {
2238 Editor::snap_to (jack_nframes_t& start, int32_t direction, bool for_mark)
2240 Location* before = 0;
2241 Location* after = 0;
2247 const jack_nframes_t one_second = session->frame_rate();
2248 const jack_nframes_t one_minute = session->frame_rate() * 60;
2250 jack_nframes_t presnap = start;
2252 switch (snap_type) {
2258 start = (jack_nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2260 start = (jack_nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2263 case SnapToSMPTEFrame:
2265 start = (jack_nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2267 start = (jack_nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2271 case SnapToSMPTESeconds:
2272 if (session->smpte_offset_negative())
2274 start += session->smpte_offset ();
2276 start -= session->smpte_offset ();
2278 if (direction > 0) {
2279 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2281 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2284 if (session->smpte_offset_negative())
2286 start -= session->smpte_offset ();
2288 start += session->smpte_offset ();
2292 case SnapToSMPTEMinutes:
2293 if (session->smpte_offset_negative())
2295 start += session->smpte_offset ();
2297 start -= session->smpte_offset ();
2300 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2302 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2304 if (session->smpte_offset_negative())
2306 start -= session->smpte_offset ();
2308 start += session->smpte_offset ();
2314 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2316 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2322 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2324 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2329 start = session->tempo_map().round_to_bar (start, direction);
2333 start = session->tempo_map().round_to_beat (start, direction);
2336 case SnapToAThirtysecondBeat:
2337 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2340 case SnapToASixteenthBeat:
2341 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2344 case SnapToAEighthBeat:
2345 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2348 case SnapToAQuarterBeat:
2349 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2352 case SnapToAThirdBeat:
2353 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2356 case SnapToEditCursor:
2357 start = edit_cursor->current_frame;
2365 before = session->locations()->first_location_before (start);
2366 after = session->locations()->first_location_after (start);
2368 if (direction < 0) {
2370 start = before->start();
2374 } else if (direction > 0) {
2376 start = after->start();
2378 start = session->current_end_frame();
2383 /* find nearest of the two */
2384 if ((start - before->start()) < (after->start() - start)) {
2385 start = before->start();
2387 start = after->start();
2390 start = before->start();
2393 start = after->start();
2400 case SnapToRegionStart:
2401 case SnapToRegionEnd:
2402 case SnapToRegionSync:
2403 case SnapToRegionBoundary:
2404 if (!region_boundary_cache.empty()) {
2405 vector<jack_nframes_t>::iterator i;
2407 if (direction > 0) {
2408 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2410 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2413 if (i != region_boundary_cache.end()) {
2416 start = region_boundary_cache.back();
2422 switch (snap_mode) {
2428 if (presnap > start) {
2429 if (presnap > (start + unit_to_frame(snap_threshold))) {
2433 } else if (presnap < start) {
2434 if (presnap < (start - unit_to_frame(snap_threshold))) {
2446 Editor::setup_toolbar ()
2449 vector<ToggleButton *> mouse_mode_buttons;
2451 mouse_mode_buttons.push_back (&mouse_move_button);
2452 mouse_mode_buttons.push_back (&mouse_select_button);
2453 mouse_mode_buttons.push_back (&mouse_gain_button);
2454 mouse_mode_buttons.push_back (&mouse_zoom_button);
2455 mouse_mode_buttons.push_back (&mouse_timefx_button);
2456 mouse_mode_buttons.push_back (&mouse_audition_button);
2457 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2459 mouse_mode_button_table.set_homogeneous (true);
2460 mouse_mode_button_table.set_col_spacings (2);
2461 mouse_mode_button_table.set_row_spacings (2);
2462 mouse_mode_button_table.set_border_width (5);
2464 mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1);
2465 mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1);
2466 mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1);
2468 mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2);
2469 mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2);
2470 mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2);
2472 mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table));
2473 mouse_mode_tearoff->set_name ("MouseModeBase");
2475 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
2476 &mouse_mode_tearoff->tearoff_window()));
2477 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
2478 &mouse_mode_tearoff->tearoff_window(), 1));
2480 mouse_move_button.set_name ("MouseModeButton");
2481 mouse_select_button.set_name ("MouseModeButton");
2482 mouse_gain_button.set_name ("MouseModeButton");
2483 mouse_zoom_button.set_name ("MouseModeButton");
2484 mouse_timefx_button.set_name ("MouseModeButton");
2485 mouse_audition_button.set_name ("MouseModeButton");
2487 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects"));
2488 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges"));
2489 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation"));
2490 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range"));
2491 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions"));
2492 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions"));
2494 mouse_move_button.unset_flags (Gtk::CAN_FOCUS);
2495 mouse_select_button.unset_flags (Gtk::CAN_FOCUS);
2496 mouse_gain_button.unset_flags (Gtk::CAN_FOCUS);
2497 mouse_zoom_button.unset_flags (Gtk::CAN_FOCUS);
2498 mouse_timefx_button.unset_flags (Gtk::CAN_FOCUS);
2499 mouse_audition_button.unset_flags (Gtk::CAN_FOCUS);
2501 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2502 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2504 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2505 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2506 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2507 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2508 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2510 // mouse_move_button.set_active (true);
2512 /* automation control */
2514 global_automation_button.set_name ("MouseModeButton");
2515 automation_mode_button.set_name ("MouseModeButton");
2517 automation_box.set_spacing (2);
2518 automation_box.set_border_width (2);
2519 automation_box.pack_start (global_automation_button, false, false);
2520 automation_box.pack_start (automation_mode_button, false, false);
2524 edit_mode_label.set_name ("ToolBarLabel");
2526 edit_mode_selector.set_name ("EditModeSelector");
2528 edit_mode_box.set_spacing (3);
2529 edit_mode_box.set_border_width (3);
2531 /* XXX another disgusting hack because of the way combo boxes size themselves */
2533 const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button
2534 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2+FUDGE, 10);
2535 set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings));
2536 edit_mode_box.pack_start (edit_mode_label, false, false);
2537 edit_mode_box.pack_start (edit_mode_selector, false, false);
2539 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2543 snap_type_label.set_name ("ToolBarLabel");
2545 snap_type_selector.set_name ("SnapTypeSelector");
2547 snap_type_box.set_spacing (3);
2548 snap_type_box.set_border_width (3);
2550 /* XXX another disgusting hack because of the way combo boxes size themselves */
2552 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2553 set_popdown_strings (snap_type_selector, internationalize (snap_type_strings));
2555 snap_type_box.pack_start (snap_type_label, false, false);
2556 snap_type_box.pack_start (snap_type_selector, false, false);
2558 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2560 /* Snap mode, not snap type */
2562 snap_mode_label.set_name ("ToolBarLabel");
2564 snap_mode_selector.set_name ("SnapModeSelector");
2566 snap_mode_box.set_spacing (3);
2567 snap_mode_box.set_border_width (3);
2569 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2+FUDGE, 10);
2570 set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings));
2572 snap_mode_box.pack_start (snap_mode_label, false, false);
2573 snap_mode_box.pack_start (snap_mode_selector, false, false);
2575 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2577 /* Zoom focus mode */
2579 zoom_focus_label.set_name ("ToolBarLabel");
2581 zoom_focus_selector.set_name ("ZoomFocusSelector");
2583 zoom_focus_box.set_spacing (3);
2584 zoom_focus_box.set_border_width (3);
2586 /* XXX another disgusting hack because of the way combo boxes size themselves */
2588 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2+FUDGE, 10);
2589 set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings));
2591 zoom_focus_box.pack_start (zoom_focus_label, false, false);
2592 zoom_focus_box.pack_start (zoom_focus_selector, false, false);
2594 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2596 /* selection/cursor clocks */
2598 toolbar_selection_cursor_label.set_name ("ToolBarLabel");
2599 selection_start_clock_label.set_name ("ToolBarLabel");
2600 selection_end_clock_label.set_name ("ToolBarLabel");
2601 edit_cursor_clock_label.set_name ("ToolBarLabel");
2603 selection_start_clock_label.set_text (_("Start:"));
2604 selection_end_clock_label.set_text (_("End:"));
2605 edit_cursor_clock_label.set_text (_("Edit:"));
2607 toolbar_selection_clock_table.set_border_width (5);
2608 toolbar_selection_clock_table.set_col_spacings (2);
2609 toolbar_selection_clock_table.set_homogeneous (false);
2611 // toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0);
2612 // toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0);
2613 toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, FILL, FILL, 0, 0);
2615 // toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0);
2616 // toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0);
2617 toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, FILL, FILL);
2620 // toolbar_clock_vbox.set_spacing (2);
2621 // toolbar_clock_vbox.set_border_width (10);
2622 /* the editor/mixer button will be enabled at session connect */
2624 editor_mixer_button.set_active(false);
2625 editor_mixer_button.set_sensitive(false);
2627 HBox* hbox = new HBox;
2629 hbox->pack_start (editor_mixer_button, false, false);
2630 hbox->pack_start (toolbar_selection_clock_table, false, false);
2631 hbox->pack_start (zoom_indicator_vbox, false, false);
2632 hbox->pack_start (zoom_focus_box, false, false);
2633 hbox->pack_start (snap_type_box, false, false);
2634 hbox->pack_start (snap_mode_box, false, false);
2635 hbox->pack_start (edit_mode_box, false, false);
2637 VBox *vbox = manage (new VBox);
2639 vbox->set_spacing (3);
2640 vbox->set_border_width (3);
2642 HBox *nbox = manage (new HBox);
2644 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2645 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2647 nbox->pack_start (nudge_backward_button, false, false);
2648 nbox->pack_start (nudge_forward_button, false, false);
2649 nbox->pack_start (nudge_clock, false, false, 5);
2651 nudge_label.set_name ("ToolBarLabel");
2653 vbox->pack_start (nudge_label, false, false);
2654 vbox->pack_start (*nbox, false, false);
2656 hbox->pack_start (*vbox, false, false);
2660 tools_tearoff = new TearOff (*hbox);
2661 tools_tearoff->set_name ("MouseModeBase");
2663 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
2664 &tools_tearoff->tearoff_window()));
2665 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
2666 &tools_tearoff->tearoff_window(), 0));
2669 toolbar_hbox.set_spacing (8);
2670 toolbar_hbox.set_border_width (2);
2672 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2673 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2675 toolbar_base.set_name ("ToolBarBase");
2676 toolbar_base.add (toolbar_hbox);
2678 toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT);
2679 toolbar_frame.set_name ("BaseFrame");
2680 toolbar_frame.add (toolbar_base);
2684 Editor::_autoscroll_canvas (void *arg)
2686 return ((Editor *) arg)->autoscroll_canvas ();
2690 Editor::autoscroll_canvas ()
2692 jack_nframes_t new_frame;
2693 bool keep_calling = true;
2695 if (autoscroll_direction < 0) {
2696 if (leftmost_frame < autoscroll_distance) {
2699 new_frame = leftmost_frame - autoscroll_distance;
2702 if (leftmost_frame > max_frames - autoscroll_distance) {
2703 new_frame = max_frames;
2705 new_frame = leftmost_frame + autoscroll_distance;
2709 if (new_frame != leftmost_frame) {
2710 reposition_x_origin (new_frame);
2713 if (new_frame == 0 || new_frame == max_frames) {
2720 if (autoscroll_cnt == 1) {
2722 /* connect the timeout so that we get called repeatedly */
2724 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
2725 keep_calling = false;
2727 } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
2729 /* after about a while, speed up a bit by changing the timeout interval */
2731 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
2732 keep_calling = false;
2734 } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
2736 /* after about another while, speed up some more */
2738 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
2739 keep_calling = false;
2741 } else if (autoscroll_cnt >= 30) {
2743 /* we've been scrolling for a while ... crank it up */
2745 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
2748 return keep_calling;
2752 Editor::start_canvas_autoscroll (int dir)
2758 stop_canvas_autoscroll ();
2760 autoscroll_direction = dir;
2761 autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
2764 /* do it right now, which will start the repeated callbacks */
2766 autoscroll_canvas ();
2770 Editor::stop_canvas_autoscroll ()
2772 if (autoscroll_timeout_tag >= 0) {
2773 gtk_timeout_remove (autoscroll_timeout_tag);
2774 autoscroll_timeout_tag = -1;
2779 Editor::convert_drop_to_paths (vector<string>& paths,
2780 const RefPtr<Gdk::DragContext>& context,
2783 const SelectionData& data,
2792 vector<ustring> uris = data.get_uris();
2796 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2797 are actually URI lists. So do it by hand.
2800 if (data.get_target() != "text/plain") {
2804 /* Parse the "uri-list" format that Nautilus provides,
2805 where each pathname is delimited by \r\n
2808 const char* p = data.get_text().c_str();
2815 while (g_ascii_isspace (*p))
2819 while (*q && (*q != '\n') && (*q != '\r'))
2825 while (q > p && g_ascii_isspace (*q))
2830 uris.push_back (ustring (p, q - p + 1));
2834 p = strchr (p, '\n');
2844 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2845 if ((*i).substr (0,7) == "file://") {
2848 cerr << "adding " << p << endl;
2849 paths.push_back (p.substr (7));
2857 Editor::new_tempo_section ()
2863 Editor::map_transport_state ()
2865 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2867 if (session->transport_stopped()) {
2868 have_pending_keyboard_selection = false;
2874 Editor::State::State ()
2876 selection = new Selection;
2879 Editor::State::~State ()
2885 Editor::get_memento () const
2887 State *state = new State;
2889 store_state (*state);
2890 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2894 Editor::store_state (State& state) const
2896 *state.selection = *selection;
2900 Editor::restore_state (State *state)
2902 if (*selection == *state->selection) {
2906 *selection = *state->selection;
2907 time_selection_changed ();
2908 region_selection_changed ();
2910 /* XXX other selection change handlers? */
2914 Editor::begin_reversible_command (string name)
2917 UndoAction ua = get_memento();
2918 session->begin_reversible_command (name, &ua);
2923 Editor::commit_reversible_command ()
2926 UndoAction ua = get_memento();
2927 session->commit_reversible_command (&ua);
2932 Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove)
2934 if (!clicked_trackview) {
2939 begin_reversible_command (_("set selected trackview"));
2944 if (selection->selected (clicked_trackview)) {
2946 selection->remove (clicked_trackview);
2949 selection->add (clicked_trackview);
2954 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
2955 /* no commit necessary */
2959 selection->set (clicked_trackview);
2963 commit_reversible_command ();
2968 Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove)
2970 if (!clicked_control_point) {
2975 begin_reversible_command (_("set selected control point"));
2985 commit_reversible_command ();
2990 Editor::set_selected_regionview_from_click (bool add, bool no_track_remove)
2992 if (!clicked_regionview) {
2996 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view());
3002 RouteGroup* group = atv->route().edit_group();
3003 vector<AudioRegionView*> all_equivalent_regions;
3005 if (group && group->is_active()) {
3007 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3009 AudioTimeAxisView* tatv;
3011 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3013 if (tatv->route().edit_group() != group) {
3018 vector<AudioRegion*> results;
3019 AudioRegionView* marv;
3022 if ((ds = tatv->get_diskstream()) == 0) {
3027 if ((pl = ds->playlist()) != 0) {
3028 pl->get_equivalent_regions (clicked_regionview->region,
3032 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3033 if ((marv = tatv->view->find_view (**ir)) != 0) {
3034 all_equivalent_regions.push_back (marv);
3043 all_equivalent_regions.push_back (clicked_regionview);
3047 begin_reversible_command (_("set selected regionview"));
3051 if (clicked_regionview->get_selected()) {
3052 if (group && group->is_active() && selection->audio_regions.size() > 1) {
3053 /* reduce selection down to just the one clicked */
3054 selection->set (clicked_regionview);
3056 selection->remove (clicked_regionview);
3059 selection->add (all_equivalent_regions);
3062 set_selected_track_from_click (add, false, no_track_remove);
3066 // karsten wiese suggested these two lines to make
3067 // a selected region rise to the top. but this
3068 // leads to a mismatch between actual layering
3069 // and visual layering. resolution required ....
3071 // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3072 // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3074 if (clicked_regionview->get_selected()) {
3075 /* no commit necessary: we are the one selected. */
3080 selection->set (all_equivalent_regions);
3081 set_selected_track_from_click (add, false, false);
3085 commit_reversible_command () ;
3089 Editor::set_selected_regionview_from_region_list (Region& r, bool add)
3091 vector<AudioRegionView*> all_equivalent_regions;
3092 AudioRegion* region;
3094 if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3098 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3100 AudioTimeAxisView* tatv;
3102 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3105 vector<AudioRegion*> results;
3106 AudioRegionView* marv;
3109 if ((ds = tatv->get_diskstream()) == 0) {
3114 if ((pl = ds->playlist()) != 0) {
3115 pl->get_region_list_equivalent_regions (*region, results);
3118 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3119 if ((marv = tatv->view->find_view (**ir)) != 0) {
3120 all_equivalent_regions.push_back (marv);
3127 begin_reversible_command (_("set selected regions"));
3131 selection->add (all_equivalent_regions);
3135 selection->set (all_equivalent_regions);
3138 commit_reversible_command () ;
3142 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3144 AudioRegionView* rv;
3147 if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3151 if ((rv = sv->find_view (*ar)) == 0) {
3155 /* don't reset the selection if its something other than
3156 a single other region.
3159 if (selection->audio_regions.size() > 1) {
3163 begin_reversible_command (_("set selected regions"));
3165 selection->set (rv);
3167 commit_reversible_command () ;
3173 Editor::set_edit_group_solo (Route& route, bool yn)
3175 RouteGroup *edit_group;
3177 if ((edit_group = route.edit_group()) != 0) {
3178 edit_group->apply (&Route::set_solo, yn, this);
3180 route.set_solo (yn, this);
3185 Editor::set_edit_group_mute (Route& route, bool yn)
3187 RouteGroup *edit_group = 0;
3189 if ((edit_group == route.edit_group()) != 0) {
3190 edit_group->apply (&Route::set_mute, yn, this);
3192 route.set_mute (yn, this);
3197 Editor::set_edit_menu (Menu& menu)
3200 edit_menu->signal_map_event().connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3204 Editor::edit_menu_map_handler (GdkEventAny* ev)
3206 using namespace Menu_Helpers;
3207 MenuList& edit_items = edit_menu->items();
3210 /* Nuke all the old items */
3212 edit_items.clear ();
3218 if (session->undo_depth() == 0) {
3221 label = string_compose(_("Undo (%1)"), session->next_undo());
3224 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3226 if (session->undo_depth() == 0) {
3227 edit_items.back().set_sensitive (false);
3230 if (session->redo_depth() == 0) {
3233 label = string_compose(_("Redo (%1)"), session->next_redo());
3236 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3237 if (session->redo_depth() == 0) {
3238 edit_items.back().set_sensitive (false);
3241 vector<MenuItem*> mitems;
3243 edit_items.push_back (SeparatorElem());
3244 edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3245 mitems.push_back (&edit_items.back());
3246 edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3247 mitems.push_back (&edit_items.back());
3248 edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3249 mitems.push_back (&edit_items.back());
3250 edit_items.push_back (SeparatorElem());
3251 edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3252 mitems.push_back (&edit_items.back());
3253 edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3254 mitems.push_back (&edit_items.back());
3255 edit_items.push_back (SeparatorElem());
3257 if (selection->empty()) {
3258 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3259 (*i)->set_sensitive (false);
3263 Menu* import_menu = manage (new Menu());
3264 import_menu->set_name ("ArdourContextMenu");
3265 MenuList& import_items = import_menu->items();
3267 import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3268 import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3270 Menu* embed_menu = manage (new Menu());
3271 embed_menu->set_name ("ArdourContextMenu");
3272 MenuList& embed_items = embed_menu->items();
3274 embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3275 embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3277 edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3278 edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3279 edit_items.push_back (SeparatorElem());
3281 edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3282 if (!session->have_captured()) {
3283 edit_items.back().set_sensitive (false);
3290 Editor::duplicate_dialog (bool dup_region)
3293 if (clicked_regionview == 0) {
3297 if (selection->time.length() == 0) {
3302 ArdourDialog win ("duplicate dialog");
3304 Label label (_("Duplicate how many times?"));
3306 win.get_vbox()->pack_start (label);
3307 win.add_action_widget (entry, RESPONSE_ACCEPT);
3308 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3309 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3311 win.set_position (Gtk::WIN_POS_MOUSE);
3313 entry.set_text ("1");
3314 set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
3315 entry.select_region (0, entry.get_text_length());
3316 entry.grab_focus ();
3319 // win.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
3322 switch (win.run ()) {
3323 case RESPONSE_ACCEPT:
3329 string text = entry.get_text();
3332 if (sscanf (text.c_str(), "%f", ×) == 1) {
3334 AudioRegionSelection regions;
3335 regions.add (clicked_regionview);
3336 duplicate_some_regions (regions, times);
3338 duplicate_selection (times);
3344 Editor::show_verbose_canvas_cursor ()
3346 verbose_canvas_cursor->raise_to_top();
3347 verbose_canvas_cursor->show();
3348 verbose_cursor_visible = true;
3352 Editor::hide_verbose_canvas_cursor ()
3354 verbose_canvas_cursor->hide();
3355 verbose_cursor_visible = false;
3359 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3361 /* XXX get origin of canvas relative to root window,
3362 add x and y and check compared to gdk_screen_{width,height}
3364 verbose_canvas_cursor->property_text() = txt.c_str();
3365 verbose_canvas_cursor->property_x() = x;
3366 verbose_canvas_cursor->property_y() = y;
3370 Editor::set_verbose_canvas_cursor_text (const string & txt)
3372 verbose_canvas_cursor->property_text() = txt.c_str();
3376 Editor::edit_mode_selection_done ()
3382 string choice = edit_mode_selector.get_active_text();
3383 EditMode mode = Slide;
3385 if (choice == _("Splice")) {
3387 } else if (choice == _("Slide")) {
3391 session->set_edit_mode (mode);
3395 Editor::snap_type_selection_done ()
3401 string choice = snap_type_selector.get_active_text();
3402 SnapType snaptype = SnapToFrame;
3404 if (choice == _("Beats/3")) {
3405 snaptype = SnapToAThirdBeat;
3406 } else if (choice == _("Beats/4")) {
3407 snaptype = SnapToAQuarterBeat;
3408 } else if (choice == _("Beats/8")) {
3409 snaptype = SnapToAEighthBeat;
3410 } else if (choice == _("Beats/16")) {
3411 snaptype = SnapToASixteenthBeat;
3412 } else if (choice == _("Beats/32")) {
3413 snaptype = SnapToAThirtysecondBeat;
3414 } else if (choice == _("Beats")) {
3415 snaptype = SnapToBeat;
3416 } else if (choice == _("Bars")) {
3417 snaptype = SnapToBar;
3418 } else if (choice == _("Marks")) {
3419 snaptype = SnapToMark;
3420 } else if (choice == _("Edit Cursor")) {
3421 snaptype = SnapToEditCursor;
3422 } else if (choice == _("Region starts")) {
3423 snaptype = SnapToRegionStart;
3424 } else if (choice == _("Region ends")) {
3425 snaptype = SnapToRegionEnd;
3426 } else if (choice == _("Region bounds")) {
3427 snaptype = SnapToRegionBoundary;
3428 } else if (choice == _("Region syncs")) {
3429 snaptype = SnapToRegionSync;
3430 } else if (choice == _("CD Frames")) {
3431 snaptype = SnapToCDFrame;
3432 } else if (choice == _("SMPTE Frames")) {
3433 snaptype = SnapToSMPTEFrame;
3434 } else if (choice == _("SMPTE Seconds")) {
3435 snaptype = SnapToSMPTESeconds;
3436 } else if (choice == _("SMPTE Minutes")) {
3437 snaptype = SnapToSMPTEMinutes;
3438 } else if (choice == _("Seconds")) {
3439 snaptype = SnapToSeconds;
3440 } else if (choice == _("Minutes")) {
3441 snaptype = SnapToMinutes;
3442 } else if (choice == _("None")) {
3443 snaptype = SnapToFrame;
3446 set_snap_to (snaptype);
3450 Editor::snap_mode_selection_done ()
3456 string choice = snap_mode_selector.get_active_text();
3457 SnapMode mode = SnapNormal;
3459 if (choice == _("Normal")) {
3461 } else if (choice == _("Magnetic")) {
3462 mode = SnapMagnetic;
3465 set_snap_mode (mode);
3469 Editor::zoom_focus_selection_done ()
3475 string choice = zoom_focus_selector.get_active_text();
3476 ZoomFocus focus_type = ZoomFocusLeft;
3478 if (choice == _("Left")) {
3479 focus_type = ZoomFocusLeft;
3480 } else if (choice == _("Right")) {
3481 focus_type = ZoomFocusRight;
3482 } else if (choice == _("Center")) {
3483 focus_type = ZoomFocusCenter;
3484 } else if (choice == _("Playhead")) {
3485 focus_type = ZoomFocusPlayhead;
3486 } else if (choice == _("Edit Cursor")) {
3487 focus_type = ZoomFocusEdit;
3490 set_zoom_focus (focus_type);
3494 Editor::edit_controls_button_release (GdkEventButton* ev)
3496 if (Keyboard::is_context_menu_event (ev)) {
3497 ARDOUR_UI::instance()->add_route ();
3503 Editor::track_selection_changed ()
3505 switch (selection->tracks.size()){
3509 set_selected_mixer_strip (*(selection->tracks.front()));
3513 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3514 (*i)->set_selected (false);
3515 if (mouse_mode == MouseRange) {
3516 (*i)->hide_selection ();
3520 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3521 (*i)->set_selected (true);
3522 if (mouse_mode == MouseRange) {
3523 (*i)->show_selection (selection->time);
3529 Editor::time_selection_changed ()
3531 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3532 (*i)->hide_selection ();
3535 if (selection->tracks.empty()) {
3536 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3537 (*i)->show_selection (selection->time);
3540 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3541 (*i)->show_selection (selection->time);
3547 Editor::region_selection_changed ()
3549 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3550 (*i)->set_selected_regionviews (selection->audio_regions);
3555 Editor::point_selection_changed ()
3557 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3558 (*i)->set_selected_points (selection->points);
3563 Editor::mouse_select_button_release (GdkEventButton* ev)
3565 /* this handles just right-clicks */
3567 if (ev->button != 3) {
3574 Editor::TrackViewList *
3575 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3578 TrackViewList::iterator i;
3580 v = new TrackViewList;
3582 if (track == 0 && group == 0) {
3586 for (i = track_views.begin(); i != track_views.end (); ++i) {
3590 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3592 /* just the view for this track
3595 v->push_back (track);
3599 /* views for all tracks in the edit group */
3601 for (i = track_views.begin(); i != track_views.end (); ++i) {
3603 if (group == 0 || (*i)->edit_group() == group) {
3613 Editor::set_zoom_focus (ZoomFocus f)
3615 if (zoom_focus != f) {
3617 vector<string> txt = internationalize (zoom_focus_strings);
3618 zoom_focus_selector.set_active_text (txt[(int)f]);
3619 ZoomFocusChanged (); /* EMIT_SIGNAL */
3626 Editor::ensure_float (Window& win)
3628 win.set_transient_for (*this);
3632 Editor::pane_allocation_handler (Gtk::Allocation &alloc, Gtk::Paned* which)
3634 /* recover or initialize pane positions. do this here rather than earlier because
3635 we don't want the positions to change the child allocations, which they seem to do.
3641 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3643 static int32_t done[4] = { 0, 0, 0, 0 };
3646 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3647 width = default_width;
3648 height = default_height;
3650 width = atoi(geometry->property("x_size")->value());
3651 height = atoi(geometry->property("y_size")->value());
3654 if (which == static_cast<Gtk::Paned*> (&edit_pane)) {
3660 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3662 snprintf (buf, sizeof(buf), "%d", pos);
3664 pos = atoi (prop->value());
3667 if ((done[0] = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3668 edit_pane.set_position (pos);
3674 Editor::detach_tearoff (Gtk::Box* b, Gtk::Window* w)
3676 if (tools_tearoff->torn_off() &&
3677 mouse_mode_tearoff->torn_off()) {
3678 top_hbox.remove (toolbar_frame);
3683 Editor::reattach_tearoff (Gtk::Box* b, Gtk::Window* w, int32_t n)
3685 if (toolbar_frame.get_parent() == 0) {
3686 top_hbox.pack_end (toolbar_frame);
3691 Editor::set_show_measures (bool yn)
3693 if (_show_measures != yn) {
3696 if ((_show_measures = yn) == true) {
3699 DisplayControlChanged (ShowMeasures);
3705 Editor::toggle_follow_playhead ()
3707 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleFollowPlayhead"));
3709 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3710 set_follow_playhead (tact->get_active());
3715 Editor::set_follow_playhead (bool yn)
3717 if (_follow_playhead != yn) {
3718 if ((_follow_playhead = yn) == true) {
3720 update_current_screen ();
3722 DisplayControlChanged (FollowPlayhead);
3728 Editor::toggle_xfade_active (Crossfade* xfade)
3730 xfade->set_active (!xfade->active());
3734 Editor::toggle_xfade_length (Crossfade* xfade)
3736 xfade->set_follow_overlap (!xfade->following_overlap());
3740 Editor::edit_xfade (Crossfade* xfade)
3742 CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
3747 // cew.signal_delete_event().connect (mem_fun (cew, &ArdourDialog::wm_doi_event_stop));
3749 switch (cew.run ()) {
3750 case RESPONSE_ACCEPT:
3757 xfade->StateChanged (Change (~0));
3761 Editor::playlist_selector () const
3763 return *_playlist_selector;
3767 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
3771 ret = nudge_clock.current_duration (pos);
3772 next = ret + 1; /* XXXX fix me */
3778 Editor::end_location_changed (Location* location)
3780 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3781 horizontal_adjustment.set_upper (location->end() / frames_per_unit);
3785 Editor::playlist_deletion_dialog (Playlist* pl)
3787 ArdourDialog dialog ("playlist deletion dialog");
3788 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3789 "If left alone, no audio files used by it will be cleaned.\n"
3790 "If deleted, audio files used by it alone by will cleaned."),
3793 dialog.set_position (Gtk::WIN_POS_CENTER);
3794 dialog.get_vbox()->pack_start (label);
3796 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3797 dialog.add_button (_("Keep playlist"), RESPONSE_CANCEL);
3798 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3800 switch (dialog.run ()) {
3801 case RESPONSE_ACCEPT:
3802 /* delete the playlist */
3806 case RESPONSE_REJECT:
3807 /* keep the playlist */
3819 Editor::audio_region_selection_covers (jack_nframes_t where)
3821 for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
3822 if ((*a)->region.covers (where)) {
3831 Editor::prepare_for_cleanup ()
3833 cut_buffer->clear_audio_regions ();
3834 cut_buffer->clear_playlists ();
3836 selection->clear_audio_regions ();
3837 selection->clear_playlists ();
3841 Editor::init_colormap ()
3843 for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) {
3844 pair<ColorID,int> newpair;
3846 newpair.first = (ColorID) x;
3847 newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255);
3848 color_map.insert (newpair);
3853 Editor::transport_loop_location()
3856 return session->locations()->auto_loop_location();
3863 Editor::transport_punch_location()
3866 return session->locations()->auto_punch_location();
3873 Editor::control_layout_scroll (GdkEventScroll* ev)
3875 switch (ev->direction) {
3877 scroll_tracks_up_line ();
3881 case GDK_SCROLL_DOWN:
3882 scroll_tracks_down_line ();
3886 /* no left/right handling yet */