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"
57 #include "playlist_selector.h"
58 #include "regionview.h"
59 #include "rgb_macros.h"
60 #include "selection.h"
61 #include "streamview.h"
62 #include "time_axis_view.h"
64 #include "crossfade_view.h"
66 #include "public_editor.h"
67 #include "crossfade_edit.h"
68 #include "audio_time_axis.h"
69 #include "gui_thread.h"
74 #include "imageframe_socket_handler.h"
75 /* </CMT Additions> */
79 using namespace ARDOUR;
81 using namespace Gtkmm2ext;
82 using namespace Editing;
84 /* XXX this is a hack. it ought to be the maximum value of an jack_nframes_t */
86 const double max_canvas_coordinate = 100000000.0;
87 const double Editor::timebar_height = 15.0;
89 #include "editor_xpms"
91 static const gchar *route_list_titles[] = {
96 static const gchar *edit_group_list_titles[] = {
100 static const gchar *named_selection_display_titles[] = {
105 static const int32_t slide_index = 0;
106 static const int32_t splice_index = 1;
108 static const gchar *edit_mode_strings[] = {
114 static const gchar *snap_type_strings[] = {
138 static const gchar *snap_mode_strings[] = {
144 static const gchar *zoom_focus_strings[] = {
153 /* Soundfile drag-n-drop */
161 static GtkTargetEntry target_table[] = {
162 { "STRING", 0, TARGET_STRING },
163 { "text/plain", 0, TARGET_STRING },
164 { "text/uri-list", 0, TARGET_URL },
165 { "application/x-rootwin-drop", 0, TARGET_ROOTWIN }
168 static guint n_targets = sizeof(target_table) / sizeof(target_table[0]);
170 GdkCursor* Editor::cross_hair_cursor = 0;
171 GdkCursor* Editor::selector_cursor = 0;
172 GdkCursor* Editor::trimmer_cursor = 0;
173 GdkCursor* Editor::grabber_cursor = 0;
174 GdkCursor* Editor::zoom_cursor = 0;
175 GdkCursor* Editor::time_fx_cursor = 0;
176 GdkCursor* Editor::fader_cursor = 0;
177 GdkCursor* Editor::speaker_cursor = 0;
178 GdkCursor* Editor::null_cursor = 0;
179 GdkCursor* Editor::wait_cursor = 0;
180 GdkCursor* Editor::timebar_cursor = 0;
182 GdkPixmap *Editor::check_pixmap = 0;
183 GdkBitmap *Editor::check_mask = 0;
184 GdkPixmap *Editor::empty_pixmap = 0;
185 GdkBitmap *Editor::empty_mask = 0;
187 Editor::Editor (AudioEngine& eng)
190 /* time display buttons */
192 minsec_label (_("Mins:Secs")),
193 bbt_label (_("Bars:Beats")),
194 smpte_label (_("SMPTE")),
195 frame_label (_("Frames")),
196 tempo_label (_("Tempo")),
197 meter_label (_("Meter")),
198 mark_label (_("Location Markers")),
199 range_mark_label (_("Range Markers")),
200 transport_mark_label (_("Loop/Punch Ranges")),
202 edit_packer (3, 3, false),
203 edit_hscroll_left_arrow (Gtk::ARROW_LEFT, Gtk::SHADOW_OUT),
204 edit_hscroll_right_arrow (Gtk::ARROW_RIGHT, Gtk::SHADOW_OUT),
206 named_selection_display (internationalize (named_selection_display_titles)),
208 /* tool bar related */
210 editor_mixer_button (_("editor\nmixer")),
212 selection_start_clock (X_("SelectionStartClock"), true),
213 selection_end_clock (X_("SelectionEndClock"), true),
214 edit_cursor_clock (X_("EditCursorClock"), true),
215 zoom_range_clock (X_("ZoomRangeClock"), true, true),
217 toolbar_selection_clock_table (2,3),
219 mouse_mode_button_table (2, 3),
221 mouse_select_button (_("range")),
222 mouse_move_button (_("object")),
223 mouse_gain_button (_("gain")),
224 mouse_zoom_button (_("zoom")),
225 mouse_timefx_button (_("timefx")),
226 mouse_audition_button (_("listen")),
228 automation_mode_button (_("mode")),
229 global_automation_button (_("automation")),
231 edit_mode_label (_("Edit Mode")),
232 snap_type_label (_("Snap To")),
233 snap_mode_label(_("Snap Mode")),
234 zoom_focus_label (_("Zoom Focus")),
236 /* <CMT Additions> */
237 image_socket_listener(0),
238 /* </CMT Additions> */
242 nudge_label (_("Nudge")),
243 nudge_clock (X_("NudgeClock"), true, true)
248 /* we are a singleton */
250 PublicEditor::_instance = this;
254 check_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
255 gtk_widget_get_colormap (GTK_WIDGET(edit_group_list.gobj())),
256 &check_mask, NULL, (gchar **) check_xpm);
257 empty_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,
258 gtk_widget_get_colormap (GTK_WIDGET(edit_group_list.gobj())),
259 &empty_mask, NULL, (gchar **) empty_xpm);
263 selection = new Selection;
264 cut_buffer = new Selection;
266 selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
267 selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
268 selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
269 selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
271 clicked_regionview = 0;
272 clicked_trackview = 0;
273 clicked_audio_trackview = 0;
274 clicked_crossfadeview = 0;
275 clicked_control_point = 0;
276 latest_regionview = 0;
277 last_update_frame = 0;
279 last_audition_region = 0;
280 current_mixer_strip = 0;
281 current_bbt_points = 0;
283 snap_type = SnapToFrame;
284 set_snap_to (snap_type);
285 snap_mode = SnapNormal;
286 set_snap_mode (snap_mode);
287 snap_threshold = 5.0;
288 bbt_beat_subdivision = 4;
291 autoscroll_timeout_tag = -1;
292 interthread_progress_window = 0;
293 current_interthread_info = 0;
294 _show_measures = true;
295 _show_waveforms = true;
296 _show_waveforms_recording = true;
297 first_action_message = 0;
299 show_gain_after_trim = false;
300 no_zoom_repos_update = false;
301 ignore_route_list_reorder = false;
302 verbose_cursor_on = true;
303 route_removal = false;
305 show_automatic_regions_in_region_list = true;
306 have_pending_keyboard_selection = false;
307 _follow_playhead = true;
308 _xfade_visibility = true;
309 editor_ruler_menu = 0;
310 no_ruler_shown_update = false;
311 edit_group_list_menu = 0;
313 region_list_menu = 0;
315 marker_menu_item = 0;
317 transport_marker_menu = 0;
318 new_transport_marker_menu = 0;
319 editor_mixer_strip_width = Wide;
320 repos_zoom_queued = false;
321 import_audio_item = 0;
322 embed_audio_item = 0;
323 region_edit_menu_split_item = 0;
325 region_edit_menu_split_multichannel_item = 0;
326 edit_hscroll_dragging = false;
328 ignore_mouse_mode_toggle = false;
329 current_stepping_trackview = 0;
331 entered_regionview = 0;
332 clear_entered_track = false;
333 _new_regionviews_show_envelope = false;
334 current_timestretch = 0;
339 location_marker_color = color_map[cLocationMarker];
340 location_range_color = color_map[cLocationRange];
341 location_cd_marker_color = color_map[cLocationCDMarker];
342 location_loop_color = color_map[cLocationLoop];
343 location_punch_color = color_map[cLocationPunch];
345 range_marker_drag_rect = 0;
346 marker_drag_line = 0;
348 mouse_mode = MouseZoom; /* force change in next call */
349 set_mouse_mode (MouseObject, true);
351 frames_per_unit = 2048; /* too early to use set_frames_per_unit */
352 zoom_focus = ZoomFocusLeft;
353 zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
355 initialize_rulers ();
356 initialize_canvas ();
358 track_canvas_scroller.add (track_canvas);
359 track_canvas_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
360 track_canvas_scroller.set_name ("TrackCanvasScroller");
362 track_canvas_scroller.get_vadjustment()->signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling));
363 track_canvas_scroller.get_vadjustment()->set_step_increment (10.0);
365 track_canvas_scroller.get_hadjustment()->set_lower (0.0);
366 track_canvas_scroller.get_hadjustment()->set_upper (1200.0);
367 track_canvas_scroller.get_hadjustment()->set_step_increment (20.0);
368 track_canvas_scroller.get_hadjustment()->signal_value_changed().connect (mem_fun(*this, &Editor::canvas_horizontally_scrolled));
370 edit_vscrollbar.set_adjustment(*track_canvas_scroller.get_vadjustment());
371 edit_hscrollbar.set_adjustment(*track_canvas_scroller.get_hadjustment());
373 edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_press));
374 edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscroll_slider_button_release));
375 edit_hscrollbar.size_allocate.connect (mem_fun(*this, &Editor::hscroll_slider_allocate));
377 time_canvas_scroller.add (time_canvas);
378 time_canvas_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
379 time_canvas_scroller.set_hadjustment (*track_canvas_scroller.get_hadjustment());
380 time_canvas_scroller.set_name ("TimeCanvasScroller");
382 edit_controls_vbox.set_spacing (track_spacing);
383 edit_controls_hbox.pack_start (edit_controls_vbox, true, true);
384 edit_controls_scroller.add (edit_controls_hbox);
385 edit_controls_scroller.set_name ("EditControlsBase");
386 edit_controls_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
388 Viewport* viewport = static_cast<Viewport*> (edit_controls_scroller.get_child());
390 viewport->set_shadow_type (Gtk::SHADOW_NONE);
391 viewport->set_name ("EditControlsBase");
392 viewport->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
393 viewport->signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
398 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
401 edit_cursor_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_cursor_clock_changed));
403 time_canvas_vbox.pack_start (*minsec_ruler, false, false);
404 time_canvas_vbox.pack_start (*smpte_ruler, false, false);
405 time_canvas_vbox.pack_start (*frames_ruler, false, false);
406 time_canvas_vbox.pack_start (*bbt_ruler, false, false);
407 time_canvas_vbox.pack_start (time_canvas_scroller, true, true);
408 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars));
410 bbt_label.set_name ("EditorTimeButton");
411 bbt_label.set_size_request (-1, (int)timebar_height);
412 bbt_label.set_alignment (1.0, 0.5);
413 bbt_label.set_padding (5,0);
414 minsec_label.set_name ("EditorTimeButton");
415 minsec_label.set_size_request (-1, (int)timebar_height);
416 minsec_label.set_alignment (1.0, 0.5);
417 minsec_label.set_padding (5,0);
418 smpte_label.set_name ("EditorTimeButton");
419 smpte_label.set_size_request (-1, (int)timebar_height);
420 smpte_label.set_alignment (1.0, 0.5);
421 smpte_label.set_padding (5,0);
422 frame_label.set_name ("EditorTimeButton");
423 frame_label.set_size_request (-1, (int)timebar_height);
424 frame_label.set_alignment (1.0, 0.5);
425 frame_label.set_padding (5,0);
426 tempo_label.set_name ("EditorTimeButton");
427 tempo_label.set_size_request (-1, (int)timebar_height);
428 tempo_label.set_alignment (1.0, 0.5);
429 tempo_label.set_padding (5,0);
430 meter_label.set_name ("EditorTimeButton");
431 meter_label.set_size_request (-1, (int)timebar_height);
432 meter_label.set_alignment (1.0, 0.5);
433 meter_label.set_padding (5,0);
434 mark_label.set_name ("EditorTimeButton");
435 mark_label.set_size_request (-1, (int)timebar_height);
436 mark_label.set_alignment (1.0, 0.5);
437 mark_label.set_padding (5,0);
438 range_mark_label.set_name ("EditorTimeButton");
439 range_mark_label.set_size_request (-1, (int)timebar_height);
440 range_mark_label.set_alignment (1.0, 0.5);
441 range_mark_label.set_padding (5,0);
442 transport_mark_label.set_name ("EditorTimeButton");
443 transport_mark_label.set_size_request (-1, (int)timebar_height);
444 transport_mark_label.set_alignment (1.0, 0.5);
445 transport_mark_label.set_padding (5,0);
447 time_button_vbox.pack_start (minsec_label, false, false);
448 time_button_vbox.pack_start (smpte_label, false, false);
449 time_button_vbox.pack_start (frame_label, false, false);
450 time_button_vbox.pack_start (bbt_label, false, false);
451 time_button_vbox.pack_start (meter_label, false, false);
452 time_button_vbox.pack_start (tempo_label, false, false);
453 time_button_vbox.pack_start (mark_label, false, false);
455 time_button_event_box.add (time_button_vbox);
457 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
458 time_button_event_box.set_name ("TimebarLabelBase");
459 time_button_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
461 /* these enable us to have a dedicated window (for cursor setting, etc.)
462 for the canvas areas.
465 track_canvas_event_box.add (track_canvas_scroller);
467 time_canvas_event_box.add (time_canvas_vbox);
468 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
471 edit_packer.set_col_spacings (0);
472 edit_packer.set_row_spacings (0);
473 edit_packer.set_homogeneous (false);
474 edit_packer.set_name ("EditorWindow");
476 // edit_packer.attach (edit_hscroll_left_arrow_event, 0, 1, 0, 1, Gtk::FILL, 0, 0, 0);
477 // edit_packer.attach (edit_hscroll_slider, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, 0, 0, 0);
478 // edit_packer.attach (edit_hscroll_right_arrow_event, 2, 3, 0, 1, Gtk::FILL, 0, 0, 0);
479 edit_packer.attach (edit_hscrollbar, 1, 2, 0, 1, FILL|EXPAND, FILL, 0, 0);
481 edit_packer.attach (time_button_event_box, 0, 1, 1, 2, FILL, FILL, 0, 0);
482 edit_packer.attach (time_canvas_event_box, 1, 2, 1, 2, FILL|EXPAND, FILL, 0, 0);
484 edit_packer.attach (edit_controls_scroller, 0, 1, 2, 3, FILL, FILL|EXPAND, 0, 0);
485 edit_packer.attach (track_canvas_event_box, 1, 2, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
486 edit_packer.attach (edit_vscrollbar, 2, 3, 2, 3, FILL, FILL|EXPAND, 0, 0);
488 edit_frame.set_name ("BaseFrame");
489 edit_frame.set_shadow_type (SHADOW_IN);
490 edit_frame.add (edit_packer);
492 zoom_in_button.set_name ("EditorTimeButton");
493 zoom_out_button.set_name ("EditorTimeButton");
494 ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in"));
495 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out"));
497 // zoom_onetoone_button.set_name ("EditorTimeButton");
498 zoom_out_full_button.set_name ("EditorTimeButton");
499 // ARDOUR_UI::instance()->tooltips().set_tip (zoom_onetoone_button, _("Zoom in 1:1"));
500 ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session"));
502 zoom_in_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(zoom_in_button_xpm)))));
503 zoom_out_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(zoom_out_button_xpm)))));
504 zoom_out_full_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(zoom_out_full_button_xpm)))));
505 // zoom_onetoone_button.add (*(manage (new Gtk::Image (zoom_onetoone_button_xpm))));
508 zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false));
509 zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true));
510 zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session));
511 // zoom_onetoone_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom), 1.0));
513 zoom_indicator_box.pack_start (zoom_out_button, false, false);
514 zoom_indicator_box.pack_start (zoom_in_button, false, false);
515 zoom_indicator_box.pack_start (zoom_range_clock, false, false);
516 // zoom_indicator_box.pack_start (zoom_onetoone_button, false, false);
517 zoom_indicator_box.pack_start (zoom_out_full_button, false, false);
519 zoom_indicator_label.set_text (_("Zoom Span"));
520 zoom_indicator_label.set_name ("ToolBarLabel");
523 zoom_indicator_vbox.set_spacing (3);
524 zoom_indicator_vbox.set_border_width (3);
525 zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false);
526 zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false);
529 bottom_hbox.set_border_width (3);
530 bottom_hbox.set_spacing (3);
532 route_display_model = ListStore::create(route_display_columns);
533 route_list.set_model (route_display_model);
534 route_list.append_column (_("Tracks"), route_display_columns.text);
535 route_list.set_name ("TrackListDisplay");
536 route_list.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
537 route_list.set_reorderable (true);
539 route_list.set_size_request (75,-1);
540 route_list.set_headers_visible (true);
541 route_list.set_headers_clickable (true);
543 route_display_model->set_sort_func (0, mem_fun (*this, &Editor::route_list_compare_func));
545 //route_list.set_shadow_type (Gtk::SHADOW_IN);
547 route_list_scroller.add (route_list);
548 route_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
550 route_list.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::route_display_selection_changed));
551 route_display_model->signal_rows_reordered().connect (mem_fun (*this, &Editor::queue_route_list_reordered));
552 route_list.signal_button_press_event().connect (mem_fun(*this, &Editor::route_list_column_click));
554 edit_group_list_button_label.set_text (_("Edit Groups"));
555 edit_group_list_button_label.set_name ("EditGroupTitleButton");
556 edit_group_list_button.add (edit_group_list_button_label);
557 edit_group_list_button.set_name ("EditGroupTitleButton");
559 group_model = ListStore::create(group_columns);
560 edit_group_list.set_model (group_model);
561 edit_group_list.append_column (_("active"), group_columns.is_active);
562 edit_group_list.append_column (_("groupname"), group_columns.text);
563 edit_group_list.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
564 edit_group_list.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
566 /* use checkbox for the active column */
568 CellRendererToggle *active_cell = dynamic_cast<CellRendererToggle*>(edit_group_list.get_column_cell_renderer (0));
569 active_cell->property_activatable() = true;
570 active_cell->property_radio() = false;
572 edit_group_list.set_name ("MixerGroupList");
573 //edit_group_list.set_shadow_type (Gtk::SHADOW_IN);
574 route_list.set_headers_visible (false);
575 edit_group_list.set_reorderable (false);
576 edit_group_list.set_size_request (75, -1);
577 edit_group_list.columns_autosize ();
578 edit_group_list.get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
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.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::edit_group_selection_changed));
587 TreeModel::Row row = *(group_model->append());
588 row[group_columns.is_active] = false;
589 row[group_columns.text] = (_("-all-"));
590 edit_group_list.get_selection()->select (row);
591 /* GTK2FIX is set_data(0) setting the is_active to false here?
592 list<string> stupid_list;
594 stupid_list.push_back ("*");
595 stupid_list.push_back (_("-all-"));
597 edit_group_list.rows().push_back (stupid_list);
598 edit_group_list.rows().back().set_data (0);
599 edit_group_list.rows().back().select();
602 edit_group_vbox.pack_start (edit_group_list_button, false, false);
603 edit_group_vbox.pack_start (edit_group_list_scroller, true, true);
605 route_list_frame.set_name ("BaseFrame");
606 route_list_frame.set_shadow_type (Gtk::SHADOW_IN);
607 route_list_frame.add (route_list_scroller);
609 edit_group_list_frame.set_name ("BaseFrame");
610 edit_group_list_frame.set_shadow_type (Gtk::SHADOW_IN);
611 edit_group_list_frame.add (edit_group_vbox);
613 route_group_vpane.add1 (route_list_frame);
614 route_group_vpane.add2 (edit_group_list_frame);
616 list_vpacker.pack_start (route_group_vpane, true, true);
618 region_list_model = TreeStore::create (region_list_columns);
619 region_list_sort_model = TreeModelSort::create (region_list_model);
620 region_list_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
622 region_list_display.set_model (region_list_sort_model);
623 region_list_display.append_column (_("Regions"), region_list_columns.name);
624 region_list_display.set_reorderable (true);
625 region_list_display.set_size_request (100, -1);
626 region_list_display.set_data ("editor", this);
627 region_list_display.set_flags (Gtk::CAN_FOCUS);
628 region_list_display.set_name ("RegionListDisplay");
630 region_list_scroller.add (region_list_display);
631 region_list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
633 region_list_display.drag_dest_set (GTK_DEST_DEFAULT_ALL,
634 target_table, n_targets - 1,
635 GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
636 region_list_display.drag_data_received.connect (mem_fun(*this, &Editor::region_list_display_drag_data_received));
638 region_list_display.signal_key_press_event().connect (mem_fun(*this, &Editor::region_list_display_key_press));
639 region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
640 region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press));
641 region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
642 region_list_display.signal_motion_notify_event().connect (mem_fun(*this, &Editor::region_list_display_motion));
643 region_list_display.signal_enter_notify_event().connect (mem_fun(*this, &Editor::region_list_display_enter_notify));
644 region_list_display.signal_leave_notify_event().connect (mem_fun(*this, &Editor::region_list_display_leave_notify));
645 region_list_display.select_row.connect (mem_fun(*this, &Editor::region_list_display_selected));
646 region_list_display.unselect_row.connect (mem_fun(*this, &Editor::region_list_display_unselected));
647 region_list_display.click_column.connect (mem_fun(*this, &Editor::region_list_column_click));
649 named_selection_scroller.add (named_selection_display);
650 named_selection_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
652 named_selection_model = TreeStore::create (named_selection_columns);
653 named_selection_display.set_model (named_selection_model);
654 named_selection_display.set_name ("RegionListDisplay");
655 named_selection_display.set_size_request (100, -1);
656 named_selection_display.set_headers_visible (true);
657 named_selection_display.set_headers_clickable (true);
658 named_selection_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
659 named_selection_display.signal_button_press_event().connect (mem_fun(*this, &Editor::named_selection_display_button_press));
660 named_selection_display.get_selection()->signal_changed().connect (mem_fun (*this, &Editor::named_selection_display_selection_changed));
662 region_selection_vpane.pack1 (region_list_scroller, true, true);
663 region_selection_vpane.pack2 (named_selection_scroller, true, true);
665 canvas_region_list_pane.pack1 (edit_frame, true, true);
666 canvas_region_list_pane.pack2 (region_selection_vpane, true, true);
668 track_list_canvas_pane.signal_size_allocate().connect_after (bind (mem_fun(*this, &Editor::pane_allocation_handler),
669 static_cast<Gtk::Paned*> (&track_list_canvas_pane)));
670 canvas_region_list_pane.signal_size_allocate().connect_after (bind (mem_fun(*this, &Editor::pane_allocation_handler),
671 static_cast<Gtk::Paned*> (&canvas_region_list_pane)));
672 route_group_vpane.signal_size_allocate().connect_after (bind (mem_fun(*this, &Editor::pane_allocation_handler),
673 static_cast<Gtk::Paned*> (&route_group_vpane)));
674 region_selection_vpane.signal_size_allocate().connect_after (bind (mem_fun(*this, &Editor::pane_allocation_handler),
675 static_cast<Gtk::Paned*> (®ion_selection_vpane)));
677 track_list_canvas_pane.pack1 (list_vpacker, true, true);
678 track_list_canvas_pane.pack2 (canvas_region_list_pane, true, true);
680 /* provide special pane-handle event handling for easy "hide" action */
682 /* 0: collapse to show left/upper child
683 1: collapse to show right/lower child
686 route_group_vpane.set_data ("collapse-direction", (gpointer) 0);
687 region_selection_vpane.set_data ("collapse-direction", (gpointer) 0);
688 canvas_region_list_pane.set_data ("collapse-direction", (gpointer) 0);
689 track_list_canvas_pane.set_data ("collapse-direction", (gpointer) 1);
691 route_group_vpane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (&route_group_vpane)));
692 region_selection_vpane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (®ion_selection_vpane)));
693 canvas_region_list_pane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (&canvas_region_list_pane)));
694 track_list_canvas_pane.signal_button_release_event().connect (bind (sigc::ptr_fun (pane_handler), static_cast<Paned*> (&track_list_canvas_pane)));
696 top_hbox.pack_start (toolbar_frame, true, true);
698 HBox *hbox = manage (new HBox);
699 hbox->pack_start (track_list_canvas_pane, true, true);
701 global_vpacker.pack_start (top_hbox, false, false);
702 global_vpacker.pack_start (*hbox, true, true);
704 global_hpacker.pack_start (global_vpacker, true, true);
706 set_name ("EditorWindow");
708 vpacker.pack_end (global_hpacker, true, true);
710 _playlist_selector = new PlaylistSelector();
711 _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
713 AudioRegionView::AudioRegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_audio_regionview));
717 nudge_forward_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(right_arrow_xpm)))));
718 nudge_backward_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(left_arrow_xpm)))));
720 ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards"));
721 ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards"));
723 nudge_forward_button.set_name ("TransportButton");
724 nudge_backward_button.set_name ("TransportButton");
726 fade_context_menu.set_name ("ArdourContextMenu");
728 install_keybindings ();
730 set_title (_("ardour: editor"));
731 set_wmclass (_("ardour_editor"), "Ardour");
734 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
736 configure_event.connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
737 signal_delete_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
745 /* <CMT Additions> */
746 if(image_socket_listener)
748 if(image_socket_listener->is_connected())
750 image_socket_listener->close_connection() ;
753 delete image_socket_listener ;
754 image_socket_listener = 0 ;
756 /* </CMT Additions> */
760 Editor::add_toplevel_controls (Container& cont)
762 vpacker.pack_start (cont, false, false);
767 Editor::catch_vanishing_audio_regionview (AudioRegionView *rv)
769 /* note: the selection will take care of the vanishing
770 audioregionview by itself.
773 if (clicked_regionview == rv) {
774 clicked_regionview = 0;
777 if (entered_regionview == rv) {
778 set_entered_regionview (0);
783 Editor::set_entered_regionview (AudioRegionView* rv)
785 if (rv == entered_regionview) {
789 if (entered_regionview) {
790 entered_regionview->exited ();
793 if ((entered_regionview = rv) != 0) {
794 entered_regionview->entered ();
799 Editor::set_entered_track (TimeAxisView* tav)
802 entered_track->exited ();
805 if ((entered_track = tav) != 0) {
806 entered_track->entered ();
811 Editor::left_track_canvas (GdkEventCrossing *ev)
813 set_entered_track (0);
814 set_entered_regionview (0);
820 Editor::initialize_canvas ()
822 gnome_canvas_init ();
824 /* adjust sensitivity for "picking" items */
826 // GNOME_CANVAS(track_canvas)->close_enough = 2;
828 track_canvas.signal_event().connect (slot (*this, &Editor::track_canvas_event));
829 track_canvas.set_name ("EditorMainCanvas");
830 track_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
831 track_canvas.signal_event().connect (slot (*this, &Editor::track_canvas_event));
832 track_canvas.signal_leave_notify_event().connect (mem_fun(*this, &Editor::left_track_canvas));
834 /* set up drag-n-drop */
836 track_canvas.drag_dest_set (GTK_DEST_DEFAULT_ALL,
837 target_table, n_targets - 1,
838 GdkDragAction (Gdk::ACTION_COPY|Gdk::ACTION_MOVE));
839 track_canvas.drag_data_received.connect (mem_fun(*this, &Editor::track_canvas_drag_data_received));
841 /* stuff for the verbose canvas cursor */
843 Pango::FontDescription font = get_font_for_style (N_("VerboseCanvasCursor"));
845 verbose_canvas_cursor = new Canvas::Text (track_canvas.root());
846 verbose_canvas_cursor->property_font_descr() << font;
847 verbose_canvas_cursor->property_anchor() << GTK_ANCHOR_NW;
848 verbose_canvas_cursor->property_fill_color_rgba() << color_map[cVerboseCanvasCursor];
850 verbose_cursor_visible = false;
852 /* a group to hold time (measure) lines */
854 time_line_group = new Canvas::Group (track_canvas.root(), 0.0, 0.0);
855 cursor_group = new Canvas::Group (track_canvas.root(), 0.0, 0.0);
857 time_canvas.set_name ("EditorTimeCanvas");
858 time_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK);
860 meter_group = new Canvas::Group (time_canvas.root(), 0.0, 0.0);
861 tempo_group = new Canvas::Group (time_canvas.root(), 0.0, 0.0);
862 marker_group = new Canvas::Group (time_canvas.root(), 0.0, timebar_height * 2.0);
863 range_marker_group = new Canvas::Group (time_canvas.root(), 0.0, timebar_height * 3.0);
864 transport_marker_group = new Canvas::Group (time_canvas.root(), 0.0, timebar_height * 4.0);
866 tempo_bar = Canvas::SimpleRect (*tempo_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
867 tempo_bar->property_fill_color_rgba() << color_map[cTempoBar];
868 tempo_bar->property_outline_pixels() << 0;
870 meter_bar = Canvas::SimpleRect (*meter_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
871 meter_bar->property_fill_color_rgba() << color_map[cMeterBar];
872 meter_bar->property_outline_pixels() << 0;
874 marker_bar = Canvas::SimpleRect (*marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
875 marker_bar->property_fill_color_rgba() << color_map[cMarkerBar];
876 marker_bar->property_outline_pixels() << 0;
878 range_marker_bar = Canvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
879 range_marker_bar->property_fill_color_rgba() << color_map[cRangeMarkerBar];
880 range_marker_bar->property_outline_pixels() << 0;
882 transport_marker_bar = Canvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
883 transport_marker_bar->property_fill_color_rgba() << color_map[cTransportMarkerBar];
884 transport_marker_bar->property_outline_pixels() << 0;
886 range_bar_drag_rect = Canvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height).gobj();
887 range_bar_drag_rect->property_fill_color_rgba() << color_map[cRangeBarDragRectFill];
888 range_bar_drag_rect->property_outline_color_rgba() << color_map[cRangeBarDragRect];
889 range_bar_drag_rect->property_outline_pixels() << 0;
890 range_bar_drag_rect->hide ();
892 transport_bar_drag_rect = Canvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height);
893 transport_bar_drag_rect ->property_fill_color_rgba() << color_map[cTransportBarDragRectFill];
894 transport_bar_drag_rect->property_outline_color_rgba() << color_map[cTransportBarDragRect];
895 transport_bar_drag_rect->property_outline_pixels() << 0;
896 transport_bar_drag_rect->hide ();
898 marker_drag_line_points = new Canvas::Points (2);
899 marker_drag_line_points[0]->set_x (0.0);
900 marker_drag_line_points[0]->set_y (0.0);
901 marker_drag_line_points[1]->set_x (0.0);
902 marker_drag_line_points[1]->set_y (0.0);
904 marker_drag_line = Canvas::Line (track_canvas.root());
905 marker_drag_line->property_width_pixels() << 1;
906 marker_drag_line->property_fill_color_rgba() << color_map[cMarkerDragLine];
907 marker_drag_line->property_points() << marker_drag_line_points;
908 marker_drag_line->hide();
910 range_marker_drag_rect = new Canvas::SimpleRect (track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
911 range_marker_drag_rect->property_fill_color_rgba() << color_map[cRangeDragRectFill];
912 range_marker_drag_rect->property_outline_color_rgba() << color_map[cRangeDragRect];
913 range_marker_drag_rect->hide ();
915 transport_loop_range_rect = new Canvas::Simplerect (group.root(), 0.0, 0.0, 0.0, 0.0);
916 transport_loop_range_rect->property_fill_color_rgba() << color_map[cTransportLoopRectFill];
917 transport_loop_range_rect->property_outline_color_rgba() << color_map[cTransportLoopRect];
918 transport_loop_range_rect->property_outline_pixels() << 1;
919 transport_loop_range_rect->hide();
921 transport_punch_range_rect = new Canvas::Simplerect (group.root(), 0.0, 0.0, 0.0, 0.0);
922 transport_punch_range_rect->property_fill_color_rgba() << color_map[cTransportPunchRectFill];
923 transport_punch_range_rect->property_outline_color_rgba() << color_map[cTransportPunchRect];
924 transport_punch_range_rect->property_outline_pixels() << 0;
925 transport_punch_range_rect->hide();
927 transport_loop_range_rect->lower_to_bottom (); // loop on the bottom
929 transport_punchin_line = new Canvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, 0.0);
930 transport_punchin_line->property_outline_color_rgba() << color_map[cPunchInLine];
931 transport_punchin_line->property_outline_pixels() << 1;
932 transport_punchin_line->hide ();
934 transport_punchout_line = new Canvas::Simplerect (group.root(), 0.0, 0.0, 0.0, 0.0);
935 transport_punchout_line->property_outline_color_rgba() << color_map[cPunchOutLine];
936 transport_punchout_line->property_outline_pixels() << 1;
937 transport_punchout_line->hide();
939 // used to show zoom mode active zooming
940 zoom_rect = new Canvas::Simplerect (track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
941 zoom_rect->property_fill_color_rgba() << color_map[cZoomRectFill];
942 zoom_rect->property_outline_color_rgba() << color_map[cZoomRect];
943 zoom_rect->property_outline_pixels() << 1;
946 zoom_rect.signal_event().connect (slot (*this, &PublicEditor::canvas_zoom_rect_event));
948 // used as rubberband rect
949 rubberband_rect = new Canvas::Simplerect (track_canvas.root(), 0.0, 0.0, 0.0, 0.0);
950 rubberband_rect->property_outline_color_rgba() << color_map[cRubberBandRect];
951 rubberband_rect->property_fill_color_rgba() << (guint32) color_map[cRubberBandRectFill];
952 rubberband_rect->property_outline_pixels() << 1;
953 rubberband_rect->hide();
955 tempo_bar.signal_event().connect (slot (*this, &PublicEditor::canvas_tempo_bar_event));
956 meter_bar.signal_event().connect (slot (*this, &PublicEditor::canvas_meter_bar_event));
957 marker_bar.signal_event().connect (slot (*this, &PublicEditor::canvas_marker_bar_event));
958 range_marker_bar.signal_event().connect (slot (*this, &PublicEditor::canvas_range_marker_bar_event));
959 transport_marker_bar.signal_event().connect (slot (*this, &PublicEditor::canvas_transport_marker_bar_event));
961 /* separator lines */
963 tempo_line_points = new Canvas::Points (2);
964 tempo_line_points[0]->set_x (0.0);
965 tempo_line_points[0]->set_y (timebar_height);
966 tempo_line_points[1]->set_x (max_canvas_coordinate);
967 tempo_line_points[1]->set_y (timebar_height);
969 tempo_line = Canvas::Line (*tempo_group, *tempo_line_points);
970 tempo_line->property_width_pixels() << 0;
971 tempo_line->property_fill_color() << "black";
973 meter_line_points = new Canvas::Points (2);
974 meter_line_points[0]->set_x (0);
975 meter_line_points[0]->set_y (timebar_height);
976 meter_line_points[1]->set_x (max_canvas_coordinate);
977 meter_line_points[1]->set_y (timebar_height);
979 meter_line = Canvas::Line (*meter_group, *meter_line_points);
980 meter_line->property_width_pixels() << 0;
981 meter_line->property_fill_color() << "black";
983 marker_line_points = Canvas::Points (2);
984 marker_line_points[0]->set_x (0);
985 marker_line_points[0]->set_y (timebar_height);
986 marker_line_points[1]->set_x (max_canvas_coordinate);
987 marker_line_points[1]->set_y (timebar_height);
989 marker_line = new Canvas::Line (*marker_group, *marker_line_points);
990 marker_line->property_width_pixels() << 0;
991 marker_line->property_fill_color() << "black";
993 range_marker_line = new Canvas::Line (*range_marker_group, marker_line_points);
994 range_marker_line->property_width_pixels() << 0;
995 range_marker_line->property_fill_color() << "black";
997 transport_marker_line = new Canvas::Line (*transport_marker_group, marker_line_points);
998 transport_marker_line->property_width_pixels() << 0;
999 transport_marker_line->property_fill_color() << "black";
1001 ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_loop_range_view), false));
1002 ZoomChanged.connect (bind (mem_fun(*this, &Editor::update_punch_range_view), false));
1004 double time_height = timebar_height * 5;
1005 double time_width = FLT_MAX/frames_per_unit;
1006 gnome_canvas_set_scroll_region (GNOME_CANVAS(time_canvas), 0.0, 0.0, time_width, time_height);
1008 edit_cursor = new Cursor (*this, "blue", (GtkSignalFunc) _canvas_edit_cursor_event);
1009 playhead_cursor = new Cursor (*this, "red", (GtkSignalFunc) _canvas_playhead_cursor_event);
1011 track_canvas.size_allocate.connect (mem_fun(*this, &Editor::track_canvas_allocate));
1015 Editor::show_window ()
1019 /* now reset all audio_time_axis heights, because widgets might need
1025 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1026 tv = (static_cast<TimeAxisView*>(*i));
1027 tv->reset_height ();
1032 Editor::tie_vertical_scrolling ()
1034 edit_controls_scroller.get_vadjustment()->set_value (track_canvas_scroller.get_vadjustment()->get_value());
1036 float y1 = track_canvas_scroller.get_vadjustment()->get_value();
1037 playhead_cursor->set_y_axis(y1);
1038 edit_cursor->set_y_axis(y1);
1042 Editor::set_frames_per_unit (double fpu)
1044 jack_nframes_t frames;
1046 if (fpu == frames_per_unit) {
1054 // convert fpu to frame count
1056 frames = (jack_nframes_t) (fpu * canvas_width);
1058 /* don't allow zooms that fit more than the maximum number
1059 of frames into an 800 pixel wide space.
1062 if (max_frames / fpu < 800.0) {
1066 frames_per_unit = fpu;
1068 if (frames != zoom_range_clock.current_duration()) {
1069 zoom_range_clock.set (frames);
1072 /* only update these if we not about to call reposition_x_origin,
1073 which will do the same updates.
1077 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1080 if (!no_zoom_repos_update) {
1081 track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
1082 update_hscroller ();
1083 update_fixed_rulers ();
1084 tempo_map_changed (Change (0));
1087 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
1088 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1089 (*i)->reshow_selection (selection->time);
1093 ZoomChanged (); /* EMIT_SIGNAL */
1095 if (edit_cursor) edit_cursor->set_position (edit_cursor->current_frame);
1096 if (playhead_cursor) playhead_cursor->set_position (playhead_cursor->current_frame);
1103 Editor::instant_save ()
1105 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
1110 session->add_instant_xml(get_state(), session->path());
1112 Config->add_instant_xml(get_state(), Config->get_user_ardour_path());
1117 Editor::reposition_x_origin (jack_nframes_t frame)
1119 if (frame != leftmost_frame) {
1120 leftmost_frame = frame;
1121 double pixel = frame_to_pixel (frame);
1122 if (pixel >= track_canvas_scroller.get_hadjustment()->get_upper()) {
1123 track_canvas_scroller.get_hadjustment()->set_upper (frame_to_pixel (frame + (current_page_frames())));
1125 track_canvas_scroller.get_hadjustment()->set_value (frame/frames_per_unit);
1126 XOriginChanged (); /* EMIT_SIGNAL */
1131 Editor::edit_cursor_clock_changed()
1133 if (edit_cursor->current_frame != edit_cursor_clock.current_time()) {
1134 edit_cursor->set_position (edit_cursor_clock.current_time());
1140 Editor::zoom_adjustment_changed ()
1142 if (session == 0 || no_zoom_repos_update) {
1146 double fpu = (double) zoom_range_clock.current_duration() / (double) canvas_width;
1150 zoom_range_clock.set ((jack_nframes_t) (fpu * canvas_width));
1152 else if (fpu > session->current_end_frame() / (double) canvas_width) {
1153 fpu = session->current_end_frame() / (double) canvas_width;
1154 zoom_range_clock.set ((jack_nframes_t) (fpu * canvas_width));
1157 temporal_zoom (fpu);
1161 Editor::canvas_horizontally_scrolled ()
1163 /* XXX note the potential loss of accuracy here caused by
1164 adjustments being 32bit floats with only a 24 bit mantissa,
1165 whereas jack_nframes_t is at least a 32 bit uint32_teger.
1168 leftmost_frame = (jack_nframes_t) floor (track_canvas_scroller.get_hadjustment()->get_value() * frames_per_unit);
1170 update_hscroller ();
1171 update_fixed_rulers ();
1173 if (!edit_hscroll_dragging) {
1174 tempo_map_changed (Change (0));
1176 update_tempo_based_rulers();
1181 Editor::reposition_and_zoom (jack_nframes_t frame, double nfpu)
1183 if (!repos_zoom_queued) {
1184 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::deferred_reposition_and_zoom), frame, nfpu));
1185 repos_zoom_queued = true;
1190 Editor::deferred_reposition_and_zoom (jack_nframes_t frame, double nfpu)
1192 /* if we need to force an update to the hscroller stuff,
1193 don't set no_zoom_repos_update.
1196 no_zoom_repos_update = (frame != leftmost_frame);
1198 set_frames_per_unit (nfpu);
1199 if (no_zoom_repos_update) {
1200 reposition_x_origin (frame);
1202 no_zoom_repos_update = false;
1203 repos_zoom_queued = false;
1209 Editor::on_realize ()
1211 /* Even though we're not using acceleration, we want the
1215 track_context_menu.accelerate (*this->get_toplevel());
1216 track_region_context_menu.accelerate (*this->get_toplevel());
1218 Window::on_realize ();
1220 GdkPixmap* empty_pixmap = gdk_pixmap_new (get_window()->gobj(), 1, 1, 1);
1221 GdkPixmap* empty_bitmap = gdk_pixmap_new (get_window()->gobj(), 1, 1, 1);
1222 GdkColor white = { 0, 0, 0 };
1224 null_cursor = gdk_cursor_new_from_pixmap (empty_pixmap, empty_bitmap, &white, &white, 0, 0);
1232 track_canvas_scroller.get_window()->set_cursor (current_canvas_cursor);
1233 time_canvas_scroller.get_window()->set_cursor (timebar_cursor);
1237 Editor::track_canvas_allocate (GtkAllocation *alloc)
1239 canvas_width = alloc->width;
1240 canvas_height = alloc->height;
1242 if (session == 0 && !ARDOUR_UI::instance()->will_create_new_session_automatically()) {
1244 Pango::FontDescription font = get_font_for_style (N_("FirstActionMessage"));
1246 const char *txt1 = _("Start a new session\n");
1247 const char *txt2 = _("via Session menu");
1249 /* this mess of code is here to find out how wide this text is and
1250 position the message in the center of the editor window. there
1251 are two lines, so we use the longer of the the lines to
1252 compute width, and multiply the height by 2.
1258 /* this is a dummy widget that exists so that we can get the
1259 style from the RC file.
1262 Label foo (_(txt2));
1263 Glib::RefPtr<Pango::Layout> layout;
1264 foo.set_name ("NoSessionMessage");
1265 foo.ensure_style ();
1267 layout = foo.create_pango_layout (_(txt2));
1268 layout->set_font_description (font);
1269 layout->get_pixel_size (pixel_width, pixel_height);
1271 if (first_action_message == 0) {
1273 char txt[strlen(txt1)+strlen(txt2)+1];
1275 /* merge both lines */
1277 strcpy (txt, _(txt1));
1278 strcat (txt, _(txt2));
1280 first_action_message = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(track_canvas)),
1281 gnome_canvas_text_get_type(),
1283 "fill_color_rgba", color_map[cFirstActionMessage],
1284 "x", (gdouble) (canvas_width - pixel_width) / 2.0,
1285 "y", (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height)),
1286 "anchor", GTK_ANCHOR_NORTH_WEST,
1294 gnome_canvas_item_set (first_action_message,
1295 "x", (gdouble) (canvas_width - pixel_width) / 2.0,
1296 "y", (gdouble) (canvas_height/2.0) - (2.0 * (pixel_height)),
1301 zoom_range_clock.set ((jack_nframes_t) (canvas_width * frames_per_unit));
1302 edit_cursor->set_position (edit_cursor->current_frame);
1303 playhead_cursor->set_position (playhead_cursor->current_frame);
1304 reset_scrolling_region (alloc);
1306 Resized (); /* EMIT_SIGNAL */
1310 Editor::reset_scrolling_region (GtkAllocation *alloc)
1312 guint32 last_canvas_unit;
1314 guint32 canvas_alloc_height, canvas_alloc_width;
1315 TrackViewList::iterator i;
1316 static bool first_time = true;
1318 /* We need to make sure that the canvas always has its
1319 scrolling region set to larger of:
1321 - the size allocated for it (within the container its packed in)
1322 - the size required to see the entire session
1324 If we don't ensure at least the first of these, the canvas
1325 does some wierd and in my view unnecessary stuff to center
1326 itself within the allocated area, which causes bad, bad
1329 XXX GnomeCanvas has fixed this, and has an option to
1330 control the centering behaviour.
1333 last_canvas_unit = (guint32) ceil ((float) max_frames / frames_per_unit);
1338 for (i = track_views.begin(); i != track_views.end(); ++i) {
1339 if ((*i)->control_parent) {
1340 height += (*i)->effective_height;
1341 height += track_spacing;
1346 height -= track_spacing;
1350 canvas_height = (guint32) height;
1353 canvas_alloc_height = alloc->height;
1354 canvas_alloc_width = alloc->width;
1356 canvas_alloc_height = track_canvas->allocation.height;
1357 canvas_alloc_width = track_canvas->allocation.width;
1360 canvas_height = max (canvas_height, canvas_alloc_height);
1362 gnome_canvas_set_scroll_region (GNOME_CANVAS(track_canvas), 0.0, 0.0,
1363 max (last_canvas_unit, canvas_alloc_width),
1366 if (edit_cursor) edit_cursor->set_length (canvas_alloc_height);
1367 if (playhead_cursor) playhead_cursor->set_length (canvas_alloc_height);
1369 if (marker_drag_line) {
1370 marker_drag_line_points->coords[3] = canvas_height;
1371 // cerr << "set mlA points, nc = " << marker_drag_line_points->num_points << endl;
1372 gnome_canvas_item_set (marker_drag_line, "points", marker_drag_line_points, NULL);
1374 if (range_marker_drag_rect) {
1375 gnome_canvas_item_set (range_marker_drag_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1377 if (transport_loop_range_rect) {
1378 gnome_canvas_item_set (transport_loop_range_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1380 if (transport_punch_range_rect) {
1381 gnome_canvas_item_set (transport_punch_range_rect, "y1", 0.0, "y2", (double) canvas_height, NULL);
1383 if (transport_punchin_line) {
1384 gnome_canvas_item_set (transport_punchin_line, "y1", 0.0, "y2", (double) canvas_height, NULL);
1386 if (transport_punchout_line) {
1387 gnome_canvas_item_set (transport_punchout_line, "y1", 0.0, "y2", (double) canvas_height, NULL);
1391 update_fixed_rulers ();
1393 if (is_visible() && first_time) {
1394 tempo_map_changed (Change (0));
1402 Editor::queue_session_control_changed (Session::ControlType t)
1404 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::session_control_changed), t));
1408 Editor::session_control_changed (Session::ControlType t)
1410 // right now we're only tracking the loop and punch state
1413 case Session::AutoLoop:
1414 update_loop_range_view (true);
1416 case Session::PunchIn:
1417 case Session::PunchOut:
1418 update_punch_range_view (true);
1427 Editor::fake_add_edit_group (RouteGroup *group)
1429 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::add_edit_group), group));
1433 Editor::fake_handle_new_audio_region (AudioRegion *region)
1435 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_new_audio_region), region));
1439 Editor::fake_handle_audio_region_removed (AudioRegion *region)
1441 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &Editor::handle_audio_region_removed), region));
1445 Editor::fake_handle_new_duration ()
1447 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &Editor::handle_new_duration));
1451 Editor::start_scrolling ()
1453 scroll_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect
1454 (mem_fun(*this, &Editor::update_current_screen));
1456 slower_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
1457 (mem_fun(*this, &Editor::update_slower));
1461 Editor::stop_scrolling ()
1463 scroll_connection.disconnect ();
1464 slower_update_connection.disconnect ();
1468 Editor::map_position_change (jack_nframes_t frame)
1470 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::map_position_change), frame));
1472 if (session == 0 || !_follow_playhead) {
1476 center_screen (frame);
1477 playhead_cursor->set_position (frame);
1481 Editor::center_screen (jack_nframes_t frame)
1483 float page = canvas_width * frames_per_unit;
1485 /* if we're off the page, then scroll.
1488 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1489 center_screen_internal (frame,page);
1494 Editor::center_screen_internal (jack_nframes_t frame, float page)
1499 frame -= (jack_nframes_t) page;
1504 reposition_x_origin (frame);
1508 Editor::handle_new_duration ()
1510 reset_scrolling_region ();
1513 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1514 track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
1517 update_hscroller ();
1521 Editor::update_title_s (string snap_name)
1523 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::update_title_s), snap_name));
1529 Editor::update_title ()
1531 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::update_title));
1534 bool dirty = session->dirty();
1536 string wintitle = _("ardour: editor: ");
1542 wintitle += session->name();
1544 if (session->snap_name() != session->name()) {
1546 wintitle += session->snap_name();
1553 set_title (wintitle);
1558 Editor::connect_to_session (Session *t)
1562 if (first_action_message) {
1563 gnome_canvas_item_hide (first_action_message);
1566 flush_track_canvas();
1570 session->going_away.connect (mem_fun(*this, &Editor::session_going_away));
1572 /* These signals can all be emitted by a non-GUI thread. Therefore the
1573 handlers for them must not attempt to directly interact with the GUI,
1574 but use Gtkmm2ext::UI::instance()->call_slot();
1577 session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state)));
1578 session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change)));
1579 session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p)));
1580 session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::fake_handle_new_audio_region)));
1581 session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::fake_handle_audio_region_removed)));
1582 session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::fake_handle_new_duration)));
1583 session_connections.push_back (session->edit_group_added.connect (mem_fun(*this, &Editor::fake_add_edit_group)));
1584 session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1585 session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection)));
1586 session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title)));
1587 session_connections.push_back (session->StateSaved.connect (mem_fun(*this, &Editor::update_title_s)));
1588 session_connections.push_back (session->AskAboutPlaylistDeletion.connect (mem_fun(*this, &Editor::playlist_deletion_dialog)));
1589 session_connections.push_back (session->RegionHiddenChange.connect (mem_fun(*this, &Editor::region_hidden)));
1591 session_connections.push_back (session->SMPTEOffsetChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1592 session_connections.push_back (session->SMPTETypeChanged.connect (mem_fun(*this, &Editor::update_just_smpte)));
1594 session_connections.push_back (session->tempo_map().StateChanged.connect (mem_fun(*this, &Editor::tempo_map_changed)));
1596 session->foreach_edit_group(this, &Editor::add_edit_group);
1598 editor_mixer_button.signal_toggled().connect (mem_fun(*this, &Editor::editor_mixer_button_toggled));
1599 editor_mixer_button.set_name (X_("EditorMixerButton"));
1601 edit_cursor_clock.set_session (session);
1602 selection_start_clock.set_session (session);
1603 selection_end_clock.set_session (session);
1604 zoom_range_clock.set_session (session);
1605 _playlist_selector->set_session (session);
1606 nudge_clock.set_session (session);
1608 switch (session->get_edit_mode()) {
1610 edit_mode_selector.get_entry()->set_text (edit_mode_strings[splice_index]);
1614 edit_mode_selector.get_entry()->set_text (edit_mode_strings[slide_index]);
1618 Location* loc = session->locations()->auto_loop_location();
1620 loc = new Location (0, session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1621 if (loc->start() == loc->end()) {
1622 loc->set_end (loc->start() + 1);
1624 session->locations()->add (loc, false);
1625 session->set_auto_loop_location (loc);
1629 loc->set_name (_("Loop"));
1632 loc = session->locations()->auto_punch_location();
1634 loc = new Location (0, session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1635 if (loc->start() == loc->end()) {
1636 loc->set_end (loc->start() + 1);
1638 session->locations()->add (loc, false);
1639 session->set_auto_punch_location (loc);
1643 loc->set_name (_("Punch"));
1646 update_loop_range_view (true);
1647 update_punch_range_view (true);
1649 session->ControlChanged.connect (mem_fun(*this, &Editor::queue_session_control_changed));
1652 refresh_location_display ();
1653 session->locations()->added.connect (mem_fun(*this, &Editor::add_new_location));
1654 session->locations()->removed.connect (mem_fun(*this, &Editor::location_gone));
1655 session->locations()->changed.connect (mem_fun(*this, &Editor::refresh_location_display));
1656 session->locations()->StateChanged.connect (mem_fun(*this, &Editor::refresh_location_display_s));
1657 session->locations()->end_location()->changed.connect (mem_fun(*this, &Editor::end_location_changed));
1659 reset_scrolling_region ();
1661 redisplay_regions ();
1662 redisplay_named_selections ();
1664 route_list.freeze ();
1665 route_display_model.clear ();
1666 session->foreach_route (this, &Editor::handle_new_route);
1667 // route_list.select_all ();
1669 route_list_reordered ();
1672 if (embed_audio_item) {
1673 embed_audio_item->set_sensitive (true);
1675 if (import_audio_item) {
1676 import_audio_item->set_sensitive (true);
1679 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1680 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1683 /* ::reposition_x_origin() doesn't work right here, since the old
1684 position may be zero already, and it does nothing in such
1690 track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
1691 track_canvas_scroller.get_hadjustment()->set_value (0);
1693 update_hscroller ();
1694 restore_ruler_visibility ();
1695 tempo_map_changed (Change (0));
1697 edit_cursor->set_position (0);
1698 playhead_cursor->set_position (0);
1702 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1705 /* don't show master bus in a new session */
1707 if (ARDOUR_UI::instance()->session_is_new ()) {
1709 TreeModel::Children rows = route_display_model->children();
1710 TreeModel::Children::iterator i;
1712 //route_list.freeze ();
1714 for (i = rows.begin(); i != rows.end(); ++i) {
1715 TimeAxisView *tv = (*i)[route_display_columns.tv];
1716 AudioTimeAxisView *atv;
1718 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1719 if (atv->route().master()) {
1720 route_list.get_selection()->unselect (i);
1721 //(*i)->unselect ();
1726 //route_list.thaw ();
1731 Editor::build_cursors ()
1733 GdkPixmap *source, *mask;
1734 GdkColor fg = { 0, 65535, 0, 0 }; /* Red. */
1735 GdkColor bg = { 0, 0, 0, 65535 }; /* Blue. */
1737 source = gdk_bitmap_create_from_data (NULL, hand_bits,
1738 hand_width, hand_height);
1739 mask = gdk_bitmap_create_from_data (NULL, handmask_bits,
1740 handmask_width, handmask_height);
1741 grabber_cursor = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, hand_x_hot, hand_y_hot);
1742 gdk_pixmap_unref (source);
1743 gdk_pixmap_unref (mask);
1746 GdkColor mbg = { 0, 0, 0, 0 }; /* Black */
1747 GdkColor mfg = { 0, 0, 0, 65535 }; /* Blue. */
1749 source = gdk_bitmap_create_from_data (NULL, mag_bits,
1750 mag_width, mag_height);
1751 mask = gdk_bitmap_create_from_data (NULL, magmask_bits,
1752 mag_width, mag_height);
1753 zoom_cursor = gdk_cursor_new_from_pixmap (source, mask, &mfg, &mbg, mag_x_hot, mag_y_hot);
1754 gdk_pixmap_unref (source);
1755 gdk_pixmap_unref (mask);
1757 GdkColor fbg = { 0, 65535, 65535, 65535 };
1758 GdkColor ffg = { 0, 0, 0, 0 };
1760 source = gdk_bitmap_create_from_data (NULL, fader_cursor_bits,
1761 fader_cursor_width, fader_cursor_height);
1762 mask = gdk_bitmap_create_from_data (NULL, fader_cursor_mask_bits,
1763 fader_cursor_width, fader_cursor_height);
1764 fader_cursor = gdk_cursor_new_from_pixmap (source, mask, &ffg, &fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1765 gdk_pixmap_unref (source);
1766 gdk_pixmap_unref (mask);
1768 source = gdk_bitmap_create_from_data (NULL, speaker_cursor_bits,
1769 speaker_cursor_width, speaker_cursor_height);
1770 mask = gdk_bitmap_create_from_data (NULL, speaker_cursor_mask_bits,
1771 speaker_cursor_width, speaker_cursor_height);
1772 speaker_cursor = gdk_cursor_new_from_pixmap (source, mask, &ffg, &fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1773 gdk_pixmap_unref (source);
1774 gdk_pixmap_unref (mask);
1776 cross_hair_cursor = gdk_cursor_new (GDK_CROSSHAIR);
1777 trimmer_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
1778 selector_cursor = gdk_cursor_new (GDK_XTERM);
1779 time_fx_cursor = gdk_cursor_new (GDK_SIZING);
1780 wait_cursor = gdk_cursor_new (GDK_WATCH);
1781 timebar_cursor = gdk_cursor_new (GDK_LEFT_PTR);
1785 Editor::popup_fade_context_menu (int button, int32_t time, GnomeCanvasItem* item, ItemType item_type)
1787 using namespace Menu_Helpers;
1788 AudioRegionView* arv = static_cast<AudioRegionView*> (gtk_object_get_data (GTK_OBJECT(item), "regionview"));
1791 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1795 MenuList& items (fade_context_menu.items());
1799 switch (item_type) {
1801 case FadeInHandleItem:
1802 if (arv->region.fade_in_active()) {
1803 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false)));
1805 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true)));
1808 items.push_back (SeparatorElem());
1810 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear)));
1811 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB)));
1812 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast)));
1813 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA)));
1814 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow)));
1818 case FadeOutHandleItem:
1819 if (arv->region.fade_out_active()) {
1820 items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false)));
1822 items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true)));
1825 items.push_back (SeparatorElem());
1827 items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear)));
1828 items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast)));
1829 items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB)));
1830 items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA)));
1831 items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow)));
1835 fatal << _("programming error: ")
1836 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1841 fade_context_menu.popup (button, time);
1845 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, jack_nframes_t frame)
1847 using namespace Menu_Helpers;
1848 Menu* (Editor::*build_menu_function)(jack_nframes_t);
1851 switch (item_type) {
1853 case AudioRegionViewName:
1854 case AudioRegionViewNameHighlight:
1855 if (with_selection) {
1856 build_menu_function = &Editor::build_track_selection_context_menu;
1858 build_menu_function = &Editor::build_track_region_context_menu;
1863 if (with_selection) {
1864 build_menu_function = &Editor::build_track_selection_context_menu;
1866 build_menu_function = &Editor::build_track_context_menu;
1870 case CrossfadeViewItem:
1871 build_menu_function = &Editor::build_track_crossfade_context_menu;
1875 if (clicked_audio_trackview->get_diskstream()) {
1876 build_menu_function = &Editor::build_track_context_menu;
1878 build_menu_function = &Editor::build_track_bus_context_menu;
1883 /* probably shouldn't happen but if it does, we don't care */
1887 menu = (this->*build_menu_function)(frame);
1888 menu->set_name ("ArdourContextMenu");
1890 /* now handle specific situations */
1892 switch (item_type) {
1894 case AudioRegionViewName:
1895 case AudioRegionViewNameHighlight:
1896 if (!with_selection) {
1897 if (region_edit_menu_split_item) {
1898 if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) {
1899 region_edit_menu_split_item->set_sensitive (true);
1901 region_edit_menu_split_item->set_sensitive (false);
1904 if (region_edit_menu_split_multichannel_item) {
1905 if (clicked_regionview && clicked_regionview->region.n_channels() > 1) {
1906 region_edit_menu_split_multichannel_item->set_sensitive (true);
1908 region_edit_menu_split_multichannel_item->set_sensitive (false);
1917 case CrossfadeViewItem:
1924 /* probably shouldn't happen but if it does, we don't care */
1928 if (clicked_audio_trackview && clicked_audio_trackview->audio_track()) {
1930 /* Bounce to disk */
1932 using namespace Menu_Helpers;
1933 MenuList& edit_items = menu->items();
1935 edit_items.push_back (SeparatorElem());
1937 switch (clicked_audio_trackview->audio_track()->freeze_state()) {
1938 case AudioTrack::NoFreeze:
1939 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1942 case AudioTrack::Frozen:
1943 edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
1946 case AudioTrack::UnFrozen:
1947 edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
1953 menu->popup (button, time);
1957 Editor::build_track_context_menu (jack_nframes_t ignored)
1959 using namespace Menu_Helpers;
1961 MenuList& edit_items = track_context_menu.items();
1964 add_dstream_context_items (edit_items);
1965 return &track_context_menu;
1969 Editor::build_track_bus_context_menu (jack_nframes_t ignored)
1971 using namespace Menu_Helpers;
1973 MenuList& edit_items = track_context_menu.items();
1976 add_bus_context_items (edit_items);
1977 return &track_context_menu;
1981 Editor::build_track_region_context_menu (jack_nframes_t frame)
1983 using namespace Menu_Helpers;
1984 MenuList& edit_items = track_region_context_menu.items();
1987 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
1993 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
1994 Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed()));
1995 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
1996 add_region_context_items (atv->view, (*i), edit_items);
2002 add_dstream_context_items (edit_items);
2004 return &track_region_context_menu;
2008 Editor::build_track_crossfade_context_menu (jack_nframes_t frame)
2010 using namespace Menu_Helpers;
2011 MenuList& edit_items = track_crossfade_context_menu.items();
2012 edit_items.clear ();
2014 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_trackview);
2021 if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = dynamic_cast<AudioPlaylist*> (pl)) != 0)) {
2023 Playlist::RegionList* regions = pl->regions_at (frame);
2024 AudioPlaylist::Crossfades xfades;
2026 apl->crossfades_at (frame, xfades);
2028 bool many = xfades.size() > 1;
2030 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
2031 add_crossfade_context_items (atv->view, (*i), edit_items, many);
2034 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
2035 add_region_context_items (atv->view, (*i), edit_items);
2042 add_dstream_context_items (edit_items);
2044 return &track_crossfade_context_menu;
2048 Editor::build_track_selection_context_menu (jack_nframes_t ignored)
2050 using namespace Menu_Helpers;
2051 MenuList& edit_items = track_selection_context_menu.items();
2052 edit_items.clear ();
2054 add_selection_context_items (edit_items);
2055 add_dstream_context_items (edit_items);
2057 return &track_selection_context_menu;
2061 Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many)
2063 using namespace Menu_Helpers;
2064 Menu *xfade_menu = manage (new Menu);
2065 MenuList& items = xfade_menu->items();
2066 xfade_menu->set_name ("ArdourContextMenu");
2069 if (xfade->active()) {
2075 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_active), xfade)));
2076 items.push_back (MenuElem (_("Edit"), bind (mem_fun(*this, &Editor::edit_xfade), xfade)));
2078 if (xfade->can_follow_overlap()) {
2080 if (xfade->following_overlap()) {
2081 str = _("Convert to short");
2083 str = _("Convert to full");
2086 items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
2090 str = xfade->out().name();
2092 str += xfade->in().name();
2094 str = _("Crossfade");
2097 edit_items.push_back (MenuElem (str, *xfade_menu));
2098 edit_items.push_back (SeparatorElem());
2102 Editor::xfade_edit_left_region ()
2104 if (clicked_crossfadeview) {
2105 clicked_crossfadeview->left_view.show_region_editor ();
2110 Editor::xfade_edit_right_region ()
2112 if (clicked_crossfadeview) {
2113 clicked_crossfadeview->right_view.show_region_editor ();
2118 Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items)
2120 using namespace Menu_Helpers;
2121 Menu *region_menu = manage (new Menu);
2122 MenuList& items = region_menu->items();
2123 region_menu->set_name ("ArdourContextMenu");
2125 AudioRegion* ar = 0;
2128 ar = dynamic_cast<AudioRegion*> (region);
2131 /* when this particular menu pops up, make the relevant region
2135 region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, region));
2137 items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
2138 items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top)));
2139 items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom)));
2140 items.push_back (SeparatorElem());
2141 items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
2142 items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
2143 items.push_back (SeparatorElem());
2145 items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
2146 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
2147 items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
2148 items.push_back (SeparatorElem());
2150 /* XXX hopefully this nonsense will go away with SigC++ 2.X, where the compiler
2151 might be able to figure out which overloaded member function to use in
2155 void (Editor::*type_A_pmf)(void (Region::*pmf)(bool), bool) = &Editor::region_selection_op;
2157 items.push_back (MenuElem (_("Lock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, true)));
2158 items.push_back (MenuElem (_("Unlock"), bind (mem_fun(*this, type_A_pmf), &Region::set_locked, false)));
2159 items.push_back (SeparatorElem());
2161 if (region->muted()) {
2162 items.push_back (MenuElem (_("Unmute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, false)));
2164 items.push_back (MenuElem (_("Mute"), bind (mem_fun(*this, type_A_pmf), &Region::set_muted, true)));
2166 items.push_back (SeparatorElem());
2168 items.push_back (MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)));
2169 items.push_back (SeparatorElem());
2174 items.push_back (MenuElem (_("Toggle envelope visibility"), mem_fun(*this, &Editor::toggle_gain_envelope_visibility)));
2175 items.push_back (MenuElem (_("Toggle envelope active"), mem_fun(*this, &Editor::toggle_gain_envelope_active)));
2176 items.push_back (SeparatorElem());
2178 if (ar->scale_amplitude() != 1.0f) {
2179 items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
2181 items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
2184 items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
2185 items.push_back (SeparatorElem());
2189 Menu *nudge_menu = manage (new Menu());
2190 MenuList& nudge_items = nudge_menu->items();
2191 nudge_menu->set_name ("ArdourContextMenu");
2193 nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
2194 nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
2195 nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
2196 nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
2198 items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2199 items.push_back (SeparatorElem());
2201 Menu *trim_menu = manage (new Menu);
2202 MenuList& trim_items = trim_menu->items();
2203 trim_menu->set_name ("ArdourContextMenu");
2205 trim_items.push_back (MenuElem (_("Start to edit cursor"), mem_fun(*this, &Editor::trim_region_from_edit_cursor)));
2206 trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
2208 items.push_back (MenuElem (_("Trim"), *trim_menu));
2209 items.push_back (SeparatorElem());
2211 items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
2212 region_edit_menu_split_item = &items.back();
2214 items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
2215 region_edit_menu_split_multichannel_item = &items.back();
2217 items.push_back (MenuElem (_("Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true))));
2218 items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track))));
2219 items.push_back (SeparatorElem());
2220 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region)));
2221 items.push_back (SeparatorElem());
2222 items.push_back (MenuElem (_("Destroy"), mem_fun(*this, &Editor::destroy_clicked_region)));
2224 /* OK, stick the region submenu at the top of the list, and then add
2228 /* we have to hack up the region name because "_" has a special
2229 meaning for menu titles.
2232 string::size_type pos = 0;
2233 string menu_item_name = region->name();
2235 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
2236 menu_item_name.replace (pos, 1, "__");
2240 edit_items.push_back (MenuElem (menu_item_name, *region_menu));
2241 edit_items.push_back (SeparatorElem());
2245 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
2247 using namespace Menu_Helpers;
2248 Menu *selection_menu = manage (new Menu);
2249 MenuList& items = selection_menu->items();
2250 selection_menu->set_name ("ArdourContextMenu");
2252 items.push_back (MenuElem (_("Play range"), mem_fun(*this, &Editor::play_selection)));
2253 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::set_route_loop_selection)));
2254 items.push_back (SeparatorElem());
2255 items.push_back (MenuElem (_("Create chunk from range"), mem_fun(*this, &Editor::name_selection)));
2256 items.push_back (SeparatorElem());
2257 items.push_back (MenuElem (_("Create Region"), mem_fun(*this, &Editor::new_region_from_selection)));
2258 items.push_back (MenuElem (_("Separate Region"), mem_fun(*this, &Editor::separate_region_from_selection)));
2259 items.push_back (MenuElem (_("Crop Region to range"), mem_fun(*this, &Editor::crop_region_to_selection)));
2260 items.push_back (MenuElem (_("Bounce range"), mem_fun(*this, &Editor::bounce_range_selection)));
2261 items.push_back (SeparatorElem());
2262 items.push_back (MenuElem (_("Duplicate"), bind (mem_fun(*this, &Editor::duplicate_dialog), false)));
2263 items.push_back (SeparatorElem());
2264 items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_selection)));
2265 items.push_back (SeparatorElem());
2266 items.push_back (MenuElem (_("Fill range w/Region"), mem_fun(*this, &Editor::region_fill_selection)));
2268 edit_items.push_back (MenuElem (_("Range"), *selection_menu));
2269 edit_items.push_back (SeparatorElem());
2273 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2275 using namespace Menu_Helpers;
2279 Menu *play_menu = manage (new Menu);
2280 MenuList& play_items = play_menu->items();
2281 play_menu->set_name ("ArdourContextMenu");
2283 play_items.push_back (MenuElem (_("Play from edit cursor")));
2284 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2285 play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
2286 play_items.push_back (SeparatorElem());
2287 play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
2289 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2293 Menu *select_menu = manage (new Menu);
2294 MenuList& select_items = select_menu->items();
2295 select_menu->set_name ("ArdourContextMenu");
2297 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
2298 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
2299 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2300 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
2301 select_items.push_back (SeparatorElem());
2302 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
2303 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
2304 select_items.push_back (SeparatorElem());
2306 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2310 Menu *cutnpaste_menu = manage (new Menu);
2311 MenuList& cutnpaste_items = cutnpaste_menu->items();
2312 cutnpaste_menu->set_name ("ArdourContextMenu");
2314 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2315 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2316 cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2317 cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
2319 cutnpaste_items.push_back (SeparatorElem());
2321 cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
2322 cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
2324 cutnpaste_items.push_back (SeparatorElem());
2326 cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
2328 cutnpaste_items.push_back (SeparatorElem());
2330 cutnpaste_items.push_back (MenuElem (_("New Region from range"), mem_fun(*this, &Editor::new_region_from_selection)));
2331 cutnpaste_items.push_back (MenuElem (_("Separate Range"), mem_fun(*this, &Editor::separate_region_from_selection)));
2333 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2335 /* Adding new material */
2337 Menu *import_menu = manage (new Menu());
2338 MenuList& import_items = import_menu->items();
2339 import_menu->set_name ("ArdourContextMenu");
2341 import_items.push_back (MenuElem (_("Insert Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2342 import_items.push_back (MenuElem (_("Insert external sndfile"), bind (mem_fun(*this, &Editor::insert_sndfile), false)));
2344 edit_items.push_back (MenuElem (_("Import"), *import_menu));
2348 Menu *nudge_menu = manage (new Menu());
2349 MenuList& nudge_items = nudge_menu->items();
2350 nudge_menu->set_name ("ArdourContextMenu");
2352 edit_items.push_back (SeparatorElem());
2353 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2354 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2355 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2356 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2358 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2362 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2364 using namespace Menu_Helpers;
2368 Menu *play_menu = manage (new Menu);
2369 MenuList& play_items = play_menu->items();
2370 play_menu->set_name ("ArdourContextMenu");
2372 play_items.push_back (MenuElem (_("Play from edit cursor")));
2373 play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
2374 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2378 Menu *select_menu = manage (new Menu);
2379 MenuList& select_items = select_menu->items();
2380 select_menu->set_name ("ArdourContextMenu");
2382 select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), false)));
2383 select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), false)));
2384 select_items.push_back (MenuElem (_("Invert in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
2385 select_items.push_back (MenuElem (_("Invert"), mem_fun(*this, &Editor::invert_selection)));
2386 select_items.push_back (SeparatorElem());
2387 select_items.push_back (MenuElem (_("Select loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
2388 select_items.push_back (MenuElem (_("Select punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
2389 select_items.push_back (SeparatorElem());
2391 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2395 Menu *cutnpaste_menu = manage (new Menu);
2396 MenuList& cutnpaste_items = cutnpaste_menu->items();
2397 cutnpaste_menu->set_name ("ArdourContextMenu");
2399 cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
2400 cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
2401 cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
2403 Menu *nudge_menu = manage (new Menu());
2404 MenuList& nudge_items = nudge_menu->items();
2405 nudge_menu->set_name ("ArdourContextMenu");
2407 edit_items.push_back (SeparatorElem());
2408 nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
2409 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
2410 nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
2411 nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
2413 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2416 /* CURSOR SETTING AND MARKS AND STUFF */
2419 Editor::set_snap_to (SnapType st)
2422 vector<string> txt = internationalize (snap_type_strings);
2423 snap_type_selector.get_entry()->set_text (txt[(int)st]);
2427 switch (snap_type) {
2428 case SnapToAThirtysecondBeat:
2429 case SnapToASixteenthBeat:
2430 case SnapToAEighthBeat:
2431 case SnapToAQuarterBeat:
2432 case SnapToAThirdBeat:
2433 update_tempo_based_rulers ();
2441 Editor::set_snap_mode (SnapMode mode)
2444 vector<string> txt = internationalize (snap_mode_strings);
2445 snap_mode_selector.get_entry()->set_text (txt[(int)mode]);
2451 Editor::add_location_from_selection ()
2453 if (selection->time.empty()) {
2457 if (session == 0 || clicked_trackview == 0) {
2461 jack_nframes_t start = selection->time[clicked_selection].start;
2462 jack_nframes_t end = selection->time[clicked_selection].end;
2464 Location *location = new Location (start, end, "selection");
2466 session->begin_reversible_command (_("add marker"));
2467 session->add_undo (session->locations()->get_memento());
2468 session->locations()->add (location, true);
2469 session->add_redo_no_execute (session->locations()->get_memento());
2470 session->commit_reversible_command ();
2474 Editor::add_location_from_playhead_cursor ()
2476 jack_nframes_t where = session->audible_frame();
2478 Location *location = new Location (where, where, "mark", Location::IsMark);
2479 session->begin_reversible_command (_("add marker"));
2480 session->add_undo (session->locations()->get_memento());
2481 session->locations()->add (location, true);
2482 session->add_redo_no_execute (session->locations()->get_memento());
2483 session->commit_reversible_command ();
2488 Editor::set_state (const XMLNode& node)
2490 const XMLProperty* prop;
2492 int x, y, width, height, xoff, yoff;
2494 if ((geometry = find_named_node (node, "geometry")) == 0) {
2496 width = default_width;
2497 height = default_height;
2505 width = atoi(geometry->property("x_size")->value());
2506 height = atoi(geometry->property("y_size")->value());
2507 x = atoi(geometry->property("x_pos")->value());
2508 y = atoi(geometry->property("y_pos")->value());
2509 xoff = atoi(geometry->property("x_off")->value());
2510 yoff = atoi(geometry->property("y_off")->value());
2513 set_default_size(width, height);
2514 set_uposition(x, y-yoff);
2516 if ((prop = node.property ("zoom-focus"))) {
2517 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2520 if ((prop = node.property ("zoom"))) {
2521 set_frames_per_unit (atof (prop->value()));
2524 if ((prop = node.property ("snap-to"))) {
2525 set_snap_to ((SnapType) atoi (prop->value()));
2528 if ((prop = node.property ("snap-mode"))) {
2529 set_snap_mode ((SnapMode) atoi (prop->value()));
2532 if ((prop = node.property ("show-waveforms"))) {
2533 bool yn = (prop->value() == "yes");
2534 _show_waveforms = !yn;
2535 set_show_waveforms (yn);
2538 if ((prop = node.property ("show-waveforms-recording"))) {
2539 bool yn = (prop->value() == "yes");
2540 _show_waveforms_recording = !yn;
2541 set_show_waveforms_recording (yn);
2544 if ((prop = node.property ("show-measures"))) {
2545 bool yn = (prop->value() == "yes");
2546 _show_measures = !yn;
2547 set_show_measures (yn);
2550 if ((prop = node.property ("follow-playhead"))) {
2551 bool yn = (prop->value() == "yes");
2552 _follow_playhead = !yn;
2553 set_follow_playhead (yn);
2556 if ((prop = node.property ("xfades-visible"))) {
2557 bool yn = (prop->value() == "yes");
2558 _xfade_visibility = !yn;
2559 set_xfade_visibility (yn);
2562 if ((prop = node.property ("region-list-sort-type"))) {
2563 region_list_sort_type = (Editing::RegionListSortType) -1; /* force change */
2564 reset_region_list_sort_type(str2regionlistsorttype(prop->value()));
2567 if ((prop = node.property ("mouse-mode"))) {
2568 MouseMode m = str2mousemode(prop->value());
2569 mouse_mode = MouseMode ((int) m + 1); /* lie, force mode switch */
2570 set_mouse_mode (m, true);
2572 mouse_mode = MouseGain; /* lie, to force the mode switch */
2573 set_mouse_mode (MouseObject, true);
2576 if ((prop = node.property ("editor-mixer-button"))) {
2577 editor_mixer_button.set_active(prop->value() == "yes");
2584 Editor::get_state ()
2586 XMLNode* node = new XMLNode ("Editor");
2589 if (is_realized()) {
2590 Gdk_Window win = get_window();
2592 int x, y, xoff, yoff, width, height;
2593 win.get_root_origin(x, y);
2594 win.get_position(xoff, yoff);
2595 win.get_size(width, height);
2597 XMLNode* geometry = new XMLNode ("geometry");
2599 snprintf(buf, sizeof(buf), "%d", width);
2600 geometry->add_property("x_size", string(buf));
2601 snprintf(buf, sizeof(buf), "%d", height);
2602 geometry->add_property("y_size", string(buf));
2603 snprintf(buf, sizeof(buf), "%d", x);
2604 geometry->add_property("x_pos", string(buf));
2605 snprintf(buf, sizeof(buf), "%d", y);
2606 geometry->add_property("y_pos", string(buf));
2607 snprintf(buf, sizeof(buf), "%d", xoff);
2608 geometry->add_property("x_off", string(buf));
2609 snprintf(buf, sizeof(buf), "%d", yoff);
2610 geometry->add_property("y_off", string(buf));
2611 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&canvas_region_list_pane)->gobj()));
2612 geometry->add_property("canvas_region_list_pane_pos", string(buf));
2613 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&track_list_canvas_pane)->gobj()));
2614 geometry->add_property("track_list_canvas_pane_pos", string(buf));
2615 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(®ion_selection_vpane)->gobj()));
2616 geometry->add_property("region_selection_pane_pos", string(buf));
2617 snprintf(buf,sizeof(buf), "%d", gtk_paned_get_position (static_cast<Paned*>(&route_group_vpane)->gobj()));
2618 geometry->add_property("route_group_pane_pos", string(buf));
2620 node->add_child_nocopy (*geometry);
2623 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2624 node->add_property ("zoom-focus", buf);
2625 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2626 node->add_property ("zoom", buf);
2627 snprintf (buf, sizeof(buf), "%d", (int) snap_type);
2628 node->add_property ("snap-to", buf);
2629 snprintf (buf, sizeof(buf), "%d", (int) snap_mode);
2630 node->add_property ("snap-mode", buf);
2632 node->add_property ("show-waveforms", _show_waveforms ? "yes" : "no");
2633 node->add_property ("show-waveforms-recording", _show_waveforms_recording ? "yes" : "no");
2634 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2635 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2636 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2637 node->add_property ("region-list-sort-type", enum2str(region_list_sort_type));
2638 node->add_property ("mouse-mode", enum2str(mouse_mode));
2639 node->add_property ("editor-mixer-button", editor_mixer_button.get_active() ? "yes" : "no");
2647 Editor::trackview_by_y_position (double y)
2649 TrackViewList::iterator iter;
2652 for (iter = track_views.begin(); iter != track_views.end(); ++iter) {
2660 if (tv->y_position <= y && y < ((tv->y_position + tv->height + track_spacing))) {
2669 Editor::snap_to (jack_nframes_t& start, int32_t direction, bool for_mark)
2671 Location* before = 0;
2672 Location* after = 0;
2678 const jack_nframes_t one_second = session->frame_rate();
2679 const jack_nframes_t one_minute = session->frame_rate() * 60;
2681 jack_nframes_t presnap = start;
2683 switch (snap_type) {
2689 start = (jack_nframes_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2691 start = (jack_nframes_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2694 case SnapToSMPTEFrame:
2696 start = (jack_nframes_t) (ceil ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2698 start = (jack_nframes_t) (floor ((double) start / session->frames_per_smpte_frame()) * session->frames_per_smpte_frame());
2702 case SnapToSMPTESeconds:
2703 if (session->smpte_offset_negative())
2705 start += session->smpte_offset ();
2707 start -= session->smpte_offset ();
2709 if (direction > 0) {
2710 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2712 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2715 if (session->smpte_offset_negative())
2717 start -= session->smpte_offset ();
2719 start += session->smpte_offset ();
2723 case SnapToSMPTEMinutes:
2724 if (session->smpte_offset_negative())
2726 start += session->smpte_offset ();
2728 start -= session->smpte_offset ();
2731 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2733 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2735 if (session->smpte_offset_negative())
2737 start -= session->smpte_offset ();
2739 start += session->smpte_offset ();
2745 start = (jack_nframes_t) ceil ((double) start / one_second) * one_second;
2747 start = (jack_nframes_t) floor ((double) start / one_second) * one_second;
2753 start = (jack_nframes_t) ceil ((double) start / one_minute) * one_minute;
2755 start = (jack_nframes_t) floor ((double) start / one_minute) * one_minute;
2760 start = session->tempo_map().round_to_bar (start, direction);
2764 start = session->tempo_map().round_to_beat (start, direction);
2767 case SnapToAThirtysecondBeat:
2768 start = session->tempo_map().round_to_beat_subdivision (start, 32);
2771 case SnapToASixteenthBeat:
2772 start = session->tempo_map().round_to_beat_subdivision (start, 16);
2775 case SnapToAEighthBeat:
2776 start = session->tempo_map().round_to_beat_subdivision (start, 8);
2779 case SnapToAQuarterBeat:
2780 start = session->tempo_map().round_to_beat_subdivision (start, 4);
2783 case SnapToAThirdBeat:
2784 start = session->tempo_map().round_to_beat_subdivision (start, 3);
2787 case SnapToEditCursor:
2788 start = edit_cursor->current_frame;
2796 before = session->locations()->first_location_before (start);
2797 after = session->locations()->first_location_after (start);
2799 if (direction < 0) {
2801 start = before->start();
2805 } else if (direction > 0) {
2807 start = after->start();
2809 start = session->current_end_frame();
2814 /* find nearest of the two */
2815 if ((start - before->start()) < (after->start() - start)) {
2816 start = before->start();
2818 start = after->start();
2821 start = before->start();
2824 start = after->start();
2831 case SnapToRegionStart:
2832 case SnapToRegionEnd:
2833 case SnapToRegionSync:
2834 case SnapToRegionBoundary:
2835 if (!region_boundary_cache.empty()) {
2836 vector<jack_nframes_t>::iterator i;
2838 if (direction > 0) {
2839 i = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2841 i = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2844 if (i != region_boundary_cache.end()) {
2847 start = region_boundary_cache.back();
2853 switch (snap_mode) {
2859 if (presnap > start) {
2860 if (presnap > (start + unit_to_frame(snap_threshold))) {
2864 } else if (presnap < start) {
2865 if (presnap < (start - unit_to_frame(snap_threshold))) {
2877 Editor::setup_toolbar ()
2879 nstring pixmap_path;
2880 vector<ToggleButton *> mouse_mode_buttons;
2882 mouse_mode_buttons.push_back (&mouse_move_button);
2883 mouse_mode_buttons.push_back (&mouse_select_button);
2884 mouse_mode_buttons.push_back (&mouse_gain_button);
2885 mouse_mode_buttons.push_back (&mouse_zoom_button);
2886 mouse_mode_buttons.push_back (&mouse_timefx_button);
2887 mouse_mode_buttons.push_back (&mouse_audition_button);
2888 mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons);
2890 mouse_mode_button_table.set_homogeneous (true);
2891 mouse_mode_button_table.set_col_spacings (2);
2892 mouse_mode_button_table.set_row_spacings (2);
2893 mouse_mode_button_table.set_border_width (5);
2895 mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1);
2896 mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1);
2897 mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1);
2899 mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2);
2900 mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2);
2901 mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2);
2903 mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table));
2904 mouse_mode_tearoff->set_name ("MouseModeBase");
2906 mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
2907 static_cast<Gtk::Widget*>(&mouse_mode_button_table)));
2908 mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
2909 static_cast<Gtk::Widget*> (&mouse_mode_button_table), 1));
2911 mouse_move_button.set_name ("MouseModeButton");
2912 mouse_select_button.set_name ("MouseModeButton");
2913 mouse_gain_button.set_name ("MouseModeButton");
2914 mouse_zoom_button.set_name ("MouseModeButton");
2915 mouse_timefx_button.set_name ("MouseModeButton");
2916 mouse_audition_button.set_name ("MouseModeButton");
2918 ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects"));
2919 ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges"));
2920 ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation"));
2921 ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range"));
2922 ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions"));
2923 ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions"));
2925 mouse_move_button.unset_flags (Gtk::CAN_FOCUS);
2926 mouse_select_button.unset_flags (Gtk::CAN_FOCUS);
2927 mouse_gain_button.unset_flags (Gtk::CAN_FOCUS);
2928 mouse_zoom_button.unset_flags (Gtk::CAN_FOCUS);
2929 mouse_timefx_button.unset_flags (Gtk::CAN_FOCUS);
2930 mouse_audition_button.unset_flags (Gtk::CAN_FOCUS);
2932 mouse_select_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
2933 mouse_select_button.signal_button_release_event().connect (mem_fun(*this, &Editor::mouse_select_button_release));
2935 mouse_move_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
2936 mouse_gain_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGain));
2937 mouse_zoom_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseZoom));
2938 mouse_timefx_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
2939 mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition));
2941 // mouse_move_button.set_active (true);
2943 /* automation control */
2945 global_automation_button.set_name ("MouseModeButton");
2946 automation_mode_button.set_name ("MouseModeButton");
2948 automation_box.set_spacing (2);
2949 automation_box.set_border_width (2);
2950 automation_box.pack_start (global_automation_button, false, false);
2951 automation_box.pack_start (automation_mode_button, false, false);
2955 edit_mode_label.set_name ("ToolBarLabel");
2957 edit_mode_selector.set_name ("EditModeSelector");
2958 edit_mode_selector.get_entry()->set_name ("EditModeSelector");
2959 edit_mode_selector.get_popwin()->set_name ("EditModeSelector");
2961 edit_mode_box.set_spacing (3);
2962 edit_mode_box.set_border_width (3);
2964 /* XXX another disgusting hack because of the way combo boxes size themselves */
2966 Gtkmm2ext::set_size_request_to_display_given_text (*edit_mode_selector.get_entry(), "EdgtMode", 2, 10);
2967 set_popdown_string (edit_mode_selector, internationalize (edit_mode_strings));
2969 edit_mode_box.pack_start (edit_mode_label, false, false);
2970 edit_mode_box.pack_start (edit_mode_selector, false, false);
2972 edit_mode_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
2976 snap_type_label.set_name ("ToolBarLabel");
2978 snap_type_selector.set_name ("SnapTypeSelector");
2979 snap_type_selector.get_entry()->set_name ("SnapTypeSelector");
2980 snap_type_selector.get_popwin()->set_name ("SnapTypeSelector");
2982 snap_type_box.set_spacing (3);
2983 snap_type_box.set_border_width (3);
2985 /* XXX another disgusting hack because of the way combo boxes size themselves */
2987 const guint32 FUDGE = 10; // Combo's are stupid - they steal space from the entry for the button
2988 Gtkmm2ext::set_size_request_to_display_given_text (*snap_type_selector.get_entry(), "Region bounds", 2+FUDGE, 10);
2989 set_popdown_strings (snap_type_selector, internationalize (snap_type_strings));
2991 snap_type_box.pack_start (snap_type_label, false, false);
2992 snap_type_box.pack_start (snap_type_selector, false, false);
2994 snap_type_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::snap_type_selection_done));
2996 /* Snap mode, not snap type */
2998 snap_mode_label.set_name ("ToolBarLabel");
3000 snap_mode_selector.set_name ("SnapModeSelector");
3001 snap_mode_selector.get_entry()->set_name ("SnapModeSelector");
3002 snap_mode_selector.get_popwin()->set_name ("SnapModeSelector");
3004 snap_mode_box.set_spacing (3);
3005 snap_mode_box.set_border_width (3);
3007 Gtkmm2ext::set_size_request_to_display_given_text (*snap_mode_selector.get_entry(), "SngpMode", 2, 10);
3008 set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings));
3010 snap_mode_box.pack_start (snap_mode_label, false, false);
3011 snap_mode_box.pack_start (snap_mode_selector, false, false);
3013 snap_mode_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::snap_mode_selection_done));
3015 /* Zoom focus mode */
3017 zoom_focus_label.set_name ("ToolBarLabel");
3019 zoom_focus_selector.set_name ("ZoomFocusSelector");
3020 zoom_focus_selector.get_entry()->set_name ("ZoomFocusSelector");
3021 zoom_focus_selector.get_popwin()->set_name ("ZoomFocusSelector");
3023 zoom_focus_box.set_spacing (3);
3024 zoom_focus_box.set_border_width (3);
3026 /* XXX another disgusting hack because of the way combo boxes size themselves */
3028 Gtkmm2ext::set_size_request_to_display_given_text (*zoom_focus_selector.get_entry(), "Edgt Cursor", 2, 10);
3029 set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings));
3031 zoom_focus_box.pack_start (zoom_focus_label, false, false);
3032 zoom_focus_box.pack_start (zoom_focus_selector, false, false);
3034 zoom_focus_selector.get_popwin()->signal_unmap_event().connect (mem_fun(*this, &Editor::zoom_focus_selection_done));
3036 /* selection/cursor clocks */
3038 toolbar_selection_cursor_label.set_name ("ToolBarLabel");
3039 selection_start_clock_label.set_name ("ToolBarLabel");
3040 selection_end_clock_label.set_name ("ToolBarLabel");
3041 edit_cursor_clock_label.set_name ("ToolBarLabel");
3043 selection_start_clock_label.set_text (_("Start:"));
3044 selection_end_clock_label.set_text (_("End:"));
3045 edit_cursor_clock_label.set_text (_("Edit:"));
3047 toolbar_selection_clock_table.set_border_width (5);
3048 toolbar_selection_clock_table.set_col_spacings (2);
3049 toolbar_selection_clock_table.set_homogeneous (false);
3051 // toolbar_selection_clock_table.attach (selection_start_clock_label, 0, 1, 0, 1, 0, 0, 0, 0);
3052 // toolbar_selection_clock_table.attach (selection_end_clock_label, 1, 2, 0, 1, 0, 0, 0, 0);
3053 toolbar_selection_clock_table.attach (edit_cursor_clock_label, 2, 3, 0, 1, FILL, FILL, 0, 0);
3055 // toolbar_selection_clock_table.attach (selection_start_clock, 0, 1, 1, 2, 0, 0);
3056 // toolbar_selection_clock_table.attach (selection_end_clock, 1, 2, 1, 2, 0, 0);
3057 toolbar_selection_clock_table.attach (edit_cursor_clock, 2, 3, 1, 2, FILL, FILL);
3060 // toolbar_clock_vbox.set_spacing (2);
3061 // toolbar_clock_vbox.set_border_width (10);
3062 /* the editor/mixer button will be enabled at session connect */
3064 editor_mixer_button.set_active(false);
3065 editor_mixer_button.set_sensitive(false);
3067 HBox* hbox = new HBox;
3069 hbox->pack_start (editor_mixer_button, false, false);
3070 hbox->pack_start (toolbar_selection_clock_table, false, false);
3071 hbox->pack_start (zoom_indicator_vbox, false, false);
3072 hbox->pack_start (zoom_focus_box, false, false);
3073 hbox->pack_start (snap_type_box, false, false);
3074 hbox->pack_start (snap_mode_box, false, false);
3075 hbox->pack_start (edit_mode_box, false, false);
3077 VBox *vbox = manage (new VBox);
3079 vbox->set_spacing (3);
3080 vbox->set_border_width (3);
3082 HBox *nbox = manage (new HBox);
3084 nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false));
3085 nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false));
3087 nbox->pack_start (nudge_backward_button, false, false);
3088 nbox->pack_start (nudge_forward_button, false, false);
3089 nbox->pack_start (nudge_clock, false, false, 5);
3091 nudge_label.set_name ("ToolBarLabel");
3093 vbox->pack_start (nudge_label, false, false);
3094 vbox->pack_start (*nbox, false, false);
3096 hbox->pack_start (*vbox, false, false);
3100 tools_tearoff = new TearOff (*hbox);
3101 tools_tearoff->set_name ("MouseModeBase");
3103 tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Gtk::Box*>(&toolbar_hbox),
3104 static_cast<Gtk::Widget*>(hbox)));
3105 tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Gtk::Box*> (&toolbar_hbox),
3106 static_cast<Gtk::Widget*> (hbox), 0));
3108 toolbar_hbox.set_spacing (8);
3109 toolbar_hbox.set_border_width (2);
3111 toolbar_hbox.pack_start (*tools_tearoff, false, false);
3112 toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false);
3114 toolbar_base.set_name ("ToolBarBase");
3115 toolbar_base.add (toolbar_hbox);
3117 toolbar_frame.set_shadow_type (Gtk::SHADOW_OUT);
3118 toolbar_frame.set_name ("BaseFrame");
3119 toolbar_frame.add (toolbar_base);
3123 Editor::_autoscroll_canvas (void *arg)
3125 return ((Editor *) arg)->autoscroll_canvas ();
3129 Editor::autoscroll_canvas ()
3131 jack_nframes_t new_frame;
3132 bool keep_calling = true;
3134 if (autoscroll_direction < 0) {
3135 if (leftmost_frame < autoscroll_distance) {
3138 new_frame = leftmost_frame - autoscroll_distance;
3141 if (leftmost_frame > max_frames - autoscroll_distance) {
3142 new_frame = max_frames;
3144 new_frame = leftmost_frame + autoscroll_distance;
3148 if (new_frame != leftmost_frame) {
3149 reposition_x_origin (new_frame);
3152 if (new_frame == 0 || new_frame == max_frames) {
3159 if (autoscroll_cnt == 1) {
3161 /* connect the timeout so that we get called repeatedly */
3163 autoscroll_timeout_tag = gtk_timeout_add (100, _autoscroll_canvas, this);
3164 keep_calling = false;
3166 } else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
3168 /* after about a while, speed up a bit by changing the timeout interval */
3170 autoscroll_timeout_tag = gtk_timeout_add (50, _autoscroll_canvas, this);
3171 keep_calling = false;
3173 } else if (autoscroll_cnt >= 20 && autoscroll_cnt < 30) {
3175 /* after about another while, speed up some more */
3177 autoscroll_timeout_tag = gtk_timeout_add (25, _autoscroll_canvas, this);
3178 keep_calling = false;
3180 } else if (autoscroll_cnt >= 30) {
3182 /* we've been scrolling for a while ... crank it up */
3184 autoscroll_distance = 10 * (jack_nframes_t) floor (canvas_width * frames_per_unit);
3187 return keep_calling;
3191 Editor::start_canvas_autoscroll (int dir)
3197 stop_canvas_autoscroll ();
3199 autoscroll_direction = dir;
3200 autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/10.0);
3203 /* do it right now, which will start the repeated callbacks */
3205 autoscroll_canvas ();
3209 Editor::stop_canvas_autoscroll ()
3211 if (autoscroll_timeout_tag >= 0) {
3212 gtk_timeout_remove (autoscroll_timeout_tag);
3213 autoscroll_timeout_tag = -1;
3218 Editor::convert_drop_to_paths (vector<string>& paths,
3219 GdkDragContext *context,
3222 GtkSelectionData *data,
3230 gchar *tname = gdk_atom_name (data->type);
3232 if (session == 0 || strcmp (tname, "text/plain") != 0) {
3236 /* Parse the "uri-list" format that Nautilus provides,
3237 where each pathname is delimited by \r\n
3240 path = (char *) data->data;
3243 for (int n = 0; n < data->length; ++n) {
3247 if (path[n] == '\r') {
3254 if (path[n] == '\n') {
3255 paths.push_back (spath);
3259 warning << _("incorrectly formatted URI list, ignored")
3267 /* nautilus and presumably some other file managers prefix even text/plain with file:// */
3269 for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3271 // cerr << "dropped text was " << *p << endl;
3275 // cerr << "decoded was " << *p << endl;
3277 if ((*p).substr (0,7) == "file://") {
3278 (*p) = (*p).substr (7);
3286 Editor::track_canvas_drag_data_received (GdkDragContext *context,
3289 GtkSelectionData *data,
3294 AudioTimeAxisView* tv;
3296 vector<string> paths;
3299 jack_nframes_t frame;
3301 if (convert_drop_to_paths (paths, context, x, y, data, info, time)) {
3305 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
3311 gnome_canvas_window_to_world (GNOME_CANVAS(track_canvas), (double) x, (double) y, &wx, &wy);
3313 ev.type = GDK_BUTTON_RELEASE;
3317 frame = event_frame (&ev, 0, &cy);
3321 if ((tvp = trackview_by_y_position (cy)) == 0) {
3323 /* drop onto canvas background: create a new track */
3325 insert_paths_as_new_tracks (paths, false);
3328 } else if ((tv = dynamic_cast<AudioTimeAxisView*>(tvp)) != 0) {
3330 /* check that its an audio track, not a bus */
3332 if (tv->get_diskstream()) {
3334 for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
3335 insert_sndfile_into (*p, true, tv, frame);
3342 gtk_drag_finish (context, TRUE, FALSE, time);
3346 Editor::new_tempo_section ()
3352 Editor::map_transport_state ()
3354 ENSURE_GUI_THREAD (mem_fun(*this, &Editor::map_transport_state));
3356 if (session->transport_stopped()) {
3357 have_pending_keyboard_selection = false;
3363 Editor::State::State ()
3365 selection = new Selection;
3368 Editor::State::~State ()
3374 Editor::get_memento () const
3376 State *state = new State;
3378 store_state (*state);
3379 return bind (mem_fun (*(const_cast<Editor*>(this)), &Editor::restore_state), state);
3383 Editor::store_state (State& state) const
3385 *state.selection = *selection;
3389 Editor::restore_state (State *state)
3391 if (*selection == *state->selection) {
3395 *selection = *state->selection;
3396 time_selection_changed ();
3397 region_selection_changed ();
3399 /* XXX other selection change handlers? */
3403 Editor::begin_reversible_command (string name)
3406 UndoAction ua = get_memento();
3407 session->begin_reversible_command (name, &ua);
3412 Editor::commit_reversible_command ()
3415 UndoAction ua = get_memento();
3416 session->commit_reversible_command (&ua);
3421 Editor::flush_track_canvas ()
3423 /* I don't think this is necessary, and only causes more problems.
3424 I'm commenting it out
3425 and if the imageframe folks don't have any issues, we can take
3426 out this method entirely
3429 //gnome_canvas_update_now (GNOME_CANVAS(track_canvas));
3430 //gtk_main_iteration ();
3434 Editor::set_selected_track_from_click (bool add, bool with_undo, bool no_remove)
3436 if (!clicked_trackview) {
3441 begin_reversible_command (_("set selected trackview"));
3446 if (selection->selected (clicked_trackview)) {
3448 selection->remove (clicked_trackview);
3451 selection->add (clicked_trackview);
3456 if (selection->selected (clicked_trackview) && selection->tracks.size() == 1) {
3457 /* no commit necessary */
3461 selection->set (clicked_trackview);
3465 commit_reversible_command ();
3470 Editor::set_selected_control_point_from_click (bool add, bool with_undo, bool no_remove)
3472 if (!clicked_control_point) {
3477 begin_reversible_command (_("set selected control point"));
3487 commit_reversible_command ();
3492 Editor::set_selected_regionview_from_click (bool add, bool no_track_remove)
3494 if (!clicked_regionview) {
3498 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&clicked_regionview->get_time_axis_view());
3504 RouteGroup* group = atv->route().edit_group();
3505 vector<AudioRegionView*> all_equivalent_regions;
3507 if (group && group->is_active()) {
3509 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3511 AudioTimeAxisView* tatv;
3513 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3515 if (tatv->route().edit_group() != group) {
3520 vector<AudioRegion*> results;
3521 AudioRegionView* marv;
3524 if ((ds = tatv->get_diskstream()) == 0) {
3529 if ((pl = ds->playlist()) != 0) {
3530 pl->get_equivalent_regions (clicked_regionview->region,
3534 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3535 if ((marv = tatv->view->find_view (**ir)) != 0) {
3536 all_equivalent_regions.push_back (marv);
3545 all_equivalent_regions.push_back (clicked_regionview);
3549 begin_reversible_command (_("set selected regionview"));
3553 if (clicked_regionview->get_selected()) {
3554 if (group && group->is_active() && selection->audio_regions.size() > 1) {
3555 /* reduce selection down to just the one clicked */
3556 selection->set (clicked_regionview);
3558 selection->remove (clicked_regionview);
3561 selection->add (all_equivalent_regions);
3564 set_selected_track_from_click (add, false, no_track_remove);
3568 // karsten wiese suggested these two lines to make
3569 // a selected region rise to the top. but this
3570 // leads to a mismatch between actual layering
3571 // and visual layering. resolution required ....
3573 // gnome_canvas_item_raise_to_top (clicked_regionview->get_canvas_group());
3574 // gnome_canvas_item_raise_to_top (clicked_regionview->get_time_axis_view().canvas_display);
3576 if (clicked_regionview->get_selected()) {
3577 /* no commit necessary: we are the one selected. */
3582 selection->set (all_equivalent_regions);
3583 set_selected_track_from_click (add, false, false);
3587 commit_reversible_command () ;
3591 Editor::set_selected_regionview_from_region_list (Region& r, bool add)
3593 vector<AudioRegionView*> all_equivalent_regions;
3594 AudioRegion* region;
3596 if ((region = dynamic_cast<AudioRegion*>(&r)) == 0) {
3600 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3602 AudioTimeAxisView* tatv;
3604 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
3607 vector<AudioRegion*> results;
3608 AudioRegionView* marv;
3611 if ((ds = tatv->get_diskstream()) == 0) {
3616 if ((pl = ds->playlist()) != 0) {
3617 pl->get_region_list_equivalent_regions (*region, results);
3620 for (vector<AudioRegion*>::iterator ir = results.begin(); ir != results.end(); ++ir) {
3621 if ((marv = tatv->view->find_view (**ir)) != 0) {
3622 all_equivalent_regions.push_back (marv);
3629 begin_reversible_command (_("set selected regions"));
3633 selection->add (all_equivalent_regions);
3637 selection->set (all_equivalent_regions);
3640 commit_reversible_command () ;
3644 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r)
3646 AudioRegionView* rv;
3649 if ((ar = dynamic_cast<AudioRegion*> (r)) == 0) {
3653 if ((rv = sv->find_view (*ar)) == 0) {
3657 /* don't reset the selection if its something other than
3658 a single other region.
3661 if (selection->audio_regions.size() > 1) {
3665 begin_reversible_command (_("set selected regions"));
3667 selection->set (rv);
3669 commit_reversible_command () ;
3675 Editor::set_edit_group_solo (Route& route, bool yn)
3677 RouteGroup *edit_group;
3679 if ((edit_group = route.edit_group()) != 0) {
3680 edit_group->apply (&Route::set_solo, yn, this);
3682 route.set_solo (yn, this);
3687 Editor::set_edit_group_mute (Route& route, bool yn)
3689 RouteGroup *edit_group = 0;
3691 if ((edit_group == route.edit_group()) != 0) {
3692 edit_group->apply (&Route::set_mute, yn, this);
3694 route.set_mute (yn, this);
3699 Editor::set_edit_menu (Menu& menu)
3702 edit_menu->map_.connect (mem_fun(*this, &Editor::edit_menu_map_handler));
3706 Editor::edit_menu_map_handler ()
3708 using namespace Menu_Helpers;
3709 MenuList& edit_items = edit_menu->items();
3712 /* Nuke all the old items */
3714 edit_items.clear ();
3720 if (session->undo_depth() == 0) {
3723 label = string_compose(_("Undo (%1)"), session->next_undo());
3726 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::undo), 1U)));
3728 if (session->undo_depth() == 0) {
3729 edit_items.back().set_sensitive (false);
3732 if (session->redo_depth() == 0) {
3735 label = string_compose(_("Redo (%1)"), session->next_redo());
3738 edit_items.push_back (MenuElem (label, bind (mem_fun(*this, &Editor::redo), 1U)));
3739 if (session->redo_depth() == 0) {
3740 edit_items.back().set_sensitive (false);
3743 vector<MenuItem*> mitems;
3745 edit_items.push_back (SeparatorElem());
3746 edit_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
3747 mitems.push_back (&edit_items.back());
3748 edit_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
3749 mitems.push_back (&edit_items.back());
3750 edit_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
3751 mitems.push_back (&edit_items.back());
3752 edit_items.push_back (SeparatorElem());
3753 edit_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
3754 mitems.push_back (&edit_items.back());
3755 edit_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
3756 mitems.push_back (&edit_items.back());
3757 edit_items.push_back (SeparatorElem());
3759 if (selection->empty()) {
3760 for (vector<MenuItem*>::iterator i = mitems.begin(); i != mitems.end(); ++i) {
3761 (*i)->set_sensitive (false);
3765 Menu* import_menu = manage (new Menu());
3766 import_menu->set_name ("ArdourContextMenu");
3767 MenuList& import_items = import_menu->items();
3769 import_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::import_audio), true)));
3770 import_items.push_back (MenuElem (_("... as new region"), bind (mem_fun(*this, &Editor::import_audio), false)));
3772 Menu* embed_menu = manage (new Menu());
3773 embed_menu->set_name ("ArdourContextMenu");
3774 MenuList& embed_items = embed_menu->items();
3776 embed_items.push_back (MenuElem (_("... as new track"), bind (mem_fun(*this, &Editor::insert_sndfile), true)));
3777 embed_items.push_back (MenuElem (_("... as new region"), mem_fun(*this, &Editor::embed_audio)));
3779 edit_items.push_back (MenuElem (_("Import audio (copy)"), *import_menu));
3780 edit_items.push_back (MenuElem (_("Embed audio (link)"), *embed_menu));
3781 edit_items.push_back (SeparatorElem());
3783 edit_items.push_back (MenuElem (_("Remove last capture"), mem_fun(*this, &Editor::remove_last_capture)));
3784 if (!session->have_captured()) {
3785 edit_items.back().set_sensitive (false);
3790 Editor::duplicate_dialog (bool dup_region)
3793 if (clicked_regionview == 0) {
3797 if (selection->time.length() == 0) {
3802 ArdourDialog win ("duplicate dialog");
3804 Label label (_("Duplicate how many times?"));
3807 Button ok_button (_("OK"));
3808 Button cancel_button (_("Cancel"));
3811 button_box.set_spacing (7);
3812 set_size_request_to_display_given_text (ok_button, _("Cancel"), 20, 15); // this is cancel on purpose
3813 set_size_request_to_display_given_text (cancel_button, _("Cancel"), 20, 15);
3814 button_box.pack_end (ok_button, false, false);
3815 button_box.pack_end (cancel_button, false, false);
3817 hbox.set_spacing (5);
3818 hbox.pack_start (label);
3819 hbox.pack_start (entry, true, true);
3821 vbox.set_spacing (5);
3822 vbox.set_border_width (5);
3823 vbox.pack_start (hbox);
3824 vbox.pack_start (button_box);
3827 win.set_position (Gtk::WIN_POS_MOUSE);
3830 ok_button.signal_clicked().connect (bind (mem_fun (win, &ArdourDialog::stop), 0));
3831 entry.signal_activate().connect (bind (mem_fun (win, &ArdourDialog::stop), 0));
3832 cancel_button.signal_clicked().connect (bind (mem_fun (win, &ArdourDialog::stop), 1));
3834 entry.signal_focus_in_event().connect (sigc::ptr_fun (ARDOUR_UI::generic_focus_in_event));
3835 entry.signal_focus_out_event().connect (sigc::ptr_fun (ARDOUR_UI::generic_focus_out_event));
3837 entry.set_text ("1");
3838 set_size_request_to_display_given_text (entry, X_("12345678"), 20, 15);
3839 entry.select_region (0, entry.get_text_length());
3841 win.set_position (Gtk::WIN_POS_MOUSE);
3843 win.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
3845 entry.grab_focus ();
3849 if (win.run_status() != 0) {
3853 string text = entry.get_text();
3856 if (sscanf (text.c_str(), "%f", ×) == 1) {
3858 AudioRegionSelection regions;
3859 regions.add (clicked_regionview);
3860 duplicate_some_regions (regions, times);
3862 duplicate_selection (times);
3868 Editor::show_verbose_canvas_cursor ()
3870 gnome_canvas_item_raise_to_top (verbose_canvas_cursor);
3871 gnome_canvas_item_show (verbose_canvas_cursor);
3872 verbose_cursor_visible = true;
3876 Editor::hide_verbose_canvas_cursor ()
3878 gnome_canvas_item_hide (verbose_canvas_cursor);
3879 verbose_cursor_visible = false;
3883 Editor::set_verbose_canvas_cursor (string txt, double x, double y)
3885 /* XXX get origin of canvas relative to root window,
3886 add x and y and check compared to gdk_screen_{width,height}
3888 gnome_canvas_item_set (verbose_canvas_cursor, "text", txt.c_str(), "x", x, "y", y, NULL);
3892 Editor::set_verbose_canvas_cursor_text (string txt)
3894 gnome_canvas_item_set (verbose_canvas_cursor, "text", txt.c_str(), NULL);
3898 Editor::edit_mode_selection_done (GdkEventAny *ev)
3904 string choice = edit_mode_selector.get_entry()->get_text();
3905 EditMode mode = Slide;
3907 if (choice == _("Splice")) {
3909 } else if (choice == _("Slide")) {
3913 session->set_edit_mode (mode);
3919 Editor::snap_type_selection_done (GdkEventAny *ev)
3925 string choice = snap_type_selector.get_entry()->get_text();
3926 SnapType snaptype = SnapToFrame;
3928 if (choice == _("Beats/3")) {
3929 snaptype = SnapToAThirdBeat;
3930 } else if (choice == _("Beats/4")) {
3931 snaptype = SnapToAQuarterBeat;
3932 } else if (choice == _("Beats/8")) {
3933 snaptype = SnapToAEighthBeat;
3934 } else if (choice == _("Beats/16")) {
3935 snaptype = SnapToASixteenthBeat;
3936 } else if (choice == _("Beats/32")) {
3937 snaptype = SnapToAThirtysecondBeat;
3938 } else if (choice == _("Beats")) {
3939 snaptype = SnapToBeat;
3940 } else if (choice == _("Bars")) {
3941 snaptype = SnapToBar;
3942 } else if (choice == _("Marks")) {
3943 snaptype = SnapToMark;
3944 } else if (choice == _("Edit Cursor")) {
3945 snaptype = SnapToEditCursor;
3946 } else if (choice == _("Region starts")) {
3947 snaptype = SnapToRegionStart;
3948 } else if (choice == _("Region ends")) {
3949 snaptype = SnapToRegionEnd;
3950 } else if (choice == _("Region bounds")) {
3951 snaptype = SnapToRegionBoundary;
3952 } else if (choice == _("Region syncs")) {
3953 snaptype = SnapToRegionSync;
3954 } else if (choice == _("CD Frames")) {
3955 snaptype = SnapToCDFrame;
3956 } else if (choice == _("SMPTE Frames")) {
3957 snaptype = SnapToSMPTEFrame;
3958 } else if (choice == _("SMPTE Seconds")) {
3959 snaptype = SnapToSMPTESeconds;
3960 } else if (choice == _("SMPTE Minutes")) {
3961 snaptype = SnapToSMPTEMinutes;
3962 } else if (choice == _("Seconds")) {
3963 snaptype = SnapToSeconds;
3964 } else if (choice == _("Minutes")) {
3965 snaptype = SnapToMinutes;
3966 } else if (choice == _("None")) {
3967 snaptype = SnapToFrame;
3970 set_snap_to (snaptype);
3976 Editor::snap_mode_selection_done (GdkEventAny *ev)
3978 if(session == 0) return FALSE;
3980 string choice = snap_mode_selector.get_entry()->get_text();
3981 SnapMode mode = SnapNormal;
3983 if (choice == _("Normal")) {
3985 } else if (choice == _("Magnetic")) {
3986 mode = SnapMagnetic;
3989 set_snap_mode (mode);
3995 Editor::zoom_focus_selection_done (GdkEventAny *ev)
4001 string choice = zoom_focus_selector.get_entry()->get_text();
4002 ZoomFocus focus_type = ZoomFocusLeft;
4004 if (choice == _("Left")) {
4005 focus_type = ZoomFocusLeft;
4006 } else if (choice == _("Right")) {
4007 focus_type = ZoomFocusRight;
4008 } else if (choice == _("Center")) {
4009 focus_type = ZoomFocusCenter;
4010 } else if (choice == _("Playhead")) {
4011 focus_type = ZoomFocusPlayhead;
4012 } else if (choice == _("Edit Cursor")) {
4013 focus_type = ZoomFocusEdit;
4016 set_zoom_focus (focus_type);
4022 Editor::edit_controls_button_release (GdkEventButton* ev)
4024 if (Keyboard::is_context_menu_event (ev)) {
4025 ARDOUR_UI::instance()->add_route ();
4031 Editor::track_selection_changed ()
4033 switch (selection->tracks.size()){
4037 set_selected_mixer_strip (*(selection->tracks.front()));
4041 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4042 (*i)->set_selected (false);
4043 if (mouse_mode == MouseRange) {
4044 (*i)->hide_selection ();
4048 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4049 (*i)->set_selected (true);
4050 if (mouse_mode == MouseRange) {
4051 (*i)->show_selection (selection->time);
4057 Editor::time_selection_changed ()
4059 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4060 (*i)->hide_selection ();
4063 if (selection->tracks.empty()) {
4064 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4065 (*i)->show_selection (selection->time);
4068 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4069 (*i)->show_selection (selection->time);
4075 Editor::region_selection_changed ()
4077 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4078 (*i)->set_selected_regionviews (selection->audio_regions);
4083 Editor::point_selection_changed ()
4085 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4086 (*i)->set_selected_points (selection->points);
4091 Editor::run_sub_event_loop ()
4093 Keyboard::the_keyboard().allow_focus (true);
4094 sub_event_loop_status = 0;
4099 Editor::finish_sub_event_loop (int status)
4102 Keyboard::the_keyboard().allow_focus (false);
4103 sub_event_loop_status = status;
4107 Editor::finish_sub_event_loop_on_delete (GdkEventAny *ignored, int32_t status)
4109 finish_sub_event_loop (status);
4114 Editor::mouse_select_button_release (GdkEventButton* ev)
4116 /* this handles just right-clicks */
4118 if (ev->button != 3) {
4125 Editor::TrackViewList *
4126 Editor::get_valid_views (TimeAxisView* track, RouteGroup* group)
4129 TrackViewList::iterator i;
4131 v = new TrackViewList;
4133 if (track == 0 && group == 0) {
4137 for (i = track_views.begin(); i != track_views.end (); ++i) {
4141 } else if (track != 0 && group == 0 || (track != 0 && group != 0 && !group->is_active())) {
4143 /* just the view for this track
4146 v->push_back (track);
4150 /* views for all tracks in the edit group */
4152 for (i = track_views.begin(); i != track_views.end (); ++i) {
4154 if (group == 0 || (*i)->edit_group() == group) {
4164 Editor::set_zoom_focus (ZoomFocus f)
4166 if (zoom_focus != f) {
4168 vector<string> txt = internationalize (zoom_focus_strings);
4169 zoom_focus_selector.get_entry()->set_text (txt[(int)f]);
4170 ZoomFocusChanged (); /* EMIT_SIGNAL */
4177 Editor::ensure_float (Window& win)
4179 win.set_transient_for (*this);
4183 Editor::pane_allocation_handler (GtkAllocation *alloc, Gtk::Paned* which)
4185 /* recover or initialize pane positions. do this here rather than earlier because
4186 we don't want the positions to change the child allocations, which they seem to do.
4192 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
4194 static int32_t done[4] = { 0, 0, 0, 0 };
4197 if ((geometry = find_named_node (*node, "geometry")) == 0) {
4198 width = default_width;
4199 height = default_height;
4201 width = atoi(geometry->property("x_size")->value());
4202 height = atoi(geometry->property("y_size")->value());
4205 if (which == static_cast<Gtk::Paned*> (&track_list_canvas_pane)) {
4211 if (!geometry || (prop = geometry->property("track_list_canvas_pane_pos")) == 0) {
4213 snprintf (buf, sizeof(buf), "%d", pos);
4215 pos = atoi (prop->value());
4218 if ((done[0] = GTK_WIDGET(track_list_canvas_pane.gobj())->allocation.width > pos)) {
4219 track_list_canvas_pane.set_position (pos);
4222 } else if (which == static_cast<Gtk::Paned*> (&canvas_region_list_pane)) {
4228 if (!geometry || (prop = geometry->property("canvas_region_list_pane_pos")) == 0) {
4229 pos = width - (95 * 2);
4230 snprintf (buf, sizeof(buf), "%d", pos);
4232 pos = atoi (prop->value());
4235 if ((done[1] = GTK_WIDGET(canvas_region_list_pane.gobj())->allocation.width > pos)) {
4236 canvas_region_list_pane.set_position (pos);
4239 } else if (which == static_cast<Gtk::Paned*> (&route_group_vpane)) {
4245 if (!geometry || (prop = geometry->property("route_group_pane_pos")) == 0) {
4246 pos = width - (95 * 2);
4247 snprintf (buf, sizeof(buf), "%d", pos);
4249 pos = atoi (prop->value());
4252 if ((done[2] = GTK_WIDGET(route_group_vpane.gobj())->allocation.height > pos)) {
4253 route_group_vpane.set_position (pos);
4256 } else if (which == static_cast<Gtk::Paned*> (®ion_selection_vpane)) {
4262 if (!geometry || (prop = geometry->property("region_selection_pane_pos")) == 0) {
4263 pos = width - (95 * 2);
4264 snprintf (buf, sizeof(buf), "%d", pos);
4266 pos = atoi (prop->value());
4269 if ((done[3] = GTK_WIDGET(region_selection_vpane.gobj())->allocation.height > pos)) {
4270 region_selection_vpane.set_position (pos);
4276 Editor::detach_tearoff (Gtk::Box* b, Gtk::Widget* w)
4278 if (tools_tearoff->torn_off() &&
4279 mouse_mode_tearoff->torn_off()) {
4280 top_hbox.remove (toolbar_frame);
4283 ensure_float (*w->get_toplevel());
4287 Editor::reattach_tearoff (Gtk::Box* b, Gtk::Widget* w, int32_t n)
4289 if (toolbar_frame.get_parent() == 0) {
4290 top_hbox.pack_end (toolbar_frame);
4295 Editor::set_show_measures (bool yn)
4297 if (_show_measures != yn) {
4300 if ((_show_measures = yn) == true) {
4303 DisplayControlChanged (ShowMeasures);
4309 Editor::set_follow_playhead (bool yn)
4311 if (_follow_playhead != yn) {
4312 if ((_follow_playhead = yn) == true) {
4314 update_current_screen ();
4316 DisplayControlChanged (FollowPlayhead);
4322 Editor::toggle_xfade_active (Crossfade* xfade)
4324 xfade->set_active (!xfade->active());
4328 Editor::toggle_xfade_length (Crossfade* xfade)
4330 xfade->set_follow_overlap (!xfade->following_overlap());
4334 Editor::edit_xfade (Crossfade* xfade)
4336 CrossfadeEditor cew (*session, *xfade, xfade->fade_in().get_min_y(), 1.0);
4340 cew.ok_button.signal_clicked().connect (bind (mem_fun (cew, &ArdourDialog::stop), 1));
4341 cew.cancel_button.signal_clicked().connect (bind (mem_fun (cew, &ArdourDialog::stop), 0));
4342 cew.signal_delete_event().connect (mem_fun (cew, &ArdourDialog::wm_doi_event_stop));
4346 if (cew.run_status() == 1) {
4348 xfade->StateChanged (Change (~0));
4353 Editor::playlist_selector () const
4355 return *_playlist_selector;
4359 Editor::get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next)
4363 ret = nudge_clock.current_duration (pos);
4364 next = ret + 1; /* XXXX fix me */
4370 Editor::end_location_changed (Location* location)
4372 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
4373 track_canvas_scroller.get_hadjustment()->set_upper (location->end() / frames_per_unit);
4377 Editor::playlist_deletion_dialog (Playlist* pl)
4379 ArdourDialog dialog ("playlist deletion dialog");
4380 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4381 "If left alone, no audio files used by it will be cleaned.\n"
4382 "If deleted, audio files used by it alone by will cleaned."),
4385 Button del_button (_("Delete playlist"));
4386 Button keep_button (_("Keep playlist"));
4387 Button abort_button (_("Cancel cleanup"));
4390 button_box.set_spacing (7);
4391 button_box.set_homogeneous (true);
4392 button_box.pack_end (del_button, false, false);
4393 button_box.pack_end (keep_button, false, false);
4394 button_box.pack_end (abort_button, false, false);
4396 vbox.set_spacing (5);
4397 vbox.set_border_width (5);
4398 vbox.pack_start (label);
4399 vbox.pack_start (button_box);
4402 dialog.set_position (Gtk::WIN_POS_CENTER);
4405 del_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 0));
4406 keep_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 1));
4407 abort_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 2));
4410 dialog.get_window()->set_decorations (Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH));
4414 switch (dialog.run_status()) {
4416 /* keep the playlist */
4420 /* delete the playlist */
4428 /* keep the playlist */
4434 Editor::audio_region_selection_covers (jack_nframes_t where)
4436 for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) {
4437 if ((*a)->region.covers (where)) {
4446 Editor::prepare_for_cleanup ()
4448 cut_buffer->clear_audio_regions ();
4449 cut_buffer->clear_playlists ();
4451 selection->clear_audio_regions ();
4452 selection->clear_playlists ();
4456 Editor::init_colormap ()
4458 for (size_t x = 0; x < sizeof (color_id_strs) / sizeof (color_id_strs[0]); ++x) {
4459 pair<ColorID,int> newpair;
4461 newpair.first = (ColorID) x;
4462 newpair.second = rgba_from_style (enum2str (newpair.first), 0, 0, 0, 255);
4463 color_map.insert (newpair);
4468 Editor::transport_loop_location()
4471 return session->locations()->auto_loop_location();
4478 Editor::transport_punch_location()
4481 return session->locations()->auto_punch_location();