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 <libgnomecanvas/libgnomecanvas.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.signal_button_press_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_press));
391 edit_hscrollbar.signal_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->signal_add_event()s (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK);
410 viewport->signal_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.signal_set_event()s (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
475 time_button_event_box.set_name ("TimebarLabelBase");
476 time_button_event_box.signal_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.signal_set_event()s (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.signal_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.signal_add_event()s (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.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
638 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
639 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press));
640 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
641 region_list_display.signal_motion_notify_event().connect (mem_fun(*this, &Editor::region_list_display_motion));
642 region_list_display.signal_enter_notify_event().connect (mem_fun(*this, &Editor::region_list_display_enter_notify));
643 region_list_display.signal_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.signal_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.signal_button_release_event().connect (bind (ptr_fun (pane_handler), static_cast<Paned*> (&route_group_vpane)));
690 region_selection_vpane.signal_button_release_event().connect (bind (ptr_fun (pane_handler), static_cast<Paned*> (®ion_selection_vpane)));
691 canvas_region_list_pane.signal_button_release_event().connect (bind (ptr_fun (pane_handler), static_cast<Paned*> (&canvas_region_list_pane)));
692 track_list_canvas_pane.signal_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->signal_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 ()
820 gnome_canvas_init ();
822 track_gnome_canvas = gnome_canvas_new_aa ();
824 /* adjust sensitivity for "picking" items */
826 // GNOME_CANVAS(track_gnome_canvas)->close_enough = 2;
828 gtk_signal_connect (GTK_OBJECT(gnome_canvas_root (GNOME_CANVAS(track_gnome_canvas))), "event",
829 (GtkSignalFunc) Editor::_track_canvas_event, this);
830 track_canvas = wrap (track_gnome_canvas);
831 track_canvas->set_name ("EditorMainCanvas");
833 track_canvas->signal_add_event()s (Gdk::POINTER_MOTION_HINT_MASK);
835 track_canvas->signal_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 = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
849 gnome_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 = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
859 gnome_canvas_group_get_type(),
864 cursor_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
865 gnome_canvas_group_get_type(),
870 time_gnome_canvas = gnome_canvas_new_aa ();
871 time_canvas = wrap (time_gnome_canvas);
872 time_canvas->set_name ("EditorTimeCanvas");
874 time_canvas->signal_add_event()s (Gdk::POINTER_MOTION_HINT_MASK);
876 meter_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(time_gnome_canvas)),
877 gnome_canvas_group_get_type(),
881 tempo_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(time_gnome_canvas)),
882 gnome_canvas_group_get_type(),
886 marker_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(time_gnome_canvas)),
887 gnome_canvas_group_get_type(),
889 "y", timebar_height * 2.0,
891 range_marker_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(time_gnome_canvas)),
892 gnome_canvas_group_get_type(),
894 "y", timebar_height * 3.0,
896 transport_marker_group = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(time_gnome_canvas)),
897 gnome_canvas_group_get_type(),
899 "y", timebar_height * 4.0,
902 tempo_bar = gnome_canvas_item_new (GNOME_CANVAS_GROUP(tempo_group),
903 gnome_canvas_simplerect_get_type(),
906 "x2", max_canvas_coordinate,
907 "y2", timebar_height,
908 "fill_color_rgba", color_map[cTempoBar],
911 meter_bar = gnome_canvas_item_new (GNOME_CANVAS_GROUP(meter_group),
912 gnome_canvas_simplerect_get_type(),
915 "x2", max_canvas_coordinate,
916 "y2", timebar_height,
917 "fill_color_rgba", color_map[cMeterBar],
920 marker_bar = gnome_canvas_item_new (GNOME_CANVAS_GROUP(marker_group),
921 gnome_canvas_simplerect_get_type(),
924 "x2", max_canvas_coordinate,
925 "y2", timebar_height,
926 "fill_color_rgba", color_map[cMarkerBar],
929 range_marker_bar = gnome_canvas_item_new (GNOME_CANVAS_GROUP(range_marker_group),
930 gnome_canvas_simplerect_get_type(),
933 "x2", max_canvas_coordinate,
934 "y2", timebar_height,
935 "fill_color_rgba", color_map[cRangeMarkerBar],
938 transport_marker_bar = gnome_canvas_item_new (GNOME_CANVAS_GROUP(transport_marker_group),
939 gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(range_marker_group),
949 gnome_canvas_simplerect_get_type(),
953 "y2", timebar_height,
954 "fill_color_rgba", color_map[cRangeDragBarRectFill],
955 "outline_color_rgba", color_map[cRangeDragBarRect],
957 gnome_canvas_item_hide (range_bar_drag_rect);
959 transport_bar_drag_rect = gnome_canvas_item_new (GNOME_CANVAS_GROUP(transport_marker_group),
960 gnome_canvas_simplerect_get_type(),
964 "y2", timebar_height,
965 "fill_color_rgba", color_map[cTransportDragRectFill],
966 "outline_color_rgba", color_map[cTransportDragRect],
968 gnome_canvas_item_hide (transport_bar_drag_rect);
971 marker_drag_line_points = gnome_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 = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
980 gnome_canvas_line_get_type(),
982 "fill_color_rgba", color_map[cMarkerDragLine],
983 "points", marker_drag_line_points,
985 gnome_canvas_item_hide (marker_drag_line);
987 range_marker_drag_rect = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
988 gnome_canvas_simplerect_get_type(),
993 "fill_color_rgba", color_map[cRangeDragRectFill],
994 "outline_color_rgba", color_map[cRangeDragRect],
996 gnome_canvas_item_hide (range_marker_drag_rect);
999 transport_loop_range_rect = gnome_canvas_item_new ((GNOME_CANVAS_GROUP(time_line_group)),
1000 gnome_canvas_simplerect_get_type(),
1005 "fill_color_rgba", color_map[cTransportLoopRectFill],
1006 "outline_color_rgba", color_map[cTransportLoopRect],
1007 "outline_pixels", 1,
1009 gnome_canvas_item_hide (transport_loop_range_rect);
1011 transport_punch_range_rect = gnome_canvas_item_new ((GNOME_CANVAS_GROUP(time_line_group)),
1012 gnome_canvas_simplerect_get_type(),
1017 "fill_color_rgba", color_map[cTransportPunchRectFill],
1018 "outline_color_rgba", color_map[cTransportPunchRect],
1019 "outline_pixels", 0,
1021 gnome_canvas_item_lower_to_bottom (transport_punch_range_rect);
1022 gnome_canvas_item_lower_to_bottom (transport_loop_range_rect); // loop on the bottom
1023 gnome_canvas_item_hide (transport_punch_range_rect);
1025 transport_punchin_line = gnome_canvas_item_new ((GNOME_CANVAS_GROUP(time_line_group)),
1026 gnome_canvas_simplerect_get_type(),
1031 "outline_color_rgba", color_map[cPunchInLine],
1032 "outline_pixels", 1,
1034 gnome_canvas_item_hide (transport_punchin_line);
1036 transport_punchout_line = gnome_canvas_item_new ((GNOME_CANVAS_GROUP(time_line_group)),
1037 gnome_canvas_simplerect_get_type(),
1042 "outline_color_rgba", color_map[cPunchOutLine],
1043 "outline_pixels", 1,
1045 gnome_canvas_item_hide (transport_punchout_line);
1050 // used to show zoom mode active zooming
1051 zoom_rect = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
1052 gnome_canvas_simplerect_get_type(),
1057 "fill_color_rgba", color_map[cZoomRectFill],
1058 "outline_color_rgba", color_map[cZoomRect],
1059 "outline_pixels", 1,
1061 gnome_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 = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
1068 gnome_canvas_simplerect_get_type(),
1073 "outline_color_rgba", color_map[cRubberBandRect],
1074 "fill_color_rgba", (guint32) color_map[cRubberBandRectFill],
1075 "outline_pixels", 1,
1077 gnome_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 = gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(tempo_group),
1110 gnome_canvas_line_get_type(),
1112 "fill_color", "black",
1113 "points", tempo_line_points,
1116 // cerr << "tempo line @ " << tempo_line << endl;
1118 meter_line_points = gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(meter_group),
1125 gnome_canvas_line_get_type(),
1127 "fill_color", "black",
1128 "points", meter_line_points,
1131 // cerr << "meter line @ " << tempo_line << endl;
1133 marker_line_points = gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(marker_group),
1140 gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(range_marker_group),
1147 gnome_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 = gnome_canvas_item_new (GNOME_CANVAS_GROUP(transport_marker_group),
1154 gnome_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 gnome_canvas_set_scroll_region (GNOME_CANVAS(time_gnome_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::on_realize ()
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::on_realize ();
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);
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 = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_gnome_canvas)),
1448 gnome_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 gnome_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_gnome_canvas->allocation.height;
1524 canvas_alloc_width = track_gnome_canvas->allocation.width;
1527 canvas_height = max (canvas_height, canvas_alloc_height);
1529 gnome_canvas_set_scroll_region (GNOME_CANVAS(track_gnome_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 gnome_canvas_item_set (marker_drag_line, "points", marker_drag_line_points, NULL);
1541 if (range_marker_drag_rect) {
1542 gnome_canvas_item_set (range_marker_drag_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1544 if (transport_loop_range_rect) {
1545 gnome_canvas_item_set (transport_loop_range_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1547 if (transport_punch_range_rect) {
1548 gnome_canvas_item_set (transport_punch_range_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1550 if (transport_punchin_line) {
1551 gnome_canvas_item_set (transport_punchin_line, "y1", 0.0, "y2", (double) canvas_height, NULL);
1553 if (transport_punchout_line) {
1554 gnome_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 gnome_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, GnomeCanvasItem* 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->signal_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.signal_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 set_popdown_string (edit_mode_selector, internationalize (edit_mode_strings));
3135 edit_mode_box.pack_start (edit_mode_label, false, false);
3136 edit_mode_box.pack_start (edit_mode_selector, false, false);
3138 edit_mode_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
3142 snap_type_label.set_name ("ToolBarLabel");
3144 snap_type_selector.set_name ("SnapTypeSelector");
3145 snap_type_selector.get_entry()->set_name ("SnapTypeSelector");
3146 snap_type_selector.get_popwin()->set_name ("SnapTypeSelector");
3148 snap_type_box.set_spacing (3);
3149 snap_type_box.set_border_width (3);
3151 /* XXX another disgusting hack because of the way combo boxes size themselves */
3153 const guint32 FUDGE = 10; // Combo's are stupid - they steal space from the entry for the button
3154 Gtkmm2ext::set_size_request_to_display_given_text (*snap_type_selector.get_entry(), "Region bounds", 2+FUDGE, 10);
3155 set_popdown_strings (snap_type_selector, internationalize (snap_type_strings));
3157 snap_type_box.pack_start (snap_type_label, false, false);
3158 snap_type_box.pack_start (snap_type_selector, false, false);
3160 snap_type_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::snap_type_selection_done));
3162 /* Snap mode, not snap type */
3164 snap_mode_label.set_name ("ToolBarLabel");
3166 snap_mode_selector.set_name ("SnapModeSelector");
3167 snap_mode_selector.get_entry()->set_name ("SnapModeSelector");
3168 snap_mode_selector.get_popwin()->set_name ("SnapModeSelector");
3170 snap_mode_box.set_spacing (3);
3171 snap_mode_box.set_border_width (3);
3173 Gtkmm2ext::set_size_request_to_display_given_text (*snap_mode_selector.get_entry(), "SngpMode", 2, 10);
3174 set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings));
3176 snap_mode_box.pack_start (snap_mode_label, false, false);
3177 snap_mode_box.pack_start (snap_mode_selector, false, false);
3179 snap_mode_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
3181 /* Zoom focus mode */
3183 zoom_focus_label.set_name ("ToolBarLabel");
3185 zoom_focus_selector.set_name ("ZoomFocusSelector");
3186 zoom_focus_selector.get_entry()->set_name ("ZoomFocusSelector");
3187 zoom_focus_selector.get_popwin()->set_name ("ZoomFocusSelector");
3189 zoom_focus_box.set_spacing (3);
3190 zoom_focus_box.set_border_width (3);
3192 /* XXX another disgusting hack because of the way combo boxes size themselves */
3194 Gtkmm2ext::set_size_request_to_display_given_text (*zoom_focus_selector.get_entry(), "Edgt Cursor", 2, 10);
3195 set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings));
3197 zoom_focus_box.pack_start (zoom_focus_label, false, false);
3198 zoom_focus_box.pack_start (zoom_focus_selector, false, false);
3200 zoom_focus_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
3202 /* selection/cursor clocks */
3204 toolbar_selection_cursor_label.set_name ("ToolBarLabel");
3205 selection_start_clock_label.set_name ("ToolBarLabel");
3206 selection_end_clock_label.set_name ("ToolBarLabel");
3207 edit_cursor_clock_label.set_name ("ToolBarLabel");
3209 selection_start_clock_label.set_text (_("Start:"));
3210 selection_end_clock_label.set_text (_("End:"));
3211 edit_cursor_clock_label.set_text (_("Edit:"));
3213 toolbar_selection_clock_table.set_border_width (5);
3214 toolbar_selection_clock_table.set_col_spacings (2);
3215 toolbar_selection_clock_table.set_homogeneous (false);
3217 // toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0);
3218 // toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0);
3219 toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, 0, 0, 0, 0);
3221 // toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0);
3222 // toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0);
3223 toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, 0, 0);
3226 // toolbar_clock_vbox.set_spacing (2);
3227 // toolbar_clock_vbox.set_border_width (10);
3228 /* the editor/mixer button will be enabled at session connect */
3230 editor_mixer_button.set_active(false);
3231 editor_mixer_button.set_sensitive(false);
3233 HBox* hbox = new HBox;
3235 hbox->pack_start (editor_mixer_button, false, false);
3236 hbox->pack_start (toolbar_selection_clock_table, false, false);
3237 hbox->pack_start (zoom_indicator_vbox, false, false);
3238 hbox->pack_start (zoom_focus_box, false, false);
3239 hbox->pack_start (snap_type_box, false, false);
3240 hbox->pack_start (snap_mode_box, false, false);
3241 hbox->pack_start (edit_mode_box, false, false);
3243 VBox *vbox = manage (new VBox);
3245 vbox->set_spacing (3);
3246 vbox->set_border_width (3);
3248 HBox *nbox = manage (new HBox);
3250 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
3251 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
3253 nbox->pack_start (nudge_backward_button, false, false);
3254 nbox->pack_start (nudge_forward_button, false, false);
3255 nbox->pack_start (nudge_clock, false, false, 5);
3257 nudge_label.set_name ("ToolBarLabel");
3259 vbox->pack_start (nudge_label, false, false);
3260 vbox->pack_start (*nbox, false, false);
3262 hbox->pack_start (*vbox, false, false);
3266 tools_tearoff = new TearOff (*hbox);
3267 tools_tearoff->set_name ("MouseModeBase");
3269 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
3270 static_cast<Gtk::Widget*>(hbox)));
3271 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
3272 static_cast<Gtk::Widget*> (hbox), 0));
3274 toolbar_hbox.set_spacing (8);
3275 toolbar_hbox.set_border_width (2);
3277 toolbar_hbox.pack_start (*tools_tearoff, false, false);
3278 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
3280 toolbar_base.set_name ("ToolBarBase");
3281 toolbar_base.add (toolbar_hbox);
3283 toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT);
3284 toolbar_frame.set_name ("BaseFrame");
3285 toolbar_frame.add (toolbar_base);
3289 Editor::_autoscroll_canvas (void *arg)
3291 return ((Editor *) arg)->autoscroll_canvas ();
3295 Editor::autoscroll_canvas ()
3297 jack_nframes_t new_frame;
3298 bool keep_calling = true;
3300 if (autoscroll_direction < 0) {
3301 if (leftmost_frame < autoscroll_distance) {
3304 new_frame = leftmost_frame - autoscroll_distance;
3307 if (leftmost_frame > max_frames - autoscroll_distance) {
3308 new_frame = max_frames;
3310 new_frame = leftmost_frame + autoscroll_distance;
3314 if (new_frame != leftmost_frame) {
3315 reposition_x_origin (new_frame);
3318 if (new_frame == 0 || new_frame == max_frames) {
3325 if (autoscroll_cnt == 1) {
3327 /* connect the timeout so that we get called repeatedly */
3329 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
3330 keep_calling = false;
3332 } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
3334 /* after about a while, speed up a bit by changing the timeout interval */
3336 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
3337 keep_calling = false;
3339 } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
3341 /* after about another while, speed up some more */
3343 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
3344 keep_calling = false;
3346 } else if (autoscroll_cnt >= 30) {
3348 /* we've been scrolling for a while ... crank it up */
3350 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
3353 return keep_calling;
3357 Editor::start_canvas_autoscroll (int dir)
3363 stop_canvas_autoscroll ();
3365 autoscroll_direction = dir;
3366 autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
3369 /* do it right now, which will start the repeated callbacks */
3371 autoscroll_canvas ();
3375 Editor::stop_canvas_autoscroll ()
3377 if (autoscroll_timeout_tag >= 0) {
3378 gtk_timeout_remove (autoscroll_timeout_tag);
3379 autoscroll_timeout_tag = -1;
3384 Editor::convert_drop_to_paths (vector<string>& paths,
3385 GdkDragContext *context,
3388 GtkSelectionData *data,
3396 gchar *tname = gdk_atom_name (data->type);
3398 if (session == 0 || strcmp (tname, "text/plain") != 0) {
3402 /* Parse the "uri-list" format that Nautilus provides,
3403 where each pathname is delimited by \r\n
3406 path = (char *) data->data;
3409 for (int n = 0; n < data->length; ++n) {
3413 if (path[n] == '\r') {
3420 if (path[n] == '\n') {
3421 paths.push_back (spath);
3425 warning << _("incorrectly formatted URI list, ignored")
3433 /* nautilus and presumably some other file managers prefix even text/plain with file:// */
3435 for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3437 // cerr << "dropped text was " << *p << endl;
3441 // cerr << "decoded was " << *p << endl;
3443 if ((*p).substr (0,7) == "file://") {
3444 (*p) = (*p).substr (7);
3452 Editor::track_canvas_drag_data_received (GdkDragContext *context,
3455 GtkSelectionData *data,
3460 AudioTimeAxisView* tv;
3462 vector<string> paths;
3465 jack_nframes_t frame;
3467 if (convert_drop_to_paths (paths, context, x, y, data, info, time)) {
3471 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
3477 gnome_canvas_window_to_world (GNOME_CANVAS(track_gnome_canvas), (double) x, (double) y, &wx, &wy);
3479 ev.type = GDK_BUTTON_RELEASE;
3483 frame = event_frame (&ev, 0, &cy);
3487 if ((tvp = trackview_by_y_position (cy)) == 0) {
3489 /* drop onto canvas background: create a new track */
3491 insert_paths_as_new_tracks (paths, false);
3494 } else if ((tv = dynamic_cast<AudioTimeAxisView*>(tvp)) != 0) {
3496 /* check that its an audio track, not a bus */
3498 if (tv->get_diskstream()) {
3500 for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3501 insert_sndfile_into (*p, true, tv, frame);
3508 gtk_drag_finish (context, TRUE, FALSE, time);
3512 Editor::new_tempo_section ()
3518 Editor::map_transport_state ()
3520 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
3522 if (session->transport_stopped()) {
3523 have_pending_keyboard_selection = false;
3529 Editor::State::State ()
3531 selection = new Selection;
3534 Editor::State::~State ()
3540 Editor::get_memento () const
3542 State *state = new State;
3544 store_state (*state);
3545 return bind (slot (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
3549 Editor::store_state (State& state) const
3551 *state.selection = *selection;
3555 Editor::restore_state (State *state)
3557 if (*selection == *state->selection) {
3561 *selection = *state->selection;
3562 time_selection_changed ();
3563 region_selection_changed ();
3565 /* XXX other selection change handlers? */
3569 Editor::begin_reversible_command (string name)
3572 UndoAction ua = get_memento();
3573 session->begin_reversible_command (name, &ua);
3578 Editor::commit_reversible_command ()
3581 UndoAction ua = get_memento();
3582 session->commit_reversible_command (&ua);
3587 Editor::flush_track_canvas ()
3589 /* I don't think this is necessary, and only causes more problems.
3590 I'm commenting it out
3591 and if the imageframe folks don't have any issues, we can take
3592 out this method entirely
3595 //gnome_canvas_update_now (GNOME_CANVAS(track_gnome_canvas));
3596 //gtk_main_iteration ();
3600 Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove)
3602 if (!clicked_trackview) {
3607 begin_reversible_command (_("set selected trackview"));
3612 if (selection->selected (clicked_trackview)) {
3614 selection->remove (clicked_trackview);
3617 selection->add (clicked_trackview);
3622 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
3623 /* no commit necessary */
3627 selection->set (clicked_trackview);
3631 commit_reversible_command ();
3636 Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove)
3638 if (!clicked_control_point) {
3643 begin_reversible_command (_("set selected control point"));
3653 commit_reversible_command ();
3658 Editor::set_selected_regionview_from_click (bool add, bool no_track_remove)
3660 if (!clicked_regionview) {
3664 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view());
3670 RouteGroup* group = atv->route().edit_group();
3671 vector<AudioRegionView*> all_equivalent_regions;
3673 if (group && group->is_active()) {
3675 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3677 AudioTimeAxisView* tatv;
3679 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3681 if (tatv->route().edit_group() != group) {
3686 vector<AudioRegion*> results;
3687 AudioRegionView* marv;
3690 if ((ds = tatv->get_diskstream()) == 0) {
3695 if ((pl = ds->playlist()) != 0) {
3696 pl->get_equivalent_regions (clicked_regionview->region,
3700 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3701 if ((marv = tatv->view->find_view (**ir)) != 0) {
3702 all_equivalent_regions.push_back (marv);
3711 all_equivalent_regions.push_back (clicked_regionview);
3715 begin_reversible_command (_("set selected regionview"));
3719 if (clicked_regionview->get_selected()) {
3720 if (group && group->is_active() && selection->audio_regions.size() > 1) {
3721 /* reduce selection down to just the one clicked */
3722 selection->set (clicked_regionview);
3724 selection->remove (clicked_regionview);
3727 selection->add (all_equivalent_regions);
3730 set_selected_track_from_click (add, false, no_track_remove);
3734 // karsten wiese suggested these two lines to make
3735 // a selected region rise to the top. but this
3736 // leads to a mismatch between actual layering
3737 // and visual layering. resolution required ....
3739 // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3740 // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3742 if (clicked_regionview->get_selected()) {
3743 /* no commit necessary: we are the one selected. */
3748 selection->set (all_equivalent_regions);
3749 set_selected_track_from_click (add, false, false);
3753 commit_reversible_command () ;
3757 Editor::set_selected_regionview_from_region_list (Region& r, bool add)
3759 vector<AudioRegionView*> all_equivalent_regions;
3760 AudioRegion* region;
3762 if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3766 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3768 AudioTimeAxisView* tatv;
3770 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3773 vector<AudioRegion*> results;
3774 AudioRegionView* marv;
3777 if ((ds = tatv->get_diskstream()) == 0) {
3782 if ((pl = ds->playlist()) != 0) {
3783 pl->get_region_list_equivalent_regions (*region, results);
3786 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3787 if ((marv = tatv->view->find_view (**ir)) != 0) {
3788 all_equivalent_regions.push_back (marv);
3795 begin_reversible_command (_("set selected regions"));
3799 selection->add (all_equivalent_regions);
3803 selection->set (all_equivalent_regions);
3806 commit_reversible_command () ;
3810 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3812 AudioRegionView* rv;
3815 if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3819 if ((rv = sv->find_view (*ar)) == 0) {
3823 /* don't reset the selection if its something other than
3824 a single other region.
3827 if (selection->audio_regions.size() > 1) {
3831 begin_reversible_command (_("set selected regions"));
3833 selection->set (rv);
3835 commit_reversible_command () ;
3841 Editor::set_edit_group_solo (Route& route, bool yn)
3843 RouteGroup *edit_group;
3845 if ((edit_group = route.edit_group()) != 0) {
3846 edit_group->apply (&Route::set_solo, yn, this);
3848 route.set_solo (yn, this);
3853 Editor::set_edit_group_mute (Route& route, bool yn)
3855 RouteGroup *edit_group = 0;
3857 if ((edit_group == route.edit_group()) != 0) {
3858 edit_group->apply (&Route::set_mute, yn, this);
3860 route.set_mute (yn, this);
3865 Editor::set_edit_menu (Menu& menu)
3868 edit_menu->map_.connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3872 Editor::edit_menu_map_handler ()
3874 using namespace Menu_Helpers;
3875 MenuList& edit_items = edit_menu->items();
3878 /* Nuke all the old items */
3880 edit_items.clear ();
3886 if (session->undo_depth() == 0) {
3889 label = string_compose(_("Undo (%1)"), session->next_undo());
3892 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3894 if (session->undo_depth() == 0) {
3895 edit_items.back()->set_sensitive (false);
3898 if (session->redo_depth() == 0) {
3901 label = string_compose(_("Redo (%1)"), session->next_redo());
3904 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3905 if (session->redo_depth() == 0) {
3906 edit_items.back()->set_sensitive (false);
3909 vector<MenuItem*> mitems;
3911 edit_items.push_back (SeparatorElem());
3912 edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3913 mitems.push_back (edit_items.back());
3914 edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3915 mitems.push_back (edit_items.back());
3916 edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3917 mitems.push_back (edit_items.back());
3918 edit_items.push_back (SeparatorElem());
3919 edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3920 mitems.push_back (edit_items.back());
3921 edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3922 mitems.push_back (edit_items.back());
3923 edit_items.push_back (SeparatorElem());
3925 if (selection->empty()) {
3926 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3927 (*i)->set_sensitive (false);
3931 Menu* import_menu = manage (new Menu());
3932 import_menu->set_name ("ArdourContextMenu");
3933 MenuList& import_items = import_menu->items();
3935 import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3936 import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3938 Menu* embed_menu = manage (new Menu());
3939 embed_menu->set_name ("ArdourContextMenu");
3940 MenuList& embed_items = embed_menu->items();
3942 embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3943 embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3945 edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3946 edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3947 edit_items.push_back (SeparatorElem());
3949 edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3950 if (!session->have_captured()) {
3951 edit_items.back()->set_sensitive (false);
3956 Editor::duplicate_dialog (bool dup_region)
3959 if (clicked_regionview == 0) {
3963 if (selection->time.length() == 0) {
3968 ArdourDialog win ("duplicate dialog");
3970 Label label (_("Duplicate how many times?"));
3973 Button ok_button (_("OK"));
3974 Button cancel_button (_("Cancel"));
3977 button_box.set_spacing (7);
3978 set_size_request_to_display_given_text (ok_button, _("Cancel"), 20, 15); // this is cancel on purpose
3979 set_size_request_to_display_given_text (cancel_button, _("Cancel"), 20, 15);
3980 button_box.pack_end (ok_button, false, false);
3981 button_box.pack_end (cancel_button, false, false);
3983 hbox.set_spacing (5);
3984 hbox.pack_start (label);
3985 hbox.pack_start (entry, true, true);
3987 vbox.set_spacing (5);
3988 vbox.set_border_width (5);
3989 vbox.pack_start (hbox);
3990 vbox.pack_start (button_box);
3993 win.set_position (Gtk::WIN_POS_MOUSE);
3996 ok_button.signal_clicked().connect (bind (slot (win, &ArdourDialog::stop), 0));
3997 entry.activate.connect (bind (slot (win, &ArdourDialog::stop), 0));
3998 cancel_button.signal_clicked().connect (bind (slot (win, &ArdourDialog::stop), 1));
4000 entry.signal_focus_in_event()().connect (slot (ARDOUR_UI::generic_focus_in_event));
4001 entry.signal_focus_out_event()().connect (slot (ARDOUR_UI::generic_focus_out_event));
4003 entry.set_text ("1");
4004 set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
4005 entry.select_region (0, entry.get_text_length());
4007 win.set_position (Gtk::WIN_POS_MOUSE);
4009 win.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
4011 entry.grab_focus ();
4015 if (win.run_status() != 0) {
4019 string text = entry.get_text();
4022 if (sscanf (text.c_str(), "%f", ×) == 1) {
4024 AudioRegionSelection regions;
4025 regions.add (clicked_regionview);
4026 duplicate_some_regions (regions, times);
4028 duplicate_selection (times);
4034 Editor::show_verbose_canvas_cursor ()
4036 gnome_canvas_item_raise_to_top (verbose_canvas_cursor);
4037 gnome_canvas_item_show (verbose_canvas_cursor);
4038 verbose_cursor_visible = true;
4042 Editor::hide_verbose_canvas_cursor ()
4044 gnome_canvas_item_hide (verbose_canvas_cursor);
4045 verbose_cursor_visible = false;
4049 Editor::set_verbose_canvas_cursor (string txt, double x, double y)
4051 /* XXX get origin of canvas relative to root window,
4052 add x and y and check compared to gdk_screen_{width,height}
4054 gnome_canvas_item_set (verbose_canvas_cursor, "text", txt.c_str(), "x", x, "y", y, NULL);
4058 Editor::set_verbose_canvas_cursor_text (string txt)
4060 gnome_canvas_item_set (verbose_canvas_cursor, "text", txt.c_str(), NULL);
4064 Editor::edit_mode_selection_done (GdkEventAny *ev)
4070 string choice = edit_mode_selector.get_entry()->get_text();
4071 EditMode mode = Slide;
4073 if (choice == _("Splice")) {
4075 } else if (choice == _("Slide")) {
4079 session->set_edit_mode (mode);
4085 Editor::snap_type_selection_done (GdkEventAny *ev)
4091 string choice = snap_type_selector.get_entry()->get_text();
4092 SnapType snaptype = SnapToFrame;
4094 if (choice == _("Beats/3")) {
4095 snaptype = SnapToAThirdBeat;
4096 } else if (choice == _("Beats/4")) {
4097 snaptype = SnapToAQuarterBeat;
4098 } else if (choice == _("Beats/8")) {
4099 snaptype = SnapToAEighthBeat;
4100 } else if (choice == _("Beats/16")) {
4101 snaptype = SnapToASixteenthBeat;
4102 } else if (choice == _("Beats/32")) {
4103 snaptype = SnapToAThirtysecondBeat;
4104 } else if (choice == _("Beats")) {
4105 snaptype = SnapToBeat;
4106 } else if (choice == _("Bars")) {
4107 snaptype = SnapToBar;
4108 } else if (choice == _("Marks")) {
4109 snaptype = SnapToMark;
4110 } else if (choice == _("Edit Cursor")) {
4111 snaptype = SnapToEditCursor;
4112 } else if (choice == _("Region starts")) {
4113 snaptype = SnapToRegionStart;
4114 } else if (choice == _("Region ends")) {
4115 snaptype = SnapToRegionEnd;
4116 } else if (choice == _("Region bounds")) {
4117 snaptype = SnapToRegionBoundary;
4118 } else if (choice == _("Region syncs")) {
4119 snaptype = SnapToRegionSync;
4120 } else if (choice == _("CD Frames")) {
4121 snaptype = SnapToCDFrame;
4122 } else if (choice == _("SMPTE Frames")) {
4123 snaptype = SnapToSMPTEFrame;
4124 } else if (choice == _("SMPTE Seconds")) {
4125 snaptype = SnapToSMPTESeconds;
4126 } else if (choice == _("SMPTE Minutes")) {
4127 snaptype = SnapToSMPTEMinutes;
4128 } else if (choice == _("Seconds")) {
4129 snaptype = SnapToSeconds;
4130 } else if (choice == _("Minutes")) {
4131 snaptype = SnapToMinutes;
4132 } else if (choice == _("None")) {
4133 snaptype = SnapToFrame;
4136 set_snap_to (snaptype);
4142 Editor::snap_mode_selection_done (GdkEventAny *ev)
4144 if(session == 0) return FALSE;
4146 string choice = snap_mode_selector.get_entry()->get_text();
4147 SnapMode mode = SnapNormal;
4149 if (choice == _("Normal")) {
4151 } else if (choice == _("Magnetic")) {
4152 mode = SnapMagnetic;
4155 set_snap_mode (mode);
4161 Editor::zoom_focus_selection_done (GdkEventAny *ev)
4167 string choice = zoom_focus_selector.get_entry()->get_text();
4168 ZoomFocus focus_type = ZoomFocusLeft;
4170 if (choice == _("Left")) {
4171 focus_type = ZoomFocusLeft;
4172 } else if (choice == _("Right")) {
4173 focus_type = ZoomFocusRight;
4174 } else if (choice == _("Center")) {
4175 focus_type = ZoomFocusCenter;
4176 } else if (choice == _("Playhead")) {
4177 focus_type = ZoomFocusPlayhead;
4178 } else if (choice == _("Edit Cursor")) {
4179 focus_type = ZoomFocusEdit;
4182 set_zoom_focus (focus_type);
4188 Editor::edit_controls_button_release (GdkEventButton* ev)
4190 if (Keyboard::is_context_menu_event (ev)) {
4191 ARDOUR_UI::instance()->add_route ();
4197 Editor::track_selection_changed ()
4199 switch (selection->tracks.size()){
4203 set_selected_mixer_strip (*(selection->tracks.front()));
4207 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4208 (*i)->set_selected (false);
4209 if (mouse_mode == MouseRange) {
4210 (*i)->hide_selection ();
4214 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4215 (*i)->set_selected (true);
4216 if (mouse_mode == MouseRange) {
4217 (*i)->show_selection (selection->time);
4223 Editor::time_selection_changed ()
4225 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4226 (*i)->hide_selection ();
4229 if (selection->tracks.empty()) {
4230 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4231 (*i)->show_selection (selection->time);
4234 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4235 (*i)->show_selection (selection->time);
4241 Editor::region_selection_changed ()
4243 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4244 (*i)->set_selected_regionviews (selection->audio_regions);
4249 Editor::point_selection_changed ()
4251 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4252 (*i)->set_selected_points (selection->points);
4257 Editor::run_sub_event_loop ()
4259 Keyboard::the_keyboard().allow_focus (true);
4260 sub_event_loop_status = 0;
4265 Editor::finish_sub_event_loop (int status)
4268 Keyboard::the_keyboard().allow_focus (false);
4269 sub_event_loop_status = status;
4273 Editor::finish_sub_event_loop_on_delete (GdkEventAny *ignored, int32_t status)
4275 finish_sub_event_loop (status);
4280 Editor::mouse_select_button_release (GdkEventButton* ev)
4282 /* this handles just right-clicks */
4284 if (ev->button != 3) {
4291 Editor::TrackViewList *
4292 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
4295 TrackViewList::iterator i;
4297 v = new TrackViewList;
4299 if (track == 0 && group == 0) {
4303 for (i = track_views.begin(); i != track_views.end (); ++i) {
4307 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
4309 /* just the view for this track
4312 v->push_back (track);
4316 /* views for all tracks in the edit group */
4318 for (i = track_views.begin(); i != track_views.end (); ++i) {
4320 if (group == 0 || (*i)->edit_group() == group) {
4330 Editor::set_zoom_focus (ZoomFocus f)
4332 if (zoom_focus != f) {
4334 vector<string> txt = internationalize (zoom_focus_strings);
4335 zoom_focus_selector.get_entry()->set_text (txt[(int)f]);
4336 ZoomFocusChanged (); /* EMIT_SIGNAL */
4343 Editor::ensure_float (Window& win)
4345 win.set_transient_for (*this);
4349 Editor::pane_allocation_handler (GtkAllocation *alloc, Gtk::Paned* which)
4351 /* recover or initialize pane positions. do this here rather than earlier because
4352 we don't want the positions to change the child allocations, which they seem to do.
4358 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
4360 static int32_t done[4] = { 0, 0, 0, 0 };
4363 if ((geometry = find_named_node (*node, "geometry")) == 0) {
4364 width = default_width;
4365 height = default_height;
4367 width = atoi(geometry->property("x_size")->value());
4368 height = atoi(geometry->property("y_size")->value());
4371 if (which == static_cast<Gtk::Paned*> (&track_list_canvas_pane)) {
4377 if (!geometry || (prop = geometry->property("track_list_canvas_pane_pos")) == 0) {
4379 snprintf (buf, sizeof(buf), "%d", pos);
4381 pos = atoi (prop->value());
4384 if ((done[0] = GTK_WIDGET(track_list_canvas_pane.gobj())->allocation.width > pos)) {
4385 track_list_canvas_pane.set_position (pos);
4388 } else if (which == static_cast<Gtk::Paned*> (&canvas_region_list_pane)) {
4394 if (!geometry || (prop = geometry->property("canvas_region_list_pane_pos")) == 0) {
4395 pos = width - (95 * 2);
4396 snprintf (buf, sizeof(buf), "%d", pos);
4398 pos = atoi (prop->value());
4401 if ((done[1] = GTK_WIDGET(canvas_region_list_pane.gobj())->allocation.width > pos)) {
4402 canvas_region_list_pane.set_position (pos);
4405 } else if (which == static_cast<Gtk::Paned*> (&route_group_vpane)) {
4411 if (!geometry || (prop = geometry->property("route_group_pane_pos")) == 0) {
4412 pos = width - (95 * 2);
4413 snprintf (buf, sizeof(buf), "%d", pos);
4415 pos = atoi (prop->value());
4418 if ((done[2] = GTK_WIDGET(route_group_vpane.gobj())->allocation.height > pos)) {
4419 route_group_vpane.set_position (pos);
4422 } else if (which == static_cast<Gtk::Paned*> (®ion_selection_vpane)) {
4428 if (!geometry || (prop = geometry->property("region_selection_pane_pos")) == 0) {
4429 pos = width - (95 * 2);
4430 snprintf (buf, sizeof(buf), "%d", pos);
4432 pos = atoi (prop->value());
4435 if ((done[3] = GTK_WIDGET(region_selection_vpane.gobj())->allocation.height > pos)) {
4436 region_selection_vpane.set_position (pos);
4442 Editor::detach_tearoff (Gtk::Box* b, Gtk::Widget* w)
4444 if (tools_tearoff->torn_off() &&
4445 mouse_mode_tearoff->torn_off()) {
4446 top_hbox.remove (toolbar_frame);
4449 ensure_float (*w->get_toplevel());
4453 Editor::reattach_tearoff (Gtk::Box* b, Gtk::Widget* w, int32_t n)
4455 if (toolbar_frame.get_parent() == 0) {
4456 top_hbox.pack_end (toolbar_frame);
4461 Editor::set_show_measures (bool yn)
4463 if (_show_measures != yn) {
4466 if ((_show_measures = yn) == true) {
4469 DisplayControlChanged (ShowMeasures);
4475 Editor::set_follow_playhead (bool yn)
4477 if (_follow_playhead != yn) {
4478 if ((_follow_playhead = yn) == true) {
4480 update_current_screen ();
4482 DisplayControlChanged (FollowPlayhead);
4488 Editor::toggle_xfade_active (Crossfade* xfade)
4490 xfade->set_active (!xfade->active());
4494 Editor::toggle_xfade_length (Crossfade* xfade)
4496 xfade->set_follow_overlap (!xfade->following_overlap());
4500 Editor::edit_xfade (Crossfade* xfade)
4502 CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
4506 cew.ok_button.signal_clicked().connect (bind (slot (cew, &ArdourDialog::stop), 1));
4507 cew.cancel_button.signal_clicked().connect (bind (slot (cew, &ArdourDialog::stop), 0));
4508 cew.signal_delete_event().connect (slot (cew, &ArdourDialog::wm_doi_event_stop));
4512 if (cew.run_status() == 1) {
4514 xfade->StateChanged (Change (~0));
4519 Editor::playlist_selector () const
4521 return *_playlist_selector;
4525 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
4529 ret = nudge_clock.current_duration (pos);
4530 next = ret + 1; /* XXXX fix me */
4536 Editor::end_location_changed (Location* location)
4538 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
4539 track_canvas_scroller.get_hadjustment()->set_upper (location->end() / frames_per_unit);
4543 Editor::playlist_deletion_dialog (Playlist* pl)
4545 ArdourDialog dialog ("playlist deletion dialog");
4546 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4547 "If left alone, no audio files used by it will be cleaned.\n"
4548 "If deleted, audio files used by it alone by will cleaned."),
4551 Button del_button (_("Delete playlist"));
4552 Button keep_button (_("Keep playlist"));
4553 Button abort_button (_("Cancel cleanup"));
4556 button_box.set_spacing (7);
4557 button_box.set_homogeneous (true);
4558 button_box.pack_end (del_button, false, false);
4559 button_box.pack_end (keep_button, false, false);
4560 button_box.pack_end (abort_button, false, false);
4562 vbox.set_spacing (5);
4563 vbox.set_border_width (5);
4564 vbox.pack_start (label);
4565 vbox.pack_start (button_box);
4568 dialog.set_position (GTK_WIN_POS_CENTER);
4571 del_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 0));
4572 keep_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 1));
4573 abort_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 2));
4576 dialog.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
4580 switch (dialog.run_status()) {
4582 /* keep the playlist */
4586 /* delete the playlist */
4594 /* keep the playlist */
4600 Editor::audio_region_selection_covers (jack_nframes_t where)
4602 for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
4603 if ((*a)->region.covers (where)) {
4612 Editor::prepare_for_cleanup ()
4614 cut_buffer->clear_audio_regions ();
4615 cut_buffer->clear_playlists ();
4617 selection->clear_audio_regions ();
4618 selection->clear_playlists ();
4622 Editor::init_colormap ()
4624 for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) {
4625 pair<ColorID,int> newpair;
4627 newpair.first = (ColorID) x;
4628 newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255);
4629 color_map.insert (newpair);
4634 Editor::transport_loop_location()
4637 return session->locations()->auto_loop_location();
4644 Editor::transport_punch_location()
4647 return session->locations()->auto_punch_location();