2 Copyright (C) 2000 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"
51 #include "check_mark.h"
53 #include "grouped_buttons.h"
56 #include "playlist_selector.h"
57 #include "regionview.h"
58 #include "rgb_macros.h"
59 #include "selection.h"
60 #include "streamview.h"
61 #include "time_axis_view.h"
63 #include "crossfade_view.h"
65 #include "public_editor.h"
66 #include "crossfade_edit.h"
67 #include "audio_time_axis.h"
68 #include "canvas_impl.h"
70 #include "gui_thread.h"
75 #include "imageframe_socket_handler.h"
76 /* </CMT Additions> */
80 using namespace ARDOUR;
83 using namespace Gtkmm2ext;
84 using namespace Editing;
86 const double Editor::timebar_height = 15.0;
88 #include "editor_xpms"
90 static const int32_t slide_index = 0;
91 static const int32_t splice_index = 1;
93 static const gchar *edit_mode_strings[] = {
99 static const gchar *snap_type_strings[] = {
123 static const gchar *snap_mode_strings[] = {
129 static const gchar *zoom_focus_strings[] = {
138 /* Soundfile drag-n-drop */
140 Gdk::Cursor* Editor::cross_hair_cursor = 0;
141 Gdk::Cursor* Editor::selector_cursor = 0;
142 Gdk::Cursor* Editor::trimmer_cursor = 0;
143 Gdk::Cursor* Editor::grabber_cursor = 0;
144 Gdk::Cursor* Editor::zoom_cursor = 0;
145 Gdk::Cursor* Editor::time_fx_cursor = 0;
146 Gdk::Cursor* Editor::fader_cursor = 0;
147 Gdk::Cursor* Editor::speaker_cursor = 0;
148 Gdk::Cursor* Editor::null_cursor = 0;
149 Gdk::Cursor* Editor::wait_cursor = 0;
150 Gdk::Cursor* Editor::timebar_cursor = 0;
152 GdkPixmap *Editor::check_pixmap = 0;
153 GdkBitmap *Editor::check_mask = 0;
154 GdkPixmap *Editor::empty_pixmap = 0;
155 GdkBitmap *Editor::empty_mask = 0;
157 Editor::Editor (AudioEngine& eng)
160 /* time display buttons */
162 minsec_label (_("Mins:Secs")),
163 bbt_label (_("Bars:Beats")),
164 smpte_label (_("SMPTE")),
165 frame_label (_("Frames")),
166 tempo_label (_("Tempo")),
167 meter_label (_("Meter")),
168 mark_label (_("Location Markers")),
169 range_mark_label (_("Range Markers")),
170 transport_mark_label (_("Loop/Punch Ranges")),
172 edit_packer (3, 3, false),
173 edit_hscroll_left_arrow (Gtk::ARROW_LEFT, Gtk::SHADOW_OUT),
174 edit_hscroll_right_arrow (Gtk::ARROW_RIGHT, Gtk::SHADOW_OUT),
176 /* tool bar related */
178 editor_mixer_button (_("editor\nmixer")),
180 selection_start_clock (X_("SelectionStartClock"), true),
181 selection_end_clock (X_("SelectionEndClock"), true),
182 edit_cursor_clock (X_("EditCursorClock"), true),
183 zoom_range_clock (X_("ZoomRangeClock"), true, true),
185 toolbar_selection_clock_table (2,3),
187 mouse_mode_button_table (2, 3),
189 mouse_select_button (_("range")),
190 mouse_move_button (_("object")),
191 mouse_gain_button (_("gain")),
192 mouse_zoom_button (_("zoom")),
193 mouse_timefx_button (_("timefx")),
194 mouse_audition_button (_("listen")),
196 automation_mode_button (_("mode")),
197 global_automation_button (_("automation")),
199 edit_mode_label (_("Edit Mode")),
200 snap_type_label (_("Snap To")),
201 snap_mode_label(_("Snap Mode")),
202 zoom_focus_label (_("Zoom Focus")),
204 /* <CMT Additions> */
205 image_socket_listener(0),
206 /* </CMT Additions> */
210 nudge_label (_("Nudge")),
211 nudge_clock (X_("NudgeClock"), true, true)
216 /* we are a singleton */
218 PublicEditor::_instance = this;
222 check_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
223 gtk_widget_get_colormap (GTK_WIDGET(edit_group_list.gobj())),
224 &check_mask, NULL, (gchar **) check_xpm);
225 empty_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
226 gtk_widget_get_colormap (GTK_WIDGET(edit_group_list.gobj())),
227 &empty_mask, NULL, (gchar **) empty_xpm);
231 selection = new Selection;
232 cut_buffer = new Selection;
234 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
235 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
236 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
237 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
239 clicked_regionview = 0;
240 clicked_trackview = 0;
241 clicked_audio_trackview = 0;
242 clicked_crossfadeview = 0;
243 clicked_control_point = 0;
244 latest_regionview = 0;
245 last_update_frame = 0;
247 last_audition_region = 0;
248 current_mixer_strip = 0;
249 current_bbt_points = 0;
251 snap_type = SnapToFrame;
252 set_snap_to (snap_type);
253 snap_mode = SnapNormal;
254 set_snap_mode (snap_mode);
255 snap_threshold = 5.0;
256 bbt_beat_subdivision = 4;
259 autoscroll_timeout_tag = -1;
260 interthread_progress_window = 0;
261 current_interthread_info = 0;
262 _show_measures = true;
263 _show_waveforms = true;
264 _show_waveforms_recording = true;
265 first_action_message = 0;
267 show_gain_after_trim = false;
268 no_zoom_repos_update = false;
269 ignore_route_list_reorder = false;
270 verbose_cursor_on = true;
271 route_removal = false;
273 show_automatic_regions_in_region_list = true;
274 have_pending_keyboard_selection = false;
275 _follow_playhead = true;
276 _xfade_visibility = true;
277 editor_ruler_menu = 0;
278 no_ruler_shown_update = false;
279 edit_group_list_menu = 0;
281 region_list_menu = 0;
283 marker_menu_item = 0;
285 transport_marker_menu = 0;
286 new_transport_marker_menu = 0;
287 editor_mixer_strip_width = Wide;
288 repos_zoom_queued = false;
289 import_audio_item = 0;
290 embed_audio_item = 0;
291 region_edit_menu_split_item = 0;
293 region_edit_menu_split_multichannel_item = 0;
294 edit_hscroll_dragging = false;
296 ignore_mouse_mode_toggle = false;
297 current_stepping_trackview = 0;
299 entered_regionview = 0;
300 clear_entered_track = false;
301 _new_regionviews_show_envelope = false;
302 current_timestretch = 0;
307 location_marker_color = color_map[cLocationMarker];
308 location_range_color = color_map[cLocationRange];
309 location_cd_marker_color = color_map[cLocationCDMarker];
310 location_loop_color = color_map[cLocationLoop];
311 location_punch_color = color_map[cLocationPunch];
313 range_marker_drag_rect = 0;
314 marker_drag_line = 0;
316 mouse_mode = MouseZoom; /* force change in next call */
317 set_mouse_mode (MouseObject, true);
319 frames_per_unit = 2048; /* too early to use set_frames_per_unit */
320 zoom_focus = ZoomFocusLeft;
321 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
323 initialize_rulers ();
324 initialize_canvas ();
326 track_canvas_scroller.add (track_canvas);
327 track_canvas_scroller.set_policy (POLICY_NEVER, POLICY_NEVER);
328 track_canvas_scroller.set_name ("TrackCanvasScroller");
330 track_canvas_scroller.get_vadjustment()->signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
331 track_canvas_scroller.get_vadjustment()->set_step_increment (10.0);
333 track_canvas_scroller.get_hadjustment()->set_lower (0.0);
334 track_canvas_scroller.get_hadjustment()->set_upper (1200.0);
335 track_canvas_scroller.get_hadjustment()->set_step_increment (20.0);
336 track_canvas_scroller.get_hadjustment()->signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
338 edit_vscrollbar.set_adjustment(*track_canvas_scroller.get_vadjustment());
339 edit_hscrollbar.set_adjustment(*track_canvas_scroller.get_hadjustment());
341 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_press));
342 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_release));
343 edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscroll_slider_allocate));
345 time_canvas_scroller.add (time_canvas);
346 time_canvas_scroller.set_policy (POLICY_NEVER, POLICY_NEVER);
347 time_canvas_scroller.set_hadjustment (*track_canvas_scroller.get_hadjustment());
348 time_canvas_scroller.set_name ("TimeCanvasScroller");
350 track_canvas_scroller.signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
351 time_canvas_scroller.signal_map_event().connect (mem_fun (*this, &Editor::time_canvas_map_handler));
353 edit_controls_vbox.set_spacing (track_spacing);
354 edit_controls_hbox.pack_start (edit_controls_vbox, true, true);
355 edit_controls_scroller.add (edit_controls_hbox);
356 edit_controls_scroller.set_name ("EditControlsBase");
357 edit_controls_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
359 Viewport* viewport = static_cast<Viewport*> (edit_controls_scroller.get_child());
361 viewport->set_shadow_type (Gtk::SHADOW_NONE);
362 viewport->set_name ("EditControlsBase");
363 viewport->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
364 viewport->signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
369 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
371 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
372 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
373 time_canvas_vbox.pack_start (*frames_ruler, false, false);
374 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
375 time_canvas_vbox.pack_start (time_canvas_scroller, true, true);
376 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars));
378 bbt_label.set_name ("EditorTimeButton");
379 bbt_label.set_size_request (-1, (int)timebar_height);
380 bbt_label.set_alignment (1.0, 0.5);
381 bbt_label.set_padding (5,0);
382 minsec_label.set_name ("EditorTimeButton");
383 minsec_label.set_size_request (-1, (int)timebar_height);
384 minsec_label.set_alignment (1.0, 0.5);
385 minsec_label.set_padding (5,0);
386 smpte_label.set_name ("EditorTimeButton");
387 smpte_label.set_size_request (-1, (int)timebar_height);
388 smpte_label.set_alignment (1.0, 0.5);
389 smpte_label.set_padding (5,0);
390 frame_label.set_name ("EditorTimeButton");
391 frame_label.set_size_request (-1, (int)timebar_height);
392 frame_label.set_alignment (1.0, 0.5);
393 frame_label.set_padding (5,0);
394 tempo_label.set_name ("EditorTimeButton");
395 tempo_label.set_size_request (-1, (int)timebar_height);
396 tempo_label.set_alignment (1.0, 0.5);
397 tempo_label.set_padding (5,0);
398 meter_label.set_name ("EditorTimeButton");
399 meter_label.set_size_request (-1, (int)timebar_height);
400 meter_label.set_alignment (1.0, 0.5);
401 meter_label.set_padding (5,0);
402 mark_label.set_name ("EditorTimeButton");
403 mark_label.set_size_request (-1, (int)timebar_height);
404 mark_label.set_alignment (1.0, 0.5);
405 mark_label.set_padding (5,0);
406 range_mark_label.set_name ("EditorTimeButton");
407 range_mark_label.set_size_request (-1, (int)timebar_height);
408 range_mark_label.set_alignment (1.0, 0.5);
409 range_mark_label.set_padding (5,0);
410 transport_mark_label.set_name ("EditorTimeButton");
411 transport_mark_label.set_size_request (-1, (int)timebar_height);
412 transport_mark_label.set_alignment (1.0, 0.5);
413 transport_mark_label.set_padding (5,0);
415 time_button_vbox.pack_start (minsec_label, false, false);
416 time_button_vbox.pack_start (smpte_label, false, false);
417 time_button_vbox.pack_start (frame_label, false, false);
418 time_button_vbox.pack_start (bbt_label, false, false);
419 time_button_vbox.pack_start (meter_label, false, false);
420 time_button_vbox.pack_start (tempo_label, false, false);
421 time_button_vbox.pack_start (mark_label, false, false);
423 time_button_event_box.add (time_button_vbox);
425 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
426 time_button_event_box.set_name ("TimebarLabelBase");
427 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
429 /* these enable us to have a dedicated window (for cursor setting, etc.)
430 for the canvas areas.
433 track_canvas_event_box.add (track_canvas_scroller);
435 time_canvas_event_box.add (time_canvas_vbox);
436 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
439 edit_packer.set_col_spacings (0);
440 edit_packer.set_row_spacings (0);
441 edit_packer.set_homogeneous (false);
442 edit_packer.set_name ("EditorWindow");
444 edit_packer.attach (edit_hscrollbar, 1, 2, 0, 1, FILL|EXPAND, FILL, 0, 0);
446 edit_packer.attach (time_button_event_box, 0, 1, 1, 2, FILL, FILL, 0, 0);
447 edit_packer.attach (time_canvas_event_box, 1, 2, 1, 2, FILL|EXPAND, FILL, 0, 0);
449 edit_packer.attach (edit_controls_scroller, 0, 1, 2, 3, FILL,FILL, 0, 0);
450 edit_packer.attach (track_canvas_event_box, 1, 2, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
451 edit_packer.attach (edit_vscrollbar, 2, 3, 2, 3, FILL, FILL|EXPAND, 0, 0);
453 edit_frame.set_name ("BaseFrame");
454 edit_frame.set_shadow_type (SHADOW_IN);
455 edit_frame.add (edit_packer);
457 zoom_in_button.set_name ("EditorTimeButton");
458 zoom_out_button.set_name ("EditorTimeButton");
459 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in"));
460 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out"));
462 zoom_out_full_button.set_name ("EditorTimeButton");
463 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session"));
465 zoom_in_button.add (*(manage (new Gtk::Image (Stock::ZOOM_IN, ICON_SIZE_BUTTON))));
466 zoom_out_button.add (*(manage (new Gtk::Image (Stock::ZOOM_OUT, ICON_SIZE_BUTTON))));
467 zoom_out_full_button.add (*(manage (new Gtk::Image (Stock::ZOOM_FIT, ICON_SIZE_BUTTON))));
469 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
470 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
471 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
473 zoom_indicator_box.pack_start (zoom_out_button, false, false);
474 zoom_indicator_box.pack_start (zoom_in_button, false, false);
475 zoom_indicator_box.pack_start (zoom_range_clock, false, false);
476 zoom_indicator_box.pack_start (zoom_out_full_button, false, false);
478 zoom_indicator_label.set_text (_("Zoom Span"));
479 zoom_indicator_label.set_name ("ToolBarLabel");
481 zoom_indicator_vbox.set_spacing (3);
482 zoom_indicator_vbox.set_border_width (3);
483 zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false);
484 zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false);
486 bottom_hbox.set_border_width (3);
487 bottom_hbox.set_spacing (3);
489 route_display_model = ListStore::create(route_display_columns);
490 route_list.set_model (route_display_model);
491 route_list.append_column (_("Tracks"), route_display_columns.text);
492 route_list.set_name ("TrackListDisplay");
493 route_list.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
494 route_list.set_reorderable (true);
496 route_list.set_size_request (75,-1);
497 route_list.set_headers_visible (true);
498 route_list.set_headers_clickable (true);
501 // route_list.signal_rows_reordered().connect (mem_fun (*this, &Editor::queue_route_list_reordered));
504 // route_display_model->set_sort_func (0, mem_fun (*this, &Editor::route_list_compare_func));
507 //route_list.set_shadow_type (Gtk::SHADOW_IN);
509 route_list_scroller.add (route_list);
510 route_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
512 route_list.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::route_display_selection_changed));
513 route_list.signal_columns_changed().connect (mem_fun(*this, &Editor::route_list_column_click));
515 edit_group_list_button_label.set_text (_("Edit Groups"));
516 edit_group_list_button_label.set_name ("EditGroupTitleButton");
517 edit_group_list_button.add (edit_group_list_button_label);
518 edit_group_list_button.set_name ("EditGroupTitleButton");
520 group_model = ListStore::create(group_columns);
521 edit_group_list.set_model (group_model);
522 edit_group_list.append_column (_("active"), group_columns.is_active);
523 edit_group_list.append_column (_("groupname"), group_columns.text);
524 edit_group_list.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
525 edit_group_list.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
527 /* use checkbox for the active column */
529 CellRendererToggle *active_cell = dynamic_cast<CellRendererToggle*>(edit_group_list.get_column_cell_renderer (0));
530 active_cell->property_activatable() = true;
531 active_cell->property_radio() = false;
533 edit_group_list.set_name ("MixerGroupList");
534 //edit_group_list.set_shadow_type (Gtk::SHADOW_IN);
536 edit_group_list.columns_autosize ();
537 edit_group_list.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
538 edit_group_list.set_reorderable (false);
540 edit_group_list.set_size_request (75, -1);
541 edit_group_list.set_headers_visible (true);
543 edit_group_list_scroller.add (edit_group_list);
544 edit_group_list_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
546 edit_group_list_button.signal_clicked().connect (mem_fun(*this, &Editor::edit_group_list_button_clicked));
547 edit_group_list.signal_button_press_event().connect (mem_fun(*this, &Editor::edit_group_list_button_press_event));
548 edit_group_list.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::edit_group_selection_changed));
550 TreeModel::Row row = *(group_model->append());
551 row[group_columns.is_active] = false;
552 row[group_columns.text] = (_("-all-"));
553 edit_group_list.get_selection()->select (row);
554 /* GTK2FIX is set_data(0) setting the is_active to false here?
555 list<string> stupid_list;
557 stupid_list.push_back ("*");
558 stupid_list.push_back (_("-all-"));
560 edit_group_list.rows().push_back (stupid_list);
561 edit_group_list.rows().back().set_data (0);
562 edit_group_list.rows().back().select();
565 edit_group_vbox.pack_start (edit_group_list_button, false, false);
566 edit_group_vbox.pack_start (edit_group_list_scroller, true, true);
568 route_list_frame.set_name ("BaseFrame");
569 route_list_frame.set_shadow_type (Gtk::SHADOW_IN);
570 route_list_frame.add (route_list_scroller);
572 edit_group_list_frame.set_name ("BaseFrame");
573 edit_group_list_frame.set_shadow_type (Gtk::SHADOW_IN);
574 edit_group_list_frame.add (edit_group_vbox);
576 route_group_vpane.add1 (route_list_frame);
577 route_group_vpane.add2 (edit_group_list_frame);
579 list_vpacker.pack_start (route_group_vpane, true, true);
581 region_list_model = TreeStore::create (region_list_columns);
582 region_list_sort_model = TreeModelSort::create (region_list_model);
583 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
585 region_list_display.set_model (region_list_sort_model);
586 region_list_display.append_column (_("Regions"), region_list_columns.name);
587 region_list_display.set_reorderable (true);
588 region_list_display.set_size_request (100, -1);
589 region_list_display.set_data ("editor", this);
590 region_list_display.set_flags (Gtk::CAN_FOCUS);
591 region_list_display.set_name ("RegionListDisplay");
593 region_list_scroller.add (region_list_display);
594 region_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
596 list<Gtk::TargetEntry> region_list_target_table;
598 region_list_target_table.push_back (TargetEntry ("STRING"));
599 region_list_target_table.push_back (TargetEntry ("text/plain"));
600 region_list_target_table.push_back (TargetEntry ("text/uri-list"));
601 region_list_target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
604 // region_list_display.drag_dest_set (region_list_target_table, DEST_DEFAULT_ALL, GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
605 // region_list_display.signal_drag_data_received().connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
607 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
608 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
609 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press));
610 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
611 region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
613 //region_list_display.unselect_row.connect (mem_fun(*this, &Editor::region_list_display_unselected));
614 //region_list_display.signal_columns_changed().connect (mem_fun(*this, &Editor::region_list_column_click));
616 named_selection_scroller.add (named_selection_display);
617 named_selection_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
619 named_selection_model = TreeStore::create (named_selection_columns);
620 named_selection_display.set_model (named_selection_model);
621 named_selection_display.append_column (_("Chunks"), named_selection_columns.text);
622 named_selection_display.set_size_request (100, -1);
623 named_selection_display.set_name ("RegionListDisplay");
625 named_selection_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
626 named_selection_display.set_size_request (100, -1);
627 named_selection_display.set_headers_visible (true);
628 named_selection_display.set_headers_clickable (true);
629 named_selection_display.signal_button_press_event().connect (mem_fun(*this, &Editor::named_selection_display_button_press));
630 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
632 region_selection_vpane.pack1 (region_list_scroller, true, true);
633 region_selection_vpane.pack2 (named_selection_scroller, true, true);
635 canvas_region_list_pane.pack1 (edit_frame, true, true);
636 canvas_region_list_pane.pack2 (region_selection_vpane, true, true);
638 track_list_canvas_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler),
639 static_cast<Gtk::Paned*> (&track_list_canvas_pane)));
640 canvas_region_list_pane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler),
641 static_cast<Gtk::Paned*> (&canvas_region_list_pane)));
642 route_group_vpane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler),
643 static_cast<Gtk::Paned*> (&route_group_vpane)));
644 region_selection_vpane.signal_size_allocate().connect_notify (bind (mem_fun(*this, &Editor::pane_allocation_handler),
645 static_cast<Gtk::Paned*> (®ion_selection_vpane)));
647 track_list_canvas_pane.pack1 (list_vpacker, true, true);
648 track_list_canvas_pane.pack2 (canvas_region_list_pane, true, true);
650 /* provide special pane-handle event handling for easy "hide" action */
652 /* 0: collapse to show left/upper child
653 1: collapse to show right/lower child
656 route_group_vpane.set_data ("collapse-direction", (gpointer) 0);
657 region_selection_vpane.set_data ("collapse-direction", (gpointer) 0);
658 canvas_region_list_pane.set_data ("collapse-direction", (gpointer) 0);
659 track_list_canvas_pane.set_data ("collapse-direction", (gpointer) 1);
661 route_group_vpane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (&route_group_vpane)));
662 region_selection_vpane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (®ion_selection_vpane)));
663 canvas_region_list_pane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (&canvas_region_list_pane)));
664 track_list_canvas_pane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (&track_list_canvas_pane)));
666 top_hbox.pack_start (toolbar_frame, true, true);
668 HBox *hbox = manage (new HBox);
669 hbox->pack_start (track_list_canvas_pane, true, true);
671 global_vpacker.pack_start (top_hbox, false, false);
672 global_vpacker.pack_start (*hbox, true, true);
674 global_hpacker.pack_start (global_vpacker, true, true);
676 set_name ("EditorWindow");
677 add_accel_group (ActionManager::ui_manager->get_accel_group());
679 vpacker.pack_end (global_hpacker, true, true);
681 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
684 _playlist_selector = new PlaylistSelector();
685 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
687 AudioRegionView::AudioRegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_audio_regionview));
691 nudge_forward_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(right_arrow_xpm)))));
692 nudge_backward_button.add (*(manage (new Gtk::Image (Gdk::Pixbuf::create_from_xpm_data(left_arrow_xpm)))));
694 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards"));
695 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards"));
697 nudge_forward_button.set_name ("TransportButton");
698 nudge_backward_button.set_name ("TransportButton");
700 fade_context_menu.set_name ("ArdourContextMenu");
702 set_title (_("ardour: editor"));
703 set_wmclass (_("ardour_editor"), "Ardour");
706 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
708 signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
709 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
717 /* <CMT Additions> */
718 if(image_socket_listener)
720 if(image_socket_listener->is_connected())
722 image_socket_listener->close_connection() ;
725 delete image_socket_listener ;
726 image_socket_listener = 0 ;
728 /* </CMT Additions> */
732 Editor::add_toplevel_controls (Container& cont)
734 vpacker.pack_start (cont, false, false);
739 Editor::catch_vanishing_audio_regionview (AudioRegionView *rv)
741 /* note: the selection will take care of the vanishing
742 audioregionview by itself.
745 if (clicked_regionview == rv) {
746 clicked_regionview = 0;
749 if (entered_regionview == rv) {
750 set_entered_regionview (0);
755 Editor::set_entered_regionview (AudioRegionView* rv)
757 if (rv == entered_regionview) {
761 if (entered_regionview) {
762 entered_regionview->exited ();
765 if ((entered_regionview = rv) != 0) {
766 entered_regionview->entered ();
771 Editor::set_entered_track (TimeAxisView* tav)
774 entered_track->exited ();
777 if ((entered_track = tav) != 0) {
778 entered_track->entered ();
783 Editor::left_track_canvas (GdkEventCrossing *ev)
785 set_entered_track (0);
786 set_entered_regionview (0);
792 Editor::show_window ()
797 /* now reset all audio_time_axis heights, because widgets might need
803 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
804 tv = (static_cast<TimeAxisView*>(*i));
810 Editor::tie_vertical_scrolling ()
812 edit_controls_scroller.get_vadjustment()->set_value (track_canvas_scroller.get_vadjustment()->get_value());
814 float y1 = track_canvas_scroller.get_vadjustment()->get_value();
815 playhead_cursor->set_y_axis(y1);
816 edit_cursor->set_y_axis(y1);
820 Editor::set_frames_per_unit (double fpu)
822 jack_nframes_t frames;
824 if (fpu == frames_per_unit) {
832 // convert fpu to frame count
834 frames = (jack_nframes_t) (fpu * canvas_width);
836 /* don't allow zooms that fit more than the maximum number
837 of frames into an 800 pixel wide space.
840 if (max_frames / fpu < 800.0) {
844 frames_per_unit = fpu;
846 if (frames != zoom_range_clock.current_duration()) {
847 zoom_range_clock.set (frames);
850 /* only update these if we not about to call reposition_x_origin,
851 which will do the same updates.
855 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
858 if (!no_zoom_repos_update) {
859 track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
861 update_fixed_rulers ();
862 tempo_map_changed (Change (0));
865 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
866 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
867 (*i)->reshow_selection (selection->time);
871 ZoomChanged (); /* EMIT_SIGNAL */
873 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
874 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
881 Editor::instant_save ()
883 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
888 session->add_instant_xml(get_state(), session->path());
890 Config->add_instant_xml(get_state(), Config->get_user_ardour_path());
895 Editor::reposition_x_origin (jack_nframes_t frame)
897 if (frame != leftmost_frame) {
898 leftmost_frame = frame;
899 double pixel = frame_to_pixel (frame);
900 if (pixel >= track_canvas_scroller.get_hadjustment()->get_upper()) {
901 track_canvas_scroller.get_hadjustment()->set_upper (frame_to_pixel (frame + (current_page_frames())));
903 track_canvas_scroller.get_hadjustment()->set_value (frame/frames_per_unit);
904 XOriginChanged (); /* EMIT_SIGNAL */
909 Editor::edit_cursor_clock_changed()
911 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
912 edit_cursor->set_position (edit_cursor_clock.current_time());
918 Editor::zoom_adjustment_changed ()
920 if (session == 0 || no_zoom_repos_update) {
924 double fpu = (double) zoom_range_clock.current_duration() / (double) canvas_width;
928 zoom_range_clock.set ((jack_nframes_t) (fpu * canvas_width));
930 else if (fpu > session->current_end_frame() / (double) canvas_width) {
931 fpu = session->current_end_frame() / (double) canvas_width;
932 zoom_range_clock.set ((jack_nframes_t) (fpu * canvas_width));
939 Editor::canvas_horizontally_scrolled ()
941 /* XXX note the potential loss of accuracy here caused by
942 adjustments being 32bit floats with only a 24 bit mantissa,
943 whereas jack_nframes_t is at least a 32 bit uint32_teger.
946 leftmost_frame = (jack_nframes_t) floor (track_canvas_scroller.get_hadjustment()->get_value() * frames_per_unit);
949 update_fixed_rulers ();
951 if (!edit_hscroll_dragging) {
952 tempo_map_changed (Change (0));
954 update_tempo_based_rulers();
959 Editor::reposition_and_zoom (jack_nframes_t frame, double nfpu)
961 if (!repos_zoom_queued) {
962 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu));
963 repos_zoom_queued = true;
968 Editor::deferred_reposition_and_zoom (jack_nframes_t frame, double nfpu)
970 /* if we need to force an update to the hscroller stuff,
971 don't set no_zoom_repos_update.
974 no_zoom_repos_update = (frame != leftmost_frame);
976 set_frames_per_unit (nfpu);
977 if (no_zoom_repos_update) {
978 reposition_x_origin (frame);
980 no_zoom_repos_update = false;
981 repos_zoom_queued = false;
987 Editor::on_realize ()
989 Window::on_realize ();
991 /* Even though we're not using acceleration, we want the
995 track_context_menu.accelerate (*this->get_toplevel());
996 track_region_context_menu.accelerate (*this->get_toplevel());
998 Glib::RefPtr<Gdk::Pixmap> empty_pixmap = Gdk::Pixmap::create(get_window(), 1, 1, 1);
999 Glib::RefPtr<Gdk::Pixmap> empty_bitmap = Gdk::Pixmap::create(get_window(), 1, 1, 1);
1000 Gdk::Color white ("#ffffff" );
1002 null_cursor = new Gdk::Cursor(empty_pixmap, empty_bitmap, white, white, 0, 0);
1007 Editor::queue_session_control_changed (Session::ControlType t)
1009 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::session_control_changed), t));
1013 Editor::session_control_changed (Session::ControlType t)
1015 // right now we're only tracking the loop and punch state
1018 case Session::AutoLoop:
1019 update_loop_range_view (true);
1021 case Session::PunchIn:
1022 case Session::PunchOut:
1023 update_punch_range_view (true);
1032 Editor::fake_add_edit_group (RouteGroup *group)
1034 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::add_edit_group), group));
1038 Editor::fake_handle_new_audio_region (AudioRegion *region)
1040 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_new_audio_region), region));
1044 Editor::fake_handle_audio_region_removed (AudioRegion *region)
1046 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_audio_region_removed), region));
1050 Editor::fake_handle_new_duration ()
1052 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &Editor::handle_new_duration));
1056 Editor::start_scrolling ()
1058 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1059 (mem_fun(*this, &Editor::update_current_screen));
1061 slower_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
1062 (mem_fun(*this, &Editor::update_slower));
1066 Editor::stop_scrolling ()
1068 scroll_connection.disconnect ();
1069 slower_update_connection.disconnect ();
1073 Editor::map_position_change (jack_nframes_t frame)
1075 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1077 if (session == 0 || !_follow_playhead) {
1081 center_screen (frame);
1082 playhead_cursor->set_position (frame);
1086 Editor::center_screen (jack_nframes_t frame)
1088 float page = canvas_width * frames_per_unit;
1090 /* if we're off the page, then scroll.
1093 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1094 center_screen_internal (frame,page);
1099 Editor::center_screen_internal (jack_nframes_t frame, float page)
1104 frame -= (jack_nframes_t) page;
1109 reposition_x_origin (frame);
1113 Editor::handle_new_duration ()
1115 reset_scrolling_region ();
1118 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1119 track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
1122 update_hscroller ();
1126 Editor::update_title_s (string snap_name)
1128 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1134 Editor::update_title ()
1136 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1139 bool dirty = session->dirty();
1141 string wintitle = _("ardour: editor: ");
1147 wintitle += session->name();
1149 if (session->snap_name() != session->name()) {
1151 wintitle += session->snap_name();
1158 set_title (wintitle);
1163 Editor::connect_to_session (Session *t)
1167 if (first_action_message) {
1168 first_action_message->hide();
1171 flush_track_canvas();
1175 session->going_away.connect (mem_fun(*this, &Editor::session_going_away));
1177 /* These signals can all be emitted by a non-GUI thread. Therefore the
1178 handlers for them must not attempt to directly interact with the GUI,
1179 but use Gtkmm2ext::UI::instance()->call_slot();
1182 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1183 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1184 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p)));
1185 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::fake_handle_new_audio_region)));
1186 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::fake_handle_audio_region_removed)));
1187 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::fake_handle_new_duration)));
1188 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::fake_add_edit_group)));
1189 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1190 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1191 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1192 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1193 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1194 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1196 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1197 session_connections.push_back (session->SMPTETypeChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1199 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1201 session->foreach_edit_group(this, &Editor::add_edit_group);
1203 editor_mixer_button.signal_toggled().connect (mem_fun(*this, &Editor::editor_mixer_button_toggled));
1204 editor_mixer_button.set_name (X_("EditorMixerButton"));
1206 edit_cursor_clock.set_session (session);
1207 selection_start_clock.set_session (session);
1208 selection_end_clock.set_session (session);
1209 zoom_range_clock.set_session (session);
1210 _playlist_selector->set_session (session);
1211 nudge_clock.set_session (session);
1213 switch (session->get_edit_mode()) {
1215 edit_mode_selector.set_active_text (edit_mode_strings[splice_index]);
1219 edit_mode_selector.set_active_text (edit_mode_strings[slide_index]);
1223 Location* loc = session->locations()->auto_loop_location();
1225 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1226 if (loc->start() == loc->end()) {
1227 loc->set_end (loc->start() + 1);
1229 session->locations()->add (loc, false);
1230 session->set_auto_loop_location (loc);
1234 loc->set_name (_("Loop"));
1237 loc = session->locations()->auto_punch_location();
1239 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1240 if (loc->start() == loc->end()) {
1241 loc->set_end (loc->start() + 1);
1243 session->locations()->add (loc, false);
1244 session->set_auto_punch_location (loc);
1248 loc->set_name (_("Punch"));
1251 update_loop_range_view (true);
1252 update_punch_range_view (true);
1254 session->ControlChanged.connect (mem_fun(*this, &Editor::queue_session_control_changed));
1257 refresh_location_display ();
1258 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1259 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1260 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1261 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1262 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1264 reset_scrolling_region ();
1266 redisplay_regions ();
1267 redisplay_named_selections ();
1269 //route_list.freeze (); GTK2FIX
1270 route_display_model->clear ();
1271 session->foreach_route (this, &Editor::handle_new_route);
1272 // route_list.select_all ();
1274 //route_list.sort ();
1275 route_list_reordered ();
1276 //route_list.thaw ();
1278 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1279 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1282 /* ::reposition_x_origin() doesn't work right here, since the old
1283 position may be zero already, and it does nothing in such
1289 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1290 track_canvas_scroller.get_hadjustment()->set_value (0);
1292 update_hscroller ();
1293 restore_ruler_visibility ();
1294 tempo_map_changed (Change (0));
1296 edit_cursor->set_position (0);
1297 playhead_cursor->set_position (0);
1301 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1304 /* don't show master bus in a new session */
1306 if (ARDOUR_UI::instance()->session_is_new ()) {
1308 TreeModel::Children rows = route_display_model->children();
1309 TreeModel::Children::iterator i;
1311 //route_list.freeze ();
1313 for (i = rows.begin(); i != rows.end(); ++i) {
1314 TimeAxisView *tv = (*i)[route_display_columns.tv];
1315 AudioTimeAxisView *atv;
1317 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1318 if (atv->route().master()) {
1319 route_list.get_selection()->unselect (i);
1320 //(*i)->unselect ();
1325 //route_list.thaw ();
1330 Editor::build_cursors ()
1332 using namespace Gdk;
1334 Gdk::Color mbg ("#000000" ); /* Black */
1335 Gdk::Color mfg ("#0000ff" ); /* Blue. */
1338 RefPtr<Bitmap> source, mask;
1339 source = Bitmap::create (mag_bits, mag_width, mag_height);
1340 mask = Bitmap::create (magmask_bits, mag_width, mag_height);
1341 zoom_cursor = new Gdk::Cursor (source, mask, mfg, mbg, mag_x_hot, mag_y_hot);
1344 Gdk::Color fbg ("#ffffff" );
1345 Gdk::Color ffg ("#000000" );
1348 RefPtr<Bitmap> source, mask;
1350 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1351 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1352 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1356 RefPtr<Bitmap> source, mask;
1357 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1358 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1359 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1362 grabber_cursor = new Gdk::Cursor (HAND2);
1363 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1364 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1365 selector_cursor = new Gdk::Cursor (XTERM);
1366 time_fx_cursor = new Gdk::Cursor (SIZING);
1367 wait_cursor = new Gdk::Cursor (WATCH);
1368 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1372 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1374 using namespace Menu_Helpers;
1375 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1378 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1382 MenuList& items (fade_context_menu.items());
1386 switch (item_type) {
1388 case FadeInHandleItem:
1389 if (arv->region.fade_in_active()) {
1390 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false)));
1392 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true)));
1395 items.push_back (SeparatorElem());
1397 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear)));
1398 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB)));
1399 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast)));
1400 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA)));
1401 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow)));
1405 case FadeOutHandleItem:
1406 if (arv->region.fade_out_active()) {
1407 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false)));
1409 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true)));
1412 items.push_back (SeparatorElem());
1414 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear)));
1415 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast)));
1416 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB)));
1417 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA)));
1418 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow)));
1422 fatal << _("programming error: ")
1423 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1428 fade_context_menu.popup (button, time);
1432 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, jack_nframes_t frame)
1434 using namespace Menu_Helpers;
1435 Menu* (Editor::*build_menu_function)(jack_nframes_t);
1438 switch (item_type) {
1440 case AudioRegionViewName:
1441 case AudioRegionViewNameHighlight:
1442 if (with_selection) {
1443 build_menu_function = &Editor::build_track_selection_context_menu;
1445 build_menu_function = &Editor::build_track_region_context_menu;
1450 if (with_selection) {
1451 build_menu_function = &Editor::build_track_selection_context_menu;
1453 build_menu_function = &Editor::build_track_context_menu;
1457 case CrossfadeViewItem:
1458 build_menu_function = &Editor::build_track_crossfade_context_menu;
1462 if (clicked_audio_trackview->get_diskstream()) {
1463 build_menu_function = &Editor::build_track_context_menu;
1465 build_menu_function = &Editor::build_track_bus_context_menu;
1470 /* probably shouldn't happen but if it does, we don't care */
1474 menu = (this->*build_menu_function)(frame);
1475 menu->set_name ("ArdourContextMenu");
1477 /* now handle specific situations */
1479 switch (item_type) {
1481 case AudioRegionViewName:
1482 case AudioRegionViewNameHighlight:
1483 if (!with_selection) {
1484 if (region_edit_menu_split_item) {
1485 if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) {
1486 // GTK2FIX find the action, change its sensitivity
1487 // region_edit_menu_split_item->set_sensitive (true);
1489 // GTK2FIX see above
1490 // region_edit_menu_split_item->set_sensitive (false);
1493 if (region_edit_menu_split_multichannel_item) {
1494 if (clicked_regionview && clicked_regionview->region.n_channels() > 1) {
1495 // GTK2FIX find the action, change its sensitivity
1496 // region_edit_menu_split_multichannel_item->set_sensitive (true);
1498 // GTK2FIX see above
1499 // region_edit_menu_split_multichannel_item->set_sensitive (false);
1508 case CrossfadeViewItem:
1515 /* probably shouldn't happen but if it does, we don't care */
1519 if (clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1521 /* Bounce to disk */
1523 using namespace Menu_Helpers;
1524 MenuList& edit_items = menu->items();
1526 edit_items.push_back (SeparatorElem());
1528 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1529 case AudioTrack::NoFreeze:
1530 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1533 case AudioTrack::Frozen:
1534 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1537 case AudioTrack::UnFrozen:
1538 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1544 menu->popup (button, time);
1548 Editor::build_track_context_menu (jack_nframes_t ignored)
1550 using namespace Menu_Helpers;
1552 MenuList& edit_items = track_context_menu.items();
1555 add_dstream_context_items (edit_items);
1556 return &track_context_menu;
1560 Editor::build_track_bus_context_menu (jack_nframes_t ignored)
1562 using namespace Menu_Helpers;
1564 MenuList& edit_items = track_context_menu.items();
1567 add_bus_context_items (edit_items);
1568 return &track_context_menu;
1572 Editor::build_track_region_context_menu (jack_nframes_t frame)
1574 using namespace Menu_Helpers;
1575 MenuList& edit_items = track_region_context_menu.items();
1578 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1584 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1585 Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed()));
1586 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1587 add_region_context_items (atv->view, (*i), edit_items);
1593 add_dstream_context_items (edit_items);
1595 return &track_region_context_menu;
1599 Editor::build_track_crossfade_context_menu (jack_nframes_t frame)
1601 using namespace Menu_Helpers;
1602 MenuList& edit_items = track_crossfade_context_menu.items();
1603 edit_items.clear ();
1605 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1612 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = dynamic_cast<AudioPlaylist*> (pl)) != 0)) {
1614 Playlist::RegionList* regions = pl->regions_at (frame);
1615 AudioPlaylist::Crossfades xfades;
1617 apl->crossfades_at (frame, xfades);
1619 bool many = xfades.size() > 1;
1621 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1622 add_crossfade_context_items (atv->view, (*i), edit_items, many);
1625 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1626 add_region_context_items (atv->view, (*i), edit_items);
1633 add_dstream_context_items (edit_items);
1635 return &track_crossfade_context_menu;
1639 Editor::build_track_selection_context_menu (jack_nframes_t ignored)
1641 using namespace Menu_Helpers;
1642 MenuList& edit_items = track_selection_context_menu.items();
1643 edit_items.clear ();
1645 add_selection_context_items (edit_items);
1646 add_dstream_context_items (edit_items);
1648 return &track_selection_context_menu;
1652 Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many)
1654 using namespace Menu_Helpers;
1655 Menu *xfade_menu = manage (new Menu);
1656 MenuList& items = xfade_menu->items();
1657 xfade_menu->set_name ("ArdourContextMenu");
1660 if (xfade->active()) {
1666 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), xfade)));
1667 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), xfade)));
1669 if (xfade->can_follow_overlap()) {
1671 if (xfade->following_overlap()) {
1672 str = _("Convert to short");
1674 str = _("Convert to full");
1677 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1681 str = xfade->out().name();
1683 str += xfade->in().name();
1685 str = _("Crossfade");
1688 edit_items.push_back (MenuElem (str, *xfade_menu));
1689 edit_items.push_back (SeparatorElem());
1693 Editor::xfade_edit_left_region ()
1695 if (clicked_crossfadeview) {
1696 clicked_crossfadeview->left_view.show_region_editor ();
1701 Editor::xfade_edit_right_region ()
1703 if (clicked_crossfadeview) {
1704 clicked_crossfadeview->right_view.show_region_editor ();
1709 Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items)
1711 using namespace Menu_Helpers;
1712 Menu *region_menu = manage (new Menu);
1713 MenuList& items = region_menu->items();
1714 region_menu->set_name ("ArdourContextMenu");
1716 AudioRegion* ar = 0;
1719 ar = dynamic_cast<AudioRegion*> (region);
1722 /* when this particular menu pops up, make the relevant region
1726 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, region));
1728 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
1729 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
1730 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
1731 items.push_back (SeparatorElem());
1732 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
1733 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
1734 items.push_back (SeparatorElem());
1736 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
1737 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
1738 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
1739 items.push_back (SeparatorElem());
1741 /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler
1742 might be able to figure out which overloaded member function to use in
1746 void (Editor::*type_A_pmf)(void (Region::*pmf)(bool), bool) = &Editor::region_selection_op;
1748 items.push_back (MenuElem (_("Lock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, true)));
1749 items.push_back (MenuElem (_("Unlock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, false)));
1750 items.push_back (SeparatorElem());
1752 if (region->muted()) {
1753 items.push_back (MenuElem (_("Unmute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, false)));
1755 items.push_back (MenuElem (_("Mute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, true)));
1757 items.push_back (SeparatorElem());
1759 items.push_back (MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
1760 items.push_back (SeparatorElem());
1765 items.push_back (MenuElem (_("Toggle envelope visibility"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility)));
1766 items.push_back (MenuElem (_("Toggle envelope active"), mem_fun(*this, &Editor::toggle_gain_envelope_active)));
1767 items.push_back (SeparatorElem());
1769 if (ar->scale_amplitude() != 1.0f) {
1770 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
1772 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
1775 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
1776 items.push_back (SeparatorElem());
1780 Menu *nudge_menu = manage (new Menu());
1781 MenuList& nudge_items = nudge_menu->items();
1782 nudge_menu->set_name ("ArdourContextMenu");
1784 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
1785 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
1786 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
1787 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
1789 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1790 items.push_back (SeparatorElem());
1792 Menu *trim_menu = manage (new Menu);
1793 MenuList& trim_items = trim_menu->items();
1794 trim_menu->set_name ("ArdourContextMenu");
1796 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
1797 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
1799 items.push_back (MenuElem (_("Trim"), *trim_menu));
1800 items.push_back (SeparatorElem());
1802 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
1803 region_edit_menu_split_item = &items.back();
1805 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
1806 region_edit_menu_split_multichannel_item = &items.back();
1808 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
1809 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
1810 items.push_back (SeparatorElem());
1811 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
1812 items.push_back (SeparatorElem());
1813 items.push_back (MenuElem (_("Destroy"), mem_fun(*this, &Editor::destroy_clicked_region)));
1815 /* OK, stick the region submenu at the top of the list, and then add
1819 /* we have to hack up the region name because "_" has a special
1820 meaning for menu titles.
1823 string::size_type pos = 0;
1824 string menu_item_name = region->name();
1826 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1827 menu_item_name.replace (pos, 1, "__");
1831 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
1832 edit_items.push_back (SeparatorElem());
1836 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1838 using namespace Menu_Helpers;
1839 Menu *selection_menu = manage (new Menu);
1840 MenuList& items = selection_menu->items();
1841 selection_menu->set_name ("ArdourContextMenu");
1843 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
1844 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
1845 items.push_back (SeparatorElem());
1846 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection)));
1847 items.push_back (SeparatorElem());
1848 items.push_back (MenuElem (_("Create Region"), mem_fun(*this, &Editor::new_region_from_selection)));
1849 items.push_back (MenuElem (_("Separate Region"), mem_fun(*this, &Editor::separate_region_from_selection)));
1850 items.push_back (MenuElem (_("Crop Region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
1851 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
1852 items.push_back (SeparatorElem());
1853 items.push_back (MenuElem (_("Duplicate"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
1854 items.push_back (SeparatorElem());
1855 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_selection)));
1856 items.push_back (SeparatorElem());
1857 items.push_back (MenuElem (_("Fill range w/Region"), mem_fun(*this, &Editor::region_fill_selection)));
1859 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
1860 edit_items.push_back (SeparatorElem());
1864 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1866 using namespace Menu_Helpers;
1870 Menu *play_menu = manage (new Menu);
1871 MenuList& play_items = play_menu->items();
1872 play_menu->set_name ("ArdourContextMenu");
1874 play_items.push_back (MenuElem (_("Play from edit cursor")));
1875 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1876 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
1877 play_items.push_back (SeparatorElem());
1878 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
1880 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1884 Menu *select_menu = manage (new Menu);
1885 MenuList& select_items = select_menu->items();
1886 select_menu->set_name ("ArdourContextMenu");
1888 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
1889 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
1890 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1891 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
1892 select_items.push_back (SeparatorElem());
1893 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1894 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1895 select_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1901 Menu *cutnpaste_menu = manage (new Menu);
1902 MenuList& cutnpaste_items = cutnpaste_menu->items();
1903 cutnpaste_menu->set_name ("ArdourContextMenu");
1905 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1906 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1907 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1908 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
1910 cutnpaste_items.push_back (SeparatorElem());
1912 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
1913 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
1915 cutnpaste_items.push_back (SeparatorElem());
1917 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
1919 cutnpaste_items.push_back (SeparatorElem());
1921 cutnpaste_items.push_back (MenuElem (_("New Region from range"), mem_fun(*this, &Editor::new_region_from_selection)));
1922 cutnpaste_items.push_back (MenuElem (_("Separate Range"), mem_fun(*this, &Editor::separate_region_from_selection)));
1924 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1926 /* Adding new material */
1928 Menu *import_menu = manage (new Menu());
1929 MenuList& import_items = import_menu->items();
1930 import_menu->set_name ("ArdourContextMenu");
1932 import_items.push_back (MenuElem (_("Insert Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1933 import_items.push_back (MenuElem (_("Insert external sndfile"), bind (mem_fun(*this, &Editor::insert_sndfile), false)));
1935 edit_items.push_back (MenuElem (_("Import"), *import_menu));
1939 Menu *nudge_menu = manage (new Menu());
1940 MenuList& nudge_items = nudge_menu->items();
1941 nudge_menu->set_name ("ArdourContextMenu");
1943 edit_items.push_back (SeparatorElem());
1944 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
1945 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
1946 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
1947 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
1949 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1953 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1955 using namespace Menu_Helpers;
1959 Menu *play_menu = manage (new Menu);
1960 MenuList& play_items = play_menu->items();
1961 play_menu->set_name ("ArdourContextMenu");
1963 play_items.push_back (MenuElem (_("Play from edit cursor")));
1964 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
1965 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1969 Menu *select_menu = manage (new Menu);
1970 MenuList& select_items = select_menu->items();
1971 select_menu->set_name ("ArdourContextMenu");
1973 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
1974 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
1975 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
1976 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
1977 select_items.push_back (SeparatorElem());
1978 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
1979 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
1980 select_items.push_back (SeparatorElem());
1982 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1986 Menu *cutnpaste_menu = manage (new Menu);
1987 MenuList& cutnpaste_items = cutnpaste_menu->items();
1988 cutnpaste_menu->set_name ("ArdourContextMenu");
1990 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
1991 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
1992 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
1994 Menu *nudge_menu = manage (new Menu());
1995 MenuList& nudge_items = nudge_menu->items();
1996 nudge_menu->set_name ("ArdourContextMenu");
1998 edit_items.push_back (SeparatorElem());
1999 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2000 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2001 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2002 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2004 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2007 /* CURSOR SETTING AND MARKS AND STUFF */
2010 Editor::set_snap_to (SnapType st)
2013 vector<string> txt = internationalize (snap_type_strings);
2014 snap_type_selector.set_active_text (txt[(int)st]);
2018 switch (snap_type) {
2019 case SnapToAThirtysecondBeat:
2020 case SnapToASixteenthBeat:
2021 case SnapToAEighthBeat:
2022 case SnapToAQuarterBeat:
2023 case SnapToAThirdBeat:
2024 update_tempo_based_rulers ();
2032 Editor::set_snap_mode (SnapMode mode)
2035 vector<string> txt = internationalize (snap_mode_strings);
2036 snap_mode_selector.set_active_text (txt[(int)mode]);
2042 Editor::add_location_from_selection ()
2044 if (selection->time.empty()) {
2048 if (session == 0 || clicked_trackview == 0) {
2052 jack_nframes_t start = selection->time[clicked_selection].start;
2053 jack_nframes_t end = selection->time[clicked_selection].end;
2055 Location *location = new Location (start, end, "selection");
2057 session->begin_reversible_command (_("add marker"));
2058 session->add_undo (session->locations()->get_memento());
2059 session->locations()->add (location, true);
2060 session->add_redo_no_execute (session->locations()->get_memento());
2061 session->commit_reversible_command ();
2065 Editor::add_location_from_playhead_cursor ()
2067 jack_nframes_t where = session->audible_frame();
2069 Location *location = new Location (where, where, "mark", Location::IsMark);
2070 session->begin_reversible_command (_("add marker"));
2071 session->add_undo (session->locations()->get_memento());
2072 session->locations()->add (location, true);
2073 session->add_redo_no_execute (session->locations()->get_memento());
2074 session->commit_reversible_command ();
2079 Editor::set_state (const XMLNode& node)
2081 const XMLProperty* prop;
2083 int x, y, width, height, xoff, yoff;
2085 if ((geometry = find_named_node (node, "geometry")) == 0) {
2087 width = default_width;
2088 height = default_height;
2096 width = atoi(geometry->property("x_size")->value());
2097 height = atoi(geometry->property("y_size")->value());
2098 x = atoi(geometry->property("x_pos")->value());
2099 y = atoi(geometry->property("y_pos")->value());
2100 xoff = atoi(geometry->property("x_off")->value());
2101 yoff = atoi(geometry->property("y_off")->value());
2104 set_default_size(width, height);
2106 // set_position(x, y-yoff);
2108 if ((prop = node.property ("zoom-focus"))) {
2109 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2112 if ((prop = node.property ("zoom"))) {
2113 set_frames_per_unit (atof (prop->value()));
2116 if ((prop = node.property ("snap-to"))) {
2117 set_snap_to ((SnapType) atoi (prop->value()));
2120 if ((prop = node.property ("snap-mode"))) {
2121 set_snap_mode ((SnapMode) atoi (prop->value()));
2124 if ((prop = node.property ("show-waveforms"))) {
2125 bool yn = (prop->value() == "yes");
2126 _show_waveforms = !yn;
2127 set_show_waveforms (yn);
2130 if ((prop = node.property ("show-waveforms-recording"))) {
2131 bool yn = (prop->value() == "yes");
2132 _show_waveforms_recording = !yn;
2133 set_show_waveforms_recording (yn);
2136 if ((prop = node.property ("show-measures"))) {
2137 bool yn = (prop->value() == "yes");
2138 _show_measures = !yn;
2139 set_show_measures (yn);
2142 if ((prop = node.property ("follow-playhead"))) {
2143 bool yn = (prop->value() == "yes");
2144 _follow_playhead = !yn;
2145 set_follow_playhead (yn);
2148 if ((prop = node.property ("xfades-visible"))) {
2149 bool yn = (prop->value() == "yes");
2150 _xfade_visibility = !yn;
2151 set_xfade_visibility (yn);
2154 if ((prop = node.property ("region-list-sort-type"))) {
2155 region_list_sort_type = (Editing::RegionListSortType) -1; /* force change */
2156 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2159 if ((prop = node.property ("mouse-mode"))) {
2160 MouseMode m = str2mousemode(prop->value());
2161 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2162 set_mouse_mode (m, true);
2164 mouse_mode = MouseGain; /* lie, to force the mode switch */
2165 set_mouse_mode (MouseObject, true);
2168 if ((prop = node.property ("editor-mixer-button"))) {
2169 editor_mixer_button.set_active(prop->value() == "yes");
2176 Editor::get_state ()
2178 XMLNode* node = new XMLNode ("Editor");
2181 if (is_realized()) {
2182 Glib::RefPtr<Gdk::Window> win = get_window();
2184 int x, y, xoff, yoff, width, height;
2185 win->get_root_origin(x, y);
2186 win->get_position(xoff, yoff);
2187 win->get_size(width, height);
2189 XMLNode* geometry = new XMLNode ("geometry");
2191 snprintf(buf, sizeof(buf), "%d", width);
2192 geometry->add_property("x_size", string(buf));
2193 snprintf(buf, sizeof(buf), "%d", height);
2194 geometry->add_property("y_size", string(buf));
2195 snprintf(buf, sizeof(buf), "%d", x);
2196 geometry->add_property("x_pos", string(buf));
2197 snprintf(buf, sizeof(buf), "%d", y);
2198 geometry->add_property("y_pos", string(buf));
2199 snprintf(buf, sizeof(buf), "%d", xoff);
2200 geometry->add_property("x_off", string(buf));
2201 snprintf(buf, sizeof(buf), "%d", yoff);
2202 geometry->add_property("y_off", string(buf));
2203 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&canvas_region_list_pane)->gobj()));
2204 geometry->add_property("canvas_region_list_pane_pos", string(buf));
2205 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&track_list_canvas_pane)->gobj()));
2206 geometry->add_property("track_list_canvas_pane_pos", string(buf));
2207 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(®ion_selection_vpane)->gobj()));
2208 geometry->add_property("region_selection_pane_pos", string(buf));
2209 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&route_group_vpane)->gobj()));
2210 geometry->add_property("route_group_pane_pos", string(buf));
2212 node->add_child_nocopy (*geometry);
2215 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2216 node->add_property ("zoom-focus", buf);
2217 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2218 node->add_property ("zoom", buf);
2219 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2220 node->add_property ("snap-to", buf);
2221 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2222 node->add_property ("snap-mode", buf);
2224 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2225 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2226 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2227 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2228 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2229 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2230 node->add_property ("mouse-mode", enum2str(mouse_mode));
2231 node->add_property ("editor-mixer-button", editor_mixer_button.get_active() ? "yes" : "no");
2239 Editor::trackview_by_y_position (double y)
2241 TrackViewList::iterator iter;
2244 for (iter = track_views.begin(); iter != track_views.end(); ++iter) {
2252 if (tv->y_position <= y && y < ((tv->y_position + tv->height + track_spacing))) {
2261 Editor::snap_to (jack_nframes_t& start, int32_t direction, bool for_mark)
2263 Location* before = 0;
2264 Location* after = 0;
2270 const jack_nframes_t one_second = session->frame_rate();
2271 const jack_nframes_t one_minute = session->frame_rate() * 60;
2273 jack_nframes_t presnap = start;
2275 switch (snap_type) {
2281 start = (jack_nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2283 start = (jack_nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2286 case SnapToSMPTEFrame:
2288 start = (jack_nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2290 start = (jack_nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2294 case SnapToSMPTESeconds:
2295 if (session->smpte_offset_negative())
2297 start += session->smpte_offset ();
2299 start -= session->smpte_offset ();
2301 if (direction > 0) {
2302 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2304 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2307 if (session->smpte_offset_negative())
2309 start -= session->smpte_offset ();
2311 start += session->smpte_offset ();
2315 case SnapToSMPTEMinutes:
2316 if (session->smpte_offset_negative())
2318 start += session->smpte_offset ();
2320 start -= session->smpte_offset ();
2323 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2325 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2327 if (session->smpte_offset_negative())
2329 start -= session->smpte_offset ();
2331 start += session->smpte_offset ();
2337 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2339 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2345 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2347 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2352 start = session->tempo_map().round_to_bar (start, direction);
2356 start = session->tempo_map().round_to_beat (start, direction);
2359 case SnapToAThirtysecondBeat:
2360 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2363 case SnapToASixteenthBeat:
2364 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2367 case SnapToAEighthBeat:
2368 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2371 case SnapToAQuarterBeat:
2372 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2375 case SnapToAThirdBeat:
2376 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2379 case SnapToEditCursor:
2380 start = edit_cursor->current_frame;
2388 before = session->locations()->first_location_before (start);
2389 after = session->locations()->first_location_after (start);
2391 if (direction < 0) {
2393 start = before->start();
2397 } else if (direction > 0) {
2399 start = after->start();
2401 start = session->current_end_frame();
2406 /* find nearest of the two */
2407 if ((start - before->start()) < (after->start() - start)) {
2408 start = before->start();
2410 start = after->start();
2413 start = before->start();
2416 start = after->start();
2423 case SnapToRegionStart:
2424 case SnapToRegionEnd:
2425 case SnapToRegionSync:
2426 case SnapToRegionBoundary:
2427 if (!region_boundary_cache.empty()) {
2428 vector<jack_nframes_t>::iterator i;
2430 if (direction > 0) {
2431 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2433 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2436 if (i != region_boundary_cache.end()) {
2439 start = region_boundary_cache.back();
2445 switch (snap_mode) {
2451 if (presnap > start) {
2452 if (presnap > (start + unit_to_frame(snap_threshold))) {
2456 } else if (presnap < start) {
2457 if (presnap < (start - unit_to_frame(snap_threshold))) {
2469 Editor::setup_toolbar ()
2472 vector<ToggleButton *> mouse_mode_buttons;
2474 mouse_mode_buttons.push_back (&mouse_move_button);
2475 mouse_mode_buttons.push_back (&mouse_select_button);
2476 mouse_mode_buttons.push_back (&mouse_gain_button);
2477 mouse_mode_buttons.push_back (&mouse_zoom_button);
2478 mouse_mode_buttons.push_back (&mouse_timefx_button);
2479 mouse_mode_buttons.push_back (&mouse_audition_button);
2480 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2482 mouse_mode_button_table.set_homogeneous (true);
2483 mouse_mode_button_table.set_col_spacings (2);
2484 mouse_mode_button_table.set_row_spacings (2);
2485 mouse_mode_button_table.set_border_width (5);
2487 mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1);
2488 mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1);
2489 mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1);
2491 mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2);
2492 mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2);
2493 mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2);
2495 mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table));
2496 mouse_mode_tearoff->set_name ("MouseModeBase");
2498 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
2499 mouse_mode_tearoff->tearoff_window()));
2500 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
2501 mouse_mode_tearoff->tearoff_window(), 1));
2503 mouse_move_button.set_name ("MouseModeButton");
2504 mouse_select_button.set_name ("MouseModeButton");
2505 mouse_gain_button.set_name ("MouseModeButton");
2506 mouse_zoom_button.set_name ("MouseModeButton");
2507 mouse_timefx_button.set_name ("MouseModeButton");
2508 mouse_audition_button.set_name ("MouseModeButton");
2510 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects"));
2511 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges"));
2512 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation"));
2513 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range"));
2514 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions"));
2515 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions"));
2517 mouse_move_button.unset_flags (Gtk::CAN_FOCUS);
2518 mouse_select_button.unset_flags (Gtk::CAN_FOCUS);
2519 mouse_gain_button.unset_flags (Gtk::CAN_FOCUS);
2520 mouse_zoom_button.unset_flags (Gtk::CAN_FOCUS);
2521 mouse_timefx_button.unset_flags (Gtk::CAN_FOCUS);
2522 mouse_audition_button.unset_flags (Gtk::CAN_FOCUS);
2524 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2525 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2527 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2528 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2529 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2530 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2531 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2533 // mouse_move_button.set_active (true);
2535 /* automation control */
2537 global_automation_button.set_name ("MouseModeButton");
2538 automation_mode_button.set_name ("MouseModeButton");
2540 automation_box.set_spacing (2);
2541 automation_box.set_border_width (2);
2542 automation_box.pack_start (global_automation_button, false, false);
2543 automation_box.pack_start (automation_mode_button, false, false);
2547 edit_mode_label.set_name ("ToolBarLabel");
2549 edit_mode_selector.set_name ("EditModeSelector");
2551 edit_mode_box.set_spacing (3);
2552 edit_mode_box.set_border_width (3);
2554 /* XXX another disgusting hack because of the way combo boxes size themselves */
2556 Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2, 10);
2557 set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings));
2558 edit_mode_box.pack_start (edit_mode_label, false, false);
2559 edit_mode_box.pack_start (edit_mode_selector, false, false);
2561 edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2565 snap_type_label.set_name ("ToolBarLabel");
2567 snap_type_selector.set_name ("SnapTypeSelector");
2569 snap_type_box.set_spacing (3);
2570 snap_type_box.set_border_width (3);
2572 /* XXX another disgusting hack because of the way combo boxes size themselves */
2574 const guint32 FUDGE = 10; // Combo's are stupid - they steal space from the entry for the button
2575 Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "Region bounds", 2+FUDGE, 10);
2576 set_popdown_strings (snap_type_selector, internationalize (snap_type_strings));
2578 snap_type_box.pack_start (snap_type_label, false, false);
2579 snap_type_box.pack_start (snap_type_selector, false, false);
2581 snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2583 /* Snap mode, not snap type */
2585 snap_mode_label.set_name ("ToolBarLabel");
2587 snap_mode_selector.set_name ("SnapModeSelector");
2589 snap_mode_box.set_spacing (3);
2590 snap_mode_box.set_border_width (3);
2592 Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2, 10);
2593 set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings));
2595 snap_mode_box.pack_start (snap_mode_label, false, false);
2596 snap_mode_box.pack_start (snap_mode_selector, false, false);
2598 snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
2600 /* Zoom focus mode */
2602 zoom_focus_label.set_name ("ToolBarLabel");
2604 zoom_focus_selector.set_name ("ZoomFocusSelector");
2606 zoom_focus_box.set_spacing (3);
2607 zoom_focus_box.set_border_width (3);
2609 /* XXX another disgusting hack because of the way combo boxes size themselves */
2611 Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2, 10);
2612 set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings));
2614 zoom_focus_box.pack_start (zoom_focus_label, false, false);
2615 zoom_focus_box.pack_start (zoom_focus_selector, false, false);
2617 zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
2619 /* selection/cursor clocks */
2621 toolbar_selection_cursor_label.set_name ("ToolBarLabel");
2622 selection_start_clock_label.set_name ("ToolBarLabel");
2623 selection_end_clock_label.set_name ("ToolBarLabel");
2624 edit_cursor_clock_label.set_name ("ToolBarLabel");
2626 selection_start_clock_label.set_text (_("Start:"));
2627 selection_end_clock_label.set_text (_("End:"));
2628 edit_cursor_clock_label.set_text (_("Edit:"));
2630 toolbar_selection_clock_table.set_border_width (5);
2631 toolbar_selection_clock_table.set_col_spacings (2);
2632 toolbar_selection_clock_table.set_homogeneous (false);
2634 // toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0);
2635 // toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0);
2636 toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, FILL, FILL, 0, 0);
2638 // toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0);
2639 // toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0);
2640 toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, FILL, FILL);
2643 // toolbar_clock_vbox.set_spacing (2);
2644 // toolbar_clock_vbox.set_border_width (10);
2645 /* the editor/mixer button will be enabled at session connect */
2647 editor_mixer_button.set_active(false);
2648 editor_mixer_button.set_sensitive(false);
2650 HBox* hbox = new HBox;
2652 hbox->pack_start (editor_mixer_button, false, false);
2653 hbox->pack_start (toolbar_selection_clock_table, false, false);
2654 hbox->pack_start (zoom_indicator_vbox, false, false);
2655 hbox->pack_start (zoom_focus_box, false, false);
2656 hbox->pack_start (snap_type_box, false, false);
2657 hbox->pack_start (snap_mode_box, false, false);
2658 hbox->pack_start (edit_mode_box, false, false);
2660 VBox *vbox = manage (new VBox);
2662 vbox->set_spacing (3);
2663 vbox->set_border_width (3);
2665 HBox *nbox = manage (new HBox);
2667 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
2668 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
2670 nbox->pack_start (nudge_backward_button, false, false);
2671 nbox->pack_start (nudge_forward_button, false, false);
2672 nbox->pack_start (nudge_clock, false, false, 5);
2674 nudge_label.set_name ("ToolBarLabel");
2676 vbox->pack_start (nudge_label, false, false);
2677 vbox->pack_start (*nbox, false, false);
2679 hbox->pack_start (*vbox, false, false);
2683 tools_tearoff = new TearOff (*hbox);
2684 tools_tearoff->set_name ("MouseModeBase");
2686 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
2687 tools_tearoff->tearoff_window()));
2688 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
2689 tools_tearoff->tearoff_window(), 0));
2692 toolbar_hbox.set_spacing (8);
2693 toolbar_hbox.set_border_width (2);
2695 toolbar_hbox.pack_start (*tools_tearoff, false, false);
2696 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
2698 toolbar_base.set_name ("ToolBarBase");
2699 toolbar_base.add (toolbar_hbox);
2701 toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT);
2702 toolbar_frame.set_name ("BaseFrame");
2703 toolbar_frame.add (toolbar_base);
2707 Editor::_autoscroll_canvas (void *arg)
2709 return ((Editor *) arg)->autoscroll_canvas ();
2713 Editor::autoscroll_canvas ()
2715 jack_nframes_t new_frame;
2716 bool keep_calling = true;
2718 if (autoscroll_direction < 0) {
2719 if (leftmost_frame < autoscroll_distance) {
2722 new_frame = leftmost_frame - autoscroll_distance;
2725 if (leftmost_frame > max_frames - autoscroll_distance) {
2726 new_frame = max_frames;
2728 new_frame = leftmost_frame + autoscroll_distance;
2732 if (new_frame != leftmost_frame) {
2733 reposition_x_origin (new_frame);
2736 if (new_frame == 0 || new_frame == max_frames) {
2743 if (autoscroll_cnt == 1) {
2745 /* connect the timeout so that we get called repeatedly */
2747 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
2748 keep_calling = false;
2750 } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
2752 /* after about a while, speed up a bit by changing the timeout interval */
2754 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
2755 keep_calling = false;
2757 } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
2759 /* after about another while, speed up some more */
2761 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
2762 keep_calling = false;
2764 } else if (autoscroll_cnt >= 30) {
2766 /* we've been scrolling for a while ... crank it up */
2768 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
2771 return keep_calling;
2775 Editor::start_canvas_autoscroll (int dir)
2781 stop_canvas_autoscroll ();
2783 autoscroll_direction = dir;
2784 autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
2787 /* do it right now, which will start the repeated callbacks */
2789 autoscroll_canvas ();
2793 Editor::stop_canvas_autoscroll ()
2795 if (autoscroll_timeout_tag >= 0) {
2796 gtk_timeout_remove (autoscroll_timeout_tag);
2797 autoscroll_timeout_tag = -1;
2802 Editor::convert_drop_to_paths (vector<string>& paths,
2803 GdkDragContext *context,
2806 GtkSelectionData *data,
2814 gchar *tname = gdk_atom_name (data->type);
2816 if (session == 0 || strcmp (tname, "text/plain") != 0) {
2820 /* Parse the "uri-list" format that Nautilus provides,
2821 where each pathname is delimited by \r\n
2824 path = (char *) data->data;
2827 for (int n = 0; n < data->length; ++n) {
2831 if (path[n] == '\r') {
2838 if (path[n] == '\n') {
2839 paths.push_back (spath);
2843 warning << _("incorrectly formatted URI list, ignored")
2851 /* nautilus and presumably some other file managers prefix even text/plain with file:// */
2853 for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
2855 // cerr << "dropped text was " << *p << endl;
2859 // cerr << "decoded was " << *p << endl;
2861 if ((*p).substr (0,7) == "file://") {
2862 (*p) = (*p).substr (7);
2870 Editor::track_canvas_drag_data_received (GdkDragContext *context,
2873 GtkSelectionData *data,
2878 AudioTimeAxisView* tv;
2880 vector<string> paths;
2883 jack_nframes_t frame;
2885 if (convert_drop_to_paths (paths, context, x, y, data, info, time)) {
2889 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
2895 track_canvas.c2w( x, y, wx, wy);
2897 ev.type = GDK_BUTTON_RELEASE;
2901 frame = event_frame (&ev, 0, &cy);
2905 if ((tvp = trackview_by_y_position (cy)) == 0) {
2907 /* drop onto canvas background: create a new track */
2909 insert_paths_as_new_tracks (paths, false);
2912 } else if ((tv = dynamic_cast<AudioTimeAxisView*>(tvp)) != 0) {
2914 /* check that its an audio track, not a bus */
2916 if (tv->get_diskstream()) {
2918 for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
2919 insert_sndfile_into (*p, true, tv, frame);
2926 gtk_drag_finish (context, TRUE, FALSE, time);
2930 Editor::new_tempo_section ()
2936 Editor::map_transport_state ()
2938 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
2940 if (session->transport_stopped()) {
2941 have_pending_keyboard_selection = false;
2947 Editor::State::State ()
2949 selection = new Selection;
2952 Editor::State::~State ()
2958 Editor::get_memento () const
2960 State *state = new State;
2962 store_state (*state);
2963 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
2967 Editor::store_state (State& state) const
2969 *state.selection = *selection;
2973 Editor::restore_state (State *state)
2975 if (*selection == *state->selection) {
2979 *selection = *state->selection;
2980 time_selection_changed ();
2981 region_selection_changed ();
2983 /* XXX other selection change handlers? */
2987 Editor::begin_reversible_command (string name)
2990 UndoAction ua = get_memento();
2991 session->begin_reversible_command (name, &ua);
2996 Editor::commit_reversible_command ()
2999 UndoAction ua = get_memento();
3000 session->commit_reversible_command (&ua);
3005 Editor::flush_track_canvas ()
3007 /* I don't think this is necessary, and only causes more problems.
3008 I'm commenting it out
3009 and if the imageframe folks don't have any issues, we can take
3010 out this method entirely
3013 //gnome_canvas_update_now (GNOME_CANVAS(track_canvas));
3014 //gtk_main_iteration ();
3018 Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove)
3020 if (!clicked_trackview) {
3025 begin_reversible_command (_("set selected trackview"));
3030 if (selection->selected (clicked_trackview)) {
3032 selection->remove (clicked_trackview);
3035 selection->add (clicked_trackview);
3040 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
3041 /* no commit necessary */
3045 selection->set (clicked_trackview);
3049 commit_reversible_command ();
3054 Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove)
3056 if (!clicked_control_point) {
3061 begin_reversible_command (_("set selected control point"));
3071 commit_reversible_command ();
3076 Editor::set_selected_regionview_from_click (bool add, bool no_track_remove)
3078 if (!clicked_regionview) {
3082 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view());
3088 RouteGroup* group = atv->route().edit_group();
3089 vector<AudioRegionView*> all_equivalent_regions;
3091 if (group && group->is_active()) {
3093 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3095 AudioTimeAxisView* tatv;
3097 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3099 if (tatv->route().edit_group() != group) {
3104 vector<AudioRegion*> results;
3105 AudioRegionView* marv;
3108 if ((ds = tatv->get_diskstream()) == 0) {
3113 if ((pl = ds->playlist()) != 0) {
3114 pl->get_equivalent_regions (clicked_regionview->region,
3118 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3119 if ((marv = tatv->view->find_view (**ir)) != 0) {
3120 all_equivalent_regions.push_back (marv);
3129 all_equivalent_regions.push_back (clicked_regionview);
3133 begin_reversible_command (_("set selected regionview"));
3137 if (clicked_regionview->get_selected()) {
3138 if (group && group->is_active() && selection->audio_regions.size() > 1) {
3139 /* reduce selection down to just the one clicked */
3140 selection->set (clicked_regionview);
3142 selection->remove (clicked_regionview);
3145 selection->add (all_equivalent_regions);
3148 set_selected_track_from_click (add, false, no_track_remove);
3152 // karsten wiese suggested these two lines to make
3153 // a selected region rise to the top. but this
3154 // leads to a mismatch between actual layering
3155 // and visual layering. resolution required ....
3157 // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3158 // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3160 if (clicked_regionview->get_selected()) {
3161 /* no commit necessary: we are the one selected. */
3166 selection->set (all_equivalent_regions);
3167 set_selected_track_from_click (add, false, false);
3171 commit_reversible_command () ;
3175 Editor::set_selected_regionview_from_region_list (Region& r, bool add)
3177 vector<AudioRegionView*> all_equivalent_regions;
3178 AudioRegion* region;
3180 if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3184 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3186 AudioTimeAxisView* tatv;
3188 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3191 vector<AudioRegion*> results;
3192 AudioRegionView* marv;
3195 if ((ds = tatv->get_diskstream()) == 0) {
3200 if ((pl = ds->playlist()) != 0) {
3201 pl->get_region_list_equivalent_regions (*region, results);
3204 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3205 if ((marv = tatv->view->find_view (**ir)) != 0) {
3206 all_equivalent_regions.push_back (marv);
3213 begin_reversible_command (_("set selected regions"));
3217 selection->add (all_equivalent_regions);
3221 selection->set (all_equivalent_regions);
3224 commit_reversible_command () ;
3228 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3230 AudioRegionView* rv;
3233 if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3237 if ((rv = sv->find_view (*ar)) == 0) {
3241 /* don't reset the selection if its something other than
3242 a single other region.
3245 if (selection->audio_regions.size() > 1) {
3249 begin_reversible_command (_("set selected regions"));
3251 selection->set (rv);
3253 commit_reversible_command () ;
3259 Editor::set_edit_group_solo (Route& route, bool yn)
3261 RouteGroup *edit_group;
3263 if ((edit_group = route.edit_group()) != 0) {
3264 edit_group->apply (&Route::set_solo, yn, this);
3266 route.set_solo (yn, this);
3271 Editor::set_edit_group_mute (Route& route, bool yn)
3273 RouteGroup *edit_group = 0;
3275 if ((edit_group == route.edit_group()) != 0) {
3276 edit_group->apply (&Route::set_mute, yn, this);
3278 route.set_mute (yn, this);
3283 Editor::set_edit_menu (Menu& menu)
3286 edit_menu->signal_map_event().connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3290 Editor::edit_menu_map_handler (GdkEventAny* ev)
3292 using namespace Menu_Helpers;
3293 MenuList& edit_items = edit_menu->items();
3296 /* Nuke all the old items */
3298 edit_items.clear ();
3304 if (session->undo_depth() == 0) {
3307 label = string_compose(_("Undo (%1)"), session->next_undo());
3310 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3312 if (session->undo_depth() == 0) {
3313 edit_items.back().set_sensitive (false);
3316 if (session->redo_depth() == 0) {
3319 label = string_compose(_("Redo (%1)"), session->next_redo());
3322 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3323 if (session->redo_depth() == 0) {
3324 edit_items.back().set_sensitive (false);
3327 vector<MenuItem*> mitems;
3329 edit_items.push_back (SeparatorElem());
3330 edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3331 mitems.push_back (&edit_items.back());
3332 edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3333 mitems.push_back (&edit_items.back());
3334 edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3335 mitems.push_back (&edit_items.back());
3336 edit_items.push_back (SeparatorElem());
3337 edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3338 mitems.push_back (&edit_items.back());
3339 edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3340 mitems.push_back (&edit_items.back());
3341 edit_items.push_back (SeparatorElem());
3343 if (selection->empty()) {
3344 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3345 (*i)->set_sensitive (false);
3349 Menu* import_menu = manage (new Menu());
3350 import_menu->set_name ("ArdourContextMenu");
3351 MenuList& import_items = import_menu->items();
3353 import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3354 import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3356 Menu* embed_menu = manage (new Menu());
3357 embed_menu->set_name ("ArdourContextMenu");
3358 MenuList& embed_items = embed_menu->items();
3360 embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3361 embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3363 edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3364 edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3365 edit_items.push_back (SeparatorElem());
3367 edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3368 if (!session->have_captured()) {
3369 edit_items.back().set_sensitive (false);
3376 Editor::duplicate_dialog (bool dup_region)
3379 if (clicked_regionview == 0) {
3383 if (selection->time.length() == 0) {
3388 ArdourDialog win ("duplicate dialog");
3390 Label label (_("Duplicate how many times?"));
3392 win.get_vbox()->pack_start (label);
3393 win.add_action_widget (entry, RESPONSE_ACCEPT);
3394 win.add_button (Stock::OK, RESPONSE_ACCEPT);
3395 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3397 win.set_position (Gtk::WIN_POS_MOUSE);
3399 entry.set_text ("1");
3400 set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
3401 entry.select_region (0, entry.get_text_length());
3402 entry.grab_focus ();
3405 // win.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
3408 switch (win.run ()) {
3409 case RESPONSE_ACCEPT:
3415 string text = entry.get_text();
3418 if (sscanf (text.c_str(), "%f", ×) == 1) {
3420 AudioRegionSelection regions;
3421 regions.add (clicked_regionview);
3422 duplicate_some_regions (regions, times);
3424 duplicate_selection (times);
3430 Editor::show_verbose_canvas_cursor ()
3432 verbose_canvas_cursor->raise_to_top();
3433 verbose_canvas_cursor->show();
3434 verbose_cursor_visible = true;
3438 Editor::hide_verbose_canvas_cursor ()
3440 verbose_canvas_cursor->hide();
3441 verbose_cursor_visible = false;
3445 Editor::set_verbose_canvas_cursor (string txt, double x, double y)
3447 /* XXX get origin of canvas relative to root window,
3448 add x and y and check compared to gdk_screen_{width,height}
3450 verbose_canvas_cursor->property_text() = txt.c_str();
3451 verbose_canvas_cursor->property_x() = x;
3452 verbose_canvas_cursor->property_y() = y;
3456 Editor::set_verbose_canvas_cursor_text (string txt)
3458 verbose_canvas_cursor->property_text() = txt.c_str();
3462 Editor::edit_mode_selection_done ()
3468 string choice = edit_mode_selector.get_active_text();
3469 EditMode mode = Slide;
3471 if (choice == _("Splice")) {
3473 } else if (choice == _("Slide")) {
3477 session->set_edit_mode (mode);
3481 Editor::snap_type_selection_done ()
3487 string choice = snap_type_selector.get_active_text();
3488 SnapType snaptype = SnapToFrame;
3490 if (choice == _("Beats/3")) {
3491 snaptype = SnapToAThirdBeat;
3492 } else if (choice == _("Beats/4")) {
3493 snaptype = SnapToAQuarterBeat;
3494 } else if (choice == _("Beats/8")) {
3495 snaptype = SnapToAEighthBeat;
3496 } else if (choice == _("Beats/16")) {
3497 snaptype = SnapToASixteenthBeat;
3498 } else if (choice == _("Beats/32")) {
3499 snaptype = SnapToAThirtysecondBeat;
3500 } else if (choice == _("Beats")) {
3501 snaptype = SnapToBeat;
3502 } else if (choice == _("Bars")) {
3503 snaptype = SnapToBar;
3504 } else if (choice == _("Marks")) {
3505 snaptype = SnapToMark;
3506 } else if (choice == _("Edit Cursor")) {
3507 snaptype = SnapToEditCursor;
3508 } else if (choice == _("Region starts")) {
3509 snaptype = SnapToRegionStart;
3510 } else if (choice == _("Region ends")) {
3511 snaptype = SnapToRegionEnd;
3512 } else if (choice == _("Region bounds")) {
3513 snaptype = SnapToRegionBoundary;
3514 } else if (choice == _("Region syncs")) {
3515 snaptype = SnapToRegionSync;
3516 } else if (choice == _("CD Frames")) {
3517 snaptype = SnapToCDFrame;
3518 } else if (choice == _("SMPTE Frames")) {
3519 snaptype = SnapToSMPTEFrame;
3520 } else if (choice == _("SMPTE Seconds")) {
3521 snaptype = SnapToSMPTESeconds;
3522 } else if (choice == _("SMPTE Minutes")) {
3523 snaptype = SnapToSMPTEMinutes;
3524 } else if (choice == _("Seconds")) {
3525 snaptype = SnapToSeconds;
3526 } else if (choice == _("Minutes")) {
3527 snaptype = SnapToMinutes;
3528 } else if (choice == _("None")) {
3529 snaptype = SnapToFrame;
3532 set_snap_to (snaptype);
3536 Editor::snap_mode_selection_done ()
3542 string choice = snap_mode_selector.get_active_text();
3543 SnapMode mode = SnapNormal;
3545 if (choice == _("Normal")) {
3547 } else if (choice == _("Magnetic")) {
3548 mode = SnapMagnetic;
3551 set_snap_mode (mode);
3555 Editor::zoom_focus_selection_done ()
3561 string choice = zoom_focus_selector.get_active_text();
3562 ZoomFocus focus_type = ZoomFocusLeft;
3564 if (choice == _("Left")) {
3565 focus_type = ZoomFocusLeft;
3566 } else if (choice == _("Right")) {
3567 focus_type = ZoomFocusRight;
3568 } else if (choice == _("Center")) {
3569 focus_type = ZoomFocusCenter;
3570 } else if (choice == _("Playhead")) {
3571 focus_type = ZoomFocusPlayhead;
3572 } else if (choice == _("Edit Cursor")) {
3573 focus_type = ZoomFocusEdit;
3576 set_zoom_focus (focus_type);
3580 Editor::edit_controls_button_release (GdkEventButton* ev)
3582 if (Keyboard::is_context_menu_event (ev)) {
3583 ARDOUR_UI::instance()->add_route ();
3589 Editor::track_selection_changed ()
3591 switch (selection->tracks.size()){
3595 set_selected_mixer_strip (*(selection->tracks.front()));
3599 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3600 (*i)->set_selected (false);
3601 if (mouse_mode == MouseRange) {
3602 (*i)->hide_selection ();
3606 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3607 (*i)->set_selected (true);
3608 if (mouse_mode == MouseRange) {
3609 (*i)->show_selection (selection->time);
3615 Editor::time_selection_changed ()
3617 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3618 (*i)->hide_selection ();
3621 if (selection->tracks.empty()) {
3622 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3623 (*i)->show_selection (selection->time);
3626 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3627 (*i)->show_selection (selection->time);
3633 Editor::region_selection_changed ()
3635 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3636 (*i)->set_selected_regionviews (selection->audio_regions);
3641 Editor::point_selection_changed ()
3643 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3644 (*i)->set_selected_points (selection->points);
3649 Editor::run_sub_event_loop ()
3651 sub_event_loop_status = 0;
3656 Editor::finish_sub_event_loop (int status)
3659 sub_event_loop_status = status;
3663 Editor::finish_sub_event_loop_on_delete (GdkEventAny *ignored, int32_t status)
3665 finish_sub_event_loop (status);
3670 Editor::mouse_select_button_release (GdkEventButton* ev)
3672 /* this handles just right-clicks */
3674 if (ev->button != 3) {
3681 Editor::TrackViewList *
3682 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
3685 TrackViewList::iterator i;
3687 v = new TrackViewList;
3689 if (track == 0 && group == 0) {
3693 for (i = track_views.begin(); i != track_views.end (); ++i) {
3697 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
3699 /* just the view for this track
3702 v->push_back (track);
3706 /* views for all tracks in the edit group */
3708 for (i = track_views.begin(); i != track_views.end (); ++i) {
3710 if (group == 0 || (*i)->edit_group() == group) {
3720 Editor::set_zoom_focus (ZoomFocus f)
3722 if (zoom_focus != f) {
3724 vector<string> txt = internationalize (zoom_focus_strings);
3725 zoom_focus_selector.set_active_text (txt[(int)f]);
3726 ZoomFocusChanged (); /* EMIT_SIGNAL */
3733 Editor::ensure_float (Window& win)
3735 win.set_transient_for (*this);
3739 Editor::pane_allocation_handler (Gtk::Allocation &alloc, Gtk::Paned* which)
3741 /* recover or initialize pane positions. do this here rather than earlier because
3742 we don't want the positions to change the child allocations, which they seem to do.
3748 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3750 static int32_t done[4] = { 0, 0, 0, 0 };
3753 if ((geometry = find_named_node (*node, "geometry")) == 0) {
3754 width = default_width;
3755 height = default_height;
3757 width = atoi(geometry->property("x_size")->value());
3758 height = atoi(geometry->property("y_size")->value());
3761 if (which == static_cast<Gtk::Paned*> (&track_list_canvas_pane)) {
3767 if (!geometry || (prop = geometry->property("track_list_canvas_pane_pos")) == 0) {
3769 snprintf (buf, sizeof(buf), "%d", pos);
3771 pos = atoi (prop->value());
3774 if ((done[0] = GTK_WIDGET(track_list_canvas_pane.gobj())->allocation.width > pos)) {
3775 track_list_canvas_pane.set_position (pos);
3778 } else if (which == static_cast<Gtk::Paned*> (&canvas_region_list_pane)) {
3784 if (!geometry || (prop = geometry->property("canvas_region_list_pane_pos")) == 0) {
3785 pos = width - (95 * 2);
3786 snprintf (buf, sizeof(buf), "%d", pos);
3788 pos = atoi (prop->value());
3791 if ((done[1] = GTK_WIDGET(canvas_region_list_pane.gobj())->allocation.width > pos)) {
3792 canvas_region_list_pane.set_position (pos);
3795 } else if (which == static_cast<Gtk::Paned*> (&route_group_vpane)) {
3801 if (!geometry || (prop = geometry->property("route_group_pane_pos")) == 0) {
3802 pos = width - (95 * 2);
3803 snprintf (buf, sizeof(buf), "%d", pos);
3805 pos = atoi (prop->value());
3808 if ((done[2] = GTK_WIDGET(route_group_vpane.gobj())->allocation.height > pos)) {
3809 route_group_vpane.set_position (pos);
3812 } else if (which == static_cast<Gtk::Paned*> (®ion_selection_vpane)) {
3818 if (!geometry || (prop = geometry->property("region_selection_pane_pos")) == 0) {
3819 pos = width - (95 * 2);
3820 snprintf (buf, sizeof(buf), "%d", pos);
3822 pos = atoi (prop->value());
3825 if ((done[3] = GTK_WIDGET(region_selection_vpane.gobj())->allocation.height > pos)) {
3826 region_selection_vpane.set_position (pos);
3832 Editor::detach_tearoff (Gtk::Box* b, Gtk::Window* w)
3834 if (tools_tearoff->torn_off() &&
3835 mouse_mode_tearoff->torn_off()) {
3836 top_hbox.remove (toolbar_frame);
3843 Editor::reattach_tearoff (Gtk::Box* b, Gtk::Window* w, int32_t n)
3845 if (toolbar_frame.get_parent() == 0) {
3846 top_hbox.pack_end (toolbar_frame);
3851 Editor::set_show_measures (bool yn)
3853 if (_show_measures != yn) {
3856 if ((_show_measures = yn) == true) {
3859 DisplayControlChanged (ShowMeasures);
3865 Editor::set_follow_playhead (bool yn)
3867 if (_follow_playhead != yn) {
3868 if ((_follow_playhead = yn) == true) {
3870 update_current_screen ();
3872 DisplayControlChanged (FollowPlayhead);
3878 Editor::toggle_xfade_active (Crossfade* xfade)
3880 xfade->set_active (!xfade->active());
3884 Editor::toggle_xfade_length (Crossfade* xfade)
3886 xfade->set_follow_overlap (!xfade->following_overlap());
3890 Editor::edit_xfade (Crossfade* xfade)
3892 CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
3897 // cew.signal_delete_event().connect (mem_fun (cew, &ArdourDialog::wm_doi_event_stop));
3899 switch (cew.run ()) {
3900 case RESPONSE_ACCEPT:
3907 xfade->StateChanged (Change (~0));
3911 Editor::playlist_selector () const
3913 return *_playlist_selector;
3917 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
3921 ret = nudge_clock.current_duration (pos);
3922 next = ret + 1; /* XXXX fix me */
3928 Editor::end_location_changed (Location* location)
3930 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
3931 track_canvas_scroller.get_hadjustment()->set_upper (location->end() / frames_per_unit);
3935 Editor::playlist_deletion_dialog (Playlist* pl)
3937 ArdourDialog dialog ("playlist deletion dialog");
3938 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3939 "If left alone, no audio files used by it will be cleaned.\n"
3940 "If deleted, audio files used by it alone by will cleaned."),
3943 dialog.set_position (Gtk::WIN_POS_CENTER);
3944 dialog.get_vbox()->pack_start (label);
3946 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3947 dialog.add_button (_("Keep playlist"), RESPONSE_CANCEL);
3948 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3950 switch (dialog.run ()) {
3951 case RESPONSE_ACCEPT:
3952 /* delete the playlist */
3956 case RESPONSE_REJECT:
3957 /* keep the playlist */
3969 Editor::audio_region_selection_covers (jack_nframes_t where)
3971 for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
3972 if ((*a)->region.covers (where)) {
3981 Editor::prepare_for_cleanup ()
3983 cut_buffer->clear_audio_regions ();
3984 cut_buffer->clear_playlists ();
3986 selection->clear_audio_regions ();
3987 selection->clear_playlists ();
3991 Editor::init_colormap ()
3993 for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) {
3994 pair<ColorID,int> newpair;
3996 newpair.first = (ColorID) x;
3997 newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255);
3998 color_map.insert (newpair);
4003 Editor::transport_loop_location()
4006 return session->locations()->auto_loop_location();
4013 Editor::transport_punch_location()
4016 return session->locations()->auto_punch_location();