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 <gtk-canvas.h>
30 #include <pbd/error.h>
32 #include <gtkmm2ext/gtk_ui.h>
33 #include <gtkmm2ext/tearoff.h>
34 #include <gtkmm2ext/utils.h>
36 #include <ardour/audio_track.h>
37 #include <ardour/diskstream.h>
38 #include <ardour/plugin_manager.h>
39 #include <ardour/location.h>
40 #include <ardour/audioplaylist.h>
41 #include <ardour/audioregion.h>
42 #include <ardour/session.h>
43 #include <ardour/session_route.h>
44 #include <ardour/tempo.h>
45 #include <ardour/utils.h>
47 #include "ardour_ui.h"
48 #include "canvas-ruler.h"
49 #include "canvas-simpleline.h"
50 #include "canvas-simplerect.h"
51 #include "canvas-waveview.h"
52 #include "check_mark.h"
54 #include "grouped_buttons.h"
56 #include "library_ui.h"
58 #include "playlist_selector.h"
59 #include "regionview.h"
60 #include "rgb_macros.h"
61 #include "selection.h"
62 #include "streamview.h"
63 #include "time_axis_view.h"
65 #include "crossfade_view.h"
67 #include "public_editor.h"
68 #include "crossfade_edit.h"
69 #include "extra_bind.h"
70 #include "audio_time_axis.h"
71 #include "gui_thread.h"
76 #include "imageframe_socket_handler.h"
77 /* </CMT Additions> */
81 using namespace ARDOUR;
83 using namespace Gtkmm2ext;
84 using namespace Editing;
86 /* XXX this is a hack. it ought to be the maximum value of an jack_nframes_t */
88 const double max_canvas_coordinate = 100000000.0;
89 const double Editor::timebar_height = 15.0;
91 #include "editor_xpms"
93 static const gchar *route_list_titles[] = {
98 static const gchar *edit_group_list_titles[] = {
102 static const gchar *region_list_display_titles[] = {
107 static const gchar *named_selection_display_titles[] = {
112 static const int32_t slide_index = 0;
113 static const int32_t splice_index = 1;
115 static const gchar *edit_mode_strings[] = {
121 static const gchar *snap_type_strings[] = {
145 static const gchar *snap_mode_strings[] = {
151 static const gchar *zoom_focus_strings[] = {
160 /* Soundfile drag-n-drop */
168 static GtkTargetEntry target_table[] = {
169 { "STRING", 0, TARGET_STRING },
170 { "text/plain", 0, TARGET_STRING },
171 { "text/uri-list", 0, TARGET_URL },
172 { "application/x-rootwin-drop", 0, TARGET_ROOTWIN }
175 static guint n_targets = sizeof(target_table) / sizeof(target_table[0]);
177 GdkCursor* Editor::cross_hair_cursor = 0;
178 GdkCursor* Editor::selector_cursor = 0;
179 GdkCursor* Editor::trimmer_cursor = 0;
180 GdkCursor* Editor::grabber_cursor = 0;
181 GdkCursor* Editor::zoom_cursor = 0;
182 GdkCursor* Editor::time_fx_cursor = 0;
183 GdkCursor* Editor::fader_cursor = 0;
184 GdkCursor* Editor::speaker_cursor = 0;
185 GdkCursor* Editor::null_cursor = 0;
186 GdkCursor* Editor::wait_cursor = 0;
187 GdkCursor* Editor::timebar_cursor = 0;
189 GdkPixmap *Editor::check_pixmap = 0;
190 GdkBitmap *Editor::check_mask = 0;
191 GdkPixmap *Editor::empty_pixmap = 0;
192 GdkBitmap *Editor::empty_mask = 0;
194 extern gint route_list_compare_func (GtkCList*,gconstpointer,gconstpointer);
196 Editor::Editor (AudioEngine& eng)
199 /* time display buttons */
201 minsec_label (_("Mins:Secs")),
202 bbt_label (_("Bars:Beats")),
203 smpte_label (_("SMPTE")),
204 frame_label (_("Frames")),
205 tempo_label (_("Tempo")),
206 meter_label (_("Meter")),
207 mark_label (_("Location Markers")),
208 range_mark_label (_("Range Markers")),
209 transport_mark_label (_("Loop/Punch Ranges")),
211 edit_packer (3, 3, false),
212 edit_hscroll_left_arrow (Gtk::ARROW_LEFT, Gtk::SHADOW_OUT),
213 edit_hscroll_right_arrow (Gtk::ARROW_RIGHT, Gtk::SHADOW_OUT),
215 region_list_display (internationalize (region_list_display_titles)),
217 named_selection_display (internationalize (named_selection_display_titles)),
219 /* tool bar related */
221 editor_mixer_button (_("editor\nmixer")),
223 selection_start_clock (X_("SelectionStartClock"), true),
224 selection_end_clock (X_("SelectionEndClock"), true),
225 edit_cursor_clock (X_("EditCursorClock"), true),
226 zoom_range_clock (X_("ZoomRangeClock"), true, true),
228 toolbar_selection_clock_table (2,3),
230 mouse_mode_button_table (2, 3),
232 mouse_select_button (_("range")),
233 mouse_move_button (_("object")),
234 mouse_gain_button (_("gain")),
235 mouse_zoom_button (_("zoom")),
236 mouse_timefx_button (_("timefx")),
237 mouse_audition_button (_("listen")),
239 automation_mode_button (_("mode")),
240 global_automation_button (_("automation")),
242 edit_mode_label (_("Edit Mode")),
243 snap_type_label (_("Snap To")),
244 snap_mode_label(_("Snap Mode")),
245 zoom_focus_label (_("Zoom Focus")),
247 route_list (internationalize (route_list_titles)),
248 edit_group_list (internationalize (edit_group_list_titles)),
250 /* <CMT Additions> */
251 image_socket_listener(0),
252 /* </CMT Additions> */
256 nudge_label (_("Nudge")),
257 nudge_clock (X_("NudgeClock"), true, true)
262 /* we are a singleton */
264 PublicEditor::_instance = this;
268 check_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
269 gtk_widget_get_colormap (GTK_WIDGET(edit_group_list.gobj())),
270 &check_mask, NULL, (gchar **) check_xpm);
271 empty_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
272 gtk_widget_get_colormap (GTK_WIDGET(edit_group_list.gobj())),
273 &empty_mask, NULL, (gchar **) empty_xpm);
277 selection = new Selection;
278 cut_buffer = new Selection;
280 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
281 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
282 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
283 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
285 clicked_regionview = 0;
286 clicked_trackview = 0;
287 clicked_audio_trackview = 0;
288 clicked_crossfadeview = 0;
289 clicked_control_point = 0;
290 latest_regionview = 0;
291 region_list_display_drag_region = 0;
292 last_update_frame = 0;
294 last_audition_region = 0;
295 region_list_button_region = 0;
296 current_mixer_strip = 0;
297 current_bbt_points = 0;
299 snap_type = SnapToFrame;
300 set_snap_to (snap_type);
301 snap_mode = SnapNormal;
302 set_snap_mode (snap_mode);
303 snap_threshold = 5.0;
304 bbt_beat_subdivision = 4;
307 autoscroll_timeout_tag = -1;
308 interthread_progress_window = 0;
309 current_interthread_info = 0;
310 _show_measures = true;
311 _show_waveforms = true;
312 _show_waveforms_recording = true;
313 first_action_message = 0;
315 show_gain_after_trim = false;
316 no_zoom_repos_update = false;
317 need_wave_cursor = 0;
318 ignore_route_list_reorder = false;
319 verbose_cursor_on = true;
320 route_removal = false;
322 show_automatic_regions_in_region_list = true;
323 have_pending_keyboard_selection = false;
324 _follow_playhead = true;
325 _xfade_visibility = true;
326 editor_ruler_menu = 0;
327 no_ruler_shown_update = false;
328 edit_group_list_menu = 0;
330 region_list_menu = 0;
332 marker_menu_item = 0;
334 transport_marker_menu = 0;
335 new_transport_marker_menu = 0;
336 editor_mixer_strip_width = Wide;
337 repos_zoom_queued = false;
338 import_audio_item = 0;
339 embed_audio_item = 0;
340 region_edit_menu_split_item = 0;
342 region_edit_menu_split_multichannel_item = 0;
343 edit_hscroll_dragging = false;
345 ignore_mouse_mode_toggle = false;
346 current_stepping_trackview = 0;
348 entered_regionview = 0;
349 clear_entered_track = false;
350 _new_regionviews_show_envelope = false;
351 current_timestretch = 0;
356 location_marker_color = color_map[cLocationMarker];
357 location_range_color = color_map[cLocationRange];
358 location_cd_marker_color = color_map[cLocationCDMarker];
359 location_loop_color = color_map[cLocationLoop];
360 location_punch_color = color_map[cLocationPunch];
362 range_marker_drag_rect = 0;
363 marker_drag_line = 0;
365 mouse_mode = MouseZoom; /* force change in next call */
366 set_mouse_mode (MouseObject, true);
368 frames_per_unit = 2048; /* too early to use set_frames_per_unit */
369 zoom_focus = ZoomFocusLeft;
370 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
372 initialize_rulers ();
373 initialize_canvas ();
375 track_canvas_scroller.add (*track_canvas);
376 track_canvas_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
377 track_canvas_scroller.set_name ("TrackCanvasScroller");
379 track_canvas_scroller.get_vadjustment()->value_changed.connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
380 track_canvas_scroller.get_vadjustment()->set_step_increment (10.0);
382 track_canvas_scroller.get_hadjustment()->set_lower (0.0);
383 track_canvas_scroller.get_hadjustment()->set_upper (1200.0);
384 track_canvas_scroller.get_hadjustment()->set_step_increment (20.0);
385 track_canvas_scroller.get_hadjustment()->value_changed.connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
387 edit_vscrollbar.set_adjustment(track_canvas_scroller.get_vadjustment());
388 edit_hscrollbar.set_adjustment(track_canvas_scroller.get_hadjustment());
390 edit_hscrollbar.button_press_event.connect (mem_fun(*this, &Editor::hscroll_slider_button_press));
391 edit_hscrollbar.button_release_event.connect (mem_fun(*this, &Editor::hscroll_slider_button_release));
392 edit_hscrollbar.size_allocate.connect (mem_fun(*this, &Editor::hscroll_slider_allocate));
394 time_canvas_scroller.add (*time_canvas);
395 time_canvas_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
396 time_canvas_scroller.set_hadjustment (track_canvas_scroller.get_hadjustment());
397 time_canvas_scroller.set_name ("TimeCanvasScroller");
399 edit_controls_vbox.set_spacing (track_spacing);
400 edit_controls_hbox.pack_start (edit_controls_vbox, true, true);
401 edit_controls_scroller.add_with_viewport (edit_controls_hbox);
402 edit_controls_scroller.set_name ("EditControlsBase");
403 edit_controls_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
405 Viewport* viewport = static_cast<Viewport*> (edit_controls_scroller.get_child());
407 viewport->set_shadow_type (GTK_SHADOW_NONE);
408 viewport->set_name ("EditControlsBase");
409 viewport->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK);
410 viewport->button_release_event.connect (mem_fun(*this, &Editor::edit_controls_button_release));
415 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
418 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
420 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
421 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
422 time_canvas_vbox.pack_start (*frames_ruler, false, false);
423 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
424 time_canvas_vbox.pack_start (time_canvas_scroller, true, true);
425 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars));
427 bbt_label.set_name ("EditorTimeButton");
428 bbt_label.set_size_request (-1, (int)timebar_height);
429 bbt_label.set_alignment (1.0, 0.5);
430 bbt_label.set_padding (5,0);
431 minsec_label.set_name ("EditorTimeButton");
432 minsec_label.set_size_request (-1, (int)timebar_height);
433 minsec_label.set_alignment (1.0, 0.5);
434 minsec_label.set_padding (5,0);
435 smpte_label.set_name ("EditorTimeButton");
436 smpte_label.set_size_request (-1, (int)timebar_height);
437 smpte_label.set_alignment (1.0, 0.5);
438 smpte_label.set_padding (5,0);
439 frame_label.set_name ("EditorTimeButton");
440 frame_label.set_size_request (-1, (int)timebar_height);
441 frame_label.set_alignment (1.0, 0.5);
442 frame_label.set_padding (5,0);
443 tempo_label.set_name ("EditorTimeButton");
444 tempo_label.set_size_request (-1, (int)timebar_height);
445 tempo_label.set_alignment (1.0, 0.5);
446 tempo_label.set_padding (5,0);
447 meter_label.set_name ("EditorTimeButton");
448 meter_label.set_size_request (-1, (int)timebar_height);
449 meter_label.set_alignment (1.0, 0.5);
450 meter_label.set_padding (5,0);
451 mark_label.set_name ("EditorTimeButton");
452 mark_label.set_size_request (-1, (int)timebar_height);
453 mark_label.set_alignment (1.0, 0.5);
454 mark_label.set_padding (5,0);
455 range_mark_label.set_name ("EditorTimeButton");
456 range_mark_label.set_size_request (-1, (int)timebar_height);
457 range_mark_label.set_alignment (1.0, 0.5);
458 range_mark_label.set_padding (5,0);
459 transport_mark_label.set_name ("EditorTimeButton");
460 transport_mark_label.set_size_request (-1, (int)timebar_height);
461 transport_mark_label.set_alignment (1.0, 0.5);
462 transport_mark_label.set_padding (5,0);
464 time_button_vbox.pack_start (minsec_label, false, false);
465 time_button_vbox.pack_start (smpte_label, false, false);
466 time_button_vbox.pack_start (frame_label, false, false);
467 time_button_vbox.pack_start (bbt_label, false, false);
468 time_button_vbox.pack_start (meter_label, false, false);
469 time_button_vbox.pack_start (tempo_label, false, false);
470 time_button_vbox.pack_start (mark_label, false, false);
472 time_button_event_box.add (time_button_vbox);
474 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
475 time_button_event_box.set_name ("TimebarLabelBase");
476 time_button_event_box.button_release_event.connect (mem_fun(*this, &Editor::ruler_label_button_release));
478 /* these enable us to have a dedicated window (for cursor setting, etc.)
479 for the canvas areas.
482 track_canvas_event_box.add (track_canvas_scroller);
484 time_canvas_event_box.add (time_canvas_vbox);
485 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
488 edit_packer.set_col_spacings (0);
489 edit_packer.set_row_spacings (0);
490 edit_packer.set_homogeneous (false);
491 edit_packer.set_name ("EditorWindow");
493 // edit_packer.attach (edit_hscroll_left_arrow_event, 0, 1, 0, 1, Gtk::FILL, 0, 0, 0);
494 // edit_packer.attach (edit_hscroll_slider, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, 0, 0, 0);
495 // edit_packer.attach (edit_hscroll_right_arrow_event, 2, 3, 0, 1, Gtk::FILL, 0, 0, 0);
496 edit_packer.attach (edit_hscrollbar, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, 0, 0, 0);
498 edit_packer.attach (time_button_event_box, 0, 1, 1, 2, Gtk::FILL, 0, 0, 0);
499 edit_packer.attach (time_canvas_event_box, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, 0, 0, 0);
501 edit_packer.attach (edit_controls_scroller, 0, 1, 2, 3, Gtk::FILL, Gtk::FILL|Gtk::EXPAND, 0, 0);
502 edit_packer.attach (track_canvas_event_box, 1, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
503 edit_packer.attach (edit_vscrollbar, 2, 3, 2, 3, 0, Gtk::FILL|Gtk::EXPAND, 0, 0);
505 edit_frame.set_name ("BaseFrame");
506 edit_frame.set_shadow_type (Gtk::SHADOW_IN);
507 edit_frame.add (edit_packer);
509 zoom_in_button.set_name ("EditorTimeButton");
510 zoom_out_button.set_name ("EditorTimeButton");
511 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in"));
512 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out"));
514 // zoom_onetoone_button.set_name ("EditorTimeButton");
515 zoom_out_full_button.set_name ("EditorTimeButton");
516 // ARDOUR_UI::instance()->tooltips().set_tip (zoom_onetoone_button, _("Zoom in 1:1"));
517 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session"));
519 zoom_in_button.add (*(manage (new Gtk::Image (zoom_in_button_xpm))));
520 zoom_out_button.add (*(manage (new Gtk::Image (zoom_out_button_xpm))));
521 zoom_out_full_button.add (*(manage (new Gtk::Image (zoom_out_full_button_xpm))));
522 // zoom_onetoone_button.add (*(manage (new Gtk::Image (zoom_onetoone_button_xpm))));
525 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
526 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
527 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
528 // zoom_onetoone_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom), 1.0));
530 zoom_indicator_box.pack_start (zoom_out_button, false, false);
531 zoom_indicator_box.pack_start (zoom_in_button, false, false);
532 zoom_indicator_box.pack_start (zoom_range_clock, false, false);
533 // zoom_indicator_box.pack_start (zoom_onetoone_button, false, false);
534 zoom_indicator_box.pack_start (zoom_out_full_button, false, false);
536 zoom_indicator_label.set_text (_("Zoom Span"));
537 zoom_indicator_label.set_name ("ToolBarLabel");
540 zoom_indicator_vbox.set_spacing (3);
541 zoom_indicator_vbox.set_border_width (3);
542 zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false);
543 zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false);
546 bottom_hbox.set_border_width (3);
547 bottom_hbox.set_spacing (3);
549 route_list.set_name ("TrackListDisplay");
550 route_list.set_size_request (75,-1);
551 route_list.column_titles_active();
552 route_list.set_compare_func (route_list_compare_func);
553 route_list.set_shadow_type (Gtk::SHADOW_IN);
554 route_list.set_selection_mode (GTK_SELECTION_MULTIPLE);
555 route_list.set_reorderable (true);
556 edit_group_list.set_size_request (75, -1);
558 route_list_scroller.add (route_list);
559 route_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
561 route_list.select_row.connect (mem_fun(*this, &Editor::route_list_selected));
562 route_list.unselect_row.connect (mem_fun(*this, &Editor::route_list_unselected));
563 route_list.row_move.connect (mem_fun(*this, &Editor::queue_route_list_reordered));
564 route_list.click_column.connect (mem_fun(*this, &Editor::route_list_column_click));
566 edit_group_list_button_label.set_text (_("Edit Groups"));
567 edit_group_list_button_label.set_name ("EditGroupTitleButton");
568 edit_group_list_button.add (edit_group_list_button_label);
569 edit_group_list_button.set_name ("EditGroupTitleButton");
571 edit_group_list.column_titles_hide();
572 edit_group_list.set_name ("MixerGroupList");
573 edit_group_list.set_shadow_type (Gtk::SHADOW_IN);
574 edit_group_list.set_selection_mode (GTK_SELECTION_MULTIPLE);
575 edit_group_list.set_reorderable (false);
576 edit_group_list.set_size_request (75, -1);
577 edit_group_list.set_column_auto_resize (0, true);
578 edit_group_list.columns_autosize ();
580 edit_group_list_scroller.add (edit_group_list);
581 edit_group_list_scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
583 edit_group_list_button.signal_clicked().connect (mem_fun(*this, &Editor::edit_group_list_button_clicked));
584 edit_group_list.button_press_event.connect (mem_fun(*this, &Editor::edit_group_list_button_press_event));
585 edit_group_list.select_row.connect (mem_fun(*this, &Editor::edit_group_selected));
586 edit_group_list.unselect_row.connect (mem_fun(*this, &Editor::edit_group_unselected));
588 list<string> stupid_list;
590 stupid_list.push_back ("*");
591 stupid_list.push_back (_("-all-"));
593 edit_group_list.rows().push_back (stupid_list);
594 edit_group_list.rows().back().set_data (0);
595 edit_group_list.rows().back().select();
597 edit_group_vbox.pack_start (edit_group_list_button, false, false);
598 edit_group_vbox.pack_start (edit_group_list_scroller, true, true);
600 route_list_frame.set_name ("BaseFrame");
601 route_list_frame.set_shadow_type (Gtk::SHADOW_IN);
602 route_list_frame.add (route_list_scroller);
604 edit_group_list_frame.set_name ("BaseFrame");
605 edit_group_list_frame.set_shadow_type (Gtk::SHADOW_IN);
606 edit_group_list_frame.add (edit_group_vbox);
608 route_group_vpane.add1 (route_list_frame);
609 route_group_vpane.add2 (edit_group_list_frame);
611 list_vpacker.pack_start (route_group_vpane, true, true);
613 region_list_hidden_node = region_list_display.rows().end();
615 region_list_display.add_events (GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|Gdk::POINTER_MOTION_MASK);
617 region_list_display.drag_dest_set (GTK_DEST_DEFAULT_ALL,
618 target_table, n_targets - 1,
619 GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
620 region_list_display.drag_data_received.connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
622 region_list_scroller.add (region_list_display);
623 region_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
625 region_list_display.set_name ("RegionListDisplay");
626 region_list_display.set_size_request (100, -1);
627 region_list_display.column_titles_active ();
628 region_list_display.set_selection_mode (GTK_SELECTION_SINGLE);
630 region_list_display.set_data ("editor", this);
631 region_list_display.set_compare_func (_region_list_sorter);
632 region_list_sort_type = ByName;
633 reset_region_list_sort_type (region_list_sort_type);
635 region_list_display.set_flags (Gtk::CAN_FOCUS);
637 region_list_display.key_press_event.connect (mem_fun(*this, &Editor::region_list_display_key_press));
638 region_list_display.key_release_event.connect (mem_fun(*this, &Editor::region_list_display_key_release));
639 region_list_display.button_press_event.connect (mem_fun(*this, &Editor::region_list_display_button_press));
640 region_list_display.button_release_event.connect (mem_fun(*this, &Editor::region_list_display_button_release));
641 region_list_display.motion_notify_event.connect (mem_fun(*this, &Editor::region_list_display_motion));
642 region_list_display.enter_notify_event.connect (mem_fun(*this, &Editor::region_list_display_enter_notify));
643 region_list_display.leave_notify_event.connect (mem_fun(*this, &Editor::region_list_display_leave_notify));
644 region_list_display.select_row.connect (mem_fun(*this, &Editor::region_list_display_selected));
645 region_list_display.unselect_row.connect (mem_fun(*this, &Editor::region_list_display_unselected));
646 region_list_display.click_column.connect (mem_fun(*this, &Editor::region_list_column_click));
648 named_selection_scroller.add (named_selection_display);
649 named_selection_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
651 named_selection_display.set_name ("RegionListDisplay");
652 named_selection_display.set_size_request (100, -1);
653 named_selection_display.column_titles_active ();
654 named_selection_display.set_selection_mode (GTK_SELECTION_SINGLE);
656 named_selection_display.button_press_event.connect (mem_fun(*this, &Editor::named_selection_display_button_press));
657 named_selection_display.select_row.connect (mem_fun(*this, &Editor::named_selection_display_selected));
658 named_selection_display.unselect_row.connect (mem_fun(*this, &Editor::named_selection_display_unselected));
660 region_selection_vpane.pack1 (region_list_scroller, true, true);
661 region_selection_vpane.pack2 (named_selection_scroller, true, true);
663 canvas_region_list_pane.pack1 (edit_frame, true, true);
664 canvas_region_list_pane.pack2 (region_selection_vpane, true, true);
666 track_list_canvas_pane.size_allocate.connect_after (bind (mem_fun(*this, &Editor::pane_allocation_handler),
667 static_cast<Gtk::Paned*> (&track_list_canvas_pane)));
668 canvas_region_list_pane.size_allocate.connect_after (bind (mem_fun(*this, &Editor::pane_allocation_handler),
669 static_cast<Gtk::Paned*> (&canvas_region_list_pane)));
670 route_group_vpane.size_allocate.connect_after (bind (mem_fun(*this, &Editor::pane_allocation_handler),
671 static_cast<Gtk::Paned*> (&route_group_vpane)));
672 region_selection_vpane.size_allocate.connect_after (bind (mem_fun(*this, &Editor::pane_allocation_handler),
673 static_cast<Gtk::Paned*> (®ion_selection_vpane)));
675 track_list_canvas_pane.pack1 (list_vpacker, true, true);
676 track_list_canvas_pane.pack2 (canvas_region_list_pane, true, true);
678 /* provide special pane-handle event handling for easy "hide" action */
680 /* 0: collapse to show left/upper child
681 1: collapse to show right/lower child
684 route_group_vpane.set_data ("collapse-direction", (gpointer) 0);
685 region_selection_vpane.set_data ("collapse-direction", (gpointer) 0);
686 canvas_region_list_pane.set_data ("collapse-direction", (gpointer) 0);
687 track_list_canvas_pane.set_data ("collapse-direction", (gpointer) 1);
689 route_group_vpane.button_release_event.connect (bind (ptr_fun (pane_handler), static_cast<Paned*> (&route_group_vpane)));
690 region_selection_vpane.button_release_event.connect (bind (ptr_fun (pane_handler), static_cast<Paned*> (®ion_selection_vpane)));
691 canvas_region_list_pane.button_release_event.connect (bind (ptr_fun (pane_handler), static_cast<Paned*> (&canvas_region_list_pane)));
692 track_list_canvas_pane.button_release_event.connect (bind (ptr_fun (pane_handler), static_cast<Paned*> (&track_list_canvas_pane)));
694 top_hbox.pack_start (toolbar_frame, true, true);
696 HBox *hbox = manage (new HBox);
697 hbox->pack_start (track_list_canvas_pane, true, true);
699 global_vpacker.pack_start (top_hbox, false, false);
700 global_vpacker.pack_start (*hbox, true, true);
702 global_hpacker.pack_start (global_vpacker, true, true);
704 set_name ("EditorWindow");
706 vpacker.pack_end (global_hpacker, true, true);
708 _playlist_selector = new PlaylistSelector();
709 _playlist_selector->delete_event.connect (bind (ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
711 AudioRegionView::AudioRegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_audio_regionview));
715 nudge_forward_button.add (*(manage (new Gtk::Image (right_arrow_xpm))));
716 nudge_backward_button.add (*(manage (new Gtk::Image (left_arrow_xpm))));
718 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards"));
719 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards"));
721 nudge_forward_button.set_name ("TransportButton");
722 nudge_backward_button.set_name ("TransportButton");
724 fade_context_menu.set_name ("ArdourContextMenu");
726 install_keybindings ();
728 set_title (_("ardour: editor"));
729 set_wmclass (_("ardour_editor"), "Ardour");
732 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
734 configure_event.connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
735 delete_event.connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
743 /* <CMT Additions> */
744 if(image_socket_listener)
746 if(image_socket_listener->is_connected())
748 image_socket_listener->close_connection() ;
751 delete image_socket_listener ;
752 image_socket_listener = 0 ;
754 /* </CMT Additions> */
758 Editor::add_toplevel_controls (Container& cont)
760 vpacker.pack_start (cont, false, false);
765 Editor::catch_vanishing_audio_regionview (AudioRegionView *rv)
767 /* note: the selection will take care of the vanishing
768 audioregionview by itself.
771 if (clicked_regionview == rv) {
772 clicked_regionview = 0;
775 if (entered_regionview == rv) {
776 set_entered_regionview (0);
781 Editor::set_entered_regionview (AudioRegionView* rv)
783 if (rv == entered_regionview) {
787 if (entered_regionview) {
788 entered_regionview->exited ();
791 if ((entered_regionview = rv) != 0) {
792 entered_regionview->entered ();
797 Editor::set_entered_track (TimeAxisView* tav)
800 entered_track->exited ();
803 if ((entered_track = tav) != 0) {
804 entered_track->entered ();
809 Editor::left_track_canvas (GdkEventCrossing *ev)
811 set_entered_track (0);
812 set_entered_regionview (0);
818 Editor::initialize_canvas ()
822 track_gtk_canvas = gtk_canvas_new_aa ();
824 /* adjust sensitivity for "picking" items */
826 // GTK_CANVAS(track_gtk_canvas)->close_enough = 2;
828 gtk_signal_connect (GTK_OBJECT(gtk_canvas_root (GTK_CANVAS(track_gtk_canvas))), "event",
829 (GtkSignalFunc) Editor::_track_canvas_event, this);
830 track_canvas = wrap (track_gtk_canvas);
831 track_canvas->set_name ("EditorMainCanvas");
833 track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK);
835 track_canvas->leave_notify_event.connect (mem_fun(*this, &Editor::left_track_canvas));
837 /* set up drag-n-drop */
839 track_canvas->drag_dest_set (GTK_DEST_DEFAULT_ALL,
840 target_table, n_targets - 1,
841 GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
842 track_canvas->drag_data_received.connect (mem_fun(*this, &Editor::track_canvas_drag_data_received));
844 /* stuff for the verbose canvas cursor */
846 string fontname = get_font_for_style (N_("VerboseCanvasCursor"));
848 verbose_canvas_cursor = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(track_gtk_canvas)),
849 gtk_canvas_text_get_type(),
850 "font", fontname.c_str(),
851 "anchor", GTK_ANCHOR_NW,
852 "fill_color_rgba", color_map[cVerboseCanvasCursor],
854 verbose_cursor_visible = false;
856 /* a group to hold time (measure) lines */
858 time_line_group = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(track_gtk_canvas)),
859 gtk_canvas_group_get_type(),
864 cursor_group = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(track_gtk_canvas)),
865 gtk_canvas_group_get_type(),
870 time_gtk_canvas = gtk_canvas_new_aa ();
871 time_canvas = wrap (time_gtk_canvas);
872 time_canvas->set_name ("EditorTimeCanvas");
874 time_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK);
876 meter_group = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(time_gtk_canvas)),
877 gtk_canvas_group_get_type(),
881 tempo_group = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(time_gtk_canvas)),
882 gtk_canvas_group_get_type(),
886 marker_group = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(time_gtk_canvas)),
887 gtk_canvas_group_get_type(),
889 "y", timebar_height * 2.0,
891 range_marker_group = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(time_gtk_canvas)),
892 gtk_canvas_group_get_type(),
894 "y", timebar_height * 3.0,
896 transport_marker_group = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(time_gtk_canvas)),
897 gtk_canvas_group_get_type(),
899 "y", timebar_height * 4.0,
902 tempo_bar = gtk_canvas_item_new (GTK_CANVAS_GROUP(tempo_group),
903 gtk_canvas_simplerect_get_type(),
906 "x2", max_canvas_coordinate,
907 "y2", timebar_height,
908 "fill_color_rgba", color_map[cTempoBar],
911 meter_bar = gtk_canvas_item_new (GTK_CANVAS_GROUP(meter_group),
912 gtk_canvas_simplerect_get_type(),
915 "x2", max_canvas_coordinate,
916 "y2", timebar_height,
917 "fill_color_rgba", color_map[cMeterBar],
920 marker_bar = gtk_canvas_item_new (GTK_CANVAS_GROUP(marker_group),
921 gtk_canvas_simplerect_get_type(),
924 "x2", max_canvas_coordinate,
925 "y2", timebar_height,
926 "fill_color_rgba", color_map[cMarkerBar],
929 range_marker_bar = gtk_canvas_item_new (GTK_CANVAS_GROUP(range_marker_group),
930 gtk_canvas_simplerect_get_type(),
933 "x2", max_canvas_coordinate,
934 "y2", timebar_height,
935 "fill_color_rgba", color_map[cRangeMarkerBar],
938 transport_marker_bar = gtk_canvas_item_new (GTK_CANVAS_GROUP(transport_marker_group),
939 gtk_canvas_simplerect_get_type(),
942 "x2", max_canvas_coordinate,
943 "y2", timebar_height,
944 "fill_color_rgba", color_map[cTransportMarkerBar],
948 range_bar_drag_rect = gtk_canvas_item_new (GTK_CANVAS_GROUP(range_marker_group),
949 gtk_canvas_simplerect_get_type(),
953 "y2", timebar_height,
954 "fill_color_rgba", color_map[cRangeDragBarRectFill],
955 "outline_color_rgba", color_map[cRangeDragBarRect],
957 gtk_canvas_item_hide (range_bar_drag_rect);
959 transport_bar_drag_rect = gtk_canvas_item_new (GTK_CANVAS_GROUP(transport_marker_group),
960 gtk_canvas_simplerect_get_type(),
964 "y2", timebar_height,
965 "fill_color_rgba", color_map[cTransportDragRectFill],
966 "outline_color_rgba", color_map[cTransportDragRect],
968 gtk_canvas_item_hide (transport_bar_drag_rect);
971 marker_drag_line_points = gtk_canvas_points_new (2);
972 marker_drag_line_points->coords[0] = 0.0;
973 marker_drag_line_points->coords[1] = 0.0;
974 marker_drag_line_points->coords[2] = 0.0;
975 marker_drag_line_points->coords[3] = 0.0;
978 //cerr << "set mdl points, nc = " << marker_drag_line_points->num_points << endl;
979 marker_drag_line = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(track_gtk_canvas)),
980 gtk_canvas_line_get_type(),
982 "fill_color_rgba", color_map[cMarkerDragLine],
983 "points", marker_drag_line_points,
985 gtk_canvas_item_hide (marker_drag_line);
987 range_marker_drag_rect = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(track_gtk_canvas)),
988 gtk_canvas_simplerect_get_type(),
993 "fill_color_rgba", color_map[cRangeDragRectFill],
994 "outline_color_rgba", color_map[cRangeDragRect],
996 gtk_canvas_item_hide (range_marker_drag_rect);
999 transport_loop_range_rect = gtk_canvas_item_new ((GTK_CANVAS_GROUP(time_line_group)),
1000 gtk_canvas_simplerect_get_type(),
1005 "fill_color_rgba", color_map[cTransportLoopRectFill],
1006 "outline_color_rgba", color_map[cTransportLoopRect],
1007 "outline_pixels", 1,
1009 gtk_canvas_item_hide (transport_loop_range_rect);
1011 transport_punch_range_rect = gtk_canvas_item_new ((GTK_CANVAS_GROUP(time_line_group)),
1012 gtk_canvas_simplerect_get_type(),
1017 "fill_color_rgba", color_map[cTransportPunchRectFill],
1018 "outline_color_rgba", color_map[cTransportPunchRect],
1019 "outline_pixels", 0,
1021 gtk_canvas_item_lower_to_bottom (transport_punch_range_rect);
1022 gtk_canvas_item_lower_to_bottom (transport_loop_range_rect); // loop on the bottom
1023 gtk_canvas_item_hide (transport_punch_range_rect);
1025 transport_punchin_line = gtk_canvas_item_new ((GTK_CANVAS_GROUP(time_line_group)),
1026 gtk_canvas_simplerect_get_type(),
1031 "outline_color_rgba", color_map[cPunchInLine],
1032 "outline_pixels", 1,
1034 gtk_canvas_item_hide (transport_punchin_line);
1036 transport_punchout_line = gtk_canvas_item_new ((GTK_CANVAS_GROUP(time_line_group)),
1037 gtk_canvas_simplerect_get_type(),
1042 "outline_color_rgba", color_map[cPunchOutLine],
1043 "outline_pixels", 1,
1045 gtk_canvas_item_hide (transport_punchout_line);
1050 // used to show zoom mode active zooming
1051 zoom_rect = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(track_gtk_canvas)),
1052 gtk_canvas_simplerect_get_type(),
1057 "fill_color_rgba", color_map[cZoomRectFill],
1058 "outline_color_rgba", color_map[cZoomRect],
1059 "outline_pixels", 1,
1061 gtk_canvas_item_hide (zoom_rect);
1062 gtk_signal_connect (GTK_OBJECT(zoom_rect), "event",
1063 (GtkSignalFunc) PublicEditor::canvas_zoom_rect_event,
1066 // used as rubberband rect
1067 rubberband_rect = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(track_gtk_canvas)),
1068 gtk_canvas_simplerect_get_type(),
1073 "outline_color_rgba", color_map[cRubberBandRect],
1074 "fill_color_rgba", (guint32) color_map[cRubberBandRectFill],
1075 "outline_pixels", 1,
1077 gtk_canvas_item_hide (rubberband_rect);
1081 gtk_signal_connect (GTK_OBJECT(tempo_bar), "event",
1082 (GtkSignalFunc) PublicEditor::canvas_tempo_bar_event,
1085 gtk_signal_connect (GTK_OBJECT(meter_bar), "event",
1086 (GtkSignalFunc) PublicEditor::canvas_meter_bar_event,
1089 gtk_signal_connect (GTK_OBJECT(marker_bar), "event",
1090 (GtkSignalFunc) PublicEditor::canvas_marker_bar_event,
1093 gtk_signal_connect (GTK_OBJECT(range_marker_bar), "event",
1094 (GtkSignalFunc) PublicEditor::canvas_range_marker_bar_event,
1097 gtk_signal_connect (GTK_OBJECT(transport_marker_bar), "event",
1098 (GtkSignalFunc) PublicEditor::canvas_transport_marker_bar_event,
1101 /* separator lines */
1103 tempo_line_points = gtk_canvas_points_new (2);
1104 tempo_line_points->coords[0] = 0;
1105 tempo_line_points->coords[1] = timebar_height;
1106 tempo_line_points->coords[2] = max_canvas_coordinate;
1107 tempo_line_points->coords[3] = timebar_height;
1108 //cerr << "set tl points, nc = " << tempo_line_points->num_points << endl;
1109 tempo_line = gtk_canvas_item_new (GTK_CANVAS_GROUP(tempo_group),
1110 gtk_canvas_line_get_type(),
1112 "fill_color", "black",
1113 "points", tempo_line_points,
1116 // cerr << "tempo line @ " << tempo_line << endl;
1118 meter_line_points = gtk_canvas_points_new (2);
1119 meter_line_points->coords[0] = 0;
1120 meter_line_points->coords[1] = timebar_height;
1121 meter_line_points->coords[2] = max_canvas_coordinate;
1122 meter_line_points->coords[3] = timebar_height;
1123 // cerr << "set ml points, nc = " << tempo_line_points->num_points << endl;
1124 meter_line = gtk_canvas_item_new (GTK_CANVAS_GROUP(meter_group),
1125 gtk_canvas_line_get_type(),
1127 "fill_color", "black",
1128 "points", meter_line_points,
1131 // cerr << "meter line @ " << tempo_line << endl;
1133 marker_line_points = gtk_canvas_points_new (2);
1134 marker_line_points->coords[0] = 0;
1135 marker_line_points->coords[1] = timebar_height;
1136 marker_line_points->coords[2] = max_canvas_coordinate;
1137 marker_line_points->coords[3] = timebar_height;
1138 // cerr << "set ml2 points, nc = " << marker_line_points->num_points << endl;
1139 marker_line = gtk_canvas_item_new (GTK_CANVAS_GROUP(marker_group),
1140 gtk_canvas_line_get_type(),
1142 "fill_color", "black",
1143 "points", marker_line_points,
1145 // cerr << "set rml points, nc = " << marker_line_points->num_points << endl;
1146 range_marker_line = gtk_canvas_item_new (GTK_CANVAS_GROUP(range_marker_group),
1147 gtk_canvas_line_get_type(),
1149 "fill_color", "black",
1150 "points", marker_line_points,
1152 // cerr << "set tml2 points, nc = " << marker_line_points->num_points << endl;
1153 transport_marker_line = gtk_canvas_item_new (GTK_CANVAS_GROUP(transport_marker_group),
1154 gtk_canvas_line_get_type(),
1156 "fill_color", "black",
1157 "points", marker_line_points,
1160 // cerr << "marker line @ " << marker_line << endl;
1162 ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_loop_range_view), false));
1163 ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_punch_range_view), false));
1165 double time_height = timebar_height * 5;
1166 double time_width = FLT_MAX/frames_per_unit;
1167 gtk_canvas_set_scroll_region (GTK_CANVAS(time_gtk_canvas), 0.0, 0.0, time_width, time_height);
1169 edit_cursor = new Cursor (*this, "blue", (GtkSignalFunc) _canvas_edit_cursor_event);
1170 playhead_cursor = new Cursor (*this, "red", (GtkSignalFunc) _canvas_playhead_cursor_event);
1172 track_canvas->size_allocate.connect (mem_fun(*this, &Editor::track_canvas_allocate));
1176 Editor::show_window ()
1180 /* now reset all audio_time_axis heights, because widgets might need
1186 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1187 tv = (static_cast<TimeAxisView*>(*i));
1188 tv->reset_height ();
1193 Editor::tie_vertical_scrolling ()
1195 edit_controls_scroller.get_vadjustment()->set_value (track_canvas_scroller.get_vadjustment()->get_value());
1197 float y1 = track_canvas_scroller.get_vadjustment()->get_value();
1198 playhead_cursor->set_y_axis(y1);
1199 edit_cursor->set_y_axis(y1);
1203 Editor::set_frames_per_unit (double fpu)
1205 jack_nframes_t frames;
1207 if (fpu == frames_per_unit) {
1215 // convert fpu to frame count
1217 frames = (jack_nframes_t) (fpu * canvas_width);
1219 /* don't allow zooms that fit more than the maximum number
1220 of frames into an 800 pixel wide space.
1223 if (max_frames / fpu < 800.0) {
1227 frames_per_unit = fpu;
1229 if (frames != zoom_range_clock.current_duration()) {
1230 zoom_range_clock.set (frames);
1233 /* only update these if we not about to call reposition_x_origin,
1234 which will do the same updates.
1238 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1241 if (!no_zoom_repos_update) {
1242 track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
1243 update_hscroller ();
1244 update_fixed_rulers ();
1245 tempo_map_changed (Change (0));
1248 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
1249 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1250 (*i)->reshow_selection (selection->time);
1254 ZoomChanged (); /* EMIT_SIGNAL */
1256 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
1257 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
1264 Editor::instant_save ()
1266 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
1271 session->add_instant_xml(get_state(), session->path());
1273 Config->add_instant_xml(get_state(), Config->get_user_ardour_path());
1278 Editor::reposition_x_origin (jack_nframes_t frame)
1280 if (frame != leftmost_frame) {
1281 leftmost_frame = frame;
1282 double pixel = frame_to_pixel (frame);
1283 if (pixel >= track_canvas_scroller.get_hadjustment()->get_upper()) {
1284 track_canvas_scroller.get_hadjustment()->set_upper (frame_to_pixel (frame + (current_page_frames())));
1286 track_canvas_scroller.get_hadjustment()->set_value (frame/frames_per_unit);
1287 XOriginChanged (); /* EMIT_SIGNAL */
1292 Editor::edit_cursor_clock_changed()
1294 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
1295 edit_cursor->set_position (edit_cursor_clock.current_time());
1301 Editor::zoom_adjustment_changed ()
1303 if (session == 0 || no_zoom_repos_update) {
1307 double fpu = (double) zoom_range_clock.current_duration() / (double) canvas_width;
1311 zoom_range_clock.set ((jack_nframes_t) (fpu * canvas_width));
1313 else if (fpu > session->current_end_frame() / (double) canvas_width) {
1314 fpu = session->current_end_frame() / (double) canvas_width;
1315 zoom_range_clock.set ((jack_nframes_t) (fpu * canvas_width));
1318 temporal_zoom (fpu);
1322 Editor::canvas_horizontally_scrolled ()
1324 /* XXX note the potential loss of accuracy here caused by
1325 adjustments being 32bit floats with only a 24 bit mantissa,
1326 whereas jack_nframes_t is at least a 32 bit uint32_teger.
1329 leftmost_frame = (jack_nframes_t) floor (track_canvas_scroller.get_hadjustment()->get_value() * frames_per_unit);
1331 update_hscroller ();
1332 update_fixed_rulers ();
1334 if (!edit_hscroll_dragging) {
1335 tempo_map_changed (Change (0));
1337 update_tempo_based_rulers();
1342 Editor::reposition_and_zoom (jack_nframes_t frame, double nfpu)
1344 if (!repos_zoom_queued) {
1345 Main::idle.connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu));
1346 repos_zoom_queued = true;
1351 Editor::deferred_reposition_and_zoom (jack_nframes_t frame, double nfpu)
1353 /* if we need to force an update to the hscroller stuff,
1354 don't set no_zoom_repos_update.
1357 no_zoom_repos_update = (frame != leftmost_frame);
1359 set_frames_per_unit (nfpu);
1360 if (no_zoom_repos_update) {
1361 reposition_x_origin (frame);
1363 no_zoom_repos_update = false;
1364 repos_zoom_queued = false;
1370 Editor::realize_impl ()
1372 /* Even though we're not using acceleration, we want the
1376 track_context_menu.accelerate (*this->get_toplevel());
1377 track_region_context_menu.accelerate (*this->get_toplevel());
1379 Window::realize_impl ();
1381 GdkPixmap* empty_pixmap = gdk_pixmap_new (get_window(), 1, 1, 1);
1382 GdkPixmap* empty_bitmap = gdk_pixmap_new (get_window(), 1, 1, 1);
1383 GdkColor white = { 0, 0, 0 };
1385 null_cursor = gdk_cursor_new_from_pixmap (empty_pixmap, empty_bitmap, &white, &white, 0, 0);
1389 Editor::map__impl ()
1391 Window::map__impl ();
1393 track_canvas_scroller.get_window().set_cursor (current_canvas_cursor);
1394 time_canvas_scroller.get_window().set_cursor (timebar_cursor);
1398 Editor::track_canvas_allocate (GtkAllocation *alloc)
1400 canvas_width = alloc->width;
1401 canvas_height = alloc->height;
1403 if (session == 0 && !ARDOUR_UI::instance()->will_create_new_session_automatically()) {
1405 string fontname = get_font_for_style (N_("FirstActionMessage"));
1407 const char *txt1 = _("Start a new session\n");
1408 const char *txt2 = _("via Session menu");
1410 /* this mess of code is here to find out how wide this text is and
1411 position the message in the center of the editor window. there
1412 are two lines, so we use the longer of the the lines to
1413 compute width, and multiply the height by 2.
1422 /* this is a dummy widget that exists so that we can get the
1423 style from the RC file.
1426 Label foo (_(txt2));
1427 foo.set_name ("NoSessionMessage");
1428 foo.ensure_style ();
1430 gdk_string_extents (foo.get_style()->get_font(),
1438 if (first_action_message == 0) {
1440 char txt[strlen(txt1)+strlen(txt2)+1];
1442 /* merge both lines */
1444 strcpy (txt, _(txt1));
1445 strcat (txt, _(txt2));
1447 first_action_message = gtk_canvas_item_new (gtk_canvas_root(GTK_CANVAS(track_gtk_canvas)),
1448 gtk_canvas_text_get_type(),
1449 "font", fontname.c_str(),
1450 "fill_color_rgba", color_map[cFirstActionMessage],
1451 "x", (gdouble) (canvas_width - width) / 2.0,
1452 "y", (gdouble) (canvas_height/2.0) - (2.0 * (ascent+descent)),
1453 "anchor", GTK_ANCHOR_NORTH_WEST,
1461 gtk_canvas_item_set (first_action_message,
1462 "x", (gdouble) (canvas_width - width) / 2.0,
1463 "y", (gdouble) (canvas_height/2.0) - (2.0 * (ascent+descent)),
1468 zoom_range_clock.set ((jack_nframes_t) (canvas_width * frames_per_unit));
1469 edit_cursor->set_position (edit_cursor->current_frame);
1470 playhead_cursor->set_position (playhead_cursor->current_frame);
1471 reset_scrolling_region (alloc);
1473 Resized (); /* EMIT_SIGNAL */
1477 Editor::reset_scrolling_region (GtkAllocation *alloc)
1479 guint32 last_canvas_unit;
1481 guint32 canvas_alloc_height, canvas_alloc_width;
1482 TrackViewList::iterator i;
1483 static bool first_time = true;
1485 /* We need to make sure that the canvas always has its
1486 scrolling region set to larger of:
1488 - the size allocated for it (within the container its packed in)
1489 - the size required to see the entire session
1491 If we don't ensure at least the first of these, the canvas
1492 does some wierd and in my view unnecessary stuff to center
1493 itself within the allocated area, which causes bad, bad
1496 XXX GnomeCanvas has fixed this, and has an option to
1497 control the centering behaviour.
1500 last_canvas_unit = (guint32) ceil ((float) max_frames / frames_per_unit);
1505 for (i = track_views.begin(); i != track_views.end(); ++i) {
1506 if ((*i)->control_parent) {
1507 height += (*i)->effective_height;
1508 height += track_spacing;
1513 height -= track_spacing;
1517 canvas_height = (guint32) height;
1520 canvas_alloc_height = alloc->height;
1521 canvas_alloc_width = alloc->width;
1523 canvas_alloc_height = track_gtk_canvas->allocation.height;
1524 canvas_alloc_width = track_gtk_canvas->allocation.width;
1527 canvas_height = max (canvas_height, canvas_alloc_height);
1529 gtk_canvas_set_scroll_region (GTK_CANVAS(track_gtk_canvas), 0.0, 0.0,
1530 max (last_canvas_unit, canvas_alloc_width),
1533 if (edit_cursor) edit_cursor->set_length (canvas_alloc_height);
1534 if (playhead_cursor) playhead_cursor->set_length (canvas_alloc_height);
1536 if (marker_drag_line) {
1537 marker_drag_line_points->coords[3] = canvas_height;
1538 // cerr << "set mlA points, nc = " << marker_drag_line_points->num_points << endl;
1539 gtk_canvas_item_set (marker_drag_line, "points", marker_drag_line_points, NULL);
1541 if (range_marker_drag_rect) {
1542 gtk_canvas_item_set (range_marker_drag_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1544 if (transport_loop_range_rect) {
1545 gtk_canvas_item_set (transport_loop_range_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1547 if (transport_punch_range_rect) {
1548 gtk_canvas_item_set (transport_punch_range_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1550 if (transport_punchin_line) {
1551 gtk_canvas_item_set (transport_punchin_line, "y1", 0.0, "y2", (double) canvas_height, NULL);
1553 if (transport_punchout_line) {
1554 gtk_canvas_item_set (transport_punchout_line, "y1", 0.0, "y2", (double) canvas_height, NULL);
1558 update_fixed_rulers ();
1560 if (is_visible() && first_time) {
1561 tempo_map_changed (Change (0));
1569 Editor::queue_session_control_changed (Session::ControlType t)
1571 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::session_control_changed), t));
1575 Editor::session_control_changed (Session::ControlType t)
1577 // right now we're only tracking the loop and punch state
1580 case Session::AutoLoop:
1581 update_loop_range_view (true);
1583 case Session::PunchIn:
1584 case Session::PunchOut:
1585 update_punch_range_view (true);
1594 Editor::fake_add_edit_group (RouteGroup *group)
1596 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::add_edit_group), group));
1600 Editor::fake_handle_new_audio_region (AudioRegion *region)
1602 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_new_audio_region), region));
1606 Editor::fake_handle_audio_region_removed (AudioRegion *region)
1608 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_audio_region_removed), region));
1612 Editor::fake_handle_new_duration ()
1614 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &Editor::handle_new_duration));
1618 Editor::start_scrolling ()
1620 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1621 (mem_fun(*this, &Editor::update_current_screen));
1623 slower_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
1624 (mem_fun(*this, &Editor::update_slower));
1628 Editor::stop_scrolling ()
1630 scroll_connection.disconnect ();
1631 slower_update_connection.disconnect ();
1635 Editor::map_position_change (jack_nframes_t frame)
1637 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1639 if (session == 0 || !_follow_playhead) {
1643 center_screen (frame);
1644 playhead_cursor->set_position (frame);
1648 Editor::center_screen (jack_nframes_t frame)
1650 float page = canvas_width * frames_per_unit;
1652 /* if we're off the page, then scroll.
1655 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1656 center_screen_internal (frame,page);
1661 Editor::center_screen_internal (jack_nframes_t frame, float page)
1666 frame -= (jack_nframes_t) page;
1671 reposition_x_origin (frame);
1675 Editor::handle_new_duration ()
1677 reset_scrolling_region ();
1680 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1681 track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
1684 update_hscroller ();
1688 Editor::update_title_s (string snap_name)
1690 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1696 Editor::update_title ()
1698 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1701 bool dirty = session->dirty();
1703 string wintitle = _("ardour: editor: ");
1709 wintitle += session->name();
1711 if (session->snap_name() != session->name()) {
1713 wintitle += session->snap_name();
1720 set_title (wintitle);
1725 Editor::connect_to_session (Session *t)
1729 if (first_action_message) {
1730 gtk_canvas_item_hide (first_action_message);
1733 flush_track_canvas();
1737 session->going_away.connect (mem_fun(*this, &Editor::session_going_away));
1739 /* These signals can all be emitted by a non-GUI thread. Therefore the
1740 handlers for them must not attempt to directly interact with the GUI,
1741 but use Gtkmm2ext::UI::instance()->call_slot();
1744 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1745 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1746 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p)));
1747 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::fake_handle_new_audio_region)));
1748 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::fake_handle_audio_region_removed)));
1749 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::fake_handle_new_duration)));
1750 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::fake_add_edit_group)));
1751 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1752 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1753 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1754 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1755 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1756 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1758 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1759 session_connections.push_back (session->SMPTETypeChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1761 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1763 session->foreach_edit_group(this, &Editor::add_edit_group);
1765 editor_mixer_button.toggled.connect (mem_fun(*this, &Editor::editor_mixer_button_toggled));
1766 editor_mixer_button.set_name (X_("EditorMixerButton"));
1768 edit_cursor_clock.set_session (session);
1769 selection_start_clock.set_session (session);
1770 selection_end_clock.set_session (session);
1771 zoom_range_clock.set_session (session);
1772 _playlist_selector->set_session (session);
1773 nudge_clock.set_session (session);
1775 switch (session->get_edit_mode()) {
1777 edit_mode_selector.get_entry()->set_text (edit_mode_strings[splice_index]);
1781 edit_mode_selector.get_entry()->set_text (edit_mode_strings[slide_index]);
1785 Location* loc = session->locations()->auto_loop_location();
1787 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1788 if (loc->start() == loc->end()) {
1789 loc->set_end (loc->start() + 1);
1791 session->locations()->add (loc, false);
1792 session->set_auto_loop_location (loc);
1796 loc->set_name (_("Loop"));
1799 loc = session->locations()->auto_punch_location();
1801 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1802 if (loc->start() == loc->end()) {
1803 loc->set_end (loc->start() + 1);
1805 session->locations()->add (loc, false);
1806 session->set_auto_punch_location (loc);
1810 loc->set_name (_("Punch"));
1813 update_loop_range_view (true);
1814 update_punch_range_view (true);
1816 session->ControlChanged.connect (mem_fun(*this, &Editor::queue_session_control_changed));
1819 refresh_location_display ();
1820 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1821 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1822 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1823 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1824 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1826 reset_scrolling_region ();
1828 redisplay_regions ();
1829 redisplay_named_selections ();
1831 route_list.freeze ();
1832 route_list.clear ();
1833 session->foreach_route (this, &Editor::handle_new_route);
1834 // route_list.select_all ();
1836 route_list_reordered ();
1839 if (embed_audio_item) {
1840 embed_audio_item->set_sensitive (true);
1842 if (import_audio_item) {
1843 import_audio_item->set_sensitive (true);
1846 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1847 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1850 /* ::reposition_x_origin() doesn't work right here, since the old
1851 position may be zero already, and it does nothing in such
1857 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1858 track_canvas_scroller.get_hadjustment()->set_value (0);
1860 update_hscroller ();
1861 restore_ruler_visibility ();
1862 tempo_map_changed (Change (0));
1864 edit_cursor->set_position (0);
1865 playhead_cursor->set_position (0);
1869 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1872 /* don't show master bus in a new session */
1874 if (ARDOUR_UI::instance()->session_is_new ()) {
1876 Gtk::CList_Helpers::RowList::iterator i;
1877 Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
1879 route_list.freeze ();
1881 for (i = rowlist.begin(); i != rowlist.end(); ++i) {
1882 TimeAxisView *tv = (TimeAxisView *) i->get_data ();
1883 AudioTimeAxisView *atv;
1885 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1886 if (atv->route().master()) {
1897 Editor::build_cursors ()
1899 GdkPixmap *source, *mask;
1900 GdkColor fg = { 0, 65535, 0, 0 }; /* Red. */
1901 GdkColor bg = { 0, 0, 0, 65535 }; /* Blue. */
1903 source = gdk_bitmap_create_from_data (NULL, hand_bits,
1904 hand_width, hand_height);
1905 mask = gdk_bitmap_create_from_data (NULL, handmask_bits,
1906 handmask_width, handmask_height);
1907 grabber_cursor = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, hand_x_hot, hand_y_hot);
1908 gdk_pixmap_unref (source);
1909 gdk_pixmap_unref (mask);
1912 GdkColor mbg = { 0, 0, 0, 0 }; /* Black */
1913 GdkColor mfg = { 0, 0, 0, 65535 }; /* Blue. */
1915 source = gdk_bitmap_create_from_data (NULL, mag_bits,
1916 mag_width, mag_height);
1917 mask = gdk_bitmap_create_from_data (NULL, magmask_bits,
1918 mag_width, mag_height);
1919 zoom_cursor = gdk_cursor_new_from_pixmap (source, mask, &mfg, &mbg, mag_x_hot, mag_y_hot);
1920 gdk_pixmap_unref (source);
1921 gdk_pixmap_unref (mask);
1923 GdkColor fbg = { 0, 65535, 65535, 65535 };
1924 GdkColor ffg = { 0, 0, 0, 0 };
1926 source = gdk_bitmap_create_from_data (NULL, fader_cursor_bits,
1927 fader_cursor_width, fader_cursor_height);
1928 mask = gdk_bitmap_create_from_data (NULL, fader_cursor_mask_bits,
1929 fader_cursor_width, fader_cursor_height);
1930 fader_cursor = gdk_cursor_new_from_pixmap (source, mask, &ffg, &fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1931 gdk_pixmap_unref (source);
1932 gdk_pixmap_unref (mask);
1934 source = gdk_bitmap_create_from_data (NULL, speaker_cursor_bits,
1935 speaker_cursor_width, speaker_cursor_height);
1936 mask = gdk_bitmap_create_from_data (NULL, speaker_cursor_mask_bits,
1937 speaker_cursor_width, speaker_cursor_height);
1938 speaker_cursor = gdk_cursor_new_from_pixmap (source, mask, &ffg, &fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1939 gdk_pixmap_unref (source);
1940 gdk_pixmap_unref (mask);
1942 cross_hair_cursor = gdk_cursor_new (GDK_CROSSHAIR);
1943 trimmer_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
1944 selector_cursor = gdk_cursor_new (GDK_XTERM);
1945 time_fx_cursor = gdk_cursor_new (GDK_SIZING);
1946 wait_cursor = gdk_cursor_new (GDK_WATCH);
1947 timebar_cursor = gdk_cursor_new (GDK_LEFT_PTR);
1951 Editor::popup_fade_context_menu (int button, int32_t time, GtkCanvasItem* item, ItemType item_type)
1953 using namespace Menu_Helpers;
1954 AudioRegionView* arv = static_cast<AudioRegionView*> (gtk_object_get_data (GTK_OBJECT(item), "regionview"));
1957 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1961 MenuList& items (fade_context_menu.items());
1965 switch (item_type) {
1967 case FadeInHandleItem:
1968 if (arv->region.fade_in_active()) {
1969 items.push_back (MenuElem (_("Deactivate"), bind (slot (*arv, &AudioRegionView::set_fade_in_active), false)));
1971 items.push_back (MenuElem (_("Activate"), bind (slot (*arv, &AudioRegionView::set_fade_in_active), true)));
1974 items.push_back (SeparatorElem());
1976 items.push_back (MenuElem (_("Linear"), bind (slot (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear)));
1977 items.push_back (MenuElem (_("Slowest"), bind (slot (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB)));
1978 items.push_back (MenuElem (_("Slow"), bind (slot (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast)));
1979 items.push_back (MenuElem (_("Fast"), bind (slot (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA)));
1980 items.push_back (MenuElem (_("Fastest"), bind (slot (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow)));
1984 case FadeOutHandleItem:
1985 if (arv->region.fade_out_active()) {
1986 items.push_back (MenuElem (_("Deactivate"), bind (slot (*arv, &AudioRegionView::set_fade_out_active), false)));
1988 items.push_back (MenuElem (_("Activate"), bind (slot (*arv, &AudioRegionView::set_fade_out_active), true)));
1991 items.push_back (SeparatorElem());
1993 items.push_back (MenuElem (_("Linear"), bind (slot (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear)));
1994 items.push_back (MenuElem (_("Slowest"), bind (slot (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast)));
1995 items.push_back (MenuElem (_("Slow"), bind (slot (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB)));
1996 items.push_back (MenuElem (_("Fast"), bind (slot (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA)));
1997 items.push_back (MenuElem (_("Fastest"), bind (slot (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow)));
2001 fatal << _("programming error: ")
2002 << X_("non-fade canvas item passed to popup_fade_context_menu()")
2007 fade_context_menu.popup (button, time);
2011 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, jack_nframes_t frame)
2013 using namespace Menu_Helpers;
2014 Menu* (Editor::*build_menu_function)(jack_nframes_t);
2017 switch (item_type) {
2019 case AudioRegionViewName:
2020 case AudioRegionViewNameHighlight:
2021 if (with_selection) {
2022 build_menu_function = &Editor::build_track_selection_context_menu;
2024 build_menu_function = &Editor::build_track_region_context_menu;
2029 if (with_selection) {
2030 build_menu_function = &Editor::build_track_selection_context_menu;
2032 build_menu_function = &Editor::build_track_context_menu;
2036 case CrossfadeViewItem:
2037 build_menu_function = &Editor::build_track_crossfade_context_menu;
2041 if (clicked_audio_trackview->get_diskstream()) {
2042 build_menu_function = &Editor::build_track_context_menu;
2044 build_menu_function = &Editor::build_track_bus_context_menu;
2049 /* probably shouldn't happen but if it does, we don't care */
2053 menu = (this->*build_menu_function)(frame);
2054 menu->set_name ("ArdourContextMenu");
2056 /* now handle specific situations */
2058 switch (item_type) {
2060 case AudioRegionViewName:
2061 case AudioRegionViewNameHighlight:
2062 if (!with_selection) {
2063 if (region_edit_menu_split_item) {
2064 if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) {
2065 region_edit_menu_split_item->set_sensitive (true);
2067 region_edit_menu_split_item->set_sensitive (false);
2070 if (region_edit_menu_split_multichannel_item) {
2071 if (clicked_regionview && clicked_regionview->region.n_channels() > 1) {
2072 region_edit_menu_split_multichannel_item->set_sensitive (true);
2074 region_edit_menu_split_multichannel_item->set_sensitive (false);
2083 case CrossfadeViewItem:
2090 /* probably shouldn't happen but if it does, we don't care */
2094 if (clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
2096 /* Bounce to disk */
2098 using namespace Menu_Helpers;
2099 MenuList& edit_items = menu->items();
2101 edit_items.push_back (SeparatorElem());
2103 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
2104 case AudioTrack::NoFreeze:
2105 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
2108 case AudioTrack::Frozen:
2109 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
2112 case AudioTrack::UnFrozen:
2113 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
2119 menu->popup (button, time);
2123 Editor::build_track_context_menu (jack_nframes_t ignored)
2125 using namespace Menu_Helpers;
2127 MenuList& edit_items = track_context_menu.items();
2130 add_dstream_context_items (edit_items);
2131 return &track_context_menu;
2135 Editor::build_track_bus_context_menu (jack_nframes_t ignored)
2137 using namespace Menu_Helpers;
2139 MenuList& edit_items = track_context_menu.items();
2142 add_bus_context_items (edit_items);
2143 return &track_context_menu;
2147 Editor::build_track_region_context_menu (jack_nframes_t frame)
2149 using namespace Menu_Helpers;
2150 MenuList& edit_items = track_region_context_menu.items();
2153 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
2159 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
2160 Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed()));
2161 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
2162 add_region_context_items (atv->view, (*i), edit_items);
2168 add_dstream_context_items (edit_items);
2170 return &track_region_context_menu;
2174 Editor::build_track_crossfade_context_menu (jack_nframes_t frame)
2176 using namespace Menu_Helpers;
2177 MenuList& edit_items = track_crossfade_context_menu.items();
2178 edit_items.clear ();
2180 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
2187 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = dynamic_cast<AudioPlaylist*> (pl)) != 0)) {
2189 Playlist::RegionList* regions = pl->regions_at (frame);
2190 AudioPlaylist::Crossfades xfades;
2192 apl->crossfades_at (frame, xfades);
2194 bool many = xfades.size() > 1;
2196 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
2197 add_crossfade_context_items (atv->view, (*i), edit_items, many);
2200 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
2201 add_region_context_items (atv->view, (*i), edit_items);
2208 add_dstream_context_items (edit_items);
2210 return &track_crossfade_context_menu;
2214 Editor::build_track_selection_context_menu (jack_nframes_t ignored)
2216 using namespace Menu_Helpers;
2217 MenuList& edit_items = track_selection_context_menu.items();
2218 edit_items.clear ();
2220 add_selection_context_items (edit_items);
2221 add_dstream_context_items (edit_items);
2223 return &track_selection_context_menu;
2227 Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many)
2229 using namespace Menu_Helpers;
2230 Menu *xfade_menu = manage (new Menu);
2231 MenuList& items = xfade_menu->items();
2232 xfade_menu->set_name ("ArdourContextMenu");
2235 if (xfade->active()) {
2241 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), xfade)));
2242 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), xfade)));
2244 if (xfade->can_follow_overlap()) {
2246 if (xfade->following_overlap()) {
2247 str = _("Convert to short");
2249 str = _("Convert to full");
2252 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
2256 str = xfade->out().name();
2258 str += xfade->in().name();
2260 str = _("Crossfade");
2263 edit_items.push_back (MenuElem (str, *xfade_menu));
2264 edit_items.push_back (SeparatorElem());
2268 Editor::xfade_edit_left_region ()
2270 if (clicked_crossfadeview) {
2271 clicked_crossfadeview->left_view.show_region_editor ();
2276 Editor::xfade_edit_right_region ()
2278 if (clicked_crossfadeview) {
2279 clicked_crossfadeview->right_view.show_region_editor ();
2284 Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items)
2286 using namespace Menu_Helpers;
2287 Menu *region_menu = manage (new Menu);
2288 MenuList& items = region_menu->items();
2289 region_menu->set_name ("ArdourContextMenu");
2291 AudioRegion* ar = 0;
2294 ar = dynamic_cast<AudioRegion*> (region);
2297 /* when this particular menu pops up, make the relevant region
2301 region_menu->map_event.connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, region));
2303 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
2304 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
2305 items.push_back (MenuElem (_("Lower to bottom layer"), slot (*this, &Editor::lower_region_to_bottom)));
2306 items.push_back (SeparatorElem());
2307 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
2308 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
2309 items.push_back (SeparatorElem());
2311 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
2312 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
2313 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
2314 items.push_back (SeparatorElem());
2316 /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler
2317 might be able to figure out which overloaded member function to use in
2321 void (Editor::*type_A_pmf)(void (Region::*pmf)(bool), bool) = &Editor::region_selection_op;
2323 items.push_back (MenuElem (_("Lock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, true)));
2324 items.push_back (MenuElem (_("Unlock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, false)));
2325 items.push_back (SeparatorElem());
2327 if (region->muted()) {
2328 items.push_back (MenuElem (_("Unmute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, false)));
2330 items.push_back (MenuElem (_("Mute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, true)));
2332 items.push_back (SeparatorElem());
2334 items.push_back (MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
2335 items.push_back (SeparatorElem());
2340 items.push_back (MenuElem (_("Toggle envelope visibility"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility)));
2341 items.push_back (MenuElem (_("Toggle envelope active"), mem_fun(*this, &Editor::toggle_gain_envelope_active)));
2342 items.push_back (SeparatorElem());
2344 if (ar->scale_amplitude() != 1.0f) {
2345 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
2347 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
2350 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
2351 items.push_back (SeparatorElem());
2355 Menu *nudge_menu = manage (new Menu());
2356 MenuList& nudge_items = nudge_menu->items();
2357 nudge_menu->set_name ("ArdourContextMenu");
2359 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
2360 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
2361 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
2362 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
2364 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2365 items.push_back (SeparatorElem());
2367 Menu *trim_menu = manage (new Menu);
2368 MenuList& trim_items = trim_menu->items();
2369 trim_menu->set_name ("ArdourContextMenu");
2371 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
2372 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
2374 items.push_back (MenuElem (_("Trim"), *trim_menu));
2375 items.push_back (SeparatorElem());
2377 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
2378 region_edit_menu_split_item = items.back();
2380 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
2381 region_edit_menu_split_multichannel_item = items.back();
2383 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
2384 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
2385 items.push_back (SeparatorElem());
2386 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
2387 items.push_back (SeparatorElem());
2388 items.push_back (MenuElem (_("Destroy"), mem_fun(*this, &Editor::destroy_clicked_region)));
2390 /* OK, stick the region submenu at the top of the list, and then add
2394 /* we have to hack up the region name because "_" has a special
2395 meaning for menu titles.
2398 string::size_type pos = 0;
2399 string menu_item_name = region->name();
2401 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
2402 menu_item_name.replace (pos, 1, "__");
2406 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
2407 edit_items.push_back (SeparatorElem());
2411 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
2413 using namespace Menu_Helpers;
2414 Menu *selection_menu = manage (new Menu);
2415 MenuList& items = selection_menu->items();
2416 selection_menu->set_name ("ArdourContextMenu");
2418 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
2419 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
2420 items.push_back (SeparatorElem());
2421 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection)));
2422 items.push_back (SeparatorElem());
2423 items.push_back (MenuElem (_("Create Region"), mem_fun(*this, &Editor::new_region_from_selection)));
2424 items.push_back (MenuElem (_("Separate Region"), mem_fun(*this, &Editor::separate_region_from_selection)));
2425 items.push_back (MenuElem (_("Crop Region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
2426 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
2427 items.push_back (SeparatorElem());
2428 items.push_back (MenuElem (_("Duplicate"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
2429 items.push_back (SeparatorElem());
2430 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_selection)));
2431 items.push_back (SeparatorElem());
2432 items.push_back (MenuElem (_("Fill range w/Region"), mem_fun(*this, &Editor::region_fill_selection)));
2434 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
2435 edit_items.push_back (SeparatorElem());
2439 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2441 using namespace Menu_Helpers;
2445 Menu *play_menu = manage (new Menu);
2446 MenuList& play_items = play_menu->items();
2447 play_menu->set_name ("ArdourContextMenu");
2449 play_items.push_back (MenuElem (_("Play from edit cursor")));
2450 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2451 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
2452 play_items.push_back (SeparatorElem());
2453 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
2455 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2459 Menu *select_menu = manage (new Menu);
2460 MenuList& select_items = select_menu->items();
2461 select_menu->set_name ("ArdourContextMenu");
2463 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
2464 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
2465 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2466 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
2467 select_items.push_back (SeparatorElem());
2468 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
2469 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
2470 select_items.push_back (SeparatorElem());
2472 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2476 Menu *cutnpaste_menu = manage (new Menu);
2477 MenuList& cutnpaste_items = cutnpaste_menu->items();
2478 cutnpaste_menu->set_name ("ArdourContextMenu");
2480 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2481 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2482 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2483 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
2485 cutnpaste_items.push_back (SeparatorElem());
2487 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
2488 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
2490 cutnpaste_items.push_back (SeparatorElem());
2492 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
2494 cutnpaste_items.push_back (SeparatorElem());
2496 cutnpaste_items.push_back (MenuElem (_("New Region from range"), mem_fun(*this, &Editor::new_region_from_selection)));
2497 cutnpaste_items.push_back (MenuElem (_("Separate Range"), mem_fun(*this, &Editor::separate_region_from_selection)));
2499 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2501 /* Adding new material */
2503 Menu *import_menu = manage (new Menu());
2504 MenuList& import_items = import_menu->items();
2505 import_menu->set_name ("ArdourContextMenu");
2507 import_items.push_back (MenuElem (_("Insert Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2508 import_items.push_back (MenuElem (_("Insert external sndfile"), bind (mem_fun(*this, &Editor::insert_sndfile), false)));
2510 edit_items.push_back (MenuElem (_("Import"), *import_menu));
2514 Menu *nudge_menu = manage (new Menu());
2515 MenuList& nudge_items = nudge_menu->items();
2516 nudge_menu->set_name ("ArdourContextMenu");
2518 edit_items.push_back (SeparatorElem());
2519 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2520 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2521 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2522 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2524 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2528 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2530 using namespace Menu_Helpers;
2534 Menu *play_menu = manage (new Menu);
2535 MenuList& play_items = play_menu->items();
2536 play_menu->set_name ("ArdourContextMenu");
2538 play_items.push_back (MenuElem (_("Play from edit cursor")));
2539 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2540 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2544 Menu *select_menu = manage (new Menu);
2545 MenuList& select_items = select_menu->items();
2546 select_menu->set_name ("ArdourContextMenu");
2548 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
2549 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
2550 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2551 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
2552 select_items.push_back (SeparatorElem());
2553 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
2554 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
2555 select_items.push_back (SeparatorElem());
2557 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2561 Menu *cutnpaste_menu = manage (new Menu);
2562 MenuList& cutnpaste_items = cutnpaste_menu->items();
2563 cutnpaste_menu->set_name ("ArdourContextMenu");
2565 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2566 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2567 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2569 Menu *nudge_menu = manage (new Menu());
2570 MenuList& nudge_items = nudge_menu->items();
2571 nudge_menu->set_name ("ArdourContextMenu");
2573 edit_items.push_back (SeparatorElem());
2574 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2575 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2576 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2577 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2579 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2582 /* CURSOR SETTING AND MARKS AND STUFF */
2585 Editor::set_snap_to (SnapType st)
2588 vector<string> txt = internationalize (snap_type_strings);
2589 snap_type_selector.get_entry()->set_text (txt[(int)st]);
2593 switch (snap_type) {
2594 case SnapToAThirtysecondBeat:
2595 case SnapToASixteenthBeat:
2596 case SnapToAEighthBeat:
2597 case SnapToAQuarterBeat:
2598 case SnapToAThirdBeat:
2599 update_tempo_based_rulers ();
2607 Editor::set_snap_mode (SnapMode mode)
2610 vector<string> txt = internationalize (snap_mode_strings);
2611 snap_mode_selector.get_entry()->set_text (txt[(int)mode]);
2617 Editor::add_location_from_selection ()
2619 if (selection->time.empty()) {
2623 if (session == 0 || clicked_trackview == 0) {
2627 jack_nframes_t start = selection->time[clicked_selection].start;
2628 jack_nframes_t end = selection->time[clicked_selection].end;
2630 Location *location = new Location (start, end, "selection");
2632 session->begin_reversible_command (_("add marker"));
2633 session->add_undo (session->locations()->get_memento());
2634 session->locations()->add (location, true);
2635 session->add_redo_no_execute (session->locations()->get_memento());
2636 session->commit_reversible_command ();
2640 Editor::add_location_from_playhead_cursor ()
2642 jack_nframes_t where = session->audible_frame();
2644 Location *location = new Location (where, where, "mark", Location::IsMark);
2645 session->begin_reversible_command (_("add marker"));
2646 session->add_undo (session->locations()->get_memento());
2647 session->locations()->add (location, true);
2648 session->add_redo_no_execute (session->locations()->get_memento());
2649 session->commit_reversible_command ();
2654 Editor::set_state (const XMLNode& node)
2656 const XMLProperty* prop;
2658 int x, y, width, height, xoff, yoff;
2660 if ((geometry = find_named_node (node, "geometry")) == 0) {
2662 width = default_width;
2663 height = default_height;
2671 width = atoi(geometry->property("x_size")->value());
2672 height = atoi(geometry->property("y_size")->value());
2673 x = atoi(geometry->property("x_pos")->value());
2674 y = atoi(geometry->property("y_pos")->value());
2675 xoff = atoi(geometry->property("x_off")->value());
2676 yoff = atoi(geometry->property("y_off")->value());
2679 set_default_size(width, height);
2680 set_uposition(x, y-yoff);
2682 if ((prop = node.property ("zoom-focus"))) {
2683 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2686 if ((prop = node.property ("zoom"))) {
2687 set_frames_per_unit (atof (prop->value()));
2690 if ((prop = node.property ("snap-to"))) {
2691 set_snap_to ((SnapType) atoi (prop->value()));
2694 if ((prop = node.property ("snap-mode"))) {
2695 set_snap_mode ((SnapMode) atoi (prop->value()));
2698 if ((prop = node.property ("show-waveforms"))) {
2699 bool yn = (prop->value() == "yes");
2700 _show_waveforms = !yn;
2701 set_show_waveforms (yn);
2704 if ((prop = node.property ("show-waveforms-recording"))) {
2705 bool yn = (prop->value() == "yes");
2706 _show_waveforms_recording = !yn;
2707 set_show_waveforms_recording (yn);
2710 if ((prop = node.property ("show-measures"))) {
2711 bool yn = (prop->value() == "yes");
2712 _show_measures = !yn;
2713 set_show_measures (yn);
2716 if ((prop = node.property ("follow-playhead"))) {
2717 bool yn = (prop->value() == "yes");
2718 _follow_playhead = !yn;
2719 set_follow_playhead (yn);
2722 if ((prop = node.property ("xfades-visible"))) {
2723 bool yn = (prop->value() == "yes");
2724 _xfade_visibility = !yn;
2725 set_xfade_visibility (yn);
2728 if ((prop = node.property ("region-list-sort-type"))) {
2729 region_list_sort_type = (Editing::RegionListSortType) -1; /* force change */
2730 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2733 if ((prop = node.property ("mouse-mode"))) {
2734 MouseMode m = str2mousemode(prop->value());
2735 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2736 set_mouse_mode (m, true);
2738 mouse_mode = MouseGain; /* lie, to force the mode switch */
2739 set_mouse_mode (MouseObject, true);
2742 if ((prop = node.property ("editor-mixer-button"))) {
2743 editor_mixer_button.set_active(prop->value() == "yes");
2750 Editor::get_state ()
2752 XMLNode* node = new XMLNode ("Editor");
2755 if (is_realized()) {
2756 Gdk_Window win = get_window();
2758 int x, y, xoff, yoff, width, height;
2759 win.get_root_origin(x, y);
2760 win.get_position(xoff, yoff);
2761 win.get_size(width, height);
2763 XMLNode* geometry = new XMLNode ("geometry");
2765 snprintf(buf, sizeof(buf), "%d", width);
2766 geometry->add_property("x_size", string(buf));
2767 snprintf(buf, sizeof(buf), "%d", height);
2768 geometry->add_property("y_size", string(buf));
2769 snprintf(buf, sizeof(buf), "%d", x);
2770 geometry->add_property("x_pos", string(buf));
2771 snprintf(buf, sizeof(buf), "%d", y);
2772 geometry->add_property("y_pos", string(buf));
2773 snprintf(buf, sizeof(buf), "%d", xoff);
2774 geometry->add_property("x_off", string(buf));
2775 snprintf(buf, sizeof(buf), "%d", yoff);
2776 geometry->add_property("y_off", string(buf));
2777 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&canvas_region_list_pane)->gobj()));
2778 geometry->add_property("canvas_region_list_pane_pos", string(buf));
2779 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&track_list_canvas_pane)->gobj()));
2780 geometry->add_property("track_list_canvas_pane_pos", string(buf));
2781 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(®ion_selection_vpane)->gobj()));
2782 geometry->add_property("region_selection_pane_pos", string(buf));
2783 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&route_group_vpane)->gobj()));
2784 geometry->add_property("route_group_pane_pos", string(buf));
2786 node->add_child_nocopy (*geometry);
2789 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2790 node->add_property ("zoom-focus", buf);
2791 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2792 node->add_property ("zoom", buf);
2793 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2794 node->add_property ("snap-to", buf);
2795 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2796 node->add_property ("snap-mode", buf);
2798 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2799 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2800 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2801 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2802 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2803 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2804 node->add_property ("mouse-mode", enum2str(mouse_mode));
2805 node->add_property ("editor-mixer-button", editor_mixer_button.get_active() ? "yes" : "no");
2813 Editor::trackview_by_y_position (double y)
2815 TrackViewList::iterator iter;
2818 for (iter = track_views.begin(); iter != track_views.end(); ++iter) {
2826 if (tv->y_position <= y && y < ((tv->y_position + tv->height + track_spacing))) {
2835 Editor::snap_to (jack_nframes_t& start, int32_t direction, bool for_mark)
2837 Location* before = 0;
2838 Location* after = 0;
2844 const jack_nframes_t one_second = session->frame_rate();
2845 const jack_nframes_t one_minute = session->frame_rate() * 60;
2847 jack_nframes_t presnap = start;
2849 switch (snap_type) {
2855 start = (jack_nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2857 start = (jack_nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2860 case SnapToSMPTEFrame:
2862 start = (jack_nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2864 start = (jack_nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2868 case SnapToSMPTESeconds:
2869 if (session->smpte_offset_negative())
2871 start += session->smpte_offset ();
2873 start -= session->smpte_offset ();
2875 if (direction > 0) {
2876 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2878 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2881 if (session->smpte_offset_negative())
2883 start -= session->smpte_offset ();
2885 start += session->smpte_offset ();
2889 case SnapToSMPTEMinutes:
2890 if (session->smpte_offset_negative())
2892 start += session->smpte_offset ();
2894 start -= session->smpte_offset ();
2897 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2899 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2901 if (session->smpte_offset_negative())
2903 start -= session->smpte_offset ();
2905 start += session->smpte_offset ();
2911 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2913 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2919 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2921 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2926 start = session->tempo_map().round_to_bar (start, direction);
2930 start = session->tempo_map().round_to_beat (start, direction);
2933 case SnapToAThirtysecondBeat:
2934 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2937 case SnapToASixteenthBeat:
2938 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2941 case SnapToAEighthBeat:
2942 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2945 case SnapToAQuarterBeat:
2946 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2949 case SnapToAThirdBeat:
2950 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2953 case SnapToEditCursor:
2954 start = edit_cursor->current_frame;
2962 before = session->locations()->first_location_before (start);
2963 after = session->locations()->first_location_after (start);
2965 if (direction < 0) {
2967 start = before->start();
2971 } else if (direction > 0) {
2973 start = after->start();
2975 start = session->current_end_frame();
2980 /* find nearest of the two */
2981 if ((start - before->start()) < (after->start() - start)) {
2982 start = before->start();
2984 start = after->start();
2987 start = before->start();
2990 start = after->start();
2997 case SnapToRegionStart:
2998 case SnapToRegionEnd:
2999 case SnapToRegionSync:
3000 case SnapToRegionBoundary:
3001 if (!region_boundary_cache.empty()) {
3002 vector<jack_nframes_t>::iterator i;
3004 if (direction > 0) {
3005 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
3007 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
3010 if (i != region_boundary_cache.end()) {
3013 start = region_boundary_cache.back();
3019 switch (snap_mode) {
3025 if (presnap > start) {
3026 if (presnap > (start + unit_to_frame(snap_threshold))) {
3030 } else if (presnap < start) {
3031 if (presnap < (start - unit_to_frame(snap_threshold))) {
3043 Editor::setup_toolbar ()
3045 nstring pixmap_path;
3046 vector<ToggleButton *> mouse_mode_buttons;
3048 mouse_mode_buttons.push_back (&mouse_move_button);
3049 mouse_mode_buttons.push_back (&mouse_select_button);
3050 mouse_mode_buttons.push_back (&mouse_gain_button);
3051 mouse_mode_buttons.push_back (&mouse_zoom_button);
3052 mouse_mode_buttons.push_back (&mouse_timefx_button);
3053 mouse_mode_buttons.push_back (&mouse_audition_button);
3054 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
3056 mouse_mode_button_table.set_homogeneous (true);
3057 mouse_mode_button_table.set_col_spacings (2);
3058 mouse_mode_button_table.set_row_spacings (2);
3059 mouse_mode_button_table.set_border_width (5);
3061 mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1);
3062 mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1);
3063 mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1);
3065 mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2);
3066 mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2);
3067 mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2);
3069 mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table));
3070 mouse_mode_tearoff->set_name ("MouseModeBase");
3072 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
3073 static_cast<Gtk::Widget*>(&mouse_mode_button_table)));
3074 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
3075 static_cast<Gtk::Widget*> (&mouse_mode_button_table), 1));
3077 mouse_move_button.set_name ("MouseModeButton");
3078 mouse_select_button.set_name ("MouseModeButton");
3079 mouse_gain_button.set_name ("MouseModeButton");
3080 mouse_zoom_button.set_name ("MouseModeButton");
3081 mouse_timefx_button.set_name ("MouseModeButton");
3082 mouse_audition_button.set_name ("MouseModeButton");
3084 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects"));
3085 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges"));
3086 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation"));
3087 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range"));
3088 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions"));
3089 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions"));
3091 mouse_move_button.unset_flags (Gtk::CAN_FOCUS);
3092 mouse_select_button.unset_flags (Gtk::CAN_FOCUS);
3093 mouse_gain_button.unset_flags (Gtk::CAN_FOCUS);
3094 mouse_zoom_button.unset_flags (Gtk::CAN_FOCUS);
3095 mouse_timefx_button.unset_flags (Gtk::CAN_FOCUS);
3096 mouse_audition_button.unset_flags (Gtk::CAN_FOCUS);
3098 mouse_select_button.toggled.connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
3099 mouse_select_button.button_release_event.connect (mem_fun(*this, &Editor::mouse_select_button_release));
3101 mouse_move_button.toggled.connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
3102 mouse_gain_button.toggled.connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
3103 mouse_zoom_button.toggled.connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
3104 mouse_timefx_button.toggled.connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
3105 mouse_audition_button.toggled.connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
3107 // mouse_move_button.set_active (true);
3109 /* automation control */
3111 global_automation_button.set_name ("MouseModeButton");
3112 automation_mode_button.set_name ("MouseModeButton");
3114 automation_box.set_spacing (2);
3115 automation_box.set_border_width (2);
3116 automation_box.pack_start (global_automation_button, false, false);
3117 automation_box.pack_start (automation_mode_button, false, false);
3121 edit_mode_label.set_name ("ToolBarLabel");
3123 edit_mode_selector.set_name ("EditModeSelector");
3124 edit_mode_selector.get_entry()->set_name ("EditModeSelector");
3125 edit_mode_selector.get_popwin()->set_name ("EditModeSelector");
3127 edit_mode_box.set_spacing (3);
3128 edit_mode_box.set_border_width (3);
3130 /* XXX another disgusting hack because of the way combo boxes size themselves */
3132 Gtkmm2ext::set_size_request_to_display_given_text (*edit_mode_selector.get_entry(), "EdgtMode", 2, 10);
3133 edit_mode_selector.set_popdown_strings (internationalize (edit_mode_strings));
3134 edit_mode_selector.set_value_in_list (true, false);
3136 edit_mode_box.pack_start (edit_mode_label, false, false);
3137 edit_mode_box.pack_start (edit_mode_selector, false, false);
3139 edit_mode_selector.get_popwin()->unmap_event.connect (mem_fun(*this, &Editor::edit_mode_selection_done));
3143 snap_type_label.set_name ("ToolBarLabel");
3145 snap_type_selector.set_name ("SnapTypeSelector");
3146 snap_type_selector.get_entry()->set_name ("SnapTypeSelector");
3147 snap_type_selector.get_popwin()->set_name ("SnapTypeSelector");
3149 snap_type_box.set_spacing (3);
3150 snap_type_box.set_border_width (3);
3152 /* XXX another disgusting hack because of the way combo boxes size themselves */
3154 const guint32 FUDGE = 10; // Combo's are stupid - they steal space from the entry for the button
3155 Gtkmm2ext::set_size_request_to_display_given_text (*snap_type_selector.get_entry(), "Region bounds", 2+FUDGE, 10);
3156 snap_type_selector.set_popdown_strings (internationalize (snap_type_strings));
3157 snap_type_selector.set_value_in_list (true, false);
3159 snap_type_box.pack_start (snap_type_label, false, false);
3160 snap_type_box.pack_start (snap_type_selector, false, false);
3162 snap_type_selector.get_popwin()->unmap_event.connect (mem_fun(*this, &Editor::snap_type_selection_done));
3164 /* Snap mode, not snap type */
3166 snap_mode_label.set_name ("ToolBarLabel");
3168 snap_mode_selector.set_name ("SnapModeSelector");
3169 snap_mode_selector.get_entry()->set_name ("SnapModeSelector");
3170 snap_mode_selector.get_popwin()->set_name ("SnapModeSelector");
3172 snap_mode_box.set_spacing (3);
3173 snap_mode_box.set_border_width (3);
3175 Gtkmm2ext::set_size_request_to_display_given_text (*snap_mode_selector.get_entry(), "SngpMode", 2, 10);
3176 snap_mode_selector.set_popdown_strings (internationalize (snap_mode_strings));
3177 snap_mode_selector.set_value_in_list (true, false);
3179 snap_mode_box.pack_start (snap_mode_label, false, false);
3180 snap_mode_box.pack_start (snap_mode_selector, false, false);
3182 snap_mode_selector.get_popwin()->unmap_event.connect (mem_fun(*this, &Editor::snap_mode_selection_done));
3184 /* Zoom focus mode */
3186 zoom_focus_label.set_name ("ToolBarLabel");
3188 zoom_focus_selector.set_name ("ZoomFocusSelector");
3189 zoom_focus_selector.get_entry()->set_name ("ZoomFocusSelector");
3190 zoom_focus_selector.get_popwin()->set_name ("ZoomFocusSelector");
3192 zoom_focus_box.set_spacing (3);
3193 zoom_focus_box.set_border_width (3);
3195 /* XXX another disgusting hack because of the way combo boxes size themselves */
3197 Gtkmm2ext::set_size_request_to_display_given_text (*zoom_focus_selector.get_entry(), "Edgt Cursor", 2, 10);
3198 zoom_focus_selector.set_popdown_strings (internationalize (zoom_focus_strings));
3199 zoom_focus_selector.set_value_in_list (true, false);
3201 zoom_focus_box.pack_start (zoom_focus_label, false, false);
3202 zoom_focus_box.pack_start (zoom_focus_selector, false, false);
3204 zoom_focus_selector.get_popwin()->unmap_event.connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
3206 /* selection/cursor clocks */
3208 toolbar_selection_cursor_label.set_name ("ToolBarLabel");
3209 selection_start_clock_label.set_name ("ToolBarLabel");
3210 selection_end_clock_label.set_name ("ToolBarLabel");
3211 edit_cursor_clock_label.set_name ("ToolBarLabel");
3213 selection_start_clock_label.set_text (_("Start:"));
3214 selection_end_clock_label.set_text (_("End:"));
3215 edit_cursor_clock_label.set_text (_("Edit:"));
3217 toolbar_selection_clock_table.set_border_width (5);
3218 toolbar_selection_clock_table.set_col_spacings (2);
3219 toolbar_selection_clock_table.set_homogeneous (false);
3221 // toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0);
3222 // toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0);
3223 toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, 0, 0, 0, 0);
3225 // toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0);
3226 // toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0);
3227 toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, 0, 0);
3230 // toolbar_clock_vbox.set_spacing (2);
3231 // toolbar_clock_vbox.set_border_width (10);
3232 /* the editor/mixer button will be enabled at session connect */
3234 editor_mixer_button.set_active(false);
3235 editor_mixer_button.set_sensitive(false);
3237 HBox* hbox = new HBox;
3239 hbox->pack_start (editor_mixer_button, false, false);
3240 hbox->pack_start (toolbar_selection_clock_table, false, false);
3241 hbox->pack_start (zoom_indicator_vbox, false, false);
3242 hbox->pack_start (zoom_focus_box, false, false);
3243 hbox->pack_start (snap_type_box, false, false);
3244 hbox->pack_start (snap_mode_box, false, false);
3245 hbox->pack_start (edit_mode_box, false, false);
3247 VBox *vbox = manage (new VBox);
3249 vbox->set_spacing (3);
3250 vbox->set_border_width (3);
3252 HBox *nbox = manage (new HBox);
3254 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
3255 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
3257 nbox->pack_start (nudge_backward_button, false, false);
3258 nbox->pack_start (nudge_forward_button, false, false);
3259 nbox->pack_start (nudge_clock, false, false, 5);
3261 nudge_label.set_name ("ToolBarLabel");
3263 vbox->pack_start (nudge_label, false, false);
3264 vbox->pack_start (*nbox, false, false);
3266 hbox->pack_start (*vbox, false, false);
3270 tools_tearoff = new TearOff (*hbox);
3271 tools_tearoff->set_name ("MouseModeBase");
3273 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
3274 static_cast<Gtk::Widget*>(hbox)));
3275 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
3276 static_cast<Gtk::Widget*> (hbox), 0));
3278 toolbar_hbox.set_spacing (8);
3279 toolbar_hbox.set_border_width (2);
3281 toolbar_hbox.pack_start (*tools_tearoff, false, false);
3282 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
3284 toolbar_base.set_name ("ToolBarBase");
3285 toolbar_base.add (toolbar_hbox);
3287 toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT);
3288 toolbar_frame.set_name ("BaseFrame");
3289 toolbar_frame.add (toolbar_base);
3293 Editor::_autoscroll_canvas (void *arg)
3295 return ((Editor *) arg)->autoscroll_canvas ();
3299 Editor::autoscroll_canvas ()
3301 jack_nframes_t new_frame;
3302 bool keep_calling = true;
3304 if (autoscroll_direction < 0) {
3305 if (leftmost_frame < autoscroll_distance) {
3308 new_frame = leftmost_frame - autoscroll_distance;
3311 if (leftmost_frame > max_frames - autoscroll_distance) {
3312 new_frame = max_frames;
3314 new_frame = leftmost_frame + autoscroll_distance;
3318 if (new_frame != leftmost_frame) {
3319 reposition_x_origin (new_frame);
3322 if (new_frame == 0 || new_frame == max_frames) {
3329 if (autoscroll_cnt == 1) {
3331 /* connect the timeout so that we get called repeatedly */
3333 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
3334 keep_calling = false;
3336 } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
3338 /* after about a while, speed up a bit by changing the timeout interval */
3340 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
3341 keep_calling = false;
3343 } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
3345 /* after about another while, speed up some more */
3347 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
3348 keep_calling = false;
3350 } else if (autoscroll_cnt >= 30) {
3352 /* we've been scrolling for a while ... crank it up */
3354 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
3357 return keep_calling;
3361 Editor::start_canvas_autoscroll (int dir)
3367 stop_canvas_autoscroll ();
3369 autoscroll_direction = dir;
3370 autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
3373 /* do it right now, which will start the repeated callbacks */
3375 autoscroll_canvas ();
3379 Editor::stop_canvas_autoscroll ()
3381 if (autoscroll_timeout_tag >= 0) {
3382 gtk_timeout_remove (autoscroll_timeout_tag);
3383 autoscroll_timeout_tag = -1;
3388 Editor::convert_drop_to_paths (vector<string>& paths,
3389 GdkDragContext *context,
3392 GtkSelectionData *data,
3400 gchar *tname = gdk_atom_name (data->type);
3402 if (session == 0 || strcmp (tname, "text/plain") != 0) {
3406 /* Parse the "uri-list" format that Nautilus provides,
3407 where each pathname is delimited by \r\n
3410 path = (char *) data->data;
3413 for (int n = 0; n < data->length; ++n) {
3417 if (path[n] == '\r') {
3424 if (path[n] == '\n') {
3425 paths.push_back (spath);
3429 warning << _("incorrectly formatted URI list, ignored")
3437 /* nautilus and presumably some other file managers prefix even text/plain with file:// */
3439 for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3441 // cerr << "dropped text was " << *p << endl;
3445 // cerr << "decoded was " << *p << endl;
3447 if ((*p).substr (0,7) == "file://") {
3448 (*p) = (*p).substr (7);
3456 Editor::track_canvas_drag_data_received (GdkDragContext *context,
3459 GtkSelectionData *data,
3464 AudioTimeAxisView* tv;
3466 vector<string> paths;
3469 jack_nframes_t frame;
3471 if (convert_drop_to_paths (paths, context, x, y, data, info, time)) {
3475 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
3481 gtk_canvas_window_to_world (GTK_CANVAS(track_gtk_canvas), (double) x, (double) y, &wx, &wy);
3483 ev.type = GDK_BUTTON_RELEASE;
3487 frame = event_frame (&ev, 0, &cy);
3491 if ((tvp = trackview_by_y_position (cy)) == 0) {
3493 /* drop onto canvas background: create a new track */
3495 insert_paths_as_new_tracks (paths, false);
3498 } else if ((tv = dynamic_cast<AudioTimeAxisView*>(tvp)) != 0) {
3500 /* check that its an audio track, not a bus */
3502 if (tv->get_diskstream()) {
3504 for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3505 insert_sndfile_into (*p, true, tv, frame);
3512 gtk_drag_finish (context, TRUE, FALSE, time);
3516 Editor::new_tempo_section ()
3522 Editor::map_transport_state ()
3524 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
3526 if (session->transport_stopped()) {
3527 have_pending_keyboard_selection = false;
3533 Editor::State::State ()
3535 selection = new Selection;
3538 Editor::State::~State ()
3544 Editor::get_memento () const
3546 State *state = new State;
3548 store_state (*state);
3549 return bind (slot (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
3553 Editor::store_state (State& state) const
3555 *state.selection = *selection;
3559 Editor::restore_state (State *state)
3561 if (*selection == *state->selection) {
3565 *selection = *state->selection;
3566 time_selection_changed ();
3567 region_selection_changed ();
3569 /* XXX other selection change handlers? */
3573 Editor::begin_reversible_command (string name)
3576 UndoAction ua = get_memento();
3577 session->begin_reversible_command (name, &ua);
3582 Editor::commit_reversible_command ()
3585 UndoAction ua = get_memento();
3586 session->commit_reversible_command (&ua);
3591 Editor::flush_track_canvas ()
3593 /* I don't think this is necessary, and only causes more problems.
3594 I'm commenting it out
3595 and if the imageframe folks don't have any issues, we can take
3596 out this method entirely
3599 //gtk_canvas_update_now (GTK_CANVAS(track_gtk_canvas));
3600 //gtk_main_iteration ();
3604 Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove)
3606 if (!clicked_trackview) {
3611 begin_reversible_command (_("set selected trackview"));
3616 if (selection->selected (clicked_trackview)) {
3618 selection->remove (clicked_trackview);
3621 selection->add (clicked_trackview);
3626 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
3627 /* no commit necessary */
3631 selection->set (clicked_trackview);
3635 commit_reversible_command ();
3640 Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove)
3642 if (!clicked_control_point) {
3647 begin_reversible_command (_("set selected control point"));
3657 commit_reversible_command ();
3662 Editor::set_selected_regionview_from_click (bool add, bool no_track_remove)
3664 if (!clicked_regionview) {
3668 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view());
3674 RouteGroup* group = atv->route().edit_group();
3675 vector<AudioRegionView*> all_equivalent_regions;
3677 if (group && group->is_active()) {
3679 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3681 AudioTimeAxisView* tatv;
3683 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3685 if (tatv->route().edit_group() != group) {
3690 vector<AudioRegion*> results;
3691 AudioRegionView* marv;
3694 if ((ds = tatv->get_diskstream()) == 0) {
3699 if ((pl = ds->playlist()) != 0) {
3700 pl->get_equivalent_regions (clicked_regionview->region,
3704 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3705 if ((marv = tatv->view->find_view (**ir)) != 0) {
3706 all_equivalent_regions.push_back (marv);
3715 all_equivalent_regions.push_back (clicked_regionview);
3719 begin_reversible_command (_("set selected regionview"));
3723 if (clicked_regionview->get_selected()) {
3724 if (group && group->is_active() && selection->audio_regions.size() > 1) {
3725 /* reduce selection down to just the one clicked */
3726 selection->set (clicked_regionview);
3728 selection->remove (clicked_regionview);
3731 selection->add (all_equivalent_regions);
3734 set_selected_track_from_click (add, false, no_track_remove);
3738 // karsten wiese suggested these two lines to make
3739 // a selected region rise to the top. but this
3740 // leads to a mismatch between actual layering
3741 // and visual layering. resolution required ....
3743 // gtk_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3744 // gtk_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3746 if (clicked_regionview->get_selected()) {
3747 /* no commit necessary: we are the one selected. */
3752 selection->set (all_equivalent_regions);
3753 set_selected_track_from_click (add, false, false);
3757 commit_reversible_command () ;
3761 Editor::set_selected_regionview_from_region_list (Region& r, bool add)
3763 vector<AudioRegionView*> all_equivalent_regions;
3764 AudioRegion* region;
3766 if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3770 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3772 AudioTimeAxisView* tatv;
3774 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3777 vector<AudioRegion*> results;
3778 AudioRegionView* marv;
3781 if ((ds = tatv->get_diskstream()) == 0) {
3786 if ((pl = ds->playlist()) != 0) {
3787 pl->get_region_list_equivalent_regions (*region, results);
3790 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3791 if ((marv = tatv->view->find_view (**ir)) != 0) {
3792 all_equivalent_regions.push_back (marv);
3799 begin_reversible_command (_("set selected regions"));
3803 selection->add (all_equivalent_regions);
3807 selection->set (all_equivalent_regions);
3810 commit_reversible_command () ;
3814 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3816 AudioRegionView* rv;
3819 if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3823 if ((rv = sv->find_view (*ar)) == 0) {
3827 /* don't reset the selection if its something other than
3828 a single other region.
3831 if (selection->audio_regions.size() > 1) {
3835 begin_reversible_command (_("set selected regions"));
3837 selection->set (rv);
3839 commit_reversible_command () ;
3845 Editor::set_edit_group_solo (Route& route, bool yn)
3847 RouteGroup *edit_group;
3849 if ((edit_group = route.edit_group()) != 0) {
3850 edit_group->apply (&Route::set_solo, yn, this);
3852 route.set_solo (yn, this);
3857 Editor::set_edit_group_mute (Route& route, bool yn)
3859 RouteGroup *edit_group = 0;
3861 if ((edit_group == route.edit_group()) != 0) {
3862 edit_group->apply (&Route::set_mute, yn, this);
3864 route.set_mute (yn, this);
3869 Editor::set_edit_menu (Menu& menu)
3872 edit_menu->map_.connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3876 Editor::edit_menu_map_handler ()
3878 using namespace Menu_Helpers;
3879 MenuList& edit_items = edit_menu->items();
3882 /* Nuke all the old items */
3884 edit_items.clear ();
3890 if (session->undo_depth() == 0) {
3893 label = compose(_("Undo (%1)"), session->next_undo());
3896 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3898 if (session->undo_depth() == 0) {
3899 edit_items.back()->set_sensitive (false);
3902 if (session->redo_depth() == 0) {
3905 label = compose(_("Redo (%1)"), session->next_redo());
3908 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3909 if (session->redo_depth() == 0) {
3910 edit_items.back()->set_sensitive (false);
3913 vector<MenuItem*> mitems;
3915 edit_items.push_back (SeparatorElem());
3916 edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3917 mitems.push_back (edit_items.back());
3918 edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3919 mitems.push_back (edit_items.back());
3920 edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3921 mitems.push_back (edit_items.back());
3922 edit_items.push_back (SeparatorElem());
3923 edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3924 mitems.push_back (edit_items.back());
3925 edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3926 mitems.push_back (edit_items.back());
3927 edit_items.push_back (SeparatorElem());
3929 if (selection->empty()) {
3930 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3931 (*i)->set_sensitive (false);
3935 Menu* import_menu = manage (new Menu());
3936 import_menu->set_name ("ArdourContextMenu");
3937 MenuList& import_items = import_menu->items();
3939 import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3940 import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3942 Menu* embed_menu = manage (new Menu());
3943 embed_menu->set_name ("ArdourContextMenu");
3944 MenuList& embed_items = embed_menu->items();
3946 embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3947 embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3949 edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3950 edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3951 edit_items.push_back (SeparatorElem());
3953 edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3954 if (!session->have_captured()) {
3955 edit_items.back()->set_sensitive (false);
3960 Editor::duplicate_dialog (bool dup_region)
3963 if (clicked_regionview == 0) {
3967 if (selection->time.length() == 0) {
3972 ArdourDialog win ("duplicate dialog");
3974 Label label (_("Duplicate how many times?"));
3977 Button ok_button (_("OK"));
3978 Button cancel_button (_("Cancel"));
3981 button_box.set_spacing (7);
3982 set_size_request_to_display_given_text (ok_button, _("Cancel"), 20, 15); // this is cancel on purpose
3983 set_size_request_to_display_given_text (cancel_button, _("Cancel"), 20, 15);
3984 button_box.pack_end (ok_button, false, false);
3985 button_box.pack_end (cancel_button, false, false);
3987 hbox.set_spacing (5);
3988 hbox.pack_start (label);
3989 hbox.pack_start (entry, true, true);
3991 vbox.set_spacing (5);
3992 vbox.set_border_width (5);
3993 vbox.pack_start (hbox);
3994 vbox.pack_start (button_box);
3997 win.set_position (Gtk::WIN_POS_MOUSE);
4000 ok_button.signal_clicked().connect (bind (slot (win, &ArdourDialog::stop), 0));
4001 entry.activate.connect (bind (slot (win, &ArdourDialog::stop), 0));
4002 cancel_button.signal_clicked().connect (bind (slot (win, &ArdourDialog::stop), 1));
4004 entry.signal_focus_in_event().connect (slot (ARDOUR_UI::generic_focus_in_event));
4005 entry.signal_focus_out_event().connect (slot (ARDOUR_UI::generic_focus_out_event));
4007 entry.set_text ("1");
4008 set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
4009 entry.select_region (0, entry.get_text_length());
4011 win.set_position (Gtk::WIN_POS_MOUSE);
4013 win.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
4015 entry.grab_focus ();
4019 if (win.run_status() != 0) {
4023 string text = entry.get_text();
4026 if (sscanf (text.c_str(), "%f", ×) == 1) {
4028 AudioRegionSelection regions;
4029 regions.add (clicked_regionview);
4030 duplicate_some_regions (regions, times);
4032 duplicate_selection (times);
4038 Editor::show_verbose_canvas_cursor ()
4040 gtk_canvas_item_raise_to_top (verbose_canvas_cursor);
4041 gtk_canvas_item_show (verbose_canvas_cursor);
4042 verbose_cursor_visible = true;
4046 Editor::hide_verbose_canvas_cursor ()
4048 gtk_canvas_item_hide (verbose_canvas_cursor);
4049 verbose_cursor_visible = false;
4053 Editor::set_verbose_canvas_cursor (string txt, double x, double y)
4055 /* XXX get origin of canvas relative to root window,
4056 add x and y and check compared to gdk_screen_{width,height}
4058 gtk_canvas_item_set (verbose_canvas_cursor, "text", txt.c_str(), "x", x, "y", y, NULL);
4062 Editor::set_verbose_canvas_cursor_text (string txt)
4064 gtk_canvas_item_set (verbose_canvas_cursor, "text", txt.c_str(), NULL);
4068 Editor::edit_mode_selection_done (GdkEventAny *ev)
4074 string choice = edit_mode_selector.get_entry()->get_text();
4075 EditMode mode = Slide;
4077 if (choice == _("Splice")) {
4079 } else if (choice == _("Slide")) {
4083 session->set_edit_mode (mode);
4089 Editor::snap_type_selection_done (GdkEventAny *ev)
4095 string choice = snap_type_selector.get_entry()->get_text();
4096 SnapType snaptype = SnapToFrame;
4098 if (choice == _("Beats/3")) {
4099 snaptype = SnapToAThirdBeat;
4100 } else if (choice == _("Beats/4")) {
4101 snaptype = SnapToAQuarterBeat;
4102 } else if (choice == _("Beats/8")) {
4103 snaptype = SnapToAEighthBeat;
4104 } else if (choice == _("Beats/16")) {
4105 snaptype = SnapToASixteenthBeat;
4106 } else if (choice == _("Beats/32")) {
4107 snaptype = SnapToAThirtysecondBeat;
4108 } else if (choice == _("Beats")) {
4109 snaptype = SnapToBeat;
4110 } else if (choice == _("Bars")) {
4111 snaptype = SnapToBar;
4112 } else if (choice == _("Marks")) {
4113 snaptype = SnapToMark;
4114 } else if (choice == _("Edit Cursor")) {
4115 snaptype = SnapToEditCursor;
4116 } else if (choice == _("Region starts")) {
4117 snaptype = SnapToRegionStart;
4118 } else if (choice == _("Region ends")) {
4119 snaptype = SnapToRegionEnd;
4120 } else if (choice == _("Region bounds")) {
4121 snaptype = SnapToRegionBoundary;
4122 } else if (choice == _("Region syncs")) {
4123 snaptype = SnapToRegionSync;
4124 } else if (choice == _("CD Frames")) {
4125 snaptype = SnapToCDFrame;
4126 } else if (choice == _("SMPTE Frames")) {
4127 snaptype = SnapToSMPTEFrame;
4128 } else if (choice == _("SMPTE Seconds")) {
4129 snaptype = SnapToSMPTESeconds;
4130 } else if (choice == _("SMPTE Minutes")) {
4131 snaptype = SnapToSMPTEMinutes;
4132 } else if (choice == _("Seconds")) {
4133 snaptype = SnapToSeconds;
4134 } else if (choice == _("Minutes")) {
4135 snaptype = SnapToMinutes;
4136 } else if (choice == _("None")) {
4137 snaptype = SnapToFrame;
4140 set_snap_to (snaptype);
4146 Editor::snap_mode_selection_done (GdkEventAny *ev)
4148 if(session == 0) return FALSE;
4150 string choice = snap_mode_selector.get_entry()->get_text();
4151 SnapMode mode = SnapNormal;
4153 if (choice == _("Normal")) {
4155 } else if (choice == _("Magnetic")) {
4156 mode = SnapMagnetic;
4159 set_snap_mode (mode);
4165 Editor::zoom_focus_selection_done (GdkEventAny *ev)
4171 string choice = zoom_focus_selector.get_entry()->get_text();
4172 ZoomFocus focus_type = ZoomFocusLeft;
4174 if (choice == _("Left")) {
4175 focus_type = ZoomFocusLeft;
4176 } else if (choice == _("Right")) {
4177 focus_type = ZoomFocusRight;
4178 } else if (choice == _("Center")) {
4179 focus_type = ZoomFocusCenter;
4180 } else if (choice == _("Playhead")) {
4181 focus_type = ZoomFocusPlayhead;
4182 } else if (choice == _("Edit Cursor")) {
4183 focus_type = ZoomFocusEdit;
4186 set_zoom_focus (focus_type);
4192 Editor::edit_controls_button_release (GdkEventButton* ev)
4194 if (Keyboard::is_context_menu_event (ev)) {
4195 ARDOUR_UI::instance()->add_route ();
4201 Editor::track_selection_changed ()
4203 switch (selection->tracks.size()){
4207 set_selected_mixer_strip (*(selection->tracks.front()));
4211 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4212 (*i)->set_selected (false);
4213 if (mouse_mode == MouseRange) {
4214 (*i)->hide_selection ();
4218 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4219 (*i)->set_selected (true);
4220 if (mouse_mode == MouseRange) {
4221 (*i)->show_selection (selection->time);
4227 Editor::time_selection_changed ()
4229 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4230 (*i)->hide_selection ();
4233 if (selection->tracks.empty()) {
4234 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4235 (*i)->show_selection (selection->time);
4238 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4239 (*i)->show_selection (selection->time);
4245 Editor::region_selection_changed ()
4247 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4248 (*i)->set_selected_regionviews (selection->audio_regions);
4253 Editor::point_selection_changed ()
4255 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4256 (*i)->set_selected_points (selection->points);
4261 Editor::run_sub_event_loop ()
4263 Keyboard::the_keyboard().allow_focus (true);
4264 sub_event_loop_status = 0;
4269 Editor::finish_sub_event_loop (int status)
4272 Keyboard::the_keyboard().allow_focus (false);
4273 sub_event_loop_status = status;
4277 Editor::finish_sub_event_loop_on_delete (GdkEventAny *ignored, int32_t status)
4279 finish_sub_event_loop (status);
4284 Editor::mouse_select_button_release (GdkEventButton* ev)
4286 /* this handles just right-clicks */
4288 if (ev->button != 3) {
4295 Editor::TrackViewList *
4296 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
4299 TrackViewList::iterator i;
4301 v = new TrackViewList;
4303 if (track == 0 && group == 0) {
4307 for (i = track_views.begin(); i != track_views.end (); ++i) {
4311 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
4313 /* just the view for this track
4316 v->push_back (track);
4320 /* views for all tracks in the edit group */
4322 for (i = track_views.begin(); i != track_views.end (); ++i) {
4324 if (group == 0 || (*i)->edit_group() == group) {
4334 Editor::set_zoom_focus (ZoomFocus f)
4336 if (zoom_focus != f) {
4338 vector<string> txt = internationalize (zoom_focus_strings);
4339 zoom_focus_selector.get_entry()->set_text (txt[(int)f]);
4340 ZoomFocusChanged (); /* EMIT_SIGNAL */
4347 Editor::ensure_float (Window& win)
4349 win.set_transient_for (*this);
4353 Editor::pane_allocation_handler (GtkAllocation *alloc, Gtk::Paned* which)
4355 /* recover or initialize pane positions. do this here rather than earlier because
4356 we don't want the positions to change the child allocations, which they seem to do.
4362 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
4364 static int32_t done[4] = { 0, 0, 0, 0 };
4367 if ((geometry = find_named_node (*node, "geometry")) == 0) {
4368 width = default_width;
4369 height = default_height;
4371 width = atoi(geometry->property("x_size")->value());
4372 height = atoi(geometry->property("y_size")->value());
4375 if (which == static_cast<Gtk::Paned*> (&track_list_canvas_pane)) {
4381 if (!geometry || (prop = geometry->property("track_list_canvas_pane_pos")) == 0) {
4383 snprintf (buf, sizeof(buf), "%d", pos);
4385 pos = atoi (prop->value());
4388 if ((done[0] = GTK_WIDGET(track_list_canvas_pane.gobj())->allocation.width > pos)) {
4389 track_list_canvas_pane.set_position (pos);
4392 } else if (which == static_cast<Gtk::Paned*> (&canvas_region_list_pane)) {
4398 if (!geometry || (prop = geometry->property("canvas_region_list_pane_pos")) == 0) {
4399 pos = width - (95 * 2);
4400 snprintf (buf, sizeof(buf), "%d", pos);
4402 pos = atoi (prop->value());
4405 if ((done[1] = GTK_WIDGET(canvas_region_list_pane.gobj())->allocation.width > pos)) {
4406 canvas_region_list_pane.set_position (pos);
4409 } else if (which == static_cast<Gtk::Paned*> (&route_group_vpane)) {
4415 if (!geometry || (prop = geometry->property("route_group_pane_pos")) == 0) {
4416 pos = width - (95 * 2);
4417 snprintf (buf, sizeof(buf), "%d", pos);
4419 pos = atoi (prop->value());
4422 if ((done[2] = GTK_WIDGET(route_group_vpane.gobj())->allocation.height > pos)) {
4423 route_group_vpane.set_position (pos);
4426 } else if (which == static_cast<Gtk::Paned*> (®ion_selection_vpane)) {
4432 if (!geometry || (prop = geometry->property("region_selection_pane_pos")) == 0) {
4433 pos = width - (95 * 2);
4434 snprintf (buf, sizeof(buf), "%d", pos);
4436 pos = atoi (prop->value());
4439 if ((done[3] = GTK_WIDGET(region_selection_vpane.gobj())->allocation.height > pos)) {
4440 region_selection_vpane.set_position (pos);
4446 Editor::detach_tearoff (Gtk::Box* b, Gtk::Widget* w)
4448 if (tools_tearoff->torn_off() &&
4449 mouse_mode_tearoff->torn_off()) {
4450 top_hbox.remove (toolbar_frame);
4453 ensure_float (*w->get_toplevel());
4457 Editor::reattach_tearoff (Gtk::Box* b, Gtk::Widget* w, int32_t n)
4459 if (toolbar_frame.get_parent() == 0) {
4460 top_hbox.pack_end (toolbar_frame);
4465 Editor::set_show_measures (bool yn)
4467 if (_show_measures != yn) {
4470 if ((_show_measures = yn) == true) {
4473 DisplayControlChanged (ShowMeasures);
4479 Editor::set_follow_playhead (bool yn)
4481 if (_follow_playhead != yn) {
4482 if ((_follow_playhead = yn) == true) {
4484 update_current_screen ();
4486 DisplayControlChanged (FollowPlayhead);
4492 Editor::toggle_xfade_active (Crossfade* xfade)
4494 xfade->set_active (!xfade->active());
4498 Editor::toggle_xfade_length (Crossfade* xfade)
4500 xfade->set_follow_overlap (!xfade->following_overlap());
4504 Editor::edit_xfade (Crossfade* xfade)
4506 CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
4510 cew.ok_button.signal_clicked().connect (bind (slot (cew, &ArdourDialog::stop), 1));
4511 cew.cancel_button.signal_clicked().connect (bind (slot (cew, &ArdourDialog::stop), 0));
4512 cew.delete_event.connect (slot (cew, &ArdourDialog::wm_doi_event_stop));
4516 if (cew.run_status() == 1) {
4518 xfade->StateChanged (Change (~0));
4523 Editor::playlist_selector () const
4525 return *_playlist_selector;
4529 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
4533 ret = nudge_clock.current_duration (pos);
4534 next = ret + 1; /* XXXX fix me */
4540 Editor::end_location_changed (Location* location)
4542 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
4543 track_canvas_scroller.get_hadjustment()->set_upper (location->end() / frames_per_unit);
4547 Editor::playlist_deletion_dialog (Playlist* pl)
4549 ArdourDialog dialog ("playlist deletion dialog");
4550 Label label (compose (_("Playlist %1 is currently unused.\n"
4551 "If left alone, no audio files used by it will be cleaned.\n"
4552 "If deleted, audio files used by it alone by will cleaned."),
4555 Button del_button (_("Delete playlist"));
4556 Button keep_button (_("Keep playlist"));
4557 Button abort_button (_("Cancel cleanup"));
4560 button_box.set_spacing (7);
4561 button_box.set_homogeneous (true);
4562 button_box.pack_end (del_button, false, false);
4563 button_box.pack_end (keep_button, false, false);
4564 button_box.pack_end (abort_button, false, false);
4566 vbox.set_spacing (5);
4567 vbox.set_border_width (5);
4568 vbox.pack_start (label);
4569 vbox.pack_start (button_box);
4572 dialog.set_position (GTK_WIN_POS_CENTER);
4575 del_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 0));
4576 keep_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 1));
4577 abort_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 2));
4580 dialog.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
4584 switch (dialog.run_status()) {
4586 /* keep the playlist */
4590 /* delete the playlist */
4598 /* keep the playlist */
4604 Editor::audio_region_selection_covers (jack_nframes_t where)
4606 for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
4607 if ((*a)->region.covers (where)) {
4616 Editor::prepare_for_cleanup ()
4618 cut_buffer->clear_audio_regions ();
4619 cut_buffer->clear_playlists ();
4621 selection->clear_audio_regions ();
4622 selection->clear_playlists ();
4626 Editor::init_colormap ()
4628 for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) {
4629 pair<ColorID,int> newpair;
4631 newpair.first = (ColorID) x;
4632 newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255);
4633 color_map.insert (newpair);
4638 Editor::transport_loop_location()
4641 return session->locations()->auto_loop_location();
4648 Editor::transport_punch_location()
4651 return session->locations()->auto_punch_location();