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 selection_start_clock (X_("SelectionStartClock"), true),
238 selection_end_clock (X_("SelectionEndClock"), true),
239 edit_cursor_clock (X_("EditCursorClock"), true),
240 zoom_range_clock (X_("ZoomRangeClock"), true, true),
242 toolbar_selection_clock_table (2,3),
244 mouse_mode_button_table (2, 3),
246 mouse_select_button (_("range")),
247 mouse_move_button (_("object")),
248 mouse_gain_button (_("gain")),
249 mouse_zoom_button (_("zoom")),
250 mouse_timefx_button (_("timefx")),
251 mouse_audition_button (_("listen")),
253 automation_mode_button (_("mode")),
254 global_automation_button (_("automation")),
256 edit_mode_label (_("Edit Mode")),
257 snap_type_label (_("Snap To")),
258 snap_mode_label(_("Snap Mode")),
259 zoom_focus_label (_("Zoom Focus")),
261 /* <CMT Additions> */
262 image_socket_listener(0),
263 /* </CMT Additions> */
267 nudge_label (_("Nudge")),
268 nudge_clock (X_("NudgeClock"), true, true)
273 /* we are a singleton */
275 PublicEditor::_instance = this;
279 selection = new Selection;
280 cut_buffer = new Selection;
282 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
283 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
284 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
285 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
287 clicked_regionview = 0;
288 clicked_trackview = 0;
289 clicked_audio_trackview = 0;
290 clicked_crossfadeview = 0;
291 clicked_control_point = 0;
292 latest_regionview = 0;
293 last_update_frame = 0;
295 last_audition_region = 0;
296 current_mixer_strip = 0;
297 current_bbt_points = 0;
299 snap_type = SnapToFrame;
300 set_snap_to (snap_type);
301 snap_mode = SnapNormal;
302 set_snap_mode (snap_mode);
303 snap_threshold = 5.0;
304 bbt_beat_subdivision = 4;
307 autoscroll_timeout_tag = -1;
308 interthread_progress_window = 0;
309 current_interthread_info = 0;
310 _show_measures = true;
311 _show_waveforms = true;
312 _show_waveforms_recording = true;
313 first_action_message = 0;
315 show_gain_after_trim = false;
316 no_zoom_repos_update = false;
317 ignore_route_list_reorder = false;
318 no_route_list_redisplay = false;
319 verbose_cursor_on = true;
320 route_removal = false;
322 show_automatic_regions_in_region_list = true;
323 region_list_sort_type = (Editing::RegionListSortType) 0;
324 have_pending_keyboard_selection = false;
325 _follow_playhead = true;
326 _xfade_visibility = true;
327 editor_ruler_menu = 0;
328 no_ruler_shown_update = false;
329 edit_hscroll_dragging = false;
330 edit_group_list_menu = 0;
332 region_list_menu = 0;
334 marker_menu_item = 0;
336 transport_marker_menu = 0;
337 new_transport_marker_menu = 0;
338 editor_mixer_strip_width = Wide;
339 repos_zoom_queued = false;
340 region_edit_menu_split_item = 0;
342 region_edit_menu_split_multichannel_item = 0;
344 ignore_mouse_mode_toggle = false;
345 current_stepping_trackview = 0;
347 entered_regionview = 0;
348 clear_entered_track = false;
349 _new_regionviews_show_envelope = false;
350 current_timestretch = 0;
355 location_marker_color = color_map[cLocationMarker];
356 location_range_color = color_map[cLocationRange];
357 location_cd_marker_color = color_map[cLocationCDMarker];
358 location_loop_color = color_map[cLocationLoop];
359 location_punch_color = color_map[cLocationPunch];
361 range_marker_drag_rect = 0;
362 marker_drag_line = 0;
364 set_mouse_mode (MouseObject, true);
366 frames_per_unit = 2048; /* too early to use set_frames_per_unit */
367 zoom_focus = ZoomFocusLeft;
368 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
370 initialize_rulers ();
371 initialize_canvas ();
373 edit_controls_vbox.set_spacing (0);
374 horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
375 vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
377 track_canvas.set_hadjustment (horizontal_adjustment);
378 track_canvas.set_vadjustment (vertical_adjustment);
379 time_canvas.set_hadjustment (horizontal_adjustment);
381 track_canvas.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
382 time_canvas.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
384 controls_layout.add (edit_controls_vbox);
385 controls_layout.set_name ("EditControlsBase");
386 controls_layout.add_events (Gdk::SCROLL_MASK);
387 controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
389 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
390 controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
391 controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
393 edit_vscrollbar.set_adjustment (vertical_adjustment);
394 edit_hscrollbar.set_adjustment (horizontal_adjustment);
396 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press));
397 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release));
398 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
403 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
405 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
406 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
407 time_canvas_vbox.pack_start (*frames_ruler, false, false);
408 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
409 time_canvas_vbox.pack_start (time_canvas, true, true);
410 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars));
412 bbt_label.set_name ("EditorTimeButton");
413 bbt_label.set_size_request (-1, (int)timebar_height);
414 bbt_label.set_alignment (1.0, 0.5);
415 bbt_label.set_padding (5,0);
416 minsec_label.set_name ("EditorTimeButton");
417 minsec_label.set_size_request (-1, (int)timebar_height);
418 minsec_label.set_alignment (1.0, 0.5);
419 minsec_label.set_padding (5,0);
420 smpte_label.set_name ("EditorTimeButton");
421 smpte_label.set_size_request (-1, (int)timebar_height);
422 smpte_label.set_alignment (1.0, 0.5);
423 smpte_label.set_padding (5,0);
424 frame_label.set_name ("EditorTimeButton");
425 frame_label.set_size_request (-1, (int)timebar_height);
426 frame_label.set_alignment (1.0, 0.5);
427 frame_label.set_padding (5,0);
428 tempo_label.set_name ("EditorTimeButton");
429 tempo_label.set_size_request (-1, (int)timebar_height);
430 tempo_label.set_alignment (1.0, 0.5);
431 tempo_label.set_padding (5,0);
432 meter_label.set_name ("EditorTimeButton");
433 meter_label.set_size_request (-1, (int)timebar_height);
434 meter_label.set_alignment (1.0, 0.5);
435 meter_label.set_padding (5,0);
436 mark_label.set_name ("EditorTimeButton");
437 mark_label.set_size_request (-1, (int)timebar_height);
438 mark_label.set_alignment (1.0, 0.5);
439 mark_label.set_padding (5,0);
440 range_mark_label.set_name ("EditorTimeButton");
441 range_mark_label.set_size_request (-1, (int)timebar_height);
442 range_mark_label.set_alignment (1.0, 0.5);
443 range_mark_label.set_padding (5,0);
444 transport_mark_label.set_name ("EditorTimeButton");
445 transport_mark_label.set_size_request (-1, (int)timebar_height);
446 transport_mark_label.set_alignment (1.0, 0.5);
447 transport_mark_label.set_padding (5,0);
449 time_button_vbox.pack_start (minsec_label, false, false);
450 time_button_vbox.pack_start (smpte_label, false, false);
451 time_button_vbox.pack_start (frame_label, false, false);
452 time_button_vbox.pack_start (bbt_label, false, false);
453 time_button_vbox.pack_start (meter_label, false, false);
454 time_button_vbox.pack_start (tempo_label, false, false);
455 time_button_vbox.pack_start (mark_label, false, false);
457 time_button_event_box.add (time_button_vbox);
459 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
460 time_button_event_box.set_name ("TimebarLabelBase");
461 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
463 /* these enable us to have a dedicated window (for cursor setting, etc.)
464 for the canvas areas.
467 track_canvas_event_box.add (track_canvas);
469 time_canvas_event_box.add (time_canvas_vbox);
470 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
472 edit_packer.set_col_spacings (0);
473 edit_packer.set_row_spacings (0);
474 edit_packer.set_homogeneous (false);
475 edit_packer.set_name ("EditorWindow");
477 edit_packer.attach (edit_hscrollbar, 1, 2, 0, 1, FILL|EXPAND, FILL, 0, 0);
479 edit_packer.attach (time_button_event_box, 0, 1, 1, 2, FILL, FILL, 0, 0);
480 edit_packer.attach (time_canvas_event_box, 1, 2, 1, 2, FILL|EXPAND, FILL, 0, 0);
482 edit_packer.attach (controls_layout, 0, 1, 2, 3, FILL, FILL|EXPAND, 0, 0);
483 edit_packer.attach (track_canvas_event_box, 1, 2, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
484 edit_packer.attach (edit_vscrollbar, 2, 3, 2, 3, FILL, FILL|EXPAND, 0, 0);
486 edit_frame.set_name ("BaseFrame");
487 edit_frame.set_shadow_type (SHADOW_IN);
488 edit_frame.add (edit_packer);
490 zoom_in_button.set_name ("EditorTimeButton");
491 zoom_out_button.set_name ("EditorTimeButton");
492 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in"));
493 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out"));
495 zoom_out_full_button.set_name ("EditorTimeButton");
496 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session"));
498 zoom_in_button.add (*(manage (new Image (Stock::ZOOM_IN, ICON_SIZE_BUTTON))));
499 zoom_out_button.add (*(manage (new Image (Stock::ZOOM_OUT, ICON_SIZE_BUTTON))));
500 zoom_out_full_button.add (*(manage (new Image (Stock::ZOOM_FIT, ICON_SIZE_BUTTON))));
502 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
503 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
504 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
506 zoom_indicator_box.pack_start (zoom_out_button, false, false);
507 zoom_indicator_box.pack_start (zoom_in_button, false, false);
508 zoom_indicator_box.pack_start (zoom_range_clock, false, false);
509 zoom_indicator_box.pack_start (zoom_out_full_button, false, false);
511 zoom_indicator_label.set_text (_("Zoom Span"));
512 zoom_indicator_label.set_name ("ToolBarLabel");
514 zoom_indicator_vbox.set_spacing (3);
515 zoom_indicator_vbox.set_border_width (3);
516 zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false);
517 zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false);
519 bottom_hbox.set_border_width (3);
520 bottom_hbox.set_spacing (3);
522 route_display_model = ListStore::create(route_display_columns);
523 route_list_display.set_model (route_display_model);
524 route_list_display.append_column (_("Visible"), route_display_columns.visible);
525 route_list_display.append_column (_("Name"), route_display_columns.text);
526 route_list_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
527 route_list_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
528 route_list_display.set_headers_visible (true);
529 route_list_display.set_name ("TrackListDisplay");
530 route_list_display.get_selection()->set_mode (SELECTION_NONE);
531 route_list_display.set_reorderable (true);
532 route_list_display.set_size_request (100,-1);
534 CellRendererToggle* route_list_visible_cell = dynamic_cast<CellRendererToggle*>(route_list_display.get_column_cell_renderer (0));
535 route_list_visible_cell->property_activatable() = true;
536 route_list_visible_cell->property_radio() = false;
538 route_display_model->signal_row_deleted().connect (mem_fun (*this, &Editor::route_list_delete));
539 route_display_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_list_change));
541 route_list_display.signal_button_press_event().connect (mem_fun (*this, &Editor::route_list_display_button_press), false);
543 route_list_scroller.add (route_list_display);
544 route_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
546 group_model = ListStore::create(group_columns);
547 edit_group_display.set_model (group_model);
548 edit_group_display.append_column (_("Active"), group_columns.is_active);
549 edit_group_display.append_column (_("Visible"), group_columns.is_visible);
550 edit_group_display.append_column (_("Name"), group_columns.text);
551 edit_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
552 edit_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
553 edit_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
554 edit_group_display.set_headers_visible (true);
556 /* use checkbox for the active + visible columns */
558 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (0));
559 active_cell->property_activatable() = true;
560 active_cell->property_radio() = false;
562 active_cell = dynamic_cast<CellRendererToggle*>(edit_group_display.get_column_cell_renderer (1));
563 active_cell->property_activatable() = true;
564 active_cell->property_radio() = false;
566 edit_group_display.set_name ("EditGroupList");
568 group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change));
570 edit_group_display.set_name ("EditGroupList");
571 edit_group_display.get_selection()->set_mode (SELECTION_NONE);
572 edit_group_display.set_reorderable (false);
574 edit_group_display.set_size_request (75, -1);
576 edit_group_display_scroller.add (edit_group_display);
577 edit_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
579 edit_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event), false);
583 row = *(group_model->append());
584 row[group_columns.is_active] = false;
585 row[group_columns.is_visible] = true;
586 row[group_columns.text] = (_("-all-"));
587 row[group_columns.routegroup] = 0;
590 region_list_display.set_size_request (100, -1);
591 region_list_display.set_name ("RegionListDisplay");
593 region_list_model = TreeStore::create (region_list_columns);
594 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
595 region_list_model->set_sort_column (0, SORT_ASCENDING);
597 region_list_display.set_model (region_list_model);
598 region_list_display.append_column (_("Regions"), region_list_columns.name);
599 region_list_display.set_headers_visible (false);
601 region_list_display.get_selection()->set_select_function (mem_fun (*this, &Editor::region_list_selection_filter));
603 TreeViewColumn* tv_col = region_list_display.get_column(0);
604 CellRendererText* renderer = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
605 tv_col->add_attribute(renderer->property_text(), region_list_columns.name);
606 tv_col->add_attribute(renderer->property_foreground_gdk(), region_list_columns.color_);
608 region_list_display.get_selection()->set_mode (SELECTION_MULTIPLE);
609 region_list_display.add_object_drag (region_list_columns.region.index(), "regions");
611 /* setup DnD handling */
613 list<TargetEntry> region_list_target_table;
615 region_list_target_table.push_back (TargetEntry ("text/plain"));
616 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
617 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
619 region_list_display.add_drop_targets (region_list_target_table);
620 region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
622 region_list_scroller.add (region_list_display);
623 region_list_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
625 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
626 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
627 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
628 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
629 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
630 // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
632 named_selection_scroller.add (named_selection_display);
633 named_selection_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
635 named_selection_model = TreeStore::create (named_selection_columns);
636 named_selection_display.set_model (named_selection_model);
637 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
638 named_selection_display.set_headers_visible (false);
639 named_selection_display.set_size_request (100, -1);
640 named_selection_display.set_name ("RegionListDisplay");
642 named_selection_display.get_selection()->set_mode (SELECTION_SINGLE);
643 named_selection_display.set_size_request (100, -1);
644 named_selection_display.signal_button_press_event().connect (mem_fun(*this, &Editor::named_selection_display_button_press), false);
645 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
649 snapshot_display_model = ListStore::create (snapshot_display_columns);
650 snapshot_display.set_model (snapshot_display_model);
651 snapshot_display.append_column (X_("snapshot"), snapshot_display_columns.visible_name);
652 snapshot_display.set_name ("SnapshotDisplayList");
653 snapshot_display.set_size_request (75, -1);
654 snapshot_display.set_headers_visible (false);
655 snapshot_display.set_reorderable (false);
656 snapshot_display_scroller.add (snapshot_display);
657 snapshot_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
659 snapshot_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::snapshot_display_selection_changed));
660 snapshot_display.signal_button_press_event().connect (mem_fun (*this, &Editor::snapshot_display_button_press), false);
662 the_notebook.append_page (region_list_scroller, _("Regions"));
663 the_notebook.append_page (route_list_scroller, _("Tracks/Busses"));
664 the_notebook.append_page (snapshot_display_scroller, _("Snapshots"));
665 the_notebook.append_page (edit_group_display_scroller, _("Edit Groups"));
666 the_notebook.append_page (named_selection_scroller, _("Chunks"));
667 the_notebook.set_show_tabs (true);
668 the_notebook.set_scrollable (true);
669 the_notebook.popup_enable ();
671 TearOff *notebook_tearoff = manage (new TearOff (the_notebook, true));
672 notebook_tearoff->tearoff_window().set_size_request (200, 400);
674 edit_pane.pack1 (edit_frame, true, true);
675 edit_pane.pack2 (*notebook_tearoff, false, true);
677 edit_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
679 top_hbox.pack_start (toolbar_frame, true, true);
681 HBox *hbox = manage (new HBox);
682 hbox->pack_start (edit_pane, true, true);
684 global_vpacker.pack_start (top_hbox, false, false);
685 global_vpacker.pack_start (*hbox, true, true);
687 global_hpacker.pack_start (global_vpacker, true, true);
689 set_name ("EditorWindow");
690 add_accel_group (ActionManager::ui_manager->get_accel_group());
692 vpacker.pack_end (global_hpacker, true, true);
694 /* register actions now so that set_state() can find them and set toggles/checks etc */
698 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
701 _playlist_selector = new PlaylistSelector();
702 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
704 AudioRegionView::AudioRegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_audio_regionview));
708 nudge_forward_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(right_arrow_xpm)))));
709 nudge_backward_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(left_arrow_xpm)))));
711 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards"));
712 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards"));
714 nudge_forward_button.set_name ("TransportButton");
715 nudge_backward_button.set_name ("TransportButton");
717 fade_context_menu.set_name ("ArdourContextMenu");
719 set_title (_("ardour: editor"));
720 set_wmclass (_("ardour_editor"), "Ardour");
723 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
725 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
726 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
734 /* <CMT Additions> */
735 if(image_socket_listener)
737 if(image_socket_listener->is_connected())
739 image_socket_listener->close_connection() ;
742 delete image_socket_listener ;
743 image_socket_listener = 0 ;
745 /* </CMT Additions> */
749 Editor::add_toplevel_controls (Container& cont)
751 vpacker.pack_start (cont, false, false);
756 Editor::catch_vanishing_audio_regionview (AudioRegionView *rv)
758 /* note: the selection will take care of the vanishing
759 audioregionview by itself.
762 if (clicked_regionview == rv) {
763 clicked_regionview = 0;
766 if (entered_regionview == rv) {
767 set_entered_regionview (0);
772 Editor::set_entered_regionview (AudioRegionView* rv)
774 if (rv == entered_regionview) {
778 if (entered_regionview) {
779 entered_regionview->exited ();
782 if ((entered_regionview = rv) != 0) {
783 entered_regionview->entered ();
788 Editor::set_entered_track (TimeAxisView* tav)
791 entered_track->exited ();
794 if ((entered_track = tav) != 0) {
795 entered_track->entered ();
800 Editor::left_track_canvas (GdkEventCrossing *ev)
802 set_entered_track (0);
803 set_entered_regionview (0);
809 Editor::show_window ()
814 /* now reset all audio_time_axis heights, because widgets might need
820 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
821 tv = (static_cast<TimeAxisView*>(*i));
827 Editor::tie_vertical_scrolling ()
829 double y1 = vertical_adjustment.get_value();
830 controls_layout.get_vadjustment()->set_value (y1);
831 playhead_cursor->set_y_axis(y1);
832 edit_cursor->set_y_axis(y1);
836 Editor::set_frames_per_unit (double fpu)
838 jack_nframes_t frames;
840 if (fpu == frames_per_unit) {
848 // convert fpu to frame count
850 frames = (jack_nframes_t) floor (fpu * canvas_width);
852 /* don't allow zooms that fit more than the maximum number
853 of frames into an 800 pixel wide space.
856 if (max_frames / fpu < 800.0) {
860 frames_per_unit = fpu;
862 if (frames != zoom_range_clock.current_duration()) {
863 zoom_range_clock.set (frames);
866 /* only update these if we not about to call reposition_x_origin,
867 which will do the same updates.
870 if (session && !no_zoom_repos_update) {
871 horizontal_adjustment.set_upper (session->current_end_frame() / frames_per_unit);
874 if (!no_zoom_repos_update) {
875 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
876 update_fixed_rulers ();
877 tempo_map_changed (Change (0));
880 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
881 if (!selection->tracks.empty()) {
882 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
883 (*i)->reshow_selection (selection->time);
886 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
887 (*i)->reshow_selection (selection->time);
892 ZoomChanged (); /* EMIT_SIGNAL */
894 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
895 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
902 Editor::instant_save ()
904 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
909 session->add_instant_xml(get_state(), session->path());
911 Config->add_instant_xml(get_state(), Config->get_user_ardour_path());
916 Editor::reposition_x_origin (jack_nframes_t frame)
918 if (frame != leftmost_frame) {
919 leftmost_frame = frame;
920 double pixel = frame_to_pixel (frame);
921 if (pixel >= horizontal_adjustment.get_upper()) {
922 horizontal_adjustment.set_upper (frame_to_pixel (frame + (current_page_frames())));
924 horizontal_adjustment.set_value (frame/frames_per_unit);
925 XOriginChanged (); /* EMIT_SIGNAL */
930 Editor::edit_cursor_clock_changed()
932 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
933 edit_cursor->set_position (edit_cursor_clock.current_time());
939 Editor::zoom_adjustment_changed ()
941 if (session == 0 || no_zoom_repos_update) {
945 double fpu = zoom_range_clock.current_duration() / canvas_width;
949 zoom_range_clock.set ((jack_nframes_t) floor (fpu * canvas_width));
950 } else if (fpu > session->current_end_frame() / canvas_width) {
951 fpu = session->current_end_frame() / canvas_width;
952 zoom_range_clock.set ((jack_nframes_t) floor (fpu * canvas_width));
959 Editor::canvas_horizontally_scrolled ()
961 leftmost_frame = (jack_nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
963 update_fixed_rulers ();
965 if (!edit_hscroll_dragging) {
966 tempo_map_changed (Change (0));
968 update_tempo_based_rulers();
973 Editor::reposition_and_zoom (jack_nframes_t frame, double nfpu)
975 if (!repos_zoom_queued) {
976 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu));
977 repos_zoom_queued = true;
982 Editor::deferred_reposition_and_zoom (jack_nframes_t frame, double nfpu)
984 /* if we need to force an update to the hscroller stuff,
985 don't set no_zoom_repos_update.
988 no_zoom_repos_update = (frame != leftmost_frame);
990 set_frames_per_unit (nfpu);
991 if (no_zoom_repos_update) {
992 reposition_x_origin (frame);
994 no_zoom_repos_update = false;
995 repos_zoom_queued = false;
1001 Editor::on_realize ()
1003 Window::on_realize ();
1008 Editor::queue_session_control_changed (Session::ControlType t)
1010 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::session_control_changed), t));
1014 Editor::session_control_changed (Session::ControlType t)
1016 // right now we're only tracking the loop and punch state
1019 case Session::AutoLoop:
1020 update_loop_range_view (true);
1022 case Session::PunchIn:
1023 case Session::PunchOut:
1024 update_punch_range_view (true);
1033 Editor::fake_add_edit_group (RouteGroup *group)
1035 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::add_edit_group), group));
1039 Editor::fake_handle_new_audio_region (AudioRegion *region)
1041 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_new_audio_region), region));
1045 Editor::fake_handle_audio_region_removed (AudioRegion *region)
1047 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_audio_region_removed), region));
1051 Editor::fake_handle_new_duration ()
1053 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &Editor::handle_new_duration));
1057 Editor::start_scrolling ()
1059 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1060 (mem_fun(*this, &Editor::update_current_screen));
1062 slower_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
1063 (mem_fun(*this, &Editor::update_slower));
1067 Editor::stop_scrolling ()
1069 scroll_connection.disconnect ();
1070 slower_update_connection.disconnect ();
1074 Editor::map_position_change (jack_nframes_t frame)
1076 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1078 if (session == 0 || !_follow_playhead) {
1082 center_screen (frame);
1083 playhead_cursor->set_position (frame);
1087 Editor::center_screen (jack_nframes_t frame)
1089 double page = canvas_width * frames_per_unit;
1091 /* if we're off the page, then scroll.
1094 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1095 center_screen_internal (frame, page);
1100 Editor::center_screen_internal (jack_nframes_t frame, float page)
1105 frame -= (jack_nframes_t) page;
1110 reposition_x_origin (frame);
1114 Editor::handle_new_duration ()
1116 reset_scrolling_region ();
1119 horizontal_adjustment.set_upper (session->current_end_frame() / frames_per_unit);
1120 horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
1125 Editor::update_title_s (const string & snap_name)
1127 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1133 Editor::update_title ()
1135 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1138 bool dirty = session->dirty();
1140 string wintitle = _("ardour: editor: ");
1146 wintitle += session->name();
1148 if (session->snap_name() != session->name()) {
1150 wintitle += session->snap_name();
1157 set_title (wintitle);
1162 Editor::connect_to_session (Session *t)
1166 if (first_action_message) {
1167 first_action_message->hide();
1172 session->going_away.connect (mem_fun(*this, &Editor::session_going_away));
1174 /* These signals can all be emitted by a non-GUI thread. Therefore the
1175 handlers for them must not attempt to directly interact with the GUI,
1176 but use Gtkmm2ext::UI::instance()->call_slot();
1179 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1180 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1181 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p)));
1182 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::fake_handle_new_audio_region)));
1183 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::fake_handle_audio_region_removed)));
1184 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::fake_handle_new_duration)));
1185 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::fake_add_edit_group)));
1186 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1187 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1188 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1189 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1190 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1191 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1193 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1194 session_connections.push_back (session->SMPTETypeChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1196 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1198 session->foreach_edit_group (mem_fun (*this, &Editor::add_edit_group));
1200 edit_cursor_clock.set_session (session);
1201 selection_start_clock.set_session (session);
1202 selection_end_clock.set_session (session);
1203 zoom_range_clock.set_session (session);
1204 _playlist_selector->set_session (session);
1205 nudge_clock.set_session (session);
1207 switch (session->get_edit_mode()) {
1209 edit_mode_selector.set_active_text (edit_mode_strings[splice_index]);
1213 edit_mode_selector.set_active_text (edit_mode_strings[slide_index]);
1217 Location* loc = session->locations()->auto_loop_location();
1219 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1220 if (loc->start() == loc->end()) {
1221 loc->set_end (loc->start() + 1);
1223 session->locations()->add (loc, false);
1224 session->set_auto_loop_location (loc);
1228 loc->set_name (_("Loop"));
1231 loc = session->locations()->auto_punch_location();
1233 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1234 if (loc->start() == loc->end()) {
1235 loc->set_end (loc->start() + 1);
1237 session->locations()->add (loc, false);
1238 session->set_auto_punch_location (loc);
1242 loc->set_name (_("Punch"));
1245 update_loop_range_view (true);
1246 update_punch_range_view (true);
1248 session->ControlChanged.connect (mem_fun(*this, &Editor::queue_session_control_changed));
1249 session->StateSaved.connect (mem_fun(*this, &Editor::session_state_saved));
1251 refresh_location_display ();
1252 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1253 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1254 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1255 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1256 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1258 reset_scrolling_region ();
1260 redisplay_regions ();
1261 redisplay_named_selections ();
1262 redisplay_snapshots ();
1264 initial_route_list_display ();
1266 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1267 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1270 /* ::reposition_x_origin() doesn't work right here, since the old
1271 position may be zero already, and it does nothing in such
1277 horizontal_adjustment.set_upper (session->current_end_frame() / frames_per_unit);
1278 horizontal_adjustment.set_value (0);
1280 restore_ruler_visibility ();
1281 tempo_map_changed (Change (0));
1283 edit_cursor->set_position (0);
1284 playhead_cursor->set_position (0);
1288 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1291 /* don't show master bus in a new session */
1293 if (ARDOUR_UI::instance()->session_is_new ()) {
1295 TreeModel::Children rows = route_display_model->children();
1296 TreeModel::Children::iterator i;
1298 no_route_list_redisplay = true;
1300 for (i = rows.begin(); i != rows.end(); ++i) {
1301 TimeAxisView *tv = (*i)[route_display_columns.tv];
1302 AudioTimeAxisView *atv;
1304 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1305 if (atv->route().master()) {
1306 route_list_display.get_selection()->unselect (i);
1311 no_route_list_redisplay = false;
1312 redisplay_route_list ();
1317 Editor::build_cursors ()
1319 using namespace Gdk;
1321 Gdk::Color mbg ("#000000" ); /* Black */
1322 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1325 RefPtr<Bitmap> source, mask;
1326 source = Bitmap::create (mag_bits, mag_width, mag_height);
1327 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1328 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1331 Gdk::Color fbg ("#ffffff" );
1332 Gdk::Color ffg ("#000000" );
1335 RefPtr<Bitmap> source, mask;
1337 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1338 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1339 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1343 RefPtr<Bitmap> source, mask;
1344 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1345 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1346 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1349 grabber_cursor = new Gdk::Cursor (HAND2);
1350 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1351 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1352 selector_cursor = new Gdk::Cursor (XTERM);
1353 time_fx_cursor = new Gdk::Cursor (SIZING);
1354 wait_cursor = new Gdk::Cursor (WATCH);
1355 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1359 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1361 using namespace Menu_Helpers;
1362 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1365 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1369 MenuList& items (fade_context_menu.items());
1373 switch (item_type) {
1375 case FadeInHandleItem:
1376 if (arv->region.fade_in_active()) {
1377 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false)));
1379 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true)));
1382 items.push_back (SeparatorElem());
1384 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear)));
1385 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB)));
1386 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast)));
1387 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA)));
1388 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow)));
1392 case FadeOutHandleItem:
1393 if (arv->region.fade_out_active()) {
1394 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false)));
1396 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true)));
1399 items.push_back (SeparatorElem());
1401 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear)));
1402 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast)));
1403 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB)));
1404 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA)));
1405 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow)));
1409 fatal << _("programming error: ")
1410 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1415 fade_context_menu.popup (button, time);
1419 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, jack_nframes_t frame)
1421 using namespace Menu_Helpers;
1422 Menu* (Editor::*build_menu_function)(jack_nframes_t);
1425 switch (item_type) {
1427 case AudioRegionViewName:
1428 case AudioRegionViewNameHighlight:
1429 if (with_selection) {
1430 build_menu_function = &Editor::build_track_selection_context_menu;
1432 build_menu_function = &Editor::build_track_region_context_menu;
1437 if (with_selection) {
1438 build_menu_function = &Editor::build_track_selection_context_menu;
1440 build_menu_function = &Editor::build_track_context_menu;
1444 case CrossfadeViewItem:
1445 build_menu_function = &Editor::build_track_crossfade_context_menu;
1449 if (clicked_audio_trackview->get_diskstream()) {
1450 build_menu_function = &Editor::build_track_context_menu;
1452 build_menu_function = &Editor::build_track_bus_context_menu;
1457 /* probably shouldn't happen but if it does, we don't care */
1461 menu = (this->*build_menu_function)(frame);
1462 menu->set_name ("ArdourContextMenu");
1464 /* now handle specific situations */
1466 switch (item_type) {
1468 case AudioRegionViewName:
1469 case AudioRegionViewNameHighlight:
1470 if (!with_selection) {
1471 if (region_edit_menu_split_item) {
1472 if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) {
1473 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, true);
1475 ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, false);
1478 if (region_edit_menu_split_multichannel_item) {
1479 if (clicked_regionview && clicked_regionview->region.n_channels() > 1) {
1480 // GTK2FIX find the action, change its sensitivity
1481 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1483 // GTK2FIX see above
1484 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1493 case CrossfadeViewItem:
1500 /* probably shouldn't happen but if it does, we don't care */
1504 if (clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1506 /* Bounce to disk */
1508 using namespace Menu_Helpers;
1509 MenuList& edit_items = menu->items();
1511 edit_items.push_back (SeparatorElem());
1513 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1514 case AudioTrack::NoFreeze:
1515 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1518 case AudioTrack::Frozen:
1519 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1522 case AudioTrack::UnFrozen:
1523 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1529 menu->popup (button, time);
1533 Editor::build_track_context_menu (jack_nframes_t ignored)
1535 using namespace Menu_Helpers;
1537 MenuList& edit_items = track_context_menu.items();
1540 add_dstream_context_items (edit_items);
1541 return &track_context_menu;
1545 Editor::build_track_bus_context_menu (jack_nframes_t ignored)
1547 using namespace Menu_Helpers;
1549 MenuList& edit_items = track_context_menu.items();
1552 add_bus_context_items (edit_items);
1553 return &track_context_menu;
1557 Editor::build_track_region_context_menu (jack_nframes_t frame)
1559 using namespace Menu_Helpers;
1560 MenuList& edit_items = track_region_context_menu.items();
1563 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1569 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1570 Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed()));
1571 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1572 add_region_context_items (atv->view, (*i), edit_items);
1578 add_dstream_context_items (edit_items);
1580 return &track_region_context_menu;
1584 Editor::build_track_crossfade_context_menu (jack_nframes_t frame)
1586 using namespace Menu_Helpers;
1587 MenuList& edit_items = track_crossfade_context_menu.items();
1588 edit_items.clear ();
1590 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1597 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = dynamic_cast<AudioPlaylist*> (pl)) != 0)) {
1599 Playlist::RegionList* regions = pl->regions_at (frame);
1600 AudioPlaylist::Crossfades xfades;
1602 apl->crossfades_at (frame, xfades);
1604 bool many = xfades.size() > 1;
1606 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1607 add_crossfade_context_items (atv->view, (*i), edit_items, many);
1610 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1611 add_region_context_items (atv->view, (*i), edit_items);
1618 add_dstream_context_items (edit_items);
1620 return &track_crossfade_context_menu;
1624 Editor::build_track_selection_context_menu (jack_nframes_t ignored)
1626 using namespace Menu_Helpers;
1627 MenuList& edit_items = track_selection_context_menu.items();
1628 edit_items.clear ();
1630 add_selection_context_items (edit_items);
1631 add_dstream_context_items (edit_items);
1633 return &track_selection_context_menu;
1637 Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many)
1639 using namespace Menu_Helpers;
1640 Menu *xfade_menu = manage (new Menu);
1641 MenuList& items = xfade_menu->items();
1642 xfade_menu->set_name ("ArdourContextMenu");
1645 if (xfade->active()) {
1651 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), xfade)));
1652 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), xfade)));
1654 if (xfade->can_follow_overlap()) {
1656 if (xfade->following_overlap()) {
1657 str = _("Convert to short");
1659 str = _("Convert to full");
1662 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1666 str = xfade->out().name();
1668 str += xfade->in().name();
1670 str = _("Crossfade");
1673 edit_items.push_back (MenuElem (str, *xfade_menu));
1674 edit_items.push_back (SeparatorElem());
1678 Editor::xfade_edit_left_region ()
1680 if (clicked_crossfadeview) {
1681 clicked_crossfadeview->left_view.show_region_editor ();
1686 Editor::xfade_edit_right_region ()
1688 if (clicked_crossfadeview) {
1689 clicked_crossfadeview->right_view.show_region_editor ();
1694 Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items)
1696 using namespace Menu_Helpers;
1697 Menu *region_menu = manage (new Menu);
1698 MenuList& items = region_menu->items();
1699 region_menu->set_name ("ArdourContextMenu");
1701 AudioRegion* ar = 0;
1704 ar = dynamic_cast<AudioRegion*> (region);
1707 /* when this particular menu pops up, make the relevant region
1711 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, region));
1713 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1714 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1715 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1716 items.push_back (SeparatorElem());
1717 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1718 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1719 items.push_back (SeparatorElem());
1721 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1722 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1723 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1724 items.push_back (SeparatorElem());
1726 /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler
1727 might be able to figure out which overloaded member function to use in
1731 void (Editor::*type_A_pmf)(void (Region::*pmf)(bool), bool) = &Editor::region_selection_op;
1733 items.push_back (MenuElem (_("Lock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, true)));
1734 items.push_back (MenuElem (_("Unlock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, false)));
1735 items.push_back (SeparatorElem());
1737 if (region->muted()) {
1738 items.push_back (MenuElem (_("Unmute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, false)));
1740 items.push_back (MenuElem (_("Mute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, true)));
1742 items.push_back (SeparatorElem());
1744 items.push_back (MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1745 items.push_back (SeparatorElem());
1750 items.push_back (MenuElem (_("Toggle envelope visibility"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility)));
1751 items.push_back (MenuElem (_("Toggle envelope active"), mem_fun(*this, &Editor::toggle_gain_envelope_active)));
1752 items.push_back (SeparatorElem());
1754 if (ar->scale_amplitude() != 1.0f) {
1755 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1757 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1760 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1761 items.push_back (SeparatorElem());
1765 Menu *nudge_menu = manage (new Menu());
1766 MenuList& nudge_items = nudge_menu->items();
1767 nudge_menu->set_name ("ArdourContextMenu");
1769 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1770 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1771 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1772 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1774 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1775 items.push_back (SeparatorElem());
1777 Menu *trim_menu = manage (new Menu);
1778 MenuList& trim_items = trim_menu->items();
1779 trim_menu->set_name ("ArdourContextMenu");
1781 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1782 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1784 items.push_back (MenuElem (_("Trim"), *trim_menu));
1785 items.push_back (SeparatorElem());
1787 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1788 region_edit_menu_split_item = &items.back();
1790 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1791 region_edit_menu_split_multichannel_item = &items.back();
1793 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1794 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1795 items.push_back (SeparatorElem());
1796 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1797 items.push_back (SeparatorElem());
1798 items.push_back (MenuElem (_("Destroy"), mem_fun(*this, &Editor::destroy_clicked_region)));
1800 /* OK, stick the region submenu at the top of the list, and then add
1804 /* we have to hack up the region name because "_" has a special
1805 meaning for menu titles.
1808 string::size_type pos = 0;
1809 string menu_item_name = region->name();
1811 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1812 menu_item_name.replace (pos, 1, "__");
1816 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1817 edit_items.push_back (SeparatorElem());
1821 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1823 using namespace Menu_Helpers;
1824 Menu *selection_menu = manage (new Menu);
1825 MenuList& items = selection_menu->items();
1826 selection_menu->set_name ("ArdourContextMenu");
1828 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1829 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1830 items.push_back (SeparatorElem());
1831 items.push_back (MenuElem (_("Separate range to track"), mem_fun(*this, &Editor::separate_region_from_selection)));
1832 items.push_back (MenuElem (_("Separate range to region list"), mem_fun(*this, &Editor::new_region_from_selection)));
1833 items.push_back (SeparatorElem());
1834 items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1835 items.push_back (SeparatorElem());
1836 items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1837 items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1838 items.push_back (SeparatorElem());
1839 items.push_back (MenuElem (_("Crop region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1840 items.push_back (MenuElem (_("Fill range with region"), mem_fun(*this, &Editor::region_fill_selection)));
1841 items.push_back (MenuElem (_("Duplicate range"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1842 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection)));
1843 items.push_back (SeparatorElem());
1844 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1845 items.push_back (MenuElem (_("Export range"), mem_fun(*this, &Editor::export_selection)));
1847 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1848 edit_items.push_back (SeparatorElem());
1852 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1854 using namespace Menu_Helpers;
1858 Menu *play_menu = manage (new Menu);
1859 MenuList& play_items = play_menu->items();
1860 play_menu->set_name ("ArdourContextMenu");
1862 play_items.push_back (MenuElem (_("Play from edit cursor")));
1863 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1864 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1865 play_items.push_back (SeparatorElem());
1866 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1868 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1872 Menu *select_menu = manage (new Menu);
1873 MenuList& select_items = select_menu->items();
1874 select_menu->set_name ("ArdourContextMenu");
1876 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1877 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1878 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1879 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1880 select_items.push_back (SeparatorElem());
1881 select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1882 select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1883 select_items.push_back (SeparatorElem());
1884 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1885 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1886 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1887 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1888 select_items.push_back (SeparatorElem());
1890 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1894 Menu *cutnpaste_menu = manage (new Menu);
1895 MenuList& cutnpaste_items = cutnpaste_menu->items();
1896 cutnpaste_menu->set_name ("ArdourContextMenu");
1898 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1899 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1900 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1901 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1903 cutnpaste_items.push_back (SeparatorElem());
1905 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1906 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1908 cutnpaste_items.push_back (SeparatorElem());
1910 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1912 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1914 /* Adding new material */
1916 Menu *import_menu = manage (new Menu());
1917 MenuList& import_items = import_menu->items();
1918 import_menu->set_name ("ArdourContextMenu");
1920 import_items.push_back (MenuElem (_("Insert Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1921 import_items.push_back (MenuElem (_("Insert external sndfile"), bind (mem_fun(*this, &Editor::insert_sndfile), false)));
1923 edit_items.push_back (MenuElem (_("Import"), *import_menu));
1927 Menu *nudge_menu = manage (new Menu());
1928 MenuList& nudge_items = nudge_menu->items();
1929 nudge_menu->set_name ("ArdourContextMenu");
1931 edit_items.push_back (SeparatorElem());
1932 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1933 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1934 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1935 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1937 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1941 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1943 using namespace Menu_Helpers;
1947 Menu *play_menu = manage (new Menu);
1948 MenuList& play_items = play_menu->items();
1949 play_menu->set_name ("ArdourContextMenu");
1951 play_items.push_back (MenuElem (_("Play from edit cursor")));
1952 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1953 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1957 Menu *select_menu = manage (new Menu);
1958 MenuList& select_items = select_menu->items();
1959 select_menu->set_name ("ArdourContextMenu");
1961 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1962 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
1963 select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1964 select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
1965 select_items.push_back (SeparatorElem());
1966 select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
1967 select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
1968 select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1969 select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1971 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1975 Menu *cutnpaste_menu = manage (new Menu);
1976 MenuList& cutnpaste_items = cutnpaste_menu->items();
1977 cutnpaste_menu->set_name ("ArdourContextMenu");
1979 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1980 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1981 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1983 Menu *nudge_menu = manage (new Menu());
1984 MenuList& nudge_items = nudge_menu->items();
1985 nudge_menu->set_name ("ArdourContextMenu");
1987 edit_items.push_back (SeparatorElem());
1988 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1989 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1990 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1991 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1993 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1996 /* CURSOR SETTING AND MARKS AND STUFF */
1999 Editor::set_snap_to (SnapType st)
2002 vector<string> txt = internationalize (snap_type_strings);
2003 snap_type_selector.set_active_text (txt[(int)st]);
2007 switch (snap_type) {
2008 case SnapToAThirtysecondBeat:
2009 case SnapToASixteenthBeat:
2010 case SnapToAEighthBeat:
2011 case SnapToAQuarterBeat:
2012 case SnapToAThirdBeat:
2013 update_tempo_based_rulers ();
2021 Editor::set_snap_mode (SnapMode mode)
2024 vector<string> txt = internationalize (snap_mode_strings);
2025 snap_mode_selector.set_active_text (txt[(int)mode]);
2031 Editor::add_location_from_selection ()
2033 if (selection->time.empty()) {
2037 if (session == 0 || clicked_trackview == 0) {
2041 jack_nframes_t start = selection->time[clicked_selection].start;
2042 jack_nframes_t end = selection->time[clicked_selection].end;
2044 Location *location = new Location (start, end, "selection");
2046 session->begin_reversible_command (_("add marker"));
2047 session->add_undo (session->locations()->get_memento());
2048 session->locations()->add (location, true);
2049 session->add_redo_no_execute (session->locations()->get_memento());
2050 session->commit_reversible_command ();
2054 Editor::add_location_from_playhead_cursor ()
2056 jack_nframes_t where = session->audible_frame();
2058 Location *location = new Location (where, where, "mark", Location::IsMark);
2059 session->begin_reversible_command (_("add marker"));
2060 session->add_undo (session->locations()->get_memento());
2061 session->locations()->add (location, true);
2062 session->add_redo_no_execute (session->locations()->get_memento());
2063 session->commit_reversible_command ();
2068 Editor::set_state (const XMLNode& node)
2070 const XMLProperty* prop;
2072 int x, y, xoff, yoff;
2076 if ((geometry = find_named_node (node, "geometry")) == 0) {
2078 g.base_width = default_width;
2079 g.base_height = default_height;
2087 g.base_width = atoi(geometry->property("x_size")->value());
2088 g.base_height = atoi(geometry->property("y_size")->value());
2089 x = atoi(geometry->property("x_pos")->value());
2090 y = atoi(geometry->property("y_pos")->value());
2091 xoff = atoi(geometry->property("x_off")->value());
2092 yoff = atoi(geometry->property("y_off")->value());
2095 set_geometry_hints (vpacker, g, Gdk::HINT_BASE_SIZE);
2096 set_default_size (g.base_width, g.base_height);
2099 if ((prop = node.property ("zoom-focus"))) {
2100 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2103 if ((prop = node.property ("zoom"))) {
2104 set_frames_per_unit (atof (prop->value()));
2107 if ((prop = node.property ("snap-to"))) {
2108 set_snap_to ((SnapType) atoi (prop->value()));
2111 if ((prop = node.property ("snap-mode"))) {
2112 set_snap_mode ((SnapMode) atoi (prop->value()));
2115 if ((prop = node.property ("mouse-mode"))) {
2116 MouseMode m = str2mousemode(prop->value());
2117 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2118 set_mouse_mode (m, true);
2120 mouse_mode = MouseGain; /* lie, to force the mode switch */
2121 set_mouse_mode (MouseObject, true);
2124 if ((prop = node.property ("show-waveforms"))) {
2125 bool yn = (prop->value() == "yes");
2126 _show_waveforms = !yn;
2127 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
2129 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2130 /* do it twice to force the change */
2131 tact->set_active (!yn);
2132 tact->set_active (yn);
2136 if ((prop = node.property ("show-waveforms-recording"))) {
2137 bool yn = (prop->value() == "yes");
2138 _show_waveforms_recording = !yn;
2139 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
2141 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2142 /* do it twice to force the change */
2143 tact->set_active (!yn);
2144 tact->set_active (yn);
2148 if ((prop = node.property ("show-measures"))) {
2149 bool yn = (prop->value() == "yes");
2150 _show_measures = !yn;
2151 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2153 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2154 /* do it twice to force the change */
2155 tact->set_active (!yn);
2156 tact->set_active (yn);
2160 if ((prop = node.property ("follow-playhead"))) {
2161 bool yn = (prop->value() == "yes");
2162 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleFollowPlayhead"));
2164 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2165 /* do it twice to force the change */
2166 tact->set_active (!yn);
2167 tact->set_active (yn);
2172 if ((prop = node.property ("region-list-sort-type"))) {
2173 region_list_sort_type = (Editing::RegionListSortType) -1; // force change
2174 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2177 if ((prop = node.property ("xfades-visible"))) {
2178 bool yn = (prop->value() == "yes");
2179 _xfade_visibility = !yn;
2180 set_xfade_visibility (yn);
2183 if ((prop = node.property ("show-editor-mixer"))) {
2185 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2187 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2188 bool yn = (prop->value() == X_("yes"));
2190 /* do it twice to force the change */
2192 tact->set_active (!yn);
2193 tact->set_active (yn);
2201 Editor::get_state ()
2203 XMLNode* node = new XMLNode ("Editor");
2206 if (is_realized()) {
2207 Glib::RefPtr<Gdk::Window> win = get_window();
2209 int x, y, xoff, yoff, width, height;
2210 win->get_root_origin(x, y);
2211 win->get_position(xoff, yoff);
2212 win->get_size(width, height);
2214 XMLNode* geometry = new XMLNode ("geometry");
2216 snprintf(buf, sizeof(buf), "%d", width);
2217 geometry->add_property("x_size", string(buf));
2218 snprintf(buf, sizeof(buf), "%d", height);
2219 geometry->add_property("y_size", string(buf));
2220 snprintf(buf, sizeof(buf), "%d", x);
2221 geometry->add_property("x_pos", string(buf));
2222 snprintf(buf, sizeof(buf), "%d", y);
2223 geometry->add_property("y_pos", string(buf));
2224 snprintf(buf, sizeof(buf), "%d", xoff);
2225 geometry->add_property("x_off", string(buf));
2226 snprintf(buf, sizeof(buf), "%d", yoff);
2227 geometry->add_property("y_off", string(buf));
2228 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2229 geometry->add_property("edit_pane_pos", string(buf));
2231 node->add_child_nocopy (*geometry);
2234 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2235 node->add_property ("zoom-focus", buf);
2236 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2237 node->add_property ("zoom", buf);
2238 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2239 node->add_property ("snap-to", buf);
2240 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2241 node->add_property ("snap-mode", buf);
2243 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2244 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2245 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2246 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2247 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2248 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2249 node->add_property ("mouse-mode", enum2str(mouse_mode));
2251 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2253 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2254 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2263 Editor::trackview_by_y_position (double y)
2265 TrackViewList::iterator iter;
2268 for (iter = track_views.begin(); iter != track_views.end(); ++iter) {
2276 if (tv->y_position <= y && y < ((tv->y_position + tv->height + track_spacing))) {
2285 Editor::snap_to (jack_nframes_t& start, int32_t direction, bool for_mark)
2287 Location* before = 0;
2288 Location* after = 0;
2294 const jack_nframes_t one_second = session->frame_rate();
2295 const jack_nframes_t one_minute = session->frame_rate() * 60;
2297 jack_nframes_t presnap = start;
2299 switch (snap_type) {
2305 start = (jack_nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2307 start = (jack_nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2310 case SnapToSMPTEFrame:
2312 start = (jack_nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2314 start = (jack_nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2318 case SnapToSMPTESeconds:
2319 if (session->smpte_offset_negative())
2321 start += session->smpte_offset ();
2323 start -= session->smpte_offset ();
2325 if (direction > 0) {
2326 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2328 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2331 if (session->smpte_offset_negative())
2333 start -= session->smpte_offset ();
2335 start += session->smpte_offset ();
2339 case SnapToSMPTEMinutes:
2340 if (session->smpte_offset_negative())
2342 start += session->smpte_offset ();
2344 start -= session->smpte_offset ();
2347 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2349 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2351 if (session->smpte_offset_negative())
2353 start -= session->smpte_offset ();
2355 start += session->smpte_offset ();
2361 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2363 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2369 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2371 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2376 start = session->tempo_map().round_to_bar (start, direction);
2380 start = session->tempo_map().round_to_beat (start, direction);
2383 case SnapToAThirtysecondBeat:
2384 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2387 case SnapToASixteenthBeat:
2388 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2391 case SnapToAEighthBeat:
2392 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2395 case SnapToAQuarterBeat:
2396 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2399 case SnapToAThirdBeat:
2400 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2403 case SnapToEditCursor:
2404 start = edit_cursor->current_frame;
2412 before = session->locations()->first_location_before (start);
2413 after = session->locations()->first_location_after (start);
2415 if (direction < 0) {
2417 start = before->start();
2421 } else if (direction > 0) {
2423 start = after->start();
2425 start = session->current_end_frame();
2430 /* find nearest of the two */
2431 if ((start - before->start()) < (after->start() - start)) {
2432 start = before->start();
2434 start = after->start();
2437 start = before->start();
2440 start = after->start();
2447 case SnapToRegionStart:
2448 case SnapToRegionEnd:
2449 case SnapToRegionSync:
2450 case SnapToRegionBoundary:
2451 if (!region_boundary_cache.empty()) {
2452 vector<jack_nframes_t>::iterator i;
2454 if (direction > 0) {
2455 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2457 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2460 if (i != region_boundary_cache.end()) {
2463 start = region_boundary_cache.back();
2469 switch (snap_mode) {
2475 if (presnap > start) {
2476 if (presnap > (start + unit_to_frame(snap_threshold))) {
2480 } else if (presnap < start) {
2481 if (presnap < (start - unit_to_frame(snap_threshold))) {
2493 Editor::setup_toolbar ()
2496 vector<ToggleButton *> mouse_mode_buttons;
2498 mouse_mode_buttons.push_back (&mouse_move_button);
2499 mouse_mode_buttons.push_back (&mouse_select_button);
2500 mouse_mode_buttons.push_back (&mouse_gain_button);
2501 mouse_mode_buttons.push_back (&mouse_zoom_button);
2502 mouse_mode_buttons.push_back (&mouse_timefx_button);
2503 mouse_mode_buttons.push_back (&mouse_audition_button);
2504 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2506 mouse_mode_button_table.set_homogeneous (true);
2507 mouse_mode_button_table.set_col_spacings (2);
2508 mouse_mode_button_table.set_row_spacings (2);
2509 mouse_mode_button_table.set_border_width (5);
2511 mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1);
2512 mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1);
2513 mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1);
2515 mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2);
2516 mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2);
2517 mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2);
2519 mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table));
2520 mouse_mode_tearoff->set_name ("MouseModeBase");
2522 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2523 &mouse_mode_tearoff->tearoff_window()));
2524 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2525 &mouse_mode_tearoff->tearoff_window(), 1));
2526 mouse_mode_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2527 &mouse_mode_tearoff->tearoff_window()));
2528 mouse_mode_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2529 &mouse_mode_tearoff->tearoff_window(), 1));
2531 mouse_move_button.set_name ("MouseModeButton");
2532 mouse_select_button.set_name ("MouseModeButton");
2533 mouse_gain_button.set_name ("MouseModeButton");
2534 mouse_zoom_button.set_name ("MouseModeButton");
2535 mouse_timefx_button.set_name ("MouseModeButton");
2536 mouse_audition_button.set_name ("MouseModeButton");
2538 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects"));
2539 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges"));
2540 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation"));
2541 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range"));
2542 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions"));
2543 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions"));
2545 mouse_move_button.unset_flags (CAN_FOCUS);
2546 mouse_select_button.unset_flags (CAN_FOCUS);
2547 mouse_gain_button.unset_flags (CAN_FOCUS);
2548 mouse_zoom_button.unset_flags (CAN_FOCUS);
2549 mouse_timefx_button.unset_flags (CAN_FOCUS);
2550 mouse_audition_button.unset_flags (CAN_FOCUS);
2552 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2553 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2555 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2556 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2557 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2558 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2559 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2561 // mouse_move_button.set_active (true);
2563 /* automation control */
2565 global_automation_button.set_name ("MouseModeButton");
2566 automation_mode_button.set_name ("MouseModeButton");
2568 automation_box.set_spacing (2);
2569 automation_box.set_border_width (2);
2570 automation_box.pack_start (global_automation_button, false, false);
2571 automation_box.pack_start (automation_mode_button, false, false);
2575 edit_mode_label.set_name ("ToolBarLabel");
2577 edit_mode_selector.set_name ("EditModeSelector");
2579 edit_mode_box.set_spacing (3);
2580 edit_mode_box.set_border_width (3);
2582 /* XXX another disgusting hack because of the way combo boxes size themselves */
2584 const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button
2585 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2+FUDGE, 10);
2586 set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings));
2587 edit_mode_box.pack_start (edit_mode_label, false, false);
2588 edit_mode_box.pack_start (edit_mode_selector, false, false);
2590 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2594 snap_type_label.set_name ("ToolBarLabel");
2596 snap_type_selector.set_name ("SnapTypeSelector");
2598 snap_type_box.set_spacing (3);
2599 snap_type_box.set_border_width (3);
2601 /* XXX another disgusting hack because of the way combo boxes size themselves */
2603 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10);
2604 set_popdown_strings (snap_type_selector, internationalize (snap_type_strings));
2606 snap_type_box.pack_start (snap_type_label, false, false);
2607 snap_type_box.pack_start (snap_type_selector, false, false);
2609 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2611 /* Snap mode, not snap type */
2613 snap_mode_label.set_name ("ToolBarLabel");
2615 snap_mode_selector.set_name ("SnapModeSelector");
2617 snap_mode_box.set_spacing (3);
2618 snap_mode_box.set_border_width (3);
2620 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2+FUDGE, 10);
2621 set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings));
2623 snap_mode_box.pack_start (snap_mode_label, false, false);
2624 snap_mode_box.pack_start (snap_mode_selector, false, false);
2626 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2628 /* Zoom focus mode */
2630 zoom_focus_label.set_name ("ToolBarLabel");
2632 zoom_focus_selector.set_name ("ZoomFocusSelector");
2634 zoom_focus_box.set_spacing (3);
2635 zoom_focus_box.set_border_width (3);
2637 /* XXX another disgusting hack because of the way combo boxes size themselves */
2639 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2+FUDGE, 10);
2640 set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings));
2642 zoom_focus_box.pack_start (zoom_focus_label, false, false);
2643 zoom_focus_box.pack_start (zoom_focus_selector, false, false);
2645 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2647 /* selection/cursor clocks */
2649 toolbar_selection_cursor_label.set_name ("ToolBarLabel");
2650 selection_start_clock_label.set_name ("ToolBarLabel");
2651 selection_end_clock_label.set_name ("ToolBarLabel");
2652 edit_cursor_clock_label.set_name ("ToolBarLabel");
2654 selection_start_clock_label.set_text (_("Start:"));
2655 selection_end_clock_label.set_text (_("End:"));
2656 edit_cursor_clock_label.set_text (_("Edit"));
2658 /* the zoom in/out buttons are generally taller than the clocks, so
2659 put all the toolbar clocks into a size group with one of the
2660 buttons to make them all equal height.
2662 this also applies to the various toolbar combos
2665 RefPtr<SizeGroup> toolbar_clock_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2666 toolbar_clock_size_group->add_widget (zoom_out_button);
2667 toolbar_clock_size_group->add_widget (edit_cursor_clock);
2668 toolbar_clock_size_group->add_widget (zoom_range_clock);
2669 toolbar_clock_size_group->add_widget (nudge_clock);
2670 toolbar_clock_size_group->add_widget (edit_mode_selector);
2671 toolbar_clock_size_group->add_widget (snap_type_selector);
2672 toolbar_clock_size_group->add_widget (snap_mode_selector);
2673 toolbar_clock_size_group->add_widget (zoom_focus_selector);
2675 HBox* edit_clock_hbox = manage (new HBox());
2676 VBox* edit_clock_vbox = manage (new VBox());
2678 edit_clock_hbox->pack_start (edit_cursor_clock, false, false);
2680 edit_clock_vbox->set_spacing (3);
2681 edit_clock_vbox->set_border_width (3);
2682 edit_clock_vbox->pack_start (edit_cursor_clock_label, false, false);
2683 edit_clock_vbox->pack_start (*edit_clock_hbox, false, false);
2685 HBox* hbox = new HBox;
2687 hbox->pack_start (*edit_clock_vbox, false, false);
2688 hbox->pack_start (zoom_indicator_vbox, false, false);
2689 hbox->pack_start (zoom_focus_box, false, false);
2690 hbox->pack_start (snap_type_box, false, false);
2691 hbox->pack_start (snap_mode_box, false, false);
2692 hbox->pack_start (edit_mode_box, false, false);
2694 VBox *vbox = manage (new VBox);
2696 vbox->set_spacing (3);
2697 vbox->set_border_width (3);
2699 HBox *nbox = manage (new HBox);
2701 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2702 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2704 nbox->pack_start (nudge_backward_button, false, false);
2705 nbox->pack_start (nudge_forward_button, false, false);
2706 nbox->pack_start (nudge_clock, false, false, 5);
2708 nudge_label.set_name ("ToolBarLabel");
2710 vbox->pack_start (nudge_label, false, false);
2711 vbox->pack_start (*nbox, false, false);
2713 hbox->pack_start (*vbox, false, false);
2717 tools_tearoff = new TearOff (*hbox);
2718 tools_tearoff->set_name ("MouseModeBase");
2720 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2721 &tools_tearoff->tearoff_window()));
2722 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2723 &tools_tearoff->tearoff_window(), 0));
2724 tools_tearoff->Hidden.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2725 &tools_tearoff->tearoff_window()));
2726 tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2727 &tools_tearoff->tearoff_window(), 0));
2729 toolbar_hbox.set_spacing (8);
2730 toolbar_hbox.set_border_width (2);
2732 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2733 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2735 toolbar_base.set_name ("ToolBarBase");
2736 toolbar_base.add (toolbar_hbox);
2738 toolbar_frame.set_shadow_type (SHADOW_OUT);
2739 toolbar_frame.set_name ("BaseFrame");
2740 toolbar_frame.add (toolbar_base);
2744 Editor::_autoscroll_canvas (void *arg)
2746 return ((Editor *) arg)->autoscroll_canvas ();
2750 Editor::autoscroll_canvas ()
2752 jack_nframes_t new_frame;
2753 bool keep_calling = true;
2755 if (autoscroll_direction < 0) {
2756 if (leftmost_frame < autoscroll_distance) {
2759 new_frame = leftmost_frame - autoscroll_distance;
2762 if (leftmost_frame > max_frames - autoscroll_distance) {
2763 new_frame = max_frames;
2765 new_frame = leftmost_frame + autoscroll_distance;
2769 if (new_frame != leftmost_frame) {
2770 reposition_x_origin (new_frame);
2773 if (new_frame == 0 || new_frame == max_frames) {
2780 if (autoscroll_cnt == 1) {
2782 /* connect the timeout so that we get called repeatedly */
2784 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
2785 keep_calling = false;
2787 } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
2789 /* after about a while, speed up a bit by changing the timeout interval */
2791 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
2792 keep_calling = false;
2794 } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
2796 /* after about another while, speed up some more */
2798 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
2799 keep_calling = false;
2801 } else if (autoscroll_cnt >= 30) {
2803 /* we've been scrolling for a while ... crank it up */
2805 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
2808 return keep_calling;
2812 Editor::start_canvas_autoscroll (int dir)
2818 stop_canvas_autoscroll ();
2820 autoscroll_direction = dir;
2821 autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
2824 /* do it right now, which will start the repeated callbacks */
2826 autoscroll_canvas ();
2830 Editor::stop_canvas_autoscroll ()
2832 if (autoscroll_timeout_tag >= 0) {
2833 gtk_timeout_remove (autoscroll_timeout_tag);
2834 autoscroll_timeout_tag = -1;
2839 Editor::convert_drop_to_paths (vector<string>& paths,
2840 const RefPtr<Gdk::DragContext>& context,
2843 const SelectionData& data,
2852 vector<ustring> uris = data.get_uris();
2856 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2857 are actually URI lists. So do it by hand.
2860 if (data.get_target() != "text/plain") {
2864 /* Parse the "uri-list" format that Nautilus provides,
2865 where each pathname is delimited by \r\n
2868 const char* p = data.get_text().c_str();
2875 while (g_ascii_isspace (*p))
2879 while (*q && (*q != '\n') && (*q != '\r'))
2885 while (q > p && g_ascii_isspace (*q))
2890 uris.push_back (ustring (p, q - p + 1));
2894 p = strchr (p, '\n');
2904 for (vector<ustring>::iterator i = uris.begin(); i != uris.end(); ++i) {
2905 if ((*i).substr (0,7) == "file://") {
2908 paths.push_back (p.substr (7));
2916 Editor::new_tempo_section ()
2922 Editor::map_transport_state ()
2924 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2926 if (session->transport_stopped()) {
2927 have_pending_keyboard_selection = false;
2933 Editor::State::State ()
2935 selection = new Selection;
2938 Editor::State::~State ()
2944 Editor::get_memento () const
2946 State *state = new State;
2948 store_state (*state);
2949 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2953 Editor::store_state (State& state) const
2955 *state.selection = *selection;
2959 Editor::restore_state (State *state)
2961 if (*selection == *state->selection) {
2965 *selection = *state->selection;
2966 time_selection_changed ();
2967 cerr << "RS: RSC\n";
2968 region_selection_changed ();
2970 /* XXX other selection change handlers? */
2974 Editor::begin_reversible_command (string name)
2977 UndoAction ua = get_memento();
2978 session->begin_reversible_command (name, &ua);
2983 Editor::commit_reversible_command ()
2986 UndoAction ua = get_memento();
2987 session->commit_reversible_command (&ua);
2992 Editor::set_selected_track_from_click (Selection::Operation op, bool with_undo, bool no_remove)
2994 if (!clicked_trackview) {
2999 begin_reversible_command (_("set selected trackview"));
3003 case Selection::Toggle:
3004 if (selection->selected (clicked_trackview)) {
3006 selection->remove (clicked_trackview);
3009 selection->toggle (clicked_trackview);
3012 case Selection::Set:
3013 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
3014 /* no commit necessary */
3018 selection->set (clicked_trackview);
3021 case Selection::Extend:
3022 /* not defined yet */
3027 commit_reversible_command ();
3032 Editor::set_selected_control_point_from_click (Selection::Operation op, bool with_undo, bool no_remove)
3034 if (!clicked_control_point) {
3039 begin_reversible_command (_("set selected control point"));
3043 case Selection::Set:
3045 case Selection::Toggle:
3047 case Selection::Extend:
3051 commit_reversible_command ();
3056 Editor::mapover_audio_tracks (slot<void,AudioTimeAxisView&,uint32_t> sl)
3058 set<AudioTimeAxisView*> relevant_tracks;
3060 /* step one: get all selected tracks and all tracks in the relevant edit groups */
3062 for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) {
3064 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*ti);
3070 RouteGroup* group = atv->route().edit_group();
3072 if (group && group->is_active()) {
3074 /* active group for this track, loop over all tracks and get every member of the group */
3076 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3078 AudioTimeAxisView* tatv;
3080 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3082 if (tatv->route().edit_group() == group) {
3083 relevant_tracks.insert (tatv);
3090 /* no active group, or no group */
3092 relevant_tracks.insert (atv);
3097 /* step two: apply operation to each track */
3099 uint32_t sz = relevant_tracks.size();
3101 for (set<AudioTimeAxisView*>::iterator ati = relevant_tracks.begin(); ati != relevant_tracks.end(); ++ati) {
3107 Editor::mapped_set_selected_regionview_from_click (AudioTimeAxisView& atv, uint32_t ignored,
3108 AudioRegionView* basis, vector<AudioRegionView*>* all_equivs)
3111 vector<AudioRegion*> results;
3112 AudioRegionView* marv;
3115 if ((ds = atv.get_diskstream()) == 0) {
3120 if ((pl = ds->playlist()) != 0) {
3121 pl->get_equivalent_regions (basis->region, results);
3124 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3125 if ((marv = atv.view->find_view (**ir)) != 0) {
3126 all_equivs->push_back (marv);
3132 Editor::set_selected_regionview_from_click (Selection::Operation op, bool no_track_remove)
3134 cerr << "In SSRfC\n";
3136 vector<AudioRegionView*> all_equivalent_regions;
3138 if (!clicked_regionview) {
3142 mapover_audio_tracks (bind (mem_fun (*this, &Editor::mapped_set_selected_regionview_from_click),
3143 clicked_regionview, &all_equivalent_regions));
3146 cerr << "mapover done\n";
3148 begin_reversible_command (_("set selected regionview"));
3151 case Selection::Toggle:
3152 selection->toggle (clicked_regionview);
3154 if (clicked_regionview->get_selected()) {
3155 if (/* group && group->is_active() && */ selection->audio_regions.size() > 1) {
3156 /* reduce selection down to just the one clicked */
3157 selection->set (clicked_regionview);
3159 selection->remove (clicked_regionview);
3162 selection->add (all_equivalent_regions);
3165 set_selected_track_from_click (op, false, no_track_remove);
3168 case Selection::Set:
3169 // karsten wiese suggested these two lines to make
3170 // a selected region rise to the top. but this
3171 // leads to a mismatch between actual layering
3172 // and visual layering. resolution required ....
3174 // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3175 // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3177 if (clicked_regionview->get_selected()) {
3178 /* no commit necessary: we are the one selected. */
3183 selection->set (all_equivalent_regions);
3184 set_selected_track_from_click (op, false, false);
3188 case Selection::Extend:
3189 /* not defined yet */
3192 cerr << "case done\n";
3194 commit_reversible_command () ;
3198 Editor::set_selected_regionview_from_region_list (Region& r, Selection::Operation op)
3200 vector<AudioRegionView*> all_equivalent_regions;
3201 AudioRegion* region;
3203 if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3207 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3209 AudioTimeAxisView* tatv;
3211 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3214 vector<AudioRegion*> results;
3215 AudioRegionView* marv;
3218 if ((ds = tatv->get_diskstream()) == 0) {
3223 if ((pl = ds->playlist()) != 0) {
3224 pl->get_region_list_equivalent_regions (*region, results);
3227 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3228 if ((marv = tatv->view->find_view (**ir)) != 0) {
3229 all_equivalent_regions.push_back (marv);
3236 begin_reversible_command (_("set selected regions"));
3239 case Selection::Toggle:
3240 /* XXX this is not correct */
3241 selection->add (all_equivalent_regions);
3243 case Selection::Set:
3244 selection->set (all_equivalent_regions);
3246 case Selection::Extend:
3247 /* not defined yet */
3251 commit_reversible_command () ;
3255 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3257 AudioRegionView* rv;
3260 if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3264 if ((rv = sv->find_view (*ar)) == 0) {
3268 /* don't reset the selection if its something other than
3269 a single other region.
3272 if (selection->audio_regions.size() > 1) {
3276 begin_reversible_command (_("set selected regions"));
3278 selection->set (rv);
3280 commit_reversible_command () ;
3286 Editor::set_edit_group_solo (Route& route, bool yn)
3288 RouteGroup *edit_group;
3290 if ((edit_group = route.edit_group()) != 0) {
3291 edit_group->apply (&Route::set_solo, yn, this);
3293 route.set_solo (yn, this);
3298 Editor::set_edit_group_mute (Route& route, bool yn)
3300 RouteGroup *edit_group = 0;
3302 if ((edit_group == route.edit_group()) != 0) {
3303 edit_group->apply (&Route::set_mute, yn, this);
3305 route.set_mute (yn, this);
3310 Editor::set_edit_menu (Menu& menu)
3313 edit_menu->signal_map_event().connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3317 Editor::edit_menu_map_handler (GdkEventAny* ev)
3319 using namespace Menu_Helpers;
3320 MenuList& edit_items = edit_menu->items();
3323 /* Nuke all the old items */
3325 edit_items.clear ();
3331 if (session->undo_depth() == 0) {
3334 label = string_compose(_("Undo (%1)"), session->next_undo());
3337 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3339 if (session->undo_depth() == 0) {
3340 edit_items.back().set_sensitive (false);
3343 if (session->redo_depth() == 0) {
3346 label = string_compose(_("Redo (%1)"), session->next_redo());
3349 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3350 if (session->redo_depth() == 0) {
3351 edit_items.back().set_sensitive (false);
3354 vector<MenuItem*> mitems;
3356 edit_items.push_back (SeparatorElem());
3357 edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3358 mitems.push_back (&edit_items.back());
3359 edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3360 mitems.push_back (&edit_items.back());
3361 edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3362 mitems.push_back (&edit_items.back());
3363 edit_items.push_back (SeparatorElem());
3364 edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3365 mitems.push_back (&edit_items.back());
3366 edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3367 mitems.push_back (&edit_items.back());
3368 edit_items.push_back (SeparatorElem());
3370 if (selection->empty()) {
3371 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3372 (*i)->set_sensitive (false);
3376 Menu* import_menu = manage (new Menu());
3377 import_menu->set_name ("ArdourContextMenu");
3378 MenuList& import_items = import_menu->items();
3380 import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3381 import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3383 Menu* embed_menu = manage (new Menu());
3384 embed_menu->set_name ("ArdourContextMenu");
3385 MenuList& embed_items = embed_menu->items();
3387 embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3388 embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3390 edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3391 edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3392 edit_items.push_back (SeparatorElem());
3394 edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3395 if (!session->have_captured()) {
3396 edit_items.back().set_sensitive (false);
3403 Editor::duplicate_dialog (bool dup_region)
3406 if (clicked_regionview == 0) {
3410 if (selection->time.length() == 0) {
3415 ArdourDialog win ("duplicate dialog");
3417 Label label (_("Duplicate how many times?"));
3419 win.get_vbox()->pack_start (label);
3420 win.add_action_widget (entry, RESPONSE_ACCEPT);
3421 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3422 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3424 win.set_position (WIN_POS_MOUSE);
3426 entry.set_text ("1");
3427 set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
3428 entry.select_region (0, entry.get_text_length());
3429 entry.grab_focus ();
3432 switch (win.run ()) {
3433 case RESPONSE_ACCEPT:
3439 string text = entry.get_text();
3442 if (sscanf (text.c_str(), "%f", ×) == 1) {
3444 AudioRegionSelection regions;
3445 regions.add (clicked_regionview);
3446 duplicate_some_regions (regions, times);
3448 duplicate_selection (times);
3454 Editor::show_verbose_canvas_cursor ()
3456 verbose_canvas_cursor->raise_to_top();
3457 verbose_canvas_cursor->show();
3458 verbose_cursor_visible = true;
3462 Editor::hide_verbose_canvas_cursor ()
3464 verbose_canvas_cursor->hide();
3465 verbose_cursor_visible = false;
3469 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3471 /* XXX get origin of canvas relative to root window,
3472 add x and y and check compared to gdk_screen_{width,height}
3474 verbose_canvas_cursor->property_text() = txt.c_str();
3475 verbose_canvas_cursor->property_x() = x;
3476 verbose_canvas_cursor->property_y() = y;
3480 Editor::set_verbose_canvas_cursor_text (const string & txt)
3482 verbose_canvas_cursor->property_text() = txt.c_str();
3486 Editor::edit_mode_selection_done ()
3492 string choice = edit_mode_selector.get_active_text();
3493 EditMode mode = Slide;
3495 if (choice == _("Splice")) {
3497 } else if (choice == _("Slide")) {
3501 session->set_edit_mode (mode);
3505 Editor::snap_type_selection_done ()
3511 string choice = snap_type_selector.get_active_text();
3512 SnapType snaptype = SnapToFrame;
3514 if (choice == _("Beats/3")) {
3515 snaptype = SnapToAThirdBeat;
3516 } else if (choice == _("Beats/4")) {
3517 snaptype = SnapToAQuarterBeat;
3518 } else if (choice == _("Beats/8")) {
3519 snaptype = SnapToAEighthBeat;
3520 } else if (choice == _("Beats/16")) {
3521 snaptype = SnapToASixteenthBeat;
3522 } else if (choice == _("Beats/32")) {
3523 snaptype = SnapToAThirtysecondBeat;
3524 } else if (choice == _("Beats")) {
3525 snaptype = SnapToBeat;
3526 } else if (choice == _("Bars")) {
3527 snaptype = SnapToBar;
3528 } else if (choice == _("Marks")) {
3529 snaptype = SnapToMark;
3530 } else if (choice == _("Edit Cursor")) {
3531 snaptype = SnapToEditCursor;
3532 } else if (choice == _("Region starts")) {
3533 snaptype = SnapToRegionStart;
3534 } else if (choice == _("Region ends")) {
3535 snaptype = SnapToRegionEnd;
3536 } else if (choice == _("Region bounds")) {
3537 snaptype = SnapToRegionBoundary;
3538 } else if (choice == _("Region syncs")) {
3539 snaptype = SnapToRegionSync;
3540 } else if (choice == _("CD Frames")) {
3541 snaptype = SnapToCDFrame;
3542 } else if (choice == _("SMPTE Frames")) {
3543 snaptype = SnapToSMPTEFrame;
3544 } else if (choice == _("SMPTE Seconds")) {
3545 snaptype = SnapToSMPTESeconds;
3546 } else if (choice == _("SMPTE Minutes")) {
3547 snaptype = SnapToSMPTEMinutes;
3548 } else if (choice == _("Seconds")) {
3549 snaptype = SnapToSeconds;
3550 } else if (choice == _("Minutes")) {
3551 snaptype = SnapToMinutes;
3552 } else if (choice == _("None")) {
3553 snaptype = SnapToFrame;
3556 set_snap_to (snaptype);
3560 Editor::snap_mode_selection_done ()
3566 string choice = snap_mode_selector.get_active_text();
3567 SnapMode mode = SnapNormal;
3569 if (choice == _("Normal")) {
3571 } else if (choice == _("Magnetic")) {
3572 mode = SnapMagnetic;
3575 set_snap_mode (mode);
3579 Editor::zoom_focus_selection_done ()
3585 string choice = zoom_focus_selector.get_active_text();
3586 ZoomFocus focus_type = ZoomFocusLeft;
3588 if (choice == _("Left")) {
3589 focus_type = ZoomFocusLeft;
3590 } else if (choice == _("Right")) {
3591 focus_type = ZoomFocusRight;
3592 } else if (choice == _("Center")) {
3593 focus_type = ZoomFocusCenter;
3594 } else if (choice == _("Playhead")) {
3595 focus_type = ZoomFocusPlayhead;
3596 } else if (choice == _("Edit Cursor")) {
3597 focus_type = ZoomFocusEdit;
3600 set_zoom_focus (focus_type);
3604 Editor::edit_controls_button_release (GdkEventButton* ev)
3606 if (Keyboard::is_context_menu_event (ev)) {
3607 ARDOUR_UI::instance()->add_route ();
3613 Editor::track_selection_changed ()
3615 switch (selection->tracks.size()){
3619 set_selected_mixer_strip (*(selection->tracks.front()));
3623 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3624 (*i)->set_selected (false);
3625 if (mouse_mode == MouseRange) {
3626 (*i)->hide_selection ();
3630 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3631 (*i)->set_selected (true);
3632 if (mouse_mode == MouseRange) {
3633 (*i)->show_selection (selection->time);
3639 Editor::time_selection_changed ()
3641 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3642 (*i)->hide_selection ();
3645 if (selection->tracks.empty()) {
3646 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3647 (*i)->show_selection (selection->time);
3650 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3651 (*i)->show_selection (selection->time);
3655 if (selection->time.empty()) {
3656 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
3658 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
3663 Editor::region_selection_changed ()
3665 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3666 (*i)->set_selected_regionviews (selection->audio_regions);
3671 Editor::point_selection_changed ()
3673 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3674 (*i)->set_selected_points (selection->points);
3679 Editor::mouse_select_button_release (GdkEventButton* ev)
3681 /* this handles just right-clicks */
3683 if (ev->button != 3) {
3690 Editor::TrackViewList *
3691 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3694 TrackViewList::iterator i;
3696 v = new TrackViewList;
3698 if (track == 0 && group == 0) {
3702 for (i = track_views.begin(); i != track_views.end (); ++i) {
3706 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3708 /* just the view for this track
3711 v->push_back (track);
3715 /* views for all tracks in the edit group */
3717 for (i = track_views.begin(); i != track_views.end (); ++i) {
3719 if (group == 0 || (*i)->edit_group() == group) {
3729 Editor::set_zoom_focus (ZoomFocus f)
3731 if (zoom_focus != f) {
3733 vector<string> txt = internationalize (zoom_focus_strings);
3734 zoom_focus_selector.set_active_text (txt[(int)f]);
3735 ZoomFocusChanged (); /* EMIT_SIGNAL */
3742 Editor::ensure_float (Window& win)
3744 win.set_transient_for (*this);
3748 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3750 /* recover or initialize pane positions. do this here rather than earlier because
3751 we don't want the positions to change the child allocations, which they seem to do.
3757 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3759 static int32_t done;
3762 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3763 width = default_width;
3764 height = default_height;
3766 width = atoi(geometry->property("x_size")->value());
3767 height = atoi(geometry->property("y_size")->value());
3770 if (which == static_cast<Paned*> (&edit_pane)) {
3776 if (!geometry || (prop = geometry->property ("edit_pane_pos")) == 0) {
3777 /* initial allocation is 90% to canvas, 10% to notebook */
3778 pos = (int) floor (alloc.get_width() * 0.90f);
3779 snprintf (buf, sizeof(buf), "%d", pos);
3781 pos = atoi (prop->value());
3784 if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
3785 edit_pane.set_position (pos);
3786 pre_maximal_pane_position = pos;
3792 Editor::detach_tearoff (Box* b, Window* w)
3794 if (tools_tearoff->torn_off() &&
3795 mouse_mode_tearoff->torn_off()) {
3796 top_hbox.remove (toolbar_frame);
3801 Editor::reattach_tearoff (Box* b, Window* w, int32_t n)
3803 if (toolbar_frame.get_parent() == 0) {
3804 top_hbox.pack_end (toolbar_frame);
3809 Editor::set_show_measures (bool yn)
3811 if (_show_measures != yn) {
3814 if ((_show_measures = yn) == true) {
3817 DisplayControlChanged (ShowMeasures);
3823 Editor::toggle_follow_playhead ()
3825 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleFollowPlayhead"));
3827 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3828 set_follow_playhead (tact->get_active());
3833 Editor::set_follow_playhead (bool yn)
3835 if (_follow_playhead != yn) {
3836 if ((_follow_playhead = yn) == true) {
3838 update_current_screen ();
3840 DisplayControlChanged (FollowPlayhead);
3846 Editor::toggle_xfade_active (Crossfade* xfade)
3848 xfade->set_active (!xfade->active());
3852 Editor::toggle_xfade_length (Crossfade* xfade)
3854 xfade->set_follow_overlap (!xfade->following_overlap());
3858 Editor::edit_xfade (Crossfade* xfade)
3860 CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
3864 switch (cew.run ()) {
3865 case RESPONSE_ACCEPT:
3872 xfade->StateChanged (Change (~0));
3876 Editor::playlist_selector () const
3878 return *_playlist_selector;
3882 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
3886 ret = nudge_clock.current_duration (pos);
3887 next = ret + 1; /* XXXX fix me */
3893 Editor::end_location_changed (Location* location)
3895 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3896 horizontal_adjustment.set_upper (location->end() / frames_per_unit);
3900 Editor::playlist_deletion_dialog (Playlist* pl)
3902 ArdourDialog dialog ("playlist deletion dialog");
3903 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3904 "If left alone, no audio files used by it will be cleaned.\n"
3905 "If deleted, audio files used by it alone by will cleaned."),
3908 dialog.set_position (WIN_POS_CENTER);
3909 dialog.get_vbox()->pack_start (label);
3911 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3912 dialog.add_button (_("Keep playlist"), RESPONSE_CANCEL);
3913 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3915 switch (dialog.run ()) {
3916 case RESPONSE_ACCEPT:
3917 /* delete the playlist */
3921 case RESPONSE_REJECT:
3922 /* keep the playlist */
3934 Editor::audio_region_selection_covers (jack_nframes_t where)
3936 for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
3937 if ((*a)->region.covers (where)) {
3946 Editor::prepare_for_cleanup ()
3948 cut_buffer->clear_audio_regions ();
3949 cut_buffer->clear_playlists ();
3951 selection->clear_audio_regions ();
3952 selection->clear_playlists ();
3956 Editor::transport_loop_location()
3959 return session->locations()->auto_loop_location();
3966 Editor::transport_punch_location()
3969 return session->locations()->auto_punch_location();
3976 Editor::control_layout_scroll (GdkEventScroll* ev)
3978 switch (ev->direction) {
3980 scroll_tracks_up_line ();
3984 case GDK_SCROLL_DOWN:
3985 scroll_tracks_down_line ();
3989 /* no left/right handling yet */
3997 Editor::snapshot_display_selection_changed ()
3999 if (snapshot_display.get_selection()->count_selected_rows() > 0) {
4001 TreeModel::iterator i = snapshot_display.get_selection()->get_selected();
4003 Glib::ustring snap_name = (*i)[snapshot_display_columns.real_name];
4005 if (snap_name.length() == 0) {
4009 if (session->snap_name() == snap_name) {
4013 ARDOUR_UI::instance()->load_session(session->path(), string (snap_name));
4018 Editor::snapshot_display_button_press (GdkEventButton* ev)
4024 Editor::redisplay_snapshots ()
4030 vector<string*>* states;
4032 if ((states = session->possible_states()) == 0) {
4036 snapshot_display_model->clear ();
4038 for (vector<string*>::iterator i = states->begin(); i != states->end(); ++i) {
4039 string statename = *(*i);
4040 TreeModel::Row row = *(snapshot_display_model->append());
4041 row[snapshot_display_columns.visible_name] = statename;
4042 row[snapshot_display_columns.real_name] = statename;
4049 Editor::session_state_saved (string snap_name)
4051 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::session_state_saved), snap_name));
4052 redisplay_snapshots ();
4056 Editor::maximise_editing_space ()
4058 mouse_mode_tearoff->set_visible (false);
4059 tools_tearoff->set_visible (false);
4061 pre_maximal_pane_position = edit_pane.get_position();
4062 edit_pane.set_position (edit_pane.get_width());
4068 Editor::restore_editing_space ()
4070 mouse_mode_tearoff->set_visible (true);
4071 tools_tearoff->set_visible (true);
4072 edit_pane.set_position (pre_maximal_pane_position);
4078 Editor::new_playlists ()
4080 begin_reversible_command (_("new playlists"));
4081 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_new_playlist));
4082 commit_reversible_command ();
4086 Editor::copy_playlists ()
4088 begin_reversible_command (_("copy playlists"));
4089 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_use_copy_playlist));
4090 commit_reversible_command ();
4094 Editor::clear_playlists ()
4096 begin_reversible_command (_("clear playlists"));
4097 mapover_audio_tracks (mem_fun (*this, &Editor::mapped_clear_playlist));
4098 commit_reversible_command ();
4102 Editor::mapped_use_new_playlist (AudioTimeAxisView& atv, uint32_t sz)
4104 atv.use_new_playlist (sz > 1 ? false : true);
4108 Editor::mapped_use_copy_playlist (AudioTimeAxisView& atv, uint32_t sz)
4110 atv.use_copy_playlist (sz > 1 ? false : true);
4114 Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz)
4116 atv.clear_playlist ();